3 * Juniper NetScreen snoop output parser
4 * Created by re-using a lot of code from cosine.c
5 * Copyright (c) 2007 by Sake Blok <sake@euronet.nl>
8 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #include "netscreen.h"
31 #include "file_wrappers.h"
40 * o Create a wiki-page with instruction on how to make tracefiles
41 * on Juniper NetScreen devices. Also put a few examples up
42 * on the wiki (Done: wiki-page added 2007-08-03)
44 * o Use the interface names to properly detect the encapsulation
45 * type (ie adsl packets are now not properly dissected)
46 * (Done: adsl packets are now correctly seen as PPP, 2007-08-03)
48 * o Pass the interface names and the traffic direction to either
49 * the frame-structure, a pseudo-header or use PPI. This needs
50 * to be discussed on the dev-list first
51 * (Posted a message to wireshark-dev abou this 2007-08-03)
57 static gboolean empty_line(const gchar *line);
58 static gboolean info_line(const gchar *line);
59 static gint64 netscreen_seek_next_packet(wtap *wth, int *err, char *hdr);
60 static gboolean netscreen_check_file_type(wtap *wth, int *err);
61 static gboolean netscreen_read(wtap *wth, int *err, gchar **err_info,
63 static gboolean netscreen_seek_read(wtap *wth, gint64 seek_off,
64 union wtap_pseudo_header *pseudo_header, guint8 *pd,
65 int len, int *err, gchar **err_info);
66 static int parse_netscreen_rec_hdr(wtap *wth, const char *line,
67 char *cap_int, gboolean *cap_dir,
68 union wtap_pseudo_header *pseudo_header, int *err, gchar **err_info);
69 static int parse_netscreen_hex_dump(FILE_T fh, int pkt_len, guint8* buf,
70 int *err, gchar **err_info);
71 static int parse_single_hex_dump_line(char* rec, guint8 *buf,
74 /* Returns TRUE if the line appears to be an empty line. Otherwise it
76 static gboolean empty_line(const gchar *line)
79 if (isspace((guchar)*line)) {
92 /* Returns TRUE if the line appears to be a line with protocol info.
93 Otherwise it returns FALSE. */
94 static gboolean info_line(const gchar *line)
96 int i=NETSCREEN_SPACES_ON_INFO_LINE;
99 if (isspace((guchar)*line)) {
109 /* Seeks to the beginning of the next packet, and returns the
110 byte offset. Copy the header line to hdr. Returns -1 on failure,
111 and sets "*err" to the error and set hdr as NULL. */
112 static gint64 netscreen_seek_next_packet(wtap *wth, int *err, char *hdr)
115 char buf[NETSCREEN_LINE_LENGTH];
118 cur_off = file_tell(wth->fh);
121 *err = file_error(wth->fh);
125 if (file_gets(buf, sizeof(buf), wth->fh) != NULL) {
126 if (strstr(buf, NETSCREEN_REC_MAGIC_STR1) ||
127 strstr(buf, NETSCREEN_REC_MAGIC_STR2)) {
128 strncpy(hdr, buf, NETSCREEN_LINE_LENGTH-1);
129 hdr[NETSCREEN_LINE_LENGTH-1] = '\0';
133 if (file_eof(wth->fh)) {
137 /* We (presumably) got an error (there's no
138 equivalent to "ferror()" in zlib, alas,
139 so we don't have a wrapper to check for
141 *err = file_error(wth->fh);
150 /* Look through the first part of a file to see if this is
151 * NetScreen snoop output.
153 * Returns TRUE if it is, FALSE if it isn't or if we get an I/O error;
154 * if we get an I/O error, "*err" will be set to a non-zero value.
156 static gboolean netscreen_check_file_type(wtap *wth, int *err)
158 char buf[NETSCREEN_LINE_LENGTH];
161 buf[NETSCREEN_LINE_LENGTH-1] = '\0';
163 for (line = 0; line < NETSCREEN_HEADER_LINES_TO_CHECK; line++) {
164 if (file_gets(buf, NETSCREEN_LINE_LENGTH, wth->fh) != NULL) {
166 reclen = strlen(buf);
167 if (reclen < strlen(NETSCREEN_HDR_MAGIC_STR1) ||
168 reclen < strlen(NETSCREEN_HDR_MAGIC_STR2)) {
172 if (strstr(buf, NETSCREEN_HDR_MAGIC_STR1) ||
173 strstr(buf, NETSCREEN_HDR_MAGIC_STR2)) {
178 if (file_eof(wth->fh))
181 *err = file_error(wth->fh);
190 int netscreen_open(wtap *wth, int *err, gchar **err_info _U_)
193 /* Look for a NetScreen snoop header line */
194 if (!netscreen_check_file_type(wth, err)) {
201 if (file_seek(wth->fh, 0L, SEEK_SET, err) == -1) /* rewind */
204 wth->data_offset = 0;
205 wth->file_encap = WTAP_ENCAP_PER_PACKET;
206 wth->file_type = WTAP_FILE_NETSCREEN;
207 wth->snapshot_length = 0; /* not known */
208 wth->subtype_read = netscreen_read;
209 wth->subtype_seek_read = netscreen_seek_read;
210 wth->tsprecision = WTAP_FILE_TSPREC_DSEC;
215 /* Find the next packet and parse it; called from wtap_read(). */
216 static gboolean netscreen_read(wtap *wth, int *err, gchar **err_info,
222 char line[NETSCREEN_LINE_LENGTH];
223 char cap_int[NETSCREEN_MAX_INT_NAME_LENGTH];
226 /* Find the next packet */
227 offset = netscreen_seek_next_packet(wth, err, line);
231 /* Parse the header */
232 pkt_len = parse_netscreen_rec_hdr(wth, line, cap_int, &cap_dir,
233 &wth->pseudo_header, err, err_info);
237 /* Make sure we have enough room for the packet */
238 buffer_assure_space(wth->frame_buffer, NETSCREEN_MAX_PACKET_LEN);
239 buf = buffer_start_ptr(wth->frame_buffer);
241 /* Convert the ASCII hex dump to binary data */
242 if ((caplen = parse_netscreen_hex_dump(wth->fh, pkt_len, buf, err,
247 if (strncmp(cap_int, "adsl", 4) == 0)
248 wth->phdr.pkt_encap = WTAP_ENCAP_PPP;
249 else if (strncmp(cap_int, "seri", 4) == 0)
250 wth->phdr.pkt_encap = WTAP_ENCAP_PPP;
252 wth->phdr.pkt_encap = WTAP_ENCAP_ETHERNET;
254 wth->data_offset = offset;
255 wth->phdr.caplen = caplen;
256 *data_offset = offset;
260 /* Used to read packets in random-access fashion */
262 netscreen_seek_read (wtap *wth, gint64 seek_off,
263 union wtap_pseudo_header *pseudo_header, guint8 *pd, int len,
264 int *err, gchar **err_info)
266 char line[NETSCREEN_LINE_LENGTH];
267 char cap_int[NETSCREEN_MAX_INT_NAME_LENGTH];
270 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) {
274 if (file_gets(line, NETSCREEN_LINE_LENGTH, wth->random_fh) == NULL) {
275 *err = file_error(wth->random_fh);
277 *err = WTAP_ERR_SHORT_READ;
282 if (parse_netscreen_rec_hdr(NULL, line, cap_int, &cap_dir, pseudo_header,
283 err, err_info) == -1) {
287 return parse_netscreen_hex_dump(wth->random_fh, len, pd, err, err_info);
290 /* Parses a packet record header. There are a few possible formats:
292 * XXX list extra formats here!
293 6843828.0: trust(o) len=98:00121ebbd132->00600868d659/0800
294 192.168.1.1 -> 192.168.1.10/6
295 vhl=45, tos=00, id=37739, frag=0000, ttl=64 tlen=84
296 tcp:ports 2222->2333, seq=3452113890, ack=1540618280, flag=5018/ACK
297 00 60 08 68 d6 59 00 12 1e bb d1 32 08 00 45 00 .`.h.Y.....2..E.
298 00 54 93 6b 00 00 40 06 63 dd c0 a8 01 01 c0 a8 .T.k..@.c.......
299 01 0a 08 ae 09 1d cd c3 13 e2 5b d3 f8 28 50 18 ..........[..(P.
300 1f d4 79 21 00 00 e7 76 89 64 16 e2 19 0a 80 09 ..y!...v.d......
301 31 e7 04 28 04 58 f3 d9 b1 9f 3d 65 1a db d8 61 1..(.X....=e...a
302 2c 21 b6 d3 20 60 0c 8c 35 98 88 cf 20 91 0e a9 ,!...`..5.......
308 parse_netscreen_rec_hdr(wtap *wth, const char *line, char *cap_int, gboolean *cap_dir,
309 union wtap_pseudo_header *pseudo_header _U_, int *err, gchar **err_info)
315 if (sscanf(line, "%d.%d: %[a-z0-9/](%[io]) len=%d:",
316 &sec, &dsec, cap_int, direction, &pkt_len) != 5) {
317 *err = WTAP_ERR_BAD_RECORD;
318 *err_info = g_strdup("netscreen: Can't parse packet-header");
322 *cap_dir = (direction[0] == 'o' ? NETSCREEN_EGRESS : NETSCREEN_INGRESS);
325 wth->phdr.ts.secs = sec;
326 wth->phdr.ts.nsecs = dsec * 100000000;
327 wth->phdr.len = pkt_len;
333 /* Converts ASCII hex dump to binary data. Returns the capture length.
334 If any error is encountered, -1 is returned. */
336 parse_netscreen_hex_dump(FILE_T fh, int pkt_len, guint8* buf, int *err, gchar **err_info)
338 gchar line[NETSCREEN_LINE_LENGTH];
339 int n, i = 0, offset = 0;
343 /* The last packet is not delimited by an empty line, but by EOF
344 * So accept EOF as a valid delimiter too
346 if (file_gets(line, NETSCREEN_LINE_LENGTH, fh) == NULL) {
350 /* packets are delimited with empty lines */
351 if (empty_line(line)) {
355 /* terminate the line before the ascii-data to prevent the
356 * parser from parsing one or more extra bytes from the
358 * Check for longer lines to prevent wireless hexdumps to
359 * be cut in the middle (they can have 14 extra spaces
360 * before the hex-data)
362 if(strlen(line) != 98)
367 n = parse_single_hex_dump_line(line, buf, offset);
369 /* the smallest packet has a length of 6 bytes, if
370 * the first hex-data is less then check whether
371 * it is a info-line and act accordingly
373 if (offset == 0 && n < 6) {
374 if (info_line(line)) {
375 if (++i <= NETSCREEN_MAX_INFOLINES) {
379 *err = WTAP_ERR_BAD_RECORD;
380 *err_info = g_strdup("netscreen: cannot parse hex-data");
385 /* If there is no more data and the line was not empty,
386 * then there must be an error in the file
389 *err = WTAP_ERR_BAD_RECORD;
390 *err_info = g_strdup("netscreen: cannot parse hex-data");
394 /* Adjust the offset to the data that was just added to the buffer */
397 /* If there was more hex-data than was announced in the len=x
398 * header, then then there must be an error in the file
400 if(offset > pkt_len) {
401 *err = WTAP_ERR_BAD_RECORD;
402 *err_info = g_strdup("netscreen: to much hex-data");
410 /* Take a string representing one line from a hex dump and converts
411 * the text to binary data. We place the bytes in the buffer at the
414 * Returns number of bytes successfully read, -1 if bad. */
416 parse_single_hex_dump_line(char* rec, guint8 *buf, guint byte_offset)
418 int num_items_scanned, i;
419 unsigned int bytes[16];
421 num_items_scanned = sscanf(rec, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
422 &bytes[0], &bytes[1], &bytes[2], &bytes[3],
423 &bytes[4], &bytes[5], &bytes[6], &bytes[7],
424 &bytes[8], &bytes[9], &bytes[10], &bytes[11],
425 &bytes[12], &bytes[13], &bytes[14], &bytes[15]);
426 if (num_items_scanned == 0)
429 if (num_items_scanned > 16)
430 num_items_scanned = 16;
432 for (i=0; i<num_items_scanned; i++) {
433 buf[byte_offset + i] = (guint8)bytes[i];
436 return num_items_scanned;