3253ecb9746c64b6a840383e17cd1cff0128069b
[obnox/wireshark/wip.git] / wiretap / file.c
1 /* file.c
2  *
3  * $Id: file.c,v 1.94 2002/07/16 07:15:08 guy Exp $
4  *
5  * Wiretap Library
6  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
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 #include "visual.h"
70
71 /* The open_file_* routines should return:
72  *
73  *      -1 on an I/O error;
74  *
75  *      1 if the file they're reading is one of the types it handles;
76  *
77  *      0 if the file they're reading isn't the type they're checking for.
78  *
79  * If the routine handles this type of file, it should set the "file_type"
80  * field in the "struct wtap" to the type of the file.
81  *
82  * XXX - I need to drag my damn ANSI C spec in to figure out how to
83  * declare a "const" array of pointers to functions; putting "const"
84  * right after "static" isn't the right answer, at least according
85  * to GCC, which whines if I do that.
86  *
87  * Put the trace files that are merely saved telnet-sessions last, since it's
88  * possible that you could have captured someone a router telnet-session
89  * using another tool. So, a libpcap trace of an toshiba "snoop" session
90  * should be discovered as a libpcap file, not a toshiba file.
91  */
92
93 static int (*open_routines[])(wtap *, int *) = {
94         /* Files that have magic bytes in fixed locations. These
95          * are easy to identify.
96          */
97         libpcap_open,
98         lanalyzer_open,
99         ngsniffer_open,
100         snoop_open,
101         iptrace_open,
102         netmon_open,
103         netxray_open,
104         radcom_open,
105         nettl_open,
106         visual_open,
107
108         /* Files that don't have magic bytes at a fixed location,
109          * but that instead require a heuristic of some sort to
110          * identify them.  This includes the ASCII trace files that
111          * would be, for example, saved copies of a Telnet session
112          * to some box.
113          */
114         etherpeek_open,
115         pppdump_open,
116         ascend_open,
117         toshiba_open,
118         i4btrace_open,
119         csids_open,
120         vms_open,
121         dbs_etherwatch_open,
122 };
123
124 #define N_FILE_TYPES    (sizeof open_routines / sizeof open_routines[0])
125
126 gboolean wtap_def_seek_read(wtap *wth, long seek_off,
127         union wtap_pseudo_header *pseudo_header _U_,
128         guint8 *pd, int len, int *err)
129 {
130         int bytes_read;
131
132         if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
133                 return FALSE;
134
135         bytes_read = file_read(pd, sizeof(guint8), len, wth->random_fh);
136         if (bytes_read != len) {
137                 *err = file_error(wth->random_fh);
138                 if (*err == 0)
139                         *err = WTAP_ERR_SHORT_READ;
140                 return FALSE;
141         }
142         return TRUE;
143 }
144
145 /*
146  * Visual C++ on Win32 systems doesn't define these.  (Old UNIX systems don't
147  * define them either.)
148  *
149  * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
150  */
151 #ifndef S_ISREG
152 #define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
153 #endif
154 #ifndef S_IFIFO
155 #define S_IFIFO _S_IFIFO
156 #endif
157 #ifndef S_ISFIFO
158 #define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
159 #endif
160 #ifndef S_ISDIR
161 #define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
162 #endif
163
164 /* Opens a file and prepares a wtap struct.
165    If "do_random" is TRUE, it opens the file twice; the second open
166    allows the application to do random-access I/O without moving
167    the seek offset for sequential I/O, which is used by Ethereal
168    so that it can do sequential I/O to a capture file that's being
169    written to as new packets arrive independently of random I/O done
170    to display protocol trees for packets when they're selected. */
171 wtap* wtap_open_offline(const char *filename, int *err, gboolean do_random)
172 {
173         struct stat statb;
174         wtap    *wth;
175         unsigned int    i;
176
177         /* First, make sure the file is valid */
178         if (stat(filename, &statb) < 0) {
179                 *err = errno;
180                 return NULL;
181         }
182         if (S_ISFIFO(statb.st_mode)) {
183                 /*
184                  * Opens of FIFOs are allowed only when not opening
185                  * for random access.
186                  *
187                  * XXX - currently, we do seeking when trying to find
188                  * out the file type, so we don't actually support
189                  * opening FIFOs.  However, we may eventually
190                  * do buffering that allows us to do at least some
191                  * file type determination even on pipes, so we
192                  * allow FIFO opens and let things fail later when
193                  * we try to seek.
194                  */
195                 if (do_random) {
196                         *err = WTAP_ERR_RANDOM_OPEN_PIPE;
197                         return NULL;
198                 }
199         } else if (S_ISDIR(statb.st_mode)) {
200                 /*
201                  * Return different errors for "this is a directory"
202                  * and "this is some random special file type", so
203                  * the user can get a potentially more helpful error.
204                  */
205                 *err = EISDIR;
206                 return NULL;
207         } else if (! S_ISREG(statb.st_mode)) {
208                 *err = WTAP_ERR_NOT_REGULAR_FILE;
209                 return NULL;
210         }
211
212         errno = ENOMEM;
213         wth = g_malloc(sizeof(wtap));
214         if (wth == NULL) {
215                 *err = errno;
216                 return NULL;
217         }
218
219 /* Win32 needs the O_BINARY flag for open() */
220 #ifndef O_BINARY
221 #define O_BINARY        0
222 #endif
223
224         /* Open the file */
225         errno = WTAP_ERR_CANT_OPEN;
226         wth->fd = open(filename, O_RDONLY|O_BINARY);
227         if (wth->fd < 0) {
228                 *err = errno;
229                 g_free(wth);
230                 return NULL;
231         }
232         if (!(wth->fh = filed_open(wth->fd, "rb"))) {
233                 *err = errno;
234                 g_free(wth);
235                 return NULL;
236         }
237
238         if (do_random) {
239                 if (!(wth->random_fh = file_open(filename, "rb"))) {
240                         *err = errno;
241                         file_close(wth->fh);
242                         g_free(wth);
243                         return NULL;
244                 }
245         } else
246                 wth->random_fh = NULL;
247
248         /* initialization */
249         wth->file_encap = WTAP_ENCAP_UNKNOWN;
250         wth->data_offset = 0;
251         wth->subtype_sequential_close = NULL;
252         wth->subtype_close = NULL;
253
254         /* Try all file types */
255         for (i = 0; i < N_FILE_TYPES; i++) {
256                 /* Seek back to the beginning of the file; the open routine
257                    for the previous file type may have left the file
258                    position somewhere other than the beginning, and the
259                    open routine for this file type will probably want
260                    to start reading at the beginning.
261
262                    Initialize the data offset while we're at it. */
263                 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
264                         /* I/O error - give up */
265                         if (wth->random_fh != NULL)
266                                 file_close(wth->random_fh);
267                         file_close(wth->fh);
268                         g_free(wth);
269                         return NULL;
270                 }
271                 wth->data_offset = 0;
272                 switch ((*open_routines[i])(wth, err)) {
273
274                 case -1:
275                         /* I/O error - give up */
276                         if (wth->random_fh != NULL)
277                                 file_close(wth->random_fh);
278                         file_close(wth->fh);
279                         g_free(wth);
280                         return NULL;
281
282                 case 0:
283                         /* No I/O error, but not that type of file */
284                         break;
285
286                 case 1:
287                         /* We found the file type */
288                         goto success;
289                 }
290         }
291
292         /* Well, it's not one of the types of file we know about. */
293         if (wth->random_fh != NULL)
294                 file_close(wth->random_fh);
295         file_close(wth->fh);
296         g_free(wth);
297         *err = WTAP_ERR_FILE_UNKNOWN_FORMAT;
298         return NULL;
299
300 success:
301         wth->frame_buffer = g_malloc(sizeof(struct Buffer));
302         buffer_init(wth->frame_buffer, 1500);
303         return wth;
304 }
305
306 /* Table of the file types we know about. */
307 static const struct file_type_info {
308         const char *name;
309         const char *short_name;
310         int     (*can_write_encap)(int);
311         int     (*dump_open)(wtap_dumper *, gboolean, int *);
312 } dump_open_table[WTAP_NUM_FILE_TYPES] = {
313         /* WTAP_FILE_UNKNOWN */
314         { NULL, NULL,
315           NULL, NULL },
316
317         /* WTAP_FILE_WTAP */
318         { "Wiretap (Ethereal)", NULL,
319           NULL, NULL },
320
321         /* WTAP_FILE_PCAP */
322         { "libpcap (tcpdump, Ethereal, etc.)", "libpcap",
323           libpcap_dump_can_write_encap, libpcap_dump_open },
324
325         /* WTAP_FILE_PCAP_SS990417 */
326         { "Red Hat Linux 6.1 libpcap (tcpdump)", "rh6_1libpcap",
327           libpcap_dump_can_write_encap, libpcap_dump_open },
328
329         /* WTAP_FILE_PCAP_SS990915 */
330         { "SuSE Linux 6.3 libpcap (tcpdump)", "suse6_3libpcap",
331           libpcap_dump_can_write_encap, libpcap_dump_open },
332
333         /* WTAP_FILE_PCAP_SS991029 */
334         { "modified libpcap (tcpdump)", "modlibpcap",
335           libpcap_dump_can_write_encap, libpcap_dump_open },
336
337         /* WTAP_FILE_PCAP_NOKIA */
338         { "Nokia libpcap (tcpdump)", "nokialibpcap",
339           libpcap_dump_can_write_encap, libpcap_dump_open },
340
341         /* WTAP_FILE_PCAP_AIX */
342         { "AIX libpcap (tcpdump)", NULL,
343           NULL, NULL },
344
345         /* WTAP_FILE_LANALYZER */
346         { "Novell LANalyzer","lanalyzer",
347           lanalyzer_dump_can_write_encap, lanalyzer_dump_open },
348
349         /* WTAP_FILE_NGSNIFFER_UNCOMPRESSED */
350         { "Network Associates Sniffer (DOS-based)", "ngsniffer",
351           ngsniffer_dump_can_write_encap, ngsniffer_dump_open },
352
353         /* WTAP_FILE_NGSNIFFER_COMPRESSED */
354         { "Network Associates Sniffer (DOS-based), compressed", "ngsniffer_comp",
355           NULL, NULL },
356
357         /* WTAP_FILE_SNOOP */
358         { "Sun snoop", "snoop",
359           snoop_dump_can_write_encap, snoop_dump_open },
360
361         /* WTAP_FILE_IPTRACE_1_0 */
362         { "AIX iptrace 1.0", NULL,
363           NULL, NULL },
364
365         /* WTAP_FILE_IPTRACE_2_0 */
366         { "AIX iptrace 2.0", NULL,
367           NULL, NULL },
368
369         /* WTAP_FILE_NETMON_1_x */
370         { "Microsoft Network Monitor 1.x", "netmon1",
371           netmon_dump_can_write_encap, netmon_dump_open },
372
373         /* WTAP_FILE_NETMON_2_x */
374         { "Microsoft Network Monitor 2.x", "netmon2",
375           netmon_dump_can_write_encap, netmon_dump_open },
376
377         /* WTAP_FILE_NETXRAY_OLD */
378         { "Cinco Networks NetXRay 1.x", NULL,
379           NULL, NULL },
380
381         /* WTAP_FILE_NETXRAY_1_0 */
382         { "Cinco Networks NetXRay 2.0 or later", NULL,
383           NULL, NULL },
384
385         /* WTAP_FILE_NETXRAY_1_1 */
386         { "Network Associates Sniffer (Windows-based) 1.1", "ngwsniffer_1_1",
387           netxray_dump_can_write_encap, netxray_dump_open_1_1 },
388
389         /* WTAP_FILE_NETXRAY_2_00x */
390         { "Network Associates Sniffer (Windows-based) 2.00x", "ngwsniffer_2_0",
391           netxray_dump_can_write_encap, netxray_dump_open_2_0 },
392
393         /* WTAP_FILE_RADCOM */
394         { "RADCOM WAN/LAN analyzer", NULL,
395           NULL, NULL },
396
397         /* WTAP_FILE_ASCEND */
398         { "Lucent/Ascend access server trace", NULL,
399           NULL, NULL },
400
401         /* WTAP_FILE_NETTL */
402         { "HP-UX nettl trace", NULL,
403           NULL, NULL },
404
405         /* WTAP_FILE_TOSHIBA */
406         { "Toshiba Compact ISDN Router snoop trace", NULL,
407           NULL, NULL },
408
409         /* WTAP_FILE_I4BTRACE */
410         { "I4B ISDN trace", NULL,
411           NULL, NULL },
412
413         /* WTAP_FILE_CSIDS */
414         { "CSIDS IPLog", NULL,
415           NULL, NULL },
416
417         /* WTAP_FILE_PPPDUMP */
418         { "pppd log (pppdump format)", NULL,
419           NULL, NULL },
420
421         /* WTAP_FILE_ETHERPEEK_V56 */
422         { "EtherPeek/TokenPeek trace (V5 & V6 file format)", NULL,
423           NULL, NULL },
424
425         /* WTAP_FILE_ETHERPEEK_V7 */
426         { "EtherPeek/TokenPeek/AiroPeek trace (V7 file format)", NULL,
427           NULL, NULL },
428
429         /* WTAP_FILE_VMS */
430         { "TCPIPtrace (VMS)", NULL,
431           NULL, NULL},
432
433         /* WTAP_FILE_DBS_ETHERWATCH */
434         { "DBS Etherwatch (VMS)", NULL,
435           NULL, NULL},
436
437         /* WTAP_FILE_VISUAL_NETWORKS */
438         { "Visual Networks traffic capture", "visual",
439           visual_dump_can_write_encap, visual_dump_open },
440 };
441
442 /* Name that should be somewhat descriptive. */
443 const char *wtap_file_type_string(int filetype)
444 {
445         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES) {
446                 g_error("Unknown capture file type %d", filetype);
447                 return NULL;
448         } else
449                 return dump_open_table[filetype].name;
450 }
451
452 /* Name to use in, say, a command-line flag specifying the type. */
453 const char *wtap_file_type_short_string(int filetype)
454 {
455         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES)
456                 return NULL;
457         else
458                 return dump_open_table[filetype].short_name;
459 }
460
461 /* Translate a short name to a capture file type. */
462 int wtap_short_string_to_file_type(const char *short_name)
463 {
464         int filetype;
465
466         for (filetype = 0; filetype < WTAP_NUM_FILE_TYPES; filetype++) {
467                 if (dump_open_table[filetype].short_name != NULL &&
468                     strcmp(short_name, dump_open_table[filetype].short_name) == 0)
469                         return filetype;
470         }
471         return -1;      /* no such file type, or we can't write it */
472 }
473
474 gboolean wtap_dump_can_open(int filetype)
475 {
476         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES
477             || dump_open_table[filetype].dump_open == NULL)
478                 return FALSE;
479
480         return TRUE;
481 }
482
483 gboolean wtap_dump_can_write_encap(int filetype, int encap)
484 {
485         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES
486             || dump_open_table[filetype].can_write_encap == NULL)
487                 return FALSE;
488
489         if ((*dump_open_table[filetype].can_write_encap)(encap) != 0)
490                 return FALSE;
491
492         return TRUE;
493 }
494
495 static gboolean wtap_dump_open_check(int filetype, int encap, int *err);
496 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
497     int *err);
498 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, int *err);
499
500 wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap,
501                                 int snaplen, int *err)
502 {
503         wtap_dumper *wdh;
504         FILE *fh;
505
506         /* Check whether we can open a capture file with that file type
507            and that encapsulation. */
508         if (!wtap_dump_open_check(filetype, encap, err))
509                 return NULL;
510
511         /* Allocate a data structure for the output stream. */
512         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, err);
513         if (wdh == NULL)
514                 return NULL;    /* couldn't allocate it */
515
516         /* Empty filename means stdout */
517         if (*filename == '\0')
518                 wdh->fh = stdout;
519         else {
520                 /* In case "fopen()" fails but doesn't set "errno", set "errno"
521                    to a generic "the open failed" error. */
522                 errno = WTAP_ERR_CANT_OPEN;
523                 fh = fopen(filename, "wb");
524                 if (fh == NULL) {
525                         *err = errno;
526                         return NULL;    /* can't create file */
527                 }
528                 wdh->fh = fh;
529         }
530
531         if (!wtap_dump_open_finish(wdh, filetype, err)) {
532                 /* Get rid of the file we created; we couldn't finish
533                    opening it. */
534                 if (wdh->fh != stdout)
535                         unlink(filename);
536                 return NULL;
537         }
538         return wdh;
539 }
540
541 wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen,
542                                 int *err)
543 {
544         wtap_dumper *wdh;
545         FILE *fh;
546
547         /* Check whether we can open a capture file with that file type
548            and that encapsulation. */
549         if (!wtap_dump_open_check(filetype, encap, err))
550                 return NULL;
551
552         /* Allocate a data structure for the output stream. */
553         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, err);
554         if (wdh == NULL)
555                 return NULL;    /* couldn't allocate it */
556
557         /* In case "fopen()" fails but doesn't set "errno", set "errno"
558            to a generic "the open failed" error. */
559         errno = WTAP_ERR_CANT_OPEN;
560         fh = fdopen(fd, "wb");
561         if (fh == NULL) {
562                 *err = errno;
563                 return NULL;    /* can't create standard I/O stream */
564         }
565         wdh->fh = fh;
566
567         if (!wtap_dump_open_finish(wdh, filetype, err))
568                 return NULL;
569         return wdh;
570 }
571
572 static gboolean wtap_dump_open_check(int filetype, int encap, int *err)
573 {
574         if (!wtap_dump_can_open(filetype)) {
575                 /* Invalid type, or type we don't know how to write. */
576                 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
577                 return FALSE;
578         }
579
580         /* OK, we know how to write that type; can we write the specified
581            encapsulation type? */
582         *err = (*dump_open_table[filetype].can_write_encap)(encap);
583         if (*err != 0)
584                 return FALSE;
585
586         /* All systems go! */
587         return TRUE;
588 }
589
590 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
591                                         int *err)
592 {
593         wtap_dumper *wdh;
594
595         wdh = g_malloc(sizeof (wtap_dumper));
596         if (wdh == NULL) {
597                 *err = errno;
598                 return NULL;
599         }
600         wdh->fh = NULL;
601         wdh->file_type = filetype;
602         wdh->snaplen = snaplen;
603         wdh->encap = encap;
604         wdh->bytes_dumped = 0;
605         wdh->dump.opaque = NULL;
606         wdh->subtype_write = NULL;
607         wdh->subtype_close = NULL;
608         return wdh;
609 }
610
611 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype, int *err)
612 {
613         int fd;
614         gboolean cant_seek;
615
616         /* Can we do a seek on the file descriptor?
617            If not, note that fact. */
618         fd = fileno(wdh->fh);
619         if (lseek(fd, 1, SEEK_CUR) == -1)
620           cant_seek = TRUE;
621         else {
622           /* Undo the seek. */
623           lseek(fd, 0, SEEK_SET);
624           cant_seek = FALSE;
625         }
626
627         /* Now try to open the file for writing. */
628         if (!(*dump_open_table[filetype].dump_open)(wdh, cant_seek, err)) {
629                 /* The attempt failed.  Close the stream for the file.
630                    NOTE: this means the FD handed to "wtap_dump_fdopen()"
631                    will be closed if the open fails. */
632                 if (wdh->fh != stdout)
633                         fclose(wdh->fh);
634
635                 /* Now free up the dumper handle. */
636                 g_free(wdh);
637                 return FALSE;
638         }
639
640         return TRUE;    /* success! */
641 }
642
643 FILE* wtap_dump_file(wtap_dumper *wdh)
644 {
645         return wdh->fh;
646 }
647
648 gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
649     const union wtap_pseudo_header *pseudo_header, const u_char *pd, int *err)
650 {
651         return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err);
652 }
653
654 gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
655 {
656         gboolean ret = TRUE;
657
658         if (wdh->subtype_close != NULL) {
659                 /* There's a close routine for this dump stream. */
660                 if (!(wdh->subtype_close)(wdh, err))
661                         ret = FALSE;
662         }
663         errno = WTAP_ERR_CANT_CLOSE;
664         /* Don't close stdout */
665         if (wdh->fh != stdout) {
666                 if (fclose(wdh->fh) == EOF) {
667                         if (ret) {
668                                 /* The per-format close function succeeded,
669                                    but the fclose didn't.  Save the reason
670                                    why, if our caller asked for it. */
671                                 if (err != NULL)
672                                         *err = errno;
673                         }
674                         ret = FALSE;
675                 }
676         }
677         if (wdh->dump.opaque != NULL)
678                 g_free(wdh->dump.opaque);
679         g_free(wdh);
680         return ret;
681 }
682
683 long wtap_get_bytes_dumped(wtap_dumper *wdh)
684 {
685         return wdh->bytes_dumped;
686 }
687
688 void wtap_set_bytes_dumped(wtap_dumper *wdh, long bytes_dumped)
689 {
690         wdh->bytes_dumped = bytes_dumped;
691 }
692