/src/wireshark/wiretap/iptrace.c
Line | Count | Source |
1 | | /* iptrace.c |
2 | | * |
3 | | * Wiretap Library |
4 | | * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu> |
5 | | * |
6 | | * SPDX-License-Identifier: GPL-2.0-or-later |
7 | | * |
8 | | */ |
9 | | #include "config.h" |
10 | | #include "iptrace.h" |
11 | | |
12 | | #include <stdlib.h> |
13 | | #include <string.h> |
14 | | |
15 | | #include <wsutil/array.h> |
16 | | #include <wsutil/pint.h> |
17 | | |
18 | | #include "wtap_module.h" |
19 | | #include "file_wrappers.h" |
20 | | #include "atm.h" |
21 | | |
22 | | /* |
23 | | * iptrace is the capture program that comes with AIX 3.x and 4.x. AIX 3 uses |
24 | | * the iptrace 1.0 file format, while AIX4 uses iptrace 2.0. iptrace has |
25 | | * an undocumented, yet very simple, file format. The interesting thing |
26 | | * about iptrace is that it will record packets coming in from all network |
27 | | * interfaces; a single iptrace file can contain multiple datalink types. |
28 | | */ |
29 | | |
30 | | /* |
31 | | * Private per-wtap_t data needed to read a file. |
32 | | */ |
33 | | typedef struct { |
34 | | GHashTable *interface_ids; /* map name/description/link-layer type to interface ID */ |
35 | | unsigned num_interface_ids; /* Number of interface IDs assigned */ |
36 | | } iptrace_t; |
37 | | |
38 | 0 | #define IPTRACE_IFT_HF 0x3d /* Support for PERCS IP-HFI*/ |
39 | 0 | #define IPTRACE_IFT_IB 0xc7 /* IP over Infiniband. Number by IANA */ |
40 | | |
41 | | static void iptrace_close(wtap *wth); |
42 | | |
43 | | static bool iptrace_read_1_0(wtap *wth, wtap_rec *rec, |
44 | | int *err, char **err_info, int64_t *data_offset); |
45 | | static bool iptrace_seek_read_1_0(wtap *wth, int64_t seek_off, |
46 | | wtap_rec *rec, int *err, char **err_info); |
47 | | |
48 | | static bool iptrace_read_2_0(wtap *wth, wtap_rec *rec, |
49 | | int *err, char **err_info, int64_t *data_offset); |
50 | | static bool iptrace_seek_read_2_0(wtap *wth, int64_t seek_off, |
51 | | wtap_rec *rec, int *err, char **err_info); |
52 | | |
53 | | static bool iptrace_read_rec_data(FILE_T fh, |
54 | | wtap_rec *rec, int *err, char **err_info); |
55 | | static void fill_in_pseudo_header(int encap, |
56 | | union wtap_pseudo_header *pseudo_header, const char *pkt_text); |
57 | | static int wtap_encap_ift(unsigned int ift); |
58 | | |
59 | | /* |
60 | | * Size of the version string in the file header. |
61 | | */ |
62 | 0 | #define VERSION_STRING_SIZE 11 |
63 | | |
64 | | /* |
65 | | * Hash table to map interface name and description, and link-layer |
66 | | * type, to interface ID. |
67 | | */ |
68 | 0 | #define PREFIX_SIZE 4 |
69 | | |
70 | | typedef struct { |
71 | | char prefix[PREFIX_SIZE+1]; |
72 | | uint8_t unit; |
73 | | uint8_t if_type; |
74 | | } if_info; |
75 | | |
76 | | static int iptrace_1_0_file_type_subtype = -1; |
77 | | static int iptrace_2_0_file_type_subtype = -1; |
78 | | |
79 | | void register_iptrace(void); |
80 | | |
81 | | static gboolean destroy_if_info(void *key, void *value _U_, |
82 | | void *user_data _U_) |
83 | 0 | { |
84 | 0 | if_info *info = (if_info *)key; |
85 | |
|
86 | 0 | g_free(info); |
87 | |
|
88 | 0 | return true; |
89 | 0 | } |
90 | | |
91 | | static unsigned if_info_hash(const void *info_arg) |
92 | 0 | { |
93 | 0 | if_info *info = (if_info *)info_arg; |
94 | |
|
95 | 0 | return g_str_hash(info->prefix) + info->unit + info->if_type; |
96 | 0 | } |
97 | | |
98 | | static gboolean if_info_equal(const void *info1_arg, const void *info2_arg) |
99 | 0 | { |
100 | 0 | if_info *info1 = (if_info *)info1_arg; |
101 | 0 | if_info *info2 = (if_info *)info2_arg; |
102 | |
|
103 | 0 | return strcmp(info1->prefix, info2->prefix) == 0 && |
104 | 0 | info1->unit == info2->unit && |
105 | 0 | info1->if_type == info2->if_type; |
106 | 0 | } |
107 | | |
108 | | wtap_open_return_val iptrace_open(wtap *wth, int *err, char **err_info) |
109 | 0 | { |
110 | 0 | char version_string[VERSION_STRING_SIZE+1]; |
111 | 0 | iptrace_t *iptrace; |
112 | |
|
113 | 0 | if (!wtap_read_bytes(wth->fh, version_string, VERSION_STRING_SIZE, |
114 | 0 | err, err_info)) { |
115 | 0 | if (*err != WTAP_ERR_SHORT_READ) |
116 | 0 | return WTAP_OPEN_ERROR; |
117 | 0 | return WTAP_OPEN_NOT_MINE; |
118 | 0 | } |
119 | 0 | version_string[VERSION_STRING_SIZE] = '\0'; |
120 | |
|
121 | 0 | if (strcmp(version_string, "iptrace 1.0") == 0) { |
122 | 0 | wth->file_type_subtype = iptrace_1_0_file_type_subtype; |
123 | 0 | wth->subtype_read = iptrace_read_1_0; |
124 | 0 | wth->subtype_seek_read = iptrace_seek_read_1_0; |
125 | 0 | wth->file_tsprec = WTAP_TSPREC_SEC; |
126 | 0 | } |
127 | 0 | else if (strcmp(version_string, "iptrace 2.0") == 0) { |
128 | 0 | wth->file_type_subtype = iptrace_2_0_file_type_subtype; |
129 | 0 | wth->subtype_read = iptrace_read_2_0; |
130 | 0 | wth->subtype_seek_read = iptrace_seek_read_2_0; |
131 | 0 | wth->file_tsprec = WTAP_TSPREC_NSEC; |
132 | 0 | } |
133 | 0 | else { |
134 | 0 | return WTAP_OPEN_NOT_MINE; |
135 | 0 | } |
136 | | |
137 | | /* This is an iptrace file */ |
138 | 0 | wth->subtype_close = iptrace_close; |
139 | 0 | iptrace = g_new(iptrace_t, 1); |
140 | 0 | iptrace->interface_ids = g_hash_table_new(if_info_hash, if_info_equal); |
141 | 0 | iptrace->num_interface_ids = 0; |
142 | 0 | wth->priv = (void *)iptrace; |
143 | |
|
144 | 0 | return WTAP_OPEN_MINE; |
145 | 0 | } |
146 | | |
147 | | static void iptrace_close(wtap *wth) |
148 | 0 | { |
149 | 0 | iptrace_t *iptrace = (iptrace_t *)wth->priv; |
150 | |
|
151 | 0 | g_hash_table_foreach_remove(iptrace->interface_ids, destroy_if_info, NULL); |
152 | 0 | g_hash_table_destroy(iptrace->interface_ids); |
153 | 0 | } |
154 | | |
155 | | static void add_new_if_info(iptrace_t *iptrace, if_info *info, void * *result) |
156 | 0 | { |
157 | 0 | if_info *new_info = g_new(if_info, 1); |
158 | 0 | *new_info = *info; |
159 | 0 | *result = GUINT_TO_POINTER(iptrace->num_interface_ids); |
160 | 0 | g_hash_table_insert(iptrace->interface_ids, (void *)new_info, *result); |
161 | 0 | iptrace->num_interface_ids++; |
162 | 0 | } |
163 | | |
164 | | /*********************************************************** |
165 | | * iptrace 1.0 * |
166 | | ***********************************************************/ |
167 | | |
168 | | /* |
169 | | * iptrace 1.0, discovered through inspection |
170 | | * |
171 | | * Packet record contains: |
172 | | * |
173 | | * an initial header, with a length field and a time stamp, in |
174 | | * seconds since the Epoch; |
175 | | * |
176 | | * data, with the specified length. |
177 | | * |
178 | | * The data contains: |
179 | | * |
180 | | * a bunch of information about the packet; |
181 | | * |
182 | | * padding, at least for FDDI; |
183 | | * |
184 | | * the raw packet data. |
185 | | */ |
186 | | |
187 | | /* |
188 | | * Offsets of fields in the initial header. |
189 | | */ |
190 | 0 | #define IPTRACE_1_0_REC_LENGTH_OFFSET 0 /* 0-3: size of record data */ |
191 | 0 | #define IPTRACE_1_0_TV_SEC_OFFSET 4 /* 4-7: time stamp, seconds since the Epoch */ |
192 | | |
193 | 0 | #define IPTRACE_1_0_PHDR_SIZE 8 /* initial header */ |
194 | | |
195 | | /* |
196 | | * Offsets of fields in the packet information. |
197 | | */ |
198 | | /* Bytes 0-2 unknown */ |
199 | 0 | #define IPTRACE_1_0_UNIT_OFFSET 3 /* 3: interface unit number */ |
200 | 0 | #define IPTRACE_1_0_PREFIX_OFFSET 4 /* 4-7: null-terminated name prefix */ |
201 | 0 | #define IPTRACE_1_0_PKT_TEXT_OFFSET 8 /* 8-19: text in 2.0; what is it in 1.0? */ |
202 | 0 | #define IPTRACE_1_0_IF_TYPE_OFFSET 20 /* 20: SNMP ifType value */ |
203 | 0 | #define IPTRACE_1_0_TX_FLAGS_OFFSET 21 /* 21: 0=receive, 1=transmit */ |
204 | | |
205 | 0 | #define IPTRACE_1_0_PINFO_SIZE 22 /* packet information */ |
206 | | |
207 | | static bool |
208 | | iptrace_read_rec_1_0(wtap *wth, FILE_T fh, wtap_rec *rec, |
209 | | int *err, char **err_info) |
210 | 0 | { |
211 | 0 | iptrace_t *iptrace = (iptrace_t *)wth->priv; |
212 | 0 | uint8_t header[IPTRACE_1_0_PHDR_SIZE]; |
213 | 0 | uint32_t record_length; |
214 | 0 | uint8_t pkt_info[IPTRACE_1_0_PINFO_SIZE]; |
215 | 0 | if_info info; |
216 | 0 | uint32_t packet_size; |
217 | 0 | void *result; |
218 | |
|
219 | 0 | if (!wtap_read_bytes_or_eof(fh, header, IPTRACE_1_0_PHDR_SIZE, err, |
220 | 0 | err_info)) { |
221 | | /* Read error or EOF */ |
222 | 0 | return false; |
223 | 0 | } |
224 | | |
225 | | /* Get the record length */ |
226 | 0 | record_length = pntohu32(&header[IPTRACE_1_0_REC_LENGTH_OFFSET]); |
227 | 0 | if (record_length < IPTRACE_1_0_PINFO_SIZE) { |
228 | | /* |
229 | | * Uh-oh, the record isn't big enough to even have a |
230 | | * packet information header. |
231 | | */ |
232 | 0 | *err = WTAP_ERR_BAD_FILE; |
233 | 0 | *err_info = ws_strdup_printf("iptrace: file has a %u-byte record, too small to have even a packet information header", |
234 | 0 | record_length); |
235 | 0 | return false; |
236 | 0 | } |
237 | | |
238 | | /* |
239 | | * Get the packet information. |
240 | | */ |
241 | 0 | if (!wtap_read_bytes(fh, pkt_info, IPTRACE_1_0_PINFO_SIZE, err, |
242 | 0 | err_info)) { |
243 | | /* Read error or EOF */ |
244 | 0 | return false; |
245 | 0 | } |
246 | | |
247 | 0 | wtap_setup_packet_rec(rec, wth->file_encap); |
248 | 0 | rec->block = wtap_block_create(WTAP_BLOCK_PACKET); |
249 | | |
250 | | /* |
251 | | * The if_type field of the frame header appears to be an SNMP |
252 | | * ifType value giving the type of the interface. Check out the |
253 | | * <net/if_types.h> header file. |
254 | | */ |
255 | 0 | info.if_type = pkt_info[IPTRACE_1_0_IF_TYPE_OFFSET]; |
256 | 0 | rec->rec_header.packet_header.pkt_encap = wtap_encap_ift(info.if_type); |
257 | 0 | if (rec->rec_header.packet_header.pkt_encap == WTAP_ENCAP_UNKNOWN) { |
258 | 0 | *err = WTAP_ERR_UNSUPPORTED; |
259 | 0 | *err_info = ws_strdup_printf("iptrace: interface type IFT=0x%02x unknown or unsupported", |
260 | 0 | info.if_type); |
261 | 0 | return false; |
262 | 0 | } |
263 | | |
264 | | /* Get the packet data size */ |
265 | 0 | packet_size = record_length - IPTRACE_1_0_PINFO_SIZE; |
266 | | |
267 | | /* |
268 | | * AIX appears to put 3 bytes of padding in front of FDDI |
269 | | * frames; strip that crap off. |
270 | | */ |
271 | 0 | if (rec->rec_header.packet_header.pkt_encap == WTAP_ENCAP_FDDI_BITSWAPPED) { |
272 | | /* |
273 | | * The packet size is really a record size and includes |
274 | | * the padding. |
275 | | */ |
276 | 0 | if (packet_size < 3) { |
277 | | /* |
278 | | * Uh-oh, the record isn't big enough to even have |
279 | | * the padding. |
280 | | */ |
281 | 0 | *err = WTAP_ERR_BAD_FILE; |
282 | 0 | *err_info = ws_strdup_printf("iptrace: file has a %u-byte record, too small to have even a packet meta-data header", |
283 | 0 | record_length); |
284 | 0 | return false; |
285 | 0 | } |
286 | 0 | packet_size -= 3; |
287 | | |
288 | | /* |
289 | | * Skip the padding. |
290 | | */ |
291 | 0 | if (!wtap_read_bytes(fh, NULL, 3, err, err_info)) |
292 | 0 | return false; |
293 | 0 | } |
294 | 0 | if (packet_size > WTAP_MAX_PACKET_SIZE_STANDARD) { |
295 | | /* |
296 | | * Probably a corrupt capture file; don't blow up trying |
297 | | * to allocate space for an immensely-large packet. |
298 | | */ |
299 | 0 | *err = WTAP_ERR_BAD_FILE; |
300 | 0 | *err_info = ws_strdup_printf("iptrace: File has %u-byte packet, bigger than maximum of %u", |
301 | 0 | packet_size, WTAP_MAX_PACKET_SIZE_STANDARD); |
302 | 0 | return false; |
303 | 0 | } |
304 | | |
305 | 0 | rec->presence_flags = WTAP_HAS_TS | WTAP_HAS_INTERFACE_ID; |
306 | 0 | rec->rec_header.packet_header.len = packet_size; |
307 | 0 | rec->rec_header.packet_header.caplen = packet_size; |
308 | 0 | rec->ts.secs = pntohu32(&header[IPTRACE_1_0_TV_SEC_OFFSET]); |
309 | 0 | rec->ts.nsecs = 0; |
310 | 0 | wtap_block_add_uint32_option(rec->block, OPT_PKT_FLAGS, |
311 | 0 | pkt_info[IPTRACE_1_0_TX_FLAGS_OFFSET] ? |
312 | 0 | (PACK_FLAGS_DIRECTION_OUTBOUND << PACK_FLAGS_DIRECTION_SHIFT) : |
313 | 0 | (PACK_FLAGS_DIRECTION_INBOUND << PACK_FLAGS_DIRECTION_SHIFT)); |
314 | | |
315 | | /* Fill in the pseudo-header. */ |
316 | 0 | fill_in_pseudo_header(rec->rec_header.packet_header.pkt_encap, |
317 | 0 | &rec->rec_header.packet_header.pseudo_header, |
318 | 0 | (const char *)&pkt_info[IPTRACE_1_0_PKT_TEXT_OFFSET]); |
319 | | |
320 | | /* Get the packet data */ |
321 | 0 | if (!iptrace_read_rec_data(fh, rec, err, err_info)) |
322 | 0 | return false; |
323 | | |
324 | | /* |
325 | | * No errors - get the interface ID. |
326 | | * |
327 | | * We do *not* trust the name to be null-terminated. |
328 | | */ |
329 | 0 | memcpy(info.prefix, &pkt_info[IPTRACE_1_0_PREFIX_OFFSET], |
330 | 0 | sizeof info.prefix); |
331 | 0 | info.prefix[PREFIX_SIZE] = '\0'; |
332 | 0 | info.unit = pkt_info[IPTRACE_1_0_UNIT_OFFSET]; |
333 | | |
334 | | /* |
335 | | * Try to find the entry with that name, description, and |
336 | | * interface type. |
337 | | */ |
338 | 0 | if (!g_hash_table_lookup_extended(iptrace->interface_ids, |
339 | 0 | (const void *)&info, NULL, &result)) { |
340 | 0 | wtap_block_t int_data; |
341 | 0 | wtapng_if_descr_mandatory_t *int_data_mand; |
342 | | |
343 | | /* |
344 | | * Not found; make a new entry. |
345 | | */ |
346 | 0 | add_new_if_info(iptrace, &info, &result); |
347 | | |
348 | | /* |
349 | | * Now make a new IDB and add it. |
350 | | */ |
351 | 0 | int_data = wtap_block_create(WTAP_BLOCK_IF_ID_AND_INFO); |
352 | 0 | int_data_mand = (wtapng_if_descr_mandatory_t *)wtap_block_get_mandatory_data(int_data); |
353 | |
|
354 | 0 | int_data_mand->wtap_encap = rec->rec_header.packet_header.pkt_encap; |
355 | 0 | int_data_mand->tsprecision = WTAP_TSPREC_SEC; |
356 | 0 | int_data_mand->time_units_per_second = 1; /* No fractional time stamp */ |
357 | 0 | int_data_mand->snap_len = WTAP_MAX_PACKET_SIZE_STANDARD; /* XXX - not known */ |
358 | |
|
359 | 0 | wtap_block_add_uint8_option(int_data, OPT_IDB_TSRESOL, 0); /* 1-second resolution */ |
360 | | /* Interface statistics */ |
361 | 0 | int_data_mand->num_stat_entries = 0; |
362 | 0 | int_data_mand->interface_statistics = NULL; |
363 | |
|
364 | 0 | wtap_block_set_string_option_value_format(int_data, |
365 | 0 | OPT_IDB_NAME, "%s%u", info.prefix, info.unit); |
366 | 0 | wtap_add_idb(wth, int_data); |
367 | 0 | } |
368 | 0 | rec->rec_header.packet_header.interface_id = GPOINTER_TO_UINT(result); |
369 | 0 | return true; |
370 | 0 | } |
371 | | |
372 | | /* Read the next packet */ |
373 | | static bool iptrace_read_1_0(wtap *wth, wtap_rec *rec, |
374 | | int *err, char **err_info, int64_t *data_offset) |
375 | 0 | { |
376 | 0 | *data_offset = file_tell(wth->fh); |
377 | | |
378 | | /* Read the packet */ |
379 | 0 | if (!iptrace_read_rec_1_0(wth, wth->fh, rec, err, err_info)) { |
380 | | /* Read error or EOF */ |
381 | 0 | return false; |
382 | 0 | } |
383 | | |
384 | | /* If the per-file encapsulation isn't known, set it to this |
385 | | packet's encapsulation. |
386 | | |
387 | | If it *is* known, and it isn't this packet's encapsulation, |
388 | | set it to WTAP_ENCAP_PER_PACKET, as this file doesn't |
389 | | have a single encapsulation for all packets in the file. */ |
390 | 0 | if (wth->file_encap == WTAP_ENCAP_UNKNOWN) |
391 | 0 | wth->file_encap = rec->rec_header.packet_header.pkt_encap; |
392 | 0 | else { |
393 | 0 | if (wth->file_encap != rec->rec_header.packet_header.pkt_encap) |
394 | 0 | wth->file_encap = WTAP_ENCAP_PER_PACKET; |
395 | 0 | } |
396 | |
|
397 | 0 | return true; |
398 | 0 | } |
399 | | |
400 | | static bool iptrace_seek_read_1_0(wtap *wth, int64_t seek_off, |
401 | | wtap_rec *rec, int *err, char **err_info) |
402 | 0 | { |
403 | 0 | if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) |
404 | 0 | return false; |
405 | | |
406 | | /* Read the packet */ |
407 | 0 | if (!iptrace_read_rec_1_0(wth, wth->random_fh, rec, err, |
408 | 0 | err_info)) { |
409 | 0 | if (*err == 0) |
410 | 0 | *err = WTAP_ERR_SHORT_READ; |
411 | 0 | return false; |
412 | 0 | } |
413 | 0 | return true; |
414 | 0 | } |
415 | | |
416 | | /*********************************************************** |
417 | | * iptrace 2.0 * |
418 | | ***********************************************************/ |
419 | | |
420 | | /* |
421 | | * iptrace 2.0, discovered through inspection |
422 | | * |
423 | | * Packet record contains: |
424 | | * |
425 | | * an initial header, with a length field and a time stamp, in |
426 | | * seconds since the Epoch; |
427 | | * |
428 | | * data, with the specified length. |
429 | | * |
430 | | * The data contains: |
431 | | * |
432 | | * a bunch of information about the packet; |
433 | | * |
434 | | * padding, at least for FDDI; |
435 | | * |
436 | | * the raw packet data. |
437 | | */ |
438 | | |
439 | | /* |
440 | | * Offsets of fields in the initial header. |
441 | | */ |
442 | 0 | #define IPTRACE_2_0_REC_LENGTH_OFFSET 0 /* 0-3: size of record data */ |
443 | | #define IPTRACE_2_0_TV_SEC0_OFFSET 4 /* 4-7: time stamp, seconds since the Epoch */ |
444 | | |
445 | 0 | #define IPTRACE_2_0_PHDR_SIZE 8 /* initial header */ |
446 | | |
447 | | /* |
448 | | * Offsets of fields in the packet information. |
449 | | */ |
450 | | /* Bytes 0-2 unknown */ |
451 | 0 | #define IPTRACE_2_0_UNIT_OFFSET 3 /* 3: interface unit number */ |
452 | 0 | #define IPTRACE_2_0_PREFIX_OFFSET 4 /* 4-7: null-terminated name prefix */ |
453 | | #define IPTRACE_2_0_PKT_TEXT_OFFSET 8 /* 8-19: text stuff */ |
454 | 0 | #define IPTRACE_2_0_IF_TYPE_OFFSET 20 /* 20: SNMP ifType value */ |
455 | 0 | #define IPTRACE_2_0_TX_FLAGS_OFFSET 21 /* 21: 0=receive, 1=transmit */ |
456 | | /* Bytes 22-23 unknown */ |
457 | 0 | #define IPTRACE_2_0_TV_SEC_OFFSET 24 /* 24-27: time stamp, seconds since the Epoch */ |
458 | 0 | #define IPTRACE_2_0_TV_NSEC_OFFSET 28 /* 28-31: nanoseconds since that second */ |
459 | | |
460 | 0 | #define IPTRACE_2_0_PINFO_SIZE 32 /* packet information */ |
461 | | |
462 | | static bool |
463 | | iptrace_read_rec_2_0(wtap *wth, FILE_T fh, wtap_rec *rec, |
464 | | int *err, char **err_info) |
465 | 0 | { |
466 | 0 | iptrace_t *iptrace = (iptrace_t *)wth->priv; |
467 | 0 | uint8_t header[IPTRACE_2_0_PHDR_SIZE]; |
468 | 0 | uint32_t record_length; |
469 | 0 | uint8_t pkt_info[IPTRACE_2_0_PINFO_SIZE]; |
470 | 0 | if_info info; |
471 | 0 | uint32_t packet_size; |
472 | 0 | void *result; |
473 | |
|
474 | 0 | if (!wtap_read_bytes_or_eof(fh, header, IPTRACE_2_0_PHDR_SIZE, err, |
475 | 0 | err_info)) { |
476 | | /* Read error or EOF */ |
477 | 0 | return false; |
478 | 0 | } |
479 | | |
480 | | /* Get the record length */ |
481 | 0 | record_length = pntohu32(&header[IPTRACE_2_0_REC_LENGTH_OFFSET]); |
482 | 0 | if (record_length < IPTRACE_2_0_PINFO_SIZE) { |
483 | | /* |
484 | | * Uh-oh, the record isn't big enough to even have a |
485 | | * packet information header. |
486 | | */ |
487 | 0 | *err = WTAP_ERR_BAD_FILE; |
488 | 0 | *err_info = ws_strdup_printf("iptrace: file has a %u-byte record, too small to have even a packet information header", |
489 | 0 | record_length); |
490 | 0 | return false; |
491 | 0 | } |
492 | | |
493 | | /* |
494 | | * Get the packet information. |
495 | | */ |
496 | 0 | if (!wtap_read_bytes(fh, pkt_info, IPTRACE_2_0_PINFO_SIZE, err, |
497 | 0 | err_info)) { |
498 | | /* Read error or EOF */ |
499 | 0 | return false; |
500 | 0 | } |
501 | | |
502 | 0 | wtap_setup_packet_rec(rec, wth->file_encap); |
503 | 0 | rec->block = wtap_block_create(WTAP_BLOCK_PACKET); |
504 | | |
505 | | /* |
506 | | * The if_type field of the frame header appears to be an SNMP |
507 | | * ifType value giving the type of the interface. Check out the |
508 | | * <net/if_types.h> header file. |
509 | | */ |
510 | 0 | info.if_type = pkt_info[IPTRACE_2_0_IF_TYPE_OFFSET]; |
511 | 0 | rec->rec_header.packet_header.pkt_encap = wtap_encap_ift(info.if_type); |
512 | | #if 0 |
513 | | /* |
514 | | * We used to error out if the interface type in iptrace was |
515 | | * unknown/unhandled, but an iptrace may contain packets |
516 | | * from a variety of interfaces, some known, and others |
517 | | * unknown. |
518 | | * |
519 | | * It is better to display the data even for unknown interface |
520 | | * types, instead of erroring out. In the future, it would be |
521 | | * nice to be able to flag which frames are shown as data |
522 | | * because their interface type is unknown, and also present |
523 | | * the interface type number to the user so that it can be |
524 | | * reported easily back to the Wireshark developer. |
525 | | * |
526 | | * XXX - what types are there that are used in files but |
527 | | * that we don't handle? |
528 | | */ |
529 | | if (rec->rec_header.packet_header.pkt_encap == WTAP_ENCAP_UNKNOWN) { |
530 | | *err = WTAP_ERR_UNSUPPORTED; |
531 | | *err_info = ws_strdup_printf("iptrace: interface type IFT=0x%02x unknown or unsupported", |
532 | | info.if_type); |
533 | | return false; |
534 | | } |
535 | | #endif |
536 | | |
537 | | /* Get the packet data size */ |
538 | 0 | packet_size = record_length - IPTRACE_2_0_PINFO_SIZE; |
539 | | |
540 | | /* |
541 | | * AIX appears to put 3 bytes of padding in front of FDDI |
542 | | * frames; strip that crap off. |
543 | | */ |
544 | 0 | if (rec->rec_header.packet_header.pkt_encap == WTAP_ENCAP_FDDI_BITSWAPPED) { |
545 | | /* |
546 | | * The packet size is really a record size and includes |
547 | | * the padding. |
548 | | */ |
549 | 0 | if (packet_size < 3) { |
550 | | /* |
551 | | * Uh-oh, the record isn't big enough to even have |
552 | | * the padding. |
553 | | */ |
554 | 0 | *err = WTAP_ERR_BAD_FILE; |
555 | 0 | *err_info = ws_strdup_printf("iptrace: file has a %u-byte record, too small to have even a packet meta-data header", |
556 | 0 | record_length); |
557 | 0 | return false; |
558 | 0 | } |
559 | 0 | packet_size -= 3; |
560 | | |
561 | | /* |
562 | | * Skip the padding. |
563 | | */ |
564 | 0 | if (!wtap_read_bytes(fh, NULL, 3, err, err_info)) |
565 | 0 | return false; |
566 | 0 | } |
567 | 0 | if (packet_size > WTAP_MAX_PACKET_SIZE_STANDARD) { |
568 | | /* |
569 | | * Probably a corrupt capture file; don't blow up trying |
570 | | * to allocate space for an immensely-large packet. |
571 | | */ |
572 | 0 | *err = WTAP_ERR_BAD_FILE; |
573 | 0 | *err_info = ws_strdup_printf("iptrace: File has %u-byte packet, bigger than maximum of %u", |
574 | 0 | packet_size, WTAP_MAX_PACKET_SIZE_STANDARD); |
575 | 0 | return false; |
576 | 0 | } |
577 | | |
578 | 0 | rec->presence_flags = WTAP_HAS_TS | WTAP_HAS_INTERFACE_ID; |
579 | 0 | rec->rec_header.packet_header.len = packet_size; |
580 | 0 | rec->rec_header.packet_header.caplen = packet_size; |
581 | 0 | rec->ts.secs = pntohu32(&pkt_info[IPTRACE_2_0_TV_SEC_OFFSET]); |
582 | 0 | rec->ts.nsecs = pntohu32(&pkt_info[IPTRACE_2_0_TV_NSEC_OFFSET]); |
583 | 0 | wtap_block_add_uint32_option(rec->block, OPT_PKT_FLAGS, |
584 | 0 | pkt_info[IPTRACE_2_0_TX_FLAGS_OFFSET] ? |
585 | 0 | (PACK_FLAGS_DIRECTION_OUTBOUND << PACK_FLAGS_DIRECTION_SHIFT) : |
586 | 0 | (PACK_FLAGS_DIRECTION_INBOUND << PACK_FLAGS_DIRECTION_SHIFT)); |
587 | | |
588 | | /* Fill in the pseudo-header. */ |
589 | 0 | fill_in_pseudo_header(rec->rec_header.packet_header.pkt_encap, |
590 | 0 | &rec->rec_header.packet_header.pseudo_header, |
591 | 0 | (const char *)&pkt_info[IPTRACE_1_0_PKT_TEXT_OFFSET]); |
592 | | |
593 | | /* Get the packet data */ |
594 | 0 | if (!iptrace_read_rec_data(fh, rec, err, err_info)) |
595 | 0 | return false; |
596 | | |
597 | | /* |
598 | | * No errors - get the interface ID. |
599 | | * |
600 | | * We do *not* trust the name to be null-terminated. |
601 | | */ |
602 | 0 | memcpy(info.prefix, &pkt_info[IPTRACE_2_0_PREFIX_OFFSET], |
603 | 0 | sizeof info.prefix); |
604 | 0 | info.prefix[PREFIX_SIZE] = '\0'; |
605 | 0 | info.unit = pkt_info[IPTRACE_2_0_UNIT_OFFSET]; |
606 | | |
607 | | /* |
608 | | * Try to find the entry with that name, description, and |
609 | | * interface type. |
610 | | */ |
611 | 0 | if (!g_hash_table_lookup_extended(iptrace->interface_ids, |
612 | 0 | (const void *)&info, NULL, &result)) { |
613 | 0 | wtap_block_t int_data; |
614 | 0 | wtapng_if_descr_mandatory_t *int_data_mand; |
615 | | |
616 | | /* |
617 | | * Not found; make a new entry. |
618 | | */ |
619 | 0 | add_new_if_info(iptrace, &info, &result); |
620 | | |
621 | | /* |
622 | | * Now make a new IDB and add it. |
623 | | */ |
624 | 0 | int_data = wtap_block_create(WTAP_BLOCK_IF_ID_AND_INFO); |
625 | 0 | int_data_mand = (wtapng_if_descr_mandatory_t *)wtap_block_get_mandatory_data(int_data); |
626 | |
|
627 | 0 | int_data_mand->wtap_encap = rec->rec_header.packet_header.pkt_encap; |
628 | 0 | int_data_mand->tsprecision = WTAP_TSPREC_NSEC; |
629 | 0 | int_data_mand->time_units_per_second = 1000000000; /* Nanosecond resolution */ |
630 | 0 | int_data_mand->snap_len = WTAP_MAX_PACKET_SIZE_STANDARD; /* XXX - not known */ |
631 | |
|
632 | 0 | wtap_block_add_uint8_option(int_data, OPT_IDB_TSRESOL, 0x09); /* nanosecond resolution */ |
633 | | /* Interface statistics */ |
634 | 0 | int_data_mand->num_stat_entries = 0; |
635 | 0 | int_data_mand->interface_statistics = NULL; |
636 | |
|
637 | 0 | wtap_block_set_string_option_value_format(int_data, |
638 | 0 | OPT_IDB_NAME, "%s%u", info.prefix, info.unit); |
639 | 0 | wtap_add_idb(wth, int_data); |
640 | 0 | } |
641 | 0 | rec->rec_header.packet_header.interface_id = GPOINTER_TO_UINT(result); |
642 | 0 | return true; |
643 | 0 | } |
644 | | |
645 | | /* Read the next packet */ |
646 | | static bool iptrace_read_2_0(wtap *wth, wtap_rec *rec, |
647 | | int *err, char **err_info, int64_t *data_offset) |
648 | 0 | { |
649 | 0 | *data_offset = file_tell(wth->fh); |
650 | | |
651 | | /* Read the packet */ |
652 | 0 | if (!iptrace_read_rec_2_0(wth, wth->fh, rec, err, err_info)) { |
653 | | /* Read error or EOF */ |
654 | 0 | return false; |
655 | 0 | } |
656 | | |
657 | | /* If the per-file encapsulation isn't known, set it to this |
658 | | packet's encapsulation. |
659 | | |
660 | | If it *is* known, and it isn't this packet's encapsulation, |
661 | | set it to WTAP_ENCAP_PER_PACKET, as this file doesn't |
662 | | have a single encapsulation for all packets in the file. */ |
663 | 0 | if (wth->file_encap == WTAP_ENCAP_UNKNOWN) |
664 | 0 | wth->file_encap = rec->rec_header.packet_header.pkt_encap; |
665 | 0 | else { |
666 | 0 | if (wth->file_encap != rec->rec_header.packet_header.pkt_encap) |
667 | 0 | wth->file_encap = WTAP_ENCAP_PER_PACKET; |
668 | 0 | } |
669 | |
|
670 | 0 | return true; |
671 | 0 | } |
672 | | |
673 | | static bool iptrace_seek_read_2_0(wtap *wth, int64_t seek_off, |
674 | | wtap_rec *rec, int *err, char **err_info) |
675 | 0 | { |
676 | 0 | if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) |
677 | 0 | return false; |
678 | | |
679 | | /* Read the packet */ |
680 | 0 | if (!iptrace_read_rec_2_0(wth, wth->random_fh, rec, err, |
681 | 0 | err_info)) { |
682 | 0 | if (*err == 0) |
683 | 0 | *err = WTAP_ERR_SHORT_READ; |
684 | 0 | return false; |
685 | 0 | } |
686 | 0 | return true; |
687 | 0 | } |
688 | | |
689 | | static bool |
690 | | iptrace_read_rec_data(FILE_T fh, wtap_rec *rec, int *err, char **err_info) |
691 | 0 | { |
692 | 0 | if (!wtap_read_bytes_buffer(fh, &rec->data, rec->rec_header.packet_header.caplen, err, err_info)) |
693 | 0 | return false; |
694 | | |
695 | 0 | if (rec->rec_header.packet_header.pkt_encap == WTAP_ENCAP_ATM_PDUS) { |
696 | | /* |
697 | | * Attempt to guess from the packet data, the VPI, |
698 | | * and the VCI information about the type of traffic. |
699 | | */ |
700 | 0 | atm_guess_traffic_type(rec); |
701 | 0 | } |
702 | |
|
703 | 0 | return true; |
704 | 0 | } |
705 | | |
706 | | /* |
707 | | * Fill in the pseudo-header information we can. |
708 | | * |
709 | | * For ATM traffic, "iptrace", alas, doesn't tell us what type of traffic |
710 | | * is in the packet - it was presumably run on a machine that was one of |
711 | | * the endpoints of the connection, so in theory it could presumably have |
712 | | * told us, but, for whatever reason, it failed to do so - perhaps the |
713 | | * low-level mechanism that feeds the presumably-AAL5 frames to us doesn't |
714 | | * have access to that information (e.g., because it's in the ATM driver, |
715 | | * and the ATM driver merely knows that stuff on VPI/VCI X.Y should be |
716 | | * handed up to some particular client, it doesn't know what that client is). |
717 | | * |
718 | | * We let our caller try to figure out what kind of traffic it is, either |
719 | | * by guessing based on the VPI/VCI, guessing based on the header of the |
720 | | * packet, seeing earlier traffic that set up the circuit and specified |
721 | | * in some fashion what sort of traffic it is, or being told by the user. |
722 | | */ |
723 | | static void |
724 | | fill_in_pseudo_header(int encap, union wtap_pseudo_header *pseudo_header, |
725 | | const char *pkt_text) |
726 | 0 | { |
727 | 0 | char if_text[9]; |
728 | 0 | char *decimal; |
729 | 0 | int Vpi = 0; |
730 | 0 | int Vci = 0; |
731 | |
|
732 | 0 | switch (encap) { |
733 | | |
734 | 0 | case WTAP_ENCAP_ATM_PDUS: |
735 | | /* Rip apart the "x.y" text into Vpi/Vci numbers */ |
736 | 0 | memcpy(if_text, &pkt_text[4], 8); |
737 | 0 | if_text[8] = '\0'; |
738 | 0 | decimal = strchr(if_text, '.'); |
739 | 0 | if (decimal) { |
740 | 0 | *decimal = '\0'; |
741 | 0 | Vpi = (int)strtoul(if_text, NULL, 10); |
742 | 0 | decimal++; |
743 | 0 | Vci = (int)strtoul(decimal, NULL, 10); |
744 | 0 | } |
745 | | |
746 | | /* |
747 | | * OK, which value means "DTE->DCE" and which value means |
748 | | * "DCE->DTE"? |
749 | | */ |
750 | 0 | pseudo_header->atm.channel = pkt_text[13]; |
751 | |
|
752 | 0 | pseudo_header->atm.vpi = Vpi; |
753 | 0 | pseudo_header->atm.vci = Vci; |
754 | | |
755 | | /* We don't have this information */ |
756 | 0 | pseudo_header->atm.flags = 0; |
757 | 0 | pseudo_header->atm.cells = 0; |
758 | 0 | pseudo_header->atm.aal5t_u2u = 0; |
759 | 0 | pseudo_header->atm.aal5t_len = 0; |
760 | 0 | pseudo_header->atm.aal5t_chksum = 0; |
761 | 0 | break; |
762 | | |
763 | 0 | case WTAP_ENCAP_ETHERNET: |
764 | | /* We assume there's no FCS in this frame. */ |
765 | 0 | pseudo_header->eth.fcs_len = 0; |
766 | 0 | break; |
767 | 0 | } |
768 | 0 | } |
769 | | |
770 | | /* Given an RFC1573 (SNMP ifType) interface type, |
771 | | * return the appropriate Wiretap Encapsulation Type. |
772 | | */ |
773 | | static int |
774 | | wtap_encap_ift(unsigned int ift) |
775 | 0 | { |
776 | |
|
777 | 0 | static const int ift_encap[] = { |
778 | 0 | /* 0x0 */ WTAP_ENCAP_UNKNOWN, /* nothing */ |
779 | 0 | /* 0x1 */ WTAP_ENCAP_UNKNOWN, /* IFT_OTHER */ |
780 | 0 | /* 0x2 */ WTAP_ENCAP_UNKNOWN, /* IFT_1822 */ |
781 | 0 | /* 0x3 */ WTAP_ENCAP_UNKNOWN, /* IFT_HDH1822 */ |
782 | 0 | /* 0x4 */ WTAP_ENCAP_RAW_IP, /* IFT_X25DDN */ |
783 | 0 | /* 0x5 */ WTAP_ENCAP_UNKNOWN, /* IFT_X25 */ |
784 | 0 | /* 0x6 */ WTAP_ENCAP_ETHERNET, /* IFT_ETHER */ |
785 | 0 | /* 0x7 */ WTAP_ENCAP_ETHERNET, /* IFT_ISO88023 */ |
786 | 0 | /* 0x8 */ WTAP_ENCAP_UNKNOWN, /* IFT_ISO88024 */ |
787 | 0 | /* 0x9 */ WTAP_ENCAP_TOKEN_RING, /* IFT_ISO88025 */ |
788 | 0 | /* 0xa */ WTAP_ENCAP_UNKNOWN, /* IFT_ISO88026 */ |
789 | 0 | /* 0xb */ WTAP_ENCAP_UNKNOWN, /* IFT_STARLAN */ |
790 | 0 | /* 0xc */ WTAP_ENCAP_RAW_IP, /* IFT_P10, IBM SP switch */ |
791 | 0 | /* 0xd */ WTAP_ENCAP_UNKNOWN, /* IFT_P80 */ |
792 | 0 | /* 0xe */ WTAP_ENCAP_UNKNOWN, /* IFT_HY */ |
793 | 0 | /* 0xf */ WTAP_ENCAP_FDDI_BITSWAPPED, /* IFT_FDDI */ |
794 | 0 | /* 0x10 */ WTAP_ENCAP_LAPB, /* IFT_LAPB */ /* no data to back this up */ |
795 | 0 | /* 0x11 */ WTAP_ENCAP_UNKNOWN, /* IFT_SDLC */ |
796 | 0 | /* 0x12 */ WTAP_ENCAP_UNKNOWN, /* IFT_T1 */ |
797 | 0 | /* 0x13 */ WTAP_ENCAP_UNKNOWN, /* IFT_CEPT */ |
798 | 0 | /* 0x14 */ WTAP_ENCAP_UNKNOWN, /* IFT_ISDNBASIC */ |
799 | 0 | /* 0x15 */ WTAP_ENCAP_UNKNOWN, /* IFT_ISDNPRIMARY */ |
800 | 0 | /* 0x16 */ WTAP_ENCAP_UNKNOWN, /* IFT_PTPSERIAL */ |
801 | 0 | /* 0x17 */ WTAP_ENCAP_UNKNOWN, /* IFT_PPP */ |
802 | 0 | /* 0x18 */ WTAP_ENCAP_RAW_IP, /* IFT_LOOP */ |
803 | 0 | /* 0x19 */ WTAP_ENCAP_UNKNOWN, /* IFT_EON */ |
804 | 0 | /* 0x1a */ WTAP_ENCAP_UNKNOWN, /* IFT_XETHER */ |
805 | 0 | /* 0x1b */ WTAP_ENCAP_UNKNOWN, /* IFT_NSIP */ |
806 | 0 | /* 0x1c */ WTAP_ENCAP_UNKNOWN, /* IFT_SLIP */ |
807 | 0 | /* 0x1d */ WTAP_ENCAP_UNKNOWN, /* IFT_ULTRA */ |
808 | 0 | /* 0x1e */ WTAP_ENCAP_UNKNOWN, /* IFT_DS3 */ |
809 | 0 | /* 0x1f */ WTAP_ENCAP_UNKNOWN, /* IFT_SIP */ |
810 | 0 | /* 0x20 */ WTAP_ENCAP_UNKNOWN, /* IFT_FRELAY */ |
811 | 0 | /* 0x21 */ WTAP_ENCAP_UNKNOWN, /* IFT_RS232 */ |
812 | 0 | /* 0x22 */ WTAP_ENCAP_UNKNOWN, /* IFT_PARA */ |
813 | 0 | /* 0x23 */ WTAP_ENCAP_UNKNOWN, /* IFT_ARCNET */ |
814 | 0 | /* 0x24 */ WTAP_ENCAP_UNKNOWN, /* IFT_ARCNETPLUS */ |
815 | 0 | /* 0x25 */ WTAP_ENCAP_ATM_PDUS, /* IFT_ATM */ |
816 | 0 | }; |
817 | 0 | #define NUM_IFT_ENCAPS array_length(ift_encap) |
818 | |
|
819 | 0 | if (ift < NUM_IFT_ENCAPS) { |
820 | 0 | return ift_encap[ift]; |
821 | 0 | } |
822 | 0 | else { |
823 | 0 | switch(ift) { |
824 | | /* Infiniband*/ |
825 | 0 | case IPTRACE_IFT_IB: |
826 | 0 | return WTAP_ENCAP_INFINIBAND; |
827 | | |
828 | | /* Host Fabric Interface */ |
829 | 0 | case IPTRACE_IFT_HF: |
830 | | /* The HFI interface on AIX provides raw IP |
831 | | in the packet trace. It's unclear if the HFI |
832 | | can be configured for any other protocol, and if |
833 | | any field in the iptrace header indicates what |
834 | | that protocol is. For now, we are hard-coding |
835 | | this as RAW_IP, but if we find another iptrace file |
836 | | using HFI that provides another protocol, we will |
837 | | have to figure out which field in the iptrace file |
838 | | encodes it. */ |
839 | 0 | return WTAP_ENCAP_RAW_IP; |
840 | | |
841 | 0 | default: |
842 | 0 | return WTAP_ENCAP_UNKNOWN; |
843 | 0 | } |
844 | 0 | } |
845 | 0 | } |
846 | | |
847 | | /* Options for interface blocks. */ |
848 | | static const struct supported_option_type interface_block_options_supported[] = { |
849 | | /* No comments, just an interface name. */ |
850 | | { OPT_IDB_NAME, ONE_OPTION_SUPPORTED } |
851 | | }; |
852 | | |
853 | | static const struct supported_block_type iptrace_1_0_blocks_supported[] = { |
854 | | /* |
855 | | * iptrace supports multiple interfaces, with descriptions, and |
856 | | * supports associating packets with interfaces. Interface |
857 | | * description blocks are used for that. |
858 | | */ |
859 | | { WTAP_BLOCK_IF_ID_AND_INFO, MULTIPLE_BLOCKS_SUPPORTED, OPTION_TYPES_SUPPORTED(interface_block_options_supported) }, |
860 | | |
861 | | /* |
862 | | * iptrace is a capture format, so it obviously supports packets. |
863 | | * It supports no packet options, however. |
864 | | */ |
865 | | { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED } |
866 | | }; |
867 | | |
868 | | static const struct file_type_subtype_info iptrace_1_0_info = { |
869 | | "AIX iptrace 1.0", "iptrace_1", NULL, NULL, |
870 | | false, BLOCKS_SUPPORTED(iptrace_1_0_blocks_supported), |
871 | | NULL, NULL, NULL |
872 | | }; |
873 | | |
874 | | static const struct supported_block_type iptrace_2_0_blocks_supported[] = { |
875 | | /* |
876 | | * iptrace supports multiple interfaces, with descriptions, and |
877 | | * supports associating packets with interfaces. Interface |
878 | | * description blocks are used for that. |
879 | | */ |
880 | | { WTAP_BLOCK_IF_ID_AND_INFO, MULTIPLE_BLOCKS_SUPPORTED, OPTION_TYPES_SUPPORTED(interface_block_options_supported) }, |
881 | | |
882 | | /* |
883 | | * iptrace is a capture format, so it obviously supports packets. |
884 | | * It supports no packet options, however. |
885 | | */ |
886 | | { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED } |
887 | | }; |
888 | | |
889 | | static const struct file_type_subtype_info iptrace_2_0_info = { |
890 | | "AIX iptrace 2.0", "iptrace_2", NULL, NULL, |
891 | | false, BLOCKS_SUPPORTED(iptrace_2_0_blocks_supported), |
892 | | NULL, NULL, NULL |
893 | | }; |
894 | | |
895 | | void register_iptrace(void) |
896 | 14 | { |
897 | 14 | iptrace_1_0_file_type_subtype = wtap_register_file_type_subtype(&iptrace_1_0_info); |
898 | 14 | iptrace_2_0_file_type_subtype = wtap_register_file_type_subtype(&iptrace_2_0_info); |
899 | | |
900 | | /* |
901 | | * Register names for backwards compatibility with the |
902 | | * wtap_filetypes table in Lua. |
903 | | */ |
904 | 14 | wtap_register_backwards_compatibility_lua_name("IPTRACE_1_0", |
905 | 14 | iptrace_1_0_file_type_subtype); |
906 | 14 | wtap_register_backwards_compatibility_lua_name("IPTRACE_2_0", |
907 | 14 | iptrace_2_0_file_type_subtype); |
908 | 14 | } |
909 | | |
910 | | /* |
911 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
912 | | * |
913 | | * Local variables: |
914 | | * c-basic-offset: 8 |
915 | | * tab-width: 8 |
916 | | * indent-tabs-mode: t |
917 | | * End: |
918 | | * |
919 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
920 | | * :indentSize=8:tabSize=8:noTabs=false: |
921 | | */ |