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