tests: add regression tests for Follow TCP Stream
[metze/wireshark/wip.git] / wiretap / ruby_marshal.c
1 /* ruby_marshal.c
2  *
3  * Routines for reading a binary file containing a ruby marshal object
4  *
5  * Copyright 2018, Dario Lombardo <lomato@gmail.com>
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  */
9
10 #include "config.h"
11
12 #include <string.h>
13
14 #include "wtap-int.h"
15 #include "file_wrappers.h"
16
17 #include "ruby_marshal.h"
18
19 /*
20  * Impose a not-too-large limit on the maximum file size, to avoid eating
21  * up 99% of the (address space, swap partition, disk space for swap/page
22  * files); if we were to return smaller chunks and let the dissector do
23  * reassembly, it would *still* have to allocate a buffer the size of
24  * the file, so it's not as if we'd neve try to allocate a buffer the
25  * size of the file.
26  *
27  * For now, go for 50MB.
28  */
29 #define MAX_FILE_SIZE (50*1024*1024)
30
31 static gboolean ruby_marshal_read_file(wtap *wth, FILE_T fh, wtap_rec *rec,
32     Buffer *buf, int *err, gchar **err_info)
33 {
34     gint64 file_size;
35     int packet_size;
36
37     if ((file_size = wtap_file_size(wth, err)) == -1)
38         return FALSE;
39
40     if (file_size > MAX_FILE_SIZE) {
41         /*
42          * Don't blow up trying to allocate space for an
43          * immensely-large file.
44          */
45         *err = WTAP_ERR_BAD_FILE;
46         *err_info = g_strdup_printf("ruby_marshal: File has %" G_GINT64_MODIFIER "d-byte packet, bigger than maximum of %u",
47             file_size, MAX_FILE_SIZE);
48         return FALSE;
49     }
50     packet_size = (int)file_size;
51
52     rec->rec_type = REC_TYPE_PACKET;
53     rec->presence_flags = 0;
54
55     rec->rec_header.packet_header.caplen = packet_size;
56     rec->rec_header.packet_header.len = packet_size;
57
58     rec->ts.secs = 0;
59     rec->ts.nsecs = 0;
60
61     return wtap_read_packet_bytes(fh, buf, packet_size, err, err_info);
62 }
63
64 static gboolean ruby_marshal_seek_read(wtap *wth, gint64 seek_off, wtap_rec *rec, Buffer *buf,
65     int *err, gchar **err_info)
66 {
67     /* there is only one packet */
68     if (seek_off > 0) {
69         *err = 0;
70         return FALSE;
71     }
72
73     if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
74         return FALSE;
75
76     return ruby_marshal_read_file(wth, wth->random_fh, rec, buf, err, err_info);
77 }
78
79 static gboolean ruby_marshal_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
80 {
81     gint64 offset;
82
83     *err = 0;
84
85     offset = file_tell(wth->fh);
86
87     /* there is only ever one packet */
88     if (offset != 0)
89         return FALSE;
90
91     *data_offset = offset;
92
93     return ruby_marshal_read_file(wth, wth->fh, &wth->rec, wth->rec_data, err, err_info);
94 }
95
96 static gboolean is_ruby_marshal(const guint8* filebuf)
97 {
98     if (filebuf[0] != RUBY_MARSHAL_MAJOR)
99         return FALSE;
100     if (filebuf[1] != RUBY_MARSHAL_MINOR)
101         return FALSE;
102     switch (filebuf[2]) {
103         case '0':
104         case 'T':
105         case 'F':
106         case 'i':
107         case ':':
108         case '"':
109         case 'I':
110         case '[':
111         case '{':
112         case 'f':
113         case 'c':
114         case 'm':
115         case 'S':
116         case '/':
117         case 'o':
118         case 'C':
119         case 'e':
120         case ';':
121         case '@':
122             return TRUE;
123             break;
124         default:
125             return FALSE;
126     }
127 }
128
129 wtap_open_return_val ruby_marshal_open(wtap *wth, int *err, gchar **err_info)
130 {
131     guint8* filebuf;
132     int bytes_read;
133
134     filebuf = (guint8*)g_malloc0(MAX_FILE_SIZE);
135     if (!filebuf)
136         return WTAP_OPEN_ERROR;
137
138     bytes_read = file_read(filebuf, MAX_FILE_SIZE, wth->fh);
139     if (bytes_read < 0) {
140         /* Read error. */
141         *err = file_error(wth->fh, err_info);
142         g_free(filebuf);
143         return WTAP_OPEN_ERROR;
144     }
145     if (bytes_read == 0) {
146         /* empty file, not *anybody's* */
147         g_free(filebuf);
148         return WTAP_OPEN_NOT_MINE;
149     }
150
151     if (!is_ruby_marshal(filebuf)) {
152         g_free(filebuf);
153         return WTAP_OPEN_NOT_MINE;
154     }
155
156     if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
157         g_free(filebuf);
158         return WTAP_OPEN_ERROR;
159     }
160
161     wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_RUBY_MARSHAL;
162     wth->file_encap = WTAP_ENCAP_RUBY_MARSHAL;
163     wth->file_tsprec = WTAP_TSPREC_SEC;
164     wth->subtype_read = ruby_marshal_read;
165     wth->subtype_seek_read = ruby_marshal_seek_read;
166     wth->snapshot_length = 0;
167
168     g_free(filebuf);
169     return WTAP_OPEN_MINE;
170 }
171
172 /*
173  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
174  *
175  * Local variables:
176  * c-basic-offset: 4
177  * tab-width: 8
178  * indent-tabs-mode: nil
179  * End:
180  *
181  * vi: set shiftwidth=4 tabstop=8 expandtab:
182  * :indentSize=4:tabSize=8:noTabs=true:
183  */