iface_lists: select interfaces via command line (option -i)
[gd/wireshark/.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  * Try to populate the given device with options (like capture filter) from
59  * the capture options that are in use for an existing capture interface.
60  * Returns TRUE if the interface is selected for capture and FALSE otherwise.
61  */
62 static gboolean
63 fill_from_ifaces (interface_t *device)
64 {
65     interface_options interface_opts;
66     guint i;
67
68     for (i = 0; i < global_capture_opts.ifaces->len; i++) {
69         interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, i);
70         if (strcmp(interface_opts.name, device->name) != 0) {
71             continue;
72         }
73
74 #if defined(HAVE_PCAP_CREATE)
75         device->buffer = interface_opts.buffer_size;
76         device->monitor_mode_enabled = interface_opts.monitor_mode;
77 #endif
78         device->pmode = interface_opts.promisc_mode;
79         device->has_snaplen = interface_opts.has_snaplen;
80         device->snaplen = interface_opts.snaplen;
81         g_free(device->cfilter);
82         device->cfilter = g_strdup(interface_opts.cfilter);
83         if (interface_opts.linktype != -1) {
84             device->active_dlt = interface_opts.linktype;
85         }
86         return TRUE;
87     }
88     return FALSE;
89 }
90
91 /*
92  * Fetch the list of local interfaces with capture_interface_list()
93  * and set the list of "all interfaces" in *capture_opts to include
94  * those interfaces.
95  */
96 void
97 scan_local_interfaces(void (*update_cb)(void))
98 {
99     GList             *if_entry, *lt_entry, *if_list;
100     if_info_t         *if_info, temp;
101     gchar             *descr;
102     if_capabilities_t *caps=NULL;
103     gint              linktype_count;
104     gboolean          monitor_mode;
105     GSList            *curr_addr;
106     int               ips = 0, i;
107     guint             count = 0, j;
108     if_addr_t         *addr, *temp_addr;
109     link_row          *link = NULL;
110     data_link_info_t  *data_link_info;
111     interface_t       device;
112     GString           *ip_str;
113     interface_options interface_opts;
114     gboolean          found = FALSE;
115     static gboolean   running = FALSE;
116     GHashTable        *selected_devices;
117
118     if (running) {
119         /* scan_local_interfaces internally calls update_cb to process UI events
120            to avoid stuck UI while running possibly slow operations. A side effect
121            of this is that new interface changes can be detected before completing
122            the last one.
123            This return avoids recursive scan_local_interfaces operation. */
124         return;
125     }
126     running = TRUE;
127
128     /*
129      * Clear list of known interfaces (all_ifaces) that will be re-discovered on
130      * scanning, but remember their selection state.
131      *
132      * XXX shouldn't this copy settings (like capture filter) from the "old"
133      * device to the "new" device? Refreshing the interfaces list should
134      * probably just remove disappeared devices and add discovered devices.
135      */
136     selected_devices = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
137     if (global_capture_opts.all_ifaces->len > 0) {
138         for (i = (int)global_capture_opts.all_ifaces->len-1; i >= 0; i--) {
139             device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
140             if (device.local && device.type != IF_PIPE && device.type != IF_STDIN) {
141                 global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, i);
142                 /*
143                  * Device is about to be destroyed, unmark as selected. It will
144                  * be reselected on rediscovery.
145                  */
146                 if (device.selected) {
147                     gchar *device_name = g_strdup(device.name);
148                     /* g_hash_table_add() only exists since 2.32. */
149                     g_hash_table_replace(selected_devices, device_name, device_name);
150                     global_capture_opts.num_selected--;
151                 }
152
153                 capture_opts_free_interface_t(&device);
154             }
155         }
156     }
157
158     /* Retrieve list of interface information (if_info_t) into if_list. */
159     g_free(global_capture_opts.ifaces_err_info);
160     if_list = capture_interface_list(&global_capture_opts.ifaces_err,
161                                      &global_capture_opts.ifaces_err_info,
162                                      update_cb);
163     count = 0;
164
165     /*
166      * For each discovered interface name, create a new device and add extra
167      * information (like supported DLTs, assigned IP addresses).
168      */
169     for (if_entry = if_list; if_entry != NULL; if_entry = g_list_next(if_entry)) {
170         memset(&device, 0, sizeof(device));
171         if_info = (if_info_t *)if_entry->data;
172         ip_str = g_string_new("");
173         ips = 0;
174         if (strstr(if_info->name, "rpcap:")) {
175             continue;
176         }
177         device.name = g_strdup(if_info->name);
178         if (if_info->friendly_name != NULL) {
179             device.friendly_name = g_strdup(if_info->friendly_name);
180         } else {
181             device.friendly_name = NULL;
182         }
183         device.hidden = FALSE;
184         device.locked = FALSE;
185         memset(&temp, 0, sizeof(temp));
186         temp.name = g_strdup(if_info->name);
187         temp.friendly_name = g_strdup(if_info->friendly_name);
188         temp.vendor_description = g_strdup(if_info->vendor_description);
189         temp.loopback = if_info->loopback;
190         temp.type = if_info->type;
191 #ifdef HAVE_EXTCAP
192         temp.extcap = g_strdup(if_info->extcap);
193 #endif
194         /* Is this interface hidden and, if so, should we include it anyway? */
195
196         descr = capture_dev_user_descr_find(if_info->name);
197         device.display_name = get_iface_display_name(descr, if_info);
198         g_free(descr);
199         device.selected = FALSE;
200         if (prefs_is_capture_device_hidden(if_info->name)) {
201             device.hidden = TRUE;
202         }
203         device.type = if_info->type;
204         monitor_mode = prefs_capture_device_monitor_mode(if_info->name);
205         caps = capture_get_if_capabilities(if_info->name, monitor_mode, NULL, NULL, update_cb);
206         for (; (curr_addr = g_slist_nth(if_info->addrs, ips)) != NULL; ips++) {
207             temp_addr = (if_addr_t *)g_malloc0(sizeof(if_addr_t));
208             if (ips != 0) {
209                 g_string_append(ip_str, "\n");
210             }
211             addr = (if_addr_t *)curr_addr->data;
212             if (addr) {
213                 address addr_str;
214                 char* temp_addr_str = NULL;
215                 temp_addr->ifat_type = addr->ifat_type;
216                 switch (addr->ifat_type) {
217                     case IF_AT_IPv4:
218                         temp_addr->addr.ip4_addr = addr->addr.ip4_addr;
219                         set_address(&addr_str, AT_IPv4, 4, &addr->addr.ip4_addr);
220                         temp_addr_str = address_to_str(NULL, &addr_str);
221                         g_string_append(ip_str, temp_addr_str);
222                         break;
223                     case IF_AT_IPv6:
224                         memcpy(temp_addr->addr.ip6_addr, addr->addr.ip6_addr, sizeof(addr->addr));
225                         set_address(&addr_str, AT_IPv6, 16, addr->addr.ip6_addr);
226                         temp_addr_str = address_to_str(NULL, &addr_str);
227                         g_string_append(ip_str, temp_addr_str);
228                         break;
229                     default:
230                         /* In case we add non-IP addresses */
231                         break;
232                 }
233                 wmem_free(NULL, temp_addr_str);
234             } else {
235                 g_free(temp_addr);
236                 temp_addr = NULL;
237             }
238             if (temp_addr) {
239                 temp.addrs = g_slist_append(temp.addrs, temp_addr);
240             }
241         }
242 #ifdef HAVE_PCAP_REMOTE
243         device.local = TRUE;
244         device.remote_opts.src_type = CAPTURE_IFLOCAL;
245         device.remote_opts.remote_host_opts.remote_host = g_strdup(global_capture_opts.default_options.remote_host);
246         device.remote_opts.remote_host_opts.remote_port = g_strdup(global_capture_opts.default_options.remote_port);
247         device.remote_opts.remote_host_opts.auth_type = global_capture_opts.default_options.auth_type;
248         device.remote_opts.remote_host_opts.auth_username = g_strdup(global_capture_opts.default_options.auth_username);
249         device.remote_opts.remote_host_opts.auth_password = g_strdup(global_capture_opts.default_options.auth_password);
250         device.remote_opts.remote_host_opts.datatx_udp = global_capture_opts.default_options.datatx_udp;
251         device.remote_opts.remote_host_opts.nocap_rpcap = global_capture_opts.default_options.nocap_rpcap;
252         device.remote_opts.remote_host_opts.nocap_local = global_capture_opts.default_options.nocap_local;
253 #endif
254 #ifdef HAVE_PCAP_SETSAMPLING
255         device.remote_opts.sampling_method = global_capture_opts.default_options.sampling_method;
256         device.remote_opts.sampling_param  = global_capture_opts.default_options.sampling_param;
257 #endif
258         linktype_count = 0;
259         device.links = NULL;
260         if (caps != NULL) {
261 #if defined(HAVE_PCAP_CREATE)
262             device.monitor_mode_enabled = monitor_mode;
263             device.monitor_mode_supported = caps->can_set_rfmon;
264 #endif
265             /*
266              * Process the list of link-layer header types.
267              */
268             for (lt_entry = caps->data_link_types; lt_entry != NULL; lt_entry = g_list_next(lt_entry)) {
269                 data_link_info = (data_link_info_t *)lt_entry->data;
270                 link = (link_row *)g_malloc(sizeof(link_row));
271                 if (data_link_info->description != NULL) {
272                     link->dlt = data_link_info->dlt;
273                     link->name = g_strdup(data_link_info->description);
274                 } else {
275                     link->dlt = -1;
276                     link->name = g_strdup_printf("%s (not supported)", data_link_info->name);
277                 }
278                 device.links = g_list_append(device.links, link);
279                 linktype_count++;
280             }
281
282             /*
283              * Set the active DLT for the device appropriately.
284              */
285             set_active_dlt(&device, global_capture_opts.default_options.linktype);
286         } else {
287 #if defined(HAVE_PCAP_CREATE)
288             device.monitor_mode_enabled = FALSE;
289             device.monitor_mode_supported = FALSE;
290 #endif
291             device.active_dlt = -1;
292         }
293         device.addresses = g_strdup(ip_str->str);
294         device.no_addresses = ips;
295         device.local = TRUE;
296         device.if_info = temp;
297         device.last_packets = 0;
298         if (!capture_dev_user_pmode_find(if_info->name, &device.pmode)) {
299             device.pmode = global_capture_opts.default_options.promisc_mode;
300         }
301         if (!capture_dev_user_snaplen_find(if_info->name, &device.has_snaplen,
302                                            &device.snaplen)) {
303             device.has_snaplen = global_capture_opts.default_options.has_snaplen;
304             device.snaplen = global_capture_opts.default_options.snaplen;
305         }
306         device.cfilter      = g_strdup(global_capture_opts.default_options.cfilter);
307 #ifdef CAN_SET_CAPTURE_BUFFER_SIZE
308         if ((device.buffer = capture_dev_user_buffersize_find(if_info->name)) == -1) {
309             device.buffer = global_capture_opts.default_options.buffer_size;
310         }
311 #endif
312
313         /* Copy interface options for active capture devices. */
314         gboolean selected = fill_from_ifaces(&device);
315         /* Restore device selection (for next capture). */
316         if (!device.selected && (selected || g_hash_table_lookup(selected_devices, device.name))) {
317             device.selected = TRUE;
318             global_capture_opts.num_selected++;
319         }
320
321 #ifdef HAVE_EXTCAP
322         /* Extcap devices start with no cached args */
323         device.external_cap_args_settings = NULL;
324 #endif
325         if (global_capture_opts.all_ifaces->len <= count) {
326             g_array_append_val(global_capture_opts.all_ifaces, device);
327             count = global_capture_opts.all_ifaces->len;
328         } else {
329             g_array_insert_val(global_capture_opts.all_ifaces, count, device);
330         }
331         if (caps != NULL) {
332             free_if_capabilities(caps);
333         }
334
335         g_string_free(ip_str, TRUE);
336         count++;
337     }
338     free_interface_list(if_list);
339
340     /*
341      * Pipes and stdin are not really discoverable interfaces, so re-add them to
342      * the list of all interfaces (all_ifaces).
343      */
344     for (j = 0; j < global_capture_opts.ifaces->len; j++) {
345         interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, j);
346
347         /* Skip non-pipes (like Ethernet, Wi-Fi, ...). */
348         if (interface_opts.if_type != IF_PIPE && interface_opts.if_type != IF_STDIN) {
349             /* Note: the interface options are not destroyed for these
350              * interfaces in case it is briefly removed and re-added. */
351             continue;
352         }
353
354         found = FALSE;
355         for (i = 0; i < (int)global_capture_opts.all_ifaces->len; i++) {
356             device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
357             if (strcmp(device.name, interface_opts.name) == 0) {
358                 found = TRUE;
359                 break;
360             }
361         }
362         if (!found) {  /* new interface, maybe a pipe */
363             memset(&device, 0, sizeof(device));
364             device.name         = g_strdup(interface_opts.name);
365             device.display_name = interface_opts.descr ?
366                 g_strdup_printf("%s: %s", device.name, interface_opts.descr) :
367                 g_strdup(device.name);
368             device.hidden       = FALSE;
369             device.selected     = TRUE;
370             /* XXX shouldn't this be interface_opts.if_type (for IF_STDIN)? */
371             device.type         = IF_PIPE;
372 #ifdef CAN_SET_CAPTURE_BUFFER_SIZE
373             device.buffer = interface_opts.buffer_size;
374 #endif
375 #if defined(HAVE_PCAP_CREATE)
376             device.monitor_mode_enabled = interface_opts.monitor_mode;
377             device.monitor_mode_supported = FALSE;
378 #endif
379             device.pmode = interface_opts.promisc_mode;
380             device.has_snaplen = interface_opts.has_snaplen;
381             device.snaplen = interface_opts.snaplen;
382             device.cfilter = g_strdup(interface_opts.cfilter);
383             device.active_dlt = interface_opts.linktype;
384             device.addresses    = NULL;
385             device.no_addresses = 0;
386             device.last_packets = 0;
387             device.links        = NULL;
388             device.local        = TRUE;
389             device.locked       = FALSE;
390             device.if_info.name = g_strdup(interface_opts.name);
391             device.if_info.friendly_name = NULL;
392             device.if_info.vendor_description = g_strdup(interface_opts.descr);
393             device.if_info.addrs = NULL;
394             device.if_info.loopback = FALSE;
395 #ifdef HAVE_EXTCAP
396             device.if_info.extcap = g_strdup(interface_opts.extcap);
397 #endif
398
399             g_array_append_val(global_capture_opts.all_ifaces, device);
400             global_capture_opts.num_selected++;
401         }
402     }
403
404     g_hash_table_destroy(selected_devices);
405     running = FALSE;
406 }
407
408 /*
409  * Get the global interface list.  Generate it if we haven't done so
410  * already.  This can be quite time consuming the first time, so
411  * record how long it takes in the info log.
412  */
413 void
414 fill_in_local_interfaces(void(*update_cb)(void))
415 {
416     GTimeVal start_time;
417     GTimeVal end_time;
418     float elapsed;
419     static gboolean initialized = FALSE;
420
421     /* record the time we started, so we can log total time later */
422     g_get_current_time(&start_time);
423     g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "fill_in_local_interfaces() starts");
424
425     if (!initialized) {
426         /* do the actual work */
427         scan_local_interfaces(update_cb);
428         initialized = TRUE;
429     }
430     /* log how long it took */
431     g_get_current_time(&end_time);
432     elapsed = (float) ((end_time.tv_sec - start_time.tv_sec) +
433                        ((end_time.tv_usec - start_time.tv_usec) / 1e6));
434
435     g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "fill_in_local_interfaces() ends, taking %.3fs", elapsed);
436 }
437
438 void
439 hide_interface(gchar* new_hide)
440 {
441     gchar       *tok;
442     guint       i;
443     interface_t device;
444     gboolean    found = FALSE;
445     GList       *hidden_devices = NULL, *entry;
446     if (new_hide != NULL) {
447         for (tok = strtok (new_hide, ","); tok; tok = strtok(NULL, ",")) {
448             hidden_devices = g_list_append(hidden_devices, tok);
449         }
450     }
451     for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
452         device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
453         found = FALSE;
454         for (entry = hidden_devices; entry != NULL; entry = g_list_next(entry)) {
455             if (strcmp((char *)entry->data, device.name)==0) {
456                 device.hidden = TRUE;
457                 if (device.selected) {
458                     device.selected = FALSE;
459                     global_capture_opts.num_selected--;
460                 }
461                 found = TRUE;
462                 break;
463             }
464         }
465         if (!found) {
466             device.hidden = FALSE;
467         }
468         global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, i);
469         g_array_insert_val(global_capture_opts.all_ifaces, i, device);
470     }
471     g_list_free(hidden_devices);
472     g_free(new_hide);
473 }
474
475 void
476 update_local_interfaces(void)
477 {
478     interface_t device;
479     gchar *descr;
480     guint i;
481
482     for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
483         device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
484         device.type = capture_dev_user_linktype_find(device.name);
485         g_free (device.display_name);
486         descr = capture_dev_user_descr_find(device.name);
487         device.display_name = get_iface_display_name(descr, &device.if_info);
488         g_free (descr);
489         device.hidden = prefs_is_capture_device_hidden(device.name);
490         fill_from_ifaces(&device);
491
492         global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, i);
493         g_array_insert_val(global_capture_opts.all_ifaces, i, device);
494     }
495 }
496 #endif /* HAVE_LIBPCAP */
497
498 /*
499  * Editor modelines
500  *
501  * Local Variables:
502  * c-basic-offset: 4
503  * tab-width: 8
504  * indent-tabs-mode: nil
505  * End:
506  *
507  * ex: set shiftwidth=4 tabstop=8 expandtab:
508  * :indentSize=4:tabSize=8:noTabs=true:
509  */