Fix compilation under VS6 (hopefully without breaking compilation
[obnox/wireshark/wip.git] / capture.c
1 /* capture.c
2  * Routines for packet capture
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #ifdef HAVE_LIBPCAP
30
31 #ifdef HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include <ctype.h>
38
39 #ifdef HAVE_FCNTL_H
40 #include <fcntl.h>
41 #endif
42
43 #ifdef HAVE_SYS_TYPES_H
44 #include <sys/types.h>
45 #endif
46
47 #ifdef HAVE_SYS_SOCKET_H
48 #include <sys/socket.h>
49 #endif
50
51 #ifdef HAVE_NETINET_IN_H
52 #include <netinet/in.h>
53 #endif
54
55 #ifdef HAVE_SYS_SOCKET_H
56 #include <sys/socket.h>         /* needed to define AF_ values on UNIX */
57 #endif
58
59 #ifdef HAVE_WINSOCK2_H
60 #include <winsock2.h>           /* needed to define AF_ values on Windows */
61 #endif
62
63 #ifdef NEED_INET_V6DEFS_H
64 # include "inet_v6defs.h"
65 #endif
66
67 #include <signal.h>
68 #include <errno.h>
69
70 #include <glib.h>
71
72 #include <epan/packet.h>
73 #include <epan/dfilter/dfilter.h>
74 #include <epan/ws_strsplit.h>
75 #include "file.h"
76 #include "capture.h"
77 #include "capture_sync.h"
78 #include "capture_info.h"
79 #include "capture_ui_utils.h"
80 #include "util.h"
81 #include "capture-pcap-util.h"
82 #include "alert_box.h"
83 #include "simple_dialog.h"
84 #include <epan/prefs.h>
85 #include "conditions.h"
86 #include "ringbuffer.h"
87
88 #ifdef _WIN32
89 #include "capture-wpcap.h"
90 #endif
91 #include "ui_util.h"
92 #include "file_util.h"
93 #include "log.h"
94
95
96
97 /**
98  * Start a capture.
99  *
100  * @return TRUE if the capture starts successfully, FALSE otherwise.
101  */
102 gboolean
103 capture_start(capture_options *capture_opts)
104 {
105   gboolean ret;
106
107
108   /* close the currently loaded capture file */
109   cf_close(capture_opts->cf);
110
111   g_assert(capture_opts->state == CAPTURE_STOPPED);
112   capture_opts->state = CAPTURE_PREPARING;
113
114   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Start ...");
115
116   /* try to start the capture child process */
117   ret = sync_pipe_start(capture_opts);
118   if(!ret) {
119       if(capture_opts->save_file != NULL) {
120           g_free(capture_opts->save_file);
121           capture_opts->save_file = NULL;
122       }
123
124       g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Start failed!");
125       capture_opts->state = CAPTURE_STOPPED;
126   } else {
127       /* the capture child might not respond shortly after bringing it up */
128       /* (especially it will block, if no input coming from an input capture pipe (e.g. mkfifo) is coming in) */
129
130       /* to prevent problems, bring the main GUI into "capture mode" right after successfully */
131       /* spawn/exec the capture child, without waiting for any response from it */
132       cf_callback_invoke(cf_cb_live_capture_prepared, capture_opts);
133
134       if(capture_opts->show_info)
135         capture_info_open(capture_opts->iface);
136   }
137
138   return ret;
139 }
140
141
142 void
143 capture_stop(capture_options *capture_opts)
144 {
145   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Stop ...");
146
147   cf_callback_invoke(cf_cb_live_capture_stopping, capture_opts);
148
149   /* stop the capture child gracefully */
150   sync_pipe_stop(capture_opts);
151 }
152
153
154 void
155 capture_restart(capture_options *capture_opts)
156 {
157     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Restart");
158
159     capture_opts->restart = TRUE;
160     capture_stop(capture_opts);
161 }
162
163
164 void
165 capture_kill_child(capture_options *capture_opts)
166 {
167   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "Capture Kill");
168
169   /* kill the capture child */
170   sync_pipe_kill(capture_opts->fork_child);
171 }
172
173
174
175 /* We've succeeded a (non real-time) capture, try to read it into a new capture file */
176 static gboolean
177 capture_input_read_all(capture_options *capture_opts, gboolean is_tempfile, gboolean drops_known,
178 guint32 drops)
179 {
180   int err;
181
182
183   /* Capture succeeded; attempt to open the capture file. */
184   if (cf_open(capture_opts->cf, capture_opts->save_file, is_tempfile, &err) != CF_OK) {
185     /* We're not doing a capture any more, so we don't have a save
186        file. */
187     return FALSE;
188   }
189
190   /* Set the read filter to NULL. */
191   /* XXX - this is odd here, try to put it somewhere, where it fits better */
192   cf_set_rfcode(capture_opts->cf, NULL);
193
194   /* Get the packet-drop statistics.
195
196      XXX - there are currently no packet-drop statistics stored
197      in libpcap captures, and that's what we're reading.
198
199      At some point, we will add support in Wiretap to return
200      packet-drop statistics for capture file formats that store it,
201      and will make "cf_read()" get those statistics from Wiretap.
202      We clear the statistics (marking them as "not known") in
203      "cf_open()", and "cf_read()" will only fetch them and mark
204      them as known if Wiretap supplies them, so if we get the
205      statistics now, after calling "cf_open()" but before calling
206      "cf_read()", the values we store will be used by "cf_read()".
207
208      If a future libpcap capture file format stores the statistics,
209      we'll put them into the capture file that we write, and will
210      thus not have to set them here - "cf_read()" will get them from
211      the file and use them. */
212   if (drops_known) {
213     cf_set_drops_known(capture_opts->cf, TRUE);
214
215     /* XXX - on some systems, libpcap doesn't bother filling in
216        "ps_ifdrop" - it doesn't even set it to zero - so we don't
217        bother looking at it.
218
219        Ideally, libpcap would have an interface that gave us
220        several statistics - perhaps including various interface
221        error statistics - and would tell us which of them it
222        supplies, allowing us to display only the ones it does. */
223     cf_set_drops(capture_opts->cf, drops);
224   }
225
226   /* read in the packet data */
227   switch (cf_read(capture_opts->cf)) {
228
229   case CF_READ_OK:
230   case CF_READ_ERROR:
231     /* Just because we got an error, that doesn't mean we were unable
232        to read any of the file; we handle what we could get from the
233        file. */
234     break;
235
236   case CF_READ_ABORTED:
237     /* User wants to quit program. Exit by leaving the main loop,
238        so that any quit functions we registered get called. */
239     main_window_nested_quit();
240     return FALSE;
241   }
242
243   /* if we didn't captured even a single packet, close the file again */
244   if(cf_get_packet_count(capture_opts->cf) == 0 && !capture_opts->restart) {
245     simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
246 "%sNo packets captured!%s\n"
247 "\n"
248 "As no data was captured, closing the %scapture file!\n"
249 "\n"
250 "\n"
251 "Help about capturing can be found at:\n"
252 "\n"
253 "       http://wiki.wireshark.org/CaptureSetup"
254 #ifdef _WIN32
255 "\n\n"
256 "Wireless (Wi-Fi/WLAN):\n"
257 "Try to switch off promiscuous mode in the Capture Options!"
258 #endif
259 "",
260     simple_dialog_primary_start(), simple_dialog_primary_end(),
261     (cf_is_tempfile(capture_opts->cf)) ? "temporary " : "");
262     cf_close(capture_opts->cf);
263   }
264   return TRUE;
265 }
266
267
268 /* capture child tells us we have a new (or the first) capture file */
269 gboolean
270 capture_input_new_file(capture_options *capture_opts, gchar *new_file)
271 {
272   gboolean is_tempfile;
273   int  err;
274
275
276   if(capture_opts->state == CAPTURE_PREPARING) {
277     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture started!");
278   }
279   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "File: \"%s\"", new_file);
280
281   g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
282
283   /* free the old filename */
284   if(capture_opts->save_file != NULL) {
285     /* we start a new capture file, close the old one (if we had one before) */
286     /* (we can only have an open capture file in real_time_mode!) */
287     if( ((capture_file *) capture_opts->cf)->state != FILE_CLOSED) {
288         cf_callback_invoke(cf_cb_live_capture_update_finished, capture_opts->cf);
289         cf_finish_tail(capture_opts->cf, &err);
290         cf_close(capture_opts->cf);
291     }
292     g_free(capture_opts->save_file);
293     is_tempfile = FALSE;
294     cf_set_tempfile(capture_opts->cf, FALSE);
295   } else {
296     /* we didn't had a save_file before, must be a tempfile */
297     is_tempfile = TRUE;
298     cf_set_tempfile(capture_opts->cf, TRUE);
299   }
300
301   /* save the new filename */
302   capture_opts->save_file = g_strdup(new_file);
303
304   /* if we are in real-time mode, open the new file now */
305   if(capture_opts->real_time_mode) {
306     /* Attempt to open the capture file and set up to read from it. */
307     switch(cf_start_tail(capture_opts->cf, capture_opts->save_file, is_tempfile, &err)) {
308     case CF_OK:
309       break;
310     case CF_ERROR:
311       /* Don't unlink (delete) the save file - leave it around,
312          for debugging purposes. */
313       g_free(capture_opts->save_file);
314       capture_opts->save_file = NULL;
315       return FALSE;
316       break;
317     }
318   }
319
320   if(capture_opts->show_info) {
321     if (!capture_info_new_file(new_file))
322       return FALSE;
323   }
324
325   if(capture_opts->real_time_mode) {
326     cf_callback_invoke(cf_cb_live_capture_update_started, capture_opts);
327   } else {
328     cf_callback_invoke(cf_cb_live_capture_fixed_started, capture_opts);
329   }
330   capture_opts->state = CAPTURE_RUNNING;
331
332   return TRUE;
333 }
334
335
336 /* capture child tells us we have new packets to read */
337 void
338 capture_input_new_packets(capture_options *capture_opts, int to_read)
339 {
340   int  err;
341
342
343   g_assert(capture_opts->save_file);
344
345   if(capture_opts->real_time_mode) {
346     /* Read from the capture file the number of records the child told us it added. */
347     switch (cf_continue_tail(capture_opts->cf, to_read, &err)) {
348
349     case CF_READ_OK:
350     case CF_READ_ERROR:
351       /* Just because we got an error, that doesn't mean we were unable
352          to read any of the file; we handle what we could get from the
353          file.
354
355          XXX - abort on a read error? */
356          cf_callback_invoke(cf_cb_live_capture_update_continue, capture_opts->cf);
357       break;
358
359     case CF_READ_ABORTED:
360       /* Kill the child capture process; the user wants to exit, and we
361          shouldn't just leave it running. */
362       capture_kill_child(capture_opts);
363       break;
364     }
365   } else {
366     /* increase capture file packet counter by the number or incoming packets */
367     cf_set_packet_count(capture_opts->cf,
368         cf_get_packet_count(capture_opts->cf) + to_read);
369
370     cf_callback_invoke(cf_cb_live_capture_fixed_continue, capture_opts->cf);
371   }
372
373   /* update the main window, so we get events (e.g. from the stop toolbar button) */
374   main_window_update();
375
376   if(capture_opts->show_info)
377     capture_info_new_packets(to_read);
378 }
379
380
381 /* Capture child told us how many dropped packets it counted.
382  */
383 void
384 capture_input_drops(capture_options *capture_opts, int dropped)
385 {
386   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_INFO, "%d packet%s dropped", dropped, plurality(dropped, "", "s"));
387
388   g_assert(capture_opts->state == CAPTURE_RUNNING);
389
390   cf_set_drops_known(capture_opts->cf, TRUE);
391   cf_set_drops(capture_opts->cf, dropped);
392 }
393
394
395 /* Capture child told us that an error has occurred while starting/running
396    the capture.
397    The buffer we're handed has *two* null-terminated strings in it - a
398    primary message and a secondary message, one right after the other.
399    The secondary message might be a null string.
400  */
401 void
402 capture_input_error_message(capture_options *capture_opts, char *error_msg, char *secondary_error_msg)
403 {
404   gchar *safe_error_msg;
405   gchar *safe_secondary_error_msg;
406
407   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Error message from child: \"%s\", \"%s\"",
408         error_msg, secondary_error_msg);
409
410   g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
411
412   safe_error_msg = simple_dialog_format_message(error_msg);
413   if (*secondary_error_msg != '\0') {
414     /* We have both primary and secondary messages. */
415     safe_secondary_error_msg = simple_dialog_format_message(secondary_error_msg);
416     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s\n\n%s",
417                   simple_dialog_primary_start(), safe_error_msg,
418                   simple_dialog_primary_end(), safe_secondary_error_msg);
419     g_free(safe_secondary_error_msg);
420   } else {
421     /* We have only a primary message. */
422     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s%s%s",
423                   simple_dialog_primary_start(), safe_error_msg,
424                   simple_dialog_primary_end());
425   }
426   g_free(safe_error_msg);
427
428   /* the capture child will close the sync_pipe if required, nothing to do for now */
429 }
430
431
432
433 /* Capture child told us that an error has occurred while parsing a
434    capture filter when starting/running the capture.
435  */
436 void
437 capture_input_cfilter_error_message(capture_options *capture_opts, char *error_message)
438 {
439   dfilter_t   *rfcode = NULL;
440   gchar *safe_cfilter = simple_dialog_format_message(capture_opts->cfilter);
441   gchar *safe_cfilter_error_msg = simple_dialog_format_message(error_message);
442
443   g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture filter error message from child: \"%s\"", error_message);
444
445   g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
446
447   /* Did the user try a display filter? */
448   if (dfilter_compile(capture_opts->cfilter, &rfcode) && rfcode != NULL) {
449     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
450       "%sInvalid capture filter: \"%s\"!%s\n"
451       "\n"
452       "That string looks like a valid display filter; however, it isn't a valid\n"
453       "capture filter (%s).\n"
454       "\n"
455       "Note that display filters and capture filters don't have the same syntax,\n"
456       "so you can't use most display filter expressions as capture filters.\n"
457       "\n"
458       "See the User's Guide for a description of the capture filter syntax.",
459       simple_dialog_primary_start(), safe_cfilter,
460       simple_dialog_primary_end(), safe_cfilter_error_msg);
461       dfilter_free(rfcode);
462   } else {
463     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
464       "%sInvalid capture filter: \"%s\"!%s\n"
465       "\n"
466       "That string isn't a valid capture filter (%s).\n"
467       "See the User's Guide for a description of the capture filter syntax.",
468       simple_dialog_primary_start(), safe_cfilter,
469       simple_dialog_primary_end(), safe_cfilter_error_msg);
470   }
471   g_free(safe_cfilter_error_msg);
472   g_free(safe_cfilter);
473
474   /* the capture child will close the sync_pipe if required, nothing to do for now */
475 }
476
477
478 /* capture child closed its side of the pipe, do the required cleanup */
479 void
480 capture_input_closed(capture_options *capture_opts)
481 {
482     int  err;
483     int  packet_count_save;
484
485     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture stopped!");
486     g_assert(capture_opts->state == CAPTURE_PREPARING || capture_opts->state == CAPTURE_RUNNING);
487
488     /* if we didn't started the capture, do a fake start */
489     /* (happens if we got an error message - we won't get a filename then) */
490     if(capture_opts->state == CAPTURE_PREPARING) {
491         if(capture_opts->real_time_mode) {
492             cf_callback_invoke(cf_cb_live_capture_update_started, capture_opts);
493         } else {
494             cf_callback_invoke(cf_cb_live_capture_fixed_started, capture_opts);
495         }
496     }
497
498     if(capture_opts->real_time_mode) {
499         cf_read_status_t status;
500
501         /* Read what remains of the capture file. */
502         status = cf_finish_tail(capture_opts->cf, &err);
503
504         /* XXX: If -Q (quit-after-cap) then cf->count clr'd below so save it first */
505         packet_count_save = cf_get_packet_count(capture_opts->cf);
506         /* Tell the GUI, we are not doing a capture any more.
507                    Must be done after the cf_finish_tail(), so file lengths are displayed
508                    correct. */
509         cf_callback_invoke(cf_cb_live_capture_update_finished, capture_opts->cf);
510
511         /* Finish the capture. */
512         switch (status) {
513
514         case CF_READ_OK:
515             if ((packet_count_save == 0) && !capture_opts->restart) {
516                 simple_dialog(ESD_TYPE_INFO, ESD_BTN_OK,
517 "%sNo packets captured!%s\n"
518 "\n"
519 "As no data was captured, closing the %scapture file!\n"
520 "\n"
521 "\n"
522 "Help about capturing can be found at:\n"
523 "\n"
524 "       http://wiki.wireshark.org/CaptureSetup"
525 #ifdef _WIN32
526 "\n\n"
527 "Wireless (Wi-Fi/WLAN):\n"
528 "Try to switch off promiscuous mode in the Capture Options!"
529 #endif
530 "",
531               simple_dialog_primary_start(), simple_dialog_primary_end(),
532               cf_is_tempfile(capture_opts->cf) ? "temporary " : "");
533               cf_close(capture_opts->cf);
534             }
535             break;
536         case CF_READ_ERROR:
537           /* Just because we got an error, that doesn't mean we were unable
538              to read any of the file; we handle what we could get from the
539              file. */
540           break;
541
542         case CF_READ_ABORTED:
543           /* Exit by leaving the main loop, so that any quit functions
544              we registered get called. */
545           main_window_quit();
546         }
547
548     } else {
549         /* first of all, we are not doing a capture any more */
550         cf_callback_invoke(cf_cb_live_capture_fixed_finished, capture_opts->cf);
551
552         /* this is a normal mode capture and if no error happened, read in the capture file data */
553         if(capture_opts->save_file != NULL) {
554             capture_input_read_all(capture_opts, cf_is_tempfile(capture_opts->cf),
555                 cf_get_drops_known(capture_opts->cf), cf_get_drops(capture_opts->cf));
556         }
557     }
558
559     if(capture_opts->show_info)
560       capture_info_close();
561
562     capture_opts->state = CAPTURE_STOPPED;
563
564     /* if we couldn't open a capture file, there's nothing more for us to do */
565     if(capture_opts->save_file == NULL) {
566         cf_close(capture_opts->cf);
567         return;
568     }
569
570     /* does the user wants to restart the current capture? */
571     if(capture_opts->restart) {
572         capture_opts->restart = FALSE;
573
574         eth_unlink(capture_opts->save_file);
575
576         /* if it was a tempfile, throw away the old filename (so it will become a tempfile again) */
577         if(cf_is_tempfile(capture_opts->cf)) {
578             g_free(capture_opts->save_file);
579             capture_opts->save_file = NULL;
580         }
581
582         /* ... and start the capture again */
583         capture_start(capture_opts);
584     } else {
585         /* We're not doing a capture any more, so we don't have a save file. */
586         g_free(capture_opts->save_file);
587         capture_opts->save_file = NULL;
588     }
589 }
590
591 /**
592  * Fetch the interface list from a child process (dumpcap).
593  *
594  * @return A GList containing if_info_t structs if successful, NULL otherwise.
595  */
596
597 /* XXX - We parse simple text output to get our interface list.  Should
598  * we use "real" data serialization instead, e.g. via XML? */
599 GList *
600 capture_interface_list(int *err, char **err_str)
601 {
602     GList     *if_list = NULL;
603     int        i, j;
604     gchar     *msg;
605     gchar    **raw_list, **if_parts, **addr_parts;
606     gchar     *name;
607     if_info_t *if_info;
608     if_addr_t *if_addr;
609
610     g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List ...");
611
612     /* Try to get our interface list */
613     *err = sync_interface_list_open(&msg);
614     if (*err != 0) {
615         g_log(LOG_DOMAIN_CAPTURE, G_LOG_LEVEL_MESSAGE, "Capture Interface List failed!");
616         if (err_str) {
617             if (*err_str)
618                 *err_str = msg;
619             else
620                 g_free(msg);
621         } else {
622             g_free(msg);
623         }
624         return NULL;
625     }
626
627     /* Split our lines */
628     raw_list = g_strsplit(msg, "\n", 0);
629     g_free(msg);
630
631     for (i = 0; raw_list[i] != NULL; i++) {
632         if_parts = g_strsplit(raw_list[i], "\t", 4);
633         if (if_parts[0] == NULL || if_parts[1] == NULL || if_parts[2] == NULL ||
634                 if_parts[3] == NULL) {
635             g_strfreev(if_parts);
636             continue;
637         }
638
639         /* Number followed by the name, e.g "1. eth0" */
640         name = strchr(if_parts[0], ' ');
641         if (name) {
642             name++;
643         } else {
644             g_strfreev(if_parts);
645             continue;
646         }
647
648         if_info = g_malloc0(sizeof(if_info_t));
649         if_info->name = g_strdup(name);
650         if (strlen(if_parts[1]) > 0)
651             if_info->description = g_strdup(if_parts[1]);
652         addr_parts = g_strsplit(if_parts[2], ",", 0);
653         for (j = 0; addr_parts[j] != NULL; j++) {
654             if_addr = g_malloc0(sizeof(if_addr_t));
655             if (inet_pton(AF_INET, addr_parts[j], &if_addr->ip_addr.ip4_addr)) {
656                 if_addr->type = AT_IPv4;
657             } else if (inet_pton(AF_INET6, addr_parts[j],
658                     &if_addr->ip_addr.ip6_addr)) {
659                 if_addr->type = AT_IPv6;
660             } else {
661                 g_free(if_addr);
662                 if_addr = NULL;
663             }
664             if (if_addr) {
665                 if_info->ip_addr = g_slist_append(if_info->ip_addr, if_addr);
666             }
667         }
668         if (strcmp(if_parts[3], "loopback") == 0)
669             if_info->loopback = TRUE;
670         g_strfreev(if_parts);
671         g_strfreev(addr_parts);
672         if_list = g_list_append(if_list, if_info);
673     }
674     g_strfreev(raw_list);
675
676     /* Check to see if we built a list */
677     if (if_list == NULL) {
678         if (*err_str)
679             *err_str = g_strdup("No interfaces found");
680         *err = NO_INTERFACES_FOUND;
681     }
682     return if_list;
683 }
684
685
686 #endif /* HAVE_LIBPCAP */