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