#if 0 (with XXX comment) use of try_conversion(); Also: do misc cosmetic changes.
[metze/wireshark/wip.git] / capture_ifinfo.c
1 /* capture_ifinfo.c
2  * Routines for getting interface information from dumpcap
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include "config.h"
24
25 #ifdef HAVE_LIBPCAP
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30
31 #ifdef HAVE_ARPA_INET_H
32 #include <arpa/inet.h>
33 #endif
34
35 #ifdef HAVE_SYS_SOCKET_H
36 #include <sys/socket.h>         /* needed to define AF_ values on UNIX */
37 #endif
38
39 #ifdef HAVE_WINSOCK2_H
40 #include <winsock2.h>           /* needed to define AF_ values on Windows */
41 #endif
42
43 #ifdef NEED_INET_V6DEFS_H
44 # include "wsutil/inet_v6defs.h"
45 #endif
46
47 #include <glib.h>
48
49 #include "capture_opts.h"
50 #include "capture_session.h"
51 #include "capture_sync.h"
52 #include "log.h"
53
54 #include "capture_ifinfo.h"
55
56 #ifdef HAVE_PCAP_REMOTE
57 static GList *remote_interface_list = NULL;
58
59 static void append_remote_list(GList *iflist)
60 {
61     GSList *list;
62     GList *rlist;
63     if_addr_t *if_addr, *temp_addr;
64     if_info_t *if_info, *temp;
65
66     for (rlist = g_list_nth(remote_interface_list, 0); rlist != NULL; rlist = g_list_next(rlist)) {
67         if_info = (if_info_t *)rlist->data;
68         temp = g_malloc0(sizeof(if_info_t));
69         temp->name = g_strdup(if_info->name);
70         temp->friendly_name = g_strdup(if_info->friendly_name);
71         temp->vendor_description = g_strdup(if_info->vendor_description);
72         for (list = g_slist_nth(if_info->addrs, 0); list != NULL; list = g_slist_next(list)) {
73             temp_addr = g_malloc0(sizeof(if_addr_t));
74             if_addr = (if_addr_t *)list->data;
75             if (if_addr) {
76                 temp_addr->ifat_type = if_addr->ifat_type;
77                 if (temp_addr->ifat_type == IF_AT_IPv4) {
78                     temp_addr->addr.ip4_addr = if_addr->addr.ip4_addr;
79                 } else {
80                     memcpy(temp_addr->addr.ip6_addr, if_addr->addr.ip6_addr, sizeof(if_addr->addr));
81                 }
82             } else {
83                 g_free(temp_addr);
84                 temp_addr = NULL;
85             }
86             if (temp_addr) {
87                 temp->addrs = g_slist_append(temp->addrs, temp_addr);
88             }
89         }
90         temp->loopback = if_info->loopback;
91         iflist = g_list_append(iflist, temp);
92    }
93 }
94 #endif
95
96 /**
97  * Fetch the interface list from a child process (dumpcap).
98  *
99  * @return A GList containing if_info_t structs if successful, NULL (with err and possibly err_str set) otherwise.
100  *
101  */
102
103 /* XXX - We parse simple text output to get our interface list.  Should
104  * we use "real" data serialization instead, e.g. via XML? */
105 GList *
106 capture_interface_list(int *err, char **err_str, void (*update_cb)(void))
107 {
108     int        ret;
109     GList     *if_list = NULL;
110     int        i, j;
111     gchar     *data, *primary_msg, *secondary_msg;
112     gchar    **raw_list, **if_parts, **addr_parts;
113     gchar     *name;
114     if_info_t *if_info;
115     if_addr_t *if_addr;
116
117     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List ...");
118
119     /* Try to get our interface list */
120     ret = sync_interface_list_open(&data, &primary_msg, &secondary_msg, update_cb);
121     if (ret != 0) {
122         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List failed!");
123         if (err_str) {
124             *err_str = primary_msg;
125         } else {
126             g_free(primary_msg);
127         }
128         g_free(secondary_msg);
129         *err = CANT_GET_INTERFACE_LIST;
130         return NULL;
131     }
132
133     /* Split our lines */
134 #ifdef _WIN32
135     raw_list = g_strsplit(data, "\r\n", 0);
136 #else
137     raw_list = g_strsplit(data, "\n", 0);
138 #endif
139     g_free(data);
140
141     for (i = 0; raw_list[i] != NULL; i++) {
142         if_parts = g_strsplit(raw_list[i], "\t", 6);
143         if (if_parts[0] == NULL || if_parts[1] == NULL || if_parts[2] == NULL ||
144                 if_parts[3] == NULL || if_parts[4] == NULL || if_parts[5] == NULL) {
145             g_strfreev(if_parts);
146             continue;
147         }
148
149         /* Number followed by the name, e.g "1. eth0" */
150         name = strchr(if_parts[0], ' ');
151         if (name) {
152             name++;
153         } else {
154             g_strfreev(if_parts);
155             continue;
156         }
157
158         if_info = g_new0(if_info_t,1);
159         if_info->name = g_strdup(name);
160         if (strlen(if_parts[1]) > 0)
161             if_info->vendor_description = g_strdup(if_parts[1]);
162         if (strlen(if_parts[2]) > 0)
163             if_info->friendly_name = g_strdup(if_parts[2]);
164         if_info->type = (interface_type)(int)strtol(if_parts[3], NULL, 10);
165         addr_parts = g_strsplit(if_parts[4], ",", 0);
166         for (j = 0; addr_parts[j] != NULL; j++) {
167             if_addr = g_new0(if_addr_t,1);
168             if (inet_pton(AF_INET, addr_parts[j], &if_addr->addr.ip4_addr) > 0) {
169                 if_addr->ifat_type = IF_AT_IPv4;
170             } else if (inet_pton(AF_INET6, addr_parts[j],
171                     &if_addr->addr.ip6_addr) > 0) {
172                 if_addr->ifat_type = IF_AT_IPv6;
173             } else {
174                 g_free(if_addr);
175                 if_addr = NULL;
176             }
177             if (if_addr) {
178                 if_info->addrs = g_slist_append(if_info->addrs, if_addr);
179             }
180         }
181         if (strcmp(if_parts[5], "loopback") == 0)
182             if_info->loopback = TRUE;
183         g_strfreev(if_parts);
184         g_strfreev(addr_parts);
185         if_list = g_list_append(if_list, if_info);
186     }
187     g_strfreev(raw_list);
188
189     /* Check to see if we built a list */
190     if (if_list == NULL) {
191         *err = NO_INTERFACES_FOUND;
192         if (err_str)
193             *err_str = g_strdup("No interfaces found");
194     }
195 #ifdef HAVE_PCAP_REMOTE
196     if (remote_interface_list && g_list_length(remote_interface_list) > 0) {
197         append_remote_list(if_list);
198     }
199 #endif
200     return if_list;
201 }
202
203 /* XXX - We parse simple text output to get our interface list.  Should
204  * we use "real" data serialization instead, e.g. via XML? */
205 if_capabilities_t *
206 capture_get_if_capabilities(const gchar *ifname, gboolean monitor_mode,
207                             char **err_str, void (*update_cb)(void))
208 {
209     if_capabilities_t *caps;
210     GList              *linktype_list = NULL;
211     int                 err, i;
212     gchar              *data, *primary_msg, *secondary_msg;
213     gchar             **raw_list, **lt_parts;
214     data_link_info_t   *data_link_info;
215
216     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities ...");
217
218     /* Try to get our interface list */
219     err = sync_if_capabilities_open(ifname, monitor_mode, &data,
220                                     &primary_msg, &secondary_msg, update_cb);
221     if (err != 0) {
222         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities failed!");
223         if (err_str) {
224             *err_str = primary_msg;
225         } else {
226             g_free(primary_msg);
227         }
228         g_free(secondary_msg);
229         return NULL;
230     }
231
232     /* Split our lines */
233 #ifdef _WIN32
234     raw_list = g_strsplit(data, "\r\n", 0);
235 #else
236     raw_list = g_strsplit(data, "\n", 0);
237 #endif
238     g_free(data);
239
240     /*
241      * First line is 0 if monitor mode isn't supported, 1 if it is.
242      */
243     if (raw_list[0] == NULL || *raw_list[0] == '\0') {
244         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities returned no information!");
245         if (err_str) {
246             *err_str = g_strdup("Dumpcap returned no interface capability information");
247         }
248         return NULL;
249     }
250
251     /*
252      * Allocate the interface capabilities structure.
253      */
254     caps = (if_capabilities_t *)g_malloc(sizeof *caps);
255     switch (*raw_list[0]) {
256
257     case '0':
258         caps->can_set_rfmon = FALSE;
259         break;
260
261     case '1':
262         caps->can_set_rfmon = TRUE;
263         break;
264
265     default:
266         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities returned bad information!");
267         if (err_str) {
268             *err_str = g_strdup_printf("Dumpcap returned \"%s\" for monitor-mode capability",
269                                        raw_list[0]);
270         }
271         g_free(caps);
272         return NULL;
273     }
274
275     /*
276      * The rest are link-layer types.
277      */
278     for (i = 1; raw_list[i] != NULL; i++) {
279         /* ...and what if the interface name has a tab in it, Mr. Clever Programmer? */
280         lt_parts = g_strsplit(raw_list[i], "\t", 3);
281         if (lt_parts[0] == NULL || lt_parts[1] == NULL || lt_parts[2] == NULL) {
282             g_strfreev(lt_parts);
283             continue;
284         }
285
286         data_link_info = g_new(data_link_info_t,1);
287         data_link_info->dlt = (int) strtol(lt_parts[0], NULL, 10);
288         data_link_info->name = g_strdup(lt_parts[1]);
289         if (strcmp(lt_parts[2], "(not supported)") != 0)
290             data_link_info->description = g_strdup(lt_parts[2]);
291         else
292             data_link_info->description = NULL;
293
294         linktype_list = g_list_append(linktype_list, data_link_info);
295     }
296     g_strfreev(raw_list);
297
298     /* Check to see if we built a list */
299     if (linktype_list == NULL) {
300         /* No. */
301         if (err_str)
302             *err_str = g_strdup("Dumpcap returned no link-layer types");
303         g_free(caps);
304         return NULL;
305     }
306     caps->data_link_types = linktype_list;
307     return caps;
308 }
309
310 #ifdef HAVE_PCAP_REMOTE
311 void add_interface_to_remote_list(if_info_t *if_info)
312 {
313     GSList *list;
314     if_addr_t *if_addr, *temp_addr;
315
316     if_info_t *temp = g_malloc0(sizeof(if_info_t));
317     temp->name = g_strdup(if_info->name);
318     temp->friendly_name = g_strdup(if_info->friendly_name);
319     temp->vendor_description = g_strdup(if_info->vendor_description);
320     for (list = g_slist_nth(if_info->addrs, 0); list != NULL; list = g_slist_next(list)) {
321         temp_addr = g_malloc0(sizeof(if_addr_t));
322         if_addr = (if_addr_t *)list->data;
323         if (if_addr) {
324             temp_addr->ifat_type = if_addr->ifat_type;
325             if (temp_addr->ifat_type == IF_AT_IPv4) {
326                 temp_addr->addr.ip4_addr = if_addr->addr.ip4_addr;
327             } else {
328                 memcpy(temp_addr->addr.ip6_addr, if_addr->addr.ip6_addr, sizeof(if_addr->addr));
329             }
330         } else {
331             g_free(temp_addr);
332             temp_addr = NULL;
333         }
334         if (temp_addr) {
335             temp->addrs = g_slist_append(temp->addrs, temp_addr);
336         }
337     }
338     temp->loopback = if_info->loopback;
339     remote_interface_list = g_list_append(remote_interface_list, temp);
340 }
341 #endif
342 #endif /* HAVE_LIBPCAP */