tests: add regression tests for Follow TCP Stream
[metze/wireshark/wip.git] / capchild / capture_ifinfo.c
1 /* capture_ifinfo.c
2  * Routines for getting interface information from dumpcap
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10
11 #include "config.h"
12
13 #ifdef HAVE_LIBPCAP
14
15 #include <stdlib.h>
16 #include <string.h>
17 #include <stdio.h>
18
19 #include <glib.h>
20
21 #include "capture_opts.h"
22
23 #include "capchild/capture_session.h"
24 #include "capchild/capture_sync.h"
25 #include "extcap.h"
26 #include "log.h"
27
28 #include <caputils/capture_ifinfo.h>
29 #include <wsutil/inet_addr.h>
30
31 #ifdef HAVE_PCAP_REMOTE
32 static GList *remote_interface_list = NULL;
33
34 static GList * append_remote_list(GList *iflist)
35 {
36     GSList *list;
37     GList *rlist;
38     if_addr_t *if_addr, *temp_addr;
39     if_info_t *if_info, *temp;
40
41     for (rlist = g_list_nth(remote_interface_list, 0); rlist != NULL; rlist = g_list_next(rlist)) {
42         if_info = (if_info_t *)rlist->data;
43         temp = (if_info_t*) g_malloc0(sizeof(if_info_t));
44         temp->name = g_strdup(if_info->name);
45         temp->friendly_name = g_strdup(if_info->friendly_name);
46         temp->vendor_description = g_strdup(if_info->vendor_description);
47         for (list = g_slist_nth(if_info->addrs, 0); list != NULL; list = g_slist_next(list)) {
48             temp_addr = (if_addr_t *) g_malloc0(sizeof(if_addr_t));
49             if_addr = (if_addr_t *)list->data;
50             if (if_addr) {
51                 temp_addr->ifat_type = if_addr->ifat_type;
52                 if (temp_addr->ifat_type == IF_AT_IPv4) {
53                     temp_addr->addr.ip4_addr = if_addr->addr.ip4_addr;
54                 } else {
55                     memcpy(temp_addr->addr.ip6_addr, if_addr->addr.ip6_addr, sizeof(if_addr->addr));
56                 }
57             } else {
58                 g_free(temp_addr);
59                 temp_addr = NULL;
60             }
61             if (temp_addr) {
62                 temp->addrs = g_slist_append(temp->addrs, temp_addr);
63             }
64         }
65         temp->loopback = if_info->loopback;
66         iflist = g_list_append(iflist, temp);
67    }
68    return iflist;
69 }
70 #endif
71
72 /**
73  * Fetch the interface list from a child process (dumpcap).
74  *
75  * @return A GList containing if_info_t structs if successful, NULL (with err and possibly err_str set) otherwise.
76  *
77  */
78
79 /* XXX - We parse simple text output to get our interface list.  Should
80  * we use "real" data serialization instead, e.g. via XML? */
81 GList *
82 capture_interface_list(int *err, char **err_str, void (*update_cb)(void))
83 {
84     int        ret;
85     GList     *if_list = NULL;
86     int        i, j;
87     gchar     *data, *primary_msg, *secondary_msg;
88     gchar    **raw_list, **if_parts, **addr_parts;
89     gchar     *name;
90     if_info_t *if_info;
91     if_addr_t *if_addr;
92
93     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List ...");
94
95     *err = 0;
96     if (err_str) {
97         *err_str = NULL;
98     }
99
100     /* Try to get our interface list */
101     ret = sync_interface_list_open(&data, &primary_msg, &secondary_msg, update_cb);
102     if (ret != 0) {
103         /* Add the extcap interfaces that can exist, even if no native interfaces have been found */
104         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Loading External Capture Interface List ...");
105         if_list = append_extcap_interface_list(if_list, err_str);
106         /* err_str is ignored, as the error for the interface loading list will take precedence */
107         if ( g_list_length(if_list) == 0 ) {
108
109             g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List failed. Error %d, %s (%s)",
110                   *err, primary_msg ? primary_msg : "no message",
111                   secondary_msg ? secondary_msg : "no secondary message");
112             if (err_str) {
113                 *err_str = primary_msg;
114             } else {
115                 g_free(primary_msg);
116             }
117             g_free(secondary_msg);
118             *err = CANT_GET_INTERFACE_LIST;
119
120         }
121         return if_list;
122     }
123
124     /* Split our lines */
125 #ifdef _WIN32
126     raw_list = g_strsplit(data, "\r\n", 0);
127 #else
128     raw_list = g_strsplit(data, "\n", 0);
129 #endif
130     g_free(data);
131
132     for (i = 0; raw_list[i] != NULL; i++) {
133         if_parts = g_strsplit(raw_list[i], "\t", 7);
134         if (if_parts[0] == NULL || if_parts[1] == NULL || if_parts[2] == NULL ||
135                 if_parts[3] == NULL || if_parts[4] == NULL || if_parts[5] == NULL ||
136                 if_parts[6] == NULL) {
137             g_strfreev(if_parts);
138             continue;
139         }
140
141         /* Number followed by the name, e.g "1. eth0" */
142         name = strchr(if_parts[0], ' ');
143         if (name) {
144             name++;
145         } else {
146             g_strfreev(if_parts);
147             continue;
148         }
149
150         if_info = g_new0(if_info_t,1);
151         if_info->name = g_strdup(name);
152         if (strlen(if_parts[1]) > 0)
153             if_info->vendor_description = g_strdup(if_parts[1]);
154         if (strlen(if_parts[2]) > 0)
155             if_info->friendly_name = g_strdup(if_parts[2]);
156         if_info->type = (interface_type)(int)strtol(if_parts[3], NULL, 10);
157         addr_parts = g_strsplit(if_parts[4], ",", 0);
158         for (j = 0; addr_parts[j] != NULL; j++) {
159             if_addr = g_new0(if_addr_t,1);
160             if (ws_inet_pton4(addr_parts[j], &if_addr->addr.ip4_addr)) {
161                 if_addr->ifat_type = IF_AT_IPv4;
162             } else if (ws_inet_pton6(addr_parts[j], (ws_in6_addr *)&if_addr->addr.ip6_addr)) {
163                 if_addr->ifat_type = IF_AT_IPv6;
164             } else {
165                 g_free(if_addr);
166                 if_addr = NULL;
167             }
168             if (if_addr) {
169                 if_info->addrs = g_slist_append(if_info->addrs, if_addr);
170             }
171         }
172         if (strcmp(if_parts[5], "loopback") == 0)
173             if_info->loopback = TRUE;
174         if_info->extcap = g_strdup(if_parts[6]);
175         g_strfreev(if_parts);
176         g_strfreev(addr_parts);
177         if_list = g_list_append(if_list, if_info);
178     }
179     g_strfreev(raw_list);
180
181 #ifdef HAVE_PCAP_REMOTE
182     if (remote_interface_list && g_list_length(remote_interface_list) > 0) {
183         if_list = append_remote_list(if_list);
184     }
185 #endif
186
187     /* Add the extcap interfaces after the native and remote interfaces */
188     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Loading External Capture Interface List ...");
189     if_list = append_extcap_interface_list(if_list, err_str);
190
191     return if_list;
192 }
193
194 /* XXX - We parse simple text output to get our interface list.  Should
195  * we use "real" data serialization instead, e.g. via XML? */
196 if_capabilities_t *
197 capture_get_if_capabilities(const gchar *ifname, gboolean monitor_mode,
198                             const gchar *auth_string,
199                             char **err_str, void (*update_cb)(void))
200 {
201     if_capabilities_t *caps;
202     GList              *linktype_list = NULL, *timestamp_list = NULL;
203     int                 err, i;
204     gchar              *data, *primary_msg, *secondary_msg;
205     gchar             **raw_list;
206
207     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities ...");
208
209     /* see if the interface is from extcap */
210     caps = extcap_get_if_dlts(ifname, err_str);
211     if (caps != NULL)
212         return caps;
213
214     /* return if the extcap interface generated an error */
215     if (err_str != NULL && *err_str != NULL)
216         return NULL;
217
218     /* Try to get our interface list */
219     err = sync_if_capabilities_open(ifname, monitor_mode, auth_string, &data,
220                                     &primary_msg, &secondary_msg, update_cb);
221     if (err != 0) {
222         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities failed. Error %d, %s (%s)",
223               err, primary_msg ? primary_msg : "no message",
224               secondary_msg ? secondary_msg : "no secondary message");
225         if (err_str) {
226             *err_str = primary_msg;
227         } else {
228             g_free(primary_msg);
229         }
230         g_free(secondary_msg);
231         return NULL;
232     }
233
234     /* Split our lines */
235 #ifdef _WIN32
236     raw_list = g_strsplit(data, "\r\n", 0);
237 #else
238     raw_list = g_strsplit(data, "\n", 0);
239 #endif
240     g_free(data);
241
242     /*
243      * First line is 0 if monitor mode isn't supported, 1 if it is.
244      */
245     if (raw_list[0] == NULL || *raw_list[0] == '\0') {
246         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities returned no information.");
247         if (err_str) {
248             *err_str = g_strdup("Dumpcap returned no interface capability information");
249         }
250         g_strfreev(raw_list);
251         return NULL;
252     }
253
254     /*
255      * Allocate the interface capabilities structure.
256      */
257     caps = (if_capabilities_t *)g_malloc(sizeof *caps);
258     switch (*raw_list[0]) {
259
260     case '0':
261         caps->can_set_rfmon = FALSE;
262         break;
263
264     case '1':
265         caps->can_set_rfmon = TRUE;
266         break;
267
268     default:
269         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface Capabilities returned bad information.");
270         if (err_str) {
271             *err_str = g_strdup_printf("Dumpcap returned \"%s\" for monitor-mode capability",
272                                        raw_list[0]);
273         }
274         g_free(caps);
275         g_strfreev(raw_list);
276         return NULL;
277     }
278
279     /*
280      * The following are link-layer types.
281      */
282     for (i = 1; raw_list[i] != NULL && *raw_list[i] != '\0'; i++) {
283         data_link_info_t *data_link_info;
284         /* ...and what if the interface name has a tab in it, Mr. Clever Programmer? */
285         char **lt_parts = g_strsplit(raw_list[i], "\t", 3);
286         if (lt_parts[0] == NULL || lt_parts[1] == NULL || lt_parts[2] == NULL) {
287             g_strfreev(lt_parts);
288             continue;
289         }
290
291         data_link_info = g_new(data_link_info_t,1);
292         data_link_info->dlt = (int) strtol(lt_parts[0], NULL, 10);
293         data_link_info->name = g_strdup(lt_parts[1]);
294         if (strcmp(lt_parts[2], "(not supported)") != 0)
295             data_link_info->description = g_strdup(lt_parts[2]);
296         else
297             data_link_info->description = NULL;
298         g_strfreev(lt_parts);
299
300         linktype_list = g_list_append(linktype_list, data_link_info);
301     }
302
303     if (raw_list[i]) { /* Oh, timestamp types! */
304         for (i++; raw_list[i] != NULL && *raw_list[i] != '\0'; i++) {
305             timestamp_info_t *timestamp_info;
306             char **tt_parts = g_strsplit(raw_list[i], "\t", 2);
307             if (tt_parts[0] == NULL || tt_parts[1] == NULL) {
308                 g_strfreev(tt_parts);
309                 continue;
310             }
311
312             timestamp_info = g_new(timestamp_info_t,1);
313             timestamp_info->name = g_strdup(tt_parts[0]);
314             timestamp_info->description = g_strdup(tt_parts[1]);
315             g_strfreev(tt_parts);
316
317             timestamp_list = g_list_append(timestamp_list, timestamp_info);
318         }
319     }
320
321     g_strfreev(raw_list);
322
323     /* Check to see if we built a list */
324     if (linktype_list == NULL) {
325         /* No. */
326         if (err_str)
327             *err_str = g_strdup("Dumpcap returned no link-layer types");
328         g_free(caps);
329         return NULL;
330     }
331
332     caps->data_link_types = linktype_list;
333     /* Might be NULL. Not all systems report timestamp types */
334     caps->timestamp_types = timestamp_list;
335
336     return caps;
337 }
338
339 #ifdef HAVE_PCAP_REMOTE
340 void add_interface_to_remote_list(if_info_t *if_info)
341 {
342     GSList *list;
343     if_addr_t *if_addr, *temp_addr;
344
345     if_info_t *temp = (if_info_t*) g_malloc0(sizeof(if_info_t));
346     temp->name = g_strdup(if_info->name);
347     temp->friendly_name = g_strdup(if_info->friendly_name);
348     temp->vendor_description = g_strdup(if_info->vendor_description);
349     for (list = g_slist_nth(if_info->addrs, 0); list != NULL; list = g_slist_next(list)) {
350         temp_addr = (if_addr_t *)g_malloc0(sizeof(if_addr_t));
351         if_addr = (if_addr_t *)list->data;
352         if (if_addr) {
353             temp_addr->ifat_type = if_addr->ifat_type;
354             if (temp_addr->ifat_type == IF_AT_IPv4) {
355                 temp_addr->addr.ip4_addr = if_addr->addr.ip4_addr;
356             } else {
357                 memcpy(temp_addr->addr.ip6_addr, if_addr->addr.ip6_addr, sizeof(if_addr->addr));
358             }
359         } else {
360             g_free(temp_addr);
361             temp_addr = NULL;
362         }
363         if (temp_addr) {
364             temp->addrs = g_slist_append(temp->addrs, temp_addr);
365         }
366     }
367     temp->loopback = if_info->loopback;
368     remote_interface_list = g_list_append(remote_interface_list, temp);
369 }
370 #endif
371 #endif /* HAVE_LIBPCAP */