Propset eol-style and Id for all
[obnox/wireshark/wip.git] / dumpcap.c
1 /* dumpcap.c
2  *
3  * $Id$
4  *
5  * Ethereal - Network traffic analyzer
6  * By Gerald Combs <gerald@ethereal.com>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <glib.h>
29
30 #include <string.h>
31 #include <ctype.h>
32
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36
37 #ifdef NEED_GETOPT_H
38 #include "getopt.h"
39 #endif
40
41 #ifdef HAVE_NETDB_H
42 #include <netdb.h>
43 #endif
44
45 #ifdef _WIN32 /* Needed for console I/O */
46 #include <conio.h>
47 #endif
48
49 #include "ringbuffer.h"
50 #include "clopts_common.h"
51 #include "cmdarg_err.h"
52 #include "version_info.h"
53
54 #include <pcap.h>
55 #include "capture-pcap-util.h"
56
57 #ifdef _WIN32
58 #include "capture-wpcap.h"
59 /*#include "capture_wpcap_packet.h"*/
60 #endif
61
62 #include "capture.h"
63 #include "capture_loop.h"
64 #include "capture_sync.h"
65
66 #include "simple_dialog.h"
67 #include "util.h"
68 #include "log.h"
69 #include "file_util.h"
70
71
72
73 /* Win32 console handling */
74 #ifdef _WIN32
75 static gboolean has_console = TRUE;             /* TRUE if app has console */
76 static void create_console(void);
77 static void destroy_console(void);
78 #endif
79 static void
80 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
81                     const char *message, gpointer user_data _U_);
82
83 /* capture related options */
84 capture_options global_capture_opts;
85 capture_options *capture_opts = &global_capture_opts;
86
87 #if __GNUC__ >= 2
88 void exit_main(int err) __attribute__ ((noreturn));
89 #else
90 void exit_main(int err);
91 #endif
92
93
94
95 static void
96 print_usage(gboolean print_ver) {
97
98   FILE *output;
99
100 #ifdef _WIN32
101   create_console();
102 #endif
103
104   if (print_ver) {
105     output = stdout;
106     fprintf(output,
107         "Dumpcap " VERSION "%s\n"
108         "Capture network packets and dump them into a libpcap file.\n"
109         "See http://www.ethereal.com for more information.\n",
110         svnversion);
111   } else {
112     output = stderr;
113   }
114   fprintf(output, "\nUsage: dumpcap [options] ...\n");
115   fprintf(output, "\n");
116   fprintf(output, "Capture interface:\n");
117   fprintf(output, "  -i <interface>           name or idx of interface (def: first none loopback)\n");
118   fprintf(output, "  -f <capture filter>      packet filter in libpcap filter syntax\n");
119   fprintf(output, "  -s <snaplen>             packet snapshot length (def: 65535)\n");
120   fprintf(output, "  -p                       don't capture in promiscuous mode\n");
121 #ifdef _WIN32
122   fprintf(output, "  -B <buffer size>         size of kernel buffer (def: 1MB)\n");
123 #endif
124   fprintf(output, "  -y <link type>           link layer type (def: first appropriate)\n");
125   fprintf(output, "  -D                       print list of interfaces and exit\n");
126   fprintf(output, "  -L                       print list of link-layer types of iface and exit\n");
127   fprintf(output, "\n");
128   fprintf(output, "Stop conditions:\n");
129   fprintf(output, "  -c <packet count>        stop after n packets (def: infinite)\n");
130   fprintf(output, "  -a <autostop cond.> ...  duration:NUM - stop after NUM seconds\n");
131   fprintf(output, "                           filesize:NUM - stop this file after NUM KB\n");
132   fprintf(output, "                              files:NUM - stop after NUM files\n");
133   /*fprintf(output, "\n");*/
134   fprintf(output, "Output (files):\n");
135   fprintf(output, "  -w <filename>            name of file to save (def: tempfile)\n");
136   fprintf(output, "  -b <ringbuffer opt.> ... duration:NUM - switch to next file after NUM secs\n");
137   fprintf(output, "                           filesize:NUM - switch to next file after NUM KB\n");
138   fprintf(output, "                              files:NUM - ringbuffer: replace after NUM files\n");
139   /*fprintf(output, "\n");*/
140   fprintf(output, "Miscellaneous:\n");
141   fprintf(output, "  -v                       print version information and exit\n");
142   fprintf(output, "  -h                       display this help and exit\n");
143   fprintf(output, "\n");
144   fprintf(output, "Example: dumpcap -i eth0 -a duration:60 -w output.pcap\n");
145   fprintf(output, "\"Capture network packets from interface eth0 until 60s passed into output.pcap\"\n");
146   fprintf(output, "\n");
147   fprintf(output, "Use Ctrl-C to stop capturing at any time.\n");
148 }
149
150 static void
151 show_version(GString *comp_info_str, GString *runtime_info_str)
152 {
153 #ifdef _WIN32
154   create_console();
155 #endif
156
157   printf(
158         "Dumpcap " VERSION "%s\n"
159         "\n"
160         "%s\n"
161         "%s\n"
162         "%s\n"
163         "See http://www.ethereal.com for more information.\n",
164         svnversion, get_copyright_info() ,comp_info_str->str, runtime_info_str->str);
165 }
166
167 /*
168  * Report an error in command-line arguments.
169  * Creates a console on Windows.
170  * XXX - pop this up in a window of some sort on UNIX+X11 if the controlling
171  * terminal isn't the standard error?
172  */
173 void
174 cmdarg_err(const char *fmt, ...)
175 {
176   va_list ap;
177
178 #ifdef _WIN32
179   create_console();
180 #endif
181   va_start(ap, fmt);
182   fprintf(stderr, "dumpcap: ");
183   vfprintf(stderr, fmt, ap);
184   fprintf(stderr, "\n");
185   va_end(ap);
186 }
187
188 /*
189  * Report additional information for an error in command-line arguments.
190  * Creates a console on Windows.
191  * XXX - pop this up in a window of some sort on UNIX+X11 if the controlling
192  * terminal isn't the standard error?
193  */
194 void
195 cmdarg_err_cont(const char *fmt, ...)
196 {
197   va_list ap;
198
199 #ifdef _WIN32
200   create_console();
201 #endif
202   va_start(ap, fmt);
203   vfprintf(stderr, fmt, ap);
204   fprintf(stderr, "\n");
205   va_end(ap);
206 }
207
208
209 #ifdef _WIN32
210 BOOL WINAPI ConsoleCtrlHandlerRoutine(DWORD dwCtrlType)
211 {
212     /*printf("Event: %u", dwCtrlType);*/
213     capture_loop_stop();
214
215     return TRUE;
216 }
217 #endif
218
219 void exit_main(int err)
220 {
221 #ifdef _WIN32
222   /* Shutdown windows sockets */
223   WSACleanup();
224
225   destroy_console();
226 #endif
227
228   exit(err);
229 }
230
231
232 /* And now our feature presentation... [ fade to music ] */
233 int
234 main(int argc, char *argv[])
235 {
236   int                  opt;
237   extern char         *optarg;
238   gboolean             arg_error = FALSE;
239   GString             *comp_info_str;
240   GString             *runtime_info_str;
241
242 #ifdef _WIN32
243   WSADATA              wsaData;
244 #endif  /* _WIN32 */
245
246   gboolean             start_capture = TRUE;
247   gboolean             stats_known;
248   struct pcap_stat     stats;
249   GLogLevelFlags       log_flags;
250   gboolean             list_link_layer_types = FALSE;
251
252 #define OPTSTRING_INIT "a:b:c:Df:hi:Lps:vw:y:"
253
254 #ifdef _WIN32
255 #define OPTSTRING_WIN32 "B:Z:"
256 #else
257 #define OPTSTRING_WIN32 ""
258 #endif  /* _WIN32 */
259
260   char optstring[sizeof(OPTSTRING_INIT) + sizeof(OPTSTRING_WIN32) - 1] =
261     OPTSTRING_INIT OPTSTRING_WIN32;
262
263
264
265 #ifdef _WIN32
266   /* Load wpcap if possible. Do this before collecting the run-time version information */
267   load_wpcap();
268
269   /* ... and also load the packet.dll from wpcap */
270   /* XXX - currently not required, may change later. */
271   /*wpcap_packet_load();*/
272
273   /* Start windows sockets */
274   WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
275
276   /* Set handler for Ctrl+C key */
277   SetConsoleCtrlHandler(&ConsoleCtrlHandlerRoutine, TRUE);
278 #endif  /* _WIN32 */
279
280   /* Assemble the compile-time version information string */
281   comp_info_str = g_string_new("Compiled ");
282   g_string_append(comp_info_str, "with ");
283   get_compiled_version_info(comp_info_str);
284
285   /* Assemble the run-time version information string */
286   runtime_info_str = g_string_new("Running ");
287   get_runtime_version_info(runtime_info_str);
288
289   /* Arrange that if we have no console window, and a GLib message logging
290      routine is called to log a message, we pop up a console window.
291
292      We do that by inserting our own handler for all messages logged
293      to the default domain; that handler pops up a console if necessary,
294      and then calls the default handler. */
295
296   /* We might want to have component specific log levels later ... */
297
298   /* the default_log_handler will use stdout, which makes trouble with the */
299   /* capture child, as it uses stdout for it's sync_pipe */
300   /* so do the filtering in the console_log_handler and not here */
301   log_flags = 
302                     G_LOG_LEVEL_ERROR|
303                     G_LOG_LEVEL_CRITICAL|
304                     G_LOG_LEVEL_WARNING|
305                     G_LOG_LEVEL_MESSAGE|
306                     G_LOG_LEVEL_INFO|
307                     G_LOG_LEVEL_DEBUG|
308                     G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION;
309
310   g_log_set_handler(NULL,
311                     log_flags,
312                     console_log_handler, NULL /* user_data */);
313   g_log_set_handler(LOG_DOMAIN_MAIN,
314                     log_flags,
315                     console_log_handler, NULL /* user_data */);
316   g_log_set_handler(LOG_DOMAIN_CAPTURE,
317                     log_flags,
318             console_log_handler, NULL /* user_data */);
319   g_log_set_handler(LOG_DOMAIN_CAPTURE_CHILD,
320                     log_flags,
321             console_log_handler, NULL /* user_data */);
322
323   /* Set the initial values in the capture_opts. This might be overwritten 
324      by the command line parameters. */
325   capture_opts_init(capture_opts, NULL);
326
327   capture_opts->snaplen             = MIN_PACKET_SIZE;
328   capture_opts->has_ring_num_files  = TRUE;
329
330   /* Now get our args */
331   while ((opt = getopt(argc, argv, optstring)) != -1) {
332     switch (opt) {
333       case 'h':        /* Print help and exit */
334         print_usage(TRUE);
335         exit_main(0);
336         break;
337       case 'v':        /* Show version and exit */
338         show_version(comp_info_str, runtime_info_str);
339         exit_main(0);
340         break;
341       /*** capture option specific ***/
342       case 'a':        /* autostop criteria */
343       case 'b':        /* Ringbuffer option */
344       case 'c':        /* Capture x packets */
345       case 'f':        /* capture filter */
346       case 'i':        /* Use interface x */
347       case 'p':        /* Don't capture in promiscuous mode */
348       case 's':        /* Set the snapshot (capture) length */
349       case 'w':        /* Write to capture file x */
350       case 'y':        /* Set the pcap data link type */
351 #ifdef _WIN32
352       case 'B':        /* Buffer size */
353       /* Hidden option supporting Sync mode */
354       case 'Z':        /* Write to pipe FD x */
355 #endif /* _WIN32 */
356         capture_opts_add_opt(capture_opts, opt, optarg, &start_capture);
357         break;
358
359       /*** all non capture option specific ***/
360       case 'D':        /* Print a list of capture devices and exit */
361         capture_opts_list_interfaces();
362         exit_main(0);
363         break;
364       case 'L':        /* Print list of link-layer types and exit */
365         list_link_layer_types = TRUE;
366         break;
367       default:
368       case '?':        /* Bad flag - print usage message */
369         cmdarg_err("Invalid Option: %s", argv[optind-1]);
370         arg_error = TRUE;
371         break;
372     }
373   }
374   argc -= optind;
375   argv += optind;
376   if (argc >= 1) {
377       /* user specified file name as regular command-line argument */
378       /* XXX - use it as the capture file name (or something else)? */
379     argc--;
380     argv++;
381   }
382
383   if (argc != 0) {
384     /*
385      * Extra command line arguments were specified; complain.
386      */
387     cmdarg_err("Invalid argument: %s", argv[0]);
388     arg_error = TRUE;
389   }
390
391   if (arg_error) {
392     print_usage(FALSE);
393     exit_main(1);
394   }
395
396   if (list_link_layer_types) {
397     /* We're supposed to list the link-layer types for an interface;
398        did the user also specify a capture file to be read? */
399     /* No - did they specify a ring buffer option? */
400     if (capture_opts->multi_files_on) {
401       cmdarg_err("Ring buffer requested, but a capture isn't being done.");
402       exit_main(1);
403     }
404   } else {
405     /* No - was the ring buffer option specified and, if so, does it make
406        sense? */
407     if (capture_opts->multi_files_on) {
408       /* Ring buffer works only under certain conditions:
409          a) ring buffer does not work with temporary files;
410          b) it makes no sense to enable the ring buffer if the maximum
411             file size is set to "infinite". */
412       if (capture_opts->save_file == NULL) {
413         cmdarg_err("Ring buffer requested, but capture isn't being saved to a permanent file.");
414         capture_opts->multi_files_on = FALSE;
415       }
416       if (!capture_opts->has_autostop_filesize && !capture_opts->has_file_duration) {
417         cmdarg_err("Ring buffer requested, but no maximum capture file size or duration were specified.");
418 /* XXX - this must be redesigned as the conditions changed */
419 /*      capture_opts->multi_files_on = FALSE;*/
420       }
421     }
422   }
423
424   if (capture_opts_trim_iface(capture_opts, NULL) == FALSE) {
425         cmdarg_err("No capture interfaces available (maybe lack of privileges?).");
426     exit_main(1);
427   }
428
429   /* Let the user know what interface was chosen. */
430 /*  descr = get_interface_descriptive_name(capture_opts.iface);
431   fprintf(stderr, "Capturing on %s\n", descr);
432   g_free(descr);*/
433   fprintf(stderr, "Capturing on %s\n", capture_opts->iface);
434   
435
436   if (list_link_layer_types) {
437     capture_opts_list_link_layer_types(capture_opts);
438     exit_main(0);
439   }
440
441   capture_opts_trim_snaplen(capture_opts, MIN_PACKET_SIZE);
442   capture_opts_trim_ring_num_files(capture_opts);
443
444   /* Now start the capture. */
445
446   /* XXX - hand the stats to the parent process */
447   if(capture_loop_start(capture_opts, &stats_known, &stats) == TRUE) {
448       /* capture ok */
449       exit_main(0);
450   } else {
451       /* capture failed */
452       exit_main(1);
453   }
454 }
455
456 #ifdef _WIN32
457
458 /* We build this as a GUI subsystem application on Win32, so
459    "WinMain()", not "main()", gets called.
460
461    Hack shamelessly stolen from the Win32 port of the GIMP. */
462 #ifdef __GNUC__
463 #define _stdcall  __attribute__((stdcall))
464 #endif
465
466 int _stdcall
467 WinMain (struct HINSTANCE__ *hInstance,
468          struct HINSTANCE__ *hPrevInstance,
469          char               *lpszCmdLine,
470          int                 nCmdShow)
471 {
472   has_console = FALSE;
473   return main (__argc, __argv);
474 }
475
476 /*
477  * If this application has no console window to which its standard output
478  * would go, create one.
479  */
480 void
481 create_console(void)
482 {
483   if (!has_console) {
484     /* We have no console to which to print the version string, so
485        create one and make it the standard input, output, and error. */
486     if (!AllocConsole())
487       return;   /* couldn't create console */
488     eth_freopen("CONIN$", "r", stdin);
489     eth_freopen("CONOUT$", "w", stdout);
490     eth_freopen("CONOUT$", "w", stderr);
491
492     /* Well, we have a console now. */
493     has_console = TRUE;
494
495     /* Now register "destroy_console()" as a routine to be called just
496        before the application exits, so that we can destroy the console
497        after the user has typed a key (so that the console doesn't just
498        disappear out from under them, giving the user no chance to see
499        the message(s) we put in there). */
500     atexit(destroy_console);
501
502     SetConsoleTitle("Dumpcap Console");
503   }
504 }
505
506 static void
507 destroy_console(void)
508 {
509   if (has_console) {
510 /* XXX - doesn't make sense while we're linked as a console application */
511 /*    printf("\n\nPress any key to exit\n");
512     _getch();*/
513     FreeConsole();
514   }
515 }
516 #endif /* _WIN32 */
517
518
519 /* This routine should not be necessary, at least as I read the GLib
520    source code, as it looks as if GLib is, on Win32, *supposed* to
521    create a console window into which to display its output.
522
523    That doesn't happen, however.  I suspect there's something completely
524    broken about that code in GLib-for-Win32, and that it may be related
525    to the breakage that forces us to just call "printf()" on the message
526    rather than passing the message on to "g_log_default_handler()"
527    (which is the routine that does the aforementioned non-functional
528    console window creation). */
529 static void
530 console_log_handler(const char *log_domain, GLogLevelFlags log_level,
531                     const char *message, gpointer user_data _U_)
532 {
533   time_t curr;
534   struct tm *today;
535   const char *level;
536
537
538   /* ignore log message, if log_level isn't interesting */
539   if( !(log_level & G_LOG_LEVEL_MASK & ~(G_LOG_LEVEL_DEBUG|G_LOG_LEVEL_INFO) /*prefs.console_log_level*/)) {
540     return;
541   }
542
543   /* create a "timestamp" */
544   time(&curr);
545   today = localtime(&curr);    
546
547 #ifdef _WIN32
548 /*  if (prefs.gui_console_open != console_open_never) {*/
549     create_console();
550 /*  }*/
551   if (has_console) {
552     /* For some unknown reason, the above doesn't appear to actually cause
553        anything to be sent to the standard output, so we'll just splat the
554        message out directly, just to make sure it gets out. */
555 #endif
556     switch(log_level & G_LOG_LEVEL_MASK) {
557     case G_LOG_LEVEL_ERROR:
558         level = "Err ";
559         break;
560     case G_LOG_LEVEL_CRITICAL:
561         level = "Crit";
562         break;
563     case G_LOG_LEVEL_WARNING:
564         level = "Warn";
565         break;
566     case G_LOG_LEVEL_MESSAGE:
567         level = "Msg ";
568         break;
569     case G_LOG_LEVEL_INFO:
570         level = "Info";
571         break;
572     case G_LOG_LEVEL_DEBUG:
573         level = "Dbg ";
574         break;
575     default:
576         fprintf(stderr, "unknown log_level %u\n", log_level);
577         level = NULL;
578         g_assert_not_reached();
579     }
580
581     /* don't use printf (stdout), as the capture child uses stdout for it's sync_pipe */
582     fprintf(stderr, "%02u:%02u:%02u %8s %s %s\n",
583             today->tm_hour, today->tm_min, today->tm_sec,
584             log_domain != NULL ? log_domain : "",
585             level, message);
586 #ifdef _WIN32
587   } else {
588     g_log_default_handler(log_domain, log_level, message, user_data);
589   }
590 #endif
591 }
592
593 /****************************************************************************************************************/
594 /* sync_pipe stubs */
595
596 /*
597  * Maximum length of sync pipe message data.  Must be < 2^24, as the
598  * message length is 3 bytes.
599  * XXX - this must be large enough to handle a Really Big Filter
600  * Expression, as the error message for an incorrect filter expression
601  * is a bit larger than the filter expression.
602  */
603 #define SP_MAX_MSG_LEN  4096
604
605
606  /* write a message to the recipient pipe in the standard format 
607    (3 digit message length (excluding length and indicator field), 
608    1 byte message indicator and the rest is the message) */
609 static void
610 pipe_write_block(int pipe, char indicator, int len, const char *msg)
611 {
612     guchar header[3+1]; /* indicator + 3-byte len */
613     int ret;
614
615     /*g_warning("write %d enter", pipe);*/
616
617     /* XXX - find a suitable way to switch between pipe and console output */
618     return;
619
620     g_assert(indicator < '0' || indicator > '9');
621     g_assert(len <= SP_MAX_MSG_LEN);
622
623     /* write header (indicator + 3-byte len) */
624     header[0] = indicator;
625     header[1] = (len >> 16) & 0xFF;
626     header[2] = (len >> 8) & 0xFF;
627     header[3] = (len >> 0) & 0xFF;
628
629     ret = write(pipe, header, sizeof header);
630     if(ret == -1) {
631         return;
632     }
633
634     /* write value (if we have one) */
635     if(len) {
636         /*g_warning("write %d indicator: %c value len: %u msg: %s", pipe, indicator, len, msg);*/
637         ret = write(pipe, msg, len);
638         if(ret == -1) {
639             return;
640         }
641     } else {
642         /*g_warning("write %d indicator: %c no value", pipe, indicator);*/
643     }
644
645     /*g_warning("write %d leave", pipe);*/
646 }
647
648
649 int count = 0;
650
651 void
652 sync_pipe_packet_count_to_parent(int packet_count)
653 {
654     char tmp[SP_DECISIZE+1+1];
655
656
657     count += packet_count;
658     fprintf(stderr, "\r%u", count);
659     /* stderr could be line buffered */
660     fflush(stderr);
661
662
663     g_snprintf(tmp, sizeof(tmp), "%d", packet_count);
664
665     /*g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_packet_count_to_parent: %s", tmp);*/
666
667     pipe_write_block(1, SP_PACKET_COUNT, strlen(tmp)+1, tmp);
668 }
669
670 void
671 sync_pipe_filename_to_parent(const char *filename)
672 {
673     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_INFO, "File: %s", filename);
674
675     pipe_write_block(1, SP_FILE, strlen(filename)+1, filename);
676 }
677
678 void
679 sync_pipe_errmsg_to_parent(const char *errmsg)
680 {
681     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_errmsg_to_parent: %s", errmsg);
682
683     pipe_write_block(1, SP_ERROR_MSG, strlen(errmsg)+1, errmsg);
684 }
685
686 void
687 sync_pipe_drops_to_parent(int drops)
688 {
689     char tmp[SP_DECISIZE+1+1];
690
691
692     g_snprintf(tmp, sizeof(tmp), "%d", drops);
693
694     g_log(LOG_DOMAIN_CAPTURE_CHILD, G_LOG_LEVEL_DEBUG, "sync_pipe_drops_to_parent: %s", tmp);
695
696     pipe_write_block(1, SP_DROPS, strlen(tmp)+1, tmp);
697 }
698
699
700
701 /****************************************************************************************************************/
702 /* simple_dialog stubs */
703
704
705 char *simple_dialog_primary_start(void)
706 {
707     return "";
708 }
709
710 char *simple_dialog_primary_end(void)
711 {
712     return "";
713 }
714
715 char *
716 simple_dialog_format_message(const char *msg)
717 {
718     char *str;
719
720     if (msg) {
721 #if GTK_MAJOR_VERSION < 2
722         str = g_strdup(msg);
723 #else
724         str = xml_escape(msg);
725 #endif
726     } else {
727         str = NULL;
728     }
729     return str;
730 }
731
732 /****************************************************************************************************************/
733 /* Stub functions */
734
735
736 const char *netsnmp_get_version(void) { return ""; }
737
738 gboolean dfilter_compile(const gchar *text, dfilter_t **dfp) { (void)text; (void)dfp; return FALSE; }
739
740 void dfilter_free(dfilter_t *df) { (void)df; }
741
742
743 /*
744  * Find out whether a hostname resolves to an ip or ipv6 address
745  * Return "ip6" if it is IPv6, "ip" otherwise (including the case
746  * that we don't know)
747  */
748 const char* host_ip_af(const char *host
749 #ifndef HAVE_GETHOSTBYNAME2
750 _U_
751 #endif
752 )
753 {
754 #ifdef HAVE_GETHOSTBYNAME2
755         struct hostent *h;
756         return (h = gethostbyname2(host, AF_INET6)) && h->h_addrtype == AF_INET6 ? "ip6" : "ip";
757 #else
758         return "ip";
759 #endif
760 }
761