ca0ee5b19a1c9b3b8d541bd6bdb536967ea0f9cd
[obnox/wireshark/wip.git] / wiretap / file.c
1 /* file.c
2  *
3  * $Id: file.c,v 1.72 2001/10/28 01:51:46 guy Exp $
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@xiexie.org>
7  * 
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  * 
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  */
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #ifdef HAVE_FCNTL_H
32 #include <fcntl.h>
33 #endif
34
35 #ifdef HAVE_SYS_STAT_H
36 #include <sys/stat.h>
37 #endif
38
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42
43 #include <errno.h>
44
45 #ifdef HAVE_IO_H
46 #include <io.h> /* open/close on win32 */
47 #endif
48
49 #include "wtap-int.h"
50 #include "file_wrappers.h"
51 #include "buffer.h"
52 #include "lanalyzer.h"
53 #include "ngsniffer.h"
54 #include "radcom.h"
55 #include "ascend.h"
56 #include "nettl.h"
57 #include "libpcap.h"
58 #include "snoop.h"
59 #include "iptrace.h"
60 #include "netmon.h"
61 #include "netxray.h"
62 #include "toshiba.h"
63 #include "i4btrace.h"
64 #include "csids.h"
65 #include "pppdump.h"
66 #include "etherpeek.h"
67 #include "vms.h"
68 #include "dbs-etherwatch.h"
69
70 /* The open_file_* routines should return:
71  *
72  *      -1 on an I/O error;
73  *
74  *      1 if the file they're reading is one of the types it handles;
75  *
76  *      0 if the file they're reading isn't the type they're checking for.
77  *
78  * If the routine handles this type of file, it should set the "file_type"
79  * field in the "struct wtap" to the type of the file.
80  *
81  * XXX - I need to drag my damn ANSI C spec in to figure out how to
82  * declare a "const" array of pointers to functions; putting "const"
83  * right after "static" isn't the right answer, at least according
84  * to GCC, which whines if I do that.
85  *
86  * Put the trace files that are merely saved telnet-sessions last, since it's
87  * possible that you could have captured someone a router telnet-session
88  * using another tool. So, a libpcap trace of an toshiba "snoop" session
89  * should be discovered as a libpcap file, not a toshiba file.
90  */
91
92 static int (*open_routines[])(wtap *, int *) = {
93         /* Files that have magic bytes in fixed locations. These
94          * are easy to identify.
95          */
96         libpcap_open,
97         lanalyzer_open,
98         ngsniffer_open,
99         snoop_open,
100         iptrace_open,
101         netmon_open,
102         netxray_open,
103         radcom_open,
104         nettl_open,
105         pppdump_open,
106         etherpeek_open,
107
108         /* Files whose magic headers are in text *somewhere* in the
109          * file (usually because the trace is just a saved copy of
110          * the telnet session). 
111          */
112         ascend_open,
113         toshiba_open,
114         i4btrace_open,
115         csids_open,
116         vms_open,
117         dbs_etherwatch_open,
118 };
119
120 #define N_FILE_TYPES    (sizeof open_routines / sizeof open_routines[0])
121
122 int wtap_def_seek_read(wtap *wth, long seek_off,
123         union wtap_pseudo_header *pseudo_header, guint8 *pd, int len)
124 {
125         file_seek(wth->random_fh, seek_off, SEEK_SET);
126
127         return file_read(pd, sizeof(guint8), len, wth->random_fh);
128 }
129
130 /*
131  * Visual C++ on Win32 systems doesn't define these.  (Old UNIX systems don't
132  * define them either.)
133  *
134  * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
135  */
136 #ifndef S_ISREG
137 #define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
138 #endif
139 #ifndef S_IFIFO
140 #define S_IFIFO _S_IFIFO
141 #endif
142 #ifndef S_ISFIFO
143 #define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
144 #endif
145 #ifndef S_ISDIR
146 #define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
147 #endif
148
149 /* Opens a file and prepares a wtap struct.
150    If "do_random" is TRUE, it opens the file twice; the second open
151    allows the application to do random-access I/O without moving
152    the seek offset for sequential I/O, which is used by Ethereal
153    so that it can do sequential I/O to a capture file that's being
154    written to as new packets arrive independently of random I/O done
155    to display protocol trees for packets when they're selected. */
156 wtap* wtap_open_offline(const char *filename, int *err, gboolean do_random)
157 {
158         struct stat statb;
159         wtap    *wth;
160         unsigned int    i;
161
162         /* First, make sure the file is valid */
163         if (stat(filename, &statb) < 0) {
164                 *err = errno;
165                 return NULL;
166         }
167         if (! S_ISREG(statb.st_mode) && ! S_ISFIFO(statb.st_mode)) {
168                 if (S_ISDIR(statb.st_mode))
169                         *err = EISDIR;
170                 else
171                         *err = WTAP_ERR_NOT_REGULAR_FILE;
172                 return NULL;
173         }
174
175         errno = ENOMEM;
176         wth = g_malloc(sizeof(wtap));
177         if (wth == NULL) {
178                 *err = errno;
179                 return NULL;
180         }
181
182 /* Win32 needs the O_BINARY flag for open() */
183 #ifndef O_BINARY
184 #define O_BINARY        0
185 #endif
186
187         /* Open the file */
188         errno = WTAP_ERR_CANT_OPEN;
189         wth->fd = open(filename, O_RDONLY|O_BINARY);
190         if (wth->fd < 0) {
191                 *err = errno;
192                 g_free(wth);
193                 return NULL;
194         }
195         if (!(wth->fh = filed_open(wth->fd, "rb"))) {
196                 *err = errno;
197                 g_free(wth);
198                 return NULL;
199         }
200
201         if (do_random) {
202                 if (!(wth->random_fh = file_open(filename, "rb"))) {
203                         *err = errno;
204                         file_close(wth->fh);
205                         g_free(wth);
206                         return NULL;
207                 }
208         } else
209                 wth->random_fh = NULL;
210
211         /* initialization */
212         wth->file_encap = WTAP_ENCAP_UNKNOWN;
213         wth->data_offset = 0;
214         wth->subtype_sequential_close = NULL;
215         wth->subtype_close = NULL;
216
217         /* Try all file types */
218         for (i = 0; i < N_FILE_TYPES; i++) {
219                 /* Seek back to the beginning of the file; the open routine
220                    for the previous file type may have left the file
221                    position somewhere other than the beginning, and the
222                    open routine for this file type will probably want
223                    to start reading at the beginning.
224
225                    Initialize the data offset while we're at it. */
226                 file_seek(wth->fh, 0, SEEK_SET);
227                 wth->data_offset = 0;
228                 switch ((*open_routines[i])(wth, err)) {
229
230                 case -1:
231                         /* I/O error - give up */
232                         if (wth->random_fh != NULL)
233                                 file_close(wth->random_fh);
234                         file_close(wth->fh);
235                         g_free(wth);
236                         return NULL;
237
238                 case 0:
239                         /* No I/O error, but not that type of file */
240                         break;
241
242                 case 1:
243                         /* We found the file type */
244                         goto success;
245                 }
246         }
247
248         /* Well, it's not one of the types of file we know about. */
249         if (wth->random_fh != NULL)
250                 file_close(wth->random_fh);
251         file_close(wth->fh);
252         g_free(wth);
253         *err = WTAP_ERR_FILE_UNKNOWN_FORMAT;
254         return NULL;
255
256 success:
257         wth->frame_buffer = g_malloc(sizeof(struct Buffer));
258         buffer_init(wth->frame_buffer, 1500);
259         return wth;
260 }
261
262 /* Table of the file types we know about. */
263 static const struct file_type_info {
264         const char *name;
265         const char *short_name;
266         int     (*can_write_encap)(int, int);
267         int     (*dump_open)(wtap_dumper *, int *);
268 } dump_open_table[WTAP_NUM_FILE_TYPES] = {
269         /* WTAP_FILE_UNKNOWN */
270         { NULL, NULL,
271           NULL, NULL },
272
273         /* WTAP_FILE_WTAP */
274         { "Wiretap (Ethereal)", NULL,
275           NULL, NULL },
276
277         /* WTAP_FILE_PCAP */
278         { "libpcap (tcpdump, Ethereal, etc.)", "libpcap",
279           libpcap_dump_can_write_encap, libpcap_dump_open },
280
281         /* WTAP_FILE_PCAP_SS990417 */
282         { "Red Hat Linux 6.1 libpcap (tcpdump)", "rh6_1libpcap",
283           libpcap_dump_can_write_encap, libpcap_dump_open },
284
285         /* WTAP_FILE_PCAP_SS990915 */
286         { "SuSE Linux 6.3 libpcap (tcpdump)", "suse6_3libpcap",
287           libpcap_dump_can_write_encap, libpcap_dump_open },
288
289         /* WTAP_FILE_PCAP_SS991029 */
290         { "modified libpcap (tcpdump)", "modlibpcap",
291           libpcap_dump_can_write_encap, libpcap_dump_open },
292
293         /* WTAP_FILE_PCAP_NOKIA */
294         { "Nokia libpcap (tcpdump)", "nokialibpcap",
295           libpcap_dump_can_write_encap, libpcap_dump_open },
296
297         /* WTAP_FILE_LANALYZER */
298         { "Novell LANalyzer", NULL,
299           NULL, NULL },
300
301         /* WTAP_FILE_NGSNIFFER_UNCOMPRESSED */
302         { "Network Associates Sniffer (DOS-based)", "ngsniffer",
303           ngsniffer_dump_can_write_encap, ngsniffer_dump_open },
304
305         /* WTAP_FILE_NGSNIFFER_COMPRESSED */
306         { "Network Associates Sniffer (DOS-based), compressed", "ngsniffer_comp",
307           NULL, NULL },
308
309         /* WTAP_FILE_SNOOP */
310         { "Sun snoop", "snoop",
311           snoop_dump_can_write_encap, snoop_dump_open },
312
313         /* WTAP_FILE_IPTRACE_1_0 */
314         { "AIX iptrace 1.0", NULL,
315           NULL, NULL },
316
317         /* WTAP_FILE_IPTRACE_2_0 */
318         { "AIX iptrace 2.0", NULL,
319           NULL, NULL },
320
321         /* WTAP_FILE_NETMON_1_x */
322         { "Microsoft Network Monitor 1.x", "netmon1",
323           netmon_dump_can_write_encap, netmon_dump_open },
324
325         /* WTAP_FILE_NETMON_2_x */
326         { "Microsoft Network Monitor 2.x", "netmon2",
327           netmon_dump_can_write_encap, netmon_dump_open },
328
329         /* WTAP_FILE_NETXRAY_1_0 */
330         { "Cinco Networks NetXRay", NULL,
331           NULL, NULL },
332
333         /* WTAP_FILE_NETXRAY_1_1 */
334         { "Network Associates Sniffer (Windows-based) 1.1", "ngwsniffer_1_1",
335           netxray_dump_can_write_encap, netxray_dump_open_1_1 },
336
337         /* WTAP_FILE_NETXRAY_2_00x */
338         { "Network Associates Sniffer (Windows-based) 2.00x", NULL,
339           NULL, NULL },
340
341         /* WTAP_FILE_RADCOM */
342         { "RADCOM WAN/LAN analyzer", NULL,
343           NULL, NULL },
344
345         /* WTAP_FILE_ASCEND */
346         { "Lucent/Ascend access server trace", NULL,
347           NULL, NULL },
348
349         /* WTAP_FILE_NETTL */
350         { "HP-UX nettl trace", NULL,
351           NULL, NULL },
352
353         /* WTAP_FILE_TOSHIBA */
354         { "Toshiba Compact ISDN Router snoop trace", NULL,
355           NULL, NULL },
356
357         /* WTAP_FILE_I4BTRACE */
358         { "I4B ISDN trace", NULL,
359           NULL, NULL },
360
361         /* WTAP_FILE_CSIDS */
362         { "CSIDS IPLog", NULL,
363           NULL, NULL },
364
365         /* WTAP_FILE_PPPDUMP */
366         { "pppd log (pppdump format)", NULL,
367           NULL, NULL },
368
369         /* WTAP_FILE_ETHERPEEK_MAC_V56 */
370         { "Etherpeek trace (Macintosh V5 & V6)", NULL,
371           NULL, NULL },
372
373         /* WTAP_FILE_ETHERPEEK_MAC_V7 */
374         { "Etherpeek trace (Macintosh V7)", NULL,
375           NULL, NULL },
376
377         /* WTAP_FILE_VMS */
378         { "TCPIPtrace (VMS)", NULL,
379           NULL, NULL},
380
381         /* WTAP_FILE_DBS_ETHERWATCH */
382         { "DBS Etherwatch (VMS)", NULL,
383           NULL, NULL},
384 };
385
386 /* Name that should be somewhat descriptive. */
387 const char *wtap_file_type_string(int filetype)
388 {
389         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES) {
390                 g_error("Unknown capture file type %d", filetype);
391                 return NULL;
392         } else
393                 return dump_open_table[filetype].name;
394 }
395
396 /* Name to use in, say, a command-line flag specifying the type. */
397 const char *wtap_file_type_short_string(int filetype)
398 {
399         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES)
400                 return NULL;
401         else
402                 return dump_open_table[filetype].short_name;
403 }
404
405 /* Translate a short name to a capture file type. */
406 int wtap_short_string_to_file_type(const char *short_name)
407 {
408         int filetype;
409
410         for (filetype = 0; filetype < WTAP_NUM_FILE_TYPES; filetype++) {
411                 if (dump_open_table[filetype].short_name != NULL &&
412                     strcmp(short_name, dump_open_table[filetype].short_name) == 0)
413                         return filetype;
414         }
415         return -1;      /* no such file type, or we can't write it */
416 }
417
418 gboolean wtap_dump_can_open(int filetype)
419 {
420         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES
421             || dump_open_table[filetype].dump_open == NULL)
422                 return FALSE;
423
424         return TRUE;
425 }
426
427 gboolean wtap_dump_can_write_encap(int filetype, int encap)
428 {
429         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES
430             || dump_open_table[filetype].can_write_encap == NULL)
431                 return FALSE;
432
433         if ((*dump_open_table[filetype].can_write_encap)(filetype, encap) != 0)
434                 return FALSE;
435
436         return TRUE;
437 }
438
439 static gboolean wtap_dump_open_check(int filetype, int encap, int *err);
440 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
441     int *err);
442 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype,
443     int encap, int snaplen, int *err);
444
445 wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap,
446                                 int snaplen, int *err)
447 {
448         wtap_dumper *wdh;
449         FILE *fh;
450
451         /* Check whether we can open a capture file with that file type
452            and that encapsulation. */
453         if (!wtap_dump_open_check(filetype, encap, err))
454                 return NULL;
455
456         /* Allocate a data structure for the output stream. */
457         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, err);
458         if (wdh == NULL)
459                 return NULL;    /* couldn't allocate it */
460
461         /* In case "fopen()" fails but doesn't set "errno", set "errno"
462            to a generic "the open failed" error. */
463         errno = WTAP_ERR_CANT_OPEN;
464         fh = fopen(filename, "wb");
465         if (fh == NULL) {
466                 *err = errno;
467                 return NULL;    /* can't create file */
468         }
469         wdh->fh = fh;
470
471         if (!wtap_dump_open_finish(wdh, filetype, encap, snaplen, err)) {
472                 /* Get rid of the file we created; we couldn't finish
473                    opening it. */
474                 unlink(filename);
475                 return NULL;
476         }
477         return wdh;
478 }
479
480 wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen,
481                                 int *err)
482 {
483         wtap_dumper *wdh;
484         FILE *fh;
485
486         /* Check whether we can open a capture file with that file type
487            and that encapsulation. */
488         if (!wtap_dump_open_check(filetype, encap, err))
489                 return NULL;
490
491         /* Allocate a data structure for the output stream. */
492         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, err);
493         if (wdh == NULL)
494                 return NULL;    /* couldn't allocate it */
495
496         /* In case "fopen()" fails but doesn't set "errno", set "errno"
497            to a generic "the open failed" error. */
498         errno = WTAP_ERR_CANT_OPEN;
499         fh = fdopen(fd, "wb");
500         if (fh == NULL) {
501                 *err = errno;
502                 return NULL;    /* can't create standard I/O stream */
503         }
504         wdh->fh = fh;
505
506         if (!wtap_dump_open_finish(wdh, filetype, encap, snaplen, err))
507                 return NULL;
508         return wdh;
509 }
510
511 static gboolean wtap_dump_open_check(int filetype, int encap, int *err)
512 {
513         if (!wtap_dump_can_open(filetype)) {
514                 /* Invalid type, or type we don't know how to write. */
515                 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
516                 return FALSE;
517         }
518
519         /* OK, we know how to write that type; can we write the specified
520            encapsulation type? */
521         *err = (*dump_open_table[filetype].can_write_encap)(filetype, encap);
522         if (*err != 0)
523                 return FALSE;
524
525         /* All systems go! */
526         return TRUE;
527 }
528
529 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
530                                         int *err)
531 {
532         wtap_dumper *wdh;
533
534         wdh = g_malloc(sizeof (wtap_dumper));
535         if (wdh == NULL) {
536                 *err = errno;
537                 return NULL;
538         }
539         wdh->fh = NULL;
540         wdh->file_type = filetype;
541         wdh->snaplen = snaplen;
542         wdh->encap = encap;
543         wdh->dump.opaque = NULL;
544         wdh->subtype_write = NULL;
545         wdh->subtype_close = NULL;
546         return wdh;
547 }
548
549 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype,
550                                       int encap, int snaplen, int *err)
551 {
552         /* Now try to open the file for writing. */
553         if (!(*dump_open_table[filetype].dump_open)(wdh, err)) {
554                 /* The attempt failed.  Close the stream for the file.
555                    NOTE: this means the FD handed to "wtap_dump_fdopen()"
556                    will be closed if the open fails. */
557                 fclose(wdh->fh);
558
559                 /* Now free up the dumper handle. */
560                 g_free(wdh);
561                 return FALSE;
562         }
563
564         return TRUE;    /* success! */
565 }
566
567 FILE* wtap_dump_file(wtap_dumper *wdh)
568 {
569         return wdh->fh;
570 }
571
572 gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
573     const union wtap_pseudo_header *pseudo_header, const u_char *pd, int *err)
574 {
575         return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err);
576 }
577
578 gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
579 {
580         gboolean ret = TRUE;
581
582         if (wdh->subtype_close != NULL) {
583                 /* There's a close routine for this dump stream. */
584                 if (!(wdh->subtype_close)(wdh, err))
585                         ret = FALSE;
586         }
587         errno = WTAP_ERR_CANT_CLOSE;
588         if (fclose(wdh->fh) == EOF) {
589                 if (ret) {
590                         /* The per-format close function succeeded,
591                            but the fclose didn't.  Save the reason
592                            why, if our caller asked for it. */
593                         if (err != NULL)
594                                 *err = errno;
595                 }
596                 ret = FALSE;
597         }
598         if (wdh->dump.opaque != NULL)
599                 g_free(wdh->dump.opaque);
600         g_free(wdh);
601         return ret;
602 }