Coverage Report

Created: 2025-02-15 06:25

/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
 */