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