diff options
author | dm <dm@cvs.openbsd.org> | 1996-01-07 02:34:41 +0000 |
---|---|---|
committer | dm <dm@cvs.openbsd.org> | 1996-01-07 02:34:41 +0000 |
commit | 01b9b71d86a5edcc543a88b2d407927fa52c042d (patch) | |
tree | 878168b4effcec4e50c243cfd1095656af14f4db /usr.sbin/ipftest | |
parent | 2defc765aa92d65e239f5b4d36582850fd58b7da (diff) |
from beurton@fnet.fr: Darren Reed's IP filter
Diffstat (limited to 'usr.sbin/ipftest')
-rw-r--r-- | usr.sbin/ipftest/Makefile | 8 | ||||
-rw-r--r-- | usr.sbin/ipftest/fil.c | 534 | ||||
-rw-r--r-- | usr.sbin/ipftest/ipft_ef.c | 157 | ||||
-rw-r--r-- | usr.sbin/ipftest/ipft_pc.c | 189 | ||||
-rw-r--r-- | usr.sbin/ipftest/ipft_sn.c | 201 | ||||
-rw-r--r-- | usr.sbin/ipftest/ipft_td.c | 201 | ||||
-rw-r--r-- | usr.sbin/ipftest/ipft_tx.c | 248 | ||||
-rw-r--r-- | usr.sbin/ipftest/ipftest.1 | 99 | ||||
-rw-r--r-- | usr.sbin/ipftest/ipt.c | 197 | ||||
-rw-r--r-- | usr.sbin/ipftest/ipt.h | 15 | ||||
-rw-r--r-- | usr.sbin/ipftest/misc.c | 103 | ||||
-rw-r--r-- | usr.sbin/ipftest/pcap.h | 32 | ||||
-rw-r--r-- | usr.sbin/ipftest/snoop.h | 41 |
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, ðerf, &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 == ðerf) + 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; +}; |