summaryrefslogtreecommitdiff
path: root/usr.sbin/ipftest
diff options
context:
space:
mode:
authordm <dm@cvs.openbsd.org>1996-01-07 02:34:41 +0000
committerdm <dm@cvs.openbsd.org>1996-01-07 02:34:41 +0000
commit01b9b71d86a5edcc543a88b2d407927fa52c042d (patch)
tree878168b4effcec4e50c243cfd1095656af14f4db /usr.sbin/ipftest
parent2defc765aa92d65e239f5b4d36582850fd58b7da (diff)
from beurton@fnet.fr: Darren Reed's IP filter
Diffstat (limited to 'usr.sbin/ipftest')
-rw-r--r--usr.sbin/ipftest/Makefile8
-rw-r--r--usr.sbin/ipftest/fil.c534
-rw-r--r--usr.sbin/ipftest/ipft_ef.c157
-rw-r--r--usr.sbin/ipftest/ipft_pc.c189
-rw-r--r--usr.sbin/ipftest/ipft_sn.c201
-rw-r--r--usr.sbin/ipftest/ipft_td.c201
-rw-r--r--usr.sbin/ipftest/ipft_tx.c248
-rw-r--r--usr.sbin/ipftest/ipftest.199
-rw-r--r--usr.sbin/ipftest/ipt.c197
-rw-r--r--usr.sbin/ipftest/ipt.h15
-rw-r--r--usr.sbin/ipftest/misc.c103
-rw-r--r--usr.sbin/ipftest/pcap.h32
-rw-r--r--usr.sbin/ipftest/snoop.h41
13 files changed, 2025 insertions, 0 deletions
diff --git a/usr.sbin/ipftest/Makefile b/usr.sbin/ipftest/Makefile
new file mode 100644
index 00000000000..723b31469d7
--- /dev/null
+++ b/usr.sbin/ipftest/Makefile
@@ -0,0 +1,8 @@
+PROG= ipftest
+MAN= ipftest.1
+SRCS= ipt.c fil.c ipft_sn.c ipft_ef.c ipft_td.c ipft_pc.c ipft_tx.c misc.c parse.c opt.c
+.PATH: ${.CURDIR}/../../sbin/ipf ${.CURDIR}/../../sbin/ipfstat
+CFLAGS+=-DIPL_NAME=\"/dev/ipl\" -I${.CURDIR}/../../sbin/ipf
+
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ipftest/fil.c b/usr.sbin/ipftest/fil.c
new file mode 100644
index 00000000000..b485678d5a7
--- /dev/null
+++ b/usr.sbin/ipftest/fil.c
@@ -0,0 +1,534 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+#ifndef lint
+static char sccsid[] = "@(#)fil.c 1.18 10/24/95 (C) 1993-1995 Darren Reed";
+#endif
+
+#ifndef linux
+# include <sys/errno.h>
+# include <sys/types.h>
+# include <sys/param.h>
+# include <sys/file.h>
+# include <sys/ioctl.h>
+# if defined(_KERNEL) || defined(KERNEL)
+# include <sys/systm.h>
+# endif
+# include <sys/uio.h>
+# if !defined(__SVR4) && !defined(__svr4__)
+# include <sys/dir.h>
+# include <sys/mbuf.h>
+# else
+# include <sys/byteorder.h>
+# include <sys/dditypes.h>
+# include <sys/stream.h>
+# endif
+# include <sys/protosw.h>
+# include <sys/socket.h>
+# include <net/if.h>
+# ifdef sun
+# include <net/af.h>
+# endif
+# include <net/route.h>
+# include <netinet/in.h>
+# include <netinet/in_systm.h>
+# include <netinet/ip.h>
+# include <netinet/ip_var.h>
+# include <netinet/tcp.h>
+# include <netinet/udp.h>
+# include <netinet/tcpip.h>
+# include <netinet/ip_icmp.h>
+#endif
+#include <netinet/ip_fil.h>
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#ifndef _KERNEL
+#include "ipf.h"
+extern int opts;
+extern void debug(), verbose();
+
+#define FR_IFVERBOSE(ex,second,verb_pr) if (ex) { verbose verb_pr; second; }
+#define FR_IFDEBUG(ex,second,verb_pr) if (ex) { debug verb_pr; second; }
+#define FR_VERBOSE(verb_pr) verbose verb_pr
+#define FR_DEBUG(verb_pr) debug verb_pr
+#else
+#define FR_IFVERBOSE(ex,second,verb_pr) ;
+#define FR_IFDEBUG(ex,second,verb_pr) ;
+#define FR_VERBOSE(verb_pr)
+#define FR_DEBUG(verb_pr)
+
+extern int ipl_unreach, ipllog();
+#endif
+
+struct filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}};
+struct frentry *filterin[2] = { NULL, NULL },
+ *filterout[2] = { NULL, NULL };
+int fr_flags = 0, fr_active = 0;
+int fr_check();
+
+
+/*
+ * bit values for identifying presence of individual IP options
+ */
+struct optlist ipopts[20] = {
+ { IPOPT_NOP, 0x000001 },
+ { IPOPT_RR, 0x000002 },
+ { IPOPT_ZSU, 0x000004 },
+ { IPOPT_MTUP, 0x000008 },
+ { IPOPT_MTUR, 0x000010 },
+ { IPOPT_ENCODE, 0x000020 },
+ { IPOPT_TS, 0x000040 },
+ { IPOPT_TR, 0x000080 },
+ { IPOPT_SECURITY, 0x000100 },
+ { IPOPT_LSRR, 0x000200 },
+ { IPOPT_E_SEC, 0x000400 },
+ { IPOPT_CIPSO, 0x000800 },
+ { IPOPT_SATID, 0x001000 },
+ { IPOPT_SSRR, 0x002000 },
+ { IPOPT_ADDEXT, 0x004000 },
+ { IPOPT_VISA, 0x008000 },
+ { IPOPT_IMITD, 0x010000 },
+ { IPOPT_EIP, 0x020000 },
+ { IPOPT_FINN, 0x040000 },
+ { 0, 0x000000 }
+};
+
+/*
+ * bit values for identifying presence of individual IP security options
+ */
+struct optlist secopt[8] = {
+ { IPSO_CLASS_RES4, 0x01 },
+ { IPSO_CLASS_TOPS, 0x02 },
+ { IPSO_CLASS_SECR, 0x04 },
+ { IPSO_CLASS_RES3, 0x08 },
+ { IPSO_CLASS_CONF, 0x10 },
+ { IPSO_CLASS_UNCL, 0x20 },
+ { IPSO_CLASS_RES2, 0x40 },
+ { IPSO_CLASS_RES1, 0x80 }
+};
+
+
+/*
+ * compact the IP header into a structure which contains just the info.
+ * which is useful for comparing IP headers with.
+ */
+struct fr_ip *fr_makefrip(hlen, ip)
+int hlen;
+ip_t *ip;
+{
+ static struct fr_ip fi;
+ struct optlist *op;
+ u_short optmsk = 0, secmsk = 0, auth = 0;
+ int i, mv, ol, off;
+ u_char *s, opt;
+
+ fi.fi_fl = 0;
+ fi.fi_v = ip->ip_v;
+ fi.fi_tos = ip->ip_tos;
+ (*(((u_short *)&fi) + 1)) = (*(((u_short *)ip) + 4));
+ (*(((u_long *)&fi) + 1)) = (*(((u_long *)ip) + 3));
+ (*(((u_long *)&fi) + 2)) = (*(((u_long *)ip) + 4));
+
+ if (hlen > sizeof(struct ip))
+ fi.fi_fl |= FI_OPTIONS;
+ off = (ip->ip_off & 0x1fff) << 3;
+ if (ip->ip_off & 0x3fff)
+ fi.fi_fl |= FI_FRAG;
+ switch (ip->ip_p)
+ {
+ case IPPROTO_ICMP :
+ if ((!IPMINLEN(ip, icmp) && !off) ||
+ (off && off < sizeof(struct icmp)))
+ fi.fi_fl |= FI_SHORT;
+ break;
+ case IPPROTO_TCP :
+ fi.fi_fl |= FI_TCPUDP;
+ if ((!IPMINLEN(ip, tcphdr) && !off) ||
+ (off && off < sizeof(struct tcphdr)))
+ fi.fi_fl |= FI_SHORT;
+ break;
+ case IPPROTO_UDP :
+ fi.fi_fl |= FI_TCPUDP;
+ if ((!IPMINLEN(ip, udphdr) && !off) ||
+ (off && off < sizeof(struct udphdr)))
+ fi.fi_fl |= FI_SHORT;
+ break;
+ default :
+ break;
+ }
+
+ for (s = (u_char *)(ip + 1), hlen -= sizeof(*ip); hlen; ) {
+ if (!(opt = *s))
+ break;
+ ol = (opt == IPOPT_NOP) ? 1 : (int)*(s+1);
+ if (opt > 1 && (ol < 0 || ol > hlen))
+ break;
+ for (i = 9, mv = 4; mv >= 0; ) {
+ op = ipopts + i;
+ if (opt == (u_char)op->ol_val) {
+ optmsk |= op->ol_bit;
+ if (opt == IPOPT_SECURITY) {
+ struct optlist *sp;
+ u_char sec;
+ int j, m;
+
+ sec = *(s + 3); /* classification */
+ for (j = 3, m = 2; m >= 0; ) {
+ sp = secopt + j;
+ if (sec == sp->ol_val) {
+ secmsk |= sp->ol_bit;
+ auth = *(s + 3);
+ auth *= 256;
+ auth += *(s + 4);
+ break;
+ }
+ if (sec < sp->ol_val)
+ j -= m--;
+ else
+ j += m--;
+ }
+ }
+ break;
+ }
+ if (opt < op->ol_val)
+ i -= mv--;
+ else
+ i += mv--;
+ }
+ hlen -= ol;
+ s += ol;
+ }
+ if (auth && !(auth & 0x0100))
+ auth &= 0xff00;
+ fi.fi_optmsk = optmsk;
+ fi.fi_secmsk = secmsk;
+ fi.fi_auth = auth;
+ return &fi;
+}
+
+
+/*
+ * check an IP packet for TCP/UDP characteristics such as ports and flags.
+ */
+int fr_tcpudpchk(ip, tcp, fr)
+ip_t *ip;
+tcphdr_t *tcp;
+struct frentry *fr;
+{
+ register u_short po, tup;
+ register char i;
+ int err = 1;
+
+ /*
+ * Both ports should *always* be in the first fragment.
+ * So far, I cannot find any cases where they can not be.
+ *
+ * compare destination ports
+ */
+ if ((i = (int)fr->fr_dcmp)) {
+ po = ntohs(fr->fr_dport);
+ tup = ntohs(tcp->th_dport);
+ /*
+ * Do opposite test to that required and
+ * continue if that succeeds.
+ */
+ if (!--i && tup != po) /* EQUAL */
+ err = 0;
+ else if (!--i && tup == po) /* NOTEQUAL */
+ err = 0;
+ else if (!--i && tup >= po) /* LESSTHAN */
+ err = 0;
+ else if (!--i && tup <= po) /* GREATERTHAN */
+ err = 0;
+ else if (!--i && tup > po) /* LT or EQ */
+ err = 0;
+ else if (!--i && tup < po) /* GT or EQ */
+ err = 0;
+ else if (!--i && /* Out of range */
+ (tup >= po && tup <= ntohs(fr->fr_dtop)))
+ err = 0;
+ else if (!--i && /* In range */
+ (tup <= po || tup >= ntohs(fr->fr_dtop)))
+ err = 0;
+ }
+ /*
+ * compare source ports
+ */
+ if (err && (i = (int)fr->fr_scmp)) {
+ po = ntohs(fr->fr_sport);
+ tup = ntohs(tcp->th_sport);
+ if (!--i && tup != po)
+ err = 0;
+ else if (!--i && tup == po)
+ err = 0;
+ else if (!--i && tup >= po)
+ err = 0;
+ else if (!--i && tup <= po)
+ err = 0;
+ else if (!--i && tup > po)
+ err = 0;
+ else if (!--i && tup < po)
+ err = 0;
+ else if (!--i && /* Out of range */
+ (tup >= po && tup <= ntohs(fr->fr_stop)))
+ err = 0;
+ else if (!--i && /* In range */
+ (tup <= po || tup >= ntohs(fr->fr_stop)))
+ err = 0;
+ }
+
+ /*
+ * If we don't have all the TCP/UDP header, then how can we
+ * expect to do any sort of match on it ? If we were looking for
+ * TCP flags, then NO match. If not, then match (which should
+ * satisfy the "short" class too).
+ */
+ if (err)
+ if (ip->ip_p == IPPROTO_TCP) {
+ if (!IPMINLEN(ip, tcphdr))
+ return !(fr->fr_tcpf);
+ /*
+ * Match the flags ? If not, abort this match.
+ */
+ if (fr->fr_tcpf &&
+ fr->fr_tcpf != (tcp->th_flags & fr->fr_tcpfm)) {
+ FR_DEBUG(("f. %#x & %#x != %#x\n",
+ tcp->th_flags, fr->fr_tcpfm,
+ fr->fr_tcpf));
+ err = 0;
+ }
+ }
+ else if (!IPMINLEN(ip, udphdr)) /* must be UDP */
+ return 1;
+ return err;
+}
+
+/*
+ * Check the input/output list of rules for a match and result.
+ * Could be per interface, but this gets real nasty when you don't have
+ * kernel sauce.
+ */
+int fr_scanlist(pass, ip, hlen, ifp, out, rule)
+int pass;
+ip_t *ip;
+int hlen, out;
+struct ifnet *ifp;
+u_short *rule;
+{
+ register struct frentry *fr;
+ register struct fr_ip *fi;
+ tcphdr_t *tcp;
+ int rulen;
+
+ *rule = 1;
+ tcp = (tcphdr_t *)((char *)ip + hlen);
+ fr = (out) ? filterout[fr_active] : filterin[fr_active];
+ fi = fr_makefrip(hlen, ip);
+
+ for (rulen = 0; fr; fr = fr->fr_next, rulen++) {
+ /*
+ * In all checks below, a null (zero) value in the
+ * filter struture is taken to mean a wildcard.
+ *
+ * check that we are working for the right interface
+ */
+#ifdef _KERNEL
+ if (fr->fr_ifa && fr->fr_ifa != ifp)
+ continue;
+#else
+ if (opts & (OPT_VERBOSE|OPT_DEBUG))
+ printf("\n");
+ FR_VERBOSE(("%c", (pass & FR_PASS) ? 'p' : 'b'));
+ if (ifp && *fr->fr_ifname && strcasecmp(ifp->if_name,
+ fr->fr_ifname))
+ continue;
+ FR_VERBOSE((":i"));
+#endif
+ {
+ register u_long *ld, *lm, *lip;
+ register int i;
+
+ lip = (u_long *)fi;
+ lm = (u_long *)&fr->fr_mip;
+ ld = (u_long *)&fr->fr_ip;
+ i = ((lip[0] & lm[0]) != ld[0]);
+ FR_IFDEBUG(i,continue,("0. %#08x & %#08x != %#08x\n",
+ lip[0], lm[0], ld[0]));
+ i |= ((lip[1] & lm[1]) != ld[1]);
+ FR_IFDEBUG(i,continue,("1. %#08x & %#08x != %#08x\n",
+ lip[1], lm[1], ld[1]));
+ i |= ((lip[2] & lm[2]) != ld[2]);
+ FR_IFDEBUG(i,continue,("2. %#08x & %#08x != %#08x\n",
+ lip[2], lm[2], ld[2]));
+ i |= ((lip[3] & lm[3]) != ld[3]);
+ FR_IFDEBUG(i,continue,("3. %#08x & %#08x != %#08x\n",
+ lip[3], lm[3], ld[3]));
+ i |= ((lip[4] & lm[4]) != ld[4]);
+ FR_IFDEBUG(i,continue,("4. %#08x & %#08x != %#08x\n",
+ lip[4], lm[4], ld[4]));
+ if (i)
+ continue;
+ }
+
+ /*
+ * If a fragment, then only the first has what we're looking
+ * for here...
+ */
+ if (!(ip->ip_off & 0x1fff)) {
+ if ((fi->fi_fl & FI_TCPUDP) &&
+ !fr_tcpudpchk(ip, tcp, fr))
+ continue;
+ else if (ip->ip_p == IPPROTO_ICMP &&
+ (*(u_short *)((char *)ip + hlen) &
+ fr->fr_icmpm) != fr->fr_icmp) {
+ FR_DEBUG(("i. %#x & %#x != %#x\n",
+ *(u_short *)((char *)ip + hlen),
+ fr->fr_icmpm, fr->fr_icmp));
+ continue;
+ }
+ } else if (fr->fr_dcmp || fr->fr_scmp || fr->fr_icmpm ||
+ fr->fr_tcpfm)
+ continue;
+ FR_VERBOSE(("*"));
+ /*
+ * Just log this packet...
+ */
+ if (fr->fr_flags & FR_LOG) {
+#ifdef IPFILTER_LOG
+ if (!ipllog(hlen, fr->fr_flags, ip, ifp, *rule))
+ frstats[out].fr_skip++;
+ frstats[out].fr_pkl++;
+#endif /* IPFILTER_LOG */
+ } else
+ pass = fr->fr_flags;
+ FR_DEBUG(("pass %#x\n", pass));
+ fr->fr_hits++;
+ *rule = rulen;
+ if (pass & FR_QUICK)
+ break;
+ }
+ return pass;
+}
+
+
+/*
+ * frcheck - filter check
+ * check using source and destination addresses/pors in a packet whether
+ * or not to pass it on or not.
+ */
+int fr_check(ip, hlen, ifp, out
+#if SOLARIS && defined(_KERNEL)
+, qif, q)
+qif_t *qif;
+queue_t *q;
+#else
+)
+#endif
+ip_t *ip;
+int hlen;
+struct ifnet *ifp;
+int out;
+{
+ int pass = FR_NOMATCH;
+ int sl;
+ u_short rule;
+
+ SPLNET(sl);
+
+ pass = fr_scanlist(pass, ip, hlen, ifp, out, &rule);
+ if (pass == FR_NOMATCH) {
+ frstats[out].fr_nom++;
+#ifdef NOMATCH
+ pass |= NOMATCH;
+#endif
+ }
+
+#ifdef IPFILTER_LOG
+ if ((pass & FR_LOGP) ||
+ ((pass & FR_PASS) && (fr_flags & FF_LOGPASS))) {
+ if (!(pass & FR_LOGP))
+ pass |= FF_LOGPASS << 8;
+ if (!ipllog(hlen, pass, ip, ifp, rule))
+ frstats[out].fr_skip++;
+ frstats[out].fr_ppkl++;
+ } else if ((pass & FR_LOGB) ||
+ ((pass & FR_BLOCK) && (fr_flags & FF_LOGBLOCK))) {
+ if (!(pass & FR_LOGB))
+ pass |= FF_LOGBLOCK << 8;
+ if (!ipllog(hlen, pass, ip, ifp, rule))
+ frstats[out].fr_skip++;
+ frstats[out].fr_bpkl++;
+ }
+#endif /* IPFILTER_LOG */
+ SPLX(sl);
+ if (pass & FR_PASS)
+ frstats[out].fr_pass++;
+ else if (pass & FR_BLOCK) {
+ frstats[out].fr_block++;
+ /*
+ * Should we return an ICMP packet to indicate error
+ * status passing through the packet filter ?
+ * XXX - copy mbuf as icmp_error() calls mfree() - fix this
+ * later, but preserve backward compatibility for now.
+ */
+#ifdef _KERNEL
+ if (pass & FR_RETICMP) {
+# if SOLARIS
+ icmp_error(q, ip, ICMP_UNREACH, ipl_unreach, qif,
+ ip->ip_src);
+# else
+ struct mbuf *copy;
+
+ copy = m_copy(dtom(ip), 0, imin((int)ip->ip_len, 64));
+# if BSD < 199103
+ icmp_error(mtod(copy, struct ip *),
+ ICMP_UNREACH, ipl_unreach, ifp, ip->ip_src);
+# else
+ icmp_error(copy, ICMP_UNREACH, ipl_unreach,
+ ip->ip_src.s_addr, ifp);
+# endif
+# endif
+ frstats[0].fr_ret++;
+ } else if (pass & FR_RETRST && IPMINLEN(ip, tcphdr)) {
+# if SOLARIS
+ if (send_reset(ip, qif, q) == 0)
+# else
+ if (send_reset(ip) == 0)
+# endif
+ frstats[1].fr_ret++;
+ }
+#else
+ if (pass & FR_RETICMP) {
+ verbose("- ICMP unreachable sent\n");
+ frstats[0].fr_ret++;
+ } else if (pass & FR_RETRST && IPMINLEN(ip, tcphdr)) {
+ verbose("- TCP RST sent\n");
+ frstats[1].fr_ret++;
+ }
+#endif
+ }
+#ifdef _KERNEL
+ return (pass & FR_PASS) ? 0 : -1;
+#else
+ if (pass & FR_NOMATCH)
+ return 1;
+ if (pass & FR_PASS)
+ return 0;
+ return -1;
+#endif
+}
+
+
+#ifndef _KERNEL
+int ipllog()
+{
+ verbose("l");
+ return 1;
+}
+#endif
diff --git a/usr.sbin/ipftest/ipft_ef.c b/usr.sbin/ipftest/ipft_ef.c
new file mode 100644
index 00000000000..fb8f67215b8
--- /dev/null
+++ b/usr.sbin/ipftest/ipft_ef.c
@@ -0,0 +1,157 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+
+/*
+ icmp type
+ lnth proto source destination src port dst port
+
+etherfind -n
+
+ 60 tcp 128.250.20.20 128.250.133.13 2419 telnet
+
+etherfind -n -t
+
+ 0.32 91 04 131.170.1.10 128.250.133.13
+ 0.33 566 udp 128.250.37.155 128.250.133.3 901 901
+*/
+#include <stdio.h>
+#include <string.h>
+#if !defined(__SVR4) && !defined(__GNUC__)
+#include <strings.h>
+#endif
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcpip.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <netinet/ip_fil.h>
+#include "ipf.h"
+#include "ipt.h"
+
+#ifndef lint
+static char sccsid[] = "@(#)ipft_ef.c 1.5 10/15/95 (C)1995 Darren Reed";
+#endif
+
+static int etherf_open(), etherf_close(), etherf_readip();
+
+struct ipread etherf = { etherf_open, etherf_close, etherf_readip };
+
+static FILE *efp = NULL;
+static int efd = -1;
+
+#ifdef NEED_INET_ATON
+extern u_long inet_aton();
+#else
+#include <arpa/inet.h>
+#endif
+
+static int etherf_open(fname)
+char *fname;
+{
+ if (efd != -1)
+ return efd;
+
+ if (!strcmp(fname, "-")) {
+ efd = 0;
+ efp = stdin;
+ } else {
+ efd = open(fname, O_RDONLY);
+ efp = fdopen(efd, "r");
+ }
+ return efd;
+}
+
+
+static int etherf_close()
+{
+ return close(efd);
+}
+
+
+static int etherf_readip(buf, cnt, ifn, dir)
+char *buf, **ifn;
+int cnt, *dir;
+{
+ struct tcpiphdr pkt;
+ struct ip *ip = (struct ip *)&pkt;
+ struct protoent *p = NULL;
+ char src[16], dst[16], sprt[16], dprt[16];
+ char lbuf[128], len[8], prot[8], time[8], *s;
+ int slen, extra = 0, i, n;
+
+ if (!fgets(lbuf, sizeof(lbuf) - 1, efp))
+ return 0;
+
+ if ((s = strchr(lbuf, '\n')))
+ *s = '\0';
+ lbuf[sizeof(lbuf)-1] = '\0';
+
+ bzero(&pkt, sizeof(pkt));
+
+ if ((n = sscanf(lbuf, "%s %s %s %s %s %s", len, prot, src, dst,
+ sprt, dprt)) != 6)
+ if ((n = sscanf(lbuf, "%s %s %s %s %s %s %s", time,
+ len, prot, src, dst, sprt, dprt)) != 7)
+ return -1;
+
+ ip->ip_p = atoi(prot);
+ if (ip->ip_p == 0) {
+ if (!(p = getprotobyname(prot)))
+ return -1;
+ ip->ip_p = p->p_proto;
+ }
+
+ switch (ip->ip_p) {
+ case IPPROTO_TCP :
+ case IPPROTO_UDP :
+ s = strtok(NULL, " :");
+ ip->ip_len += atoi(s);
+ if (p->p_proto == IPPROTO_TCP)
+ extra = sizeof(struct tcphdr);
+ else if (p->p_proto == IPPROTO_UDP)
+ extra = sizeof(struct udphdr);
+ break;
+#ifdef IGMP
+ case IPPROTO_IGMP :
+ extra = sizeof(struct igmp);
+ break;
+#endif
+ case IPPROTO_ICMP :
+ extra = sizeof(struct icmp);
+ break;
+ default :
+ break;
+ }
+
+#ifdef NEED_INET_ATON
+ ip->ip_src.s_addr = inet_aton(src);
+ ip->ip_dst.s_addr = inet_aton(dst);
+#else
+ (void) inet_aton(src, &ip->ip_src);
+ (void) inet_aton(dst, &ip->ip_dst);
+#endif
+ ip->ip_len = atoi(len);
+ ip->ip_hl = sizeof(struct ip);
+
+ slen = ip->ip_hl + extra;
+ i = MIN(cnt, slen);
+ bcopy((char *)&pkt, buf, i);
+ return i;
+}
diff --git a/usr.sbin/ipftest/ipft_pc.c b/usr.sbin/ipftest/ipft_pc.c
new file mode 100644
index 00000000000..06af91f4897
--- /dev/null
+++ b/usr.sbin/ipftest/ipft_pc.c
@@ -0,0 +1,189 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+#include <stdio.h>
+#include <string.h>
+#if !defined(__SVR4) && !defined(__GNUC__)
+#include <strings.h>
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <net/if.h>
+#include <netinet/ip_fil.h>
+#include "ipf.h"
+#include "ipt.h"
+#include "pcap.h"
+
+struct llc {
+ int lc_sz; /* LLC header length */
+ int lc_to; /* LLC Type offset */
+ int lc_tl; /* LLC Type length */
+};
+
+/*
+ * While many of these maybe the same, some do have different header formats
+ * which make this useful.
+ */
+#define DLT_MAX 10
+
+static struct llc llcs[DLT_MAX+1] = {
+ { 0, 0, 0 }, /* DLT_NULL */
+ { 14, 12, 2 }, /* DLT_E10MB */
+ { 0, 0, 0 }, /* DLT_EN3MB */
+ { 0, 0, 0 }, /* DLT_AX25 */
+ { 0, 0, 0 }, /* DLT_PRONET */
+ { 0, 0, 0 }, /* DLT_CHAOS */
+ { 0, 0, 0 }, /* DLT_IEEE802 */
+ { 0, 0, 0 }, /* DLT_ARCNET */
+ { 0, 0, 0 }, /* DLT_SLIP */
+ { 0, 0, 0 }, /* DLT_PPP */
+ { 0, 0, 0 } /* DLT_FDDI */
+};
+
+static int pcap_open(), pcap_close(), pcap_readip();
+
+static int pfd = -1, s_type = -1;
+
+struct ipread pcap = { pcap_open, pcap_close, pcap_readip };
+
+
+static int pcap_open(fname)
+char *fname;
+{
+ pcaphdr_t ph;
+ int fd;
+
+ if (pfd != -1)
+ return pfd;
+
+ if (!strcmp(fname, "-"))
+ fd = 0;
+ else if ((fd = open(fname, O_RDONLY)) == -1)
+ return -1;
+
+ if (read(fd, (char *)&ph, sizeof(ph)) != sizeof(ph))
+ return -2;
+
+ if (ph.pc_v_maj != PCAP_VERSION_MAJ || ph.pc_type > DLT_MAX) {
+ (void) close(fd);
+ return -2;
+ }
+
+ pfd = fd;
+ s_type = ph.pc_type;
+ printf("opened pcap file %s:\n", fname);
+ printf("\tid: %08x version: %d.%d type: %d snap %d\n",
+ ph.pc_id, ph.pc_v_maj, ph.pc_v_min, ph.pc_type, ph.pc_slen);
+
+ return fd;
+}
+
+
+static int pcap_close()
+{
+ return close(pfd);
+}
+
+
+/*
+ * read in the header (and validate) which should be the first record
+ * in a pcap file.
+ */
+static int pcap_read_rec(rec)
+struct pcap_pkthdr *rec;
+{
+ int n, p;
+
+ if (read(pfd, (char *)rec, sizeof(*rec)) != sizeof(*rec))
+ return -2;
+
+ p = rec->ph_clen;
+ n = MIN(p, rec->ph_len);
+ if (!n || n < 0)
+ return -3;
+
+ return p;
+}
+
+
+/*
+ * read an entire pcap packet record. only the data part is copied into
+ * the available buffer, with the number of bytes copied returned.
+ */
+static int pcap_read(buf, cnt)
+char *buf;
+int cnt;
+{
+ struct pcap_pkthdr rec;
+ static char *bufp = NULL;
+ int i, n;
+
+ if ((i = pcap_read_rec(&rec)) <= 0)
+ return i;
+
+ if (!bufp)
+ bufp = malloc(i);
+ else
+ bufp = realloc(bufp, i);
+
+ if (read(pfd, bufp, i) != i)
+ return -2;
+
+ n = MIN(i, cnt);
+ bcopy(bufp, buf, n);
+ return n;
+}
+
+
+/*
+ * return only an IP packet read into buf
+ */
+static int pcap_readip(buf, cnt, ifn, dir)
+char *buf, **ifn;
+int cnt, *dir;
+{
+ static char *bufp = NULL;
+ struct pcap_pkthdr rec;
+ struct llc *l;
+ char *s, ty[4];
+ int i, n;
+
+ do {
+ if ((i = pcap_read_rec(&rec)) <= 0)
+ return i;
+
+ if (!bufp)
+ bufp = malloc(i);
+ else
+ bufp = realloc(bufp, i);
+ s = bufp;
+
+ if (read(pfd, s, i) != i)
+ return -2;
+
+ l = &llcs[s_type];
+ i -= l->lc_sz;
+ s += l->lc_to;
+ bcopy(s, ty, l->lc_tl);
+ s += l->lc_tl;
+ } while (ty[0] != 0x8 && ty[1] != 0);
+ n = MIN(i, cnt);
+ bcopy(s, buf, n);
+ return n;
+}
diff --git a/usr.sbin/ipftest/ipft_sn.c b/usr.sbin/ipftest/ipft_sn.c
new file mode 100644
index 00000000000..b94a477e61b
--- /dev/null
+++ b/usr.sbin/ipftest/ipft_sn.c
@@ -0,0 +1,201 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+
+/*
+ * Written to comply with the recent RFC 1761 from Sun.
+ */
+#include <stdio.h>
+#include <string.h>
+#if !defined(__SVR4) && !defined(__GNUC__)
+#include <strings.h>
+#endif
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <net/if.h>
+#include <netinet/ip_fil.h>
+#include "ipf.h"
+#include "ipt.h"
+#include "snoop.h"
+
+struct llc {
+ int lc_sz; /* LLC header length */
+ int lc_to; /* LLC Type offset */
+ int lc_tl; /* LLC Type length */
+};
+
+/*
+ * While many of these maybe the same, some do have different header formats
+ * which make this useful.
+ */
+static struct llc llcs[SDL_MAX+1] = {
+ { 0, 0, 0 }, /* SDL_8023 */
+ { 0, 0, 0 }, /* SDL_8024 */
+ { 0, 0, 0 }, /* SDL_8025 */
+ { 0, 0, 0 }, /* SDL_8026 */
+ { 14, 12, 2 }, /* SDL_ETHER */
+ { 0, 0, 0 }, /* SDL_HDLC */
+ { 0, 0, 0 }, /* SDL_CHSYNC */
+ { 0, 0, 0 }, /* SDL_IBMCC */
+ { 0, 0, 0 }, /* SDL_FDDI */
+ { 0, 0, 0 }, /* SDL_OTHER */
+};
+
+static int snoop_open(), snoop_close(), snoop_readip();
+
+static int sfd = -1, s_type = -1;
+
+struct ipread snoop = { snoop_open, snoop_close, snoop_readip };
+
+
+static int snoop_open(fname)
+char *fname;
+{
+ struct snoophdr sh;
+ int fd;
+
+ if (sfd != -1)
+ return sfd;
+
+ if (!strcmp(fname, "-"))
+ fd = 0;
+ else if ((fd = open(fname, O_RDONLY)) == -1)
+ return -1;
+
+ if (read(fd, (char *)&sh, sizeof(sh)) != sizeof(sh))
+ return -2;
+
+ if (sh.s_v != SNOOP_VERSION ||
+ sh.s_type < 0 || sh.s_type > SDL_MAX) {
+ (void) close(fd);
+ return -2;
+ }
+
+ sfd = fd;
+ s_type = sh.s_type;
+ printf("opened snoop file %s:\n", fname);
+ printf("\tid: %8.8s version: %d type: %d\n", sh.s_id, sh.s_v, s_type);
+
+ return fd;
+}
+
+
+static int snoop_close()
+{
+ return close(sfd);
+}
+
+
+/*
+ * read in the header (and validate) which should be the first record
+ * in a snoop file.
+ */
+static int snoop_read_rec(rec)
+struct snooppkt *rec;
+{
+ int n, p;
+
+ if (read(sfd, (char *)rec, sizeof(*rec)) != sizeof(*rec))
+ return -2;
+
+ if (rec->sp_ilen > rec->sp_plen || rec->sp_plen < sizeof(*rec))
+ return -2;
+
+ p = rec->sp_plen - sizeof(*rec);
+ n = MIN(p, rec->sp_ilen);
+ if (!n || n < 0)
+ return -3;
+
+ return p;
+}
+
+
+/*
+ * read an entire snoop packet record. only the data part is copied into
+ * the available buffer, with the number of bytes copied returned.
+ */
+static int snoop_read(buf, cnt)
+char *buf;
+int cnt;
+{
+ struct snooppkt rec;
+ static char *bufp = NULL;
+ int i, n;
+
+ if ((i = snoop_read_rec(&rec)) <= 0)
+ return i;
+
+ if (!bufp)
+ bufp = malloc(i);
+ else
+ bufp = realloc(bufp, i);
+
+ if (read(sfd, bufp, i) != i)
+ return -2;
+
+ n = MIN(i, cnt);
+ bcopy(bufp, buf, n);
+ return n;
+}
+
+
+/*
+ * return only an IP packet read into buf
+ */
+static int snoop_readip(buf, cnt, ifn, dir)
+char *buf, **ifn;
+int cnt, *dir;
+{
+ static char *bufp = NULL;
+ struct snooppkt rec;
+ struct llc *l;
+ char ty[4], *s;
+ int i, n;
+
+ do {
+ if ((i = snoop_read_rec(&rec)) <= 0)
+ return i;
+
+ if (!bufp)
+ bufp = malloc(i);
+ else
+ bufp = realloc(bufp, i);
+ s = bufp;
+
+ if (read(sfd, s, i) != i)
+ return -2;
+
+ l = &llcs[s_type];
+ i -= l->lc_to;
+ s += l->lc_to;
+ /*
+ * XXX - bogus assumption here on the part of the time field
+ * that it won't be greater than 4 bytes and the 1st two will
+ * have the values 8 and 0 for IP. Should be a table of
+ * these too somewhere. Really only works for SDL_ETHER.
+ */
+ bcopy(s, ty, l->lc_tl);
+ } while (ty[0] != 0x8 && ty[1] != 0);
+
+ i -= l->lc_tl;
+ s += l->lc_tl;
+ n = MIN(i, cnt);
+ bcopy(s, buf, n);
+
+ return n;
+}
diff --git a/usr.sbin/ipftest/ipft_td.c b/usr.sbin/ipftest/ipft_td.c
new file mode 100644
index 00000000000..3ddee115192
--- /dev/null
+++ b/usr.sbin/ipftest/ipft_td.c
@@ -0,0 +1,201 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+
+/*
+tcpdump -n
+
+00:05:47.816843 128.231.76.76.3291 > 224.2.252.231.36573: udp 36 (encap)
+
+tcpdump -nq
+
+00:33:48.410771 192.73.213.11.1463 > 224.2.248.153.59360: udp 31 (encap)
+
+tcpdump -nqt
+
+128.250.133.13.23 > 128.250.20.20.2419: tcp 27
+
+tcpdump -nqtt
+
+123456789.1234567 128.250.133.13.23 > 128.250.20.20.2419: tcp 27
+
+tcpdump -nqte
+
+8:0:20:f:65:f7 0:0:c:1:8a:c5 81: 128.250.133.13.23 > 128.250.20.20.2419: tcp 27
+
+*/
+#include <stdio.h>
+#include <string.h>
+#if !defined(__SVR4) && !defined(__GNUC__)
+#include <strings.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcpip.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <netinet/ip_fil.h>
+#include "ipf.h"
+#include "ipt.h"
+
+#ifndef lint
+static char sccsid[] = "@(#)ipft_td.c 1.6 10/15/95 (C)1995 Darren Reed";
+#endif
+
+static int tcpd_open(), tcpd_close(), tcpd_readip();
+#ifdef NEED_INET_ATON
+static u_long inet_aton();
+#else
+#include <arpa/inet.h>
+#endif
+
+struct ipread tcpd = { tcpd_open, tcpd_close, tcpd_readip };
+
+static FILE *tfp = NULL;
+static int tfd = -1;
+
+
+static int tcpd_open(fname)
+char *fname;
+{
+ if (tfd != -1)
+ return tfd;
+
+ if (!strcmp(fname, "-")) {
+ tfd = 0;
+ tfp = stdin;
+ } else {
+ tfd = open(fname, O_RDONLY);
+ tfp = fdopen(tfd, "r");
+ }
+ return tfd;
+}
+
+
+static int tcpd_close()
+{
+ (void) fclose(tfp);
+ return close(tfd);
+}
+
+
+static int count_dots(str)
+char *str;
+{
+ int i = 0;
+
+ while (*str)
+ if (*str++ == '.')
+ i++;
+ return i;
+}
+
+
+static int tcpd_readip(buf, cnt, ifn, dir)
+char *buf, **ifn;
+int cnt, *dir;
+{
+ struct tcpiphdr pkt;
+ struct ip *ip = (struct ip *)&pkt;
+ struct protoent *p;
+ char src[32], dst[32], misc[256], time[32], link1[32], link2[32];
+ char lbuf[160], *s;
+ int n, dots, slen, extra = 0;
+
+ if (!fgets(lbuf, sizeof(lbuf) - 1, tfp))
+ return 0;
+
+ if ((s = strchr(lbuf, '\n')))
+ *s = '\0';
+ lbuf[sizeof(lbuf)-1] = '\0';
+
+ bzero(&pkt, sizeof(pkt));
+
+ if ((n = sscanf(lbuf, "%s > %s: %s", src, dst, misc)) != 3)
+ if ((n = sscanf(lbuf, "%s %s > %s: %s",
+ time, src, dst, misc)) != 4)
+ if ((n = sscanf(lbuf, "%s %s: %s > %s: %s",
+ link1, link2, src, dst, misc)) != 5) {
+ n = sscanf(lbuf, "%s %s %s: %s > %s: %s",
+ time, link1, link2, src, dst, misc);
+ if (n != 6)
+ return -1;
+ }
+
+ if ((dots = count_dots(dst)) == 4) {
+ s = strrchr(src, '.');
+ *s++ = '\0';
+#ifdef NEED_INET_ATON
+ ip->ip_src.s_addr = inet_aton(src);
+#else
+ (void) inet_aton(src, &ip->ip_src);
+#endif
+ pkt.ti_sport = htons(atoi(s));
+ *--s = '.';
+ s = strrchr(dst, '.');
+
+ *s++ = '\0';
+#ifdef NEED_INET_ATON
+ ip->ip_dst.s_addr = inet_aton(dst);
+#else
+ (void) inet_aton(src, &ip->ip_dst);
+#endif
+ pkt.ti_dport = htons(atoi(s));
+ *--s = '.';
+
+ } else {
+#ifdef NEED_INET_ATON
+ ip->ip_src.s_addr = inet_aton(src);
+ ip->ip_dst.s_addr = inet_aton(dst);
+#else
+ (void) inet_aton(src, &ip->ip_src);
+ (void) inet_aton(src, &ip->ip_dst);
+#endif
+ }
+ ip->ip_len = ip->ip_hl = sizeof(struct ip);
+
+ s = strtok(misc, " :");
+ if ((p = getprotobyname(s))) {
+ ip->ip_p = p->p_proto;
+
+ switch (p->p_proto) {
+ case IPPROTO_TCP :
+ case IPPROTO_UDP :
+ s = strtok(NULL, " :");
+ ip->ip_len += atoi(s);
+ if (p->p_proto == IPPROTO_TCP)
+ extra = sizeof(struct tcphdr);
+ else if (p->p_proto == IPPROTO_UDP)
+ extra = sizeof(struct udphdr);
+ break;
+#ifdef IGMP
+ case IPPROTO_IGMP :
+ extra = sizeof(struct igmp);
+ break;
+#endif
+ case IPPROTO_ICMP :
+ extra = sizeof(struct icmp);
+ break;
+ default :
+ break;
+ }
+ }
+ slen = ip->ip_hl + extra + ip->ip_len;
+ return slen;
+}
diff --git a/usr.sbin/ipftest/ipft_tx.c b/usr.sbin/ipftest/ipft_tx.c
new file mode 100644
index 00000000000..4ca44a8380e
--- /dev/null
+++ b/usr.sbin/ipftest/ipft_tx.c
@@ -0,0 +1,248 @@
+/*
+ * (C)opyright 1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+#include <strings.h>
+#else
+#include <sys/byteorder.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcpip.h>
+#include <net/if.h>
+#include <netinet/ip_fil.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include "ipf.h"
+#include "ipt.h"
+
+#ifndef lint
+static char sccsid[] = "@(#)ipft_tx.c 1.2 10/17/95 (C) 1993 Darren Reed";
+#endif
+
+extern int opts;
+
+static int text_open(), text_close(), text_readip(), parseline();
+
+struct ipread iptext = { text_open, text_close, text_readip };
+static FILE *tfp = NULL;
+static int tfd = -1;
+
+static int text_open(fname)
+char *fname;
+{
+ if (tfp && tfd != -1) {
+ rewind(tfp);
+ return tfd;
+ }
+
+ if (!strcmp(fname, "-")) {
+ tfd = 0;
+ tfp = stdin;
+ } else {
+ tfd = open(fname, O_RDONLY);
+ if (tfd != -1)
+ tfp = fdopen(tfd, "r");
+ }
+ return tfd;
+}
+
+
+static int text_close()
+{
+ int cfd = tfd;
+
+ tfd = -1;
+ return close(cfd);
+}
+
+
+static int text_readip(buf, cnt, ifn, dir)
+char *buf, **ifn;
+int cnt, *dir;
+{
+ register char *s;
+ struct ip *ip;
+ char line[513];
+
+ ip = (struct ip *)buf;
+ *ifn = NULL;
+ while (fgets(line, sizeof(line)-1, tfp)) {
+ if ((s = index(line, '\n')))
+ *s = '\0';
+ if ((s = index(line, '\r')))
+ *s = '\0';
+ if ((s = index(line, '#')))
+ *s = '\0';
+ if (!*line)
+ continue;
+ if (!(opts & OPT_BRIEF))
+ printf("input: %s\n", line);
+ *ifn = NULL;
+ *dir = 0;
+ if (!parseline(line, buf, ifn, dir))
+#if 0
+ return sizeof(struct tcpiphdr);
+#else
+ return sizeof(struct ip);
+#endif
+ }
+ return -1;
+}
+
+static int parseline(line, ip, ifn, out)
+char *line;
+struct ip *ip;
+char **ifn;
+int *out;
+{
+ extern char *proto;
+ tcphdr_t th, *tcp = &th;
+ struct icmp icmp, *ic = &icmp;
+ char *cps[20], **cpp, c, opts[68];
+ int i;
+
+ bzero((char *)ip, MAX(sizeof(*tcp), sizeof(*ic)) + sizeof(*ip));
+ bzero((char *)tcp, sizeof(*tcp));
+ bzero((char *)ic, sizeof(*ic));
+ bzero(opts, sizeof(opts));
+ ip->ip_hl = sizeof(*ip) >> 2;
+ ip->ip_v = IPVERSION;
+ for (i = 0, cps[0] = strtok(line, " \b\t\r\n"); cps[i] && i < 19; )
+ cps[++i] = strtok(NULL, " \b\t\r\n");
+ if (i < 2)
+ return 1;
+
+ cpp = cps;
+
+ c = **cpp;
+ if (!isalpha(c) || (tolower(c) != 'o' && tolower(c) != 'i')) {
+ fprintf(stderr, "bad direction \"%s\"\n", *cpp);
+ return 1;
+ }
+ *out = (tolower(c) == 'o') ? 1 : 0;
+ cpp++;
+
+ if (!strcasecmp(*cpp, "on")) {
+ cpp++;
+ if (!*cpp)
+ return 1;
+ *ifn = *cpp++;
+ }
+
+ c = **cpp;
+ ip->ip_len = sizeof(struct ip);
+ if (!strcasecmp(*cpp, "tcp") || !strcasecmp(*cpp, "udp") ||
+ !strcasecmp(*cpp, "icmp")) {
+ if (c == 't') {
+ ip->ip_p = IPPROTO_TCP;
+ ip->ip_len += sizeof(struct tcphdr);
+ proto = "tcp";
+ } else if (c == 'u') {
+ ip->ip_p = IPPROTO_UDP;
+ ip->ip_len += sizeof(struct udphdr);
+ proto = "udp";
+ } else {
+ ip->ip_p = IPPROTO_ICMP;
+ ip->ip_len += sizeof(struct icmp);
+ proto = "icmp";
+ }
+ cpp++;
+ } else
+ ip->ip_p = IPPROTO_IP;
+
+ if (!*cpp)
+ return 1;
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) {
+ char *last;
+
+ last = index(*cpp, ',');
+ if (!last) {
+ fprintf(stderr, "tcp/udp with no source port\n");
+ return 1;
+ }
+ *last++ = '\0';
+ tcp->th_sport = portnum(last);
+ }
+ ip->ip_src.s_addr = hostnum(*cpp);
+ cpp++;
+ if (!*cpp)
+ return 1;
+
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) {
+ char *last;
+
+ last = index(*cpp, ',');
+ if (!last) {
+ fprintf(stderr, "tcp/udp with no destination port\n");
+ return 1;
+ }
+ *last++ = '\0';
+ tcp->th_dport = portnum(last);
+ }
+ ip->ip_dst.s_addr = hostnum(*cpp);
+ cpp++;
+ if (*cpp && ip->ip_p == IPPROTO_TCP) {
+ extern char flagset[];
+ extern u_char flags[];
+ char *s, *t;
+
+ for (s = *cpp; *s; s++)
+ if ((t = index(flagset, *s)))
+ tcp->th_flags |= flags[t - flagset];
+ if (tcp->th_flags)
+ cpp++;
+ assert(tcp->th_flags != 0);
+ } else if (*cpp && ip->ip_p == IPPROTO_ICMP) {
+ extern char *icmptypes[];
+ char **s, *t;
+ int i;
+
+ for (s = icmptypes, i = 0; !*s || strcmp(*s, "END"); s++, i++)
+ if (*s && !strncasecmp(*cpp, *s, strlen(*s))) {
+ ic->icmp_type = i;
+ if ((t = index(*cpp, ',')))
+ ic->icmp_code = atoi(t+1);
+ cpp++;
+ break;
+ }
+ }
+
+ if (*cpp && !strcasecmp(*cpp, "opt")) {
+ u_long olen;
+
+ cpp++;
+ olen = buildopts(*cpp, opts);
+ if (olen) {
+ bcopy(opts, (char *)(ip + 1), olen);
+ ip->ip_hl += olen >> 2;
+ }
+ }
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
+ bcopy((char *)tcp, ((char *)ip) + (ip->ip_hl << 2),
+ sizeof(*tcp));
+ else if (ip->ip_p == IPPROTO_ICMP)
+ bcopy((char *)ic, ((char *)ip) + (ip->ip_hl << 2),
+ sizeof(*ic));
+ return 0;
+}
diff --git a/usr.sbin/ipftest/ipftest.1 b/usr.sbin/ipftest/ipftest.1
new file mode 100644
index 00000000000..2e6991a0d09
--- /dev/null
+++ b/usr.sbin/ipftest/ipftest.1
@@ -0,0 +1,99 @@
+.LP
+.TH ipftest 8
+.SH NAME
+ipftest - test packet filter rules with arbitary input.
+.SH SYNOPSIS
+ipftest [-vbdPSTE] [-I interface] -r <filename> [-i <filename>]
+.SH DESCRIPTION
+.LP
+.PP
+\fBipftest\fP is provided for the purpose of being able to test a set of
+filter rules without having to put them in place, in operation and procede
+to test their effectiveness. The hope is that this minimises disruptions
+in providing a secure IP environment.
+.PP
+\fBipftest\fP will parse any standard ruleset for use with \fBipf\fP
+and apply input, returning output as to the result. However, \fBipftest\fP
+will return one of three values for packets passed through the filter:
+pass, block or nomatch. This is intended to give the operator a better
+idea of what is happening with packets passing through their filter
+ruleset.
+.PP
+When used without eiether of \fB-S\fP, \fB-T\fP or \fB-E\fP,
+\fBipftest\fP uses its own text input format to generate "fake" IP packets.
+The format used is as follows:
+.nf
+ "in"|"out" "on" if ["tcp"|"udp"|"icmp"]
+ srchost[,srcport] dsthost[,destport] [FSRPAU]
+.fi
+.PP
+This allows for a packet going "in" or "out" of an interface (if) to be
+generated, being one of the three main protocols (optionally), and if
+either TCP or UDP, a port parameter is also expected. If TCP is selected,
+it is possible to (optionally) supply TCP flags at the end. Some examples
+are:
+.nf
+ # a UDP packet coming in on le0
+ in on le0 udp 10.1.1.1,2210 10.2.1.5,23
+ # an IP packet coming in on le0 from localhost - hmm :)
+ in on le0 localhost 10.4.12.1
+ # a TCP packet going out of le0 with the SYN flag set.
+ out on le0 tcp 10.4.12.1,2245 10.1.1.1,23 S
+.fi
+.SH OPTIONS
+.IP -v
+Verbose mode. This provides more information about which parts of rule
+matching the input packet passes and fails.
+.IP -d
+Turn on filter rule debugging. Currently, this only shows you what caused
+the rule to not match in the IP header checking (addresses/netmasks, etc).
+.IP -b
+Cause the output to be a brief summary (one-word) of the result of passing
+the packet through the filter; either "pass", "block" or "nomatch".
+This is used in the regression testing.
+.IP -I <interface>
+Set the interface name (used in rule matching) to be the name supplied.
+This is useful with the \fB-P, -S, -T\fP and \fB-E\fP options, where it is
+not otherwise possible to associate a packet with an interface. Normal
+"text packets" can override this setting.
+.IP -P
+The input file specified by \fB-i\fP is a binary file produced using libpcap
+(ie tcpdump version 3). Packets are read from this file as being input
+(for rule purposes). An interface maybe specified using \fB-I\fP.
+.IP -S
+The input file is to be in "snoop" format (see RFC 1761). Packets are read
+from this file and used as input from any interface. This is perhaps the
+most useful input type, currently.
+.IP -T
+The input file is to be text output from tcpdump. The text formats which
+are currently supported are those which result from the following tcpdump
+option combinations:
+.PP
+.nf
+ tcpdump -n
+ tcpdump -nq
+ tcpdump -nqt
+ tcpdump -nqtt
+ tcpdump -nqte
+.fi
+.LP
+.IP -E
+The input file is to be text output from etherfind. The text formats which
+are currently supported are those which result from the following etherfind
+option combinations:
+.PP
+.nf
+ etherfind -n
+ etherfind -n -t
+.fi
+.LP
+.IP -i <filename>
+Specify the filename to take input from. Default is stdin.
+.IP -r <filename>
+Specify the filename from which to read filter rules.
+.SH FILES
+.SH SEE ALSO
+ipf(1), ipf(5), snoop(1m), tcpdump(8), etherfind(8c)
+.SH BUGS
+Not all of the input formats are sufficiently capable of introducing a
+wide enough variety of packets for them to be all useful in testing.
diff --git a/usr.sbin/ipftest/ipt.c b/usr.sbin/ipftest/ipt.c
new file mode 100644
index 00000000000..bbb5d2a3e5f
--- /dev/null
+++ b/usr.sbin/ipftest/ipt.c
@@ -0,0 +1,197 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+#include <strings.h>
+#else
+#include <sys/byteorder.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcpip.h>
+#include <net/if.h>
+#include <netinet/ip_fil.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include "ipf.h"
+#include "ipt.h"
+#include <ctype.h>
+
+#ifndef lint
+static char sccsid[] = "@(#)ipt.c 1.13 11/11/95 (C) 1993 Darren Reed";
+#endif
+
+extern int fr_check();
+extern char *optarg;
+extern struct frentry *filterin[], *filterout[];
+extern struct ipread snoop, etherf, tcpd, pcap, iptext;
+extern void debug(), verbose();
+
+struct frentry *ft_in = NULL, *ft_out = NULL;
+struct ipread *readers[] = { &iptext, &etherf, &tcpd, &snoop, &pcap, NULL };
+
+int opts = 0;
+
+int main(argc,argv)
+int argc;
+char *argv[];
+{
+ struct ipread **r = readers;
+ struct frentry *f;
+ struct ip *ip;
+ u_long buf[64];
+ char c;
+ char *rules = NULL, *datain = NULL, *iface = NULL;
+ int fd, i, dir = 0;
+
+ while ((c = getopt(argc, argv, "I:PSTEbdi:r:v")) != -1)
+ switch (c)
+ {
+ case 'b' :
+ opts |= OPT_BRIEF;
+ break;
+ case 'd' :
+ opts |= OPT_DEBUG;
+ break;
+ case 'i' :
+ datain = optarg;
+ break;
+ case 'I' :
+ iface = optarg;
+ break;
+ case 'r' :
+ rules = optarg;
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ case 'E' :
+ for (i = 0, r = readers; *r; i++, r++)
+ if (*r == &etherf)
+ break;
+ break;
+ case 'P' :
+ for (i = 0, r = readers; *r; i++, r++)
+ if (*r == &pcap)
+ break;
+ break;
+ case 'S' :
+ for (i = 0, r = readers; *r; i++, r++)
+ if (*r == &snoop)
+ break;
+ break;
+ case 'T' :
+ for (i = 0, r = readers; *r; i++, r++)
+ if (*r == &tcpd)
+ break;
+ break;
+ }
+
+ if (!rules) {
+ (void)fprintf(stderr,"no rule file present\n");
+ exit(-1);
+ }
+
+ if (rules) {
+ struct frentry *fr;
+ char line[513], *s;
+ FILE *fp;
+
+ if (!strcmp(rules, "-"))
+ fp = stdin;
+ else if (!(fp = fopen(rules, "r"))) {
+ (void)fprintf(stderr, "couldn't open %s\n", rules);
+ exit(-1);
+ }
+ if (!(opts & OPT_BRIEF))
+ (void)printf("opening rule file \"%s\"\n", rules);
+ while (fgets(line, sizeof(line)-1, fp)) {
+ /*
+ * treat both CR and LF as EOL
+ */
+ if ((s = index(line, '\n')))
+ *s = '\0';
+ if ((s = index(line, '\r')))
+ *s = '\0';
+ /*
+ * # is comment marker, everything after is a ignored
+ */
+ if ((s = index(line, '#')))
+ *s = '\0';
+
+ if (!*line)
+ continue;
+
+ if (!(fr = parse(line)))
+ continue;
+ f = (struct frentry *)malloc(sizeof(*f));
+ if (fr->fr_flags & FR_INQUE) {
+ if (!ft_in)
+ ft_in = filterin[0] = f;
+ else
+ ft_in->fr_next = f, ft_in = f;
+ } else if (fr->fr_flags & FR_OUTQUE) {
+ if (!ft_out)
+ ft_out = filterout[0] = f;
+ else
+ ft_out->fr_next = f, ft_out = f;
+ }
+ bcopy((char *)fr, (char *)f, sizeof(*fr));
+ }
+ (void)fclose(fp);
+ }
+
+ if (datain)
+ fd = (*(*r)->r_open)(datain);
+ else
+ fd = (*(*r)->r_open)("-");
+
+ if (fd < 0)
+ exit(-1);
+
+ ip = (struct ip *)buf;
+ while ((i = (*(*r)->r_readip)(buf, sizeof(buf), &iface, &dir)) > 0) {
+ switch (fr_check(ip, ip->ip_hl << 2, iface, dir))
+ {
+ case -1 :
+ (void)printf("block");
+ break;
+ case 0 :
+ (void)printf("pass");
+ break;
+ case 1 :
+ (void)printf("nomatch");
+ break;
+ }
+ if (!(opts & OPT_BRIEF)) {
+ putchar(' ');
+ printpacket(buf);
+ printf("--------------");
+ }
+ putchar('\n');
+ dir = 0;
+ }
+ (*(*r)->r_close)();
+ return 0;
+}
diff --git a/usr.sbin/ipftest/ipt.h b/usr.sbin/ipftest/ipt.h
new file mode 100644
index 00000000000..fd0e5acf3e0
--- /dev/null
+++ b/usr.sbin/ipftest/ipt.h
@@ -0,0 +1,15 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+
+#include <fcntl.h>
+
+struct ipread {
+ int (*r_open)();
+ int (*r_close)();
+ int (*r_readip)();
+};
diff --git a/usr.sbin/ipftest/misc.c b/usr.sbin/ipftest/misc.c
new file mode 100644
index 00000000000..89a9883c4d7
--- /dev/null
+++ b/usr.sbin/ipftest/misc.c
@@ -0,0 +1,103 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+#include <strings.h>
+#else
+#include <sys/byteorder.h>
+#endif
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcpip.h>
+#include <net/if.h>
+#include <netinet/ip_fil.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include "ipf.h"
+#include "ipt.h"
+
+#ifndef lint
+static char sccsid[] = "@(#)misc.c 1.1 10/15/95 (C) 1995 Darren Reed";
+#endif
+
+void debug(), verbose();
+
+extern int opts;
+
+
+void printpacket(ip)
+struct ip *ip;
+{
+ struct tcphdr *tcp;
+
+ tcp = (struct tcphdr *)((char *)ip + (ip->ip_hl << 2));
+ printf("ip %d(%d) %d ", ip->ip_len, ip->ip_hl << 2, ip->ip_p);
+ if (ip->ip_off & 0x1fff)
+ printf("@%d", ip->ip_off << 3);
+ (void)printf(" %s", inet_ntoa(ip->ip_src));
+ if (!(ip->ip_off & 0x1fff))
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
+ (void)printf(",%d", ntohs(tcp->th_sport));
+ (void)printf(" > ");
+ (void)printf("%s", inet_ntoa(ip->ip_dst));
+ if (!(ip->ip_off & 0x1fff))
+ if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP)
+ (void)printf(",%d", ntohs(tcp->th_dport));
+ putchar('\n');
+}
+
+
+#ifdef NEED_INET_ATON
+u_long inet_aton(buf)
+char *buf;
+{
+ u_long n;
+ char *s = (char *)&n;
+ int a, b, c, d;
+
+ if (sscanf(buf, "%d.%d.%d.%d", &a, &b, &c, &d) != 4)
+ return -1;
+
+ *s++ = (u_char)a;
+ *s++ = (u_char)b;
+ *s++ = (u_char)c;
+ *s++ = (u_char)d;
+ return n;
+}
+#endif
+
+
+void verbose(fmt, p1, p2, p3, p4, p5, p6, p7, p8, p9)
+char *fmt, *p1, *p2, *p3, *p4, *p5, *p6, *p7,*p8,*p9;
+{
+ if (opts & OPT_VERBOSE)
+ printf(fmt, p1, p2, p3, p4, p5, p6, p7, p8, p9);
+}
+
+
+void debug(fmt, p1, p2, p3, p4, p5, p6, p7, p8, p9)
+char *fmt, *p1, *p2, *p3, *p4, *p5, *p6, *p7,*p8,*p9;
+{
+ if (opts & OPT_DEBUG)
+ printf(fmt, p1, p2, p3, p4, p5, p6, p7, p8, p9);
+}
diff --git a/usr.sbin/ipftest/pcap.h b/usr.sbin/ipftest/pcap.h
new file mode 100644
index 00000000000..f7efe142c6e
--- /dev/null
+++ b/usr.sbin/ipftest/pcap.h
@@ -0,0 +1,32 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+/*
+ * This header file is constructed to match the version described by
+ * PCAP_VERSION_MAJ.
+ *
+ * The structure largely derives from libpcap which wouldn't include
+ * nicely without bpf.
+ */
+typedef struct pcap_filehdr {
+ u_int pc_id;
+ u_short pc_v_maj;
+ u_short pc_v_min;
+ u_int pc_zone;
+ u_int pc_sigfigs;
+ u_int pc_slen;
+ u_int pc_type;
+} pcaphdr_t;
+
+#define PCAP_VERSION_MAJ 2
+
+typedef struct pcap_pkthdr {
+ struct timeval ph_ts;
+ u_int ph_clen;
+ u_int ph_len;
+} pcappkt_t;
+
diff --git a/usr.sbin/ipftest/snoop.h b/usr.sbin/ipftest/snoop.h
new file mode 100644
index 00000000000..37503ea29f8
--- /dev/null
+++ b/usr.sbin/ipftest/snoop.h
@@ -0,0 +1,41 @@
+/*
+ * (C)opyright 1993,1994,1995 by Darren Reed.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and due credit is given
+ * to the original author and the contributors.
+ */
+
+/*
+ * written to comply with the RFC (1761) from Sun.
+ */
+struct snoophdr {
+ char s_id[8];
+ int s_v;
+ int s_type;
+};
+
+#define SNOOP_VERSION 2
+
+#define SDL_8023 0
+#define SDL_8024 1
+#define SDL_8025 2
+#define SDL_8026 3
+#define SDL_ETHER 4
+#define SDL_HDLC 5
+#define SDL_CHSYNC 6
+#define SDL_IBMCC 7
+#define SDL_FDDI 8
+#define SDL_OTHER 9
+
+#define SDL_MAX 9
+
+
+struct snooppkt {
+ int sp_olen;
+ int sp_ilen;
+ int sp_plen;
+ int sp_drop;
+ int sp_sec;
+ int sp_usec;
+};