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*/
19 #include <epan/prefs.h>
20 #include <epan/to_str.h>
22 #include "ui/capture_ui_utils.h"
23 #include "ui/capture_globals.h"
24 #include "ui/iface_lists.h"
28 * Used when sorting an interface list into alphabetical order by
29 * their friendly names.
32 if_list_comparator_alph(const void *first_arg, const void *second_arg)
34 const if_info_t *first = (const if_info_t *)first_arg, *second = (const if_info_t *)second_arg;
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);
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.
50 fill_from_ifaces (interface_t *device)
52 interface_options *interface_opts;
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) {
61 #if defined(HAVE_PCAP_CREATE)
62 device->buffer = interface_opts->buffer_size;
63 device->monitor_mode_enabled = interface_opts->monitor_mode;
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;
80 * Fetch the list of local interfaces with capture_interface_list()
81 * and set the list of "all interfaces" in *capture_opts to include
85 scan_local_interfaces(void (*update_cb)(void))
87 GList *if_entry, *lt_entry, *if_list;
88 if_info_t *if_info, temp;
90 if_capabilities_t *caps=NULL;
92 gboolean monitor_mode;
96 if_addr_t *addr, *temp_addr;
97 link_row *link = NULL;
98 data_link_info_t *data_link_info;
101 interface_options *interface_opts;
102 gboolean found = FALSE;
103 static gboolean running = FALSE;
104 GHashTable *selected_devices;
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
111 This return avoids recursive scan_local_interfaces operation. */
117 * Clear list of known interfaces (all_ifaces) that will be re-discovered on
118 * scanning, but remember their selection state.
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.
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);
131 * Device is about to be destroyed, unmark as selected. It will
132 * be reselected on rediscovery.
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--;
141 capture_opts_free_interface_t(&device);
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,
154 * For each discovered interface name, create a new device and add extra
155 * information (like supported DLTs, assigned IP addresses).
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("");
162 if (strstr(if_info->name, "rpcap:")) {
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);
176 /* Is this interface hidden and, if so, should we include it anyway? */
178 descr = capture_dev_user_descr_find(if_info->name);
179 device.display_name = get_iface_display_name(descr, if_info);
181 device.selected = FALSE;
182 if (prefs_is_capture_device_hidden(if_info->name)) {
183 device.hidden = TRUE;
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));
191 g_string_append(ip_str, "\n");
193 addr = (if_addr_t *)curr_addr->data;
196 char* temp_addr_str = NULL;
197 temp_addr->ifat_type = addr->ifat_type;
198 switch (addr->ifat_type) {
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);
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);
212 /* In case we add non-IP addresses */
215 wmem_free(NULL, temp_addr_str);
221 temp.addrs = g_slist_append(temp.addrs, temp_addr);
224 #ifdef HAVE_PCAP_REMOTE
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;
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;
243 #if defined(HAVE_PCAP_CREATE)
244 device.monitor_mode_enabled = monitor_mode;
245 device.monitor_mode_supported = caps->can_set_rfmon;
248 * Process the list of link-layer header types.
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);
258 link->name = g_strdup_printf("%s (not supported)", data_link_info->name);
260 device.links = g_list_append(device.links, link);
265 * Set the active DLT for the device appropriately.
267 set_active_dlt(&device, global_capture_opts.default_options.linktype);
269 #if defined(HAVE_PCAP_CREATE)
270 device.monitor_mode_enabled = FALSE;
271 device.monitor_mode_supported = FALSE;
273 device.active_dlt = -1;
275 device.addresses = g_strdup(ip_str->str);
276 device.no_addresses = ips;
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;
283 if (!capture_dev_user_snaplen_find(if_info->name, &device.has_snaplen,
285 device.has_snaplen = global_capture_opts.default_options.has_snaplen;
286 device.snaplen = global_capture_opts.default_options.snaplen;
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;
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++;
304 /* Extcap devices start with no cached args */
305 device.external_cap_args_settings = NULL;
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;
311 g_array_insert_val(global_capture_opts.all_ifaces, count, device);
314 free_if_capabilities(caps);
317 g_string_free(ip_str, TRUE);
320 free_interface_list(if_list);
323 * Pipes and stdin are not really discoverable interfaces, so re-add them to
324 * the list of all interfaces (all_ifaces).
326 for (j = 0; j < global_capture_opts.ifaces->len; j++) {
327 interface_opts = &g_array_index(global_capture_opts.ifaces, interface_options, j);
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) {
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;
349 #if defined(HAVE_PCAP_CREATE)
350 device.monitor_mode_enabled = interface_opts->monitor_mode;
351 device.monitor_mode_supported = FALSE;
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;
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);
371 g_array_append_val(global_capture_opts.all_ifaces, device);
372 global_capture_opts.num_selected++;
376 g_hash_table_destroy(selected_devices);
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.
386 fill_in_local_interfaces(void(*update_cb)(void))
391 static gboolean initialized = FALSE;
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");
398 /* do the actual work */
399 scan_local_interfaces(update_cb);
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));
407 g_log(LOG_DOMAIN_MAIN, G_LOG_LEVEL_INFO, "fill_in_local_interfaces() ends, taking %.3fs", elapsed);
411 hide_interface(gchar* new_hide)
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);
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);
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--;
438 device->hidden = FALSE;
441 g_list_free(hidden_devices);
446 update_local_interfaces(void)
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);
459 device->hidden = prefs_is_capture_device_hidden(device->name);
460 fill_from_ifaces(device);
463 #endif /* HAVE_LIBPCAP */
471 * indent-tabs-mode: nil
474 * ex: set shiftwidth=4 tabstop=8 expandtab:
475 * :indentSize=4:tabSize=8:noTabs=true: