diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/fil.c | 548 | ||||
-rw-r--r-- | sys/netinet/ip_auth.c | 75 | ||||
-rw-r--r-- | sys/netinet/ip_auth.h | 31 | ||||
-rw-r--r-- | sys/netinet/ip_fil.c | 547 | ||||
-rw-r--r-- | sys/netinet/ip_fil.h | 250 | ||||
-rw-r--r-- | sys/netinet/ip_fil_compat.h | 74 | ||||
-rw-r--r-- | sys/netinet/ip_frag.c | 221 | ||||
-rw-r--r-- | sys/netinet/ip_frag.h | 17 | ||||
-rw-r--r-- | sys/netinet/ip_ftp_pxy.c | 212 | ||||
-rw-r--r-- | sys/netinet/ip_log.c | 160 | ||||
-rw-r--r-- | sys/netinet/ip_nat.c | 1222 | ||||
-rw-r--r-- | sys/netinet/ip_nat.h | 117 | ||||
-rw-r--r-- | sys/netinet/ip_proxy.c | 150 | ||||
-rw-r--r-- | sys/netinet/ip_proxy.h | 65 | ||||
-rw-r--r-- | sys/netinet/ip_state.c | 744 | ||||
-rw-r--r-- | sys/netinet/ip_state.h | 63 |
16 files changed, 2964 insertions, 1532 deletions
diff --git a/sys/netinet/fil.c b/sys/netinet/fil.c index 84bfd975173..f4acf66b495 100644 --- a/sys/netinet/fil.c +++ b/sys/netinet/fil.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fil.c,v 1.16 1999/12/08 06:50:18 itojun Exp $ */ +/* $OpenBSD: fil.c,v 1.17 1999/12/15 05:20:20 kjell Exp $ */ /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -8,7 +8,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-1996 Darren Reed"; -static const char rcsid[] = "@(#)$Id: fil.c,v 1.16 1999/12/08 06:50:18 itojun Exp $"; +static const char rcsid[] = "@(#)$Id: fil.c,v 1.17 1999/12/15 05:20:20 kjell Exp $"; #endif #include <sys/errno.h> @@ -16,7 +16,17 @@ static const char rcsid[] = "@(#)$Id: fil.c,v 1.16 1999/12/08 06:50:18 itojun Ex #include <sys/param.h> #include <sys/time.h> #include <sys/file.h> -#include <sys/ioctl.h> +#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ + defined(_KERNEL) +# include "opt_ipfilter_log.h" +#endif +#if defined(KERNEL) && defined(__FreeBSD_version) && \ + (__FreeBSD_version >= 220000) +# include <sys/filio.h> +# include <sys/fcntl.h> +#else +# include <sys/ioctl.h> +#endif #if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) # include <sys/systm.h> #else @@ -32,9 +42,9 @@ static const char rcsid[] = "@(#)$Id: fil.c,v 1.16 1999/12/08 06:50:18 itojun Ex #else # include <sys/byteorder.h> # if SOLARIS2 < 5 -# include <sys/dditypes.h> +# include <sys/dditypes.h> # endif -# include <sys/stream.h> +# include <sys/stream.h> #endif #ifndef linux # include <sys/protosw.h> @@ -46,9 +56,9 @@ static const char rcsid[] = "@(#)$Id: fil.c,v 1.16 1999/12/08 06:50:18 itojun Ex #endif #include <net/route.h> #ifdef _KERNEL -#ifndef INET -#error ipfilter assumes options INET -#endif +# ifndef INET +# error ipfilter assumes options INET +# endif #endif #include <netinet/in.h> #include <netinet/in_systm.h> @@ -56,14 +66,14 @@ static const char rcsid[] = "@(#)$Id: fil.c,v 1.16 1999/12/08 06:50:18 itojun Ex #ifndef linux # include <netinet/ip_var.h> #endif +#if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ +# include <sys/hashing.h> +# include <netinet/in_var.h> +#endif #include <netinet/tcp.h> #include <netinet/udp.h> #include <netinet/ip_icmp.h> -#if defined(__OpenBSD__) -# include <netinet/ip_fil_compat.h> -#else -# include <netinet/ip_compat.h> -#endif +#include <netinet/ip_fil_compat.h> #include <netinet/tcpip.h> #include <netinet/ip_fil.h> #include <netinet/ip_proxy.h> @@ -71,9 +81,16 @@ static const char rcsid[] = "@(#)$Id: fil.c,v 1.16 1999/12/08 06:50:18 itojun Ex #include <netinet/ip_frag.h> #include <netinet/ip_state.h> #include <netinet/ip_auth.h> +# if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include <sys/malloc.h> +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" +# endif +# endif #ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) +# define MIN(a,b) (((a)<(b))?(a):(b)) #endif +#include <netinet/ipl.h> #ifndef _KERNEL # include "ipf.h" @@ -86,14 +103,9 @@ extern int opts; second; } # define FR_VERBOSE(verb_pr) verbose verb_pr # define FR_DEBUG(verb_pr) debug verb_pr -# define SEND_RESET(ip, qif, if, m) send_reset(ip, if) +# define SEND_RESET(ip, qif, if, m, fin) 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) ; @@ -101,39 +113,25 @@ extern int opts; # define FR_DEBUG(verb_pr) # define IPLLOG(a, c, d, e) ipflog(a, c, d, e) # if SOLARIS || defined(__sgi) -extern KRWLOCK_T ipf_mutex, ipf_auth; +extern KRWLOCK_T ipf_mutex, ipf_auth, ipf_nat; extern kmutex_t ipf_rw; # 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) +# define SEND_RESET(ip, qif, if, fin) send_reset(fin, ip, qif) +# define ICMP_ERROR(b, ip, t, c, if, dst) \ + icmp_error(ip, t, c, if, dst) # else /* SOLARIS */ # define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip) # ifdef linux -# define SEND_RESET(ip, qif, if) send_reset((tcpiphdr_t *)ip,\ - ifp) +# define SEND_RESET(ip, qif, if, fin) send_reset(ip, ifp) +# define ICMP_ERROR(b, ip, t, c, if, dst) icmp_send(b,t,c,0,if) # else -# define SEND_RESET(ip, qif, if) send_reset((tcpiphdr_t *)ip) -# endif -# ifdef __sgi -# define ICMP_ERROR(b, ip, t, c, if, src) \ - icmp_error(b, t, c, if, src, if) -# else -# if BSD < 199103 -# ifdef linux -# define ICMP_ERROR(b, ip, t, c, if, src) icmp_send(b,t,c,0,if) -# else -# define ICMP_ERROR(b, ip, t, c, if, src) \ - icmp_error(mtod(b, ip_t *), t, c, if, src) -# 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 */ +# define SEND_RESET(ip, qif, if, fin) send_reset(fin, ip) +# define ICMP_ERROR(b, ip, t, c, if, dst) \ + send_icmp_err(ip, t, c, if, dst) +# endif /* linux */ # endif /* SOLARIS || __sgi */ #endif /* _KERNEL */ @@ -148,12 +146,15 @@ int fr_pass = FR_NOMATCH|FR_BLOCK; #else int fr_pass = (IPF_DEFAULT_PASS|FR_NOMATCH); #endif +char ipfilter_version[] = IPL_VERSION; 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 frflushlist __P((int, int, int *, frentry_t *, frentry_t **)); +static int frflushlist __P((int, minor_t, int *, frentry_t **)); +#ifdef _KERNEL +static void frsynclist __P((frentry_t *)); +#endif /* @@ -201,7 +202,7 @@ struct optlist secopt[8] = { * compact the IP header into a structure which contains just the info. * which is useful for comparing IP headers with. */ -static void fr_makefrip(hlen, ip, fin) +void fr_makefrip(hlen, ip, fin) int hlen; ip_t *ip; fr_info_t *fin; @@ -213,6 +214,7 @@ fr_info_t *fin; int i, mv, ol, off; u_char *s, opt; + fin->fin_rev = 0; fin->fin_fr = NULL; fin->fin_tcpf = 0; fin->fin_data[0] = 0; @@ -230,8 +232,8 @@ fr_info_t *fin; tcp = (tcphdr_t *)((char *)ip + hlen); fin->fin_dp = (void *)tcp; (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4)); - (*(((u_32_t *)fi) + 1)) = (*(((u_32_t *)ip) + 3)); - (*(((u_32_t *)fi) + 2)) = (*(((u_32_t *)ip) + 4)); + fi->fi_src.s_addr = ip->ip_src.s_addr; + fi->fi_dst.s_addr = ip->ip_dst.s_addr; fi->fi_fl = (hlen > sizeof(ip_t)) ? FI_OPTIONS : 0; off = (ip->ip_off & IP_OFFMASK) << 3; @@ -280,8 +282,9 @@ getports: } - for (s = (u_char *)(ip + 1), hlen -= sizeof(*ip); hlen; ) { - if (!(opt = *s)) + for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen; ) { + opt = *s; + if (opt == '\0') break; ol = (opt == IPOPT_NOP) ? 1 : (int)*(s+1); if (opt > 1 && (ol < 2 || ol > hlen)) @@ -426,14 +429,15 @@ fr_info_t *fin; * kernel sauce. */ int fr_scanlist(pass, ip, fin, m) -int pass; +u_32_t pass; ip_t *ip; register fr_info_t *fin; void *m; { register struct frentry *fr; register fr_ip_t *fi = &fin->fin_fi; - int rulen, portcmp = 0, off, skip = 0; + int rulen, portcmp = 0, off, skip = 0, logged = 0; + u_32_t passt; fr = fin->fin_fr; fin->fin_fr = NULL; @@ -457,8 +461,16 @@ void *m; * check that we are working for the right interface */ #ifdef _KERNEL - if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) - continue; +# if BSD >= 199306 + if (fin->fin_out != 0) { + if ((fr->fr_oifa && + fr->fr_oifa != ((mb_t *)m)->m_pkthdr.rcvif) || + (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp)) + continue; + } else +# endif + if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) + continue; #else if (opts & (OPT_VERBOSE|OPT_DEBUG)) printf("\n"); @@ -478,10 +490,12 @@ void *m; i = ((lip[0] & lm[0]) != ld[0]); FR_IFDEBUG(i,continue,("0. %#08x & %#08x != %#08x\n", lip[0], lm[0], ld[0])); - i |= ((lip[1] & lm[1]) != ld[1]) << 21; + i |= ((lip[1] & lm[1]) != ld[1]) << 19; + i ^= (fr->fr_flags & FR_NOTSRCIP); FR_IFDEBUG(i,continue,("1. %#08x & %#08x != %#08x\n", lip[1], lm[1], ld[1])); - i |= ((lip[2] & lm[2]) != ld[2]) << 22; + i |= ((lip[2] & lm[2]) != ld[2]) << 20; + i ^= (fr->fr_flags & FR_NOTDSTIP); FR_IFDEBUG(i,continue,("2. %#08x & %#08x != %#08x\n", lip[2], lm[2], ld[2])); i |= ((lip[3] & lm[3]) != ld[3]); @@ -490,7 +504,6 @@ void *m; i |= ((lip[4] & lm[4]) != ld[4]); FR_IFDEBUG(i,continue,("4. %#08x & %#08x != %#08x\n", lip[4], lm[4], ld[4])); - i ^= (fi->fi_fl & (FR_NOTSRCIP|FR_NOTDSTIP)); if (i) continue; } @@ -520,18 +533,21 @@ void *m; /* * Just log this packet... */ - if (!(skip = fr->fr_skip)) - pass = fr->fr_flags; - if ((pass & FR_CALLNOW) && fr->fr_func) - pass = (*fr->fr_func)(pass, ip, fin); + passt = fr->fr_flags; + if ((passt & FR_CALLNOW) && fr->fr_func) + passt = (*fr->fr_func)(passt, ip, fin); + fin->fin_fr = fr; #ifdef IPFILTER_LOG - if ((pass & FR_LOGMASK) == FR_LOG) { - if (!IPLLOG(fr->fr_flags, ip, fin, m)) { + if ((passt & FR_LOGMASK) == FR_LOG) { + if (!IPLLOG(passt, ip, fin, m)) { ATOMIC_INC(frstats[fin->fin_out].fr_skip); } ATOMIC_INC(frstats[fin->fin_out].fr_pkl); + logged = 1; } #endif /* IPFILTER_LOG */ + if (!(skip = fr->fr_skip) && (passt & FR_LOGMASK) != FR_LOG) + pass = passt; FR_DEBUG(("pass %#x\n", pass)); ATOMIC_INC(fr->fr_hits); if (pass & FR_ACCOUNT) @@ -540,7 +556,6 @@ void *m; 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); @@ -549,10 +564,14 @@ void *m; fin->fin_group = fr->fr_group; fin->fin_fr = fr; } + if (pass & FR_DONTCACHE) + logged = 1; } if (pass & FR_QUICK) break; } + if (logged) + pass |= FR_DONTCACHE; return pass; } @@ -581,7 +600,8 @@ int out; fr_info_t frinfo, *fc; register fr_info_t *fin = &frinfo; frentry_t *fr = NULL; - int pass, changed, apass, error = EHOSTUNREACH; + int changed, error = EHOSTUNREACH; + u_32_t pass, apass; #if !SOLARIS || !defined(_KERNEL) register mb_t *m = *mp; #endif @@ -616,8 +636,8 @@ int out; case IPPROTO_UDP: plen = sizeof(udphdr_t); break; - case IPPROTO_ICMP: /* need enough for complete ICMP error IP header */ + case IPPROTO_ICMP: plen = ICMPERR_MAXPKTLEN - sizeof(ip_t); break; } @@ -653,13 +673,24 @@ int out; # if SOLARIS mb_t *m = qif->qf_m; + if ((u_int)ip & 0x3) + return 2; fin->fin_qfm = m; + fin->fin_qif = qif; # endif #endif /* _KERNEL */ + + /* + * Be careful here: ip_id is in network byte order when called + * from ip_output() + */ + if (out) + ip->ip_id = ntohs(ip->ip_id); fr_makefrip(hlen, ip, fin); fin->fin_ifp = ifp; fin->fin_out = out; fin->fin_mp = mp; + pass = fr_pass; READ_ENTER(&ipf_mutex); @@ -673,15 +704,15 @@ int out; apass = fr_checkauth(ip, fin); if (!out) { - changed = ip_natin(ip, hlen, fin); + changed = ip_natin(ip, fin); if (!apass && (fin->fin_fr = ipacct[0][fr_active]) && - (FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { + (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { ATOMIC_INC(frstats[0].fr_acct); } } - if (apass || (!(pass = ipfr_knownfrag(ip, fin)) && - !(pass = fr_checkstate(ip, fin)))) { + if (apass || (!(fr = ipfr_knownfrag(ip, fin)) && + !(fr = 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 @@ -699,13 +730,13 @@ int out; if ((fr = fin->fin_fr)) { ATOMIC_INC(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); + pass = fr_scanlist(fr_pass, ip, fin, m); + if (!(pass & (FR_KEEPSTATE|FR_DONTCACHE))) + bcopy((char *)fin, (char *)fc, + FI_COPYSIZE); if (pass & FR_NOMATCH) { ATOMIC_INC(frstats[out].fr_nom); } @@ -730,7 +761,7 @@ int out; if (pass & FR_PREAUTH) { READ_ENTER(&ipf_auth); if ((fin->fin_fr = ipauth) && - (pass = FR_SCANLIST(0, ip, fin, m))) { + (pass = fr_scanlist(0, ip, fin, m))) { ATOMIC_INC(fr_authstats.fas_hits); } else { ATOMIC_INC(fr_authstats.fas_miss); @@ -738,7 +769,8 @@ int out; RWLOCK_EXIT(&ipf_auth); } - if (pass & FR_KEEPFRAG) { + fin->fin_fr = fr; + if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) { if (fin->fin_fi.fi_fl & FI_FRAG) { if (ipfr_newfrag(ip, fin, pass) == -1) { ATOMIC_INC(frstats[out].fr_bnfr); @@ -750,12 +782,16 @@ int out; } } if (pass & FR_KEEPSTATE) { - if (fr_addstate(ip, fin, pass) == -1) { + if (fr_addstate(ip, fin, 0) == NULL) { ATOMIC_INC(frstats[out].fr_bads); } else { ATOMIC_INC(frstats[out].fr_ads); } } + } else if (fr != NULL) { + pass = fr->fr_flags; + if (pass & FR_LOGFIRST) + pass &= ~(FR_LOGFIRST|FR_LOG); } if (fr && fr->fr_func && !(pass & FR_CALLNOW)) @@ -767,13 +803,13 @@ int out; */ if (out && (pass & FR_PASS)) { if ((fin->fin_fr = ipacct[1][fr_active]) && - (FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { + (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { ATOMIC_INC(frstats[1].fr_acct); } - fin->fin_fr = NULL; - changed = ip_natout(ip, hlen, fin); - } - fin->fin_fr = fr; + fin->fin_fr = fr; + changed = ip_natout(ip, fin); + } else + fin->fin_fr = fr; RWLOCK_EXIT(&ipf_mutex); #ifdef IPFILTER_LOG @@ -803,6 +839,10 @@ logit: } } #endif /* IPFILTER_LOG */ + + if (out) + ip->ip_id = htons(ip->ip_id); + #ifdef _KERNEL /* * Only allow FR_DUP to work if a rule matched - it makes no sense to @@ -835,27 +875,34 @@ logit: if (!out) { #ifdef _KERNEL if (pass & FR_RETICMP) { + struct in_addr dst; + + if ((pass & FR_RETMASK) == FR_FAKEICMP) + dst = ip->ip_dst; + else + dst.s_addr = 0; # if SOLARIS ICMP_ERROR(q, ip, ICMP_UNREACH, fin->fin_icode, - qif, ip->ip_src); + qif, dst); # else ICMP_ERROR(m, ip, ICMP_UNREACH, fin->fin_icode, - ifp, ip->ip_src); - m = *mp = NULL; /* freed by icmp_error() */ + ifp, dst); # endif - ATOMIC_INC(frstats[0].fr_ret); - } else if ((pass & FR_RETRST) && + } else if (((pass & FR_RETMASK) == FR_RETRST) && !(fin->fin_fi.fi_fl & FI_SHORT)) { - if (SEND_RESET(ip, qif, ifp) == 0) { + if (SEND_RESET(ip, qif, ifp, fin) == 0) { ATOMIC_INC(frstats[1].fr_ret); } } #else - if (pass & FR_RETICMP) { + if ((pass & FR_RETMASK) == FR_RETICMP) { verbose("- ICMP unreachable sent\n"); ATOMIC_INC(frstats[0].fr_ret); - } else if ((pass & FR_RETRST) && + } else if ((pass & FR_RETMASK) == FR_FAKEICMP) { + verbose("- forged ICMP unreachable sent\n"); + ATOMIC_INC(frstats[0].fr_ret); + } else if (((pass & FR_RETMASK) == FR_RETRST) && !(fin->fin_fi.fi_fl & FI_SHORT)) { verbose("- TCP RST sent\n"); ATOMIC_INC(frstats[1].fr_ret); @@ -880,10 +927,10 @@ logit: if (fr) { frdest_t *fdp = &fr->fr_tif; - if ((pass & FR_FASTROUTE) || + if (((pass & FR_FASTROUTE) && !out) || (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) { - ipfr_fastroute(m, fin, fdp); - m = *mp = NULL; + if (ipfr_fastroute(m, fin, fdp) == 0) + m = *mp = NULL; } if (mc) ipfr_fastroute(mc, fin, &fr->fr_dif); @@ -895,21 +942,20 @@ logit: m_copyback(m, 0, up, hbuf); # endif # endif /* !linux */ - return (pass & FR_PASS) ? 0 : error; # else /* !SOLARIS */ if (fr) { frdest_t *fdp = &fr->fr_tif; - if ((pass & FR_FASTROUTE) || + if (((pass & FR_FASTROUTE) && !out) || (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) { - ipfr_fastroute(qif, ip, m, mp, fin, fdp); - m = *mp = NULL; + if (ipfr_fastroute(qif, ip, m, mp, fin, fdp) == 0) + m = *mp = NULL; } if (mc) ipfr_fastroute(qif, ip, mc, mp, fin, &fr->fr_dif); } - return (pass & FR_PASS) ? changed : error; # endif /* !SOLARIS */ + return (pass & FR_PASS) ? 0 : error; #else /* _KERNEL */ if (pass & FR_NOMATCH) return 1; @@ -954,23 +1000,21 @@ register int len; * and the TCP header. We also assume that data blocks aren't allocated in * odd sizes. */ -u_short fr_tcpsum(m, ip, tcp, len) +u_short fr_tcpsum(m, ip, tcp) mb_t *m; ip_t *ip; tcphdr_t *tcp; -int len; { u_short *sp, slen, ts; u_int sum, sum2; int hlen; - /* * Add up IP Header portion */ hlen = ip->ip_hl << 2; slen = ip->ip_len - hlen; - sum = htons(ip->ip_p); + sum = htons((u_short)ip->ip_p); sum += htons(slen); sp = (u_short *)&ip->ip_src; sum += *sp++; /* ip_src */ @@ -981,7 +1025,7 @@ int len; tcp->th_sum = 0; #ifdef KERNEL # if SOLARIS - sum2 = ip_cksum(m, hlen, sum); + sum2 = ip_cksum(m, hlen, sum); /* hlen == offset */ sum2 = (sum2 & 0xffff) + (sum2 >> 16); sum2 = ~sum2 & 0xffff; # else /* SOLARIS */ @@ -1008,13 +1052,11 @@ int len; sum2 = (sum2 & 0xffff) + (sum2 >> 16); # else /* defined(BSD) || defined(sun) */ { - union { u_char c[2]; u_short s; } bytes; - u_32_t sum; - u_short *sp, slen; + u_short len = ip->ip_len; # if defined(__sgi) int add; # endif @@ -1025,7 +1067,7 @@ int len; sp = (u_short *)&ip->ip_src; len -= (ip->ip_hl << 2); sum = ntohs(IPPROTO_TCP); - sum += htons((u_short)len); + sum += htons(len); sum += *sp++; /* ip_src */ sum += *sp++; sum += *sp++; /* ip_dst */ @@ -1039,8 +1081,8 @@ int len; sum += *sp++; /* ack */ sum += *sp++; sum += *sp++; /* off */ - sum += *sp; /* win */ - sp += 2; /* Skip over checksum */ + sum += *sp++; /* win */ + sum += *sp++; /* Skip over checksum */ sum += *sp++; /* urp */ # ifdef __sgi @@ -1098,7 +1140,7 @@ nodata: sum = (sum & 0xffff) + (sum >> 16); sum2 = (u_short)(~sum & 0xffff); } -# endif /* defined(BSD) || defined(sun) */ +# endif /* defined(BSD) || defined(sun) */ # endif /* SOLARIS */ #else /* KERNEL */ sum2 = 0; @@ -1142,7 +1184,7 @@ nodata: * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 - * $Id: fil.c,v 1.16 1999/12/08 06:50:18 itojun Exp $ + * $Id: fil.c,v 1.17 1999/12/15 05:20:20 kjell Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, @@ -1242,9 +1284,10 @@ out: frgroup_t *fr_findgroup(num, flags, which, set, fgpp) -u_short num; +u_int num; u_32_t flags; -int which, set; +minor_t which; +int set; frgroup_t ***fgpp; { frgroup_t *fg, **fgp; @@ -1257,6 +1300,7 @@ frgroup_t ***fgpp; fgp = &ipfgroups[0][set]; else return NULL; + num &= 0xffff; while ((fg = *fgp)) if (fg->fg_num == num) @@ -1270,18 +1314,19 @@ frgroup_t ***fgpp; frgroup_t *fr_addgroup(num, fp, which, set) -u_short num; +u_int num; frentry_t *fp; -int which, set; +minor_t which; +int set; { frgroup_t *fg, **fgp; if ((fg = fr_findgroup(num, fp->fr_flags, which, set, &fgp))) return fg; - KMALLOC(fg, frgroup_t *, sizeof(*fg)); + KMALLOC(fg, frgroup_t *); if (fg) { - fg->fg_num = num; + fg->fg_num = num & 0xffff; fg->fg_next = *fgp; fg->fg_head = fp; fg->fg_start = &fp->fr_grp; @@ -1292,9 +1337,10 @@ int which, set; void fr_delgroup(num, flags, which, set) -u_short num; +u_int num; u_32_t flags; -int which, set; +minor_t which; +int set; { frgroup_t *fg, **fgp; @@ -1312,63 +1358,255 @@ int which, set; * 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; +static int frflushlist(set, unit, nfreedp, listp) +int set; +minor_t unit; +int *nfreedp; +frentry_t **listp; { - register frentry_t *fp = list, *fpn; - register int freed = 0; + register int freed = 0, i; + register frentry_t *fp; - while (fp) { - fpn = fp->fr_next; + while ((fp = *listp)) { + *listp = fp->fr_next; if (fp->fr_grp) { - fp->fr_ref -= frflushlist(set, unit, nfreedp, - fp->fr_grp, &fp->fr_grp); + i = frflushlist(set, unit, nfreedp, &fp->fr_grp); + MUTEX_ENTER(&ipf_rw); + fp->fr_ref -= i; + MUTEX_EXIT(&ipf_rw); } - if (fp->fr_ref == 1) { - if (fp->fr_grhead) - fr_delgroup(fp->fr_grhead, fp->fr_flags, unit, - set); + ATOMIC_DEC(fp->fr_ref); + if (fp->fr_grhead) { + fr_delgroup((u_int)fp->fr_grhead, fp->fr_flags, + unit, set); + fp->fr_grhead = NULL; + } + if (fp->fr_ref == 0) { KFREE(fp); - *listp = fpn; freed++; - } - fp = fpn; + } else + fp->fr_next = NULL; } *nfreedp += freed; return freed; } -void frflush(unit, result) -int unit; -int *result; +int frflush(unit, flags) +minor_t unit; +int flags; { - int flags = *result, flushed = 0, set = fr_active; + int flushed = 0, set; + if (unit != IPL_LOGIPF) + return 0; WRITE_ENTER(&ipf_mutex); bzero((char *)frcache, sizeof(frcache[0]) * 2); + set = fr_active; 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_OUTQUE) { + (void) frflushlist(set, unit, &flushed, &ipfilter[1][set]); + (void) frflushlist(set, unit, &flushed, &ipacct[1][set]); + } + if (flags & FR_INQUE) { + (void) frflushlist(set, unit, &flushed, &ipfilter[0][set]); + (void) frflushlist(set, unit, &flushed, &ipacct[0][set]); + } + RWLOCK_EXIT(&ipf_mutex); + return flushed; +} + + +char *memstr(src, dst, slen, dlen) +char *src, *dst; +int slen, dlen; +{ + char *s = NULL; + + while (dlen >= slen) { + if (bcmp(src, dst, slen) == 0) { + s = dst; + break; } - 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]); + dst++; + dlen--; + } + return s; +} + + +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; +} + + +#ifdef _KERNEL +/* + * count consecutive 1's in bit mask. If the mask generated by counting + * consecutive 1's is different to that passed, return -1, else return # + * of bits. + */ +int countbits(ip) +u_32_t ip; +{ + u_32_t ipn; + int cnt = 0, i, j; + + ip = ipn = ntohl(ip); + for (i = 32; i; i--, ipn *= 2) + if (ipn & 0x80000000) + cnt++; + else + break; + ipn = 0; + for (i = 32, j = cnt; i; i--, j--) { + ipn *= 2; + if (j > 0) + ipn++; + } + if (ipn == ip) + return cnt; + return -1; +} + + +/* + * return the first IP Address associated with an interface + */ +int fr_ifpaddr(ifptr, inp) +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 = (struct sockaddr_in *)&ifa->ifa_addr; +# else + sin = (struct 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 = (struct sockaddr_in *)ifa->ifa_addr; + } + if (ifa == NULL) + sin = NULL; + if (sin == NULL) + return -1; +# endif /* (BSD < 199306) && (!__sgi && IFF_DRVLOCK) */ + in = sin->sin_addr; +# endif /* linux */ +# endif /* SOLARIS */ + in.s_addr = ntohl(in.s_addr); + *inp = in; + return 0; +} + + +static void frsynclist(fr) +register frentry_t *fr; +{ + for (; fr; fr = fr->fr_next) { + if (fr->fr_ifa != NULL) { + fr->fr_ifa = GETUNIT(fr->fr_ifname); + if (fr->fr_ifa == NULL) + fr->fr_ifa = (void *)-1; } + if (fr->fr_grp) + frsynclist(fr->fr_grp); } +} + + +void frsync() +{ + register struct ifnet *ifp; + +# if !SOLARIS +# if defined(__OpenBSD__) || ((NetBSD >= 199511) && (NetBSD < 1991011)) || \ + (defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)) +# if (NetBSD >= 199905) || defined(__OpenBSD__) + for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) +# else + for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) +# endif +# else + for (ifp = ifnet; ifp; ifp = ifp->if_next) +# endif + ip_natsync(ifp); +# endif + + WRITE_ENTER(&ipf_mutex); + frsynclist(ipacct[0][fr_active]); + frsynclist(ipacct[1][fr_active]); + frsynclist(ipfilter[0][fr_active]); + frsynclist(ipfilter[1][fr_active]); RWLOCK_EXIT(&ipf_mutex); - *result = flushed; } + +#else + + +/* + * return the first IP Address associated with an interface + */ +int fr_ifpaddr(ifptr, inp) +void *ifptr; +struct in_addr *inp; +{ + return 0; +} +#endif diff --git a/sys/netinet/ip_auth.c b/sys/netinet/ip_auth.c index 0de609a5b2d..ad69de43d9d 100644 --- a/sys/netinet/ip_auth.c +++ b/sys/netinet/ip_auth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_auth.c,v 1.8 1999/12/13 10:41:56 itojun Exp $ */ +/* $OpenBSD: ip_auth.c,v 1.9 1999/12/15 05:20:21 kjell Exp $ */ /* * Copyright (C) 1998 by Darren Reed & Guido van Rooij. * @@ -7,7 +7,7 @@ * to the original author and the contributors. */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_auth.c,v 1.8 1999/12/13 10:41:56 itojun Exp $"; +static const char rcsid[] = "@(#)$Id: ip_auth.c,v 1.9 1999/12/15 05:20:21 kjell Exp $"; #endif #include <sys/errno.h> @@ -41,34 +41,39 @@ static const char rcsid[] = "@(#)$Id: ip_auth.c,v 1.8 1999/12/13 10:41:56 itojun #else # include <sys/filio.h> # include <sys/byteorder.h> -# include <sys/dditypes.h> +# ifdef _KERNEL +# include <sys/dditypes.h> +# endif # include <sys/stream.h> # include <sys/kmem.h> #endif +#if _BSDI_VERSION >= 199802 +# include <sys/queue.h> +#endif #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) # include <machine/cpu.h> #endif #include <net/if.h> #ifdef sun -#include <net/af.h> +# include <net/af.h> #endif #include <net/route.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #ifndef KERNEL -#define KERNEL -#define NOT_KERNEL +# define KERNEL +# define NOT_KERNEL #endif #ifndef linux # include <netinet/ip_var.h> #endif #ifdef NOT_KERNEL -#undef KERNEL +# undef KERNEL #endif #ifdef __sgi # ifdef IFF_DRVRLOCK /* IRIX6 */ -#include <sys/hashing.h> +# include <sys/hashing.h> # endif #endif #include <netinet/tcp.h> @@ -76,17 +81,16 @@ static const char rcsid[] = "@(#)$Id: ip_auth.c,v 1.8 1999/12/13 10:41:56 itojun extern struct ifqueue ipintrq; /* ip packet input queue */ #else # ifndef linux +# if __FreeBSD_version >= 300000 +# include <net/if_var.h> +# endif # include <netinet/in_var.h> # include <netinet/tcp_fsm.h> # endif #endif #include <netinet/udp.h> #include <netinet/ip_icmp.h> -#if defined(__OpenBSD__) -# include <netinet/ip_fil_compat.h> -#else -# include <netinet/ip_compat.h> -#endif +#include <netinet/ip_fil_compat.h> #include <netinet/tcpip.h> #include <netinet/ip_fil.h> #include <netinet/ip_auth.h> @@ -96,6 +100,14 @@ extern struct ifqueue ipintrq; /* ip packet input queue */ # include <machine/cpufunc.h> # endif #endif +#if (__FreeBSD_version >= 300000) +# include <sys/malloc.h> +# if (defined(_KERNEL) || defined(KERNEL)) && !defined(IPFILTER_LKM) +# include <sys/libkern.h> +# include <sys/systm.h> +# endif +#endif + #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) @@ -125,7 +137,7 @@ frentry_t *ipauth = NULL; * 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) +u_32_t fr_checkauth(ip, fin) ip_t *ip; fr_info_t *fin; { @@ -199,15 +211,16 @@ ip_t *ip; int i; WRITE_ENTER(&ipf_auth); - if ((fr_authstart > fr_authend) && (fr_authstart - fr_authend == -1)) { - fr_authstats.fas_nospace++; - RWLOCK_EXIT(&ipf_auth); - return 0; - } - if (fr_authend - fr_authstart == FR_NUMAUTH - 1) { + if (fr_authstart > fr_authend) { fr_authstats.fas_nospace++; RWLOCK_EXIT(&ipf_auth); return 0; + } else { + if ((fr_authstart == 0) && (fr_authend == FR_NUMAUTH - 1)) { + fr_authstats.fas_nospace++; + RWLOCK_EXIT(&ipf_auth); + return 0; + } } fr_authstats.fas_added++; @@ -304,24 +317,27 @@ frentry_t *fr, **frptr; KFREE(fae); } } else { - KMALLOC(fae, frauthent_t *, sizeof(*fae)); + KMALLOC(fae, frauthent_t *); if (fae != NULL) { IRCOPY((char *)data, (char *)&fae->fae_fr, sizeof(fae->fae_fr)); WRITE_ENTER(&ipf_auth); - if (!fae->fae_age) - fae->fae_age = fr_defaultauthage; + 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; + ipauth = &fae_list->fae_fr; RWLOCK_EXIT(&ipf_auth); } else error = ENOMEM; } break; case SIOCATHST: + READ_ENTER(&ipf_auth); + fr_authstats.fas_faelist = fae_list; + RWLOCK_EXIT(&ipf_auth); IWCOPY((char *)&fr_authstats, data, sizeof(fr_authstats)); break; case SIOCAUTHW: @@ -381,11 +397,12 @@ fr_authioctlloop: # if SOLARIS error = fr_qout(fr_auth[i].fra_q, m); # else /* SOLARIS */ -#ifdef __OpenBSD__ - error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL); -#else +# if ((_BSDI_VERSION >= 199802) || defined(__OpenBSD__)) + error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, + NULL); +# else error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); -#endif +# endif # endif /* SOLARIS */ if (error) fr_authstats.fas_sendfail++; @@ -475,6 +492,7 @@ void fr_authunload() *faep = fae->fae_next; KFREE(fae); } + ipauth = NULL; RWLOCK_EXIT(&ipf_auth); } @@ -506,13 +524,14 @@ void fr_authexpire() } for (faep = &fae_list; (fae = *faep); ) { - if (!--fra->fra_age) { + if (!--fae->fae_age) { *faep = fae->fae_next; KFREE(fae); fr_authstats.fas_expire++; } else faep = &fae->fae_next; } + ipauth = &fae_list->fae_fr; RWLOCK_EXIT(&ipf_auth); SPL_X(s); } diff --git a/sys/netinet/ip_auth.h b/sys/netinet/ip_auth.h index 71c1c43ff6f..7f6dead90e7 100644 --- a/sys/netinet/ip_auth.h +++ b/sys/netinet/ip_auth.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_auth.h,v 1.3 1999/02/05 05:58:50 deraadt Exp $ */ +/* $OpenBSD: ip_auth.h,v 1.4 1999/12/15 05:20:21 kjell Exp $ */ /* * Copyright (C) 1997-1998 by Darren Reed & Guido Van Rooij. * @@ -6,7 +6,7 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: ip_auth.h,v 1.3 1999/02/05 05:58:50 deraadt Exp $ + * $Id: ip_auth.h,v 1.4 1999/12/15 05:20:21 kjell Exp $ * */ #ifndef __IP_AUTH_H__ @@ -14,18 +14,6 @@ #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; @@ -42,6 +30,19 @@ typedef struct frauthent { u_long fae_age; } frauthent_t; +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; + frauthent_t *fas_faelist; +} fr_authstat_t; + extern frentry_t *ipauth; extern struct fr_authstat fr_authstats; @@ -50,7 +51,7 @@ 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 u_32_t 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[]; diff --git a/sys/netinet/ip_fil.c b/sys/netinet/ip_fil.c index 95428bf29f9..7885d41230e 100644 --- a/sys/netinet/ip_fil.c +++ b/sys/netinet/ip_fil.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_fil.c,v 1.26 1999/12/13 10:41:56 itojun Exp $ */ +/* $OpenBSD: ip_fil.c,v 1.27 1999/12/15 05:20:21 kjell Exp $ */ /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -8,7 +8,7 @@ */ #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 1.26 1999/12/13 10:41:56 itojun Exp $"; +static const char rcsid[] = "@(#)$Id: ip_fil.c,v 1.27 1999/12/15 05:20:21 kjell Exp $"; #endif #ifndef SOLARIS @@ -18,6 +18,11 @@ static const char rcsid[] = "@(#)$Id: ip_fil.c,v 1.26 1999/12/13 10:41:56 itojun #if defined(KERNEL) && !defined(_KERNEL) # define _KERNEL #endif +#include <sys/param.h> +#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ + defined(_KERNEL) +# include "opt_ipfilter_log.h" +#endif #ifdef __FreeBSD__ # if defined(_KERNEL) && !defined(IPFILTER_LKM) # include <sys/osreldate.h> @@ -30,10 +35,10 @@ static const char rcsid[] = "@(#)$Id: ip_fil.c,v 1.26 1999/12/13 10:41:56 itojun # include <string.h> # include <stdlib.h> # include <ctype.h> +# include <fcntl.h> #endif #include <sys/errno.h> #include <sys/types.h> -#include <sys/param.h> #include <sys/file.h> #if __FreeBSD_version >= 220000 && defined(_KERNEL) # include <sys/fcntl.h> @@ -47,7 +52,7 @@ static const char rcsid[] = "@(#)$Id: ip_fil.c,v 1.26 1999/12/13 10:41:56 itojun #endif #include <sys/uio.h> #if !SOLARIS -# if (NetBSD > 199609) || (OpenBSD > 199603) +# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) # include <sys/dirent.h> # else # include <sys/dir.h> @@ -65,6 +70,9 @@ static const char rcsid[] = "@(#)$Id: ip_fil.c,v 1.26 1999/12/13 10:41:56 itojun #endif #if __FreeBSD_version >= 300000 # include <net/if_var.h> +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" +# endif #endif #ifdef __sgi #include <sys/debug.h> @@ -75,7 +83,7 @@ static const char rcsid[] = "@(#)$Id: ip_fil.c,v 1.26 1999/12/13 10:41:56 itojun #include <net/route.h> #include <netinet/in.h> #if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */ -#include <netinet/in_var.h> +# include <netinet/in_var.h> #endif #include <netinet/in_systm.h> #include <netinet/ip.h> @@ -85,23 +93,24 @@ static const char rcsid[] = "@(#)$Id: ip_fil.c,v 1.26 1999/12/13 10:41:56 itojun #include <netinet/tcpip.h> #include <netinet/ip_icmp.h> #ifndef _KERNEL +# include <unistd.h> # include <syslog.h> #endif -#if defined(__OpenBSD__) #include <netinet/ip_fil_compat.h> -#else -#include <netinet/ip_compat.h> -#endif #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> +#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include <sys/malloc.h> +#endif #ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) +# define MIN(a,b) (((a)<(b))?(a):(b)) #endif -#if !SOLARIS && defined(_KERNEL) +#if !SOLARIS && defined(_KERNEL) && !defined(__sgi) +# include <sys/kernel.h> extern int ip_optcopy __P((struct ip *, struct ip *)); #endif @@ -113,27 +122,21 @@ extern struct protosw inetsw[]; 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; -#if defined(__OpenBSD__) +# if defined (__OpenBSD__) int ipl_unreach = ICMP_UNREACH_FILTER_PROHIB; -#else +# else int ipl_unreach = ICMP_UNREACH_FILTER; -#endif +# endif + u_long ipl_frouteok[2] = {0, 0}; -static void fixskip __P((frentry_t **, frentry_t *, int)); static void frzerostats __P((caddr_t)); -static void frsync __P((void)); #if defined(__NetBSD__) || defined(__OpenBSD__) static int frrequest __P((int, u_long, caddr_t, int)); #else @@ -141,8 +144,10 @@ static int frrequest __P((int, int, caddr_t, int)); #endif #ifdef _KERNEL static int (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **)); +static int send_ip __P((struct mbuf *, ip_t *)); # ifdef __sgi extern kmutex_t ipf_rw; +extern KRWLOCK_T ipf_mutex; # endif #else int ipllog __P((void)); @@ -159,6 +164,15 @@ static int write_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); # endif #endif +#if defined(IPFILTER_LKM) +int fr_running = 1; +#else +int fr_running = 0; +#endif + +#if (__FreeBSD_version >= 300000) && defined(_KERNEL) +struct callout_handle ipfr_slowtimer_ch; +#endif #if (_BSDI_VERSION >= 199510) && defined(_KERNEL) # include <sys/device.h> @@ -207,7 +221,8 @@ void ipfilterattach(count) int count; { - iplattach(); + if (iplattach() != 0) + printf("IP Filter failed to attach\n"); } # endif @@ -239,6 +254,16 @@ int iplattach() return EBUSY; } +# ifdef IPFILTER_LOG + ipflog_init(); +# endif + if (nat_init() == -1) + return -1; + if (fr_stateinit() == -1) + return -1; + if (appr_init() == -1) + return -1; + # ifdef NETBSD_PF pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT); # endif @@ -253,15 +278,9 @@ int iplattach() ipl_inited = 1; 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; -# ifdef IPFILTER_LOG - ipflog_init(); -# endif SPL_X(s); if (fr_pass & FR_PASS) defpass = "pass"; @@ -277,6 +296,14 @@ int iplattach() # else "disabled"); # endif + printf("%s\n", ipfilter_version); +#ifdef _KERNEL +# if (__FreeBSD_version >= 300000) && defined(_KERNEL) + ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); +# else + timeout(ipfr_slowtimer, NULL, hz/2); +# endif +#endif return 0; } @@ -293,6 +320,17 @@ int ipldetach() { int s, i = FR_INQUE|FR_OUTQUE; +#ifdef _KERNEL +# if (__FreeBSD_version >= 300000) + untimeout(ipfr_slowtimer, NULL, ipfr_slowtimer_ch); +# else +# ifdef __sgi + untimeout(ipfr_slowtimer); +# else + untimeout(ipfr_slowtimer, NULL); +# endif +# endif +#endif SPL_NET(s); if (!ipl_inited) { @@ -302,8 +340,7 @@ int ipldetach() } fr_checkp = fr_savep; - inetsw[0].pr_slowtimo = fr_saveslowtimo; - frflush(IPL_LOGIPF, &i); + i = frflush(IPL_LOGIPF, i); ipl_inited = 0; # ifdef NETBSD_PF @@ -328,7 +365,7 @@ int ipldetach() static void frzerostats(data) caddr_t data; { - struct friostat fio; + friostat_t fio; bcopy((char *)frstats, (char *)fio.f_st, sizeof(struct filterstats) * 2); @@ -367,7 +404,8 @@ struct proc *p; ) #endif dev_t dev; -#if defined(__NetBSD__) || defined(__OpenBSD__) || (_BSDI_VERSION >= 199701) +#if defined(__NetBSD__) || defined(__OpenBSD__) || \ + (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) u_long cmd; #else int cmd; @@ -381,12 +419,17 @@ int mode; #endif int error = 0, unit = 0, tmp; +#if (BSD >= 199306) && defined(_KERNEL) + if ((securelevel >= 2) && (mode & FWRITE)) + return EPERM; +#endif #ifdef _KERNEL unit = GET_MINOR(dev); if ((IPL_LOGMAX < unit) || (unit < 0)) return ENXIO; # if defined(__OpenBSD__) + /* Prevent IPF and NAT changes when securelevel > 1 */ if (securelevel > 1) { switch (cmd) { # ifndef IPFILTER_LKM @@ -414,7 +457,9 @@ int mode; } } # endif /* OpenBSD */ -#endif /* _KERNEL */ +#else /* _KERNEL */ + unit = dev; +#endif SPL_NET(s); @@ -428,7 +473,6 @@ int mode; SPL_X(s); return error; } - switch (cmd) { case FIONREAD : #ifdef IPFILTER_LOG @@ -445,16 +489,23 @@ int mode; error = EPERM; else { IRCOPY(data, (caddr_t)&enable, sizeof(enable)); - if (enable) + if (enable) { # if defined(__OpenBSD__) error = ipl_enable(); - else - error = ipl_disable(); # else error = iplattach(); - else +# endif + if (error == 0) + fr_running = 1; + } else { +# if defined(__OpenBSD__) + error = ipl_disable(); +# else error = ipldetach(); -# endif /* OpenBSD */ +# endif + if (error == 0) + fr_running = 0; + } } break; } @@ -512,6 +563,21 @@ int mode; fio.f_active = fr_active; fio.f_froute[0] = ipl_frouteok[0]; fio.f_froute[1] = ipl_frouteok[1]; + fio.f_running = fr_running; + fio.f_groups[0][0] = ipfgroups[0][0]; + fio.f_groups[0][1] = ipfgroups[0][1]; + fio.f_groups[1][0] = ipfgroups[1][0]; + fio.f_groups[1][1] = ipfgroups[1][1]; + fio.f_groups[2][0] = ipfgroups[2][0]; + fio.f_groups[2][1] = ipfgroups[2][1]; +#ifdef IPFILTER_LOG + fio.f_logging = 1; +#else + fio.f_logging = 0; +#endif + fio.f_defpass = fr_pass; + strncpy(fio.f_version, ipfilter_version, + sizeof(fio.f_version)); IWCOPY((caddr_t)&fio, data, sizeof(fio)); break; } @@ -526,7 +592,7 @@ int mode; error = EPERM; else { IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); - frflush(unit, &tmp); + tmp = frflush(unit, tmp); IWCOPY((caddr_t)&tmp, data, sizeof(tmp)); } break; @@ -569,37 +635,26 @@ int mode; } -static void frsync() +void fr_forgetifp(ifp) +void *ifp; { -#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; + register frentry_t *f; + + WRITE_ENTER(&ipf_mutex); + for (f = ipacct[0][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = ipacct[1][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = ipfilter[0][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = ipfilter[1][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + RWLOCK_EXIT(&ipf_mutex); + ip_natsync(ifp); } @@ -618,20 +673,22 @@ caddr_t data; frentry_t frd; frdest_t *fdp; frgroup_t *fg = NULL; - int error = 0, in, group; + int error = 0, in; + u_int group; fp = &frd; IRCOPY(data, (caddr_t)fp, sizeof(*fp)); + fp->fr_ref = 0; /* * 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)) + if ((req != SIOCZRLST) && fp->fr_grhead && + fr_findgroup((u_int)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)) + if ((req != SIOCZRLST) && fp->fr_group && + !fr_findgroup((u_int)fp->fr_group, fp->fr_flags, unit, set, NULL)) return ESRCH; in = (fp->fr_flags & FR_INQUE) ? 0 : 1; @@ -658,6 +715,13 @@ caddr_t data; if (!fp->fr_ifa) fp->fr_ifa = (void *)-1; } +#if BSD >= 199306 + if (*fp->fr_oifname) { + fp->fr_oifa = GETUNIT(fp->fr_oifname); + if (!fp->fr_oifa) + fp->fr_oifa = (void *)-1; + } +#endif fdp = &fp->fr_dif; fp->fr_flags &= ~FR_DUP; @@ -698,13 +762,14 @@ caddr_t data; } if (!f) { - ftail = fprev; - if (req != SIOCINAFR && req != SIOCINIFR) - while ((f = *ftail)) - ftail = &f->fr_next; - else if (fp->fr_hits) - while (--fp->fr_hits && (f = *ftail)) - ftail = &f->fr_next; + if (req == SIOCINAFR || req == SIOCINIFR) { + ftail = fprev; + if (fp->fr_hits) { + while (--fp->fr_hits && (f = *ftail)) { + ftail = &f->fr_next; + } + } + } f = NULL; } @@ -719,8 +784,8 @@ caddr_t data; 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); + fr_delgroup((u_int)f->fr_grhead, fp->fr_flags, + unit, set); fixskip(fprev, f, -1); *ftail = f->fr_next; KFREE(f); @@ -731,7 +796,7 @@ caddr_t data; else { if (unit == IPL_LOGAUTH) return fr_auth_ioctl(data, req, f, ftail); - KMALLOC(f, frentry_t *, sizeof(*f)); + KMALLOC(f, frentry_t *); if (f != NULL) { if (fg && fg->fg_head) fg->fg_head->fr_ref++; @@ -757,33 +822,33 @@ caddr_t data; /* * routines below for saving IP headers to buffer */ -#ifdef __sgi -# ifdef _KERNEL +# ifdef __sgi +# ifdef _KERNEL int IPL_EXTERN(open)(dev_t *pdev, int flags, int devtype, cred_t *cp) -# else +# else int IPL_EXTERN(open)(dev_t dev, int flags) -# endif -#else +# endif +# else int IPL_EXTERN(open)(dev, flags -# if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ +# if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL) , devtype, p) int devtype; struct proc *p; -# else +# else ) -# endif +# endif dev_t dev; int flags; -#endif /* __sgi */ +# endif /* __sgi */ { -#if defined(__sgi) && defined(_KERNEL) +# if defined(__sgi) && defined(_KERNEL) u_int min = geteminor(*pdev); -#else +# else u_int min = GET_MINOR(dev); -#endif +# endif - if (2 < min) + if (IPL_LOGMAX < min) min = ENXIO; else min = 0; @@ -791,25 +856,25 @@ int flags; } -#ifdef __sgi +# 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) || \ +# if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL) , devtype, p) int devtype; struct proc *p; -# else +# else ) -# endif +# endif dev_t dev; int flags; -#endif /* __sgi */ +# endif /* __sgi */ { u_int min = GET_MINOR(dev); - if (2 < min) + if (IPL_LOGMAX < min) min = ENXIO; else min = 0; @@ -822,9 +887,9 @@ int flags; * called during packet processing and cause an inconsistancy to appear in * the filter lists. */ -#ifdef __sgi +# ifdef __sgi int IPL_EXTERN(read)(dev_t dev, uio_t *uio, cred_t *crp) -#else +# else # if BSD >= 199306 int IPL_EXTERN(read)(dev, uio, ioflag) int ioflag; @@ -833,13 +898,13 @@ int IPL_EXTERN(read)(dev, uio) # endif dev_t dev; register struct uio *uio; -#endif /* __sgi */ +# endif /* __sgi */ { -# ifdef IPFILTER_LOG +# ifdef IPFILTER_LOG return ipflog_read(GET_MINOR(dev), uio); -# else +# else return ENXIO; -# endif +# endif } @@ -847,77 +912,171 @@ register struct uio *uio; * 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. */ -int send_reset(ti) -struct tcpiphdr *ti; +int send_reset(fin, oip) +fr_info_t *fin; +struct ip *oip; { + struct tcphdr *tcp, *tcp2; struct tcpiphdr *tp; - struct tcphdr *tcp; struct mbuf *m; - int tlen = 0, err; + int tlen = 0; ip_t *ip; -# if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) - struct route ro; -# endif - if (ti->ti_flags & TH_RST) + tcp = (struct tcphdr *)fin->fin_dp; + if (tcp->th_flags & TH_RST) return -1; /* feedback loop */ # if (BSD < 199306) || defined(__sgi) m = m_get(M_DONTWAIT, MT_HEADER); # else m = m_gethdr(M_DONTWAIT, MT_HEADER); - m->m_data += max_linkhdr; # endif if (m == NULL) + return ENOBUFS; + if (m == NULL) return -1; - if (ti->ti_flags & TH_SYN) + if (tcp->th_flags & TH_SYN) tlen = 1; - m->m_len = sizeof (struct tcpiphdr); + m->m_len = sizeof(*tcp2) + sizeof(*ip); # if BSD >= 199306 - m->m_pkthdr.len = sizeof (struct tcpiphdr); + m->m_data += max_linkhdr; + m->m_pkthdr.len = m->m_len; m->m_pkthdr.rcvif = (struct ifnet *)0; # endif bzero(mtod(m, char *), sizeof(struct tcpiphdr)); ip = mtod(m, struct ip *); tp = mtod(m, struct tcpiphdr *); - tcp = (struct tcphdr *)((char *)ip + sizeof(struct ip)); - - ip->ip_src.s_addr = ti->ti_dst.s_addr; - ip->ip_dst.s_addr = ti->ti_src.s_addr; - tcp->th_dport = ti->ti_sport; - tcp->th_sport = ti->ti_dport; - tcp->th_ack = htonl(ntohl(ti->ti_seq) + tlen); - tcp->th_off = sizeof(struct tcphdr) >> 2; - tcp->th_flags = TH_RST|TH_ACK; - tp->ti_pr = ((struct ip *)ti)->ip_p; + tcp2 = (struct tcphdr *)((char *)ip + sizeof(*ip)); + + ip->ip_src.s_addr = oip->ip_dst.s_addr; + ip->ip_dst.s_addr = oip->ip_src.s_addr; + tcp2->th_dport = tcp->th_sport; + tcp2->th_sport = tcp->th_dport; + tcp2->th_ack = ntohl(tcp->th_seq); + tcp2->th_ack += tlen; + tcp2->th_ack = htonl(tcp2->th_ack); + tcp2->th_off = sizeof(*tcp2) >> 2; + tcp2->th_flags = TH_RST|TH_ACK; + tp->ti_pr = oip->ip_p; tp->ti_len = htons(sizeof(struct tcphdr)); - tcp->th_sum = in_cksum(m, sizeof(struct tcpiphdr)); + tcp2->th_sum = in_cksum(m, sizeof(*ip) + sizeof(*tcp2)); + + ip->ip_tos = oip->ip_tos; + ip->ip_p = oip->ip_p; + ip->ip_len = sizeof(*ip) + sizeof(*tcp2); + + return send_ip(m, ip); +} + + +static int send_ip(m, ip) +struct mbuf *m; +ip_t *ip; +{ +# if (defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)) || \ + (defined(_BSDI_VERSION) && (_BSDI_VERSION >= 199802)) + struct route ro; +# endif - 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) || defined(__sgi) ip->ip_ttl = tcp_ttl; # else ip->ip_ttl = ip_defttl; # endif +# ifdef IPSEC + m->m_pkthdr.rcvif = NULL; +# endif # if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) + { + int err; + bzero((char *)&ro, sizeof(ro)); err = ip_output(m, (struct mbuf *)0, &ro, 0, 0); if (ro.ro_rt) RTFREE(ro.ro_rt); + return err; + } # else /* * extra 0 in case of multicast */ -# ifdef __OpenBSD__ - err = ip_output(m, (struct mbuf *)0, 0, 0, 0, 0); +# if _BSDI_VERSION >= 199802 + return ip_output(m, (struct mbuf *)0, &ro, 0, 0, NULL); # else - err = ip_output(m, (struct mbuf *)0, 0, 0, 0); +# if defined(__OpenBSD__) + return ip_output(m, (struct mbuf *)0, 0, 0, 0, NULL); +# else + return ip_output(m, (struct mbuf *)0, 0, 0, 0); +# endif # endif # endif - return err; +} + + +int send_icmp_err(oip, type, code, ifp, dst) +ip_t *oip; +int type, code; +void *ifp; +struct in_addr dst; +{ + struct icmp *icmp; + struct mbuf *m; + ip_t *nip; + +# if (BSD < 199306) || defined(__sgi) + m = m_get(M_DONTWAIT, MT_HEADER); +# else + m = m_gethdr(M_DONTWAIT, MT_HEADER); +# endif + if (m == NULL) + return ENOBUFS; + m->m_len = sizeof(*nip) + sizeof(*icmp) + 8; +# if BSD >= 199306 + m->m_data += max_linkhdr; + m->m_pkthdr.len = sizeof(*nip) + sizeof(*icmp) + 8; + m->m_pkthdr.rcvif = (struct ifnet *)0; +# endif + + bzero(mtod(m, char *), (size_t)sizeof(*nip) + sizeof(*icmp) + 8); + nip = mtod(m, ip_t *); + icmp = (struct icmp *)(nip + 1); + + nip->ip_v = IPVERSION; + nip->ip_hl = (sizeof(*nip) >> 2); + nip->ip_p = IPPROTO_ICMP; + nip->ip_id = oip->ip_id; + nip->ip_sum = 0; + nip->ip_ttl = 60; + nip->ip_tos = oip->ip_tos; + nip->ip_len = sizeof(*nip) + sizeof(*icmp) + 8; + if (dst.s_addr == 0) { + if (fr_ifpaddr(ifp, &dst) == -1) + return -1; + dst.s_addr = htonl(dst.s_addr); + } + nip->ip_src = dst; + nip->ip_dst = oip->ip_src; + + icmp->icmp_type = type; + icmp->icmp_code = code; + icmp->icmp_cksum = 0; + bcopy((char *)oip, (char *)&icmp->icmp_ip, sizeof(*oip)); + bcopy((char *)oip + (oip->ip_hl << 2), + (char *)&icmp->icmp_ip + sizeof(*oip), 8); /* 64 bits */ +# ifndef sparc + { + register u_short __iplen, __ipoff; + ip_t *ip = &icmp->icmp_ip; + + __iplen = ip->ip_len; + __ipoff = ip->ip_off; + ip->ip_len = htons(__iplen); + ip->ip_off = htons(__ipoff); + } +# endif + icmp->icmp_cksum = ipf_cksum((u_short *)icmp, sizeof(*icmp) + 8); + return send_ip(m, nip); } @@ -937,11 +1096,12 @@ iplinit() /* must explicitly enable with 'ipf -E' * which invokes ipl_enable(); */ # else - (void) iplattach(); + if (iplattach() != 0) + printf("IP Filter failed to attach\n"); # endif ip_init(); } -# endif /* !LKM, !sgi, FreeBSD < 3 */ +# endif /* ! __NetBSD__ */ size_t mbufchainlen(m0) @@ -955,7 +1115,7 @@ register struct mbuf *m0; } -void ipfr_fastroute(m0, fin, fdp) +int ipfr_fastroute(m0, fin, fdp) struct mbuf *m0; fr_info_t *fin; frdest_t *fdp; @@ -963,12 +1123,13 @@ frdest_t *fdp; register struct ip *ip, *mhip; register struct mbuf *m = m0; register struct route *ro; - struct ifnet *ifp = fdp->fd_ifp; - int len, off, error = 0; - int hlen = fin->fin_hlen; - struct route iproute; + int len, off, error = 0, hlen; struct sockaddr_in *dst; + struct route iproute; + struct ifnet *ifp; + frentry_t *fr; + hlen = fin->fin_hlen; ip = mtod(m0, struct ip *); /* * Route packet. @@ -977,13 +1138,25 @@ frdest_t *fdp; bzero((caddr_t)ro, sizeof (*ro)); 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; + + fr = fin->fin_fr; + ifp = fdp->fd_ifp; + /* + * In case we're here due to "to <if>" being used with "keep state", + * check that we're going in the correct direction. + */ + if ((fr != NULL) && (fin->fin_rev != 0)) { + if ((ifp != NULL) && (fdp == &fr->fr_tif)) + return -1; + dst->sin_addr = ip->ip_dst; + } else + dst->sin_addr = fdp->fd_ip.s_addr ? fdp->fd_ip : ip->ip_dst; # ifdef __bsdi__ dst->sin_len = sizeof(*dst); # endif # if (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \ !defined(__OpenBSD__) -# ifdef RTF_CLONING +# ifdef RTF_CLONING rtalloc_ign(ro, RTF_CLONING); # else rtalloc_ign(ro, RTF_PRCLONING); @@ -1014,15 +1187,17 @@ frdest_t *fdp; * go back through output filtering and miss their chance to get * NAT'd and counted. */ + fin->fin_ifp = ifp; if (fin->fin_out == 0) { + fin->fin_out = 1; if ((fin->fin_fr = ipacct[1][fr_active]) && - (FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { + (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { ATOMIC_INC(frstats[1].fr_acct); } fin->fin_fr = NULL; - (void) ip_natout(ip, hlen, fin); - } - if (fin->fin_out) + (void) fr_checkstate(ip, fin); + (void) ip_natout(ip, fin); + } else ip->ip_sum = 0; /* * If small enough for interface, can just send directly. @@ -1066,7 +1241,11 @@ frdest_t *fdp; m0 = m; mhlen = sizeof (struct ip); for (off = hlen + len; off < ip->ip_len; off += len) { +# ifdef MGETHDR + MGETHDR(m, M_DONTWAIT, MT_HEADER); +# else MGET(m, M_DONTWAIT, MT_HEADER); +# endif if (m == 0) { error = ENOBUFS; goto bad; @@ -1096,6 +1275,10 @@ frdest_t *fdp; error = ENOBUFS; /* ??? */ goto sendorfree; } +# if BSD >= 199306 + m->m_pkthdr.len = mhlen + len; + m->m_pkthdr.rcvif = NULL; +# endif mhip->ip_off = htons((u_short)mhip->ip_off); mhip->ip_sum = 0; mhip->ip_sum = in_cksum(m, mhlen); @@ -1135,50 +1318,60 @@ done: if (ro->ro_rt) RTFREE(ro->ro_rt); - return; + return 0; bad: +# if BSD >= 199306 + if (error == EMSGSIZE) { + /* Send ICMP error here */ + struct mbuf *mcopy; + + mcopy = m_copy(m, 0, imin((int)ip->ip_len, 68)); + if (mcopy) { + mcopy->m_pkthdr.rcvif = (struct ifnet *)ifp; + icmp_error(mcopy, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, + ip->ip_dst.s_addr, ifp); + } + } +# endif m_freem(m); goto done; } #else /* #ifdef _KERNEL */ -#ifdef __sgi +# ifdef __sgi static int no_output __P((struct ifnet *ifp, struct mbuf *m, struct sockaddr *s)) -#else +# else static int no_output __P((struct ifnet *ifp, struct mbuf *m, struct sockaddr *s, struct rtentry *rt)) -#endif +# endif { return 0; } # ifdef __STDC__ -#ifdef __sgi +# ifdef __sgi static int write_output __P((struct ifnet *ifp, struct mbuf *m, struct sockaddr *s)) -#else +# else static int write_output __P((struct ifnet *ifp, struct mbuf *m, struct sockaddr *s, struct rtentry *rt)) -#endif +# 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; ip_t *ip; { # endif - FILE *fp; char fname[32]; + FILE *fp; # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) + (defined(OpenBSD) && (OpenBSD >= 199603)) # if defined __OpenBSD__ sprintf(fname, "/var/run/%s", ifp->if_xname); # else @@ -1258,7 +1451,6 @@ char *name; void init_ifp() { - struct ifnet *ifp, **ifa; char fname[32]; int fd; @@ -1271,8 +1463,11 @@ void init_ifp() sprintf(fname, "/var/run/%s", ifp->if_xname); # else sprintf(fname, "/tmp/%s", ifp->if_xname); -#endif - if ((fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0600)) != -1) +# endif + fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); + if (fd == -1) + perror("open"); + else close(fd); } # else @@ -1280,14 +1475,17 @@ void init_ifp() for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { ifp->if_output = write_output; sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); - if ((fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0600)) != -1) + fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); + if (fd == -1) + perror("open"); + else close(fd); } # endif } -void ipfr_fastroute(ip, fin, fdp) +int ipfr_fastroute(ip, fin, fdp) ip_t *ip; fr_info_t *fin; frdest_t *fdp; @@ -1295,7 +1493,7 @@ frdest_t *fdp; struct ifnet *ifp = fdp->fd_ifp; if (!ifp) - return; /* no routing table out here */ + return 0; /* no routing table out here */ ip->ip_len = htons((u_short)ip->ip_len); ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); @@ -1305,6 +1503,7 @@ frdest_t *fdp; #else (*ifp->if_output)(ifp, (void *)ip, NULL, 0); #endif + return 0; } @@ -1331,4 +1530,10 @@ struct ifnet *ifp; verbose("- TCP RST sent\n"); return 0; } + + +void frsync() +{ + return; +} #endif /* _KERNEL */ diff --git a/sys/netinet/ip_fil.h b/sys/netinet/ip_fil.h index 0340b0676e6..a44e5780b47 100644 --- a/sys/netinet/ip_fil.h +++ b/sys/netinet/ip_fil.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_fil.h,v 1.12 1999/02/05 05:58:50 deraadt Exp $ */ +/* $OpenBSD: ip_fil.h,v 1.13 1999/12/15 05:20:21 kjell Exp $ */ /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -7,16 +7,12 @@ * to the original author and the contributors. * * @(#)ip_fil.h 1.35 6/5/96 - * $Id: ip_fil.h,v 1.12 1999/02/05 05:58:50 deraadt Exp $ + * $Id: ip_fil.h,v 1.13 1999/12/15 05:20:21 kjell Exp $ */ #ifndef __IP_FIL_H__ #define __IP_FIL_H__ -#if defined(__NetBSD__) && defined(PFIL_HOOKS) -#include "opt_pfil_hooks.h" -#endif - /* * Pathnames for various IP Filter control devices. Used by LKM * and userland, so defined here. @@ -26,11 +22,11 @@ #define IPAUTH_NAME "/dev/ipauth" #ifndef SOLARIS -#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) +# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #endif #if defined(KERNEL) && !defined(_KERNEL) -#define _KERNEL +# define _KERNEL #endif #ifndef __P @@ -42,45 +38,45 @@ #endif #if defined(__STDC__) || defined(__GNUC__) -#define SIOCADAFR _IOW('r', 60, struct frentry) -#define SIOCRMAFR _IOW('r', 61, struct frentry) -#define SIOCSETFF _IOW('r', 62, u_int) -#define SIOCGETFF _IOR('r', 63, u_int) -#define SIOCGETFS _IOR('r', 64, struct friostat) -#define SIOCIPFFL _IOWR('r', 65, int) -#define SIOCIPFFB _IOR('r', 66, int) -#define SIOCADIFR _IOW('r', 67, struct frentry) -#define SIOCRMIFR _IOW('r', 68, struct frentry) -#define SIOCSWAPA _IOR('r', 69, u_int) -#define SIOCINAFR _IOW('r', 70, struct frentry) -#define SIOCINIFR _IOW('r', 71, struct frentry) -#define SIOCFRENB _IOW('r', 72, u_int) -#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) +# define SIOCADAFR _IOW('r', 60, struct frentry) +# define SIOCRMAFR _IOW('r', 61, struct frentry) +# define SIOCSETFF _IOW('r', 62, u_int) +# define SIOCGETFF _IOR('r', 63, u_int) +# define SIOCGETFS _IOR('r', 64, struct friostat) +# define SIOCIPFFL _IOWR('r', 65, int) +# define SIOCIPFFB _IOR('r', 66, int) +# define SIOCADIFR _IOW('r', 67, struct frentry) +# define SIOCRMIFR _IOW('r', 68, struct frentry) +# define SIOCSWAPA _IOR('r', 69, u_int) +# define SIOCINAFR _IOW('r', 70, struct frentry) +# define SIOCINIFR _IOW('r', 71, struct frentry) +# define SIOCFRENB _IOW('r', 72, u_int) +# 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) -#define SIOCSETFF _IOW(r, 62, u_int) -#define SIOCGETFF _IOR(r, 63, u_int) -#define SIOCGETFS _IOR(r, 64, struct friostat) -#define SIOCIPFFL _IOWR(r, 65, int) -#define SIOCIPFFB _IOR(r, 66, int) -#define SIOCADIFR _IOW(r, 67, struct frentry) -#define SIOCRMIFR _IOW(r, 68, struct frentry) -#define SIOCSWAPA _IOR(r, 69, u_int) -#define SIOCINAFR _IOW(r, 70, struct frentry) -#define SIOCINIFR _IOW(r, 71, struct frentry) -#define SIOCFRENB _IOW(r, 72, u_int) -#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) +# define SIOCADAFR _IOW(r, 60, struct frentry) +# define SIOCRMAFR _IOW(r, 61, struct frentry) +# define SIOCSETFF _IOW(r, 62, u_int) +# define SIOCGETFF _IOR(r, 63, u_int) +# define SIOCGETFS _IOR(r, 64, struct friostat) +# define SIOCIPFFL _IOWR(r, 65, int) +# define SIOCIPFFB _IOR(r, 66, int) +# define SIOCADIFR _IOW(r, 67, struct frentry) +# define SIOCRMIFR _IOW(r, 68, struct frentry) +# define SIOCSWAPA _IOR(r, 69, u_int) +# define SIOCINAFR _IOW(r, 70, struct frentry) +# define SIOCINIFR _IOW(r, 71, struct frentry) +# define SIOCFRENB _IOW(r, 72, u_int) +# 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 @@ -103,32 +99,43 @@ typedef struct fr_ip { #define FI_TCPUDP (FF_TCPUDP >> 24) /* TCP/UCP implied comparison*/ #define FI_FRAG (FF_FRAG >> 24) #define FI_SHORT (FF_SHORT >> 24) +#define FI_CMP (FI_OPTIONS|FI_TCPUDP|FI_SHORT) + +/* + * These are both used by the state and NAT code to indicate that one port or + * the other should be treated as a wildcard. + */ +#define FI_W_SPORT 0x00000100 +#define FI_W_DPORT 0x00000200 +#define FI_WILD (FI_W_SPORT|FI_W_DPORT) typedef struct fr_info { + void *fin_ifp; /* interface packet is `on' */ struct fr_ip fin_fi; /* IP Packet summary */ u_short fin_data[2]; /* TCP/UDP ports, ICMP code/type */ - u_short fin_out; /* in or out ? 1 == out, 0 == in */ + u_char fin_out; /* in or out ? 1 == out, 0 == in */ + u_char fin_rev; /* state only: 1 = reverse */ u_short fin_hlen; /* length of IP header in bytes */ u_char fin_tcpf; /* TCP header flags (SYN, ACK, etc) */ /* From here on is packet specific */ u_char fin_icode; /* ICMP error to return */ u_short fin_rule; /* rule # last matched */ u_short fin_group; /* group number, -1 for none */ - u_short fin_dlen; /* length of data portion of packet */ - u_short fin_id; /* IP packet id field */ - void *fin_ifp; /* interface packet is `on' */ struct frentry *fin_fr; /* last matching rule */ char *fin_dp; /* start of data past IP header */ + u_short fin_dlen; /* length of data portion of packet */ + u_short fin_id; /* IP packet id field */ void *fin_mp; /* pointer to pointer to mbuf */ #if SOLARIS && defined(_KERNEL) void *fin_qfm; /* pointer to mblk where pkt starts */ + void *fin_qif; #endif } fr_info_t; /* * Size for compares on fr_info structures */ -#define FI_CSIZE offsetof(fr_info_t, fin_icode) +#define FI_CSIZE offsetof(fr_info_t, fin_icode) /* * Size for copying cache fr_info structure @@ -148,6 +155,9 @@ typedef struct frentry { struct frentry *fr_grp; int fr_ref; /* reference count - for grouping */ void *fr_ifa; +#if BSD >= 199306 + void *fr_oifa; +#endif /* * These are only incremented when a packet matches this rule and * it is the last match @@ -173,10 +183,14 @@ typedef struct frentry { u_short fr_stop; /* top port for <> and >< */ u_short fr_dtop; /* top port for <> and >< */ u_32_t fr_flags; /* per-rule flags && options (see below) */ - int fr_skip; /* # of rules to skip */ + u_short fr_skip; /* # of rules to skip */ + u_short fr_loglevel; /* syslog log facility + priority */ int (*fr_func) __P((int, ip_t *, fr_info_t *)); /* call this function */ char fr_icode; /* return ICMP code */ char fr_ifname[IFNAMSIZ]; +#if BSD >= 199306 + char fr_oifname[IFNAMSIZ]; +#endif struct frdest fr_tif; /* "to" interface */ struct frdest fr_dif; /* duplicate packet interfaces */ } frentry_t; @@ -208,6 +222,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_FAKEICMP 0x00180 /* Return ICMP unreachable with fake source */ #define FR_NOMATCH 0x00200 /* no match occured */ #define FR_ACCOUNT 0x00400 /* count packet bytes */ #define FR_KEEPFRAG 0x00800 /* keep fragment information */ @@ -222,8 +237,10 @@ typedef struct frentry { #define FR_NOTDSTIP 0x100000 /* not the dst IP# */ #define FR_AUTH 0x200000 /* use authentication */ #define FR_PREAUTH 0x400000 /* require preauthentication */ +#define FR_DONTCACHE 0x800000 /* don't cache the result */ #define FR_LOGMASK (FR_LOG|FR_LOGP|FR_LOGB) +#define FR_RETMASK (FR_RETICMP|FR_RETRST|FR_FAKEICMP) /* * These correspond to #define's for FI_* and are stored in fr_flags @@ -289,8 +306,13 @@ typedef struct friostat { struct frentry *f_acctin[2]; struct frentry *f_acctout[2]; struct frentry *f_auth; + struct frgroup *f_groups[3][2]; u_long f_froute[2]; - int f_active; + int f_active; /* 1 or 0 - active rule set */ + int f_defpass; /* default pass - from fr_pass */ + int f_running; /* 1 if running, else 0 */ + int f_logging; /* 1 if enabled, else 0 */ + char f_version[32]; /* version string */ } friostat_t; typedef struct optlist { @@ -316,11 +338,10 @@ typedef struct frgroup { * structure which is then followed by any packet data. */ typedef struct iplog { - u_long ipl_magic; + u_32_t ipl_magic; + u_int ipl_count; 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; @@ -339,7 +360,9 @@ typedef struct ipflog { 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_short fl_loglevel; /* syslog log level */ u_32_t fl_flags; + u_32_t fl_lflags; } ipflog_t; @@ -352,7 +375,6 @@ typedef struct ipflog { #ifndef IPF_LOGGING # define IPF_LOGGING 0 #endif - #ifndef IPF_DEFAULT_PASS # define IPF_DEFAULT_PASS FR_PASS #endif @@ -386,16 +408,32 @@ typedef struct ipflog { # define CDEV_MAJOR 79 #endif +/* + * 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) +# if (NetBSD >= 199905) +# define PFIL_HOOKS +# endif +# ifdef PFIL_HOOKS +# define NETBSD_PF +# endif +#endif + + #ifndef _KERNEL 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 int 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__) || (_BSDI_VERSION >= 199701) +# if defined(__NetBSD__) || defined(__OpenBSD__) || \ + (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) extern int iplioctl __P((dev_t, u_long, caddr_t, int)); # else extern int iplioctl __P((dev_t, int, caddr_t, int)); @@ -404,7 +442,7 @@ 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)); +extern void ipfilterattach __P((int)); # endif #if !defined(__OpenBSD__) @@ -418,25 +456,28 @@ extern int iplattach __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_clear __P((minor_t)); +extern int ipflog_read __P((minor_t, 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)); +extern int ipllog __P((int, fr_info_t *, void **, size_t *, int *, int)); # if SOLARIS 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 icmp_error __P((ip_t *, int, int, qif_t *, struct in_addr)); +# if SOLARIS2 >= 7 +extern int iplioctl __P((dev_t, int, intptr_t, int, cred_t *, int *)); +# else +extern int iplioctl __P((dev_t, int, int *, int, cred_t *, int *)); +# endif 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 send_reset __P((fr_info_t *, 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 void copyin_mblk __P((mblk_t *, size_t, size_t, char *)); +extern void copyout_mblk __P((mblk_t *, size_t, size_t, char *)); extern int fr_qin __P((queue_t *, mblk_t *)); extern int fr_qout __P((queue_t *, mblk_t *)); # ifdef IPFILTER_LOG @@ -448,9 +489,10 @@ extern int (*fr_checkp) __P((ip_t *, int, void *, int, mb_t **)); # ifdef linux extern int send_reset __P((tcpiphdr_t *, struct ifnet *)); # else -extern int send_reset __P((tcpiphdr_t *)); +extern int send_reset __P((fr_info_t *, struct ip *)); +extern int send_icmp_err __P((ip_t *, int, int, void *, struct in_addr)); # endif -extern void ipfr_fastroute __P((mb_t *, fr_info_t *, frdest_t *)); +extern int ipfr_fastroute __P((mb_t *, fr_info_t *, frdest_t *)); extern size_t mbufchainlen __P((mb_t *)); # ifdef __sgi # include <sys/cred.h> @@ -468,57 +510,54 @@ extern int iplidentify __P((char *)); # endif # if (_BSDI_VERSION >= 199510) || (__FreeBSD_version >= 220000) || \ (NetBSD >= 199511) || defined(__OpenBSD__) -# if defined(__NetBSD__) || (_BSDI_VERSION >= 199701) || defined(__OpenBSD__) +# if defined(__NetBSD__) || (_BSDI_VERSION >= 199701) || \ + defined(__OpenBSD__) || (__FreeBSD_version >= 300000) extern int iplioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); -# else /* FreeBSD v2.2+ or BSDI >= 199510 and < 199701 */ +# else extern int iplioctl __P((dev_t, int, caddr_t, int, struct proc *)); -# endif /* NetBSD, modern BSDI and OpenBSD */ +# endif extern int iplopen __P((dev_t, int, int, struct proc *)); extern int iplclose __P((dev_t, int, int, struct proc *)); -# else /* everybody else */ -# ifdef linux -extern int iplioctl(struct inode *, struct file *, u_int, u_long); -extern int iplopen __P((struct inode *, struct file *)); -extern void iplclose __P((struct inode *, struct file *)); - else -extern int iplioctl __P((dev_t, int, caddr_t, int)); +# else +# ifndef linux extern int iplopen __P((dev_t, int)); extern int iplclose __P((dev_t, int)); -# endif /* linux */ +extern int iplioctl __P((dev_t, int, caddr_t, int)); +# else +extern int iplioctl(struct inode *, struct file *, u_int, u_long); +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 -# ifdef linux -extern int iplread(struct inode *, struct file *, char *, int); - else +# ifndef linux extern int iplread __P((dev_t, struct uio *)); -# endif /* linux */ +# else +extern int iplread(struct inode *, struct file *, char *, int); +# endif /* !linux */ # endif /* BSD >= 199306 */ # 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 void fixskip __P((frentry_t **, frentry_t *, int)); +extern int countbits __P((u_32_t)); extern int ipldetach __P((void)); -extern u_short fr_tcpsum __P((mb_t *, ip_t *, tcphdr_t *, int)); -#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 fr_tcpsum __P((mb_t *, ip_t *, tcphdr_t *)); +extern int fr_scanlist __P((u_32_t, 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, int *)); -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 void fr_forgetifp __P((void *)); +extern int frflush __P((minor_t, int)); +extern void frsync __P((void)); +extern frgroup_t *fr_addgroup __P((u_int, frentry_t *, minor_t, int)); +extern frgroup_t *fr_findgroup __P((u_int, u_32_t, minor_t, int, frgroup_t ***)); +extern void fr_delgroup __P((u_int, u_32_t, minor_t, int)); +extern void fr_makefrip __P((int, ip_t *, fr_info_t *)); +extern int fr_ifpaddr __P((void *, struct in_addr *)); +extern char *memstr __P((char *, char *, int, int)); extern int ipl_unreach; extern int ipl_inited; extern u_long ipl_frouteok[2]; @@ -526,9 +565,10 @@ extern int fr_pass; extern int fr_flags; extern int fr_active; extern fr_info_t frcache[2]; +extern char ipfilter_version[]; #ifdef IPFILTER_LOG extern iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1]; -extern int iplused[IPL_LOGMAX + 1]; +extern size_t iplused[IPL_LOGMAX + 1]; #endif extern struct frentry *ipfilter[2][2], *ipacct[2][2]; extern struct frgroup *ipfgroups[3][2]; diff --git a/sys/netinet/ip_fil_compat.h b/sys/netinet/ip_fil_compat.h index e78149c266b..eab1ee7e804 100644 --- a/sys/netinet/ip_fil_compat.h +++ b/sys/netinet/ip_fil_compat.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_fil_compat.h,v 1.10 1999/02/05 05:58:51 deraadt Exp $ */ +/* $OpenBSD: ip_fil_compat.h,v 1.11 1999/12/15 05:20:21 kjell Exp $ */ /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -7,7 +7,7 @@ * to the original author and the contributors. * * @(#)ip_compat.h 1.8 1/14/96 - * $Id: ip_fil_compat.h,v 1.10 1999/02/05 05:58:51 deraadt Exp $ + * $Id: ip_fil_compat.h,v 1.11 1999/12/15 05:20:21 kjell Exp $ */ #ifndef __IP_COMPAT_H__ @@ -18,9 +18,12 @@ # define __P(x) x # else # define __P(x) () -# define const # endif #endif +#ifndef __STDC__ +# undef const +# define const +#endif #ifndef SOLARIS #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) @@ -73,6 +76,7 @@ struct ether_addr { #endif #if SOLARIS # define MTYPE(m) ((m)->b_datap->db_type) +# include <sys/isa_defs.h> # include <sys/ioccom.h> # include <sys/sysmacros.h> # include <sys/kmem.h> @@ -96,6 +100,15 @@ struct ether_addr { # include <inet/ip.h> # include <inet/ip_ire.h> # endif /* _KERNEL */ +# if SOLARIS2 >= 8 +# include <netinet/ip6.h> +# include <inet/ip6.h> +# define ipif_local_addr ipif_lcl_addr +# endif +#else +# if !defined(__sgi) +typedef int minor_t; +#endif #endif /* SOLARIS */ #define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h))) @@ -122,7 +135,7 @@ typedef u_int32_t u_32_t; /* * Really, any arch where sizeof(long) != sizeof(int). */ -# if defined(__alpha__) || defined(__alpha) +# if defined(__alpha__) || defined(__alpha) || defined(_LP64) typedef unsigned int u_32_t; # else typedef unsigned long u_32_t; @@ -214,6 +227,10 @@ typedef unsigned long u_32_t; # define KRWLOCK_T krwlock_t # define READ_ENTER(x) rw_enter(x, RW_READER) # define WRITE_ENTER(x) rw_enter(x, RW_WRITER) +# define RW_UPGRADE(x) { if (rw_tryupgrade(x) == 0) { \ + rw_exit(x); \ + rw_enter(x, RW_WRITER); } \ + } # define MUTEX_DOWNGRADE(x) rw_downgrade(x) # define RWLOCK_INIT(x, y, z) rw_init((x), (y), RW_DRIVER, (z)) # define RWLOCK_EXIT(x) rw_exit(x) @@ -242,7 +259,8 @@ typedef unsigned long u_32_t; # define htons(x) (x) # define htonl(x) (x) # endif /* sparc */ -# define KMALLOC(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) +# define KMALLOC(a,b) (a) = (b)kmem_alloc(sizeof(*(a)), KM_NOSLEEP) +# define KMALLOCS(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) # define GET_MINOR(x) getminor(x) typedef struct qif { struct qif *qf_next; @@ -258,18 +276,19 @@ typedef struct qif { 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 */ + size_t qf_off; + size_t 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 */ + size_t qf_hl; /* header length */ } qif_t; extern ill_t *get_unit __P((char *)); # define GETUNIT(n) get_unit((n)) # else /* SOLARIS */ # if defined(__sgi) +# define hz HZ # include <sys/ksynch.h> # define IPF_LOCK_PL plhi # include <sys/sema.h> @@ -286,6 +305,7 @@ typedef struct { # define KRWLOCK_T kmutex_t # define READ_ENTER(x) MUTEX_ENTER(x) # define WRITE_ENTER(x) MUTEX_ENTER(x) +# define RW_UPGRADE(x) ; # define MUTEX_DOWNGRADE(x) ; # define RWLOCK_EXIT(x) MUTEX_EXIT(x) # define MUTEX_EXIT(x) UNLOCK((x)->l, (x)->pl); @@ -295,6 +315,7 @@ typedef struct { # define MUTEX_ENTER(x) ; # define READ_ENTER(x) ; # define WRITE_ENTER(x) ; +# define RW_UPGRADE(x) ; # define MUTEX_DOWNGRADE(x) ; # define RWLOCK_EXIT(x) ; # define MUTEX_EXIT(x) ; @@ -331,11 +352,14 @@ extern void m_copyback __P((struct mbuf *, int, int, caddr_t)); # ifdef __sgi # include <sys/kmem.h> # include <sys/ddi.h> -# define KMALLOC(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) +# define KMALLOC(a,b) (a) = (b)kmem_alloc(sizeof(*(a)), KM_NOSLEEP) +# define KMALLOCS(a,b,c) (a) = (b)kmem_alloc((c), KM_NOSLEEP) # define GET_MINOR(x) getminor(x) # else # if !SOLARIS -# define KMALLOC(a,b,c) (a) = (b)new_kmem_alloc((c), KMEM_NOSLEEP) +# define KMALLOC(a,b) (a) = (b)new_kmem_alloc(sizeof(*(a)), \ + KMEM_NOSLEEP) +# define KMALLOCS(a,b,c) (a) = (b)new_kmem_alloc((c), KMEM_NOSLEEP) # endif /* SOLARIS */ # endif /* __sgi */ # endif /* sun && !linux */ @@ -352,11 +376,13 @@ extern vm_map_t kmem_map; # include <vm/vm_kern.h> # endif /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD__>=3) */ # ifdef M_PFIL -# define KMALLOC(a, b, c) MALLOC((a), b, (c), M_PFIL, M_NOWAIT) +# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_PFIL, M_NOWAIT) +# define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_PFIL, M_NOWAIT) # define KFREE(x) FREE((x), M_PFIL) # define KFREES(x,s) FREE((x), M_PFIL) # else -# define KMALLOC(a, b, c) MALLOC((a), b, (c), M_TEMP, M_NOWAIT) +# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_TEMP, M_NOWAIT) +# define KMALLOCS(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 /* M_PFIL */ @@ -384,6 +410,7 @@ extern vm_map_t kmem_map; # define MUTEX_ENTER(x) ; # define READ_ENTER(x) ; # define WRITE_ENTER(x) ; +# define RW_UPGRADE(x) ; # define MUTEX_DOWNGRADE(x) ; # define RWLOCK_EXIT(x) ; # define MUTEX_EXIT(x) ; @@ -391,7 +418,8 @@ extern vm_map_t kmem_map; # define SPL_IMP(x) ; # undef SPL_X # define SPL_X(x) ; -# define KMALLOC(a,b,c) (a) = (b)malloc(c) +# define KMALLOC(a,b) (a) = (b)malloc(sizeof(*a)) +# define KMALLOCS(a,b,c) (a) = (b)malloc(c) # define KFREE(x) free(x) # define KFREES(x,s) free(x) # define GETUNIT(x) get_unit(x) @@ -401,6 +429,15 @@ extern vm_map_t kmem_map; #if SOLARIS typedef mblk_t mb_t; +# if SOLARIS2 >= 7 +# ifdef lint +# define ALIGN32(ptr) (ptr ? 0L : 0L) +# define ALIGN16(ptr) (ptr ? 0L : 0L) +# else +# define ALIGN32(ptr) (ptr) +# define ALIGN16(ptr) (ptr) +# endif +# endif #else # ifdef linux # ifndef kernel @@ -619,8 +656,8 @@ typedef struct { __u8 ip_hl:4; __u8 ip_v:4; # else - __u8 ip_hl:4; __u8 ip_v:4; + __u8 ip_hl:4; # endif __u8 ip_tos; __u16 ip_len; @@ -727,7 +764,8 @@ typedef struct uio { # define UNITNAME(n) dev_get((n)) -# define KMALLOC(a,b,c) (a) = (b)kmalloc((c), GFP_ATOMIC) +# define KMALLOC(a,b) (a) = (b)kmalloc(sizeof(*(a)), GFP_ATOMIC) +# define KMALLOCS(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) { \ @@ -791,7 +829,9 @@ struct ether_addr { * another IP header and then 64 bits of data, totalling 56. Of course, * the last 64 bits is dependant on that being available. */ -#define ICMPERR_MINPKTLEN (20 + 8 + 20) -#define ICMPERR_MAXPKTLEN (20 + 8 + 20 + 8) +#define ICMPERR_ICMPHLEN 8 +#define ICMPERR_IPICMPHLEN (20 + 8) +#define ICMPERR_MINPKTLEN (20 + 8 + 20) +#define ICMPERR_MAXPKTLEN (20 + 8 + 20 + 8) #endif /* __IP_COMPAT_H__ */ diff --git a/sys/netinet/ip_frag.c b/sys/netinet/ip_frag.c index ef679f3f798..1444e14c23d 100644 --- a/sys/netinet/ip_frag.c +++ b/sys/netinet/ip_frag.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_frag.c,v 1.13 1999/12/13 10:41:56 itojun Exp $ */ +/* $OpenBSD: ip_frag.c,v 1.14 1999/12/15 05:20:22 kjell Exp $ */ /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -8,7 +8,11 @@ */ #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 1.13 1999/12/13 10:41:56 itojun Exp $"; +static const char rcsid[] = "@(#)$Id: ip_frag.c,v 1.14 1999/12/15 05:20:22 kjell Exp $"; +#endif + +#if defined(KERNEL) && !defined(_KERNEL) +# define _KERNEL #endif #include <sys/errno.h> @@ -22,49 +26,49 @@ static const char rcsid[] = "@(#)$Id: ip_frag.c,v 1.13 1999/12/13 10:41:56 itoju # include <stdlib.h> #endif #if defined(KERNEL) && (__FreeBSD_version >= 220000) -#include <sys/filio.h> -#include <sys/fcntl.h> +# include <sys/filio.h> +# include <sys/fcntl.h> #else -#include <sys/ioctl.h> +# include <sys/ioctl.h> #endif #include <sys/uio.h> #ifndef linux -#include <sys/protosw.h> +# include <sys/protosw.h> #endif #include <sys/socket.h> #if defined(_KERNEL) && !defined(linux) # include <sys/systm.h> #endif #if !defined(__SVR4) && !defined(__svr4__) +# if defined(_KERNEL) && !defined(__sgi) +# include <sys/kernel.h> +# endif # ifndef linux # include <sys/mbuf.h> # endif #else # include <sys/byteorder.h> -# include <sys/dditypes.h> +# ifdef _KERNEL +# include <sys/dditypes.h> +# endif # include <sys/stream.h> # include <sys/kmem.h> #endif - #include <net/if.h> #ifdef sun -#include <net/af.h> +# include <net/af.h> #endif #include <net/route.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #ifndef linux -#include <netinet/ip_var.h> +# include <netinet/ip_var.h> #endif #include <netinet/tcp.h> #include <netinet/udp.h> #include <netinet/ip_icmp.h> -#if defined(__OpenBSD__) -# include <netinet/ip_fil_compat.h> -#else -# include <netinet/ip_compat.h> -#endif +#include <netinet/ip_fil_compat.h> #include <netinet/tcpip.h> #include <netinet/ip_fil.h> #include <netinet/ip_proxy.h> @@ -72,6 +76,17 @@ static const char rcsid[] = "@(#)$Id: ip_frag.c,v 1.13 1999/12/13 10:41:56 itoju #include <netinet/ip_frag.h> #include <netinet/ip_state.h> #include <netinet/ip_auth.h> +#if (__FreeBSD_version >= 300000) +# include <sys/malloc.h> +# if (defined(KERNEL) || defined(_KERNEL)) +# ifndef IPFILTER_LKM +# include <sys/libkern.h> +# include <sys/systm.h> +# endif +extern struct callout_handle ipfr_slowtimer_ch; +# endif +#endif + ipfr_t *ipfr_heads[IPFT_SIZE]; ipfr_t *ipfr_nattab[IPFT_SIZE]; @@ -79,16 +94,26 @@ ipfrstat_t ipfr_stats; int ipfr_inuse = 0, fr_ipfrttl = 120; /* 60 seconds */ #ifdef _KERNEL +# if SOLARIS2 >= 7 +extern timeout_id_t ipfr_timer_id; +# else extern int ipfr_timer_id; +# endif #endif #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern KRWLOCK_T ipf_frag, ipf_natfrag, ipf_nat; +extern KRWLOCK_T ipf_frag, ipf_natfrag, ipf_nat, ipf_mutex; +# if SOLARIS +extern KRWLOCK_T ipf_solaris; +# else +KRWLOCK_T ipf_solaris; +# endif extern kmutex_t ipf_rw; #endif -static ipfr_t *ipfr_new __P((ip_t *, fr_info_t *, int, ipfr_t **)); +static ipfr_t *ipfr_new __P((ip_t *, fr_info_t *, u_int, ipfr_t **)); static ipfr_t *ipfr_lookup __P((ip_t *, fr_info_t *, ipfr_t **)); +static void ipfr_delete __P((ipfr_t *)); ipfrstat_t *ipfr_fragstats() @@ -107,10 +132,10 @@ ipfrstat_t *ipfr_fragstats() static ipfr_t *ipfr_new(ip, fin, pass, table) ip_t *ip; fr_info_t *fin; -int pass; +u_int pass; ipfr_t *table[]; { - ipfr_t **fp, *fr, frag; + ipfr_t **fp, *fra, frag; u_int idx; frag.ipfr_p = ip->ip_p; @@ -128,8 +153,8 @@ ipfr_t *table[]; /* * first, make sure it isn't already there... */ - for (fp = &table[idx]; (fr = *fp); fp = &fr->ipfr_next) - if (!bcmp((char *)&frag.ipfr_src, (char *)&fr->ipfr_src, + for (fp = &table[idx]; (fra = *fp); fp = &fra->ipfr_next) + if (!bcmp((char *)&frag.ipfr_src, (char *)&fra->ipfr_src, IPFR_CMPSZ)) { ATOMIC_INC(ipfr_stats.ifs_exists); return NULL; @@ -139,39 +164,43 @@ ipfr_t *table[]; * allocate some memory, if possible, if not, just record that we * failed to do so. */ - KMALLOC(fr, ipfr_t *, sizeof(*fr)); - if (fr == NULL) { + KMALLOC(fra, ipfr_t *); + if (fra == NULL) { ATOMIC_INC(ipfr_stats.ifs_nomem); return NULL; } + if ((fra->ipfr_rule = fin->fin_fr) != NULL) { + ATOMIC_INC(fin->fin_fr->fr_ref); + } + + /* * Instert the fragment into the fragment table, copy the struct used * in the search using bcopy rather than reassign each field. * Set the ttl to the default and mask out logging from "pass" */ - if ((fr->ipfr_next = table[idx])) - table[idx]->ipfr_prev = fr; - fr->ipfr_prev = NULL; - fr->ipfr_data = NULL; - table[idx] = fr; - bcopy((char *)&frag.ipfr_src, (char *)&fr->ipfr_src, IPFR_CMPSZ); - fr->ipfr_ttl = fr_ipfrttl; - fr->ipfr_pass = pass & ~(FR_LOGFIRST|FR_LOG); + if ((fra->ipfr_next = table[idx])) + table[idx]->ipfr_prev = fra; + fra->ipfr_prev = NULL; + fra->ipfr_data = NULL; + table[idx] = fra; + bcopy((char *)&frag.ipfr_src, (char *)&fra->ipfr_src, IPFR_CMPSZ); + fra->ipfr_ttl = fr_ipfrttl; /* * Compute the offset of the expected start of the next packet. */ - fr->ipfr_off = (ip->ip_off & IP_OFFMASK) + (fin->fin_dlen >> 3); + fra->ipfr_off = (ip->ip_off & IP_OFFMASK) + (fin->fin_dlen >> 3); ATOMIC_INC(ipfr_stats.ifs_new); ATOMIC_INC(ipfr_inuse); - return fr; + return fra; } int ipfr_newfrag(ip, fin, pass) ip_t *ip; fr_info_t *fin; -int pass; +u_int pass; { ipfr_t *ipf; @@ -185,7 +214,7 @@ int pass; int ipfr_nat_newfrag(ip, fin, pass, nat) ip_t *ip; fr_info_t *fin; -int pass; +u_int pass; nat_t *nat; { ipfr_t *ipf; @@ -251,14 +280,14 @@ ipfr_t *table[]; f->ipfr_prev = NULL; table[idx] = f; } - off = ip->ip_off; + off = ip->ip_off & IP_OFFMASK; atoff = off + (fin->fin_dlen >> 3); /* * If we've follwed the fragments, and this is the * last (in order), shrink expiration time. */ - if ((off & IP_OFFMASK) == f->ipfr_off) { - if (!(off & IP_MF)) + if (off == f->ipfr_off) { + if (!(ip->ip_off & IP_MF)) f->ipfr_ttl = 1; else f->ipfr_off = atoff; @@ -301,18 +330,19 @@ fr_info_t *fin; /* * functional interface for normal lookups of the fragment cache */ -int ipfr_knownfrag(ip, fin) +frentry_t *ipfr_knownfrag(ip, fin) ip_t *ip; fr_info_t *fin; { - int ret; - ipfr_t *ipf; + frentry_t *fr = NULL; + ipfr_t *fra; READ_ENTER(&ipf_frag); - ipf = ipfr_lookup(ip, fin, ipfr_heads); - ret = ipf ? ipf->ipfr_pass : 0; + fra = ipfr_lookup(ip, fin, ipfr_heads); + if (fra != NULL) + fr = fra->ipfr_rule; RWLOCK_EXIT(&ipf_frag); - return ret; + return fr; } @@ -335,34 +365,53 @@ void *nat; } +static void ipfr_delete(fra) +ipfr_t *fra; +{ + frentry_t *fr; + + fr = fra->ipfr_rule; + if (fr != NULL) { + ATOMIC_DEC(fr->fr_ref); + if (fr->fr_ref == 0) + KFREE(fr); + } + if (fra->ipfr_prev) + fra->ipfr_prev->ipfr_next = fra->ipfr_next; + if (fra->ipfr_next) + fra->ipfr_next->ipfr_prev = fra->ipfr_prev; + KFREE(fra); +} + + /* * Free memory in use by fragment state info. kept. */ void ipfr_unload() { - ipfr_t **fp, *fr; + ipfr_t **fp, *fra; nat_t *nat; int idx; WRITE_ENTER(&ipf_frag); for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_heads[idx]; (fr = *fp); ) { - *fp = fr->ipfr_next; - KFREE(fr); + for (fp = &ipfr_heads[idx]; (fra = *fp); ) { + *fp = fra->ipfr_next; + ipfr_delete(fra); } RWLOCK_EXIT(&ipf_frag); WRITE_ENTER(&ipf_nat); WRITE_ENTER(&ipf_natfrag); for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_nattab[idx]; (fr = *fp); ) { - *fp = fr->ipfr_next; - nat = (nat_t *)fr->ipfr_data; + for (fp = &ipfr_nattab[idx]; (fra = *fp); ) { + *fp = fra->ipfr_next; + nat = fra->ipfr_data; if (nat != NULL) { - if (nat->nat_data == fr) + if (nat->nat_data == fra) nat->nat_data = NULL; } - KFREE(fr); + ipfr_delete(fra); } RWLOCK_EXIT(&ipf_natfrag); RWLOCK_EXIT(&ipf_nat); @@ -375,15 +424,30 @@ void ipfr_unload() * of this being called twice per second. */ # if (BSD >= 199306) || SOLARIS || defined(__sgi) +# if defined(SOLARIS2) && (SOLARIS2 < 7) void ipfr_slowtimer() +# else +void ipfr_slowtimer __P((void *ptr)) +# endif # else int ipfr_slowtimer() # endif { - ipfr_t **fp, *fr; + ipfr_t **fp, *fra; nat_t *nat; - int s, idx; + int idx; +#if defined(_KERNEL) +# if !SOLARIS + int s; +# else + extern int fr_running; + + if (fr_running <= 0) + return; +# endif +#endif + READ_ENTER(&ipf_solaris); #ifdef __sgi ipfilter_sgi_intfsync(); #endif @@ -397,21 +461,15 @@ int ipfr_slowtimer() * remove it from the chain and free it. */ for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_heads[idx]; (fr = *fp); ) { - --fr->ipfr_ttl; - if (fr->ipfr_ttl == 0) { - if (fr->ipfr_prev) - fr->ipfr_prev->ipfr_next = - fr->ipfr_next; - if (fr->ipfr_next) - fr->ipfr_next->ipfr_prev = - fr->ipfr_prev; - *fp = fr->ipfr_next; + for (fp = &ipfr_heads[idx]; (fra = *fp); ) { + --fra->ipfr_ttl; + if (fra->ipfr_ttl == 0) { + *fp = fra->ipfr_next; + ipfr_delete(fra); ATOMIC_INC(ipfr_stats.ifs_expire); ATOMIC_DEC(ipfr_inuse); - KFREE(fr); } else - fp = &fr->ipfr_next; + fp = &fra->ipfr_next; } RWLOCK_EXIT(&ipf_frag); @@ -425,26 +483,20 @@ int ipfr_slowtimer() WRITE_ENTER(&ipf_nat); WRITE_ENTER(&ipf_natfrag); for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_nattab[idx]; (fr = *fp); ) { - --fr->ipfr_ttl; - if (fr->ipfr_ttl == 0) { - if (fr->ipfr_prev) - fr->ipfr_prev->ipfr_next = - fr->ipfr_next; - if (fr->ipfr_next) - fr->ipfr_next->ipfr_prev = - fr->ipfr_prev; - *fp = fr->ipfr_next; + for (fp = &ipfr_nattab[idx]; (fra = *fp); ) { + --fra->ipfr_ttl; + if (fra->ipfr_ttl == 0) { ATOMIC_INC(ipfr_stats.ifs_expire); ATOMIC_DEC(ipfr_inuse); - nat = (nat_t *)fr->ipfr_data; + nat = fra->ipfr_data; if (nat != NULL) { - if (nat->nat_data == fr) + if (nat->nat_data == fra) nat->nat_data = NULL; } - KFREE(fr); + *fp = fra->ipfr_next; + ipfr_delete(fra); } else - fp = &fr->ipfr_next; + fp = &fra->ipfr_next; } RWLOCK_EXIT(&ipf_natfrag); RWLOCK_EXIT(&ipf_nat); @@ -456,11 +508,16 @@ int ipfr_slowtimer() ipfr_timer_id = timeout(ipfr_slowtimer, NULL, drv_usectohz(500000)); # else # ifndef linux - ip_slowtimo(); +# if (__FreeBSD_version >= 300000) + ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); +# else + timeout(ipfr_slowtimer, NULL, hz/2); +# endif # endif # if (BSD < 199306) && !defined(__sgi) return 0; # endif # endif + RWLOCK_EXIT(&ipf_solaris); } #endif /* defined(_KERNEL) */ diff --git a/sys/netinet/ip_frag.h b/sys/netinet/ip_frag.h index 54e92d29bbf..647bf54dc29 100644 --- a/sys/netinet/ip_frag.h +++ b/sys/netinet/ip_frag.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_frag.h,v 1.8 1999/02/05 05:58:51 deraadt Exp $ */ +/* $OpenBSD: ip_frag.h,v 1.9 1999/12/15 05:20:22 kjell Exp $ */ /* * Copyright (C) 1993-1998 by Darren Reed. * @@ -7,7 +7,7 @@ * to the original author and the contributors. * * @(#)ip_frag.h 1.5 3/24/96 - * $Id: ip_frag.h,v 1.8 1999/02/05 05:58:51 deraadt Exp $ + * $Id: ip_frag.h,v 1.9 1999/12/15 05:20:22 kjell Exp $ */ #ifndef __IP_FRAG_H__ @@ -25,7 +25,7 @@ typedef struct ipfr { u_char ipfr_tos; u_short ipfr_off; u_short ipfr_ttl; - u_char ipfr_pass; + frentry_t *ipfr_rule; } ipfr_t; @@ -44,16 +44,21 @@ typedef struct ipfrstat { 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 int ipfr_newfrag __P((ip_t *, fr_info_t *, u_int)); +extern int ipfr_nat_newfrag __P((ip_t *, fr_info_t *, u_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 frentry_t *ipfr_knownfrag __P((ip_t *, fr_info_t *)); extern void ipfr_forget __P((void *)); extern void ipfr_unload __P((void)); #if (BSD >= 199306) || SOLARIS || defined(__sgi) +# if defined(SOLARIS2) && (SOLARIS2 < 7) extern void ipfr_slowtimer __P((void)); +# else +extern void ipfr_slowtimer __P((void *)); +# endif #else extern int ipfr_slowtimer __P((void)); #endif + #endif /* __IP_FIL_H__ */ diff --git a/sys/netinet/ip_ftp_pxy.c b/sys/netinet/ip_ftp_pxy.c index 7079c4efa1c..08e5ce5ae3f 100644 --- a/sys/netinet/ip_ftp_pxy.c +++ b/sys/netinet/ip_ftp_pxy.c @@ -1,5 +1,5 @@ -/* $OpenBSD: ip_ftp_pxy.c,v 1.4 1999/02/05 05:58:52 deraadt Exp $ - * $Id: ip_ftp_pxy.c,v 1.4 1999/02/05 05:58:52 deraadt Exp $ +/* $OpenBSD: ip_ftp_pxy.c,v 1.5 1999/12/15 05:20:22 kjell Exp $ */ +/* * Simple FTP transparent proxy for in-kernel use. For use with the NAT * code. */ @@ -17,27 +17,25 @@ extern kmutex_t ipf_rw; #define IPF_MAX227LEN 51 -int ippr_ftp_init __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_ftp_init __P((void)); int ippr_ftp_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); int ippr_ftp_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); -int ippr_ftp_portmsg __P((fr_info_t *, ip_t *, nat_t *nat)); -int ippr_ftp_pasvmsg __P((fr_info_t *, ip_t *, tcphdr_t *, nat_t *)); +int ippr_ftp_portmsg __P((fr_info_t *, ip_t *, nat_t *)); +int ippr_ftp_pasvmsg __P((fr_info_t *, ip_t *, nat_t *)); + u_short ipf_ftp_atoi __P((char **)); +static frentry_t natfr; + /* - * FTP application proxy initialization. + * Initialize local structures. */ -int ippr_ftp_init(fin, ip, aps, nat) -fr_info_t *fin; -ip_t *ip; -ap_session_t *aps; -nat_t *nat; +int ippr_ftp_init() { - tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; - - aps->aps_sport = tcp->th_sport; - aps->aps_dport = tcp->th_dport; + bzero((char *)&natfr, sizeof(natfr)); + natfr.fr_ref = 1; + natfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; return 0; } @@ -77,11 +75,12 @@ ip_t *ip; nat_t *nat; { char portbuf[IPF_MAXPORTLEN + 1], newbuf[IPF_MAXPORTLEN + 1], *s; - int off, olen, dlen, nlen = 0, inc = 0; - u_int a1, a2, a3, a4; tcphdr_t *tcp, tcph, *tcp2 = &tcph; - struct in_addr swip; + size_t nlen = 0, dlen, olen; u_short a5, a6, sp, dp; + u_int a1, a2, a3, a4; + struct in_addr swip; + int off, inc = 0; fr_info_t fi; nat_t *ipn; mb_t *m; @@ -90,23 +89,26 @@ nat_t *nat; #endif tcp = (tcphdr_t *)fin->fin_dp; + bzero(portbuf, sizeof(portbuf)); off = (ip->ip_hl << 2) + (tcp->th_off << 2); - m = *(mb_t **)fin->fin_mp; #if SOLARIS m = fin->fin_qfm; dlen = msgdsize(m) - off; - bzero(portbuf, sizeof(portbuf)); - copyout_mblk(m, off, MIN(sizeof(portbuf), dlen), portbuf); + if (dlen > 0) + copyout_mblk(m, off, MIN(sizeof(portbuf), dlen), portbuf); #else + m = *(mb_t **)fin->fin_mp; + dlen = mbufchainlen(m) - off; - bzero(portbuf, sizeof(portbuf)); - m_copydata(m, off, MIN(sizeof(portbuf), dlen), portbuf); + if (dlen > 0) + m_copydata(m, off, MIN(sizeof(portbuf), dlen), portbuf); #endif + if (dlen == 0) + return 0; portbuf[sizeof(portbuf) - 1] = '\0'; *newbuf = '\0'; - if (!strncmp(portbuf, "PORT ", 5)) { if (dlen < IPF_MINPORTLEN) return 0; @@ -128,9 +130,9 @@ nat_t *nat; return 0; /* - * check that IP address in the PORT/PASV reply is the same as the - * sender of the command - prevents using PORT for port scanning. - */ + * check that IP address in the PORT/PASV reply is the same as the + * sender of the command - prevents using PORT for port scanning. + */ a1 <<= 16; a1 |= a2; if (a1 != ntohl(nat->nat_inip.s_addr)) @@ -139,14 +141,18 @@ nat_t *nat; a5 = ipf_ftp_atoi(&s); if (!s) return 0; + if (*s == ')') + s++; /* * check for CR-LF at the end. */ - if (((*s == '\r') && (*(s + 1) == '\n')) || - ((*(s - 1) == '\r') && (*s == '\n'))) + if (*s == '\n') + s--; + if ((*s == '\r') && (*(s + 1) == '\n')) { + s += 2; a6 = a5 & 0xff; - else + } else return 0; a5 >>= 8; /* @@ -157,8 +163,8 @@ nat_t *nat; a3 = (a1 >> 8) & 0xff; a4 = a1 & 0xff; a1 >>= 24; - olen = s - portbuf + 1; - (void) sprintf(newbuf, "%s %d,%d,%d,%d,%d,%d\r\n", + olen = s - portbuf; + (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", "PORT", a1, a2, a3, a4, a5, a6); nlen = strlen(newbuf); @@ -182,6 +188,9 @@ nat_t *nat; linkb(m1, nm); } else { + if (m1->b_datap->db_struiolim == m1->b_wptr) + m1->b_datap->db_struiolim += inc; + m1->b_datap->db_struioflag &= ~STRUIO_IP; m1->b_wptr += inc; } copyin_mblk(m, off, nlen, newbuf); @@ -191,7 +200,7 @@ nat_t *nat; /* the mbuf chain will be extended if necessary by m_copyback() */ m_copyback(m, off, nlen, newbuf); #endif - if (inc) { + if (inc != 0) { #if SOLARIS || defined(__sgi) register u_32_t sum1, sum2; @@ -204,32 +213,40 @@ nat_t *nat; sum2 -= sum1; sum2 = (sum2 & 0xffff) + (sum2 >> 16); - fix_outcksum(&ip->ip_sum, sum2); + fix_outcksum(&ip->ip_sum, sum2, 0); #endif ip->ip_len += inc; } /* - * Add skeleton NAT entry for connection which will come back the - * other way. - */ + * Add skeleton NAT entry for connection which will come back the + * other way. + */ sp = htons(a5 << 8 | a6); + /* + * The server may not make the connection back from port 20, but + * it is the most likely so use it here to check for a conflicting + * mapping. + */ dp = htons(fin->fin_data[1] - 1); - ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_inip, sp, - ip->ip_dst, dp); + ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_p, nat->nat_inip, + ip->ip_dst, (dp << 16) | sp); if (ipn == NULL) { bcopy((char *)fin, (char *)&fi, sizeof(fi)); bzero((char *)tcp2, sizeof(*tcp2)); + tcp2->th_win = htons(8192); tcp2->th_sport = sp; - tcp2->th_dport = dp; + tcp2->th_dport = 0; /* XXX - don't specify remote port */ + fi.fin_data[0] = ntohs(sp); + fi.fin_data[1] = 0; fi.fin_dp = (char *)tcp2; swip = ip->ip_src; ip->ip_src = nat->nat_inip; - ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_TCP, NAT_OUTBOUND); + ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_TCP|FI_W_DPORT, + NAT_OUTBOUND); if (ipn != NULL) { ipn->nat_age = fr_defnatage; - (void) fr_addstate(ip, &fi, FR_INQUE|FR_PASS| - FR_QUICK|FR_KEEPSTATE); + (void) fr_addstate(ip, &fi, FI_W_DPORT); } ip->ip_src = swip; } @@ -247,18 +264,18 @@ nat_t *nat; } -int ippr_ftp_pasvmsg(fin, ip, tcp, nat) +int ippr_ftp_pasvmsg(fin, ip, nat) fr_info_t *fin; ip_t *ip; -tcphdr_t *tcp; nat_t *nat; { char portbuf[IPF_MAX227LEN + 1], newbuf[IPF_MAX227LEN + 1], *s; int off, olen, dlen, nlen = 0, inc = 0; - u_int a1, a2, a3, a4; tcphdr_t tcph, *tcp2 = &tcph; - struct in_addr swip; - u_short a5, a6; + struct in_addr swip, swip2; + u_short a5, a6, dp, sp; + u_int a1, a2, a3, a4; + tcphdr_t *tcp; fr_info_t fi; nat_t *ipn; mb_t *m; @@ -266,20 +283,24 @@ nat_t *nat; mb_t *m1; #endif + tcp = (tcphdr_t *)fin->fin_dp; off = (ip->ip_hl << 2) + (tcp->th_off << 2); m = *(mb_t **)fin->fin_mp; + bzero(portbuf, sizeof(portbuf)); #if SOLARIS m = fin->fin_qfm; dlen = msgdsize(m) - off; - bzero(portbuf, sizeof(portbuf)); - copyout_mblk(m, off, MIN(sizeof(portbuf), dlen), portbuf); + if (dlen > 0) + copyout_mblk(m, off, MIN(sizeof(portbuf), dlen), portbuf); #else dlen = mbufchainlen(m) - off; - bzero(portbuf, sizeof(portbuf)); - m_copydata(m, off, MIN(sizeof(portbuf), dlen), portbuf); + if (dlen > 0) + m_copydata(m, off, MIN(sizeof(portbuf), dlen), portbuf); #endif + if (dlen == 0) + return 0; portbuf[sizeof(portbuf) - 1] = '\0'; *newbuf = '\0'; @@ -288,21 +309,17 @@ nat_t *nat; return 0; else if (strncmp(portbuf, "227 Entering Passive Mode", 25)) return 0; -#ifndef notyet - return 0; -#endif } else return 0; - /* - * Skip the PORT command + space - */ + * Skip the PORT command + space + */ s = portbuf + 25; while (*s && !isdigit(*s)) s++; /* - * Pick out the address components, two at a time. - */ + * Pick out the address components, two at a time. + */ a1 = ipf_ftp_atoi(&s); if (!s) return 0; @@ -311,9 +328,9 @@ nat_t *nat; return 0; /* - * check that IP address in the PORT/PASV reply is the same as the - * sender of the command - prevents using PORT for port scanning. - */ + * check that IP address in the PORT/PASV reply is the same as the + * sender of the command - prevents using PORT for port scanning. + */ a1 <<= 16; a1 |= a2; if (a1 != ntohl(nat->nat_oip.s_addr)) @@ -323,25 +340,29 @@ nat_t *nat; if (!s) return 0; + if (*s == ')') + s++; + if (*s == '\n') + s--; /* - * check for CR-LF at the end. - */ - if (((*s == '\r') && (*(s + 1) == '\n')) || - ((*(s - 1) == '\r') && (*s == '\n'))) + * check for CR-LF at the end. + */ + if ((*s == '\r') && (*(s + 1) == '\n')) { + s += 2; a6 = a5 & 0xff; - else + } else return 0; a5 >>= 8; /* - * Calculate new address parts for 227 reply - */ - a1 = ntohl(nat->nat_inip.s_addr); + * Calculate new address parts for 227 reply + */ + a1 = ntohl(ip->ip_src.s_addr); a2 = (a1 >> 16) & 0xff; a3 = (a1 >> 8) & 0xff; a4 = a1 & 0xff; a1 >>= 24; - olen = s - portbuf + 1; - (void) sprintf(newbuf, "%s %d,%d,%d,%d,%d,%d\r\n", + olen = s - portbuf; + (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", "227 Entering Passive Mode", a1, a2, a3, a4, a5, a6); nlen = strlen(newbuf); @@ -374,7 +395,7 @@ nat_t *nat; /* the mbuf chain will be extended if necessary by m_copyback() */ m_copyback(m, off, nlen, newbuf); #endif - if (inc) { + if (inc != 0) { #if SOLARIS || defined(__sgi) register u_32_t sum1, sum2; @@ -387,7 +408,7 @@ nat_t *nat; sum2 -= sum1; sum2 = (sum2 & 0xffff) + (sum2 >> 16); - fix_outcksum(&ip->ip_sum, sum2); + fix_outcksum(&ip->ip_sum, sum2, 0); #endif ip->ip_len += inc; } @@ -396,27 +417,42 @@ nat_t *nat; * Add skeleton NAT entry for connection which will come back the * other way. */ - bcopy((char *)fin, (char *)&fi, sizeof(fi)); - bzero((char *)tcp2, sizeof(*tcp2)); - tcp2->th_sport = htons(a5 << 8 | a6); - fi.fin_dp = (char *)tcp2; - swip = ip->ip_src; - ip->ip_src = nat->nat_oip; - ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_TCP, NAT_INBOUND); - if (ipn != NULL) - ipn->nat_age = fr_defnatage; - (void) fr_addstate(ip, &fi, FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE); - ip->ip_src = swip; + sp = 0; + dp = htons(fin->fin_data[1] - 1); + ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_p, nat->nat_inip, + ip->ip_dst, (dp << 16) | sp); + if (ipn == NULL) { + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + bzero((char *)tcp2, sizeof(*tcp2)); + tcp2->th_win = htons(8192); + tcp2->th_sport = 0; /* XXX - fake it for nat_new */ + fi.fin_data[0] = a5 << 8 | a6; + tcp2->th_dport = htons(fi.fin_data[0]); + fi.fin_data[1] = 0; + fi.fin_dp = (char *)tcp2; + swip = ip->ip_src; + swip2 = ip->ip_dst; + ip->ip_dst = ip->ip_src; + ip->ip_src = nat->nat_inip; + ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_TCP|FI_W_SPORT, + NAT_OUTBOUND); + if (ipn != NULL) { + ipn->nat_age = fr_defnatage; + (void) fr_addstate(ip, &fi, FI_W_SPORT); + } + ip->ip_src = swip; + ip->ip_dst = swip2; + } return inc; } + int ippr_ftp_in(fin, ip, aps, nat) fr_info_t *fin; ip_t *ip; ap_session_t *aps; nat_t *nat; { - tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; - return ippr_ftp_pasvmsg(fin, ip, tcp, nat); + return ippr_ftp_pasvmsg(fin, ip, nat); } diff --git a/sys/netinet/ip_log.c b/sys/netinet/ip_log.c index 414bf35c88d..87c9de1c4a1 100644 --- a/sys/netinet/ip_log.c +++ b/sys/netinet/ip_log.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_log.c,v 1.4 1999/02/05 05:58:52 deraadt Exp $ */ +/* $OpenBSD: ip_log.c,v 1.5 1999/12/15 05:20:22 kjell Exp $ */ /* * Copyright (C) 1997-1998 by Darren Reed. * @@ -6,23 +6,29 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: ip_log.c,v 1.4 1999/02/05 05:58:52 deraadt Exp $ + * $Id: ip_log.c,v 1.5 1999/12/15 05:20:22 kjell Exp $ */ +#include <sys/param.h> +#if defined(KERNEL) && !defined(_KERNEL) +# define _KERNEL +#endif +#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) +# include "opt_ipfilter_log.h" +#endif +#ifdef __FreeBSD__ +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include <sys/osreldate.h> +# if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include "opt_ipfilter.h" +# endif +# else +# include <osreldate.h> +# endif +#endif #ifdef IPFILTER_LOG # 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(IPFILTER_LKM) -# include <sys/osreldate.h> -# else -# include <osreldate.h> -# endif -# endif # ifndef _KERNEL # include <stdio.h> # include <string.h> @@ -31,7 +37,6 @@ # endif # include <sys/errno.h> # include <sys/types.h> -# include <sys/param.h> # include <sys/file.h> # if __FreeBSD_version >= 220000 && defined(_KERNEL) # include <sys/fcntl.h> @@ -45,7 +50,7 @@ # endif # include <sys/uio.h> # if !SOLARIS -# if (NetBSD > 199609) || (OpenBSD > 199603) +# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) # include <sys/dirent.h> # else # include <sys/dir.h> @@ -98,11 +103,7 @@ # ifndef _KERNEL # include <syslog.h> # endif -# if defined(__OpenBSD__) -# include <netinet/ip_fil_compat.h> -# else -# include <netinet/ip_compat.h> -# endif +# include <netinet/ip_fil_compat.h> # include <netinet/tcpip.h> # include <netinet/ip_fil.h> # include <netinet/ip_proxy.h> @@ -110,6 +111,10 @@ # include <netinet/ip_frag.h> # include <netinet/ip_state.h> # include <netinet/ip_auth.h> +# if (__FreeBSD_version >= 300000) +# include <sys/malloc.h> +# endif + # ifndef MIN # define MIN(a,b) (((a)<(b))?(a):(b)) # endif @@ -122,10 +127,9 @@ 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; +iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1], *ipll[IPL_LOGMAX+1]; +size_t iplused[IPL_LOGMAX+1]; +fr_info_t iplcrc[IPL_LOGMAX+1]; # ifdef linux static struct wait_queue *iplwait[IPL_LOGMAX+1]; # endif @@ -137,20 +141,15 @@ static struct wait_queue *iplwait[IPL_LOGMAX+1]; */ void ipflog_init() { - struct timeval tv; int i; for (i = IPL_LOGMAX; i >= 0; i--) { iplt[i] = NULL; + ipll[i] = NULL; iplh[i] = &iplt[i]; iplused[i] = 0; + bzero((char *)&iplcrc[i], sizeof(iplcrc[i])); } -# if BSD >= 199306 || defined(__FreeBSD__) || defined(__sgi) - microtime(&tv); -# else - uniqtime(&tv); -# endif - iplcrcinit = tv.tv_sec ^ (tv.tv_usec << 8) ^ tv.tv_usec; } @@ -169,8 +168,7 @@ fr_info_t *fin; mb_t *m; { ipflog_t ipfl; - register int mlen, hlen; - u_long crc; + register size_t mlen, hlen; size_t sizes[2]; void *ptrs[2]; int types[2]; @@ -193,12 +191,12 @@ mb_t *m; struct icmp *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. - */ + * 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 : @@ -243,11 +241,15 @@ mb_t *m; ipfl.fl_hlen = (u_char)hlen; ipfl.fl_rule = fin->fin_rule; ipfl.fl_group = fin->fin_group; + if (fin->fin_fr != NULL) + ipfl.fl_loglevel = fin->fin_fr->fr_loglevel; + else + ipfl.fl_loglevel = 0xffff; ipfl.fl_flags = flags; ptrs[0] = (void *)&ipfl; sizes[0] = sizeof(ipfl); types[0] = 0; -#if SOLARIS +# if SOLARIS /* * Are we copied from the mblk or an aligned array ? */ @@ -260,45 +262,47 @@ mb_t *m; sizes[1] = hlen + mlen; types[1] = 0; } -#else +# 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); +# endif + return ipllog(IPL_LOGIPF, fin, ptrs, sizes, types, 2); } /* * ipllog */ -int ipllog(dev, crc, items, itemsz, types, cnt) +int ipllog(dev, fin, items, itemsz, types, cnt) int dev; -u_long crc; +fr_info_t *fin; void **items; size_t *itemsz; int *types, cnt; { - iplog_t *ipl; caddr_t buf, s; - int len, i; + iplog_t *ipl; + size_t len; + int 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_ENTER(&ipl_mutex); + if (fin != NULL) { + if ((ipll[dev] != NULL) && + bcmp((char *)fin, (char *)&iplcrc[dev], FI_CSIZE) == 0) { + ipll[dev]->ipl_count++; MUTEX_EXIT(&ipl_mutex); return 1; } - iplcrc[dev] = crc; - MUTEX_EXIT(&ipl_mutex); - } + bcopy((char *)fin, (char *)&iplcrc[dev], FI_CSIZE); + } else + bzero((char *)&iplcrc[dev], FI_CSIZE); + MUTEX_EXIT(&ipl_mutex); /* * Get the total amount of data to be logged. @@ -310,7 +314,7 @@ int *types, cnt; * check that we have space to record this information and can * allocate that much. */ - KMALLOC(buf, caddr_t, len); + KMALLOCS(buf, caddr_t, len); if (!buf) return 0; MUTEX_ENTER(&ipl_mutex); @@ -356,6 +360,7 @@ int *types, cnt; s += itemsz[i]; } MUTEX_ENTER(&ipl_mutex); + ipll[dev] = ipl; *iplh[dev] = ipl; iplh[dev] = &ipl->ipl_next; # if SOLARIS @@ -374,11 +379,12 @@ int *types, cnt; int ipflog_read(unit, uio) -int unit; +minor_t unit; struct uio *uio; { + size_t dlen, copied; + int error = 0; iplog_t *ipl; - int error = 0, dlen, copied; # if defined(_KERNEL) && !SOLARIS int s; # endif @@ -387,7 +393,7 @@ struct uio *uio; * Sanity checks. Make sure the minor # is valid and we're copying * a valid chunk of data. */ - if ((IPL_LOGMAX < unit) || (unit < 0)) + if (IPL_LOGMAX < unit) return ENXIO; if (!uio->uio_resid) return 0; @@ -431,43 +437,48 @@ struct uio *uio; for (copied = 0; (ipl = iplt[unit]); copied += dlen) { dlen = ipl->ipl_dsize; - if (dlen + sizeof(iplog_t) > uio->uio_resid) + if (dlen > uio->uio_resid) break; /* * Don't hold the mutex over the uiomove call. */ iplt[unit] = ipl->ipl_next; + iplused[unit] -= dlen; 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) + error = UIOMOVE((caddr_t)ipl, dlen, UIO_READ, uio); + if (error) { + SPL_NET(s); + MUTEX_ENTER(&ipl_mutex); + ipl->ipl_next = iplt[unit]; + iplt[unit] = ipl; + iplused[unit] += dlen; break; + } + KFREES((caddr_t)ipl, dlen); SPL_NET(s); MUTEX_ENTER(&ipl_mutex); - iplused[unit] -= dlen; } - if (!ipl) { + if (!iplt[unit]) { iplused[unit] = 0; iplh[unit] = &iplt[unit]; + ipll[unit] = NULL; } - if (!error) { - MUTEX_EXIT(&ipl_mutex); - SPL_X(s); - } -#ifdef linux + MUTEX_EXIT(&ipl_mutex); + SPL_X(s); +# ifdef linux if (!error) - return copied; + return (int)copied; return -error; -#else +# else return error; -#endif +# endif } int ipflog_clear(unit) -int unit; +minor_t unit; { iplog_t *ipl; int used; @@ -478,9 +489,10 @@ int unit; KFREES((caddr_t)ipl, ipl->ipl_dsize); } iplh[unit] = &iplt[unit]; + ipll[unit] = NULL; used = iplused[unit]; iplused[unit] = 0; - iplcrc[unit] = 0; + bzero((char *)&iplcrc[unit], FI_CSIZE); MUTEX_EXIT(&ipl_mutex); return used; } diff --git a/sys/netinet/ip_nat.c b/sys/netinet/ip_nat.c index b6eaf071b04..45631f9e547 100644 --- a/sys/netinet/ip_nat.c +++ b/sys/netinet/ip_nat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_nat.c,v 1.22 1999/08/08 00:43:00 niklas Exp $ */ +/* $OpenBSD: ip_nat.c,v 1.23 1999/12/15 05:20:22 kjell Exp $ */ /* * Copyright (C) 1995-1998 by Darren Reed. * @@ -10,7 +10,7 @@ */ #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 1.22 1999/08/08 00:43:00 niklas Exp $"; +static const char rcsid[] = "@(#)$Id: ip_nat.c,v 1.23 1999/12/15 05:20:22 kjell Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) @@ -22,6 +22,10 @@ static const char rcsid[] = "@(#)$Id: ip_nat.c,v 1.22 1999/08/08 00:43:00 niklas #include <sys/param.h> #include <sys/time.h> #include <sys/file.h> +#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ + defined(_KERNEL) +# include "opt_ipfilter_log.h" +#endif #if !defined(_KERNEL) && !defined(KERNEL) # include <stdio.h> # include <string.h> @@ -49,7 +53,9 @@ static const char rcsid[] = "@(#)$Id: ip_nat.c,v 1.22 1999/08/08 00:43:00 niklas #else # include <sys/filio.h> # include <sys/byteorder.h> -# include <sys/dditypes.h> +# ifdef _KERNEL +# include <sys/dditypes.h> +# endif # include <sys/stream.h> # include <sys/kmem.h> #endif @@ -59,9 +65,12 @@ static const char rcsid[] = "@(#)$Id: ip_nat.c,v 1.22 1999/08/08 00:43:00 niklas #include <net/if.h> #if __FreeBSD_version >= 300000 # include <net/if_var.h> +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" +# endif #endif #ifdef sun -#include <net/af.h> +# include <net/af.h> #endif #include <net/route.h> #include <netinet/in.h> @@ -76,8 +85,8 @@ static const char rcsid[] = "@(#)$Id: ip_nat.c,v 1.22 1999/08/08 00:43:00 niklas #endif #ifdef RFC1825 -#include <vpn/md5.h> -#include <vpn/ipsec.h> +# include <vpn/md5.h> +# include <vpn/ipsec.h> extern struct ifnet vpnif; #endif @@ -87,27 +96,35 @@ extern struct ifnet vpnif; #include <netinet/tcp.h> #include <netinet/udp.h> #include <netinet/ip_icmp.h> -#if defined(__OpenBSD__) #include <netinet/ip_fil_compat.h> -#else -#include <netinet/ip_compat.h> -#endif #include <netinet/tcpip.h> #include <netinet/ip_fil.h> #include <netinet/ip_proxy.h> #include <netinet/ip_nat.h> #include <netinet/ip_frag.h> #include <netinet/ip_state.h> +#if (__FreeBSD_version >= 300000) +# include <sys/malloc.h> +#endif #ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) +# define MIN(a,b) (((a)<(b))?(a):(b)) #endif #undef SOCKADDR_IN #define SOCKADDR_IN struct sockaddr_in -nat_t *nat_table[2][NAT_SIZE], *nat_instances = NULL; +nat_t **nat_table[2] = { NULL, NULL }, + *nat_instances = NULL; ipnat_t *nat_list = NULL; -u_long fr_defnatage = 1200, /* 10 minutes (600 seconds) */ - fr_defnaticmpage = 6; /* 3 seconds */ +u_int ipf_nattable_sz = NAT_TABLE_SZ; +u_int ipf_natrules_sz = NAT_SIZE; +u_int ipf_rdrrules_sz = RDR_SIZE; +u_32_t nat_masks = 0; +u_32_t rdr_masks = 0; +ipnat_t **nat_rules = NULL; +ipnat_t **rdr_rules = NULL; + +u_long fr_defnatage = DEF_NAT_AGE, + fr_defnaticmpage = 6; /* 3 seconds */ natstat_t nat_stats; #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) extern kmutex_t ipf_rw; @@ -117,31 +134,87 @@ extern KRWLOCK_T ipf_nat; 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 *)); +static void nat_delrdr __P((struct ipnat *)); +static void nat_delnat __P((struct ipnat *)); + + +int nat_init() +{ + KMALLOCS(nat_table[0], nat_t **, sizeof(nat_t *) * ipf_nattable_sz); + if (nat_table[0] != NULL) + bzero((char *)nat_table[0], ipf_nattable_sz * sizeof(nat_t *)); + else + return -1; + KMALLOCS(nat_table[1], nat_t **, sizeof(nat_t *) * ipf_nattable_sz); + if (nat_table[1] != NULL) + bzero((char *)nat_table[1], ipf_nattable_sz * sizeof(nat_t *)); + else + return -1; -#define LONG_SUM(in) (((in) & 0xffff) + ((in) >> 16)) + KMALLOCS(nat_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_natrules_sz); + if (nat_rules != NULL) + bzero((char *)nat_rules, ipf_natrules_sz * sizeof(ipnat_t *)); + else + return -1; -#define CALC_SUMD(s1, s2, sd) { \ - (s1) = ((s1) & 0xffff) + ((s1) >> 16); \ - (s2) = ((s2) & 0xffff) + ((s2) >> 16); \ - /* Do it twice */ \ - (s1) = ((s1) & 0xffff) + ((s1) >> 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); } + KMALLOCS(rdr_rules, ipnat_t **, sizeof(ipnat_t *) * ipf_rdrrules_sz); + if (rdr_rules != NULL) + bzero((char *)rdr_rules, ipf_rdrrules_sz * sizeof(ipnat_t *)); + else + return -1; + return 0; +} + + +void nat_delrdr(n) +ipnat_t *n; +{ + ipnat_t **n1; + u_32_t iph; + u_int hv; + + iph = n->in_outip & n->in_outmsk; + hv = NAT_HASH_FN(iph, ipf_rdrrules_sz); + for (n1 = &rdr_rules[hv]; *n1 && (*n1 != n); n1 = &(*n1)->in_rnext) + ; + if (*n1) + *n1 = n->in_rnext; +} + + +static void nat_delnat(n) +ipnat_t *n; +{ + ipnat_t **n1; + u_32_t iph; + u_int hv; + + iph = n->in_inip & n->in_inmsk; + hv = NAT_HASH_FN(iph, ipf_natrules_sz); + for (n1 = &nat_rules[hv]; *n1 && (*n1 != n); n1 = &(*n1)->in_mnext) + ; + if (*n1) + *n1 = n->in_mnext; +} -void fix_outcksum(sp, n) + +void fix_outcksum(sp, n , len) u_short *sp; u_32_t n; +int len; { register u_short sumshort; register u_32_t sum1; if (!n) return; +#if SOLARIS2 >= 6 + else if (n & NAT_HW_CKSUM) { + *sp = n & 0xffff; + return; + } +#endif sum1 = (~ntohs(*sp)) & 0xffff; sum1 += (n); sum1 = (sum1 >> 16) + (sum1 & 0xffff); @@ -152,15 +225,22 @@ u_32_t n; } -void fix_incksum(sp, n) +void fix_incksum(sp, n , len) u_short *sp; u_32_t n; +int len; { register u_short sumshort; register u_32_t sum1; if (!n) return; +#if SOLARIS2 >= 6 + else if (n & NAT_HW_CKSUM) { + *sp = n & 0xffff; + return; + } +#endif sum1 = (~ntohs(*sp)) & 0xffff; sum1 += ~(n) & 0xffff; sum1 = (sum1 >> 16) + (sum1 & 0xffff); @@ -205,14 +285,20 @@ caddr_t data; int mode; { register ipnat_t *nat, *nt, *n = NULL, **np = NULL; + int error = 0, ret, k; ipnat_t natd; - int error = 0, ret; + u_32_t i, j; #if defined(_KERNEL) && !SOLARIS int s; #endif +#if (BSD >= 199306) && defined(_KERNEL) + if ((securelevel >= 2) && (mode & FWRITE)) + return EPERM; +#endif + nat = NULL; /* XXX gcc -Wuninitialized */ - KMALLOC(nt, ipnat_t *, sizeof(*nt)); + KMALLOC(nt, ipnat_t *); if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) IRCOPY(data, (char *)&natd, sizeof(natd)); @@ -223,8 +309,12 @@ int mode; WRITE_ENTER(&ipf_nat); if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) { nat = &natd; - nat->in_inip &= nat->in_inmsk; - nat->in_outip &= nat->in_outmsk; + nat->in_flags &= IPN_USERFLAGS; + if ((nat->in_redir & NAT_MAPBLK) == 0) { + nat->in_inip &= nat->in_inmsk; + if ((nat->in_flags & IPN_RANGE) == 0) + 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)) @@ -242,31 +332,82 @@ int mode; error = EEXIST; break; } - n = nt; - nt = NULL; - if (n == NULL) { + if (nt == NULL) { error = ENOMEM; break; } + n = nt; + nt = NULL; bcopy((char *)nat, (char *)n, sizeof(*n)); n->in_ifp = (void *)GETUNIT(n->in_ifname); if (!n->in_ifp) n->in_ifp = (void *)-1; if (n->in_plabel[0] != '\0') { - n->in_apr = ap_match(n->in_p, n->in_plabel); + n->in_apr = appr_match(n->in_p, n->in_plabel); if (!n->in_apr) { error = ENOENT; break; } } - n->in_next = *np; + n->in_next = NULL; + *np = n; + + if (n->in_redir & NAT_REDIRECT) { + u_int hv; + + k = countbits(n->in_outmsk); + if ((k >= 0) && (k != 32)) + rdr_masks |= 1 << k; + j = (n->in_outip & n->in_outmsk); + hv = NAT_HASH_FN(j, ipf_rdrrules_sz); + np = rdr_rules + hv; + while (*np != NULL) + np = &(*np)->in_rnext; + n->in_rnext = NULL; + *np = n; + } + if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { + u_int hv; + + k = countbits(n->in_inmsk); + if ((k >= 0) && (k != 32)) + nat_masks |= 1 << k; + j = (n->in_inip & n->in_inmsk); + hv = NAT_HASH_FN(j, ipf_natrules_sz); + np = nat_rules + hv; + while (*np != NULL) + np = &(*np)->in_mnext; + n->in_mnext = NULL; + *np = n; + } + n->in_use = 0; - n->in_space = ~(0xffffffff & ntohl(n->in_outmsk)); - if (n->in_space) /* lose 2: broadcast + network address */ - n->in_space -= 2; + if (n->in_redir & NAT_MAPBLK) + n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk); + else if (n->in_flags & IPN_AUTOPORTMAP) + n->in_space = USABLE_PORTS * ~ntohl(n->in_inmsk); + else if (n->in_flags & IPN_RANGE) + n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip); else - n->in_space = 1; /* single IP# mapping */ - if ((n->in_outmsk != 0xffffffff) && n->in_outmsk) + n->in_space = ~ntohl(n->in_outmsk); + /* + * Calculate the number of valid IP addresses in the output + * mapping range. In all cases, the range is inclusive of + * the start and ending IP addresses. + * If to a CIDR address, lose 2: broadcast + network address + * (so subtract 1) + * If to a range, add one. + * If to a single IP address, set to 1. + */ + if (n->in_space) { + if ((n->in_flags & IPN_RANGE) != 0) + n->in_space += 1; + else + n->in_space -= 1; + } else + n->in_space = 1; + if ((n->in_outmsk != 0xffffffff) && (n->in_outmsk != 0) && + ((n->in_flags & IPN_RANGE) == 0)) n->in_nip = ntohl(n->in_outip) + 1; else n->in_nip = ntohl(n->in_outip); @@ -275,12 +416,37 @@ int mode; /* * Multiply by the number of ports made available. */ - if (ntohs(n->in_pmax) > ntohs(n->in_pmin)) + if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) { n->in_space *= (ntohs(n->in_pmax) - - ntohs(n->in_pmin)); + ntohs(n->in_pmin) + 1); + /* + * Because two different sources can map to + * different destinations but use the same + * local IP#/port #. + * If the result is smaller than in_space, then + * we may have wrapped around 32bits. + */ + i = n->in_inmsk; + if ((i != 0) && (i != 0xffffffff)) { + j = n->in_space * (~ntohl(i) + 1); + if (j >= n->in_space) + n->in_space = j; + else + n->in_space = 0xffffffff; + } + } + /* + * If no protocol is specified, multiple by 256. + */ + if ((n->in_flags & IPN_TCPUDP) == 0) { + j = n->in_space * 256; + if (j >= n->in_space) + n->in_space = j; + else + n->in_space = 0xffffffff; + } } /* Otherwise, these fields are preset */ - *np = n; n = NULL; nat_stats.ns_rules++; break; @@ -294,10 +460,18 @@ int mode; error = ESRCH; break; } + if (n->in_redir & NAT_REDIRECT) + nat_delrdr(n); + if (n->in_redir & (NAT_MAPBLK|NAT_MAP)) + nat_delnat(n); + if (nat_list == NULL) { + nat_masks = 0; + rdr_masks = 0; + } *np = n->in_next; if (!n->in_use) { if (n->in_apr) - ap_free(n->in_apr); + appr_free(n->in_apr); KFREE(n); nat_stats.ns_rules--; } else { @@ -311,6 +485,10 @@ int mode; nat_stats.ns_table[0] = nat_table[0]; nat_stats.ns_table[1] = nat_table[1]; nat_stats.ns_list = nat_list; + nat_stats.ns_nattab_sz = ipf_nattable_sz; + nat_stats.ns_rultab_sz = ipf_natrules_sz; + nat_stats.ns_rdrtab_sz = ipf_rdrrules_sz; + nat_stats.ns_instances = nat_instances; nat_stats.ns_apslist = ap_sess_list; IWCOPY((char *)&nat_stats, (char *)data, sizeof(nat_stats)); break; @@ -387,17 +565,21 @@ struct nat *natd; break; } + if (natd->nat_fr != NULL) { + ATOMIC_DEC(natd->nat_fr->fr_ref); + } /* * 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 = natd->nat_ptr; + if (ipn != NULL) { ipn->in_space++; ipn->in_use--; if (!ipn->in_use && (ipn->in_flags & IPN_DELETE)) { if (ipn->in_apr) - ap_free(ipn->in_apr); + appr_free(ipn->in_apr); KFREE(ipn); nat_stats.ns_rules--; } @@ -423,7 +605,7 @@ nat_ifdetach(ifp) *np = n->in_next; if (!n->in_use) { if (n->in_apr) - ap_free(n->in_apr); + appr_free(n->in_apr); KFREE(n); nat_stats.ns_rules--; } else { @@ -434,6 +616,7 @@ nat_ifdetach(ifp) } } + /* * nat_flushtable - clear the NAT table of all mapping entries. */ @@ -441,13 +624,17 @@ static int nat_flushtable() { register nat_t *nat, **natp; register int j = 0; - + /* - * ALL NAT mappings deleted, so lets just make it the deletions + * ALL NAT mappings deleted, so lets just make the deletions * quicker. */ - bzero((char *)nat_table[0], sizeof(nat_table[0])); - bzero((char *)nat_table[1], sizeof(nat_table[1])); + if (nat_table[0] != NULL) + bzero((char *)nat_table[0], + sizeof(nat_table[0]) * ipf_nattable_sz); + if (nat_table[1] != NULL) + bzero((char *)nat_table[1], + sizeof(nat_table[1]) * ipf_nattable_sz); for (natp = &nat_instances; (nat = *natp); ) { *natp = nat->nat_next; @@ -467,11 +654,16 @@ static int nat_clearlist() register ipnat_t *n, **np = &nat_list; int i = 0; + if (nat_rules != NULL) + bzero((char *)nat_rules, sizeof(*nat_rules) * ipf_natrules_sz); + if (rdr_rules != NULL) + bzero((char *)rdr_rules, sizeof(*rdr_rules) * ipf_rdrrules_sz); + while ((n = *np)) { *np = n->in_next; if (!n->in_use) { if (n->in_apr) - ap_free(n->in_apr); + appr_free(n->in_apr); KFREE(n); nat_stats.ns_rules--; } else { @@ -480,78 +672,13 @@ static int nat_clearlist() } i++; } + nat_masks = 0; + rdr_masks = 0; return i; } /* - * 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 = ntohl(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) - 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. * NOTE: assumes write lock on ipf_nat has been obtained already. */ @@ -559,15 +686,19 @@ nat_t *nat_new(np, ip, fin, flags, direction) ipnat_t *np; ip_t *ip; fr_info_t *fin; -u_short flags; +u_int flags; int direction; { register u_32_t sum1, sum2, sumd, l; u_short port = 0, sport = 0, dport = 0, nport = 0; - struct in_addr in; + nat_t *nat, **natp, *natl = NULL; + struct in_addr in, inb; tcphdr_t *tcp = NULL; - nat_t *nat, **natp; u_short nflags; + u_int hv; +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) + qif_t *qf = fin->fin_qif; +#endif nflags = flags & np->in_flags; if (flags & IPN_TCPUDP) { @@ -577,20 +708,19 @@ int direction; } /* Give me a new nat */ - KMALLOC(nat, nat_t *, sizeof(*nat)); + KMALLOC(nat, nat_t *); if (nat == NULL) return NULL; bzero((char *)nat, sizeof(*nat)); nat->nat_flags = flags; - /* * Search the current table for a match. */ if (direction == NAT_OUTBOUND) { /* - * Values at which the search for a free resouce starts. - */ + * Values at which the search for a free resouce starts. + */ u_32_t st_ip; u_short st_port; @@ -603,66 +733,153 @@ int direction; st_port = np->in_pnext; do { - l++; port = 0; in.s_addr = np->in_nip; + if (l == 0) { + natl = nat_maplookup(fin->fin_ifp, flags, + ip->ip_src, ip->ip_dst); + if (natl != NULL) { + in = natl->nat_outip; +#ifndef sparc + in.s_addr = ntohl(in.s_addr); +#endif + } + } + if ((np->in_outmsk == 0xffffffff) && (np->in_pnext == 0)) { - if (l > 1) { + if (l > 0) { KFREE(nat); return NULL; } } - if (!in.s_addr && (np->in_outmsk == 0xffffffff)) { - if ((l > 1) || - nat_ifpaddr(nat, fin->fin_ifp, &in) == -1) { + if (np->in_redir & NAT_MAPBLK) { + if ((l >= np->in_ppip) || ((l > 0) && + !(flags & IPN_TCPUDP))) { + KFREE(nat); + return NULL; + } + /* + * map-block - Calculate destination address. + */ + in.s_addr = ntohl(ip->ip_src.s_addr); + in.s_addr &= ntohl(~np->in_inmsk); + inb.s_addr = in.s_addr; + in.s_addr /= np->in_ippip; + in.s_addr &= ntohl(~np->in_outmsk); + in.s_addr += ntohl(np->in_outip); + /* + * Calculate destination port. + */ + if ((flags & IPN_TCPUDP) && + (np->in_ppip != 0)) { + port = ntohs(sport) + l; + port %= np->in_ppip; + port += np->in_ppip * + (inb.s_addr % np->in_ippip); + port += MAPBLK_MINPORT; + port = htons(port); + } + } else if (!in.s_addr && + (np->in_outmsk == 0xffffffff)) { + /* + * 0/32 - use the interface's IP address. + */ + if ((l > 0) || + fr_ifpaddr(fin->fin_ifp, &in) == -1) { KFREE(nat); return NULL; } } else if (!in.s_addr && !np->in_outmsk) { - if (l > 1) { + /* + * 0/0 - use the original source address/port. + */ + if (l > 0) { KFREE(nat); return NULL; } in.s_addr = ntohl(ip->ip_src.s_addr); - } else if ((nflags & IPN_TCPUDP)) { + } else if ((np->in_outmsk != 0xffffffff) && + (np->in_pnext == 0) && + ((l > 0) || (natl == NULL))) + np->in_nip++; + natl = NULL; + + if ((nflags & IPN_TCPUDP) && + ((np->in_redir & NAT_MAPBLK) == 0) && + (np->in_flags & IPN_AUTOPORTMAP)) { + if ((l > 0) && (l % np->in_ppip == 0)) { + if (l > np->in_space) { + KFREE(nat); + return NULL; + } else if ((l > np->in_ppip) && + np->in_outmsk != 0xffffffff) + np->in_nip++; + } + if (np->in_ppip != 0) { + port = ntohs(sport); + port += (l % np->in_ppip); + port %= np->in_ppip; + port += np->in_ppip * + (ntohl(ip->ip_src.s_addr) % + np->in_ippip); + port += MAPBLK_MINPORT; + port = htons(port); + } + } else if (((np->in_redir & NAT_MAPBLK) == 0) && + (nflags & IPN_TCPUDP) && + (np->in_pnext != 0)) { port = htons(np->in_pnext++); - if (np->in_pnext >= ntohs(np->in_pmax)) { + if (np->in_pnext > ntohs(np->in_pmax)) { np->in_pnext = ntohs(np->in_pmin); if (np->in_outmsk != 0xffffffff) np->in_nip++; } - } else if (np->in_outmsk != 0xffffffff) - np->in_nip++; + } - if (!np->in_nip && (nflags & IPN_TCPUDP) && - (np->in_pnext != 0)) { - port = htons(np->in_pnext++); - if (np->in_pnext >= ntohs(np->in_pmax)) - np->in_pnext = ntohs(np->in_pmin); + if (np->in_flags & IPN_RANGE) { + if (np->in_nip >= ntohl(np->in_outmsk)) + np->in_nip = ntohl(np->in_outip); + } else { + if ((np->in_outmsk != 0xffffffff) && + ((np->in_nip + 1) & ntohl(np->in_outmsk)) > + ntohl(np->in_outip)) + np->in_nip = ntohl(np->in_outip) + 1; } if (!port && (flags & IPN_TCPUDP)) port = sport; - if ((np->in_nip & ntohl(np->in_outmsk)) > - ntohl(np->in_outip)) - np->in_nip = ntohl(np->in_outip) + 1; /* - * Has the search wrapped around and come back to the - * start ? - */ - if ((np->in_pnext != 0) && (st_port == np->in_pnext) && + * Here we do a lookup of the connection as seen from + * the outside. If an IP# pair already exists, try + * again. So if you have A->B becomes C->B, you can + * also have D->E become C->E but not D->B causing + * another C->B. Also take protocol and ports into + * account when determining whether a pre-existing + * NAT setup will cause an external conflict where + * this is appropriate. + */ + inb.s_addr = htonl(in.s_addr); + natl = nat_inlookup(fin->fin_ifp, flags & ~FI_WILD, + (u_int)ip->ip_p, ip->ip_dst, inb, + (port << 16) | dport); + + /* + * Has the search wrapped around and come back to the + * start ? + */ + if ((natl != NULL) && + (np->in_pnext != 0) && (st_port == np->in_pnext) && (np->in_nip != 0) && (st_ip == np->in_nip)) { KFREE(nat); return NULL; } + l++; + } while (natl != NULL); - } while (nat_inlookup(fin->fin_ifp, flags, ip->ip_dst, - dport, in, port)); - - if (np->in_space > 1) + if (np->in_space > 0) np->in_space--; /* Setup the NAT table */ @@ -670,18 +887,15 @@ int direction; nat->nat_outip.s_addr = htonl(in.s_addr); nat->nat_oip = ip->ip_dst; - sum1 = (ntohl(ip->ip_src.s_addr) & 0xffff) + - (ntohl(ip->ip_src.s_addr) >> 16) + ntohs(sport); - - sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16) + ntohs(port); + sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr)) + ntohs(sport); + sum2 = LONG_SUM(in.s_addr) + ntohs(port); if (flags & IPN_TCPUDP) { nat->nat_inport = sport; - nat->nat_outport = port; + nat->nat_outport = port; /* sport */ nat->nat_oport = dport; } } else { - /* * Otherwise, it's an inbound packet. Most likely, we don't * want to rewrite source ports and source addresses. Instead, @@ -692,14 +906,22 @@ int direction; if (!(nport = np->in_pnext)) nport = dport; + /* + * When the redirect-to address is set to 0.0.0.0, just + * assume a blank `forwarding' of the packet. We don't + * setup any translation for this either. + */ + if ((in.s_addr == 0) && (nport == dport)) { + KFREE(nat); + return NULL; + } + nat->nat_inip.s_addr = htonl(in.s_addr); nat->nat_outip = ip->ip_dst; nat->nat_oip = ip->ip_src; - sum1 = (ntohl(ip->ip_dst.s_addr) & 0xffff) + - (ntohl(ip->ip_dst.s_addr) >> 16) + ntohs(dport); - - sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16) + ntohs(nport); + sum1 = LONG_SUM(ntohl(ip->ip_dst.s_addr)) + ntohs(dport); + sum2 = LONG_SUM(in.s_addr) + ntohs(nport); if (flags & IPN_TCPUDP) { nat->nat_inport = nport; @@ -708,59 +930,60 @@ int direction; } } - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - /* Do it twice */ - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - - if (sum1 > sum2) - sum2--; /* Because ~1 == -2, We really need ~1 == -1 */ - sumd = sum2 - sum1; - sumd = (sumd & 0xffff) + (sumd >> 16); - nat->nat_sumd = (sumd & 0xffff) + (sumd >> 16); + CALC_SUMD(sum1, sum2, sumd); + nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) + if ((flags == IPN_TCP) && dohwcksum && + (qf->qf_ill->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) { + if (direction == NAT_OUTBOUND) + sum1 = LONG_SUM(ntohl(in.s_addr)); + else + sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr)); + sum1 += LONG_SUM(ntohl(ip->ip_dst.s_addr)); + sum1 += 30; + sum1 = (sum1 & 0xffff) + (sum1 >> 16); + nat->nat_sumd[1] = NAT_HW_CKSUM|(sum1 & 0xffff); + } else +#endif + nat->nat_sumd[1] = nat->nat_sumd[0]; if ((flags & IPN_TCPUDP) && ((sport != port) || (dport != nport))) { if (direction == NAT_OUTBOUND) - sum1 = (ntohl(ip->ip_src.s_addr) & 0xffff) + - (ntohl(ip->ip_src.s_addr) >> 16); + sum1 = LONG_SUM(ntohl(ip->ip_src.s_addr)); else - sum1 = (ntohl(ip->ip_dst.s_addr) & 0xffff) + - (ntohl(ip->ip_dst.s_addr) >> 16); + sum1 = LONG_SUM(ntohl(ip->ip_dst.s_addr)); - sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16); - - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - /* Do it twice */ - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - sum2 = (sum2 & 0xffff) + (sum2 >> 16); + sum2 = LONG_SUM(in.s_addr); - if (sum1 > sum2) - sum2--; /* Because ~1 == -2, We really need ~1 == -1 */ - sumd = sum2 - sum1; - sumd = (sumd & 0xffff) + (sumd >> 16); + CALC_SUMD(sum1, sum2, sumd); nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); } else - nat->nat_ipsumd = nat->nat_sumd; + nat->nat_ipsumd = nat->nat_sumd[0]; in.s_addr = htonl(in.s_addr); nat->nat_next = nat_instances; nat_instances = nat; - natp = &nat_table[0][nat->nat_inip.s_addr % NAT_SIZE]; + hv = NAT_HASH_FN(nat->nat_inip.s_addr, ipf_nattable_sz); + natp = &nat_table[0][hv]; nat->nat_hstart[0] = natp; nat->nat_hnext[0] = *natp; *natp = nat; - natp = &nat_table[1][nat->nat_outip.s_addr % NAT_SIZE]; + hv = NAT_HASH_FN(nat->nat_outip.s_addr, ipf_nattable_sz); + natp = &nat_table[1][hv]; nat->nat_hstart[1] = natp; nat->nat_hnext[1] = *natp; *natp = nat; + nat->nat_dir = direction; + nat->nat_ifp = fin->fin_ifp; nat->nat_ptr = np; + nat->nat_p = ip->ip_p; nat->nat_bytes = 0; nat->nat_pkts = 0; - nat->nat_ifp = fin->fin_ifp; - nat->nat_dir = direction; nat->nat_age = fr_defnatage; + nat->nat_fr = fin->fin_fr; + if (nat->nat_fr != NULL) { + ATOMIC_INC(nat->nat_fr->fr_ref); + } if (direction == NAT_OUTBOUND) { if (flags & IPN_TCPUDP) tcp->th_sport = port; @@ -810,10 +1033,12 @@ fr_info_t *fin; 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, flags, (u_int)oip->ip_p, + oip->ip_dst, oip->ip_src, + (tcp->th_sport << 16) | tcp->th_dport); } - return nat_inlookup(fin->fin_ifp, 0, oip->ip_dst, 0, oip->ip_src, 0); + return nat_inlookup(fin->fin_ifp, 0, (u_int)oip->ip_p, oip->ip_dst, + oip->ip_src, 0); } @@ -824,7 +1049,7 @@ fr_info_t *fin; nat_t *nat_icmpin(ip, fin, nflags) ip_t *ip; fr_info_t *fin; -int *nflags; +u_int *nflags; { u_32_t sum1, sum2, sumd; struct in_addr in; @@ -866,24 +1091,24 @@ int *nflags; CALC_SUMD(sum1, sum2, sumd); if (nat->nat_dir == NAT_OUTBOUND) { - fix_incksum(&oip->ip_sum, sumd); + fix_incksum(&oip->ip_sum, sumd, 0); sumd += (sumd & 0xffff); while (sumd > 0xffff) sumd = (sumd & 0xffff) + (sumd >> 16); - fix_outcksum(&icmp->icmp_cksum, sumd); + fix_outcksum(&icmp->icmp_cksum, sumd, 0); } else { - fix_outcksum(&oip->ip_sum, sumd); + fix_outcksum(&oip->ip_sum, sumd, 0); - sumd += (sumd & 0xffff); - while (sumd > 0xffff) - sumd = (sumd & 0xffff) + (sumd >> 16); - fix_incksum(&icmp->icmp_cksum, sumd); + sumd += (sumd & 0xffff); + while (sumd > 0xffff) + sumd = (sumd & 0xffff) + (sumd >> 16); + fix_incksum(&icmp->icmp_cksum, sumd, 0); } - - + + if ((flags & IPN_TCPUDP) != 0) { - tcphdr_t *tcp; + tcphdr_t *tcp; /* XXX - what if this is bogus hl and we go off the end ? */ tcp = (tcphdr_t *)((((char *)oip) + (oip->ip_hl << 2))); @@ -894,7 +1119,7 @@ int *nflags; sum2 = ntohs(nat->nat_inport); CALC_SUMD(sum1, sum2, sumd); tcp->th_sport = nat->nat_inport; - fix_outcksum(&icmp->icmp_cksum, sumd); + fix_outcksum(&icmp->icmp_cksum, sumd, 0); } } else { if (tcp->th_dport != nat->nat_outport) { @@ -902,11 +1127,10 @@ int *nflags; sum2 = ntohs(nat->nat_outport); CALC_SUMD(sum1, sum2, sumd); tcp->th_dport = nat->nat_outport; - fix_incksum(&icmp->icmp_cksum, sumd); + fix_incksum(&icmp->icmp_cksum, sumd, 0); } } } - nat->nat_age = fr_defnaticmpage; return nat; } @@ -922,29 +1146,35 @@ int *nflags; * 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) +nat_t *nat_inlookup(ifp, flags, p, src, mapdst, ports) void *ifp; -register int flags; +register u_int flags, p; struct in_addr src , mapdst; -u_short sport, mapdport; -#endif +u_32_t ports; { + register u_short sport, mapdport; register nat_t *nat; + register int nflags; + u_int hv; + mapdport = ports >> 16; + sport = ports & 0xffff; flags &= IPN_TCPUDP; - nat = nat_table[1][mapdst.s_addr % NAT_SIZE]; - for (; nat; nat = nat->nat_hnext[1]) + hv = NAT_HASH_FN(mapdst.s_addr, ipf_nattable_sz); + nat = nat_table[1][hv]; + for (; nat; nat = nat->nat_hnext[1]) { + nflags = nat->nat_flags; if ((!ifp || ifp == nat->nat_ifp) && nat->nat_oip.s_addr == src.s_addr && nat->nat_outip.s_addr == mapdst.s_addr && - flags == nat->nat_flags && (!flags || - (nat->nat_oport == sport && - nat->nat_outport == mapdport))) + (((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP))) + || (p == nat->nat_p)) && (!flags || + (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) && + ((nat->nat_outport == mapdport) || + (nflags & FI_W_SPORT))))) return nat; + } return NULL; } @@ -955,27 +1185,33 @@ 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) +nat_t *nat_outlookup(ifp, flags, p, src, dst, ports) void *ifp; -register int flags; +register u_int flags, p; struct in_addr src , dst; -u_short sport, dport; -#endif +u_32_t ports; { + register u_short sport, dport; register nat_t *nat; + register int nflags; + u_int hv; + sport = ports & 0xffff; + dport = ports >> 16; flags &= IPN_TCPUDP; - nat = nat_table[0][src.s_addr % NAT_SIZE]; + hv = NAT_HASH_FN(src.s_addr, ipf_nattable_sz); + nat = nat_table[0][hv]; for (; nat; nat = nat->nat_hnext[0]) { + nflags = nat->nat_flags; + 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))) + (((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP))) + || (p == nat->nat_p)) && (!flags || + ((nat->nat_inport == sport || nflags & FI_W_SPORT) && + (nat->nat_oport == dport || nflags & FI_W_DPORT)))) return nat; } return NULL; @@ -983,33 +1219,30 @@ u_short sport, dport; /* - * Lookup a nat entry based on the mapped source ip address/port and - * 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. + * check if an ip address has already been allocated for a given mapping that + * is not doing port based translation. */ -#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) +nat_t *nat_maplookup(ifp, flags, src, dst) void *ifp; -register int flags; -struct in_addr mapsrc , dst; -u_short mapsport, dport; -#endif +register u_int flags; +struct in_addr src , dst; { register nat_t *nat; + register int oflags; + u_int hv; - flags &= IPN_TCPUDP; + hv = NAT_HASH_FN(src.s_addr, ipf_nattable_sz); + nat = nat_table[0][hv]; + for (; nat; nat = nat->nat_hnext[0]) { + oflags = (flags & IPN_TCPUDP) & nat->nat_ptr->in_flags; + if (oflags != 0) + continue; - nat = nat_table[1][mapsrc.s_addr % NAT_SIZE]; - for (; nat; nat = nat->nat_hnext[0]) if ((!ifp || ifp == nat->nat_ifp) && - nat->nat_oip.s_addr == dst.s_addr && - nat->nat_outip.s_addr == mapsrc.s_addr && - flags == nat->nat_flags && (!flags || - (nat->nat_outport == mapsport && - nat->nat_oport == dport))) + nat->nat_inip.s_addr == src.s_addr && + nat->nat_oip.s_addr == dst.s_addr) return nat; + } return NULL; } @@ -1020,15 +1253,16 @@ u_short mapsport, dport; nat_t *nat_lookupredir(np) register natlookup_t *np; { + u_32_t ports; nat_t *nat; + ports = (np->nl_outport << 16) | np->nl_inport; /* * 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, np->nl_flags, np->nl_inip, - np->nl_inport, np->nl_outip, - np->nl_outport))) { + if ((nat = nat_outlookup(NULL, np->nl_flags, 0, np->nl_inip, + np->nl_outip, ports))) { np->nl_realip = nat->nat_outip; np->nl_realport = nat->nat_outport; } @@ -1040,19 +1274,24 @@ register natlookup_t *np; * Packets going out on the external interface go through this. * Here, the source address requires alteration, if anything. */ -int ip_natout(ip, hlen, fin) +int ip_natout(ip, fin) ip_t *ip; -int hlen; fr_info_t *fin; { - register ipnat_t *np; + register ipnat_t *np = NULL; register u_32_t ipa; tcphdr_t *tcp = NULL; u_short nflags = 0, sport = 0, dport = 0, *csump = NULL; struct ifnet *ifp; + int natadd = 1; frentry_t *fr; + u_int hv, msk; + u_32_t iph; nat_t *nat; - int natadd = 1; + int i; + + if (nat_list == NULL) + return 0; if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) && fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1) @@ -1078,23 +1317,42 @@ fr_info_t *fin; 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))) - ; - else { + else if ((nat = nat_outlookup(ifp, nflags, (u_int)ip->ip_p, ip->ip_src, + ip->ip_dst, (dport << 16) | sport))) { + nflags = nat->nat_flags; + if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) { + if ((nflags & FI_W_SPORT) && + (nat->nat_inport != sport)) + nat->nat_inport = sport; + else if ((nflags & FI_W_DPORT) && + (nat->nat_oport != dport)) + nat->nat_oport = dport; + if (nat->nat_outport == 0) + nat->nat_outport = sport; + nat->nat_flags &= ~(FI_W_DPORT|FI_W_SPORT); + nflags = nat->nat_flags; + } + } else { RWLOCK_EXIT(&ipf_nat); WRITE_ENTER(&ipf_nat); /* * If there is no current entry in the nat table for this IP#, * create one for it (if there is a matching rule). */ - for (np = nat_list; np; np = np->in_next) + msk = 0xffffffff; + i = 32; +maskloop: + iph = ipa & htonl(msk); + hv = NAT_HASH_FN(iph, ipf_natrules_sz); + for (np = nat_rules[hv]; np; np = np->in_mnext) + { if ((np->in_ifp == ifp) && np->in_space && - (!np->in_flags || (np->in_flags & nflags)) && + (!(np->in_flags & IPN_RF) || + (np->in_flags & nflags)) && ((ipa & np->in_inmsk) == np->in_inip) && - ((np->in_redir & NAT_MAP) || + ((np->in_redir & (NAT_MAP|NAT_MAPBLK)) || (np->in_pnext == sport))) { - if (*np->in_plabel && !ap_ok(ip, tcp, np)) + if (*np->in_plabel && !appr_ok(ip, tcp, np)) continue; /* * If it's a redirection, then we don't want to @@ -1102,84 +1360,101 @@ fr_info_t *fin; * Redirections are only for incoming * connections. */ - if (!(np->in_redir & NAT_MAP)) + if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK))) continue; - if ((nat = nat_new(np, ip, fin, nflags, - NAT_OUTBOUND))) + if ((nat = nat_new(np, ip, fin, (u_int)nflags, + NAT_OUTBOUND))) { + np->in_hits++; #ifdef IPFILTER_LOG - nat_log(nat, (u_short)np->in_redir); -#else - ; + nat_log(nat, (u_int)np->in_redir); #endif - break; + break; + } } + } + if ((np == NULL) && (i > 0)) { + do { + i--; + msk <<= 1; + } while ((i >= 0) && ((nat_masks & (1 << i)) == 0)); + if (i >= 0) + goto maskloop; + } MUTEX_DOWNGRADE(&ipf_nat); } if (nat) { - if (natadd && fin->fin_fi.fi_fl & FI_FRAG) - ipfr_nat_newfrag(ip, fin, 0, nat); - ip->ip_src = nat->nat_outip; - MUTEX_ENTER(&ipf_rw); - nat->nat_age = fr_defnatage; - nat->nat_bytes += ip->ip_len; - nat->nat_pkts++; - MUTEX_EXIT(&ipf_rw); + np = nat->nat_ptr; + if (natadd && fin->fin_fi.fi_fl & FI_FRAG) + ipfr_nat_newfrag(ip, fin, 0, nat); + ip->ip_src = nat->nat_outip; + MUTEX_ENTER(&ipf_rw); + nat->nat_age = fr_defnatage; + nat->nat_bytes += ip->ip_len; + nat->nat_pkts++; + MUTEX_EXIT(&ipf_rw); - /* - * Fix up checksums, not by recalculating them, but - * simply computing adjustments. - */ + /* + * Fix up checksums, not by recalculating them, but + * simply computing adjustments. + */ #if SOLARIS || defined(__sgi) - if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(&ip->ip_sum, nat->nat_ipsumd); - else - fix_incksum(&ip->ip_sum, nat->nat_ipsumd); + if (nat->nat_dir == NAT_OUTBOUND) + fix_outcksum(&ip->ip_sum, nat->nat_ipsumd, 0); + else + fix_incksum(&ip->ip_sum, nat->nat_ipsumd, 0); #endif - if (!(ip->ip_off & IP_OFFMASK) && - !(fin->fin_fi.fi_fl & FI_SHORT)) { + if (!(ip->ip_off & IP_OFFMASK) && + !(fin->fin_fi.fi_fl & FI_SHORT)) { - if ((nat->nat_outport != 0) && - (nflags & IPN_TCPUDP)) { - tcp->th_sport = nat->nat_outport; - fin->fin_data[0] = ntohs(tcp->th_sport); - } + if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) { + tcp->th_sport = nat->nat_outport; + fin->fin_data[0] = ntohs(tcp->th_sport); + } - if (ip->ip_p == IPPROTO_TCP) { - csump = &tcp->th_sum; - MUTEX_ENTER(&ipf_rw); - fr_tcp_age(&nat->nat_age, - nat->nat_state, ip, fin,1); - /* - * Increase this because we may have - * "keep state" following this too and - * packet storms can occur if this is - * removed too quickly. - */ - if (nat->nat_age == fr_tcpclosed) - nat->nat_age = fr_tcplastack; - MUTEX_EXIT(&ipf_rw); - } else if (ip->ip_p == IPPROTO_UDP) { - udphdr_t *udp = (udphdr_t *)tcp; - - if (udp->uh_sum) - csump = &udp->uh_sum; - } - if (csump) { - if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(csump, - nat->nat_sumd); - else - fix_incksum(csump, - nat->nat_sumd); - } + if (ip->ip_p == IPPROTO_TCP) { + csump = &tcp->th_sum; + MUTEX_ENTER(&ipf_rw); + fr_tcp_age(&nat->nat_age, + nat->nat_tcpstate, ip, fin, 1); + if (nat->nat_age < fr_defnaticmpage) + nat->nat_age = fr_defnaticmpage; +#ifdef LARGE_NAT + else if (nat->nat_age > DEF_NAT_AGE) + nat->nat_age = DEF_NAT_AGE; +#endif + /* + * Increase this because we may have + * "keep state" following this too and + * packet storms can occur if this is + * removed too quickly. + */ + if (nat->nat_age == fr_tcpclosed) + nat->nat_age = fr_tcplastack; + MUTEX_EXIT(&ipf_rw); + } else if (ip->ip_p == IPPROTO_UDP) { + udphdr_t *udp = (udphdr_t *)tcp; + + if (udp->uh_sum) + csump = &udp->uh_sum; + } + if (csump) { + if (nat->nat_dir == NAT_OUTBOUND) + fix_outcksum(csump, nat->nat_sumd[1], + ip->ip_len); + else + fix_incksum(csump, nat->nat_sumd[1], + ip->ip_len); } - (void) ap_check(ip, fin, nat); - ATOMIC_INC(nat_stats.ns_mapped[1]); - RWLOCK_EXIT(&ipf_nat); /* READ */ - return -2; } + if ((np->in_apr != NULL) && (np->in_dport == 0 || + (tcp != NULL && dport == np->in_dport))) + (void) appr_check(ip, fin, nat); + ATOMIC_INC(nat_stats.ns_mapped[1]); + RWLOCK_EXIT(&ipf_nat); /* READ */ + return 1; + } RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ return 0; } @@ -1189,18 +1464,23 @@ fr_info_t *fin; * Packets coming in from the external interface go through this. * Here, the destination address requires alteration, if anything. */ -int ip_natin(ip, hlen, fin) +int ip_natin(ip, fin) ip_t *ip; -int hlen; fr_info_t *fin; { - register ipnat_t *np; + register struct in_addr src; register struct in_addr in; + register ipnat_t *np; + u_int nflags = 0, natadd = 1, hv, msk; struct ifnet *ifp = fin->fin_ifp; tcphdr_t *tcp = NULL; u_short sport = 0, dport = 0, *csump = NULL; nat_t *nat; - int nflags = 0, natadd = 1; + u_32_t iph; + int i; + + if (nat_list == NULL) + return 0; if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) { if (ip->ip_p == IPPROTO_TCP) @@ -1215,6 +1495,8 @@ fr_info_t *fin; } in = ip->ip_dst; + /* make sure the source address is to be redirected */ + src = ip->ip_src; READ_ENTER(&ipf_nat); @@ -1223,100 +1505,131 @@ fr_info_t *fin; 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))) - ; - else { + else if ((nat = nat_inlookup(fin->fin_ifp, nflags, (u_int)ip->ip_p, + ip->ip_src, in, (dport << 16) | sport))) { + nflags = nat->nat_flags; + if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) { + if ((nat->nat_oport != sport) && (nflags & FI_W_DPORT)) + nat->nat_oport = sport; + else if ((nat->nat_outport != dport) && + (nflags & FI_W_SPORT)) + nat->nat_outport = dport; + nat->nat_flags &= ~(FI_W_SPORT|FI_W_DPORT); + nflags = nat->nat_flags; + } + } else { RWLOCK_EXIT(&ipf_nat); WRITE_ENTER(&ipf_nat); /* * If there is no current entry in the nat table for this IP#, * create one for it (if there is a matching rule). */ - for (np = nat_list; np; np = np->in_next) + msk = 0xffffffff; + i = 32; +maskloop: + iph = in.s_addr & htonl(msk); + hv = NAT_HASH_FN(iph, ipf_rdrrules_sz); + for (np = rdr_rules[hv]; np; np = np->in_rnext) if ((np->in_ifp == ifp) && (!np->in_flags || (nflags & np->in_flags)) && ((in.s_addr & np->in_outmsk) == np->in_outip) && + ((src.s_addr & np->in_srcmsk) == np->in_srcip) && (np->in_redir & NAT_REDIRECT) && - (!np->in_pmin || np->in_pmin == dport)) { + (!np->in_pmin || np->in_pmin == dport) && + (!np->in_p || np->in_p == ip->ip_p)) { if ((nat = nat_new(np, ip, fin, nflags, - NAT_INBOUND))) + NAT_INBOUND))) { + np->in_hits++; #ifdef IPFILTER_LOG - nat_log(nat, (u_short)np->in_redir); -#else - ; + nat_log(nat, (u_int)np->in_redir); #endif - break; + break; + } } + if ((np == NULL) && (i > 0)) { + do { + i--; + msk <<= 1; + } while ((i >= 0) && ((rdr_masks & (1 << i)) == 0)); + if (i >= 0) + goto maskloop; + } MUTEX_DOWNGRADE(&ipf_nat); } if (nat) { - if (natadd && fin->fin_fi.fi_fl & FI_FRAG) - ipfr_nat_newfrag(ip, fin, 0, nat); - (void) ap_check(ip, fin, nat); - - MUTEX_ENTER(&ipf_rw); - if (nflags != IPN_ICMPERR) - nat->nat_age = fr_defnatage; + np = nat->nat_ptr; + fin->fin_fr = nat->nat_fr; + if (natadd && fin->fin_fi.fi_fl & FI_FRAG) + ipfr_nat_newfrag(ip, fin, 0, nat); + if ((np->in_apr != NULL) && (np->in_dport == 0 || + (tcp != NULL && sport == np->in_dport))) + (void) appr_check(ip, fin, nat); + + MUTEX_ENTER(&ipf_rw); + if (nflags != IPN_ICMPERR) + nat->nat_age = fr_defnatage; - nat->nat_bytes += ip->ip_len; - nat->nat_pkts++; - MUTEX_EXIT(&ipf_rw); - ip->ip_dst = nat->nat_inip; - fin->fin_fi.fi_dst = nat->nat_inip; + nat->nat_bytes += ip->ip_len; + nat->nat_pkts++; + MUTEX_EXIT(&ipf_rw); + ip->ip_dst = nat->nat_inip; + fin->fin_fi.fi_dst = nat->nat_inip; - /* - * Fix up checksums, not by recalculating them, but - * simply computing adjustments. - */ + /* + * Fix up checksums, not by recalculating them, but + * simply computing adjustments. + */ #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); + if (nat->nat_dir == NAT_OUTBOUND) + fix_incksum(&ip->ip_sum, nat->nat_ipsumd, 0); + else + fix_outcksum(&ip->ip_sum, nat->nat_ipsumd, 0); #endif - if (!(ip->ip_off & IP_OFFMASK) && - !(fin->fin_fi.fi_fl & FI_SHORT)) { + if (!(ip->ip_off & IP_OFFMASK) && + !(fin->fin_fi.fi_fl & FI_SHORT)) { - if ((nat->nat_inport != 0) && - (nflags & IPN_TCPUDP)) { - tcp->th_dport = nat->nat_inport; - fin->fin_data[1] = ntohs(tcp->th_dport); - } + if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) { + tcp->th_dport = nat->nat_inport; + fin->fin_data[1] = ntohs(tcp->th_dport); + } - if (ip->ip_p == IPPROTO_TCP) { - csump = &tcp->th_sum; - MUTEX_ENTER(&ipf_rw); - fr_tcp_age(&nat->nat_age, - nat->nat_state, ip, fin,0); - /* - * Increase this because we may have - * "keep state" following this too and - * packet storms can occur if this is - * removed too quickly. - */ - if (nat->nat_age == fr_tcpclosed) - nat->nat_age = fr_tcplastack; - MUTEX_EXIT(&ipf_rw); - } else if (ip->ip_p == IPPROTO_UDP) { - udphdr_t *udp = (udphdr_t *)tcp; - - if (udp->uh_sum) - csump = &udp->uh_sum; - } - if (csump) { - if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(csump, - nat->nat_sumd); - else - fix_outcksum(csump, - nat->nat_sumd); - } + if (ip->ip_p == IPPROTO_TCP) { + csump = &tcp->th_sum; + MUTEX_ENTER(&ipf_rw); + fr_tcp_age(&nat->nat_age, + nat->nat_tcpstate, ip, fin, 0); + if (nat->nat_age < fr_defnaticmpage) + nat->nat_age = fr_defnaticmpage; +#ifdef LARGE_NAT + else if (nat->nat_age > DEF_NAT_AGE) + nat->nat_age = DEF_NAT_AGE; +#endif + /* + * Increase this because we may have + * "keep state" following this too and + * packet storms can occur if this is + * removed too quickly. + */ + if (nat->nat_age == fr_tcpclosed) + nat->nat_age = fr_tcplastack; + MUTEX_EXIT(&ipf_rw); + } else if (ip->ip_p == IPPROTO_UDP) { + udphdr_t *udp = (udphdr_t *)tcp; + + if (udp->uh_sum) + csump = &udp->uh_sum; + } + if (csump) { + if (nat->nat_dir == NAT_OUTBOUND) + fix_incksum(csump, nat->nat_sumd[0], 0); + else + fix_outcksum(csump, nat->nat_sumd[0], 0); } - ATOMIC_INC(nat_stats.ns_mapped[0]); - RWLOCK_EXIT(&ipf_nat); /* READ */ - return -2; } + ATOMIC_INC(nat_stats.ns_mapped[0]); + RWLOCK_EXIT(&ipf_nat); /* READ */ + return 1; + } RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ return 0; } @@ -1331,6 +1644,23 @@ void ip_natunload() (void) nat_clearlist(); (void) nat_flushtable(); RWLOCK_EXIT(&ipf_nat); + + if (nat_table[0] != NULL) { + KFREES(nat_table[0], sizeof(nat_t *) * ipf_nattable_sz); + nat_table[0] = NULL; + } + if (nat_table[1] != NULL) { + KFREES(nat_table[1], sizeof(nat_t *) * ipf_nattable_sz); + nat_table[1] = NULL; + } + if (nat_rules != NULL) { + KFREES(nat_rules, sizeof(ipnat_t *) * ipf_natrules_sz); + nat_rules = NULL; + } + if (rdr_rules != NULL) { + KFREES(rdr_rules, sizeof(ipnat_t *) * ipf_rdrrules_sz); + rdr_rules = NULL; + } } @@ -1367,69 +1697,69 @@ void ip_natexpire() /* */ -#ifdef __STDC__ -void ip_natsync(void *ifp) -#else void ip_natsync(ifp) void *ifp; -#endif { + register ipnat_t *n; register nat_t *nat; register u_32_t sum1, sum2, sumd; struct in_addr in; ipnat_t *np; + void *ifp2; #if defined(_KERNEL) && !SOLARIS int s; #endif + /* + * Change IP addresses for NAT sessions for any protocol except TCP + * since it will break the TCP connection anyway. + */ SPL_NET(s); WRITE_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; + if (((ifp == NULL) || (ifp == nat->nat_ifp)) && + !(nat->nat_flags & IPN_TCP) && (np = nat->nat_ptr) && + (np->in_outmsk == 0xffffffff) && !np->in_nip) { + ifp2 = nat->nat_ifp; + /* + * Change the map-to address to be the same as the + * new one. + */ + sum1 = nat->nat_outip.s_addr; + if (fr_ifpaddr(ifp2, &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); - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - - /* Do it twice */ - sum1 = (sum1 & 0xffff) + (sum1 >> 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); - } + if (sum1 == sum2) + continue; + /* + * Readjust the checksum adjustment to take into + * account the new IP#. + */ + CALC_SUMD(sum1, sum2, sumd); + /* XXX - dont change for TCP when solaris does + * hardware checksumming. + */ + sumd += nat->nat_sumd[0]; + nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); + nat->nat_sumd[1] = nat->nat_sumd[0]; + } + + for (n = nat_list; (n != NULL); n = n->in_next) + if (n->in_ifp == ifp) { + n->in_ifp = (void *)GETUNIT(n->in_ifname); + if (!n->in_ifp) + n->in_ifp = (void *)-1; + } RWLOCK_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 +u_int type; { struct ipnat *np; struct natlog natl; @@ -1447,17 +1777,19 @@ u_short type; natl.nl_outport = nat->nat_outport; natl.nl_type = type; natl.nl_rule = -1; - if (nat->nat_ptr) { +#ifndef LARGE_NAT + if (nat->nat_ptr != NULL) { for (rulen = 0, np = nat_list; np; np = np->in_next, rulen++) if (np == nat->nat_ptr) { natl.nl_rule = rulen; break; } } +#endif items[0] = &natl; sizes[0] = sizeof(natl); types[0] = 0; - (void) ipllog(IPL_LOGNAT, 0, items, sizes, types, 1); + (void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1); } #endif diff --git a/sys/netinet/ip_nat.h b/sys/netinet/ip_nat.h index 7aae04b8194..60f4533c844 100644 --- a/sys/netinet/ip_nat.h +++ b/sys/netinet/ip_nat.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_nat.h,v 1.12 1999/08/08 00:43:00 niklas Exp $ */ +/* $OpenBSD: ip_nat.h,v 1.13 1999/12/15 05:20:22 kjell Exp $ */ /* * Copyright (C) 1995-1998 by Darren Reed. * @@ -7,7 +7,7 @@ * to the original author and the contributors. * * @(#)ip_nat.h 1.5 2/4/96 - * $Id: ip_nat.h,v 1.12 1999/08/08 00:43:00 niklas Exp $ + * $Id: ip_nat.h,v 1.13 1999/12/15 05:20:22 kjell Exp $ */ #ifndef __IP_NAT_H__ @@ -37,18 +37,39 @@ #define SIOCCNATL _IOWR(r, 87, int) #endif -#define NAT_SIZE 367 +#undef LARGE_NAT /* define this if you're setting up a system to NAT + * LARGE numbers of networks/hosts - i.e. in the + * hundreds or thousands. In such a case, you should + * also change the RDR_SIZE and NAT_SIZE below to more + * appropriate sizes. The figures below were used for + * a setup with 1000-2000 networks to NAT. + */ +#define NAT_SIZE 127 +#define RDR_SIZE 127 +#define NAT_TABLE_SZ 127 +#ifdef LARGE_NAT +#undef NAT_SIZE +#undef RDR_SIZE +#undef NAT_TABLE_SZ +#define NAT_SIZE 2047 +#define RDR_SIZE 2047 +#define NAT_TABLE_SZ 16383 +#endif #ifndef APR_LABELLEN #define APR_LABELLEN 16 #endif +#define NAT_HW_CKSUM 0x80000000 + +#define DEF_NAT_AGE 1200 /* 10 minutes (600 seconds) */ typedef struct nat { u_long nat_age; int nat_flags; - u_32_t nat_sumd; + u_32_t nat_sumd[2]; u_32_t nat_ipsumd; void *nat_data; void *nat_aps; /* proxy session */ + frentry_t *nat_fr; /* filter rule ptr if appropriate */ struct in_addr nat_inip; struct in_addr nat_outip; struct in_addr nat_oip; /* other ip */ @@ -58,7 +79,8 @@ typedef struct nat { u_short nat_inport; u_short nat_outport; u_short nat_use; - u_char nat_state[2]; + u_char nat_tcpstate[2]; + u_char nat_p; /* protocol for NAT */ struct ipnat *nat_ptr; /* pointer back to the rule */ struct nat *nat_next; struct nat *nat_hnext[2]; @@ -69,16 +91,22 @@ typedef struct nat { typedef struct ipnat { struct ipnat *in_next; - void *in_ifp; /* interface pointer */ - void *in_apr; /* proxy structure ptr */ - u_int in_space; + struct ipnat *in_rnext; + struct ipnat *in_mnext; + void *in_ifp; + void *in_apr; + u_long in_space; u_int in_use; + u_int in_hits; struct in_addr in_nextip; u_short in_pnext; - u_short in_flags; - u_short in_port[2]; + u_short in_ppip; /* ports per IP */ + u_short in_ippip; /* IP #'s per IP# */ + u_short in_flags; /* From here to in_dport must be reflected */ + u_short in_port[2]; /* correctly in IPN_CMPSIZ */ struct in_addr in_in[2]; struct in_addr in_out[2]; + struct in_addr in_src[2]; 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 */ @@ -93,6 +121,8 @@ typedef struct ipnat { #define in_inmsk in_in[1].s_addr #define in_outip in_out[0].s_addr #define in_outmsk in_out[1].s_addr +#define in_srcip in_src[0].s_addr +#define in_srcmsk in_src[1].s_addr #define NAT_OUTBOUND 0 #define NAT_INBOUND 1 @@ -100,8 +130,12 @@ typedef struct ipnat { #define NAT_MAP 0x01 #define NAT_REDIRECT 0x02 #define NAT_BIMAP (NAT_MAP|NAT_REDIRECT) +#define NAT_MAPBLK 0x04 + +#define MAPBLK_MINPORT 1024 /* don't use reserved ports for src port */ +#define USABLE_PORTS (65536 - MAPBLK_MINPORT) -#define IPN_CMPSIZ (sizeof(ipnat_t) - offsetof(ipnat_t, in_flags)) +#define IPN_CMPSIZ (sizeof(ipnat_t) - offsetof(ipnat_t, in_flags)) typedef struct natlookup { struct in_addr nl_inip; @@ -124,14 +158,22 @@ typedef struct natstat { nat_t **ns_table[2]; ipnat_t *ns_list; void *ns_apslist; + u_int ns_nattab_sz; + u_int ns_rultab_sz; + u_int ns_rdrtab_sz; + nat_t *ns_instances; } natstat_t; #define IPN_ANY 0x00 #define IPN_TCP 0x01 #define IPN_UDP 0x02 -#define IPN_TCPUDP 0x03 +#define IPN_TCPUDP (IPN_TCP|IPN_UDP) #define IPN_DELETE 0x04 #define IPN_ICMPERR 0x08 +#define IPN_RF (IPN_TCPUDP|IPN_DELETE|IPN_ICMPERR) +#define IPN_AUTOPORTMAP 0x10 +#define IPN_RANGE 0x20 +#define IPN_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_RANGE) typedef struct natlog { @@ -152,33 +194,56 @@ typedef struct natlog { #define NL_NEWRDR NAT_REDIRECT #define NL_EXPIRE 0xffff +#define NAT_HASH_FN(k,m) (((k) + ((k) >> 12)) % (m)) + +#define LONG_SUM(in) (((in) & 0xffff) + ((in) >> 16)) + +#define CALC_SUMD(s1, s2, sd) { \ + (s1) = ((s1) & 0xffff) + ((s1) >> 16); \ + (s2) = ((s2) & 0xffff) + ((s2) >> 16); \ + /* Do it twice */ \ + (s1) = ((s1) & 0xffff) + ((s1) >> 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); } + +extern u_int ipf_nattable_sz; +extern u_int ipf_natrules_sz; +extern u_int ipf_rdrrules_sz; extern void ip_natsync __P((void *)); extern u_long fr_defnatage; extern u_long fr_defnaticmpage; -extern nat_t *nat_table[2][NAT_SIZE]; +extern nat_t **nat_table[2]; +extern nat_t *nat_instances; +extern ipnat_t **nat_rules; +extern ipnat_t **rdr_rules; +extern natstat_t nat_stats; #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 void nat_ifdetach __P((struct ifnet *)); -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, - struct in_addr, u_short)); +extern int nat_init __P((void)); +extern nat_t *nat_new __P((ipnat_t *, ip_t *, fr_info_t *, u_int, int)); +extern nat_t *nat_outlookup __P((void *, u_int, u_int, struct in_addr, + struct in_addr, u_32_t)); +extern nat_t *nat_inlookup __P((void *, u_int, u_int, struct in_addr, + struct in_addr, u_32_t)); +extern nat_t *nat_maplookup __P((void *, u_int, struct in_addr, + struct in_addr)); 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 nat_t *nat_icmpin __P((ip_t *, fr_info_t *, u_int *)); -extern int ip_natout __P((ip_t *, int, fr_info_t *)); -extern int ip_natin __P((ip_t *, int, fr_info_t *)); +extern int ip_natout __P((ip_t *, fr_info_t *)); +extern int ip_natin __P((ip_t *, 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_32_t)); -extern void fix_outcksum __P((u_short *, u_32_t)); +extern void nat_log __P((struct nat *, u_int)); +extern void fix_incksum __P((u_short *, u_32_t, int)); +extern void fix_outcksum __P((u_short *, u_32_t, int)); #endif /* __IP_NAT_H__ */ diff --git a/sys/netinet/ip_proxy.c b/sys/netinet/ip_proxy.c index c8a14ebc798..0cf9c2d265c 100644 --- a/sys/netinet/ip_proxy.c +++ b/sys/netinet/ip_proxy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_proxy.c,v 1.4 1999/02/05 05:58:53 deraadt Exp $ */ +/* $OpenBSD: ip_proxy.c,v 1.5 1999/12/15 05:20:22 kjell Exp $ */ /* * Copyright (C) 1997-1998 by Darren Reed. * @@ -7,7 +7,7 @@ * to the original author and the contributors. */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 1.4 1999/02/05 05:58:53 deraadt Exp $"; +static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 1.5 1999/12/15 05:20:22 kjell Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) @@ -19,7 +19,9 @@ static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 1.4 1999/02/05 05:58:53 deraa #include <sys/param.h> #include <sys/time.h> #include <sys/file.h> -#include <sys/ioctl.h> +#if !defined(__FreeBSD_version) +# include <sys/ioctl.h> +#endif #include <sys/fcntl.h> #include <sys/uio.h> #if !defined(_KERNEL) && !defined(KERNEL) @@ -44,7 +46,9 @@ static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 1.4 1999/02/05 05:58:53 deraa # endif #else # include <sys/byteorder.h> -# include <sys/dditypes.h> +# ifdef _KERNEL +# include <sys/dditypes.h> +# endif # include <sys/stream.h> # include <sys/kmem.h> #endif @@ -65,42 +69,54 @@ static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 1.4 1999/02/05 05:58:53 deraa #include <netinet/tcp.h> #include <netinet/udp.h> #include <netinet/ip_icmp.h> -#if defined(__OpenBSD__) -# include <netinet/ip_fil_compat.h> -#else -# include <netinet/ip_compat.h> -#endif +#include <netinet/ip_fil_compat.h> #include <netinet/tcpip.h> #include <netinet/ip_fil.h> #include <netinet/ip_proxy.h> #include <netinet/ip_nat.h> #include <netinet/ip_state.h> +#if (__FreeBSD_version >= 300000) +# include <sys/malloc.h> +#endif + #ifndef MIN #define MIN(a,b) (((a)<(b))?(a):(b)) #endif -static ap_session_t *ap_new_session __P((aproxy_t *, ip_t *, - fr_info_t *, nat_t *)); +static ap_session_t *appr_new_session __P((aproxy_t *, ip_t *, + fr_info_t *, nat_t *)); +static int appr_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int )); #define AP_SESS_SIZE 53 #if defined(_KERNEL) && !defined(linux) #include <netinet/ip_ftp_pxy.c> +#include <netinet/ip_rcmd_pxy.c> +#include <netinet/ip_raudio_pxy.c> #endif ap_session_t *ap_sess_tab[AP_SESS_SIZE]; ap_session_t *ap_sess_list = NULL; aproxy_t ap_proxies[] = { #ifdef IPF_FTP_PROXY - { "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, ippr_ftp_in, ippr_ftp_out }, + { "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, NULL, + ippr_ftp_in, ippr_ftp_out }, +#endif +#ifdef IPF_RCMD_PROXY + { "rcmd", (char)IPPROTO_TCP, 0, 0, ippr_rcmd_init, ippr_rcmd_new, + NULL, ippr_rcmd_out }, +#endif +#ifdef IPF_RAUDIO_PROXY + { "raudio", (char)IPPROTO_TCP, 0, 0, ippr_raudio_init, + ippr_raudio_new, ippr_raudio_in, ippr_raudio_out }, #endif { "", '\0', 0, 0, NULL, NULL } }; -int ap_ok(ip, tcp, nat) +int appr_ok(ip, tcp, nat) ip_t *ip; tcphdr_t *tcp; ipnat_t *nat; @@ -108,7 +124,7 @@ ipnat_t *nat; aproxy_t *apr = nat->in_apr; u_short dport = nat->in_dport; - if (!apr || (apr && (apr->apr_flags & APR_DELETE)) || + if (!apr || (apr->apr_flags & APR_DELETE) || (ip->ip_p != apr->apr_p)) return 0; if ((tcp && (tcp->th_dport != dport)) || (!tcp && dport)) @@ -122,60 +138,31 @@ ipnat_t *nat; * relevant details. call the init function once complete, prior to * returning. */ -static ap_session_t *ap_new_session(apr, ip, fin, nat) +static ap_session_t *appr_new_session(apr, ip, fin, nat) aproxy_t *apr; ip_t *ip; fr_info_t *fin; nat_t *nat; { register ap_session_t *aps; - tcphdr_t *tcp; - u_short dport; - u_int hv; - if (!apr || (apr && (apr->apr_flags & APR_DELETE)) || - (ip->ip_p != apr->apr_p)) - return NULL; - - if (!(fin->fin_fi.fi_fl & FI_TCPUDP)) - tcp = NULL; - else - tcp = (tcphdr_t *)fin->fin_dp; - dport = nat->nat_ptr->in_dport; - - if ((tcp && (tcp->th_dport != dport)) || (!tcp && dport)) + if (!apr || (apr->apr_flags & APR_DELETE) || (ip->ip_p != apr->apr_p)) return NULL; - hv = ip->ip_src.s_addr ^ ip->ip_dst.s_addr; - hv *= 651733; - if (tcp) { - hv ^= (tcp->th_sport + tcp->th_dport); - hv *= 5; - } - hv %= AP_SESS_SIZE; - - KMALLOC(aps, ap_session_t *, sizeof(*aps)); + KMALLOC(aps, ap_session_t *); if (!aps) return NULL; bzero((char *)aps, sizeof(*aps)); - aps->aps_apr = apr; - aps->aps_src = ip->ip_src; - aps->aps_dst = ip->ip_dst; + aps->aps_next = ap_sess_list; aps->aps_p = ip->ip_p; - if (tcp) { - aps->aps_sport = tcp->th_sport; - aps->aps_dport = tcp->th_dport; - } aps->aps_data = NULL; + aps->aps_apr = apr; aps->aps_psiz = 0; - aps->aps_hnext = ap_sess_tab[hv]; - aps->aps_next = ap_sess_list; ap_sess_list = aps; aps->aps_nat = nat; - aps->aps_hv = hv; nat->nat_aps = aps; - ap_sess_tab[hv] = aps; - (void) (*apr->apr_init)(fin, ip, aps, nat); + if (apr->apr_new != NULL) + (void) (*apr->apr_new)(fin, ip, aps, nat); return aps; } @@ -184,7 +171,7 @@ 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, fin, nat) +int appr_check(ip, fin, nat) ip_t *ip; fr_info_t *fin; nat_t *nat; @@ -195,8 +182,11 @@ nat_t *nat; u_32_t sum; int err; - if ((aps = nat->nat_aps) || - (aps = ap_new_session(nat->nat_ptr->in_apr, ip, fin, nat))) { + if (nat->nat_aps == NULL) + nat->nat_aps = appr_new_session(nat->nat_ptr->in_apr, ip, + fin, nat); + aps = nat->nat_aps; + if ((aps != NULL) && (aps->aps_p == ip->ip_p)) { if (ip->ip_p == IPPROTO_TCP) { tcp = (tcphdr_t *)fin->fin_dp; /* @@ -204,12 +194,11 @@ nat_t *nat; * don't do anything with this packet. */ #if SOLARIS && defined(_KERNEL) - sum = fr_tcpsum(fin->fin_qfm, ip, tcp, ip->ip_len); + sum = fr_tcpsum(fin->fin_qfm, ip, tcp); #else - sum = fr_tcpsum(*(mb_t **)fin->fin_mp, - ip, tcp, ip->ip_len); + sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp); #endif - if (tcp->th_sum != sum) { + if (sum != tcp->th_sum) { frstats[fin->fin_out].fr_tcpbad++; return -1; } @@ -217,22 +206,20 @@ nat_t *nat; apr = aps->aps_apr; err = 0; - if (fin->fin_out) { - if (apr->apr_outpkt) + if (fin->fin_out != 0) { + if (apr->apr_outpkt != NULL) err = (*apr->apr_outpkt)(fin, ip, aps, nat); } else { - if (apr->apr_inpkt) + if (apr->apr_inpkt != NULL) err = (*apr->apr_inpkt)(fin, ip, aps, nat); } if (tcp != NULL) { - err = ap_fixseqack(fin, ip, aps, err); + err = appr_fixseqack(fin, ip, aps, err); #if SOLARIS && defined(_KERNEL) - tcp->th_sum = fr_tcpsum(fin->fin_qfm, ip, tcp, - ip->ip_len); + tcp->th_sum = fr_tcpsum(fin->fin_qfm, ip, tcp); #else - tcp->th_sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, - tcp, ip->ip_len); + tcp->th_sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp); #endif } aps->aps_bytes += ip->ip_len; @@ -243,8 +230,8 @@ nat_t *nat; } -aproxy_t *ap_match(pr, name) -u_char pr; +aproxy_t *appr_match(pr, name) +u_int pr; char *name; { aproxy_t *ap; @@ -259,7 +246,7 @@ char *name; } -void ap_free(ap) +void appr_free(ap) aproxy_t *ap; { ap->apr_ref--; @@ -270,19 +257,10 @@ void aps_free(aps) ap_session_t *aps; { ap_session_t *a, **ap; - u_int hv; if (!aps) return; - hv = aps->aps_hv; - - for (ap = ap_sess_tab + hv; (a = *ap); ap = &a->aps_hnext) - if (a == aps) { - *ap = a->aps_hnext; - break; - } - for (ap = &ap_sess_list; (a = *ap); ap = &a->aps_next) if (a == aps) { *ap = a->aps_next; @@ -290,14 +268,14 @@ ap_session_t *aps; } if (a) { - if (aps->aps_data && aps->aps_psiz) + if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) KFREES(aps->aps_data, aps->aps_psiz); KFREE(aps); } } -int ap_fixseqack(fin, ip, aps, inc) +static int appr_fixseqack(fin, ip, aps, inc) fr_info_t *fin; ip_t *ip; ap_session_t *aps; @@ -394,3 +372,17 @@ int inc; } return ch ? 2 : 0; } + + +int appr_init() +{ + aproxy_t *ap; + int err = 0; + + for (ap = ap_proxies; ap->apr_p; ap++) { + err = (*ap->apr_init)(); + if (err != 0) + break; + } + return err; +} diff --git a/sys/netinet/ip_proxy.h b/sys/netinet/ip_proxy.h index e13444be48f..bcc464b1779 100644 --- a/sys/netinet/ip_proxy.h +++ b/sys/netinet/ip_proxy.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_proxy.h,v 1.3 1999/02/05 05:58:54 deraadt Exp $ */ +/* $OpenBSD: ip_proxy.h,v 1.4 1999/12/15 05:20:23 kjell Exp $ */ /* * Copyright (C) 1997-1998 by Darren Reed. * @@ -6,7 +6,7 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: ip_proxy.h,v 1.3 1999/02/05 05:58:54 deraadt Exp $ + * $Id: ip_proxy.h,v 1.4 1999/12/15 05:20:23 kjell Exp $ */ #ifndef __IP_PROXY_H__ @@ -42,19 +42,16 @@ typedef struct ap_udp { typedef struct ap_session { struct aproxy *aps_apr; - struct in_addr aps_src; /* source IP# */ - struct in_addr aps_dst; /* destination IP# */ - u_char aps_p; /* protocol */ union { struct ap_tcp apu_tcp; struct ap_udp apu_udp; } aps_un; - u_int aps_hv; u_int aps_flags; U_QUAD_T aps_bytes; /* bytes sent */ U_QUAD_T aps_pkts; /* packets sent */ void *aps_nat; /* pointer back to nat struct */ void *aps_data; /* private data */ + int aps_p; /* protocol */ int aps_psiz; /* size of private data */ struct ap_session *aps_hnext; struct ap_session *aps_next; @@ -75,8 +72,9 @@ typedef struct aproxy { 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 *, - ap_session_t *, struct nat *)); + int (* apr_init) __P((void)); + int (* apr_new) __P((fr_info_t *, ip_t *, + ap_session_t *, struct nat *)); int (* apr_inpkt) __P((fr_info_t *, ip_t *, ap_session_t *, struct nat *)); int (* apr_outpkt) __P((fr_info_t *, ip_t *, @@ -86,24 +84,47 @@ typedef struct aproxy { #define APR_DELETE 1 +/* + * Real audio proxy structure and #defines + */ +typedef struct { + int rap_seenpna; + int rap_seenver; + int rap_version; + int rap_eos; /* End Of Startup */ + int rap_gotid; + int rap_gotlen; + int rap_mode; + int rap_sdone; + u_short rap_plport; + u_short rap_prport; + u_short rap_srport; + char rap_svr[19]; + u_32_t rap_sbf; /* flag to indicate which of the 19 bytes have + * been filled + */ + tcp_seq rap_sseq; +} raudio_t; + +#define RA_ID_END 0 +#define RA_ID_UDP 1 +#define RA_ID_ROBUST 7 + +#define RAP_M_UDP 1 +#define RAP_M_ROBUST 2 +#define RAP_M_TCP 4 +#define RAP_M_UDP_ROBUST (RAP_M_UDP|RAP_M_ROBUST) + + extern ap_session_t *ap_sess_tab[AP_SESS_SIZE]; extern ap_session_t *ap_sess_list; extern aproxy_t ap_proxies[]; -extern int ap_ok __P((ip_t *, tcphdr_t *, struct ipnat *)); -extern void ap_free __P((aproxy_t *)); +extern int appr_init __P((void)); +extern int appr_ok __P((ip_t *, tcphdr_t *, struct ipnat *)); +extern void appr_free __P((aproxy_t *)); extern void aps_free __P((ap_session_t *)); -extern int ap_check __P((ip_t *, fr_info_t *, struct nat *)); -extern aproxy_t *ap_match __P((u_char, char *)); -extern int ap_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int inc)); - +extern int appr_check __P((ip_t *, fr_info_t *, struct nat *)); +extern aproxy_t *appr_match __P((u_int, char *)); #endif /* __IP_PROXY_H__ */ - - - - - - - - diff --git a/sys/netinet/ip_state.c b/sys/netinet/ip_state.c index 51aa6302d36..94d3376f256 100644 --- a/sys/netinet/ip_state.c +++ b/sys/netinet/ip_state.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_state.c,v 1.13 1999/02/05 05:58:54 deraadt Exp $ */ +/* $OpenBSD: ip_state.c,v 1.14 1999/12/15 05:20:23 kjell Exp $ */ /* * Copyright (C) 1995-1998 by Darren Reed. * @@ -8,13 +8,17 @@ */ #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 1.13 1999/02/05 05:58:54 deraadt Exp $"; +static const char rcsid[] = "@(#)$Id: ip_state.c,v 1.14 1999/12/15 05:20:23 kjell Exp $"; #endif #include <sys/errno.h> #include <sys/types.h> #include <sys/param.h> #include <sys/file.h> +#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ + defined(_KERNEL) +# include "opt_ipfilter_log.h" +#endif #if !defined(_KERNEL) && !defined(KERNEL) && !defined(__KERNEL__) # include <stdio.h> # include <stdlib.h> @@ -28,13 +32,16 @@ static const char rcsid[] = "@(#)$Id: ip_state.c,v 1.13 1999/02/05 05:58:54 dera #if defined(KERNEL) && (__FreeBSD_version >= 220000) # include <sys/filio.h> # include <sys/fcntl.h> +# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" +# endif #else # include <sys/ioctl.h> #endif #include <sys/time.h> #include <sys/uio.h> #ifndef linux -#include <sys/protosw.h> +# include <sys/protosw.h> #endif #include <sys/socket.h> #if defined(_KERNEL) && !defined(linux) @@ -47,14 +54,16 @@ static const char rcsid[] = "@(#)$Id: ip_state.c,v 1.13 1999/02/05 05:58:54 dera #else # include <sys/filio.h> # include <sys/byteorder.h> -# include <sys/dditypes.h> +# ifdef _KERNEL +# include <sys/dditypes.h> +# endif # include <sys/stream.h> # include <sys/kmem.h> #endif #include <net/if.h> #ifdef sun -#include <net/af.h> +# include <net/af.h> #endif #include <net/route.h> #include <netinet/in.h> @@ -67,46 +76,67 @@ static const char rcsid[] = "@(#)$Id: ip_state.c,v 1.13 1999/02/05 05:58:54 dera #endif #include <netinet/udp.h> #include <netinet/ip_icmp.h> -#if defined(__OpenBSD__) -# include <netinet/ip_fil_compat.h> -#else -# include <netinet/ip_compat.h> -#endif +#include <netinet/ip_fil_compat.h> #include <netinet/tcpip.h> #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> +#if (__FreeBSD_version >= 300000) +# include <sys/malloc.h> +# if (defined(_KERNEL) || defined(KERNEL)) && !defined(IPFILTER_LKM) +# include <sys/libkern.h> +# include <sys/systm.h> +# endif +#endif + #ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) +# define MIN(a,b) (((a)<(b))?(a):(b)) #endif #define TCP_CLOSE (TH_FIN|TH_RST) -ipstate_t *ips_table[IPSTATE_SIZE]; +ipstate_t **ips_table = NULL; int ips_num = 0; ips_stat_t ips_stats; #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern KRWLOCK_T ipf_state; +extern KRWLOCK_T ipf_state, ipf_mutex; extern kmutex_t ipf_rw; #endif static int fr_matchsrcdst __P((ipstate_t *, struct in_addr, struct in_addr, - fr_info_t *, void *, u_short, u_short)); + fr_info_t *, tcphdr_t *)); +static frentry_t *fr_checkicmpmatchingstate __P((ip_t *, fr_info_t *)); static int fr_state_flush __P((int)); static ips_stat_t *fr_statetstats __P((void)); +static void fr_delstate __P((ipstate_t *)); #define FIVE_DAYS (2 * 5 * 86400) /* 5 days: half closed session */ +#define TCP_MSL 240 /* 2 minutes */ u_long fr_tcpidletimeout = FIVE_DAYS, - fr_tcpclosewait = 60, - fr_tcplastack = 20, - fr_tcptimeout = 120, + fr_tcpclosewait = 2 * TCP_MSL, + fr_tcplastack = 2 * TCP_MSL, + fr_tcptimeout = 2 * TCP_MSL, fr_tcpclosed = 1, - fr_udptimeout = 120, + fr_udptimeout = 240, fr_icmptimeout = 120; +int fr_statemax = IPSTATE_MAX, + fr_statesize = IPSTATE_SIZE; +int fr_state_doflush = 0; + + +int fr_stateinit() +{ + KMALLOCS(ips_table, ipstate_t **, fr_statesize * sizeof(ipstate_t *)); + if (ips_table != NULL) + bzero((char *)ips_table, fr_statesize * sizeof(ipstate_t *)); + else + return -1; + return 0; +} static ips_stat_t *fr_statetstats() @@ -135,7 +165,7 @@ int which; SPL_NET(s); WRITE_ENTER(&ipf_state); - for (i = 0; i < IPSTATE_SIZE; i++) + for (i = fr_statesize - 1; i >= 0; i--) for (isp = &ips_table[i]; (is = *isp); ) { delete = 0; @@ -160,10 +190,12 @@ int which; ips_stats.iss_fin++; else ips_stats.iss_expire++; + if (ips_table[i] == NULL) + ips_stats.iss_inuse--; #ifdef IPFILTER_LOG ipstate_log(is, ISL_FLUSH); #endif - KFREE(is); + fr_delstate(is); ips_num--; removed++; } else @@ -206,7 +238,8 @@ int mode; #endif break; default : - return EINVAL; + error = EINVAL; + break; } return error; } @@ -215,21 +248,25 @@ int mode; /* * Create a new ipstate structure and hang it off the hash table. */ -int fr_addstate(ip, fin, pass) +ipstate_t *fr_addstate(ip, fin, flags) ip_t *ip; fr_info_t *fin; -u_int pass; +u_int flags; { - ipstate_t ips; - register ipstate_t *is = &ips; + register ipstate_t *is; register u_int hv; + ipstate_t ips; + u_int pass; if ((ip->ip_off & IP_OFFMASK) || (fin->fin_fi.fi_fl & FI_SHORT)) - return -1; - if (ips_num == IPSTATE_MAX) { + return NULL; + if (ips_num == fr_statemax) { ips_stats.iss_max++; - return -1; + fr_state_doflush = 1; + return NULL; } + is = &ips; + bzero((char *)is, sizeof(*is)); ips.is_age = 1; ips.is_state[0] = 0; ips.is_state[1] = 0; @@ -259,7 +296,7 @@ u_int pass; is->is_icmp.ics_type = ic->icmp_type + 1; break; default : - return -1; + return NULL; } ATOMIC_INC(ips_stats.iss_icmp); is->is_age = fr_icmptimeout; @@ -273,19 +310,28 @@ u_int pass; * The endian of the ports doesn't matter, but the ack and * sequence numbers do as we do mathematics on them later. */ - hv += (is->is_dport = tcp->th_dport); - hv += (is->is_sport = tcp->th_sport); - is->is_seq = ntohl(tcp->th_seq); - is->is_ack = ntohl(tcp->th_ack); - is->is_swin = ntohs(tcp->th_win); - is->is_dwin = is->is_swin; /* start them the same */ + is->is_dport = tcp->th_dport; + is->is_sport = tcp->th_sport; + if ((flags & (FI_W_DPORT|FI_W_SPORT)) == 0) { + hv += tcp->th_dport; + hv += tcp->th_sport; + } + if (tcp->th_seq != 0) { + is->is_send = ntohl(tcp->th_seq) + ip->ip_len - + fin->fin_hlen - (tcp->th_off << 2) + + ((tcp->th_flags & TH_SYN) ? 1 : 0) + + ((tcp->th_flags & TH_FIN) ? 1 : 0); + is->is_maxsend = is->is_send + 1; + } + is->is_dend = 0; + is->is_maxswin = ntohs(tcp->th_win); + if (is->is_maxswin == 0) + is->is_maxswin = 1; /* * 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. */ - if ((tcp->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) - is->is_ack = 0; /* Trumpet WinSock 'ism */ MUTEX_ENTER(&ipf_rw); ips_stats.iss_tcp++; fr_tcp_age(&is->is_age, is->is_state, ip, fin, @@ -297,25 +343,38 @@ u_int pass; { register tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; - hv += (is->is_dport = tcp->th_dport); - hv += (is->is_sport = tcp->th_sport); + is->is_dport = tcp->th_dport; + is->is_sport = tcp->th_sport; + if ((flags & (FI_W_DPORT|FI_W_SPORT)) == 0) { + hv += tcp->th_dport; + hv += tcp->th_sport; + } ATOMIC_INC(ips_stats.iss_udp); is->is_age = fr_udptimeout; break; } default : - return -1; + return NULL; } - KMALLOC(is, ipstate_t *, sizeof(*is)); + KMALLOC(is, ipstate_t *); if (is == NULL) { ATOMIC_INC(ips_stats.iss_nomem); - return -1; + return NULL; } bcopy((char *)&ips, (char *)is, sizeof(*is)); - hv %= IPSTATE_SIZE; + hv %= fr_statesize; + RW_UPGRADE(&ipf_mutex); + is->is_rule = fin->fin_fr; + if (is->is_rule != NULL) { + is->is_rule->fr_ref++; + pass = is->is_rule->fr_flags; + } else + pass = fr_flags; + MUTEX_DOWNGRADE(&ipf_mutex); WRITE_ENTER(&ipf_state); + is->is_rout = pass & FR_OUTQUE ? 1 : 0; is->is_pass = pass; is->is_pkts = 1; is->is_bytes = ip->ip_len; @@ -330,14 +389,16 @@ u_int pass; is->is_secmsk = 0xffff; is->is_auth = fin->fin_fi.fi_auth; is->is_authmsk = 0xffff; - is->is_flags = fin->fin_fi.fi_fl; - is->is_flags |= FI_OPTIONS|FI_TCPUDP|FI_SHORT; - is->is_flags |= fin->fin_fi.fi_fl << 4; + is->is_flags = fin->fin_fi.fi_fl & FI_CMP; + is->is_flags |= FI_CMP << 4; + is->is_flags |= flags & (FI_W_DPORT|FI_W_SPORT); /* * add into table. */ is->is_next = ips_table[hv]; ips_table[hv] = is; + if (is->is_next == NULL) + ips_stats.iss_inuse++; if (fin->fin_out) { is->is_ifpin = NULL; is->is_ifpout = fin->fin_ifp; @@ -352,12 +413,14 @@ u_int pass; ipstate_log(is, ISL_NEW); #endif RWLOCK_EXIT(&ipf_state); + fin->fin_rev = (is->is_dst.s_addr != ip->ip_dst.s_addr); if (fin->fin_fi.fi_fl & FI_FRAG) ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE); - return 0; + return is; } + /* * check to see if a packet with TCP headers fits within the TCP window. * change timeout depending on whether new packet is a SYN-ACK returning for a @@ -369,65 +432,86 @@ fr_info_t *fin; ip_t *ip; tcphdr_t *tcp; { - register int seqskew, ackskew; - register tcp_seq seq, ack; - u_short win; + register tcp_seq seq, ack, end; + register int ackskew; + tcpdata_t *fdata, *tdata; + u_short win, maxwin; + int ret = 0; int source; /* * Find difference between last checked packet and this packet. */ + source = (ip->ip_src.s_addr == is->is_src.s_addr); + fdata = &is->is_tcp.ts_data[!source]; + tdata = &is->is_tcp.ts_data[source]; seq = ntohl(tcp->th_seq); ack = ntohl(tcp->th_ack); - source = (ip->ip_src.s_addr == is->is_src.s_addr); - - if (!(tcp->th_flags & TH_ACK)) /* Pretend an ack was sent */ - ack = source ? is->is_ack : is->is_seq; + win = ntohs(tcp->th_win); + end = seq + ip->ip_len - fin->fin_hlen - (tcp->th_off << 2) + + ((tcp->th_flags & TH_SYN) ? 1 : 0) + + ((tcp->th_flags & TH_FIN) ? 1 : 0); - 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 - 1) - is->is_ack; - } else { - 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 - 1) - is->is_seq; + if (fdata->td_end == 0) { + /* + * Must be a (outgoing) SYN-ACK in reply to a SYN. + */ + fdata->td_end = end; + fdata->td_maxwin = 1; + fdata->td_maxend = end + 1; } - /* - * Make skew values absolute - */ - if (seqskew < 0) - seqskew = -seqskew; - if (ackskew < 0) - ackskew = -ackskew; + if (!(tcp->th_flags & TH_ACK)) { /* Pretend an ack was sent */ + ack = tdata->td_end; + win = 1; + } else if (((tcp->th_flags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) && + (ack == 0)) { + /* gross hack to get around certain broken tcp stacks */ + ack = tdata->td_end; + } - /* - * If the difference in sequence and ack numbers is within the - * window size of the connection, store these values and match - * the packet. - */ - win = ntohs(tcp->th_win); - if ((seqskew <= is->is_dwin) && (ackskew <= is->is_swin)) { - if (source) { - is->is_seq = seq; - is->is_ack = ack; - if (win != 0) - is->is_swin = win; - } else { - is->is_seq = ack; - is->is_ack = seq; - if (win != 0) - is->is_dwin = win; + if (seq == end) + seq = end = fdata->td_end; + + maxwin = tdata->td_maxwin; + ackskew = tdata->td_end - ack; + +#define SEQ_GE(a,b) ((int)((a) - (b)) >= 0) +#define SEQ_GT(a,b) ((int)((a) - (b)) > 0) + if ((SEQ_GE(fdata->td_maxend, end)) && + (SEQ_GE(seq + maxwin, fdata->td_end - maxwin)) && +/* XXX what about big packets */ +#define MAXACKWINDOW 66000 + (ackskew >= -MAXACKWINDOW) && + (ackskew <= MAXACKWINDOW)) { + /* if ackskew < 0 then this should be due to fragented + * packets. There is no way to know the length of the + * total packet in advance. + * We do know the total length from the fragment cache though. + * Note however that there might be more sessions with + * exactly the same source and destination paramters in the + * state cache (and source and destination is the only stuff + * that is saved in the fragment cache). Note further that + * some TCP connections in the state cache are hashed with + * sport and dport as well which makes it not worthwhile to + * look for them. + * Thus, when ackskew is negative but still seems to belong + * to this session, we bump up the destinations end value. + */ + if (ackskew < 0) + tdata->td_end = ack; + + /* update max window seen */ + if (fdata->td_maxwin < win) + fdata->td_maxwin = win; + if (SEQ_GT(end, fdata->td_end)) + fdata->td_end = end; + if (SEQ_GE(ack + win, tdata->td_maxend)) { + tdata->td_maxend = ack + win; + if (win == 0) + tdata->td_maxend++; } + ATOMIC_INC(ips_stats.iss_hits); is->is_pkts++; is->is_bytes += ip->ip_len; @@ -437,97 +521,311 @@ tcphdr_t *tcp; MUTEX_ENTER(&ipf_rw); fr_tcp_age(&is->is_age, is->is_state, ip, fin, source); MUTEX_EXIT(&ipf_rw); - return 1; + ret = 1; } - return 0; + return ret; } -static int fr_matchsrcdst(is, src, dst, fin, tcp, sp, dp) +static int fr_matchsrcdst(is, src, dst, fin, tcp) ipstate_t *is; struct in_addr src, dst; fr_info_t *fin; -void *tcp; -u_short sp, dp; +tcphdr_t *tcp; { - int ret = 0, rev, out; + int ret = 0, rev, out, flags; + u_short sp, dp; void *ifp; - rev = (is->is_dst.s_addr != dst.s_addr); + rev = fin->fin_rev = (is->is_dst.s_addr != dst.s_addr); ifp = fin->fin_ifp; out = fin->fin_out; - if (!rev) { - if (out) { - if (!is->is_ifpout) - is->is_ifpout = ifp; + if (tcp != NULL) { + flags = is->is_flags; + sp = tcp->th_sport; + dp = tcp->th_dport; + } else { + flags = 0; + sp = 0; + dp = 0; + } + + if (rev == 0) { + if (!out) { + if (is->is_ifpin == ifp) + ret = 1; } else { - if (!is->is_ifpin) - is->is_ifpin = ifp; + if (is->is_ifpout == NULL || is->is_ifpout == ifp) + ret = 1; } } else { if (out) { - if (!is->is_ifpin) - is->is_ifpin = ifp; + if (is->is_ifpin == ifp) + ret = 1; } else { - if (!is->is_ifpout) - is->is_ifpout = ifp; + if (is->is_ifpout == NULL || is->is_ifpout == ifp) + ret = 1; } } + if (ret == 0) + return 0; + ret = 0; - if (!rev) { - if (((out && is->is_ifpout == ifp) || - (!out && is->is_ifpin == ifp)) && - (is->is_dst.s_addr == dst.s_addr) && + if (rev == 0) { + if ((is->is_dst.s_addr == dst.s_addr) && (is->is_src.s_addr == src.s_addr) && - (!tcp || ((sp == is->is_sport) && - (dp == is->is_dport)))) { + (!tcp || ((sp == is->is_sport || flags & FI_W_SPORT) && + (dp == is->is_dport || flags & FI_W_DPORT)))) { ret = 1; } } else { - if (((out && is->is_ifpin == ifp) || - (!out && is->is_ifpout == ifp)) && - (is->is_dst.s_addr == src.s_addr) && + if ((is->is_dst.s_addr == src.s_addr) && (is->is_src.s_addr == dst.s_addr) && - (!tcp || ((sp == is->is_dport) && - (dp == is->is_sport)))) { + (!tcp || ((sp == is->is_dport || flags & FI_W_DPORT) && + (dp == is->is_sport || flags & FI_W_SPORT)))) { ret = 1; } } + if (ret == 0) + return 0; /* * Whether or not this should be here, is questionable, but the aim * is to get this out of the main line. */ - if (ret) { - if (((fin->fin_fi.fi_optmsk & is->is_optmsk) != is->is_opt) || - ((fin->fin_fi.fi_secmsk & is->is_secmsk) != is->is_sec) || - ((fin->fin_fi.fi_auth & is->is_authmsk) != is->is_auth) || - ((fin->fin_fi.fi_fl & (is->is_flags & 0xf)) != - (is->is_flags >> 4))) - ret = 0; + if (tcp == NULL) + flags = is->is_flags & (FI_CMP|(FI_CMP<<4)); + + if (((fin->fin_fi.fi_fl & (flags >> 4)) != (flags & FI_CMP)) || + ((fin->fin_fi.fi_optmsk & is->is_optmsk) != is->is_opt) || + ((fin->fin_fi.fi_secmsk & is->is_secmsk) != is->is_sec) || + ((fin->fin_fi.fi_auth & is->is_authmsk) != is->is_auth)) + return 0; + + if ((flags & (FI_W_SPORT|FI_W_DPORT))) { + if ((flags & FI_W_SPORT) != 0) { + if (rev == 0) { + is->is_sport = sp; + is->is_send = htonl(tcp->th_seq); + } else { + is->is_sport = dp; + is->is_send = htonl(tcp->th_ack); + } + is->is_maxsend = is->is_send + 1; + } else if ((flags & FI_W_DPORT) != 0) { + if (rev == 0) { + is->is_dport = dp; + is->is_dend = htonl(tcp->th_ack); + } else { + is->is_dport = sp; + is->is_dend = htonl(tcp->th_seq); + } + is->is_maxdend = is->is_dend + 1; + } + is->is_flags &= ~(FI_W_SPORT|FI_W_DPORT); } - return ret; + + if (!rev) { + if (out && (out == is->is_rout)) { + if (!is->is_ifpout) + is->is_ifpout = ifp; + } else { + if (!is->is_ifpin) + is->is_ifpin = ifp; + } + } else { + if (!out && (out != is->is_rout)) { + if (!is->is_ifpin) + is->is_ifpin = ifp; + } else { + if (!is->is_ifpout) + is->is_ifpout = ifp; + } + } + return 1; } +frentry_t *fr_checkicmpmatchingstate(ip, fin) +ip_t *ip; +fr_info_t *fin; +{ + register struct in_addr dst, src; + register ipstate_t *is, **isp; + register u_short sport, dport; + register u_char pr; + struct icmp *ic; + u_short savelen; + fr_info_t ofin; + u_int hv, dest; + tcphdr_t *tcp; + icmphdr_t *icmp; + frentry_t *fr; + ip_t *oip; + int type; + + /* + * 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 < ICMPERR_MINPKTLEN)) + return NULL; + ic = (struct icmp *)((char *)ip + fin->fin_hlen); + type = ic->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 + ICMPERR_ICMPHLEN); + if (ip->ip_len < ICMPERR_MAXPKTLEN + ((oip->ip_hl - 5) << 2)) + return NULL; + + if (oip->ip_p == IPPROTO_ICMP) { + + icmp = (icmphdr_t *)((char *)oip + (oip->ip_hl << 2)); + + /* + * a ICMP error can only be generated as a result of an + * ICMP query, not as the response on an ICMP error + * + * XXX theoretically ICMP_ECHOREP and the other reply's are + * ICMP query's as well, but adding them here seems strange XXX + */ + if ((icmp->icmp_type != ICMP_ECHO) && (icmp->icmp_type != ICMP_TSTAMP) && + (icmp->icmp_type != ICMP_IREQ) && (icmp->icmp_type != ICMP_MASKREQ)) + return NULL; + + /* + * perform a lookup of the ICMP packet in the state table + */ + + hv = (pr = oip->ip_p); + hv += (src.s_addr = oip->ip_src.s_addr); + hv += (dst.s_addr = oip->ip_dst.s_addr); + hv += icmp->icmp_id; + hv += icmp->icmp_seq; + hv %= fr_statesize; + + oip->ip_len = ntohs(oip->ip_len); + fr_makefrip(oip->ip_hl << 2, oip, &ofin); + oip->ip_len = htons(oip->ip_len); + ofin.fin_ifp = fin->fin_ifp; + ofin.fin_out = !fin->fin_out; + ofin.fin_mp = NULL; /* if dereferenced, panic XXX */ + + READ_ENTER(&ipf_state); + for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next) + if ((is->is_p == pr) && + (icmp->icmp_id == is->is_icmp.ics_id) && + (icmp->icmp_seq == is->is_icmp.ics_seq) && + fr_matchsrcdst(is, src, dst, &ofin, NULL)) { + + /* + * in the state table ICMP query's are stored + * with the type of the corresponding ICMP + * response. Correct here + */ + if (((is->is_type == ICMP_ECHOREPLY) && + (icmp->icmp_type == ICMP_ECHO)) || + (is->is_type - 1 == ic->icmp_type )) { + ips_stats.iss_hits++; + is->is_pkts++; + is->is_bytes += ip->ip_len; + return is->is_rule; + } + } + RWLOCK_EXIT(&ipf_state); + + return NULL; + }; + + if ((oip->ip_p != IPPROTO_TCP) && (oip->ip_p != IPPROTO_UDP)) + return NULL; + + tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2)); + dport = tcp->th_dport; + sport = tcp->th_sport; + + hv = (pr = oip->ip_p); + hv += (src.s_addr = oip->ip_src.s_addr); + hv += (dst.s_addr = oip->ip_dst.s_addr); + hv += dport; + hv += sport; + hv %= fr_statesize; + /* + * we make an fin entry to be able to feed it to + * matchsrcdst note that not all fields are encessary + * but this is the cleanest way. Note further we fill + * in fin_mp such that if someone uses it we'll get + * a kernel panic. fr_matchsrcdst does not use this. + * + * watch out here, as ip is in host order and oip in network + * order. Any change we make must be undone afterwards. + */ + savelen = oip->ip_len; + oip->ip_len = ip->ip_len - (ip->ip_hl << 2) - ICMPERR_ICMPHLEN; + fr_makefrip(oip->ip_hl << 2, oip, &ofin); + oip->ip_len = savelen; + ofin.fin_ifp = fin->fin_ifp; + ofin.fin_out = !fin->fin_out; + ofin.fin_mp = NULL; /* if dereferenced, panic XXX */ + READ_ENTER(&ipf_state); + for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next) { + /* + * Only allow this icmp though if the + * encapsulated packet was allowed through the + * other way around. Note that the minimal amount + * of info present does not allow for checking against + * tcp internals such as seq and ack numbers. + */ + if ((is->is_p == pr) && + fr_matchsrcdst(is, src, dst, &ofin, tcp)) { + fr = is->is_rule; + ips_stats.iss_hits++; + /* + * we must swap src and dst here because the icmp + * comes the other way around + */ + dest = (is->is_dst.s_addr != src.s_addr); + is->is_pkts++; + is->is_bytes += ip->ip_len; + /* + * we deliberately do not touch the timeouts + * for the accompanying state table entry. + * It remains to be seen if that is correct. XXX + */ + RWLOCK_EXIT(&ipf_state); + return fr; + } + } + RWLOCK_EXIT(&ipf_state); + return NULL; +} /* * Check if a packet has a registered state. */ -int fr_checkstate(ip, fin) +frentry_t *fr_checkstate(ip, fin) ip_t *ip; fr_info_t *fin; { register struct in_addr dst, src; register ipstate_t *is, **isp; register u_char pr; + u_int hv, hvm, hlen, tryagain, pass; struct icmp *ic; + frentry_t *fr; tcphdr_t *tcp; - u_int hv, hlen, pass; if ((ip->ip_off & IP_OFFMASK) || (fin->fin_fi.fi_fl & FI_SHORT)) - return 0; + return NULL; + is = NULL; hlen = fin->fin_hlen; tcp = (tcphdr_t *)((char *)ip + hlen); ic = (struct icmp *)tcp; @@ -543,99 +841,133 @@ fr_info_t *fin; case IPPROTO_ICMP : hv += ic->icmp_id; hv += ic->icmp_seq; - hv %= IPSTATE_SIZE; + hv %= fr_statesize; READ_ENTER(&ipf_state); for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next) if ((is->is_p == pr) && (ic->icmp_id == is->is_icmp.ics_id) && (ic->icmp_seq == is->is_icmp.ics_seq) && - fr_matchsrcdst(is, src, dst, fin, NULL, 0, 0)) { - if (is->is_icmp.ics_type != ic->icmp_type) + fr_matchsrcdst(is, src, dst, fin, NULL)) { + if ((is->is_type == ICMP_ECHOREPLY) && + (ic->icmp_type == ICMP_ECHO)) + ; + else if (is->is_type != ic->icmp_type) continue; - pass = is->is_pass; - RWLOCK_EXIT(&ipf_state); - if (fin->fin_fi.fi_fl & FI_FRAG) - ipfr_newfrag(ip, fin, - pass ^ FR_KEEPSTATE); - WRITE_ENTER(&ipf_state); is->is_age = fr_icmptimeout; - is->is_bytes += ip->ip_len; - ips_stats.iss_hits++; - is->is_pkts++; - RWLOCK_EXIT(&ipf_state); - return pass; + break; } + if (is != NULL) + break; RWLOCK_EXIT(&ipf_state); + /* + * No matching icmp state entry. Perhaps this is a + * response to another state entry. + */ + fr = fr_checkicmpmatchingstate(ip, fin); + if (fr) + return fr; break; case IPPROTO_TCP : { register u_short dport = tcp->th_dport, sport = tcp->th_sport; - hv += dport; - hv += sport; - hv %= IPSTATE_SIZE; + tryagain = 0; +retry_tcp: + hvm = hv % fr_statesize; WRITE_ENTER(&ipf_state); - for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next) + for (isp = &ips_table[hvm]; (is = *isp); + isp = &is->is_next) if ((is->is_p == pr) && - fr_matchsrcdst(is, src, dst, fin, tcp, - sport, dport)) { + fr_matchsrcdst(is, src, dst, fin, tcp)) { if (fr_tcpstate(is, fin, ip, tcp)) { - pass = is->is_pass; -#ifdef _KERNEL - RWLOCK_EXIT(&ipf_state); -#else - +#ifndef _KERNEL if (tcp->th_flags & TCP_CLOSE) { *isp = is->is_next; - isp = &ips_table[hv]; - KFREE(is); + isp = &ips_table[hvm]; + if (ips_table[hvm] == NULL) + ips_stats.iss_inuse--; + fr_delstate(is); + ips_num--; } #endif - if (fin->fin_fi.fi_fl & FI_FRAG) - ipfr_newfrag(ip, fin, - pass ^ FR_KEEPSTATE); - return pass; + break; } + is = NULL; + break; } + if (is != NULL) + break; RWLOCK_EXIT(&ipf_state); + hv += dport; + hv += sport; + if (tryagain == 0) { + tryagain = 1; + goto retry_tcp; + } break; } case IPPROTO_UDP : { register u_short dport = tcp->th_dport, sport = tcp->th_sport; - hv += dport; - hv += sport; - hv %= IPSTATE_SIZE; + tryagain = 0; +retry_udp: + hvm = hv % fr_statesize; /* * Nothing else to match on but ports. and IP#'s */ READ_ENTER(&ipf_state); - for (is = ips_table[hv]; is; is = is->is_next) + for (is = ips_table[hvm]; is; is = is->is_next) if ((is->is_p == pr) && - fr_matchsrcdst(is, src, dst, fin, - tcp, sport, dport)) { - pass = is->is_pass; - MUTEX_ENTER(&ipf_rw); - is->is_bytes += ip->ip_len; + fr_matchsrcdst(is, src, dst, fin, tcp)) { is->is_age = fr_udptimeout; - ips_stats.iss_hits++; - is->is_pkts++; - MUTEX_EXIT(&ipf_rw); - RWLOCK_EXIT(&ipf_state); - if (fin->fin_fi.fi_fl & FI_FRAG) - ipfr_newfrag(ip, fin, - pass ^ FR_KEEPSTATE); - return pass; + break; } + if (is != NULL) + break; RWLOCK_EXIT(&ipf_state); + hv += dport; + hv += sport; + if (tryagain == 0) { + tryagain = 1; + goto retry_udp; + } break; } default : break; } - ATOMIC_INC(ips_stats.iss_miss); - return 0; + if (is == NULL) { + ATOMIC_INC(ips_stats.iss_miss); + return NULL; + } + MUTEX_ENTER(&ipf_rw); + is->is_bytes += ip->ip_len; + ips_stats.iss_hits++; + is->is_pkts++; + MUTEX_EXIT(&ipf_rw); + fr = is->is_rule; + fin->fin_fr = fr; + pass = is->is_pass; + RWLOCK_EXIT(&ipf_state); + if (fin->fin_fi.fi_fl & FI_FRAG) + ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE); + return fr; +} + + +static void fr_delstate(is) +ipstate_t *is; +{ + frentry_t *fr; + + fr = is->is_rule; + if (fr != NULL) { + ATOMIC_DEC(fr->fr_ref); + if (fr->fr_ref == 0) + KFREE(fr); + } + KFREE(is); } @@ -648,13 +980,17 @@ void fr_stateunload() register ipstate_t *is, **isp; WRITE_ENTER(&ipf_state); - for (i = 0; i < IPSTATE_SIZE; i++) + for (i = fr_statesize - 1; i >= 0; i--) for (isp = &ips_table[i]; (is = *isp); ) { *isp = is->is_next; - KFREE(is); + fr_delstate(is); + ips_num--; } + ips_stats.iss_inuse = 0; ips_num = 0; RWLOCK_EXIT(&ipf_state); + KFREES(ips_table, fr_statesize * sizeof(ipstate_t *)); + ips_table = NULL; } @@ -672,7 +1008,7 @@ void fr_timeoutstate() SPL_NET(s); WRITE_ENTER(&ipf_state); - for (i = 0; i < IPSTATE_SIZE; i++) + for (i = fr_statesize - 1; i >= 0; i--) for (isp = &ips_table[i]; (is = *isp); ) if (is->is_age && !--is->is_age) { *isp = is->is_next; @@ -680,13 +1016,19 @@ void fr_timeoutstate() ips_stats.iss_fin++; else ips_stats.iss_expire++; + if (ips_table[i] == NULL) + ips_stats.iss_inuse--; #ifdef IPFILTER_LOG ipstate_log(is, ISL_EXPIRE); #endif - KFREE(is); + fr_delstate(is); ips_num--; } else isp = &is->is_next; + if (fr_state_doflush) { + (void) fr_state_flush(1); + fr_state_doflush = 0; + } RWLOCK_EXIT(&ipf_state); SPL_X(s); } @@ -726,23 +1068,29 @@ int dir; switch(state[dir]) { - case TCPS_FIN_WAIT_2: case TCPS_CLOSED: + if ((flags & (TH_FIN|TH_SYN|TH_RST|TH_ACK)) == TH_ACK) { + state[dir] = TCPS_ESTABLISHED; + *age = fr_tcpidletimeout; + } + case TCPS_FIN_WAIT_2: if ((flags & TH_OPENING) == TH_OPENING) state[dir] = TCPS_SYN_RECEIVED; else if (flags & TH_SYN) state[dir] = TCPS_SYN_SENT; break; case TCPS_SYN_RECEIVED: - if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) { - state[dir] = TCPS_ESTABLISHED; - *age = fr_tcpidletimeout; - } - break; case TCPS_SYN_SENT: if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) { state[dir] = TCPS_ESTABLISHED; *age = fr_tcpidletimeout; + } else if ((flags & (TH_FIN|TH_ACK)) == (TH_FIN|TH_ACK)) { + state[dir] = TCPS_CLOSE_WAIT; + if (!(flags & TH_PUSH) && !dlen && + ostate > TCPS_ESTABLISHED) + *age = fr_tcplastack; + else + *age = fr_tcpclosewait; } break; case TCPS_ESTABLISHED: @@ -753,8 +1101,10 @@ int dir; *age = fr_tcplastack; else *age = fr_tcpclosewait; - } else - *age = fr_tcpidletimeout; + } else { + if (ostate < TCPS_CLOSE_WAIT) + *age = fr_tcpidletimeout; + } break; case TCPS_CLOSE_WAIT: if ((flags & TH_FIN) && !(flags & TH_PUSH) && !dlen && @@ -783,7 +1133,7 @@ int dir; #ifdef IPFILTER_LOG void ipstate_log(is, type) struct ipstate *is; -u_short type; +u_int type; { struct ipslog ipsl; void *items[1]; @@ -814,6 +1164,6 @@ u_short type; sizes[0] = sizeof(ipsl); types[0] = 0; - (void) ipllog(IPL_LOGSTATE, 0, items, sizes, types, 1); + (void) ipllog(IPL_LOGSTATE, NULL, items, sizes, types, 1); } #endif diff --git a/sys/netinet/ip_state.h b/sys/netinet/ip_state.h index 20aa1b819d3..8752f068b98 100644 --- a/sys/netinet/ip_state.h +++ b/sys/netinet/ip_state.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_state.h,v 1.9 1999/02/05 05:58:54 deraadt Exp $ */ +/* $OpenBSD: ip_state.h,v 1.10 1999/12/15 05:20:23 kjell Exp $ */ /* * Copyright (C) 1995-1998 by Darren Reed. * @@ -7,7 +7,7 @@ * to the original author and the contributors. * * @(#)ip_state.h 1.3 1/12/96 (C) 1995 Darren Reed - * $Id: ip_state.h,v 1.9 1999/02/05 05:58:54 deraadt Exp $ + * $Id: ip_state.h,v 1.10 1999/12/15 05:20:23 kjell Exp $ */ #ifndef __IP_STATE_H__ #define __IP_STATE_H__ @@ -32,13 +32,16 @@ typedef struct icmpstate { u_char ics_type; } icmpstate_t; +typedef struct tcpdata { + u_32_t td_end; + u_32_t td_maxend; + u_short td_maxwin; +} tcpdata_t; + typedef struct tcpstate { u_short ts_sport; u_short ts_dport; - u_long ts_seq; - u_long ts_ack; - u_short ts_swin; - u_short ts_dwin; + tcpdata_t ts_data[2]; u_char ts_state[2]; } tcpstate_t; @@ -50,16 +53,18 @@ typedef struct ipstate { U_QUAD_T is_bytes; void *is_ifpin; void *is_ifpout; + frentry_t *is_rule; struct in_addr is_src; struct in_addr is_dst; - u_char is_p; - u_char is_flags; - u_32_t is_opt; - u_32_t is_optmsk; - u_short is_sec; - u_short is_secmsk; - u_short is_auth; - u_short is_authmsk; + u_char is_p; /* Protocol */ + u_char is_rout; /* Is rule in/out ? */ + u_32_t is_flags; + u_32_t is_opt; /* packet options set */ + u_32_t is_optmsk; /* " " mask */ + u_short is_sec; /* security options set */ + u_short is_secmsk; /* " " mask */ + u_short is_auth; /* authentication options set */ + u_short is_authmsk; /* " " mask */ union { icmpstate_t is_ics; tcpstate_t is_ts; @@ -68,17 +73,29 @@ typedef struct ipstate { } ipstate_t; #define is_icmp is_ps.is_ics +#define is_type is_icmp.ics_type +#define is_code is_icmp.ics_code #define is_tcp is_ps.is_ts #define is_udp is_ps.is_us -#define is_seq is_tcp.ts_seq -#define is_ack is_tcp.ts_ack -#define is_dwin is_tcp.ts_dwin -#define is_swin is_tcp.ts_swin +#define is_send is_tcp.ts_data[0].td_end +#define is_dend is_tcp.ts_data[1].td_end +#define is_maxswin is_tcp.ts_data[0].td_maxwin +#define is_maxdwin is_tcp.ts_data[1].td_maxwin +#define is_maxsend is_tcp.ts_data[0].td_maxend +#define is_maxdend is_tcp.ts_data[1].td_maxend #define is_sport is_tcp.ts_sport #define is_dport is_tcp.ts_dport #define is_state is_tcp.ts_state #define TH_OPENING (TH_SYN|TH_ACK) +/* + * is_flags: + * Bits 0 - 3 are use as a mask with the current packet's bits to check for + * whether it is short, tcp/udp, a fragment or the presence of IP options. + * Bits 4 - 7 are set from the initial packet and contain what the packet + * anded with bits 0-3 must match. + * Bits 8,9 are used to indicate wildcard source/destination port matching. + */ typedef struct ipslog { @@ -88,7 +105,7 @@ typedef struct ipslog { struct in_addr isl_dst; u_char isl_p; u_char isl_flags; - u_char isl_state[2]; + u_char isl_state[2]; u_short isl_type; union { u_short isl_filler[2]; @@ -119,6 +136,7 @@ typedef struct ips_stat { u_long iss_active; u_long iss_logged; u_long iss_logfail; + u_long iss_inuse; ipstate_t **iss_table; } ips_stat_t; @@ -130,13 +148,14 @@ extern u_long fr_tcptimeout; extern u_long fr_tcpclosed; extern u_long fr_udptimeout; extern u_long fr_icmptimeout; +extern int fr_stateinit __P((void)); extern int fr_tcpstate __P((ipstate_t *, fr_info_t *, ip_t *, tcphdr_t *)); -extern int fr_addstate __P((ip_t *, fr_info_t *, u_int)); -extern int fr_checkstate __P((ip_t *, fr_info_t *)); +extern ipstate_t *fr_addstate __P((ip_t *, fr_info_t *, u_int)); +extern frentry_t *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 void ipstate_log __P((struct ipstate *, u_int)); #if defined(__NetBSD__) || defined(__OpenBSD__) extern int fr_state_ioctl __P((caddr_t, u_long, int)); #else |