2 * Routines for getting interface information from dumpcap
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
12 #define WS_LOG_DOMAIN LOG_DOMAIN_CAPTURE
16 #include <wireshark.h>
21 #include "capture_opts.h"
23 #include "capture/capture_session.h"
24 #include "capture/capture_sync.h"
25 #include "capture/iface_monitor.h"
28 #include <capture/capture-pcap-util.h>
29 #include <capture/capture-pcap-util-int.h>
30 #include <capture/capture_ifinfo.h>
31 #include <wsutil/inet_addr.h>
32 #include <wsutil/wsjson.h>
34 #ifdef HAVE_PCAP_REMOTE
35 static GList
*remote_interface_list
;
37 GList
* append_remote_list(GList
*iflist
)
41 if_addr_t
*if_addr
, *temp_addr
;
42 if_info_t
*if_info
, *temp
;
44 for (rlist
= g_list_nth(remote_interface_list
, 0); rlist
!= NULL
; rlist
= g_list_next(rlist
)) {
45 if_info
= (if_info_t
*)rlist
->data
;
46 temp
= g_new0(if_info_t
, 1);
47 temp
->name
= g_strdup(if_info
->name
);
48 temp
->friendly_name
= g_strdup(if_info
->friendly_name
);
49 temp
->vendor_description
= g_strdup(if_info
->vendor_description
);
50 for (list
= g_slist_nth(if_info
->addrs
, 0); list
!= NULL
; list
= g_slist_next(list
)) {
51 temp_addr
= g_new0(if_addr_t
, 1);
52 if_addr
= (if_addr_t
*)list
->data
;
54 temp_addr
->ifat_type
= if_addr
->ifat_type
;
55 if (temp_addr
->ifat_type
== IF_AT_IPv4
) {
56 temp_addr
->addr
.ip4_addr
= if_addr
->addr
.ip4_addr
;
58 memcpy(temp_addr
->addr
.ip6_addr
, if_addr
->addr
.ip6_addr
, sizeof(if_addr
->addr
));
65 temp
->addrs
= g_slist_append(temp
->addrs
, temp_addr
);
68 temp
->loopback
= if_info
->loopback
;
69 iflist
= g_list_append(iflist
, temp
);
75 static if_capabilities_t
*
76 deserialize_if_capability(char* data
, jsmntok_t
*inf_tok
)
78 if_capabilities_t
*caps
;
79 GList
*linktype_list
= NULL
, *timestamp_list
= NULL
;
80 GList
*linktype_rfmon_list
= NULL
;
84 jsmntok_t
*array_tok
, *cur_tok
;
87 * Allocate the interface capabilities structure.
89 caps
= (if_capabilities_t
*)g_malloc0(sizeof *caps
);
91 if (inf_tok
== NULL
|| !json_get_double(data
, inf_tok
, "status", &val_d
)) {
92 ws_info("Capture Interface Capabilities failed with invalid JSON.");
93 caps
->primary_msg
= g_strdup("Dumpcap returned bad JSON");
99 caps
->primary_msg
= json_get_string(data
, inf_tok
, "primary_msg");
100 if (caps
->primary_msg
) {
101 caps
->primary_msg
= g_strdup(caps
->primary_msg
);
102 caps
->secondary_msg
= get_pcap_failure_secondary_error_message(err
, caps
->primary_msg
);
104 caps
->primary_msg
= g_strdup("Failed with no message");
106 ws_info("Capture Interface Capabilities failed. Error %d, %s",
107 err
, caps
->primary_msg
? caps
->primary_msg
: "no message");
112 if (!json_get_boolean(data
, inf_tok
, "rfmon", &rfmon
)) {
113 ws_message("Capture Interface Capabilities returned bad information.");
114 ws_message("Didn't return monitor-mode cap");
115 caps
->primary_msg
= g_strdup("Dumpcap didn't return monitor-mode capability");
119 caps
->can_set_rfmon
= rfmon
;
122 * The following are link-layer types.
124 array_tok
= json_get_array(data
, inf_tok
, "data_link_types");
126 ws_info("Capture Interface Capabilities returned bad data_link information.");
127 caps
->primary_msg
= g_strdup("Dumpcap didn't return data link types capability");
130 for (i
= 0; i
< json_get_array_len(array_tok
); i
++) {
131 cur_tok
= json_get_array_index(array_tok
, i
);
133 if (!json_get_double(data
, cur_tok
, "dlt", &val_d
)) {
137 data_link_info_t
*data_link_info
;
138 data_link_info
= g_new(data_link_info_t
,1);
140 data_link_info
->dlt
= (int)val_d
;
141 val_s
= json_get_string(data
, cur_tok
, "name");
142 data_link_info
->name
= val_s
? g_strdup(val_s
) : NULL
;
143 val_s
= json_get_string(data
, cur_tok
, "description");
144 if (!val_s
|| strcmp(val_s
, "(not supported)") == 0) {
145 data_link_info
->description
= NULL
;
147 data_link_info
->description
= g_strdup(val_s
);
149 linktype_list
= g_list_append(linktype_list
, data_link_info
);
153 array_tok
= json_get_array(data
, inf_tok
, "data_link_types_rfmon");
156 ws_info("Capture Interface Capabilities returned bad data_link information for monitor mode.");
157 caps
->primary_msg
= g_strdup("Dumpcap claimed that interface supported monitor mode, but didn't return data link types when in monitor mode");
158 caps
->can_set_rfmon
= false;
159 } else for (i
= 0; i
< json_get_array_len(array_tok
); i
++) {
160 cur_tok
= json_get_array_index(array_tok
, i
);
162 if (!json_get_double(data
, cur_tok
, "dlt", &val_d
)) {
166 data_link_info_t
*data_link_info
;
167 data_link_info
= g_new(data_link_info_t
,1);
169 data_link_info
->dlt
= (int)val_d
;
170 val_s
= json_get_string(data
, cur_tok
, "name");
171 data_link_info
->name
= val_s
? g_strdup(val_s
) : NULL
;
172 val_s
= json_get_string(data
, cur_tok
, "description");
173 if (!val_s
|| strcmp(val_s
, "(not supported)") == 0) {
174 data_link_info
->description
= NULL
;
176 data_link_info
->description
= g_strdup(val_s
);
178 linktype_rfmon_list
= g_list_append(linktype_rfmon_list
, data_link_info
);
182 array_tok
= json_get_array(data
, inf_tok
, "timestamp_types");
184 for (i
= 0; i
< json_get_array_len(array_tok
); i
++) {
185 cur_tok
= json_get_array_index(array_tok
, i
);
187 timestamp_info_t
*timestamp_info
;
188 timestamp_info
= g_new(timestamp_info_t
,1);
189 val_s
= json_get_string(data
, cur_tok
, "name");
190 timestamp_info
->name
= val_s
? g_strdup(val_s
) : NULL
;
191 val_s
= json_get_string(data
, cur_tok
, "description");
192 timestamp_info
->description
= val_s
? g_strdup(val_s
) : NULL
;
194 timestamp_list
= g_list_append(timestamp_list
, timestamp_info
);
198 caps
->data_link_types
= linktype_list
;
199 /* Should be NULL if rfmon unsupported. */
200 caps
->data_link_types_rfmon
= linktype_rfmon_list
;
201 /* Might be NULL. Not all systems report timestamp types */
202 caps
->timestamp_types
= timestamp_list
;
208 deserialize_interface_list(char *data
, int *err
, char **err_str
)
218 jsmntok_t
*tokens
, *if_tok
, *addrs_tok
, *cur_tok
;
219 GList
*if_list
= NULL
;
222 ws_info("Passed NULL capture interface list");
223 *err
= CANT_GET_INTERFACE_LIST
;
227 int num_tokens
= json_parse(data
, NULL
, 0);
228 if (num_tokens
<= 0) {
229 ws_info("Capture Interface List failed with invalid JSON.");
231 *err_str
= g_strdup("Dumpcap returned bad JSON.");
234 *err
= CANT_GET_INTERFACE_LIST
;
238 tokens
= wmem_alloc_array(NULL
, jsmntok_t
, num_tokens
);
239 if (json_parse(data
, tokens
, num_tokens
) <= 0) {
240 ws_info("Capture Interface List failed with invalid JSON.");
242 *err_str
= g_strdup("Dumpcap returned bad JSON.");
244 wmem_free(NULL
, tokens
);
246 *err
= CANT_GET_INTERFACE_LIST
;
250 for (i
= 0; i
< json_get_array_len(tokens
); i
++) {
251 if_tok
= json_get_array_index(tokens
, i
);
252 if (if_tok
&& if_tok
->type
== JSMN_OBJECT
) {
254 name
= g_strndup(&data
[if_tok
->start
], if_tok
->end
- if_tok
->start
);
255 if (!json_decode_string_inplace(name
)) {
261 if (!json_get_double(data
, if_tok
, "type", &val_d
)) {
265 type
= (interface_type
)val_d
;
267 if (!json_get_boolean(data
, if_tok
, "loopback", &loopback
)) {
272 if_info
= g_new0(if_info_t
,1);
273 if_info
->name
= name
;
274 val_s
= json_get_string(data
, if_tok
, "friendly_name");
275 if_info
->friendly_name
= g_strdup(val_s
);
276 val_s
= json_get_string(data
, if_tok
, "vendor_description");
277 if_info
->vendor_description
= g_strdup(val_s
);
278 if_info
->type
= type
;
280 addrs_tok
= json_get_array(data
, if_tok
, "addrs");
281 for (cur_tok
= addrs_tok
+ 1, j
= 0; j
< json_get_array_len(addrs_tok
); cur_tok
++, j
++) {
282 addr
= g_strndup(&data
[cur_tok
->start
], cur_tok
->end
- cur_tok
->start
);
283 if (json_decode_string_inplace(addr
)) {
284 if_addr
= g_new0(if_addr_t
, 1);
285 if (ws_inet_pton4(addr
, &if_addr
->addr
.ip4_addr
)) {
286 if_addr
->ifat_type
= IF_AT_IPv4
;
287 } else if (ws_inet_pton6(addr
, (ws_in6_addr
*)&if_addr
->addr
.ip6_addr
)) {
288 if_addr
->ifat_type
= IF_AT_IPv6
;
294 if_info
->addrs
= g_slist_append(if_info
->addrs
, if_addr
);
300 if_info
->loopback
= loopback
;
302 val_s
= json_get_string(data
, if_tok
, "extcap");
303 /* if_info->extcap is never NULL, unlike the friendly name
304 * and vendor description. (see if_info_new)
306 if_info
->extcap
= val_s
? g_strdup(val_s
) : "";
308 cur_tok
= json_get_object(data
, if_tok
, "caps");
310 if_info
->caps
= deserialize_if_capability(data
, cur_tok
);
313 if_list
= g_list_append(if_list
, if_info
);
317 wmem_free(NULL
, tokens
);
324 * Fetch the interface list from a child process (dumpcap).
326 * @return A GList containing if_info_t structs if successful, NULL (with err and possibly err_str set) otherwise.
330 capture_interface_list(int *err
, char **err_str
, void (*update_cb
)(void))
333 GList
*if_list
= NULL
;
334 char *data
, *primary_msg
, *secondary_msg
;
341 /* Try to get the local interface list */
342 ret
= sync_interface_list_open(&data
, &primary_msg
, &secondary_msg
, update_cb
);
344 ws_info("sync_interface_list_open() failed. %s (%s)",
345 primary_msg
? primary_msg
: "no message",
346 secondary_msg
? secondary_msg
: "no secondary message");
348 *err_str
= primary_msg
;
352 g_free(secondary_msg
);
353 *err
= CANT_GET_INTERFACE_LIST
;
356 * Add the extcap interfaces that can exist; they may exist
357 * even if no native interfaces have been found.
359 ws_debug("Loading External Capture Interface List ...");
360 if_list
= append_extcap_interface_list(if_list
);
364 if_list
= deserialize_interface_list(data
, err
, err_str
);
366 #ifdef HAVE_PCAP_REMOTE
367 /* Add the remote interface list */
368 if (remote_interface_list
&& g_list_length(remote_interface_list
) > 0) {
369 if_list
= append_remote_list(if_list
);
373 /* Add the extcap interfaces after the native and remote interfaces */
374 ws_debug("Loading External Capture Interface List ...");
375 if_list
= append_extcap_interface_list(if_list
);
381 capture_get_if_capabilities(const char *ifname
, bool monitor_mode
,
382 const char *auth_string
,
383 char **err_primary_msg
, char **err_secondary_msg
,
384 void (*update_cb
)(void))
386 if_capabilities_t
*caps
;
388 char *data
, *primary_msg
, *secondary_msg
;
389 jsmntok_t
*tokens
, *inf_tok
;
391 /* see if the interface is from extcap */
392 caps
= extcap_get_if_dlts(ifname
, err_primary_msg
);
394 /* return if the extcap interface generated an error */
395 if (caps
->primary_msg
) {
396 free_if_capabilities(caps
);
402 /* Try to get our interface list */
403 iface_mon_enable(false);
404 err
= sync_if_capabilities_open(ifname
, monitor_mode
, auth_string
, &data
,
405 &primary_msg
, &secondary_msg
, update_cb
);
406 iface_mon_enable(true);
408 ws_info("Capture Interface Capabilities failed. Error %d, %s",
409 err
, primary_msg
? primary_msg
: "no message");
411 *err_primary_msg
= primary_msg
;
414 if (err_secondary_msg
)
415 *err_secondary_msg
= secondary_msg
;
417 g_free(secondary_msg
);
421 int num_tokens
= json_parse(data
, NULL
, 0);
422 if (num_tokens
<= 0) {
423 ws_info("Capture Interface Capabilities failed with invalid JSON.");
424 if (err_primary_msg
) {
425 *err_primary_msg
= g_strdup("Dumpcap returned bad JSON.");
431 tokens
= wmem_alloc_array(NULL
, jsmntok_t
, num_tokens
);
432 if (json_parse(data
, tokens
, num_tokens
) <= 0) {
433 ws_info("Capture Interface Capabilities returned no information.");
434 if (err_primary_msg
) {
435 *err_primary_msg
= g_strdup("Dumpcap returned no interface capability information");
437 wmem_free(NULL
, tokens
);
442 inf_tok
= json_get_array_index(tokens
, 0);
443 if (inf_tok
&& inf_tok
->type
== JSMN_OBJECT
) {
445 char *ifname2
= g_strndup(&data
[inf_tok
->start
], inf_tok
->end
- inf_tok
->start
);
446 if (json_decode_string_inplace(ifname2
) && g_strcmp0(ifname2
, ifname
) == 0) {
448 caps
= deserialize_if_capability(data
, inf_tok
);
449 if (caps
->primary_msg
) {
450 if (err_primary_msg
) {
451 *err_primary_msg
= caps
->primary_msg
;
452 caps
->primary_msg
= NULL
;
454 if (caps
->secondary_msg
&& err_secondary_msg
) {
455 *err_secondary_msg
= g_strdup(caps
->secondary_msg
);
457 free_if_capabilities(caps
);
460 } else if (err_primary_msg
) {
461 *err_primary_msg
= g_strdup("Dumpcap returned bad JSON.");
464 } else if (err_primary_msg
) {
465 *err_primary_msg
= g_strdup("Dumpcap returned bad JSON.");
468 wmem_free(NULL
, tokens
);
475 free_if_capabilities_cb(void *data
)
478 free_if_capabilities((if_capabilities_t
*)data
);
483 capture_get_if_list_capabilities(GList
*if_cap_queries
,
484 char **err_primary_msg
, char **err_secondary_msg
,
485 void (*update_cb
)(void))
487 if_cap_query_t
*query
;
488 if_capabilities_t
*caps
;
489 GHashTable
*caps_hash
;
490 GList
*local_queries
= NULL
;
492 char *data
, *primary_msg
, *secondary_msg
;
493 jsmntok_t
*tokens
, *inf_tok
;
495 caps_hash
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, free_if_capabilities_cb
);
496 for (GList
*li
= if_cap_queries
; li
!= NULL
; li
= g_list_next(li
)) {
498 query
= (if_cap_query_t
*)li
->data
;
499 /* see if the interface is from extcap */
500 caps
= extcap_get_if_dlts(query
->name
, NULL
);
501 /* if the extcap interface generated an error, it was from extcap */
503 g_hash_table_replace(caps_hash
, g_strdup(query
->name
), caps
);
505 local_queries
= g_list_prepend(local_queries
, query
);
509 if (local_queries
== NULL
)
512 local_queries
= g_list_reverse(local_queries
);
514 /* Try to get our interface list */
515 iface_mon_enable(false);
516 err
= sync_if_list_capabilities_open(local_queries
, &data
,
517 &primary_msg
, &secondary_msg
, update_cb
);
518 iface_mon_enable(true);
519 g_list_free(local_queries
);
521 ws_info("Capture Interface Capabilities failed. Error %d, %s",
522 err
, primary_msg
? primary_msg
: "no message");
524 *err_primary_msg
= primary_msg
;
527 if (err_secondary_msg
)
528 *err_secondary_msg
= secondary_msg
;
530 g_free(secondary_msg
);
534 int num_tokens
= json_parse(data
, NULL
, 0);
535 if (num_tokens
<= 0) {
536 ws_info("Capture Interface Capabilities failed with invalid JSON.");
541 tokens
= wmem_alloc_array(NULL
, jsmntok_t
, num_tokens
);
542 if (json_parse(data
, tokens
, num_tokens
) <= 0) {
543 ws_info("Capture Interface Capabilities returned no information.");
544 if (err_primary_msg
) {
545 *err_primary_msg
= g_strdup("Dumpcap returned no interface capability information");
547 wmem_free(NULL
, tokens
);
553 for (i
= 0; i
< json_get_array_len(tokens
); i
++) {
554 inf_tok
= json_get_array_index(tokens
, i
);
555 if (inf_tok
&& inf_tok
->type
== JSMN_OBJECT
) {
557 ifname
= g_strndup(&data
[inf_tok
->start
], inf_tok
->end
- inf_tok
->start
);
558 if (!json_decode_string_inplace(ifname
)) {
563 caps
= deserialize_if_capability(data
, inf_tok
);
564 g_hash_table_replace(caps_hash
, ifname
, caps
);
568 wmem_free(NULL
, tokens
);
574 #ifdef HAVE_PCAP_REMOTE
575 void add_interface_to_remote_list(if_info_t
*if_info
)
578 if_addr_t
*if_addr
, *temp_addr
;
580 if_info_t
*temp
= g_new0(if_info_t
, 1);
581 temp
->name
= g_strdup(if_info
->name
);
582 temp
->friendly_name
= g_strdup(if_info
->friendly_name
);
583 temp
->vendor_description
= g_strdup(if_info
->vendor_description
);
584 for (list
= g_slist_nth(if_info
->addrs
, 0); list
!= NULL
; list
= g_slist_next(list
)) {
585 temp_addr
= g_new0(if_addr_t
, 1);
586 if_addr
= (if_addr_t
*)list
->data
;
588 temp_addr
->ifat_type
= if_addr
->ifat_type
;
589 if (temp_addr
->ifat_type
== IF_AT_IPv4
) {
590 temp_addr
->addr
.ip4_addr
= if_addr
->addr
.ip4_addr
;
592 memcpy(temp_addr
->addr
.ip6_addr
, if_addr
->addr
.ip6_addr
, sizeof(if_addr
->addr
));
599 temp
->addrs
= g_slist_append(temp
->addrs
, temp_addr
);
602 temp
->loopback
= if_info
->loopback
;
603 remote_interface_list
= g_list_append(remote_interface_list
, temp
);
606 #endif /* HAVE_LIBPCAP */