diff options
author | peter <peter@FreeBSD.org> | 1997-11-16 05:55:52 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1997-11-16 05:55:52 +0000 |
commit | 7a56344e6a21f069b204a2d12d165387b09258f2 (patch) | |
tree | c8cdc77281d6ea71cae48ee9fcc2e4ae8430414f /sys/netinet/fil.c | |
parent | a93925894facc20de4d8d36bcb61fc349047c73f (diff) | |
download | FreeBSD-src-7a56344e6a21f069b204a2d12d165387b09258f2.zip FreeBSD-src-7a56344e6a21f069b204a2d12d165387b09258f2.tar.gz |
Import kernel parts of ipfilter-3.2.1
Diffstat (limited to 'sys/netinet/fil.c')
-rw-r--r-- | sys/netinet/fil.c | 670 |
1 files changed, 531 insertions, 139 deletions
diff --git a/sys/netinet/fil.c b/sys/netinet/fil.c index b40695f..4c0f8c1b 100644 --- a/sys/netinet/fil.c +++ b/sys/netinet/fil.c @@ -1,13 +1,13 @@ /* - * (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 !defined(lint) && defined(LIBC_SCCS) -static char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-1996 Darren Reed"; -static char rcsid[] = "$Id: fil.c,v 2.0.2.13 1997/05/24 07:33:37 darrenr Exp $"; +#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 2.0.2.41.2.3 1997/11/12 10:44:22 darrenr Exp $"; #endif #include <sys/errno.h> @@ -16,7 +16,7 @@ static char rcsid[] = "$Id: fil.c,v 2.0.2.13 1997/05/24 07:33:37 darrenr Exp $"; #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> @@ -24,14 +24,18 @@ static char rcsid[] = "$Id: fil.c,v 2.0.2.13 1997/05/24 07:33:37 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> @@ -40,17 +44,20 @@ static char rcsid[] = "$Id: fil.c,v 2.0.2.13 1997/05/24 07:33:37 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 "netinet/ip_compat.h" +#include <netinet/tcpip.h> #include "netinet/ip_fil.h" #include "netinet/ip_proxy.h" #include "netinet/ip_nat.h" #include "netinet/ip_frag.h" #include "netinet/ip_state.h" +#include "netinet/ip_auth.h" #ifndef MIN #define MIN(a,b) (((a)<(b))?(a):(b)) #endif @@ -66,52 +73,68 @@ extern int opts; 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, m) -# define SEND_RESET(ip, qif, q, if) send_reset(ip, if) +# define SEND_RESET(ip, qif, if) 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 ICMP_ERROR(b, ip, t, c, if, src) icmp_error(ip) # else # define ICMP_ERROR(b, ip, t, c, if, src) icmp_error(b, ip, if) # endif - #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 FR_SCANLIST(p, ip, fi, m) fr_scanlist(p, ip, fi, m) -# define IPLLOG(a, c, d, e) ipllog(a, IPL_LOGIPF, c, d, e) +# 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 -extern kmutex_t ipf_mutex; -# define SEND_RESET(ip, qif, q, if) send_reset(ip, qif, q) +# 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(b, ip, t, c, if, src) -# else -# define FR_SCANLIST(p, ip, fi, m) fr_scanlist(p, ip, fi, m) -# define SEND_RESET(ip, qif, q, if) send_reset((struct tcpiphdr *)ip) -# if BSD < 199103 + icmp_error(ip, t, c, if, src) +# else /* SOLARIS */ +# define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip) +# define SEND_RESET(ip, qif, if) send_reset((struct tcpiphdr *)ip) +# ifdef __sgi # define ICMP_ERROR(b, ip, t, c, if, src) \ - icmp_error(mtod(b, ip_t *), t, c, if, src) + icmp_error(b, t, c, if, src, if) # else -# define ICMP_ERROR(b, ip, t, c, if, src) \ +# 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) +# endif /* linux */ +# else +# define ICMP_ERROR(b, ip, t, c, if, src) \ icmp_error(b, t, c, (src).s_addr, if) -# endif -# endif -#endif +# endif /* BSD < 199103 */ +# endif /* __sgi */ +# endif /* SOLARIS || __sgi */ +#endif /* _KERNEL */ 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]; static void fr_makefrip __P((int, ip_t *, fr_info_t *)); static int fr_tcpudpchk __P((frentry_t *, fr_info_t *)); -static int fr_scanlist __P((int, ip_t *, fr_info_t *, void *)); +static int frflushlist __P((int, int, int *, frentry_t *, frentry_t **)); /* @@ -176,6 +199,8 @@ fr_info_t *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 @@ -186,10 +211,10 @@ fr_info_t *fin; tcp = (tcphdr_t *)((char *)ip + hlen); fin->fin_dp = (void *)tcp; (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4)); - (*(((u_long *)fi) + 1)) = (*(((u_long *)ip) + 3)); - (*(((u_long *)fi) + 2)) = (*(((u_long *)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; @@ -371,7 +396,7 @@ fr_info_t *fin; * Could be per interface, but this gets real nasty when you don't have * kernel sauce. */ -static int fr_scanlist(pass, ip, fin, m) +int fr_scanlist(pass, ip, fin, m) int pass; ip_t *ip; register fr_info_t *fin; @@ -379,18 +404,23 @@ 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. @@ -403,18 +433,19 @@ void *m; #else if (opts & (OPT_VERBOSE|OPT_DEBUG)) printf("\n"); - FR_VERBOSE(("%c", (pass & FR_PASS) ? 'p' : 'b')); + 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 int i, j; + 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])); @@ -462,7 +493,8 @@ void *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 @@ -479,7 +511,17 @@ void *m; 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; } @@ -493,23 +535,16 @@ void *m; * or not to pass it on or not. */ int fr_check(ip, hlen, ifp, out -#ifdef _KERNEL -# if SOLARIS -, qif, q, mp) +#if defined(_KERNEL) && SOLARIS +, qif, mp) qif_t *qif; -queue_t *q; -mblk_t **mp; -# else -, mp) -struct mbuf **mp; -# endif #else , mp) -char *mp; #endif +mb_t **mp; ip_t *ip; int hlen; -struct ifnet *ifp; +void *ifp; int out; { /* @@ -518,34 +553,66 @@ int out; fr_info_t frinfo, *fc; register fr_info_t *fin = &frinfo; frentry_t *fr = NULL; - int pass, changed; -#ifndef _KERNEL - char *mc = mp, *m = mp; + int pass, changed, apass; +#if !SOLARIS || !defined(_KERNEL) + register mb_t *m = *mp; #endif #ifdef _KERNEL + mb_t *mc = NULL; # if !defined(__SVR4) && !defined(__svr4__) - register struct mbuf *m = *mp; - struct mbuf *mc = NULL; +# 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 + } else + up = 0; + } else + up = 0; # endif # if SOLARIS - mblk_t *mc = NULL, *m = qif->qf_m; + mb_t *m = qif->qf_m; # endif #endif fr_makefrip(hlen, ip, fin); @@ -554,33 +621,78 @@ int 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)) && - !(pass = fr_checkstate(ip, fin))) { - 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 = fr_pass; - if ((fin->fin_fr = ipfilter[out][fr_active])) - pass = FR_SCANLIST(fr_pass, ip, fin, m); - bcopy((char *)fin, (char *)fc, FI_CSIZE); - if (pass & FR_NOMATCH) - frstats[out].fr_nom++; + 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 + fr_authstats.fas_miss++; + MUTEX_EXIT(&ipf_auth); } - fr = fin->fin_fr; if (pass & FR_KEEPFRAG) { if (fin->fin_fi.fi_fl & FI_FRAG) { @@ -602,7 +714,11 @@ int 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++; @@ -649,7 +765,9 @@ logit: # if SOLARIS mc = dupmsg(m); # else +# ifndef linux mc = m_copy(m, 0, M_COPYALL); +# endif # endif #endif @@ -680,7 +798,7 @@ logit: frstats[0].fr_ret++; } else if ((pass & FR_RETRST) && !(fin->fin_fi.fi_fl & FI_SHORT)) { - if (SEND_RESET(ip, qif, q, ifp) == 0) + if (SEND_RESET(ip, qif, ifp) == 0) frstats[1].fr_ret++; } #else @@ -703,8 +821,9 @@ logit: * Once we're finished return to our caller, freeing the packet if * we are dropping it (* BSD ONLY *). */ -#ifdef _KERNEL -# if !SOLARIS +#if defined(_KERNEL) +# if !SOLARIS +# if !defined(linux) if (fr) { frdest_t *fdp = &fr->fr_tif; @@ -718,8 +837,13 @@ logit: } if (!(pass & FR_PASS) && m) m_freem(m); +# ifdef __sgi + else if (changed && up && m) + m_copyback(m, 0, up, hbuf); +# endif +# endif /* !linux */ return (pass & FR_PASS) ? 0 : -1; -# else +# else /* !SOLARIS */ if (fr) { frdest_t *fdp = &fr->fr_tif; @@ -732,49 +856,23 @@ logit: ipfr_fastroute(qif, ip, mc, mp, fin, &fr->fr_dif); } return (pass & FR_PASS) ? changed : -1; -# endif -#else +# 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 -int fr_copytolog(dev, buf, len) -int dev; -char *buf; -int len; -{ - register char *bufp = iplbuf[dev], *tp = iplt[dev], *hp = iplh[dev]; - register int clen, tail; - - tail = (hp >= tp) ? (bufp + IPLLOGSIZE - hp) : (tp - hp); - clen = MIN(tail, len); - bcopy(buf, hp, clen); - len -= clen; - tail -= clen; - hp += clen; - buf += clen; - if (hp == bufp + IPLLOGSIZE) { - hp = bufp; - tail = tp - hp; - } - if (len && tail) { - clen = MIN(tail, len); - bcopy(buf, hp, clen); - len -= clen; - hp += clen; - } - iplh[dev] = hp; - return len; -} -#endif - - +/* + * ipf_cksum + * addr should be 16bit aligned and len is in bytes. + */ u_short ipf_cksum(addr, len) register u_short *addr; register int len; @@ -803,11 +901,7 @@ register int len; * odd sizes. */ u_short fr_tcpsum(m, ip, tcp) -#if SOLARIS -mblk_t *m; -#else -struct mbuf *m; -#endif +mb_t *m; ip_t *ip; tcphdr_t *tcp; { @@ -817,12 +911,22 @@ tcphdr_t *tcp; } bytes; u_long sum; u_short *sp; - int len, add, hlen, ilen; + int len; +# 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 */ - ilen = len = ip->ip_len - (ip->ip_hl << 2); + len = ip->ip_len - (ip->ip_hl << 2); bytes.c[0] = 0; bytes.c[1] = IPPROTO_TCP; sum = bytes.s; @@ -855,35 +959,58 @@ tcphdr_t *tcp; while (hlen) { add = MIN(hlen, m->b_wptr - m->b_rptr); sp = (u_short *)((caddr_t)m->b_rptr + add); - if ((hlen -= 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 > 1) { - sum += *sp++; - len -= 2; + while (len > 0) { #if SOLARIS - if ((caddr_t)sp > (caddr_t)m->b_wptr) { + if ((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 -# ifdef m_data - if ((caddr_t)sp > (m->m_data + m->m_len)) -# else - if ((caddr_t)sp > (caddr_t)(m->m_dat + m->m_off + m->m_len)) -# endif + if (((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; + sum += *sp++; + len -= 2; } if (len) { bytes.c[1] = 0; @@ -896,3 +1023,268 @@ nodata: 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 2.0.2.41.2.3 1997/11/12 10:44:22 darrenr 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; + } + 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; + } +} + + +# 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, data) +int unit; +caddr_t data; +{ + int flags = *(int *)data, 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]); + } + } + + *(int *)data = flushed; +} |