5 * Juniper NetScreen snoop output parser
6 * Created by re-using a lot of code from cosine.c
7 * Copyright (c) 2007 by Sake Blok <sake@euronet.nl>
10 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #include "netscreen.h"
33 #include "file_wrappers.h"
42 * o Create a wiki-page with instruction on how to make tracefiles
43 * on Juniper NetScreen devices. Also put a few examples up
44 * on the wiki (Done: wiki-page added 2007-08-03)
46 * o Use the interface names to properly detect the encapsulation
47 * type (ie adsl packets are now not properly dissected)
48 * (Done: adsl packets are now correctly seen as PPP, 2007-08-03)
50 * o Pass the interface names and the traffic direction to either
51 * the frame-structure, a pseudo-header or use PPI. This needs
52 * to be discussed on the dev-list first
53 * (Posted a message to wireshark-dev abou this 2007-08-03)
59 static gboolean empty_line(const gchar *line);
60 static gboolean info_line(const gchar *line);
61 static gint64 netscreen_seek_next_packet(wtap *wth, int *err, char *hdr);
62 static gboolean netscreen_check_file_type(wtap *wth, int *err);
63 static gboolean netscreen_read(wtap *wth, int *err, gchar **err_info,
65 static gboolean netscreen_seek_read(wtap *wth, gint64 seek_off,
66 union wtap_pseudo_header *pseudo_header, guint8 *pd,
67 int len, int *err, gchar **err_info);
68 static int parse_netscreen_rec_hdr(wtap *wth, const char *line,
69 char *cap_int, gboolean *cap_dir,
70 union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info);
71 static int parse_netscreen_hex_dump(FILE_T fh, int pkt_len, guint8* buf,
72 int *err, gchar **err_info);
73 static int parse_single_hex_dump_line(char* rec, guint8 *buf,
76 /* Returns TRUE if the line appears to be an empty line. Otherwise it
78 static gboolean empty_line(const gchar *line)
81 if (isspace((guchar)*line)) {
94 /* Returns TRUE if the line appears to be a line with protocol info.
95 Otherwise it returns FALSE. */
96 static gboolean info_line(const gchar *line)
98 int i=NETSCREEN_SPACES_ON_INFO_LINE;
101 if (isspace((guchar)*line)) {
111 /* Seeks to the beginning of the next packet, and returns the
112 byte offset. Copy the header line to hdr. Returns -1 on failure,
113 and sets "*err" to the error and set hdr as NULL. */
114 static gint64 netscreen_seek_next_packet(wtap *wth, int *err, char *hdr)
117 char buf[NETSCREEN_LINE_LENGTH];
120 cur_off = file_tell(wth->fh);
123 *err = file_error(wth->fh);
127 if (file_gets(buf, sizeof(buf), wth->fh) != NULL) {
128 if (strstr(buf, NETSCREEN_REC_MAGIC_STR1) ||
129 strstr(buf, NETSCREEN_REC_MAGIC_STR2)) {
130 g_strlcpy(hdr, buf, NETSCREEN_LINE_LENGTH);
134 if (file_eof(wth->fh)) {
138 /* We (presumably) got an error (there's no
139 equivalent to "ferror()" in zlib, alas,
140 so we don't have a wrapper to check for
142 *err = file_error(wth->fh);
151 /* Look through the first part of a file to see if this is
152 * NetScreen snoop output.
154 * Returns TRUE if it is, FALSE if it isn't or if we get an I/O error;
155 * if we get an I/O error, "*err" will be set to a non-zero value.
157 static gboolean netscreen_check_file_type(wtap *wth, int *err)
159 char buf[NETSCREEN_LINE_LENGTH];
162 buf[NETSCREEN_LINE_LENGTH-1] = '\0';
164 for (line = 0; line < NETSCREEN_HEADER_LINES_TO_CHECK; line++) {
165 if (file_gets(buf, NETSCREEN_LINE_LENGTH, wth->fh) != NULL) {
167 reclen = strlen(buf);
168 if (reclen < strlen(NETSCREEN_HDR_MAGIC_STR1) ||
169 reclen < strlen(NETSCREEN_HDR_MAGIC_STR2)) {
173 if (strstr(buf, NETSCREEN_HDR_MAGIC_STR1) ||
174 strstr(buf, NETSCREEN_HDR_MAGIC_STR2)) {
179 if (file_eof(wth->fh))
182 *err = file_error(wth->fh);
191 int netscreen_open(wtap *wth, int *err, gchar **err_info _U_)
194 /* Look for a NetScreen snoop header line */
195 if (!netscreen_check_file_type(wth, err)) {
202 if (file_seek(wth->fh, 0L, SEEK_SET, err) == -1) /* rewind */
205 wth->data_offset = 0;
206 wth->file_encap = WTAP_ENCAP_UNKNOWN;
207 wth->file_type = WTAP_FILE_NETSCREEN;
208 wth->snapshot_length = 0; /* not known */
209 wth->subtype_read = netscreen_read;
210 wth->subtype_seek_read = netscreen_seek_read;
211 wth->tsprecision = WTAP_FILE_TSPREC_DSEC;
216 /* Find the next packet and parse it; called from wtap_read(). */
217 static gboolean netscreen_read(wtap *wth, int *err, gchar **err_info,
223 char line[NETSCREEN_LINE_LENGTH];
224 char cap_int[NETSCREEN_MAX_INT_NAME_LENGTH];
227 /* Find the next packet */
228 offset = netscreen_seek_next_packet(wth, err, line);
232 /* Parse the header */
233 pkt_len = parse_netscreen_rec_hdr(wth, line, cap_int, &cap_dir,
234 &wth->pseudo_header, err, err_info);
238 /* Make sure we have enough room for the packet */
239 buffer_assure_space(wth->frame_buffer, NETSCREEN_MAX_PACKET_LEN);
240 buf = buffer_start_ptr(wth->frame_buffer);
242 /* Convert the ASCII hex dump to binary data */
243 if ((caplen = parse_netscreen_hex_dump(wth->fh, pkt_len, buf, err,
249 * Determine the encapsulation type, based on the
250 * first 4 characters of the interface name
252 * XXX convert this to a 'case' structure when adding more
253 * (non-ethernet) interfacetypes
255 if (strncmp(cap_int, "adsl", 4) == 0)
256 wth->phdr.pkt_encap = WTAP_ENCAP_PPP;
257 else if (strncmp(cap_int, "seri", 4) == 0)
258 wth->phdr.pkt_encap = WTAP_ENCAP_PPP;
260 wth->phdr.pkt_encap = WTAP_ENCAP_ETHERNET;
263 * If the per-file encapsulation isn't known, set it to this
264 * packet's encapsulation.
266 * If it *is* known, and it isn't this packet's encapsulation,
267 * set it to WTAP_ENCAP_PER_PACKET, as this file doesn't
268 * have a single encapsulation for all packets in the file.
270 if (wth->file_encap == WTAP_ENCAP_UNKNOWN)
271 wth->file_encap = wth->phdr.pkt_encap;
273 if (wth->file_encap != wth->phdr.pkt_encap)
274 wth->file_encap = WTAP_ENCAP_PER_PACKET;
277 wth->data_offset = offset;
278 wth->phdr.caplen = caplen;
279 *data_offset = offset;
283 /* Used to read packets in random-access fashion */
285 netscreen_seek_read (wtap *wth, gint64 seek_off,
286 union wtap_pseudo_header *pseudo_header, guint8 *pd, int len,
287 int *err, gchar **err_info)
289 char line[NETSCREEN_LINE_LENGTH];
290 char cap_int[NETSCREEN_MAX_INT_NAME_LENGTH];
293 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) {
297 if (file_gets(line, NETSCREEN_LINE_LENGTH, wth->random_fh) == NULL) {
298 *err = file_error(wth->random_fh);
300 *err = WTAP_ERR_SHORT_READ;
305 if (parse_netscreen_rec_hdr(NULL, line, cap_int, &cap_dir, pseudo_header,
306 err, err_info) == -1) {
310 return parse_netscreen_hex_dump(wth->random_fh, len, pd, err, err_info);
313 /* Parses a packet record header. There are a few possible formats:
315 * XXX list extra formats here!
316 6843828.0: trust(o) len=98:00121ebbd132->00600868d659/0800
317 192.168.1.1 -> 192.168.1.10/6
318 vhl=45, tos=00, id=37739, frag=0000, ttl=64 tlen=84
319 tcp:ports 2222->2333, seq=3452113890, ack=1540618280, flag=5018/ACK
320 00 60 08 68 d6 59 00 12 1e bb d1 32 08 00 45 00 .`.h.Y.....2..E.
321 00 54 93 6b 00 00 40 06 63 dd c0 a8 01 01 c0 a8 .T.k..@.c.......
322 01 0a 08 ae 09 1d cd c3 13 e2 5b d3 f8 28 50 18 ..........[..(P.
323 1f d4 79 21 00 00 e7 76 89 64 16 e2 19 0a 80 09 ..y!...v.d......
324 31 e7 04 28 04 58 f3 d9 b1 9f 3d 65 1a db d8 61 1..(.X....=e...a
325 2c 21 b6 d3 20 60 0c 8c 35 98 88 cf 20 91 0e a9 ,!...`..5.......
331 parse_netscreen_rec_hdr(wtap *wth, const char *line, char *cap_int, gboolean *cap_dir,
332 union wtap_pseudo_header *pseudo_header _U_, int *err, gchar **err_info)
338 if (sscanf(line, "%d.%d: %15[a-z0-9/:.](%1[io]) len=%d:",
339 &sec, &dsec, cap_int, direction, &pkt_len) != 5) {
340 *err = WTAP_ERR_BAD_RECORD;
341 *err_info = g_strdup("netscreen: Can't parse packet-header");
345 *cap_dir = (direction[0] == 'o' ? NETSCREEN_EGRESS : NETSCREEN_INGRESS);
348 wth->phdr.ts.secs = sec;
349 wth->phdr.ts.nsecs = dsec * 100000000;
350 wth->phdr.len = pkt_len;
356 /* Converts ASCII hex dump to binary data. Returns the capture length.
357 If any error is encountered, -1 is returned. */
359 parse_netscreen_hex_dump(FILE_T fh, int pkt_len, guint8* buf, int *err, gchar **err_info)
361 gchar line[NETSCREEN_LINE_LENGTH];
362 int n, i = 0, offset = 0;
366 /* The last packet is not delimited by an empty line, but by EOF
367 * So accept EOF as a valid delimiter too
369 if (file_gets(line, NETSCREEN_LINE_LENGTH, fh) == NULL) {
373 /* packets are delimited with empty lines */
374 if (empty_line(line)) {
378 /* terminate the line before the ascii-data to prevent the
379 * parser from parsing one or more extra bytes from the
381 * Check for longer lines to prevent wireless hexdumps to
382 * be cut in the middle (they can have 14 extra spaces
383 * before the hex-data)
385 if(strlen(line) != 98)
390 n = parse_single_hex_dump_line(line, buf, offset);
392 /* the smallest packet has a length of 6 bytes, if
393 * the first hex-data is less then check whether
394 * it is a info-line and act accordingly
396 if (offset == 0 && n < 6) {
397 if (info_line(line)) {
398 if (++i <= NETSCREEN_MAX_INFOLINES) {
402 *err = WTAP_ERR_BAD_RECORD;
403 *err_info = g_strdup("netscreen: cannot parse hex-data");
408 /* If there is no more data and the line was not empty,
409 * then there must be an error in the file
412 *err = WTAP_ERR_BAD_RECORD;
413 *err_info = g_strdup("netscreen: cannot parse hex-data");
417 /* Adjust the offset to the data that was just added to the buffer */
420 /* If there was more hex-data than was announced in the len=x
421 * header, then then there must be an error in the file
423 if(offset > pkt_len) {
424 *err = WTAP_ERR_BAD_RECORD;
425 *err_info = g_strdup("netscreen: to much hex-data");
433 /* Take a string representing one line from a hex dump and converts
434 * the text to binary data. We place the bytes in the buffer at the
437 * Returns number of bytes successfully read, -1 if bad. */
439 parse_single_hex_dump_line(char* rec, guint8 *buf, guint byte_offset)
441 int num_items_scanned, i;
442 unsigned int bytes[16];
444 num_items_scanned = sscanf(rec, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
445 &bytes[0], &bytes[1], &bytes[2], &bytes[3],
446 &bytes[4], &bytes[5], &bytes[6], &bytes[7],
447 &bytes[8], &bytes[9], &bytes[10], &bytes[11],
448 &bytes[12], &bytes[13], &bytes[14], &bytes[15]);
449 if (num_items_scanned == 0)
452 if (num_items_scanned > 16)
453 num_items_scanned = 16;
455 for (i=0; i<num_items_scanned; i++) {
456 buf[byte_offset + i] = (guint8)bytes[i];
459 return num_items_scanned;