update epan/dissectors/pidl/drsuapi/drsuapi.idl from samba
[wireshark-sm.git] / ui / iface_lists.c
blob4191b84a70760a7ae3fad34d6d09d12090b89bd4
1 /* iface_lists.c
2 * Code to manage the global list of interfaces and to update widgets/windows
3 * displaying items from those lists
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
12 #include "config.h"
14 #ifdef HAVE_LIBPCAP
16 #include <string.h>
18 #include <glib.h>
20 #include <epan/prefs.h>
21 #include <epan/to_str.h>
22 #include <wsutil/wslog.h>
24 #include "ui/capture_ui_utils.h"
25 #include "ui/capture_globals.h"
26 #include "ui/iface_lists.h"
29 * Try to populate the given device with options (like capture filter) from
30 * the capture options that are in use for an existing capture interface.
31 * Returns true if the interface is selected for capture and false otherwise.
33 static bool
34 fill_from_ifaces (interface_t *device)
36 interface_options *interface_opts;
37 unsigned i;
39 for (i = 0; i < global_capture_opts.ifaces->len; i++) {
40 interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, i);
41 if (strcmp(interface_opts->name, device->name) != 0) {
42 continue;
45 #if defined(HAVE_PCAP_CREATE)
46 device->buffer = interface_opts->buffer_size;
47 device->monitor_mode_enabled = interface_opts->monitor_mode;
48 #endif
49 device->pmode = interface_opts->promisc_mode;
50 device->has_snaplen = interface_opts->has_snaplen;
51 device->snaplen = interface_opts->snaplen;
52 g_free(device->cfilter);
53 device->cfilter = g_strdup(interface_opts->cfilter);
54 device->timestamp_type = g_strdup(interface_opts->timestamp_type);
55 if (interface_opts->linktype != -1) {
56 device->active_dlt = interface_opts->linktype;
58 return true;
60 return false;
63 static char *
64 get_iface_display_name(const char *description, const if_info_t *if_info)
66 /* Do we have a user-supplied description? */
67 if (description && description[0]) {
69 * Yes - show both the user-supplied description and a name for the
70 * interface.
72 #ifdef _WIN32
74 * On Windows, if we have a friendly name, just show it
75 * rather than the name, as the name is a string made out
76 * of the device GUID, and not at all friendly.
78 char *if_string = if_info->friendly_name ? if_info->friendly_name : if_info->name;
79 return ws_strdup_printf("%s: %s", description, if_string);
80 #else
82 * On UN*X, show the interface name; it's short and somewhat
83 * friendly, and many UN*X users are used to interface names,
84 * so we should show it.
86 return ws_strdup_printf("%s: %s", description, if_info->name);
87 #endif
90 if (if_info->friendly_name) {
91 /* We have a friendly name from the OS. */
92 #ifdef _WIN32
94 * On Windows, if we have a friendly name, just show it,
95 * don't show the name, as that's a string made out of
96 * the device GUID, and not at all friendly.
98 return ws_strdup_printf("%s", if_info->friendly_name);
99 #else
101 * On UN*X, if we have a friendly name, show it along
102 * with the interface name; the interface name is short
103 * and somewhat friendly, and many UN*X users are used
104 * to interface names, so we should show it.
106 return ws_strdup_printf("%s: %s", if_info->friendly_name, if_info->name);
107 #endif
110 if (if_info->vendor_description) {
111 /* We have a device description from libpcap. */
112 return ws_strdup_printf("%s: %s", if_info->vendor_description, if_info->name);
115 /* No additional descriptions found. */
116 return g_strdup(if_info->name);
120 * Fetch the list of local interfaces with capture_interface_list()
121 * and set the list of "all interfaces" in *capture_opts to include
122 * those interfaces.
124 void
125 scan_local_interfaces(void (*update_cb)(void))
127 scan_local_interfaces_filtered((GList *)0, update_cb);
131 * Fetch the list of local interfaces with capture_interface_list()
132 * and set the list of "all interfaces" in *capture_opts to include
133 * those interfaces.
135 void
136 scan_local_interfaces_filtered(GList * allowed_types, void (*update_cb)(void))
138 GList *if_entry, *lt_entry, *if_list;
139 if_info_t *if_info;
140 char *descr;
141 if_capabilities_t *caps=NULL;
142 bool monitor_mode;
143 GSList *curr_addr;
144 int ips = 0, i;
145 unsigned count = 0, j;
146 if_addr_t *addr;
147 link_row *link = NULL;
148 data_link_info_t *data_link_info;
149 interface_t device;
150 GString *ip_str = NULL;
151 interface_options *interface_opts;
152 bool found = false;
153 static bool running = false;
155 if (running) {
156 /* scan_local_interfaces internally calls update_cb to process UI events
157 to avoid stuck UI while running possibly slow operations. A side effect
158 of this is that new interface changes can be detected before completing
159 the last one.
160 This return avoids recursive scan_local_interfaces operation. */
161 return;
163 running = true;
165 /* Retrieve list of interface information (if_info_t) into if_list. */
166 g_free(global_capture_opts.ifaces_err_info);
167 if_list = global_capture_opts.get_iface_list(&global_capture_opts.ifaces_err,
168 &global_capture_opts.ifaces_err_info);
171 * For each discovered interface name, look up its list of capabilities.
172 * (if it supports monitor mode, supported DLTs, assigned IP addresses).
173 * Do this all at once to reduce the number of spawned privileged dumpcap
174 * processes.
175 * It might be even better to get this information when getting the list,
176 * but some devices can support different DLTs depending on whether
177 * monitor mode is enabled, and we have to look up the monitor mode pref.
179 GList *if_cap_queries = NULL;
180 if_cap_query_t *if_cap_query;
181 GHashTable *capability_hash;
182 for (if_entry = if_list; if_entry != NULL; if_entry = g_list_next(if_entry)) {
183 if_info = (if_info_t *)if_entry->data;
184 if (strstr(if_info->name, "rpcap:")) {
185 continue;
187 /* Filter out all interfaces which are not allowed to be scanned */
188 if (allowed_types != NULL)
190 if(g_list_find(allowed_types, GUINT_TO_POINTER((unsigned) if_info->type)) == NULL) {
191 continue;
194 if (if_info->caps != NULL) {
196 * XXX - We might have capabilities for the wrong monitor mode.
197 * Note that for a current device, the monitor mode setting in
198 * global_capture_opts.all_ifaces is *not* immediately written
199 * to prefs if the Capture Options dialog is still open.
201 continue;
203 if_cap_query = g_new(if_cap_query_t, 1);
204 if_cap_query->name = if_info->name;
205 if_cap_query->monitor_mode = prefs_capture_device_monitor_mode(if_info->name);
206 if_cap_query->auth_username = NULL;
207 if_cap_query->auth_password = NULL;
208 if_cap_queries = g_list_prepend(if_cap_queries, if_cap_query);
210 if_cap_queries = g_list_reverse(if_cap_queries);
211 capability_hash = capture_get_if_list_capabilities(if_cap_queries, NULL, NULL, update_cb);
212 /* The if_info->name are not copied, so we can just free the
213 * if_cap_query_t's and not their members. */
214 g_list_free_full(if_cap_queries, g_free);
217 * From the existing list of known interfaces, remove devices that we
218 * expected to re-discover on scanning but did not (i.e., local devices,
219 * but not pipes, stdin, and remote devices.)
221 if (global_capture_opts.all_ifaces->len > 0) {
222 for (i = (int)global_capture_opts.all_ifaces->len-1; i >= 0; i--) {
223 device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
224 if (device.local && device.if_info.type != IF_PIPE && device.if_info.type != IF_STDIN) {
226 found = false;
227 for (if_entry = if_list; if_entry != NULL; if_entry = g_list_next(if_entry)) {
228 if_info = (if_info_t *)if_entry->data;
230 if (strcmp(device.name, if_info->name) == 0) {
231 found = true;
232 break;
236 if (found) {
237 continue;
240 global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, i);
241 if (device.selected) {
242 global_capture_opts.num_selected--;
244 capture_opts_free_interface_t(&device);
250 * For each discovered interface name, look for it in the list of
251 * devices. If not found, create a new device and add extra
252 * information (including the capabilities we retrieved above).
253 * If found, make sure that the information copied from if_info
254 * is still valid.
256 count = 0;
257 for (if_entry = if_list; if_entry != NULL; if_entry = g_list_next(if_entry)) {
258 if_info = (if_info_t *)if_entry->data;
259 ips = 0;
260 if (strstr(if_info->name, "rpcap:")) {
261 continue;
263 /* Filter out all interfaces which are not allowed to be scanned */
264 if (allowed_types != NULL)
266 if(g_list_find(allowed_types, GUINT_TO_POINTER((unsigned) if_info->type)) == NULL) {
267 continue;
271 found = false;
272 for (i = 0; i < (int)global_capture_opts.all_ifaces->len; i++) {
273 device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
274 if (strcmp(device.name, if_info->name) == 0) {
275 found = true;
276 /* Remove it because we'll reinsert it below (in the proper
277 * index order, if that matters. Does it?)
279 global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, i);
280 break;
284 if (!found) {
285 /* New device. Create a new one and set all the defaults. */
286 memset(&device, 0, sizeof(device));
287 device.name = g_strdup(if_info->name);
288 device.hidden = false;
289 if (prefs_is_capture_device_hidden(if_info->name)) {
290 device.hidden = true;
292 device.selected = false;
294 #ifdef HAVE_PCAP_REMOTE
295 device.remote_opts.src_type = CAPTURE_IFLOCAL;
296 device.remote_opts.remote_host_opts.remote_host = g_strdup(global_capture_opts.default_options.remote_host);
297 device.remote_opts.remote_host_opts.remote_port = g_strdup(global_capture_opts.default_options.remote_port);
298 device.remote_opts.remote_host_opts.auth_type = global_capture_opts.default_options.auth_type;
299 device.remote_opts.remote_host_opts.auth_username = g_strdup(global_capture_opts.default_options.auth_username);
300 device.remote_opts.remote_host_opts.auth_password = g_strdup(global_capture_opts.default_options.auth_password);
301 device.remote_opts.remote_host_opts.datatx_udp = global_capture_opts.default_options.datatx_udp;
302 device.remote_opts.remote_host_opts.nocap_rpcap = global_capture_opts.default_options.nocap_rpcap;
303 device.remote_opts.remote_host_opts.nocap_local = global_capture_opts.default_options.nocap_local;
304 #endif
305 #ifdef HAVE_PCAP_SETSAMPLING
306 device.remote_opts.sampling_method = global_capture_opts.default_options.sampling_method;
307 device.remote_opts.sampling_param = global_capture_opts.default_options.sampling_param;
308 #endif
310 device.local = true;
311 device.last_packets = 0;
312 if (!capture_dev_user_pmode_find(if_info->name, &device.pmode)) {
313 device.pmode = global_capture_opts.default_options.promisc_mode;
315 if (!capture_dev_user_snaplen_find(if_info->name, &device.has_snaplen,
316 &device.snaplen)) {
317 device.has_snaplen = global_capture_opts.default_options.has_snaplen;
318 device.snaplen = global_capture_opts.default_options.snaplen;
320 device.cfilter = g_strdup(global_capture_opts.default_options.cfilter);
321 device.timestamp_type = g_strdup(global_capture_opts.default_options.timestamp_type);
322 #ifdef CAN_SET_CAPTURE_BUFFER_SIZE
323 if ((device.buffer = capture_dev_user_buffersize_find(if_info->name)) == -1) {
324 device.buffer = global_capture_opts.default_options.buffer_size;
326 #endif
328 /* Extcap devices start with no cached args */
329 device.external_cap_args_settings = NULL;
331 monitor_mode = prefs_capture_device_monitor_mode(if_info->name);
332 device.active_dlt = -1;
333 } else {
334 /* We can divide device_t members into three categories:
335 * 1. Those that don't depend on if_info and the capabilities.
336 * Keep those the same.
337 * 2. Those that need to match the retrieved information.
338 * Free those and set them below.
339 * 3. Those that an option chosen from a set of options determined
340 * from the capabilities. We have to check if the chosen values of
341 * monitor mode enabled and active dlt are still supported.
342 * There could be a knock on effect on the capture filter, as if
343 * your previously chosen link-layer type isn't supported then
344 * your capture filter might not be either, which will result in
345 * it being marked invalid instead of being cleared. */
346 /* XXX: We have duplicate copies of the name and we have
347 * the addresses and links from the if_info transformed into new
348 * types, but perhaps that transformation should be done when
349 * creating the if_info and if_capabilities.
351 g_free(device.display_name);
352 g_free(device.addresses);
353 g_list_free_full(device.links, capture_opts_free_link_row);
354 g_free(device.if_info.name);
355 g_free(device.if_info.friendly_name);
356 g_free(device.if_info.vendor_description);
357 g_slist_free_full(device.if_info.addrs, g_free);
358 g_free(device.if_info.extcap);
359 if (device.if_info.caps) {
360 free_if_capabilities(device.if_info.caps);
362 monitor_mode = device.monitor_mode_enabled;
365 descr = capture_dev_user_descr_find(if_info->name);
366 device.display_name = get_iface_display_name(descr, if_info);
367 g_free(descr);
368 ip_str = g_string_new("");
369 for (; (curr_addr = g_slist_nth(if_info->addrs, ips)) != NULL; ips++) {
370 if (ips != 0) {
371 g_string_append(ip_str, "\n");
373 addr = (if_addr_t *)curr_addr->data;
374 if (addr) {
375 address addr_str;
376 char* temp_addr_str = NULL;
377 switch (addr->ifat_type) {
378 case IF_AT_IPv4:
379 set_address(&addr_str, AT_IPv4, 4, &addr->addr.ip4_addr);
380 temp_addr_str = address_to_str(NULL, &addr_str);
381 g_string_append(ip_str, temp_addr_str);
382 break;
383 case IF_AT_IPv6:
384 set_address(&addr_str, AT_IPv6, 16, addr->addr.ip6_addr);
385 temp_addr_str = address_to_str(NULL, &addr_str);
386 g_string_append(ip_str, temp_addr_str);
387 break;
388 default:
389 /* In case we add non-IP addresses */
390 break;
392 wmem_free(NULL, temp_addr_str);
395 device.addresses = g_strdup(ip_str->str);
396 g_string_free(ip_str, TRUE);
398 device.links = NULL;
399 caps = if_info->caps;
400 if (caps == NULL) {
401 caps = g_hash_table_lookup(capability_hash, if_info->name);
403 if (caps != NULL && !caps->primary_msg) {
404 GList *lt_list = caps->data_link_types;
405 #if defined(HAVE_PCAP_CREATE)
406 device.monitor_mode_enabled = monitor_mode && caps->can_set_rfmon;
407 device.monitor_mode_supported = caps->can_set_rfmon;
408 if (device.monitor_mode_enabled) {
409 lt_list = caps->data_link_types_rfmon;
412 if (lt_list == NULL) {
413 /* No failure in retrieving caps, but we have the wrong type.
414 * We need to do a query for link-layer for the correct monitor
415 * mode.
417 ws_debug("%s missing correct link-layer type for monitor_mode %u",
418 if_info->name, monitor_mode);
419 /* On Linux, if libpcap has been compiled with libnl support, this
420 * can cause an infinite loop because of creating a new interface.
422 caps = capture_get_if_capabilities(if_info->name, monitor_mode, NULL, NULL, NULL, update_cb);
423 if (caps) {
424 g_hash_table_replace(capability_hash, g_strdup(if_info->name), caps);
425 lt_list = (device.monitor_mode_enabled) ? caps->data_link_types_rfmon : caps->data_link_types;
428 #endif
430 * Process the list of link-layer header types.
432 bool found_active_dlt = false;
433 for (lt_entry = lt_list; lt_entry != NULL; lt_entry = g_list_next(lt_entry)) {
434 data_link_info = (data_link_info_t *)lt_entry->data;
435 link = g_new(link_row, 1);
436 if (data_link_info->description != NULL) {
437 link->dlt = data_link_info->dlt;
438 link->name = g_strdup(data_link_info->description);
439 } else {
440 link->dlt = -1;
441 link->name = ws_strdup_printf("%s (not supported)", data_link_info->name);
443 if (link->dlt != -1 && link->dlt == device.active_dlt) {
444 found_active_dlt = true;
446 device.links = g_list_append(device.links, link);
450 * Set the active DLT for the device appropriately.
452 if (!found_active_dlt) {
453 set_active_dlt(&device, global_capture_opts.default_options.linktype);
455 } else {
456 #if defined(HAVE_PCAP_CREATE)
457 device.monitor_mode_enabled = false;
458 device.monitor_mode_supported = false;
459 #endif
460 device.active_dlt = -1;
463 device.no_addresses = ips;
465 /* Copy interface options for active capture devices.
466 * XXX: Not clear if we still need to do this, since we're not
467 * destroying the old devices. */
468 bool selected = fill_from_ifaces(&device);
469 /* Restore device selection (for next capture). */
470 if (!device.selected && selected) {
471 device.selected = true;
472 global_capture_opts.num_selected++;
475 /* We shallow copy if_info and then adding to the GArray shallow
476 * copies it again, so free the if_info_t itself but not its members.
477 * Then set the GList element data to NULL so that we don't free
478 * it or its members when freeing the interface list. (This seems a
479 * little easier than removing the link from the list while iterating.)
481 device.if_info = *if_info;
482 if_entry->data = NULL;
483 g_free(if_info);
484 if (global_capture_opts.all_ifaces->len <= count) {
485 g_array_append_val(global_capture_opts.all_ifaces, device);
486 count = global_capture_opts.all_ifaces->len;
487 } else {
488 g_array_insert_val(global_capture_opts.all_ifaces, count, device);
490 count++;
492 g_hash_table_destroy(capability_hash);
493 free_interface_list(if_list);
496 * Pipes and stdin are not really discoverable interfaces, so re-add them to
497 * the list of all interfaces (all_ifaces).
499 for (j = 0; j < global_capture_opts.ifaces->len; j++) {
500 interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, j);
502 found = false;
503 for (i = 0; i < (int)global_capture_opts.all_ifaces->len; i++) {
504 device = g_array_index(global_capture_opts.all_ifaces, interface_t, i);
506 /* Filter out all interfaces, which are not allowed to be scanned */
507 if (allowed_types != NULL && g_list_find(allowed_types, GINT_TO_POINTER(interface_opts->if_type)) == NULL) {
508 continue;
511 if (strcmp(device.name, interface_opts->name) == 0) {
512 found = true;
513 break;
516 if (!found) { /* new interface, maybe a pipe */
517 memset(&device, 0, sizeof(device));
518 device.name = g_strdup(interface_opts->name);
519 device.display_name = interface_opts->descr ?
520 ws_strdup_printf("%s: %s", device.name, interface_opts->descr) :
521 g_strdup(device.name);
522 device.hidden = false;
523 device.selected = true;
524 #ifdef CAN_SET_CAPTURE_BUFFER_SIZE
525 device.buffer = interface_opts->buffer_size;
526 #endif
527 #if defined(HAVE_PCAP_CREATE)
528 device.monitor_mode_enabled = interface_opts->monitor_mode;
529 device.monitor_mode_supported = false;
530 #endif
531 device.pmode = interface_opts->promisc_mode;
532 device.has_snaplen = interface_opts->has_snaplen;
533 device.snaplen = interface_opts->snaplen;
534 device.cfilter = g_strdup(interface_opts->cfilter);
535 device.timestamp_type = g_strdup(interface_opts->timestamp_type);
536 device.active_dlt = interface_opts->linktype;
537 device.addresses = NULL;
538 device.no_addresses = 0;
539 device.last_packets = 0;
540 device.links = NULL;
541 device.local = true;
542 device.if_info.name = g_strdup(interface_opts->name);
543 device.if_info.type = interface_opts->if_type;
544 device.if_info.friendly_name = NULL;
545 device.if_info.vendor_description = g_strdup(interface_opts->hardware);
546 device.if_info.addrs = NULL;
547 device.if_info.loopback = false;
548 device.if_info.extcap = g_strdup(interface_opts->extcap);
550 g_array_append_val(global_capture_opts.all_ifaces, device);
551 global_capture_opts.num_selected++;
555 running = false;
559 * Get the global interface list. Generate it if we haven't done so
560 * already. This can be quite time consuming the first time, so
561 * record how long it takes in the info log.
563 void
564 fill_in_local_interfaces(void(*update_cb)(void))
566 fill_in_local_interfaces_filtered((GList *)0, update_cb);
570 * Get the global interface list. Generate it if we haven't done so
571 * already. This can be quite time consuming the first time, so
572 * record how long it takes in the info log.
574 void
575 fill_in_local_interfaces_filtered(GList * filter_list, void(*update_cb)(void))
577 int64_t start_time;
578 double elapsed;
579 static bool initialized = false;
581 /* record the time we started, so we can log total time later */
582 start_time = g_get_monotonic_time();
584 if (!initialized) {
585 /* do the actual work */
586 scan_local_interfaces_filtered(filter_list, update_cb);
587 initialized = true;
589 /* log how long it took */
590 elapsed = (g_get_monotonic_time() - start_time) / 1e6;
592 ws_log(LOG_DOMAIN_MAIN, LOG_LEVEL_INFO, "Finished getting the global interface list, taking %.3fs", elapsed);
595 void
596 hide_interface(char* new_hide)
598 char *tok;
599 unsigned i;
600 interface_t *device;
601 bool found = false;
602 GList *hidden_devices = NULL, *entry;
603 if (new_hide != NULL) {
604 for (tok = strtok (new_hide, ","); tok; tok = strtok(NULL, ",")) {
605 hidden_devices = g_list_append(hidden_devices, tok);
608 for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
609 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
610 found = false;
611 for (entry = hidden_devices; entry != NULL; entry = g_list_next(entry)) {
612 if (strcmp((char *)entry->data, device->name)==0) {
613 device->hidden = true;
614 if (device->selected) {
615 device->selected = false;
616 global_capture_opts.num_selected--;
618 found = true;
619 break;
622 if (!found) {
623 device->hidden = false;
626 g_list_free(hidden_devices);
627 g_free(new_hide);
630 void
631 update_local_interfaces(void)
633 interface_t *device;
634 char *descr;
635 unsigned i;
637 for (i = 0; i < global_capture_opts.all_ifaces->len; i++) {
638 device = &g_array_index(global_capture_opts.all_ifaces, interface_t, i);
639 device->if_info.type = capture_dev_user_linktype_find(device->name);
640 g_free(device->display_name);
641 descr = capture_dev_user_descr_find(device->name);
642 device->display_name = get_iface_display_name(descr, &device->if_info);
643 g_free (descr);
644 device->hidden = prefs_is_capture_device_hidden(device->name);
645 fill_from_ifaces(device);
648 #endif /* HAVE_LIBPCAP */