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