tests: add regression tests for Follow TCP Stream
[metze/wireshark/wip.git] / rawshark.c
index 25fa0fa24466aa500a4850c73e3faf9f9dc96705..59df20018783667d87f966a1d63f71d1977bcdd4 100644 (file)
@@ -9,19 +9,7 @@
  * Based on TShark, by Gilbert Ramirez <gram@alumni.rice.edu> and Guy Harris
  * <guy@alum.mit.edu>.
  *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * SPDX-License-Identifier: GPL-2.0-or-later
  */
 
 /*
@@ -56,7 +44,6 @@
 #endif
 
 #include <glib.h>
-#include <epan/epan-int.h>
 #include <epan/epan.h>
 
 #include <wsutil/cmdarg_err.h>
@@ -82,7 +69,8 @@
 #endif
 #include "ui/util.h"
 #include "ui/dissect_opts.h"
-#include "register.h"
+#include "ui/failure_message.h"
+#include "epan/register.h"
 #include "conditions.h"
 #include "capture_stop_conditions.h"
 #include <epan/epan_dissect.h>
 #include <wiretap/pcap-encap.h>
 
 #include <wsutil/clopts_common.h>
-#include <ws_version_info.h>
+#include <version_info.h>
 
 #include "caputils/capture-pcap-util.h"
 
-#ifdef HAVE_EXTCAP
 #include "extcap.h"
-#endif
 
 #ifdef HAVE_LIBPCAP
 #include <setjmp.h>
@@ -128,12 +114,11 @@ static const gchar decode_as_arg_template[] = "<layer_type>==<selector>,<decode_
 #define OPEN_ERROR 2
 #define FORMAT_ERROR 2
 
+capture_file cfile;
+
 static guint32 cum_bytes;
-static const frame_data *ref;
 static frame_data ref_frame;
-static frame_data *prev_dis;
 static frame_data prev_dis_frame;
-static frame_data *prev_cap;
 static frame_data prev_cap_frame;
 
 /*
@@ -153,7 +138,7 @@ static gboolean want_pcap_pkthdr;
 cf_status_t raw_cf_open(capture_file *cf, const char *fname);
 static gboolean load_cap_file(capture_file *cf);
 static gboolean process_packet(capture_file *cf, epan_dissect_t *edt, gint64 offset,
-                               struct wtap_pkthdr *whdr, const guchar *pd);
+                               wtap_rec *rec, const guchar *pd);
 static void show_print_file_io_error(int err);
 
 static void failure_warning_message(const char *msg_format, va_list ap);
@@ -178,7 +163,6 @@ typedef struct string_fmt_s {
     string_fmt_e format;    /* Valid if plain is NULL */
 } string_fmt_t;
 
-capture_file cfile;
 int n_rfilters;
 int n_rfcodes;
 dfilter_t *rfcodes[64];
@@ -204,7 +188,7 @@ print_usage(FILE *output)
     fprintf(output, "                           packet encapsulation or protocol\n");
     fprintf(output, "  -F <field>               field to display\n");
 #ifndef _WIN32
-    fprintf(output, "  -m                       virtual memory limit, in bytes \n");
+    fprintf(output, "  -m                       virtual memory limit, in bytes\n");
 #endif
     fprintf(output, "  -n                       disable all name resolution (def: all enabled)\n");
     fprintf(output, "  -N <name resolve flags>  enable specific name resolution(s): \"mnNtd\"\n");
@@ -369,6 +353,7 @@ set_link_type(const char *lt_arg) {
     long val;
     dissector_handle_t dhandle;
     GString *pref_str;
+    char *errmsg = NULL;
 
     if (!spec_ptr)
         return FALSE;
@@ -409,8 +394,9 @@ set_link_type(const char *lt_arg) {
             g_string_append_printf(pref_str,
                                    "\"User 0 (DLT=147)\",\"%s\",\"0\",\"\",\"0\",\"\"",
                                    spec_ptr);
-            if (prefs_set_pref(pref_str->str) != PREFS_SET_OK) {
+            if (prefs_set_pref(pref_str->str, &errmsg) != PREFS_SET_OK) {
                 g_string_free(pref_str, TRUE);
+                g_free(errmsg);
                 return FALSE;
             }
             g_string_free(pref_str, TRUE);
@@ -427,7 +413,6 @@ main(int argc, char *argv[])
     GString             *runtime_info_str;
     char                *init_progfile_dir_error;
     int                  opt, i;
-    gboolean             arg_error = FALSE;
 
 #ifdef _WIN32
     int                  result;
@@ -436,9 +421,6 @@ main(int argc, char *argv[])
     struct rlimit limit;
 #endif  /* _WIN32 */
 
-    char                *gpf_path, *pf_path;
-    int                  gpf_open_errno, gpf_read_errno;
-    int                  pf_open_errno, pf_read_errno;
     gchar               *pipe_name = NULL;
     gchar               *rfilters[64];
     e_prefs             *prefs_p;
@@ -504,7 +486,7 @@ main(int argc, char *argv[])
      * Attempt to get the pathname of the directory containing the
      * executable file.
      */
-    init_progfile_dir_error = init_progfile_dir(argv[0], main);
+    init_progfile_dir_error = init_progfile_dir(argv[0]);
     if (init_progfile_dir_error != NULL) {
         fprintf(stderr, "rawshark: Can't get pathname of rawshark program: %s.\n",
                 init_progfile_dir_error);
@@ -532,7 +514,7 @@ main(int argc, char *argv[])
     timestamp_set_precision(TS_PREC_AUTO);
     timestamp_set_seconds_type(TS_SECONDS_DEFAULT);
 
-    wtap_init();
+    wtap_init(FALSE);
 
     /* Register all dissectors; we must do this before checking for the
        "-G" flag, as the "-G" flag dumps information registered by the
@@ -544,36 +526,8 @@ main(int argc, char *argv[])
         goto clean_exit;
     }
 
-    prefs_p = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
-                         &pf_open_errno, &pf_read_errno, &pf_path);
-    if (gpf_path != NULL) {
-        if (gpf_open_errno != 0) {
-            cmdarg_err("Can't open global preferences file \"%s\": %s.",
-                       pf_path, g_strerror(gpf_open_errno));
-        }
-        if (gpf_read_errno != 0) {
-            cmdarg_err("I/O error reading global preferences file \"%s\": %s.",
-                       pf_path, g_strerror(gpf_read_errno));
-        }
-    }
-    if (pf_path != NULL) {
-        if (pf_open_errno != 0) {
-            cmdarg_err("Can't open your preferences file \"%s\": %s.", pf_path,
-                       g_strerror(pf_open_errno));
-        }
-        if (pf_read_errno != 0) {
-            cmdarg_err("I/O error reading your preferences file \"%s\": %s.",
-                       pf_path, g_strerror(pf_read_errno));
-        }
-        g_free(pf_path);
-        pf_path = NULL;
-    }
-
-    /*
-     * Read the files that enable and disable protocols and heuristic
-     * dissectors.
-     */
-    read_enabled_and_disabled_protos();
+    /* Load libwireshark settings from the current profile. */
+    prefs_p = epan_load_settings();
 
 #ifdef _WIN32
     ws_init_dll_search_path();
@@ -651,13 +605,18 @@ main(int argc, char *argv[])
                 }
                 break;
             case 'o':        /* Override preference from command line */
-                switch (prefs_set_pref(optarg)) {
+            {
+                char *errmsg = NULL;
+
+                switch (prefs_set_pref(optarg, &errmsg)) {
 
                     case PREFS_SET_OK:
                         break;
 
                     case PREFS_SET_SYNTAX_ERR:
-                        cmdarg_err("Invalid -o flag \"%s\"", optarg);
+                        cmdarg_err("Invalid -o flag \"%s\"%s%s", optarg,
+                                errmsg ? ": " : "", errmsg ? errmsg : "");
+                        g_free(errmsg);
                         ret = INVALID_OPTION;
                         goto clean_exit;
                         break;
@@ -670,6 +629,7 @@ main(int argc, char *argv[])
                         break;
                 }
                 break;
+            }
             case 'p':        /* Expect pcap_pkthdr packet headers, which may have 64-bit timestamps */
                 want_pcap_pkthdr = TRUE;
                 break;
@@ -740,14 +700,12 @@ main(int argc, char *argv[])
                 g_string_free(comp_info_str, TRUE);
                 g_string_free(runtime_info_str, TRUE);
                 goto clean_exit;
-                break;
             }
             default:
             case '?':        /* Bad flag - print usage message */
                 print_usage(stderr);
-            ret = INVALID_OPTION;
-            goto clean_exit;
-            break;
+                ret = INVALID_OPTION;
+                goto clean_exit;
         }
     }
 
@@ -789,13 +747,6 @@ main(int argc, char *argv[])
         goto clean_exit;
     }
 
-    if (arg_error) {
-        print_usage(stderr);
-        ret = INVALID_OPTION;
-        goto clean_exit;
-    }
-
-
 #ifdef _WIN32
     /* Start windows sockets */
     result = WSAStartup( MAKEWORD( 1, 1 ), &wsaData );
@@ -806,11 +757,6 @@ main(int argc, char *argv[])
     }
 #endif /* _WIN32 */
 
-    /* At this point MATE will have registered its field array so we can
-       have a tap filter with one of MATE's late-registered fields as part
-       of the filter.  We can now process all the "-z" arguments. */
-    start_requested_stats();
-
     /*
      * Enabled and disabled protocols and heuristic dissectors as per
      * command-line options.
@@ -862,7 +808,7 @@ main(int argc, char *argv[])
                     ret =  FORMAT_ERROR;
                     goto clean_exit;
                 }
-                bytes_left -= bytes;
+                bytes_left -= (unsigned int)bytes;
             }
         }
 
@@ -881,9 +827,7 @@ main(int argc, char *argv[])
 clean_exit:
     epan_free(cfile.epan);
     epan_cleanup();
-#ifdef HAVE_EXTCAP
     extcap_cleanup();
-#endif
     wtap_cleanup();
     return ret;
 }
@@ -893,14 +837,13 @@ clean_exit:
  * packet header followed by the payload.
  * @param pd [IN] A POSIX file descriptor.  Because that's _exactly_ the sort
  *           of thing you want to use in Windows.
- * @param phdr [OUT] Packet header information.
  * @param err [OUT] Error indicator.  Uses wiretap values.
  * @param err_info [OUT] Error message.
  * @param data_offset [OUT] data offset in the pipe.
  * @return TRUE on success, FALSE on failure.
  */
 static gboolean
-raw_pipe_read(struct wtap_pkthdr *phdr, guchar * pd, int *err, gchar **err_info, gint64 *data_offset) {
+raw_pipe_read(wtap_rec *rec, guchar * pd, int *err, gchar **err_info, gint64 *data_offset) {
     struct pcap_pkthdr mem_hdr;
     struct pcaprec_hdr disk_hdr;
     ssize_t bytes_read = 0;
@@ -943,34 +886,36 @@ raw_pipe_read(struct wtap_pkthdr *phdr, guchar * pd, int *err, gchar **err_info,
             *err_info = NULL;
             return FALSE;
         }
-        bytes_needed -= bytes_read;
+        bytes_needed -= (unsigned int)bytes_read;
         *data_offset += bytes_read;
         ptr += bytes_read;
     }
 
+    rec->rec_type = REC_TYPE_PACKET;
+    rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
     if (want_pcap_pkthdr) {
-        phdr->ts.secs = mem_hdr.ts.tv_sec;
-        phdr->ts.nsecs = (gint32)mem_hdr.ts.tv_usec * 1000;
-        phdr->caplen = mem_hdr.caplen;
-        phdr->len = mem_hdr.len;
+        rec->ts.secs = mem_hdr.ts.tv_sec;
+        rec->ts.nsecs = (gint32)mem_hdr.ts.tv_usec * 1000;
+        rec->rec_header.packet_header.caplen = mem_hdr.caplen;
+        rec->rec_header.packet_header.len = mem_hdr.len;
     } else {
-        phdr->ts.secs = disk_hdr.ts_sec;
-        phdr->ts.nsecs = disk_hdr.ts_usec * 1000;
-        phdr->caplen = disk_hdr.incl_len;
-        phdr->len = disk_hdr.orig_len;
+        rec->ts.secs = disk_hdr.ts_sec;
+        rec->ts.nsecs = disk_hdr.ts_usec * 1000;
+        rec->rec_header.packet_header.caplen = disk_hdr.incl_len;
+        rec->rec_header.packet_header.len = disk_hdr.orig_len;
     }
-    bytes_needed = phdr->caplen;
+    bytes_needed = rec->rec_header.packet_header.caplen;
 
-    phdr->pkt_encap = encap;
+    rec->rec_header.packet_header.pkt_encap = encap;
 
 #if 0
     printf("mem_hdr: %lu disk_hdr: %lu\n", sizeof(mem_hdr), sizeof(disk_hdr));
-    printf("tv_sec: %u (%04x)\n", (unsigned int) phdr->ts.secs, (unsigned int) phdr->ts.secs);
-    printf("tv_nsec: %d (%04x)\n", phdr->ts.nsecs, phdr->ts.nsecs);
-    printf("caplen: %d (%04x)\n", phdr->caplen, phdr->caplen);
-    printf("len: %d (%04x)\n", phdr->len, phdr->len);
+    printf("tv_sec: %u (%04x)\n", (unsigned int) rec->ts.secs, (unsigned int) rec->ts.secs);
+    printf("tv_nsec: %d (%04x)\n", rec->ts.nsecs, rec->ts.nsecs);
+    printf("caplen: %d (%04x)\n", rec->rec_header.packet_header.caplen, rec->rec_header.packet_header.caplen);
+    printf("len: %d (%04x)\n", rec->rec_header.packet_header.len, rec->rec_header.packet_header.len);
 #endif
-    if (bytes_needed > WTAP_MAX_PACKET_SIZE) {
+    if (bytes_needed > WTAP_MAX_PACKET_SIZE_STANDARD) {
         *err = WTAP_ERR_BAD_FILE;
         *err_info = g_strdup_printf("Bad packet length: %lu\n",
                    (unsigned long) bytes_needed);
@@ -989,7 +934,7 @@ raw_pipe_read(struct wtap_pkthdr *phdr, guchar * pd, int *err, gchar **err_info,
             *err_info = NULL;
             return FALSE;
         }
-        bytes_needed -= bytes_read;
+        bytes_needed -= (unsigned int)bytes_read;
         *data_offset += bytes_read;
         ptr += bytes_read;
     }
@@ -1004,57 +949,25 @@ load_cap_file(capture_file *cf)
     gint64       data_offset = 0;
 
     guchar      *pd;
-    struct wtap_pkthdr phdr;
+    wtap_rec     rec;
     epan_dissect_t edt;
 
-    wtap_phdr_init(&phdr);
+    wtap_rec_init(&rec);
 
     epan_dissect_init(&edt, cf->epan, TRUE, FALSE);
 
-    pd = (guchar*)g_malloc(WTAP_MAX_PACKET_SIZE);
-    while (raw_pipe_read(&phdr, pd, &err, &err_info, &data_offset)) {
-        process_packet(cf, &edt, data_offset, &phdr, pd);
+    pd = (guchar*)g_malloc(WTAP_MAX_PACKET_SIZE_STANDARD);
+    while (raw_pipe_read(&rec, pd, &err, &err_info, &data_offset)) {
+        process_packet(cf, &edt, data_offset, &rec, pd);
     }
 
     epan_dissect_cleanup(&edt);
 
-    wtap_phdr_cleanup(&phdr);
+    wtap_rec_cleanup(&rec);
     g_free(pd);
     if (err != 0) {
         /* Print a message noting that the read failed somewhere along the line. */
-        switch (err) {
-
-            case WTAP_ERR_UNSUPPORTED:
-                cmdarg_err("The file \"%s\" contains record data that Rawshark doesn't support.\n(%s)",
-                           cf->filename,
-                           err_info != NULL ? err_info : "no information supplied");
-                g_free(err_info);
-                break;
-
-            case WTAP_ERR_SHORT_READ:
-                cmdarg_err("The file \"%s\" appears to have been cut short in the middle of a packet.",
-                           cf->filename);
-                break;
-
-            case WTAP_ERR_BAD_FILE:
-                cmdarg_err("The file \"%s\" appears to be damaged or corrupt.\n(%s)",
-                           cf->filename,
-                           err_info != NULL ? err_info : "no information supplied");
-                g_free(err_info);
-                break;
-
-            case WTAP_ERR_DECOMPRESS:
-                cmdarg_err("The compressed file \"%s\" appears to be damaged or corrupt.\n(%s)",
-                           cf->filename,
-                           err_info != NULL ? err_info : "no information supplied");
-                g_free(err_info);
-                break;
-
-            default:
-                cmdarg_err("An error occurred while reading the file \"%s\": %s.",
-                           cf->filename, wtap_strerror(err));
-                break;
-        }
+        cfile_read_failure_message("Rawshark", cf->filename, err, err_info);
         return FALSE;
     }
 
@@ -1063,20 +976,20 @@ load_cap_file(capture_file *cf)
 
 static gboolean
 process_packet(capture_file *cf, epan_dissect_t *edt, gint64 offset,
-               struct wtap_pkthdr *whdr, const guchar *pd)
+               wtap_rec *rec, const guchar *pd)
 {
     frame_data fdata;
     gboolean passed;
     int i;
 
-    if(whdr->len == 0)
+    if(rec->rec_header.packet_header.len == 0)
     {
         /* The user sends an empty packet when he wants to get output from us even if we don't currently have
            packets to process. We spit out a line with the timestamp and the text "void"
         */
         printf("%lu %lu %lu void -\n", (unsigned long int)cf->count,
-               (unsigned long int)whdr->ts.secs,
-               (unsigned long int)whdr->ts.nsecs);
+               (unsigned long int)rec->ts.secs,
+               (unsigned long int)rec->ts.nsecs);
 
         fflush(stdout);
 
@@ -1089,7 +1002,7 @@ process_packet(capture_file *cf, epan_dissect_t *edt, gint64 offset,
     /* If we're going to print packet information, or we're going to
        run a read filter, or we're going to process taps, set up to
        do a dissection and do so. */
-    frame_data_init(&fdata, cf->count, whdr, offset, cum_bytes);
+    frame_data_init(&fdata, cf->count, rec, offset, cum_bytes);
 
     passed = TRUE;
 
@@ -1097,31 +1010,33 @@ process_packet(capture_file *cf, epan_dissect_t *edt, gint64 offset,
        filter. */
     if (n_rfilters > 0) {
         for(i = 0; i < n_rfcodes; i++) {
-            epan_dissect_prime_dfilter(edt, rfcodes[i]);
+            epan_dissect_prime_with_dfilter(edt, rfcodes[i]);
         }
     }
 
     printf("%lu", (unsigned long int) cf->count);
 
     frame_data_set_before_dissect(&fdata, &cf->elapsed_time,
-                                  &ref, prev_dis);
+                                  &cf->provider.ref, cf->provider.prev_dis);
 
-    if (ref == &fdata) {
+    if (cf->provider.ref == &fdata) {
        ref_frame = fdata;
-       ref = &ref_frame;
+       cf->provider.ref = &ref_frame;
     }
 
     /* We only need the columns if we're printing packet info but we're
      *not* verbose; in verbose mode, we print the protocol tree, not
      the protocol summary. */
-    epan_dissect_run_with_taps(edt, cf->cd_t, whdr, frame_tvbuff_new(&fdata, pd), &fdata, &cf->cinfo);
+    epan_dissect_run_with_taps(edt, cf->cd_t, rec,
+                               frame_tvbuff_new(&cf->provider, &fdata, pd),
+                               &fdata, &cf->cinfo);
 
     frame_data_set_after_dissect(&fdata, &cum_bytes);
     prev_dis_frame = fdata;
-    prev_dis = &prev_dis_frame;
+    cf->provider.prev_dis = &prev_dis_frame;
 
     prev_cap_frame = fdata;
-    prev_cap = &prev_cap_frame;
+    cf->provider.prev_cap = &prev_cap_frame;
 
     for(i = 0; i < n_rfilters; i++) {
         /* Run the read filter if we have one. */
@@ -1540,16 +1455,16 @@ open_failure_message(const char *filename, int err, gboolean for_writing)
 }
 
 static const nstime_t *
-raw_get_frame_ts(void *data _U_, guint32 frame_num)
+raw_get_frame_ts(struct packet_provider_data *prov, guint32 frame_num)
 {
-    if (ref && ref->num == frame_num)
-        return &ref->abs_ts;
+    if (prov->ref && prov->ref->num == frame_num)
+        return &prov->ref->abs_ts;
 
-    if (prev_dis && prev_dis->num == frame_num)
-        return &prev_dis->abs_ts;
+    if (prov->prev_dis && prov->prev_dis->num == frame_num)
+        return &prov->prev_dis->abs_ts;
 
-    if (prev_cap && prev_cap->num == frame_num)
-        return &prev_cap->abs_ts;
+    if (prov->prev_cap && prov->prev_cap->num == frame_num)
+        return &prov->prev_cap->abs_ts;
 
     return NULL;
 }
@@ -1557,15 +1472,14 @@ raw_get_frame_ts(void *data _U_, guint32 frame_num)
 static epan_t *
 raw_epan_new(capture_file *cf)
 {
-    epan_t *epan = epan_new();
-
-    epan->data = cf;
-    epan->get_frame_ts = raw_get_frame_ts;
-    epan->get_interface_name = cap_file_get_interface_name;
-    epan->get_interface_description = cap_file_get_interface_description;
-    epan->get_user_comment = NULL;
+    static const struct packet_provider_funcs funcs = {
+        raw_get_frame_ts,
+        cap_file_provider_get_interface_name,
+        cap_file_provider_get_interface_description,
+        NULL,
+    };
 
-    return epan;
+    return epan_new(&cf->provider, &funcs);
 }
 
 cf_status_t
@@ -1580,7 +1494,7 @@ raw_cf_open(capture_file *cf, const char *fname)
     epan_free(cf->epan);
     cf->epan = raw_epan_new(cf);
 
-    cf->wth = NULL;
+    cf->provider.wth = NULL;
     cf->f_datalen = 0; /* not used, but set it anyway */
 
     /* Set the file name because we need it to set the follow stream filter.
@@ -1599,12 +1513,11 @@ raw_cf_open(capture_file *cf, const char *fname)
     cf->count     = 0;
     cf->drops_known = FALSE;
     cf->drops     = 0;
-    cf->has_snap = FALSE;
-    cf->snap = WTAP_MAX_PACKET_SIZE;
+    cf->snap      = 0;
     nstime_set_zero(&cf->elapsed_time);
-    ref = NULL;
-    prev_dis = NULL;
-    prev_cap = NULL;
+    cf->provider.ref = NULL;
+    cf->provider.prev_dis = NULL;
+    cf->provider.prev_cap = NULL;
 
     return CF_OK;
 }