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