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
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.
34 fill_from_ifaces (interface_t
*device
)
36 interface_options
*interface_opts
;
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) {
45 #if defined(HAVE_PCAP_CREATE)
46 device
->buffer
= interface_opts
->buffer_size
;
47 device
->monitor_mode_enabled
= interface_opts
->monitor_mode
;
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
;
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
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
);
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
);
90 if (if_info
->friendly_name
) {
91 /* We have a friendly name from the OS. */
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
);
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
);
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
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
136 scan_local_interfaces_filtered(GList
* allowed_types
, void (*update_cb
)(void))
138 GList
*if_entry
, *lt_entry
, *if_list
;
141 if_capabilities_t
*caps
=NULL
;
145 unsigned count
= 0, j
;
147 link_row
*link
= NULL
;
148 data_link_info_t
*data_link_info
;
150 GString
*ip_str
= NULL
;
151 interface_options
*interface_opts
;
153 static bool running
= false;
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
160 This return avoids recursive scan_local_interfaces operation. */
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
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:")) {
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
) {
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.
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
) {
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) {
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
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
;
260 if (strstr(if_info
->name
, "rpcap:")) {
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
) {
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) {
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
);
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
;
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
;
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
,
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
;
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;
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
);
368 ip_str
= g_string_new("");
369 for (; (curr_addr
= g_slist_nth(if_info
->addrs
, ips
)) != NULL
; ips
++) {
371 g_string_append(ip_str
, "\n");
373 addr
= (if_addr_t
*)curr_addr
->data
;
376 char* temp_addr_str
= NULL
;
377 switch (addr
->ifat_type
) {
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
);
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
);
389 /* In case we add non-IP addresses */
392 wmem_free(NULL
, temp_addr_str
);
395 device
.addresses
= g_strdup(ip_str
->str
);
396 g_string_free(ip_str
, TRUE
);
399 caps
= if_info
->caps
;
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
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
);
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
;
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
);
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
);
456 #if defined(HAVE_PCAP_CREATE)
457 device
.monitor_mode_enabled
= false;
458 device
.monitor_mode_supported
= false;
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
;
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
;
488 g_array_insert_val(global_capture_opts
.all_ifaces
, count
, device
);
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
);
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
) {
511 if (strcmp(device
.name
, interface_opts
->name
) == 0) {
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
;
527 #if defined(HAVE_PCAP_CREATE)
528 device
.monitor_mode_enabled
= interface_opts
->monitor_mode
;
529 device
.monitor_mode_supported
= false;
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;
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
++;
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.
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.
575 fill_in_local_interfaces_filtered(GList
* filter_list
, void(*update_cb
)(void))
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();
585 /* do the actual work */
586 scan_local_interfaces_filtered(filter_list
, update_cb
);
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
);
596 hide_interface(char* new_hide
)
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
);
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
--;
623 device
->hidden
= false;
626 g_list_free(hidden_devices
);
631 update_local_interfaces(void)
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
);
644 device
->hidden
= prefs_is_capture_device_hidden(device
->name
);
645 fill_from_ifaces(device
);
648 #endif /* HAVE_LIBPCAP */