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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "netscreen.h"
28 #include "file_wrappers.h"
35 * o Construct a list of interfaces, with interface names, give
36 * them link-layer types based on the interface name and packet
37 * data, and supply interface IDs with each packet (i.e., make
38 * this supply a pcap-ng-style set of interfaces and associate
39 * packets with interfaces). This is probably the right way
40 * to "Pass the interface names and the traffic direction to either
41 * the frame-structure, a pseudo-header or use PPI." See the
44 * http://www.wireshark.org/lists/wireshark-dev/200708/msg00029.html
46 * to see whether any further discussion is still needed. I suspect
47 * it doesn't; pcap-NG existed at the time, as per the final
48 * message in that thread:
50 * http://www.wireshark.org/lists/wireshark-dev/200708/msg00039.html
52 * but I don't think we fully *supported* it at that point. Now
53 * that we do, we have the infrastructure to support this, except
54 * that we currently have no way to translate interface IDs to
55 * interface names in the "frame" dissector or to supply interface
56 * information as part of the packet metadata from Wiretap modules.
57 * That should be fixed so that we can show interface information,
58 * such as the interface name, in packet dissections from, for example,
62 static gboolean info_line(const gchar *line);
63 static gint64 netscreen_seek_next_packet(wtap *wth, int *err, gchar **err_info,
65 static gboolean netscreen_check_file_type(wtap *wth, int *err,
67 static gboolean netscreen_read(wtap *wth, int *err, gchar **err_info,
69 static gboolean netscreen_seek_read(wtap *wth, gint64 seek_off,
70 struct wtap_pkthdr *phdr, Buffer *buf,
71 int *err, gchar **err_info);
72 static gboolean parse_netscreen_packet(FILE_T fh, struct wtap_pkthdr *phdr,
73 Buffer* buf, char *line, int *err, gchar **err_info);
74 static int parse_single_hex_dump_line(char* rec, guint8 *buf,
77 /* Returns TRUE if the line appears to be a line with protocol info.
78 Otherwise it returns FALSE. */
79 static gboolean info_line(const gchar *line)
81 int i=NETSCREEN_SPACES_ON_INFO_LINE;
84 if (g_ascii_isspace(*line)) {
94 /* Seeks to the beginning of the next packet, and returns the
95 byte offset. Copy the header line to hdr. Returns -1 on failure,
96 and sets "*err" to the error and sets "*err_info" to null or an
97 additional error string. */
98 static gint64 netscreen_seek_next_packet(wtap *wth, int *err, gchar **err_info,
102 char buf[NETSCREEN_LINE_LENGTH];
105 cur_off = file_tell(wth->fh);
108 *err = file_error(wth->fh, err_info);
111 if (file_gets(buf, sizeof(buf), wth->fh) == NULL) {
113 *err = file_error(wth->fh, err_info);
116 if (strstr(buf, NETSCREEN_REC_MAGIC_STR1) ||
117 strstr(buf, NETSCREEN_REC_MAGIC_STR2)) {
118 g_strlcpy(hdr, buf, NETSCREEN_LINE_LENGTH);
125 /* Look through the first part of a file to see if this is
126 * NetScreen snoop output.
128 * Returns TRUE if it is, FALSE if it isn't or if we get an I/O error;
129 * if we get an I/O error, "*err" will be set to a non-zero value and
130 * "*err_info" is set to null or an additional error string.
132 static gboolean netscreen_check_file_type(wtap *wth, int *err, gchar **err_info)
134 char buf[NETSCREEN_LINE_LENGTH];
137 buf[NETSCREEN_LINE_LENGTH-1] = '\0';
139 for (line = 0; line < NETSCREEN_HEADER_LINES_TO_CHECK; line++) {
140 if (file_gets(buf, NETSCREEN_LINE_LENGTH, wth->fh) == NULL) {
142 *err = file_error(wth->fh, err_info);
146 reclen = (guint) strlen(buf);
147 if (reclen < strlen(NETSCREEN_HDR_MAGIC_STR1) ||
148 reclen < strlen(NETSCREEN_HDR_MAGIC_STR2)) {
152 if (strstr(buf, NETSCREEN_HDR_MAGIC_STR1) ||
153 strstr(buf, NETSCREEN_HDR_MAGIC_STR2)) {
162 wtap_open_return_val netscreen_open(wtap *wth, int *err, gchar **err_info)
165 /* Look for a NetScreen snoop header line */
166 if (!netscreen_check_file_type(wth, err, err_info)) {
167 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
168 return WTAP_OPEN_ERROR;
169 return WTAP_OPEN_NOT_MINE;
172 if (file_seek(wth->fh, 0L, SEEK_SET, err) == -1) /* rewind */
173 return WTAP_OPEN_ERROR;
175 wth->file_encap = WTAP_ENCAP_UNKNOWN;
176 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_NETSCREEN;
177 wth->snapshot_length = 0; /* not known */
178 wth->subtype_read = netscreen_read;
179 wth->subtype_seek_read = netscreen_seek_read;
180 wth->file_tsprec = WTAP_TSPREC_DSEC;
182 return WTAP_OPEN_MINE;
185 /* Find the next packet and parse it; called from wtap_read(). */
186 static gboolean netscreen_read(wtap *wth, int *err, gchar **err_info,
190 char line[NETSCREEN_LINE_LENGTH];
192 /* Find the next packet */
193 offset = netscreen_seek_next_packet(wth, err, err_info, line);
197 /* Parse the header and convert the ASCII hex dump to binary data */
198 if (!parse_netscreen_packet(wth->fh, &wth->phdr,
199 wth->frame_buffer, line, err, err_info))
203 * If the per-file encapsulation isn't known, set it to this
204 * packet's encapsulation.
206 * If it *is* known, and it isn't this packet's encapsulation,
207 * set it to WTAP_ENCAP_PER_PACKET, as this file doesn't
208 * have a single encapsulation for all packets in the file.
210 if (wth->file_encap == WTAP_ENCAP_UNKNOWN)
211 wth->file_encap = wth->phdr.pkt_encap;
213 if (wth->file_encap != wth->phdr.pkt_encap)
214 wth->file_encap = WTAP_ENCAP_PER_PACKET;
217 *data_offset = offset;
221 /* Used to read packets in random-access fashion */
223 netscreen_seek_read(wtap *wth, gint64 seek_off,
224 struct wtap_pkthdr *phdr, Buffer *buf,
225 int *err, gchar **err_info)
227 char line[NETSCREEN_LINE_LENGTH];
229 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) {
233 if (file_gets(line, NETSCREEN_LINE_LENGTH, wth->random_fh) == NULL) {
234 *err = file_error(wth->random_fh, err_info);
236 *err = WTAP_ERR_SHORT_READ;
241 return parse_netscreen_packet(wth->random_fh, phdr, buf, line,
245 /* Parses a packet record header. There are a few possible formats:
247 * XXX list extra formats here!
248 6843828.0: trust(o) len=98:00121ebbd132->00600868d659/0800
249 192.168.1.1 -> 192.168.1.10/6
250 vhl=45, tos=00, id=37739, frag=0000, ttl=64 tlen=84
251 tcp:ports 2222->2333, seq=3452113890, ack=1540618280, flag=5018/ACK
252 00 60 08 68 d6 59 00 12 1e bb d1 32 08 00 45 00 .`.h.Y.....2..E.
253 00 54 93 6b 00 00 40 06 63 dd c0 a8 01 01 c0 a8 .T.k..@.c.......
254 01 0a 08 ae 09 1d cd c3 13 e2 5b d3 f8 28 50 18 ..........[..(P.
255 1f d4 79 21 00 00 e7 76 89 64 16 e2 19 0a 80 09 ..y!...v.d......
256 31 e7 04 28 04 58 f3 d9 b1 9f 3d 65 1a db d8 61 1..(.X....=e...a
257 2c 21 b6 d3 20 60 0c 8c 35 98 88 cf 20 91 0e a9 ,!...`..5.......
263 parse_netscreen_packet(FILE_T fh, struct wtap_pkthdr *phdr, Buffer* buf,
264 char *line, int *err, gchar **err_info)
269 char cap_int[NETSCREEN_MAX_INT_NAME_LENGTH];
279 phdr->rec_type = REC_TYPE_PACKET;
280 phdr->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
282 if (sscanf(line, "%9d.%9d: %15[a-z0-9/:.-](%1[io]) len=%9d:%12s->%12s/",
283 &sec, &dsec, cap_int, direction, &pkt_len, cap_src, cap_dst) < 5) {
284 *err = WTAP_ERR_BAD_FILE;
285 *err_info = g_strdup("netscreen: Can't parse packet-header");
289 *err = WTAP_ERR_BAD_FILE;
290 *err_info = g_strdup("netscreen: packet header has a negative packet length");
293 if (pkt_len > WTAP_MAX_PACKET_SIZE) {
295 * Probably a corrupt capture file; don't blow up trying
296 * to allocate space for an immensely-large packet.
298 *err = WTAP_ERR_BAD_FILE;
299 *err_info = g_strdup_printf("netscreen: File has %u-byte packet, bigger than maximum of %u",
300 pkt_len, WTAP_MAX_PACKET_SIZE);
305 * If direction[0] is 'o', the direction is NETSCREEN_EGRESS,
306 * otherwise it's NETSCREEN_INGRESS.
310 phdr->ts.nsecs = dsec * 100000000;
313 /* Make sure we have enough room for the packet */
314 ws_buffer_assure_space(buf, pkt_len);
315 pd = ws_buffer_start_ptr(buf);
319 /* The last packet is not delimited by an empty line, but by EOF
320 * So accept EOF as a valid delimiter too
322 if (file_gets(line, NETSCREEN_LINE_LENGTH, fh) == NULL) {
328 * The number of blanks is not fixed - for wireless
329 * interfaces, there may be 14 extra spaces before
332 for (p = &line[0]; g_ascii_isspace(*p); p++)
334 /* packets are delimited with empty lines */
339 n = parse_single_hex_dump_line(p, pd, offset);
341 /* the smallest packet has a length of 6 bytes, if
342 * the first hex-data is less then check whether
343 * it is a info-line and act accordingly
345 if (offset == 0 && n < 6) {
346 if (info_line(line)) {
347 if (++i <= NETSCREEN_MAX_INFOLINES) {
351 *err = WTAP_ERR_BAD_FILE;
352 *err_info = g_strdup("netscreen: cannot parse hex-data");
357 /* If there is no more data and the line was not empty,
358 * then there must be an error in the file
361 *err = WTAP_ERR_BAD_FILE;
362 *err_info = g_strdup("netscreen: cannot parse hex-data");
366 /* Adjust the offset to the data that was just added to the buffer */
369 /* If there was more hex-data than was announced in the len=x
370 * header, then then there must be an error in the file
372 if (offset > pkt_len) {
373 *err = WTAP_ERR_BAD_FILE;
374 *err_info = g_strdup("netscreen: too much hex-data");
380 * Determine the encapsulation type, based on the
381 * first 4 characters of the interface name
383 * XXX convert this to a 'case' structure when adding more
384 * (non-ethernet) interfacetypes
386 if (strncmp(cap_int, "adsl", 4) == 0) {
387 /* The ADSL interface can be bridged with or without
388 * PPP encapsulation. Check whether the first six bytes
389 * of the hex data are the same as the destination mac
390 * address in the header. If they are, assume ethernet
391 * LinkLayer or else PPP
393 g_snprintf(dststr, 13, "%02x%02x%02x%02x%02x%02x",
394 pd[0], pd[1], pd[2], pd[3], pd[4], pd[5]);
395 if (strncmp(dststr, cap_dst, 12) == 0)
396 phdr->pkt_encap = WTAP_ENCAP_ETHERNET;
398 phdr->pkt_encap = WTAP_ENCAP_PPP;
400 else if (strncmp(cap_int, "seri", 4) == 0)
401 phdr->pkt_encap = WTAP_ENCAP_PPP;
403 phdr->pkt_encap = WTAP_ENCAP_ETHERNET;
405 phdr->caplen = offset;
410 /* Take a string representing one line from a hex dump, with leading white
411 * space removed, and converts the text to binary data. We place the bytes
412 * in the buffer at the specified offset.
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;
423 for (num_items_scanned = 0; num_items_scanned < 16; num_items_scanned++) {
425 if (character >= '0' && character <= '9')
426 byte = character - '0' + 0;
427 else if (character >= 'A' && character <= 'F')
428 byte = character - 'A' + 0xA;
429 else if (character >= 'a' && character <= 'f')
430 byte = character - 'a' + 0xa;
431 else if (character == ' ' || character == '\r' || character == '\n' || character == '\0') {
432 /* Nothing more to parse */
435 return -1; /* not a hex digit, space before ASCII dump, or EOL */
437 character = *rec++ & 0xFF;
438 if (character >= '0' && character <= '9')
439 byte += character - '0' + 0;
440 else if (character >= 'A' && character <= 'F')
441 byte += character - 'A' + 0xA;
442 else if (character >= 'a' && character <= 'f')
443 byte += character - 'a' + 0xa;
445 return -1; /* not a hex digit */
446 buf[byte_offset + num_items_scanned] = byte;
447 character = *rec++ & 0xFF;
448 if (character == '\0' || character == '\r' || character == '\n') {
449 /* Nothing more to parse */
451 } else if (character != ' ') {
452 /* not space before ASCII dump */
456 if (num_items_scanned == 0)
459 return num_items_scanned;
463 * Editor modelines - http://www.wireshark.org/tools/modelines.html
468 * indent-tabs-mode: t
471 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
472 * :indentSize=8:tabSize=8:noTabs=false: