nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 | * Wireshark - Network traffic analyzer |
||
20 | * By Gerald Combs <gerald@wireshark.org> |
||
21 | * Copyright 1998 Gerald Combs |
||
22 | * |
||
23 | * Derived from code in the Wiretap Library |
||
24 | * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu> |
||
25 | * |
||
26 | * This program is free software; you can redistribute it and/or |
||
27 | * modify it under the terms of the GNU General Public License |
||
28 | * as published by the Free Software Foundation; either version 2 |
||
29 | * of the License, or (at your option) any later version. |
||
30 | * |
||
31 | * This program is distributed in the hope that it will be useful, |
||
32 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
33 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
34 | * GNU General Public License for more details. |
||
35 | * |
||
36 | * You should have received a copy of the GNU General Public License |
||
37 | * along with this program; if not, write to the Free Software |
||
38 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||
39 | */ |
||
40 | |||
41 | #include <config.h> |
||
42 | |||
43 | #include <stdlib.h> |
||
44 | #include <stdio.h> |
||
45 | #include <errno.h> |
||
46 | #include <string.h> |
||
47 | #ifdef HAVE_SYS_TIME_H |
||
48 | #include <sys/time.h> |
||
49 | #endif |
||
50 | #ifdef _WIN32 |
||
51 | #include <Windows.h> |
||
52 | #endif |
||
53 | |||
54 | #include <glib.h> |
||
55 | |||
56 | #include "pcapio.h" |
||
57 | |||
58 | /* Magic numbers in "libpcap" files. |
||
59 | |||
60 | "libpcap" file records are written in the byte order of the host that |
||
61 | writes them, and the reader is expected to fix this up. |
||
62 | |||
63 | PCAP_MAGIC is the magic number, in host byte order; PCAP_SWAPPED_MAGIC |
||
64 | is a byte-swapped version of that. |
||
65 | |||
66 | PCAP_NSEC_MAGIC is for Ulf Lamping's modified "libpcap" format, |
||
67 | which uses the same common file format as PCAP_MAGIC, but the |
||
68 | timestamps are saved in nanosecond resolution instead of microseconds. |
||
69 | PCAP_SWAPPED_NSEC_MAGIC is a byte-swapped version of that. */ |
||
70 | #define PCAP_MAGIC 0xa1b2c3d4 |
||
71 | #define PCAP_SWAPPED_MAGIC 0xd4c3b2a1 |
||
72 | #define PCAP_NSEC_MAGIC 0xa1b23c4d |
||
73 | #define PCAP_SWAPPED_NSEC_MAGIC 0x4d3cb2a1 |
||
74 | |||
75 | /* "libpcap" file header. */ |
||
76 | struct pcap_hdr { |
||
77 | guint32 magic; /* magic number */ |
||
78 | guint16 version_major; /* major version number */ |
||
79 | guint16 version_minor; /* minor version number */ |
||
80 | gint32 thiszone; /* GMT to local correction */ |
||
81 | guint32 sigfigs; /* accuracy of timestamps */ |
||
82 | guint32 snaplen; /* max length of captured packets, in octets */ |
||
83 | guint32 network; /* data link type */ |
||
84 | }; |
||
85 | |||
86 | /* "libpcap" record header. */ |
||
87 | struct pcaprec_hdr { |
||
88 | guint32 ts_sec; /* timestamp seconds */ |
||
89 | guint32 ts_usec; /* timestamp microseconds (nsecs for PCAP_NSEC_MAGIC) */ |
||
90 | guint32 incl_len; /* number of octets of packet saved in file */ |
||
91 | guint32 orig_len; /* actual length of packet */ |
||
92 | }; |
||
93 | |||
94 | /* Magic numbers in ".pcapng" files. |
||
95 | * |
||
96 | * .pcapng file records are written in the byte order of the host that |
||
97 | * writes them, and the reader is expected to fix this up. |
||
98 | * PCAPNG_MAGIC is the magic number, in host byte order; |
||
99 | * PCAPNG_SWAPPED_MAGIC is a byte-swapped version of that. |
||
100 | */ |
||
101 | #define PCAPNG_MAGIC 0x1A2B3C4D |
||
102 | #define PCAPNG_SWAPPED_MAGIC 0xD4C3B2A1 |
||
103 | |||
104 | /* Currently we are only supporting the initial version of |
||
105 | the file format. */ |
||
106 | #define PCAPNG_MAJOR_VERSION 1 |
||
107 | #define PCAPNG_MINOR_VERSION 0 |
||
108 | |||
109 | /* Section Header Block without options and trailing Block Total Length */ |
||
110 | struct shb { |
||
111 | guint32 block_type; |
||
112 | guint32 block_total_length; |
||
113 | guint32 byte_order_magic; |
||
114 | guint16 major_version; |
||
115 | guint16 minor_version; |
||
116 | guint64 section_length; |
||
117 | }; |
||
118 | #define SECTION_HEADER_BLOCK_TYPE 0x0A0D0D0A |
||
119 | |||
120 | /* Interface Description Block without options and trailing Block Total Length */ |
||
121 | struct idb { |
||
122 | guint32 block_type; |
||
123 | guint32 block_total_length; |
||
124 | guint16 link_type; |
||
125 | guint16 reserved; |
||
126 | guint32 snap_len; |
||
127 | }; |
||
128 | #define INTERFACE_DESCRIPTION_BLOCK_TYPE 0x00000001 |
||
129 | |||
130 | /* Interface Statistics Block without actual packet, options, and trailing |
||
131 | Block Total Length */ |
||
132 | struct isb { |
||
133 | guint32 block_type; |
||
134 | guint32 block_total_length; |
||
135 | guint32 interface_id; |
||
136 | guint32 timestamp_high; |
||
137 | guint32 timestamp_low; |
||
138 | }; |
||
139 | #define INTERFACE_STATISTICS_BLOCK_TYPE 0x00000005 |
||
140 | |||
141 | /* Enhanced Packet Block without actual packet, options, and trailing |
||
142 | Block Total Length */ |
||
143 | struct epb { |
||
144 | guint32 block_type; |
||
145 | guint32 block_total_length; |
||
146 | guint32 interface_id; |
||
147 | guint32 timestamp_high; |
||
148 | guint32 timestamp_low; |
||
149 | guint32 captured_len; |
||
150 | guint32 packet_len; |
||
151 | }; |
||
152 | #define ENHANCED_PACKET_BLOCK_TYPE 0x00000006 |
||
153 | |||
154 | struct option { |
||
155 | guint16 type; |
||
156 | guint16 value_length; |
||
157 | }; |
||
158 | #define OPT_ENDOFOPT 0 |
||
159 | #define OPT_COMMENT 1 |
||
160 | #define EPB_FLAGS 2 |
||
161 | #define SHB_HARDWARE 2 /* currently not used */ |
||
162 | #define SHB_OS 3 |
||
163 | #define SHB_USERAPPL 4 |
||
164 | #define IDB_NAME 2 |
||
165 | #define IDB_DESCRIPTION 3 |
||
166 | #define IDB_IF_SPEED 8 |
||
167 | #define IDB_TSRESOL 9 |
||
168 | #define IDB_FILTER 11 |
||
169 | #define IDB_OS 12 |
||
170 | #define ISB_STARTTIME 2 |
||
171 | #define ISB_ENDTIME 3 |
||
172 | #define ISB_IFRECV 4 |
||
173 | #define ISB_IFDROP 5 |
||
174 | #define ISB_FILTERACCEPT 6 |
||
175 | #define ISB_OSDROP 7 |
||
176 | #define ISB_USRDELIV 8 |
||
177 | #define ADD_PADDING(x) ((((x) + 3) >> 2) << 2) |
||
178 | |||
179 | /* Write to capture file */ |
||
180 | static gboolean |
||
181 | write_to_file(FILE* pfile, const guint8* data, size_t data_length, |
||
182 | guint64 *bytes_written, int *err) |
||
183 | { |
||
184 | size_t nwritten; |
||
185 | |||
186 | nwritten = fwrite(data, data_length, 1, pfile); |
||
187 | if (nwritten != 1) { |
||
188 | if (ferror(pfile)) { |
||
189 | *err = errno; |
||
190 | } else { |
||
191 | *err = 0; |
||
192 | } |
||
193 | return FALSE; |
||
194 | } |
||
195 | |||
196 | (*bytes_written) += data_length; |
||
197 | return TRUE; |
||
198 | } |
||
199 | |||
200 | /* Writing pcap files */ |
||
201 | |||
202 | /* Write the file header to a dump file. |
||
203 | Returns TRUE on success, FALSE on failure. |
||
204 | Sets "*err" to an error code, or 0 for a short write, on failure*/ |
||
205 | gboolean |
||
206 | libpcap_write_file_header(FILE* pfile, int linktype, int snaplen, gboolean ts_nsecs, guint64 *bytes_written, int *err) |
||
207 | { |
||
208 | struct pcap_hdr file_hdr; |
||
209 | |||
210 | file_hdr.magic = ts_nsecs ? PCAP_NSEC_MAGIC : PCAP_MAGIC; |
||
211 | /* current "libpcap" format is 2.4 */ |
||
212 | file_hdr.version_major = 2; |
||
213 | file_hdr.version_minor = 4; |
||
214 | file_hdr.thiszone = 0; /* XXX - current offset? */ |
||
215 | file_hdr.sigfigs = 0; /* unknown, but also apparently unused */ |
||
216 | file_hdr.snaplen = snaplen; |
||
217 | file_hdr.network = linktype; |
||
218 | |||
219 | return write_to_file(pfile, (const guint8*)&file_hdr, sizeof(file_hdr), bytes_written, err); |
||
220 | } |
||
221 | |||
222 | /* Write a record for a packet to a dump file. |
||
223 | Returns TRUE on success, FALSE on failure. */ |
||
224 | gboolean |
||
225 | libpcap_write_packet(FILE* pfile, |
||
226 | time_t sec, guint32 usec, |
||
227 | guint32 caplen, guint32 len, |
||
228 | const guint8 *pd, |
||
229 | guint64 *bytes_written, int *err) |
||
230 | { |
||
231 | struct pcaprec_hdr rec_hdr; |
||
232 | |||
233 | rec_hdr.ts_sec = (guint32)sec; /* Y2.038K issue in pcap format.... */ |
||
234 | rec_hdr.ts_usec = usec; |
||
235 | rec_hdr.incl_len = caplen; |
||
236 | rec_hdr.orig_len = len; |
||
237 | if (!write_to_file(pfile, (const guint8*)&rec_hdr, sizeof(rec_hdr), bytes_written, err)) |
||
238 | return FALSE; |
||
239 | |||
240 | return write_to_file(pfile, pd, caplen, bytes_written, err); |
||
241 | } |
||
242 | |||
243 | /* Writing pcap-ng files */ |
||
244 | |||
245 | static guint32 |
||
246 | pcapng_count_string_option(const char *option_value) |
||
247 | { |
||
248 | if ((option_value != NULL) && (strlen(option_value) > 0) && (strlen(option_value) < G_MAXUINT16)) { |
||
249 | /* There's a value to write; get its length */ |
||
250 | return (guint32)(sizeof(struct option) + |
||
251 | (guint16)ADD_PADDING(strlen(option_value))); |
||
252 | } |
||
253 | return 0; /* nothing to write */ |
||
254 | } |
||
255 | |||
256 | static gboolean |
||
257 | pcapng_write_string_option(FILE* pfile, |
||
258 | guint16 option_type, const char *option_value, |
||
259 | guint64 *bytes_written, int *err) |
||
260 | { |
||
261 | size_t option_value_length; |
||
262 | struct option option; |
||
263 | const guint32 padding = 0; |
||
264 | |||
265 | if (option_value == NULL) |
||
266 | return TRUE; /* nothing to write */ |
||
267 | option_value_length = strlen(option_value); |
||
268 | if ((option_value_length > 0) && (option_value_length < G_MAXUINT16)) { |
||
269 | /* something to write */ |
||
270 | option.type = option_type; |
||
271 | option.value_length = (guint16)option_value_length; |
||
272 | |||
273 | if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err)) |
||
274 | return FALSE; |
||
275 | |||
276 | if (!write_to_file(pfile, (const guint8*)option_value, (int) option_value_length, bytes_written, err)) |
||
277 | return FALSE; |
||
278 | |||
279 | if (option_value_length % 4) { |
||
280 | if (!write_to_file(pfile, (const guint8*)&padding, 4 - option_value_length % 4, bytes_written, err)) |
||
281 | return FALSE; |
||
282 | } |
||
283 | } |
||
284 | return TRUE; |
||
285 | } |
||
286 | |||
287 | gboolean |
||
288 | pcapng_write_session_header_block(FILE* pfile, |
||
289 | const char *comment, |
||
290 | const char *hw, |
||
291 | const char *os, |
||
292 | const char *appname, |
||
293 | guint64 section_length, |
||
294 | guint64 *bytes_written, |
||
295 | int *err) |
||
296 | { |
||
297 | struct shb shb; |
||
298 | struct option option; |
||
299 | guint32 block_total_length; |
||
300 | guint32 options_length; |
||
301 | |||
302 | /* Size of base header */ |
||
303 | block_total_length = sizeof(struct shb) + |
||
304 | sizeof(guint32); |
||
305 | options_length = 0; |
||
306 | options_length += pcapng_count_string_option(comment); |
||
307 | options_length += pcapng_count_string_option(hw); |
||
308 | options_length += pcapng_count_string_option(os); |
||
309 | options_length += pcapng_count_string_option(appname); |
||
310 | /* If we have options add size of end-of-options */ |
||
311 | if (options_length != 0) { |
||
312 | options_length += (guint32)sizeof(struct option); |
||
313 | } |
||
314 | block_total_length += options_length; |
||
315 | |||
316 | /* write shb header */ |
||
317 | shb.block_type = SECTION_HEADER_BLOCK_TYPE; |
||
318 | shb.block_total_length = block_total_length; |
||
319 | shb.byte_order_magic = PCAPNG_MAGIC; |
||
320 | shb.major_version = PCAPNG_MAJOR_VERSION; |
||
321 | shb.minor_version = PCAPNG_MINOR_VERSION; |
||
322 | shb.section_length = section_length; |
||
323 | |||
324 | if (!write_to_file(pfile, (const guint8*)&shb, sizeof(struct shb), bytes_written, err)) |
||
325 | return FALSE; |
||
326 | |||
327 | if (!pcapng_write_string_option(pfile, OPT_COMMENT, comment, |
||
328 | bytes_written, err)) |
||
329 | return FALSE; |
||
330 | if (!pcapng_write_string_option(pfile, SHB_HARDWARE, hw, |
||
331 | bytes_written, err)) |
||
332 | return FALSE; |
||
333 | if (!pcapng_write_string_option(pfile, SHB_OS, os, |
||
334 | bytes_written, err)) |
||
335 | return FALSE; |
||
336 | if (!pcapng_write_string_option(pfile, SHB_USERAPPL, appname, |
||
337 | bytes_written, err)) |
||
338 | return FALSE; |
||
339 | if (options_length != 0) { |
||
340 | /* write end of options */ |
||
341 | option.type = OPT_ENDOFOPT; |
||
342 | option.value_length = 0; |
||
343 | if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err)) |
||
344 | return FALSE; |
||
345 | } |
||
346 | |||
347 | /* write the trailing block total length */ |
||
348 | return write_to_file(pfile, (const guint8*)&block_total_length, sizeof(guint32), bytes_written, err); |
||
349 | } |
||
350 | |||
351 | gboolean |
||
352 | pcapng_write_interface_description_block(FILE* pfile, |
||
353 | const char *comment, /* OPT_COMMENT 1 */ |
||
354 | const char *name, /* IDB_NAME 2 */ |
||
355 | const char *descr, /* IDB_DESCRIPTION 3 */ |
||
356 | const char *filter, /* IDB_FILTER 11 */ |
||
357 | const char *os, /* IDB_OS 12 */ |
||
358 | int link_type, |
||
359 | int snap_len, |
||
360 | guint64 *bytes_written, |
||
361 | guint64 if_speed, /* IDB_IF_SPEED 8 */ |
||
362 | guint8 tsresol, /* IDB_TSRESOL 9 */ |
||
363 | int *err) |
||
364 | { |
||
365 | struct idb idb; |
||
366 | struct option option; |
||
367 | guint32 block_total_length; |
||
368 | guint32 options_length; |
||
369 | const guint32 padding = 0; |
||
370 | |||
371 | block_total_length = (guint32)(sizeof(struct idb) + sizeof(guint32)); |
||
372 | options_length = 0; |
||
373 | /* 01 - OPT_COMMENT */ |
||
374 | options_length += pcapng_count_string_option(comment); |
||
375 | |||
376 | /* 02 - IDB_NAME */ |
||
377 | options_length += pcapng_count_string_option(name); |
||
378 | |||
379 | /* 03 - IDB_DESCRIPTION */ |
||
380 | options_length += pcapng_count_string_option(descr); |
||
381 | |||
382 | /* 08 - IDB_IF_SPEED */ |
||
383 | if (if_speed != 0) { |
||
384 | options_length += (guint32)(sizeof(struct option) + |
||
385 | sizeof(guint64)); |
||
386 | } |
||
387 | |||
388 | /* 09 - IDB_TSRESOL */ |
||
389 | if (tsresol != 0) { |
||
390 | options_length += (guint32)(sizeof(struct option) + |
||
391 | sizeof(struct option)); |
||
392 | } |
||
393 | |||
394 | /* 11 - IDB_FILTER */ |
||
395 | if ((filter != NULL) && (strlen(filter) > 0) && (strlen(filter) < G_MAXUINT16)) { |
||
396 | /* No, this isn't a string, it has an extra type byte */ |
||
397 | options_length += (guint32)(sizeof(struct option) + |
||
398 | (guint16)(ADD_PADDING(strlen(filter)+ 1))); |
||
399 | } |
||
400 | |||
401 | /* 12 - IDB_OS */ |
||
402 | options_length += pcapng_count_string_option(os); |
||
403 | |||
404 | /* If we have options add size of end-of-options */ |
||
405 | if (options_length != 0) { |
||
406 | options_length += (guint32)sizeof(struct option); |
||
407 | } |
||
408 | block_total_length += options_length; |
||
409 | |||
410 | /* write block header */ |
||
411 | idb.block_type = INTERFACE_DESCRIPTION_BLOCK_TYPE; |
||
412 | idb.block_total_length = block_total_length; |
||
413 | idb.link_type = link_type; |
||
414 | idb.reserved = 0; |
||
415 | idb.snap_len = snap_len; |
||
416 | if (!write_to_file(pfile, (const guint8*)&idb, sizeof(struct idb), bytes_written, err)) |
||
417 | return FALSE; |
||
418 | |||
419 | /* 01 - OPT_COMMENT - write comment string if applicable */ |
||
420 | if (!pcapng_write_string_option(pfile, OPT_COMMENT, comment, |
||
421 | bytes_written, err)) |
||
422 | return FALSE; |
||
423 | |||
424 | /* 02 - IDB_NAME - write interface name string if applicable */ |
||
425 | if (!pcapng_write_string_option(pfile, IDB_NAME, name, |
||
426 | bytes_written, err)) |
||
427 | return FALSE; |
||
428 | |||
429 | /* 03 - IDB_DESCRIPTION */ |
||
430 | /* write interface description string if applicable */ |
||
431 | if (!pcapng_write_string_option(pfile, IDB_DESCRIPTION, descr, |
||
432 | bytes_written, err)) |
||
433 | return FALSE; |
||
434 | |||
435 | /* 08 - IDB_IF_SPEED */ |
||
436 | if (if_speed != 0) { |
||
437 | option.type = IDB_IF_SPEED; |
||
438 | option.value_length = sizeof(guint64); |
||
439 | |||
440 | if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err)) |
||
441 | return FALSE; |
||
442 | |||
443 | if (!write_to_file(pfile, (const guint8*)&if_speed, sizeof(guint64), bytes_written, err)) |
||
444 | return FALSE; |
||
445 | } |
||
446 | |||
447 | /* 09 - IDB_TSRESOL */ |
||
448 | if (tsresol != 0) { |
||
449 | option.type = IDB_TSRESOL; |
||
450 | option.value_length = sizeof(guint8); |
||
451 | |||
452 | if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err)) |
||
453 | return FALSE; |
||
454 | |||
455 | if (!write_to_file(pfile, (const guint8*)&tsresol, sizeof(guint8), bytes_written, err)) |
||
456 | return FALSE; |
||
457 | |||
458 | if (!write_to_file(pfile, (const guint8*)&padding, 3, bytes_written, err)) |
||
459 | return FALSE; |
||
460 | } |
||
461 | |||
462 | /* 11 - IDB_FILTER - write filter string if applicable |
||
463 | * We only write version 1 of the filter, pcapng string |
||
464 | */ |
||
465 | if ((filter != NULL) && (strlen(filter) > 0) && (strlen(filter) < G_MAXUINT16 - 1)) { |
||
466 | option.type = IDB_FILTER; |
||
467 | option.value_length = (guint16)(strlen(filter) + 1 ); |
||
468 | if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err)) |
||
469 | return FALSE; |
||
470 | |||
471 | /* The first byte of the Option Data keeps a code of the filter used, 0 = lipbpcap filter string */ |
||
472 | if (!write_to_file(pfile, (const guint8*)&padding, 1, bytes_written, err)) |
||
473 | return FALSE; |
||
474 | if (!write_to_file(pfile, (const guint8*)filter, (int) strlen(filter), bytes_written, err)) |
||
475 | return FALSE; |
||
476 | if ((strlen(filter) + 1) % 4) { |
||
477 | if (!write_to_file(pfile, (const guint8*)&padding, 4 - (strlen(filter) + 1) % 4, bytes_written, err)) |
||
478 | return FALSE; |
||
479 | } |
||
480 | } |
||
481 | |||
482 | /* 12 - IDB_OS - write os string if applicable */ |
||
483 | if (!pcapng_write_string_option(pfile, IDB_OS, os, |
||
484 | bytes_written, err)) |
||
485 | return FALSE; |
||
486 | |||
487 | if (options_length != 0) { |
||
488 | /* write end of options */ |
||
489 | option.type = OPT_ENDOFOPT; |
||
490 | option.value_length = 0; |
||
491 | if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err)) |
||
492 | return FALSE; |
||
493 | } |
||
494 | |||
495 | /* write the trailing Block Total Length */ |
||
496 | return write_to_file(pfile, (const guint8*)&block_total_length, sizeof(guint32), bytes_written, err); |
||
497 | } |
||
498 | |||
499 | /* Write a record for a packet to a dump file. |
||
500 | Returns TRUE on success, FALSE on failure. */ |
||
501 | gboolean |
||
502 | pcapng_write_enhanced_packet_block(FILE* pfile, |
||
503 | const char *comment, |
||
504 | time_t sec, guint32 usec, |
||
505 | guint32 caplen, guint32 len, |
||
506 | guint32 interface_id, |
||
507 | guint ts_mul, |
||
508 | const guint8 *pd, |
||
509 | guint32 flags, |
||
510 | guint64 *bytes_written, |
||
511 | int *err) |
||
512 | { |
||
513 | struct epb epb; |
||
514 | struct option option; |
||
515 | guint32 block_total_length; |
||
516 | guint64 timestamp; |
||
517 | guint32 options_length; |
||
518 | const guint32 padding = 0; |
||
519 | |||
520 | block_total_length = (guint32)(sizeof(struct epb) + |
||
521 | ADD_PADDING(caplen) + |
||
522 | sizeof(guint32)); |
||
523 | options_length = 0; |
||
524 | options_length += pcapng_count_string_option(comment); |
||
525 | if (flags != 0) { |
||
526 | options_length += (guint32)(sizeof(struct option) + |
||
527 | sizeof(guint32)); |
||
528 | } |
||
529 | /* If we have options add size of end-of-options */ |
||
530 | if (options_length != 0) { |
||
531 | options_length += (guint32)sizeof(struct option); |
||
532 | } |
||
533 | block_total_length += options_length; |
||
534 | timestamp = (guint64)sec * ts_mul + (guint64)usec; |
||
535 | epb.block_type = ENHANCED_PACKET_BLOCK_TYPE; |
||
536 | epb.block_total_length = block_total_length; |
||
537 | epb.interface_id = interface_id; |
||
538 | epb.timestamp_high = (guint32)((timestamp>>32) & 0xffffffff); |
||
539 | epb.timestamp_low = (guint32)(timestamp & 0xffffffff); |
||
540 | epb.captured_len = caplen; |
||
541 | epb.packet_len = len; |
||
542 | if (!write_to_file(pfile, (const guint8*)&epb, sizeof(struct epb), bytes_written, err)) |
||
543 | return FALSE; |
||
544 | if (!write_to_file(pfile, pd, caplen, bytes_written, err)) |
||
545 | return FALSE; |
||
546 | if (caplen % 4) { |
||
547 | if (!write_to_file(pfile, (const guint8*)&padding, 4 - caplen % 4, bytes_written, err)) |
||
548 | return FALSE; |
||
549 | } |
||
550 | if (!pcapng_write_string_option(pfile, OPT_COMMENT, comment, |
||
551 | bytes_written, err)) |
||
552 | return FALSE; |
||
553 | if (flags != 0) { |
||
554 | option.type = EPB_FLAGS; |
||
555 | option.value_length = sizeof(guint32); |
||
556 | if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err)) |
||
557 | return FALSE; |
||
558 | if (!write_to_file(pfile, (const guint8*)&flags, sizeof(guint32), bytes_written, err)) |
||
559 | return FALSE; |
||
560 | } |
||
561 | if (options_length != 0) { |
||
562 | /* write end of options */ |
||
563 | option.type = OPT_ENDOFOPT; |
||
564 | option.value_length = 0; |
||
565 | if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err)) |
||
566 | return FALSE; |
||
567 | } |
||
568 | |||
569 | return write_to_file(pfile, (const guint8*)&block_total_length, sizeof(guint32), bytes_written, err); |
||
570 | } |
||
571 | |||
572 | gboolean |
||
573 | pcapng_write_interface_statistics_block(FILE* pfile, |
||
574 | guint32 interface_id, |
||
575 | guint64 *bytes_written, |
||
576 | const char *comment, /* OPT_COMMENT 1 */ |
||
577 | guint64 isb_starttime, /* ISB_STARTTIME 2 */ |
||
578 | guint64 isb_endtime, /* ISB_ENDTIME 3 */ |
||
579 | guint64 isb_ifrecv, /* ISB_IFRECV 4 */ |
||
580 | guint64 isb_ifdrop, /* ISB_IFDROP 5 */ |
||
581 | int *err) |
||
582 | { |
||
583 | struct isb isb; |
||
584 | #ifdef _WIN32 |
||
585 | FILETIME now; |
||
586 | #else |
||
587 | struct timeval now; |
||
588 | #endif |
||
589 | struct option option; |
||
590 | guint32 block_total_length; |
||
591 | guint32 options_length; |
||
592 | guint64 timestamp; |
||
593 | |||
594 | #ifdef _WIN32 |
||
595 | /* |
||
596 | * Current time, represented as 100-nanosecond intervals since |
||
597 | * January 1, 1601, 00:00:00 UTC. |
||
598 | * |
||
599 | * I think DWORD might be signed, so cast both parts of "now" |
||
600 | * to guint32 so that the sign bit doesn't get treated specially. |
||
601 | * |
||
602 | * Windows 8 provides GetSystemTimePreciseAsFileTime which we |
||
603 | * might want to use instead. |
||
604 | */ |
||
605 | GetSystemTimeAsFileTime(&now); |
||
606 | timestamp = (((guint64)(guint32)now.dwHighDateTime) << 32) + |
||
607 | (guint32)now.dwLowDateTime; |
||
608 | |||
609 | /* |
||
610 | * Convert to same thing but as 1-microsecond, i.e. 1000-nanosecond, |
||
611 | * intervals. |
||
612 | */ |
||
613 | timestamp /= 10; |
||
614 | |||
615 | /* |
||
616 | * Subtract difference, in microseconds, between January 1, 1601 |
||
617 | * 00:00:00 UTC and January 1, 1970, 00:00:00 UTC. |
||
618 | */ |
||
619 | timestamp -= G_GUINT64_CONSTANT(11644473600000000); |
||
620 | #else |
||
621 | /* |
||
622 | * Current time, represented as seconds and microseconds since |
||
623 | * January 1, 1970, 00:00:00 UTC. |
||
624 | */ |
||
625 | gettimeofday(&now, NULL); |
||
626 | |||
627 | /* |
||
628 | * Convert to delta in microseconds. |
||
629 | */ |
||
630 | timestamp = (guint64)(now.tv_sec) * 1000000 + |
||
631 | (guint64)(now.tv_usec); |
||
632 | #endif |
||
633 | block_total_length = (guint32)(sizeof(struct isb) + sizeof(guint32)); |
||
634 | options_length = 0; |
||
635 | if (isb_ifrecv != G_MAXUINT64) { |
||
636 | options_length += (guint32)(sizeof(struct option) + |
||
637 | sizeof(guint64)); |
||
638 | } |
||
639 | if (isb_ifdrop != G_MAXUINT64) { |
||
640 | options_length += (guint32)(sizeof(struct option) + |
||
641 | sizeof(guint64)); |
||
642 | } |
||
643 | /* OPT_COMMENT */ |
||
644 | options_length += pcapng_count_string_option(comment); |
||
645 | if (isb_starttime !=0) { |
||
646 | options_length += (guint32)(sizeof(struct option) + |
||
647 | sizeof(guint64)); /* ISB_STARTTIME */ |
||
648 | } |
||
649 | if (isb_endtime !=0) { |
||
650 | options_length += (guint32)(sizeof(struct option) + |
||
651 | sizeof(guint64)); /* ISB_ENDTIME */ |
||
652 | } |
||
653 | /* If we have options add size of end-of-options */ |
||
654 | if (options_length != 0) { |
||
655 | options_length += (guint32)sizeof(struct option); |
||
656 | } |
||
657 | block_total_length += options_length; |
||
658 | |||
659 | isb.block_type = INTERFACE_STATISTICS_BLOCK_TYPE; |
||
660 | isb.block_total_length = block_total_length; |
||
661 | isb.interface_id = interface_id; |
||
662 | isb.timestamp_high = (guint32)((timestamp>>32) & 0xffffffff); |
||
663 | isb.timestamp_low = (guint32)(timestamp & 0xffffffff); |
||
664 | if (!write_to_file(pfile, (const guint8*)&isb, sizeof(struct isb), bytes_written, err)) |
||
665 | return FALSE; |
||
666 | |||
667 | /* write comment string if applicable */ |
||
668 | if (!pcapng_write_string_option(pfile, OPT_COMMENT, comment, |
||
669 | bytes_written, err)) |
||
670 | return FALSE; |
||
671 | |||
672 | if (isb_starttime !=0) { |
||
673 | guint32 high, low; |
||
674 | |||
675 | option.type = ISB_STARTTIME; |
||
676 | option.value_length = sizeof(guint64); |
||
677 | high = (guint32)((isb_starttime>>32) & 0xffffffff); |
||
678 | low = (guint32)(isb_starttime & 0xffffffff); |
||
679 | if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err)) |
||
680 | return FALSE; |
||
681 | |||
682 | if (!write_to_file(pfile, (const guint8*)&high, sizeof(guint32), bytes_written, err)) |
||
683 | return FALSE; |
||
684 | |||
685 | if (!write_to_file(pfile, (const guint8*)&low, sizeof(guint32), bytes_written, err)) |
||
686 | return FALSE; |
||
687 | } |
||
688 | if (isb_endtime !=0) { |
||
689 | guint32 high, low; |
||
690 | |||
691 | option.type = ISB_ENDTIME; |
||
692 | option.value_length = sizeof(guint64); |
||
693 | high = (guint32)((isb_endtime>>32) & 0xffffffff); |
||
694 | low = (guint32)(isb_endtime & 0xffffffff); |
||
695 | if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err)) |
||
696 | return FALSE; |
||
697 | |||
698 | if (!write_to_file(pfile, (const guint8*)&high, sizeof(guint32), bytes_written, err)) |
||
699 | return FALSE; |
||
700 | |||
701 | if (!write_to_file(pfile, (const guint8*)&low, sizeof(guint32), bytes_written, err)) |
||
702 | return FALSE; |
||
703 | } |
||
704 | if (isb_ifrecv != G_MAXUINT64) { |
||
705 | option.type = ISB_IFRECV; |
||
706 | option.value_length = sizeof(guint64); |
||
707 | if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err)) |
||
708 | return FALSE; |
||
709 | |||
710 | if (!write_to_file(pfile, (const guint8*)&isb_ifrecv, sizeof(guint64), bytes_written, err)) |
||
711 | return FALSE; |
||
712 | } |
||
713 | if (isb_ifdrop != G_MAXUINT64) { |
||
714 | option.type = ISB_IFDROP; |
||
715 | option.value_length = sizeof(guint64); |
||
716 | if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err)) |
||
717 | return FALSE; |
||
718 | |||
719 | if (!write_to_file(pfile, (const guint8*)&isb_ifdrop, sizeof(guint64), bytes_written, err)) |
||
720 | return FALSE; |
||
721 | } |
||
722 | if (options_length != 0) { |
||
723 | /* write end of options */ |
||
724 | option.type = OPT_ENDOFOPT; |
||
725 | option.value_length = 0; |
||
726 | if (!write_to_file(pfile, (const guint8*)&option, sizeof(struct option), bytes_written, err)) |
||
727 | return FALSE; |
||
728 | } |
||
729 | |||
730 | return write_to_file(pfile, (const guint8*)&block_total_length, sizeof(guint32), bytes_written, err); |
||
731 | } |
||
732 | |||
733 | /* |
||
734 | * Editor modelines - http://www.wireshark.org/tools/modelines.html |
||
735 | * |
||
736 | * Local variables: |
||
737 | * c-basic-offset: 8 |
||
738 | * tab-width: 8 |
||
739 | * indent-tabs-mode: nil |
||
740 | * End: |
||
741 | * |
||
742 | * vi: set shiftwidth=8 tabstop=8 expandtab: |
||
743 | * :indentSize=8:tabSize=8:noTabs=true: |
||
744 | */ |