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