summaryrefslogtreecommitdiff
path: root/sys/netinet/fil.c
diff options
context:
space:
mode:
authordgregor <dgregor@cvs.openbsd.org>1998-01-26 04:10:47 +0000
committerdgregor <dgregor@cvs.openbsd.org>1998-01-26 04:10:47 +0000
commit3bc04ed9d84fa464f1185f97ecbf0d42a35278d5 (patch)
tree4ee1d204830b235bf592a7f663cfabdc7bf34a5a /sys/netinet/fil.c
parenta95cd44675061863d776c0b405c6cffa4721f915 (diff)
IPF 3.2.3
Diffstat (limited to 'sys/netinet/fil.c')
-rw-r--r--sys/netinet/fil.c905
1 files changed, 710 insertions, 195 deletions
diff --git a/sys/netinet/fil.c b/sys/netinet/fil.c
index 8bbb4f70aad..ec88678a4d2 100644
--- a/sys/netinet/fil.c
+++ b/sys/netinet/fil.c
@@ -1,24 +1,22 @@
-/* $OpenBSD: fil.c,v 1.10 1997/06/23 19:03:47 kstailey Exp $ */
/*
- * (C)opyright 1993-1996 by Darren Reed.
+ * Copyright (C) 1993-1997 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.
*/
-#if 0
-#if !defined(lint) && defined(LIBC_SCCS)
-static char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-1996 Darren Reed";
-static char rcsid[] = "$DRId: fil.c,v 2.0.1.10 1997/04/13 22:33:07 darrenr Exp $";
-#endif
+#if !defined(lint)
+static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-1996 Darren Reed";
+static const char rcsid[] = "@(#)$Id: fil.c,v 1.11 1998/01/26 04:10:37 dgregor Exp $";
#endif
#include <sys/errno.h>
#include <sys/types.h>
#include <sys/param.h>
+#include <sys/time.h>
#include <sys/file.h>
#include <sys/ioctl.h>
-#if defined(_KERNEL) || defined(KERNEL)
+#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux)
# include <sys/systm.h>
#else
# include <stdio.h>
@@ -26,14 +24,18 @@ static char rcsid[] = "$DRId: fil.c,v 2.0.1.10 1997/04/13 22:33:07 darrenr Exp $
#endif
#include <sys/uio.h>
#if !defined(__SVR4) && !defined(__svr4__)
-# include <sys/mbuf.h>
+# ifndef linux
+# include <sys/mbuf.h>
+# endif
#else
# include <sys/byteorder.h>
# include <sys/dditypes.h>
# include <sys/stream.h>
#endif
-#include <sys/protosw.h>
-#include <sys/socket.h>
+#ifndef linux
+# include <sys/protosw.h>
+# include <sys/socket.h>
+#endif
#include <net/if.h>
#ifdef sun
# include <net/af.h>
@@ -42,86 +44,103 @@ static char rcsid[] = "$DRId: fil.c,v 2.0.1.10 1997/04/13 22:33:07 darrenr Exp $
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
-#include <netinet/ip_var.h>
+#ifndef linux
+# include <netinet/ip_var.h>
+#endif
#include <netinet/tcp.h>
#include <netinet/udp.h>
-#include <netinet/tcpip.h>
#include <netinet/ip_icmp.h>
#include "ip_fil_compat.h"
+#include <netinet/tcpip.h>
#include "ip_fil.h"
+#include "ip_proxy.h"
#include "ip_nat.h"
#include "ip_frag.h"
#include "ip_state.h"
+#include "ip_auth.h"
#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif
#ifndef _KERNEL
-#include "ipf.h"
+# include "ipf.h"
+# include "ipt.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
-#define FR_SCANLIST(p, ip, fi, m) fr_scanlist(p, ip, fi, NULL)
+# 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
+# define SEND_RESET(ip, qif, if, m) send_reset(ip, if)
+# define IPLLOG(a, c, d, e) ipllog()
+# define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip)
# if SOLARIS
-# define bcmp memcmp
-# endif
-#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)
-#define FR_SCANLIST(p, ip, fi, m) fr_scanlist(p, ip, fi, m)
-extern int send_reset __P((struct tcpiphdr *));
-# if SOLARIS
-extern int icmp_error(), ipfr_fastroute();
-extern kmutex_t ipf_mutex, ipl_mutex;
+# define ICMP_ERROR(b, ip, t, c, if, src) icmp_error(ip)
# else
-extern void ipfr_fastroute __P((struct mbuf *, fr_info_t *, frdest_t *));
+# define ICMP_ERROR(b, ip, t, c, if, src) icmp_error(b, ip, if)
# endif
-extern int ipl_unreach;
-extern int ipllog __P((u_int, ip_t *, register fr_info_t *,
- struct mbuf *));
-#endif
-
-#if SOLARIS
-# define SEND_RESET(ip, if, q) send_reset(ip, qif, q)
-# define ICMP_ERROR(b, ip, t, c, if, src) \
- icmp_error(b, ip, t, c, if, src)
-#else
-# define SEND_RESET(ip, if, q) send_reset( \
- (struct tcpiphdr *)ip)
-# if BSD < 199103
+#else /* #ifndef _KERNEL */
+# define FR_IFVERBOSE(ex,second,verb_pr) ;
+# define FR_IFDEBUG(ex,second,verb_pr) ;
+# define FR_VERBOSE(verb_pr)
+# define FR_DEBUG(verb_pr)
+# define IPLLOG(a, c, d, e) ipflog(a, c, d, e)
+# if SOLARIS || defined(__sgi)
+extern kmutex_t ipf_mutex, ipf_auth;
+# endif
+# if SOLARIS
+# define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, \
+ ip, qif)
+# define SEND_RESET(ip, qif, if) send_reset(ip, qif)
# define ICMP_ERROR(b, ip, t, c, if, src) \
+ icmp_error(ip, t, c, if, src)
+# else /* SOLARIS */
+# define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip)
+# ifdef linux
+# define SEND_RESET(ip, qif, if) send_reset((tcpiphdr_t *)ip,\
+ ifp)
+# else
+# define SEND_RESET(ip, qif, if) send_reset((tcpiphdr_t *)ip)
+# endif
+# ifdef __sgi
+# define ICMP_ERROR(b, ip, t, c, if, src) \
+ icmp_error(b, t, c, if, src, if)
+# else
+# if BSD < 199103
+# ifdef linux
+# define ICMP_ERROR(b, ip, t, c, if, src) icmp_send(b,t,c,0,if)
+# else
+# define ICMP_ERROR(b, ip, t, c, if, src) \
icmp_error(mtod(b, ip_t *), t, c, if, src)
-# else
-# define ICMP_ERROR(b, ip, t, c, if, src) \
+# endif /* linux */
+# else
+# define ICMP_ERROR(b, ip, t, c, if, src) \
icmp_error(b, t, c, (src).s_addr, if)
-# endif
-#endif
+# endif /* BSD < 199103 */
+# endif /* __sgi */
+# endif /* SOLARIS || __sgi */
+#endif /* _KERNEL */
-#ifndef IPF_LOGGING
-#define IPF_LOGGING 0
-#endif
-#ifdef IPF_DEFAULT_PASS
-#define IPF_NOMATCH (IPF_DEFAULT_PASS|FR_NOMATCH)
-#else
-#define IPF_NOMATCH (FR_PASS|FR_NOMATCH)
-#endif
struct filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}};
struct frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } },
*ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } };
+struct frgroup *ipfgroups[3][2];
int fr_flags = IPF_LOGGING, fr_active = 0;
+#if defined(IPFILTER_DEFAULT_BLOCK)
+int fr_pass = FR_NOMATCH|FR_BLOCK;
+#else
+int fr_pass = (IPF_DEFAULT_PASS|FR_NOMATCH);
+#endif
fr_info_t frcache[2];
-void fr_makefrip __P((int, ip_t *, fr_info_t *));
-int fr_tcpudpchk __P((frentry_t *, fr_info_t *));
-int fr_scanlist __P((int, ip_t *, fr_info_t *, void *m));
+static void fr_makefrip __P((int, ip_t *, fr_info_t *));
+static int fr_tcpudpchk __P((frentry_t *, fr_info_t *));
+static int frflushlist __P((int, int, int *, frentry_t *, frentry_t **));
+
/*
* bit values for identifying presence of individual IP options
@@ -168,11 +187,10 @@ struct optlist secopt[8] = {
* compact the IP header into a structure which contains just the info.
* which is useful for comparing IP headers with.
*/
-void
-fr_makefrip(hlen, ip, fin)
- int hlen;
- ip_t *ip;
- fr_info_t *fin;
+static void fr_makefrip(hlen, ip, fin)
+int hlen;
+ip_t *ip;
+fr_info_t *fin;
{
struct optlist *op;
tcphdr_t *tcp;
@@ -186,6 +204,8 @@ fr_makefrip(hlen, ip, fin)
fin->fin_data[0] = 0;
fin->fin_data[1] = 0;
fin->fin_rule = -1;
+ fin->fin_group = -1;
+ fin->fin_id = ip->ip_id;
#ifdef _KERNEL
fin->fin_icode = ipl_unreach;
#endif
@@ -196,10 +216,10 @@ fr_makefrip(hlen, ip, fin)
tcp = (tcphdr_t *)((char *)ip + hlen);
fin->fin_dp = (void *)tcp;
(*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4));
- (*(((u_int32_t *)fi) + 1)) = (*(((u_int32_t *)ip) + 3));
- (*(((u_int32_t *)fi) + 2)) = (*(((u_int32_t *)ip) + 4));
+ (*(((u_32_t *)fi) + 1)) = (*(((u_32_t *)ip) + 3));
+ (*(((u_32_t *)fi) + 2)) = (*(((u_32_t *)ip) + 4));
- fi->fi_fl = (hlen > sizeof(struct ip)) ? FI_OPTIONS : 0;
+ fi->fi_fl = (hlen > sizeof(ip_t)) ? FI_OPTIONS : 0;
off = (ip->ip_off & 0x1fff) << 3;
if (ip->ip_off & 0x3fff)
fi->fi_fl |= FI_FRAG;
@@ -288,10 +308,9 @@ getports:
/*
* check an IP packet for TCP/UDP characteristics such as ports and flags.
*/
-int
-fr_tcpudpchk(fr, fin)
- frentry_t *fr;
- fr_info_t *fin;
+static int fr_tcpudpchk(fr, fin)
+frentry_t *fr;
+fr_info_t *fin;
{
register u_short po, tup;
register char i;
@@ -382,27 +401,31 @@ fr_tcpudpchk(fr, fin)
* Could be per interface, but this gets real nasty when you don't have
* kernel sauce.
*/
-int
-fr_scanlist(pass, ip, fin, m)
- int pass;
- ip_t *ip;
- register fr_info_t *fin;
- void *m;
+int fr_scanlist(pass, ip, fin, m)
+int pass;
+ip_t *ip;
+register fr_info_t *fin;
+void *m;
{
register struct frentry *fr;
register fr_ip_t *fi = &fin->fin_fi;
- int rulen, portcmp = 0, off;
+ int rulen, portcmp = 0, off, skip = 0;
fr = fin->fin_fr;
fin->fin_fr = NULL;
fin->fin_rule = 0;
+ fin->fin_group = 0;
off = ip->ip_off & 0x1fff;
- pass |= (fi->fi_fl << 20);
+ pass |= (fi->fi_fl << 24);
if ((fi->fi_fl & FI_TCPUDP) && (fin->fin_dlen > 3) && !off)
portcmp = 1;
for (rulen = 0; fr; fr = fr->fr_next, rulen++) {
+ if (skip) {
+ skip--;
+ continue;
+ }
/*
* In all checks below, a null (zero) value in the
* filter struture is taken to mean a wildcard.
@@ -415,26 +438,26 @@ fr_scanlist(pass, ip, fin, m)
#else
if (opts & (OPT_VERBOSE|OPT_DEBUG))
printf("\n");
- FR_VERBOSE(("%c", (pass & FR_PASS) ? 'p' : 'b'));
- if (fin->fin_ifp && *fr->fr_ifname &&
- strcasecmp((char *)fin->fin_ifp, fr->fr_ifname))
+ FR_VERBOSE(("%c", (pass & FR_PASS) ? 'p' :
+ (pass & FR_AUTH) ? 'a' : 'b'));
+ if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)
continue;
FR_VERBOSE((":i"));
#endif
{
- register u_long *ld, *lm, *lip;
+ register u_32_t *ld, *lm, *lip;
register int i;
- lip = (u_long *)fi;
- lm = (u_long *)&fr->fr_mip;
- ld = (u_long *)&fr->fr_ip;
+ lip = (u_32_t *)fi;
+ lm = (u_32_t *)&fr->fr_mip;
+ ld = (u_32_t *)&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]);
+ i |= ((lip[1] & lm[1]) != ld[1]) << 21;
FR_IFDEBUG(i,continue,("1. %#08x & %#08x != %#08x\n",
lip[1], lm[1], ld[1]));
- i |= ((lip[2] & lm[2]) != ld[2]);
+ i |= ((lip[2] & lm[2]) != ld[2]) << 22;
FR_IFDEBUG(i,continue,("2. %#08x & %#08x != %#08x\n",
lip[2], lm[2], ld[2]));
i |= ((lip[3] & lm[3]) != ld[3]);
@@ -443,6 +466,7 @@ fr_scanlist(pass, ip, fin, m)
i |= ((lip[4] & lm[4]) != ld[4]);
FR_IFDEBUG(i,continue,("4. %#08x & %#08x != %#08x\n",
lip[4], lm[4], ld[4]));
+ i ^= (fi->fi_fl & (FR_NOTSRCIP|FR_NOTDSTIP));
if (i)
continue;
}
@@ -474,12 +498,13 @@ fr_scanlist(pass, ip, fin, m)
/*
* Just log this packet...
*/
- pass = fr->fr_flags;
+ if (!(skip = fr->fr_skip))
+ pass = fr->fr_flags;
if ((pass & FR_CALLNOW) && fr->fr_func)
pass = (*fr->fr_func)(pass, ip, fin);
#ifdef IPFILTER_LOG
if ((pass & FR_LOGMASK) == FR_LOG) {
- if (!ipllog(fr->fr_flags, ip, fin, m))
+ if (!IPLLOG(fr->fr_flags, ip, fin, m))
frstats[fin->fin_out].fr_skip++;
frstats[fin->fin_out].fr_pkl++;
}
@@ -487,11 +512,21 @@ fr_scanlist(pass, ip, fin, m)
FR_DEBUG(("pass %#x\n", pass));
fr->fr_hits++;
if (pass & FR_ACCOUNT)
- fr->fr_bytes += ip->ip_len;
+ fr->fr_bytes += (U_QUAD_T)ip->ip_len;
else
fin->fin_icode = fr->fr_icode;
fin->fin_rule = rulen;
+ fin->fin_group = fr->fr_group;
fin->fin_fr = fr;
+ if (fr->fr_grp) {
+ fin->fin_fr = fr->fr_grp;
+ pass = fr_scanlist(pass, ip, fin, m);
+ if (fin->fin_fr == NULL) {
+ fin->fin_rule = rulen;
+ fin->fin_group = fr->fr_group;
+ fin->fin_fr = fr;
+ }
+ }
if (pass & FR_QUICK)
break;
}
@@ -501,28 +536,21 @@ fr_scanlist(pass, ip, fin, m)
/*
* frcheck - filter check
- * check using source and destination addresses/ports in a packet whether
+ * 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
-#ifdef _KERNEL
-# if SOLARIS
- , qif, q, mp)
- qif_t *qif;
- queue_t *q;
- mblk_t **mp;
-# else
- , mp)
- struct mbuf **mp;
-# endif
+int fr_check(ip, hlen, ifp, out
+#if defined(_KERNEL) && SOLARIS
+, qif, mp)
+qif_t *qif;
#else
- )
+, mp)
#endif
- ip_t *ip;
- int hlen;
- struct ifnet *ifp;
- int out;
+mb_t **mp;
+ip_t *ip;
+int hlen;
+void *ifp;
+int out;
{
/*
* The above really sucks, but short of writing a diff
@@ -530,81 +558,148 @@ fr_check(ip, hlen, ifp, out
fr_info_t frinfo, *fc;
register fr_info_t *fin = &frinfo;
frentry_t *fr = NULL;
- int pass, changed;
+ int pass, changed, apass, error = EHOSTUNREACH;
+#if !SOLARIS || !defined(_KERNEL)
+ register mb_t *m = *mp;
+#endif
-#if !defined(__SVR4) && !defined(__svr4__) && defined(_KERNEL)
- register struct mbuf *m = *mp;
- struct mbuf *mc = NULL;
+#ifdef _KERNEL
+ mb_t *mc = NULL;
+# if !defined(__SVR4) && !defined(__svr4__)
+# ifdef __sgi
+ char hbuf[(0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8];
+# endif
+ int up;
if ((ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP ||
ip->ip_p == IPPROTO_ICMP)) {
- register int up = MIN(hlen + 8, ip->ip_len);
+ int plen = 0;
+
+ switch(ip->ip_p)
+ {
+ case IPPROTO_TCP:
+ plen = sizeof(tcphdr_t);
+ break;
+ case IPPROTO_UDP:
+ plen = sizeof(udphdr_t);
+ break;
+ case IPPROTO_ICMP:
+ /* 96 - enough for complete ICMP error IP header */
+ plen = sizeof(struct icmp) + sizeof(ip_t) + 8;
+ break;
+ }
+ up = MIN(hlen + plen, ip->ip_len);
if (up > m->m_len) {
+#ifdef __sgi /* Under IRIX, avoid m_pullup as it makes ping <hostname> panic */
+ if ((up > sizeof(hbuf)) || (m_length(m) < up)) {
+ frstats[out].fr_pull[1]++;
+ return -1;
+ }
+ m_copydata(m, 0, up, hbuf);
+ frstats[out].fr_pull[0]++;
+ ip = (ip_t *)hbuf;
+#else
+# ifndef linux
if ((*mp = m_pullup(m, up)) == 0) {
frstats[out].fr_pull[1]++;
return -1;
} else {
frstats[out].fr_pull[0]++;
m = *mp;
- ip = mtod(m, struct ip *);
+ ip = mtod(m, ip_t *);
}
- }
- }
+# endif
#endif
-#if SOLARIS && defined(_KERNEL)
- mblk_t *mc = NULL, *m = qif->qf_m;
+ } else
+ up = 0;
+ } else
+ up = 0;
+# endif
+# if SOLARIS
+ mb_t *m = qif->qf_m;
+# endif
#endif
fr_makefrip(hlen, ip, fin);
fin->fin_ifp = ifp;
fin->fin_out = out;
+ fin->fin_mp = mp;
MUTEX_ENTER(&ipf_mutex);
+
+ /*
+ * Check auth now. This, combined with the check below to see if apass
+ * is 0 is to ensure that we don't count the packet twice, which can
+ * otherwise occur when we reprocess it. As it is, we only count it
+ * after it has no auth. table matchup. This also stops NAT from
+ * occuring until after the packet has been auth'd.
+ */
+ apass = fr_checkauth(ip, fin);
+
if (!out) {
changed = ip_natin(ip, hlen, fin);
- if ((fin->fin_fr = ipacct[0][fr_active]) &&
+ if (!apass && (fin->fin_fr = ipacct[0][fr_active]) &&
(FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT))
frstats[0].fr_acct++;
}
- if ((pass = ipfr_knownfrag(ip, fin))) {
- if ((pass & FR_KEEPSTATE)) {
- if (fr_addstate(ip, fin, pass) == -1)
- frstats[out].fr_bads++;
+ if (apass || (!(pass = ipfr_knownfrag(ip, fin)) &&
+ !(pass = fr_checkstate(ip, fin)))) {
+ /*
+ * If a packet is found in the auth table, then skip checking
+ * the access lists for permission but we do need to consider
+ * the result as if it were from the ACL's.
+ */
+ if (!apass) {
+ fc = frcache + out;
+ if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) {
+ /*
+ * copy cached data so we can unlock the mutex
+ * earlier.
+ */
+ bcopy((char *)fc, (char *)fin, FI_COPYSIZE);
+ frstats[out].fr_chit++;
+ if ((fr = fin->fin_fr)) {
+ fr->fr_hits++;
+ pass = fr->fr_flags;
+ } else
+ pass = fr_pass;
+ } else {
+ pass = fr_pass;
+ if ((fin->fin_fr = ipfilter[out][fr_active]))
+ pass = FR_SCANLIST(fr_pass, ip, fin, m);
+ bcopy((char *)fin, (char *)fc, FI_COPYSIZE);
+ if (pass & FR_NOMATCH)
+ frstats[out].fr_nom++;
+ }
+ fr = fin->fin_fr;
+ } else
+ pass = apass;
+
+ /*
+ * If we fail to add a packet to the authorization queue,
+ * then we drop the packet later. However, if it was added
+ * then pretend we've dropped it already.
+ */
+ if ((pass & FR_AUTH))
+ if (FR_NEWAUTH(m, fin, ip, qif) != 0)
+#ifdef _KERNEL
+ m = *mp = NULL;
+#else
+ ;
+#endif
+
+ if (pass & FR_PREAUTH) {
+ MUTEX_ENTER(&ipf_auth);
+ if ((fin->fin_fr = ipauth) &&
+ (pass = FR_SCANLIST(0, ip, fin, m)))
+ fr_authstats.fas_hits++;
else
- frstats[out].fr_ads++;
- }
- } else if ((pass = fr_checkstate(ip, fin))) {
- if ((pass & FR_KEEPFRAG)) {
- if (fin->fin_fi.fi_fl & FI_FRAG) {
- if (ipfr_newfrag(ip, fin, pass) == -1)
- frstats[out].fr_bnfr++;
- else
- frstats[out].fr_nfr++;
- } else
- frstats[out].fr_cfr++;
- }
- } else {
- fc = frcache + out;
- if (fc->fin_fr && !bcmp((char *)fin, (char *)fc, FI_CSIZE)) {
- /*
- * copy cached data so we can unlock the mutex
- * earlier.
- */
- bcopy((char *)fc, (char *)fin, sizeof(*fin));
- frstats[out].fr_chit++;
- pass = fin->fin_fr->fr_flags;
- } else {
- pass = IPF_NOMATCH;
- if ((fin->fin_fr = ipfilter[out][fr_active]))
- pass = FR_SCANLIST(IPF_NOMATCH, ip, fin, m);
- bcopy((char *)fin, (char *)fc, FI_CSIZE);
- if (pass & FR_NOMATCH)
- frstats[out].fr_nom++;
+ fr_authstats.fas_miss++;
+ MUTEX_EXIT(&ipf_auth);
}
- fr = fin->fin_fr;
- if ((pass & FR_KEEPFRAG)) {
+ if (pass & FR_KEEPFRAG) {
if (fin->fin_fi.fi_fl & FI_FRAG) {
if (ipfr_newfrag(ip, fin, pass) == -1)
frstats[out].fr_bnfr++;
@@ -624,7 +719,11 @@ fr_check(ip, hlen, ifp, out
if (fr && fr->fr_func && !(pass & FR_CALLNOW))
pass = (*fr->fr_func)(pass, ip, fin);
- if (out) {
+ /*
+ * Only count/translate packets which will be passed on, out the
+ * interface.
+ */
+ if (out && (pass & FR_PASS)) {
if ((fin->fin_fr = ipacct[1][fr_active]) &&
(FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT))
frstats[1].fr_acct++;
@@ -652,7 +751,7 @@ fr_check(ip, hlen, ifp, out
pass |= FF_LOGBLOCK;
frstats[out].fr_bpkl++;
logit:
- if (!ipllog(pass, ip, fin, m)) {
+ if (!IPLLOG(pass, ip, fin, m)) {
frstats[out].fr_skip++;
if ((pass & (FR_PASS|FR_LOGORBLOCK)) ==
(FR_PASS|FR_LOGORBLOCK))
@@ -661,13 +760,21 @@ logit:
}
}
#endif /* IPFILTER_LOG */
-
#ifdef _KERNEL
+ /*
+ * Only allow FR_DUP to work if a rule matched - it makes no sense to
+ * set FR_DUP as a "default" as there are no instructions about where
+ * to send the packet.
+ */
if (fr && (pass & FR_DUP))
-# if SOLARIS
+# if SOLARIS
mc = dupmsg(m);
# else
+# ifndef linux
mc = m_copy(m, 0, M_COPYALL);
+# else
+ ;
+# endif
# endif
#endif
if (pass & FR_PASS)
@@ -697,7 +804,7 @@ logit:
frstats[0].fr_ret++;
} else if ((pass & FR_RETRST) &&
!(fin->fin_fi.fi_fl & FI_SHORT)) {
- if (SEND_RESET(ip, qif, q) == 0)
+ if (SEND_RESET(ip, qif, ifp) == 0)
frstats[1].fr_ret++;
}
#else
@@ -710,10 +817,22 @@ logit:
frstats[1].fr_ret++;
}
#endif
+ } else {
+ if (pass & FR_RETRST)
+ error = ECONNRESET;
}
}
-#ifdef _KERNEL
-# if !SOLARIS
+
+ /*
+ * If we didn't drop off the bottom of the list of rules (and thus
+ * the 'current' rule fr is not NULL), then we may have some extra
+ * instructions about what to do with a packet.
+ * Once we're finished return to our caller, freeing the packet if
+ * we are dropping it (* BSD ONLY *).
+ */
+#if defined(_KERNEL)
+# if !SOLARIS
+# if !defined(linux)
if (fr) {
frdest_t *fdp = &fr->fr_tif;
@@ -727,8 +846,13 @@ logit:
}
if (!(pass & FR_PASS) && m)
m_freem(m);
- return (pass & FR_PASS) ? 0 : -1;
-# else
+# ifdef __sgi
+ else if (changed && up && m)
+ m_copyback(m, 0, up, hbuf);
+# endif
+# endif /* !linux */
+ return (pass & FR_PASS) ? 0 : error;
+# else /* !SOLARIS */
if (fr) {
frdest_t *fdp = &fr->fr_tif;
@@ -740,50 +864,441 @@ logit:
if (mc)
ipfr_fastroute(qif, ip, mc, mp, fin, &fr->fr_dif);
}
- return (pass & FR_PASS) ? changed : -1;
-# endif
-#else
+ return (pass & FR_PASS) ? changed : error;
+# endif /* !SOLARIS */
+#else /* _KERNEL */
if (pass & FR_NOMATCH)
return 1;
if (pass & FR_PASS)
return 0;
+ if (pass & FR_AUTH)
+ return -2;
return -1;
-#endif
+#endif /* _KERNEL */
}
-#ifdef IPFILTER_LOG
-# if !(defined(_KERNEL))
-static void ipllog()
+/*
+ * ipf_cksum
+ * addr should be 16bit aligned and len is in bytes.
+ * length is in bytes
+ */
+u_short ipf_cksum(addr, len)
+register u_short *addr;
+register int len;
{
- verbose("l");
+ register u_long sum = 0;
+
+ for (sum = 0; len > 1; len -= 2)
+ sum += *addr++;
+
+ /* mop up an odd byte, if necessary */
+ if (len == 1)
+ sum += *(u_char *)addr;
+
+ /*
+ * add back carry outs from top 16 bits to low 16 bits
+ */
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ return (u_short)(~sum);
}
-# endif
-int fr_copytolog(buf, len)
-char *buf;
+/*
+ * NB: This function assumes we've pullup'd enough for all of the IP header
+ * and the TCP header. We also assume that data blocks aren't allocated in
+ * odd sizes.
+ */
+u_short fr_tcpsum(m, ip, tcp, len)
+mb_t *m;
+ip_t *ip;
+tcphdr_t *tcp;
int len;
{
- int clen, tail;
-
- tail = (iplh >= iplt) ? (iplbuf + IPLLOGSIZE - iplh) : (iplt - iplh);
- clen = MIN(tail, len);
- bcopy(buf, iplh, clen);
- len -= clen;
- tail -= clen;
- iplh += clen;
- buf += clen;
- if (iplh == iplbuf + IPLLOGSIZE) {
- iplh = iplbuf;
- tail = iplt - iplh;
+ union {
+ u_char c[2];
+ u_short s;
+ } bytes;
+ u_long sum;
+ u_short *sp;
+# if SOLARIS || defined(__sgi)
+ int add, hlen;
+# endif
+
+# if SOLARIS
+ /* skip any leading M_PROTOs */
+ while(m && (MTYPE(m) != M_DATA))
+ m = m->b_cont;
+ PANIC((!m),("fr_tcpsum: no M_DATA"));
+# endif
+
+ /*
+ * Add up IP Header portion
+ */
+ bytes.c[0] = 0;
+ bytes.c[1] = IPPROTO_TCP;
+ len -= (ip->ip_hl << 2);
+ sum = bytes.s;
+ sum += htons((u_short)len);
+ sp = (u_short *)&ip->ip_src;
+ sum += *sp++;
+ sum += *sp++;
+ sum += *sp++;
+ sum += *sp++;
+ if (sp != (u_short *)tcp)
+ sp = (u_short *)tcp;
+ sum += *sp++;
+ sum += *sp++;
+ sum += *sp++;
+ sum += *sp++;
+ sum += *sp++;
+ sum += *sp++;
+ sum += *sp++;
+ sum += *sp;
+ sp += 2; /* Skip over checksum */
+ sum += *sp++;
+
+#if SOLARIS
+ /*
+ * In case we had to copy the IP & TCP header out of mblks,
+ * skip over the mblk bits which are the header
+ */
+ if ((caddr_t)ip != (caddr_t)m->b_rptr) {
+ hlen = (caddr_t)sp - (caddr_t)ip;
+ while (hlen) {
+ add = MIN(hlen, m->b_wptr - m->b_rptr);
+ sp = (u_short *)((caddr_t)m->b_rptr + add);
+ hlen -= add;
+ if ((caddr_t)sp >= (caddr_t)m->b_wptr) {
+ m = m->b_cont;
+ PANIC((!m),("fr_tcpsum: not enough data"));
+ if (!hlen)
+ sp = (u_short *)m->b_rptr;
+ }
+ }
+ }
+#endif
+#ifdef __sgi
+ /*
+ * In case we had to copy the IP & TCP header out of mbufs,
+ * skip over the mbuf bits which are the header
+ */
+ if ((caddr_t)ip != mtod(m, caddr_t)) {
+ hlen = (caddr_t)sp - (caddr_t)ip;
+ while (hlen) {
+ add = MIN(hlen, m->m_len);
+ sp = (u_short *)(mtod(m, caddr_t) + add);
+ hlen -= add;
+ if (add >= m->m_len) {
+ m = m->m_next;
+ PANIC((!m),("fr_tcpsum: not enough data"));
+ if (!hlen)
+ sp = mtod(m, u_short *);
+ }
+ }
+ }
+#endif
+
+ if (!(len -= sizeof(*tcp)))
+ goto nodata;
+ while (len > 0) {
+#if SOLARIS
+ while ((caddr_t)sp >= (caddr_t)m->b_wptr) {
+ m = m->b_cont;
+ PANIC((!m),("fr_tcpsum: not enough data"));
+ sp = (u_short *)m->b_rptr;
+ }
+#else
+ while (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len)
+ {
+ m = m->m_next;
+ PANIC((!m),("fr_tcpsum: not enough data"));
+ sp = mtod(m, u_short *);
+ }
+#endif /* SOLARIS */
+ if (len < 2)
+ break;
+ if((u_long)sp & 1) {
+ bcopy((char *)sp++, (char *)&bytes.s, sizeof(bytes.s));
+ sum += bytes.s;
+ } else
+ sum += *sp++;
+ len -= 2;
+ }
+ if (len) {
+ bytes.c[1] = 0;
+ bytes.c[0] = *(u_char *)sp;
+ sum += bytes.s;
+ }
+nodata:
+ sum = (sum >> 16) + (sum & 0xffff);
+ sum += (sum >> 16);
+ sum = (u_short)((~sum) & 0xffff);
+ return sum;
+}
+
+
+#if defined(_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || defined(__sgi) )
+/*
+ * Copyright (c) 1982, 1986, 1988, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
+ * $Id: fil.c,v 1.11 1998/01/26 04:10:37 dgregor Exp $
+ */
+/*
+ * Copy data from an mbuf chain starting "off" bytes from the beginning,
+ * continuing for "len" bytes, into the indicated buffer.
+ */
+void
+m_copydata(m, off, len, cp)
+ register mb_t *m;
+ register int off;
+ register int len;
+ caddr_t cp;
+{
+ register unsigned count;
+
+ if (off < 0 || len < 0)
+ panic("m_copydata");
+ while (off > 0) {
+ if (m == 0)
+ panic("m_copydata");
+ if (off < m->m_len)
+ break;
+ off -= m->m_len;
+ m = m->m_next;
}
- if (len && tail) {
- clen = MIN(tail, len);
- bcopy(buf, iplh, clen);
- len -= clen;
- iplh += clen;
+ while (len > 0) {
+ if (m == 0)
+ panic("m_copydata");
+ count = MIN(m->m_len - off, len);
+ bcopy(mtod(m, caddr_t) + off, cp, count);
+ len -= count;
+ cp += count;
+ off = 0;
+ m = m->m_next;
}
- return len;
}
+
+
+# ifndef linux
+/*
+ * Copy data from a buffer back into the indicated mbuf chain,
+ * starting "off" bytes from the beginning, extending the mbuf
+ * chain if necessary.
+ */
+void
+m_copyback(m0, off, len, cp)
+ struct mbuf *m0;
+ register int off;
+ register int len;
+ caddr_t cp;
+{
+ register int mlen;
+ register struct mbuf *m = m0, *n;
+ int totlen = 0;
+
+ if (m0 == 0)
+ return;
+ while (off > (mlen = m->m_len)) {
+ off -= mlen;
+ totlen += mlen;
+ if (m->m_next == 0) {
+ n = m_getclr(M_DONTWAIT, m->m_type);
+ if (n == 0)
+ goto out;
+ n->m_len = min(MLEN, len + off);
+ m->m_next = n;
+ }
+ m = m->m_next;
+ }
+ while (len > 0) {
+ mlen = min (m->m_len - off, len);
+ bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
+ cp += mlen;
+ len -= mlen;
+ mlen += off;
+ off = 0;
+ totlen += mlen;
+ if (len == 0)
+ break;
+ if (m->m_next == 0) {
+ n = m_get(M_DONTWAIT, m->m_type);
+ if (n == 0)
+ break;
+ n->m_len = min(MLEN, len);
+ m->m_next = n;
+ }
+ m = m->m_next;
+ }
+out:
+#if 0
+ if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
+ m->m_pkthdr.len = totlen;
#endif
+ return;
+}
+# endif /* linux */
+#endif /* (_KERNEL) && ( ((BSD < 199306) && !SOLARIS) || __sgi) */
+
+
+frgroup_t *fr_findgroup(num, flags, which, set, fgpp)
+u_short num;
+u_32_t flags;
+int which, set;
+frgroup_t ***fgpp;
+{
+ frgroup_t *fg, **fgp;
+
+ if (which == IPL_LOGAUTH)
+ fgp = &ipfgroups[2][set];
+ else if (flags & FR_ACCOUNT)
+ fgp = &ipfgroups[1][set];
+ else if (flags & (FR_OUTQUE|FR_INQUE))
+ fgp = &ipfgroups[0][set];
+ else
+ return NULL;
+
+ while ((fg = *fgp))
+ if (fg->fg_num == num)
+ break;
+ else
+ fgp = &fg->fg_next;
+ if (fgpp)
+ *fgpp = fgp;
+ return fg;
+}
+
+
+frgroup_t *fr_addgroup(num, fp, which, set)
+u_short num;
+frentry_t *fp;
+int which, set;
+{
+ frgroup_t *fg, **fgp;
+
+ if ((fg = fr_findgroup(num, fp->fr_flags, which, set, &fgp)))
+ return fg;
+
+ KMALLOC(fg, frgroup_t *, sizeof(*fg));
+ if (fg) {
+ fg->fg_num = num;
+ fg->fg_next = *fgp;
+ fg->fg_head = fp;
+ fg->fg_start = &fp->fr_grp;
+ *fgp = fg;
+ }
+ return fg;
+}
+
+
+void fr_delgroup(num, flags, which, set)
+u_short num;
+u_32_t flags;
+int which, set;
+{
+ frgroup_t *fg, **fgp;
+
+ if (!(fg = fr_findgroup(num, flags, which, set, &fgp)))
+ return;
+
+ *fgp = fg->fg_next;
+ KFREE(fg);
+}
+
+
+
+/*
+ * recursively flush rules from the list, descending groups as they are
+ * encountered. if a rule is the head of a group and it has lost all its
+ * group members, then also delete the group reference.
+ */
+static int frflushlist(set, unit, nfreedp, list, listp)
+int set, unit, *nfreedp;
+frentry_t *list, **listp;
+{
+ register frentry_t *fp = list, *fpn;
+ register int freed = 0;
+
+ while (fp) {
+ fpn = fp->fr_next;
+ if (fp->fr_grp) {
+ fp->fr_ref -= frflushlist(set, unit, nfreedp,
+ fp->fr_grp, &fp->fr_grp);
+ }
+
+ if (fp->fr_ref == 1) {
+ if (fp->fr_grhead)
+ fr_delgroup(fp->fr_grhead, fp->fr_flags, unit,
+ set);
+ KFREE(fp);
+ *listp = fpn;
+ freed++;
+ }
+ fp = fpn;
+ }
+ *nfreedp += freed;
+ return freed;
+}
+
+
+void frflush(unit, result)
+int unit;
+int *result;
+{
+ int flags = *result, flushed = 0, set = fr_active;
+
+ bzero((char *)frcache, sizeof(frcache[0]) * 2);
+
+ if (flags & FR_INACTIVE)
+ set = 1 - set;
+
+ if (unit == IPL_LOGIPF) {
+ if (flags & FR_OUTQUE) {
+ (void) frflushlist(set, unit, &flushed,
+ ipfilter[1][set],
+ &ipfilter[1][set]);
+ (void) frflushlist(set, unit, &flushed,
+ ipacct[1][set], &ipacct[1][set]);
+ }
+ if (flags & FR_INQUE) {
+ (void) frflushlist(set, unit, &flushed,
+ ipfilter[0][set],
+ &ipfilter[0][set]);
+ (void) frflushlist(set, unit, &flushed,
+ ipacct[0][set], &ipacct[0][set]);
+ }
+ }
+
+ *result = flushed;
+}