diff --git a/sys/netinet/fil.c b/sys/netinet/fil.c index b40695f829e3..4c0f8c1b74d6 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 @@ -16,7 +16,7 @@ static char rcsid[] = "$Id: fil.c,v 2.0.2.13 1997/05/24 07:33:37 darrenr Exp $"; #include #include #include -#if defined(_KERNEL) || defined(KERNEL) +#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) # include #else # include @@ -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 #if !defined(__SVR4) && !defined(__svr4__) -# include +# ifndef linux +# include +# endif #else # include # include # include #endif -#include -#include +#ifndef linux +# include +# include +#endif #include #ifdef sun # include @@ -40,17 +44,20 @@ static char rcsid[] = "$Id: fil.c,v 2.0.2.13 1997/05/24 07:33:37 darrenr Exp $"; #include #include #include -#include +#ifndef linux +# include +#endif #include #include -#include #include #include "netinet/ip_compat.h" +#include #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) -# if SOLARIS -extern kmutex_t ipf_mutex; -# define SEND_RESET(ip, qif, q, if) send_reset(ip, qif, q) -# 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 -# 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) \ - icmp_error(b, t, c, (src).s_addr, if) -# endif +# define IPLLOG(a, c, d, e) ipflog(a, c, d, e) +# if SOLARIS || defined(__sgi) +extern kmutex_t ipf_mutex, ipf_auth; # endif -#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) +# define SEND_RESET(ip, qif, if) send_reset((struct tcpiphdr *)ip) +# 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) +# endif /* linux */ +# else +# define ICMP_ERROR(b, ip, t, c, if, src) \ + icmp_error(b, t, c, (src).s_addr, if) +# 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 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; +} diff --git a/sys/netinet/ip_auth.c b/sys/netinet/ip_auth.c new file mode 100644 index 000000000000..2640a77245cc --- /dev/null +++ b/sys/netinet/ip_auth.c @@ -0,0 +1,494 @@ +/* + * Copyright (C) 1997 by Darren Reed & Guido van Rooij. + * + * 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) +static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.0.2.21.2.2 1997/11/12 10:45:51 darrenr Exp $"; +#endif + +#if !defined(_KERNEL) && !defined(KERNEL) +# include +# include +#endif +#include +#include +#include +#include +#include +#if defined(KERNEL) && (__FreeBSD_version >= 220000) +# include +# include +#else +# include +#endif +#include +#ifndef linux +# include +#endif +#include +#if defined(_KERNEL) && !defined(linux) +# include +#endif +#if !defined(__SVR4) && !defined(__svr4__) +# ifndef linux +# include +# endif +#else +# include +# include +# include +# include +# include +#endif +#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) +# include +#endif +#include +#ifdef sun +#include +#endif +#include +#include +#include +#include +#ifndef KERNEL +#define KERNEL +#define NOT_KERNEL +#endif +#ifndef linux +# include +#endif +#ifdef NOT_KERNEL +#undef KERNEL +#endif +#ifdef __sgi +# ifdef IFF_DRVRLOCK /* IRIX6 */ +#include +# endif +#endif +#include +#if defined(__sgi) && !defined(IFF_DRVRLOCK) /* IRIX < 6 */ +extern struct ifqueue ipintrq; /* ip packet input queue */ +#else +# ifndef linux +# include +# include +# endif +#endif +#include +#include +#include "netinet/ip_compat.h" +#include +#include "netinet/ip_fil.h" +#include "netinet/ip_auth.h" +#if !SOLARIS && !defined(linux) +# include +#endif + + +#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) +extern kmutex_t ipf_auth; +# if SOLARIS +extern kcondvar_t ipfauthwait; +# endif +#endif +#ifdef linux +static struct wait_queue *ipfauthwait = NULL; +#endif + +int fr_authsize = FR_NUMAUTH; +int fr_authused = 0; +int fr_defaultauthage = 600; +fr_authstat_t fr_authstats; +frauth_t fr_auth[FR_NUMAUTH]; +mb_t *fr_authpkts[FR_NUMAUTH]; +int fr_authstart = 0, fr_authend = 0, fr_authnext = 0; +frauthent_t *fae_list = NULL; +frentry_t *ipauth = NULL; + + +/* + * Check if a packet has authorization. If the packet is found to match an + * authorization result and that would result in a feedback loop (i.e. it + * will end up returning FR_AUTH) then return FR_BLOCK instead. + */ +int fr_checkauth(ip, fin) +ip_t *ip; +fr_info_t *fin; +{ + u_short id = ip->ip_id; + u_32_t pass; + int i; + + MUTEX_ENTER(&ipf_auth); + for (i = fr_authstart; i != fr_authend; ) { + /* + * index becomes -2 only after an SIOCAUTHW. Check this in + * case the same packet gets sent again and it hasn't yet been + * auth'd. + */ + if ((fr_auth[i].fra_index == -2) && + (id == fr_auth[i].fra_info.fin_id) && + !bcmp((char *)fin,(char *)&fr_auth[i].fra_info,FI_CSIZE)) { + /* + * Avoid feedback loop. + */ + if (!(pass = fr_auth[i].fra_pass) || (pass & FR_AUTH)) + pass = FR_BLOCK; + fr_authstats.fas_hits++; + fr_auth[i].fra_index = -1; + fr_authused--; + if (i == fr_authstart) { + while (fr_auth[i].fra_index == -1) { + i++; + if (i == FR_NUMAUTH) + i = 0; + fr_authstart = i; + if (i == fr_authend) + break; + } + if (fr_authstart == fr_authend) { + fr_authnext = 0; + fr_authstart = fr_authend = 0; + } + } + MUTEX_EXIT(&ipf_auth); + return pass; + } + i++; + if (i == FR_NUMAUTH) + i = 0; + } + fr_authstats.fas_miss++; + MUTEX_EXIT(&ipf_auth); + return 0; +} + + +/* + * Check if we have room in the auth array to hold details for another packet. + * If we do, store it and wake up any user programs which are waiting to + * hear about these events. + */ +int fr_newauth(m, fin, ip +#if defined(_KERNEL) && SOLARIS +, qif) +qif_t *qif; +#else +) +#endif +mb_t *m; +fr_info_t *fin; +ip_t *ip; +{ + int i; + + MUTEX_ENTER(&ipf_auth); + if ((fr_authstart > fr_authend) && (fr_authstart - fr_authend == -1)) { + fr_authstats.fas_nospace++; + MUTEX_EXIT(&ipf_auth); + return 0; + } + if (fr_authend - fr_authstart == FR_NUMAUTH - 1) { + fr_authstats.fas_nospace++; + MUTEX_EXIT(&ipf_auth); + return 0; + } + + fr_authstats.fas_added++; + fr_authused++; + i = fr_authend++; + if (fr_authend == FR_NUMAUTH) + fr_authend = 0; + MUTEX_EXIT(&ipf_auth); + fr_auth[i].fra_index = i; + fr_auth[i].fra_pass = 0; + fr_auth[i].fra_age = fr_defaultauthage; + bcopy((char *)fin, (char *)&fr_auth[i].fra_info, sizeof(*fin)); +#if !defined(sparc) && !defined(m68k) + /* + * No need to copyback here as we want to undo the changes, not keep + * them. + */ +# if SOLARIS && defined(_KERNEL) + if (ip == (ip_t *)m->b_rptr) +# endif + { + register u_short bo; + + bo = ip->ip_len; + ip->ip_len = htons(bo); +# if !SOLARIS /* 4.4BSD converts this ip_input.c, but I don't in solaris.c */ + bo = ip->ip_id; + ip->ip_id = htons(bo); +# endif + bo = ip->ip_off; + ip->ip_off = htons(bo); + } +#endif +#if SOLARIS && defined(_KERNEL) + m->b_rptr -= qif->qf_off; + fr_authpkts[i] = *(mblk_t **)fin->fin_mp; + fr_auth[i].fra_q = qif->qf_q; + cv_signal(&ipfauthwait); +#else + fr_authpkts[i] = m; +# if defined(linux) && defined(_KERNEL) + wake_up_interruptible(&ipfauthwait); +# else + WAKEUP(&fr_authnext); +# endif +#endif + return 1; +} + + +int fr_auth_ioctl(data, cmd, fr, frptr) +caddr_t data; +#if defined(__NetBSD__) || defined(__OpenBSD__) +u_long cmd; +#else +int cmd; +#endif +frentry_t *fr, **frptr; +{ + mb_t *m; +#if defined(_KERNEL) +# if !SOLARIS + struct ifqueue *ifq; + int s; +# endif +#endif + frauth_t auth, *au = &auth; + frauthent_t *fae, **faep; + int i, error = 0; + + switch (cmd) + { + case SIOCINIFR : + case SIOCRMIFR : + case SIOCADIFR : + error = EINVAL; + break; + case SIOCINAFR : + case SIOCRMAFR : + case SIOCADAFR : + for (faep = &fae_list; (fae = *faep); ) + if (&fae->fae_fr == fr) + break; + else + faep = &fae->fae_next; + if (cmd == SIOCRMAFR) { + if (!fae) + error = ESRCH; + else { + *faep = fae->fae_next; + *frptr = fr->fr_next; + KFREE(fae); + } + } else { + KMALLOC(fae, frauthent_t *, sizeof(*fae)); + if (fae != NULL) { + IRCOPY((char *)data, (char *)&fae->fae_fr, + sizeof(fae->fae_fr)); + if (!fae->fae_age) + fae->fae_age = fr_defaultauthage; + fae->fae_fr.fr_hits = 0; + fae->fae_fr.fr_next = *frptr; + *frptr = &fae->fae_fr; + fae->fae_next = *faep; + *faep = fae; + } else + error = ENOMEM; + } + break; + case SIOCATHST: + IWCOPY((char *)&fr_authstats, data, sizeof(fr_authstats)); + break; + case SIOCAUTHW: +fr_authioctlloop: + MUTEX_ENTER(&ipf_auth); + if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) { + IWCOPY((char *)&fr_auth[fr_authnext++], data, + sizeof(fr_info_t)); + if (fr_authnext == FR_NUMAUTH) + fr_authnext = 0; + MUTEX_EXIT(&ipf_auth); + return 0; + } +#ifdef _KERNEL +# if SOLARIS + if (!cv_wait_sig(&ipfauthwait, &ipf_auth)) { + mutex_exit(&ipf_auth); + return EINTR; + } +# else +# ifdef linux + interruptible_sleep_on(&ipfauthwait); + if (current->signal & ~current->blocked) + error = -EINTR; +# else + error = SLEEP(&fr_authnext, "fr_authnext"); +# endif +# endif +#endif + MUTEX_EXIT(&ipf_auth); + if (!error) + goto fr_authioctlloop; + break; + case SIOCAUTHR: + IRCOPY(data, (caddr_t)&auth, sizeof(auth)); + MUTEX_ENTER(&ipf_auth); + i = au->fra_index; + if ((i < 0) || (i > FR_NUMAUTH) || + (fr_auth[i].fra_info.fin_id != au->fra_info.fin_id)) { + MUTEX_EXIT(&ipf_auth); + return EINVAL; + } + m = fr_authpkts[i]; + fr_auth[i].fra_index = -2; + fr_auth[i].fra_pass = au->fra_pass; + fr_authpkts[i] = NULL; +#ifdef _KERNEL + MUTEX_EXIT(&ipf_auth); + SPL_NET(s); +# ifndef linux + if (m && au->fra_info.fin_out) { +# if SOLARIS + error = fr_qout(fr_auth[i].fra_q, m); +# else /* SOLARIS */ + error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); +# endif /* SOLARIS */ + if (error) + fr_authstats.fas_sendfail++; + else + fr_authstats.fas_sendok++; + } else if (m) { +# if SOLARIS + error = fr_qin(fr_auth[i].fra_q, m); +# else /* SOLARIS */ + ifq = &ipintrq; + if (IF_QFULL(ifq)) { + IF_DROP(ifq); + m_freem(m); + error = ENOBUFS; + } else { + IF_ENQUEUE(ifq, m); + schednetisr(NETISR_IP); + } +# endif /* SOLARIS */ + if (error) + fr_authstats.fas_quefail++; + else + fr_authstats.fas_queok++; + } else + error = EINVAL; +# endif +# if SOLARIS + if (error) + error = EINVAL; +# else + /* + * If we experience an error which will result in the packet + * not being processed, make sure we advance to the next one. + */ + if (error == ENOBUFS) { + fr_authused--; + fr_auth[i].fra_index = -1; + fr_auth[i].fra_pass = 0; + if (i == fr_authstart) { + while (fr_auth[i].fra_index == -1) { + i++; + if (i == FR_NUMAUTH) + i = 0; + fr_authstart = i; + if (i == fr_authend) + break; + } + if (fr_authstart == fr_authend) { + fr_authnext = 0; + fr_authstart = fr_authend = 0; + } + } + } +# endif + SPL_X(s); +#endif /* _KERNEL */ + break; + default : + error = EINVAL; + break; + } + return error; +} + + +#ifdef _KERNEL +/* + * Free all network buffer memory used to keep saved packets. + */ +void fr_authunload() +{ + register int i; + register frauthent_t *fae, **faep; + mb_t *m; + + MUTEX_ENTER(&ipf_auth); + for (i = 0; i < FR_NUMAUTH; i++) { + if ((m = fr_authpkts[i])) { + FREE_MB_T(m); + fr_authpkts[i] = NULL; + fr_auth[i].fra_index = -1; + } + } + + + for (faep = &fae_list; (fae = *faep); ) { + *faep = fae->fae_next; + KFREE(fae); + } + MUTEX_EXIT(&ipf_auth); +} + + +/* + * Slowly expire held auth records. Timeouts are set + * in expectation of this being called twice per second. + */ +void fr_authexpire() +{ + register int i; + register frauth_t *fra; + register frauthent_t *fae, **faep; + mb_t *m; +#if !SOLARIS + int s; +#endif + + SPL_NET(s); + MUTEX_ENTER(&ipf_auth); + for (i = 0, fra = fr_auth; i < FR_NUMAUTH; i++, fra++) { + if ((!--fra->fra_age) && (m = fr_authpkts[i])) { + FREE_MB_T(m); + fr_authpkts[i] = NULL; + fr_auth[i].fra_index = -1; + fr_authstats.fas_expire++; + fr_authused--; + } + } + + for (faep = &fae_list; (fae = *faep); ) { + if (!--fra->fra_age) { + *faep = fae->fae_next; + KFREE(fae); + fr_authstats.fas_expire++; + } else + faep = &fae->fae_next; + } + MUTEX_EXIT(&ipf_auth); + SPL_X(s); +} +#endif diff --git a/sys/netinet/ip_auth.h b/sys/netinet/ip_auth.h new file mode 100644 index 000000000000..06f7cf6f00ec --- /dev/null +++ b/sys/netinet/ip_auth.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 1997 by Darren Reed & Guido Van Rooij. + * + * 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. + * + * $Id: ip_auth.h,v 2.0.2.10 1997/10/29 12:14:07 darrenr Exp $ + * + */ +#ifndef __IP_AUTH_H__ +#define __IP_AUTH_H__ + +#define FR_NUMAUTH 32 + +typedef struct fr_authstat { + U_QUAD_T fas_hits; + U_QUAD_T fas_miss; + u_long fas_nospace; + u_long fas_added; + u_long fas_sendfail; + u_long fas_sendok; + u_long fas_queok; + u_long fas_quefail; + u_long fas_expire; +} fr_authstat_t; + +typedef struct frauth { + int fra_age; + int fra_index; + u_32_t fra_pass; + fr_info_t fra_info; +#if SOLARIS + queue_t *fra_q; +#endif +} frauth_t; + +typedef struct frauthent { + struct frentry fae_fr; + struct frauthent *fae_next; + u_long fae_age; +} frauthent_t; + + +extern frentry_t *ipauth; +extern struct fr_authstat fr_authstats; +extern int fr_defaultauthage; +extern int fr_authstart; +extern int fr_authend; +extern int fr_authsize; +extern int fr_authused; +extern int fr_checkauth __P((ip_t *, fr_info_t *)); +extern void fr_authexpire __P((void)); +extern void fr_authunload __P((void)); +extern mb_t *fr_authpkts[]; +#if defined(_KERNEL) && SOLARIS +extern int fr_newauth __P((mb_t *, fr_info_t *, ip_t *, qif_t *)); +#else +extern int fr_newauth __P((mb_t *, fr_info_t *, ip_t *)); +#endif +#if defined(__NetBSD__) || defined(__OpenBSD__) +extern int fr_auth_ioctl __P((caddr_t, u_long, frentry_t *, frentry_t **)); +#else +extern int fr_auth_ioctl __P((caddr_t, int, frentry_t *, frentry_t **)); +#endif +#endif /* __IP_AUTH_H__ */ diff --git a/sys/netinet/ip_compat.h b/sys/netinet/ip_compat.h index cbb3239b2b8d..3866ef083540 100644 --- a/sys/netinet/ip_compat.h +++ b/sys/netinet/ip_compat.h @@ -1,12 +1,12 @@ /* - * (C)opyright 1993-1997 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. * * @(#)ip_compat.h 1.8 1/14/96 - * $Id: ip_compat.h,v 2.0.2.11 1997/05/04 05:29:02 darrenr Exp $ + * $Id: ip_compat.h,v 2.0.2.31.2.4 1997/11/12 10:48:43 darrenr Exp $ */ #ifndef __IP_COMPAT_H__ @@ -17,6 +17,7 @@ # define __P(x) x # else # define __P(x) () +# define const # endif #endif @@ -25,25 +26,51 @@ #endif #if defined(_KERNEL) && !defined(KERNEL) -#define KERNEL +# define KERNEL #endif #if defined(KERNEL) && !defined(_KERNEL) -#define _KERNEL +# define _KERNEL +#endif +#if!defined(__KERNEL__) && defined(KERNEL) +# define __KERNEL__ #endif -#if defined(__SVR4) || defined(__svr4__) +#if defined(__SVR4) || defined(__svr4__) || defined(__sgi) #define index strchr -# ifndef _KERNEL +# if !defined(_KERNEL) # define bzero(a,b) memset(a,0,b) # define bcmp memcmp # define bcopy(a,b,c) memmove(b,a,c) # endif #endif +#if defined(__sgi) || defined(bsdi) +struct ether_addr { + u_char ether_addr_octet[6]; +}; +#endif + +#ifdef __sgi +# ifdef IPFILTER_LKM +# define IPL_PRFX ipl +# define IPL_EXTERN(ep) ipl##ep +# else +# define IPL_PRFX ipfilter +# define IPL_EXTERN(ep) ipfilter##ep +# endif +#else +# define IPL_PRFX ipl +# define IPL_EXTERN(ep) ipl##ep +#endif + +#ifdef linux +# include +#endif #if SOLARIS # define MTYPE(m) ((m)->b_datap->db_type) # include # include +# include /* * because Solaris 2 defines these in two places :-/ */ @@ -59,12 +86,12 @@ # include # include # undef _KERNEL -# else +# else /* _KERNEL */ # include # include # include -# endif -#endif +# endif /* _KERNEL */ +#endif /* SOLARIS */ #define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h))) #ifndef IP_OFFMASK @@ -75,10 +102,26 @@ # define USE_QUAD_T # define U_QUAD_T u_quad_t # define QUAD_T quad_t -#else +#else /* BSD > 199306 */ # define U_QUAD_T u_long # define QUAD_T long -#endif +#endif /* BSD > 199306 */ + +/* + * These operating systems already take care of the problem for us. + */ +#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) +typedef u_int32_t u_32_t; +#else +/* + * Really, any arch where sizeof(long) != sizeof(int). + */ +# if defined(__alpha__) || defined(__alpha) +typedef unsigned int u_32_t; +# else +typedef unsigned long u_32_t; +# endif +#endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ */ #ifndef MAX #define MAX(a,b) (((a) > (b)) ? (a) : (b)) @@ -141,52 +184,39 @@ #define IPOPT_FINN 205 /* FINN */ -#ifdef __FreeBSD__ -# include +#if defined(__FreeBSD__) && defined(KERNEL) +# if __FreeBSD__ < 3 +# include +# endif # if defined(IPFILTER_LKM) && !defined(ACTUALLY_LKM_NOT_KERNEL) # define ACTUALLY_LKM_NOT_KERNEL # endif -#endif +#endif /* __FreeBSD__ && KERNEL */ /* * Build some macros and #defines to enable the same code to compile anywhere * Well, that's the idea, anyway :-) */ -#if defined(_KERNEL) || defined(KERNEL) +#ifdef KERNEL # if SOLARIS # define MUTEX_ENTER(x) mutex_enter(x) # define MUTEX_EXIT(x) mutex_exit(x) # define MTOD(m,t) (t)((m)->b_rptr) # define IRCOPY(a,b,c) copyin((a), (b), (c)) # define IWCOPY(a,b,c) copyout((a), (b), (c)) -# else -# define MUTEX_ENTER(x) ; -# define MUTEX_EXIT(x) ; -# ifndef linux -# define MTOD(m,t) mtod(m,t) -# define IRCOPY(a,b,c) bcopy((a), (b), (c)) -# define IWCOPY(a,b,c) bcopy((a), (b), (c)) -# endif -# endif /* SOLARIS */ - -# ifdef sun -# if defined(__svr4__) || defined(__SVR4) -extern ill_t *get_unit __P((char *)); -# define GETUNIT(n) get_unit((n)) -# else -# include -# define GETUNIT(n) ifunit((n), IFNAMSIZ) -# endif -# else -# define GETUNIT(n) ifunit((n)) -# endif /* sun */ - -# if defined(sun) && !defined(linux) -# define UIOMOVE(a,b,c,d) uiomove(a,b,c,d) -# define SLEEP(id, n) sleep((id), PZERO+1) -# define KFREE(x) kmem_free((char *)(x), sizeof(*(x))) -# define KFREES(x,s) kmem_free((char *)(x), (s)) -# if SOLARIS +# define FREE_MB_T(m) freemsg(m) +# define SPL_NET(x) ; +# define SPL_IMP(x) ; +# undef SPL_X +# define SPL_X(x) ; +# ifdef sparc +# define ntohs(x) (x) +# define ntohl(x) (x) +# define htons(x) (x) +# define htonl(x) (x) +# endif /* sparc */ +# define KMALLOC(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) +# define GET_MINOR(x) getminor(x) typedef struct qif { struct qif *qf_next; ill_t *qf_ill; @@ -195,51 +225,90 @@ typedef struct qif { void *qf_optr; queue_t *qf_in; queue_t *qf_out; - void *qf_wqinfo; - void *qf_rqinfo; - int (*qf_inp) __P((queue_t *, mblk_t *)); - int (*qf_outp) __P((queue_t *, mblk_t *)); - mblk_t *qf_m; - int qf_len; + struct qinit *qf_wqinfo; + struct qinit *qf_rqinfo; + struct qinit qf_wqinit; + struct qinit qf_rqinit; + mblk_t *qf_m; /* These three fields are for passing data up from */ + queue_t *qf_q; /* fr_qin and fr_qout to the packet processing. */ + int qf_off; + int qf_len; /* this field is used for in ipfr_fastroute */ char qf_name[8]; /* * in case the ILL has disappeared... */ int qf_hl; /* header length */ } qif_t; -# define SPLNET(x) ; -# undef SPLX -# define SPLX(x) ; -# ifdef sparc -# define ntohs(x) (x) -# define ntohl(x) (x) -# define htons(x) (x) -# define htonl(x) (x) -# endif +extern ill_t *get_unit __P((char *)); +# define GETUNIT(n) get_unit((n)) +# else /* SOLARIS */ +# if defined(__sgi) +# include +# define IPF_LOCK_PL plhi +# include +#undef kmutex_t +typedef struct { + lock_t *l; + int pl; +} kmutex_t; +# define MUTEX_ENTER(x) (x)->pl = LOCK((x)->l, IPF_LOCK_PL); +# define MUTEX_EXIT(x) UNLOCK((x)->l, (x)->pl); +# else /* __sgi */ +# define MUTEX_ENTER(x) ; +# define MUTEX_EXIT(x) ; +# endif /* __sgi */ +# ifndef linux +# define FREE_MB_T(m) m_freem(m) +# define MTOD(m,t) mtod(m,t) +# define IRCOPY(a,b,c) bcopy((a), (b), (c)) +# define IWCOPY(a,b,c) bcopy((a), (b), (c)) +# endif /* !linux */ +# endif /* SOLARIS */ + +# ifdef sun +# if !SOLARIS +# include +# define GETUNIT(n) ifunit((n), IFNAMSIZ) +# endif +# else +# ifndef linux +# define GETUNIT(n) ifunit((n)) +# endif +# endif /* sun */ + +# if defined(sun) && !defined(linux) || defined(__sgi) +# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d) +# define SLEEP(id, n) sleep((id), PZERO+1) +# define WAKEUP(id) wakeup(id) +# define KFREE(x) kmem_free((char *)(x), sizeof(*(x))) +# define KFREES(x,s) kmem_free((char *)(x), (s)) +# if !SOLARIS +extern void m_copydata __P((struct mbuf *, int, int, caddr_t)); +extern void m_copyback __P((struct mbuf *, int, int, caddr_t)); +# endif +# ifdef __sgi +# include +# include # define KMALLOC(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) # define GET_MINOR(x) getminor(x) # else -# define KMALLOC(a,b,c) (a) = (b)new_kmem_alloc((c), KMEM_NOSLEEP) -# endif /* __svr4__ */ +# if !SOLARIS +# define KMALLOC(a,b,c) (a) = (b)new_kmem_alloc((c), KMEM_NOSLEEP) +# endif /* SOLARIS */ +# endif /* __sgi */ # endif /* sun && !linux */ # ifndef GET_MINOR # define GET_MINOR(x) minor(x) # endif -# if BSD >= 199306 || defined(__FreeBSD__) +# if (BSD >= 199306) || defined(__FreeBSD__) # include # if !defined(__FreeBSD__) || (defined (__FreeBSD__) && __FreeBSD__>=3) # include # include extern vm_map_t kmem_map; -# else +# else /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD__>=3) */ # include -# endif /* __FreeBSD__ */ -/* -# define KMALLOC(a,b,c) (a) = (b)kmem_alloc(kmem_map, (c)) -# define KFREE(x) kmem_free(kmem_map, (vm_offset_t)(x), \ - sizeof(*(x))) -# define KFREES(x,s) kmem_free(kmem_map, (vm_offset_t)(x), (s)) -*/ +# endif /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD__>=3) */ # ifdef M_PFIL # define KMALLOC(a, b, c) MALLOC((a), b, (c), M_PFIL, M_NOWAIT) # define KFREE(x) FREE((x), M_PFIL) @@ -248,26 +317,32 @@ extern vm_map_t kmem_map; # define KMALLOC(a, b, c) MALLOC((a), b, (c), M_TEMP, M_NOWAIT) # define KFREE(x) FREE((x), M_TEMP) # define KFREES(x,s) FREE((x), M_TEMP) -# endif +# endif /* M_PFIL */ # define UIOMOVE(a,b,c,d) uiomove(a,b,d) # define SLEEP(id, n) tsleep((id), PPAUSE|PCATCH, n, 0) +# define WAKEUP(id) wakeup(id) # endif /* BSD */ -# if defined(NetBSD1_0) && (NetBSD1_0 > 1) -# define SPLNET(x) x = splsoftnet() +# if defined(NetBSD) && NetBSD <= 1991011 && NetBSD >= 199407 +# define SPL_NET(x) x = splsoftnet() +# define SPL_X(x) (void) splx(x) # else -# if !SOLARIS -# define SPLNET(x) x = splnet() -# define SPLX(x) (void) splx(x) +# if !SOLARIS && !defined(linux) +# define SPL_IMP(x) x = splimp() +# define SPL_NET(x) x = splnet() +# define SPL_X(x) (void) splx(x) # endif -# endif +# endif /* NetBSD && NetBSD <= 1991011 && NetBSD >= 199407 */ # define PANIC(x,y) if (x) panic y -#else +#else /* KERNEL */ +# define SLEEP(x,y) ; +# define WAKEUP(x) ; # define PANIC(x,y) ; # define MUTEX_ENTER(x) ; # define MUTEX_EXIT(x) ; -# define SPLNET(x) ; -# undef SPLX -# define SPLX(x) ; +# define SPL_NET(x) ; +# define SPL_IMP(x) ; +# undef SPL_X +# define SPL_X(x) ; # define KMALLOC(a,b,c) (a) = (b)malloc(c) # define KFREE(x) free(x) # define KFREES(x,s) free(x) @@ -276,25 +351,187 @@ extern vm_map_t kmem_map; # define IWCOPY(a,b,c) bcopy((a), (b), (c)) #endif /* KERNEL */ -#ifdef linux -# define ICMP_UNREACH ICMP_DEST_UNREACH -# define ICMP_SOURCEQUENCH ICMP_SOURCE_QUENCH -# define ICMP_TIMXCEED ICMP_TIME_EXCEEDED -# define ICMP_PARAMPROB ICMP_PARAMETERPROB +#if SOLARIS +typedef mblk_t mb_t; +#else +# ifdef linux +typedef struct sk_buff mb_t; +# else +typedef struct mbuf mb_t; +# endif +#endif /* SOLARIS */ +#if defined(linux) || defined(__sgi) +/* + * These #ifdef's are here mainly for linux, but who knows, they may + * not be in other places or maybe one day linux will grow up and some + * of these will turn up there too. + */ +#ifndef ICMP_UNREACH +# define ICMP_UNREACH ICMP_DEST_UNREACH +#endif +#ifndef ICMP_SOURCEQUENCH +# define ICMP_SOURCEQUENCH ICMP_SOURCE_QUENCH +#endif +#ifndef ICMP_TIMXCEED +# define ICMP_TIMXCEED ICMP_TIME_EXCEEDED +#endif +#ifndef ICMP_PARAMPROB +# define ICMP_PARAMPROB ICMP_PARAMETERPROB +#endif +#ifndef ICMP_TSTAMP +# define ICMP_TSTAMP ICMP_TIMESTAMP +#endif +#ifndef ICMP_TSTAMPREPLY +# define ICMP_TSTAMPREPLY ICMP_TIMESTAMPREPLY +#endif +#ifndef ICMP_IREQ +# define ICMP_IREQ ICMP_INFO_REQUEST +#endif +#ifndef ICMP_IREQREPLY +# define ICMP_IREQREPLY ICMP_INFO_REPLY +#endif +#ifndef ICMP_MASKREQ +# define ICMP_MASKREQ ICMP_ADDRESS +#endif +#ifndef ICMP_MASKREPLY +# define ICMP_MASKREPLY ICMP_ADDRESSREPLY +#endif +#ifndef IPVERSION +# define IPVERSION 4 +#endif +#ifndef IPOPT_MINOFF +# define IPOPT_MINOFF 4 +#endif +#ifndef IPOPT_COPIED +# define IPOPT_COPIED(x) ((x)&0x80) +#endif +#ifndef IPOPT_EOL +# define IPOPT_EOL 0 +#endif +#ifndef IPOPT_NOP +# define IPOPT_NOP 1 +#endif +#ifndef IP_MF +# define IP_MF ((u_short)0x2000) +#endif +#ifndef ETHERTYPE_IP +# define ETHERTYPE_IP ((u_short)0x0800) +#endif +#ifndef TH_FIN # define TH_FIN 0x01 +#endif +#ifndef TH_SYN # define TH_SYN 0x02 +#endif +#ifndef TH_RST # define TH_RST 0x04 +#endif +#ifndef TH_PUSH # define TH_PUSH 0x08 +#endif +#ifndef TH_ACK # define TH_ACK 0x10 +#endif +#ifndef TH_URG # define TH_URG 0x20 +#endif +#ifndef IPOPT_EOL +# define IPOPT_EOL 0 +#endif +#ifndef IPOPT_NOP +# define IPOPT_NOP 1 +#endif +#ifndef IPOPT_RR +# define IPOPT_RR 7 +#endif +#ifndef IPOPT_TS +# define IPOPT_TS 68 +#endif +#ifndef IPOPT_SECURITY +# define IPOPT_SECURITY 130 +#endif +#ifndef IPOPT_LSRR +# define IPOPT_LSRR 131 +#endif +#ifndef IPOPT_SATID +# define IPOPT_SATID 136 +#endif +#ifndef IPOPT_SSRR +# define IPOPT_SSRR 137 +#endif +#ifndef IPOPT_SECUR_UNCLASS +# define IPOPT_SECUR_UNCLASS ((u_short)0x0000) +#endif +#ifndef IPOPT_SECUR_CONFID +# define IPOPT_SECUR_CONFID ((u_short)0xf135) +#endif +#ifndef IPOPT_SECUR_EFTO +# define IPOPT_SECUR_EFTO ((u_short)0x789a) +#endif +#ifndef IPOPT_SECUR_MMMM +# define IPOPT_SECUR_MMMM ((u_short)0xbc4d) +#endif +#ifndef IPOPT_SECUR_RESTR +# define IPOPT_SECUR_RESTR ((u_short)0xaf13) +#endif +#ifndef IPOPT_SECUR_SECRET +# define IPOPT_SECUR_SECRET ((u_short)0xd788) +#endif +#ifndef IPOPT_SECUR_TOPSECRET +# define IPOPT_SECUR_TOPSECRET ((u_short)0x6bc5) +#endif +#ifndef IPOPT_OLEN +# define IPOPT_OLEN 1 +#endif +#endif /* linux || __sgi */ + +#ifdef linux +/* + * TCP States + */ +#define TCPS_CLOSED 0 /* closed */ +#define TCPS_LISTEN 1 /* listening for connection */ +#define TCPS_SYN_SENT 2 /* active, have sent syn */ +#define TCPS_SYN_RECEIVED 3 /* have send and received syn */ +/* states < TCPS_ESTABLISHED are those where connections not established */ +#define TCPS_ESTABLISHED 4 /* established */ +#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ +/* states > TCPS_CLOSE_WAIT are those where user has closed */ +#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ +#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ +#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ +/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ +#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ +#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ + +/* + * file flags. + */ +#define FWRITE WRITE +#define FREAD READ +/* + * mbuf related problems. + */ +#define mtod(m,t) (t)((m)->data) +#define m_len len +#define m_next next + +#define IP_DF 0x8000 typedef struct { __u16 th_sport; __u16 th_dport; __u32 th_seq; __u32 th_ack; - __u8 th_x; +# if defined(__i386__) || defined(__MIPSEL__) || defined(__alpha__) ||\ + defined(vax) + __u8 th_res:4; + __u8 th_off:4; +#else + __u8 th_off:4; + __u8 th_res:4; +#endif __u8 th_flags; __u16 th_win; __u16 th_sum; @@ -305,7 +542,7 @@ typedef struct { __u16 uh_sport; __u16 uh_dport; __u16 uh_ulen; - __u16 uh_sun; + __u16 uh_sum; } udphdr_t; typedef struct { @@ -331,7 +568,7 @@ typedef struct { /* * Structure of an icmp header. */ -struct icmp { +typedef struct icmp { u_char icmp_type; /* type of message, see below */ u_char icmp_code; /* type sub code */ u_short icmp_cksum; /* ones complement cksum of struct */ @@ -368,8 +605,10 @@ struct icmp { # define icmp_ip icmp_dun.id_ip.idi_ip # define icmp_mask icmp_dun.id_mask # define icmp_data icmp_dun.id_data -}; +} icmphdr_t; +# ifndef LINUX_IPOVLY +# define LINUX_IPOVLY struct ipovly { caddr_t ih_next, ih_prev; /* for protocol sequence q's */ u_char ih_x1; /* (unused) */ @@ -378,36 +617,98 @@ struct ipovly { struct in_addr ih_src; /* source internet address */ struct in_addr ih_dst; /* destination internet address */ }; +# endif -# define SPLX(x) (void) -# define SPLNET(x) (void) +typedef struct { + __u8 ether_dhost[6]; + __u8 ether_shost[6]; + __u16 ether_type; +} ether_header_t; -# define bcopy(a,b,c) memmove(b,a,c) -# define bcmp(a,b,c) memcmp(a,b,c) +typedef struct uio { + int uio_resid; + int uio_rw; + caddr_t uio_buf; +} uio_t; -# define UNITNAME(n) dev_get((n)) -# define ifnet device +# define UIO_READ 0 +# define UIO_WRITE 1 +# define UIOMOVE(a, b, c, d) uiomove(a,b,c,d) -# define KMALLOC(a,b,c) (a) = (b)kmalloc((c), GFP_ATOMIC) -# define KFREE(x) kfree_s((x), sizeof(*(x))) -# define KFREES(x,s) kfree_s((x), (s)) -# define IRCOPY(a,b,c) { \ - error = verify_area(VERIFY_READ, \ - (b) ,sizeof((b))); \ +/* + * For masking struct ifnet onto struct device + */ +# define if_name name + +# ifdef KERNEL +# define GETUNIT(x) dev_get(x) +# define FREE_MB_T(m) kfree_skb(m, FREE_WRITE) +# define uniqtime do_gettimeofday +# undef INT_MAX +# undef UINT_MAX +# undef LONG_MAX +# undef ULONG_MAX +# include +# define SPL_X(x) +# define SPL_NET(x) +# define SPL_IMP(x) + +# define bcmp(a,b,c) memcmp(a,b,c) +# define bcopy(a,b,c) memcpy(b,a,c) +# define bzero(a,c) memset(a,0,c) + +# define UNITNAME(n) dev_get((n)) + +# define KMALLOC(a,b,c) (a) = (b)kmalloc((c), GFP_ATOMIC) +# define KFREE(x) kfree_s((x), sizeof(*(x))) +# define KFREES(x,s) kfree_s((x), (s)) +# define IRCOPY(a,b,c) { \ + error = verify_area(VERIFY_READ, (a) ,(c)); \ if (!error) \ memcpy_fromfs((b), (a), (c)); \ } -# define IWCOPY(a,b,c) { \ - error = verify_area(VERIFY_WRITE, \ - (b) ,sizeof((b))); \ +# define IWCOPY(a,b,c) { \ + error = verify_area(VERIFY_WRITE, (b), (c)); \ if (!error) \ memcpy_tofs((b), (a), (c)); \ } +# else +# define __KERNEL__ +# undef INT_MAX +# undef UINT_MAX +# undef LONG_MAX +# undef ULONG_MAX +# include +# undef __KERNEL__ +# endif +# define ifnet device #else typedef struct tcphdr tcphdr_t; typedef struct udphdr udphdr_t; typedef struct icmp icmphdr_t; typedef struct ip ip_t; +typedef struct ether_header ether_header_t; #endif /* linux */ +#if defined(hpux) || defined(linux) +struct ether_addr { + char ether_addr_octet[6]; +}; +#endif + +/* + * XXX - This is one of those *awful* hacks which nobody likes + */ +#ifdef ultrix +#define A_A +#else +#define A_A & +#endif + +#ifndef ICMP_ROUTERADVERT +# define ICMP_ROUTERADVERT 9 +#endif +#ifndef ICMP_ROUTERSOLICIT +# define ICMP_ROUTERSOLICIT 10 +#endif #endif /* __IP_COMPAT_H__ */ diff --git a/sys/netinet/ip_fil.c b/sys/netinet/ip_fil.c index b79c030bb822..c3c758e74396 100644 --- a/sys/netinet/ip_fil.c +++ b/sys/netinet/ip_fil.c @@ -1,23 +1,23 @@ /* - * (C)opyright 1993-1997 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[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-1995 Darren Reed"; -static char rcsid[] = "$Id: ip_fil.c,v 2.0.2.12 1997/05/24 07:39:56 darrenr Exp $"; +#if !defined(lint) +static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.0.2.44.2.2 1997/11/12 10:49:25 darrenr Exp $"; #endif #ifndef SOLARIS #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #endif +#if defined(KERNEL) && !defined(_KERNEL) +# define _KERNEL +#endif #ifdef __FreeBSD__ -# if defined(KERNEL) && !defined(_KERNEL) -# define _KERNEL -# endif # if defined(_KERNEL) && !defined(IPFILTER_LKM) # include # else @@ -25,8 +25,10 @@ static char rcsid[] = "$Id: ip_fil.c,v 2.0.2.12 1997/05/24 07:39:56 darrenr Exp # endif #endif #ifndef _KERNEL -#include -#include +# include +# include +# include +# include #endif #include #include @@ -40,28 +42,40 @@ static char rcsid[] = "$Id: ip_fil.c,v 2.0.2.12 1997/05/24 07:39:56 darrenr Exp #endif #include #ifdef _KERNEL -#include +# include #endif #include #if !SOLARIS -#include -#include +# if (NetBSD > 199609) || (OpenBSD > 199603) +# include +# else +# include +# endif +# include #else -#include +# include #endif #include #include #include #ifdef sun -#include +# include #endif #if __FreeBSD_version >= 300000 # include #endif +#ifdef __sgi +#include +# ifdef IFF_DRVRLOCK /* IRIX6 */ +#include +# endif +#endif #include #include +#if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */ #include +#endif #include #include #include @@ -78,6 +92,7 @@ static char rcsid[] = "$Id: ip_fil.c,v 2.0.2.12 1997/05/24 07:39:56 darrenr Exp #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 @@ -87,45 +102,52 @@ extern int ip_optcopy __P((struct ip *, struct ip *)); extern struct protosw inetsw[]; -#if BSD < 199306 -static int (*fr_saveslowtimo) __P((void)); -extern int tcp_ttl; + +#ifndef _KERNEL +# include "ipt.h" +static struct ifnet **ifneta = NULL; +static int nifs = 0; #else +# if (BSD < 199306) && !defined(__sgi) +static int (*fr_saveslowtimo) __P((void)); +# else static void (*fr_saveslowtimo) __P((void)); +# endif +# if (BSD < 199306) || defined(__sgi) +extern int tcp_ttl; +# endif #endif int ipl_inited = 0; int ipl_unreach = ICMP_UNREACH_FILTER; +u_long ipl_frouteok[2] = {0, 0}; -#ifndef _KERNEL -#include "ipt.h" -static struct ifnet **ifneta = NULL; -static int nifs = 0; -struct ifnet *get_unit __P((char *)); -#endif - -#ifdef IPFILTER_LOG -char iplbuf[3][IPLLOGSIZE]; -caddr_t iplh[3], iplt[3]; -int iplused[3] = {0,0,0}; -#endif /* IPFILTER_LOG */ -static void frflush __P((caddr_t)); -static int frrequest __P((int, caddr_t, int)); +static void fixskip __P((frentry_t **, frentry_t *, int)); static void frzerostats __P((caddr_t)); -#ifdef _KERNEL -static int (*fr_savep) __P((struct ip *, int, struct ifnet *, - int, struct mbuf **)); +static void frsync __P((void)); +#if defined(__NetBSD__) || defined(__OpenBSD__) +static int frrequest __P((int, u_long, caddr_t, int)); #else +static int frrequest __P((int, int, caddr_t, int)); +#endif +#ifdef _KERNEL +static int (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **)); +#else +int ipllog __P((void)); void init_ifp __P((void)); -static int (*fr_savep) __P((struct ip *, int, struct ifnet *, - int, char *)); +# ifdef __sgi +static int no_output __P((struct ifnet *, struct mbuf *, + struct sockaddr *)); +static int write_output __P((struct ifnet *, struct mbuf *, + struct sockaddr *)); +# else static int no_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); -static int write_output __P((struct ifnet *, struct mbuf *, - struct sockaddr *, struct rtentry *)); +static int write_output __P((struct ifnet *, struct mbuf *, + struct sockaddr *, struct rtentry *)); +# endif #endif - #if (_BSDI_VERSION >= 199510) && defined(_KERNEL) # include # include @@ -142,9 +164,19 @@ struct devsw iplsw = { }; #endif /* _BSDI_VERSION >= 199510 && _KERNEL */ +#if defined(__NetBSD__) || defined(__OpenBSD__) +# include +# if defined(NETBSD_PF) +# include +/* + * We provide the fr_checkp name just to minimize changes later. + */ +int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp)); +# endif /* NETBSD_PF */ +#endif /* __NetBSD__ */ #ifdef _KERNEL -# ifdef IPFILTER_LKM +# if defined(IPFILTER_LKM) && !defined(__sgi) int iplidentify(s) char *s; { @@ -155,34 +187,58 @@ char *s; # endif /* IPFILTER_LKM */ +/* + * Try to detect the case when compiling for NetBSD with pseudo-device + */ +# if defined(__NetBSD__) && defined(PFIL_HOOKS) +void +ipfilterattach(count) +int count; +{ + iplattach(); +} +# endif + + int iplattach() { char *defpass; - int s, i; + int s; +# ifdef __sgi + int error; +# endif - SPLNET(s); + SPL_NET(s); if (ipl_inited || (fr_checkp == fr_check)) { printf("IP Filter: already initialized\n"); - SPLX(s); + SPL_X(s); return EBUSY; } + +# ifdef NETBSD_PF + pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT); +# endif + +# ifdef __sgi + error = ipfilter_sgi_attach(); + if (error) { + SPL_X(s); + return error; + } +# endif + ipl_inited = 1; - bzero((char *)nat_table, sizeof(nat_t *) * NAT_SIZE * 2); + bzero((char *)frcache, sizeof(frcache)); + bzero((char *)nat_table, sizeof(nat_table)); fr_savep = fr_checkp; fr_checkp = fr_check; fr_saveslowtimo = inetsw[0].pr_slowtimo; inetsw[0].pr_slowtimo = ipfr_slowtimer; - /* - * Set log buffer pointers for each of the log buffers - */ -#ifdef IPFILTER_LOG - for (i = 0; i <= 2; i++) { - iplh[i] = iplbuf[i]; - iplt[i] = iplbuf[i]; - } -#endif - SPLX(s); +# ifdef IPFILTER_LOG + ipflog_init(); +# endif + SPL_X(s); if (fr_pass & FR_PASS) defpass = "pass"; else if (fr_pass & FR_BLOCK) @@ -190,35 +246,52 @@ int iplattach() else defpass = "no-match -> block"; - printf("IP Filter: initialized. Default = %s all\n", defpass); + printf("IP Filter: initialized. Default = %s all, Logging = %s\n", + defpass, +# ifdef IPFILTER_LOG + "enabled"); +# else + "disabled"); +# endif return 0; } +/* + * Disable the filter by removing the hooks from the IP input/output + * stream. + */ int ipldetach() { int s, i = FR_INQUE|FR_OUTQUE; - SPLNET(s); + SPL_NET(s); if (!ipl_inited) { printf("IP Filter: not initialized\n"); - SPLX(s); - return EBUSY; + SPL_X(s); + return 0; } -#if defined(IPFILTER_LKM) || defined(IPFILTER) fr_checkp = fr_savep; -#endif inetsw[0].pr_slowtimo = fr_saveslowtimo; - frflush((caddr_t)&i); + frflush(IPL_LOGIPF, (caddr_t)&i); ipl_inited = 0; +# ifdef NETBSD_PF + pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT); +# endif + +# ifdef __sgi + ipfilter_sgi_detach(); +# endif + ipfr_unload(); ip_natunload(); fr_stateunload(); + fr_authunload(); - SPLX(s); + SPL_X(s); return 0; } #endif /* _KERNEL */ @@ -240,53 +313,24 @@ caddr_t data; fio.f_acctout[0] = ipacct[1][0]; fio.f_acctout[1] = ipacct[1][1]; fio.f_active = fr_active; + fio.f_froute[0] = ipl_frouteok[0]; + fio.f_froute[1] = ipl_frouteok[1]; IWCOPY((caddr_t)&fio, data, sizeof(fio)); bzero((char *)frstats, sizeof(*frstats) * 2); } -static void frflush(data) -caddr_t data; -{ - struct frentry *f, **fp; - int flags = *(int *)data, flushed = 0, set = fr_active; - - bzero((char *)frcache, sizeof(frcache[0]) * 2); - - if (flags & FR_INACTIVE) - set = 1 - set; - if (flags & FR_OUTQUE) { - for (fp = &ipfilter[1][set]; (f = *fp); ) { - *fp = f->fr_next; - KFREE(f); - flushed++; - } - for (fp = &ipacct[1][set]; (f = *fp); ) { - *fp = f->fr_next; - KFREE(f); - flushed++; - } - } - if (flags & FR_INQUE) { - for (fp = &ipfilter[0][set]; (f = *fp); ) { - *fp = f->fr_next; - KFREE(f); - flushed++; - } - for (fp = &ipacct[0][set]; (f = *fp); ) { - *fp = f->fr_next; - KFREE(f); - flushed++; - } - } - *(int *)data = flushed; -} - - /* * Filter ioctl interface. */ -int iplioctl(dev, cmd, data, mode +#ifdef __sgi +int IPL_EXTERN(ioctl)(dev_t dev, int cmd, caddr_t data, int mode +# ifdef _KERNEL + , cred_t *cp, int *rp +# endif +) +#else +int IPL_EXTERN(ioctl)(dev, cmd, data, mode #if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ (__FreeBSD_version >= 220000)) && defined(_KERNEL) , p) @@ -295,34 +339,43 @@ struct proc *p; ) #endif dev_t dev; +#if defined(__NetBSD__) || defined(__OpenBSD__) +u_long cmd; +#else int cmd; +#endif caddr_t data; int mode; +#endif /* __sgi */ { - int error = 0, s, unit; +#if defined(_KERNEL) && !SOLARIS + int s; +#endif + int error = 0, unit = 0; #ifdef _KERNEL - unit = minor(dev); - if ((2 < unit) || (unit < 0)) + unit = GET_MINOR(dev); + if ((IPL_LOGMAX < unit) || (unit < 0)) return ENXIO; #endif - SPLNET(s); + SPL_NET(s); if (unit == IPL_LOGNAT) { error = nat_ioctl(data, cmd, mode); - SPLX(s); + SPL_X(s); return error; } if (unit == IPL_LOGSTATE) { error = fr_state_ioctl(data, cmd, mode); - SPLX(s); + SPL_X(s); return error; } switch (cmd) { case FIONREAD : #ifdef IPFILTER_LOG - *(int *)data = iplused[IPL_LOGIPF]; + IWCOPY((caddr_t)&iplused[IPL_LOGIPF], (caddr_t)data, + sizeof(iplused[IPL_LOGIPF])); #endif break; #if !defined(IPFILTER_LKM) && defined(_KERNEL) @@ -358,7 +411,7 @@ int mode; if (!(mode & FWRITE)) error = EPERM; else - error = frrequest(cmd, data, fr_active); + error = frrequest(unit, cmd, data, fr_active); break; case SIOCINIFR : case SIOCRMIFR : @@ -366,7 +419,7 @@ int mode; if (!(mode & FWRITE)) error = EPERM; else - error = frrequest(cmd, data, 1 - fr_active); + error = frrequest(unit, cmd, data, 1 - fr_active); break; case SIOCSWAPA : if (!(mode & FWRITE)) @@ -391,7 +444,10 @@ int mode; fio.f_acctin[1] = ipacct[0][1]; fio.f_acctout[0] = ipacct[1][0]; fio.f_acctout[1] = ipacct[1][1]; + fio.f_auth = ipauth; fio.f_active = fr_active; + fio.f_froute[0] = ipl_frouteok[0]; + fio.f_froute[1] = ipl_frouteok[1]; IWCOPY((caddr_t)&fio, data, sizeof(fio)); break; } @@ -405,58 +461,135 @@ int mode; if (!(mode & FWRITE)) error = EPERM; else - frflush(data); + frflush(unit, data); break; #ifdef IPFILTER_LOG case SIOCIPFFB : if (!(mode & FWRITE)) error = EPERM; - else { - *(int *)data = iplused[unit]; - iplh[unit] = iplt[unit] = iplbuf[unit]; - iplused[unix] = 0; - } + else + *(int *)data = ipflog_clear(unit); break; #endif /* IPFILTER_LOG */ case SIOCGFRST : IWCOPY((caddr_t)ipfr_fragstats(), data, sizeof(ipfrstat_t)); break; + case SIOCAUTHW : + case SIOCAUTHR : + if (!(mode & FWRITE)) { + error = EPERM; + break; + } + case SIOCATHST : + error = fr_auth_ioctl(data, cmd, NULL, NULL); + break; + case SIOCFRSYN : + if (!(mode & FWRITE)) + error = EPERM; + else { +#if defined(_KERNEL) && defined(__sgi) + ipfsync(); +#endif + frsync(); + } + break; default : error = EINVAL; break; } - SPLX(s); + SPL_X(s); return error; } -static int frrequest(req, data, set) -int req, set; +static void frsync() +{ +#ifdef _KERNEL + struct ifnet *ifp; + +# if defined(__OpenBSD__) || (NetBSD >= 199511) + for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) +# else + for (ifp = ifnet; ifp; ifp = ifp->if_next) +# endif + ip_natsync(ifp); +#endif +} + + +static void fixskip(listp, rp, addremove) +frentry_t **listp, *rp; +int addremove; +{ + frentry_t *fp; + int rules = 0, rn = 0; + + for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rules++) + ; + + if (!fp) + return; + + for (fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++) + if (fp->fr_skip && (rn + fp->fr_skip >= rules)) + fp->fr_skip += addremove; +} + + +static int frrequest(unit, req, data, set) +int unit; +#if defined(__NetBSD__) || defined(__OpenBSD__) +u_long req; +#else +int req; +#endif +int set; caddr_t data; { register frentry_t *fp, *f, **fprev; register frentry_t **ftail; frentry_t frd; frdest_t *fdp; - int error = 0, in; + frgroup_t *fg = NULL; + int error = 0, in, group; fp = &frd; IRCOPY(data, (caddr_t)fp, sizeof(*fp)); + /* + * Check that the group number does exist and that if a head group + * has been specified, doesn't exist. + */ + if (fp->fr_grhead && + fr_findgroup(fp->fr_grhead, fp->fr_flags, unit, set, NULL)) + return EEXIST; + if (fp->fr_group && + !fr_findgroup(fp->fr_group, fp->fr_flags, unit, set, NULL)) + return ESRCH; + in = (fp->fr_flags & FR_INQUE) ? 0 : 1; - if (fp->fr_flags & FR_ACCOUNT) { + + if (unit == IPL_LOGAUTH) + ftail = fprev = &ipauth; + else if (fp->fr_flags & FR_ACCOUNT) ftail = fprev = &ipacct[in][set]; - } else if (fp->fr_flags & (FR_OUTQUE|FR_INQUE)) + else if (fp->fr_flags & (FR_OUTQUE|FR_INQUE)) ftail = fprev = &ipfilter[in][set]; else return ESRCH; + if ((group = fp->fr_group)) { + if (!(fg = fr_findgroup(group, fp->fr_flags, unit, set, NULL))) + return ESRCH; + ftail = fprev = fg->fg_start; + } + bzero((char *)frcache, sizeof(frcache[0]) * 2); if (*fp->fr_ifname) { fp->fr_ifa = GETUNIT(fp->fr_ifname); if (!fp->fr_ifa) - fp->fr_ifa = (struct ifnet *)-1; + fp->fr_ifa = (void *)-1; } fdp = &fp->fr_dif; @@ -512,19 +645,39 @@ caddr_t data; if (!f) error = ESRCH; else { + if (f->fr_ref > 1) + return EBUSY; + if (fg && fg->fg_head) + fg->fg_head->fr_ref--; + if (unit == IPL_LOGAUTH) + return fr_auth_ioctl(data, req, f, ftail); + if (f->fr_grhead) + fr_delgroup(f->fr_grhead, fp->fr_flags, unit, + set); + fixskip(fprev, f, -1); *ftail = f->fr_next; - (void) KFREE(f); + KFREE(f); } } else { if (f) error = EEXIST; else { + if (unit == IPL_LOGAUTH) + return fr_auth_ioctl(data, req, f, ftail); KMALLOC(f, frentry_t *, sizeof(*f)); if (f != NULL) { + if (fg && fg->fg_head) + fg->fg_head->fr_ref++; bcopy((char *)fp, (char *)f, sizeof(*f)); + f->fr_ref = 1; f->fr_hits = 0; f->fr_next = *ftail; *ftail = f; + if (req == SIOCINIFR || req == SIOCINAFR) + fixskip(fprev, f, 1); + f->fr_grp = NULL; + if ((group = f->fr_grhead)) + fg = fr_addgroup(group, f, unit, set); } else error = ENOMEM; } @@ -537,8 +690,15 @@ caddr_t data; /* * routines below for saving IP headers to buffer */ -int iplopen(dev, flags -#if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ +#ifdef __sgi +# ifdef _KERNEL +int IPL_EXTERN(open)(dev_t *pdev, int flags, int devtype, cred_t *cp) +# else +int IPL_EXTERN(open)(dev_t dev, int flags) +# endif +#else +int IPL_EXTERN(open)(dev, flags +# if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ (__FreeBSD_version >= 220000)) && defined(_KERNEL) , devtype, p) int devtype; @@ -548,8 +708,13 @@ struct proc *p; # endif dev_t dev; int flags; +#endif /* __sgi */ { - u_int min = minor(dev); +#if defined(__sgi) && defined(_KERNEL) + u_int min = geteminor(*pdev); +#else + u_int min = GET_MINOR(dev); +#endif if (2 < min) min = ENXIO; @@ -559,8 +724,11 @@ int flags; } -int iplclose(dev, flags -#if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ +#ifdef __sgi +int IPL_EXTERN(close)(dev_t dev, int flags, int devtype, cred_t *cp) +#else +int IPL_EXTERN(close)(dev, flags +# if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ (__FreeBSD_version >= 220000)) && defined(_KERNEL) , devtype, p) int devtype; @@ -570,8 +738,9 @@ struct proc *p; # endif dev_t dev; int flags; +#endif /* __sgi */ { - u_int min = minor(dev); + u_int min = GET_MINOR(dev); if (2 < min) min = ENXIO; @@ -580,145 +749,33 @@ int flags; return min; } -# ifdef IPFILTER_LOG /* * iplread/ipllog * both of these must operate with at least splnet() lest they be * called during packet processing and cause an inconsistancy to appear in * the filter lists. */ +#ifdef __sgi +int IPL_EXTERN(read)(dev_t dev, uio_t *uio, cred_t *crp) +#else # if BSD >= 199306 -int iplread(dev, uio, ioflag) +int IPL_EXTERN(read)(dev, uio, ioflag) int ioflag; # else -int iplread(dev, uio) +int IPL_EXTERN(read)(dev, uio) # endif dev_t dev; register struct uio *uio; +#endif /* __sgi */ { - register int ret, s, unit; - register size_t sz, sx; - int error; - - unit = minor(dev); - if ((2 < unit) || (unit < 0)) - return ENXIO; - - if (!uio->uio_resid) - return 0; - - while (!iplused[unit]) { - error = SLEEP(iplbuf[unit], "ipl sleep"); - if (error) - return error; - } - SPLNET(s); - - sx = sz = MIN(uio->uio_resid, iplused[unit]); - if (iplh[unit] < iplt[unit]) - sz = MIN(sz, IPLLOGSIZE - (iplt[unit] - iplbuf[unit])); - sx -= sz; - -# if BSD >= 199306 || defined(__FreeBSD__) - uio->uio_rw = UIO_READ; +# ifdef IPFILTER_LOG + return ipflog_read(GET_MINOR(dev), uio); +# else + return ENXIO; # endif - if (!(ret = UIOMOVE(iplt[unit], sz, UIO_READ, uio))) { - iplt[unit] += sz; - iplused[unit] -= sz; - if ((iplh[unit] < iplt[unit]) && (iplt[unit] == iplbuf[unit] + IPLLOGSIZE)) - iplt[unit] = iplbuf[unit]; - - if (sx && !(ret = UIOMOVE(iplt[unit], sx, UIO_READ, uio))) { - iplt[unit] += sx; - iplused[unit] -= sx; - if ((iplh[unit] < iplt[unit]) && (iplt[unit] == iplbuf[unit] + IPLLOGSIZE)) - iplt[unit] = iplbuf[unit]; - } - if (!iplused[unit]) /* minimise wrapping around the end */ - iplh[unit] = iplt[unit] = iplbuf[unit]; - } - SPLX(s); - return ret; } -# endif /* IPFILTER_LOG */ -# ifdef IPFILTER_LOG -int ipllog(flags, dev, ip, fin, m) -u_int flags; -int dev; -ip_t *ip; -register fr_info_t *fin; -struct mbuf *m; -{ - struct ipl_ci iplci; - register int len, mlen, hlen; - struct ifnet *ifp = fin->fin_ifp; - - hlen = fin->fin_hlen; - if (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) - hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen); - else if (ip->ip_p == IPPROTO_ICMP) { - struct icmp *icmp = (struct icmp *)((char *)ip + hlen); - - switch (icmp->icmp_type) { - case ICMP_UNREACH : - case ICMP_SOURCEQUENCH : - case ICMP_REDIRECT : - case ICMP_TIMXCEED : - case ICMP_PARAMPROB : - hlen += MIN(sizeof(struct icmp) + 8, fin->fin_dlen); - break; - default : - hlen += MIN(sizeof(struct icmp), fin->fin_dlen); - break; - } - } - - mlen = (flags & FR_LOGBODY) ? MIN(ip->ip_len - hlen, 128) : 0; - len = hlen + sizeof(iplci) + mlen; - if (iplused[dev] + len > IPLLOGSIZE) - return 0; - iplused[dev] += len; - -# ifdef sun - uniqtime(&iplci); -# endif -# if BSD >= 199306 || defined(__FreeBSD__) - microtime((struct timeval *)&iplci); -# endif - iplci.flags = flags; - iplci.hlen = (u_char)hlen; - iplci.plen = (u_char)mlen; - iplci.rule = fin->fin_rule; -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) - strncpy(iplci.ifname, ifp->if_xname, IFNAMSIZ); -# else - iplci.unit = (u_char)ifp->if_unit; - if ((iplci.ifname[0] = ifp->if_name[0])) - if ((iplci.ifname[1] = ifp->if_name[1])) - if ((iplci.ifname[2] = ifp->if_name[2])) - iplci.ifname[3] = ifp->if_name[3]; -# endif - if (iplh[dev] == iplbuf[dev] + IPLLOGSIZE) - iplh[dev] = iplbuf[dev]; - - /* - * Gauranteed to succeed from above - */ - (void) fr_copytolog(dev, (char *)&iplci, sizeof(iplci)); - - for (len -= sizeof(iplci); m && len > 0; m = m->m_next, len -= hlen) { - hlen = MIN(len, m->m_len); - if (fr_copytolog(dev, mtod(m, char *), hlen)) - break; - } - - wakeup(iplbuf[dev]); - return 1; -} -# endif /* IPFILTER_LOG */ - /* * send_reset - this could conceivably be a call to tcp_respond(), but that * requires a large amount of setting up and isn't any more efficient. @@ -727,17 +784,17 @@ int send_reset(ti) struct tcpiphdr *ti; { struct tcpiphdr *tp; - struct ip *ip; struct tcphdr *tcp; struct mbuf *m; int tlen = 0; -#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) + ip_t *ip; +# if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) struct route ro; -#endif +# endif if (ti->ti_flags & TH_RST) return -1; /* feedback loop */ -# if BSD < 199306 +# if (BSD < 199306) || defined(__sgi) m = m_get(M_DONTWAIT, MT_HEADER); # else m = m_gethdr(M_DONTWAIT, MT_HEADER); @@ -745,8 +802,6 @@ struct tcpiphdr *ti; # endif if (m == NULL) return -1; -#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) -#endif if (ti->ti_flags & TH_SYN) tlen = 1; @@ -774,29 +829,29 @@ struct tcpiphdr *ti; ip->ip_tos = ((struct ip *)ti)->ip_tos; ip->ip_p = ((struct ip *)ti)->ip_p; ip->ip_len = sizeof (struct tcpiphdr); -# if BSD < 199306 +# if (BSD < 199306) || defined(__sgi) ip->ip_ttl = tcp_ttl; # else ip->ip_ttl = ip_defttl; # endif -#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) +# if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) bzero((char *)&ro, sizeof(ro)); (void) ip_output(m, (struct mbuf *)0, &ro, 0, 0); if (ro.ro_rt) RTFREE(ro.ro_rt); -#else +# else /* * extra 0 in case of multicast */ (void) ip_output(m, (struct mbuf *)0, 0, 0, 0); -#endif +# endif return 0; } -# if !defined(IPFILTER_LKM) && !(__FreeBSD_version >= 300000) -# if BSD < 199306 +# if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000) && !defined(__sgi) +# if (BSD < 199306) int iplinit __P((void)); int @@ -810,7 +865,18 @@ iplinit() (void) iplattach(); ip_init(); } -# endif +# endif /* ! __NetBSD__ */ + + +size_t mbufchainlen(m0) +register struct mbuf *m0; +{ + register size_t len = 0; + + for (; m0; m0 = m0->m_next) + len += m0->m_len; + return len; +} void ipfr_fastroute(m0, fin, fdp) @@ -836,10 +902,11 @@ frdest_t *fdp; dst = (struct sockaddr_in *)&ro->ro_dst; dst->sin_family = AF_INET; dst->sin_addr = fdp->fd_ip.s_addr ? fdp->fd_ip : ip->ip_dst; -#ifdef __bsdi__ +# ifdef __bsdi__ dst->sin_len = sizeof(*dst); -#endif -#if (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) +# endif +# if (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \ + !defined(__OpenBSD__) # ifdef RTF_CLONING rtalloc_ign(ro, RTF_CLONING); # else @@ -981,6 +1048,11 @@ sendorfree: } } done: + if (!error) + ipl_frouteok[0]++; + else + ipl_frouteok[1]++; + if (ro->ro_rt) { RTFREE(ro->ro_rt); } @@ -992,18 +1064,31 @@ bad: #else /* #ifdef _KERNEL */ +#ifdef __sgi +static int no_output __P((struct ifnet *ifp, struct mbuf *m, + struct sockaddr *s)) +#else static int no_output __P((struct ifnet *ifp, struct mbuf *m, struct sockaddr *s, struct rtentry *rt)) +#endif { return 0; } # ifdef __STDC__ +#ifdef __sgi +static int write_output __P((struct ifnet *ifp, struct mbuf *m, + struct sockaddr *s)) +#else static int write_output __P((struct ifnet *ifp, struct mbuf *m, struct sockaddr *s, struct rtentry *rt)) +#endif { +# if !(defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) ip_t *ip = (ip_t *)m; +# endif # else static int write_output(ifp, ip) struct ifnet *ifp; @@ -1013,18 +1098,20 @@ ip_t *ip; FILE *fp; char fname[32]; -#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) sprintf(fname, "/tmp/%s", ifp->if_xname); if ((fp = fopen(fname, "a"))) { fclose(fp); } -#else +# else sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); if ((fp = fopen(fname, "a"))) { fwrite((char *)ip, ntohs(ip->ip_len), 1, fp); fclose(fp); } -#endif +# endif + return 0; } @@ -1032,12 +1119,13 @@ struct ifnet *get_unit(name) char *name; { struct ifnet *ifp, **ifa; -#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { if (!strcmp(name, ifp->if_xname)) return ifp; } -#else +# else char ifname[32], *s; for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { @@ -1045,7 +1133,7 @@ char *name; if (!strcmp(name, ifname)) return ifp; } -#endif +# endif if (!ifneta) { ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2); @@ -1061,9 +1149,10 @@ char *name; } ifp = ifneta[nifs - 1]; -#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) strncpy(ifp->if_xname, name, sizeof(ifp->if_xname)); -#else +# else for (s = name; *s && !isdigit(*s); s++) ; if (*s && isdigit(*s)) { @@ -1075,25 +1164,27 @@ char *name; ifp->if_name = strdup(name); ifp->if_unit = -1; } -#endif +# endif ifp->if_output = no_output; return ifp; } + void init_ifp() { FILE *fp; struct ifnet *ifp, **ifa; char fname[32]; -#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { ifp->if_output = write_output; sprintf(fname, "/tmp/%s", ifp->if_xname); if ((fp = fopen(fname, "w"))) fclose(fp); } -#else +# else for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { ifp->if_output = write_output; @@ -1101,7 +1192,7 @@ void init_ifp() if ((fp = fopen(fname, "w"))) fclose(fp); } -#endif +# endif } @@ -1118,13 +1209,18 @@ frdest_t *fdp; ip->ip_len = htons((u_short)ip->ip_len); ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); ip->ip_sum = 0; +#ifdef __sgi + (*ifp->if_output)(ifp, (void *)ip, NULL); +#else (*ifp->if_output)(ifp, (void *)ip, NULL, 0); +#endif } -void ipllog() +int ipllog __P((void)) { verbose("l"); + return 0; } diff --git a/sys/netinet/ip_fil.h b/sys/netinet/ip_fil.h index 661e109f407e..39cca349e319 100644 --- a/sys/netinet/ip_fil.h +++ b/sys/netinet/ip_fil.h @@ -1,17 +1,25 @@ /* - * (C)opyright 1993-1997 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. * * @(#)ip_fil.h 1.35 6/5/96 - * $Id: ip_fil.h,v 2.0.2.13 1997/05/24 07:41:55 darrenr Exp $ + * $Id: ip_fil.h,v 2.0.2.39.2.4 1997/11/12 10:50:02 darrenr Exp $ */ #ifndef __IP_FIL_H__ #define __IP_FIL_H__ +/* + * Pathnames for various IP Filter control devices. Used by LKM + * and userland, so defined here. + */ +#define IPNAT_NAME "/dev/ipnat" +#define IPSTATE_NAME "/dev/ipstate" +#define IPAUTH_NAME "/dev/ipauth" + #ifndef SOLARIS #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #endif @@ -45,6 +53,9 @@ #define SIOCFRSYN _IOW('r', 73, u_int) #define SIOCFRZST _IOWR('r', 74, struct friostat) #define SIOCZRLST _IOWR('r', 75, struct frentry) +#define SIOCAUTHW _IOWR('r', 76, struct fr_info) +#define SIOCAUTHR _IOWR('r', 77, struct fr_info) +#define SIOCATHST _IOWR('r', 78, struct fr_authstat) #else #define SIOCADAFR _IOW(r, 60, struct frentry) #define SIOCRMAFR _IOW(r, 61, struct frentry) @@ -62,6 +73,9 @@ #define SIOCFRSYN _IOW(r, 73, u_int) #define SIOCFRZST _IOWR(r, 74, struct friostat) #define SIOCZRLST _IOWR(r, 75, struct frentry) +#define SIOCAUTHW _IOWR(r, 76, struct fr_info) +#define SIOCAUTHR _IOWR(r, 77, struct fr_info) +#define SIOCATHST _IOWR(r, 78, struct fr_authstat) #endif #define SIOCADDFR SIOCADAFR #define SIOCDELFR SIOCRMAFR @@ -75,7 +89,7 @@ typedef struct fr_ip { u_char fi_p; struct in_addr fi_src; struct in_addr fi_dst; - u_long fi_optmsk; /* bitmask composed from IP options */ + u_32_t fi_optmsk; /* bitmask composed from IP options */ u_short fi_secmsk; /* bitmask composed from IP security options */ u_short fi_auth; } fr_ip_t; @@ -87,20 +101,30 @@ typedef struct fr_ip { typedef struct fr_info { struct fr_ip fin_fi; - void *fin_ifp; u_short fin_data[2]; u_short fin_out; - u_char fin_tcpf; - u_char fin_icode; - u_short fin_rule; u_short fin_hlen; + u_char fin_tcpf; + u_char fin_icode; /* From here on is packet specific */ + u_short fin_rule; + u_short fin_group; u_short fin_dlen; - char *fin_dp; /* start of data past IP header */ + u_short fin_id; + void *fin_ifp; struct frentry *fin_fr; + char *fin_dp; /* start of data past IP header */ void *fin_mp; } fr_info_t; -#define FI_CSIZE (sizeof(struct fr_ip) + 11) +/* + * Size for compares on fr_info structures + */ +#define FI_CSIZE (sizeof(struct fr_ip) + sizeof(u_short) * 4 + \ + sizeof(u_char)) +/* + * Size for copying cache fr_info structure + */ +#define FI_COPYSIZE (sizeof(fr_info_t) - sizeof(void *) * 2) typedef struct frdest { void *fd_ifp; @@ -110,9 +134,13 @@ typedef struct frdest { typedef struct frentry { struct frentry *fr_next; - struct ifnet *fr_ifa; + u_short fr_group; /* group to which this rule belongs */ + u_short fr_grhead; /* group # which this rule starts */ + struct frentry *fr_grp; + int fr_ref; /* reference count - for grouping */ + void *fr_ifa; /* - * There are only incremented when a packet matches this rule and + * These are only incremented when a packet matches this rule and * it is the last match */ U_QUAD_T fr_hits; @@ -135,8 +163,9 @@ typedef struct frentry { u_short fr_sport; u_short fr_stop; /* top port for <> and >< */ u_short fr_dtop; /* top port for <> and >< */ - u_long fr_flags; /* per-rule flags && options (see below) */ - int (*fr_func) __P((int, struct ip *, fr_info_t *)); /* call this function */ + u_32_t fr_flags; /* per-rule flags && options (see below) */ + int fr_skip; /* # of rules to skip */ + int (*fr_func) __P((int, ip_t *, fr_info_t *)); /* call this function */ char fr_icode; /* return ICMP code */ char fr_ifname[IFNAMSIZ]; struct frdest fr_tif; /* "to" interface */ @@ -159,10 +188,10 @@ typedef struct frentry { /* * fr_flags */ -#define FR_BLOCK 0x00001 -#define FR_PASS 0x00002 -#define FR_OUTQUE 0x00004 -#define FR_INQUE 0x00008 +#define FR_BLOCK 0x00001 /* do not allow packet to pass */ +#define FR_PASS 0x00002 /* allow packet to pass */ +#define FR_OUTQUE 0x00004 /* outgoing packets */ +#define FR_INQUE 0x00008 /* ingoing packets */ #define FR_LOG 0x00010 /* Log */ #define FR_LOGB 0x00011 /* Log-fail */ #define FR_LOGP 0x00012 /* Log-pass */ @@ -170,7 +199,7 @@ typedef struct frentry { #define FR_LOGFIRST 0x00040 /* Log the first byte if state held */ #define FR_RETRST 0x00080 /* Return TCP RST packet - reset connection */ #define FR_RETICMP 0x00100 /* Return ICMP unreachable packet */ -#define FR_NOMATCH 0x00200 +#define FR_NOMATCH 0x00200 /* no match occured */ #define FR_ACCOUNT 0x00400 /* count packet bytes */ #define FR_KEEPFRAG 0x00800 /* keep fragment information */ #define FR_KEEPSTATE 0x01000 /* keep `connection' state information */ @@ -182,10 +211,20 @@ typedef struct frentry { #define FR_LOGORBLOCK 0x40000 /* block the packet if it can't be logged */ #define FR_NOTSRCIP 0x80000 /* not the src IP# */ #define FR_NOTDSTIP 0x100000 /* not the dst IP# */ +#define FR_AUTH 0x200000 /* use authentication */ +#define FR_PREAUTH 0x400000 /* require preauthentication */ #define FR_LOGMASK (FR_LOG|FR_LOGP|FR_LOGB) + /* - * recognized flags for SIOCGETFF and SIOCSETFF + * These correspond to #define's for FI_* and are stored in fr_flags + */ +#define FF_OPTIONS 0x01000000 +#define FF_TCPUDP 0x02000000 +#define FF_FRAG 0x04000000 +#define FF_SHORT 0x08000000 +/* + * recognized flags for SIOCGETFF and SIOCSETFF, and get put in fr_flags */ #define FF_LOGPASS 0x10000000 #define FF_LOGBLOCK 0x20000000 @@ -220,6 +259,7 @@ typedef struct filterstats { u_long fr_bads; /* bad attempts to allocate packet state */ u_long fr_ads; /* new packet state kept */ u_long fr_chit; /* cached hit */ + u_long fr_tcpbad; /* TCP checksum check failures */ u_long fr_pull[2]; /* good and bad pullup attempts */ #if SOLARIS u_long fr_bad; /* bad IP packets to the filter */ @@ -237,34 +277,59 @@ typedef struct friostat { struct frentry *f_fout[2]; struct frentry *f_acctin[2]; struct frentry *f_acctout[2]; + struct frentry *f_auth; + u_long f_froute[2]; int f_active; } friostat_t; -typedef struct optlist { +typedef struct optlist { u_short ol_val; - int ol_bit; + int ol_bit; } optlist_t; + /* - * Log structure. Each packet header logged is prepended by one of these, - * minimize size to make most effective use of log space which should - * (ideally) be a muliple of the most common log entry size. + * Group list structure. */ -typedef struct ipl_ci { - u_long sec; - u_long usec; - u_char hlen; - u_char plen; - u_short rule; /* assume never more than 64k rules, total */ -#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) - u_long flags; - u_char ifname[IFNAMSIZ]; /* = 32 bytes */ +typedef struct frgroup { + u_short fg_num; + struct frgroup *fg_next; + struct frentry *fg_head; + struct frentry **fg_start; +} frgroup_t; + + +/* + * Log structure. Each packet header logged is prepended by one of these. + * Following this in the log records read from the device will be an ipflog + * structure which is then followed by any packet data. + */ +typedef struct iplog { + u_long ipl_magic; + u_long ipl_sec; + u_long ipl_usec; + u_int ipl_len; + u_int ipl_count; + size_t ipl_dsize; + struct iplog *ipl_next; +} iplog_t; + +#define IPL_MAGIC 0x49504c4d /* 'IPLM' */ + +typedef struct ipflog { +#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) + u_char fl_ifname[IFNAMSIZ]; #else - u_long flags; - u_int unit; - u_char ifname[4]; /* = 24 bytes */ + u_int fl_unit; + u_char fl_ifname[4]; #endif -} ipl_ci_t; + u_char fl_plen; /* extra data after hlen */ + u_char fl_hlen; /* length of IP headers saved */ + u_short fl_rule; /* assume never more than 64k rules, total */ + u_short fl_group; + u_32_t fl_flags; +} ipflog_t; #ifndef ICMP_UNREACH_FILTER @@ -275,15 +340,15 @@ typedef struct ipl_ci { #define IPF_LOGGING 0 #endif #ifndef IPF_DEFAULT_PASS -#define IPF_DEFAULT_PASS 0 +#define IPF_DEFAULT_PASS FR_PASS #endif #define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h))) #define IPLLOGSIZE 8192 /* - * Device filenames. Use ipf on Solaris2 because ipl is already a name used - * by something else. + * Device filenames for reading log information. Use ipf on Solaris2 because + * ipl is already a name used by something else. */ #ifndef IPL_NAME # if SOLARIS @@ -292,11 +357,15 @@ typedef struct ipl_ci { # define IPL_NAME "/dev/ipl" # endif #endif -#define IPL_NAT "/dev/ipnat" -#define IPL_STATE "/dev/ipstate" +#define IPL_NAT IPNAT_NAME +#define IPL_STATE IPSTATE_NAME +#define IPL_AUTH IPAUTH_NAME + #define IPL_LOGIPF 0 /* Minor device #'s for accessing logs */ #define IPL_LOGNAT 1 #define IPL_LOGSTATE 2 +#define IPL_LOGAUTH 3 +#define IPL_LOGMAX 3 #if !defined(CDEV_MAJOR) && defined (__FreeBSD_version) && \ (__FreeBSD_version >= 220000) @@ -304,78 +373,145 @@ typedef struct ipl_ci { #endif #ifndef _KERNEL -extern int fr_check __P((struct ip *, int, struct ifnet *, int, char *)); -extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, - int, char *)); -extern int send_reset __P((struct ip *, struct ifnet *)); -extern int icmp_error __P((struct ip *, struct ifnet *)); -extern void ipllog __P((void)); -extern void ipfr_fastroute __P((struct ip *, fr_info_t *, frdest_t *)); +extern int fr_check __P((ip_t *, int, void *, int, mb_t **)); +extern int (*fr_checkp) __P((ip_t *, int, void *, int, mb_t **)); +extern int send_reset __P((ip_t *, struct ifnet *)); +extern int icmp_error __P((ip_t *, struct ifnet *)); +extern int ipf_log __P((void)); +extern void ipfr_fastroute __P((ip_t *, fr_info_t *, frdest_t *)); +extern struct ifnet *get_unit __P((char *)); +# define FR_SCANLIST(p, ip, fi, m) fr_scanlist(p, ip, fi, m) +# if defined(__NetBSD__) || defined(__OpenBSD__) +extern int iplioctl __P((dev_t, u_long, caddr_t, int)); +# else extern int iplioctl __P((dev_t, int, caddr_t, int)); +# endif extern int iplopen __P((dev_t, int)); extern int iplclose __P((dev_t, int)); #else /* #ifndef _KERNEL */ +# if defined(__NetBSD__) && defined(PFIL_HOOKS) +extern int ipfilterattach __P((int)); +# endif extern int iplattach __P((void)); -extern int ipldetach __P((void)); +extern int ipl_enable __P((void)); +extern int ipl_disable __P((void)); +extern void ipflog_init __P((void)); +extern int ipflog_clear __P((int)); +extern int ipflog_read __P((int, struct uio *)); +extern int ipflog __P((u_int, ip_t *, fr_info_t *, mb_t *)); +extern int ipllog __P((int, u_long, void **, size_t *, int *, int)); # if SOLARIS -extern int fr_check __P((struct ip *, int, struct ifnet *, int, qif_t *, - queue_t *, mblk_t **)); -extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, - int, qif_t *, queue_t *, mblk_t *)); -extern int icmp_error __P((queue_t *, ip_t *, int, int, qif_t *, +extern int fr_check __P((ip_t *, int, void *, int, qif_t *, mb_t **)); +extern int (*fr_checkp) __P((ip_t *, int, void *, + int, qif_t *, mb_t **)); +extern int icmp_error __P((ip_t *, int, int, qif_t *, struct in_addr)); extern int iplioctl __P((dev_t, int, int, int, cred_t *, int *)); extern int iplopen __P((dev_t *, int, int, cred_t *)); extern int iplclose __P((dev_t, int, int, cred_t *)); extern int ipfsync __P((void)); +extern int send_reset __P((ip_t *, qif_t *)); +extern int ipfr_fastroute __P((qif_t *, ip_t *, mblk_t *, mblk_t **, + fr_info_t *, frdest_t *)); +extern void copyin_mblk __P((mblk_t *, int, int, char *)); +extern void copyout_mblk __P((mblk_t *, int, int, char *)); +extern int fr_qin __P((queue_t *, mblk_t *)); +extern int fr_qout __P((queue_t *, mblk_t *)); # ifdef IPFILTER_LOG extern int iplread __P((dev_t, struct uio *, cred_t *)); # endif -extern u_short fr_tcpsum __P((mblk_t *, ip_t *, tcphdr_t *)); # else /* SOLARIS */ -extern int fr_check __P((struct ip *, int, struct ifnet *, int, - struct mbuf **)); -extern int (*fr_checkp) __P((struct ip *, int, struct ifnet *, int, - struct mbuf **)); +extern int fr_check __P((ip_t *, int, void *, int, mb_t **)); +extern int (*fr_checkp) __P((ip_t *, int, void *, int, mb_t **)); extern int send_reset __P((struct tcpiphdr *)); -extern int ipllog __P((u_int, int, struct ip *, fr_info_t *, struct mbuf *)); -extern void ipfr_fastroute __P((struct mbuf *, fr_info_t *, frdest_t *)); -# ifdef IPFILTER_LKM +extern void ipfr_fastroute __P((mb_t *, fr_info_t *, frdest_t *)); +extern size_t mbufchainlen __P((mb_t *)); +# ifdef __sgi +# include +extern int iplioctl __P((dev_t, int, caddr_t, int, cred_t *, int *)); +extern int iplopen __P((dev_t *, int, int, cred_t *)); +extern int iplclose __P((dev_t, int, int, cred_t *)); +extern int iplread __P((dev_t, struct uio *, cred_t *)); +extern int ipfsync __P((void)); +extern int ipfilter_sgi_attach __P((void)); +extern void ipfilter_sgi_detach __P((void)); +extern void ipfilter_sgi_intfsync __P((void)); +# else +# ifdef IPFILTER_LKM extern int iplidentify __P((char *)); -# endif -extern u_short fr_tcpsum __P((struct mbuf *, ip_t *, tcphdr_t *)); -# if (_BSDI_VERSION >= 199510) || (__FreeBSD_version >= 220000) || \ +# endif +# if (_BSDI_VERSION >= 199510) || (__FreeBSD_version >= 220000) || \ (NetBSD >= 199511) +# ifdef __NetBSD__ +extern int iplioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); +# else extern int iplioctl __P((dev_t, int, caddr_t, int, struct proc *)); +# endif extern int iplopen __P((dev_t, int, int, struct proc *)); extern int iplclose __P((dev_t, int, int, struct proc *)); -# else +# else +# if defined(__OpenBSD__) +extern int iplioctl __P((dev_t, u_long, caddr_t, int)); +# else /* __OpenBSD__ */ +# ifndef linux extern int iplioctl __P((dev_t, int, caddr_t, int)); +# else +extern int iplioctl(struct inode *, struct file *, u_int, u_long); +# endif +# endif /* __OpenBSD__ */ +# ifndef linux extern int iplopen __P((dev_t, int)); extern int iplclose __P((dev_t, int)); -# endif /* (_BSDI_VERSION >= 199510) */ -# ifdef IPFILTER_LOG +# else +extern int iplopen __P((struct inode *, struct file *)); +extern void iplclose __P((struct inode *, struct file *)); +# endif /* !linux */ +# endif /* (_BSDI_VERSION >= 199510) */ # if BSD >= 199306 extern int iplread __P((dev_t, struct uio *, int)); # else +# ifndef linux extern int iplread __P((dev_t, struct uio *)); +# else +extern int iplread(struct inode *, struct file *, char *, int); +# endif /* !linux */ # endif /* BSD >= 199306 */ -# else -# define iplread noread -# endif /* IPFILTER_LOG */ +# endif /* __ sgi */ # endif /* SOLARIS */ #endif /* #ifndef _KERNEL */ + +/* + * Post NetBSD 1.2 has the PFIL interface for packet filters. This turns + * on those hooks. We don't need any special mods in non-IP Filter code + * with this! + */ +#if (defined(NetBSD) && (NetBSD > 199609) && (NetBSD <= 1991011)) || \ + (defined(NetBSD1_2) && NetBSD1_2 > 1) +# define NETBSD_PF +#endif + +extern int ipldetach __P((void)); +extern u_short fr_tcpsum __P((mb_t *, ip_t *, tcphdr_t *)); +#define FR_SCANLIST(p, ip, fi, m) fr_scanlist(p, ip, fi, m) +extern int fr_scanlist __P((int, ip_t *, fr_info_t *, void *)); extern u_short ipf_cksum __P((u_short *, int)); extern int fr_copytolog __P((int, char *, int)); +extern void frflush __P((int, caddr_t)); +extern frgroup_t *fr_addgroup __P((u_short, frentry_t *, int, int)); +extern frgroup_t *fr_findgroup __P((u_short, u_32_t, int, int, frgroup_t ***)); +extern void fr_delgroup __P((u_short, u_32_t, int, int)); extern int ipl_unreach; extern int ipl_inited; +extern u_long ipl_frouteok[2]; extern int fr_pass; extern int fr_flags; extern int fr_active; -extern fr_info_t frcache[]; -extern char *iplh[3], *iplt[3]; -extern char iplbuf[3][IPLLOGSIZE]; -extern int iplused[3]; +extern fr_info_t frcache[2]; +#ifdef IPFILTER_LOG +extern iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1]; +extern int iplused[IPL_LOGMAX + 1]; +#endif extern struct frentry *ipfilter[2][2], *ipacct[2][2]; +extern struct frgroup *ipfgroups[3][2]; extern struct filterstats frstats[]; #endif /* __IP_FIL_H__ */ diff --git a/sys/netinet/ip_frag.c b/sys/netinet/ip_frag.c index 9b9bce35e7eb..923f68522261 100644 --- a/sys/netinet/ip_frag.c +++ b/sys/netinet/ip_frag.c @@ -1,13 +1,13 @@ /* - * (C)opyright 1993,1994,1995 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[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-1995 Darren Reed"; -static char rcsid[] = "$Id: ip_frag.c,v 2.0.2.10 1997/05/24 07:36:23 darrenr Exp $"; +#if !defined(lint) +static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.0.2.19.2.1 1997/11/12 10:50:21 darrenr Exp $"; #endif #if !defined(_KERNEL) && !defined(KERNEL) @@ -26,13 +26,17 @@ static char rcsid[] = "$Id: ip_frag.c,v 2.0.2.10 1997/05/24 07:36:23 darrenr Exp #include #endif #include +#ifndef linux #include +#endif #include -#ifdef _KERNEL +#if defined(_KERNEL) && !defined(linux) # include #endif #if !defined(__SVR4) && !defined(__svr4__) -# include +# ifndef linux +# include +# endif #else # include # include @@ -48,27 +52,30 @@ static char rcsid[] = "$Id: ip_frag.c,v 2.0.2.10 1997/05/24 07:36:23 darrenr Exp #include #include #include +#ifndef linux #include +#endif #include #include -#include #include #include "netinet/ip_compat.h" +#include #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" ipfr_t *ipfr_heads[IPFT_SIZE]; ipfr_t *ipfr_nattab[IPFT_SIZE]; ipfrstat_t ipfr_stats; -u_long ipfr_inuse = 0, +int ipfr_inuse = 0, fr_ipfrttl = 120; /* 60 seconds */ #ifdef _KERNEL extern int ipfr_timer_id; #endif -#if SOLARIS && defined(_KERNEL) +#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) extern kmutex_t ipf_frag; extern kmutex_t ipf_natfrag; extern kmutex_t ipf_nat; @@ -120,7 +127,6 @@ ipfr_t *table[]; if (!bcmp((char *)&frag.ipfr_src, (char *)&fr->ipfr_src, IPFR_CMPSZ)) { ipfr_stats.ifs_exists++; - MUTEX_EXIT(&ipf_frag); return NULL; } @@ -131,7 +137,6 @@ ipfr_t *table[]; KMALLOC(fr, ipfr_t *, sizeof(*fr)); if (fr == NULL) { ipfr_stats.ifs_nomem++; - MUTEX_EXIT(&ipf_frag); return NULL; } @@ -183,7 +188,7 @@ nat_t *nat; MUTEX_ENTER(&ipf_natfrag); if ((ipf = ipfr_new(ip, fin, pass, ipfr_nattab))) { ipf->ipfr_data = nat; - nat->nat_frag = ipf; + nat->nat_data = ipf; } MUTEX_EXIT(&ipf_natfrag); return ipf ? 0 : -1; @@ -201,7 +206,6 @@ ipfr_t *table[]; { ipfr_t *f, frag; u_int idx; - int ret; /* * For fragments, we record protocol, packet id, TOS and both IP#'s @@ -242,16 +246,16 @@ ipfr_t *table[]; table[idx] = f; } off = ip->ip_off; - atoff = (off & 0x1fff) - (fin->fin_dlen >> 3); + atoff = off + (fin->fin_dlen >> 3); /* * If we've follwed the fragments, and this is the * last (in order), shrink expiration time. */ - if (atoff == f->ipfr_off) { + if ((off & 0x1fff) == f->ipfr_off) { if (!(off & IP_MF)) f->ipfr_ttl = 1; else - f->ipfr_off = off; + f->ipfr_off = atoff; } ipfr_stats.ifs_hits++; return f; @@ -261,7 +265,7 @@ ipfr_t *table[]; /* - * functional interface for normal lookups of the fragment cache + * functional interface for NAT lookups of the NAT fragment cache */ nat_t *ipfr_nat_knownfrag(ip, fin) ip_t *ip; @@ -271,15 +275,25 @@ fr_info_t *fin; ipfr_t *ipf; MUTEX_ENTER(&ipf_natfrag); - ipf = ipfr_lookup(ip, fin, ipfr_heads); - nat = ipf ? ipf->ipfr_data : NULL; + ipf = ipfr_lookup(ip, fin, ipfr_nattab); + if (ipf) { + nat = ipf->ipfr_data; + /* + * This is the last fragment for this packet. + */ + if (ipf->ipfr_ttl == 1) { + nat->nat_data = NULL; + ipf->ipfr_data = NULL; + } + } else + nat = NULL; MUTEX_EXIT(&ipf_natfrag); return nat; } /* - * functional interface for NAT lookups of the NAT fragment cache + * functional interface for normal lookups of the fragment cache */ int ipfr_knownfrag(ip, fin) ip_t *ip; @@ -296,6 +310,25 @@ fr_info_t *fin; } +/* + * forget any references to this external object. + */ +void ipfr_forget(nat) +void *nat; +{ + ipfr_t *fr; + int idx; + + MUTEX_ENTER(&ipf_natfrag); + for (idx = IPFT_SIZE - 1; idx >= 0; idx--) + for (fr = ipfr_heads[idx]; fr; fr = fr->ipfr_next) + if (fr->ipfr_data == nat) + fr->ipfr_data = NULL; + + MUTEX_EXIT(&ipf_natfrag); +} + + /* * Free memory in use by fragment state info. kept. */ @@ -304,11 +337,7 @@ void ipfr_unload() ipfr_t **fp, *fr; nat_t *nat; int idx; -#if !SOLARIS && defined(_KERNEL) - int s; -#endif - SPLNET(s); MUTEX_ENTER(&ipf_frag); for (idx = IPFT_SIZE - 1; idx >= 0; idx--) for (fp = &ipfr_heads[idx]; (fr = *fp); ) { @@ -323,14 +352,13 @@ void ipfr_unload() for (fp = &ipfr_nattab[idx]; (fr = *fp); ) { *fp = fr->ipfr_next; if ((nat = (nat_t *)fr->ipfr_data)) { - if (nat->nat_frag == fr) - nat->nat_frag = NULL; + if (nat->nat_data == fr) + nat->nat_data = NULL; } KFREE(fr); } MUTEX_EXIT(&ipf_natfrag); MUTEX_EXIT(&ipf_nat); - SPLX(s); } @@ -339,7 +367,7 @@ void ipfr_unload() * Slowly expire held state for fragments. Timeouts are set * in expectation * of this being called twice per second. */ -# if (BSD >= 199306) || SOLARIS +# if (BSD >= 199306) || SOLARIS || defined(__sgi) void ipfr_slowtimer() # else int ipfr_slowtimer() @@ -349,8 +377,12 @@ int ipfr_slowtimer() nat_t *nat; int s, idx; +#ifdef __sgi + ipfilter_sgi_intfsync(); +#endif + + SPL_NET(s); MUTEX_ENTER(&ipf_frag); - SPLNET(s); /* * Go through the entire table, looking for entries to expire, @@ -399,8 +431,8 @@ int ipfr_slowtimer() ipfr_stats.ifs_expire++; ipfr_inuse--; if ((nat = (nat_t *)fr->ipfr_data)) { - if (nat->nat_frag == fr) - nat->nat_frag = NULL; + if (nat->nat_data == fr) + nat->nat_data = NULL; } KFREE(fr); } else @@ -408,16 +440,17 @@ int ipfr_slowtimer() } MUTEX_EXIT(&ipf_natfrag); MUTEX_EXIT(&ipf_nat); - SPLX(s); -# if SOLARIS + SPL_X(s); fr_timeoutstate(); ip_natexpire(); + fr_authexpire(); +# if SOLARIS ipfr_timer_id = timeout(ipfr_slowtimer, NULL, drv_usectohz(500000)); # else - fr_timeoutstate(); - ip_natexpire(); +# ifndef linux ip_slowtimo(); -# if BSD < 199306 +# endif +# if (BSD < 199306) && !defined(__sgi) return 0; # endif # endif diff --git a/sys/netinet/ip_frag.h b/sys/netinet/ip_frag.h index df275babb318..ade7139e4933 100644 --- a/sys/netinet/ip_frag.h +++ b/sys/netinet/ip_frag.h @@ -1,12 +1,12 @@ /* - * (C)opyright 1993-1997 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. * * @(#)ip_frag.h 1.5 3/24/96 - * $Id: ip_frag.h,v 2.0.2.7 1997/05/08 10:10:18 darrenr Exp $ + * $Id: ip_frag.h,v 2.0.2.12 1997/10/23 14:56:01 darrenr Exp $ */ #ifndef __IP_FRAG_H__ @@ -41,14 +41,16 @@ typedef struct ipfrstat { #define IPFR_CMPSZ (4 + 4 + 2 + 1 + 1) -extern ipfrstat_t *ipfr_fragstats __P((void)); -extern int ipfr_newfrag __P((ip_t *, fr_info_t *, int)); -extern int ipfr_nat_newfrag __P((ip_t *, fr_info_t *, int, struct nat *)); -extern nat_t *ipfr_nat_knownfrag __P((ip_t *, fr_info_t *)); -extern int ipfr_knownfrag __P((ip_t *, fr_info_t *)); -extern void ipfr_unload __P((void)); +extern int fr_ipfrttl; +extern ipfrstat_t *ipfr_fragstats __P((void)); +extern int ipfr_newfrag __P((ip_t *, fr_info_t *, int)); +extern int ipfr_nat_newfrag __P((ip_t *, fr_info_t *, int, struct nat *)); +extern nat_t *ipfr_nat_knownfrag __P((ip_t *, fr_info_t *)); +extern int ipfr_knownfrag __P((ip_t *, fr_info_t *)); +extern void ipfr_forget __P((void *)); +extern void ipfr_unload __P((void)); -#if (BSD >= 199306) || SOLARIS +#if (BSD >= 199306) || SOLARIS || defined(__sgi) extern void ipfr_slowtimer __P((void)); #else extern int ipfr_slowtimer __P((void)); diff --git a/sys/netinet/ip_log.c b/sys/netinet/ip_log.c new file mode 100644 index 000000000000..6440124c6f91 --- /dev/null +++ b/sys/netinet/ip_log.c @@ -0,0 +1,473 @@ +/* + * Copyright (C) 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. + * + * $Id: ip_log.c,v 2.0.2.13.2.2 1997/11/12 10:52:21 darrenr Exp $ + */ +#ifdef IPFILTER_LOG +# ifndef SOLARIS +# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +# endif + +# ifdef __FreeBSD__ +# if defined(KERNEL) && !defined(_KERNEL) +# define _KERNEL +# endif +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include +# else +# include +# endif +# endif +# ifndef _KERNEL +# include +# include +# include +# include +# endif +# include +# include +# include +# include +# if __FreeBSD_version >= 220000 && defined(_KERNEL) +# include +# include +# else +# include +# endif +# include +# if defined(_KERNEL) && !defined(linux) +# include +# endif +# include +# if !SOLARIS +# if (NetBSD > 199609) || (OpenBSD > 199603) +# include +# else +# include +# endif +# ifndef linux +# include +# endif +# else +# include +# include +# include +# include +# include +# include +# include +# include +# include +# endif +# ifndef linux +# include +# endif +# include + +# include +# ifdef sun +# include +# endif +# if __FreeBSD_version >= 300000 +# include +# endif +# include +# include +# ifdef __sgi +# include +# ifdef IFF_DRVRLOCK /* IRIX6 */ +# include +# endif +# endif +# if !defined(linux) && !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/ +# include +# endif +# include +# include +# include +# include +# include +# ifndef linux +# include +# endif +# ifndef _KERNEL +# include +# endif +# include "netinet/ip_compat.h" +# include +# 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 + + +# if SOLARIS || defined(__sgi) +extern kmutex_t ipl_mutex; +# if SOLARIS +extern kcondvar_t iplwait; +# endif +# endif + +iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1]; +int iplused[IPL_LOGMAX+1]; +u_long iplcrc[IPL_LOGMAX+1]; +u_long iplcrcinit; +#ifdef linux +static struct wait_queue *iplwait[IPL_LOGMAX+1]; +#endif + + +/* + * Initialise log buffers & pointers. Also iniialised the CRC to a local + * secret for use in calculating the "last log checksum". + */ +void ipflog_init() +{ + struct timeval tv; + int i; + + for (i = IPL_LOGMAX; i >= 0; i--) { + iplt[i] = NULL; + iplh[i] = &iplt[i]; + iplused[i] = 0; + } +# if BSD >= 199306 || defined(__FreeBSD__) || defined(__sgi) + microtime(&tv); +# else + uniqtime(&tv); +# endif + iplcrcinit = tv.tv_sec ^ (tv.tv_usec << 8) ^ tv.tv_usec; +} + + +/* + * ipflog + * Create a log record for a packet given that it has been triggered by a + * rule (or the default setting). Calculate the transport protocol header + * size using predetermined size of a couple of popular protocols and thus + * how much data to copy into the log, including part of the data body if + * requested. + */ +int ipflog(flags, ip, fin, m) +u_int flags; +ip_t *ip; +fr_info_t *fin; +mb_t *m; +{ + ipflog_t ipfl; + register int mlen, hlen; + u_long crc; + size_t sizes[2]; + void *ptrs[2]; + int types[2]; +# if SOLARIS + ill_t *ifp = fin->fin_ifp; +# else + struct ifnet *ifp = fin->fin_ifp; +# endif + + /* + * calculate header size. + */ + hlen = fin->fin_hlen; + if (ip->ip_p == IPPROTO_TCP) + hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen); + else if (ip->ip_p == IPPROTO_UDP) + hlen += MIN(sizeof(udphdr_t), fin->fin_dlen); + else if (ip->ip_p == IPPROTO_ICMP) { + struct icmp *icmp = (struct icmp *)((char *)ip + hlen); + + /* + * For ICMP, if the packet is an error packet, also include + * the information about the packet which caused the error. + */ + switch (icmp->icmp_type) + { + case ICMP_UNREACH : + case ICMP_SOURCEQUENCH : + case ICMP_REDIRECT : + case ICMP_TIMXCEED : + case ICMP_PARAMPROB : + hlen += MIN(sizeof(struct icmp) + 8, fin->fin_dlen); + break; + default : + hlen += MIN(sizeof(struct icmp), fin->fin_dlen); + break; + } + } + /* + * Get the interface number and name to which this packet is + * currently associated. + */ +# if SOLARIS + ipfl.fl_unit = (u_char)ifp->ill_ppa; + bcopy(ifp->ill_name, ipfl.fl_ifname, MIN(ifp->ill_name_length, 4)); + mlen = (flags & FR_LOGBODY) ? MIN(msgdsize(m) - hlen, 128) : 0; +# else +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) + strncpy(ipfl.fl_ifname, ifp->if_xname, IFNAMSIZ); +# else +# ifndef linux + ipfl.fl_unit = (u_char)ifp->if_unit; +# endif + if ((ipfl.fl_ifname[0] = ifp->if_name[0])) + if ((ipfl.fl_ifname[1] = ifp->if_name[1])) + if ((ipfl.fl_ifname[2] = ifp->if_name[2])) + ipfl.fl_ifname[3] = ifp->if_name[3]; +# endif + mlen = (flags & FR_LOGBODY) ? MIN(ip->ip_len - hlen, 128) : 0; +# endif + ipfl.fl_plen = (u_char)mlen; + ipfl.fl_hlen = (u_char)hlen; + ipfl.fl_rule = fin->fin_rule; + ipfl.fl_group = fin->fin_group; + ipfl.fl_flags = flags; + ptrs[0] = (void *)&ipfl; + sizes[0] = sizeof(ipfl); + types[0] = 0; +#if SOLARIS + /* + * Are we copied from the mblk or an aligned array ? + */ + if (ip == (ip_t *)m->b_rptr) { + ptrs[1] = m; + sizes[1] = hlen + mlen; + types[1] = 1; + } else { + ptrs[1] = ip; + sizes[1] = hlen + mlen; + types[1] = 0; + } +#else + ptrs[1] = m; + sizes[1] = hlen + mlen; + types[1] = 1; +#endif + crc = (ipf_cksum((u_short *)fin, FI_CSIZE) << 8) + iplcrcinit; + return ipllog(IPL_LOGIPF, crc, ptrs, sizes, types, 2); +} + + +/* + * ipllog + */ +int ipllog(dev, crc, items, itemsz, types, cnt) +int dev; +u_long crc; +void **items; +size_t *itemsz; +int *types, cnt; +{ + iplog_t *ipl; + caddr_t buf, s; + int len, i; + + /* + * Check to see if this log record has a CRC which matches the last + * record logged. If it does, just up the count on the previous one + * rather than create a new one. + */ + if (crc) { + MUTEX_ENTER(&ipl_mutex); + if ((iplcrc[dev] == crc) && *iplh[dev]) { + (*iplh[dev])->ipl_count++; + MUTEX_EXIT(&ipl_mutex); + return 1; + } + iplcrc[dev] = crc; + MUTEX_EXIT(&ipl_mutex); + } + + /* + * Get the total amount of data to be logged. + */ + for (i = 0, len = sizeof(iplog_t); i < cnt; i++) + len += itemsz[i]; + + /* + * check that we have space to record this information and can + * allocate that much. + */ + KMALLOC(buf, caddr_t, len); + if (!buf) + return 0; + MUTEX_ENTER(&ipl_mutex); + if ((iplused[dev] + len) > IPLLOGSIZE) { + MUTEX_EXIT(&ipl_mutex); + KFREES(buf, len); + return 0; + } + iplused[dev] += len; + MUTEX_EXIT(&ipl_mutex); + + /* + * advance the log pointer to the next empty record and deduct the + * amount of space we're going to use. + */ + ipl = (iplog_t *)buf; + ipl->ipl_magic = IPL_MAGIC; + ipl->ipl_count = 1; + ipl->ipl_next = NULL; + ipl->ipl_dsize = len; +# if SOLARIS || defined(sun) || defined(linux) + uniqtime((struct timeval *)&ipl->ipl_sec); +# else +# if BSD >= 199306 || defined(__FreeBSD__) || defined(__sgi) + microtime((struct timeval *)&ipl->ipl_sec); +# endif +# endif + + /* + * Loop through all the items to be logged, copying each one to the + * buffer. Use bcopy for normal data or the mb_t copyout routine. + */ + for (i = 0, s = buf + sizeof(*ipl); i < cnt; i++) { + if (types[i] == 0) + bcopy(items[i], s, itemsz[i]); + else if (types[i] == 1) { +# if SOLARIS + copyout_mblk(items[i], 0, itemsz[i], s); +# else + m_copydata(items[i], 0, itemsz[i], s); +# endif + } + s += itemsz[i]; + } + MUTEX_ENTER(&ipl_mutex); + *iplh[dev] = ipl; + iplh[dev] = &ipl->ipl_next; +# if SOLARIS + cv_signal(&iplwait); + mutex_exit(&ipl_mutex); +# else + MUTEX_EXIT(&ipl_mutex); +# ifdef linux + wake_up_interruptible(&iplwait[dev]); +# else + wakeup(&iplh[dev]); +# endif +# endif + return 1; +} + + +int ipflog_read(unit, uio) +int unit; +struct uio *uio; +{ + iplog_t *ipl; + int error = 0, dlen, copied; +# if defined(_KERNEL) && !SOLARIS + int s; +# endif + + /* + * Sanity checks. Make sure the minor # is valid and we're copying + * a valid chunk of data. + */ + if ((IPL_LOGMAX < unit) || (unit < 0)) + return ENXIO; + if (!uio->uio_resid) + return 0; + if ((uio->uio_resid < sizeof(iplog_t)) || + (uio->uio_resid > IPLLOGSIZE)) + return EINVAL; + + /* + * Lock the log so we can snapshot the variables. Wait for a signal + * if the log is empty. + */ + SPL_NET(s); + MUTEX_ENTER(&ipl_mutex); + + while (!iplused[unit] || !iplt[unit]) { +# if SOLARIS && defined(_KERNEL) + if (!cv_wait_sig(&iplwait, &ipl_mutex)) { + MUTEX_EXIT(&ipl_mutex); + return EINTR; + } +# else +# ifdef linux + interruptible_sleep_on(&iplwait[unit]); + if (current->signal & ~current->blocked) + return -EINTR; +# else + MUTEX_EXIT(&ipl_mutex); + SPL_X(s); + error = SLEEP(&iplh[unit], "ipl sleep"); + if (error) + return error; + SPL_NET(s); + MUTEX_ENTER(&ipl_mutex); +# endif /* linux */ +# endif /* SOLARIS */ + } + +# if BSD >= 199306 || defined(__FreeBSD__) + uio->uio_rw = UIO_READ; +# endif + + for (copied = 0; (ipl = iplt[unit]); copied += dlen) { + dlen = ipl->ipl_dsize; + if (dlen + sizeof(iplog_t) > uio->uio_resid) + break; + /* + * Don't hold the mutex over the uiomove call. + */ + iplt[unit] = ipl->ipl_next; + MUTEX_EXIT(&ipl_mutex); + SPL_X(s); + error = UIOMOVE((caddr_t)ipl, ipl->ipl_dsize, UIO_READ, uio); + KFREES((caddr_t)ipl, ipl->ipl_dsize); + if (error) + break; + SPL_NET(s); + MUTEX_ENTER(&ipl_mutex); + iplused[unit] -= dlen; + } + if (!ipl) { + iplused[unit] = 0; + iplh[unit] = &iplt[unit]; + } + + if (!error) { + MUTEX_EXIT(&ipl_mutex); + SPL_X(s); + } +#ifdef linux + if (!error) + return copied; + return -error; +#else + return error; +#endif +} + + +int ipflog_clear(unit) +int unit; +{ + iplog_t *ipl; + int used; + + while ((ipl = iplt[unit])) { + iplt[unit] = ipl->ipl_next; + KFREES((caddr_t)ipl, ipl->ipl_dsize); + } + iplh[unit] = &iplt[unit]; + used = iplused[unit]; + iplused[unit] = 0; + iplcrc[unit] = 0; + return used; +} +#endif /* IPFILTER_LOG */ diff --git a/sys/netinet/ip_nat.c b/sys/netinet/ip_nat.c index 3c9476fe68d2..e1774b34bb05 100644 --- a/sys/netinet/ip_nat.c +++ b/sys/netinet/ip_nat.c @@ -1,5 +1,5 @@ /* - * (C)opyright 1995-1996 by Darren Reed. + * Copyright (C) 1995-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 @@ -7,9 +7,9 @@ * * Added redirect stuff and a LOT of bug fixes. (mcn@EnGarde.com) */ -#if !defined(lint) && defined(LIBC_SCCS) -static char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; -static char rcsid[] = "$Id: ip_nat.c,v 2.0.2.18 1997/05/24 07:34:44 darrenr Exp $"; +#if !defined(lint) +static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.0.2.44.2.3 1997/11/12 10:53:29 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) @@ -28,19 +28,23 @@ static char rcsid[] = "$Id: ip_nat.c,v 2.0.2.18 1997/05/24 07:34:44 darrenr Exp #include #if defined(KERNEL) && (__FreeBSD_version >= 220000) # include -# include +# include #else # include #endif #include #include -#include +#ifndef linux +# include +#endif #include -#ifdef _KERNEL +#if defined(_KERNEL) && !defined(linux) # include #endif #if !defined(__SVR4) && !defined(__svr4__) -# include +# ifndef linux +# include +# endif #else # include # include @@ -63,18 +67,27 @@ static char rcsid[] = "$Id: ip_nat.c,v 2.0.2.18 1997/05/24 07:34:44 darrenr Exp #include #include +#ifdef __sgi +# ifdef IFF_DRVRLOCK /* IRIX6 */ +#include +#include +# endif +#endif + #ifdef RFC1825 #include #include extern struct ifnet vpnif; #endif -#include +#ifndef linux +# include +#endif #include #include -#include #include #include "netinet/ip_compat.h" +#include #include "netinet/ip_fil.h" #include "netinet/ip_proxy.h" #include "netinet/ip_nat.h" @@ -88,14 +101,32 @@ extern struct ifnet vpnif; nat_t *nat_table[2][NAT_SIZE], *nat_instances = NULL; ipnat_t *nat_list = NULL; -u_long fr_defnatage = 1200; +u_long fr_defnatage = 1200, /* 10 minutes (600 seconds) */ + fr_defnaticmpage = 6; /* 3 seconds */ natstat_t nat_stats; -#if SOLARIS && defined(_KERNEL) +#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) extern kmutex_t ipf_nat; -extern kmutex_t ipf_natfrag; #endif -static int flush_nattable __P((void)), clear_natlist __P((void)); +static int nat_flushtable __P((void)); +static int nat_clearlist __P((void)); +static void nat_delete __P((struct nat *)); +static int nat_ifpaddr __P((nat_t *, void *, struct in_addr *)); + + +#define LONG_SUM(in) (((in) & 0xffff) + ((in) >> 16)) + +#define CALC_SUMD(s1, s2, sd) { \ + /* Do it twice */ \ + (s1) = ((s1) & 0xffff) + ((s1) >> 16); \ + (s1) = ((s1) & 0xffff) + ((s1) >> 16); \ + /* Do it twice */ \ + (s2) = ((s2) & 0xffff) + ((s2) >> 16); \ + (s2) = ((s2) & 0xffff) + ((s2) >> 16); \ + /* Because ~1 == -2, We really need ~1 == -1 */ \ + if ((s1) > (s2)) (s2)--; \ + (sd) = (s2) - (s1); \ + (sd) = ((sd) & 0xffff) + ((sd) >> 16); } void fix_outcksum(sp, n) u_short *sp; @@ -104,11 +135,9 @@ u_long n; register u_short sumshort; register u_long sum1; -#ifdef sparc - sum1 = (~(*sp)) & 0xffff; -#else + if (!n) + return; sum1 = (~ntohs(*sp)) & 0xffff; -#endif sum1 += (n); sum1 = (sum1 >> 16) + (sum1 & 0xffff); /* Again */ @@ -125,6 +154,8 @@ u_long n; register u_short sumshort; register u_long sum1; + if (!n) + return; #ifdef sparc sum1 = (~(*sp)) & 0xffff; #else @@ -164,21 +195,33 @@ u_long n; * Handle ioctls which manipulate the NAT. */ int nat_ioctl(data, cmd, mode) +#if defined(__NetBSD__) || defined(__OpenBSD__) +u_long cmd; +#else +int cmd; +#endif caddr_t data; -int cmd, mode; +int mode; { register ipnat_t *nat, *n = NULL, **np = NULL; ipnat_t natd; - int error = 0, ret, s; + int error = 0, ret; +#if defined(_KERNEL) && !SOLARIS + int s; +#endif + + nat = NULL; /* XXX gcc -Wuninitialized */ /* * For add/delete, look to see if the NAT entry is already present */ + SPL_NET(s); MUTEX_ENTER(&ipf_nat); - SPLNET(s); if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) { IRCOPY(data, (char *)&natd, sizeof(natd)); nat = &natd; + nat->in_inip &= nat->in_inmsk; + nat->in_outip &= nat->in_outmsk; for (np = &nat_list; (n = *np); np = &n->in_next) if (!bcmp((char *)&nat->in_flags, (char *)&n->in_flags, IPN_CMPSIZ)) @@ -201,8 +244,10 @@ int cmd, mode; error = ENOMEM; break; } - IRCOPY((char *)data, (char *)n, sizeof(*n)); + bcopy((char *)nat, (char *)n, sizeof(*n)); n->in_ifp = (void *)GETUNIT(n->in_ifname); + if (!n->in_ifp) + n->in_ifp = (void *)-1; n->in_apr = ap_match(n->in_p, n->in_plabel); n->in_next = *np; n->in_use = 0; @@ -211,7 +256,7 @@ int cmd, mode; n->in_space -= 2; else n->in_space = 1; /* single IP# mapping */ - if (n->in_outmsk != 0xffffffff) + if ((n->in_outmsk != 0xffffffff) && n->in_outmsk) n->in_nip = ntohl(n->in_outip) + 1; else n->in_nip = ntohl(n->in_outip); @@ -260,9 +305,9 @@ int cmd, mode; IRCOPY((char *)data, (char *)&nl, sizeof(nl)); - if (nat_lookupredir(&nl)) + if (nat_lookupredir(&nl)) { IWCOPY((char *)&nl, (char *)data, sizeof(nl)); - else + } else error = ESRCH; break; } @@ -271,7 +316,7 @@ int cmd, mode; error = EPERM; break; } - ret = flush_nattable(); + ret = nat_flushtable(); IWCOPY((caddr_t)&ret, data, sizeof(ret)); break; case SIOCCNATL : @@ -279,21 +324,25 @@ int cmd, mode; error = EPERM; break; } - ret = clear_natlist(); + ret = nat_clearlist(); IWCOPY((caddr_t)&ret, data, sizeof(ret)); break; case FIONREAD : #ifdef IPFILTER_LOG - *(int *)data = iplused[IPL_LOGNAT]; + IWCOPY((caddr_t)&iplused[IPL_LOGNAT], (caddr_t)data, + sizeof(iplused[IPL_LOGNAT])); #endif break; } - SPLX(s); MUTEX_EXIT(&ipf_nat); + SPL_X(s); return error; } +/* + * Delete a nat entry from the various lists and table. + */ static void nat_delete(natd) struct nat *natd; { @@ -314,6 +363,11 @@ struct nat *natd; break; } + /* + * If there is an active reference from the nat entry to its parent + * rule, decrement the rule's reference count and free it too if no + * longer being used. + */ if ((ipn = natd->nat_ptr)) { ipn->in_space++; ipn->in_use--; @@ -324,18 +378,20 @@ struct nat *natd; nat_stats.ns_rules--; } } - MUTEX_ENTER(&ipf_natfrag); - if (nat->nat_frag && nat->nat_frag->ipfr_data == nat) - nat->nat_frag->ipfr_data = NULL; - MUTEX_EXIT(&ipf_natfrag); + + /* + * If there's a fragment table entry too for this nat entry, then + * dereference that as well. + */ + ipfr_forget((void *)natd); KFREE(natd); } /* - * flush_nattable - clear the NAT table of all mapping entries. + * nat_flushtable - clear the NAT table of all mapping entries. */ -static int flush_nattable() +static int nat_flushtable() { register nat_t *nat, **natp; register int j = 0; @@ -358,9 +414,9 @@ static int flush_nattable() /* - * clear_natlist - delete all entries in the active NAT mapping list. + * nat_clearlist - delete all entries in the active NAT mapping list. */ -static int clear_natlist() +static int nat_clearlist() { register ipnat_t *n, **np = &nat_list; int i = 0; @@ -383,15 +439,90 @@ static int clear_natlist() } +/* + * return the first IP Address associated with an interface + */ +static int nat_ifpaddr(nat, ifptr, inp) +nat_t *nat; +void *ifptr; +struct in_addr *inp; +{ +#if SOLARIS + ill_t *ill = ifptr; +#else + struct ifnet *ifp = ifptr; +#endif + struct in_addr in; + +#if SOLARIS + in.s_addr = ill->ill_ipif->ipif_local_addr; +#else /* SOLARIS */ +# if linux + ; +# else /* linux */ + struct ifaddr *ifa; + struct sockaddr_in *sin; + +# if (__FreeBSD_version >= 300000) + ifa = TAILQ_FIRST(&ifp->if_addrhead); +# else +# if defined(__NetBSD__) || defined(__OpenBSD__) + ifa = ifp->if_addrlist.tqh_first; +# else +# if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ + ifa = &((struct in_ifaddr *)ifp->in_ifaddr)->ia_ifa; +# else + ifa = ifp->if_addrlist; +# endif +# endif /* __NetBSD__ || __OpenBSD__ */ +# endif /* __FreeBSD_version >= 300000 */ +# if (BSD < 199306) && !(/*IRIX6*/defined(__sgi) && defined(IFF_DRVRLOCK)) + sin = (SOCKADDR_IN *)&ifa->ifa_addr; +# else + sin = (SOCKADDR_IN *)ifa->ifa_addr; + while (sin && ifa && + sin->sin_family != AF_INET) { +# if (__FreeBSD_version >= 300000) + ifa = TAILQ_NEXT(ifa, ifa_link); +# else +# if defined(__NetBSD__) || defined(__OpenBSD__) + ifa = ifa->ifa_list.tqe_next; +# else + ifa = ifa->ifa_next; +# endif +# endif /* __FreeBSD_version >= 300000 */ + if (ifa) + sin = (SOCKADDR_IN *)ifa->ifa_addr; + } + if (!ifa) + sin = NULL; + if (!sin) { + KFREE(nat); + return -1; + } +# endif /* (BSD < 199306) && (!__sgi && IFF_DRVLOCK) */ + in = sin->sin_addr; + in.s_addr = ntohl(in.s_addr); +# endif /* linux */ +#endif /* SOLARIS */ + *inp = in; + return 0; +} + + /* * Create a new NAT table entry. */ +#ifdef __STDC__ +nat_t *nat_new(ipnat_t *np, ip_t *ip, fr_info_t *fin, u_short flags, int direction) +#else nat_t *nat_new(np, ip, fin, flags, direction) ipnat_t *np; ip_t *ip; fr_info_t *fin; u_short flags; int direction; +#endif { register u_long sum1, sum2, sumd; u_short port = 0, sport = 0, dport = 0, nport = 0; @@ -419,11 +550,6 @@ int direction; * Search the current table for a match. */ if (direction == NAT_OUTBOUND) { -#if SOLARIS - ill_t *ill = fin->fin_ifp; -#else - struct ifnet *ifp = fin->fin_ifp; -#endif /* * If it's an outbound packet which doesn't match any existing * record, then create a new port @@ -432,50 +558,13 @@ int direction; port = 0; in.s_addr = np->in_nip; if (!in.s_addr && (np->in_outmsk == 0xffffffff)) { -#if SOLARIS - in.s_addr = ill->ill_ipif->ipif_local_addr; -#else - struct ifaddr *ifa; - struct sockaddr_in *sin; - -# if (__FreeBSD_version >= 300000) - ifa = TAILQ_FIRST(&ifp->if_addrhead); -# else -# ifdef __NetBSD__ - ifa = ifp->if_addrlist.tqh_first; -# else - ifa = ifp->if_addrlist; -# endif -# endif -# if BSD < 199306 - sin = (SOCKADDR_IN *)&ifa->ifa_addr; -# else - sin = (SOCKADDR_IN *)ifa->ifa_addr; - while (sin && ifa && - sin->sin_family != AF_INET) { -# if (__FreeBSD_version >= 300000) - ifa = TAILQ_NEXT(ifa, ifa_link); -# else -# ifdef __NetBSD__ - ifa = ifa->ifa_list.tqe_next; -# else - ifa = ifa->ifa_next; -# endif -# endif - sin = (SOCKADDR_IN *)ifa->ifa_addr; - } - if (!ifa) - sin = NULL; - if (!sin) { - KFREE(nat); + if (nat_ifpaddr(nat, fin->fin_ifp, &in) == -1) return NULL; - } -# endif - in = sin->sin_addr; - in.s_addr = ntohl(in.s_addr); -#endif - } - if (nflags & IPN_TCPUDP) { + } else if (!in.s_addr && !np->in_outmsk) { + in.s_addr = ntohl(ip->ip_src.s_addr); + if (nflags & IPN_TCPUDP) + port = sport; + } else if (nflags & IPN_TCPUDP) { port = htons(np->in_pnext++); if (np->in_pnext >= ntohs(np->in_pmax)) { np->in_pnext = ntohs(np->in_pmin); @@ -520,7 +609,7 @@ int direction; * internal port. */ in.s_addr = ntohl(np->in_inip); - if (!(nport = np->in_pnext)) + if (!(nport = htons(np->in_pnext))) nport = dport; nat->nat_inip.s_addr = htonl(in.s_addr); @@ -597,10 +686,10 @@ int direction; nat->nat_dir = direction; if (direction == NAT_OUTBOUND) { if (flags & IPN_TCPUDP) - tcp->th_sport = htons(port); + tcp->th_sport = port; } else { if (flags & IPN_TCPUDP) - tcp->th_dport = htons(nport); + tcp->th_dport = nport; } nat_stats.ns_added++; nat_stats.ns_inuse++; @@ -609,6 +698,132 @@ int direction; } +nat_t *nat_icmpinlookup(ip, fin) +ip_t *ip; +fr_info_t *fin; +{ + icmphdr_t *icmp; + tcphdr_t *tcp = NULL; + ip_t *oip; + int flags = 0, type; + + icmp = (icmphdr_t *)fin->fin_dp; + /* + * Does it at least have the return (basic) IP header ? + * Only a basic IP header (no options) should be with an ICMP error + * header. + */ + if ((ip->ip_hl != 5) || (ip->ip_len < sizeof(*icmp) + sizeof(ip_t))) + return NULL; + type = icmp->icmp_type; + /* + * If it's not an error type, then return. + */ + if ((type != ICMP_UNREACH) && (type != ICMP_SOURCEQUENCH) && + (type != ICMP_REDIRECT) && (type != ICMP_TIMXCEED) && + (type != ICMP_PARAMPROB)) + return NULL; + + oip = (ip_t *)((char *)fin->fin_dp + 8); + if (oip->ip_p == IPPROTO_TCP) + flags = IPN_TCP; + else if (oip->ip_p == IPPROTO_UDP) + flags = IPN_UDP; + if (flags & IPN_TCPUDP) { + tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2)); + return nat_inlookup(fin->fin_ifp, flags, oip->ip_dst, + tcp->th_dport, oip->ip_src, tcp->th_sport); + } + return nat_inlookup(fin->fin_ifp, 0, oip->ip_src, 0, oip->ip_dst, 0); +} + + +/* + * This should *ONLY* be used for incoming packets to make sure a NAT'd ICMP + * packet gets correctly recognised. + */ +nat_t *nat_icmpin(ip, fin, nflags) +ip_t *ip; +fr_info_t *fin; +int *nflags; +{ + icmphdr_t *icmp; + nat_t *nat; + ip_t *oip; + int flags = 0; + + if (!(nat = nat_icmpinlookup(ip, fin))) + return NULL; + + *nflags = IPN_ICMPERR; + icmp = (icmphdr_t *)fin->fin_dp; + oip = (ip_t *)((char *)icmp + 8); + if (oip->ip_p == IPPROTO_TCP) + flags = IPN_TCP; + else if (oip->ip_p == IPPROTO_UDP) + flags = IPN_UDP; + /* + * Need to adjust ICMP header to include the real IP#'s and + * port #'s. Only apply a checksum change relative to the + * IP address change is it will be modified again in ip_natout + * for both address and port. Two checksum changes are + * necessary for the two header address changes. Be careful + * to only modify the checksum once for the port # and twice + * for the IP#. + */ + if (flags & IPN_TCPUDP) { + tcphdr_t *tcp = (tcphdr_t *)(oip + 1); + u_long sum1, sum2, sumd; + struct in_addr in; + + if (nat->nat_dir == NAT_OUTBOUND) { + sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr)); + in = nat->nat_outip; + oip->ip_src = in; + tcp->th_sport = nat->nat_outport; + } else { + sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr)); + in = nat->nat_inip; + oip->ip_dst = in; + tcp->th_dport = nat->nat_inport; + } + + sum2 = LONG_SUM(in.s_addr); + + CALC_SUMD(sum1, sum2, sumd); + sumd = (sumd & 0xffff) + (sumd >> 16); + + if (nat->nat_dir == NAT_OUTBOUND) { + fix_incksum(&oip->ip_sum, sumd); + fix_incksum(&icmp->icmp_cksum, sumd); + } else { + fix_outcksum(&oip->ip_sum, sumd); + fix_outcksum(&icmp->icmp_cksum, sumd); + } + + /* + * TCP checksum doesn't make it into the 1st eight + * bytes but UDP does. + */ + if (ip->ip_p == IPPROTO_UDP) { + udphdr_t *udp = (udphdr_t *)tcp; + + if (udp->uh_sum) { + if (nat->nat_dir == NAT_OUTBOUND) + fix_incksum(&udp->uh_sum, + nat->nat_sumd); + else + fix_outcksum(&udp->uh_sum, + nat->nat_sumd); + } + } + } else + ip->ip_dst = nat->nat_outip; + nat->nat_age = fr_defnaticmpage; + return nat; +} + + /* * NB: these lookups don't lock access to the list, it assume it has already * been done! @@ -619,11 +834,15 @@ int direction; * we're looking for a table entry, based on the destination address. * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ +#ifdef __STDC__ +nat_t *nat_inlookup(void *ifp, int flags, struct in_addr src, u_short sport, struct in_addr mapdst, u_short mapdport) +#else nat_t *nat_inlookup(ifp, flags, src, sport, mapdst, mapdport) void *ifp; register int flags; struct in_addr src , mapdst; u_short sport, mapdport; +#endif { register nat_t *nat; @@ -648,24 +867,29 @@ u_short sport, mapdport; * we're looking for a table entry, based on the source address. * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ +#ifdef __STDC__ +nat_t *nat_outlookup(void *ifp, int flags, struct in_addr src, u_short sport, struct in_addr dst, u_short dport) +#else nat_t *nat_outlookup(ifp, flags, src, sport, dst, dport) void *ifp; register int flags; struct in_addr src , dst; u_short sport, dport; +#endif { register nat_t *nat; flags &= IPN_TCPUDP; nat = nat_table[0][src.s_addr % NAT_SIZE]; - for (; nat; nat = nat->nat_hnext[0]) + for (; nat; nat = nat->nat_hnext[0]) { if ((!ifp || ifp == nat->nat_ifp) && nat->nat_inip.s_addr == src.s_addr && nat->nat_oip.s_addr == dst.s_addr && flags == nat->nat_flags && (!flags || (nat->nat_inport == sport && nat->nat_oport == dport))) return nat; + } return NULL; } @@ -675,11 +899,15 @@ u_short sport, dport; * real destination address/port. We use this lookup when sending a packet * out, we're looking for a table entry, based on the source address. */ +#ifdef __STDC__ +nat_t *nat_lookupmapip(void *ifp, int flags, struct in_addr mapsrc, u_short mapsport, struct in_addr dst, u_short dport) +#else nat_t *nat_lookupmapip(ifp, flags, mapsrc, mapsport, dst, dport) void *ifp; register int flags; struct in_addr mapsrc , dst; u_short mapsport, dport; +#endif { register nat_t *nat; @@ -710,10 +938,11 @@ register natlookup_t *np; * If nl_inip is non null, this is a lookup based on the real * ip address. Else, we use the fake. */ - if ((nat = nat_outlookup(NULL, IPN_TCPUDP, np->nl_inip, np->nl_inport, - np->nl_outip, np->nl_outport))) { - np->nl_inip = nat->nat_outip; - np->nl_inport = nat->nat_outport; + if ((nat = nat_outlookup(NULL, np->nl_flags, np->nl_inip, + np->nl_inport, np->nl_outip, + np->nl_outport))) { + np->nl_realip = nat->nat_outip; + np->nl_realport = nat->nat_outport; } return nat; } @@ -731,10 +960,11 @@ fr_info_t *fin; register ipnat_t *np; register u_long ipa; tcphdr_t *tcp = NULL; - nat_t *nat; u_short nflags = 0, sport = 0, dport = 0, *csump = NULL; struct ifnet *ifp; frentry_t *fr; + nat_t *nat; + int natadd = 1; if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) && fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1) @@ -757,11 +987,12 @@ fr_info_t *fin; ipa = ip->ip_src.s_addr; MUTEX_ENTER(&ipf_nat); - if ((nat = ipfr_nat_knownfrag(ip, fin))) - ; - else if ((nat = nat_outlookup(fin->fin_ifp, nflags, ip->ip_src, sport, + if ((ip->ip_off & (IP_OFFMASK|IP_MF)) && + (nat = ipfr_nat_knownfrag(ip, fin))) + natadd = 0; + else if ((nat = nat_outlookup(ifp, nflags, ip->ip_src, sport, ip->ip_dst, dport))) - np = nat->nat_ptr; + ; else /* * If there is no current entry in the nat table for this IP#, @@ -794,7 +1025,7 @@ fr_info_t *fin; } if (nat) { - if (!nat->nat_frag && fin->fin_fi.fi_fl & FI_FRAG) + if (natadd && fin->fin_fi.fi_fl & FI_FRAG) ipfr_nat_newfrag(ip, fin, 0, nat); nat->nat_age = fr_defnatage; ip->ip_src = nat->nat_outip; @@ -805,7 +1036,7 @@ fr_info_t *fin; * Fix up checksums, not by recalculating them, but * simply computing adjustments. */ -#if SOLARIS +#if SOLARIS || defined(__sgi) if (nat->nat_dir == NAT_OUTBOUND) fix_outcksum(&ip->ip_sum, nat->nat_ipsumd); else @@ -872,8 +1103,9 @@ fr_info_t *fin; register struct in_addr in; struct ifnet *ifp = fin->fin_ifp; tcphdr_t *tcp = NULL; - u_short sport = 0, dport = 0, nflags = 0, *csump = NULL; + u_short sport = 0, dport = 0, *csump = NULL; nat_t *nat; + int nflags = 0, natadd = 1; if (!(ip->ip_off & 0x1fff) && !(fin->fin_fi.fi_fl & FI_SHORT)) { if (ip->ip_p == IPPROTO_TCP) @@ -891,11 +1123,14 @@ fr_info_t *fin; MUTEX_ENTER(&ipf_nat); - if ((nat = ipfr_nat_knownfrag(ip, fin))) + if ((ip->ip_p == IPPROTO_ICMP) && (nat = nat_icmpin(ip, fin, &nflags))) ; + else if ((ip->ip_off & IP_OFFMASK) && + (nat = ipfr_nat_knownfrag(ip, fin))) + natadd = 0; else if ((nat = nat_inlookup(fin->fin_ifp, nflags, ip->ip_src, sport, ip->ip_dst, dport))) - np = nat->nat_ptr; + ; else /* * If there is no current entry in the nat table for this IP#, @@ -905,16 +1140,8 @@ fr_info_t *fin; if ((np->in_ifp == ifp) && (!np->in_flags || (nflags & np->in_flags)) && ((in.s_addr & np->in_outmsk) == np->in_outip) && - (np->in_redir & NAT_REDIRECT || - np->in_pmin == dport)) { - /* - * If this rule (np) is a redirection, rather - * than a mapping, then do a nat_new. - * Otherwise, if it's just a mapping, do a - * continue; - */ - if (!(np->in_redir & NAT_REDIRECT)) - continue; + (np->in_redir & NAT_REDIRECT) && + (!np->in_pmin || np->in_pmin == dport)) { if ((nat = nat_new(np, ip, fin, nflags, NAT_INBOUND))) #ifdef IPFILTER_LOG @@ -925,10 +1152,13 @@ fr_info_t *fin; break; } if (nat) { - if (!nat->nat_frag && fin->fin_fi.fi_fl & FI_FRAG) + if (natadd && fin->fin_fi.fi_fl & FI_FRAG) ipfr_nat_newfrag(ip, fin, 0, nat); (void) ap_check(ip, tcp, fin, nat); - nat->nat_age = fr_defnatage; + + if (nflags != IPN_ICMPERR) + nat->nat_age = fr_defnatage; + ip->ip_dst = nat->nat_inip; nat->nat_bytes += ip->ip_len; nat->nat_pkts++; @@ -937,13 +1167,13 @@ fr_info_t *fin; * Fix up checksums, not by recalculating them, but * simply computing adjustments. */ -#if SOLARIS +#if SOLARIS || defined(__sgi) if (nat->nat_dir == NAT_OUTBOUND) fix_incksum(&ip->ip_sum, nat->nat_ipsumd); else fix_outcksum(&ip->ip_sum, nat->nat_ipsumd); #endif - if (nflags && !(ip->ip_off & 0x1fff) && + if ((nflags & IPN_TCPUDP) && !(ip->ip_off & 0x1fff) && !(fin->fin_fi.fi_fl & FI_SHORT)) { if (nat->nat_inport) @@ -994,14 +1224,10 @@ fr_info_t *fin; */ void ip_natunload() { - int s; - MUTEX_ENTER(&ipf_nat); - SPLNET(s); - (void) clear_natlist(); - (void) flush_nattable(); + (void) nat_clearlist(); + (void) nat_flushtable(); (void) ap_unload(); - SPLX(s) MUTEX_EXIT(&ipf_nat); } @@ -1013,10 +1239,12 @@ void ip_natunload() void ip_natexpire() { register struct nat *nat, **natp; +#if defined(_KERNEL) && !SOLARIS int s; +#endif + SPL_NET(s); MUTEX_ENTER(&ipf_nat); - SPLNET(s); for (natp = &nat_instances; (nat = *natp); ) { if (--nat->nat_age) { natp = &nat->nat_next; @@ -1029,34 +1257,83 @@ void ip_natexpire() nat_delete(nat); nat_stats.ns_expire++; } - SPLX(s); MUTEX_EXIT(&ipf_nat); + SPL_X(s); +} + + +/* + */ +#ifdef __STDC__ +void ip_natsync(void *ifp) +#else +void ip_natsync(ifp) +void *ifp; +#endif +{ + register nat_t *nat; + register u_long sum1, sum2, sumd; + struct in_addr in; + ipnat_t *np; +#if defined(_KERNEL) && !SOLARIS + int s; +#endif + + SPL_NET(s); + MUTEX_ENTER(&ipf_nat); + for (nat = nat_instances; nat; nat = nat->nat_next) + if ((ifp == nat->nat_ifp) && (np = nat->nat_ptr)) + if ((np->in_outmsk == 0xffffffff) && !np->in_nip) { + /* + * Change the map-to address to be the same + * as the new one. + */ + sum1 = nat->nat_outip.s_addr; + if (nat_ifpaddr(nat, ifp, &in) == -1) + nat->nat_outip.s_addr = htonl(in.s_addr); + sum2 = nat->nat_outip.s_addr; + + /* + * Readjust the checksum adjustment to take + * into account the new IP#. + * + * Do it twice + */ + sum1 = (sum1 & 0xffff) + (sum1 >> 16); + sum1 = (sum1 & 0xffff) + (sum1 >> 16); + + /* Do it twice */ + sum2 = (sum2 & 0xffff) + (sum2 >> 16); + sum2 = (sum2 & 0xffff) + (sum2 >> 16); + + /* Because ~1 == -2, We really need ~1 == -1 */ + if (sum1 > sum2) + sum2--; + sumd = sum2 - sum1; + sumd = (sumd & 0xffff) + (sumd >> 16); + sumd += nat->nat_sumd; + nat->nat_sumd = (sumd & 0xffff) + (sumd >> 16); + } + MUTEX_EXIT(&ipf_nat); + SPL_X(s); } #ifdef IPFILTER_LOG +# ifdef __STDC__ +void nat_log(struct nat *nat, u_short type) +# else void nat_log(nat, type) struct nat *nat; u_short type; +# endif { - struct ipnat *np; - struct natlog natl; - int rulen; + struct ipnat *np; + struct natlog natl; + void *items[1]; + size_t sizes[1]; + int rulen, types[1]; - if (iplused[IPL_LOGNAT] + sizeof(natl) > IPLLOGSIZE) { - nat_stats.ns_logfail++; - return; - } - - if (iplh[IPL_LOGNAT] == iplbuf[IPL_LOGNAT] + IPLLOGSIZE) - iplh[IPL_LOGNAT] = iplbuf[IPL_LOGNAT]; - -# ifdef sun - uniqtime(&natl); -# endif -# if BSD >= 199306 || defined(__FreeBSD__) - microtime((struct timeval *)&natl); -# endif natl.nl_inip = nat->nat_inip; natl.nl_outip = nat->nat_outip; natl.nl_origip = nat->nat_oip; @@ -1074,12 +1351,10 @@ u_short type; break; } } + items[0] = &natl; + sizes[0] = sizeof(natl); + types[0] = 0; - if (!fr_copytolog(IPL_LOGNAT, (char *)&natl, sizeof(natl))) { - iplused[IPL_LOGNAT] += sizeof(natl); - nat_stats.ns_logged++; - } else - nat_stats.ns_logfail++; - wakeup(iplbuf[IPL_LOGNAT]); + (void) ipllog(IPL_LOGNAT, 0, items, sizes, types, 1); } #endif diff --git a/sys/netinet/ip_nat.h b/sys/netinet/ip_nat.h index add4a9a237e6..f0cb517bb007 100644 --- a/sys/netinet/ip_nat.h +++ b/sys/netinet/ip_nat.h @@ -1,21 +1,17 @@ /* - * (C)opyright 1995-1997 by Darren Reed. + * Copyright (C) 1995-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. * * @(#)ip_nat.h 1.5 2/4/96 - * $Id: ip_nat.h,v 2.0.2.12 1997/05/24 07:35:20 darrenr Exp $ + * $Id: ip_nat.h,v 2.0.2.23.2.1 1997/11/05 11:08:18 darrenr Exp $ */ #ifndef __IP_NAT_H__ #define __IP_NAT_H__ -#ifndef __IP_PROXY_H__ -#include "netinet/ip_proxy.h" -#endif - #ifndef SOLARIS #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #endif @@ -29,7 +25,6 @@ #define SIOCGIPST _IOR('r', 85, struct ips_stat) #define SIOCFLNAT _IOWR('r', 86, int) #define SIOCCNATL _IOWR('r', 87, int) - #else #define SIOCADNAT _IOW(r, 80, struct ipnat) #define SIOCRMNAT _IOW(r, 81, struct ipnat) @@ -42,13 +37,16 @@ #endif #define NAT_SIZE 367 +#ifndef APR_LABELLEN +#define APR_LABELLEN 16 +#endif typedef struct nat { u_long nat_age; int nat_flags; u_long nat_sumd; u_long nat_ipsumd; - struct ipfr *nat_frag; + void *nat_data; struct in_addr nat_inip; struct in_addr nat_outip; struct in_addr nat_oip; /* other ip */ @@ -70,6 +68,7 @@ typedef struct nat { typedef struct ipnat { struct ipnat *in_next; void *in_ifp; + void *in_apr; u_int in_space; u_int in_use; struct in_addr in_nextip; @@ -78,7 +77,6 @@ typedef struct ipnat { u_short in_port[2]; struct in_addr in_in[2]; struct in_addr in_out[2]; - struct aproxy *in_apr; int in_redir; /* 0 if it's a mapping, 1 if it's a hard redir */ char in_ifname[IFNAMSIZ]; char in_plabel[APR_LABELLEN]; /* proxy label */ @@ -102,13 +100,16 @@ typedef struct ipnat { #define NAT_BIMAP (NAT_MAP|NAT_REDIRECT) #define IPN_CMPSIZ (sizeof(struct in_addr) * 4 + sizeof(u_short) * 3 + \ - sizeof(int)) + sizeof(int) + IFNAMSIZ + APR_LABELLEN + sizeof(char)) typedef struct natlookup { struct in_addr nl_inip; struct in_addr nl_outip; + struct in_addr nl_realip; + int nl_flags; u_short nl_inport; u_short nl_outport; + u_short nl_realport; } natlookup_t; typedef struct natstat { @@ -128,10 +129,10 @@ typedef struct natstat { #define IPN_UDP 0x02 #define IPN_TCPUDP 0x03 #define IPN_DELETE 0x04 +#define IPN_ICMPERR 0x08 typedef struct natlog { - struct timeval nl_tv; struct in_addr nl_origip; struct in_addr nl_outip; struct in_addr nl_inip; @@ -150,22 +151,30 @@ typedef struct natlog { #define NL_EXPIRE 0xffff -extern u_long fr_defnatage; -extern nat_t *nat_table[2][NAT_SIZE]; -extern int nat_ioctl __P((caddr_t, int, int)); -extern nat_t *nat_new __P((ipnat_t *, ip_t *, fr_info_t *, u_short, int)); -extern nat_t *nat_outlookup __P((void *, int, struct in_addr, u_short, +extern void ip_natsync __P((void *)); +extern u_long fr_defnatage; +extern u_long fr_defnaticmpage; +extern nat_t *nat_table[2][NAT_SIZE]; +#if defined(__NetBSD__) || defined(__OpenBSD__) +extern int nat_ioctl __P((caddr_t, u_long, int)); +#else +extern int nat_ioctl __P((caddr_t, int, int)); +#endif +extern nat_t *nat_new __P((ipnat_t *, ip_t *, fr_info_t *, u_short, int)); +extern nat_t *nat_outlookup __P((void *, int, struct in_addr, u_short, struct in_addr, u_short)); -extern nat_t *nat_inlookup __P((void *, int, struct in_addr, u_short, +extern nat_t *nat_inlookup __P((void *, int, struct in_addr, u_short, struct in_addr, u_short)); -extern nat_t *nat_lookupredir __P((natlookup_t *)); -extern nat_t *nat_lookupmapip __P((void *, int, struct in_addr, u_short, +extern nat_t *nat_lookupredir __P((natlookup_t *)); +extern nat_t *nat_lookupmapip __P((void *, int, struct in_addr, u_short, struct in_addr, u_short)); +extern nat_t *nat_icmpinlookup __P((ip_t *, fr_info_t *)); +extern nat_t *nat_icmpin __P((ip_t *, fr_info_t *, int *)); -extern int ip_natout __P((ip_t *, int, fr_info_t *)); -extern int ip_natin __P((ip_t *, int, fr_info_t *)); -extern void ip_natunload __P((void)), ip_natexpire __P((void)); -extern void nat_log __P((struct nat *, u_short)); -extern void fix_incksum __P((u_short *, u_long)); -extern void fix_outcksum __P((u_short *, u_long)); +extern int ip_natout __P((ip_t *, int, fr_info_t *)); +extern int ip_natin __P((ip_t *, int, fr_info_t *)); +extern void ip_natunload __P((void)), ip_natexpire __P((void)); +extern void nat_log __P((struct nat *, u_short)); +extern void fix_incksum __P((u_short *, u_long)); +extern void fix_outcksum __P((u_short *, u_long)); #endif /* __IP_NAT_H__ */ diff --git a/sys/netinet/ip_proxy.c b/sys/netinet/ip_proxy.c index 16e5fbe2cf44..cea27f6ca0cb 100644 --- a/sys/netinet/ip_proxy.c +++ b/sys/netinet/ip_proxy.c @@ -1,12 +1,12 @@ /* - * (C)opyright 1997 by Darren Reed. + * Copyright (C) 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 rcsid[] = "$Id: ip_proxy.c,v 2.0.2.3 1997/05/24 07:36:22 darrenr Exp $"; +#if !defined(lint) +static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.0.2.11.2.2 1997/11/12 10:54:11 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) @@ -26,13 +26,21 @@ static char rcsid[] = "$Id: ip_proxy.c,v 2.0.2.3 1997/05/24 07:36:22 darrenr Exp #include #include #include -#include +#ifndef linux +# include +#endif #include -#ifdef _KERNEL -# include +#if defined(_KERNEL) +# if !defined(linux) +# include +# else +# include +# endif #endif #if !defined(__SVR4) && !defined(__svr4__) -# include +# ifndef linux +# include +# endif #else # include # include @@ -50,12 +58,14 @@ static char rcsid[] = "$Id: ip_proxy.c,v 2.0.2.3 1997/05/24 07:36:22 darrenr Exp #include #include #include -#include +#ifndef linux +# include +#endif #include #include -#include #include #include "netinet/ip_compat.h" +#include #include "netinet/ip_fil.h" #include "netinet/ip_proxy.h" #include "netinet/ip_nat.h" @@ -71,7 +81,7 @@ static ap_session_t *ap_new_session __P((aproxy_t *, ip_t *, tcphdr_t *, #define AP_SESS_SIZE 53 -#ifdef _KERNEL +#if defined(_KERNEL) && !defined(linux) #include "netinet/ip_ftp_pxy.c" #endif @@ -105,12 +115,15 @@ static ap_session_t *ap_find(ip, tcp) ip_t *ip; tcphdr_t *tcp; { - struct in_addr src = ip->ip_src, dst = ip->ip_dst; + struct in_addr src, dst; register u_long hv; register u_short sp, dp; register ap_session_t *aps; register u_char p = ip->ip_p; + src = ip->ip_src, dst = ip->ip_dst; + sp = dp = 0; /* XXX gcc -Wunitialized */ + hv = ip->ip_src.s_addr ^ ip->ip_dst.s_addr; hv *= 651733; if (tcp) { @@ -134,6 +147,12 @@ tcphdr_t *tcp; return aps; } + +/* + * Allocate a new application proxy structure and fill it in with the + * relevant details. call the init function once complete, prior to + * returning. + */ static ap_session_t *ap_new_session(apr, ip, tcp, fin, nat) aproxy_t *apr; ip_t *ip; @@ -163,20 +182,13 @@ nat_t *nat; KMALLOC(aps, ap_session_t *, sizeof(*aps)); if (!aps) return NULL; - bzero((char *)aps, sizeof(aps)); - apr->apr_ref++; + bzero((char *)aps, sizeof(*aps)); aps->aps_apr = apr; aps->aps_src = ip->ip_src; aps->aps_dst = ip->ip_dst; aps->aps_p = ip->ip_p; aps->aps_tout = 1200; /* XXX */ if (tcp) { - if (ip->ip_p == IPPROTO_TCP) { - aps->aps_seqoff = 0; - aps->aps_ackoff = 0; - aps->aps_state[0] = 0; - aps->aps_state[1] = 0; - } aps->aps_sport = tcp->th_sport; aps->aps_dport = tcp->th_dport; } @@ -189,6 +201,10 @@ nat_t *nat; } +/* + * check to see if a packet should be passed through an active proxy routine + * if one has been setup for it. + */ int ap_check(ip, tcp, fin, nat) ip_t *ip; tcphdr_t *tcp; @@ -204,9 +220,20 @@ nat_t *nat; if ((aps = ap_find(ip, tcp)) || (aps = ap_new_session(nat->nat_ptr->in_apr, ip, tcp, fin, nat))) { - if (ip->ip_p == IPPROTO_TCP) + if (ip->ip_p == IPPROTO_TCP) { + /* + * verify that the checksum is correct. If not, then + * don't do anything with this packet. + */ + if (tcp->th_sum != fr_tcpsum(*(mb_t **)fin->fin_mp, + ip, tcp)) { + frstats[fin->fin_out].fr_tcpbad++; + return -1; + } fr_tcp_age(&aps->aps_tout, aps->aps_state, ip, fin, tcp->th_sport == aps->aps_sport); + } + apr = aps->aps_apr; err = 0; if (fin->fin_out) { @@ -219,7 +246,7 @@ nat_t *nat; aps, nat); } if (err == 2) { - tcp->th_sum = fr_tcpsum(fin->fin_mp, ip, tcp); + tcp->th_sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp); err = 0; } return err; @@ -229,15 +256,17 @@ nat_t *nat; aproxy_t *ap_match(pr, name) -char pr; +u_char pr; char *name; { aproxy_t *ap; for (ap = ap_proxies; ap->apr_p; ap++) if ((ap->apr_p == pr) && - !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) + !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) { + ap->apr_ref++; return ap; + } return NULL; } @@ -245,7 +274,7 @@ char *name; void ap_free(ap) aproxy_t *ap; { - KFREE(ap); + ap->apr_ref--; } @@ -264,7 +293,7 @@ void ap_unload() int i; for (i = 0; i < AP_SESS_SIZE; i++) - while (aps = ap_sess_tab[i]) { + while ((aps = ap_sess_tab[i])) { ap_sess_tab[i] = aps->aps_next; aps_free(aps); } diff --git a/sys/netinet/ip_proxy.h b/sys/netinet/ip_proxy.h index 2d7175491b39..2f71316a6800 100644 --- a/sys/netinet/ip_proxy.h +++ b/sys/netinet/ip_proxy.h @@ -1,11 +1,11 @@ /* - * (C)opyright 1997 by Darren Reed. + * Copyright (C) 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. * - * $Id: ip_proxy.h,v 2.0.2.2 1997/05/24 07:36:44 darrenr Exp $ + * $Id: ip_proxy.h,v 2.0.2.10 1997/10/19 15:39:23 darrenr Exp $ */ #ifndef __IP_PROXY_H__ @@ -15,18 +15,21 @@ #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #endif +#ifndef APR_LABELLEN #define APR_LABELLEN 16 +#endif #define AP_SESS_SIZE 53 struct nat; +struct ipnat; typedef struct ap_tcp { u_short apt_sport; /* source port */ u_short apt_dport; /* destination port */ - short apt_seqoff; /* sequence # difference */ - short apt_ackoff; /* ack # difference */ - tcp_seq apt_after; /* don't change seq-off until after this */ - char apt_state[2]; /* connection state */ + short apt_sel; /* seqoff/after set selector */ + short apt_seqoff[2]; /* sequence # difference */ + tcp_seq apt_after[2]; /* don't change seq-off until after this */ + u_char apt_state[2]; /* connection state */ } ap_tcp_t; typedef struct ap_udp { @@ -46,7 +49,7 @@ typedef struct ap_session { u_int aps_flags; QUAD_T aps_bytes; /* bytes sent */ QUAD_T aps_pkts; /* packets sent */ - time_t aps_tout; /* time left before expiring */ + u_long aps_tout; /* time left before expiring */ void *aps_data; /* private data */ int aps_psiz; /* size of private data */ struct ap_session *aps_next; @@ -54,16 +57,15 @@ typedef struct ap_session { #define aps_sport aps_un.apu_tcp.apt_sport #define aps_dport aps_un.apu_tcp.apt_dport +#define aps_sel aps_un.apu_tcp.apt_sel #define aps_seqoff aps_un.apu_tcp.apt_seqoff -#define aps_ackoff aps_un.apu_tcp.apt_ackoff -#define aps_sumoff aps_un.apu_tcp.apt_sumoff -#define aps_state aps_un.apu_tcp.apt_state #define aps_after aps_un.apu_tcp.apt_after +#define aps_state aps_un.apu_tcp.apt_state typedef struct aproxy { char apr_label[APR_LABELLEN]; /* Proxy label # */ - char apr_p; /* protocol */ + u_char apr_p; /* protocol */ int apr_ref; /* +1 per rule referencing it */ int apr_flags; int (* apr_init) __P((fr_info_t *, ip_t *, tcphdr_t *, @@ -80,10 +82,11 @@ typedef struct aproxy { extern ap_session_t *ap_sess_tab[AP_SESS_SIZE]; extern aproxy_t ap_proxies[]; -extern void ap_unload __P((void)); -extern void ap_free __P((aproxy_t *)); -extern void aps_free __P((ap_session_t *)); -extern int ap_check __P((ip_t *, tcphdr_t *, fr_info_t *, struct nat *)); -extern aproxy_t *ap_match __P((char, char *)); +extern int ap_ok __P((ip_t *, tcphdr_t *, struct ipnat *)); +extern void ap_unload __P((void)); +extern void ap_free __P((aproxy_t *)); +extern void aps_free __P((ap_session_t *)); +extern int ap_check __P((ip_t *, tcphdr_t *, fr_info_t *, struct nat *)); +extern aproxy_t *ap_match __P((u_char, char *)); #endif /* __IP_PROXY_H__ */ diff --git a/sys/netinet/ip_state.c b/sys/netinet/ip_state.c index a6bda8a170ed..cc14c1a9d9e6 100644 --- a/sys/netinet/ip_state.c +++ b/sys/netinet/ip_state.c @@ -1,23 +1,27 @@ /* - * (C)opyright 1995 by Darren Reed. + * Copyright (C) 1995-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[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-1995 Darren Reed"; -static char rcsid[] = "$Id: ip_state.c,v 2.0.2.12 1997/05/24 07:34:10 darrenr Exp $"; +#if !defined(lint) +static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.0.2.24.2.3 1997/11/12 10:55:34 darrenr Exp $"; #endif -#if !defined(_KERNEL) && !defined(KERNEL) +#if !defined(_KERNEL) && !defined(KERNEL) && !defined(__KERNEL__) # include # include +#else +# ifdef linux +# include +# include +# endif #endif #include #include #include -#include #include #if defined(KERNEL) && (__FreeBSD_version >= 220000) # include @@ -25,14 +29,19 @@ static char rcsid[] = "$Id: ip_state.c,v 2.0.2.12 1997/05/24 07:34:10 darrenr Ex #else # include #endif +#include #include +#ifndef linux #include +#endif #include -#ifdef _KERNEL +#if defined(_KERNEL) && !defined(linux) # include #endif #if !defined(__SVR4) && !defined(__svr4__) -# include +# ifndef linux +# include +# endif #else # include # include @@ -49,15 +58,19 @@ static char rcsid[] = "$Id: ip_state.c,v 2.0.2.12 1997/05/24 07:34:10 darrenr Ex #include #include #include -#include #include -#include +#ifndef linux +# include +# include +#endif #include -#include #include #include "netinet/ip_compat.h" +#include #include "netinet/ip_fil.h" #include "netinet/ip_nat.h" +#include "netinet/ip_frag.h" +#include "netinet/ip_proxy.h" #include "netinet/ip_state.h" #ifndef MIN #define MIN(a,b) (((a)<(b))?(a):(b)) @@ -68,7 +81,7 @@ static char rcsid[] = "$Id: ip_state.c,v 2.0.2.12 1997/05/24 07:34:10 darrenr Ex ipstate_t *ips_table[IPSTATE_SIZE]; int ips_num = 0; ips_stat_t ips_stats; -#if SOLARIS && defined(_KERNEL) +#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) extern kmutex_t ipf_state; #endif @@ -92,25 +105,100 @@ ips_stat_t *fr_statetstats() } +/* + * flush state tables. two actions currently defined: + * which == 0 : flush all state table entries + * which == 1 : flush TCP connections which have started to close but are + * stuck for some reason. + */ +int fr_state_flush(which) +int which; +{ + register int i; + register ipstate_t *is, **isp; +#if defined(_KERNEL) && !SOLARIS + int s; +#endif + int delete, removed = 0; + + SPL_NET(s); + MUTEX_ENTER(&ipf_state); + for (i = 0; i < IPSTATE_SIZE; i++) + for (isp = &ips_table[i]; (is = *isp); ) { + delete = 0; + + switch (which) + { + case 0 : + delete = 1; + break; + case 1 : + if ((is->is_p == IPPROTO_TCP) && + ((is->is_state[0] <= TCPS_ESTABLISHED) && + (is->is_state[1] > TCPS_ESTABLISHED)) || + ((is->is_state[1] <= TCPS_ESTABLISHED) && + (is->is_state[0] > TCPS_ESTABLISHED))) + delete = 1; + break; + } + + if (delete) { + *isp = is->is_next; + if (is->is_p == IPPROTO_TCP) + ips_stats.iss_fin++; + else + ips_stats.iss_expire++; +#ifdef IPFILTER_LOG + ipstate_log(is, ISL_FLUSH); +#endif + KFREE(is); + ips_num--; + removed++; + } else + isp = &is->is_next; + } + MUTEX_EXIT(&ipf_state); + SPL_X(s); + return removed; +} + + int fr_state_ioctl(data, cmd, mode) caddr_t data; +#if defined(__NetBSD__) || defined(__OpenBSD__) +u_long cmd; +#else int cmd; +#endif int mode; { + int arg, ret, error = 0; + switch (cmd) { + case SIOCIPFFL : + IRCOPY(data, (caddr_t)&arg, sizeof(arg)); + if (arg == 0 || arg == 1) { + MUTEX_ENTER(&ipf_state); + ret = fr_state_flush(arg); + MUTEX_EXIT(&ipf_state); + IWCOPY((caddr_t)&ret, data, sizeof(ret)); + } else + error = EINVAL; + break; case SIOCGIPST : IWCOPY((caddr_t)fr_statetstats(), data, sizeof(ips_stat_t)); break; case FIONREAD : #ifdef IPFILTER_LOG - *(int *)data = iplused[IPL_LOGSTATE]; + IWCOPY((caddr_t)&iplused[IPL_LOGSTATE], (caddr_t)data, + sizeof(iplused[IPL_LOGSTATE])); #endif break; default : - return -1; + return EINVAL; } - return 0; + return error; } @@ -183,7 +271,7 @@ u_int pass; is->is_dwin = is->is_swin; /* start them the same */ ips_stats.iss_tcp++; /* - * If we're creating state for a starting connectoin, start the + * If we're creating state for a starting connection, start the * timer on it as we'll never see an error if it fails to * connect. */ @@ -255,17 +343,27 @@ u_short sport; */ seq = ntohl(tcp->th_seq); ack = ntohl(tcp->th_ack); - if (sport == is->is_sport) { + source = (sport == is->is_sport); + + if (!(tcp->th_flags & TH_ACK)) /* Pretend an ack was sent */ + ack = source ? is->is_ack : is->is_seq; + + if (source) { + if (!is->is_seq) + /* + * Must be an outgoing SYN-ACK in reply to a SYN. + */ + is->is_seq = seq; seqskew = seq - is->is_seq; ackskew = ack - is->is_ack; } else { - seqskew = ack - is->is_seq; if (!is->is_ack) /* * Must be a SYN-ACK in reply to a SYN. */ is->is_ack = seq; ackskew = seq - is->is_ack; + seqskew = ack - is->is_seq; } /* @@ -281,7 +379,7 @@ u_short sport; * window size of the connection, store these values and match * the packet. */ - if ((source = (sport == is->is_sport))) { + if (source) { swin = is->is_swin; dwin = is->is_dwin; } else { @@ -440,16 +538,13 @@ void fr_stateunload() { register int i; register ipstate_t *is, **isp; - int s; MUTEX_ENTER(&ipf_state); - SPLNET(s); for (i = 0; i < IPSTATE_SIZE; i++) for (isp = &ips_table[i]; (is = *isp); ) { *isp = is->is_next; KFREE(is); } - SPLX(s); MUTEX_EXIT(&ipf_state); } @@ -462,10 +557,12 @@ void fr_timeoutstate() { register int i; register ipstate_t *is, **isp; +#if defined(_KERNEL) && !SOLARIS int s; +#endif + SPL_NET(s); MUTEX_ENTER(&ipf_state); - SPLNET(s); for (i = 0; i < IPSTATE_SIZE; i++) for (isp = &ips_table[i]; (is = *isp); ) if (is->is_age && !--is->is_age) { @@ -481,8 +578,8 @@ void fr_timeoutstate() ips_num--; } else isp = &is->is_next; - SPLX(s); MUTEX_EXIT(&ipf_state); + SPL_X(s); } @@ -580,21 +677,10 @@ struct ipstate *is; u_short type; { struct ipslog ipsl; + void *items[1]; + size_t sizes[1]; + int types[1]; - if (iplused[IPL_LOGSTATE] + sizeof(ipsl) > IPLLOGSIZE) { - ips_stats.iss_logfail++; - return; - } - - if (iplh[IPL_LOGSTATE] == iplbuf[IPL_LOGSTATE] + IPLLOGSIZE) - iplh[IPL_LOGSTATE] = iplbuf[IPL_LOGSTATE]; - -# ifdef sun - uniqtime(&ipsl); -# endif -# if BSD >= 199306 || defined(__FreeBSD__) - microtime((struct timeval *)&ipsl); -# endif ipsl.isl_pkts = is->is_pkts; ipsl.isl_bytes = is->is_bytes; ipsl.isl_src = is->is_src; @@ -611,12 +697,10 @@ u_short type; ipsl.isl_ps.isl_filler[0] = 0; ipsl.isl_ps.isl_filler[1] = 0; } + items[0] = &ipsl; + sizes[0] = sizeof(ipsl); + types[0] = 0; - if (!fr_copytolog(IPL_LOGSTATE, (char *)&ipsl, sizeof(ipsl))) { - iplused[IPL_LOGSTATE] += sizeof(ipsl); - ips_stats.iss_logged++; - } else - ips_stats.iss_logfail++; - wakeup(iplbuf[IPL_LOGSTATE]); + (void) ipllog(IPL_LOGSTATE, 0, items, sizes, types, 1); } #endif diff --git a/sys/netinet/ip_state.h b/sys/netinet/ip_state.h index 930110157488..3d87a2186c6d 100644 --- a/sys/netinet/ip_state.h +++ b/sys/netinet/ip_state.h @@ -1,12 +1,12 @@ /* - * (C)opyright 1995-1997 by Darren Reed. + * Copyright (C) 1995-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. * * @(#)ip_state.h 1.3 1/12/96 (C) 1995 Darren Reed - * $Id: ip_state.h,v 2.0.2.9 1997/05/24 07:35:11 darrenr Exp $ + * $Id: ip_state.h,v 2.0.2.14.2.1 1997/11/06 21:23:15 darrenr Exp $ */ #ifndef __IP_STATE_H__ #define __IP_STATE_H__ @@ -73,7 +73,6 @@ typedef struct ipstate { typedef struct ipslog { - struct timeval isl_tv; U_QUAD_T isl_pkts; U_QUAD_T isl_bytes; struct in_addr isl_src; @@ -94,6 +93,7 @@ typedef struct ipslog { #define ISL_NEW 0 #define ISL_EXPIRE 0xffff +#define ISL_FLUSH 0xfffe typedef struct ips_stat { @@ -113,21 +113,26 @@ typedef struct ips_stat { } ips_stat_t; -extern u_long fr_tcpidletimeout; -extern u_long fr_tcpclosewait; -extern u_long fr_tcplastack; -extern u_long fr_tcptimeout; -extern u_long fr_tcpclosed; -extern u_long fr_udptimeout; -extern u_long fr_icmptimeout; -extern int fr_tcpstate __P((ipstate_t *, fr_info_t *, ip_t *, +extern u_long fr_tcpidletimeout; +extern u_long fr_tcpclosewait; +extern u_long fr_tcplastack; +extern u_long fr_tcptimeout; +extern u_long fr_tcpclosed; +extern u_long fr_udptimeout; +extern u_long fr_icmptimeout; +extern int fr_tcpstate __P((ipstate_t *, fr_info_t *, ip_t *, tcphdr_t *, u_short)); -extern ips_stat_t *fr_statetstats __P((void)); -extern int fr_addstate __P((ip_t *, fr_info_t *, u_int)); -extern int fr_checkstate __P((ip_t *, fr_info_t *)); -extern void fr_timeoutstate __P((void)); -extern void fr_tcp_age __P((u_long *, u_char *, ip_t *, fr_info_t *, int)); -extern void fr_stateunload __P((void)); -extern void ipstate_log __P((struct ipstate *, u_short)); -extern int fr_state_ioctl __P((caddr_t, int, int)); +extern ips_stat_t *fr_statetstats __P((void)); +extern int fr_addstate __P((ip_t *, fr_info_t *, u_int)); +extern int fr_checkstate __P((ip_t *, fr_info_t *)); +extern void fr_timeoutstate __P((void)); +extern void fr_tcp_age __P((u_long *, u_char *, ip_t *, fr_info_t *, int)); +extern int fr_state_flush __P((int)); +extern void fr_stateunload __P((void)); +extern void ipstate_log __P((struct ipstate *, u_short)); +#if defined(__NetBSD__) || defined(__OpenBSD__) +extern int fr_state_ioctl __P((caddr_t, u_long, int)); +#else +extern int fr_state_ioctl __P((caddr_t, int, int)); +#endif #endif /* __IP_STATE_H__ */ diff --git a/sys/netinet/mlf_ipl.c b/sys/netinet/mlf_ipl.c new file mode 100644 index 000000000000..3a8ee905620b --- /dev/null +++ b/sys/netinet/mlf_ipl.c @@ -0,0 +1,367 @@ +/* + * 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. + */ +/* + * 29/12/94 Added code from Marc Huber to allow it to allocate + * its own major char number! Way cool patch! + */ + + +#include + +#if defined(__FreeBSD__) && (__FreeBSD__ > 1) +# ifdef IPFILTER_LKM +# include +# define ACTUALLY_LKM_NOT_KERNEL +# else +# include +# endif +#endif +#include +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) +# include +# include +# ifdef DEVFS +# include +# endif /*DEVFS*/ +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if BSD >= 199506 +# include +#endif +#if (__FreeBSD_version >= 199511) +#include +#include +#include +#include +#include +#include +#include +#include +#endif +#if (__FreeBSD__ > 1) +# include +#endif +#include +#include "netinet/ipl.h" +#include "netinet/ip_compat.h" +#include "netinet/ip_fil.h" +#include "netinet/ip_state.h" +#include "netinet/ip_nat.h" +#include "netinet/ip_auth.h" +#include "netinet/ip_frag.h" + + +#if !defined(VOP_LEASE) && defined(LEASE_CHECK) +#define VOP_LEASE LEASE_CHECK +#endif + +#ifndef MIN +#define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +extern int lkmenodev __P((void)); + +static char *ipf_devfiles[] = { IPL_NAME, IPL_NAT, IPL_STATE, IPL_AUTH, + NULL }; +static int if_ipl_unload __P((struct lkm_table *, int)); +static int if_ipl_load __P((struct lkm_table *, int)); +static int if_ipl_remove __P((void)); +int xxxinit __P((struct lkm_table *, int, int)); + + +struct cdevsw ipldevsw = +{ + iplopen, /* open */ + iplclose, /* close */ + iplread, /* read */ + (void *)nullop, /* write */ + iplioctl, /* ioctl */ + (void *)nullop, /* stop */ + (void *)nullop, /* reset */ + (void *)NULL, /* tty */ + (void *)nullop, /* select */ + (void *)nullop, /* mmap */ + NULL /* strategy */ +}; + +#ifdef SYSCTL_INT +SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF"); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &fr_flags, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_pass, CTLFLAG_RW, &fr_pass, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &fr_active, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RW, + &fr_tcpidletimeout, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RW, + &fr_tcpclosewait, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RW, + &fr_tcplastack, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RW, + &fr_tcptimeout, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RW, + &fr_tcpclosed, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RW, + &fr_udptimeout, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RW, + &fr_icmptimeout, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RW, + &fr_defnatage, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW, + &fr_ipfrttl, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, ipl_unreach, CTLFLAG_RW, + &ipl_unreach, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, ipl_inited, CTLFLAG_RD, + &ipl_inited, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RD, + &fr_authsize, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, + &fr_authused, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW, + &fr_defaultauthage, 0, ""); +#endif + +#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) +int ipl_major = 0; + +MOD_DEV(IPL_VERSION, LM_DT_CHAR, -1, &ipldevsw); + +extern struct cdevsw cdevsw[]; +extern int vd_unuseddev __P((void)); +extern int nchrdev; +#else +int ipl_major = CDEV_MAJOR; + +static struct cdevsw ipl_cdevsw = { + iplopen, iplclose, iplread, nowrite, /* 79 */ + iplioctl, nostop, noreset, nodevtotty, + noselect, nommap, nostrategy, "ipl", + NULL, -1 +}; +#endif + + +static int iplaction __P((struct lkm_table *, int)); + + +static int iplaction(lkmtp, cmd) +struct lkm_table *lkmtp; +int cmd; +{ +#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) + int i = ipl_major; + struct lkm_dev *args = lkmtp->private.lkm_dev; +#endif + int err = 0; + + switch (cmd) + { + case LKM_E_LOAD : + if (lkmexists(lkmtp)) + return EEXIST; + +#if !defined(__FreeBSD_version) || (__FreeBSD_version < 220000) + for (i = 0; i < nchrdev; i++) + if (cdevsw[i].d_open == lkmenodev || + cdevsw[i].d_open == iplopen) + break; + if (i == nchrdev) { + printf("IP Filter: No free cdevsw slots\n"); + return ENODEV; + } + + ipl_major = i; + args->lkm_offset = i; /* slot in cdevsw[] */ +#endif + printf("IP Filter: loaded into slot %d\n", ipl_major); + return if_ipl_load(lkmtp, cmd); + break; + case LKM_E_UNLOAD : + err = if_ipl_unload(lkmtp, cmd); + if (!err) + printf("IP Filter: unloaded from slot %d\n", + ipl_major); + return err; + case LKM_E_STAT : + break; + default: + err = EIO; + break; + } + return 0; +} + + +static int if_ipl_remove __P((void)) +{ + char *name; + struct nameidata nd; + int error, i; + + for (i = 0; (name = ipf_devfiles[i]); i++) { + NDINIT(&nd, DELETE, LOCKPARENT, UIO_SYSSPACE, name, curproc); + if ((error = namei(&nd))) + return (error); + VOP_LEASE(nd.ni_vp, curproc, curproc->p_ucred, LEASE_WRITE); + VOP_LOCK(nd.ni_vp); + VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); + (void) VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd); + } + + return 0; +} + + +static int if_ipl_unload(lkmtp, cmd) +struct lkm_table *lkmtp; +int cmd; +{ + int error = 0; + + error = ipldetach(); + if (!error) + error = if_ipl_remove(); + return error; +} + + +static int if_ipl_load(lkmtp, cmd) +struct lkm_table *lkmtp; +int cmd; +{ + struct nameidata nd; + struct vattr vattr; + int error = 0, fmode = S_IFCHR|0600, i; + char *name; + + error = iplattach(); + if (error) + return error; + (void) if_ipl_remove(); + + for (i = 0; (name = ipf_devfiles[i]); i++) { + NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, name, curproc); + if ((error = namei(&nd))) + return error; + if (nd.ni_vp != NULL) { + VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd); + if (nd.ni_dvp == nd.ni_vp) + vrele(nd.ni_dvp); + else + vput(nd.ni_dvp); + vrele(nd.ni_vp); + return (EEXIST); + } + VATTR_NULL(&vattr); + vattr.va_type = VCHR; + vattr.va_mode = (fmode & 07777); + vattr.va_rdev = (ipl_major << 8) | i; + VOP_LEASE(nd.ni_dvp, curproc, curproc->p_ucred, LEASE_WRITE); + error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr); + if (error) + return error; + } + return 0; +} + + +#if defined(__FreeBSD_version) && (__FreeBSD_version < 220000) +/* + * strlen isn't present in 2.1.* kernels. + */ +size_t strlen(string) +char *string; +{ + register char *s; + + for (s = string; *s; s++) + ; + return (size_t)(s - string); +} + + +int xxxinit(lkmtp, cmd, ver) +struct lkm_table *lkmtp; +int cmd, ver; +{ + DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction); +} +#else +# ifdef IPFILTER_LKM +# include + +MOD_DECL(if_ipl); + + +static struct lkm_dev _module = { + LM_DEV, + LKM_VERSION, + IPL_VERSION, + CDEV_MAJOR, + LM_DT_CHAR, + { (void *)&ipl_cdevsw } +}; + + +int if_ipl __P((struct lkm_table *, int, int)); + + +int if_ipl(lkmtp, cmd, ver) +struct lkm_table *lkmtp; +int cmd, ver; +{ + DISPATCH(lkmtp, cmd, ver, iplaction, iplaction, iplaction); +} +# else + +#ifdef DEVFS +static void *ipf_devfs_token[IPL_LOGMAX + 1]; +#endif +static ipl_devsw_installed = 0; + +static void ipl_drvinit __P((void *unused)) +{ + dev_t dev; +#ifdef DEVFS + void **tp = ipf_devfs_token; +#endif + + if (!ipl_devsw_installed ) { + dev = makedev(CDEV_MAJOR, 0); + cdevsw_add(&dev, &ipl_cdevsw, NULL); + ipl_devsw_installed = 1; + +#ifdef DEVFS + tp[IPL_LOGIPF] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGIPF, + DV_CHR, 0, 0, 0600, + "ipf", IPL_LOGIPF); + tp[IPL_LOGNAT] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGNAT, + DV_CHR, 0, 0, 0600, + "ipnat", IPL_LOGNAT); + tp[IPL_LOGSTATE] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGSTATE, + DV_CHR, 0, 0, 0600, + "ipstate", IPL_LOGSTATE); + tp[IPL_LOGAUTH] = devfs_add_devswf(&ipl_cdevsw, IPL_LOGAUTH, + DV_CHR, 0, 0, 0600, + "ipstate", IPL_LOGAUTH); +#endif + } +} + +SYSINIT(ipldev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,ipl_drvinit,NULL) +# endif /* IPFILTER_LKM */ +#endif /* _FreeBSD_version */