Revert "LATER... ei_kerberos_kdc_session_key ..."
[wireshark-sm.git] / capture / capture_ifinfo.c
blob834435ecfeb84e6674349605760696c996bfc2df
1 /* capture_ifinfo.c
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
9 */
11 #include "config.h"
12 #define WS_LOG_DOMAIN LOG_DOMAIN_CAPTURE
14 #ifdef HAVE_LIBPCAP
16 #include <wireshark.h>
18 #include <stdlib.h>
19 #include <stdio.h>
21 #include "capture_opts.h"
23 #include "capture/capture_session.h"
24 #include "capture/capture_sync.h"
25 #include "capture/iface_monitor.h"
26 #include "extcap.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)
39 GSList *list;
40 GList *rlist;
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;
53 if (if_addr) {
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;
57 } else {
58 memcpy(temp_addr->addr.ip6_addr, if_addr->addr.ip6_addr, sizeof(if_addr->addr));
60 } else {
61 g_free(temp_addr);
62 temp_addr = NULL;
64 if (temp_addr) {
65 temp->addrs = g_slist_append(temp->addrs, temp_addr);
68 temp->loopback = if_info->loopback;
69 iflist = g_list_append(iflist, temp);
71 return iflist;
73 #endif
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;
81 int err, i;
82 char *val_s;
83 double val_d;
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");
94 return caps;
97 err = (int)val_d;
98 if (err != 0) {
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);
103 } else {
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");
108 return caps;
111 bool rfmon;
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");
116 return caps;
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");
125 if (!array_tok) {
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");
128 return caps;
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)) {
134 continue;
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;
146 } else {
147 data_link_info->description = g_strdup(val_s);
149 linktype_list = g_list_append(linktype_list, data_link_info);
152 if (rfmon) {
153 array_tok = json_get_array(data, inf_tok, "data_link_types_rfmon");
155 if (!array_tok) {
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)) {
163 continue;
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;
175 } else {
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");
183 if (array_tok) {
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;
204 return caps;
207 GList *
208 deserialize_interface_list(char *data, int *err, char **err_str)
210 int i, j;
211 char *name, *addr;
212 char *val_s;
213 double val_d;
214 bool loopback;
215 if_info_t *if_info;
216 interface_type type;
217 if_addr_t *if_addr;
218 jsmntok_t *tokens, *if_tok, *addrs_tok, *cur_tok;
219 GList *if_list = NULL;
221 if (data == NULL) {
222 ws_info("Passed NULL capture interface list");
223 *err = CANT_GET_INTERFACE_LIST;
224 return if_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.");
230 if (err_str) {
231 *err_str = g_strdup("Dumpcap returned bad JSON.");
233 g_free(data);
234 *err = CANT_GET_INTERFACE_LIST;
235 return NULL;
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.");
241 if (err_str) {
242 *err_str = g_strdup("Dumpcap returned bad JSON.");
244 wmem_free(NULL, tokens);
245 g_free(data);
246 *err = CANT_GET_INTERFACE_LIST;
247 return NULL;
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) {
253 if_tok++; // Key
254 name = g_strndup(&data[if_tok->start], if_tok->end - if_tok->start);
255 if (!json_decode_string_inplace(name)) {
256 g_free(name);
257 continue;
259 if_tok++;
261 if (!json_get_double(data, if_tok, "type", &val_d)) {
262 g_free(name);
263 continue;
265 type = (interface_type)val_d;
267 if (!json_get_boolean(data, if_tok, "loopback", &loopback)) {
268 g_free(name);
269 continue;
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;
289 } else {
290 g_free(if_addr);
291 if_addr = NULL;
293 if (if_addr) {
294 if_info->addrs = g_slist_append(if_info->addrs, if_addr);
297 g_free(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");
309 if (cur_tok) {
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);
318 g_free(data);
320 return if_list;
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.
329 GList *
330 capture_interface_list(int *err, char **err_str, void (*update_cb)(void))
332 int ret;
333 GList *if_list = NULL;
334 char *data, *primary_msg, *secondary_msg;
336 *err = 0;
337 if (err_str) {
338 *err_str = NULL;
341 /* Try to get the local interface list */
342 ret = sync_interface_list_open(&data, &primary_msg, &secondary_msg, update_cb);
343 if (ret != 0) {
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");
347 if (err_str) {
348 *err_str = primary_msg;
349 } else {
350 g_free(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);
361 return 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);
371 #endif
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);
377 return if_list;
380 if_capabilities_t *
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;
387 int err;
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);
393 if (caps != NULL) {
394 /* return if the extcap interface generated an error */
395 if (caps->primary_msg) {
396 free_if_capabilities(caps);
397 caps = NULL;
399 return 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);
407 if (err != 0) {
408 ws_info("Capture Interface Capabilities failed. Error %d, %s",
409 err, primary_msg ? primary_msg : "no message");
410 if (err_primary_msg)
411 *err_primary_msg = primary_msg;
412 else
413 g_free(primary_msg);
414 if (err_secondary_msg)
415 *err_secondary_msg = secondary_msg;
416 else
417 g_free(secondary_msg);
418 return NULL;
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.");
427 g_free(data);
428 return NULL;
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);
438 g_free(data);
439 return NULL;
442 inf_tok = json_get_array_index(tokens, 0);
443 if (inf_tok && inf_tok->type == JSMN_OBJECT) {
444 inf_tok++; // Key
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) {
447 inf_tok++;
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);
458 caps = NULL;
460 } else if (err_primary_msg) {
461 *err_primary_msg = g_strdup("Dumpcap returned bad JSON.");
463 g_free(ifname2);
464 } else if (err_primary_msg) {
465 *err_primary_msg = g_strdup("Dumpcap returned bad JSON.");
468 wmem_free(NULL, tokens);
469 g_free(data);
471 return caps;
474 static void
475 free_if_capabilities_cb(void *data)
477 if (data != NULL) {
478 free_if_capabilities((if_capabilities_t*)data);
482 GHashTable*
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;
491 int err, i;
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 */
502 if (caps != NULL) {
503 g_hash_table_replace(caps_hash, g_strdup(query->name), caps);
504 } else {
505 local_queries = g_list_prepend(local_queries, query);
509 if (local_queries == NULL)
510 return caps_hash;
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);
520 if (err != 0) {
521 ws_info("Capture Interface Capabilities failed. Error %d, %s",
522 err, primary_msg ? primary_msg : "no message");
523 if (err_primary_msg)
524 *err_primary_msg = primary_msg;
525 else
526 g_free(primary_msg);
527 if (err_secondary_msg)
528 *err_secondary_msg = secondary_msg;
529 else
530 g_free(secondary_msg);
531 return caps_hash;
534 int num_tokens = json_parse(data, NULL, 0);
535 if (num_tokens <= 0) {
536 ws_info("Capture Interface Capabilities failed with invalid JSON.");
537 g_free(data);
538 return caps_hash;
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);
548 g_free(data);
549 return caps_hash;
552 char *ifname;
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) {
556 inf_tok++; // Key
557 ifname = g_strndup(&data[inf_tok->start], inf_tok->end - inf_tok->start);
558 if (!json_decode_string_inplace(ifname)) {
559 g_free(ifname);
560 continue;
562 inf_tok++;
563 caps = deserialize_if_capability(data, inf_tok);
564 g_hash_table_replace(caps_hash, ifname, caps);
568 wmem_free(NULL, tokens);
569 g_free(data);
571 return caps_hash;
574 #ifdef HAVE_PCAP_REMOTE
575 void add_interface_to_remote_list(if_info_t *if_info)
577 GSList *list;
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;
587 if (if_addr) {
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;
591 } else {
592 memcpy(temp_addr->addr.ip6_addr, if_addr->addr.ip6_addr, sizeof(if_addr->addr));
594 } else {
595 g_free(temp_addr);
596 temp_addr = NULL;
598 if (temp_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);
605 #endif
606 #endif /* HAVE_LIBPCAP */