Make sure the packet length isn't > WTAP_MAX_PACKET_SIZE.
[metze/wireshark/wip.git] / wiretap / 5views.c
1 /* 5views.c
2  *
3  * Wiretap Library
4  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "config.h"
22 #include <errno.h>
23 #include <string.h>
24
25 #include "wtap-int.h"
26 #include "file_wrappers.h"
27 #include "5views.h"
28
29
30 typedef struct
31 {
32         guint32 Signature;
33         guint32 Size;           /* Total size of Header in bytes (included Signature) */
34         guint32 Version;        /* Identify version and so the format of this record */
35         guint32 DataSize;       /* Total size of data included in the Info Record (except the header size) */
36         guint32 FileType;       /* Type of the file */
37         guint32 Reserved[3];    /* Reserved for future use */
38 }t_5VW_Info_Header;
39
40 typedef struct
41 {
42         guint32 Type;   /* Id of the attribute */
43         guint16 Size;   /* Size of the data part of the attribute (not including header size) */
44         guint16 Nb;     /* Number of elements */
45 }t_5VW_Attributes_Header;
46
47
48 #define CST_5VW_INFO_HEADER_KEY         0xAAAAAAAAU             /* signature */
49
50 #define CST_5VW_INFO_RECORD_VERSION     0x00010000U             /* version */
51
52 #define CST_5VW_DECALE_FILE_TYPE        24
53 #define CST_5VW_SECTION_CAPTURES        0x08U
54 #define CST_5VW_CAPTURES_FILE           (CST_5VW_SECTION_CAPTURES << CST_5VW_DECALE_FILE_TYPE)          /* 0x08000000 */
55 #define CST_5VW_FLAT_FILE               0x10000000U
56 #define CST_5VW_CAPTURE_FILEID          (CST_5VW_FLAT_FILE | CST_5VW_CAPTURES_FILE)
57 #define CST_5VW_FAMILY_CAP_ETH          0x01U
58 #define CST_5VW_FAMILY_CAP_WAN          0x02U
59 #define CST_5VW_DECALE_FILE_FAMILY      12
60 #define CST_5VW_CAP_ETH                 (CST_5VW_FAMILY_CAP_ETH << CST_5VW_DECALE_FILE_FAMILY)  /* 0x00001000 */
61 #define CST_5VW_CAP_WAN                 (CST_5VW_FAMILY_CAP_WAN << CST_5VW_DECALE_FILE_FAMILY)  /* 0x00002000 */
62 #define CST_5VW_CAPTURE_ETH_FILEID      (CST_5VW_CAPTURE_FILEID | CST_5VW_CAP_ETH)
63 #define CST_5VW_CAPTURE_WAN_FILEID      (CST_5VW_CAPTURE_FILEID | CST_5VW_CAP_WAN)
64
65 #define CST_5VW_CAPTURE_FILE_TYPE_MASK  0xFF000000U
66
67 #define CST_5VW_FRAME_RECORD            0x00000000U
68 #define CST_5VW_RECORDS_HEADER_KEY      0x3333EEEEU
69
70 typedef struct
71 {
72         t_5VW_Info_Header       Info_Header;
73         t_5VW_Attributes_Header HeaderDateCreation;
74         guint32                 Time;
75         t_5VW_Attributes_Header HeaderNbFrames;
76         guint32                 TramesStockeesInFile;
77 }t_5VW_Capture_Header;
78
79 typedef struct
80 {
81         guint32 Key;                    /* 0x3333EEEE */
82         guint16 HeaderSize;             /* Actual size of this header in bytes (32) */
83         guint16 HeaderType;             /* Exact type of this header (0x4000) */
84         guint32 RecType;                /* Type of record */
85         guint32 RecSubType;             /* Subtype of record */
86         guint32 RecSize;                /* Size of one record */
87         guint32 RecNb;                  /* Number of records */
88         guint32 Utc;
89         guint32 NanoSecondes;
90         guint32 RecInfo;                /* Info about Alarm / Event / Frame captured */
91 }t_5VW_TimeStamped_Header;
92
93
94 #define CST_5VW_IA_CAP_INF_NB_TRAMES_STOCKEES   0x20000000U
95 #define CST_5VW_IA_DATE_CREATION                0x80000007U     /* Struct t_Attrib_Date_Create */
96 #define CST_5VW_TIMESTAMPED_HEADER_TYPE         0x4000U
97 #define CST_5VW_CAPTURES_RECORD         (CST_5VW_SECTION_CAPTURES << 28)        /* 0x80000000 */
98 #define CST_5VW_SYSTEM_RECORD           0x00000000U
99
100 static gboolean _5views_read(wtap *wth, int *err, gchar **err_info,
101     gint64 *data_offset);
102 static gboolean _5views_seek_read(wtap *wth, gint64 seek_off,
103     struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info);
104 static int _5views_read_header(wtap *wth, FILE_T fh, t_5VW_TimeStamped_Header *hdr,
105     struct wtap_pkthdr *phdr, int *err, gchar **err_info);
106
107 static gboolean _5views_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr, const guint8 *pd, int *err, gchar **err_info);
108 static gboolean _5views_dump_finish(wtap_dumper *wdh, int *err);
109
110
111 wtap_open_return_val
112 _5views_open(wtap *wth, int *err, gchar **err_info)
113 {
114         t_5VW_Capture_Header Capture_Header;
115         int encap = WTAP_ENCAP_UNKNOWN;
116
117         if (!wtap_read_bytes(wth->fh, &Capture_Header.Info_Header,
118             sizeof(t_5VW_Info_Header), err, err_info)) {
119                 if (*err != WTAP_ERR_SHORT_READ)
120                         return WTAP_OPEN_ERROR;
121                 return WTAP_OPEN_NOT_MINE;
122         }
123
124         /*      Check whether that's 5Views format or not */
125         if(Capture_Header.Info_Header.Signature != CST_5VW_INFO_HEADER_KEY)
126         {
127                 return WTAP_OPEN_NOT_MINE;
128         }
129
130         /* Check Version */
131         Capture_Header.Info_Header.Version =
132             pletoh32(&Capture_Header.Info_Header.Version);
133         switch (Capture_Header.Info_Header.Version) {
134
135         case CST_5VW_INFO_RECORD_VERSION:
136                 break;
137
138         default:
139                 *err = WTAP_ERR_UNSUPPORTED;
140                 *err_info = g_strdup_printf("5views: header version %u unsupported", Capture_Header.Info_Header.Version);
141                 return WTAP_OPEN_ERROR;
142         }
143
144         /* Check File Type */
145         Capture_Header.Info_Header.FileType =
146             pletoh32(&Capture_Header.Info_Header.FileType);
147         if((Capture_Header.Info_Header.FileType & CST_5VW_CAPTURE_FILE_TYPE_MASK) != CST_5VW_CAPTURE_FILEID)
148         {
149                 *err = WTAP_ERR_UNSUPPORTED;
150                 *err_info = g_strdup_printf("5views: file is not a capture file (filetype is %u)", Capture_Header.Info_Header.Version);
151                 return WTAP_OPEN_ERROR;
152         }
153
154         /* Check possible Encap */
155         switch (Capture_Header.Info_Header.FileType) {
156         case CST_5VW_CAPTURE_ETH_FILEID:
157                 encap = WTAP_ENCAP_ETHERNET;
158                 break;
159 /*      case CST_5VW_CAPTURE_WAN_FILEID:
160                 break;
161 */
162         default:
163                 *err = WTAP_ERR_UNSUPPORTED;
164                 *err_info = g_strdup_printf("5views: network type %u unknown or unsupported",
165                     Capture_Header.Info_Header.FileType);
166                 return WTAP_OPEN_ERROR;
167         }
168
169         /* read the remaining header information */
170         if (!wtap_read_bytes(wth->fh, &Capture_Header.HeaderDateCreation,
171             sizeof (t_5VW_Capture_Header) - sizeof(t_5VW_Info_Header), err, err_info))
172                 return WTAP_OPEN_ERROR;
173
174         /* This is a 5views capture file */
175         wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_5VIEWS;
176         wth->subtype_read = _5views_read;
177         wth->subtype_seek_read = _5views_seek_read;
178         wth->file_encap = encap;
179         wth->snapshot_length = 0;       /* not available in header */
180         wth->file_tsprec = WTAP_TSPREC_NSEC;
181
182         return WTAP_OPEN_MINE;
183 }
184
185 /* Read the next packet */
186 static gboolean
187 _5views_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
188 {
189         t_5VW_TimeStamped_Header TimeStamped_Header;
190
191         /*
192          * Keep reading until we see a record with a subtype of
193          * CST_5VW_FRAME_RECORD.
194          */
195         do
196         {
197                 *data_offset = file_tell(wth->fh);
198
199                 /* Read record header. */
200                 if (!_5views_read_header(wth, wth->fh, &TimeStamped_Header,
201                     &wth->phdr, err, err_info))
202                         return FALSE;
203
204                 if (TimeStamped_Header.RecSubType == CST_5VW_FRAME_RECORD) {
205                         /*
206                          * OK, this is a packet.
207                          */
208                         break;
209                 }
210
211                 /*
212                  * Not a packet - skip to the next record.
213                  */
214                 if (file_seek(wth->fh, TimeStamped_Header.RecSize, SEEK_CUR, err) == -1)
215                         return FALSE;
216         } while (1);
217
218         if (wth->phdr.caplen > WTAP_MAX_PACKET_SIZE) {
219                 /*
220                  * Probably a corrupt capture file; don't blow up trying
221                  * to allocate space for an immensely-large packet.
222                  */
223                 *err = WTAP_ERR_BAD_FILE;
224                 *err_info = g_strdup_printf("5views: File has %u-byte packet, bigger than maximum of %u",
225                     wth->phdr.caplen, WTAP_MAX_PACKET_SIZE);
226                 return FALSE;
227         }
228
229         return wtap_read_packet_bytes(wth->fh, wth->frame_buffer,
230             wth->phdr.caplen, err, err_info);
231 }
232
233 static gboolean
234 _5views_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr,
235     Buffer *buf, int *err, gchar **err_info)
236 {
237         t_5VW_TimeStamped_Header TimeStamped_Header;
238
239         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
240                 return FALSE;
241
242         /*
243          * Read the header.
244          */
245         if (!_5views_read_header(wth, wth->random_fh, &TimeStamped_Header,
246             phdr, err, err_info)) {
247                 if (*err == 0)
248                         *err = WTAP_ERR_SHORT_READ;
249                 return FALSE;
250         }
251
252         /*
253          * Read the packet data.
254          */
255         return wtap_read_packet_bytes(wth->random_fh, buf, phdr->caplen,
256             err, err_info);
257 }
258
259 /* Read the header of the next packet.  Return TRUE on success, FALSE
260    on error. */
261 static gboolean
262 _5views_read_header(wtap *wth, FILE_T fh, t_5VW_TimeStamped_Header *hdr,
263     struct wtap_pkthdr *phdr, int *err, gchar **err_info)
264 {
265         /* Read record header. */
266         if (!wtap_read_bytes_or_eof(fh, hdr, (unsigned int)sizeof(t_5VW_TimeStamped_Header),
267             err, err_info))
268                 return FALSE;
269
270         hdr->Key = pletoh32(&hdr->Key);
271         if (hdr->Key != CST_5VW_RECORDS_HEADER_KEY) {
272                 *err = WTAP_ERR_BAD_FILE;
273                 *err_info = g_strdup_printf("5views: Time-stamped header has bad key value 0x%08X",
274                     hdr->Key);
275                 return FALSE;
276         }
277
278         hdr->RecSubType = pletoh32(&hdr->RecSubType);
279         hdr->RecSize = pletoh32(&hdr->RecSize);
280         hdr->Utc = pletoh32(&hdr->Utc);
281         hdr->NanoSecondes = pletoh32(&hdr->NanoSecondes);
282
283         phdr->rec_type = REC_TYPE_PACKET;
284         phdr->presence_flags = WTAP_HAS_TS;
285         phdr->ts.secs = hdr->Utc;
286         phdr->ts.nsecs = hdr->NanoSecondes;
287         phdr->caplen = hdr->RecSize;
288         phdr->len = hdr->RecSize;
289
290         switch (wth->file_encap) {
291
292         case WTAP_ENCAP_ETHERNET:
293                 /* We assume there's no FCS in this frame. */
294                 phdr->pseudo_header.eth.fcs_len = 0;
295                 break;
296         }
297
298         return TRUE;
299 }
300
301 typedef struct {
302         guint32 nframes;
303 } _5views_dump_t;
304
305 static const int wtap_encap[] = {
306         -1,             /* WTAP_ENCAP_UNKNOWN -> unsupported */
307         CST_5VW_CAPTURE_ETH_FILEID,             /* WTAP_ENCAP_ETHERNET -> Ethernet */
308 };
309 #define NUM_WTAP_ENCAPS (sizeof wtap_encap / sizeof wtap_encap[0])
310
311 /* Returns 0 if we could write the specified encapsulation type,
312    an error indication otherwise. */
313 int _5views_dump_can_write_encap(int encap)
314 {
315         /* Per-packet encapsulations aren't supported. */
316         if (encap == WTAP_ENCAP_PER_PACKET)
317                 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
318
319         if (encap < 0 || (unsigned int) encap >= NUM_WTAP_ENCAPS || wtap_encap[encap] == -1)
320                 return WTAP_ERR_UNWRITABLE_ENCAP;
321
322         return 0;
323 }
324
325 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
326    failure */
327 gboolean _5views_dump_open(wtap_dumper *wdh, int *err)
328 {
329         _5views_dump_t *_5views;
330
331         /* We can't fill in all the fields in the file header, as we
332            haven't yet written any packets.  As we'll have to rewrite
333            the header when we've written out all the packets, we just
334            skip over the header for now. */
335         if (wtap_dump_file_seek(wdh, sizeof(t_5VW_Capture_Header), SEEK_SET, err) == -1)
336                 return FALSE;
337
338         /* This is a 5Views file */
339         wdh->subtype_write = _5views_dump;
340         wdh->subtype_finish = _5views_dump_finish;
341         _5views = (_5views_dump_t *)g_malloc(sizeof(_5views_dump_t));
342         wdh->priv = (void *)_5views;
343         _5views->nframes = 0;
344
345         return TRUE;
346 }
347
348 /* Write a record for a packet to a dump file.
349    Returns TRUE on success, FALSE on failure. */
350 static gboolean _5views_dump(wtap_dumper *wdh,
351         const struct wtap_pkthdr *phdr,
352         const guint8 *pd, int *err, gchar **err_info _U_)
353 {
354         _5views_dump_t *_5views = (_5views_dump_t *)wdh->priv;
355         t_5VW_TimeStamped_Header HeaderFrame;
356
357         /* We can only write packet records. */
358         if (phdr->rec_type != REC_TYPE_PACKET) {
359                 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
360                 return FALSE;
361         }
362
363         /* Don't write out something bigger than we can read. */
364         if (phdr->caplen > WTAP_MAX_PACKET_SIZE) {
365                 *err = WTAP_ERR_PACKET_TOO_LARGE;
366                 return FALSE;
367         }
368
369         /* Frame Header */
370         /* constant fields */
371         HeaderFrame.Key = GUINT32_TO_LE(CST_5VW_RECORDS_HEADER_KEY);
372         HeaderFrame.HeaderSize = GUINT16_TO_LE(sizeof(t_5VW_TimeStamped_Header));
373         HeaderFrame.HeaderType = GUINT16_TO_LE(CST_5VW_TIMESTAMPED_HEADER_TYPE);
374         HeaderFrame.RecType = GUINT32_TO_LE(CST_5VW_CAPTURES_RECORD | CST_5VW_SYSTEM_RECORD);
375         HeaderFrame.RecSubType = GUINT32_TO_LE(CST_5VW_FRAME_RECORD);
376         HeaderFrame.RecNb = GUINT32_TO_LE(1);
377
378         /* record-dependent fields */
379         HeaderFrame.Utc = GUINT32_TO_LE(phdr->ts.secs);
380         HeaderFrame.NanoSecondes = GUINT32_TO_LE(phdr->ts.nsecs);
381         HeaderFrame.RecSize = GUINT32_TO_LE(phdr->len);
382         HeaderFrame.RecInfo = GUINT32_TO_LE(0);
383
384         /* write the record header */
385         if (!wtap_dump_file_write(wdh, &HeaderFrame,
386             sizeof(t_5VW_TimeStamped_Header), err))
387                 return FALSE;
388
389         /* write the data */
390         if (!wtap_dump_file_write(wdh, pd, phdr->caplen, err))
391                 return FALSE;
392
393         _5views->nframes ++;
394
395         return TRUE;
396 }
397
398 static gboolean _5views_dump_finish(wtap_dumper *wdh, int *err)
399 {
400         _5views_dump_t *_5views = (_5views_dump_t *)wdh->priv;
401         t_5VW_Capture_Header file_hdr;
402
403         if (wtap_dump_file_seek(wdh, 0, SEEK_SET, err) == -1)
404                 return FALSE;
405
406         /* fill in the Info_Header */
407         file_hdr.Info_Header.Signature = GUINT32_TO_LE(CST_5VW_INFO_HEADER_KEY);
408         file_hdr.Info_Header.Size = GUINT32_TO_LE(sizeof(t_5VW_Info_Header));   /* Total size of Header in bytes (included Signature) */
409         file_hdr.Info_Header.Version = GUINT32_TO_LE(CST_5VW_INFO_RECORD_VERSION); /* Identify version and so the format of this record */
410         file_hdr.Info_Header.DataSize = GUINT32_TO_LE(sizeof(t_5VW_Attributes_Header)
411                                         + sizeof(guint32)
412                                         + sizeof(t_5VW_Attributes_Header)
413                                         + sizeof(guint32));
414                                         /* Total size of data included in the Info Record (except the header size) */
415         file_hdr.Info_Header.FileType = GUINT32_TO_LE(wtap_encap[wdh->encap]);  /* Type of the file */
416         file_hdr.Info_Header.Reserved[0] = 0;   /* Reserved for future use */
417         file_hdr.Info_Header.Reserved[1] = 0;   /* Reserved for future use */
418         file_hdr.Info_Header.Reserved[2] = 0;   /* Reserved for future use */
419
420         /* fill in the HeaderDateCreation */
421         file_hdr.HeaderDateCreation.Type = GUINT32_TO_LE(CST_5VW_IA_DATE_CREATION);     /* Id of the attribute */
422         file_hdr.HeaderDateCreation.Size = GUINT16_TO_LE(sizeof(guint32));      /* Size of the data part of the attribute (not including header size) */
423         file_hdr.HeaderDateCreation.Nb = GUINT16_TO_LE(1);                      /* Number of elements */
424
425         /* fill in the Time field */
426 #ifdef _WIN32
427         _tzset();
428 #endif
429         file_hdr.Time = GUINT32_TO_LE(time(NULL));
430
431         /* fill in the Time field */
432         file_hdr.HeaderNbFrames.Type = GUINT32_TO_LE(CST_5VW_IA_CAP_INF_NB_TRAMES_STOCKEES);    /* Id of the attribute */
433         file_hdr.HeaderNbFrames.Size = GUINT16_TO_LE(sizeof(guint32));  /* Size of the data part of the attribute (not including header size) */
434         file_hdr.HeaderNbFrames.Nb = GUINT16_TO_LE(1);                  /* Number of elements */
435
436         /* fill in the number of frames saved */
437         file_hdr.TramesStockeesInFile = GUINT32_TO_LE(_5views->nframes);
438
439         /* Write the file header. */
440         if (!wtap_dump_file_write(wdh, &file_hdr, sizeof(t_5VW_Capture_Header),
441             err))
442                 return FALSE;
443
444         return TRUE;
445 }
446
447 /*
448  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
449  *
450  * Local variables:
451  * c-basic-offset: 8
452  * tab-width: 8
453  * indent-tabs-mode: t
454  * End:
455  *
456  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
457  * :indentSize=8:tabSize=8:noTabs=false:
458  */