0c8d21381a8e7eae25e5cb2390ee7d1697837cf3
[obnox/wireshark/wip.git] / wiretap / file.c
1 /* file.c
2  *
3  * $Id: file.c,v 1.78 2002/01/18 00:48:37 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         pppdump_open,
108
109         /* Files that don't have magic bytes at a fixed location,
110          * but that instead require a heuristic of some sort to
111          * identify them.  This includes the ASCII trace files that
112          * would be saved copies of a Telnet session to some box.
113          */
114         etherpeek_open,
115         ascend_open,
116         toshiba_open,
117         i4btrace_open,
118         csids_open,
119         vms_open,
120         dbs_etherwatch_open,
121 };
122
123 #define N_FILE_TYPES    (sizeof open_routines / sizeof open_routines[0])
124
125 int wtap_def_seek_read(wtap *wth, long seek_off,
126         union wtap_pseudo_header *pseudo_header, guint8 *pd, int len)
127 {
128         file_seek(wth->random_fh, seek_off, SEEK_SET);
129
130         return file_read(pd, sizeof(guint8), len, wth->random_fh);
131 }
132
133 /*
134  * Visual C++ on Win32 systems doesn't define these.  (Old UNIX systems don't
135  * define them either.)
136  *
137  * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
138  */
139 #ifndef S_ISREG
140 #define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
141 #endif
142 #ifndef S_IFIFO
143 #define S_IFIFO _S_IFIFO
144 #endif
145 #ifndef S_ISFIFO
146 #define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
147 #endif
148 #ifndef S_ISDIR
149 #define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
150 #endif
151
152 /* Opens a file and prepares a wtap struct.
153    If "do_random" is TRUE, it opens the file twice; the second open
154    allows the application to do random-access I/O without moving
155    the seek offset for sequential I/O, which is used by Ethereal
156    so that it can do sequential I/O to a capture file that's being
157    written to as new packets arrive independently of random I/O done
158    to display protocol trees for packets when they're selected. */
159 wtap* wtap_open_offline(const char *filename, int *err, gboolean do_random)
160 {
161         struct stat statb;
162         wtap    *wth;
163         unsigned int    i;
164
165         /* First, make sure the file is valid */
166         if (stat(filename, &statb) < 0) {
167                 *err = errno;
168                 return NULL;
169         }
170         if (! S_ISREG(statb.st_mode) && ! S_ISFIFO(statb.st_mode)) {
171                 if (S_ISDIR(statb.st_mode))
172                         *err = EISDIR;
173                 else
174                         *err = WTAP_ERR_NOT_REGULAR_FILE;
175                 return NULL;
176         }
177
178         errno = ENOMEM;
179         wth = g_malloc(sizeof(wtap));
180         if (wth == NULL) {
181                 *err = errno;
182                 return NULL;
183         }
184
185 /* Win32 needs the O_BINARY flag for open() */
186 #ifndef O_BINARY
187 #define O_BINARY        0
188 #endif
189
190         /* Open the file */
191         errno = WTAP_ERR_CANT_OPEN;
192         wth->fd = open(filename, O_RDONLY|O_BINARY);
193         if (wth->fd < 0) {
194                 *err = errno;
195                 g_free(wth);
196                 return NULL;
197         }
198         if (!(wth->fh = filed_open(wth->fd, "rb"))) {
199                 *err = errno;
200                 g_free(wth);
201                 return NULL;
202         }
203
204         if (do_random) {
205                 if (!(wth->random_fh = file_open(filename, "rb"))) {
206                         *err = errno;
207                         file_close(wth->fh);
208                         g_free(wth);
209                         return NULL;
210                 }
211         } else
212                 wth->random_fh = NULL;
213
214         /* initialization */
215         wth->file_encap = WTAP_ENCAP_UNKNOWN;
216         wth->data_offset = 0;
217         wth->subtype_sequential_close = NULL;
218         wth->subtype_close = NULL;
219
220         /* Try all file types */
221         for (i = 0; i < N_FILE_TYPES; i++) {
222                 /* Seek back to the beginning of the file; the open routine
223                    for the previous file type may have left the file
224                    position somewhere other than the beginning, and the
225                    open routine for this file type will probably want
226                    to start reading at the beginning.
227
228                    Initialize the data offset while we're at it. */
229                 file_seek(wth->fh, 0, SEEK_SET);
230                 wth->data_offset = 0;
231                 switch ((*open_routines[i])(wth, err)) {
232
233                 case -1:
234                         /* I/O error - give up */
235                         if (wth->random_fh != NULL)
236                                 file_close(wth->random_fh);
237                         file_close(wth->fh);
238                         g_free(wth);
239                         return NULL;
240
241                 case 0:
242                         /* No I/O error, but not that type of file */
243                         break;
244
245                 case 1:
246                         /* We found the file type */
247                         goto success;
248                 }
249         }
250
251         /* Well, it's not one of the types of file we know about. */
252         if (wth->random_fh != NULL)
253                 file_close(wth->random_fh);
254         file_close(wth->fh);
255         g_free(wth);
256         *err = WTAP_ERR_FILE_UNKNOWN_FORMAT;
257         return NULL;
258
259 success:
260         wth->frame_buffer = g_malloc(sizeof(struct Buffer));
261         buffer_init(wth->frame_buffer, 1500);
262         return wth;
263 }
264
265 /* Table of the file types we know about. */
266 static const struct file_type_info {
267         const char *name;
268         const char *short_name;
269         int     (*can_write_encap)(int, int);
270         int     (*dump_open)(wtap_dumper *, int *);
271 } dump_open_table[WTAP_NUM_FILE_TYPES] = {
272         /* WTAP_FILE_UNKNOWN */
273         { NULL, NULL,
274           NULL, NULL },
275
276         /* WTAP_FILE_WTAP */
277         { "Wiretap (Ethereal)", NULL,
278           NULL, NULL },
279
280         /* WTAP_FILE_PCAP */
281         { "libpcap (tcpdump, Ethereal, etc.)", "libpcap",
282           libpcap_dump_can_write_encap, libpcap_dump_open },
283
284         /* WTAP_FILE_PCAP_SS990417 */
285         { "Red Hat Linux 6.1 libpcap (tcpdump)", "rh6_1libpcap",
286           libpcap_dump_can_write_encap, libpcap_dump_open },
287
288         /* WTAP_FILE_PCAP_SS990915 */
289         { "SuSE Linux 6.3 libpcap (tcpdump)", "suse6_3libpcap",
290           libpcap_dump_can_write_encap, libpcap_dump_open },
291
292         /* WTAP_FILE_PCAP_SS991029 */
293         { "modified libpcap (tcpdump)", "modlibpcap",
294           libpcap_dump_can_write_encap, libpcap_dump_open },
295
296         /* WTAP_FILE_PCAP_NOKIA */
297         { "Nokia libpcap (tcpdump)", "nokialibpcap",
298           libpcap_dump_can_write_encap, libpcap_dump_open },
299
300         /* WTAP_FILE_PCAP_AIX */
301         { "AIX libpcap (tcpdump)", NULL,
302           NULL, NULL },
303
304         /* WTAP_FILE_LANALYZER */
305         { "Novell LANalyzer", NULL,
306           NULL, NULL },
307
308         /* WTAP_FILE_NGSNIFFER_UNCOMPRESSED */
309         { "Network Associates Sniffer (DOS-based)", "ngsniffer",
310           ngsniffer_dump_can_write_encap, ngsniffer_dump_open },
311
312         /* WTAP_FILE_NGSNIFFER_COMPRESSED */
313         { "Network Associates Sniffer (DOS-based), compressed", "ngsniffer_comp",
314           NULL, NULL },
315
316         /* WTAP_FILE_SNOOP */
317         { "Sun snoop", "snoop",
318           snoop_dump_can_write_encap, snoop_dump_open },
319
320         /* WTAP_FILE_IPTRACE_1_0 */
321         { "AIX iptrace 1.0", NULL,
322           NULL, NULL },
323
324         /* WTAP_FILE_IPTRACE_2_0 */
325         { "AIX iptrace 2.0", NULL,
326           NULL, NULL },
327
328         /* WTAP_FILE_NETMON_1_x */
329         { "Microsoft Network Monitor 1.x", "netmon1",
330           netmon_dump_can_write_encap, netmon_dump_open },
331
332         /* WTAP_FILE_NETMON_2_x */
333         { "Microsoft Network Monitor 2.x", "netmon2",
334           netmon_dump_can_write_encap, netmon_dump_open },
335
336         /* WTAP_FILE_NETXRAY_1_0 */
337         { "Cinco Networks NetXRay", NULL,
338           NULL, NULL },
339
340         /* WTAP_FILE_NETXRAY_1_1 */
341         { "Network Associates Sniffer (Windows-based) 1.1", "ngwsniffer_1_1",
342           netxray_dump_can_write_encap, netxray_dump_open_1_1 },
343
344         /* WTAP_FILE_NETXRAY_2_00x */
345         { "Network Associates Sniffer (Windows-based) 2.00x", NULL,
346           NULL, NULL },
347
348         /* WTAP_FILE_RADCOM */
349         { "RADCOM WAN/LAN analyzer", NULL,
350           NULL, NULL },
351
352         /* WTAP_FILE_ASCEND */
353         { "Lucent/Ascend access server trace", NULL,
354           NULL, NULL },
355
356         /* WTAP_FILE_NETTL */
357         { "HP-UX nettl trace", NULL,
358           NULL, NULL },
359
360         /* WTAP_FILE_TOSHIBA */
361         { "Toshiba Compact ISDN Router snoop trace", NULL,
362           NULL, NULL },
363
364         /* WTAP_FILE_I4BTRACE */
365         { "I4B ISDN trace", NULL,
366           NULL, NULL },
367
368         /* WTAP_FILE_CSIDS */
369         { "CSIDS IPLog", NULL,
370           NULL, NULL },
371
372         /* WTAP_FILE_PPPDUMP */
373         { "pppd log (pppdump format)", NULL,
374           NULL, NULL },
375
376         /* WTAP_FILE_ETHERPEEK_MAC_V56 */
377         { "EtherPeek trace (Macintosh V5 & V6)", NULL,
378           NULL, NULL },
379
380         /* WTAP_FILE_ETHERPEEK_MAC_V7 */
381         { "EtherPeek trace (Macintosh V7)", NULL,
382           NULL, NULL },
383
384         /* WTAP_FILE_VMS */
385         { "TCPIPtrace (VMS)", NULL,
386           NULL, NULL},
387
388         /* WTAP_FILE_DBS_ETHERWATCH */
389         { "DBS Etherwatch (VMS)", NULL,
390           NULL, NULL},
391
392         /* WTAP_FILE_VISUAL_NETWORKS */
393         { "Visual Networks traffic capture", "visual",
394           visual_dump_can_write_encap, visual_dump_open },
395 };
396
397 /* Name that should be somewhat descriptive. */
398 const char *wtap_file_type_string(int filetype)
399 {
400         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES) {
401                 g_error("Unknown capture file type %d", filetype);
402                 return NULL;
403         } else
404                 return dump_open_table[filetype].name;
405 }
406
407 /* Name to use in, say, a command-line flag specifying the type. */
408 const char *wtap_file_type_short_string(int filetype)
409 {
410         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES)
411                 return NULL;
412         else
413                 return dump_open_table[filetype].short_name;
414 }
415
416 /* Translate a short name to a capture file type. */
417 int wtap_short_string_to_file_type(const char *short_name)
418 {
419         int filetype;
420
421         for (filetype = 0; filetype < WTAP_NUM_FILE_TYPES; filetype++) {
422                 if (dump_open_table[filetype].short_name != NULL &&
423                     strcmp(short_name, dump_open_table[filetype].short_name) == 0)
424                         return filetype;
425         }
426         return -1;      /* no such file type, or we can't write it */
427 }
428
429 gboolean wtap_dump_can_open(int filetype)
430 {
431         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES
432             || dump_open_table[filetype].dump_open == NULL)
433                 return FALSE;
434
435         return TRUE;
436 }
437
438 gboolean wtap_dump_can_write_encap(int filetype, int encap)
439 {
440         if (filetype < 0 || filetype >= WTAP_NUM_FILE_TYPES
441             || dump_open_table[filetype].can_write_encap == NULL)
442                 return FALSE;
443
444         if ((*dump_open_table[filetype].can_write_encap)(filetype, encap) != 0)
445                 return FALSE;
446
447         return TRUE;
448 }
449
450 static gboolean wtap_dump_open_check(int filetype, int encap, int *err);
451 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
452     int *err);
453 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype,
454     int encap, int snaplen, int *err);
455
456 wtap_dumper* wtap_dump_open(const char *filename, int filetype, int encap,
457                                 int snaplen, int *err)
458 {
459         wtap_dumper *wdh;
460         FILE *fh;
461
462         /* Check whether we can open a capture file with that file type
463            and that encapsulation. */
464         if (!wtap_dump_open_check(filetype, encap, err))
465                 return NULL;
466
467         /* Allocate a data structure for the output stream. */
468         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, err);
469         if (wdh == NULL)
470                 return NULL;    /* couldn't allocate it */
471
472         /* In case "fopen()" fails but doesn't set "errno", set "errno"
473            to a generic "the open failed" error. */
474         errno = WTAP_ERR_CANT_OPEN;
475         fh = fopen(filename, "wb");
476         if (fh == NULL) {
477                 *err = errno;
478                 return NULL;    /* can't create file */
479         }
480         wdh->fh = fh;
481
482         if (!wtap_dump_open_finish(wdh, filetype, encap, snaplen, err)) {
483                 /* Get rid of the file we created; we couldn't finish
484                    opening it. */
485                 unlink(filename);
486                 return NULL;
487         }
488         return wdh;
489 }
490
491 wtap_dumper* wtap_dump_fdopen(int fd, int filetype, int encap, int snaplen,
492                                 int *err)
493 {
494         wtap_dumper *wdh;
495         FILE *fh;
496
497         /* Check whether we can open a capture file with that file type
498            and that encapsulation. */
499         if (!wtap_dump_open_check(filetype, encap, err))
500                 return NULL;
501
502         /* Allocate a data structure for the output stream. */
503         wdh = wtap_dump_alloc_wdh(filetype, encap, snaplen, err);
504         if (wdh == NULL)
505                 return NULL;    /* couldn't allocate it */
506
507         /* In case "fopen()" fails but doesn't set "errno", set "errno"
508            to a generic "the open failed" error. */
509         errno = WTAP_ERR_CANT_OPEN;
510         fh = fdopen(fd, "wb");
511         if (fh == NULL) {
512                 *err = errno;
513                 return NULL;    /* can't create standard I/O stream */
514         }
515         wdh->fh = fh;
516
517         if (!wtap_dump_open_finish(wdh, filetype, encap, snaplen, err))
518                 return NULL;
519         return wdh;
520 }
521
522 static gboolean wtap_dump_open_check(int filetype, int encap, int *err)
523 {
524         if (!wtap_dump_can_open(filetype)) {
525                 /* Invalid type, or type we don't know how to write. */
526                 *err = WTAP_ERR_UNSUPPORTED_FILE_TYPE;
527                 return FALSE;
528         }
529
530         /* OK, we know how to write that type; can we write the specified
531            encapsulation type? */
532         *err = (*dump_open_table[filetype].can_write_encap)(filetype, encap);
533         if (*err != 0)
534                 return FALSE;
535
536         /* All systems go! */
537         return TRUE;
538 }
539
540 static wtap_dumper* wtap_dump_alloc_wdh(int filetype, int encap, int snaplen,
541                                         int *err)
542 {
543         wtap_dumper *wdh;
544
545         wdh = g_malloc(sizeof (wtap_dumper));
546         if (wdh == NULL) {
547                 *err = errno;
548                 return NULL;
549         }
550         wdh->fh = NULL;
551         wdh->file_type = filetype;
552         wdh->snaplen = snaplen;
553         wdh->encap = encap;
554         wdh->bytes_dumped = 0;
555         wdh->dump.opaque = NULL;
556         wdh->subtype_write = NULL;
557         wdh->subtype_close = NULL;
558         return wdh;
559 }
560
561 static gboolean wtap_dump_open_finish(wtap_dumper *wdh, int filetype,
562                                       int encap, int snaplen, int *err)
563 {
564         /* Now try to open the file for writing. */
565         if (!(*dump_open_table[filetype].dump_open)(wdh, err)) {
566                 /* The attempt failed.  Close the stream for the file.
567                    NOTE: this means the FD handed to "wtap_dump_fdopen()"
568                    will be closed if the open fails. */
569                 fclose(wdh->fh);
570
571                 /* Now free up the dumper handle. */
572                 g_free(wdh);
573                 return FALSE;
574         }
575
576         return TRUE;    /* success! */
577 }
578
579 FILE* wtap_dump_file(wtap_dumper *wdh)
580 {
581         return wdh->fh;
582 }
583
584 gboolean wtap_dump(wtap_dumper *wdh, const struct wtap_pkthdr *phdr,
585     const union wtap_pseudo_header *pseudo_header, const u_char *pd, int *err)
586 {
587         return (wdh->subtype_write)(wdh, phdr, pseudo_header, pd, err);
588 }
589
590 gboolean wtap_dump_close(wtap_dumper *wdh, int *err)
591 {
592         gboolean ret = TRUE;
593
594         if (wdh->subtype_close != NULL) {
595                 /* There's a close routine for this dump stream. */
596                 if (!(wdh->subtype_close)(wdh, err))
597                         ret = FALSE;
598         }
599         errno = WTAP_ERR_CANT_CLOSE;
600         if (fclose(wdh->fh) == EOF) {
601                 if (ret) {
602                         /* The per-format close function succeeded,
603                            but the fclose didn't.  Save the reason
604                            why, if our caller asked for it. */
605                         if (err != NULL)
606                                 *err = errno;
607                 }
608                 ret = FALSE;
609         }
610         if (wdh->dump.opaque != NULL)
611                 g_free(wdh->dump.opaque);
612         g_free(wdh);
613         return ret;
614 }
615
616 long wtap_get_bytes_dumped(wtap_dumper *wdh)
617 {
618         return wdh->bytes_dumped;
619 }
620
621 void wtap_set_bytes_dumped(wtap_dumper *wdh, long bytes_dumped)
622 {
623         wdh->bytes_dumped = bytes_dumped;
624 }
625