Fix parsing of interface properties strings.
[metze/wireshark/wip.git] / ui / iface_lists.c
1 /* iface_lists.c
2  * Code to manage the global list of interfaces and to update widgets/windows
3  * displaying items from those lists
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 #include "config.h"
25
26 #ifdef HAVE_LIBPCAP
27
28 #include <string.h>
29
30 #include <glib.h>
31
32 #include <epan/prefs.h>
33 #include <epan/to_str.h>
34
35 #include "ui/capture_ui_utils.h"
36 #include "ui/capture_globals.h"
37 #include "ui/iface_lists.h"
38 #include "../log.h"
39
40 /*
41  * Used when sorting an interface list into alphabetical order by
42  * their friendly names.
43  */
44 gint
45 if_list_comparator_alph(const void *first_arg, const void *second_arg)
46 {
47     const if_info_t *first = (const if_info_t *)first_arg, *second = (const if_info_t *)second_arg;
48
49     if (first != NULL && first->friendly_name != NULL &&
50         second != NULL && second->friendly_name != NULL) {
51         return g_ascii_strcasecmp(first->friendly_name, second->friendly_name);
52     } else {
53         return 0;
54     }
55 }
56
57 /*
58  * Fetch the list of local interfaces with capture_interface_list()
59  * and set the list of "all interfaces" in *capture_opts to include
60  * those interfaces.
61  */
62 void
63 scan_local_interfaces(void (*update_cb)(void))
64 {
65     GList             *if_entry, *lt_entry, *if_list;
66     if_info_t         *if_info, *temp;
67     char              *if_string;
68     gchar             *descr;
69     if_capabilities_t *caps=NULL;
70     gint              linktype_count;
71     gboolean          monitor_mode;
72     GSList            *curr_addr;
73     int               ips = 0, i;
74     guint             count = 0, j;
75     if_addr_t         *addr, *temp_addr;
76     link_row          *link = NULL;
77     data_link_info_t  *data_link_info;
78     interface_t       device;
79     GString           *ip_str;
80     interface_options interface_opts;
81     gboolean          found = FALSE;
82
83
84     if (global_capture_opts.all_ifaces->len > 0) {
85         for (i = (int)global_capture_opts.all_ifaces->len-1; i >= 0; i--) {
86             device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
87             if (device.local && device.type != IF_PIPE && device.type != IF_STDIN) {
88                 global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, i);
89
90                 if (device.selected) {
91                     global_capture_opts.num_selected--;
92                     /* if device was to be used after this statement,
93                        we should set device.selected=FALSE here */
94                 }
95
96                 /* if we remove an interface from all_interfaces,
97                    it must also be removed from ifaces if it is present there
98                    otherwise, it would be re-added to all_interfaces below
99                    (interfaces set with -i on the command line are initially present in ifaces but not
100                    in all_interfaces, but these interfaces are not removed here) */
101                 for (j = 0; j < global_capture_opts.ifaces->len; j++) {
102                     interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, j);
103                     if (strcmp(device.name, interface_opts.name) == 0) {
104                         /* 2nd param must be the index of ifaces (not all_ifaces) */
105                         capture_opts_del_iface(&global_capture_opts, j);
106                     }
107                 }
108             }
109         }
110     }
111
112     /* Scan through the list and build a list of strings to display. */
113     g_free(global_capture_opts.ifaces_err_info);
114     if_list = capture_interface_list(&global_capture_opts.ifaces_err,
115                                      &global_capture_opts.ifaces_err_info,
116                                      update_cb);
117     count = 0;
118     for (if_entry = if_list; if_entry != NULL; if_entry = g_list_next(if_entry)) {
119         if_info = (if_info_t *)if_entry->data;
120         ip_str = g_string_new("");
121         ips = 0;
122         if (strstr(if_info->name, "rpcap:")) {
123             continue;
124         }
125         device.name = g_strdup(if_info->name);
126         if (if_info->friendly_name != NULL) {
127             device.friendly_name = g_strdup(if_info->friendly_name);
128         } else {
129             device.friendly_name = NULL;
130         }
131         device.hidden = FALSE;
132         device.locked = FALSE;
133         temp = (if_info_t *)g_malloc0(sizeof(if_info_t));
134         temp->name = g_strdup(if_info->name);
135         temp->friendly_name = g_strdup(if_info->friendly_name);
136         temp->vendor_description = g_strdup(if_info->vendor_description);
137         temp->loopback = if_info->loopback;
138         temp->type = if_info->type;
139 #ifdef HAVE_EXTCAP
140         temp->extcap = g_strdup(if_info->extcap);
141 #endif
142         /* Is this interface hidden and, if so, should we include it anyway? */
143
144         /* Do we have a user-supplied description? */
145         descr = capture_dev_user_descr_find(if_info->name);
146         if (descr != NULL) {
147             /* Yes, we have a user-supplied description; use it. */
148             if_string = g_strdup_printf("%s: %s", descr, if_info->name);
149             g_free(descr);
150         } else {
151             /* No, we don't have a user-supplied description; did we get
152             one from the OS or libpcap? */
153             if (if_info->friendly_name != NULL) {
154                 /* We have a friendly name from the OS, use it */
155 #ifdef _WIN32
156                 /*
157                  * On Windows, if we have a friendly name, just show it,
158                  * don't show the name, as that's a string made out of
159                  * the device GUID, and not at all friendly.
160                  */
161                 if_string = g_strdup_printf("%s", if_info->friendly_name);
162 #else
163                 /*
164                  * On UN*X, if we have a friendly name, show it along
165                  * with the interface name; the interface name is short
166                  * and somewhat friendly, and many UN*X users are used
167                  * to interface names, so we should show it.
168                  */
169                 if_string = g_strdup_printf("%s: %s", if_info->friendly_name, if_info->name);
170 #endif
171             } else if (if_info->vendor_description != NULL) {
172                 /* We have a device description from libpcap - use it. */
173                 if_string = g_strdup_printf("%s: %s", if_info->vendor_description, if_info->name);
174             } else {
175                 /* No. */
176                 if_string = g_strdup(if_info->name);
177             }
178         }
179         device.display_name = if_string;
180         device.selected = FALSE;
181         if (prefs_is_capture_device_hidden(if_info->name)) {
182             device.hidden = TRUE;
183         }
184         device.type = if_info->type;
185         monitor_mode = prefs_capture_device_monitor_mode(if_info->name);
186         caps = capture_get_if_capabilities(if_info->name, monitor_mode, NULL, update_cb);
187         for (; (curr_addr = g_slist_nth(if_info->addrs, ips)) != NULL; ips++) {
188             temp_addr = (if_addr_t *)g_malloc0(sizeof(if_addr_t));
189             if (ips != 0) {
190                 g_string_append(ip_str, "\n");
191             }
192             addr = (if_addr_t *)curr_addr->data;
193             if (addr) {
194                 address addr_str;
195                 char* temp_addr_str = NULL;
196                 temp_addr->ifat_type = addr->ifat_type;
197                 switch (addr->ifat_type) {
198                     case IF_AT_IPv4:
199                         temp_addr->addr.ip4_addr = addr->addr.ip4_addr;
200                         SET_ADDRESS(&addr_str, AT_IPv4, 4, &addr->addr.ip4_addr);
201                         temp_addr_str = address_to_str(NULL, &addr_str);
202                         g_string_append(ip_str, temp_addr_str);
203                         break;
204                     case IF_AT_IPv6:
205                         memcpy(temp_addr->addr.ip6_addr, addr->addr.ip6_addr, sizeof(addr->addr));
206                         SET_ADDRESS(&addr_str, AT_IPv6, 16, addr->addr.ip6_addr);
207                         temp_addr_str = address_to_str(NULL, &addr_str);
208                         g_string_append(ip_str, temp_addr_str);
209                         break;
210                     default:
211                         /* In case we add non-IP addresses */
212                         break;
213                 }
214                 wmem_free(NULL, temp_addr_str);
215             } else {
216                 g_free(temp_addr);
217                 temp_addr = NULL;
218             }
219             if (temp_addr) {
220                 temp->addrs = g_slist_append(temp->addrs, temp_addr);
221             }
222         }
223 #ifdef HAVE_PCAP_REMOTE
224         device.local = TRUE;
225         device.remote_opts.src_type = CAPTURE_IFLOCAL;
226         device.remote_opts.remote_host_opts.remote_host = g_strdup(global_capture_opts.default_options.remote_host);
227         device.remote_opts.remote_host_opts.remote_port = g_strdup(global_capture_opts.default_options.remote_port);
228         device.remote_opts.remote_host_opts.auth_type = global_capture_opts.default_options.auth_type;
229         device.remote_opts.remote_host_opts.auth_username = g_strdup(global_capture_opts.default_options.auth_username);
230         device.remote_opts.remote_host_opts.auth_password = g_strdup(global_capture_opts.default_options.auth_password);
231         device.remote_opts.remote_host_opts.datatx_udp = global_capture_opts.default_options.datatx_udp;
232         device.remote_opts.remote_host_opts.nocap_rpcap = global_capture_opts.default_options.nocap_rpcap;
233         device.remote_opts.remote_host_opts.nocap_local = global_capture_opts.default_options.nocap_local;
234 #endif
235 #ifdef HAVE_PCAP_SETSAMPLING
236         device.remote_opts.sampling_method = global_capture_opts.default_options.sampling_method;
237         device.remote_opts.sampling_param  = global_capture_opts.default_options.sampling_param;
238 #endif
239         linktype_count = 0;
240         device.links = NULL;
241         if (caps != NULL) {
242 #if defined(HAVE_PCAP_CREATE)
243             device.monitor_mode_enabled = monitor_mode;
244             device.monitor_mode_supported = caps->can_set_rfmon;
245 #endif
246             /*
247              * If there's a preference for the link-layer header type for
248              * this interface, use it.  If not, use the all-interface
249              * default; if that's not set on the command line, that will
250              * be -1, meaning "use per-interface defaults", otherwise
251              * we'll fail if it's not one of the types the interface
252              * supports.
253              */
254             if ((device.active_dlt = capture_dev_user_linktype_find(if_info->name)) == -1) {
255                 device.active_dlt = global_capture_opts.default_options.linktype;
256             }
257
258             /*
259              * Process the list of link-layer header types.
260              * If the active link-layer header type wasn't set from a
261              * preference or a global option (meaning it's -1), default
262              * to the first link-layer header type in the list.
263              */
264             for (lt_entry = caps->data_link_types; lt_entry != NULL; lt_entry = g_list_next(lt_entry)) {
265                 data_link_info = (data_link_info_t *)lt_entry->data;
266                 if (linktype_count == 0 && device.active_dlt == -1) {
267                     device.active_dlt = data_link_info->dlt;
268                 }
269                 link = (link_row *)g_malloc(sizeof(link_row));
270                 if (data_link_info->description != NULL) {
271                     link->dlt = data_link_info->dlt;
272                     link->name = g_strdup_printf("%s", data_link_info->description);
273                 } else {
274                     link->dlt = -1;
275                     link->name = g_strdup_printf("%s (not supported)", data_link_info->name);
276                 }
277                 device.links = g_list_append(device.links, link);
278                 linktype_count++;
279             }
280         } else {
281 #if defined(HAVE_PCAP_CREATE)
282             device.monitor_mode_enabled = FALSE;
283             device.monitor_mode_supported = FALSE;
284 #endif
285             device.active_dlt = -1;
286         }
287         device.addresses = g_strdup(ip_str->str);
288         device.no_addresses = ips;
289         device.local = TRUE;
290         device.if_info = *temp;
291         device.last_packets = 0;
292         if ((device.pmode = capture_dev_user_pmode_find(if_info->name)) == -1) {
293             device.pmode = global_capture_opts.default_options.promisc_mode;
294         }
295         if (!capture_dev_user_snaplen_find(if_info->name, &device.has_snaplen,
296                                            &device.snaplen)) {
297             device.has_snaplen = global_capture_opts.default_options.has_snaplen;
298             device.snaplen = global_capture_opts.default_options.snaplen;
299         }
300         device.cfilter      = g_strdup(global_capture_opts.default_options.cfilter);
301 #if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
302         if ((device.buffer = capture_dev_user_buffersize_find(if_info->name)) == -1) {
303             device.buffer = global_capture_opts.default_options.buffer_size;
304         }
305 #endif
306
307         if (global_capture_opts.ifaces->len > 0) {
308             for (j = 0; j < global_capture_opts.ifaces->len; j++) {
309                 interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, j);
310                 if (strcmp(interface_opts.name, device.name) == 0) {
311 #if defined(HAVE_PCAP_CREATE)
312                     device.buffer = interface_opts.buffer_size;
313                     device.monitor_mode_enabled = interface_opts.monitor_mode;
314 #endif
315                     device.pmode = interface_opts.promisc_mode;
316                     device.has_snaplen = interface_opts.has_snaplen;
317                     device.snaplen = interface_opts.snaplen;
318                     device.cfilter = g_strdup(interface_opts.cfilter);
319                     if (interface_opts.linktype != -1) {
320                         device.active_dlt = interface_opts.linktype;
321                     }
322                     device.selected = TRUE;
323                     global_capture_opts.num_selected++;
324                     break;
325                 }
326             }
327         }
328
329 #ifdef HAVE_EXTCAP
330         /* Extcap devices start with no cached args */
331         device.external_cap_args_settings = NULL;
332 #endif
333         if (global_capture_opts.all_ifaces->len <= count) {
334             g_array_append_val(global_capture_opts.all_ifaces, device);
335             count = global_capture_opts.all_ifaces->len;
336         } else {
337             g_array_insert_val(global_capture_opts.all_ifaces, count, device);
338         }
339         if (caps != NULL) {
340             free_if_capabilities(caps);
341         }
342
343         g_string_free(ip_str, TRUE);
344         count++;
345     }
346     free_interface_list(if_list);
347     /* see whether there are additional interfaces in ifaces */
348     for (j = 0; j < global_capture_opts.ifaces->len; j++) {
349         interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, j);
350         found = FALSE;
351         for (i = 0; i < (int)global_capture_opts.all_ifaces->len; i++) {
352             device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
353             if (strcmp(device.name, interface_opts.name) == 0) {
354                 found = TRUE;
355                 break;
356             }
357         }
358         if (!found) {  /* new interface, maybe a pipe */
359             device.name         = g_strdup(interface_opts.name);
360             device.display_name = interface_opts.descr ?
361                 g_strdup_printf("%s: %s", device.name, interface_opts.descr) :
362                 g_strdup_printf("%s", device.name);
363             device.hidden       = FALSE;
364             device.selected     = TRUE;
365             device.type         = IF_PIPE;
366 #if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
367             device.buffer = interface_opts.buffer_size;
368 #endif
369 #if defined(HAVE_PCAP_CREATE)
370             device.monitor_mode_enabled = interface_opts.monitor_mode;
371             device.monitor_mode_supported = FALSE;
372 #endif
373             device.pmode = interface_opts.promisc_mode;
374             device.has_snaplen = interface_opts.has_snaplen;
375             device.snaplen = interface_opts.snaplen;
376             device.cfilter = g_strdup(interface_opts.cfilter);
377             device.active_dlt = interface_opts.linktype;
378             device.addresses    = NULL;
379             device.no_addresses = 0;
380             device.last_packets = 0;
381             device.links        = NULL;
382             device.local        = TRUE;
383             device.locked       = FALSE;
384             device.if_info.name = g_strdup(interface_opts.name);
385             device.if_info.friendly_name = NULL;
386             device.if_info.vendor_description = g_strdup(interface_opts.descr);
387             device.if_info.addrs = NULL;
388             device.if_info.loopback = FALSE;
389 #ifdef HAVE_EXTCAP
390             device.if_info.extcap = g_strdup(interface_opts.extcap);
391 #endif
392
393             g_array_append_val(global_capture_opts.all_ifaces, device);
394             global_capture_opts.num_selected++;
395         }
396     }
397 }
398
399 /*
400  * Get the global interface list.  Generate it if we haven't done so
401  * already.  This can be quite time consuming the first time, so
402  * record how long it takes in the info log.
403  */
404 void
405 fill_in_local_interfaces(void(*update_cb)(void))
406 {
407     GTimeVal start_time;
408     GTimeVal end_time;
409     float elapsed;
410     static gboolean initialized = FALSE;
411
412     /* record the time we started, so we can log total time later */
413     g_get_current_time(&start_time);
414     g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "fill_in_local_interfaces() starts");
415
416     if (!initialized) {
417         /* do the actual work */
418         scan_local_interfaces(update_cb);
419         initialized = TRUE;
420     }
421     /* log how long it took */
422     g_get_current_time(&end_time);
423     elapsed = (float) ((end_time.tv_sec - start_time.tv_sec) +
424                        ((end_time.tv_usec - start_time.tv_usec) / 1e6));
425
426     g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "fill_in_local_interfaces() ends, taking %.3fs", elapsed);
427 }
428
429 void
430 hide_interface(gchar* new_hide)
431 {
432     gchar       *tok;
433     guint       i;
434     interface_t device;
435     gboolean    found = FALSE;
436     GList       *hidden_devices = NULL, *entry;
437     if (new_hide != NULL) {
438         for (tok = strtok (new_hide, ","); tok; tok = strtok(NULL, ",")) {
439             hidden_devices = g_list_append(hidden_devices, tok);
440         }
441     }
442     for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
443         device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
444         found = FALSE;
445         for (entry = hidden_devices; entry != NULL; entry = g_list_next(entry)) {
446             if (strcmp((char *)entry->data, device.name)==0) {
447                 device.hidden = TRUE;
448                 if (device.selected) {
449                     device.selected = FALSE;
450                     global_capture_opts.num_selected--;
451                 }
452                 found = TRUE;
453                 break;
454             }
455         }
456         if (!found) {
457             device.hidden = FALSE;
458         }
459         global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, i);
460         g_array_insert_val(global_capture_opts.all_ifaces, i, device);
461     }
462 }
463 #endif /* HAVE_LIBPCAP */
464
465 /*
466  * Editor modelines
467  *
468  * Local Variables:
469  * c-basic-offset: 4
470  * tab-width: 8
471  * indent-tabs-mode: nil
472  * End:
473  *
474  * ex: set shiftwidth=4 tabstop=8 expandtab:
475  * :indentSize=4:tabSize=8:noTabs=true:
476  */