4 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
6 * SPDX-License-Identifier: GPL-2.0-or-later
14 #include "file_wrappers.h"
15 #include <wsutil/ws_assert.h>
18 * A file begins with a header containing:
20 * a 4-byte magic number, with 'c', 'p', 's', 'e';
22 * either a 2-byte little-endian "format indicator" (version number?),
23 * or a 1-byte major version number followed by a 1-byte minor version
24 * number, or a 1-byte "format indicator" followed by something else
25 * that's always been 0;
27 * a 2-byte 0xe8 0x03 (1000 - a data rate? megabits/second?)
29 * 4 bytes of 0x01 0x00 0x01 0x00;
31 * either a 4-byte little-endian file size followed by 0x00 0x00 0x00 0x00
32 * or an 8-byte little-endian file size;
34 * a 4-byte little-endian packet count (in dns_error_of_udp, it exceeds?)
36 * a 4-byte little-endian number?
38 * hex 2c 01 c8 00 00 00 da 36 00 00 00 00 00 00;
40 * the same 4-byte little-endian number as above (yes, misaligned);
44 * a bunch of 0s, up to an offset of 0x36d6;
48 * Following that is a sequence of { record offset block, up to 200 records }
51 * A record offset block has 1 byte with the value 0xfe, a sequence of
52 * up to 200 4-byte little-endian record offsets, and 4 or more bytes
53 * of unknown data, making the block 805 bytes long.
55 * The record offsets are offsets, from the beginning of the record offset
56 * block (i.e., from the 0xfe byte), of the records following the block.
59 /* Magic number in Capsa files. */
60 static const char capsa_magic
[] = {
65 * Before each group of 200 or fewer records there's a block of frame
66 * offsets, giving the offsets, from the beginning of that block minus
67 * one(1), of the next N records.
69 #define N_RECORDS_PER_GROUP 200
71 /* Capsa (format indicator 1) record header. */
73 uint32_t unknown1
; /* low-order 32 bits of a number? */
74 uint32_t unknown2
; /* 0x00 0x00 0x00 0x00 */
75 uint32_t timestamplo
; /* low-order 32 bits of the time stamp, in microseconds since January 1, 1970, 00:00:00 UTC */
76 uint32_t timestamphi
; /* high-order 32 bits of the time stamp, in microseconds since January 1, 1970, 00:00:00 UTC */
77 uint16_t rec_len
; /* length of record */
78 uint16_t incl_len
; /* number of octets captured in file */
79 uint16_t orig_len
; /* actual length of packet */
80 uint16_t unknown5
; /* 0x00 0x00 */
81 uint8_t count1
; /* count1*4 bytes after unknown8 */
82 uint8_t count2
; /* count2*4 bytes after that */
83 uint16_t unknown7
; /* 0x01 0x10 */
84 uint32_t unknown8
; /* 0x00 0x00 0x00 0x00 or random numbers */
87 /* Packet Builder (format indicator 2) record header. */
89 uint16_t rec_len
; /* length of record */
90 uint16_t incl_len
; /* number of octets captured in file */
91 uint16_t orig_len
; /* actual length of packet */
96 uint32_t timestamplo
; /* low-order 32 bits of the time stamp, in microseconds since January 1, 1970, 00:00:00 UTC */
97 uint32_t timestamphi
; /* high-order 32 bits of the time stamp, in microseconds since January 1, 1970, 00:00:00 UTC */
103 uint16_t format_indicator
;
104 uint32_t number_of_frames
;
105 uint32_t frame_count
;
107 uint32_t record_offsets
[N_RECORDS_PER_GROUP
];
110 static bool capsa_read(wtap
*wth
, wtap_rec
*rec
, Buffer
*buf
,
111 int *err
, char **err_info
, int64_t *data_offset
);
112 static bool capsa_seek_read(wtap
*wth
, int64_t seek_off
,
113 wtap_rec
*rec
, Buffer
*buf
, int *err
, char **err_info
);
114 static int capsa_read_packet(wtap
*wth
, FILE_T fh
, wtap_rec
*rec
,
115 Buffer
*buf
, int *err
, char **err_info
);
117 static int capsa_file_type_subtype
= -1;
118 static int packet_builder_file_type_subtype
= -1;
120 void register_capsa(void);
122 wtap_open_return_val
capsa_open(wtap
*wth
, int *err
, char **err_info
)
124 char magic
[sizeof capsa_magic
];
125 uint16_t format_indicator
;
126 int file_type_subtype
;
127 uint32_t number_of_frames
;
130 /* Read in the string that should be at the start of a Capsa file */
131 if (!wtap_read_bytes(wth
->fh
, magic
, sizeof magic
, err
, err_info
)) {
132 if (*err
!= WTAP_ERR_SHORT_READ
)
133 return WTAP_OPEN_ERROR
;
134 return WTAP_OPEN_NOT_MINE
;
137 if (memcmp(magic
, capsa_magic
, sizeof capsa_magic
) != 0) {
138 return WTAP_OPEN_NOT_MINE
;
141 /* Read the mysterious "format indicator" */
142 if (!wtap_read_bytes(wth
->fh
, &format_indicator
, sizeof format_indicator
,
144 return WTAP_OPEN_ERROR
;
145 format_indicator
= GUINT16_FROM_LE(format_indicator
);
148 * Make sure it's a format we support.
150 switch (format_indicator
) {
153 file_type_subtype
= capsa_file_type_subtype
;
156 case 2: /* Packet Builder */
157 file_type_subtype
= packet_builder_file_type_subtype
;
161 *err
= WTAP_ERR_UNSUPPORTED
;
162 *err_info
= ws_strdup_printf("capsa: format indicator %u unsupported",
164 return WTAP_OPEN_ERROR
;
168 * Link speed, in megabytes/second?
170 if (!wtap_read_bytes(wth
->fh
, NULL
, 2, err
, err_info
))
171 return WTAP_OPEN_ERROR
;
174 * Flags of some sort? Four 1-byte numbers, two of which are 1
175 * and two of which are zero? Two 2-byte numbers or flag fields,
176 * both of which are 1?
178 if (!wtap_read_bytes(wth
->fh
, NULL
, 4, err
, err_info
))
179 return WTAP_OPEN_ERROR
;
182 * File size, in bytes.
184 if (!wtap_read_bytes(wth
->fh
, NULL
, 4, err
, err_info
))
185 return WTAP_OPEN_ERROR
;
188 * Zeroes? Or upper 4 bytes of file size?
190 if (!wtap_read_bytes(wth
->fh
, NULL
, 4, err
, err_info
))
191 return WTAP_OPEN_ERROR
;
196 if (!wtap_read_bytes(wth
->fh
, &number_of_frames
, sizeof number_of_frames
,
198 return WTAP_OPEN_ERROR
;
199 number_of_frames
= GUINT32_FROM_LE(number_of_frames
);
202 * Skip past what we think is file header.
204 if (!file_seek(wth
->fh
, 0x44ef, SEEK_SET
, err
))
205 return WTAP_OPEN_ERROR
;
207 wth
->file_type_subtype
= file_type_subtype
;
208 capsa
= g_new(capsa_t
, 1);
209 capsa
->format_indicator
= format_indicator
;
210 capsa
->number_of_frames
= number_of_frames
;
211 capsa
->frame_count
= 0;
212 wth
->priv
= (void *)capsa
;
213 wth
->subtype_read
= capsa_read
;
214 wth
->subtype_seek_read
= capsa_seek_read
;
216 * XXX - we've never seen a Wi-Fi Capsa capture, so we don't
217 * yet know how to handle them.
219 wth
->file_encap
= WTAP_ENCAP_ETHERNET
;
220 wth
->snapshot_length
= 0; /* not available in header */
221 wth
->file_tsprec
= WTAP_TSPREC_USEC
;
224 * Add an IDB; we don't know how many interfaces were
225 * involved, so we just say one interface, about which
226 * we only know the link-layer type, snapshot length,
227 * and time stamp resolution.
229 wtap_add_generated_idb(wth
);
231 return WTAP_OPEN_MINE
;
234 /* Read the next packet */
235 static bool capsa_read(wtap
*wth
, wtap_rec
*rec
, Buffer
*buf
,
236 int *err
, char **err_info
, int64_t *data_offset
)
238 capsa_t
*capsa
= (capsa_t
*)wth
->priv
;
239 uint32_t frame_within_block
;
242 if (capsa
->frame_count
== capsa
->number_of_frames
) {
244 * No more frames left. Return an EOF.
249 frame_within_block
= capsa
->frame_count
% N_RECORDS_PER_GROUP
;
250 if (frame_within_block
== 0) {
252 * Here's a record offset block.
253 * Get the offset of the block, and then skip the
256 capsa
->base_offset
= file_tell(wth
->fh
);
257 if (!wtap_read_bytes(wth
->fh
, NULL
, 1, err
, err_info
))
261 * Now read the record offsets.
263 if (!wtap_read_bytes(wth
->fh
, &capsa
->record_offsets
,
264 sizeof capsa
->record_offsets
, err
, err_info
))
268 * And finish processing all 805 bytes by skipping
271 if (!wtap_read_bytes(wth
->fh
, NULL
, 4, err
, err_info
))
275 *data_offset
= capsa
->base_offset
+
276 GUINT32_FROM_LE(capsa
->record_offsets
[frame_within_block
]);
277 if (!file_seek(wth
->fh
, *data_offset
, SEEK_SET
, err
))
280 padbytes
= capsa_read_packet(wth
, wth
->fh
, rec
, buf
, err
, err_info
);
285 * Skip over the padding, if any.
288 if (!wtap_read_bytes(wth
->fh
, NULL
, padbytes
, err
, err_info
))
292 capsa
->frame_count
++;
298 capsa_seek_read(wtap
*wth
, int64_t seek_off
,
299 wtap_rec
*rec
, Buffer
*buf
, int *err
, char **err_info
)
301 if (file_seek(wth
->random_fh
, seek_off
, SEEK_SET
, err
) == -1)
304 if (capsa_read_packet(wth
, wth
->random_fh
, rec
, buf
, err
, err_info
) == -1) {
306 *err
= WTAP_ERR_SHORT_READ
;
313 capsa_read_packet(wtap
*wth
, FILE_T fh
, wtap_rec
*rec
,
314 Buffer
*buf
, int *err
, char **err_info
)
316 capsa_t
*capsa
= (capsa_t
*)wth
->priv
;
317 struct capsarec_hdr capsarec_hdr
;
318 struct pbrec_hdr pbrec_hdr
;
320 uint32_t packet_size
;
322 uint32_t header_size
;
325 /* Read record header. */
326 switch (capsa
->format_indicator
) {
329 if (!wtap_read_bytes_or_eof(fh
, &capsarec_hdr
,
330 sizeof capsarec_hdr
, err
, err_info
))
332 rec_size
= GUINT16_FROM_LE(capsarec_hdr
.rec_len
);
333 orig_size
= GUINT16_FROM_LE(capsarec_hdr
.orig_len
);
334 packet_size
= GUINT16_FROM_LE(capsarec_hdr
.incl_len
);
335 header_size
= sizeof capsarec_hdr
;
336 timestamp
= (((uint64_t)GUINT32_FROM_LE(capsarec_hdr
.timestamphi
))<<32) + GUINT32_FROM_LE(capsarec_hdr
.timestamplo
);
339 * OK, the rest of this is variable-length.
340 * We skip: (count1+count2)*4 bytes.
341 * XXX - what is that? Measured statistics?
342 * Calculated statistics?
344 if (!wtap_read_bytes(fh
, NULL
,
345 (capsarec_hdr
.count1
+ capsarec_hdr
.count2
)*4,
348 header_size
+= (capsarec_hdr
.count1
+ capsarec_hdr
.count2
)*4;
352 if (!wtap_read_bytes_or_eof(fh
, &pbrec_hdr
,
353 sizeof pbrec_hdr
, err
, err_info
))
355 rec_size
= GUINT16_FROM_LE(pbrec_hdr
.rec_len
);
356 orig_size
= GUINT16_FROM_LE(pbrec_hdr
.orig_len
);
357 packet_size
= GUINT16_FROM_LE(pbrec_hdr
.incl_len
);
358 header_size
= sizeof pbrec_hdr
;
359 timestamp
= (((uint64_t)GUINT32_FROM_LE(pbrec_hdr
.timestamphi
))<<32) + GUINT32_FROM_LE(pbrec_hdr
.timestamplo
);
361 * XXX - from the results of some conversions between
362 * Capsa format and pcap by Colasoft Packet Builder,
363 * I do not trust its conversion of time stamps (at
364 * least one of Colasoft's sample files, when
365 * converted to pcap format, has, as its time stamps,
366 * time stamps on the day after the conversion was
367 * done, which seems like more than just coincidence).
372 ws_assert_not_reached();
373 *err
= WTAP_ERR_INTERNAL
;
374 *err_info
= ws_strdup_printf("capsa: format indicator is %u", capsa
->format_indicator
);
377 if (orig_size
> WTAP_MAX_PACKET_SIZE_STANDARD
) {
379 * Probably a corrupt capture file; don't blow up trying
380 * to allocate space for an immensely-large packet.
382 *err
= WTAP_ERR_BAD_FILE
;
383 *err_info
= ws_strdup_printf("capsa: File has %u-byte original length, bigger than maximum of %u",
384 orig_size
, WTAP_MAX_PACKET_SIZE_STANDARD
);
387 if (packet_size
> WTAP_MAX_PACKET_SIZE_STANDARD
) {
389 * Probably a corrupt capture file; don't blow up trying
390 * to allocate space for an immensely-large packet.
392 *err
= WTAP_ERR_BAD_FILE
;
393 *err_info
= ws_strdup_printf("capsa: File has %u-byte packet, bigger than maximum of %u",
394 packet_size
, WTAP_MAX_PACKET_SIZE_STANDARD
);
397 if (header_size
+ packet_size
> rec_size
) {
399 * Probably a corrupt capture file.
401 *err
= WTAP_ERR_BAD_FILE
;
402 *err_info
= ws_strdup_printf("capsa: File has %u-byte packet with %u-byte record header, bigger than record size %u",
403 packet_size
, header_size
, rec_size
);
408 * The "on the wire" record size always includes the CRC.
409 * If it's greater than the "captured" size by 4, then
410 * we subtract 4 from it, to reflect the way the "on the wire"
411 * record size works for other file formats.
413 if (orig_size
== packet_size
+ 4)
414 orig_size
= packet_size
;
417 * We assume there's no FCS in this frame.
418 * XXX - is there ever one?
420 rec
->rec_header
.packet_header
.pseudo_header
.eth
.fcs_len
= 0;
422 rec
->rec_type
= REC_TYPE_PACKET
;
423 rec
->block
= wtap_block_create(WTAP_BLOCK_PACKET
);
424 rec
->rec_header
.packet_header
.caplen
= packet_size
;
425 rec
->rec_header
.packet_header
.len
= orig_size
;
426 rec
->presence_flags
= WTAP_HAS_CAP_LEN
|WTAP_HAS_TS
;
427 rec
->ts
.secs
= (time_t)(timestamp
/ 1000000);
428 rec
->ts
.nsecs
= ((int)(timestamp
% 1000000))*1000;
431 * Read the packet data.
433 if (!wtap_read_packet_bytes(fh
, buf
, packet_size
, err
, err_info
))
434 return -1; /* failed */
436 return rec_size
- (header_size
+ packet_size
);
439 static const struct supported_block_type capsa_blocks_supported
[] = {
441 * We support packet blocks, with no comments or other options.
443 { WTAP_BLOCK_PACKET
, MULTIPLE_BLOCKS_SUPPORTED
, NO_OPTIONS_SUPPORTED
}
446 static const struct file_type_subtype_info capsa_info
= {
447 "Colasoft Capsa format", "capsa", "cscpkt", NULL
,
448 false, BLOCKS_SUPPORTED(capsa_blocks_supported
),
452 static const struct supported_block_type packet_builder_blocks_supported
[] = {
454 * We support packet blocks, with no comments or other options.
456 { WTAP_BLOCK_PACKET
, MULTIPLE_BLOCKS_SUPPORTED
, NO_OPTIONS_SUPPORTED
}
459 static const struct file_type_subtype_info packet_builder_info
= {
460 "Colasoft Packet Builder format", "colasoft-pb", "cscpkt", NULL
,
461 false, BLOCKS_SUPPORTED(packet_builder_blocks_supported
),
465 void register_capsa(void)
467 capsa_file_type_subtype
= wtap_register_file_type_subtype(&capsa_info
);
468 packet_builder_file_type_subtype
= wtap_register_file_type_subtype(&packet_builder_info
);
471 * Register names for backwards compatibility with the
472 * wtap_filetypes table in Lua.
474 wtap_register_backwards_compatibility_lua_name("COLASOFT_CAPSA",
475 capsa_file_type_subtype
);
476 wtap_register_backwards_compatibility_lua_name("COLASOFT_PACKET_BUILDER",
477 packet_builder_file_type_subtype
);
481 * Editor modelines - https://www.wireshark.org/tools/modelines.html
486 * indent-tabs-mode: t
489 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
490 * :indentSize=8:tabSize=8:noTabs=false: