Article 2689 of comp.sources.unix:
Path: nntpd.lkg.dec.com!crl.dec.com!crl.dec.com!caen!reeve.research.aa.wl.com!decwrl!news1.digital.com!vixie!vixie!not-for-mail
From: argus@SEI.CMU.EDU
Newsgroups: comp.sources.unix
Subject: v29i033: argus-1.5 - a generic IP network transaction auditing tool, Part03/06
Date: 16 Oct 1995 23:06:59 -0700
Organization: Vixie Enterprises
Lines: 3855
Sender: vixie@vix.com
Approved: vixie@gw.home.vix.com
Message-ID: <45vh63$21r@gw.home.vix.com>
References: <1.813909952.2078@gw.home.vix.com>
NNTP-Posting-Host: gw.home.vix.com

Submitted-By: argus@SEI.CMU.EDU
Posting-Number: Volume 29, Issue 33
Archive-Name: argus-1.5/part03

#!/bin/sh
# This is `part03' (part 3 of a multipart archive).
# Do not concatenate these parts, unpack them in order with `/bin/sh'.
# File `argus-1.5/common/addrtoname.c' is being continued...
#
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
  shar_touch=touch
else
  shar_touch=:
  echo
  echo 'WARNING: not restoring timestamps.  Consider getting and'
  echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 1231235999 $$.touch
#
if test ! -r _sharseq.tmp; then
  echo 'Please unpack part 1 first!'
  exit 1
fi
shar_sequence=`cat _sharseq.tmp`
if test "$shar_sequence" != 3; then
  echo "Please unpack part $shar_sequence next!"
  exit 1
fi
if test ! -f _sharnew.tmp; then
  echo 'x - still skipping argus-1.5/common/addrtoname.c'
else
  echo 'x - continuing file argus-1.5/common/addrtoname.c'
  sed 's/^X//' << 'SHAR_EOF' >> 'argus-1.5/common/addrtoname.c' &&
X * Copyright (c) 1990, 1991, 1992, 1993, 1994
X *	The Regents of the University of California.  All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that: (1) source code distributions
X * retain the above copyright notice and this paragraph in its entirety, (2)
X * distributions including binary code include the above copyright notice and
X * this paragraph in its entirety in the documentation or other materials
X * provided with the distribution, and (3) all advertising materials mentioning
X * features or use of this software display the following acknowledgement:
X * ``This product includes software developed by the University of California,
X * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
X * the University nor the names of its contributors may be used to endorse
X * or promote products derived from this software without specific prior
X * written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
X * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X *
X *  Internet, ethernet, port, and protocol string to address
X *  and address to string conversion routines
X */
X#ifndef lint
Xstatic char rcsid[] =
X    "@(#) $Header: /us/wcb/research/src/argus/argus-1.5/common/RCS/addrtoname.c,v 1.2 1995/04/24 19:36:49 wcb Exp $ (LBL)";
X#endif
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/time.h>
X
X#include <net/if.h>
X
X#include <netinet/in.h>
X#include <netinet/if_ether.h>
X
X#include <arpa/inet.h>
X
X#include <ctype.h>
X#include <netdb.h>
X#include <pcap.h>
X#include <pcap-namedb.h>
X#include <signal.h>
X#include <stdio.h>
X#include <string.h>
X#ifdef __STDC__
X#include <stdlib.h>
X#endif
X#include <unistd.h>
X
X#include "interface.h"
X#include "addrtoname.h"
X#include "llc.h"
X
Xstatic SIGRET nohostname(int);
X#ifdef ETHER_SERVICE
Xstruct ether_addr;
Xextern int ether_ntohost(char *, struct ether_addr *);
X#endif
X
X/*
X * hash tables for whatever-to-name translations
X */
X
X#define HASHNAMESIZE 4096
X
Xstruct hnamemem {
X	u_int32 addr;
X	char *name;
X	struct hnamemem *nxt;
X};
X
Xstruct hnamemem hnametable[HASHNAMESIZE];
Xstruct hnamemem tporttable[HASHNAMESIZE];
Xstruct hnamemem uporttable[HASHNAMESIZE];
Xstruct hnamemem eprototable[HASHNAMESIZE];
Xstruct hnamemem nnametable[HASHNAMESIZE];
Xstruct hnamemem llcsaptable[HASHNAMESIZE];
X
Xstruct enamemem {
X	u_short e_addr0;
X	u_short e_addr1;
X	u_short e_addr2;
X	char *e_name;
X	u_char *e_nsap;			/* used only for nsaptable[] */
X	struct enamemem *e_nxt;
X};
X
Xstruct enamemem enametable[HASHNAMESIZE];
Xstruct enamemem nsaptable[HASHNAMESIZE];
X
Xstruct protoidmem {
X	u_long p_oui;
X	u_short p_proto;
X	char *p_name;
X	struct protoidmem *p_nxt;
X};
X
Xstruct protoidmem protoidtable[HASHNAMESIZE];
X
X/*
X * A faster replacement for inet_ntoa().
X */
Xchar *
Xintoa(u_int32 addr)
X{
X	char *cp;
X	u_int byte;
X	int n;
X	static char buf[sizeof(".xxx.xxx.xxx.xxx")];
X
X	NTOHL(addr);
X	cp = &buf[sizeof buf];
X	*--cp = '\0';
X
X	n = 4;
X	do {
X		byte = addr & 0xff;
X		*--cp = byte % 10 + '0';
X		byte /= 10;
X		if (byte > 0) {
X			*--cp = byte % 10 + '0';
X			byte /= 10;
X			if (byte > 0)
X				*--cp = byte + '0';
X		}
X		*--cp = '.';
X		addr >>= 8;
X	} while (--n > 0);
X
X	return cp + 1;
X}
X
Xstatic u_int32 f_netmask;
Xstatic u_int32 f_localnet;
Xstatic u_int32 netmask;
X
X/*
X * "getname" is written in this atrocious way to make sure we don't
X * wait forever while trying to get hostnames from yp.
X */
X#include <setjmp.h>
X
Xjmp_buf getname_env;
X
Xstatic SIGRET
Xnohostname(int signo)
X{
X	longjmp(getname_env, 1);
X}
X
X/*
X * Return a name for the IP address pointed to by ap.  This address
X * is assumed to be in network byte order.
X */
Xchar *
Xgetname(u_char *ap)
X{
X	struct hostent *hp;
X	char *cp;
X	u_int32 addr;
X	static struct hnamemem *p;		/* static for longjmp() */
X
X#ifndef TCPDUMP_ALIGN
X	addr = *(const u_int32 *)ap;
X#else
X	/*
X	 * Deal with alignment.
X	 */
X	switch ((int)ap & 3) {
X
X	case 0:
X		addr = *(u_int32 *)ap;
X		break;
X
X	case 2:
X#if BYTE_ORDER == LITTLE_ENDIAN
X		addr = ((u_int32)*(u_short *)(ap + 2) << 16) |
X			(u_int32)*(u_short *)ap;
X#else
X		addr = ((u_int32)*(u_short *)ap << 16) |
X			(u_int32)*(u_short *)(ap + 2);
X#endif
X		break;
X
X	default:
X#if BYTE_ORDER == LITTLE_ENDIAN
X		addr = ((u_int32)ap[0] << 24) |
X			((u_int32)ap[1] << 16) |
X			((u_int32)ap[2] << 8) |
X			(u_int32)ap[3];
X#else
X		addr = ((u_int32)ap[3] << 24) |
X			((u_int32)ap[2] << 16) |
X			((u_int32)ap[1] << 8) |
X			(u_int32)ap[0];
X#endif
X		break;
X	}
X#endif
X	p = &hnametable[addr & (HASHNAMESIZE-1)];
X	for (; p->nxt; p = p->nxt) {
X		if (p->addr == addr)
X			return (p->name);
X	}
X	p->addr = addr;
X	p->nxt = (struct hnamemem *)calloc(1, sizeof (*p));
X
X	/*
X	 * Only print names when:
X	 *	(1) -n was not given.
X	 *	(2) Address is foreign and -f was given.  If -f was not
X	 *	    present, f_netmask and f_local are 0 and the second
X	 *	    test will succeed.
X	 *	(3) The host portion is not 0 (i.e., a network address).
X	 *	(4) The host portion is not broadcast.
X	 */
X	if (!nflag && (addr & f_netmask) == f_localnet
X	    && (addr &~ netmask) != 0 && (addr | netmask) != 0xffffffff) {
X		if (!setjmp(getname_env)) {
X			(void)signal(SIGALRM, nohostname);
X			(void)alarm(20);
X			hp = gethostbyaddr((char *)&addr, 4, AF_INET);
X			(void)alarm(0);
X			if (hp) {
X				char *dotp;
X
X				p->name = savestr(hp->h_name);
X				if (Nflag) {
X					/* Remove domain qualifications */
X					dotp = strchr(p->name, '.');
X					if (dotp)
X						*dotp = 0;
X				}
X				return (p->name);
X			}
X		}
X	}
X	cp = intoa(addr);
X	p->name = savestr(cp);
X	return (p->name);
X}
X
Xstatic char hex[] = "0123456789abcdef";
X
X
X/* Find the hash node that corresponds the ether address 'ep'. */
X
Xstatic inline struct enamemem *
Xlookup_emem(const u_char *ep)
X{
X	u_int i, j, k;
X	struct enamemem *tp;
X
X	k = (ep[0] << 8) | ep[1];
X	j = (ep[2] << 8) | ep[3];
X	i = (ep[4] << 8) | ep[5];
X
X	tp = &enametable[(i ^ j) & (HASHNAMESIZE-1)];
X	while (tp->e_nxt)
X		if (tp->e_addr0 == i &&
X		    tp->e_addr1 == j &&
X		    tp->e_addr2 == k)
X			return tp;
X		else
X			tp = tp->e_nxt;
X	tp->e_addr0 = i;
X	tp->e_addr1 = j;
X	tp->e_addr2 = k;
X	tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
X
X	return tp;
X}
X
X/* Find the hash node that corresponds the NSAP 'nsap'. */
X
Xstatic inline struct enamemem *
Xlookup_nsap(const u_char *nsap)
X{
X	u_int i, j, k;
X	int nlen = *nsap;
X	struct enamemem *tp;
X	const u_char *ensap = nsap + nlen - 6;
X
X	if (nlen > 6) {
X		k = (ensap[0] << 8) | ensap[1];
X		j = (ensap[2] << 8) | ensap[3];
X		i = (ensap[4] << 8) | ensap[5];
X	}
X	else
X		i = j = k = 0;
X
X	tp = &nsaptable[(i ^ j) & (HASHNAMESIZE-1)];
X	while (tp->e_nxt)
X		if (tp->e_addr0 == i &&
X		    tp->e_addr1 == j &&
X		    tp->e_addr2 == k &&
X		    tp->e_nsap[0] == nlen &&
X		    bcmp((char *)&(nsap[1]),
X			(char *)&(tp->e_nsap[1]), nlen) == 0)
X			return tp;
X		else
X			tp = tp->e_nxt;
X	tp->e_addr0 = i;
X	tp->e_addr1 = j;
X	tp->e_addr2 = k;
X	tp->e_nsap = (u_char *) calloc(1, nlen + 1);
X	bcopy(nsap, tp->e_nsap, nlen + 1);
X	tp->e_nxt = (struct enamemem *)calloc(1, sizeof(*tp));
X
X	return tp;
X}
X
X/* Find the hash node that corresponds the protoid 'pi'. */
X
Xstatic inline struct protoidmem *
Xlookup_protoid(const u_char *pi)
X{
X	u_int i, j;
X	struct protoidmem *tp;
X
X	/* 5 octets won't be aligned */
X	i = (((pi[0] << 8) + pi[1]) << 8) + pi[2];
X	j =   (pi[3] << 8) + pi[4];
X	/* XXX should be endian-insensitive, but do big-endian testing  XXX */
X
X	tp = &protoidtable[(i ^ j) & (HASHNAMESIZE-1)];
X	while (tp->p_nxt)
X		if (tp->p_oui == i && tp->p_proto == j)
X			return tp;
X		else
X			tp = tp->p_nxt;
X	tp->p_oui = i;
X	tp->p_proto = j;
X	tp->p_nxt = (struct protoidmem *)calloc(1, sizeof(*tp));
X
X	return tp;
X}
X
Xchar *
Xetheraddr_string(u_char *ep)
X{
X	u_int i, j;
X	char *cp;
X	struct enamemem *tp;
X
X	tp = lookup_emem(ep);
X	if (tp->e_name)
X		return (tp->e_name);
X#ifdef ETHER_SERVICE
X	if (!nflag) {
X		char buf[128];
X		if (ether_ntohost(buf, (struct ether_addr *)ep) == 0) {
X			tp->e_name = savestr(buf);
X			return (tp->e_name);
X		}
X	}
X#endif
X	tp->e_name = cp = (char *)malloc(sizeof("00:00:00:00:00:00"));
X
X	if ((j = *ep >> 4) != 0)
X		*cp++ = hex[j];
X	*cp++ = hex[*ep++ & 0xf];
X	for (i = 5; (int)--i >= 0;) {
X		*cp++ = ':';
X		if ((j = *ep >> 4) != 0)
X			*cp++ = hex[j];
X		*cp++ = hex[*ep++ & 0xf];
X	}
X	*cp = '\0';
X	return (tp->e_name);
X}
X
Xchar *
Xetherproto_string(u_short port)
X{
X	char *cp;
X	struct hnamemem *tp;
X	u_long i = port;
X
X	for (tp = &eprototable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
X		if (tp->addr == i)
X			return (tp->name);
X
X	tp->name = cp = (char *)malloc(sizeof("0000"));
X	tp->addr = i;
X	tp->nxt = (struct hnamemem *)calloc(1, sizeof (*tp));
X
X	NTOHS(port);
X	*cp++ = hex[port >> 12 & 0xf];
X	*cp++ = hex[port >> 8 & 0xf];
X	*cp++ = hex[port >> 4 & 0xf];
X	*cp++ = hex[port & 0xf];
X	*cp++ = '\0';
X	return (tp->name);
X}
X
Xchar *
Xprotoid_string(const u_char *pi)
X{
X	u_int i, j;
X	char *cp;
X	struct protoidmem *tp;
X
X	tp = lookup_protoid(pi);
X	if (tp->p_name)
X		return tp->p_name;
X
X	tp->p_name = cp = (char *)malloc(sizeof("00:00:00:00:00"));
X
X	if ((j = *pi >> 4) != 0)
X		*cp++ = hex[j];
X	*cp++ = hex[*pi++ & 0xf];
X	for (i = 4; (int)--i >= 0;) {
X		*cp++ = ':';
X		if ((j = *pi >> 4) != 0)
X			*cp++ = hex[j];
X		*cp++ = hex[*pi++ & 0xf];
X	}
X	*cp = '\0';
X	return (tp->p_name);
X}
X
Xchar *
Xllcsap_string(u_char sap)
X{
X	char *cp;
X	struct hnamemem *tp;
X	u_long i = sap;
X
X	for (tp = &llcsaptable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
X		if (tp->addr == i)
X			return (tp->name);
X
X	tp->name = cp = (char *)malloc(sizeof("sap 00"));
X	tp->addr = i;
X	tp->nxt = (struct hnamemem *)calloc(1, sizeof (*tp));
X
X	(void)strcpy(cp, "sap ");
X	cp += strlen(cp);
X	*cp++ = hex[sap >> 4 & 0xf];
X	*cp++ = hex[sap & 0xf];
X	*cp++ = '\0';
X	return (tp->name);
X}
X
Xchar *
Xisonsap_string(const u_char *nsap)
X{
X	u_int i, nlen = nsap[0];
X	char *cp;
X	struct enamemem *tp;
X
X	tp = lookup_nsap(nsap);
X	if (tp->e_name)
X		return tp->e_name;
X
X	tp->e_name = cp = (char *)malloc(nlen * 2 + 2);
X
X	nsap++;
X	*cp++ = '/';
X	for (i = nlen; (int)--i >= 0;) {
X		*cp++ = hex[*nsap >> 4];
X		*cp++ = hex[*nsap++ & 0xf];
X	}
X	*cp = '\0';
X	return (tp->e_name);
X}
X
Xchar *
Xtcpport_string(u_short port)
X{
X	struct hnamemem *tp;
X	u_long i = port;
X
X	for (tp = &tporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
X		if (tp->addr == i)
X			return (tp->name);
X
X	tp->name = (char *)malloc(sizeof("00000"));
X	tp->addr = i;
X	tp->nxt = (struct hnamemem *)calloc(1, sizeof (*tp));
X
X	(void)sprintf(tp->name, "%d", i);
X	return (tp->name);
X}
X
Xchar *
Xudpport_string(u_short port)
X{
X	struct hnamemem *tp;
X	u_long i = port;
X
X        if (port) {
X	   for (tp = &uporttable[i & (HASHNAMESIZE-1)]; tp->nxt; tp = tp->nxt)
X		   if (tp->addr == i)
X			   return (tp->name);
X
X	   tp->name = (char *)malloc(sizeof("00000"));
X	   tp->addr = i;
X	   tp->nxt = (struct hnamemem *)calloc(1, sizeof(*tp));
X
X	   (void)sprintf(tp->name, "%d", i);
X
X	   return (tp->name);
X	} else
X	return ("*");
X}
X
Xstatic void
Xinit_servarray(void)
X{
X	struct servent *sv;
X	struct hnamemem *table;
X	int i;
X
X	while ((sv = getservent()) != NULL) {
X		int port = ntohs(sv->s_port);
X		i = port & (HASHNAMESIZE-1);
X		if (strcmp(sv->s_proto, "tcp") == 0)
X			table = &tporttable[i];
X		else if (strcmp(sv->s_proto, "udp") == 0)
X			table = &uporttable[i];
X		else
X			continue;
X
X		while (table->name)
X			table = table->nxt;
X		if (nflag) {
X			char buf[32];
X
X			(void)sprintf(buf, "%d", port);
X			table->name = savestr(buf);
X		} else
X			table->name = savestr(sv->s_name);
X		table->addr = port;
X		table->nxt = (struct hnamemem *)calloc(1, sizeof(*table));
X	}
X	endservent();
X}
X
X/*XXX from libbpfc.a */
Xextern struct eproto {
X	char *s;
X	u_short p;
X} eproto_db[];
X
Xstatic void
Xinit_eprotoarray(void)
X{
X	int i;
X	struct hnamemem *table;
X
X	for (i = 0; eproto_db[i].s; i++) {
X		int j = ntohs(eproto_db[i].p) & (HASHNAMESIZE-1);
X		table = &eprototable[j];
X		while (table->name)
X			table = table->nxt;
X		table->name = eproto_db[i].s;
X		table->addr = ntohs(eproto_db[i].p);
X		table->nxt = (struct hnamemem *)calloc(1, sizeof(*table));
X	}
X}
X
X/*
X * SNAP proto IDs with org code 0:0:0 are actually encapsulated Ethernet
X * types.
X */
Xstatic void
Xinit_protoidarray(void)
X{
X	int i;
X	struct protoidmem *tp;
X	u_char protoid[5];
X
X	protoid[0] = 0;
X	protoid[1] = 0;
X	protoid[2] = 0;
X	for (i = 0; eproto_db[i].s; i++) {
X		u_short etype = htons(eproto_db[i].p);
X		bcopy((char *)&etype, (char *)&protoid[3], 2);
X		tp = lookup_protoid(protoid);
X		tp->p_name = savestr(eproto_db[i].s);
X	}
X}
X
Xstatic struct etherlist {
X	u_char addr[6];
X	char *name;
X} etherlist[] = {
X	{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, "Broadcast" },
X	{{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, NULL }
X};
X
X/*
X * Initialize the ethers hash table.  We take two different approaches
X * depending on whether or not the system provides the ethers name
X * service.  If it does, we just wire in a few names at startup,
X * and etheraddr_string() fills in the table on demand.  If it doesn't,
X * then we suck in the entire /etc/ethers file at startup.  The idea
X * is that parsing the local file will be fast, but spinning through
X * all the ethers entries via NIS & next_etherent might be very slow.
X *
X * XXX pcap_next_etherent doesn't belong in the pcap interface, but
X * since the pcap module already does name-to-address translation,
X * it's already does most of the work for the ethernet address-to-name
X * translation, so we just pcap_next_etherent as a convenience.
X */
Xstatic void
Xinit_etherarray(void)
X{
X	struct etherlist *el;
X	struct enamemem *tp;
X#ifndef ETHER_SERVICE
X	struct pcap_etherent *ep;
X	FILE *fp;
X
X	/* Suck in entire ethers file */
X	fp = fopen(PCAP_ETHERS_FILE, "r");
X	if (fp != NULL) {
X		while ((ep = pcap_next_etherent(fp)) != NULL) {
X			tp = lookup_emem(ep->addr);
X			tp->e_name = savestr(ep->name);
X		}
X		(void)fclose(fp);
X	}
X#endif
X
X	/* Hardwire some ethernet names */
X	for (el = etherlist; el->name != NULL; ++el) {
X#ifdef ETHER_SERVICE
X                /* Use yp/nis version of name if available */
X		char wrk[256];
X                if (ether_ntohost(wrk, (struct ether_addr *)el->addr) == 0) {
X			tp = lookup_emem(el->addr);
X                        tp->e_name = savestr(wrk);
X		}
X#else
X		/* install if not already present */
X		tp = lookup_emem(el->addr);
X		if (tp->e_name == NULL)
X			tp->e_name = el->name;
X#endif
X
X	}
X}
X
Xstatic struct token llcsap_db[] = {
X	{ LLCSAP_NULL,		"null" },
X	{ LLCSAP_8021B_I,	"802.1b-gsap" },
X	{ LLCSAP_8021B_G,	"802.1b-isap" },
X	{ LLCSAP_IP,		"ip-sap" },
X	{ LLCSAP_PROWAYNM,	"proway-nm" },
X	{ LLCSAP_8021D,		"802.1d" },
X	{ LLCSAP_RS511,		"eia-rs511" },
X	{ LLCSAP_ISO8208,	"x.25/llc2" },
X	{ LLCSAP_PROWAY,	"proway" },
X	{ LLCSAP_ISONS,		"iso-clns" },
X	{ LLCSAP_GLOBAL,	"global" },
X	{ 0,			NULL }
X};
X
Xstatic void
Xinit_llcsaparray(void)
X{
X	int i;
X	struct hnamemem *table;
X
X	for (i = 0; llcsap_db[i].s != NULL; i++) {
X		table = &llcsaptable[llcsap_db[i].v];
X		while (table->name)
X			table = table->nxt;
X		table->name = llcsap_db[i].s;
X		table->addr = llcsap_db[i].v;
X		table->nxt = (struct hnamemem *)calloc(1, sizeof(*table));
X	}
X}
X
X/*
X * Initialize the address to name translation machinery.  We map all
X * non-local IP addresses to numeric addresses if fflag is true (i.e.,
X * to prevent blocking on the nameserver).  localnet is the IP address
X * of the local network.  mask is its subnet mask.
X */
Xvoid
Xinit_addrtoname(int fflag, u_int32 localnet, u_int32 mask)
X{
X	netmask = mask;
X	if (fflag) {
X		f_localnet = localnet;
X		f_netmask = mask;
X	}
X	if (nflag)
X		/*
X		 * Simplest way to suppress names.
X		 */
X		return;
X
X	init_etherarray();
X	init_servarray();
X	init_eprotoarray();
X	init_llcsaparray();
X	init_protoidarray();
X}
SHAR_EOF
  echo 'File argus-1.5/common/addrtoname.c is complete' &&
  $shar_touch -am 0508141395 'argus-1.5/common/addrtoname.c' &&
  chmod 0444 'argus-1.5/common/addrtoname.c' ||
  echo 'restore of argus-1.5/common/addrtoname.c failed'
  shar_count="`wc -c < 'argus-1.5/common/addrtoname.c'`"
  test 15570 -eq "$shar_count" ||
    echo "argus-1.5/common/addrtoname.c: original size 15570, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= argus-1.5/common/argus_filter.c ==============
if test -f 'argus-1.5/common/argus_filter.c' && test X"$1" != X"-c"; then
  echo 'x - skipping argus-1.5/common/argus_filter.c (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting argus-1.5/common/argus_filter.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'argus-1.5/common/argus_filter.c' &&
X/*-
X * Copyright (c) 1990, 1991, 1992, 1993
X *   The Regents of the University of California.  All rights reserved.
X *
X * This code is derived from the Stanford/CMU enet packet filter,
X * (net/enet.c) distributed as part of 4.3BSD, and code contributed
X * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence 
X * Berkeley Laboratory.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that the following conditions
X * are met:
X * 1. Redistributions of source code must retain the above copyright
X *    notice, this list of conditions and the following disclaimer.
X * 2. Redistributions in binary form must reproduce the above copyright
X *    notice, this list of conditions and the following disclaimer in the
X *    documentation and/or other materials provided with the distribution.
X * 3. All advertising materials mentioning features or use of this software
X *    must display the following acknowledgement:
X *   This product includes software developed by the University of
X *   California, Berkeley and its contributors.
X * 4. Neither the name of the University nor the names of its contributors
X *    may be used to endorse or promote products derived from this software
X *    without specific prior written permission.
X *
X * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
X * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
X * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
X * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
X * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
X * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
X * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
X * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
X * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
X * SUCH DAMAGE.
X *
X *   @(#)bpf.c   7.5 (Berkeley) 7/15/91
X *
X * static char rcsid[] =
X * "$Header: /usr/users/poepping/src/argus/argus-1.5/common/RCS/argus_filter.c,v 1.1 1995/02/08 21:03:27 poepping Exp $";
X */
X#if !(defined(lint) || defined(KERNEL))
Xstatic char rcsid[] =
X    "@(#) $Header: /usr/users/poepping/src/argus/argus-1.5/common/RCS/argus_filter.c,v 1.1 1995/02/08 21:03:27 poepping Exp $ (LBL)";
X#endif
X
X#include <sys/param.h>
X#include <sys/types.h>
X#include <sys/time.h>
X#include <net/bpf.h>
X
X#if   defined(__alpha)
Xtypedef   int   int32;
Xtypedef   u_int   u_int32;
X#else
Xtypedef   long   int32;
Xtypedef   u_long   u_int32;
X#endif
X
X#ifdef sun
X#include <netinet/in.h>
X#endif
X
X#if defined(sparc) || defined(mips) || defined(ibm032) || defined(__alpha)
X#define BPF_ALIGN
X#endif
X
X#ifndef BPF_ALIGN
X#define EXTRACT_SHORT(p)   ((u_short)ntohs(*(u_short *)p))
X#define EXTRACT_LONG(p)      (ntohl(*(u_int32 *)p))
X#else
X#define EXTRACT_SHORT(p)\
X   ((u_short)\
X      ((u_short)*((u_char *)p+0)<<8|\
X       (u_short)*((u_char *)p+1)<<0))
X#define EXTRACT_LONG(p)\
X      ((u_int32)*((u_char *)p+0)<<24|\
X       (u_int32)*((u_char *)p+1)<<16|\
X       (u_int32)*((u_char *)p+2)<<8|\
X       (u_int32)*((u_char *)p+3)<<0)
X#endif
X
X#ifdef KERNEL
X#include <sys/mbuf.h>
X#define MINDEX(m, k) \
X{ \
X   register int len = m->m_len; \
X \
X   while (k >= len) { \
X      k -= len; \
X      m = m->m_next; \
X      if (m == 0) \
X         return 0; \
X      len = m->m_len; \
X   } \
X}
X
Xstatic int
Xm_xword(m, k, err)
X   register struct mbuf *m;
X   register int k, *err;
X{
X   register int len;
X   register u_char *cp, *np;
X   register struct mbuf *m0;
X
X   len = m->m_len;
X   while (k >= len) {
X      k -= len;
X      m = m->m_next;
X      if (m == 0)
X         goto bad;
X      len = m->m_len;
X   }
X   cp = mtod(m, u_char *) + k;
X   if (len - k >= 4) {
X      *err = 0;
X      return EXTRACT_LONG(cp);
X   }
X   m0 = m->m_next;
X   if (m0 == 0 || m0->m_len + len - k < 4)
X      goto bad;
X   *err = 0;
X   np = mtod(m0, u_char *);
X   switch (len - k) {
X
X   case 1:
X      return (cp[k] << 24) | (np[0] << 16) | (np[1] << 8) | np[2];
X
X   case 2:
X      return (cp[k] << 24) | (cp[k + 1] << 16) | (np[0] << 8) | 
X         np[1];
X
X   default:
X      return (cp[k] << 24) | (cp[k + 1] << 16) | (cp[k + 2] << 8) |
X         np[0];
X   }
X    bad:
X   *err = 1;
X   return 0;
X}
X
Xstatic int
Xm_xhalf(m, k, err)
X   register struct mbuf *m;
X   register int k, *err;
X{
X   register int len;
X   register u_char *cp;
X   register struct mbuf *m0;
X
X   len = m->m_len;
X   while (k >= len) {
X      k -= len;
X      m = m->m_next;
X      if (m == 0)
X         goto bad;
X      len = m->m_len;
X   }
X   cp = mtod(m, u_char *) + k;
X   if (len - k >= 2) {
X      *err = 0;
X      return EXTRACT_SHORT(cp);
X   }
X   m0 = m->m_next;
X   if (m0 == 0)
X      goto bad;
X   *err = 0;
X   return (cp[k] << 8) | mtod(m0, u_char *)[0];
X bad:
X   *err = 1;
X   return 0;
X}
X#endif
X
X/*
X * Execute the filter program starting at pc on the packet p
X * wirelen is the length of the original packet
X * buflen is the amount of data present
X */
X
Xu_int argus_filter_orig ();
X
Xu_int
Xargus_filter (pc, p)
Xstruct bpf_insn *pc;
Xu_char *p;
X{
X   return argus_filter_orig (pc, p, 60, 60);
X}
X
Xu_int
Xargus_filter_orig (pc, p, wirelen, buflen) 
Xstruct bpf_insn *pc;
Xu_char *p;
Xint wirelen, buflen;
X{
X   register u_int32 A, X;
X   register int k;
X   int32 mem [BPF_MEMWORDS];
X
X   if (pc == 0)
X      /*
X       * No filter means accept all.
X       */
X      return (u_int) -1;
X#ifdef lint
X   A = 0;
X   X = 0;
X#endif
X   --pc;
X   while (1) {
X      ++pc;
X      switch (pc->code) {
X
X      default:
X#ifdef KERNEL
X         return 0;
X#else
X         abort();
X#endif         
X      case BPF_RET|BPF_K:
X         return (u_int)pc->k;
X
X      case BPF_RET|BPF_A:
X         return (u_int)A;
X
X      case BPF_LD|BPF_W|BPF_ABS:
X         k = pc->k;
X         if (k + sizeof(int32) > buflen) {
X#ifdef KERNEL
X            int merr;
X
X            if (buflen != 0)
X               return 0;
X            A = m_xword((struct mbuf *)p, k, &merr);
X            if (merr != 0)
X               return 0;
X            continue;
X#else
X            return 0;
X#endif
X         }
X         A = EXTRACT_LONG(&p[k]);
X         continue;
X
X      case BPF_LD|BPF_H|BPF_ABS:
X         k = pc->k;
X         if (k + sizeof(short) > buflen) {
X#ifdef KERNEL
X            int merr;
X
X            if (buflen != 0)
X               return 0;
X            A = m_xhalf((struct mbuf *)p, k, &merr);
X            continue;
X#else
X            return 0;
X#endif
X         }
X         A = EXTRACT_SHORT(&p[k]);
X         continue;
X
X      case BPF_LD|BPF_B|BPF_ABS:
X         k = pc->k;
X         if (k >= buflen) {
X#ifdef KERNEL
X            register struct mbuf *m;
X
X            if (buflen != 0)
X               return 0;
X            m = (struct mbuf *)p;
X            MINDEX(m, k);
X            A = mtod(m, u_char *)[k];
X            continue;
X#else
X            return 0;
X#endif
X         }
X         A = p[k];
X         continue;
X
X      case BPF_LD|BPF_W|BPF_LEN:
X         A = wirelen;
X         continue;
X
X      case BPF_LDX|BPF_W|BPF_LEN:
X         X = wirelen;
X         continue;
X
X      case BPF_LD|BPF_W|BPF_IND:
X         k = X + pc->k;
X         if (k + sizeof(int32) > buflen) {
X#ifdef KERNEL
X            int merr;
X
X            if (buflen != 0)
X               return 0;
X            A = m_xword((struct mbuf *)p, k, &merr);
X            if (merr != 0)
X               return 0;
X            continue;
X#else
X            return 0;
X#endif
X         }
X         A = EXTRACT_LONG(&p[k]);
X         continue;
X
X      case BPF_LD|BPF_H|BPF_IND:
X         k = X + pc->k;
X         if (k + sizeof(short) > buflen) {
X#ifdef KERNEL
X            int merr;
X
X            if (buflen != 0)
X               return 0;
X            A = m_xhalf((struct mbuf *)p, k, &merr);
X            if (merr != 0)
X               return 0;
X            continue;
X#else
X            return 0;
X#endif
X         }
X         A = EXTRACT_SHORT(&p[k]);
X         continue;
X
X      case BPF_LD|BPF_B|BPF_IND:
X         k = X + pc->k;
X         if (k >= buflen) {
X#ifdef KERNEL
X            register struct mbuf *m;
X
X            if (buflen != 0)
X               return 0;
X            m = (struct mbuf *)p;
X            MINDEX(m, k);
X            A = mtod(m, char *)[k];
X            continue;
X#else
X            return 0;
X#endif
X         }
X         A = p[k];
X         continue;
X
X      case BPF_LDX|BPF_MSH|BPF_B:
X         k = pc->k;
X         if (k >= buflen) {
X#ifdef KERNEL
X            register struct mbuf *m;
X
X            if (buflen != 0)
X               return 0;
X            m = (struct mbuf *)p;
X            MINDEX(m, k);
X            X = (mtod(m, char *)[k] & 0xf) << 2;
X            continue;
X#else
X            return 0;
X#endif
X         }
X         X = (p[pc->k] & 0xf) << 2;
X         continue;
X
X      case BPF_LD|BPF_IMM:
X         A = pc->k;
X         continue;
X
X      case BPF_LDX|BPF_IMM:
X         X = pc->k;
X         continue;
X
X      case BPF_LD|BPF_MEM:
X         A = mem[pc->k];
X         continue;
X         
X      case BPF_LDX|BPF_MEM:
X         X = mem[pc->k];
X         continue;
X
X      case BPF_ST:
X         mem[pc->k] = A;
X         continue;
X
X      case BPF_STX:
X         mem[pc->k] = X;
X         continue;
X
X      case BPF_JMP|BPF_JA:
X         pc += pc->k;
X         continue;
X
X      case BPF_JMP|BPF_JGT|BPF_K:
X         pc += (A > pc->k) ? pc->jt : pc->jf;
X         continue;
X
X      case BPF_JMP|BPF_JGE|BPF_K:
X         pc += (A >= pc->k) ? pc->jt : pc->jf;
X         continue;
X
X      case BPF_JMP|BPF_JEQ|BPF_K:
X         pc += (A == pc->k) ? pc->jt : pc->jf;
X         continue;
X
X      case BPF_JMP|BPF_JSET|BPF_K:
X         pc += (A & pc->k) ? pc->jt : pc->jf;
X         continue;
X
X      case BPF_JMP|BPF_JGT|BPF_X:
X         pc += (A > X) ? pc->jt : pc->jf;
X         continue;
X
X      case BPF_JMP|BPF_JGE|BPF_X:
X         pc += (A >= X) ? pc->jt : pc->jf;
X         continue;
X
X      case BPF_JMP|BPF_JEQ|BPF_X:
X         pc += (A == X) ? pc->jt : pc->jf;
X         continue;
X
X      case BPF_JMP|BPF_JSET|BPF_X:
X         pc += (A & X) ? pc->jt : pc->jf;
X         continue;
X
X      case BPF_ALU|BPF_ADD|BPF_X:
X         A += X;
X         continue;
X         
X      case BPF_ALU|BPF_SUB|BPF_X:
X         A -= X;
X         continue;
X         
X      case BPF_ALU|BPF_MUL|BPF_X:
X         A *= X;
X         continue;
X         
X      case BPF_ALU|BPF_DIV|BPF_X:
X         if (X == 0)
X            return 0;
X         A /= X;
X         continue;
X         
X      case BPF_ALU|BPF_AND|BPF_X:
X         A &= X;
X         continue;
X         
X      case BPF_ALU|BPF_OR|BPF_X:
X         A |= X;
X         continue;
X
X      case BPF_ALU|BPF_LSH|BPF_X:
X         A <<= X;
X         continue;
X
X      case BPF_ALU|BPF_RSH|BPF_X:
X         A >>= X;
X         continue;
X
X      case BPF_ALU|BPF_ADD|BPF_K:
X         A += pc->k;
X         continue;
X         
X      case BPF_ALU|BPF_SUB|BPF_K:
X         A -= pc->k;
X         continue;
X         
X      case BPF_ALU|BPF_MUL|BPF_K:
X         A *= pc->k;
X         continue;
X         
X      case BPF_ALU|BPF_DIV|BPF_K:
X         A /= pc->k;
X         continue;
X         
X      case BPF_ALU|BPF_AND|BPF_K:
X         A &= pc->k;
X         continue;
X         
X      case BPF_ALU|BPF_OR|BPF_K:
X         A |= pc->k;
X         continue;
X
X      case BPF_ALU|BPF_LSH|BPF_K:
X         A <<= pc->k;
X         continue;
X
X      case BPF_ALU|BPF_RSH|BPF_K:
X         A >>= pc->k;
X         continue;
X
X      case BPF_ALU|BPF_NEG:
X         A = -A;
X         continue;
X
X      case BPF_MISC|BPF_TAX:
X         X = A;
X         continue;
X
X      case BPF_MISC|BPF_TXA:
X         A = X;
X         continue;
X      }
X   }
X}
X
X#ifdef KERNEL
X/*
X * Return true if the 'fcode' is a valid filter program.
X * The constraints are that each jump be forward and to a valid
X * code.  The code must terminate with either an accept or reject. 
X * 'valid' is an array for use by the routine (it must be at least
X * 'len' bytes long).  
X *
X * The kernel needs to be able to verify an application's filter code.
X * Otherwise, a bogus program could easily crash the system.
X */
Xint
Xbpf_validate(f, len)
X   struct bpf_insn *f;
X   int len;
X{
X   register int i;
X   register struct bpf_insn *p;
X
X   for (i = 0; i < len; ++i) {
X      /*
X       * Check that that jumps are forward, and within 
X       * the code block.
X       */
X      p = &f[i];
X      if (BPF_CLASS(p->code) == BPF_JMP) {
X         register int from = i + 1;
X
X         if (BPF_OP(p->code) == BPF_JA) {
X            if (from + p->k >= len)
X               return 0;
X         }
X         else if (from + p->jt >= len || from + p->jf >= len)
X            return 0;
X      }
X      /*
X       * Check that memory operations use valid addresses.
X       */
X      if ((BPF_CLASS(p->code) == BPF_ST ||
X           (BPF_CLASS(p->code) == BPF_LD && 
X            (p->code & 0xe0) == BPF_MEM)) &&
X          (p->k >= BPF_MEMWORDS || p->k < 0))
X         return 0;
X      /*
X       * Check for constant division by 0.
X       */
X      if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0)
X         return 0;
X   }
X   return BPF_CLASS(f[len - 1].code) == BPF_RET;
X}
X#endif
SHAR_EOF
  $shar_touch -am 0508141395 'argus-1.5/common/argus_filter.c' &&
  chmod 0444 'argus-1.5/common/argus_filter.c' ||
  echo 'restore of argus-1.5/common/argus_filter.c failed'
  shar_count="`wc -c < 'argus-1.5/common/argus_filter.c'`"
  test 13053 -eq "$shar_count" ||
    echo "argus-1.5/common/argus_filter.c: original size 13053, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= argus-1.5/common/bpf_dump.c ==============
if test -f 'argus-1.5/common/bpf_dump.c' && test X"$1" != X"-c"; then
  echo 'x - skipping argus-1.5/common/bpf_dump.c (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting argus-1.5/common/bpf_dump.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'argus-1.5/common/bpf_dump.c' &&
X/*
X * Copyright (c) 1992, 1993, 1994
X *	The Regents of the University of California.  All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that: (1) source code distributions
X * retain the above copyright notice and this paragraph in its entirety, (2)
X * distributions including binary code include the above copyright notice and
X * this paragraph in its entirety in the documentation or other materials
X * provided with the distribution, and (3) all advertising materials mentioning
X * features or use of this software display the following acknowledgement:
X * ``This product includes software developed by the University of California,
X * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
X * the University nor the names of its contributors may be used to endorse
X * or promote products derived from this software without specific prior
X * written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
X * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X#ifndef lint
Xstatic char rcsid[] =
X    "@(#) $Header: /usr/users/poepping/src/argus/argus-1.5/common/RCS/bpf_dump.c,v 1.1 1995/02/08 21:03:27 poepping Exp $ (LBL)";
X#endif
X
X#include <sys/types.h>
X#include <sys/time.h>
X
X#include <pcap.h>
X#include <stdio.h>
X
X#include <interface.h>
X
Xextern void bpf_dump(struct bpf_program *, int);
X
Xvoid
Xbpf_dump(struct bpf_program *p, int option)
X{
X	struct bpf_insn *insn;
X	int i;
X	int n = p->bf_len;
X
X	insn = p->bf_insns;
X	if (option > 2) {
X		printf("%d\n", n);
X		for (i = 0; i < n; ++insn, ++i) {
X			printf("%lu %lu %lu %lu\n", insn->code,
X			       insn->jt, insn->jf, insn->k);
X		}
X		return ;
X	}
X	if (option > 1) {
X		for (i = 0; i < n; ++insn, ++i)
X			printf("{ 0x%x, %d, %d, 0x%08x },\n",
X			       insn->code, insn->jt, insn->jf, insn->k);
X		return;
X	}
X	for (i = 0; i < n; ++insn, ++i) {
X#ifdef BDEBUG
X		extern int bids[];
X		printf(bids[i] > 0 ? "[%02d]" : " -- ", bids[i] - 1);
X#endif
X		puts(bpf_image(insn, i));
X	}
X}
SHAR_EOF
  $shar_touch -am 0508141395 'argus-1.5/common/bpf_dump.c' &&
  chmod 0444 'argus-1.5/common/bpf_dump.c' ||
  echo 'restore of argus-1.5/common/bpf_dump.c failed'
  shar_count="`wc -c < 'argus-1.5/common/bpf_dump.c'`"
  test 2131 -eq "$shar_count" ||
    echo "argus-1.5/common/bpf_dump.c: original size 2131, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= argus-1.5/common/gencode.c ==============
if test -f 'argus-1.5/common/gencode.c' && test X"$1" != X"-c"; then
  echo 'x - skipping argus-1.5/common/gencode.c (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting argus-1.5/common/gencode.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'argus-1.5/common/gencode.c' &&
X/*
X * Copyright (c) 1990, 1991, 1992, 1993, 1994
X *   The Regents of the University of California.  All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that: (1) source code distributions
X * retain the above copyright notice and this paragraph in its entirety, (2)
X * distributions including binary code include the above copyright notice and
X * this paragraph in its entirety in the documentation or other materials
X * provided with the distribution, and (3) all advertising materials mentioning
X * features or use of this software display the following acknowledgement:
X * ``This product includes software developed by the University of California,
X * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
X * the University nor the names of its contributors may be used to endorse
X * or promote products derived from this software without specific prior
X * written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
X * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X#ifndef lint
Xstatic char rcsid[] =
X    "@(#) $Header: /usr/users/poepping/src/argus/argus-1.5/common/RCS/gencode.c,v 1.1 1995/02/08 21:03:27 poepping Exp $ (LBL)";
X#endif
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <sys/time.h>
X
X#include <net/if.h>
X#include <net/bpf.h>
X
X#include <netinet/in.h>
X#include <netinet/if_ether.h>
X
X#include <memory.h>
X#include <pcap.h>
X#include <pcap-int.h>
X#include <pcap-namedb.h>
X#include <setjmp.h>
X#if __STDC__
X#include <stdarg.h>
X#include <stdlib.h>
X#else
X#include <varargs.h>
X#endif
X
X#include <cons_def.h>
X#include "gencode.h"
X
X#ifndef __GNUC__
X#define inline
X#endif
X
X
X#define JMP(c) ((c)|BPF_JMP|BPF_K)
X
Xstatic jmp_buf top_ctx;
Xstatic pcap_t *bpf_pcap;
X
Xstatic u_int off_linktype = 0;
Xstatic u_int off_nl = 0;
X
X
X/* VARARGS */
Xvolatile void
X#if __STDC__ || defined(SOLARIS)
Xbpf_error(char *fmt, ...)
X#else
Xbpf_error(fmt, va_alist)
X   char *fmt;
X   va_dcl
X#endif
X{
X   va_list ap;
X
X#if __STDC__
X   va_start(ap, fmt);
X#else
X   va_start(ap);
X#endif
X   if (bpf_pcap != NULL)
X      (void)vsprintf(bpf_pcap->errbuf, fmt, ap);
X   va_end(ap);
X   longjmp(top_ctx, 1);
X   /* NOTREACHED */
X}
X
X
Xstatic int alloc_reg(void);
Xstatic void free_reg(int);
X
Xstatic struct block *root;
X
X/*
X * We divy out chunks of memory rather than call malloc each time so
X * we don't have to worry about leaking memory.  It's probably
X * not a big deal if all this memory was wasted but it this ever
X * goes into a library that would probably not be a good idea.
X */
X#define NCHUNKS 16
X#define CHUNK0SIZE 1024
Xstruct chunk {
X   u_int n_left;
X   void *m;
X};
X
Xstatic struct chunk chunks[NCHUNKS];
Xstatic int cur_chunk;
X
Xstatic void *newchunk(u_int);
Xstatic void freechunks(void);
Xstatic inline struct block *new_block(int);
Xstatic inline struct slist *new_stmt(int);
Xstatic struct block *gen_retblk(int);
Xstatic inline void syntax(void);
X
Xstatic void backpatch(struct block *, struct block *);
Xstatic void merge(struct block *, struct block *);
Xstatic struct block *gen_cmp(u_int, u_int, u_long);
Xstatic struct block *gen_mcmp(u_int, u_int, u_long, u_long);
Xstatic struct block *gen_bcmp(u_int, u_int, u_char *);
Xstatic struct block *gen_uncond(int);
Xstatic inline struct block *gen_true(void);
Xstatic inline struct block *gen_false(void);
Xstatic struct block *gen_prototype(u_int);
Xstatic struct block *gen_hostop(u_long, u_long, int, u_int, u_int, u_int);
Xstatic struct block *gen_ehostop(u_char *, int);
Xstatic struct block *gen_dnhostop(u_long, int, u_int);
Xstatic struct block *gen_host(u_long, u_long, int, int);
Xstatic struct block *gen_gateway(u_char *, u_long **, int, int);
Xstatic struct block *gen_portatom(int, long);
Xstruct block *gen_portop(int, int, int);
Xstatic struct block *gen_port(int, u_int, int);
Xstatic int lookup_proto(char *, int);
Xstatic struct block *gen_proto(int, int, int);
Xstatic u_long net_mask(u_long *);
Xstatic u_long net_mask(u_long *);
Xstatic struct slist *xfer_to_x(struct arth *);
Xstatic struct slist *xfer_to_a(struct arth *);
Xstatic struct block *gen_len(int, int);
X
Xstatic void *
Xnewchunk(n)
Xu_int n;
X{
X   struct chunk *cp;
X   int k, size;
X
X   /* XXX Round up to nearest long. */
X   n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
X
X   cp = &chunks[cur_chunk];
X   if (n > cp->n_left) {
X      ++cp, k = ++cur_chunk;
X      if (k >= NCHUNKS)
X         bpf_error("out of memory");
X      size = CHUNK0SIZE << k;
X      cp->m = (void *)malloc(size);
X      memset((char *)cp->m, 0, size);
X      cp->n_left = size;
X      if (n > size)
X         bpf_error("out of memory");
X   }
X   cp->n_left -= n;
X   return (void *)((char *)cp->m + cp->n_left);
X}
X
Xstatic void
Xfreechunks()
X{
X   int i;
X
X   for (i = 0; i < NCHUNKS; ++i)
X      if (chunks[i].m)
X         free(chunks[i].m);
X}
X
X/*
X * A strdup whose allocations are freed after code generation is over.
X */
Xchar *
Xsdup(s)
Xchar *s;
X{
X   int n = strlen(s) + 1;
X   char *cp = newchunk(n);
X   strcpy(cp, s);
X   return (cp);
X}
X
Xstatic inline struct block *
Xnew_block(code)
Xint code;
X{
X   struct block *p;
X
X   p = (struct block *)newchunk(sizeof(*p));
X   p->s.code = code;
X   p->head = p;
X
X   return p;
X}
X
Xstatic inline struct slist *
Xnew_stmt(code)
Xint code;
X{
X   struct slist *p;
X
X   p = (struct slist *)newchunk(sizeof(*p));
X   p->s.code = code;
X
X   return p;
X}
X
Xstatic struct block *
Xgen_retblk(v)
Xint v;
X{
X   struct block *b = new_block(BPF_RET|BPF_K);
X
X   b->s.k = v;
X   return b;
X}
X
Xstatic inline void
Xsyntax()
X{
X   bpf_error("syntax error in filter expression");
X}
X
Xstatic u_long netmask;
Xstatic int snaplen;
X
X
Xint
Xpolicy_compile(p, program, buf, optimize, mask)
Xpcap_t *p;
Xstruct bpf_program *program;
Xchar *buf;
Xint optimize;
Xu_long mask;
X{
X   extern int n_errors;
X   int len;
X
X   bpf_pcap = p;
X   if (setjmp(top_ctx))
X      return (-1);
X
X   netmask = mask;
X   snaplen = 96;
X
X   lex_init(buf ? buf : "");
X   pcap_parse();
X
X   if (n_errors)
X      syntax();
X
X   if (root == NULL)
X      root = gen_retblk(snaplen);
X
X/*
X   if (optimize) {
X      bpf_optimize(&root);
X      if (root == NULL ||
X          (root->s.code == (BPF_RET|BPF_K) && root->s.k == 0))
X         bpf_error("expression rejects all packets");
X   }
X*/
X
X   program->bf_insns = icode_to_fcode(root, &len);
X   program->bf_len = len;
X
X   freechunks();
X   return (0);
X}
X
X/*
X * Backpatch the blocks in 'list' to 'target'.  The 'sense' field indicates
X * which of the jt and jf fields has been resolved and which is a pointer
X * back to another unresolved block (or nil).  At least one of the fields
X * in each block is already resolved.
X */
Xstatic void
Xbackpatch(list, target)
Xstruct block *list, *target;
X{
X   struct block *next;
X
X   while (list) {
X      if (!list->sense) {
X         next = JT(list);
X         JT(list) = target;
X      } else {
X         next = JF(list);
X         JF(list) = target;
X      }
X      list = next;
X   }
X}
X
X/*
X * Merge the lists in b0 and b1, using the 'sense' field to indicate
X * which of jt and jf is the link.
X */
Xstatic void
Xmerge(b0, b1)
Xstruct block *b0, *b1;
X{
X   register struct block **p = &b0;
X
X   /* Find end of list. */
X   while (*p)
X      p = !((*p)->sense) ? &JT(*p) : &JF(*p);
X
X   /* Concatenate the lists. */
X   *p = b1;
X}
X
Xvoid
Xfinish_parse(p)
Xstruct block *p;
X{
X   backpatch(p, gen_retblk(snaplen));
X   p->sense = !p->sense;
X   backpatch(p, gen_retblk(0));
X   root = p->head;
X}
X
Xvoid
Xgen_and(b0, b1)
Xstruct block *b0, *b1;
X{
X   if (b0 != b1) {
X      backpatch(b0, b1->head);
X      b0->sense = !b0->sense;
X      b1->sense = !b1->sense;
X      merge(b1, b0);
X      b1->sense = !b1->sense;
X      b1->head = b0->head;
X   }
X}
X
Xvoid
Xgen_or(b0, b1)
Xstruct block *b0, *b1;
X{
X   if (b0 != b1) {
X      b0->sense = !b0->sense;
X      backpatch(b0, b1->head);
X      b0->sense = !b0->sense;
X      merge(b1, b0);
X      b1->head = b0->head;
X   }
X}
X
Xvoid
Xgen_not(b)
Xstruct block *b;
X{
X   b->sense = !b->sense;
X}
X
Xstatic struct block *
Xgen_cmp(offset, size, v)
Xu_int offset, size;
Xu_long v;
X{
X   struct slist *s;
X   struct block *b;
X
X   s = new_stmt(BPF_LD|BPF_ABS|size);
X   s->s.k = offset;
X
X   b = new_block(JMP(BPF_JEQ));
X   b->stmts = s;
X   b->s.k = v;
X
X   return b;
X}
X
Xstatic struct block *
Xgen_mcmp(offset, size, v, mask)
Xu_int offset, size;
Xu_long v;
Xu_long mask;
X{
X   struct block *b = gen_cmp(offset, size, v);
X   struct slist *s;
X
X   if (mask != 0xffffffff) {
X      s = new_stmt(BPF_ALU|BPF_AND|BPF_K);
X      s->s.k = mask;
X      b->stmts->next = s;
X   }
X   return b;
X}
X
Xstatic struct block *
Xgen_bcmp(offset, size, v)
Xu_int offset, size;
Xu_char *v;
X{
X   struct block *b, *tmp;
X
X   b = NULL;
X   while (size >= 4) {
X      u_char *p = &v[size - 4];
X      u_long w = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
X      tmp = gen_cmp(offset + size - 4, BPF_W, w);
X      if (b != NULL)
X         gen_and(b, tmp);
X      b = tmp;
X      size -= 4;
X   }
X   while (size >= 2) {
X      u_char *p = &v[size - 2];
X      u_long w = (p[0] << 8) | p[1];
X      tmp = gen_cmp(offset + size - 2, BPF_H, w);
X      if (b != NULL)
X         gen_and(b, tmp);
X      b = tmp;
X      size -= 2;
X   }
X   if (size > 0) {
X      tmp = gen_cmp(offset, BPF_B, (u_long)v[0]);
X      if (b != NULL)
X         gen_and(b, tmp);
X      b = tmp;
X   }
X   return b;
X}
X
X
X
Xstatic struct block *
Xgen_uncond(rsense)
Xint rsense;
X{
X   struct block *b;
X   struct slist *s;
X
X   s = new_stmt(BPF_LD|BPF_IMM);
X   s->s.k = !rsense;
X   b = new_block(JMP(BPF_JEQ));
X   b->stmts = s;
X
X   return b;
X}
X
Xstatic inline struct block *
Xgen_true()
X{
X   return gen_uncond(1);
X}
X
Xstatic inline struct block *
Xgen_false()
X{
X   return gen_uncond(0);
X}
X
Xstatic struct block *
Xgen_prototype(proto)
Xunsigned int proto;
X{
X   struct block *b0, *b1;
X
X   switch (proto) {
X      case IPPROTO:
X      case UDPPROTO:
X      case TCPPROTO:
X      case ICMPPROTO:
X      case ARPPROTO:
X         b0 = gen_mcmp(0, BPF_W, (u_long) proto, proto);
X         break;
X
X      default:
X         b0 = gen_cmp(40, BPF_W, (u_long) proto);
X         break;
X   }
X
X   return (b0);
X}
X
X
Xstatic struct block *
Xgen_hostop(addr, mask, dir, proto, src_off, dst_off)
Xu_long addr;
Xu_long mask;
Xint dir;
Xu_int proto, src_off, dst_off;
X{
X   struct block *b0, *b1;
X   u_int offset;
X
X   switch (dir) {
X
X   case Q_SRC:
X      offset = src_off;
X      break;
X
X   case Q_DST:
X      offset = dst_off;
X      break;
X
X   case Q_AND:
X      b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off);
X      b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off);
X      gen_and(b0, b1);
X      return b1;
X
X   case Q_OR:
X   case Q_DEFAULT:
X      b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off);
X      b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off);
X      gen_or(b0, b1);
X      return b1;
X
X   default:
X      abort();
X   }
X   b0 = gen_prototype(proto);
X   b1 = gen_mcmp(offset, BPF_W, (u_long)addr, mask);
X   gen_and(b0, b1);
X   return b1;
X}
X
X
Xstatic struct block *
Xgen_ehostop(eaddr, dir)
Xu_char *eaddr;
Xint dir;
X{
X   struct block *b0, *b1;
X
X   switch (dir) {
X   case Q_SRC:
X      return gen_bcmp (20, 6, eaddr);
X
X   case Q_DST:
X      return gen_bcmp (26, 6, eaddr);
X
X   case Q_AND:
X      b0 = gen_ehostop(eaddr, Q_SRC);
X      b1 = gen_ehostop(eaddr, Q_DST);
X      gen_and(b0, b1);
X      return b1;
X
X   case Q_DEFAULT:
X   case Q_OR:
X      b0 = gen_ehostop(eaddr, Q_SRC);
X      b1 = gen_ehostop(eaddr, Q_DST);
X      gen_or(b0, b1);
X      return b1;
X   }
X   abort();
X   /* NOTREACHED */
X}
X
X
Xstatic struct block *
Xgen_host(addr, mask, proto, dir)
Xu_long addr;
Xu_long mask;
Xint proto;
Xint dir;
X{
X   struct block *b0, *b1;
X
X   switch (proto) {
X
X   case Q_DEFAULT:
X      b0 = gen_host(addr, mask, Q_IP, dir);
X      b1 = gen_host(addr, mask, Q_ARP, dir);
X      gen_or(b1, b0);
X      return b0;
X
X   case Q_IP:
X      return gen_hostop(addr, mask, dir, IPPROTO, 32, 36);
X
X   case Q_ARP:
X      return gen_hostop(addr, mask, dir, ARPPROTO, 38, 48);
X
X   case Q_TCP:
X      bpf_error("'tcp' modifier applied to host");
X
X   case Q_UDP:
X      bpf_error("'udp' modifier applied to host");
X
X   case Q_ICMP:
X      bpf_error("'icmp' modifier applied to host");
X
X   default:
X      abort();
X   }
X   /* NOTREACHED */
X}
X
Xstatic struct block *
Xgen_gateway(eaddr, alist, proto, dir)
Xu_char *eaddr;
Xu_long **alist;
Xint proto;
Xint dir;
X{
X   struct block *b0, *b1, *tmp;
X
X   if (dir != 0)
X      bpf_error("direction applied to 'gateway'");
X
X   switch (proto) {
X   case Q_DEFAULT:
X   case Q_IP:
X   case Q_ARP:
X   case Q_RARP:
X      b0 = gen_ehostop(eaddr, Q_OR);
X      b1 = gen_host(**alist++, 0xffffffffL, proto, Q_OR);
X      while (*alist) {
X         tmp = gen_host(**alist++, 0xffffffffL, proto, Q_OR);
X         gen_or(b1, tmp);
X         b1 = tmp;
X      }
X      gen_not(b1);
X      gen_and(b0, b1);
X      return b1;
X   }
X   bpf_error("illegal modifier of 'gateway'");
X   /* NOTREACHED */
X}
X
Xstruct block *
Xgen_proto_abbrev(proto)
Xint proto;
X{
X   struct block *b0, *b1;
X
X   switch (proto) {
X
X   case Q_TCP:
X      b0 = gen_prototype(IPPROTO);
X      b1 = gen_prototype(TCPPROTO);
X      gen_and(b0, b1);
X      break;
X
X   case Q_UDP:
X      b0 = gen_prototype(IPPROTO);
X      b1 = gen_prototype(UDPPROTO);
X      gen_and(b0, b1);
X      break;
X
X   case Q_ICMP:
X      b0 = gen_prototype(IPPROTO);
X      b1 = gen_prototype(ICMPPROTO);
X      gen_and(b0, b1);
X      break;
X
X   case Q_IP:
X      b1 =  gen_prototype(IPPROTO);
X      break;
X
X   case Q_ARP:
X      b1 =  gen_prototype(ARPPROTO);
X      break;
X
X   case Q_LINK:
X      bpf_error("link layer applied in wrong context");
X
X   default:
X      abort();
X   }
X   return b1;
X}
X
Xstatic struct block *
Xgen_portatom(off, v)
Xint off;
Xlong v;
X{
X   return gen_cmp(40 + off, BPF_H, (u_long)v);
X}
X
Xstruct block *
Xgen_portop(port, proto, dir)
Xint port, proto, dir;
X{
X   struct block *b0, *b1, *tmp;
X
X   /* ip proto 'proto' */
X   b0 = gen_prototype(proto);
X
X   switch (dir) {
X   case Q_SRC:
X      b1 = gen_portatom(0, (long)port);
X      break;
X
X   case Q_DST:
X      b1 = gen_portatom(2, (long)port);
X      break;
X
X   case Q_OR:
X   case Q_DEFAULT:
X      tmp = gen_portatom(0, (long)port);
X      b1 = gen_portatom(2, (long)port);
X      gen_or(tmp, b1);
X      break;
X
X   case Q_AND:
X      tmp = gen_portatom(0, (long)port);
X      b1 = gen_portatom(2, (long)port);
X      gen_and(tmp, b1);
X      break;
X
X   default:
X      abort();
X   }
X   gen_and(b0, b1);
X
X   return b1;
X}
X
Xstatic struct block *
Xgen_port(port, ip_proto, dir)
Xint port;
Xu_int ip_proto;
Xint dir;
X{
X   struct block *b0, *b1, *tmp;
X
X   /* ether proto ip */
X   b0 =  gen_prototype(IPPROTO);
X
X   switch (ip_proto) {
X   case IPPROTO_TCP:
X      b1 = gen_portop(port, TCPPROTO, dir);
X      break;
X
X   case IPPROTO_UDP:
X      b1 = gen_portop(port, UDPPROTO, dir);
X      break;
X
X   case UDPPROTO:
X   case TCPPROTO:
X      b1 = gen_portop(port, ip_proto, dir);
X      break;
X
X   case PROTO_UNDEF:
X      tmp = gen_portop(port, TCPPROTO, dir);
X      b1 = gen_portop(port, UDPPROTO, dir);
X      gen_or(tmp, b1);
X      break;
X
X   default:
X      abort();
X   }
X   gen_and(b0, b1);
X   return b1;
X}
X
Xstatic int
Xlookup_proto(name, proto)
Xchar *name;
Xint proto;
X{
X   int v = 0;
X
X   switch (proto) {
X   case Q_DEFAULT:
X   case Q_IP:
X      v = pcap_nametoproto(name);
X      if (v == PROTO_UNDEF)
X         bpf_error("unknown ip proto '%s'", name);
X      break;
X
X   case Q_LINK:
X      /* XXX should look up h/w protocol type based on linktype */
X      v = pcap_nametoeproto(name);
X      if (v == PROTO_UNDEF)
X         bpf_error("unknown ether proto '%s'", name);
X      break;
X
X   default:
X      v = PROTO_UNDEF;
X      break;
X   }
X
X   return v;
X}
X
Xstatic struct block *
Xgen_proto(v, proto, dir)
Xint v;
Xint proto;
Xint dir;
X{
X   struct block *b0, *b1;
X
X   if (dir != Q_DEFAULT)
X      bpf_error("direction applied to 'proto'");
X
X   switch (proto) {
X   case Q_DEFAULT:
X   case Q_IP:
X      b0 = gen_prototype(IPPROTO);
X      b1 = gen_prototype(v);
X      gen_and(b0, b1);
X      b0 = gen_prototype(TCPPROTO);
X      gen_not(b0);
X      gen_and(b0, b1);
X      b0 = gen_prototype(UDPPROTO);
X      gen_not(b0);
X      gen_and(b0, b1);
X      b0 = gen_prototype(ICMPPROTO);
X      gen_not(b0);
X      gen_and(b0, b1);
X      return b1;
X
X   case Q_ARP:
X      bpf_error("arp does not encapsulate another protocol");
X      /* NOTREACHED */
X
X   case Q_RARP:
X      bpf_error("rarp does not encapsulate another protocol");
X      /* NOTREACHED */
X
X   case Q_LINK:
X      return gen_prototype(v);
X
X   case Q_UDP:
X      bpf_error("'udp proto' is bogus");
X      /* NOTREACHED */
X
X   case Q_TCP:
X      bpf_error("'tcp proto' is bogus");
X      /* NOTREACHED */
X
X   case Q_ICMP:
X      bpf_error("'icmp proto' is bogus");
X      /* NOTREACHED */
X
X   default:
X      abort();
X      /* NOTREACHED */
X   }
X   /* NOTREACHED */
X}
X
X/*
X * Left justify 'addr' and return its resulting network mask.
X */
Xstatic u_long
Xnet_mask(addr)
Xu_long *addr;
X{
X   register u_long m = 0xffffffff;
X
X   if (*addr)
X      while ((*addr & 0xff000000) == 0)
X         *addr <<= 8, m <<= 8;
X
X   return m;
X}
X
Xstruct block *
Xgen_scode(name, q)
Xchar *name;
Xstruct qual q;
X{
X   int proto = q.proto;
X   int dir = q.dir;
X   u_char *eaddr;
X   u_long mask, addr, **alist;
X   struct block *b, *tmp;
X   int port, real_proto;
X
X   switch (q.addr) {
X
X   case Q_NET:
X      addr = pcap_nametonetaddr(name);
X      if (addr == 0)
X         bpf_error("unknown network '%s'", name);
X      mask = net_mask(&addr);
X      return gen_host(addr, mask, proto, dir);
X
X   case Q_DEFAULT:
X   case Q_HOST:
X      if (proto == Q_LINK) {
X         eaddr = pcap_ether_hostton(name);
X         if (eaddr == NULL)
X            bpf_error("unknown ether host '%s'", name);
X         return gen_ehostop(eaddr, dir);
X
X      } else if (proto == Q_DECNET) {
X         unsigned short dn_addr = __pcap_nametodnaddr(name);
X         /*
X          * I don't think DECNET hosts can be multihomed, so
X          * there is no need to build up a list of addresses
X          */
X         return (gen_host(dn_addr, 0, proto, dir));
X      } else {
X         alist = pcap_nametoaddr(name);
X         if (alist == NULL || *alist == NULL)
X            bpf_error("unknown host '%s'", name);
X         b = gen_host(**alist++, 0xffffffffL, proto, dir);
X         while (*alist) {
X            tmp = gen_host(**alist++, 0xffffffffL,
X                      proto, dir);
X            gen_or(b, tmp);
X            b = tmp;
X         }
X         return b;
X      }
X
X   case Q_PORT:
X      if (proto != Q_DEFAULT && proto != Q_UDP && proto != Q_TCP)
X         bpf_error("illegal qualifier of 'port'");
X      if (pcap_nametoport(name, &port, &real_proto) == 0)
X         bpf_error("unknown port '%s'", name);
X      if (proto == Q_UDP) {
X         if (real_proto == TCPPROTO)
X            bpf_error("port '%s' is tcp", name);
X         else
X            /* override PROTO_UNDEF */
X            real_proto = UDPPROTO;
X      }
X      if (proto == Q_TCP) {
X         if (real_proto == UDPPROTO)
X            bpf_error("port '%s' is udp", name);
X         else
X            /* override PROTO_UNDEF */
X            real_proto = TCPPROTO;
X      }
X      return gen_port(port, real_proto, dir);
X
X   case Q_GATEWAY:
X      eaddr = pcap_ether_hostton(name);
X      if (eaddr == NULL)
X         bpf_error("unknown ether host: %s", name);
X
X      alist = pcap_nametoaddr(name);
X      if (alist == NULL || *alist == NULL)
X         bpf_error("unknown host '%s'", name);
X      return gen_gateway(eaddr, alist, proto, dir);
X
X   case Q_PROTO:
X      real_proto = lookup_proto(name, proto);
X      if (real_proto >= 0)
X         return gen_proto(real_proto, proto, dir);
X      else
X         bpf_error("unknown protocol: %s", name);
X
X   case Q_UNDEF:
X      syntax();
X      /* NOTREACHED */
X   }
X   abort();
X   /* NOTREACHED */
X}
X
Xstruct block *
Xgen_ncode(v, q)
Xu_long v;
Xstruct qual q;
X{
X   u_long mask;
X   int proto = q.proto;
X   int dir = q.dir;
X
X   switch (q.addr) {
X
X   case Q_DEFAULT:
X   case Q_HOST:
X   case Q_NET:
X      if (proto == Q_LINK) {
X         bpf_error("illegal link layer address");
X      } else {
X         mask = net_mask(&v);
X         return gen_host(v, mask, proto, dir);
X      }
X
X   case Q_PORT:
X      if (proto == Q_UDP)
X         proto = UDPPROTO;
X      else if (proto == Q_TCP)
X         proto = TCPPROTO;
X      else if (proto == Q_DEFAULT)
X         proto = PROTO_UNDEF;
X      else
X         bpf_error("illegal qualifier of 'port'");
X
X      return gen_port((int)v, proto, dir);
X
X   case Q_GATEWAY:
X      bpf_error("'gateway' requires a name");
X      /* NOTREACHED */
X
X   case Q_PROTO:
X      return gen_proto((int)v, proto, dir);
X
X   case Q_UNDEF:
X      syntax();
X      /* NOTREACHED */
X
X   default:
X      abort();
X      /* NOTREACHED */
X   }
X   /* NOTREACHED */
X}
X
Xstruct block *
Xgen_ecode(eaddr, q)
Xu_char *eaddr;
Xstruct qual q;
X{
X   if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK)
X      return gen_ehostop(eaddr, (int)q.dir);
X
X   bpf_error("ethernet address used in non-ether expression");
X   /* NOTREACHED */
X}
X
Xvoid
Xsappend(s0, s1)
Xstruct slist *s0, *s1;
X{
X   /*
X    * This is definitely not the best way to do this, but the
X    * lists will rarely get long.
X    */
X   while (s0->next)
X      s0 = s0->next;
X   s0->next = s1;
X}
X
Xstatic struct slist *
Xxfer_to_x(a)
Xstruct arth *a;
X{
X   struct slist *s;
X
X   s = new_stmt(BPF_LDX|BPF_MEM);
X   s->s.k = a->regno;
X   return s;
X}
X
Xstatic struct slist *
Xxfer_to_a(a)
Xstruct arth *a;
X{
X   struct slist *s;
X
X   s = new_stmt(BPF_LD|BPF_MEM);
X   s->s.k = a->regno;
X   return s;
X}
X
Xstruct arth *
Xgen_load(proto, index, size)
Xint proto;
Xstruct arth *index;
Xint size;
X{
X   struct slist *s, *tmp;
X   struct block *b;
X   int regno = alloc_reg();
X
X   free_reg(index->regno);
X   switch (size) {
X
X   default:
X      bpf_error("data size must be 1, 2, or 4");
X
X   case 1:
X      size = BPF_B;
X      break;
X
X   case 2:
X      size = BPF_H;
X      break;
X
X   case 4:
X      size = BPF_W;
X      break;
X   }
X   switch (proto) {
X   default:
X      bpf_error("unsupported index operation");
X
X   case Q_LINK:
X      s = xfer_to_x(index);
X      tmp = new_stmt(BPF_LD|BPF_IND|size);
X      sappend(s, tmp);
X      sappend(index->s, s);
X      break;
X
X   case Q_IP:
X   case Q_ARP:
X   case Q_RARP:
X      s = xfer_to_x(index);
X      tmp = new_stmt(BPF_LD|BPF_IND|size);
X      tmp->s.k = off_nl;
X      sappend(s, tmp);
X      sappend(index->s, s);
X
X      b = gen_proto_abbrev(proto);
X      if (index->b)
X         gen_and(index->b, b);
X      index->b = b;
X      break;
X
X   case Q_TCP:
X   case Q_UDP:
X   case Q_ICMP:
X      s = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
X      s->s.k = off_nl;
X      sappend(s, xfer_to_a(index));
X      sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X));
X      sappend(s, new_stmt(BPF_MISC|BPF_TAX));
X      sappend(s, tmp = new_stmt(BPF_LD|BPF_IND|size));
X      tmp->s.k = off_nl;
X      sappend(index->s, s);
X
X      b = gen_proto_abbrev(proto);
X      if (index->b)
X         gen_and(index->b, b);
X      index->b = b;
X      break;
X   }
X   index->regno = regno;
X   s = new_stmt(BPF_ST);
X   s->s.k = regno;
X   sappend(index->s, s);
X
X   return index;
X}
X
Xstruct block *
Xgen_relation(code, a0, a1, reversed)
Xint code;
Xstruct arth *a0, *a1;
Xint reversed;
X{
X   struct slist *s0, *s1, *s2;
X   struct block *b, *tmp;
X
X   s0 = xfer_to_x(a1);
X   s1 = xfer_to_a(a0);
X   s2 = new_stmt(BPF_ALU|BPF_SUB|BPF_X);
X   b = new_block(JMP(code));
X   if (reversed)
X      gen_not(b);
X
X   sappend(s1, s2);
X   sappend(s0, s1);
X   sappend(a1->s, s0);
X   sappend(a0->s, a1->s);
X
X   b->stmts = a0->s;
X
X   free_reg(a0->regno);
X   free_reg(a1->regno);
X
X   /* 'and' together protocol checks */
X   if (a0->b) {
X      if (a1->b) {
X         gen_and(a0->b, tmp = a1->b);
X      }
X      else
X         tmp = a0->b;
X   } else
X      tmp = a1->b;
X
X   if (tmp)
X      gen_and(tmp, b);
X
X   return b;
X}
X
Xstruct arth *
Xgen_loadlen()
X{
X   int regno = alloc_reg();
X   struct arth *a = (struct arth *)newchunk(sizeof(*a));
X   struct slist *s;
X
X   s = new_stmt(BPF_LD|BPF_LEN);
X   s->next = new_stmt(BPF_ST);
X   s->next->s.k = regno;
X   a->s = s;
X   a->regno = regno;
X
X   return a;
X}
X
Xstruct arth *
Xgen_loadi(val)
Xint val;
X{
X   struct arth *a;
X   struct slist *s;
X   int reg;
X
X   a = (struct arth *)newchunk(sizeof(*a));
X
X   reg = alloc_reg();
X
X   s = new_stmt(BPF_LD|BPF_IMM);
X   s->s.k = val;
X   s->next = new_stmt(BPF_ST);
X   s->next->s.k = reg;
X   a->s = s;
X   a->regno = reg;
X
X   return a;
X}
X
Xstruct arth *
Xgen_neg(a)
Xstruct arth *a;
X{
X   struct slist *s;
X
X   s = xfer_to_a(a);
X   sappend(a->s, s);
X   s = new_stmt(BPF_ALU|BPF_NEG);
X   s->s.k = 0;
X   sappend(a->s, s);
X   s = new_stmt(BPF_ST);
X   s->s.k = a->regno;
X   sappend(a->s, s);
X
X   return a;
X}
X
Xstruct arth *
Xgen_arth(code, a0, a1)
Xint code;
Xstruct arth *a0, *a1;
X{
X   struct slist *s0, *s1, *s2;
X
X   s0 = xfer_to_x(a1);
X   s1 = xfer_to_a(a0);
X   s2 = new_stmt(BPF_ALU|BPF_X|code);
X
X   sappend(s1, s2);
X   sappend(s0, s1);
X   sappend(a1->s, s0);
X   sappend(a0->s, a1->s);
X
X   free_reg(a1->regno);
X
X   s0 = new_stmt(BPF_ST);
X   a0->regno = s0->s.k = alloc_reg();
X   sappend(a0->s, s0);
X
X   return a0;
X}
X
X/*
X * Here we handle simple allocation of the scratch registers.
X * If too many registers are alloc'd, the allocator punts.
X */
Xstatic int regused[BPF_MEMWORDS];
Xstatic int curreg;
X
X/*
X * Return the next free register.
X */
Xstatic int
Xalloc_reg()
X{
X   int n = BPF_MEMWORDS;
X
X   while (--n >= 0) {
X      if (regused[curreg])
X         curreg = (curreg + 1) % BPF_MEMWORDS;
X      else {
X         regused[curreg] = 1;
X         return curreg;
X      }
X   }
X   bpf_error("too many registers needed to evaluate expression");
X   /* NOTREACHED */
X}
X
X/*
X * Return a register to the table so it can
X * be used later.
X */
Xstatic void
Xfree_reg(n)
X   int n;
X{
X   regused[n] = 0;
X}
X
Xstatic struct block *
Xgen_len(jmp, n)
X   int jmp, n;
X{
X   struct slist *s;
X   struct block *b;
X
X   s = new_stmt(BPF_LD|BPF_LEN);
X   s->next = new_stmt(BPF_ALU|BPF_SUB|BPF_K);
X   s->next->s.k = n;
X   b = new_block(JMP(jmp));
X   b->stmts = s;
X
X   return b;
X}
X
Xstruct block *
Xgen_greater(n)
X   int n;
X{
X   return gen_len(BPF_JGE, n);
X}
X
Xstruct block *
Xgen_less(n)
X   int n;
X{
X   struct block *b;
X
X   b = gen_len(BPF_JGT, n);
X   gen_not(b);
X
X   return b;
X}
X
Xstruct block *
Xgen_byteop(op, idx, val)
Xint op, idx, val;
X{
X   struct block *b;
X   struct slist *s;
X
X   switch (op) {
X   default:
X      abort();
X
X   case '=':
X      return gen_cmp((u_int)idx, BPF_B, (u_long)val);
X
X   case '<':
X      b = gen_cmp((u_int)idx, BPF_B, (u_long)val);
X      b->s.code = JMP(BPF_JGE);
X      gen_not(b);
X      return b;
X
X   case '>':
X      b = gen_cmp((u_int)idx, BPF_B, (u_long)val);
X      b->s.code = JMP(BPF_JGT);
X      return b;
X
X   case '|':
X      s = new_stmt(BPF_ALU|BPF_OR|BPF_K);
X      break;
X
X   case '&':
X      s = new_stmt(BPF_ALU|BPF_AND|BPF_K);
X      break;
X   }
X   s->s.k = val;
X   b = new_block(JMP(BPF_JEQ));
X   b->stmts = s;
X   gen_not(b);
X
X   return b;
X}
X
Xstruct block *
Xgen_broadcast(proto)
Xint proto;
X{
X   u_long hostmask;
X   struct block *b0, *b1, *b2;
X   static u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
X
X   switch (proto) {
X
X   case Q_DEFAULT:
X   case Q_LINK:
X      return gen_ehostop(ebroadcast, Q_DST);
X      break;
X
X   case Q_IP:
X      b0 = gen_prototype(IPPROTO);
X      hostmask = ~netmask;
X      b1 = gen_mcmp(off_nl + 16, BPF_W, (u_long)0, hostmask);
X      b2 = gen_mcmp(off_nl + 16, BPF_W,
X               (u_long)(~0 & hostmask), hostmask);
X      gen_or(b1, b2);
X      gen_and(b0, b2);
X      return b2;
X   }
X   bpf_error("only ether/ip broadcast filters supported");
X}
X
Xstruct block *
Xgen_multicast(proto)
X   int proto;
X{
X   register struct block *b0, *b1;
X   register struct slist *s;
X
X   switch (proto) {
X
X   case Q_DEFAULT:
X   case Q_LINK:
X      s = new_stmt(BPF_LD|BPF_B|BPF_ABS);
X      s->s.k = 0;
X      b0 = new_block(JMP(BPF_JSET));
X      b0->s.k = 1;
X      b0->stmts = s;
X      return b0;
X      break;
X
X   case Q_IP:
X      b0 = gen_prototype(IPPROTO);
X      b1 = gen_cmp(off_nl + 16, BPF_B, (u_long)224);
X      b1->s.code = JMP(BPF_JGE);
X      gen_and(b0, b1);
X      return b1;
X   }
X}
X
X/*
X * generate command for inbound/outbound.  It's here so we can
X * make it link-type specific.  'dir' = 0 implies "inbound",
X * = 1 implies "outbound".
X */
Xstruct block *
Xgen_inbound(dir)
Xint dir;
X{
X   register struct block *b0;
X
X   b0 = gen_relation(BPF_JEQ,
X           gen_load(Q_LINK, gen_loadi(0), 1),
X           gen_loadi(0),
X           dir);
X   return (b0);
X}
SHAR_EOF
  $shar_touch -am 0508141395 'argus-1.5/common/gencode.c' &&
  chmod 0444 'argus-1.5/common/gencode.c' ||
  echo 'restore of argus-1.5/common/gencode.c failed'
  shar_count="`wc -c < 'argus-1.5/common/gencode.c'`"
  test 28245 -eq "$shar_count" ||
    echo "argus-1.5/common/gencode.c: original size 28245, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= argus-1.5/common/util.c ==============
if test -f 'argus-1.5/common/util.c' && test X"$1" != X"-c"; then
  echo 'x - skipping argus-1.5/common/util.c (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting argus-1.5/common/util.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'argus-1.5/common/util.c' &&
X/*
X * Copyright (c) 1988-1990 The Regents of the University of California.
X * All rights reserved.
X *
X * Redistribution and use in source and binary forms, with or without
X * modification, are permitted provided that: (1) source code distributions
X * retain the above copyright notice and this paragraph in its entirety, (2)
X * distributions including binary code include the above copyright notice and
X * this paragraph in its entirety in the documentation or other materials
X * provided with the distribution, and (3) all advertising materials mentioning
X * features or use of this software display the following acknowledgement:
X * ``This product includes software developed by the University of California,
X * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
X * the University nor the names of its contributors may be used to endorse
X * or promote products derived from this software without specific prior
X * written permission.
X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
X * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
X * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
X */
X
X#ifndef lint
Xstatic char rcsid[] =
X    "@(#) $Header: /usr/users/poepping/src/argus/argus-1.5/common/RCS/util.c,v 1.1 1995/02/08 21:03:27 poepping Exp $ (LBL)";
X#endif
X
X#include <stdio.h>
X#ifdef __STDC__
X#include <stdlib.h>
X#endif
X#include <sys/types.h>
X#include <ctype.h>
X#include <varargs.h>
X#include <sys/file.h>
X#include <sys/stat.h>
X#ifdef SOLARIS
X#include <fcntl.h>
X#endif
X
X
X#include <pcap.h>
X#include <interface.h>
X
X/* Hex digit to integer. */
Xstatic inline int
Xxdtoi(c)
X{
X   if (isdigit(c))
X      return c - '0';
X   else if (islower(c))
X      return c - 'a' + 10;
X   else
X      return c - 'A' + 10;
X}
X
X/*
X * Convert string to integer.  Just like atoi(), but checks for 
X * preceding 0x or 0 and uses hex or octal instead of decimal.
X */
Xint
Xstoi(s)
X   char *s;
X{
X   int base = 10;
X   int n = 0;
X
X   if (*s == '0') {
X      if (s[1] == 'x' || s[1] == 'X') {
X         s += 2;
X         base = 16;
X      }
X      else {
X         base = 8;
X         s += 1;
X      }
X   }
X   while (*s)
X      n = n * base + xdtoi(*s++);
X
X   return n;
X}
X
X/*
X * Print out a filename (or other ascii string).
X * Return true if truncated.
X */
Xint
Xprintfn(s, ep)
X   register u_char *s, *ep;
X{
X   register u_char c;
X
X   putchar('"');
X   while (c = *s++) {
X      if (s > ep) {
X         putchar('"');
X         return(1);
X      }
X      if (!isascii(c)) {
X         c = toascii(c);
X         putchar('M');
X         putchar('-');
X      }
X      if (!isprint(c)) {
X         c ^= 0x40;   /* DEL to ?, others to alpha */
X         putchar('^');
X      }
X      putchar(c);
X   }
X   putchar('"');
X   return(0);
X}
X
X
X#ifdef NOVFPRINTF
X/*
X * Stock 4.3 doesn't have vfprintf. 
X * This routine is due to Chris Torek.
X */
Xvfprintf(f, fmt, args)
X   FILE *f;
X   char *fmt;
X   va_list args;
X{
X   int ret;
X
X   if ((f->_flag & _IOWRT) == 0) {
X      if (f->_flag & _IORW)
X         f->_flag |= _IOWRT;
X      else
X         return EOF;
X   }
X   ret = _doprnt(fmt, args, f);
X   return ferror(f) ? EOF : ret;
X}
X#endif
X
X/* VARARGS */
Xvoid
Xerror(va_alist)
X   va_dcl
X{
X   register char *cp;
X   va_list ap;
X
X   (void)fprintf(stderr, "connect: ");
X
X   va_start(ap);
X   cp = va_arg(ap, char *);
X   (void)vfprintf(stderr, cp, ap);
X   va_end(ap);
X   if (*cp) {
X      cp += strlen(cp);
X      if (cp[-1] != '\n')
X         (void)fputc('\n', stderr);
X   }
X   exit(1);
X   /* NOTREACHED */
X}
X
X/* VARARGS */
Xvoid
Xwarning(va_alist)
X   va_dcl
X{
X   register char *cp;
X   va_list ap;
X
X   (void)fprintf(stderr, "connect: warning: ");
X
X   va_start(ap);
X   cp = va_arg(ap, char *);
X   (void)vfprintf(stderr, cp, ap);
X   va_end(ap);
X   if (*cp) {
X      cp += strlen(cp);
X      if (cp[-1] != '\n')
X         (void)fputc('\n', stderr);
X   }
X}
X
X/* A replacement for strdup() that cuts down on malloc() overhead */
Xchar *
Xsavestr(register const char *str)
X{
X        register u_int size;
X        register char *p;
X        static char *strptr = NULL;
X        static u_int strsize = 0;
X
X        size = strlen(str) + 1;
X        if (size > strsize) {
X                strsize = 1024;
X                if (strsize < size)
X                        strsize = size;
X                strptr = malloc(strsize);
X                if (strptr == NULL)
X                        error("savestr: malloc");
X        }
X        (void)strcpy(strptr, str);
X        p = strptr;
X        strptr += size;
X        strsize -= size;
X        return (p);
X}
X
X
X
X/*
X * Copy arg vector into a new buffer, concatenating arguments with spaces.
X */
Xchar *
Xcopy_argv(argv)
Xregister char **argv;
X{
X   register char **p;
X   register int len = 0;
X   char *buf;
X   char *src, *dst;
X
X   p = argv;
X   if (*p == 0)
X      return 0;
X
X   while (*p)
X      len += strlen(*p++) + 1;
X
X   buf = malloc (len);
X
X   p = argv;
X   dst = buf;
X   while (src = *p++) {
X      while (*dst++ = *src++)
X         ;
X      dst[-1] = ' ';
X   }
X   dst[-1] = '\0';
X
X   return buf;
X}
X
Xchar *
Xread_infile(fname)
X   char *fname;
X{
X   struct stat buf;
X   int fd;
X   char *p;
X
X   fd = open(fname, O_RDONLY);
X   if (fd < 0)
X      error("can't open '%s'", fname);
X
X   if (fstat(fd, &buf) < 0)
X      error("can't state '%s'", fname);
X
X   p = malloc((unsigned)buf.st_size);
X   if (read(fd, p, (int)buf.st_size) != buf.st_size)
X      error("problem reading '%s'", fname);
X   
X   return p;
X}
X
X/*
X * Left justify 'addr' and return its resulting network mask.
X */
Xu_long
Xnet_mask(addr)
X   u_long *addr;
X{
X   register u_long m = 0xffffffff;
X
X   if (*addr)
X      while ((*addr & 0xff000000) == 0)
X         *addr <<= 8, m <<= 8;
X
X   return m;
X}
X
X#include <netinet/in.h>
X
Xu_long
Xipaddrtonetmask(addr)
Xu_long addr;
X{
X   if (IN_CLASSA (addr)) return IN_CLASSA_NET;
X   if (IN_CLASSB (addr)) return IN_CLASSB_NET;
X   if (IN_CLASSC (addr)) return IN_CLASSC_NET;
X   else return 0;
X}
X
X
Xu_long
Xgetnetnumber(addr)
Xu_long addr;
X{
X   if (IN_CLASSA (addr)) return (addr >> 24 );
X   if (IN_CLASSB (addr)) return (addr >> 16 );
X   if (IN_CLASSC (addr)) return (addr >>  8 );
X   else return 0;
X}
X
X
X
X#ifdef SOLARIS
Xbcopy (s1, s2, len)
Xchar *s1, *s2;
Xint len;
X{
X   memmove (s2, s1, len);
X}
X
Xbcmp (s1, s2, len)
Xchar *s1, *s2;
Xint len;
X{
X   return (memcmp (s1, s2, len));
X}
X
Xbzero (s1, len)
Xchar *s1;
Xint len;
X{
X   memset (s1, 0, len);
X}
X#endif
SHAR_EOF
  $shar_touch -am 0508141395 'argus-1.5/common/util.c' &&
  chmod 0444 'argus-1.5/common/util.c' ||
  echo 'restore of argus-1.5/common/util.c failed'
  shar_count="`wc -c < 'argus-1.5/common/util.c'`"
  test 6309 -eq "$shar_count" ||
    echo "argus-1.5/common/util.c: original size 6309, current size $shar_count"
  rm -f _sharnew.tmp
fi
# ============= argus-1.5/common/argus_parse.c ==============
if test -f 'argus-1.5/common/argus_parse.c' && test X"$1" != X"-c"; then
  echo 'x - skipping argus-1.5/common/argus_parse.c (file already exists)'
  rm -f _sharnew.tmp
else
  > _sharnew.tmp
  echo 'x - extracting argus-1.5/common/argus_parse.c (text)'
  sed 's/^X//' << 'SHAR_EOF' > 'argus-1.5/common/argus_parse.c' &&
X
X/*
X * Copyright (c) 1993, 1994 Carnegie Mellon University.
X * All rights reserved.
X *
X * Permission to use, copy, modify, and distribute this software and
X * its documentation for any purpose and without fee is hereby granted, 
X * provided that the above copyright notice appear in all copies and
X * that both that copyright notice and this permission notice appear
X * in supporting documentation, and that the name of CMU not be
X * used in advertising or publicity pertaining to distribution of the
X * software without specific, written prior permission.  
X * 
X * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
X * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
X * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
X * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
X * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
X * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X *
X */
X
X/*
X * argus_parse - parse argus output.
X *       this module performs all the argus(1) related connection parsing,
X *       selects datum from a set of criteria, and then calls specific
X *       protocol dependant routines, depending on the selected datum.
X *       at the end of processing, argus_parse calls an application
X *       specific finish routine, argus_parse_complete(), and when
X *       connected to a remote data source, it supplies a periodic
X *       timeout routine;
X *
X *       this module defines all things, except:
X *
X *   (void) usage ((char *) argv[0]);
X *                    this routine should print the standard usage message
X *                    for the specific application.
X *
X *          init ();  this is the application specific init
X *                    routine, which is called after all parsing
X *                    initialization is done, prior to reading the
X *                    first monitor(1) datum.
X *
X *   (void) clientTimeout ();
X *                    this routine is called every second, when
X *                    argus_parse is connected to a remote data source.
X *
X *          process_tcp ((struct writeStruct *) ptr);
X *                    this routine should process tcp events;
X *
X *          process_udp ((struct writeStruct *) ptr);
X *                    this routine should process tcp events;
X *
X *          process_icmp ((struct writeStruct *) ptr);
X *                    this routine should process tcp events;
X *
X *          process_ip ((struct writeStruct *) ptr);
X *                    this routine should process tcp events;
X *
X *   (void) argus_parse_complete ();
X *                    this routine will be called after all the
X *                    monitor data has been read.
X *
X *
X * written by Carter Bullard
X * Software Engineering Institute
X * Carnegie Mellon Univeristy
X *
X */
X
X#define MONITOR_PARSE
X
X
X#include <stdlib.h>
X#include <stdio.h>
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/time.h>
X
X#ifndef SOLARIS
X#include <strings.h>
X#endif
X#include <string.h>
X#include <time.h>
X#include <errno.h>
X 
X#include <netinet/in.h>
X#include <arpa/inet.h>
X
X#include <compat.h>
X#include <pcap.h>
X#include <interface.h>
X#include <addrtoname.h>
X
X#include <argus_util.h>
X#include <policy.h>
X#include <argus_parse.h>
X#include <argus_client.h>
X
X#include <netinet/ip_icmp.h>
X
X#include <cons_def.h>
X#include <cons_icmp.h>
X#include <cons_ip.h>
X#include <cons_udp.h>
X
X
Xextern init ();
Xextern void usage ();
Xextern parse_arg ();
Xextern process_tcp ();
Xextern process_icmp ();
Xextern process_udp ();
Xextern process_ip ();
Xextern char *copy_argv ();
Xextern void argus_parse_complete ();
Xextern char *appOptstring;
X
X
X#include <nametoaddr.h>
X#include <sys/socket.h>
X
X
Xstruct policyStruct *policy = NULL;
Xchar *policyfile =  NULL;
Xchar *wfile =  NULL;
X
Xstruct FILE_ENTRY *input_file_list = NULL;
Xstruct IP_ENTRY *remote_host_list = NULL;
X
X#include <time.h>
X
X#define MAXSTR  256
X#define MAXTIME 100000
X
Xu_long localnet, netmask;
X
Xargus_parse_init (fd, read_mode)
Xint fd;
Xint read_mode;
X{
X   struct timeval now;
X   struct timezone tz;
X   char errbuf[256];
X   char *device = NULL;
X
X   if (gettimeofday(&now, &tz) < 0)
X      error("gettimeofday");
X   thiszone = tz.tz_minuteswest * -60;
X   if (localtime ((time_t *)&now.tv_sec)->tm_isdst)
X      thiszone += 3600;
X
X   if (device = pcap_lookupdev (errbuf))
X      pcap_lookupnet(device, &localnet, &netmask, errbuf);
X
X   init_addrtoname (0, localnet, netmask);
X}
X
X
X#include <pcap-int.h>
X
Xchar *progname = NULL;
Xchar cmdline[256]; 
X
Xint portnum = 0;
X
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
X   register int i, op;
X   register char *file = NULL;
X   struct bpf_program bpfcode;
X   struct FILE_ENTRY *ptr;
X   char *cmdbuf = NULL, *infile = NULL, *read_infile ();
X   pcap_t p;
X   extern char *optarg;
X   extern int optind, opterr;
X
X   opterr = 0;
X   for (i = 0, *cmdline = '\0'; i < argc; i++) {
X      strcat (cmdline, argv[i]);
X      strcat (cmdline, " ");
X   }
X   if (strchr (argv[0], '/'))
X      argv[0] = strrchr(argv[0], '/') + 1;
X   progname = argv[0];
X   while ((op = getopt (argc, argv, "bcC:d:EF:Ir:w:P:hnmMNOPRS:TWX")) != EOF) {
X      switch (op) {
X         case 'C': policyfile = optarg; break;
X         case 'd':  debugflag = atoi (optarg); break;
X         case 'P':  portnum = atoi (optarg); break;
X         case 'b': ++bflag; break;
X         case 'c': ++cflag; break;
X         case 't': ++tflag; break;
X         case 'E': ++Eflag; break;
X         case 'I': ++Iflag; break;
X         case 'R': ++Rflag; break;
X         case 'T': ++Tflag; break;
X         case 'u': ++uflag; break;
X         case 'm': ++mflag; break;
X         case 'M': ++Mflag; break;
X         case 'n': ++nflag; break;
X         case 'N': ++Normflag; break;
X         case 'W': ++Wflag; break;
X         case 'O': ++Oflag; break;
X         case 'X': ++Xflag; break;
X         case 'F': infile = optarg; break;
X         case 'w':  
X            if ((wfile = optarg) == NULL)
X               if (!strcmp (argv[optind], "-")) {
X                  wfile = "-";
X               }
X            break;
X         case 'r': ++rflag; 
X            if (optarg == NULL) optarg = "-";
X            if (!(new_file_arg (optarg))) {
X               fprintf (stderr, "%s: error: file arg %s \n", *argv, optarg);
X               exit (1);
X            }
X            break;
X         case 'S': ++Sflag;
X            if (!(remote_host_arg (optarg))) {
X               fprintf (stderr, "%s: host %s unknown\n", *argv, optarg);
X               exit (1);
X            }
X            break;
X
X         case 'h':
X            default:  
X               usage (argv[0]);
X            /* NOTREACHED */
X      }
X   }
X 
X   if (infile)
X      cmdbuf = read_infile (infile);
X   else
X      cmdbuf = copy_argv (&argv[optind]);
X
X   bzero (&bpfcode, sizeof (bpfcode));
X   if (policy_compile (&p, &bpfcode, cmdbuf, 1, netmask) < 0) {
X      fprintf (stderr, "%s: expression: %s\n", progname, p.errbuf);
X      exit (-1);
X   }
X
X   if (bflag) {
X      bpf_dump(&bpfcode, bflag);
X      exit (0);
X   }
X
X   if (readPolicy (&policy, policyfile)) {
X      if (Sflag) {
X         if (read_remote_connection (get_server_socket (remote_host_list),
X                        &bpfcode))
X            fprintf (stderr, "%s: connection failed\n", *argv);
X      } else
X         if (ptr = input_file_list) {
X            while (ptr) {
X               if (strcmp ((char *) ptr->str, "-")) {
X                  if (read_connection (fopen (ptr->str, "r"), &bpfcode))
X                     perror ("fopen");
X               } else
X                  read_connection (stdin, &bpfcode);
X               ptr = ptr->nxt;
X            }
X         } else
X            read_connection (stdin, &bpfcode);
X
X      argus_parse_complete ();
X   }
X   exit (0);
X}
X
XreadPolicy (policy, file)
Xstruct policyStruct **policy;
Xchar *file;
X{
X   register int retn = 1, linenum = 0, parse;
X   register struct policyStruct *pol, *policyLast = NULL;
X   register FILE *fd;
X   char buffer [1024], *str;
X
X   if (file) {
X      if (fd = fopen (file, "r")) {
X         while (fgets (buffer, 1024, fd)) {
X            linenum++;
X            if ((*buffer != '#') && (*buffer != '\n') && (*buffer != '!')) {
X               if (pol = (struct policyStruct *) calloc (1, 
X                                sizeof (struct policyStruct))) {
X                  pol->str = strdup (buffer);
X                  if (!(parsePolicy (pol, buffer))) {
X                     free (pol->str);
X                     free (pol);
X                     str = parseerrorstr[parseerror];
X                     fprintf (stderr, "%s: parsing error: %s\n",
X                                           progname, file);
X                     fprintf (stderr, "\tline number %d: %s\n", linenum, str);
X                     retn = 0;
X                  }
X                  if (policyLast)  {
X                     policyLast->nxt = pol;
X                     pol->prv = policyLast;
X                     policyLast = pol;
X                  } else
X                     *policy = policyLast = pol;
X               }
X            }
X         }
X         fclose (fd);
X      } else {
X         retn = 0;
X         fprintf (stderr, "%s: error couldn't open %s\n", progname, file);
X      }
X   }
X
X   return (retn);
X}
X
X
X#include <string.h>
X
XparsePolicy (policy, buf)
Xstruct policyStruct *policy;
Xchar *buf;
X{
X   register int retn = 1, error = 0, i;
X   register char *ptr;
X
X   if (strncmp (buf, "access", 6)) {
X      if (strstr (buf, "ip"))
X         if (strstr (buf, "source-route"))
X            policy->type = SSRCROUTE;
X   } else {
X      policy->type = ACCESSLIST;
X      for (i = 0; ((i < POLICYFIELDNUM) && !(error)); i++) {
X         if ((ptr = strtok (buf, " ")) && (*ptr != '\n')) {
X            switch (i) {
X               case POLICYSTRING: 
X                  if ((strcmp (ptr, POLICY_STRING))) error++; 
X                  break;
X   
X               case POLICYID: 
X                  if (!(policy->policyID = atoi (ptr))) error++;
X                  break;
X   
X               case POLICYACTION: 
X                  if (!(strcmp (ptr, "permit")))
X                     policy->flags |= PERMIT;
X                  else if (!(strcmp (ptr, "deny")))
X                     policy->flags |= DENY;
X                  else error++;
X                  break;
X   
X               case POLICYPROTO: 
X                  if (!(strcmp (ptr, "icmp")))
X                     policy->flags |= ICMP;
X                  else if (!(strcmp (ptr, "tcp")))
X                     policy->flags |= TCP;
X                  else if (!(strcmp (ptr, "udp")))
X                     policy->flags |= UDP;
X                  else if (!(strcmp (ptr, "ip")))
X                     policy->flags |= IP;
X                  else error++;
X                  break;
X   
X               case POLICYDSTADDR: 
X                  policy->dst.addr = inet_addr (ptr); break;
X               case POLICYDSTMASK: 
X                  policy->dst.mask = inet_addr (ptr); break;
X               case POLICYSRCADDR: 
X                  policy->src.addr = inet_addr (ptr); break;
X               case POLICYSRCMASK: 
X                  policy->src.mask = inet_addr (ptr); break;
X   
X               case POLICYPORTACT: 
X                  if (!(strcmp (ptr, "eq")))
X                     policy->action |= EQ;
X                  else if (!(strcmp (ptr, "lt")))
X                     policy->action |= LT;
X                  else if (!(strcmp (ptr, "gt")))
X                     policy->action |= GT;
X                  else if (!(strcmp (ptr, "neq")))
X                     policy->action |= NEQ;
X                  else if (!(strncmp (ptr, "established",11)))
X                     policy->action |= EST;
X                  else error++;
X                  break;
X   
X               case POLICYPORT: 
X                  if (!(policy->port = (u_short) atoi (ptr))) error++;
X                  break;
X   
X               case POLICYNOTIFICATION: 
X                  break;
X            }
X   
X            buf = NULL;
X         } else
X            break;
X      }
X   }
X
X   if (error) {
X      parseerror = i - 1; retn = 0;
X   }
X
X   return (retn);
X}
X
Xcheck_flags (ptr)
Xstruct writeStruct *ptr;
X{
X   int retn = 0;
X
X   if (Eflag|Mflag|Normflag|Oflag|Xflag|Rflag|Tflag|Wflag) {
X      if (Eflag && !retn) retn = ptr->status & CON_ESTABLISHED;
X      if (Mflag && !retn) retn = ptr->status & MULTIADDR;
X      if (Normflag && !retn) retn = ptr->status & NORMAL_CLOSE;
X      if (Oflag && !retn) retn = ptr->status & IPOPTIONMASK;
X      if (Xflag && !retn) retn = ptr->status & PKTS_RETRANS;
X      if (Rflag && !retn) retn = ptr->status & RESET;
X      if (Tflag && !retn) retn = ptr->status & TIMED_OUT;
X      if (Wflag && !retn) retn = ptr->status &
X                             (SRC_WINDOW_SHUT|DST_WINDOW_SHUT);
X   } else
X      retn = 1;
X
X   return (retn);
X}
X
X
Xcheck_policy (ptr, policy)
Xstruct writeStruct *ptr;
Xstruct policyStruct *policy;
X{
X   int retn = 1, i, policymatch = 0;
X
X   if (policy) {
X      while (policy) {
X         if (retn = meets_policy_criteria (ptr, policy)) {
X            retn = do_notification (ptr, policy);
X            policymatch = 1;
X            break;
X         }
X         policy = policy->nxt;
X      }
X   }
X
X   return (retn);
X}
X
X
Xmeets_policy_criteria (ptr, policy)
Xstruct writeStruct *ptr;
Xstruct policyStruct *policy;
X{
X   register int retn = 0, i = 0;
X   u_long saddr = 0, daddr = 0, addr = 0;
X   u_short sport = 0, dport = 0, port = 0;
X
X   switch (policy->type) {
X   case SSRCROUTE:
X      if ((ptr->status & SSRCROUTE) || (ptr->status & LSRCROUTE))
X         retn++;
X      break;
X
X   case ACCESSLIST:
X      if ((ptr->status & ICMPPROTO) || (ptr->status & UDPPROTO) ||
X         ((ptr->status & TCPPROTO) && !(ptr->status & REVERSE))) {
X         saddr = ptr->addr.src.s_addr;
X         daddr = ptr->addr.dst.s_addr;
X         sport = ((u_short *)&ptr->addr.port)[0];
X         dport = ((u_short *)&ptr->addr.port)[1];
X         port = dport;
X      } else {
X         saddr = ptr->addr.dst.s_addr;
X         daddr = ptr->addr.src.s_addr;
X         sport = ((u_short *)&ptr->addr.port)[1];
X         dport = ((u_short *)&ptr->addr.port)[0];
X         port = dport;
X      }
X   
X      for (i = 0, retn = 1; ((i < POLICYTESTCRITERIA) && retn); i++) {
X         retn = 0;
X         switch (i) {
X            case POLICYTESTPROTO:
X               switch (policy->flags & (UDP | TCP | ICMP | IP)) {
X                  case  UDP: if (ptr->status &  UDPPROTO) retn++; break;
X                  case  TCP: if (ptr->status &  TCPPROTO) retn++; break;
X                  case ICMP: if (ptr->status & ICMPPROTO) retn++; break;
X                  case   IP: retn++; break;
X               }
X               break;
X   
X            case POLICYTESTSRC:
X               if ((saddr & ~policy->src.mask) == policy->src.addr)
X                  retn++;
X               break;
X            case POLICYTESTDST:
X               if ((daddr & ~policy->dst.mask) == policy->dst.addr)
X                  retn++;
X               break;
X            case POLICYTESTPORT:
X               switch (policy->action) {
X                  case  EQ:
X                     if (port == policy->port)
X                        retn++; break;
X                  case  LT:
X                     if (port < policy->port)
X                        retn++; break;
X                  case  GT:
X                     if (port > policy->port)
X                        retn++; break;
X                  case NEQ:
X                     if (port != policy->port)
X                        retn++; break;
X                  case  EST:
X                     if (!(ptr->status & SAW_SYN))
X                        retn++; break;
X                  default:
X                     retn++; break;
X               }
X               break;
X         }
X      }
X   }
X
X   return (retn);
X}
X
X
Xdo_notification (ptr, policy)
Xstruct writeStruct *ptr;
Xstruct policyStruct *policy;
X{
X   register int retn = 1;
X
X   if (policy)
X      if (policy->flags & PERMIT) {
X         if (debugflag > 1)
X            printf ("%s %s", "policy: permitted", policy->str);
X         else
X            retn = 0;
X      } else
X         if (debugflag)
X            printf ("%s %s", "policy: denyed", policy->str);
X
X   return (retn);
X}
X
X 
X
Xstruct naddrmem *naddrtable [HASHNAMESIZE];
X
Xstruct naddrmem {
X   struct naddrmem *nxt;
X   u_long addr;
X   u_short port;
X};
X
X
Xchar *tag_string = "Argus Version ";
Xextern u_long localaddr;
Xint major_version = 0, minor_version = 0;
X
X
Xhandle_argus_control (ptr)
Xstruct writeStruct *ptr;
X{
X}
X
Xhandle_datum (ptr, read_mode, bpfcode)
Xstruct writeStruct *ptr;
Xint read_mode;
Xstruct bpf_program *bpfcode;
X{
X   int retn;
X   struct writeStruct buf;
X   struct bpf_insn *fcode = bpfcode->bf_insns;
X
X   if (ptr->status & ARGUSCONTROL)
X      handle_argus_control (&ptr);
X
X   else {
X      reformat_datum (ptr, &buf);
X      if (retn = check_flags (&buf)) {
X         if (retn = argus_filter (fcode, &buf)) {
X            if (retn = check_policy (&buf, policy)) {
X               if (wfile) {
X                  writeNewLogfile (ptr);
X   
X                  if (strcmp (wfile, "-"))
X                     version_process (&buf, read_mode);
X               } else
X                  version_process (&buf, read_mode);
X            }
X         }
X      }
X   }
X}
X
X#define IPPROTOMASK  (TCPPROTO | ICMPPROTO | UDPPROTO)
X#define PROTOMASK     (IPPROTO | ARPPROTO)
X
Xreformat_datum (ptr, buf)
Xstruct writeStruct *ptr, *buf;
X{
X   u_long saddr, daddr;
X   u_short sport, dport;
X   struct writeStruct tmpbuf, *tmp = &tmpbuf;
X
X   if (ptr && buf) {
X      bcopy (ptr, tmp, sizeof (struct writeStruct));
X      if (tmp->status & REVERSE) {
X         bcopy (&ptr->etherdst, &tmp->ethersrc, 6);
X         bcopy (&ptr->ethersrc, &tmp->etherdst, 6);
X         bcopy (&ptr->addr.dst, &tmp->addr.src, 4);
X         bcopy (&ptr->addr.src, &tmp->addr.dst, 4);
X         sport = ((unsigned short *) &ptr->addr.port)[0];
X         dport = ((unsigned short *) &ptr->addr.port)[1];
SHAR_EOF
  : || echo 'restore of argus-1.5/common/argus_parse.c failed'
fi
echo 'End of archive part 3'
echo 'File argus-1.5/common/argus_parse.c is continued in part 4'
echo 4 > _sharseq.tmp
exit 0


