[alt.sources] [ultrix] Re: Ultrix 4.0 Packet Filter Devices

mogul@wrl.dec.com (Jeffrey Mogul) (10/03/90)

Archive-name: ntrace/02-Oct-90
Original-posting-by: mogul@wrl.dec.com (Jeffrey Mogul)
Original-subject: Re: Ultrix 4.0 Packet Filter Devices
Reposted-by: emv@math.lsa.umich.edu (Edward Vielmetti)

[Reposted from comp.unix.ultrix.
Comments on this service to emv@math.lsa.umich.edu (Edward Vielmetti).]

In article <1990Sep21.010402.6587@wrl.dec.com> mogul@wrl.dec.com (me) wrote:
>If people seem interested, I'll post a small program that
>demonstrates how to use the packet filter for network monitoring.

Well, I got a small flurry of "yes" votes after that; what follows
is a "shar" file that contains the sources for a really stupid program
that prints header information for IP packets going by on the network.
Don't expect to use this program for anything, except as an example
of how to use the packet filter facility.   Especially, don't use it
as an example of good programming practice!

This program is not guaranteed in any way, and I don't intend to fix any bugs.

-Jeff

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  README etherinit.c makefile ntrace.c ntrace.h pfrerror.c
#   prsubs.c ptrace.c
# Wrapped by mogul@jove.pa.dec.com on Tue Oct  2 14:08:05 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(1121 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
This directory contains some sample software to demonstrate the use
of the packet filter.  The "ntrace" program functions as a rudimentary
X"LAN tracer", reporting the source and destination of each packet on the
network. It only deals with IP packets on Ethernets, and is not meant
to be actually useful for anything.
X
Since this depends on using promiscuous-mode access to the Ethernet,
you'll have to do
X	/etc/pfconfig +p pf0
X(as super-user) before you can get anything useful.  Maybe you'll want
to put this into /etc/rc.local?
X
The main program is "ntrace", usage:
X	ntrace pf0 [-debug] [-multicast] [-broadcast] [-w filename]
X
X	INTR to get current stats, QUIT to get out
X
With no options, it just sort of runs.  With -debug, the packet header
addresses are dumped on the terminal.  With -w, info records are written
to the specified file, which can then be read using the ptrace program.
X
XE.g.,
X
X	ntrace pf0 -w foo
X	(wait a while, type ^\)
X	ptrace <foo
X
The output format is
X    (612569015.836210) UDP [128.45.1.115/513] -> [128.45.1.255/513]
X	timestamp     proto  src address/port	  dest address/port
X	seconds.usecs
END_OF_FILE
if test 1121 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'etherinit.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'etherinit.c'\"
else
echo shar: Extracting \"'etherinit.c'\" \(3502 characters\)
sed "s/^X//" >'etherinit.c' <<'END_OF_FILE'
X/*
X * etherinit.c
X *
X * Network-related subroutines for ether statistics programs
X *
X */
X
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/socket.h>
X#include <net/if.h>
X#include <net/pfilt.h>
X
struct endevp DevParams;
int backlog = -1;
X
X/* Returns fid for ethernet device */
StartEther(ifname, MulticastOnly, BroadcastOnly)
char *ifname;
int MulticastOnly;
int BroadcastOnly;
X{
X	struct eniocb IOCB;
X	short enmode;
X	int EtherFid;
X	
X	if ((EtherFid = pfopen(ifname, 0)) < 0) {
X		perror(ifname);
X		exit(1);
X	}
X	
X	if (ioctl(EtherFid, EIOCDEVP, &DevParams) < 0) {
X		perror(ifname);
X		exit(1);
X	}
X
X	IOCB.en_rtout = 50;	/* in clock ticks */
X
X	if (ioctl(EtherFid, EIOCSETP, &IOCB) < 0) {
X		perror(ifname);
X		exit(1);
X	}
X
X	enmode = ENBATCH|ENTSTAMP|ENPROMISC|ENNONEXCL;
X	if (ioctl(EtherFid, EIOCMBIS, &enmode) < 0) {
X		perror(ifname);
X		exit(1);
X	}
X
X	if (ioctl(EtherFid, EIOCSETW, &backlog) < 0) {
X		perror(ifname);
X		exit(1);
X	}
X
X	BuildFilter(EtherFid, MulticastOnly, BroadcastOnly);
X	
X	return(EtherFid);
X}
X
X/*
X * filter accepts all packets (only multicasts if mcOnly is true)
X */
X
BuildFilter(EtherFid, mcOnly, bcOnly)
int EtherFid;
int mcOnly;
int bcOnly;
X{
X	struct enfilter Filter;
X	
X	Filter.enf_Priority = 37;	/* anything > 2 should work */
X	Filter.enf_FilterLen = 0;
X	
X	/* null filter should come out to be "always true" */
X
X	if (mcOnly) {	/* check the destination address multicast bit */
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =
X		ENF_PUSHWORD + 0;
X#ifndef	ENF_PUSHONE
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =
X	    	ENF_PUSHLIT | ENF_AND;
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =
X		htons(0x0100);
X			/* low bit of first byte is first bit on ether */
X#else
X	    /* low bit of first byte is first bit on ether */
X	    if (htons(0x0100) == 1) {
X		Filter.enf_Filter[Filter.enf_FilterLen++] =
X		    ENF_PUSHONE | ENF_AND;
X	    }
X	    else {
X		Filter.enf_Filter[Filter.enf_FilterLen++] =
X		    ENF_PUSHLIT | ENF_AND;
X		Filter.enf_Filter[Filter.enf_FilterLen++] =
X		    htons(0x0100);
X	    }
X#endif	ENF_PUSHONE
X	} else if (bcOnly) {	/* check all destination words */
X#ifndef	ENF_PUSHONE
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =
X		ENF_PUSHWORD + 0;
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =
X	    	ENF_PUSHLIT | ENF_CAND;
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =	0xFFFF;
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =
X		ENF_PUSHWORD + 1;
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =
X	    	ENF_PUSHLIT | ENF_CAND;
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =	0xFFFF;
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =
X		ENF_PUSHWORD + 2;
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =
X	    	ENF_PUSHLIT | ENF_EQ;
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =	0xFFFF;
X#else
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =
X		ENF_PUSHWORD + 0;
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =
X	    	ENF_PUSHFFFF | ENF_CAND;
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =
X		ENF_PUSHWORD + 1;
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =
X	    	ENF_PUSHFFFF | ENF_CAND;
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =
X		ENF_PUSHWORD + 2;
X	    Filter.enf_Filter[Filter.enf_FilterLen++] =
X	    	ENF_PUSHFFFF | ENF_EQ;
X#endif	ENF_PUSHONE
X	}
X
X	if (ioctl(EtherFid, EIOCSETF, &Filter) < 0) {
X		perror("setting filter");
X		exit(1);
X	}	
X}
X
char *EtherInterfaceName(EtherFid)
int EtherFid;
X{
X	static struct ifreq ifr;
X	
X	if (ioctl(EtherFid, EIOCIFNAME, &ifr) < 0) {
X		perror("getting interface name");
X		return("unknown");
X	}
X	return(ifr.ifr_name);
X}
END_OF_FILE
if test 3502 -ne `wc -c <'etherinit.c'`; then
    echo shar: \"'etherinit.c'\" unpacked with wrong size!
fi
# end of 'etherinit.c'
fi
if test -f 'makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makefile'\"
else
echo shar: Extracting \"'makefile'\" \(466 characters\)
sed "s/^X//" >'makefile' <<'END_OF_FILE'
X#PROF = -pg
PROF =
X
INCLUDES = 
X
OPTIM = -O2
CFLAGS = $(OPTIM) $(INCLUDES) $(PROF)
X#CFLAGS = -g $(INCLUDES) $(PROF)
X
NWLIB = etherinit.o pfrerror.o
X
all: ntrace ptrace
X
NTRACEOBJS = ntrace.o prsubs.o
ntrace: $(NTRACEOBJS) $(NWLIB)
X	cc $(OPTIM) $(PROF) -o ntrace $(NTRACEOBJS) $(NWLIB)
X
PTRACEOBJS = ptrace.o prsubs.o
ptrace: $(PTRACEOBJS) $(NWLIB)
X	cc $(OPTIM) $(PROF) -o ptrace $(PTRACEOBJS) $(NWLIB)
X
clean:
X	rm -f  ntrace ptrace
X	rm -f *.BAK *.CKP *.o a.out core
END_OF_FILE
if test 466 -ne `wc -c <'makefile'`; then
    echo shar: \"'makefile'\" unpacked with wrong size!
fi
# end of 'makefile'
fi
if test -f 'ntrace.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ntrace.c'\"
else
echo shar: Extracting \"'ntrace.c'\" \(6712 characters\)
sed "s/^X//" >'ntrace.c' <<'END_OF_FILE'
X/*
X * ntrace.c
X *
X * Collects (source,dest) traces on Ethernet
X *
X * Usage:
X *	ntrace ifname [-debug] [-multicast] [-broadcast] [-w filename]
X *	
X *	INTR to get current stats
X *	QUIT to get out
X *
X */
X
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/socket.h>
X#include <net/if.h>
X#include <net/pfilt.h>
X#include <netinet/in_systm.h>
X#include <netinet/in.h>
X#include <netinet/ip.h>
X#include <netinet/tcp.h>
X#include <netinet/udp.h>
X#include <netinet/if_ether.h>
X#include <signal.h>
X#include <stdio.h>
X#include <errno.h>
X#include <arpa/inet.h>
X#include "ntrace.h"
X
X#define	TRUNCATION	(sizeof(struct ether_header) + \
X			 sizeof(struct ip) + \
X			 sizeof(struct tcphdr))
X
float atof();
X
int MulticastOnly = 0;
int BroadcastOnly = 0;
int debug = 0;
int Writing = 0;
X
int TotDrops = 0;
int TotMissed = 0;
int Complex = 0;
int Counted = 0;
X
int dumpf = 0;
X
long StartTime;
X
X/* signal mask: ignore everything but SIGQUIT when this is set */
X#define	SMASK	(0xFFFF & ~(1<<(SIGQUIT-1)))
X
void catcher()
X{
X	printf("\n");	/* after the ^C */
X	DoStats(1);
X}
X
void dostats()
X{
X	DoStats(0);
X}
X
int olddrops = -1;
int oldmissed = 0;
X
DoStats(force)
int force;
X{
X	if (force || (TotDrops > olddrops) || (TotMissed > oldmissed)) {
X	    printf("Drops %d Missed %d ", TotDrops, TotMissed);
X	    olddrops = TotDrops;
X	    oldmissed = TotMissed;
X	    printf("Complex %d Counted %d\n", Complex, Counted);
X	}
X}
X
void GoAway()
X{
X	printf("\n");
X	DoStats(1);
X	exit(1);
X}
X
main(argc, argv)
int argc;
char **argv;
X{
X	char *ifname = argv[1];
X	struct sigvec svec;
X	register int i;
X	struct itimerval itval;
X	int EtherFid;
X
X	DoOptions((argc - 2), &(argv[2]));
X
X	svec.sv_handler = catcher;
X	svec.sv_mask = SMASK;
X	svec.sv_onstack = 0;
X	sigvec(SIGINT, &svec, 0);
X
X	svec.sv_handler = GoAway;
X	svec.sv_mask = SMASK;
X	svec.sv_onstack = 0;
X	sigvec(SIGQUIT, &svec, 0);
X
X	svec.sv_handler = dostats;
X	svec.sv_mask = SMASK;
X	svec.sv_onstack = 0;
X	sigvec(SIGALRM, &svec, 0);
X
X	StartTime = time(0);
X
X	EtherFid = StartEther(ifname, MulticastOnly, BroadcastOnly);
X
X	itval.it_interval.tv_usec = 0;
X	itval.it_interval.tv_sec = 1;
X	itval.it_value.tv_usec = 0;
X	itval.it_value.tv_sec = 1;
X	setitimer(ITIMER_REAL, &itval, 0);
X
X	RecvLoop(EtherFid);
X}
X
char buffer[1600*256];	/* big enough */
X
RecvLoop(EtherFid)
int EtherFid;
X{
X	register int buflen;
X	register int stamplen;
X	register int pktlen;
X	register char *bufp;
X	int truncation;
X	
X	truncation = TRUNCATION;
X	if (ioctl(EtherFid, EIOCTRUNCATE, &truncation) < 0)
X	    perror("ioctl/truncate");
X
X	while (1) {
X		buflen = read(EtherFid, buffer, (sizeof(buffer)-20));
X		bufp = buffer;
X		if (buflen < 0) {
X		    PFReadError(EtherFid, "reader");
X		}
X		else if (buflen == 0)
X			continue;
X		else {
X		    while (buflen > 0) {
X			struct enstamp *stp = (struct enstamp *)bufp;
X
X		        stamplen = stp->ens_stamplen;
X			if (stamplen != sizeof(struct enstamp)) {
X			    fprintf(stderr, "dropping bad stamp\n");
X			    buflen = -1;
X			}
X			else {
X			    pktlen = stp->ens_count;
X			    TraceIt(&(stp->ens_tstamp), pktlen,
X					&(bufp[stamplen]));
X			    TotDrops += stp->ens_dropped;
X			    TotMissed = stp->ens_ifoverflows;
X			    if (pktlen > truncation)
X				pktlen = truncation;
X			    if (buflen == (pktlen + stamplen))
X			        break;
X			    pktlen = ENALIGN(pktlen);
X			    buflen -= (pktlen + stamplen);
X			    bufp += (pktlen + stamplen);
X			}
X		    }
X		    if (buflen < 0)
X		   	printf(
X			    "Warning: part of one or more packets dropped\n");
X		}
X	}
X}
X
DoOptions(optc, optv)
int optc;
char **optv;
X{
X	while (optc > 0) {
X	    if (optv[0][0] == '-') {
X		switch (optv[0][1]) {
X		
X		case 'm':
X			MulticastOnly++;
X			break;
X
X		case 'b':
X			BroadcastOnly++;
X			break;
X
X		case 'd':
X			debug++;
X			break;
X
X		case 'w':
X			if (optc < 2) {
X			    fprintf(stderr,
X			    		"-w takes a file name argument\n");
X			    exit(1);
X			}
X			optc--;
X			optv++;
X			dumpf = creat(optv[0], 0666);
X			if (dumpf < 0) {
X			    perror(optv[0]);
X			    exit(1);
X			}
X			Writing++;
X			break;
X
X		default:
X			fprintf(stderr, "Unknown option %s\n", optv[0]);
X		}
X	    }
X	    optc--;
X	    optv++;
X	}
X}
X
X#define	BUFITEMS	1024
struct NetTrace nettrace[BUFITEMS];
struct NetTrace *ntcur = nettrace;
struct NetTrace *ntend = &(nettrace[BUFITEMS]);
X
TraceIt(tvp, len, bufp)
struct timeval *tvp;
int len;
char *bufp;
X{
X	struct ether_header *ehp;
X	struct ip *ipp;
X	struct tcphdr *tcpp;
X	struct udphdr *udpp;
X	int remlen;
X	char *ipdata;
X	struct NetTrace *ntp = ntcur;
X
X	ehp = (struct ether_header *)bufp;
X	
X	if (ehp->ether_type != ntohs(ETHERTYPE_IP)) {
X/*	    printf("Not IP %x\n", ehp->ether_type); */
X	    return;
X	}
X
X	remlen = len - (sizeof(*ehp) + sizeof(*ipp));
X	if (remlen < 0) {
X	    printf("Runt, len %d\n", len);
X	    return;
X	}
X	ipp = (struct ip *)&(bufp[sizeof(*ehp)]);
X	ipdata = &(bufp[(sizeof(*ehp) + sizeof(*ipp))]);
X	if (ipp->ip_hl != 5) {
X	    Complex++;
X	    printf("Options present, hl %d\n", ipp->ip_hl);
X	    return;
X	}
X	if (ipp->ip_off) {
X/*	    printf("Not first frag, off %d\n", ntohs(ipp->ip_off)); */
X	    return;
X	}
X	
X	/* looks like a keeper? */
X	ntp->nt_timestamp = *tvp;
X#ifdef	vax
X	ntp->nt_srcaddr = ipp->ip_src;
X	ntp->nt_dstaddr = ipp->ip_dst;
X#else
X	/* possible unaligned access */
X	ntp->nt_srcaddr.S_un.S_un_b.s_b1 = ipp->ip_src.S_un.S_un_b.s_b1;
X	ntp->nt_srcaddr.S_un.S_un_b.s_b2 = ipp->ip_src.S_un.S_un_b.s_b2;
X	ntp->nt_srcaddr.S_un.S_un_b.s_b3 = ipp->ip_src.S_un.S_un_b.s_b3;
X	ntp->nt_srcaddr.S_un.S_un_b.s_b4 = ipp->ip_src.S_un.S_un_b.s_b4;
X	ntp->nt_dstaddr.S_un.S_un_b.s_b1 = ipp->ip_dst.S_un.S_un_b.s_b1;
X	ntp->nt_dstaddr.S_un.S_un_b.s_b2 = ipp->ip_dst.S_un.S_un_b.s_b2;
X	ntp->nt_dstaddr.S_un.S_un_b.s_b3 = ipp->ip_dst.S_un.S_un_b.s_b3;
X	ntp->nt_dstaddr.S_un.S_un_b.s_b4 = ipp->ip_dst.S_un.S_un_b.s_b4;
X#endif	vax
X	ntp->nt_proto = ipp->ip_p;
X	
X	switch (ipp->ip_p) {
X	case IPPROTO_UDP:
X	    if (remlen < sizeof(*udpp)) {
X		printf("Runt UDP header (%d short)\n",
X			sizeof(*udpp) - remlen);
X		return;
X	    }
X	    udpp = (struct udphdr *)ipdata;
X	    ntp->nt_srcport = udpp->uh_sport;
X	    ntp->nt_dstport = udpp->uh_dport;
X	    break;
X	case IPPROTO_TCP:
X	    if (remlen < sizeof(*tcpp)) {
X		printf("Runt TCP header (%d short)\n",
X			sizeof(*tcpp) - remlen);
X		return;
X	    }
X	    tcpp = (struct tcphdr *)ipdata;
X	    ntp->nt_srcport = tcpp->th_sport;
X	    ntp->nt_dstport = tcpp->th_dport;
X	    break;
X	/* known but not handled protocols: */
X	case IPPROTO_ICMP:
X	    return;
X	default:
X	    printf("Unknown protocol %d\n", ipp->ip_p);
X	    return;
X	}
X	
X	Counted++;
X	if (debug)
X	    PrintNetTrace(ntp);
X	if (ntcur++ >= ntend) {
X	    if (Writing)
X		if (write(dumpf, nettrace, sizeof(nettrace))
X						 < sizeof(nettrace)) {
X		    perror("writing trace buffer");
X		    exit(1);
X		}
X	    ntcur = nettrace;
X	}
X}
END_OF_FILE
if test 6712 -ne `wc -c <'ntrace.c'`; then
    echo shar: \"'ntrace.c'\" unpacked with wrong size!
fi
# end of 'ntrace.c'
fi
if test -f 'ntrace.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ntrace.h'\"
else
echo shar: Extracting \"'ntrace.h'\" \(238 characters\)
sed "s/^X//" >'ntrace.h' <<'END_OF_FILE'
X/*
X * ntrace.h
X *
X * Defines format of network trace buffer
X *
X */
X
struct NetTrace {
X	struct timeval	nt_timestamp;
X	struct in_addr	nt_srcaddr;
X	struct in_addr	nt_dstaddr;
X	u_short		nt_srcport;
X	u_short		nt_dstport;
X	u_char		nt_proto;
X};
END_OF_FILE
if test 238 -ne `wc -c <'ntrace.h'`; then
    echo shar: \"'ntrace.h'\" unpacked with wrong size!
fi
# end of 'ntrace.h'
fi
if test -f 'pfrerror.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pfrerror.c'\"
else
echo shar: Extracting \"'pfrerror.c'\" \(818 characters\)
sed "s/^X//" >'pfrerror.c' <<'END_OF_FILE'
X/*
X * pfrerror.c
X *
X * Decide what to do on a packet filter read error
X *
X * The problem is that, since the packet filter is a character device
X * rather than a socket, every read bumps the file pointer.  After a
X * few gigabytes, the file pointer becomes negative and the kernel
X * thinks this is wrong.  We check for this condition and repair it;
X * otherwise, we give up.
X *
X * $Log:	pfrerror.c,v $
X * Revision 1.1  87/09/28  13:33:07  mogul
X * Version for Ultrix2.0 and portability
X * 
X */
X
X#include <errno.h>
X
extern int errno;
X
X/* Call ONLY if there has been an error on a read(pffid, x, y) */
PFReadError(pffid, message)
int pffid;
char *message;
X{
X	if (errno == EINVAL) {
X	    if (lseek(pffid, 0, 0) < 0) {
X		perror("PFReadError/lseek:");
X		abort();
X	    }
X	}
X	else {
X	    perror(message);
X	    abort();
X	}
X}
X
END_OF_FILE
if test 818 -ne `wc -c <'pfrerror.c'`; then
    echo shar: \"'pfrerror.c'\" unpacked with wrong size!
fi
# end of 'pfrerror.c'
fi
if test -f 'prsubs.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'prsubs.c'\"
else
echo shar: Extracting \"'prsubs.c'\" \(768 characters\)
sed "s/^X//" >'prsubs.c' <<'END_OF_FILE'
X/*
X * prsubs.c
X *
X * Subroutines for printing nettrace records
X *
X */
X
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/socket.h>
X#include <netinet/in_systm.h>
X#include <netinet/in.h>
X#include <netinet/ip.h>
X#include <stdio.h>
X#include <errno.h>
X#include <arpa/inet.h>
X#include "ntrace.h"
X
PrintNetTrace(ntp)
struct NetTrace *ntp;
X{
X	printf("(%d.%06d) ",
X		ntp->nt_timestamp.tv_sec,ntp->nt_timestamp.tv_usec);
X	switch (ntp->nt_proto) {
X	case IPPROTO_TCP:
X	    printf("TCP ");
X	    break;
X	case IPPROTO_UDP:
X	    printf("UDP ");
X	    break;
X	default:
X	    printf("%d ", ntp->nt_proto);
X	    break;
X	}
X	
X	printf("[%s/%d] -> ",
X		inet_ntoa(ntp->nt_srcaddr), ntohs(ntp->nt_srcport));
X	printf("[%s/%d]\n",
X		inet_ntoa(ntp->nt_dstaddr), ntohs(ntp->nt_dstport));
X}
END_OF_FILE
if test 768 -ne `wc -c <'prsubs.c'`; then
    echo shar: \"'prsubs.c'\" unpacked with wrong size!
fi
# end of 'prsubs.c'
fi
if test -f 'ptrace.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ptrace.c'\"
else
echo shar: Extracting \"'ptrace.c'\" \(549 characters\)
sed "s/^X//" >'ptrace.c' <<'END_OF_FILE'
X/*
X * ptrace.c
X *
X * Reads trace file and prints it (filter)
X */
X
X#include <sys/types.h>
X#include <sys/time.h>
X#include <sys/socket.h>
X#include <netinet/in_systm.h>
X#include <netinet/in.h>
X#include <netinet/ip.h>
X#include <stdio.h>
X#include "ntrace.h"
X
X#define	BUFITEMS 1024
struct NetTrace nettrace[BUFITEMS];
X
main()
X{
X	int count;
X	struct NetTrace *ntp;
X
X	while ((count = read(0, nettrace, sizeof(nettrace))) > 0) {
X		count = count/sizeof(struct NetTrace);
X		ntp = nettrace;
X		while (count-- > 0) {
X		    PrintNetTrace(ntp);
X		    ntp++;
X		}
X	}
X}
END_OF_FILE
if test 549 -ne `wc -c <'ptrace.c'`; then
    echo shar: \"'ptrace.c'\" unpacked with wrong size!
fi
# end of 'ptrace.c'
fi
echo shar: End of shell archive.
exit 0