Don't use identical log messages for non-identical error cases.
[metze/wireshark/wip.git] / capchild / 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 #include <glib.h>
32
33 #include "capture_opts.h"
34
35 #include "capchild/capture_session.h"
36 #include "capchild/capture_sync.h"
37 #ifdef HAVE_EXTCAP
38 #include "extcap.h"
39 #endif
40 #include "log.h"
41
42 #include <caputils/capture_ifinfo.h>
43 #include <wsutil/inet_addr.h>
44
45 #ifdef HAVE_PCAP_REMOTE
46 static GList *remote_interface_list = NULL;
47
48 static GList * append_remote_list(GList *iflist)
49 {
50     GSList *list;
51     GList *rlist;
52     if_addr_t *if_addr, *temp_addr;
53     if_info_t *if_info, *temp;
54
55     for (rlist = g_list_nth(remote_interface_list, 0); rlist != NULL; rlist = g_list_next(rlist)) {
56         if_info = (if_info_t *)rlist->data;
57         temp = g_malloc0(sizeof(if_info_t));
58         temp->name = g_strdup(if_info->name);
59         temp->friendly_name = g_strdup(if_info->friendly_name);
60         temp->vendor_description = g_strdup(if_info->vendor_description);
61         for (list = g_slist_nth(if_info->addrs, 0); list != NULL; list = g_slist_next(list)) {
62             temp_addr = g_malloc0(sizeof(if_addr_t));
63             if_addr = (if_addr_t *)list->data;
64             if (if_addr) {
65                 temp_addr->ifat_type = if_addr->ifat_type;
66                 if (temp_addr->ifat_type == IF_AT_IPv4) {
67                     temp_addr->addr.ip4_addr = if_addr->addr.ip4_addr;
68                 } else {
69                     memcpy(temp_addr->addr.ip6_addr, if_addr->addr.ip6_addr, sizeof(if_addr->addr));
70                 }
71             } else {
72                 g_free(temp_addr);
73                 temp_addr = NULL;
74             }
75             if (temp_addr) {
76                 temp->addrs = g_slist_append(temp->addrs, temp_addr);
77             }
78         }
79         temp->loopback = if_info->loopback;
80         iflist = g_list_append(iflist, temp);
81    }
82    return iflist;
83 }
84 #endif
85
86 /**
87  * Fetch the interface list from a child process (dumpcap).
88  *
89  * @return A GList containing if_info_t structs if successful, NULL (with err and possibly err_str set) otherwise.
90  *
91  */
92
93 /* XXX - We parse simple text output to get our interface list.  Should
94  * we use "real" data serialization instead, e.g. via XML? */
95 GList *
96 capture_interface_list(int *err, char **err_str, void (*update_cb)(void))
97 {
98     int        ret;
99     GList     *if_list = NULL;
100     int        i, j;
101     gchar     *data, *primary_msg, *secondary_msg;
102     gchar    **raw_list, **if_parts, **addr_parts;
103     gchar     *name;
104     if_info_t *if_info;
105     if_addr_t *if_addr;
106
107     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List ...");
108
109     *err = 0;
110
111     /* Try to get our interface list */
112     ret = sync_interface_list_open(&data, &primary_msg, &secondary_msg, update_cb);
113     if (ret != 0) {
114 #ifdef HAVE_EXTCAP
115         /* Add the extcap interfaces that can exist, even if no native interfaces have been found */
116         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Loading External Capture Interface List ...");
117         if_list = append_extcap_interface_list(if_list, err_str);
118         /* err_str is ignored, as the error for the interface loading list will take precedence */
119         if ( g_list_length(if_list) == 0 ) {
120 #endif
121
122             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List failed. Error %d, %s (%s)",
123                   *err, primary_msg ? primary_msg : "no message",
124                   secondary_msg ? secondary_msg : "no secondary message");
125             if (err_str) {
126                 *err_str = primary_msg;
127             } else {
128                 g_free(primary_msg);
129             }
130             g_free(secondary_msg);
131             *err = CANT_GET_INTERFACE_LIST;
132
133 #ifdef HAVE_EXTCAP
134         }
135 #endif
136
137         return if_list;
138     }
139
140     /* Split our lines */
141 #ifdef _WIN32
142     raw_list = g_strsplit(data, "\r\n", 0);
143 #else
144     raw_list = g_strsplit(data, "\n", 0);
145 #endif
146     g_free(data);
147
148     for (i = 0; raw_list[i] != NULL; i++) {
149 #ifdef HAVE_EXTCAP
150         if_parts = g_strsplit(raw_list[i], "\t", 7);
151         if (if_parts[0] == NULL || if_parts[1] == NULL || if_parts[2] == NULL ||
152                 if_parts[3] == NULL || if_parts[4] == NULL || if_parts[5] == NULL ||
153                 if_parts[6] == NULL) {
154             g_strfreev(if_parts);
155             continue;
156         }
157 #else
158         if_parts = g_strsplit(raw_list[i], "\t", 6);
159         if (if_parts[0] == NULL || if_parts[1] == NULL || if_parts[2] == NULL ||
160                 if_parts[3] == NULL || if_parts[4] == NULL || if_parts[5] == NULL) {
161             g_strfreev(if_parts);
162             continue;
163         }
164 #endif
165
166         /* Number followed by the name, e.g "1. eth0" */
167         name = strchr(if_parts[0], ' ');
168         if (name) {
169             name++;
170         } else {
171             g_strfreev(if_parts);
172             continue;
173         }
174
175         if_info = g_new0(if_info_t,1);
176         if_info->name = g_strdup(name);
177         if (strlen(if_parts[1]) > 0)
178             if_info->vendor_description = g_strdup(if_parts[1]);
179         if (strlen(if_parts[2]) > 0)
180             if_info->friendly_name = g_strdup(if_parts[2]);
181         if_info->type = (interface_type)(int)strtol(if_parts[3], NULL, 10);
182         addr_parts = g_strsplit(if_parts[4], ",", 0);
183         for (j = 0; addr_parts[j] != NULL; j++) {
184             if_addr = g_new0(if_addr_t,1);
185             if (ws_inet_pton4(addr_parts[j], &if_addr->addr.ip4_addr)) {
186                 if_addr->ifat_type = IF_AT_IPv4;
187             } else if (ws_inet_pton6(addr_parts[j], (struct e_in6_addr *)&if_addr->addr.ip6_addr)) {
188                 if_addr->ifat_type = IF_AT_IPv6;
189             } else {
190                 g_free(if_addr);
191                 if_addr = NULL;
192             }
193             if (if_addr) {
194                 if_info->addrs = g_slist_append(if_info->addrs, if_addr);
195             }
196         }
197         if (strcmp(if_parts[5], "loopback") == 0)
198             if_info->loopback = TRUE;
199 #ifdef HAVE_EXTCAP
200         if_info->extcap = g_strdup(if_parts[6]);
201 #endif
202         g_strfreev(if_parts);
203         g_strfreev(addr_parts);
204         if_list = g_list_append(if_list, if_info);
205     }
206     g_strfreev(raw_list);
207
208 #ifdef HAVE_PCAP_REMOTE
209     if (remote_interface_list && g_list_length(remote_interface_list) > 0) {
210         if_list = append_remote_list(if_list);
211     }
212 #endif
213
214 #ifdef HAVE_EXTCAP
215     /* Add the extcap interfaces after the native and remote interfaces */
216     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Loading External Capture Interface List ...");
217     if_list = append_extcap_interface_list(if_list, err_str);
218 #endif
219
220     return if_list;
221 }
222
223 /* XXX - We parse simple text output to get our interface list.  Should
224  * we use "real" data serialization instead, e.g. via XML? */
225 if_capabilities_t *
226 capture_get_if_capabilities(const gchar *ifname, gboolean monitor_mode,
227                             const gchar *auth_string,
228                             char **err_str, void (*update_cb)(void))
229 {
230     if_capabilities_t *caps;
231     GList              *linktype_list = NULL;
232     int                 err, i;
233     gchar              *data, *primary_msg, *secondary_msg;
234     gchar             **raw_list, **lt_parts;
235     data_link_info_t   *data_link_info;
236
237     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities ...");
238
239 #ifdef HAVE_EXTCAP
240     /* see if the interface is from extcap */
241     caps = extcap_get_if_dlts(ifname, err_str);
242     if (caps != NULL)
243         return caps;
244
245     /* return if the extcap interface generated an error */
246     if (err_str != NULL && *err_str != NULL)
247         return NULL;
248 #endif /* HAVE_EXTCAP */
249
250     /* Try to get our interface list */
251     err = sync_if_capabilities_open(ifname, monitor_mode, auth_string, &data,
252                                     &primary_msg, &secondary_msg, update_cb);
253     if (err != 0) {
254         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities failed. Error %d, %s (%s)",
255               err, primary_msg ? primary_msg : "no message",
256               secondary_msg ? secondary_msg : "no secondary message");
257         if (err_str) {
258             *err_str = primary_msg;
259         } else {
260             g_free(primary_msg);
261         }
262         g_free(secondary_msg);
263         return NULL;
264     }
265
266     /* Split our lines */
267 #ifdef _WIN32
268     raw_list = g_strsplit(data, "\r\n", 0);
269 #else
270     raw_list = g_strsplit(data, "\n", 0);
271 #endif
272     g_free(data);
273
274     /*
275      * First line is 0 if monitor mode isn't supported, 1 if it is.
276      */
277     if (raw_list[0] == NULL || *raw_list[0] == '\0') {
278         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities returned no information.");
279         if (err_str) {
280             *err_str = g_strdup("Dumpcap returned no interface capability information");
281         }
282         g_strfreev(raw_list);
283         return NULL;
284     }
285
286     /*
287      * Allocate the interface capabilities structure.
288      */
289     caps = (if_capabilities_t *)g_malloc(sizeof *caps);
290     switch (*raw_list[0]) {
291
292     case '0':
293         caps->can_set_rfmon = FALSE;
294         break;
295
296     case '1':
297         caps->can_set_rfmon = TRUE;
298         break;
299
300     default:
301         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities returned bad information.");
302         if (err_str) {
303             *err_str = g_strdup_printf("Dumpcap returned \"%s\" for monitor-mode capability",
304                                        raw_list[0]);
305         }
306         g_free(caps);
307         g_strfreev(raw_list);
308         return NULL;
309     }
310
311     /*
312      * The rest are link-layer types.
313      */
314     for (i = 1; raw_list[i] != NULL; i++) {
315         /* ...and what if the interface name has a tab in it, Mr. Clever Programmer? */
316         lt_parts = g_strsplit(raw_list[i], "\t", 3);
317         if (lt_parts[0] == NULL || lt_parts[1] == NULL || lt_parts[2] == NULL) {
318             g_strfreev(lt_parts);
319             continue;
320         }
321
322         data_link_info = g_new(data_link_info_t,1);
323         data_link_info->dlt = (int) strtol(lt_parts[0], NULL, 10);
324         data_link_info->name = g_strdup(lt_parts[1]);
325         if (strcmp(lt_parts[2], "(not supported)") != 0)
326             data_link_info->description = g_strdup(lt_parts[2]);
327         else
328             data_link_info->description = NULL;
329         g_strfreev(lt_parts);
330
331         linktype_list = g_list_append(linktype_list, data_link_info);
332     }
333     g_strfreev(raw_list);
334
335     /* Check to see if we built a list */
336     if (linktype_list == NULL) {
337         /* No. */
338         if (err_str)
339             *err_str = g_strdup("Dumpcap returned no link-layer types");
340         g_free(caps);
341         return NULL;
342     }
343     caps->data_link_types = linktype_list;
344     return caps;
345 }
346
347 #ifdef HAVE_PCAP_REMOTE
348 void add_interface_to_remote_list(if_info_t *if_info)
349 {
350     GSList *list;
351     if_addr_t *if_addr, *temp_addr;
352
353     if_info_t *temp = g_malloc0(sizeof(if_info_t));
354     temp->name = g_strdup(if_info->name);
355     temp->friendly_name = g_strdup(if_info->friendly_name);
356     temp->vendor_description = g_strdup(if_info->vendor_description);
357     for (list = g_slist_nth(if_info->addrs, 0); list != NULL; list = g_slist_next(list)) {
358         temp_addr = g_malloc0(sizeof(if_addr_t));
359         if_addr = (if_addr_t *)list->data;
360         if (if_addr) {
361             temp_addr->ifat_type = if_addr->ifat_type;
362             if (temp_addr->ifat_type == IF_AT_IPv4) {
363                 temp_addr->addr.ip4_addr = if_addr->addr.ip4_addr;
364             } else {
365                 memcpy(temp_addr->addr.ip6_addr, if_addr->addr.ip6_addr, sizeof(if_addr->addr));
366             }
367         } else {
368             g_free(temp_addr);
369             temp_addr = NULL;
370         }
371         if (temp_addr) {
372             temp->addrs = g_slist_append(temp->addrs, temp_addr);
373         }
374     }
375     temp->loopback = if_info->loopback;
376     remote_interface_list = g_list_append(remote_interface_list, temp);
377 }
378 #endif
379 #endif /* HAVE_LIBPCAP */