/src/wireshark/wiretap/dbs-etherwatch.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* dbs-etherwatch.c |
2 | | * |
3 | | * Wiretap Library |
4 | | * Copyright (c) 2001 by Marc Milgram <ethereal@mmilgram.NOSPAMmail.net> |
5 | | * |
6 | | * SPDX-License-Identifier: GPL-2.0-or-later |
7 | | */ |
8 | | |
9 | | #include "config.h" |
10 | | #include "dbs-etherwatch.h" |
11 | | #include "wtap-int.h" |
12 | | #include "file_wrappers.h" |
13 | | |
14 | | #include <stdlib.h> |
15 | | #include <string.h> |
16 | | |
17 | | /* This module reads the text output of the 'DBS-ETHERTRACE' command in VMS |
18 | | * It was initially based on vms.c. |
19 | | */ |
20 | | |
21 | | /* |
22 | | Example 'ETHERWATCH' output data (with "printable" characters in the |
23 | | "printable characters" section of the output replaced by "." if they have |
24 | | the 8th bit set, so as not to upset compilers that are expecting text |
25 | | in comments to be in a particular character encoding that can't handle |
26 | | those values): |
27 | | ETHERWATCH X5-008 |
28 | | 42 names and addresses were loaded |
29 | | Reading recorded data from PERSISTENCE |
30 | | ------------------------------------------------------------------------------ |
31 | | From 00-D0-C0-D2-4D-60 [MF1] to AA-00-04-00-FC-94 [PSERVB] |
32 | | Protocol 08-00 00 00-00-00-00-00, 60 byte buffer at 10-OCT-2001 10:20:45.16 |
33 | | [E..<8...........]- 0-[45 00 00 3C 38 93 00 00 1D 06 D2 12 80 93 11 1A] |
34 | | [.........(......]- 16-[80 93 80 D6 02 D2 02 03 00 28 A4 90 00 00 00 00] |
35 | | [................]- 32-[A0 02 FF FF 95 BD 00 00 02 04 05 B4 03 03 04 01] |
36 | | [............ ]- 48-[01 01 08 0A 90 90 E5 14 00 00 00 00] |
37 | | ------------------------------------------------------------------------------ |
38 | | From 00-D0-C0-D2-4D-60 [MF1] to AA-00-04-00-FC-94 [PSERVB] |
39 | | Protocol 08-00 00 00-00-00-00-00, 50 byte buffer at 10-OCT-2001 10:20:45.17 |
40 | | [E..(8......%....]- 0-[45 00 00 28 38 94 00 00 1D 06 D2 25 80 93 11 1A] |
41 | | [.........(..Z.4w]- 16-[80 93 80 D6 02 D2 02 03 00 28 A4 91 5A 1C 34 77] |
42 | | [P.#(.s..........]- 32-[50 10 23 28 C1 73 00 00 02 04 05 B4 03 03 00 00] |
43 | | [.. ]- 48-[02 04] |
44 | | |
45 | | |
46 | | Alternative HEX only output, slightly more efficient and all wireshark needs: |
47 | | ------------------------------------------------------------------------------ |
48 | | From 00-D0-C0-D2-4D-60 [MF1] to AA-00-04-00-FC-94 [PSERVB] |
49 | | Protocol 08-00 00 00-00-00-00-00, 50 byte buffer at 10-OCT-2001 10:20:45.17 |
50 | | 0-[45 00 00 28 38 9B 00 00 1D 06 D2 1E 80 93 11 1A 80 93 80 D6] |
51 | | 20-[02 D2 02 03 00 28 A4 BF 5A 1C 34 79 50 10 23 28 C1 43 00 00] |
52 | | 40-[03 30 30 30 30 30 00 00 03 30] |
53 | | */ |
54 | | |
55 | | /* Magic text to check for DBS-ETHERWATCH-ness of file */ |
56 | | static const char dbs_etherwatch_hdr_magic[] = |
57 | | { 'E', 'T', 'H', 'E', 'R', 'W', 'A', 'T', 'C', 'H', ' '}; |
58 | | #define DBS_ETHERWATCH_HDR_MAGIC_SIZE \ |
59 | 0 | array_length(dbs_etherwatch_hdr_magic) |
60 | | |
61 | | /* Magic text for start of packet */ |
62 | | static const char dbs_etherwatch_rec_magic[] = |
63 | | {'F', 'r', 'o', 'm', ' '}; |
64 | | #define DBS_ETHERWATCH_REC_MAGIC_SIZE \ |
65 | 0 | array_length(dbs_etherwatch_rec_magic) |
66 | | |
67 | | /* |
68 | | * Default packet size - maximum normal Ethernet packet size, without an |
69 | | * FCS. |
70 | | */ |
71 | 0 | #define DBS_ETHERWATCH_MAX_ETHERNET_PACKET_LEN 1514 |
72 | | |
73 | | static bool dbs_etherwatch_read(wtap *wth, wtap_rec *rec, |
74 | | int *err, char **err_info, int64_t *data_offset); |
75 | | static bool dbs_etherwatch_seek_read(wtap *wth, int64_t seek_off, |
76 | | wtap_rec *rec, int *err, char **err_info); |
77 | | static bool parse_dbs_etherwatch_packet(FILE_T fh, wtap_rec *rec, |
78 | | int *err, char **err_info); |
79 | | static unsigned parse_single_hex_dump_line(char* rec, uint8_t *buf, |
80 | | int byte_offset); |
81 | | static unsigned parse_hex_dump(char* dump, uint8_t *buf, char separator, char end); |
82 | | |
83 | | static int dbs_etherwatch_file_type_subtype = -1; |
84 | | |
85 | | void register_dbs_etherwatch(void); |
86 | | |
87 | | /* Seeks to the beginning of the next packet, and returns the |
88 | | byte offset. Returns -1 on failure, and sets "*err" to the error |
89 | | and "*err_info" to null or an additional error string. */ |
90 | | static int64_t dbs_etherwatch_seek_next_packet(wtap *wth, int *err, |
91 | | char **err_info) |
92 | 0 | { |
93 | 0 | int byte; |
94 | 0 | unsigned int level = 0; |
95 | 0 | int64_t cur_off; |
96 | |
|
97 | 0 | while ((byte = file_getc(wth->fh)) != EOF) { |
98 | 0 | if (byte == dbs_etherwatch_rec_magic[level]) { |
99 | 0 | level++; |
100 | 0 | if (level >= DBS_ETHERWATCH_REC_MAGIC_SIZE) { |
101 | | /* note: we're leaving file pointer right after the magic characters */ |
102 | 0 | cur_off = file_tell(wth->fh); |
103 | 0 | if (cur_off == -1) { |
104 | | /* Error. */ |
105 | 0 | *err = file_error(wth->fh, err_info); |
106 | 0 | return -1; |
107 | 0 | } |
108 | 0 | return cur_off + 1; |
109 | 0 | } |
110 | 0 | } else { |
111 | 0 | level = 0; |
112 | 0 | } |
113 | 0 | } |
114 | | /* EOF or error. */ |
115 | 0 | *err = file_error(wth->fh, err_info); |
116 | 0 | return -1; |
117 | 0 | } |
118 | | |
119 | 0 | #define DBS_ETHERWATCH_HEADER_LINES_TO_CHECK 200 |
120 | 0 | #define DBS_ETHERWATCH_LINE_LENGTH 240 |
121 | | |
122 | | /* Look through the first part of a file to see if this is |
123 | | * a DBS Ethertrace text trace file. |
124 | | * |
125 | | * Returns true if it is, false if it isn't or if we get an I/O error; |
126 | | * if we get an I/O error, "*err" will be set to a non-zero value and |
127 | | * "*err_info" will be set to null or an error string. |
128 | | */ |
129 | | static bool dbs_etherwatch_check_file_type(wtap *wth, int *err, |
130 | | char **err_info) |
131 | 0 | { |
132 | 0 | char buf[DBS_ETHERWATCH_LINE_LENGTH]; |
133 | 0 | int line, byte; |
134 | 0 | size_t reclen; |
135 | 0 | unsigned int i, level; |
136 | |
|
137 | 0 | buf[DBS_ETHERWATCH_LINE_LENGTH-1] = 0; |
138 | |
|
139 | 0 | for (line = 0; line < DBS_ETHERWATCH_HEADER_LINES_TO_CHECK; line++) { |
140 | 0 | if (file_gets(buf, DBS_ETHERWATCH_LINE_LENGTH, wth->fh) == NULL) { |
141 | | /* EOF or error. */ |
142 | 0 | *err = file_error(wth->fh, err_info); |
143 | 0 | return false; |
144 | 0 | } |
145 | | |
146 | 0 | reclen = strlen(buf); |
147 | 0 | if (reclen < DBS_ETHERWATCH_HDR_MAGIC_SIZE) |
148 | 0 | continue; |
149 | | |
150 | 0 | level = 0; |
151 | 0 | for (i = 0; i < reclen; i++) { |
152 | 0 | byte = buf[i]; |
153 | 0 | if (byte == dbs_etherwatch_hdr_magic[level]) { |
154 | 0 | level++; |
155 | 0 | if (level >= |
156 | 0 | DBS_ETHERWATCH_HDR_MAGIC_SIZE) { |
157 | 0 | return true; |
158 | 0 | } |
159 | 0 | } |
160 | 0 | else |
161 | 0 | level = 0; |
162 | 0 | } |
163 | 0 | } |
164 | 0 | *err = 0; |
165 | 0 | return false; |
166 | 0 | } |
167 | | |
168 | | |
169 | | wtap_open_return_val dbs_etherwatch_open(wtap *wth, int *err, char **err_info) |
170 | 0 | { |
171 | | /* Look for DBS ETHERWATCH header */ |
172 | 0 | if (!dbs_etherwatch_check_file_type(wth, err, err_info)) { |
173 | 0 | if (*err != 0 && *err != WTAP_ERR_SHORT_READ) |
174 | 0 | return WTAP_OPEN_ERROR; |
175 | 0 | return WTAP_OPEN_NOT_MINE; |
176 | 0 | } |
177 | | |
178 | 0 | wth->file_encap = WTAP_ENCAP_ETHERNET; |
179 | 0 | wth->file_type_subtype = dbs_etherwatch_file_type_subtype; |
180 | 0 | wth->snapshot_length = 0; /* not known */ |
181 | 0 | wth->subtype_read = dbs_etherwatch_read; |
182 | 0 | wth->subtype_seek_read = dbs_etherwatch_seek_read; |
183 | 0 | wth->file_tsprec = WTAP_TSPREC_10_MSEC; |
184 | | |
185 | | /* |
186 | | * Add an IDB; we don't know how many interfaces were |
187 | | * involved, so we just say one interface, about which |
188 | | * we only know the link-layer type, snapshot length, |
189 | | * and time stamp resolution. |
190 | | */ |
191 | 0 | wtap_add_generated_idb(wth); |
192 | |
|
193 | 0 | return WTAP_OPEN_MINE; |
194 | 0 | } |
195 | | |
196 | | /* Find the next packet and parse it; called from wtap_read(). */ |
197 | | static bool dbs_etherwatch_read(wtap *wth, wtap_rec *rec, |
198 | | int *err, char **err_info, int64_t *data_offset) |
199 | 0 | { |
200 | 0 | int64_t offset; |
201 | | |
202 | | /* Find the next packet */ |
203 | 0 | offset = dbs_etherwatch_seek_next_packet(wth, err, err_info); |
204 | 0 | if (offset < 1) |
205 | 0 | return false; |
206 | 0 | *data_offset = offset; |
207 | | |
208 | | /* Parse the packet */ |
209 | 0 | return parse_dbs_etherwatch_packet(wth->fh, rec, err, err_info); |
210 | 0 | } |
211 | | |
212 | | /* Used to read packets in random-access fashion */ |
213 | | static bool |
214 | | dbs_etherwatch_seek_read(wtap *wth, int64_t seek_off, |
215 | | wtap_rec *rec, int *err, char **err_info) |
216 | 0 | { |
217 | 0 | if (file_seek(wth->random_fh, seek_off - 1, SEEK_SET, err) == -1) |
218 | 0 | return false; |
219 | | |
220 | 0 | return parse_dbs_etherwatch_packet(wth->random_fh, rec, err, err_info); |
221 | 0 | } |
222 | | |
223 | | /* Parse a packet */ |
224 | | /* |
225 | | Packet header: |
226 | | 1 2 3 4 |
227 | | 0123456789012345678901234567890123456789012345 |
228 | | From 00-D0-C0-D2-4D-60 [MF1] to AA-00-04-00-FC-94 [PSERVB] |
229 | | Protocol 08-00 00 00-00-00-00-00, 50 byte buffer at 10-OCT-2001 10:20:45.17 |
230 | | */ |
231 | 0 | #define MAC_ADDR_LENGTH 6 /* Length MAC address */ |
232 | 0 | #define DEST_MAC_PREFIX "] to " /* Prefix to the dest. MAC address */ |
233 | 0 | #define PROTOCOL_LENGTH 2 /* Length protocol */ |
234 | 0 | #define PROTOCOL_POS 9 /* Position protocol */ |
235 | 0 | #define SAP_LENGTH 2 /* Length DSAP+SSAP */ |
236 | 0 | #define SAP_POS 9 /* Position DSAP+SSAP */ |
237 | 0 | #define CTL_UNNUMB_LENGTH 1 /* Length unnumbered control field */ |
238 | 0 | #define CTL_NUMB_LENGTH 2 /* Length numbered control field */ |
239 | 0 | #define CTL_POS 15 /* Position control field */ |
240 | 0 | #define PID_LENGTH 5 /* Length PID */ |
241 | 0 | #define PID_POS 18 /* Position PID */ |
242 | 0 | #define LENGTH_POS 33 /* Position length */ |
243 | 0 | #define HEX_HDR_SPR '-' /* Separator char header hex values */ |
244 | 0 | #define HEX_HDR_END ' ' /* End char hdr. hex val. except PID */ |
245 | 0 | #define HEX_PID_END ',' /* End char PID hex value */ |
246 | 0 | #define IEEE802_LEN_LEN 2 /* Length of the IEEE 802 len. field */ |
247 | | /* |
248 | | To check whether it is Ethernet II or IEEE 802 we check the values of the |
249 | | control field and PID, when they are all 0's we assume it is Ethernet II |
250 | | else IEEE 802. In IEEE 802 the DSAP and SSAP are behind protocol, the |
251 | | length in the IEEE data we have to construct. |
252 | | */ |
253 | 0 | #define ETH_II_CHECK_POS 15 |
254 | 0 | #define ETH_II_CHECK_STR "00 00-00-00-00-00," |
255 | | /* |
256 | | To check whether it IEEE 802.3 with SNAP we check that both the DSAP & SSAP |
257 | | values are 0xAA and the control field 0x03. |
258 | | */ |
259 | 0 | #define SNAP_CHECK_POS 9 |
260 | 0 | #define SNAP_CHECK_STR "AA-AA 03" |
261 | | /* |
262 | | To check whether the control field is 1 or two octets we check if it is |
263 | | unnumbered. Unnumbered has length 1, numbered 2. |
264 | | */ |
265 | 0 | #define CTL_UNNUMB_MASK 0x03 |
266 | 0 | #define CTL_UNNUMB_VALUE 0x03 |
267 | | static bool |
268 | | parse_dbs_etherwatch_packet(FILE_T fh, wtap_rec *rec, |
269 | | int *err, char **err_info) |
270 | 0 | { |
271 | 0 | uint8_t *pd; |
272 | 0 | char line[DBS_ETHERWATCH_LINE_LENGTH]; |
273 | 0 | int num_items_scanned; |
274 | 0 | int eth_hdr_len, pkt_len, csec; |
275 | 0 | int length_pos, length_from, length; |
276 | 0 | struct tm tm; |
277 | 0 | char mon[4] = "xxx"; |
278 | 0 | char *p; |
279 | 0 | static const char months[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; |
280 | 0 | int count, line_count; |
281 | | |
282 | | /* Make sure we have enough room for a regular Ethernet packet */ |
283 | 0 | ws_buffer_assure_space(&rec->data, DBS_ETHERWATCH_MAX_ETHERNET_PACKET_LEN); |
284 | 0 | pd = ws_buffer_start_ptr(&rec->data); |
285 | |
|
286 | 0 | eth_hdr_len = 0; |
287 | 0 | memset(&tm, 0, sizeof(tm)); |
288 | | /* Our file pointer should be on the first line containing the |
289 | | * summary information for a packet. Read in that line and |
290 | | * extract the useful information |
291 | | */ |
292 | 0 | if (file_gets(line, DBS_ETHERWATCH_LINE_LENGTH, fh) == NULL) { |
293 | 0 | *err = file_error(fh, err_info); |
294 | 0 | if (*err == 0) { |
295 | 0 | *err = WTAP_ERR_SHORT_READ; |
296 | 0 | } |
297 | 0 | return false; |
298 | 0 | } |
299 | | |
300 | | /* Get the destination address */ |
301 | 0 | p = strstr(line, DEST_MAC_PREFIX); |
302 | 0 | if(!p) { |
303 | 0 | *err = WTAP_ERR_BAD_FILE; |
304 | 0 | *err_info = g_strdup("dbs_etherwatch: destination address not found"); |
305 | 0 | return false; |
306 | 0 | } |
307 | 0 | p += strlen(DEST_MAC_PREFIX); |
308 | 0 | if(parse_hex_dump(p, &pd[eth_hdr_len], HEX_HDR_SPR, HEX_HDR_END) |
309 | 0 | != MAC_ADDR_LENGTH) { |
310 | 0 | *err = WTAP_ERR_BAD_FILE; |
311 | 0 | *err_info = g_strdup("dbs_etherwatch: destination address not valid"); |
312 | 0 | return false; |
313 | 0 | } |
314 | 0 | eth_hdr_len += MAC_ADDR_LENGTH; |
315 | | |
316 | | /* Get the source address */ |
317 | | /* |
318 | | * Since the first part of the line is already skipped in order to find |
319 | | * the start of the record we cannot index, just look for the first |
320 | | * 'HEX' character |
321 | | */ |
322 | 0 | p = line; |
323 | 0 | while(!g_ascii_isxdigit(*p)) { |
324 | 0 | p++; |
325 | 0 | } |
326 | 0 | if(parse_hex_dump(p, &pd[eth_hdr_len], HEX_HDR_SPR, |
327 | 0 | HEX_HDR_END) != MAC_ADDR_LENGTH) { |
328 | 0 | *err = WTAP_ERR_BAD_FILE; |
329 | 0 | *err_info = g_strdup("dbs_etherwatch: source address not valid"); |
330 | 0 | return false; |
331 | 0 | } |
332 | 0 | eth_hdr_len += MAC_ADDR_LENGTH; |
333 | | |
334 | | /* Read the next line of the record header */ |
335 | 0 | if (file_gets(line, DBS_ETHERWATCH_LINE_LENGTH, fh) == NULL) { |
336 | 0 | *err = file_error(fh, err_info); |
337 | 0 | if (*err == 0) { |
338 | 0 | *err = WTAP_ERR_SHORT_READ; |
339 | 0 | } |
340 | 0 | return false; |
341 | 0 | } |
342 | | |
343 | | /* Check the lines is as least as long as the length position */ |
344 | 0 | if(strlen(line) < LENGTH_POS) { |
345 | 0 | *err = WTAP_ERR_BAD_FILE; |
346 | 0 | *err_info = g_strdup("dbs_etherwatch: line too short"); |
347 | 0 | return false; |
348 | 0 | } |
349 | | |
350 | 0 | num_items_scanned = sscanf(line + LENGTH_POS, |
351 | 0 | "%9d byte buffer at %2d-%3s-%4d %2d:%2d:%2d.%9d", |
352 | 0 | &pkt_len, |
353 | 0 | &tm.tm_mday, mon, |
354 | 0 | &tm.tm_year, &tm.tm_hour, &tm.tm_min, |
355 | 0 | &tm.tm_sec, &csec); |
356 | |
|
357 | 0 | if (num_items_scanned != 8) { |
358 | 0 | *err = WTAP_ERR_BAD_FILE; |
359 | 0 | *err_info = g_strdup("dbs_etherwatch: header line not valid"); |
360 | 0 | return false; |
361 | 0 | } |
362 | | |
363 | 0 | if (pkt_len < 0) { |
364 | 0 | *err = WTAP_ERR_BAD_FILE; |
365 | 0 | *err_info = g_strdup("dbs_etherwatch: packet header has a negative packet length"); |
366 | 0 | return false; |
367 | 0 | } |
368 | | |
369 | | /* Determine whether it is Ethernet II or IEEE 802 */ |
370 | 0 | if(strncmp(&line[ETH_II_CHECK_POS], ETH_II_CHECK_STR, |
371 | 0 | strlen(ETH_II_CHECK_STR)) == 0) { |
372 | | /* Ethernet II */ |
373 | | /* Get the Protocol */ |
374 | 0 | if(parse_hex_dump(&line[PROTOCOL_POS], &pd[eth_hdr_len], HEX_HDR_SPR, |
375 | 0 | HEX_HDR_END) != PROTOCOL_LENGTH) { |
376 | 0 | *err = WTAP_ERR_BAD_FILE; |
377 | 0 | *err_info = g_strdup("dbs_etherwatch: Ethernet II protocol value not valid"); |
378 | 0 | return false; |
379 | 0 | } |
380 | 0 | eth_hdr_len += PROTOCOL_LENGTH; |
381 | 0 | } else { |
382 | | /* IEEE 802 */ |
383 | | /* Remember where to put the length in the header */ |
384 | 0 | length_pos = eth_hdr_len; |
385 | | /* Leave room in the header for the length */ |
386 | 0 | eth_hdr_len += IEEE802_LEN_LEN; |
387 | | /* Remember how much of the header should not be added to the length */ |
388 | 0 | length_from = eth_hdr_len; |
389 | | /* Get the DSAP + SSAP */ |
390 | 0 | if(parse_hex_dump(&line[SAP_POS], &pd[eth_hdr_len], HEX_HDR_SPR, |
391 | 0 | HEX_HDR_END) != SAP_LENGTH) { |
392 | 0 | *err = WTAP_ERR_BAD_FILE; |
393 | 0 | *err_info = g_strdup("dbs_etherwatch: 802.2 DSAP+SSAP value not valid"); |
394 | 0 | return false; |
395 | 0 | } |
396 | 0 | eth_hdr_len += SAP_LENGTH; |
397 | | /* Get the (first part of the) control field */ |
398 | 0 | if(parse_hex_dump(&line[CTL_POS], &pd[eth_hdr_len], HEX_HDR_SPR, |
399 | 0 | HEX_HDR_END) != CTL_UNNUMB_LENGTH) { |
400 | 0 | *err = WTAP_ERR_BAD_FILE; |
401 | 0 | *err_info = g_strdup("dbs_etherwatch: 802.2 control field first part not valid"); |
402 | 0 | return false; |
403 | 0 | } |
404 | | /* Determine whether the control is numbered, and thus longer */ |
405 | 0 | if((pd[eth_hdr_len] & CTL_UNNUMB_MASK) != CTL_UNNUMB_VALUE) { |
406 | | /* Get the rest of the control field, the first octet in the PID */ |
407 | 0 | if(parse_hex_dump(&line[PID_POS], |
408 | 0 | &pd[eth_hdr_len + CTL_UNNUMB_LENGTH], HEX_HDR_END, |
409 | 0 | HEX_HDR_SPR) != CTL_NUMB_LENGTH - CTL_UNNUMB_LENGTH) { |
410 | 0 | *err = WTAP_ERR_BAD_FILE; |
411 | 0 | *err_info = g_strdup("dbs_etherwatch: 802.2 control field second part value not valid"); |
412 | 0 | return false; |
413 | 0 | } |
414 | 0 | eth_hdr_len += CTL_NUMB_LENGTH; |
415 | 0 | } else { |
416 | 0 | eth_hdr_len += CTL_UNNUMB_LENGTH; |
417 | 0 | } |
418 | | /* Determine whether it is SNAP */ |
419 | 0 | if(strncmp(&line[SNAP_CHECK_POS], SNAP_CHECK_STR, |
420 | 0 | strlen(SNAP_CHECK_STR)) == 0) { |
421 | | /* Get the PID */ |
422 | 0 | if(parse_hex_dump(&line[PID_POS], &pd[eth_hdr_len], HEX_HDR_SPR, |
423 | 0 | HEX_PID_END) != PID_LENGTH) { |
424 | 0 | *err = WTAP_ERR_BAD_FILE; |
425 | 0 | *err_info = g_strdup("dbs_etherwatch: 802.2 PID value not valid"); |
426 | 0 | return false; |
427 | 0 | } |
428 | 0 | eth_hdr_len += PID_LENGTH; |
429 | 0 | } |
430 | | /* Write the length in the header */ |
431 | 0 | length = eth_hdr_len - length_from + pkt_len; |
432 | 0 | pd[length_pos] = (length) >> 8; |
433 | 0 | pd[length_pos+1] = (length) & 0xFF; |
434 | 0 | } |
435 | | |
436 | 0 | rec->rec_type = REC_TYPE_PACKET; |
437 | 0 | rec->block = wtap_block_create(WTAP_BLOCK_PACKET); |
438 | 0 | rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN; |
439 | |
|
440 | 0 | p = strstr(months, mon); |
441 | 0 | if (p) |
442 | 0 | tm.tm_mon = (int)(p - months) / 3; |
443 | 0 | tm.tm_year -= 1900; |
444 | |
|
445 | 0 | tm.tm_isdst = -1; |
446 | 0 | rec->ts.secs = mktime(&tm); |
447 | 0 | rec->ts.nsecs = csec * 10000000; |
448 | 0 | rec->rec_header.packet_header.caplen = eth_hdr_len + pkt_len; |
449 | 0 | rec->rec_header.packet_header.len = eth_hdr_len + pkt_len; |
450 | |
|
451 | 0 | if (rec->rec_header.packet_header.caplen > WTAP_MAX_PACKET_SIZE_STANDARD) { |
452 | | /* |
453 | | * Probably a corrupt capture file; return an error, |
454 | | * so that our caller doesn't blow up trying to allocate |
455 | | * space for an immensely-large packet. |
456 | | */ |
457 | 0 | *err = WTAP_ERR_BAD_FILE; |
458 | 0 | *err_info = ws_strdup_printf("dbs_etherwatch: File has %u-byte packet, bigger than maximum of %u", |
459 | 0 | rec->rec_header.packet_header.caplen, WTAP_MAX_PACKET_SIZE_STANDARD); |
460 | 0 | return false; |
461 | 0 | } |
462 | | |
463 | | /* Make sure we have enough room, even for an oversized Ethernet packet */ |
464 | 0 | ws_buffer_assure_space(&rec->data, rec->rec_header.packet_header.caplen); |
465 | 0 | pd = ws_buffer_start_ptr(&rec->data); |
466 | | |
467 | | /* |
468 | | * We don't have an FCS in this frame. |
469 | | */ |
470 | 0 | rec->rec_header.packet_header.pseudo_header.eth.fcs_len = 0; |
471 | | |
472 | | /* Parse the hex dump */ |
473 | 0 | count = 0; |
474 | 0 | while (count < pkt_len) { |
475 | 0 | if (file_gets(line, DBS_ETHERWATCH_LINE_LENGTH, fh) == NULL) { |
476 | 0 | *err = file_error(fh, err_info); |
477 | 0 | if (*err == 0) { |
478 | 0 | *err = WTAP_ERR_SHORT_READ; |
479 | 0 | } |
480 | 0 | return false; |
481 | 0 | } |
482 | 0 | if (!(line_count = parse_single_hex_dump_line(line, |
483 | 0 | &pd[eth_hdr_len + count], count))) { |
484 | 0 | *err = WTAP_ERR_BAD_FILE; |
485 | 0 | *err_info = g_strdup("dbs_etherwatch: packet data value not valid"); |
486 | 0 | return false; |
487 | 0 | } |
488 | 0 | count += line_count; |
489 | 0 | if (count > pkt_len) { |
490 | 0 | *err = WTAP_ERR_BAD_FILE; |
491 | 0 | *err_info = g_strdup("dbs_etherwatch: packet data value has too many bytes"); |
492 | 0 | return false; |
493 | 0 | } |
494 | 0 | } |
495 | 0 | return true; |
496 | 0 | } |
497 | | |
498 | | /* Parse a hex dump line */ |
499 | | /* |
500 | | /DISPLAY=BOTH output: |
501 | | |
502 | | 1 2 3 4 |
503 | | 0123456789012345678901234567890123456789012345 |
504 | | [E..(8...........]- 0-[45 00 00 28 38 9B 00 00 1D 06 D2 1E 80 93 11 1A] |
505 | | [.........(..Z.4y]- 16-[80 93 80 D6 02 D2 02 03 00 28 A4 BF 5A 1C 34 79] |
506 | | [P.#(.C...00000..]- 32-[50 10 23 28 C1 43 00 00 03 30 30 30 30 30 00 00] |
507 | | [.0 ]- 48-[03 30] |
508 | | |
509 | | /DISPLAY=HEXADECIMAL output: |
510 | | |
511 | | 1 2 3 4 |
512 | | 0123456789012345678901234567890123456789012345 |
513 | | 0-[45 00 00 28 38 9B 00 00 1D 06 D2 1E 80 93 11 1A 80 93 80 D6] |
514 | | 20-[02 D2 02 03 00 28 A4 BF 5A 1C 34 79 50 10 23 28 C1 43 00 00] |
515 | | 40-[03 30 30 30 30 30 00 00 03 30] |
516 | | |
517 | | */ |
518 | | |
519 | 0 | #define TYPE_CHECK_POS 2 /* Position to check the type of hex dump */ |
520 | 0 | #define TYPE_CHECK_BOTH '[' /* Value at pos. that indicates BOTH type */ |
521 | 0 | #define COUNT_POS_BOTH 21 /* Count position BOTH type */ |
522 | 0 | #define COUNT_POS_HEX 1 /* Count position HEX type */ |
523 | 0 | #define COUNT_SIZE 5 /* Length counter */ |
524 | 0 | #define HEX_DUMP_START '[' /* Start char */ |
525 | 0 | #define HEX_DUMP_SPR ' ' /* Separator char */ |
526 | 0 | #define HEX_DUMP_END ']' /* End char */ |
527 | | |
528 | | /* Take a string representing one line from a hex dump and converts the |
529 | | * text to binary data. We check the printed offset with the offset |
530 | | * we are passed to validate the record. We place the bytes in the buffer |
531 | | * at the specified offset. |
532 | | * |
533 | | * Returns length parsed if a good hex dump, 0 if bad. |
534 | | */ |
535 | | static unsigned |
536 | 0 | parse_single_hex_dump_line(char* rec, uint8_t *buf, int byte_offset) { |
537 | |
|
538 | 0 | int pos, i; |
539 | 0 | int value; |
540 | | |
541 | | |
542 | | /* Check that the record is as least as long as the check offset */ |
543 | 0 | for(i = 0; i < TYPE_CHECK_POS; i++) |
544 | 0 | { |
545 | 0 | if(rec[i] == '\0') { |
546 | 0 | return 0; |
547 | 0 | } |
548 | 0 | } |
549 | | /* determine the format and thus the counter offset and hex dump length */ |
550 | 0 | if(rec[TYPE_CHECK_POS] == TYPE_CHECK_BOTH) |
551 | 0 | { |
552 | 0 | pos = COUNT_POS_BOTH; |
553 | 0 | } |
554 | 0 | else |
555 | 0 | { |
556 | 0 | pos = COUNT_POS_HEX; |
557 | 0 | } |
558 | | |
559 | | /* Check that the record is as least as long as the start position */ |
560 | 0 | while(i < pos) |
561 | 0 | { |
562 | 0 | if(rec[i] == '\0') { |
563 | 0 | return 0; |
564 | 0 | } |
565 | 0 | i++; |
566 | 0 | } |
567 | | |
568 | | /* Get the byte_offset directly from the record */ |
569 | 0 | value = 0; |
570 | 0 | for(i = 0; i < COUNT_SIZE; i++) { |
571 | 0 | if(!g_ascii_isspace(rec[pos])) { |
572 | 0 | if(g_ascii_isdigit(rec[pos])) { |
573 | 0 | value *= 10; |
574 | 0 | value += rec[pos] - '0'; |
575 | 0 | } else { |
576 | 0 | return 0; |
577 | 0 | } |
578 | 0 | } |
579 | 0 | pos++; |
580 | 0 | } |
581 | | |
582 | 0 | if (value != byte_offset) { |
583 | 0 | return 0; |
584 | 0 | } |
585 | | |
586 | | /* find the start of the hex dump */ |
587 | 0 | while(rec[pos] != HEX_DUMP_START) { |
588 | 0 | if(rec[pos] == '\0') { |
589 | 0 | return 0; |
590 | 0 | } |
591 | 0 | pos++; |
592 | 0 | } |
593 | 0 | pos++; |
594 | 0 | return parse_hex_dump(&rec[pos], buf, HEX_DUMP_SPR, HEX_DUMP_END); |
595 | 0 | } |
596 | | |
597 | | /* Parse a hex dump */ |
598 | | static unsigned |
599 | 0 | parse_hex_dump(char* dump, uint8_t *buf, char separator, char end) { |
600 | 0 | int pos, count; |
601 | | |
602 | | /* Parse the hex dump */ |
603 | 0 | pos = 0; |
604 | 0 | count = 0; |
605 | 0 | while(dump[pos] != end) { |
606 | | /* Check the hex value */ |
607 | 0 | if(!(g_ascii_isxdigit(dump[pos]) && |
608 | 0 | g_ascii_isxdigit(dump[pos + 1]))) { |
609 | 0 | return 0; |
610 | 0 | } |
611 | | /* Get the hex value */ |
612 | 0 | if(g_ascii_isdigit(dump[pos])) { |
613 | 0 | buf[count] = (dump[pos] - '0') << 4; |
614 | 0 | } else { |
615 | 0 | buf[count] = (g_ascii_toupper(dump[pos]) - 'A' + 10) << 4; |
616 | 0 | } |
617 | 0 | pos++; |
618 | 0 | if(g_ascii_isdigit(dump[pos])) { |
619 | 0 | buf[count] += dump[pos] - '0'; |
620 | 0 | } else { |
621 | 0 | buf[count] += g_ascii_toupper(dump[pos]) - 'A' + 10; |
622 | 0 | } |
623 | 0 | pos++; |
624 | 0 | count++; |
625 | | /* Skip the separator characters */ |
626 | 0 | while(dump[pos] == separator) { |
627 | 0 | pos++; |
628 | 0 | } |
629 | 0 | } |
630 | 0 | return count; |
631 | 0 | } |
632 | | |
633 | | static const struct supported_block_type dbs_etherwatch_blocks_supported[] = { |
634 | | /* |
635 | | * We support packet blocks, with no comments or other options. |
636 | | */ |
637 | | { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED } |
638 | | }; |
639 | | |
640 | | static const struct file_type_subtype_info dbs_etherwatch_info = { |
641 | | "DBS Etherwatch (VMS)", "etherwatch", "txt", NULL, |
642 | | false, BLOCKS_SUPPORTED(dbs_etherwatch_blocks_supported), |
643 | | NULL, NULL, NULL |
644 | | }; |
645 | | |
646 | | void register_dbs_etherwatch(void) |
647 | 14 | { |
648 | 14 | dbs_etherwatch_file_type_subtype = wtap_register_file_type_subtype(&dbs_etherwatch_info); |
649 | | |
650 | | /* |
651 | | * Register name for backwards compatibility with the |
652 | | * wtap_filetypes table in Lua. |
653 | | */ |
654 | 14 | wtap_register_backwards_compatibility_lua_name("DBS_ETHERWATCH", |
655 | 14 | dbs_etherwatch_file_type_subtype); |
656 | 14 | } |
657 | | |
658 | | /* |
659 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
660 | | * |
661 | | * Local variables: |
662 | | * c-basic-offset: 4 |
663 | | * tab-width: 8 |
664 | | * indent-tabs-mode: nil |
665 | | * End: |
666 | | * |
667 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
668 | | * :indentSize=4:tabSize=8:noTabs=true: |
669 | | */ |