1.3.5 -> 1.3.6.
[obnox/wireshark/wip.git] / pcapio.c
1 /* pcapio.c
2  * Our own private code for writing libpcap files when capturing.
3  *
4  * We have these because we want a way to open a stream for output given
5  * only a file descriptor.  libpcap 0.9[.x] has "pcap_dump_fopen()", which
6  * provides that, but
7  *
8  *      1) earlier versions of libpcap doesn't have it
9  *
10  * and
11  *
12  *      2) WinPcap doesn't have it, because a file descriptor opened
13  *         by code built for one version of the MSVC++ C library
14  *         can't be used by library routines built for another version
15  *         (e.g., threaded vs. unthreaded).
16  *
17  * Libpcap's pcap_dump() also doesn't return any error indications.
18  *
19  * $Id$
20  *
21  * Wireshark - Network traffic analyzer
22  * By Gerald Combs <gerald@wireshark.org>
23  * Copyright 1998 Gerald Combs
24  *
25  * Derived from code in the Wiretap Library
26  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
27  *
28  * This program is free software; you can redistribute it and/or
29  * modify it under the terms of the GNU General Public License
30  * as published by the Free Software Foundation; either version 2
31  * of the License, or (at your option) any later version.
32  *
33  * This program is distributed in the hope that it will be useful,
34  * but WITHOUT ANY WARRANTY; without even the implied warranty of
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36  * GNU General Public License for more details.
37  *
38  * You should have received a copy of the GNU General Public License
39  * along with this program; if not, write to the Free Software
40  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
41  */
42
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46
47 #ifdef HAVE_LIBPCAP
48
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <errno.h>
52 #include <string.h>
53
54 #include <pcap.h>
55
56 #include <glib.h>
57
58 #include "pcapio.h"
59
60 /* Magic numbers in "libpcap" files.
61
62    "libpcap" file records are written in the byte order of the host that
63    writes them, and the reader is expected to fix this up.
64
65    PCAP_MAGIC is the magic number, in host byte order; PCAP_SWAPPED_MAGIC
66    is a byte-swapped version of that.
67
68    PCAP_NSEC_MAGIC is for Ulf Lamping's modified "libpcap" format,
69    which uses the same common file format as PCAP_MAGIC, but the 
70    timestamps are saved in nanosecond resolution instead of microseconds.
71    PCAP_SWAPPED_NSEC_MAGIC is a byte-swapped version of that. */
72 #define PCAP_MAGIC                      0xa1b2c3d4
73 #define PCAP_SWAPPED_MAGIC              0xd4c3b2a1
74 #define PCAP_NSEC_MAGIC                 0xa1b23c4d
75 #define PCAP_SWAPPED_NSEC_MAGIC         0x4d3cb2a1
76
77 /* "libpcap" file header. */
78 struct pcap_hdr {
79         guint32 magic;          /* magic number */
80         guint16 version_major;  /* major version number */
81         guint16 version_minor;  /* minor version number */
82         gint32  thiszone;       /* GMT to local correction */
83         guint32 sigfigs;        /* accuracy of timestamps */
84         guint32 snaplen;        /* max length of captured packets, in octets */
85         guint32 network;        /* data link type */
86 };
87
88 /* "libpcap" record header. */
89 struct pcaprec_hdr {
90         guint32 ts_sec;         /* timestamp seconds */
91         guint32 ts_usec;        /* timestamp microseconds (nsecs for PCAP_NSEC_MAGIC) */
92         guint32 incl_len;       /* number of octets of packet saved in file */
93         guint32 orig_len;       /* actual length of packet */
94 };
95
96 /* Magic numbers in ".pcapng" files.
97  *
98  * .pcapng file records are written in the byte order of the host that
99  * writes them, and the reader is expected to fix this up.
100  * PCAPNG_MAGIC is the magic number, in host byte order;
101  * PCAPNG_SWAPPED_MAGIC is a byte-swapped version of that.
102  */
103 #define PCAPNG_MAGIC         0x1A2B3C4D
104 #define PCAPNG_SWAPPED_MAGIC 0xD4C3B2A1
105
106 /* Currently we are only supporting the initial version of
107    the file format. */
108 #define PCAPNG_MAJOR_VERSION 1
109 #define PCAPNG_MINOR_VERSION 0
110
111 /* Section Header Block without options and trailing Block Total Length */
112 struct shb {
113         guint32 block_type;
114         guint32 block_total_length;
115         guint32 byte_order_magic;
116         guint16 major_version;
117         guint16 minor_version;
118         guint64 section_length;
119 };
120 #define SECTION_HEADER_BLOCK_TYPE 0x0A0D0D0A
121
122 /* Interface Decription Block without options and trailing Block Total Length */
123 struct idb {
124         guint32 block_type;
125         guint32 block_total_length;
126         guint16 link_type;
127         guint16 reserved;
128         guint32 snap_len;
129 };
130 #define INTERFACE_DESCRIPTION_BLOCK_TYPE 0x00000001
131
132 /* Interface Statistics Block without actual packet, options, and trailing
133    Block Total Length */
134 struct isb {
135         guint32 block_type;
136         guint32 block_total_length;
137         guint32 interface_id;
138         guint32 timestamp_high;
139         guint32 timestamp_low;
140 };
141 #define INTERFACE_STATISTICS_BLOCK_TYPE 0x00000005
142
143 /* Enhanced Packet Block without actual packet, options, and trailing
144    Block Total Length */
145 struct epb {
146         guint32 block_type;
147         guint32 block_total_length;
148         guint32 interface_id;
149         guint32 timestamp_high;
150         guint32 timestamp_low;
151         guint32 captured_len;
152         guint32 packet_len;
153 };
154 #define ENHANCED_PACKET_BLOCK_TYPE 0x00000006
155
156 struct option {
157         guint16 type;
158         guint16 value_length;
159 };
160 #define OPT_ENDOFOPT 0
161 #define OPT_COMMENT  1 /* currently not used */
162 #define SHB_HARDWARE 2 /* currently not used */
163 #define SHB_OS       3 /* currently not used */
164 #define SHB_USERAPPL 4
165 #define IDB_NAME     2
166 #define IDB_FILTER  11
167 #define ISB_IFRECV   4
168 #define ISB_IFDROP   5
169 #define ISB_FILTERACCEPT 6
170
171 #define ADD_PADDING(x) ((((x) + 3) >> 2) << 2)
172
173 #define WRITE_DATA(file_pointer, data_pointer, data_length, written_length, error_pointer) \
174 {                                                                                          \
175         do {                                                                               \
176                 size_t nwritten;                                                           \
177                                                                                            \
178                 nwritten = fwrite(data_pointer, 1, data_length, file_pointer);             \
179                 if (nwritten != data_length) {                                             \
180                         if (nwritten == 0 && ferror(file_pointer)) {                       \
181                                 *error_pointer = errno;                                    \
182                         } else {                                                           \
183                                 *error_pointer = 0;                                        \
184                         }                                                                  \
185                         fclose(file_pointer);                                              \
186                         return FALSE;                                                      \
187                 }                                                                          \
188                 written_length += (long)nwritten;                                          \
189         } while (0);                                                                       \
190 }
191
192 /* Returns a FILE * to write to on success, NULL on failure */
193 FILE *
194 libpcap_fdopen(int fd, int *err)
195 {
196         FILE *fp;
197
198         fp = fdopen(fd, "wb");
199         if (fp == NULL) {
200                 *err = errno;
201         }
202         return fp;
203 }
204
205 /* Write the file header to a dump file.
206    Returns TRUE on success, FALSE on failure.
207    Sets "*err" to an error code, or 0 for a short write, on failure*/
208 gboolean
209 libpcap_write_file_header(FILE *fp, int linktype, int snaplen, long *bytes_written, int *err)
210 {
211         struct pcap_hdr file_hdr;
212         size_t nwritten;
213
214         file_hdr.magic = PCAP_MAGIC;
215         /* current "libpcap" format is 2.4 */
216         file_hdr.version_major = 2;
217         file_hdr.version_minor = 4;
218         file_hdr.thiszone = 0;  /* XXX - current offset? */
219         file_hdr.sigfigs = 0;   /* unknown, but also apparently unused */
220         file_hdr.snaplen = snaplen;
221         file_hdr.network = linktype;
222         nwritten = fwrite(&file_hdr, 1, sizeof(file_hdr), fp);
223         if (nwritten != sizeof(file_hdr)) {
224                 if (nwritten == 0 && ferror(fp))
225                         *err = errno;
226                 else
227                         *err = 0;       /* short write */
228                 return FALSE;
229         }
230         *bytes_written += sizeof(file_hdr);
231
232         return TRUE;
233 }
234
235 /* Write a record for a packet to a dump file.
236    Returns TRUE on success, FALSE on failure. */
237 gboolean
238 libpcap_write_packet(FILE *fp, const struct pcap_pkthdr *phdr, const u_char *pd,
239     long *bytes_written, int *err)
240 {
241         struct pcaprec_hdr rec_hdr;
242         size_t nwritten;
243
244         rec_hdr.ts_sec = phdr->ts.tv_sec;
245         rec_hdr.ts_usec = phdr->ts.tv_usec;
246         rec_hdr.incl_len = phdr->caplen;
247         rec_hdr.orig_len = phdr->len;
248         nwritten = fwrite(&rec_hdr, 1, sizeof rec_hdr, fp);
249         if (nwritten != sizeof rec_hdr) {
250                 if (nwritten == 0 && ferror(fp))
251                         *err = errno;
252                 else
253                         *err = 0;       /* short write */
254                 return FALSE;
255         }
256         *bytes_written += sizeof rec_hdr;
257
258         nwritten = fwrite(pd, 1, phdr->caplen, fp);
259         if (nwritten != phdr->caplen) {
260                 if (nwritten == 0 && ferror(fp))
261                         *err = errno;
262                 else
263                         *err = 0;       /* short write */
264                 return FALSE;
265         }
266         *bytes_written += phdr->caplen;
267         return TRUE;
268 }
269
270 gboolean
271 libpcap_write_session_header_block(FILE *fp,
272                                    char *appname,
273                                    long *bytes_written,
274                                    int *err)
275 {
276         struct shb shb;
277         struct option option;
278         guint32 block_total_length;
279         const guint32 padding = 0;
280         
281         block_total_length = sizeof(struct shb) +
282                              sizeof(guint32);
283         if ((strlen(appname) > 0) && (strlen(appname) < G_MAXUINT16)) {
284                 block_total_length += 2 * sizeof(struct option) +
285                                       (guint16)(ADD_PADDING(strlen(appname) + 1));
286         }
287         /* write shb header */
288         shb.block_type = SECTION_HEADER_BLOCK_TYPE;
289         shb.block_total_length = block_total_length;
290         shb.byte_order_magic = PCAPNG_MAGIC;
291         shb.major_version = PCAPNG_MAJOR_VERSION;
292         shb.minor_version = PCAPNG_MINOR_VERSION;
293         shb.section_length = -1;
294         WRITE_DATA(fp, &shb, sizeof(struct shb), *bytes_written, err);
295
296         if ((strlen(appname) > 0) && (strlen(appname) < G_MAXUINT16)) {
297                 /* write shb_userappl options */
298                 option.type = SHB_USERAPPL;
299                 option.value_length = (guint16)(strlen(appname) + 1);
300                 WRITE_DATA(fp, &option, sizeof(struct option), *bytes_written, err);
301                 WRITE_DATA(fp, appname, strlen(appname) + 1, *bytes_written, err);
302                 if ((strlen(appname) + 1) % 4) {
303                         WRITE_DATA(fp, &padding, 4 - (strlen(appname) + 1) % 4, *bytes_written, err);
304                 }
305                 /* write last option */
306                 option.type = OPT_ENDOFOPT;
307                 option.value_length = 0;
308                 WRITE_DATA(fp, &option, sizeof(struct option), *bytes_written, err);
309         }
310         /* write the trailing block total length */
311         WRITE_DATA(fp, &block_total_length, sizeof(guint32), *bytes_written, err);
312         return TRUE;
313 }
314
315 gboolean
316 libpcap_write_interface_description_block(FILE *fp,
317                                           char *name,
318                                           char *filter,
319                                           int link_type,
320                                           int snap_len,
321                                           long *bytes_written,
322                                           int *err)
323 {
324         struct idb idb;
325         struct option option;
326         guint32 block_total_length;
327         const guint32 padding = 0;
328
329         block_total_length = sizeof(struct idb) + sizeof(guint32);
330         if ((strlen(name) > 0) && (strlen(name) < G_MAXUINT16)) {
331                 block_total_length += sizeof(struct option) + 
332                                       (guint16)(ADD_PADDING(strlen(name) + 1));
333         }
334         if ((strlen(filter) > 0) && (strlen(name) < G_MAXUINT16)) {
335                 block_total_length += sizeof(struct option) +
336                                       (guint16)(ADD_PADDING(strlen(filter) + 1));
337         }
338         if (((strlen(name) > 0) && (strlen(name) < G_MAXUINT16)) ||
339             ((strlen(filter) > 0) && (strlen(name) < G_MAXUINT16))) {
340                 block_total_length += sizeof(struct option);
341         }
342         /* write block header */
343         idb.block_type = INTERFACE_DESCRIPTION_BLOCK_TYPE;
344         idb.block_total_length = block_total_length;
345         idb.link_type = link_type;
346         idb.reserved = 0;
347         idb.snap_len = snap_len;
348         WRITE_DATA(fp, &idb, sizeof(struct idb), *bytes_written, err);
349         /* write interface name string if applicable */
350         if ((strlen(name) > 0) && (strlen(name) < G_MAXUINT16)) {
351                 option.type = IDB_NAME;
352                 option.value_length = (guint16)(strlen(name) + 1);
353                 WRITE_DATA(fp, &option, sizeof(struct option), *bytes_written, err);
354                 WRITE_DATA(fp, name, strlen(name) + 1, *bytes_written, err);
355                 if ((strlen(name) + 1) % 4) {
356                         WRITE_DATA(fp, &padding, 4 - (strlen(name) + 1) % 4 , *bytes_written, err);
357                 }
358         }
359         /* write filter string if applicable */
360         if ((strlen(filter) > 0) && (strlen(filter) < G_MAXUINT16)) {
361                 option.type = IDB_FILTER;
362                 option.value_length = (guint16)(strlen(filter) + 1);
363                 WRITE_DATA(fp, &option, sizeof(struct option), *bytes_written, err);
364                 WRITE_DATA(fp, filter, strlen(filter) + 1, *bytes_written, err);
365                 if ((strlen(filter) + 1) % 4) {
366                         WRITE_DATA(fp, &padding, 4 - (strlen(filter) + 1) % 4 , *bytes_written, err);
367                 }
368         }
369         /* write endofopt option if there were any options */
370         if (((strlen(name) > 0) && (strlen(name) < G_MAXUINT16)) ||
371             ((strlen(filter) > 0) && (strlen(filter) < G_MAXUINT16))) {
372                 option.type = OPT_ENDOFOPT;
373                 option.value_length = 0;
374                 WRITE_DATA(fp, &option, sizeof(struct option), *bytes_written, err);
375         }
376         /* write the trailing Block Total Length */
377         WRITE_DATA(fp, &block_total_length, sizeof(guint32), *bytes_written, err);
378         return TRUE;
379 }
380
381 /* Write a record for a packet to a dump file.
382    Returns TRUE on success, FALSE on failure. */
383 gboolean
384 libpcap_write_enhanced_packet_block(FILE *fp,
385                                     const struct pcap_pkthdr *phdr,
386                                     guint32 interface_id,
387                                     const u_char *pd,
388                                     long *bytes_written,
389                                     int *err)
390 {
391         struct epb epb;
392         guint32 block_total_length;
393         guint64 timestamp;
394         const guint32 padding = 0;
395
396         block_total_length = sizeof(struct epb) +
397                              ADD_PADDING(phdr->caplen) +
398                              sizeof(guint32);
399         timestamp = (guint64)(phdr->ts.tv_sec) * 1000000 +
400                     (guint64)(phdr->ts.tv_usec);
401         epb.block_type = ENHANCED_PACKET_BLOCK_TYPE;
402         epb.block_total_length = block_total_length;
403         epb.interface_id = interface_id;
404         epb.timestamp_high = (guint32)((timestamp>>32) & 0xffffffff);
405         epb.timestamp_low = (guint32)(timestamp & 0xffffffff);
406         epb.captured_len = phdr->caplen;
407         epb.packet_len = phdr->len;
408         WRITE_DATA(fp, &epb, sizeof(struct epb), *bytes_written, err);
409         WRITE_DATA(fp, pd, phdr->caplen, *bytes_written, err);
410         if (phdr->caplen % 4) {
411                 WRITE_DATA(fp, &padding, 4 - phdr->caplen % 4, *bytes_written, err);
412         }
413         WRITE_DATA(fp, &block_total_length, sizeof(guint32), *bytes_written, err);
414         return TRUE;
415 }
416
417 gboolean
418 libpcap_write_interface_statistics_block(FILE *fp,
419                                          guint32 interface_id,
420                                          pcap_t *pd,
421                                          long *bytes_written,
422                                          int *err)
423 {
424         struct isb isb;
425 #ifdef _WIN32
426         FILETIME now;
427 #else
428         struct timeval now;
429 #endif
430         struct option option;
431         struct pcap_stat stats;
432         guint32 block_total_length;
433         guint64 timestamp;
434         guint64 counter;
435         gboolean stats_retrieved;
436         
437 #ifdef _WIN32
438         /*
439          * Current time, represented as 100-nanosecond intervals since
440          * January 1, 1601, 00:00:00 UTC.
441          *
442          * I think DWORD might be signed, so cast both parts of "now"
443          * to guint32 so that the sign bit doesn't get treated specially.
444          */
445         GetSystemTimeAsFileTime(&now);
446         timestamp = (((guint64)(guint32)now.dwHighDateTime) << 32) +
447                     (guint32)now.dwLowDateTime;
448
449         /*
450          * Convert to same thing but as 1-microsecond, i.e. 1000-nanosecond,
451          * intervals.
452          */
453         timestamp /= 10;
454
455         /*
456          * Subtract difference, in microseconds, between January 1, 1601
457          * 00:00:00 UTC and January 1, 1970, 00:00:00 UTC.
458          */
459         timestamp -= G_GINT64_CONSTANT(11644473600000000U);
460 #else
461         /*
462          * Current time, represented as seconds and microseconds since
463          * January 1, 1970, 00:00:00 UTC.
464          */
465         gettimeofday(&now, NULL);
466
467         /*
468          * Convert to delta in microseconds.
469          */
470         timestamp = (guint64)(now.tv_sec) * 1000000 +
471                     (guint64)(now.tv_usec);
472 #endif
473         if (pcap_stats(pd, &stats) < 0) {
474                 stats_retrieved = FALSE;
475                 g_warning("pcap_stats() failed.");
476         } else {
477                 stats_retrieved = TRUE;
478         }
479         block_total_length = sizeof(struct isb) +
480                              sizeof(guint32);
481         if (stats_retrieved) {
482                 block_total_length += 3 * sizeof(struct option) + 2 * sizeof(guint64);
483         }
484         isb.block_type = INTERFACE_STATISTICS_BLOCK_TYPE;
485         isb.block_total_length = block_total_length;
486         isb.interface_id = interface_id;
487         isb.timestamp_high = (guint32)((timestamp>>32) & 0xffffffff);
488         isb.timestamp_low = (guint32)(timestamp & 0xffffffff);
489         WRITE_DATA(fp, &isb, sizeof(struct isb), *bytes_written, err);
490         if (stats_retrieved) {
491                 /* */
492                 option.type = ISB_IFRECV;
493                 option.value_length = sizeof(guint64);
494                 counter = stats.ps_recv;
495                 WRITE_DATA(fp, &option, sizeof(struct option), *bytes_written, err);
496                 WRITE_DATA(fp, &counter, sizeof(guint64), *bytes_written, err);
497                 /* */
498                 option.type = ISB_IFDROP;
499                 option.value_length = sizeof(guint64);
500                 counter = stats.ps_drop;
501                 WRITE_DATA(fp, &option, sizeof(struct option), *bytes_written, err);
502                 WRITE_DATA(fp, &counter, sizeof(guint64), *bytes_written, err);
503                 /* last option */
504                 option.type = OPT_ENDOFOPT;
505                 option.value_length = 0;
506                 WRITE_DATA(fp, &option, sizeof(struct option), *bytes_written, err);
507         }
508         WRITE_DATA(fp, &block_total_length, sizeof(guint32), *bytes_written, err);
509         
510         return TRUE;
511 }
512
513 gboolean
514 libpcap_dump_flush(FILE *pd, int *err)
515 {
516         if (fflush(pd) == EOF) {
517                 if (err != NULL)
518                         *err = errno;
519                 return FALSE;
520         }
521         return TRUE;
522 }
523
524 gboolean
525 libpcap_dump_close(FILE *pd, int *err)
526 {
527         if (fclose(pd) == EOF) {
528                 if (err != NULL)
529                         *err = errno;
530                 return FALSE;
531         }
532         return TRUE;
533 }
534
535 #endif /* HAVE_LIBPCAP */