Ethereal-users: Re: [Ethereal-users] pcap: network type 15 unknown or unsupported

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Guy Harris <gharris@xxxxxxxxx>
Date: Tue, 26 Jul 2005 02:19:40 -0700
Guy Harris wrote:

The current heuristics for detecting Nokia files in Ethereal only check if the link-layer type value is 13, which they use for ATM; I tried adding a check for 15, but apparently the heuristics succeed for the first two packets, which is all Ethereal currently tries - perhaps it should try 3 packets, which it appears should be enough to tell the difference between the two file types.

I think that's too risky.

Instead, I wrote a program called "denokify", that reads a Nokia pcap file and turns it into a standard pcap file. It doesn't do any heuristics; it assumes the file supplied to it is a Nokia pcap file, although it does some minimal sanity checking.

It worked on your file, and some other files I had; I've attached it to this mail. I'll probably put it into tcpdump or libpcap at some point, and put it into Ethereal as well.
/*
 * Some structure definitions come from libpcap:
 *
 * Copyright (c) 1993, 1994, 1995, 1996, 1997
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the Computer Systems
 *	Engineering Group at Lawrence Berkeley Laboratory.
 * 4. Neither the name of the University nor of the Laboratory may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <arpa/inet.h>

typedef unsigned int uint32;
typedef int int32;
typedef unsigned short uint16;
typedef unsigned char uint8;

struct pcap_file_header {
	uint32 magic;
	uint16 version_major;
	uint16 version_minor;
	int32 thiszone;		/* gmt to local correction */
	uint32 sigfigs;		/* accuracy of timestamps */
	uint32 snaplen;		/* max length saved portion of each pkt */
	uint32 linktype;	/* data link type (LINKTYPE_*) */
};

#define TCPDUMP_MAGIC		0xa1b2c3d4

struct pcap_timeval {
    int32 tv_sec;		/* seconds */
    int32 tv_usec;		/* microseconds */
};

struct pcap_sf_pkthdr {
    struct pcap_timeval ts;	/* time stamp */
    uint32 caplen;		/* length of portion present */
    uint32 len;			/* length this packet (off wire) */
};

struct pcap_nokia_pkthdr {
    struct pcap_sf_pkthdr hdr;	/* regular header */
    uint8	extra[4];	/* extra stuff */
};

struct atm_phdr {
	uint8 flags;
	uint8 vpi;
	uint16 vci;
};

#define	SWAPLONG(y) \
((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff))
#define	SWAPSHORT(y) \
	( (((y)&0xff)<<8) | ((uint16)((y)&0xff00)>>8) )

#define	PKTLEN_MAX	65535

int
main(int argc, char **argv)
{
	FILE *in, *out;
	struct pcap_file_header hdr;
	size_t bytes_read;
	int byte_swapped;
	uint32 linktype;
	struct pcap_nokia_pkthdr pkthdr;
	uint32 len, caplen;
	struct atm_phdr atm_phdr;
	uint16 vci;
	uint8 buf[PKTLEN_MAX];

	if (argc != 3) {
		fprintf(stderr, "Usage: denokify <infile> <outfile>\n");
		return 1;
	};
	
	in = fopen(argv[1], "r");
	if (in == NULL) {
		fprintf(stderr, "denokify: Can't open %s: %s\n", argv[1],
		    strerror(errno));
		return 2;
	}
	if (fread(&hdr, sizeof hdr, 1, in) != 1) {
		if (ferror(in)) {
			fprintf(stderr, "denokify: Error reading %s: %s\n",
			    argv[1], strerror(errno));
		} else {
			fprintf(stderr, "denokify: File %s was cut short\n",
			    argv[1]);
		}
		return 2;
	}
	if (hdr.magic == TCPDUMP_MAGIC)
		byte_swapped = 0;
	else if (hdr.magic == SWAPLONG(TCPDUMP_MAGIC))
		byte_swapped = 1;
	else {
		fprintf(stderr, "denokify: File %s is not a libpcap file\n",
		    argv[1]);
		return 2;
	}
	if (byte_swapped)
		hdr.linktype = SWAPLONG(hdr.linktype);
	switch (hdr.linktype) {

	case 1:
		linktype = 1;	/* Ethernet (DLT_EN10MB) */
		break;

	case 13:
		linktype = 123;	/* SunATM (DLT_SUNATM) */
		break;

	case 15:
		linktype = 104;	/* Cisco HDLC (DLT_C_HDLC) */
		break;

	default:
		fprintf(stderr, "denokify: File %s is not a Nokia ATM or Cisco HDLC capture file (type %u)\n",
		    argv[1], hdr.linktype);
		return 2;
	}
	if (byte_swapped)
		hdr.linktype = SWAPLONG(linktype);
	else
		hdr.linktype = linktype;

	out = fopen(argv[2], "w");
	if (out == NULL) {
		fprintf(stderr, "denokify: Can't create %s: %s\n", argv[2],
		    strerror(errno));
		return 2;
	}
	if (fwrite(&hdr, sizeof hdr, 1, out) != 1) {
		if (ferror(out)) {
			fprintf(stderr, "denokify: Error writing %s: %s\n",
			    argv[2], strerror(errno));
		} else {
			fprintf(stderr, "denokify: Short write on %s\n",
			    argv[2]);
		}
		return 2;
	}
	while (fread(&pkthdr, sizeof pkthdr, 1, in) == 1) {
		if (byte_swapped) {
			caplen = SWAPLONG(pkthdr.hdr.caplen);
			len = SWAPLONG(pkthdr.hdr.len);
		} else {
			caplen = pkthdr.hdr.caplen;
			len = pkthdr.hdr.len;
		}
		if (len > PKTLEN_MAX || caplen > PKTLEN_MAX) {
			fprintf(stderr,
			    "denokify: %s isn't a valid Nokia capture file\n",
			    argv[1]);
			return 2;
		}
		if (fwrite(&pkthdr.hdr, sizeof pkthdr.hdr, 1, out) != 1) {
			if (ferror(out)) {
				fprintf(stderr,
				    "denokify: Error writing %s: %s\n",
				    argv[2], strerror(errno));
			} else {
				fprintf(stderr,
				    "denokify: Short write on %s\n",
				    argv[2]);
			}
			return 2;
		}

		if (linktype == 123) {
			/*
			 * Read the Nokia ATM header.
			 */
			if (caplen < 4 || len < 4) {
				/*
				 * There *isn't* a pseudo-header, or
				 * this isn't a Nokia file.
				 */
				fprintf(stderr,
				    "denokify: %s isn't a valid Nokia ATM file\n",
				    argv[1]);
				return 2;
			}
			bytes_read = fread(&atm_phdr, 1, sizeof atm_phdr, in);
			if (bytes_read == 0 && !ferror(in))
				break;	/* end of file */
			if (bytes_read != sizeof atm_phdr) {
				if (ferror(in)) {
					fprintf(stderr,
					    "denokify: Error reading %s: %s\n",
					    argv[1], strerror(errno));
				} else {
					fprintf(stderr,
					    "denokify: File %s was cut short\n",
					    argv[1]);
				}
				return 2;
			}
			caplen -= 4;
			len -= 4;
		}

		bytes_read = fread(buf, 1, caplen, in);
		if (bytes_read != caplen) {
			if (ferror(in)) {
				fprintf(stderr,
				    "denokify: Error reading %s: %s\n",
				    argv[1], strerror(errno));
			} else {
				fprintf(stderr,
				    "denokify: File %s was cut short\n",
				    argv[1]);
			}
			return 2;
		}

		if (linktype == 123) {
			/*
			 * Tranform the Nokia ATM header into a
			 * SunATM ATM header.
			 *
			 * Try to guess the traffic type.
			 */
			atm_phdr.flags &= 0x7F;	/* type is initially unknown */
			vci = ntohs(atm_phdr.vci);
			if (atm_phdr.vpi == 0) {
				switch (vci) {

				case 5:
					atm_phdr.flags |= 0x06;	/* Q.2931 */
					break;

				case 16:
					atm_phdr.flags |= 0x05;	/* ILMI */
					break;
				}
			}
			if ((atm_phdr.flags & 0x7F) == 0) {
				if (caplen >= 3) {
					if (buf[0] == 0xaa && buf[1] == 0xaa &&
					    buf[2] == 0x03) {
						/*
						 * Looks like a SNAP header;
						 * assume it's LLC-multiplexed
						 * RFC 1483.
						 */
						atm_phdr.flags |= 0x02;
					} else {
						/*
						 * Assume it's LANE.
						 */
						atm_phdr.flags |= 0x01;
					}
				}
			}
			if (fwrite(&atm_phdr, sizeof atm_phdr, 1, out) != 1) {
				if (ferror(out)) {
					fprintf(stderr,
					    "denokify: Error writing %s: %s\n",
					    argv[2], strerror(errno));
				} else {
					fprintf(stderr,
					    "denokify: Short write on %s\n",
					    argv[2]);
				}
				return 2;
			}
		}
		if (fwrite(buf, 1, caplen, out) != caplen) {
			if (ferror(out)) {
				fprintf(stderr,
				    "denokify: Error writing %s: %s\n",
				    argv[2], strerror(errno));
			} else {
				fprintf(stderr,
				    "denokify: Short write on %s\n",
				    argv[2]);
			}
			return 2;
		}
	}
	if (fclose(out) == EOF) {		
		fprintf(stderr, "denokify: Error writing %s: %s\n",
		    argv[2], strerror(errno));
		return 2;
	}
	return 0;
}