From 5b3b642ec022d7a8b911de30643c7fae10fe4feb Mon Sep 17 00:00:00 2001 From: cvs2svn Date: Mon, 6 Dec 1999 20:36:52 +0000 Subject: This commit was manufactured by cvs2svn to create branch 'VENDOR-sys-ipfilter'. --- sys/contrib/ipfilter/netinet/ip_raudio_pxy.c | 274 +++++++++++++++++++++++++++ sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c | 160 ++++++++++++++++ sys/contrib/ipfilter/netinet/mlfk_ipl.c | 178 +++++++++++++++++ 3 files changed, 612 insertions(+) create mode 100644 sys/contrib/ipfilter/netinet/ip_raudio_pxy.c create mode 100644 sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c create mode 100644 sys/contrib/ipfilter/netinet/mlfk_ipl.c diff --git a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c new file mode 100644 index 0000000..b76eea5 --- /dev/null +++ b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c @@ -0,0 +1,274 @@ +/* + * $Id$ + * $FreeBSD$ + */ +#if SOLARIS && defined(_KERNEL) +extern kmutex_t ipf_rw; +#endif + +#define IPF_RAUDIO_PROXY + + +int ippr_raudio_init __P((void)); +int ippr_raudio_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_raudio_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_raudio_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); + +static frentry_t raudiofr; + + +/* + * Real Audio application proxy initialization. + */ +int ippr_raudio_init() +{ + bzero((char *)&raudiofr, sizeof(raudiofr)); + raudiofr.fr_ref = 1; + raudiofr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + return 0; +} + + +/* + * Setup for a new proxy to handle Real Audio. + */ +int ippr_raudio_new(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + raudio_t *rap; + + + KMALLOCS(aps->aps_data, void *, sizeof(raudio_t)); + if (aps->aps_data != NULL) { + bzero(aps->aps_data, sizeof(raudio_t)); + rap = aps->aps_data; + aps->aps_psiz = sizeof(raudio_t); + rap->rap_mode = RAP_M_TCP; /* default is for TCP */ + } + return 0; +} + + + +int ippr_raudio_out(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + char membuf[512 + 1], *s; + int off, dlen, inc = 0; + tcphdr_t *tcp, tcph, *tcp2 = &tcph; + raudio_t *rap = aps->aps_data; + u_short sp, dp, id = 0; + struct in_addr swip; + fr_info_t fi; + int len = 0; + nat_t *ipn; + mb_t *m; +#if SOLARIS + mb_t *m1; +#endif + + /* + * If we've already processed the start messages, then nothing left + * for the proxy to do. + */ + if (rap->rap_eos == 1) + return 0; + + tcp = (tcphdr_t *)fin->fin_dp; + off = (ip->ip_hl << 2) + (tcp->th_off << 2); + bzero(membuf, sizeof(membuf)); +#if SOLARIS + m = fin->fin_qfm; + + dlen = msgdsize(m) - off; + if (dlen <= 0) + return 0; + copyout_mblk(m, off, MIN(sizeof(membuf), dlen), membuf); +#else + m = *(mb_t **)fin->fin_mp; + + dlen = mbufchainlen(m) - off; + if (dlen <= 0) + return 0; + m_copydata(m, off, MIN(sizeof(membuf), dlen), membuf); +#endif + /* + * In all the startup parsing, ensure that we don't go outside + * the packet buffer boundary. + */ + /* + * Look for the start of connection "PNA" string if not seen yet. + */ + if (rap->rap_seenpna == 0) { + s = memstr("PNA", membuf, 3, dlen); + if (s == NULL) + return 0; + s += 3; + rap->rap_seenpna = 1; + } else + s = membuf; + + /* + * Directly after the PNA will be the version number of this + * connection. + */ + if (rap->rap_seenpna == 1 && rap->rap_seenver == 0) { + if ((s + 1) - membuf < dlen) { + rap->rap_version = (*s << 8) | *(s + 1); + s += 2; + rap->rap_seenver = 1; + } else + return 0; + } + + /* + * Now that we've been past the PNA and version number, we're into the + * startup messages block. This ends when a message with an ID of 0. + */ + while ((rap->rap_eos == 0) && ((s + 1) - membuf < dlen)) { + if (rap->rap_gotid == 0) { + id = (*s << 8) | *(s + 1); + s += 2; + rap->rap_gotid = 1; + if (id == RA_ID_END) { + rap->rap_eos = 1; + break; + } + } else if (rap->rap_gotlen == 0) { + len = (*s << 8) | *(s + 1); + s += 2; + rap->rap_gotlen = 1; + } + + if (rap->rap_gotid == 1 && rap->rap_gotlen == 1) { + if (id == RA_ID_UDP) { + rap->rap_mode &= ~RAP_M_TCP; + rap->rap_mode |= RAP_M_UDP; + rap->rap_plport = (*s << 8) | *(s + 1); + } else if (id == RA_ID_ROBUST) { + rap->rap_mode |= RAP_M_ROBUST; + rap->rap_prport = (*s << 8) | *(s + 1); + } + s += len; + rap->rap_gotlen = 0; + rap->rap_gotid = 0; + } + } + + /* + * Wait until we've seen the end of the start messages and even then + * only proceed further if we're using UDP. + */ + if ((rap->rap_eos == 0) || ((rap->rap_mode & RAP_M_UDP) != RAP_M_UDP)) + return 0; + sp = rap->rap_plport; + dp = 0; + + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + bzero((char *)tcp2, sizeof(*tcp2)); + tcp2->th_sport = htons(sp); + tcp2->th_dport = 0; /* XXX - don't specify remote port */ + tcp2->th_win = htons(8192); + fi.fin_dp = (char *)tcp2; + fi.fin_data[0] = sp; + fi.fin_data[1] = 0; + fi.fin_fr = &raudiofr; + swip = ip->ip_src; + ip->ip_src = nat->nat_inip; + 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, FI_W_DPORT); + } + ip->ip_src = swip; + + if ((rap->rap_mode & RAP_M_UDP_ROBUST) == RAP_M_UDP_ROBUST) { + sp = rap->rap_prport; + } + return inc; +} + + +int ippr_raudio_in(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + char membuf[IPF_MAXPORTLEN + 1], *s; + int off, dlen; + raudio_t *rap = aps->aps_data; + u_int a1, a2, a3, a4; + tcphdr_t *tcp; + tcp_seq seq; + mb_t *m; +#if SOLARIS + mb_t *m1; +#endif + + if ((rap->rap_sdone != 0) || + ((rap->rap_mode & RAP_M_UDP_ROBUST) != RAP_M_UDP_ROBUST)) + return 0; + + tcp = (tcphdr_t *)fin->fin_dp; + 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; + if (dlen <= 0) + return 0; + bzero(membuf, sizeof(membuf)); + copyout_mblk(m, off, MIN(sizeof(membuf), dlen), membuf); +#else + dlen = mbufchainlen(m) - off; + if (dlen <= 0) + return 0; + bzero(membuf, sizeof(membuf)); + m_copydata(m, off, MIN(sizeof(membuf), dlen), membuf); +#endif + + seq = ntohl(tcp->th_seq); + /* + * Check to see if the data in this packet is of interest to us. + * We only care for the first 19 bytes coming back from the server. + */ + if (rap->rap_sseq == 0) { + s = memstr("PNA", membuf, 3, dlen); + if (s == NULL) + return 0; + a1 = s - membuf; + dlen -= a1; + a1 = 0; + rap->rap_sseq = seq; + a2 = MIN(dlen, sizeof(rap->rap_svr)); + } else if (seq <= rap->rap_sseq + sizeof(rap->rap_svr)) { + /* + * seq # which is the start of data and from that the offset + * into the buffer array. + */ + a1 = seq - rap->rap_sseq; + a2 = MIN(dlen, sizeof(rap->rap_svr)); + a2 -= a1; + s = membuf; + } else + return 0; + + for (a3 = a1, a4 = a2; a4 > 0; a4--, a3++) { + rap->rap_sbf |= (1 << a3); + rap->rap_svr[a3] = *s++; + } + if (rap->rap_sbf == 0x7ffff) { /* 19 bits */ + s = rap->rap_svr + 13; + rap->rap_srport = (*s << 8) | *(s + 1); + } + return 0; +} diff --git a/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c b/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c new file mode 100644 index 0000000..f9dc5b3 --- /dev/null +++ b/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c @@ -0,0 +1,160 @@ +/* + * $Id$ + * $FreeBSD$ + */ +/* + * Simple RCMD transparent proxy for in-kernel use. For use with the NAT + * code. + */ +#if SOLARIS && defined(_KERNEL) +extern kmutex_t ipf_rw; +#endif + +#define isdigit(x) ((x) >= '0' && (x) <= '9') + +#define IPF_RCMD_PROXY + + +int ippr_rcmd_init __P((void)); +int ippr_rcmd_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_rcmd_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +u_short ipf_rcmd_atoi __P((char *)); +int ippr_rcmd_portmsg __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); + +static frentry_t rcmdfr; + + +/* + * RCMD application proxy initialization. + */ +int ippr_rcmd_init() +{ + bzero((char *)&rcmdfr, sizeof(rcmdfr)); + rcmdfr.fr_ref = 1; + rcmdfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + return 0; +} + + +/* + * Setup for a new RCMD proxy. + */ +int ippr_rcmd_new(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; + + aps->aps_psiz = sizeof(u_32_t); + KMALLOCS(aps->aps_data, u_32_t *, sizeof(u_32_t)); + if (aps->aps_data == NULL) + return -1; + *(u_32_t *)aps->aps_data = 0; + aps->aps_sport = tcp->th_sport; + aps->aps_dport = tcp->th_dport; + return 0; +} + + +/* + * ipf_rcmd_atoi - implement a simple version of atoi + */ +u_short ipf_rcmd_atoi(ptr) +char *ptr; +{ + register char *s = ptr, c; + register u_short i = 0; + + while ((c = *s++) && isdigit(c)) { + i *= 10; + i += c - '0'; + } + return i; +} + + +int ippr_rcmd_portmsg(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + char portbuf[8], *s; + struct in_addr swip; + u_short sp, dp; + int off, dlen; + tcphdr_t *tcp, tcph, *tcp2 = &tcph; + fr_info_t fi; + nat_t *ipn; + mb_t *m; +#if SOLARIS + 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; + +#if SOLARIS + m = fin->fin_qfm; + + dlen = msgdsize(m) - off; + bzero(portbuf, sizeof(portbuf)); + 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); +#endif + if ((*(u_32_t *)aps->aps_data != 0) && + (tcp->th_seq != *(u_32_t *)aps->aps_data)) + return 0; + + portbuf[sizeof(portbuf) - 1] = '\0'; + s = portbuf; + sp = ipf_rcmd_atoi(s); + if (!sp) + return 0; + + /* + * Add skeleton NAT entry for connection which will come back the + * other way. + */ + sp = htons(sp); + dp = htons(fin->fin_data[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 = sp; + 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|FI_W_DPORT, + NAT_OUTBOUND); + if (ipn != NULL) { + ipn->nat_age = fr_defnatage; + fi.fin_fr = &rcmdfr; + (void) fr_addstate(ip, &fi, FI_W_DPORT); + } + ip->ip_src = swip; + } + return 0; +} + + +int ippr_rcmd_out(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + return ippr_rcmd_portmsg(fin, ip, aps, nat); +} diff --git a/sys/contrib/ipfilter/netinet/mlfk_ipl.c b/sys/contrib/ipfilter/netinet/mlfk_ipl.c new file mode 100644 index 0000000..28e7c5d --- /dev/null +++ b/sys/contrib/ipfilter/netinet/mlfk_ipl.c @@ -0,0 +1,178 @@ +/* + * Copyright 1999 Guido van Rooij. All rights reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include + +static dev_t ipf_devs[IPL_LOGMAX + 1]; + +SYSCTL_DECL(_net_inet); +SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF"); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &fr_flags, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_pass, CTLFLAG_RW, &fr_pass, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &fr_active, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RW, + &fr_tcpidletimeout, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RW, + &fr_tcpclosewait, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RW, + &fr_tcplastack, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RW, + &fr_tcptimeout, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RW, + &fr_tcpclosed, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RW, + &fr_udptimeout, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RW, + &fr_icmptimeout, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RW, + &fr_defnatage, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW, + &fr_ipfrttl, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, ipl_unreach, CTLFLAG_RW, + &ipl_unreach, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, ipl_inited, CTLFLAG_RD, + &ipl_inited, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RD, + &fr_authsize, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, + &fr_authused, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW, + &fr_defaultauthage, 0, ""); + +#define CDEV_MAJOR 79 +static struct cdevsw ipl_cdevsw = { + /* open */ iplopen, + /* close */ iplclose, + /* read */ iplread, + /* write */ nowrite, + /* ioctl */ iplioctl, + /* poll */ nopoll, + /* mmap */ nommap, + /* strategy */ nostrategy, + /* name */ "ipl", + /* maj */ CDEV_MAJOR, + /* dump */ nodump, + /* psize */ nopsize, + /* flags */ 0, + /* bmaj */ -1 +}; + +static int +ipfilter_modevent(module_t mod, int type, void *unused) +{ + char *c; + int i, error = 0; + + switch (type) { + case MOD_LOAD : + error = iplattach(); + + c = NULL; + for(i=strlen(IPL_NAME); i>0; i--) + if (IPL_NAME[i] == '/') { + c = &IPL_NAME[i+1]; + break; + } + if (!c) + c = IPL_NAME; + ipf_devs[IPL_LOGIPF] = + make_dev(&ipl_cdevsw, IPL_LOGIPF, 0, 0, 0600, c); + + c = NULL; + for(i=strlen(IPL_NAT); i>0; i--) + if (IPL_NAT[i] == '/') { + c = &IPL_NAT[i+1]; + break; + } + if (!c) + c = IPL_NAT; + ipf_devs[IPL_LOGNAT] = + make_dev(&ipl_cdevsw, IPL_LOGNAT, 0, 0, 0600, c); + + c = NULL; + for(i=strlen(IPL_STATE); i>0; i--) + if (IPL_STATE[i] == '/') { + c = &IPL_STATE[i+1]; + break; + } + if (!c) + c = IPL_STATE; + ipf_devs[IPL_LOGSTATE] = + make_dev(&ipl_cdevsw, IPL_LOGSTATE, 0, 0, 0600, c); + + c = NULL; + for(i=strlen(IPL_AUTH); i>0; i--) + if (IPL_AUTH[i] == '/') { + c = &IPL_AUTH[i+1]; + break; + } + if (!c) + c = IPL_AUTH; + ipf_devs[IPL_LOGAUTH] = + make_dev(&ipl_cdevsw, IPL_LOGAUTH, 0, 0, 0600, c); + + break; + case MOD_UNLOAD : + destroy_dev(ipf_devs[IPL_LOGIPF]); + destroy_dev(ipf_devs[IPL_LOGNAT]); + destroy_dev(ipf_devs[IPL_LOGSTATE]); + destroy_dev(ipf_devs[IPL_LOGAUTH]); + cdevsw_remove(&ipl_cdevsw); + error = ipldetach(); + break; + default: + error = EINVAL; + break; + } + return error; +} + +static moduledata_t ipfiltermod = { + IPL_VERSION, + ipfilter_modevent, + 0 +}; +DECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); -- cgit v1.1 From 911a5a839ebebfd4887c6d90650da5a675d9aaa0 Mon Sep 17 00:00:00 2001 From: darrenr Date: Wed, 24 May 2000 02:55:58 +0000 Subject: Import IP Filter 3.4.4 into the kernel --- sys/contrib/ipfilter/netinet/fil.c | 1402 ++++++++++++----- sys/contrib/ipfilter/netinet/ip_auth.c | 189 ++- sys/contrib/ipfilter/netinet/ip_auth.h | 36 +- sys/contrib/ipfilter/netinet/ip_compat.h | 381 ++++- sys/contrib/ipfilter/netinet/ip_fil.c | 980 ++++++++---- sys/contrib/ipfilter/netinet/ip_fil.h | 402 +++-- sys/contrib/ipfilter/netinet/ip_frag.c | 374 +++-- sys/contrib/ipfilter/netinet/ip_frag.h | 18 +- sys/contrib/ipfilter/netinet/ip_ftp_pxy.c | 789 ++++++++-- sys/contrib/ipfilter/netinet/ip_log.c | 206 +-- sys/contrib/ipfilter/netinet/ip_nat.c | 2070 +++++++++++++++++++------- sys/contrib/ipfilter/netinet/ip_nat.h | 215 ++- sys/contrib/ipfilter/netinet/ip_proxy.c | 410 +++-- sys/contrib/ipfilter/netinet/ip_proxy.h | 106 +- sys/contrib/ipfilter/netinet/ip_raudio_pxy.c | 155 +- sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c | 9 +- sys/contrib/ipfilter/netinet/ip_state.c | 1520 +++++++++++++++---- sys/contrib/ipfilter/netinet/ip_state.h | 116 +- sys/contrib/ipfilter/netinet/ipl.h | 5 +- sys/contrib/ipfilter/netinet/mlfk_ipl.c | 11 +- 20 files changed, 6875 insertions(+), 2519 deletions(-) diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index f2b19a5..258f76e 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/netinet/fil.c @@ -1,21 +1,35 @@ /* - * Copyright (C) 1993-1997 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ #if !defined(lint) -static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-1996 Darren Reed"; -static const char rcsid[] = "@(#)$Id: fil.c,v 2.0.2.41.2.14 1998/05/23 19:20:30 darrenr Exp $"; +static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.8 2000/05/22 10:26:09 darrenr Exp $"; #endif +#if defined(_KERNEL) && defined(__FreeBSD_version) && \ + (__FreeBSD_version >= 400000) && !defined(KLD_MODULE) +#include "opt_inet6.h" +#endif #include #include #include #include #include -#include +#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ + defined(_KERNEL) +# include "opt_ipfilter_log.h" +#endif +#if (defined(KERNEL) || defined(_KERNEL)) && defined(__FreeBSD_version) && \ + (__FreeBSD_version >= 220000) +# include +# include +#else +# include +#endif #if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) # include #else @@ -30,8 +44,10 @@ static const char rcsid[] = "@(#)$Id: fil.c,v 2.0.2.41.2.14 1998/05/23 19:20:30 # endif #else # include -# include -# include +# if SOLARIS2 < 5 +# include +# endif +# include #endif #ifndef linux # include @@ -48,10 +64,20 @@ static const char rcsid[] = "@(#)$Id: fil.c,v 2.0.2.41.2.14 1998/05/23 19:20:30 #ifndef linux # include #endif +#if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ +# include +# include +#endif #include #include #include #include "netinet/ip_compat.h" +#ifdef USE_INET6 +# include +# if !SOLARIS && defined(_KERNEL) +# include +# endif +#endif #include #include "netinet/ip_fil.h" #include "netinet/ip_proxy.h" @@ -59,88 +85,68 @@ static const char rcsid[] = "@(#)$Id: fil.c,v 2.0.2.41.2.14 1998/05/23 19:20:30 #include "netinet/ip_frag.h" #include "netinet/ip_state.h" #include "netinet/ip_auth.h" +# if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include +# 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" # include "ipt.h" extern int opts; -# define FR_IFVERBOSE(ex,second,verb_pr) if (ex) { verbose verb_pr; \ - second; } -# define FR_IFDEBUG(ex,second,verb_pr) if (ex) { debug verb_pr; \ - second; } # define FR_VERBOSE(verb_pr) verbose verb_pr # define FR_DEBUG(verb_pr) debug verb_pr -# define SEND_RESET(ip, qif, if, m) send_reset(ip, if) # define IPLLOG(a, c, d, e) ipllog() -# define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip) -# if SOLARIS -# define ICMP_ERROR(b, ip, t, c, if, src) icmp_error(ip) -# else -# define ICMP_ERROR(b, ip, t, c, if, src) icmp_error(b, ip, if) -# endif #else /* #ifndef _KERNEL */ -# define FR_IFVERBOSE(ex,second,verb_pr) ; -# define FR_IFDEBUG(ex,second,verb_pr) ; # define FR_VERBOSE(verb_pr) # define FR_DEBUG(verb_pr) # define IPLLOG(a, c, d, e) ipflog(a, c, d, e) # if SOLARIS || defined(__sgi) -extern kmutex_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) # else /* SOLARIS */ # define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip) -# ifdef linux -# define SEND_RESET(ip, qif, if) send_reset((tcpiphdr_t *)ip,\ - ifp) -# else -# define SEND_RESET(ip, qif, if) send_reset((tcpiphdr_t *)ip) -# endif -# ifdef __sgi -# define ICMP_ERROR(b, ip, t, c, if, src) \ - icmp_error(b, t, c, if, src, if) -# else -# if BSD < 199103 -# ifdef linux -# define ICMP_ERROR(b, ip, t, c, if, src) icmp_send(b,t,c,0,if) -# else -# define ICMP_ERROR(b, ip, t, c, if, src) \ - icmp_error(mtod(b, ip_t *), t, c, if, src) -# 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) # endif /* SOLARIS || __sgi */ #endif /* _KERNEL */ struct filterstats frstats[2] = {{0,0,0,0,0},{0,0,0,0,0}}; struct frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } }, +#ifdef USE_INET6 + *ipfilter6[2][2] = { { NULL, NULL }, { NULL, NULL } }, + *ipacct6[2][2] = { { NULL, NULL }, { NULL, NULL } }, +#endif *ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } }; struct frgroup *ipfgroups[3][2]; -int fr_flags = IPF_LOGGING, fr_active = 0; +int fr_flags = IPF_LOGGING; +int fr_active = 0; +int fr_chksrc = 0; #if defined(IPFILTER_DEFAULT_BLOCK) 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 /* @@ -188,55 +194,102 @@ 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; { - struct optlist *op; - tcphdr_t *tcp; - icmphdr_t *icmp; - fr_ip_t *fi = &fin->fin_fi; u_short optmsk = 0, secmsk = 0, auth = 0; - int i, mv, ol, off; + int i, mv, ol, off, p, plen, v; + fr_ip_t *fi = &fin->fin_fi; + struct optlist *op; u_char *s, opt; + tcphdr_t *tcp; + fin->fin_rev = 0; fin->fin_fr = NULL; fin->fin_tcpf = 0; fin->fin_data[0] = 0; fin->fin_data[1] = 0; fin->fin_rule = -1; fin->fin_group = -1; - fin->fin_id = ip->ip_id; #ifdef _KERNEL fin->fin_icode = ipl_unreach; #endif - fi->fi_v = ip->ip_v; - fi->fi_tos = ip->ip_tos; + v = fin->fin_v; + fi->fi_v = v; fin->fin_hlen = hlen; - fin->fin_dlen = ip->ip_len - hlen; - tcp = (tcphdr_t *)((char *)ip + hlen); - icmp = (icmphdr_t *)tcp; + if (v == 4) { + fin->fin_id = ip->ip_id; + fi->fi_tos = ip->ip_tos; + off = (ip->ip_off & IP_OFFMASK) << 3; + tcp = (tcphdr_t *)((char *)ip + hlen); + (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4)); + fi->fi_src.i6[1] = 0; + fi->fi_src.i6[2] = 0; + fi->fi_src.i6[3] = 0; + fi->fi_dst.i6[1] = 0; + fi->fi_dst.i6[2] = 0; + fi->fi_dst.i6[3] = 0; + fi->fi_saddr = ip->ip_src.s_addr; + fi->fi_daddr = ip->ip_dst.s_addr; + p = ip->ip_p; + fi->fi_fl = (hlen > sizeof(ip_t)) ? FI_OPTIONS : 0; + if (ip->ip_off & 0x3fff) + fi->fi_fl |= FI_FRAG; + plen = ip->ip_len; + fin->fin_dlen = plen - hlen; + } +#ifdef USE_INET6 + else if (v == 6) { + ip6_t *ip6 = (ip6_t *)ip; + + off = 0; + p = ip6->ip6_nxt; + fi->fi_p = p; + fi->fi_ttl = ip6->ip6_hlim; + tcp = (tcphdr_t *)(ip6 + 1); + fi->fi_src.in6 = ip6->ip6_src; + fi->fi_dst.in6 = ip6->ip6_dst; + fin->fin_id = (u_short)(ip6->ip6_flow & 0xffff); + fi->fi_tos = 0; + fi->fi_fl = 0; + plen = ntohs(ip6->ip6_plen); + fin->fin_dlen = plen; + } +#endif + else + return; + + fin->fin_off = off; + fin->fin_plen = plen; 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_fl = (hlen > sizeof(ip_t)) ? FI_OPTIONS : 0; - off = (ip->ip_off & 0x1fff) << 3; - if (ip->ip_off & 0x3fff) - fi->fi_fl |= FI_FRAG; - switch (ip->ip_p) + + switch (p) { case IPPROTO_ICMP : { int minicmpsz = sizeof(struct icmp); + icmphdr_t *icmp; + + icmp = (icmphdr_t *)tcp; - if (!off && ip->ip_len > ICMP_MINLEN + hlen && - (icmp->icmp_type == ICMP_ECHOREPLY || - icmp->icmp_type == ICMP_UNREACH)) + if (!off && (icmp->icmp_type == ICMP_ECHOREPLY || + icmp->icmp_type == ICMP_ECHO)) minicmpsz = ICMP_MINLEN; - if ((!(ip->ip_len >= hlen + minicmpsz) && !off) || + + /* type(1) + code(1) + cksum(2) + id(2) seq(2) + + * 3*timestamp(3*4) */ + else if (!off && (icmp->icmp_type == ICMP_TSTAMP || + icmp->icmp_type == ICMP_TSTAMPREPLY)) + minicmpsz = 20; + + /* type(1) + code(1) + cksum(2) + id(2) seq(2) + mask(4) */ + else if (!off && (icmp->icmp_type == ICMP_MASKREQ || + icmp->icmp_type == ICMP_MASKREPLY)) + minicmpsz = 12; + + if ((!(plen >= hlen + minicmpsz) && !off) || (off && off < sizeof(struct icmp))) fi->fi_fl |= FI_SHORT; if (fin->fin_dlen > 1) @@ -245,17 +298,33 @@ fr_info_t *fin; } case IPPROTO_TCP : fi->fi_fl |= FI_TCPUDP; - if ((!IPMINLEN(ip, tcphdr) && !off) || - (off && off < sizeof(struct tcphdr))) - fi->fi_fl |= FI_SHORT; +#ifdef USE_INET6 + if (v == 6) { + if (plen < sizeof(struct tcphdr)) + fi->fi_fl |= FI_SHORT; + } else +#endif + if (v == 4) { + if ((!IPMINLEN(ip, tcphdr) && !off) || + (off && off < sizeof(struct tcphdr))) + fi->fi_fl |= FI_SHORT; + } if (!(fi->fi_fl & FI_SHORT) && !off) fin->fin_tcpf = tcp->th_flags; goto getports; case IPPROTO_UDP : fi->fi_fl |= FI_TCPUDP; - if ((!IPMINLEN(ip, udphdr) && !off) || - (off && off < sizeof(struct udphdr))) - fi->fi_fl |= FI_SHORT; +#ifdef USE_INET6 + if (v == 6) { + if (plen < sizeof(struct udphdr)) + fi->fi_fl |= FI_SHORT; + } else +#endif + if (v == 4) { + if ((!IPMINLEN(ip, udphdr) && !off) || + (off && off < sizeof(struct udphdr))) + fi->fi_fl |= FI_SHORT; + } getports: if (!off && (fin->fin_dlen > 3)) { fin->fin_data[0] = ntohs(tcp->th_sport); @@ -266,13 +335,28 @@ getports: break; } +#ifdef USE_INET6 + if (v == 6) { + fi->fi_optmsk = 0; + fi->fi_secmsk = 0; + fi->fi_auth = 0; + return; + } +#endif - for (s = (u_char *)(ip + 1), hlen -= sizeof(*ip); hlen; ) { - if (!(opt = *s)) - break; - ol = (opt == IPOPT_NOP) ? 1 : (int)*(s+1); - if (opt > 1 && (ol < 2 || ol > hlen)) + for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) { + opt = *s; + if (opt == '\0') break; + else if (opt == IPOPT_NOP) + ol = 1; + else { + if (hlen < 2) + break; + ol = (int)*(s + 1); + if (ol < 2 || ol > hlen) + break; + } for (i = 9, mv = 4; mv >= 0; ) { op = ipopts + i; if (opt == (u_char)op->ol_val) { @@ -319,8 +403,8 @@ getports: /* * check an IP packet for TCP/UDP characteristics such as ports and flags. */ -static int fr_tcpudpchk(fr, fin) -frentry_t *fr; +int fr_tcpudpchk(ft, fin) +frtuc_t *ft; fr_info_t *fin; { register u_short po, tup; @@ -333,8 +417,8 @@ fr_info_t *fin; * * compare destination ports */ - if ((i = (int)fr->fr_dcmp)) { - po = fr->fr_dport; + if ((i = (int)ft->ftu_dcmp)) { + po = ft->ftu_dport; tup = fin->fin_data[1]; /* * Do opposite test to that required and @@ -353,17 +437,17 @@ fr_info_t *fin; else if (!--i && tup < po) /* GT or EQ */ err = 0; else if (!--i && /* Out of range */ - (tup >= po && tup <= fr->fr_dtop)) + (tup >= po && tup <= ft->ftu_dtop)) err = 0; else if (!--i && /* In range */ - (tup <= po || tup >= fr->fr_dtop)) + (tup <= po || tup >= ft->ftu_dtop)) err = 0; } /* * compare source ports */ - if (err && (i = (int)fr->fr_scmp)) { - po = fr->fr_sport; + if (err && (i = (int)ft->ftu_scmp)) { + po = ft->ftu_sport; tup = fin->fin_data[0]; if (!--i && tup != po) err = 0; @@ -378,10 +462,10 @@ fr_info_t *fin; else if (!--i && tup < po) err = 0; else if (!--i && /* Out of range */ - (tup >= po && tup <= fr->fr_stop)) + (tup >= po && tup <= ft->ftu_stop)) err = 0; else if (!--i && /* In range */ - (tup <= po || tup >= fr->fr_stop)) + (tup <= po || tup >= ft->ftu_stop)) err = 0; } @@ -393,14 +477,14 @@ fr_info_t *fin; */ if (err && (fin->fin_fi.fi_p == IPPROTO_TCP)) { if (fin->fin_fi.fi_fl & FI_SHORT) - return !(fr->fr_tcpf | fr->fr_tcpfm); + return !(ft->ftu_tcpf | ft->ftu_tcpfm); /* * Match the flags ? If not, abort this match. */ - if (fr->fr_tcpf && - fr->fr_tcpf != (fin->fin_tcpf & fr->fr_tcpfm)) { + if (ft->ftu_tcpfm && + ft->ftu_tcpf != (fin->fin_tcpf & ft->ftu_tcpfm)) { FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf, - fr->fr_tcpfm, fr->fr_tcpf)); + ft->ftu_tcpfm, ft->ftu_tcpf)); err = 0; } } @@ -413,23 +497,27 @@ 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; fin->fin_rule = 0; fin->fin_group = 0; - off = ip->ip_off & 0x1fff; + if (fin->fin_v == 4) + off = ip->ip_off & IP_OFFMASK; + else + off = 0; pass |= (fi->fi_fl << 24); - if ((fi->fi_fl & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) + if ((fi->fi_fl & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) portcmp = 1; for (rulen = 0; fr; fr = fr->fr_next, rulen++) { @@ -444,8 +532,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"); @@ -462,22 +558,77 @@ void *m; lip = (u_32_t *)fi; lm = (u_32_t *)&fr->fr_mip; ld = (u_32_t *)&fr->fr_ip; - i = ((lip[0] & lm[0]) != ld[0]); - FR_IFDEBUG(i,continue,("0. %#08x & %#08x != %#08x\n", - lip[0], lm[0], ld[0])); - i |= ((lip[1] & lm[1]) != ld[1]) << 21; - FR_IFDEBUG(i,continue,("1. %#08x & %#08x != %#08x\n", - lip[1], lm[1], ld[1])); - i |= ((lip[2] & lm[2]) != ld[2]) << 22; - FR_IFDEBUG(i,continue,("2. %#08x & %#08x != %#08x\n", - lip[2], lm[2], ld[2])); - i |= ((lip[3] & lm[3]) != ld[3]); - FR_IFDEBUG(i,continue,("3. %#08x & %#08x != %#08x\n", - lip[3], lm[3], ld[3])); - i |= ((lip[4] & lm[4]) != ld[4]); - FR_IFDEBUG(i,continue,("4. %#08x & %#08x != %#08x\n", - lip[4], lm[4], ld[4])); - i ^= (fi->fi_fl & (FR_NOTSRCIP|FR_NOTDSTIP)); + i = ((*lip & *lm) != *ld); + FR_DEBUG(("0. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (i) + continue; + /* + * We now know whether the packet version and the + * rule version match, along with protocol, ttl and + * tos. + */ + lip++, lm++, ld++; + /* + * Unrolled loops (4 each, for 32 bits). + */ + i |= ((*lip & *lm) != *ld) << 19; + FR_DEBUG(("1a. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (fi->fi_v == 6) { + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 19; + FR_DEBUG(("1b. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 19; + FR_DEBUG(("1c. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 19; + FR_DEBUG(("1d. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + } else { + lip += 3; + lm += 3; + ld += 3; + } + i ^= (fr->fr_flags & FR_NOTSRCIP); + if (i) + continue; + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 20; + FR_DEBUG(("2a. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + if (fi->fi_v == 6) { + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 20; + FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 20; + FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld) << 20; + FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + } else { + lip += 3; + lm += 3; + ld += 3; + } + i ^= (fr->fr_flags & FR_NOTDSTIP); + if (i) + continue; + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("3. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); + lip++, lm++, ld++; + i |= ((*lip & *lm) != *ld); + FR_DEBUG(("4. %#08x & %#08x != %#08x\n", + *lip, *lm, *ld)); if (i) continue; } @@ -490,7 +641,7 @@ void *m; fr->fr_tcpfm)) continue; if (fi->fi_fl & FI_TCPUDP) { - if (!fr_tcpudpchk(fr, fin)) + if (!fr_tcpudpchk(&fr->fr_tuc, fin)) continue; } else if (fr->fr_icmpm || fr->fr_icmp) { if ((fi->fi_p != IPPROTO_ICMP) || off || @@ -507,26 +658,31 @@ 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)) - frstats[fin->fin_out].fr_skip++; - frstats[fin->fin_out].fr_pkl++; + if ((passt & FR_LOGMASK) == FR_LOG) { + if (!IPLLOG(passt, ip, fin, m)) { + if (passt & FR_LOGORBLOCK) + passt |= FR_BLOCK|FR_QUICK; + ATOMIC_INCL(frstats[fin->fin_out].fr_skip); + } + ATOMIC_INCL(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)); - fr->fr_hits++; + ATOMIC_INCL(fr->fr_hits); if (pass & FR_ACCOUNT) fr->fr_bytes += (U_QUAD_T)ip->ip_len; else fin->fin_icode = fr->fr_icode; fin->fin_rule = rulen; fin->fin_group = fr->fr_group; - fin->fin_fr = fr; if (fr->fr_grp) { fin->fin_fr = fr->fr_grp; pass = fr_scanlist(pass, ip, fin, m); @@ -535,17 +691,21 @@ 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; } /* * frcheck - filter check - * check using source and destination addresses/pors in a packet whether + * check using source and destination addresses/ports in a packet whether * or not to pass it on or not. */ int fr_check(ip, hlen, ifp, out @@ -566,8 +726,9 @@ 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, v = ip->ip_v; + frentry_t *fr = NULL, *list; + u_32_t pass, apass; #if !SOLARIS || !defined(_KERNEL) register mb_t *m = *mp; #endif @@ -580,71 +741,118 @@ int out; # endif int up; -#ifdef M_CANFASTFWD +# ifdef M_CANFASTFWD /* * XXX For now, IP Filter and fast-forwarding of cached flows * XXX are mutually exclusive. Eventually, IP Filter should * XXX get a "can-fast-forward" filter rule. */ m->m_flags &= ~M_CANFASTFWD; -#endif /* M_CANFASTFWD */ +# endif /* M_CANFASTFWD */ +# ifdef CSUM_DELAY_DATA + /* + * disable delayed checksums. + */ + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + in_delayed_cksum(m); + m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; + } +# endif /* CSUM_DELAY_DATA */ + if ((ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_ICMP)) { int plen = 0; - switch(ip->ip_p) - { - case IPPROTO_TCP: - plen = sizeof(tcphdr_t); - break; - case IPPROTO_UDP: - plen = sizeof(udphdr_t); - break; - case IPPROTO_ICMP: + if ((ip->ip_off & IP_OFFMASK) == 0) + switch(ip->ip_p) + { + case IPPROTO_TCP: + plen = sizeof(tcphdr_t); + break; + case IPPROTO_UDP: + plen = sizeof(udphdr_t); + break; /* 96 - enough for complete ICMP error IP header */ - plen = sizeof(struct icmp) + sizeof(ip_t) + 8; - break; - } + case IPPROTO_ICMP: + plen = ICMPERR_MAXPKTLEN - sizeof(ip_t); + break; + } up = MIN(hlen + plen, ip->ip_len); if (up > m->m_len) { -#ifdef __sgi /* Under IRIX, avoid m_pullup as it makes ping panic */ +# ifdef __sgi + /* Under IRIX, avoid m_pullup as it makes ping panic */ if ((up > sizeof(hbuf)) || (m_length(m) < up)) { - frstats[out].fr_pull[1]++; + ATOMIC_INCL(frstats[out].fr_pull[1]); return -1; } m_copydata(m, 0, up, hbuf); - frstats[out].fr_pull[0]++; + ATOMIC_INCL(frstats[out].fr_pull[0]); ip = (ip_t *)hbuf; -#else -# ifndef linux +# else /* __ sgi */ +# ifndef linux if ((*mp = m_pullup(m, up)) == 0) { - frstats[out].fr_pull[1]++; + ATOMIC_INCL(frstats[out].fr_pull[1]); return -1; } else { - frstats[out].fr_pull[0]++; + ATOMIC_INCL(frstats[out].fr_pull[0]); m = *mp; ip = mtod(m, ip_t *); } -# endif -#endif +# endif /* !linux */ +# endif /* __sgi */ } else up = 0; } else up = 0; -# endif +# endif /* !defined(__SVR4) && !defined(__svr4__) */ # 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 - fr_makefrip(hlen, ip, fin); +# ifdef USE_INET6 + if (v == 6) { + ATOMIC_INCL(frstats[0].fr_ipv6[out]); + } else +# endif + if (!out && fr_chksrc && !fr_verifysrc(ip->ip_src, ifp)) { + ATOMIC_INCL(frstats[0].fr_badsrc); +# if !SOLARIS + m_freem(m); +# endif + return error; + } +#endif /* _KERNEL */ + + /* + * Be careful here: ip_id is in network byte order when called + * from ip_output() + */ + if ((out) && (v == 4)) + ip->ip_id = ntohs(ip->ip_id); + + changed = 0; + fin->fin_v = v; fin->fin_ifp = ifp; fin->fin_out = out; fin->fin_mp = mp; + fr_makefrip(hlen, ip, fin); + pass = fr_pass; - MUTEX_ENTER(&ipf_mutex); + if (fin->fin_fi.fi_fl & FI_SHORT) { + ATOMIC_INCL(frstats[out].fr_short); + } + + READ_ENTER(&ipf_mutex); + if (fin->fin_fi.fi_fl & FI_SHORT) + ATOMIC_INCL(frstats[out].fr_short); + /* * Check auth now. This, combined with the check below to see if apass * is 0 is to ensure that we don't count the packet twice, which can @@ -655,14 +863,21 @@ int out; apass = fr_checkauth(ip, fin); if (!out) { - changed = ip_natin(ip, hlen, fin); - if (!apass && (fin->fin_fr = ipacct[0][fr_active]) && - (FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) - frstats[0].fr_acct++; +#ifdef USE_INET6 + if (v == 6) + list = ipacct6[0][fr_active]; + else +#endif + list = ipacct[0][fr_active]; + changed = ip_natin(ip, fin); + if (!apass && (fin->fin_fr = list) && + (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { + ATOMIC_INCL(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 @@ -676,19 +891,26 @@ int out; * earlier. */ bcopy((char *)fc, (char *)fin, FI_COPYSIZE); - frstats[out].fr_chit++; + ATOMIC_INCL(frstats[out].fr_chit); if ((fr = fin->fin_fr)) { - fr->fr_hits++; + ATOMIC_INCL(fr->fr_hits); pass = fr->fr_flags; - } else - pass = fr_pass; + } } else { - pass = fr_pass; - if ((fin->fin_fr = ipfilter[out][fr_active])) - pass = FR_SCANLIST(fr_pass, ip, fin, m); - bcopy((char *)fin, (char *)fc, FI_COPYSIZE); - if (pass & FR_NOMATCH) - frstats[out].fr_nom++; +#ifdef USE_INET6 + if (v == 6) + list = ipfilter6[out][fr_active]; + else +#endif + list = ipfilter[out][fr_active]; + if ((fin->fin_fr = list)) + 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_INCL(frstats[out].fr_nom); + } } fr = fin->fin_fr; } else @@ -700,7 +922,7 @@ int out; * then pretend we've dropped it already. */ if ((pass & FR_AUTH)) - if (FR_NEWAUTH(m, fin, ip, qif) != 0) + if (fr_newauth((mb_t *)m, fin, ip) != 0) #ifdef _KERNEL m = *mp = NULL; #else @@ -708,30 +930,39 @@ int out; #endif if (pass & FR_PREAUTH) { - MUTEX_ENTER(&ipf_auth); + READ_ENTER(&ipf_auth); if ((fin->fin_fr = ipauth) && - (pass = FR_SCANLIST(0, ip, fin, m))) - fr_authstats.fas_hits++; - else - fr_authstats.fas_miss++; - MUTEX_EXIT(&ipf_auth); + (pass = fr_scanlist(0, ip, fin, m))) { + ATOMIC_INCL(fr_authstats.fas_hits); + } else { + ATOMIC_INCL(fr_authstats.fas_miss); + } + 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) - frstats[out].fr_bnfr++; - else - frstats[out].fr_nfr++; - } else - frstats[out].fr_cfr++; + if (ipfr_newfrag(ip, fin, pass) == -1) { + ATOMIC_INCL(frstats[out].fr_bnfr); + } else { + ATOMIC_INCL(frstats[out].fr_nfr); + } + } else { + ATOMIC_INCL(frstats[out].fr_cfr); + } } if (pass & FR_KEEPSTATE) { - if (fr_addstate(ip, fin, pass) == -1) - frstats[out].fr_bads++; - else - frstats[out].fr_ads++; + if (fr_addstate(ip, fin, 0) == NULL) { + ATOMIC_INCL(frstats[out].fr_bads); + } else { + ATOMIC_INCL(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)) @@ -742,35 +973,42 @@ int out; * interface. */ if (out && (pass & FR_PASS)) { - if ((fin->fin_fr = ipacct[1][fr_active]) && - (FR_SCANLIST(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) - frstats[1].fr_acct++; - fin->fin_fr = NULL; - changed = ip_natout(ip, hlen, fin); - } - fin->fin_fr = fr; - MUTEX_EXIT(&ipf_mutex); +#ifdef USE_INET6 + if (v == 6) + list = ipacct6[0][fr_active]; + else +#endif + list = ipacct[0][fr_active]; + if ((fin->fin_fr = list) && + (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { + ATOMIC_INCL(frstats[1].fr_acct); + } + fin->fin_fr = fr; + changed = ip_natout(ip, fin); + } else + fin->fin_fr = fr; + RWLOCK_EXIT(&ipf_mutex); #ifdef IPFILTER_LOG if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { pass |= FF_LOGNOMATCH; - frstats[out].fr_npkl++; + ATOMIC_INCL(frstats[out].fr_npkl); goto logit; } else if (((pass & FR_LOGMASK) == FR_LOGP) || ((pass & FR_PASS) && (fr_flags & FF_LOGPASS))) { if ((pass & FR_LOGMASK) != FR_LOGP) pass |= FF_LOGPASS; - frstats[out].fr_ppkl++; + ATOMIC_INCL(frstats[out].fr_ppkl); goto logit; } else if (((pass & FR_LOGMASK) == FR_LOGB) || ((pass & FR_BLOCK) && (fr_flags & FF_LOGBLOCK))) { if ((pass & FR_LOGMASK) != FR_LOGB) pass |= FF_LOGBLOCK; - frstats[out].fr_bpkl++; + ATOMIC_INCL(frstats[out].fr_bpkl); logit: if (!IPLLOG(pass, ip, fin, m)) { - frstats[out].fr_skip++; + ATOMIC_INCL(frstats[out].fr_skip); if ((pass & (FR_PASS|FR_LOGORBLOCK)) == (FR_PASS|FR_LOGORBLOCK)) pass ^= FR_PASS|FR_BLOCK; @@ -778,6 +1016,10 @@ logit: } } #endif /* IPFILTER_LOG */ + + if ((out) && (v == 4)) + ip->ip_id = htons(ip->ip_id); + #ifdef _KERNEL /* * Only allow FR_DUP to work if a rule matched - it makes no sense to @@ -795,10 +1037,10 @@ logit: # endif # endif #endif - if (pass & FR_PASS) - frstats[out].fr_pass++; - else if (pass & FR_BLOCK) { - frstats[out].fr_block++; + if (pass & FR_PASS) { + ATOMIC_INCL(frstats[out].fr_pass); + } else if (pass & FR_BLOCK) { + ATOMIC_INCL(frstats[out].fr_block); /* * Should we return an ICMP packet to indicate error * status passing through the packet filter ? @@ -810,29 +1052,31 @@ logit: if (!out) { #ifdef _KERNEL if (pass & FR_RETICMP) { -# if SOLARIS - ICMP_ERROR(q, ip, ICMP_UNREACH, fin->fin_icode, - qif, ip->ip_src); -# else - ICMP_ERROR(m, ip, ICMP_UNREACH, fin->fin_icode, - ifp, ip->ip_src); - m = *mp = NULL; /* freed by icmp_error() */ -# endif + int dst; - frstats[0].fr_ret++; - } else if ((pass & FR_RETRST) && + if ((pass & FR_RETMASK) == FR_FAKEICMP) + dst = 1; + else + dst = 0; + send_icmp_err(ip, ICMP_UNREACH, fin, dst); + ATOMIC_INCL(frstats[0].fr_ret); + } else if (((pass & FR_RETMASK) == FR_RETRST) && !(fin->fin_fi.fi_fl & FI_SHORT)) { - if (SEND_RESET(ip, qif, ifp) == 0) - frstats[1].fr_ret++; + if (send_reset(ip, fin) == 0) { + ATOMIC_INCL(frstats[1].fr_ret); + } } #else - if (pass & FR_RETICMP) { + if ((pass & FR_RETMASK) == FR_RETICMP) { verbose("- ICMP unreachable sent\n"); - frstats[0].fr_ret++; - } else if ((pass & FR_RETRST) && + ATOMIC_INCL(frstats[0].fr_ret); + } else if ((pass & FR_RETMASK) == FR_FAKEICMP) { + verbose("- forged ICMP unreachable sent\n"); + ATOMIC_INCL(frstats[0].fr_ret); + } else if (((pass & FR_RETMASK) == FR_RETRST) && !(fin->fin_fi.fi_fl & FI_SHORT)) { verbose("- TCP RST sent\n"); - frstats[1].fr_ret++; + ATOMIC_INCL(frstats[1].fr_ret); } #endif } else { @@ -848,16 +1092,20 @@ logit: * Once we're finished return to our caller, freeing the packet if * we are dropping it (* BSD ONLY *). */ + if ((changed == -1) && (pass & FR_PASS)) { + pass &= ~FR_PASS; + pass |= FR_BLOCK; + } #if defined(_KERNEL) # if !SOLARIS # if !defined(linux) 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); @@ -869,21 +1117,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; @@ -928,76 +1175,92 @@ 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((u_short)ip->ip_p); + sum += htons(slen); + sp = (u_short *)&ip->ip_src; + sum += *sp++; /* ip_src */ + sum += *sp++; + sum += *sp++; /* ip_dst */ + sum += *sp++; + ts = tcp->th_sum; + tcp->th_sum = 0; +#ifdef KERNEL +# if SOLARIS + sum2 = ip_cksum(m, hlen, sum); /* hlen == offset */ + sum2 = (sum2 & 0xffff) + (sum2 >> 16); + sum2 = ~sum2 & 0xffff; +# else /* SOLARIS */ +# if defined(BSD) || defined(sun) +# if BSD >= 199306 + m->m_data += hlen; +# else + m->m_off += hlen; +# endif + m->m_len -= hlen; + sum2 = in_cksum(m, slen); + m->m_len += hlen; +# if BSD >= 199306 + m->m_data -= hlen; +# else + m->m_off -= hlen; +# endif + /* + * Both sum and sum2 are partial sums, so combine them together. + */ + sum = (sum & 0xffff) + (sum >> 16); + sum = ~sum & 0xffff; + sum2 += sum; + 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; -# if SOLARIS || defined(__sgi) - int add, hlen; -# endif - -# if SOLARIS - /* skip any leading M_PROTOs */ - while(m && (MTYPE(m) != M_DATA)) - m = m->b_cont; - PANIC((!m),("fr_tcpsum: no M_DATA")); + u_short len = ip->ip_len; +# if defined(__sgi) + int add; # endif /* * Add up IP Header portion */ - bytes.c[0] = 0; - bytes.c[1] = IPPROTO_TCP; - len -= (ip->ip_hl << 2); - sum = bytes.s; - sum += htons((u_short)len); sp = (u_short *)&ip->ip_src; + len -= (ip->ip_hl << 2); + sum = ntohs(IPPROTO_TCP); + sum += htons(len); + sum += *sp++; /* ip_src */ sum += *sp++; - sum += *sp++; - sum += *sp++; + sum += *sp++; /* ip_dst */ sum += *sp++; if (sp != (u_short *)tcp) sp = (u_short *)tcp; + sum += *sp++; /* sport */ + sum += *sp++; /* dport */ + sum += *sp++; /* seq */ sum += *sp++; + sum += *sp++; /* ack */ sum += *sp++; - sum += *sp++; - sum += *sp++; - sum += *sp++; - sum += *sp++; - sum += *sp++; - sum += *sp; - sp += 2; /* Skip over checksum */ - sum += *sp++; + sum += *sp++; /* off */ + sum += *sp++; /* win */ + sum += *sp++; /* Skip over checksum */ + sum += *sp++; /* urp */ -#if SOLARIS - /* - * In case we had to copy the IP & TCP header out of mblks, - * skip over the mblk bits which are the header - */ - if ((caddr_t)ip != (caddr_t)m->b_rptr) { - hlen = (caddr_t)sp - (caddr_t)ip; - while (hlen) { - add = MIN(hlen, m->b_wptr - m->b_rptr); - sp = (u_short *)((caddr_t)m->b_rptr + add); - hlen -= add; - if ((caddr_t)sp >= (caddr_t)m->b_wptr) { - m = m->b_cont; - PANIC((!m),("fr_tcpsum: not enough data")); - if (!hlen) - sp = (u_short *)m->b_rptr; - } - } - } -#endif -#ifdef __sgi +# ifdef __sgi /* * In case we had to copy the IP & TCP header out of mbufs, * skip over the mbuf bits which are the header @@ -1008,52 +1271,57 @@ int len; add = MIN(hlen, m->m_len); sp = (u_short *)(mtod(m, caddr_t) + add); hlen -= add; - if (add >= m->m_len) { + if (add == m->m_len) { m = m->m_next; - PANIC((!m),("fr_tcpsum: not enough data")); - if (!hlen) + if (!hlen) { + if (!m) + break; sp = mtod(m, u_short *); + } + PANIC((!m),("fr_tcpsum(1): not enough data")); } } } -#endif +# endif if (!(len -= sizeof(*tcp))) goto nodata; - while (len > 0) { -#if SOLARIS - while ((caddr_t)sp >= (caddr_t)m->b_wptr) { - m = m->b_cont; - PANIC((!m),("fr_tcpsum: not enough data")); - sp = (u_short *)m->b_rptr; + while (len > 1) { + if (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len) { + m = m->m_next; + PANIC((!m),("fr_tcpsum(2): not enough data")); + sp = mtod(m, u_short *); } -#else - while (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len) - { + if (((caddr_t)(sp + 1) - mtod(m, caddr_t)) > m->m_len) { + bytes.c[0] = *(u_char *)sp; m = m->m_next; - PANIC((!m),("fr_tcpsum: not enough data")); + PANIC((!m),("fr_tcpsum(3): not enough data")); sp = mtod(m, u_short *); + bytes.c[1] = *(u_char *)sp; + sum += bytes.s; + sp = (u_short *)((u_char *)sp + 1); } -#endif /* SOLARIS */ - if (len < 2) - break; - if((u_32_t)sp & 1) { + if ((u_long)sp & 1) { bcopy((char *)sp++, (char *)&bytes.s, sizeof(bytes.s)); sum += bytes.s; } else sum += *sp++; len -= 2; } - if (len) { - bytes.c[1] = 0; - bytes.c[0] = *(u_char *)sp; - sum += bytes.s; - } + if (len) + sum += ntohs(*(u_char *)sp << 8); nodata: - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - sum = (u_short)((~sum) & 0xffff); - return sum; + while (sum > 0xffff) + sum = (sum & 0xffff) + (sum >> 16); + sum2 = (u_short)(~sum & 0xffff); +} +# endif /* defined(BSD) || defined(sun) */ +# endif /* SOLARIS */ +#else /* KERNEL */ + sum2 = 0; +#endif /* KERNEL */ + tcp->th_sum = ts; + return sum2; } @@ -1091,7 +1359,7 @@ nodata: * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 - * $Id: fil.c,v 2.0.2.41.2.14 1998/05/23 19:20:30 darrenr Exp $ + * $Id: fil.c,v 2.35.2.8 2000/05/22 10:26:09 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, @@ -1191,9 +1459,9 @@ out: frgroup_t *fr_findgroup(num, flags, which, set, fgpp) -u_short num; -u_32_t flags; -int which, set; +u_32_t num, flags; +minor_t which; +int set; frgroup_t ***fgpp; { frgroup_t *fg, **fgp; @@ -1206,6 +1474,7 @@ frgroup_t ***fgpp; fgp = &ipfgroups[0][set]; else return NULL; + num &= 0xffff; while ((fg = *fgp)) if (fg->fg_num == num) @@ -1219,16 +1488,17 @@ frgroup_t ***fgpp; frgroup_t *fr_addgroup(num, fp, which, set) -u_short num; +u_32_t 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_next = *fgp; @@ -1241,9 +1511,9 @@ int which, set; void fr_delgroup(num, flags, which, set) -u_short num; -u_32_t flags; -int which, set; +u_32_t num, flags; +minor_t which; +int set; { frgroup_t *fg, **fgp; @@ -1261,62 +1531,480 @@ 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_DEC32(fp->fr_ref); + if (fp->fr_grhead) { + fr_delgroup(fp->fr_grhead, fp->fr_flags, + unit, set); + fp->fr_grhead = 0; + } + 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) { +#ifdef USE_INET6 + (void) frflushlist(set, unit, &flushed, &ipfilter6[1][set]); + (void) frflushlist(set, unit, &flushed, &ipacct6[1][set]); +#endif + (void) frflushlist(set, unit, &flushed, &ipfilter[1][set]); + (void) frflushlist(set, unit, &flushed, &ipacct[1][set]); + } + if (flags & FR_INQUE) { +#ifdef USE_INET6 + (void) frflushlist(set, unit, &flushed, &ipfilter6[0][set]); + (void) frflushlist(set, unit, &flushed, &ipacct6[0][set]); +#endif + (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; + } + 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(v, ifptr, inp) +int v; +void *ifptr; +struct in_addr *inp; +{ +# ifdef USE_INET6 + struct in6_addr *inp6 = NULL; +# endif +# if SOLARIS + ill_t *ill = ifptr; +# else + struct ifnet *ifp = ifptr; +# endif + struct in_addr in; + +# if SOLARIS +# ifdef USE_INET6 + if (v == 6) { + struct in6_addr in6; + + /* + * First is always link local. + */ + if (ill->ill_ipif->ipif_next) + in6 = ill->ill_ipif->ipif_next->ipif_v6lcl_addr; + else + bzero((char *)&in6, sizeof(in6)); + bcopy((char *)&in6, (char *)inp, sizeof(in6)); + } else +# endif + { + in.s_addr = ill->ill_ipif->ipif_local_addr; + *inp = in; + } +# else /* SOLARIS */ +# if linux + ; +# else /* linux */ + struct sockaddr_in *sin; + struct ifaddr *ifa; + +# 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) { + if ((v == 4) && (sin->sin_family == AF_INET)) + break; +# ifdef USE_INET6 + if ((v == 6) && (sin->sin_family == AF_INET6)) { + inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr; + if (!IN6_IS_ADDR_LINKLOCAL(inp6) && + !IN6_IS_ADDR_LOOPBACK(inp6)) + 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]); +# endif +# 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) */ +# ifdef USE_INET6 + if (v == 6) + bcopy((char *)inp6, (char *)inp, sizeof(*inp6)); + else +# endif + { + in = sin->sin_addr; + *inp = in; + } +# endif /* linux */ +# endif /* SOLARIS */ + 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, fr->fr_ip.fi_v); + if (fr->fr_ifa == NULL) + fr->fr_ifa = (void *)-1; } + if (fr->fr_grp) + frsynclist(fr->fr_grp); + } +} + + +void frsync() +{ +# if !SOLARIS + register struct ifnet *ifp; + +# 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); + ip_statesync(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]); +#ifdef USE_INET6 + frsynclist(ipacct6[0][fr_active]); + frsynclist(ipacct6[1][fr_active]); + frsynclist(ipfilter6[0][fr_active]); + frsynclist(ipfilter6[1][fr_active]); +#endif + RWLOCK_EXIT(&ipf_mutex); +} + + +/* + * In the functions below, bcopy() is called because the pointer being + * copied _from_ in this instance is a pointer to a char buf (which could + * end up being unaligned) and on the kernel's local stack. + */ +int ircopyptr(a, b, c) +void *a, *b; +size_t c; +{ + caddr_t ca; + int err; + +#if SOLARIS + copyin(a, &ca, sizeof(ca)); +#else + bcopy(a, &ca, sizeof(ca)); +#endif + err = copyin(ca, b, c); + return err; +} + + +int iwcopyptr(a, b, c) +void *a, *b; +size_t c; +{ + caddr_t ca; + int err; + +#if SOLARIS + copyin(b, &ca, sizeof(ca)); +#else + bcopy(b, &ca, sizeof(ca)); +#endif + err = copyout(a, ca, c); + return err; +} + +#else /* _KERNEL */ + + +/* + * return the first IP Address associated with an interface + */ +int fr_ifpaddr(v, ifptr, inp) +int v; +void *ifptr; +struct in_addr *inp; +{ + return 0; +} + + +int ircopyptr(a, b, c) +void *a, *b; +size_t c; +{ + caddr_t ca; + + bcopy(a, &ca, sizeof(ca)); + bcopy(ca, b, c); + return 0; +} + + +int iwcopyptr(a, b, c) +void *a, *b; +size_t c; +{ + caddr_t ca; + + bcopy(b, &ca, sizeof(ca)); + bcopy(a, ca, c); + return 0; +} + + +#endif + + +int fr_lock(data, lockp) +caddr_t data; +int *lockp; +{ + int arg, error; + + error = IRCOPY(data, (caddr_t)&arg, sizeof(arg)); + if (!error) { + error = IWCOPY((caddr_t)lockp, data, sizeof(*lockp)); + if (!error) + *lockp = arg; } + return error; +} - *result = flushed; + +void fr_getstat(fiop) +friostat_t *fiop; +{ + bcopy((char *)frstats, (char *)fiop->f_st, sizeof(filterstats_t) * 2); + fiop->f_locks[0] = fr_state_lock; + fiop->f_locks[1] = fr_nat_lock; + fiop->f_locks[2] = fr_frag_lock; + fiop->f_locks[3] = fr_auth_lock; + fiop->f_fin[0] = ipfilter[0][0]; + fiop->f_fin[1] = ipfilter[0][1]; + fiop->f_fout[0] = ipfilter[1][0]; + fiop->f_fout[1] = ipfilter[1][1]; + fiop->f_acctin[0] = ipacct[0][0]; + fiop->f_acctin[1] = ipacct[0][1]; + fiop->f_acctout[0] = ipacct[1][0]; + fiop->f_acctout[1] = ipacct[1][1]; +#ifdef USE_INET6 + fiop->f_fin6[0] = ipfilter6[0][0]; + fiop->f_fin6[1] = ipfilter6[0][1]; + fiop->f_fout6[0] = ipfilter6[1][0]; + fiop->f_fout6[1] = ipfilter6[1][1]; + fiop->f_acctin6[0] = ipacct6[0][0]; + fiop->f_acctin6[1] = ipacct6[0][1]; + fiop->f_acctout6[0] = ipacct6[1][0]; + fiop->f_acctout6[1] = ipacct6[1][1]; +#endif + fiop->f_active = fr_active; + fiop->f_froute[0] = ipl_frouteok[0]; + fiop->f_froute[1] = ipl_frouteok[1]; + + fiop->f_running = fr_running; + fiop->f_groups[0][0] = ipfgroups[0][0]; + fiop->f_groups[0][1] = ipfgroups[0][1]; + fiop->f_groups[1][0] = ipfgroups[1][0]; + fiop->f_groups[1][1] = ipfgroups[1][1]; + fiop->f_groups[2][0] = ipfgroups[2][0]; + fiop->f_groups[2][1] = ipfgroups[2][1]; +#ifdef IPFILTER_LOG + fiop->f_logging = 1; +#else + fiop->f_logging = 0; +#endif + fiop->f_defpass = fr_pass; + strncpy(fiop->f_version, ipfilter_version, sizeof(fiop->f_version)); } + + +#ifdef USE_INET6 +int icmptoicmp6types[ICMP_MAXTYPE+1] = { + ICMP6_ECHO_REPLY, /* 0: ICMP_ECHOREPLY */ + -1, /* 1: UNUSED */ + -1, /* 2: UNUSED */ + ICMP6_DST_UNREACH, /* 3: ICMP_UNREACH */ + -1, /* 4: ICMP_SOURCEQUENCH */ + ND_REDIRECT, /* 5: ICMP_REDIRECT */ + -1, /* 6: UNUSED */ + -1, /* 7: UNUSED */ + ICMP6_ECHO_REQUEST, /* 8: ICMP_ECHO */ + -1, /* 9: UNUSED */ + -1, /* 10: UNUSED */ + ICMP6_TIME_EXCEEDED, /* 11: ICMP_TIMXCEED */ + ICMP6_PARAM_PROB, /* 12: ICMP_PARAMPROB */ + -1, /* 13: ICMP_TSTAMP */ + -1, /* 14: ICMP_TSTAMPREPLY */ + -1, /* 15: ICMP_IREQ */ + -1, /* 16: ICMP_IREQREPLY */ + -1, /* 17: ICMP_MASKREQ */ + -1, /* 18: ICMP_MASKREPLY */ +}; + + +int icmptoicmp6unreach[ICMP_MAX_UNREACH] = { + ICMP6_DST_UNREACH_ADDR, /* 0: ICMP_UNREACH_NET */ + ICMP6_DST_UNREACH_ADDR, /* 1: ICMP_UNREACH_HOST */ + -1, /* 2: ICMP_UNREACH_PROTOCOL */ + ICMP6_DST_UNREACH_NOPORT, /* 3: ICMP_UNREACH_PORT */ + -1, /* 4: ICMP_UNREACH_NEEDFRAG */ + ICMP6_DST_UNREACH_NOTNEIGHBOR, /* 5: ICMP_UNREACH_SRCFAIL */ + ICMP6_DST_UNREACH_ADDR, /* 6: ICMP_UNREACH_NET_UNKNOWN */ + ICMP6_DST_UNREACH_ADDR, /* 7: ICMP_UNREACH_HOST_UNKNOWN */ + -1, /* 8: ICMP_UNREACH_ISOLATED */ + ICMP6_DST_UNREACH_ADMIN, /* 9: ICMP_UNREACH_NET_PROHIB */ + ICMP6_DST_UNREACH_ADMIN, /* 10: ICMP_UNREACH_HOST_PROHIB */ + -1, /* 11: ICMP_UNREACH_TOSNET */ + -1, /* 12: ICMP_UNREACH_TOSHOST */ + ICMP6_DST_UNREACH_ADMIN, /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */ +}; +#endif diff --git a/sys/contrib/ipfilter/netinet/ip_auth.c b/sys/contrib/ipfilter/netinet/ip_auth.c index bdb3114..78aff43 100644 --- a/sys/contrib/ipfilter/netinet/ip_auth.c +++ b/sys/contrib/ipfilter/netinet/ip_auth.c @@ -1,24 +1,25 @@ /* - * Copyright (C) 1997 by Darren Reed & Guido van Rooij. + * Copyright (C) 1998-2000 by Darren Reed & Guido van Rooij. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.0.2.21.2.3 1998/04/08 13:43:29 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.2 2000/05/22 10:26:11 darrenr Exp $"; #endif -#if !defined(_KERNEL) && !defined(KERNEL) -# include -# include -#endif #include #include #include #include #include -#if defined(KERNEL) && (__FreeBSD_version >= 220000) +#if !defined(_KERNEL) && !defined(KERNEL) +# include +# include +# include +#endif +#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) # include # include #else @@ -29,7 +30,7 @@ static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.0.2.21.2.3 1998/04/08 13:43: # include #endif #include -#if defined(_KERNEL) && !defined(linux) +#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) # include #endif #if !defined(__SVR4) && !defined(__svr4__) @@ -39,34 +40,39 @@ static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.0.2.21.2.3 1998/04/08 13:43: #else # include # include -# include +# ifdef _KERNEL +# include +# endif # include # include #endif +#if _BSDI_VERSION >= 199802 +# include +#endif #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) # include #endif #include #ifdef sun -#include +# include #endif #include #include #include #include #ifndef KERNEL -#define KERNEL -#define NOT_KERNEL +# define KERNEL +# define NOT_KERNEL #endif #ifndef linux # include #endif #ifdef NOT_KERNEL -#undef KERNEL +# undef KERNEL #endif #ifdef __sgi # ifdef IFF_DRVRLOCK /* IRIX6 */ -#include +# include # endif #endif #include @@ -74,6 +80,9 @@ static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.0.2.21.2.3 1998/04/08 13:43: extern struct ifqueue ipintrq; /* ip packet input queue */ #else # ifndef linux +# if __FreeBSD_version >= 300000 +# include +# endif # include # include # endif @@ -90,10 +99,19 @@ extern struct ifqueue ipintrq; /* ip packet input queue */ # include # endif #endif +#if (__FreeBSD_version >= 300000) +# include +# if (defined(_KERNEL) || defined(KERNEL)) && !defined(IPFILTER_LKM) +# include +# include +# endif +#endif + #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern kmutex_t ipf_auth; +extern KRWLOCK_T ipf_auth; +extern kmutex_t ipf_authmx; # if SOLARIS extern kcondvar_t ipfauthwait; # endif @@ -105,11 +123,12 @@ static struct wait_queue *ipfauthwait = NULL; int fr_authsize = FR_NUMAUTH; int fr_authused = 0; int fr_defaultauthage = 600; +int fr_auth_lock = 0; fr_authstat_t fr_authstats; -frauth_t fr_auth[FR_NUMAUTH]; +static frauth_t fr_auth[FR_NUMAUTH]; mb_t *fr_authpkts[FR_NUMAUTH]; -int fr_authstart = 0, fr_authend = 0, fr_authnext = 0; -frauthent_t *fae_list = NULL; +static int fr_authstart = 0, fr_authend = 0, fr_authnext = 0; +static frauthent_t *fae_list = NULL; frentry_t *ipauth = NULL; @@ -118,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; { @@ -126,7 +145,10 @@ fr_info_t *fin; u_32_t pass; int i; - MUTEX_ENTER(&ipf_auth); + if (fr_auth_lock) + return 0; + + READ_ENTER(&ipf_auth); for (i = fr_authstart; i != fr_authend; ) { /* * index becomes -2 only after an SIOCAUTHW. Check this in @@ -141,6 +163,8 @@ fr_info_t *fin; */ if (!(pass = fr_auth[i].fra_pass) || (pass & FR_AUTH)) pass = FR_BLOCK; + RWLOCK_EXIT(&ipf_auth); + WRITE_ENTER(&ipf_auth); fr_authstats.fas_hits++; fr_auth[i].fra_index = -1; fr_authused--; @@ -158,7 +182,7 @@ fr_info_t *fin; fr_authstart = fr_authend = 0; } } - MUTEX_EXIT(&ipf_auth); + RWLOCK_EXIT(&ipf_auth); return pass; } i++; @@ -166,7 +190,7 @@ fr_info_t *fin; i = 0; } fr_authstats.fas_miss++; - MUTEX_EXIT(&ipf_auth); + RWLOCK_EXIT(&ipf_auth); return 0; } @@ -176,29 +200,30 @@ fr_info_t *fin; * If we do, store it and wake up any user programs which are waiting to * hear about these events. */ -int fr_newauth(m, fin, ip -#if defined(_KERNEL) && SOLARIS -, qif) -qif_t *qif; -#else -) -#endif +int fr_newauth(m, fin, ip) mb_t *m; fr_info_t *fin; ip_t *ip; { +#if defined(_KERNEL) && SOLARIS + qif_t *qif = fin->fin_qif; +#endif int i; - MUTEX_ENTER(&ipf_auth); - if ((fr_authstart > fr_authend) && (fr_authstart - fr_authend == -1)) { - fr_authstats.fas_nospace++; - MUTEX_EXIT(&ipf_auth); + if (fr_auth_lock) return 0; - } - if (fr_authend - fr_authstart == FR_NUMAUTH - 1) { + + WRITE_ENTER(&ipf_auth); + if (fr_authstart > fr_authend) { fr_authstats.fas_nospace++; - MUTEX_EXIT(&ipf_auth); + 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++; @@ -206,7 +231,7 @@ ip_t *ip; i = fr_authend++; if (fr_authend == FR_NUMAUTH) fr_authend = 0; - MUTEX_EXIT(&ipf_auth); + RWLOCK_EXIT(&ipf_auth); fr_auth[i].fra_index = i; fr_auth[i].fra_pass = 0; fr_auth[i].fra_age = fr_defaultauthage; @@ -217,14 +242,15 @@ ip_t *ip; * them. */ # if SOLARIS && defined(_KERNEL) - if (ip == (ip_t *)m->b_rptr) + if ((ip == (ip_t *)m->b_rptr) && (ip->ip_v == 4)) # endif { register u_short bo; bo = ip->ip_len; ip->ip_len = htons(bo); -# if !SOLARIS /* 4.4BSD converts this ip_input.c, but I don't in solaris.c */ +# if !SOLARIS && !defined(__NetBSD__) + /* 4.4BSD converts this ip_input.c, but I don't in solaris.c */ bo = ip->ip_id; ip->ip_id = htons(bo); # endif @@ -251,7 +277,7 @@ ip_t *ip; int fr_auth_ioctl(data, cmd, fr, frptr) caddr_t data; -#if defined(__NetBSD__) || defined(__OpenBSD__) +#if defined(__NetBSD__) || defined(__OpenBSD__) || (FreeBSD_version >= 300003) u_long cmd; #else int cmd; @@ -259,11 +285,8 @@ int cmd; frentry_t *fr, **frptr; { mb_t *m; -#if defined(_KERNEL) -# if !SOLARIS +#if defined(_KERNEL) && !SOLARIS struct ifqueue *ifq; - int s; -# endif #endif frauth_t auth, *au = &auth; frauthent_t *fae, **faep; @@ -271,12 +294,17 @@ frentry_t *fr, **frptr; switch (cmd) { + case SIOCSTLCK : + error = fr_lock(data, &fr_auth_lock); + break; case SIOCINIFR : case SIOCRMIFR : case SIOCADIFR : error = EINVAL; break; case SIOCINAFR : + error = EINVAL; + break; case SIOCRMAFR : case SIOCADAFR : for (faep = &fae_list; (fae = *faep); ) @@ -288,46 +316,61 @@ frentry_t *fr, **frptr; if (!fae) error = ESRCH; else { + WRITE_ENTER(&ipf_auth); *faep = fae->fae_next; *frptr = fr->fr_next; + RWLOCK_EXIT(&ipf_auth); 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)); - if (!fae->fae_age) - fae->fae_age = fr_defaultauthage; + bcopy((char *)fr, (char *)&fae->fae_fr, + sizeof(*fr)); + WRITE_ENTER(&ipf_auth); + 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: - IWCOPY((char *)&fr_authstats, data, sizeof(fr_authstats)); + READ_ENTER(&ipf_auth); + fr_authstats.fas_faelist = fae_list; + RWLOCK_EXIT(&ipf_auth); + error = IWCOPYPTR((char *)&fr_authstats, data, + sizeof(fr_authstats)); break; case SIOCAUTHW: fr_authioctlloop: - MUTEX_ENTER(&ipf_auth); + READ_ENTER(&ipf_auth); if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) { - IWCOPY((char *)&fr_auth[fr_authnext++], data, - sizeof(fr_info_t)); + error = IWCOPYPTR((char *)&fr_auth[fr_authnext], data, + sizeof(fr_info_t)); + RWLOCK_EXIT(&ipf_auth); + if (error) + break; + WRITE_ENTER(&ipf_auth); + fr_authnext++; if (fr_authnext == FR_NUMAUTH) fr_authnext = 0; - MUTEX_EXIT(&ipf_auth); + RWLOCK_EXIT(&ipf_auth); return 0; } #ifdef _KERNEL # if SOLARIS - if (!cv_wait_sig(&ipfauthwait, &ipf_auth)) { - mutex_exit(&ipf_auth); + mutex_enter(&ipf_authmx); + if (!cv_wait_sig(&ipfauthwait, &ipf_authmx)) { + mutex_exit(&ipf_authmx); return EINTR; } + mutex_exit(&ipf_authmx); # else # ifdef linux interruptible_sleep_on(&ipfauthwait); @@ -338,17 +381,19 @@ fr_authioctlloop: # endif # endif #endif - MUTEX_EXIT(&ipf_auth); + RWLOCK_EXIT(&ipf_auth); if (!error) goto fr_authioctlloop; break; case SIOCAUTHR: - IRCOPY(data, (caddr_t)&auth, sizeof(auth)); - MUTEX_ENTER(&ipf_auth); + error = IRCOPYPTR(data, (caddr_t)&auth, sizeof(auth)); + if (error) + return error; + WRITE_ENTER(&ipf_auth); i = au->fra_index; if ((i < 0) || (i > FR_NUMAUTH) || (fr_auth[i].fra_info.fin_id != au->fra_info.fin_id)) { - MUTEX_EXIT(&ipf_auth); + RWLOCK_EXIT(&ipf_auth); return EINVAL; } m = fr_authpkts[i]; @@ -356,14 +401,18 @@ fr_authioctlloop: fr_auth[i].fra_pass = au->fra_pass; fr_authpkts[i] = NULL; #ifdef _KERNEL - MUTEX_EXIT(&ipf_auth); - SPL_NET(s); + RWLOCK_EXIT(&ipf_auth); # ifndef linux if (m && au->fra_info.fin_out) { # if SOLARIS error = fr_qout(fr_auth[i].fra_q, m); # else /* SOLARIS */ +# 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 /* SOLARIS */ if (error) fr_authstats.fas_sendfail++; @@ -418,7 +467,6 @@ fr_authioctlloop: } } # endif - SPL_X(s); #endif /* _KERNEL */ break; default : @@ -439,7 +487,7 @@ void fr_authunload() register frauthent_t *fae, **faep; mb_t *m; - MUTEX_ENTER(&ipf_auth); + WRITE_ENTER(&ipf_auth); for (i = 0; i < FR_NUMAUTH; i++) { if ((m = fr_authpkts[i])) { FREE_MB_T(m); @@ -453,7 +501,8 @@ void fr_authunload() *faep = fae->fae_next; KFREE(fae); } - MUTEX_EXIT(&ipf_auth); + ipauth = NULL; + RWLOCK_EXIT(&ipf_auth); } @@ -471,8 +520,11 @@ void fr_authexpire() int s; #endif + if (fr_auth_lock) + return; + SPL_NET(s); - MUTEX_ENTER(&ipf_auth); + WRITE_ENTER(&ipf_auth); for (i = 0, fra = fr_auth; i < FR_NUMAUTH; i++, fra++) { if ((!--fra->fra_age) && (m = fr_authpkts[i])) { FREE_MB_T(m); @@ -484,14 +536,15 @@ 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; } - MUTEX_EXIT(&ipf_auth); + ipauth = &fae_list->fae_fr; + RWLOCK_EXIT(&ipf_auth); SPL_X(s); } #endif diff --git a/sys/contrib/ipfilter/netinet/ip_auth.h b/sys/contrib/ipfilter/netinet/ip_auth.h index 06f7cf6..b543318 100644 --- a/sys/contrib/ipfilter/netinet/ip_auth.h +++ b/sys/contrib/ipfilter/netinet/ip_auth.h @@ -1,11 +1,11 @@ /* - * Copyright (C) 1997 by Darren Reed & Guido Van Rooij. + * Copyright (C) 1997-2000 by Darren Reed & Guido Van Rooij. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: ip_auth.h,v 2.0.2.10 1997/10/29 12:14:07 darrenr Exp $ + * $Id: ip_auth.h,v 2.3.2.1 2000/05/22 10:26:11 darrenr Exp $ * */ #ifndef __IP_AUTH_H__ @@ -13,18 +13,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; @@ -41,6 +29,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; @@ -49,15 +50,12 @@ 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 int fr_auth_lock; +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[]; -#if defined(_KERNEL) && SOLARIS -extern int fr_newauth __P((mb_t *, fr_info_t *, ip_t *, qif_t *)); -#else extern int fr_newauth __P((mb_t *, fr_info_t *, ip_t *)); -#endif #if defined(__NetBSD__) || defined(__OpenBSD__) extern int fr_auth_ioctl __P((caddr_t, u_long, frentry_t *, frentry_t **)); #else diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h index 1f91cf3..9b7cddf 100644 --- a/sys/contrib/ipfilter/netinet/ip_compat.h +++ b/sys/contrib/ipfilter/netinet/ip_compat.h @@ -1,12 +1,12 @@ /* - * Copyright (C) 1993-1997 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * * @(#)ip_compat.h 1.8 1/14/96 - * $Id: ip_compat.h,v 2.0.2.31.2.11 1998/05/23 14:29:36 darrenr Exp $ + * $Id: ip_compat.h,v 2.26.2.3 2000/04/28 14:56:49 darrenr Exp $ */ #ifndef __IP_COMPAT_H__ @@ -17,33 +17,44 @@ # 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))) #endif +#if SOLARIS2 >= 8 +# ifndef USE_INET6 +# define USE_INET6 +# endif +#endif -#if defined(_KERNEL) && !defined(KERNEL) +#if defined(_KERNEL) || defined(KERNEL) || defined(__KERNEL__) +# undef KERNEL +# undef _KERNEL +# undef __KERNEL__ # define KERNEL -#endif -#if defined(KERNEL) && !defined(_KERNEL) # define _KERNEL -#endif -#if!defined(__KERNEL__) && defined(KERNEL) # define __KERNEL__ #endif #if defined(__SVR4) || defined(__svr4__) || defined(__sgi) #define index strchr -# if !defined(_KERNEL) +# if !defined(KERNEL) # define bzero(a,b) memset(a,0,b) # define bcmp memcmp # define bcopy(a,b,c) memmove(b,a,c) # endif #endif +#ifndef offsetof +#define offsetof(t,m) (int)((&((t *)0L)->m)) +#endif + #if defined(__sgi) || defined(bsdi) struct ether_addr { u_char ether_addr_octet[6]; @@ -69,6 +80,7 @@ struct ether_addr { #endif #if SOLARIS # define MTYPE(m) ((m)->b_datap->db_type) +# include # include # include # include @@ -80,18 +92,37 @@ struct ether_addr { # undef IPOPT_LSRR # undef IPOPT_RR # undef IPOPT_SSRR -# ifndef _KERNEL +# ifndef KERNEL # define _KERNEL # undef RES_INIT +# if SOLARIS2 >= 8 +# include +# endif # include # include # include # undef _KERNEL # else /* _KERNEL */ +# if SOLARIS2 >= 8 +# include +# endif # include # include # include # endif /* _KERNEL */ +# if SOLARIS2 >= 8 +# include +# include +# define ipif_local_addr ipif_lcl_addr +/* Only defined in private include file */ +# ifndef V4_PART_OF_V6 +# define V4_PART_OF_V6(v6) v6.s6_addr32[3] +# endif +# 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))) @@ -108,23 +139,64 @@ struct ether_addr { # define QUAD_T long #endif /* BSD > 199306 */ + /* * These operating systems already take care of the problem for us. */ #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \ defined(__sgi) typedef u_int32_t u_32_t; +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 104110000) +# include "opt_inet.h" +# endif +# if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \ + !defined(KLD_MODULE) +# include "opt_inet6.h" +# endif +# ifdef INET6 +# define USE_INET6 +# endif +# endif #else /* * 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; +# if SOLARIS2 >= 6 +typedef uint32_t u_32_t; +# else +typedef unsigned int u_32_t; +# endif # endif #endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __sgi */ +#ifdef USE_INET6 +# if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) +# include +# ifdef _KERNEL +# include +# endif +typedef struct ip6_hdr ip6_t; +# endif +union i6addr { + u_32_t i6[4]; + struct in_addr in4; + struct in6_addr in6; +}; +#else +union i6addr { + u_32_t i6[4]; + struct in_addr in4; +}; +#endif + +#define IP6CMP(a,b) bcmp((char *)&(a), (char *)&(b), sizeof(a)) +#define IP6EQ(a,b) (bcmp((char *)&(a), (char *)&(b), sizeof(a)) == 0) +#define IP6NEQ(a,b) (bcmp((char *)&(a), (char *)&(b), sizeof(a)) != 0) + #ifndef MAX #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #endif @@ -186,12 +258,15 @@ typedef unsigned long u_32_t; #define IPOPT_FINN 205 /* FINN */ -#if defined(__FreeBSD__) && defined(KERNEL) +#if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL)) # if __FreeBSD__ < 3 # include -# endif -# if defined(IPFILTER_LKM) && !defined(ACTUALLY_LKM_NOT_KERNEL) -# define ACTUALLY_LKM_NOT_KERNEL +# else +# if __FreeBSD__ == 3 +# if defined(IPFILTER_LKM) && !defined(ACTUALLY_LKM_NOT_KERNEL) +# define ACTUALLY_LKM_NOT_KERNEL +# endif +# endif # endif #endif /* __FreeBSD__ && KERNEL */ @@ -199,13 +274,69 @@ typedef unsigned long u_32_t; * Build some macros and #defines to enable the same code to compile anywhere * Well, that's the idea, anyway :-) */ +#if !SOLARIS || (SOLARIS2 < 6) || !defined(KERNEL) +# define ATOMIC_INCL ATOMIC_INC +# define ATOMIC_INC64 ATOMIC_INC +# define ATOMIC_INC32 ATOMIC_INC +# define ATOMIC_INC16 ATOMIC_INC +# define ATOMIC_DECL ATOMIC_DEC +# define ATOMIC_DEC64 ATOMIC_DEC +# define ATOMIC_DEC32 ATOMIC_DEC +# define ATOMIC_DEC16 ATOMIC_DEC +#endif #ifdef KERNEL # if SOLARIS -# define MUTEX_ENTER(x) mutex_enter(x) +# if SOLARIS2 >= 6 +# include +# if SOLARIS2 == 6 +# define ATOMIC_INCL(x) atomic_add_long((uint32_t*)&(x), 1) +# define ATOMIC_DECL(x) atomic_add_long((uint32_t*)&(x), -1) +# else +# define ATOMIC_INCL(x) atomic_add_long(&(x), 1) +# define ATOMIC_DECL(x) atomic_add_long(&(x), -1) +# endif +# define ATOMIC_INC64(x) atomic_add_64((uint64_t*)&(x), 1) +# define ATOMIC_INC32(x) atomic_add_32((uint32_t*)&(x), 1) +# define ATOMIC_INC16(x) atomic_add_16((uint16_t*)&(x), 1) +# define ATOMIC_DEC64(x) atomic_add_64((uint64_t*)&(x), -1) +# define ATOMIC_DEC32(x) atomic_add_32((uint32_t*)&(x), -1) +# define ATOMIC_DEC16(x) atomic_add_16((uint16_t*)&(x), -1) +# else +# define ATOMIC_INC(x) { mutex_enter(&ipf_rw); (x)++; \ + mutex_exit(&ipf_rw); } +# define ATOMIC_DEC(x) { mutex_enter(&ipf_rw); (x)--; \ + mutex_exit(&ipf_rw); } +# endif +# define MUTEX_ENTER(x) mutex_enter(x) +# if 1 +# 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) +# define RW_DESTROY(x) rw_destroy(x) +# else +# define KRWLOCK_T kmutex_t +# define READ_ENTER(x) mutex_enter(x) +# define WRITE_ENTER(x) mutex_enter(x) +# define MUTEX_DOWNGRADE(x) ; +# define RWLOCK_INIT(x, y, z) mutex_init((x), (y), MUTEX_DRIVER, (z)) +# define RWLOCK_EXIT(x) mutex_exit(x) +# define RW_DESTROY(x) mutex_destroy(x) +# endif +# define MUTEX_INIT(x, y, z) mutex_init((x), (y), MUTEX_DRIVER, (z)) +# define MUTEX_DESTROY(x) mutex_destroy(x) # define MUTEX_EXIT(x) mutex_exit(x) # define MTOD(m,t) (t)((m)->b_rptr) # define IRCOPY(a,b,c) copyin((a), (b), (c)) # define IWCOPY(a,b,c) copyout((a), (b), (c)) +# define IRCOPYPTR ircopyptr +# define IWCOPYPTR iwcopyptr # define FREE_MB_T(m) freemsg(m) # define SPL_NET(x) ; # define SPL_IMP(x) ; @@ -217,7 +348,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; @@ -233,18 +365,21 @@ 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 */ + int qf_sap; } qif_t; -extern ill_t *get_unit __P((char *)); -# define GETUNIT(n) get_unit((n)) +extern ill_t *get_unit __P((char *, int)); +# define GETUNIT(n, v) get_unit(n, v) +# define IFNAME(x) ((ill_t *)x)->ill_name # else /* SOLARIS */ # if defined(__sgi) +# define hz HZ # include # define IPF_LOCK_PL plhi # include @@ -253,28 +388,58 @@ typedef struct { lock_t *l; int pl; } kmutex_t; -# define MUTEX_ENTER(x) (x)->pl = LOCK((x)->l, IPF_LOCK_PL); -# define MUTEX_EXIT(x) UNLOCK((x)->l, (x)->pl); +# define ATOMIC_INC(x) { MUTEX_ENTER(&ipf_rw); \ + (x)++; MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_DEC(x) { MUTEX_ENTER(&ipf_rw); \ + (x)--; MUTEX_EXIT(&ipf_rw); } +# define MUTEX_ENTER(x) (x)->pl = LOCK((x)->l, IPF_LOCK_PL); +# 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); +# define MUTEX_INIT(x,y,z) (x).l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP) +# define MUTEX_DESTROY(x) LOCK_DEALLOC((x).l) # else /* __sgi */ -# define MUTEX_ENTER(x) ; -# define MUTEX_EXIT(x) ; +# define ATOMIC_INC(x) (x)++ +# define ATOMIC_DEC(x) (x)-- +# 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) ; +# define MUTEX_INIT(x,y,z) ; +# define MUTEX_DESTROY(x) ; # endif /* __sgi */ # ifndef linux # define FREE_MB_T(m) m_freem(m) # define MTOD(m,t) mtod(m,t) -# define IRCOPY(a,b,c) bcopy((a), (b), (c)) -# define IWCOPY(a,b,c) bcopy((a), (b), (c)) +# define IRCOPY(a,b,c) (bcopy((a), (b), (c)), 0) +# define IWCOPY(a,b,c) (bcopy((a), (b), (c)), 0) +# define IRCOPYPTR ircopyptr +# define IWCOPYPTR iwcopyptr # endif /* !linux */ # endif /* SOLARIS */ # ifdef sun # if !SOLARIS # include -# define GETUNIT(n) ifunit((n), IFNAMSIZ) +# define GETUNIT(n, v) ifunit(n, IFNAMSIZ) +# define IFNAME(x) ((struct ifnet *)x)->if_name # endif # else # ifndef linux -# define GETUNIT(n) ifunit((n)) +# define GETUNIT(n, v) ifunit(n) +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ + (defined(OpenBSD) && (OpenBSD >= 199603)) +# define IFNAME(x) ((struct ifnet *)x)->if_xname +# else +# define IFNAME(x) ((struct ifnet *)x)->if_name +# endif # endif # endif /* sun */ @@ -291,11 +456,14 @@ extern void m_copyback __P((struct mbuf *, int, int, caddr_t)); # ifdef __sgi # include # include -# 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 */ @@ -312,11 +480,13 @@ extern vm_map_t kmem_map; # include # 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 */ @@ -339,25 +509,54 @@ extern vm_map_t kmem_map; # define SLEEP(x,y) ; # define WAKEUP(x) ; # define PANIC(x,y) ; +# define ATOMIC_INC(x) (x)++ +# define ATOMIC_DEC(x) (x)-- # define MUTEX_ENTER(x) ; +# define READ_ENTER(x) ; +# define MUTEX_INIT(x,y,z) ; +# define MUTEX_DESTROY(x) ; +# define WRITE_ENTER(x) ; +# define RW_UPGRADE(x) ; +# define MUTEX_DOWNGRADE(x) ; +# define RWLOCK_EXIT(x) ; # define MUTEX_EXIT(x) ; # define SPL_NET(x) ; # define SPL_IMP(x) ; # undef SPL_X # define SPL_X(x) ; -# define KMALLOC(a,b,c) (a) = (b)malloc(c) +# define 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) -# define IRCOPY(a,b,c) bcopy((a), (b), (c)) -# define IWCOPY(a,b,c) bcopy((a), (b), (c)) +# define GETUNIT(x, v) get_unit(x,v) +# define IRCOPY(a,b,c) (bcopy((a), (b), (c)), 0) +# define IWCOPY(a,b,c) (bcopy((a), (b), (c)), 0) +# define IRCOPYPTR ircopyptr +# define IWCOPYPTR iwcopyptr #endif /* KERNEL */ #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 +typedef struct mb { + struct mb *next; + u_int len; + u_char *data; +} mb_t; +# else typedef struct sk_buff mb_t; +# endif # else typedef struct mbuf mb_t; # endif @@ -492,6 +691,7 @@ typedef struct mbuf mb_t; #endif /* linux || __sgi */ #ifdef linux +#include /* * TCP States */ @@ -513,8 +713,13 @@ typedef struct mbuf mb_t; /* * file flags. */ +#ifdef WRITE #define FWRITE WRITE #define FREAD READ +#else +#define FWRITE _IOC_WRITE +#define FREAD _IOC_READ +#endif /* * mbuf related problems. */ @@ -522,7 +727,10 @@ typedef struct mbuf mb_t; #define m_len len #define m_next next -#define IP_DF 0x8000 +#ifdef IP_DF +#undef IP_DF +#endif +#define IP_DF 0x4000 typedef struct { __u16 th_sport; @@ -556,8 +764,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; @@ -574,15 +782,15 @@ typedef struct { * Structure of an icmp header. */ typedef struct icmp { - u_char icmp_type; /* type of message, see below */ - u_char icmp_code; /* type sub code */ - u_short icmp_cksum; /* ones complement cksum of struct */ + __u8 icmp_type; /* type of message, see below */ + __u8 icmp_code; /* type sub code */ + __u16 icmp_cksum; /* ones complement cksum of struct */ union { - u_char ih_pptr; /* ICMP_PARAMPROB */ - struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ - struct ih_idseq { - n_short icd_id; - n_short icd_seq; + __u8 ih_pptr; /* ICMP_PARAMPROB */ + struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ + struct ih_idseq { + __u16 icd_id; + __u16 icd_seq; } ih_idseq; int ih_void; } icmp_hun; @@ -646,7 +854,7 @@ typedef struct uio { # define if_name name # ifdef KERNEL -# define GETUNIT(x) dev_get(x) +# define GETUNIT(x, v) dev_get(x) # define FREE_MB_T(m) kfree_skb(m, FREE_WRITE) # define uniqtime do_gettimeofday # undef INT_MAX @@ -664,19 +872,54 @@ 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) { \ - error = verify_area(VERIFY_READ, (a) ,(c)); \ - if (!error) \ - memcpy_fromfs((b), (a), (c)); \ - } -# define IWCOPY(a,b,c) { \ - error = verify_area(VERIFY_WRITE, (b), (c)); \ - if (!error) \ - memcpy_tofs((b), (a), (c)); \ - } +#define IRCOPY(const void *a, void *b, size_t c) { \ + int error; \ + + error = verify_area(VERIFY_READ, a ,c); \ + if (!error) \ + memcpy_fromfs(b, a, c); \ + return error; \ +} +static inline int IWCOPY(const void *a, void *b, size_t c) +{ + int error; + + error = verify_area(VERIFY_WRITE, b, c); + if (!error) + memcpy_tofs(b, a, c); + return error; +} +static inline int IRCOPYPTR(const void *a, void *b, size_t c) { + caddr_t ca; + int error; + + error = verify_area(VERIFY_READ, a ,sizeof(ca)); + if (!error) { + memcpy_fromfs(ca, a, sizeof(ca)); + error = verify_area(VERIFY_READ, ca , c); + if (!error) + memcpy_fromfs(b, ca, c); + } + return error; +} +static inline int IWCOPYPTR(const void *a, void *b, size_t c) { + caddr_t ca; + int error; + + + error = verify_area(VERIFY_READ, b ,sizeof(ca)); + if (!error) { + memcpy_fromfs(ca, b, sizeof(ca)); + error = verify_area(VERIFY_WRITE, ca, c); + if (!error) + memcpy_tofs(ca, a, c); + } + return error; +} # else # define __KERNEL__ # undef INT_MAX @@ -717,11 +960,27 @@ struct ether_addr { #define A_A & #endif +#define TCPF_ALL (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) + #ifndef ICMP_ROUTERADVERT # define ICMP_ROUTERADVERT 9 #endif #ifndef ICMP_ROUTERSOLICIT # define ICMP_ROUTERSOLICIT 10 #endif +#undef ICMP_MAX_UNREACH +#define ICMP_MAX_UNREACH 14 +#undef ICMP_MAXTYPE +#define ICMP_MAXTYPE 18 +/* + * ICMP error replies have an IP header (20 bytes), 8 bytes of ICMP data, + * 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_ICMPHLEN 8 +#define ICMPERR_IPICMPHLEN (20 + 8) +#define ICMPERR_MINPKTLEN (20 + 8 + 20) +#define ICMPERR_MAXPKTLEN (20 + 8 + 20 + 8) +#define ICMP6ERR_MINPKTLEN (20 + 8) #endif /* __IP_COMPAT_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_fil.c b/sys/contrib/ipfilter/netinet/ip_fil.c index 09c4b6e..9216b3c 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil.c +++ b/sys/contrib/ipfilter/netinet/ip_fil.c @@ -1,13 +1,13 @@ /* - * Copyright (C) 1993-1997 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ #if !defined(lint) -static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.0.2.44.2.7 1998/05/03 10:55:49 darrenr Exp $"; +static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.9 2000/05/22 12:48:28 darrenr Exp $"; #endif #ifndef SOLARIS @@ -17,10 +17,17 @@ static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.0.2.44.2.7 1998/05/03 10:55:4 #if defined(KERNEL) && !defined(_KERNEL) # define _KERNEL #endif -#ifdef __FreeBSD__ -# if defined(_KERNEL) && !defined(IPFILTER_LKM) -# include -# else +#if defined(_KERNEL) && defined(__FreeBSD_version) && \ + (__FreeBSD_version >= 400000) && !defined(KLD_MODULE) +#include "opt_inet6.h" +#endif +#include +#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ + defined(_KERNEL) +# include "opt_ipfilter_log.h" +#endif +#if defined(__FreeBSD__) && !defined(__FreeBSD_version) +# if !defined(_KERNEL) || defined(IPFILTER_LKM) # include # endif #endif @@ -29,10 +36,10 @@ static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.0.2.44.2.7 1998/05/03 10:55:4 # include # include # include +# include #endif #include #include -#include #include #if __FreeBSD_version >= 220000 && defined(_KERNEL) # include @@ -46,7 +53,7 @@ static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.0.2.44.2.7 1998/05/03 10:55:4 #endif #include #if !SOLARIS -# if (NetBSD > 199609) || (OpenBSD > 199603) +# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) # include # else # include @@ -64,6 +71,9 @@ static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.0.2.44.2.7 1998/05/03 10:55:4 #endif #if __FreeBSD_version >= 300000 # include +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" +# endif #endif #ifdef __sgi #include @@ -74,7 +84,7 @@ static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.0.2.44.2.7 1998/05/03 10:55:4 #include #include #if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */ -#include +# include #endif #include #include @@ -84,19 +94,27 @@ static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.0.2.44.2.7 1998/05/03 10:55:4 #include #include #ifndef _KERNEL +# include # include #endif #include "netinet/ip_compat.h" +#ifdef USE_INET6 +# include +#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 +#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 extern int ip_optcopy __P((struct ip *, struct ip *)); #endif @@ -108,30 +126,27 @@ 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; int ipl_unreach = ICMP_UNREACH_FILTER; 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 frzerostats __P((caddr_t)); +#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) static int frrequest __P((int, u_long, caddr_t, int)); #else static int frrequest __P((int, int, caddr_t, int)); #endif #ifdef _KERNEL static int (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **)); +static int send_ip __P((ip_t *, fr_info_t *, struct mbuf *)); +# ifdef __sgi +extern kmutex_t ipf_rw; +extern KRWLOCK_T ipf_mutex; +# endif #else int ipllog __P((void)); void init_ifp __P((void)); @@ -147,6 +162,15 @@ static int write_output __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *)); # endif #endif +int fr_running = 0; + +#if (__FreeBSD_version >= 300000) && defined(_KERNEL) +struct callout_handle ipfr_slowtimer_ch; +#endif +#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) +# include +struct callout ipfr_slowtimer_ch; +#endif #if (_BSDI_VERSION >= 199510) && defined(_KERNEL) # include @@ -195,7 +219,8 @@ void ipfilterattach(count) int count; { - iplattach(); + if (iplattach() != 0) + printf("IP Filter failed to attach\n"); } # endif @@ -204,40 +229,75 @@ int iplattach() { char *defpass; int s; -# ifdef __sgi - int error; +# if defined(__sgi) || (defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000)) + int error = 0; # endif SPL_NET(s); - if (ipl_inited || (fr_checkp == fr_check)) { + if (fr_running || (fr_checkp == fr_check)) { printf("IP Filter: already initialized\n"); SPL_X(s); 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 +# if __NetBSD_Version__ >= 104200000 + error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); + if (error) { +# ifdef USE_INET6 + goto pfil_error; +# else + appr_unload(); + ip_natunload(); + fr_stateunload(); + return error; +# endif + } +# else pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT); +# endif +# ifdef USE_INET6 + error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh); + if (error) { + pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); +pfil_error: + appr_unload(); + ip_natunload(); + fr_stateunload(); + return error; + } +# endif # endif # ifdef __sgi error = ipfilter_sgi_attach(); if (error) { SPL_X(s); + appr_unload(); + ip_natunload(); + fr_stateunload(); return error; } # endif - 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; + fr_running = 1; -# ifdef IPFILTER_LOG - ipflog_init(); -# endif SPL_X(s); if (fr_pass & FR_PASS) defpass = "pass"; @@ -246,13 +306,25 @@ int iplattach() else defpass = "no-match -> block"; - printf("IP Filter: initialized. Default = %s all, Logging = %s\n", - defpass, + printf("%s initialized. Default = %s all, Logging = %s\n", + ipfilter_version, defpass, # ifdef IPFILTER_LOG "enabled"); # else "disabled"); # endif +#ifdef _KERNEL +# if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) + callout_init(&ipfr_slowtimer_ch); + callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL); +# else +# if (__FreeBSD_version >= 300000) && defined(_KERNEL) + ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); +# else + timeout(ipfr_slowtimer, NULL, hz/2); +# endif +# endif +#endif return 0; } @@ -264,28 +336,61 @@ int iplattach() int ipldetach() { int s, i = FR_INQUE|FR_OUTQUE; +#if defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000) + int error = 0; +#endif +#ifdef _KERNEL +# if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) + callout_stop(&ipfr_slowtimer_ch); +# else +# if (__FreeBSD_version >= 300000) + untimeout(ipfr_slowtimer, NULL, ipfr_slowtimer_ch); +# else +# ifdef __sgi + untimeout(ipfr_slowtimer); +# else + untimeout(ipfr_slowtimer, NULL); +# endif +# endif /* FreeBSD */ +# endif /* NetBSD */ +#endif SPL_NET(s); - if (!ipl_inited) + if (!fr_running) { printf("IP Filter: not initialized\n"); SPL_X(s); return 0; } + printf("%s unloaded\n", ipfilter_version); + fr_checkp = fr_savep; - inetsw[0].pr_slowtimo = fr_saveslowtimo; - frflush(IPL_LOGIPF, &i); - ipl_inited = 0; + i = frflush(IPL_LOGIPF, i); + fr_running = 0; # ifdef NETBSD_PF +# if __NetBSD_Version__ >= 104200000 + error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); + if (error) + return error; +# else pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT); +# endif +# ifdef USE_INET6 + error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, + &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh); + if (error) + return error; +# endif # endif # ifdef __sgi ipfilter_sgi_detach(); # endif + appr_unload(); ipfr_unload(); ip_natunload(); fr_stateunload(); @@ -297,26 +402,20 @@ int ipldetach() #endif /* _KERNEL */ -static void frzerostats(data) +static int frzerostats(data) caddr_t data; { - struct friostat fio; - - bcopy((char *)frstats, (char *)fio.f_st, - sizeof(struct filterstats) * 2); - fio.f_fin[0] = ipfilter[0][0]; - fio.f_fin[1] = ipfilter[0][1]; - fio.f_fout[0] = ipfilter[1][0]; - fio.f_fout[1] = ipfilter[1][1]; - fio.f_acctin[0] = ipacct[0][0]; - fio.f_acctin[1] = ipacct[0][1]; - fio.f_acctout[0] = ipacct[1][0]; - fio.f_acctout[1] = ipacct[1][1]; - fio.f_active = fr_active; - fio.f_froute[0] = ipl_frouteok[0]; - fio.f_froute[1] = ipl_frouteok[1]; - IWCOPY((caddr_t)&fio, data, sizeof(fio)); + friostat_t fio; + int error; + + fr_getstat(&fio); + error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio)); + if (error) + return EFAULT; + bzero((char *)frstats, sizeof(*frstats) * 2); + + return 0; } @@ -331,19 +430,21 @@ int IPL_EXTERN(ioctl)(dev_t dev, int cmd, caddr_t data, int mode ) #else int IPL_EXTERN(ioctl)(dev, cmd, data, mode -#if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ - (__FreeBSD_version >= 220000)) && defined(_KERNEL) +# if (defined(_KERNEL) && ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || \ + (NetBSD >= 199511) || (__FreeBSD_version >= 220000) || \ + defined(__OpenBSD__))) , p) struct proc *p; -#else +# else ) -#endif +# 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 +# else int cmd; -#endif +# endif caddr_t data; int mode; #endif /* __sgi */ @@ -353,29 +454,49 @@ 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; +#else + unit = dev; #endif SPL_NET(s); if (unit == IPL_LOGNAT) { - error = nat_ioctl(data, cmd, mode); + if (fr_running) + error = nat_ioctl(data, cmd, mode); + else + error = EIO; SPL_X(s); return error; } if (unit == IPL_LOGSTATE) { - error = fr_state_ioctl(data, cmd, mode); + if (fr_running) + error = fr_state_ioctl(data, cmd, mode); + else + error = EIO; + SPL_X(s); + return error; + } + if (unit == IPL_LOGAUTH) { + if (!fr_running) + return EIO; + error = fr_auth_ioctl(data, cmd, NULL, NULL); SPL_X(s); return error; } + switch (cmd) { case FIONREAD : #ifdef IPFILTER_LOG - IWCOPY((caddr_t)&iplused[IPL_LOGIPF], (caddr_t)data, - sizeof(iplused[IPL_LOGIPF])); + error = IWCOPY((caddr_t)&iplused[IPL_LOGIPF], (caddr_t)data, + sizeof(iplused[IPL_LOGIPF])); #endif break; #if !defined(IPFILTER_LKM) && defined(_KERNEL) @@ -386,7 +507,9 @@ int mode; if (!(mode & FWRITE)) error = EPERM; else { - IRCOPY(data, (caddr_t)&enable, sizeof(enable)); + error = IRCOPY(data, (caddr_t)&enable, sizeof(enable)); + if (error) + break; if (enable) error = iplattach(); else @@ -399,10 +522,11 @@ int mode; if (!(mode & FWRITE)) error = EPERM; else - IRCOPY(data, (caddr_t)&fr_flags, sizeof(fr_flags)); + error = IRCOPY(data, (caddr_t)&fr_flags, + sizeof(fr_flags)); break; case SIOCGETFF : - IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags)); + error = IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags)); break; case SIOCINAFR : case SIOCRMAFR : @@ -432,40 +556,42 @@ int mode; break; case SIOCGETFS : { - struct friostat fio; - - bcopy((char *)frstats, (char *)fio.f_st, - sizeof(struct filterstats) * 2); - fio.f_fin[0] = ipfilter[0][0]; - fio.f_fin[1] = ipfilter[0][1]; - fio.f_fout[0] = ipfilter[1][0]; - fio.f_fout[1] = ipfilter[1][1]; - fio.f_acctin[0] = ipacct[0][0]; - fio.f_acctin[1] = ipacct[0][1]; - fio.f_acctout[0] = ipacct[1][0]; - fio.f_acctout[1] = ipacct[1][1]; - fio.f_auth = ipauth; - fio.f_active = fr_active; - fio.f_froute[0] = ipl_frouteok[0]; - fio.f_froute[1] = ipl_frouteok[1]; - IWCOPY((caddr_t)&fio, data, sizeof(fio)); + friostat_t fio; + + fr_getstat(&fio); + error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio)); + if (error) + return EFAULT; break; } case SIOCFRZST : if (!(mode & FWRITE)) error = EPERM; else - frzerostats(data); + error = frzerostats(data); break; case SIOCIPFFL : if (!(mode & FWRITE)) error = EPERM; else { - IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); - frflush(unit, &tmp); - IWCOPY((caddr_t)&tmp, data, sizeof(tmp)); + error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); + if (!error) { + tmp = frflush(unit, tmp); + error = IWCOPY((caddr_t)&tmp, data, + sizeof(tmp)); + } } break; + case SIOCSTLCK : + error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); + if (!error) { + fr_state_lock = tmp; + fr_nat_lock = tmp; + fr_frag_lock = tmp; + fr_auth_lock = tmp; + } else + error = EFAULT; + break; #ifdef IPFILTER_LOG case SIOCIPFFB : if (!(mode & FWRITE)) @@ -475,7 +601,10 @@ int mode; break; #endif /* IPFILTER_LOG */ case SIOCGFRST : - IWCOPY((caddr_t)ipfr_fragstats(), data, sizeof(ipfrstat_t)); + error = IWCOPYPTR((caddr_t)ipfr_fragstats(), data, + sizeof(ipfrstat_t)); + if (error) + return EFAULT; break; case SIOCAUTHW : case SIOCAUTHR : @@ -483,9 +612,6 @@ int mode; error = EPERM; break; } - case SIOCATHST : - error = fr_auth_ioctl(data, cmd, NULL, NULL); - break; case SIOCFRSYN : if (!(mode & FWRITE)) error = EPERM; @@ -505,43 +631,46 @@ 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); + 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; +#ifdef USE_INET6 + for (f = ipacct6[0][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = ipacct6[1][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = ipfilter6[0][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; + for (f = ipfilter6[1][fr_active]; (f != NULL); f = f->fr_next) + if (f->fr_ifa == ifp) + f->fr_ifa = (void *)-1; #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; + RWLOCK_EXIT(&ipf_mutex); + ip_natsync(ifp); } static int frrequest(unit, req, data, set) int unit; -#if defined(__NetBSD__) || defined(__OpenBSD__) +#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) u_long req; #else int req; @@ -554,30 +683,41 @@ caddr_t data; frentry_t frd; frdest_t *fdp; frgroup_t *fg = NULL; - int error = 0, in, group; + u_int *p, *pp; + int error = 0, in; + u_int group; fp = &frd; - IRCOPY(data, (caddr_t)fp, sizeof(*fp)); + error = IRCOPYPTR(data, (caddr_t)fp, sizeof(*fp)); + if (error) + return EFAULT; + 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; if (unit == IPL_LOGAUTH) ftail = fprev = &ipauth; - else if (fp->fr_flags & FR_ACCOUNT) + else if ((fp->fr_flags & FR_ACCOUNT) && (fp->fr_v == 4)) ftail = fprev = &ipacct[in][set]; - else if (fp->fr_flags & (FR_OUTQUE|FR_INQUE)) + else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) && (fp->fr_v == 4)) ftail = fprev = &ipfilter[in][set]; +#ifdef USE_INET6 + else if ((fp->fr_flags & FR_ACCOUNT) && (fp->fr_v == 6)) + ftail = fprev = &ipacct6[in][set]; + else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) && (fp->fr_v == 6)) + ftail = fprev = &ipfilter6[in][set]; +#endif else return ESRCH; @@ -590,15 +730,22 @@ caddr_t data; bzero((char *)frcache, sizeof(frcache[0]) * 2); if (*fp->fr_ifname) { - fp->fr_ifa = GETUNIT(fp->fr_ifname); + fp->fr_ifa = GETUNIT(fp->fr_ifname, fp->fr_v); if (!fp->fr_ifa) fp->fr_ifa = (void *)-1; } +#if BSD >= 199306 + if (*fp->fr_oifname) { + fp->fr_oifa = GETUNIT(fp->fr_oifname, fp->fr_v); + if (!fp->fr_oifa) + fp->fr_oifa = (void *)-1; + } +#endif fdp = &fp->fr_dif; fp->fr_flags &= ~FR_DUP; if (*fdp->fd_ifname) { - fdp->fd_ifp = GETUNIT(fdp->fd_ifname); + fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_v); if (!fdp->fd_ifp) fdp->fd_ifp = (struct ifnet *)-1; else @@ -607,7 +754,7 @@ caddr_t data; fdp = &fp->fr_tif; if (*fdp->fd_ifname) { - fdp->fd_ifp = GETUNIT(fdp->fd_ifname); + fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_v); if (!fdp->fd_ifp) fdp->fd_ifp = (struct ifnet *)-1; } @@ -616,9 +763,13 @@ caddr_t data; * Look for a matching filter rule, but don't include the next or * interface pointer in the comparison (fr_next, fr_ifa). */ + for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_ip, pp = &fp->fr_cksum; + p != pp; p++) + fp->fr_cksum += *p; + for (; (f = *ftail); ftail = &f->fr_next) - if (bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip, - FR_CMPSIZ) == 0) + if ((fp->fr_cksum == f->fr_cksum) && + !bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip, FR_CMPSIZ)) break; /* @@ -627,47 +778,59 @@ caddr_t data; if (req == SIOCZRLST) { if (!f) return ESRCH; - IWCOPY((caddr_t)f, data, sizeof(*f)); + error = IWCOPYPTR((caddr_t)f, data, sizeof(*f)); + if (error) + return EFAULT; f->fr_hits = 0; f->fr_bytes = 0; return 0; } 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; - f = NULL; + else { + if (fp->fr_hits) { + ftail = fprev; + while (--fp->fr_hits && (f = *ftail)) + ftail = &f->fr_next; + } + f = NULL; + } } - if (req == SIOCDELFR || req == SIOCRMIFR) { + if (req == SIOCRMAFR || req == SIOCRMIFR) { if (!f) error = ESRCH; else { - if (f->fr_ref > 1) + /* + * Only return EBUSY if there is a group list, else + * it's probably just state information referencing + * the rule. + */ + if ((f->fr_ref > 1) && f->fr_grp) return EBUSY; if (fg && fg->fg_head) fg->fg_head->fr_ref--; if (unit == IPL_LOGAUTH) return fr_auth_ioctl(data, req, f, ftail); if (f->fr_grhead) - fr_delgroup(f->fr_grhead, fp->fr_flags, unit, - set); + fr_delgroup((u_int)f->fr_grhead, fp->fr_flags, + unit, set); fixskip(fprev, f, -1); *ftail = f->fr_next; - KFREE(f); + f->fr_next = NULL; + if (f->fr_ref == 0) + KFREE(f); } } else { if (f) error = EEXIST; else { if (unit == IPL_LOGAUTH) - return fr_auth_ioctl(data, req, f, ftail); - KMALLOC(f, frentry_t *, sizeof(*f)); + return fr_auth_ioctl(data, req, fp, ftail); + KMALLOC(f, frentry_t *); if (f != NULL) { if (fg && fg->fg_head) fg->fg_head->fr_ref++; @@ -693,33 +856,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) || \ - (__FreeBSD_version >= 220000)) && defined(_KERNEL) +# 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; @@ -727,25 +890,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) || \ - (__FreeBSD_version >= 220000)) && defined(_KERNEL) +# 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; @@ -758,9 +921,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; @@ -769,13 +932,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 } @@ -783,72 +946,254 @@ 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(oip, fin) +struct ip *oip; +fr_info_t *fin; { - struct tcpiphdr *tp; - struct tcphdr *tcp; + struct tcphdr *tcp, *tcp2; + int tlen = 0, hlen; struct mbuf *m; - int tlen = 0, err; +#ifdef USE_INET6 + ip6_t *ip6, *oip6 = (ip6_t *)oip; +#endif 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); +#ifdef USE_INET6 + hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); +#else + hlen = sizeof(ip_t); +#endif + m->m_len = sizeof(*tcp2) + hlen; # 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; - tp->ti_len = htons(sizeof(struct tcphdr)); - tcp->th_sum = in_cksum(m, sizeof(struct tcpiphdr)); - - ip->ip_tos = ((struct ip *)ti)->ip_tos; - ip->ip_p = ((struct ip *)ti)->ip_p; - ip->ip_len = sizeof (struct tcpiphdr); +# ifdef USE_INET6 + ip6 = (ip6_t *)ip; +# endif + bzero((char *)ip, sizeof(*tcp2) + hlen); + tcp2 = (struct tcphdr *)((char *)ip + hlen); + + tcp2->th_sport = tcp->th_dport; + tcp2->th_dport = tcp->th_sport; + 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; +# ifdef USE_INET6 + if (fin->fin_v == 6) { + ip6->ip6_plen = htons(sizeof(struct tcphdr)); + ip6->ip6_nxt = IPPROTO_TCP; + ip6->ip6_src = oip6->ip6_dst; + ip6->ip6_dst = oip6->ip6_src; + tcp2->th_sum = in6_cksum(m, IPPROTO_TCP, + sizeof(*ip6), sizeof(*tcp2)); + return send_ip(oip, fin, m); + } +# endif + ip->ip_p = IPPROTO_TCP; + ip->ip_len = htons(sizeof(struct tcphdr)); + ip->ip_src.s_addr = oip->ip_dst.s_addr; + ip->ip_dst.s_addr = oip->ip_src.s_addr; + tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2)); + ip->ip_len = hlen + sizeof(*tcp2); + return send_ip(oip, fin, m); +} + + +static int send_ip(oip, fin, m) +ip_t *oip; +fr_info_t *fin; +struct mbuf *m; +{ + ip_t *ip; + + ip = mtod(m, ip_t *); + + ip->ip_v = fin->fin_v; + if (ip->ip_v == 4) { + ip->ip_hl = (sizeof(*oip) >> 2); + ip->ip_v = IPVERSION; + ip->ip_tos = oip->ip_tos; + ip->ip_id = oip->ip_id; + ip->ip_off = 0; # if (BSD < 199306) || defined(__sgi) - ip->ip_ttl = tcp_ttl; + ip->ip_ttl = tcp_ttl; # else - ip->ip_ttl = ip_defttl; + ip->ip_ttl = ip_defttl; +# endif + ip->ip_sum = 0; + } +# ifdef USE_INET6 + else if (ip->ip_v == 6) { + ip6_t *ip6 = (ip6_t *)ip; + + ip6->ip6_hlim = 127; + + return ip6_output(m, NULL, NULL, 0, NULL, NULL); + } # endif +# ifdef IPSEC + m->m_pkthdr.rcvif = NULL; +# endif + return ipfr_fastroute(m, fin, NULL); +} -# if defined(__FreeBSD_version) && (__FreeBSD_version >= 220000) - bzero((char *)&ro, sizeof(ro)); - err = ip_output(m, (struct mbuf *)0, &ro, 0, 0); - if (ro.ro_rt) - RTFREE(ro.ro_rt); + +int send_icmp_err(oip, type, fin, dst) +ip_t *oip; +int type; +fr_info_t *fin; +int dst; +{ + int err, hlen = 0, xtra = 0, iclen, ohlen = 0, avail, code; + struct in_addr dst4; + struct icmp *icmp; + struct mbuf *m; + void *ifp; +#ifdef USE_INET6 + ip6_t *ip6, *oip6 = (ip6_t *)oip; + struct in6_addr dst6; +#endif + ip_t *ip; + + if ((type < 0) || (type > ICMP_MAXTYPE)) + return -1; + + code = fin->fin_icode; +#ifdef USE_INET6 + if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) + return -1; +#endif + + avail = 0; + m = NULL; + ifp = fin->fin_ifp; + if (fin->fin_v == 4) { +# if (BSD < 199306) || defined(__sgi) + avail = MLEN; + m = m_get(M_DONTWAIT, MT_HEADER); # else - /* - * extra 0 in case of multicast - */ - err = ip_output(m, (struct mbuf *)0, 0, 0, 0); + avail = MHLEN; + m = m_gethdr(M_DONTWAIT, MT_HEADER); # endif + if (m == NULL) + return ENOBUFS; + + if (dst == 0) { + if (fr_ifpaddr(4, ifp, &dst4) == -1) + return -1; + } else + dst4.s_addr = oip->ip_dst.s_addr; + + hlen = sizeof(ip_t); + ohlen = oip->ip_hl << 2; + xtra = 8; + } + +#ifdef USE_INET6 + else if (fin->fin_v == 6) { + hlen = sizeof(ip6_t); + ohlen = sizeof(ip6_t); + type = icmptoicmp6types[type]; + if (type == ICMP6_DST_UNREACH) + code = icmptoicmp6unreach[code]; + + MGETHDR(m, M_DONTWAIT, MT_HEADER); + if (!m) + return ENOBUFS; + + MCLGET(m, M_DONTWAIT); + if (!m) + return ENOBUFS; + avail = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN; + xtra = MIN(ntohs(oip6->ip6_plen) + sizeof(ip6_t), + avail - hlen - sizeof(*icmp) - max_linkhdr); + if (dst == 0) { + if (fr_ifpaddr(6, ifp, (struct in_addr *)&dst6) == -1) + return -1; + } else + dst6 = oip6->ip6_dst; + } +#endif + + iclen = hlen + sizeof(*icmp); +# if BSD >= 199306 + avail -= (max_linkhdr + iclen); + m->m_data += max_linkhdr; + m->m_pkthdr.rcvif = (struct ifnet *)0; + if (xtra > avail) + xtra = avail; + iclen += xtra; + m->m_pkthdr.len = iclen; +#else + avail -= (m->m_off + iclen); + if (xtra > avail) + xtra = avail; + iclen += xtra; +#endif + m->m_len = iclen; + ip = mtod(m, ip_t *); + icmp = (struct icmp *)((char *)ip + hlen); + bzero((char *)ip, iclen); + + icmp->icmp_type = type; + icmp->icmp_code = fin->fin_icode; + icmp->icmp_cksum = 0; + if (avail) { + bcopy((char *)oip, (char *)&icmp->icmp_ip, MIN(ohlen, avail)); + avail -= MIN(ohlen, avail); + } + +#ifdef USE_INET6 + ip6 = (ip6_t *)ip; + if (fin->fin_v == 6) { + ip6->ip6_flow = 0; + ip6->ip6_plen = htons(iclen - hlen); + ip6->ip6_nxt = IPPROTO_ICMPV6; + ip6->ip6_hlim = 0; + ip6->ip6_src = dst6; + ip6->ip6_dst = oip6->ip6_src; + if (avail) + bcopy((char *)oip + ohlen, + (char *)&icmp->icmp_ip + ohlen, avail); + icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6, + sizeof(*ip6), iclen - hlen); + } else +#endif + { + ip->ip_src.s_addr = dst4.s_addr; + ip->ip_dst.s_addr = oip->ip_src.s_addr; + + if (avail > 8) + avail = 8; + if (avail) + bcopy((char *)oip + ohlen, + (char *)&icmp->icmp_ip + ohlen, avail); + icmp->icmp_cksum = ipf_cksum((u_short *)icmp, + sizeof(*icmp) + 8); + ip->ip_len = iclen; + ip->ip_p = IPPROTO_ICMP; + } + err = send_ip(oip, fin, m); return err; } @@ -865,7 +1210,8 @@ void # endif iplinit() { - (void) iplattach(); + if (iplattach() != 0) + printf("IP Filter failed to attach\n"); ip_init(); } # endif /* ! __NetBSD__ */ @@ -882,7 +1228,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; @@ -890,13 +1236,24 @@ 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, code; + struct ifnet *ifp, *sifp; struct sockaddr_in *dst; + struct route iproute; + frentry_t *fr; + hlen = fin->fin_hlen; ip = mtod(m0, struct ip *); + +#ifdef USE_INET6 + if (ip->ip_v == 6) { + /* + * currently "to " and "to :ip#" are not supported + * for IPv6 + */ + return ip6_output(m0, NULL, NULL, 0, NULL, NULL); + } +#endif /* * Route packet. */ @@ -904,13 +1261,32 @@ 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; -# ifdef __bsdi__ + + fr = fin->fin_fr; + if (fdp) + ifp = fdp->fd_ifp; + else { + ifp = fin->fin_ifp; + dst->sin_addr = ip->ip_dst; + } + + /* + * In case we're here due to "to " 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 if (fdp) + dst->sin_addr = fdp->fd_ip.s_addr ? fdp->fd_ip : ip->ip_dst; + +# if BSD >= 199306 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); @@ -919,7 +1295,7 @@ frdest_t *fdp; rtalloc(ro); # endif if (!ifp) { - if (!(fin->fin_fr->fr_flags & FR_FASTROUTE)) { + if (!fr || !(fr->fr_flags & FR_FASTROUTE)) { error = -2; goto bad; } @@ -939,15 +1315,36 @@ frdest_t *fdp; /* * For input packets which are being "fastrouted", they won't * go back through output filtering and miss their chance to get - * NAT'd. + * NAT'd and counted. */ - (void) ip_natout(ip, hlen, fin); - if (fin->fin_out) + 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)) { + ATOMIC_INCL(frstats[1].fr_acct); + } + fin->fin_fr = NULL; + if (!fr || !(fr->fr_flags & FR_RETMASK)) { + (void) fr_checkstate(ip, fin); + (void) ip_natout(ip, fin); + } + } else ip->ip_sum = 0; /* * If small enough for interface, can just send directly. */ if (ip->ip_len <= ifp->if_mtu) { +# if BSD >= 199306 + int i = 0; + +# ifdef MCLISREFERENCED + if ((m->m_flags & M_EXT) && MCLISREFERENCED(m)) +# else + if (m->m_flags & M_EXT) +# endif + i = 1; +# endif # ifndef sparc ip->ip_id = htons(ip->ip_id); ip->ip_len = htons(ip->ip_len); @@ -958,6 +1355,11 @@ frdest_t *fdp; # if BSD >= 199306 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, ro->ro_rt); + if (i) { + ip->ip_id = ntohs(ip->ip_id); + ip->ip_len = ntohs(ip->ip_len); + ip->ip_off = ntohs(ip->ip_off); + } # else error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst); # endif @@ -988,7 +1390,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; @@ -1018,6 +1424,10 @@ frdest_t *fdp; error = ENOBUFS; /* ??? */ goto sendorfree; } +# if BSD >= 199306 + m->m_pkthdr.len = mhlen + len; + m->m_pkthdr.rcvif = NULL; +# endif # ifndef sparc mhip->ip_off = htons((u_short)mhip->ip_off); # endif @@ -1057,70 +1467,104 @@ done: else ipl_frouteok[1]++; - if (ro->ro_rt) { + if (ro->ro_rt) RTFREE(ro->ro_rt); - } - return; + return 0; bad: + if (error == EMSGSIZE) { + sifp = fin->fin_ifp; + code = fin->fin_icode; + fin->fin_icode = ICMP_UNREACH_NEEDFRAG; + fin->fin_ifp = ifp; + (void) send_icmp_err(ip, ICMP_UNREACH, fin, 1); + fin->fin_ifp = sifp; + fin->fin_icode = code; + } m_freem(m); goto done; } + + +int fr_verifysrc(ipa, ifp) +struct in_addr ipa; +void *ifp; +{ + struct sockaddr_in *dst; + struct route iproute; + + bzero((char *)&iproute, sizeof(iproute)); + dst = (struct sockaddr_in *)&iproute.ro_dst; + dst->sin_family = AF_INET; + dst->sin_addr = ipa; +# if (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \ + !defined(__OpenBSD__) +# ifdef RTF_CLONING + rtalloc_ign(&iproute, RTF_CLONING); +# else + rtalloc_ign(&iproute, RTF_PRCLONING); +# endif +# else + rtalloc(&iproute); +# endif + if (iproute.ro_rt == NULL) + return 0; + return (ifp == iproute.ro_rt->rt_ifp); +} + #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]; + int fd; # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ (defined(OpenBSD) && (OpenBSD >= 199603)) sprintf(fname, "/tmp/%s", ifp->if_xname); - if ((fp = fopen(fname, "a"))) { - fclose(fp); - } # else sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); - if ((fp = fopen(fname, "a"))) { - fwrite((char *)ip, ntohs(ip->ip_len), 1, fp); - fclose(fp); - } # endif + fd = open(fname, O_WRONLY|O_APPEND); + if (fd == -1) { + perror("open"); + return -1; + } + write(fd, (char *)ip, ntohs(ip->ip_len)); + close(fd); return 0; } -struct ifnet *get_unit(name) +struct ifnet *get_unit(name, v) char *name; +int v; { struct ifnet *ifp, **ifa; # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ @@ -1177,30 +1621,37 @@ char *name; void init_ifp() { - FILE *fp; struct ifnet *ifp, **ifa; char fname[32]; + int fd; + # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ (defined(OpenBSD) && (OpenBSD >= 199603)) for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { ifp->if_output = write_output; sprintf(fname, "/tmp/%s", ifp->if_xname); - if ((fp = fopen(fname, "w"))) - fclose(fp); + fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); + if (fd == -1) + perror("open"); + else + close(fd); } # else for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { ifp->if_output = write_output; sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); - if ((fp = fopen(fname, "w"))) - fclose(fp); + 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; @@ -1208,7 +1659,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)); @@ -1218,6 +1669,7 @@ frdest_t *fdp; #else (*ifp->if_output)(ifp, (void *)ip, NULL, 0); #endif + return 0; } @@ -1244,4 +1696,10 @@ struct ifnet *ifp; verbose("- TCP RST sent\n"); return 0; } + + +void frsync() +{ + return; +} #endif /* _KERNEL */ diff --git a/sys/contrib/ipfilter/netinet/ip_fil.h b/sys/contrib/ipfilter/netinet/ip_fil.h index edbd685..14f4861 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil.h +++ b/sys/contrib/ipfilter/netinet/ip_fil.h @@ -1,12 +1,12 @@ /* - * Copyright (C) 1993-1997 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * * @(#)ip_fil.h 1.35 6/5/96 - * $Id: ip_fil.h,v 2.0.2.39.2.11 1998/05/23 14:29:37 darrenr Exp $ + * $Id: ip_fil.h,v 2.29.2.2 2000/05/22 10:26:13 darrenr Exp $ */ #ifndef __IP_FIL_H__ @@ -21,11 +21,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 @@ -37,94 +37,132 @@ #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 _IOWR('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 SIOCSTLCK _IOWR('r', 79, u_int) +# define SIOCSTPUT _IOWR('r', 80, struct ipstate_save *) +# define SIOCSTGET _IOWR('r', 81, struct ipstate_save *) +# define SIOCSTGSZ _IOWR('r', 82, struct natget *) +# define SIOCGFRST _IOWR('r', 83, struct ipfrstat *) #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 _IOWR(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 SIOCSTLCK _IOWR(r, 79, u_int) +# define SIOCSTPUT _IOWR(r, 80, struct ipstate_save *) +# define SIOCSTGET _IOWR(r, 81, struct ipstate_save *) +# define SIOCSTGSZ _IOWR(r, 82, struct natget *) +# define SIOCGFRST _IOWR(r, 83, struct ipfrstat *) #endif #define SIOCADDFR SIOCADAFR #define SIOCDELFR SIOCRMAFR #define SIOCINSFR SIOCINAFR + typedef struct fr_ip { - u_char fi_v:4; /* IP version */ - u_char fi_fl:4; /* packet flags */ - u_char fi_tos; - u_char fi_ttl; - u_char fi_p; - struct in_addr fi_src; - struct in_addr fi_dst; + u_32_t fi_v:4; /* IP version */ + u_32_t fi_fl:4; /* packet flags */ + u_32_t fi_tos:8; /* IP packet TOS */ + u_32_t fi_ttl:8; /* IP packet TTL */ + u_32_t fi_p:8; /* IP packet protocol */ + union i6addr fi_src; /* source address from packet */ + union i6addr fi_dst; /* destination address from packet */ u_32_t fi_optmsk; /* bitmask composed from IP options */ u_short fi_secmsk; /* bitmask composed from IP security options */ - u_short fi_auth; + u_short fi_auth; /* authentication code from IP sec. options */ } fr_ip_t; #define FI_OPTIONS (FF_OPTIONS >> 24) #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) + +#define fi_saddr fi_src.in4.s_addr +#define fi_daddr fi_dst.in4.s_addr + + +/* + * 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_WILDP (FI_W_SPORT|FI_W_DPORT) +#define FI_W_SADDR 0x00000400 +#define FI_W_DADDR 0x00000800 +#define FI_WILDA (FI_W_SADDR|FI_W_DADDR) +#define FI_NEWFR 0x00001000 typedef struct fr_info { - struct fr_ip fin_fi; - u_short fin_data[2]; - u_short fin_out; - u_short fin_hlen; - u_char fin_tcpf; - u_char fin_icode; /* From here on is packet specific */ - u_short fin_rule; - u_short fin_group; - u_short fin_dlen; - u_short fin_id; - void *fin_ifp; - struct frentry *fin_fr; + 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_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_32_t fin_group; /* group number, -1 for none */ + struct frentry *fin_fr; /* last matching rule */ char *fin_dp; /* start of data past IP header */ - void *fin_mp; + 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 + void *fin_qfm; /* pointer to mblk where pkt starts */ + void *fin_qif; +#endif + u_short fin_plen; + u_short fin_off; } fr_info_t; +#define fin_v fin_fi.fi_v + /* * Size for compares on fr_info structures */ -#define FI_CSIZE (sizeof(struct fr_ip) + sizeof(u_short) * 4 + \ - sizeof(u_char)) +#define FI_CSIZE offsetof(fr_info_t, fin_icode) + /* * Size for copying cache fr_info structure */ -#define FI_COPYSIZE (sizeof(fr_info_t) - sizeof(void *) * 2) +#define FI_COPYSIZE offsetof(fr_info_t, fin_dp) typedef struct frdest { void *fd_ifp; @@ -132,13 +170,36 @@ typedef struct frdest { char fd_ifname[IFNAMSIZ]; } frdest_t; +typedef struct frpcmp { + int frp_cmp; /* data for port comparisons */ + u_short frp_port; /* top port for <> and >< */ + u_short frp_top; /* top port for <> and >< */ +} frpcmp_t; + +typedef struct frtuc { + u_char ftu_tcpfm; /* tcp flags mask */ + u_char ftu_tcpf; /* tcp flags */ + frpcmp_t ftu_src; + frpcmp_t ftu_dst; +} frtuc_t; + +#define ftu_scmp ftu_src.frp_cmp +#define ftu_dcmp ftu_dst.frp_cmp +#define ftu_sport ftu_src.frp_port +#define ftu_dport ftu_dst.frp_port +#define ftu_stop ftu_src.frp_top +#define ftu_dtop ftu_dst.frp_top + typedef struct frentry { struct frentry *fr_next; - u_short fr_group; /* group to which this rule belongs */ - u_short fr_grhead; /* group # which this rule starts */ + u_32_t fr_group; /* group to which this rule belongs */ + u_32_t fr_grhead; /* group # which this rule starts */ 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 @@ -151,34 +212,42 @@ typedef struct frentry { struct fr_ip fr_ip; struct fr_ip fr_mip; /* mask structure */ - u_char fr_tcpfm; /* tcp flags mask */ - u_char fr_tcpf; /* tcp flags */ u_short fr_icmpm; /* data for ICMP packets (mask) */ u_short fr_icmp; - u_char fr_scmp; /* data for port comparisons */ - u_char fr_dcmp; - u_short fr_dport; - u_short fr_sport; - u_short fr_stop; /* top port for <> and >< */ - u_short fr_dtop; /* top port for <> and >< */ + frtuc_t fr_tuc; u_32_t fr_flags; /* per-rule flags && options (see below) */ - int fr_skip; /* # of rules to skip */ + u_int fr_skip; /* # of rules to skip */ + u_int 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 */ + int fr_sap; /* For solaris only */ + u_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 */ + u_int fr_cksum; /* checksum on filter rules for performance */ } frentry_t; +#define fr_v fr_ip.fi_v #define fr_proto fr_ip.fi_p #define fr_ttl fr_ip.fi_ttl #define fr_tos fr_ip.fi_tos -#define fr_dst fr_ip.fi_dst -#define fr_src fr_ip.fi_src -#define fr_dmsk fr_mip.fi_dst -#define fr_smsk fr_mip.fi_src +#define fr_tcpfm fr_tuc.ftu_tcpfm +#define fr_tcpf fr_tuc.ftu_tcpf +#define fr_scmp fr_tuc.ftu_scmp +#define fr_dcmp fr_tuc.ftu_dcmp +#define fr_dport fr_tuc.ftu_dport +#define fr_sport fr_tuc.ftu_sport +#define fr_stop fr_tuc.ftu_stop +#define fr_dtop fr_tuc.ftu_dtop +#define fr_dst fr_ip.fi_dst.in4 +#define fr_src fr_ip.fi_src.in4 +#define fr_dmsk fr_mip.fi_dst.in4 +#define fr_smsk fr_mip.fi_src.in4 #ifndef offsetof #define offsetof(t,m) (int)((&((t *)0L)->m)) @@ -199,6 +268,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 */ @@ -213,8 +283,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 @@ -246,6 +318,7 @@ typedef struct filterstats { u_long fr_pass; /* packets allowed */ u_long fr_block; /* packets denied */ u_long fr_nom; /* packets which don't match any rule */ + u_long fr_short; /* packets which are short */ u_long fr_ppkl; /* packets allowed and logged */ u_long fr_bpkl; /* packets denied and logged */ u_long fr_npkl; /* packets unmatched and logged */ @@ -261,11 +334,16 @@ typedef struct filterstats { u_long fr_chit; /* cached hit */ u_long fr_tcpbad; /* TCP checksum check failures */ u_long fr_pull[2]; /* good and bad pullup attempts */ + u_long fr_badsrc; /* source received doesn't match route */ #if SOLARIS + u_long fr_notdata; /* PROTO/PCPROTO that have no data */ + u_long fr_nodata; /* mblks that have no data */ u_long fr_bad; /* bad IP packets to the filter */ u_long fr_notip; /* packets passed through no on ip queue */ u_long fr_drop; /* packets dropped - no info for them! */ + u_long fr_copy; /* messages copied due to db_ref > 1 */ #endif + u_long fr_ipv6[2]; /* IPv6 packets in/out */ } filterstats_t; /* @@ -277,9 +355,19 @@ typedef struct friostat { struct frentry *f_fout[2]; struct frentry *f_acctin[2]; struct frentry *f_acctout[2]; + struct frentry *f_fin6[2]; + struct frentry *f_fout6[2]; + struct frentry *f_acctin6[2]; + struct frentry *f_acctout6[2]; struct frentry *f_auth; + struct frgroup *f_groups[3][2]; u_long f_froute[2]; - int f_active; + int f_defpass; /* default pass - from fr_pass */ + char f_active; /* 1 or 0 - active rule set */ + char f_running; /* 1 if running, else 0 */ + char f_logging; /* 1 if enabled, else 0 */ + char f_version[32]; /* version string */ + int f_locks[4]; } friostat_t; typedef struct optlist { @@ -292,7 +380,7 @@ typedef struct optlist { * Group list structure. */ typedef struct frgroup { - u_short fg_num; + u_32_t fg_num; struct frgroup *fg_next; struct frentry *fg_head; struct frentry **fg_start; @@ -305,11 +393,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; @@ -326,21 +413,23 @@ typedef struct ipflog { #endif u_char fl_plen; /* extra data after hlen */ u_char fl_hlen; /* length of IP headers saved */ - u_short fl_rule; /* assume never more than 64k rules, total */ - u_short fl_group; + u_short fl_loglevel; /* syslog log level */ + u_32_t fl_rule; + u_32_t fl_group; u_32_t fl_flags; + u_32_t fl_lflags; } ipflog_t; #ifndef ICMP_UNREACH_FILTER -#define ICMP_UNREACH_FILTER 13 +# define ICMP_UNREACH_FILTER 13 #endif #ifndef IPF_LOGGING -#define IPF_LOGGING 0 +# define IPF_LOGGING 0 #endif #ifndef IPF_DEFAULT_PASS -#define IPF_DEFAULT_PASS FR_PASS +# define IPF_DEFAULT_PASS FR_PASS #endif #define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h))) @@ -372,16 +461,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 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) +extern int ipfr_fastroute __P((ip_t *, fr_info_t *, frdest_t *)); +extern struct ifnet *get_unit __P((char *, int)); +# 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)); @@ -390,45 +495,43 @@ 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 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)); +extern int send_icmp_err __P((ip_t *, int, fr_info_t *, int)); +extern int send_reset __P((ip_t *, fr_info_t *)); # 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 *)); +# 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 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 extern int iplread __P((dev_t, struct uio *, cred_t *)); -# endif # else /* SOLARIS */ extern int fr_check __P((ip_t *, int, void *, int, mb_t **)); 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 *)); -# endif -extern void ipfr_fastroute __P((mb_t *, fr_info_t *, frdest_t *)); +extern int send_reset __P((struct ip *, fr_info_t *)); +extern int send_icmp_err __P((ip_t *, int, fr_info_t *, int)); +extern int ipfr_fastroute __P((mb_t *, fr_info_t *, frdest_t *)); extern size_t mbufchainlen __P((mb_t *)); # ifdef __sgi # include @@ -445,8 +548,9 @@ extern void ipfilter_sgi_intfsync __P((void)); extern int iplidentify __P((char *)); # endif # if (_BSDI_VERSION >= 199510) || (__FreeBSD_version >= 220000) || \ - (NetBSD >= 199511) -# if defined(__NetBSD__) || (_BSDI_VERSION >= 199701) + (NetBSD >= 199511) || 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 extern int iplioctl __P((dev_t, int, caddr_t, int, struct proc *)); @@ -454,19 +558,12 @@ extern int iplioctl __P((dev_t, int, caddr_t, int, struct proc *)); extern int iplopen __P((dev_t, int, int, struct proc *)); extern int iplclose __P((dev_t, int, int, struct proc *)); # else -# if defined(__OpenBSD__) -extern int iplioctl __P((dev_t, u_long, caddr_t, int)); -# else /* __OpenBSD__ */ -# ifndef linux -extern int iplioctl __P((dev_t, int, caddr_t, int)); -# else -extern int iplioctl(struct inode *, struct file *, u_int, u_long); -# endif -# endif /* __OpenBSD__ */ -# ifndef linux +# ifndef linux extern int iplopen __P((dev_t, int)); extern int iplclose __P((dev_t, int)); +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 */ @@ -484,38 +581,49 @@ extern int iplread(struct inode *, struct file *, char *, int); # 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 char *memstr __P((char *, char *, int, int)); +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 ipf_cksum __P((u_short *, int)); +extern int ircopyptr __P((void *, void *, size_t)); +extern int iwcopyptr __P((void *, void *, size_t)); + +extern int frflush __P((minor_t, int)); +extern void frsync __P((void)); +extern frgroup_t *fr_addgroup __P((u_32_t, frentry_t *, minor_t, int)); +extern void fr_delgroup __P((u_32_t, u_32_t, minor_t, int)); +extern frgroup_t *fr_findgroup __P((u_32_t, u_32_t, minor_t, int, + frgroup_t ***)); + 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 void fr_getstat __P((struct friostat *)); +extern int fr_ifpaddr __P((int, void *, struct in_addr *)); +extern int fr_lock __P((caddr_t, int *)); +extern void fr_makefrip __P((int, ip_t *, fr_info_t *)); +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 int fr_tcpudpchk __P((frtuc_t *, fr_info_t *)); +extern int fr_verifysrc __P((struct in_addr, void *)); + extern int ipl_unreach; -extern int ipl_inited; +extern int fr_running; extern u_long ipl_frouteok[2]; extern int fr_pass; extern int fr_flags; extern int fr_active; +extern int fr_chksrc; extern fr_info_t frcache[2]; -#ifdef IPFILTER_LOG +extern char ipfilter_version[]; extern iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1]; -extern int iplused[IPL_LOGMAX + 1]; -#endif +extern size_t iplused[IPL_LOGMAX + 1]; extern struct frentry *ipfilter[2][2], *ipacct[2][2]; +#ifdef USE_INET6 +extern struct frentry *ipfilter6[2][2], *ipacct6[2][2]; +extern int icmptoicmp6types[ICMP_MAXTYPE+1]; +extern int icmptoicmp6unreach[ICMP_MAX_UNREACH]; +#endif extern struct frgroup *ipfgroups[3][2]; extern struct filterstats frstats[]; diff --git a/sys/contrib/ipfilter/netinet/ip_frag.c b/sys/contrib/ipfilter/netinet/ip_frag.c index 923f685..3e0a7f3 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.c +++ b/sys/contrib/ipfilter/netinet/ip_frag.c @@ -1,59 +1,68 @@ /* - * Copyright (C) 1993-1997 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ #if !defined(lint) -static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.0.2.19.2.1 1997/11/12 10:50:21 darrenr Exp $"; +static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.3 2000/05/05 15:10:23 darrenr Exp $"; #endif -#if !defined(_KERNEL) && !defined(KERNEL) -# include -# include +#if defined(KERNEL) && !defined(_KERNEL) +# define _KERNEL #endif + #include #include #include #include #include -#if defined(KERNEL) && (__FreeBSD_version >= 220000) -#include -#include +#if !defined(_KERNEL) && !defined(KERNEL) +# include +# include +# include +#endif +#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) +# include +# include #else -#include +# include #endif #include #ifndef linux -#include +# include #endif #include #if defined(_KERNEL) && !defined(linux) # include #endif #if !defined(__SVR4) && !defined(__svr4__) +# if defined(_KERNEL) && !defined(__sgi) +# include +# endif # ifndef linux # include # endif #else # include -# include +# ifdef _KERNEL +# include +# endif # include # include #endif - #include #ifdef sun -#include +# include #endif #include #include #include #include #ifndef linux -#include +# include #endif #include #include @@ -66,24 +75,51 @@ static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.0.2.19.2.1 1997/11/12 10:50: #include "netinet/ip_frag.h" #include "netinet/ip_state.h" #include "netinet/ip_auth.h" +#if (__FreeBSD_version >= 300000) +# include +# if (defined(KERNEL) || defined(_KERNEL)) +# ifndef IPFILTER_LKM +# include +# include +# endif +extern struct callout_handle ipfr_slowtimer_ch; +# endif +#endif +#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) +# include +extern struct callout ipfr_slowtimer_ch; +#endif + + +static ipfr_t *ipfr_heads[IPFT_SIZE]; +static ipfr_t *ipfr_nattab[IPFT_SIZE]; +static ipfrstat_t ipfr_stats; +static int ipfr_inuse = 0; + +int fr_ipfrttl = 120; /* 60 seconds */ +int fr_frag_lock = 0; -ipfr_t *ipfr_heads[IPFT_SIZE]; -ipfr_t *ipfr_nattab[IPFT_SIZE]; -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 kmutex_t ipf_frag; -extern kmutex_t ipf_natfrag; -extern kmutex_t 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() @@ -102,10 +138,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; @@ -123,10 +159,10 @@ 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)) { - ipfr_stats.ifs_exists++; + ATOMIC_INCL(ipfr_stats.ifs_exists); return NULL; } @@ -134,45 +170,51 @@ 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) { - ipfr_stats.ifs_nomem++; + KMALLOC(fra, ipfr_t *); + if (fra == NULL) { + ATOMIC_INCL(ipfr_stats.ifs_nomem); return NULL; } + if ((fra->ipfr_rule = fin->fin_fr) != NULL) { + ATOMIC_INC32(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 & 0x1fff) + (fin->fin_dlen >> 3); - ipfr_stats.ifs_new++; - ipfr_inuse++; - return fr; + fra->ipfr_off = (ip->ip_off & IP_OFFMASK) + (fin->fin_dlen >> 3); + ATOMIC_INCL(ipfr_stats.ifs_new); + ATOMIC_INC32(ipfr_inuse); + return fra; } int ipfr_newfrag(ip, fin, pass) ip_t *ip; fr_info_t *fin; -int pass; +u_int pass; { ipfr_t *ipf; - MUTEX_ENTER(&ipf_frag); + if ((ip->ip_v != 4) || (fr_frag_lock)) + return NULL; + WRITE_ENTER(&ipf_frag); ipf = ipfr_new(ip, fin, pass, ipfr_heads); - MUTEX_EXIT(&ipf_frag); + RWLOCK_EXIT(&ipf_frag); return ipf ? 0 : -1; } @@ -180,17 +222,20 @@ 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; - MUTEX_ENTER(&ipf_natfrag); - if ((ipf = ipfr_new(ip, fin, pass, ipfr_nattab))) { + if ((ip->ip_v != 4) || (fr_frag_lock)) + return NULL; + WRITE_ENTER(&ipf_natfrag); + ipf = ipfr_new(ip, fin, pass, ipfr_nattab); + if (ipf != NULL) { ipf->ipfr_data = nat; nat->nat_data = ipf; } - MUTEX_EXIT(&ipf_natfrag); + RWLOCK_EXIT(&ipf_natfrag); return ipf ? 0 : -1; } @@ -245,19 +290,19 @@ 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 & 0x1fff) == 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; } - ipfr_stats.ifs_hits++; + ATOMIC_INCL(ipfr_stats.ifs_hits); return f; } return NULL; @@ -274,20 +319,22 @@ fr_info_t *fin; nat_t *nat; ipfr_t *ipf; - MUTEX_ENTER(&ipf_natfrag); + if ((ip->ip_v != 4) || (fr_frag_lock)) + return NULL; + READ_ENTER(&ipf_natfrag); ipf = ipfr_lookup(ip, fin, ipfr_nattab); - if (ipf) { + if (ipf != NULL) { nat = ipf->ipfr_data; /* * This is the last fragment for this packet. */ - if (ipf->ipfr_ttl == 1) { + if ((ipf->ipfr_ttl == 1) && (nat != NULL)) { nat->nat_data = NULL; ipf->ipfr_data = NULL; } } else nat = NULL; - MUTEX_EXIT(&ipf_natfrag); + RWLOCK_EXIT(&ipf_natfrag); return nat; } @@ -295,18 +342,21 @@ 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; - MUTEX_ENTER(&ipf_frag); - ipf = ipfr_lookup(ip, fin, ipfr_heads); - ret = ipf ? ipf->ipfr_pass : 0; - MUTEX_EXIT(&ipf_frag); - return ret; + if ((ip->ip_v != 4) || (fr_frag_lock)) + return NULL; + READ_ENTER(&ipf_frag); + fra = ipfr_lookup(ip, fin, ipfr_heads); + if (fra != NULL) + fr = fra->ipfr_rule; + RWLOCK_EXIT(&ipf_frag); + return fr; } @@ -319,13 +369,32 @@ void *nat; ipfr_t *fr; int idx; - MUTEX_ENTER(&ipf_natfrag); + WRITE_ENTER(&ipf_natfrag); for (idx = IPFT_SIZE - 1; idx >= 0; idx--) for (fr = ipfr_heads[idx]; fr; fr = fr->ipfr_next) if (fr->ipfr_data == nat) fr->ipfr_data = NULL; - MUTEX_EXIT(&ipf_natfrag); + RWLOCK_EXIT(&ipf_natfrag); +} + + +static void ipfr_delete(fra) +ipfr_t *fra; +{ + frentry_t *fr; + + fr = fra->ipfr_rule; + if (fr != NULL) { + ATOMIC_DEC32(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); } @@ -334,55 +403,52 @@ void *nat; */ void ipfr_unload() { - ipfr_t **fp, *fr; + ipfr_t **fp, *fra; nat_t *nat; int idx; - MUTEX_ENTER(&ipf_frag); + 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); } - MUTEX_EXIT(&ipf_frag); + RWLOCK_EXIT(&ipf_frag); - MUTEX_ENTER(&ipf_nat); - MUTEX_ENTER(&ipf_natfrag); + 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; - if ((nat = (nat_t *)fr->ipfr_data)) { - if (nat->nat_data == fr) + for (fp = &ipfr_nattab[idx]; (fra = *fp); ) { + *fp = fra->ipfr_next; + nat = fra->ipfr_data; + if (nat != NULL) { + if (nat->nat_data == fra) nat->nat_data = NULL; } - KFREE(fr); + ipfr_delete(fra); } - MUTEX_EXIT(&ipf_natfrag); - MUTEX_EXIT(&ipf_nat); + RWLOCK_EXIT(&ipf_natfrag); + RWLOCK_EXIT(&ipf_nat); } #ifdef _KERNEL -/* - * Slowly expire held state for fragments. Timeouts are set * in expectation - * of this being called twice per second. - */ -# if (BSD >= 199306) || SOLARIS || defined(__sgi) -void ipfr_slowtimer() -# else -int ipfr_slowtimer() -# endif +void ipfr_fragexpire() { - ipfr_t **fp, *fr; + ipfr_t **fp, *fra; nat_t *nat; - int s, idx; - -#ifdef __sgi - ipfilter_sgi_intfsync(); + int idx; +#if defined(_KERNEL) +# if !SOLARIS + int s; +# endif #endif + if (fr_frag_lock) + return; + SPL_NET(s); - MUTEX_ENTER(&ipf_frag); + WRITE_ENTER(&ipf_frag); /* * Go through the entire table, looking for entries to expire, @@ -390,23 +456,17 @@ 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; - ipfr_stats.ifs_expire++; - ipfr_inuse--; - KFREE(fr); + for (fp = &ipfr_heads[idx]; (fra = *fp); ) { + --fra->ipfr_ttl; + if (fra->ipfr_ttl == 0) { + *fp = fra->ipfr_next; + ipfr_delete(fra); + ATOMIC_INCL(ipfr_stats.ifs_expire); + ATOMIC_DEC32(ipfr_inuse); } else - fp = &fr->ipfr_next; + fp = &fra->ipfr_next; } - MUTEX_EXIT(&ipf_frag); + RWLOCK_EXIT(&ipf_frag); /* * Same again for the NAT table, except that if the structure also @@ -415,44 +475,76 @@ int ipfr_slowtimer() * NOTE: We need to grab both mutex's early, and in this order so as * to prevent a deadlock if both try to expire at the same time. */ - MUTEX_ENTER(&ipf_nat); - MUTEX_ENTER(&ipf_natfrag); + 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; - ipfr_stats.ifs_expire++; - ipfr_inuse--; - if ((nat = (nat_t *)fr->ipfr_data)) { - if (nat->nat_data == fr) + for (fp = &ipfr_nattab[idx]; (fra = *fp); ) { + --fra->ipfr_ttl; + if (fra->ipfr_ttl == 0) { + ATOMIC_INCL(ipfr_stats.ifs_expire); + ATOMIC_DEC32(ipfr_inuse); + nat = fra->ipfr_data; + if (nat != NULL) { + 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; } - MUTEX_EXIT(&ipf_natfrag); - MUTEX_EXIT(&ipf_nat); + RWLOCK_EXIT(&ipf_natfrag); + RWLOCK_EXIT(&ipf_nat); SPL_X(s); +} + + +/* + * Slowly expire held state for fragments. Timeouts are set * in expectation + * 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 +{ +#if defined(_KERNEL) && SOLARIS + extern int fr_running; + + if (fr_running <= 0) + return; +#endif + + READ_ENTER(&ipf_solaris); +#ifdef __sgi + ipfilter_sgi_intfsync(); +#endif + + ipfr_fragexpire(); fr_timeoutstate(); ip_natexpire(); fr_authexpire(); -# if SOLARIS +# if SOLARIS ipfr_timer_id = timeout(ipfr_slowtimer, NULL, drv_usectohz(500000)); + RWLOCK_EXIT(&ipf_solaris); # else -# ifndef linux - ip_slowtimo(); -# endif -# if (BSD < 199306) && !defined(__sgi) +# if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000) + callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL); +# else +# if (__FreeBSD_version >= 300000) + ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); +# else + timeout(ipfr_slowtimer, NULL, hz/2); +# endif +# if (BSD < 199306) && !defined(__sgi) return 0; -# endif -# endif +# endif /* FreeBSD */ +# endif /* NetBSD */ +# endif /* SOLARIS */ } #endif /* defined(_KERNEL) */ diff --git a/sys/contrib/ipfilter/netinet/ip_frag.h b/sys/contrib/ipfilter/netinet/ip_frag.h index 9122f17..6a3bd2c 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.h +++ b/sys/contrib/ipfilter/netinet/ip_frag.h @@ -1,12 +1,12 @@ /* - * Copyright (C) 1993-1997 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * * @(#)ip_frag.h 1.5 3/24/96 - * $Id: ip_frag.h,v 2.0.2.12.2.1 1998/05/23 14:29:39 darrenr Exp $ + * $Id: ip_frag.h,v 2.4 2000/03/13 22:10:21 darrenr Exp $ */ #ifndef __IP_FRAG_H__ @@ -24,7 +24,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; @@ -42,16 +42,22 @@ typedef struct ipfrstat { #define IPFR_CMPSZ (4 + 4 + 2 + 1 + 1) extern int fr_ipfrttl; +extern int fr_frag_lock; 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)); +extern void ipfr_fragexpire __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 diff --git a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c index 7ff8adb..691e0ad 100644 --- a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c @@ -1,214 +1,433 @@ /* * Simple FTP transparent proxy for in-kernel use. For use with the NAT * code. + * + * $Id: ip_ftp_pxy.c,v 2.7.2.7 2000/05/13 14:28:14 darrenr Exp $ */ +#if SOLARIS && defined(_KERNEL) +extern kmutex_t ipf_rw; +#endif #define isdigit(x) ((x) >= '0' && (x) <= '9') +#define isupper(x) ((unsigned)((x) - 'A') <= 'Z' - 'A') #define IPF_FTP_PROXY #define IPF_MINPORTLEN 18 #define IPF_MAXPORTLEN 30 +#define IPF_MIN227LEN 39 +#define IPF_MAX227LEN 51 +#define IPF_FTPBUFSZ 96 /* This *MUST* be >= 53! */ -int ippr_ftp_init __P((fr_info_t *, ip_t *, tcphdr_t *, - ap_session_t *, nat_t *)); -int ippr_ftp_in __P((fr_info_t *, ip_t *, tcphdr_t *, - ap_session_t *, nat_t *)); -int ippr_ftp_out __P((fr_info_t *, ip_t *, tcphdr_t *, - ap_session_t *, nat_t *)); -u_short ipf_ftp_atoi __P((char **)); - - -int ippr_ftp_init __P((fr_info_t *, ip_t *, tcphdr_t *, ap_session_t *, - nat_t *)); -int ippr_ftp_in __P((fr_info_t *, ip_t *, tcphdr_t *, ap_session_t *, - nat_t *)); -int ippr_ftp_out __P((fr_info_t *, ip_t *, tcphdr_t *, ap_session_t *, - nat_t *)); - -u_short ipf_ftp_atoi __P((char **)); +int ippr_ftp_client __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); +int ippr_ftp_complete __P((char *, size_t)); +int ippr_ftp_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_ftp_init __P((void)); +int ippr_ftp_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_ftp_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); +int ippr_ftp_port __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); +int ippr_ftp_process __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); +int ippr_ftp_server __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); +int ippr_ftp_valid __P((char *, size_t)); +u_short ippr_ftp_atoi __P((char **)); +static frentry_t natfr; +int ippr_ftp_pasvonly = 0; /* - * FTP application proxy initialization. + * Initialize local structures. */ -int ippr_ftp_init(fin, ip, tcp, aps, nat) +int ippr_ftp_init() +{ + bzero((char *)&natfr, sizeof(natfr)); + natfr.fr_ref = 1; + natfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + return 0; +} + + +int ippr_ftp_new(fin, ip, aps, nat) fr_info_t *fin; ip_t *ip; -tcphdr_t *tcp; ap_session_t *aps; nat_t *nat; { - aps->aps_sport = tcp->th_sport; - aps->aps_dport = tcp->th_dport; + ftpinfo_t *ftp; + ftpside_t *f; + + KMALLOC(ftp, ftpinfo_t *); + if (ftp == NULL) + return -1; + aps->aps_data = ftp; + aps->aps_psiz = sizeof(ftpinfo_t); + + bzero((char *)ftp, sizeof(*ftp)); + f = &ftp->ftp_side[0]; + f->ftps_rptr = f->ftps_buf; + f->ftps_wptr = f->ftps_buf; + f = &ftp->ftp_side[1]; + f->ftps_rptr = f->ftps_buf; + f->ftps_wptr = f->ftps_buf; return 0; } -int ippr_ftp_in(fin, ip, tcp, aps, nat) +int ippr_ftp_port(fin, ip, nat, f, dlen) fr_info_t *fin; ip_t *ip; -tcphdr_t *tcp; -ap_session_t *aps; nat_t *nat; +ftpside_t *f; +int dlen; { - u_32_t sum1, sum2; - short sel; - - if (tcp->th_sport == aps->aps_dport) { - sum2 = (u_32_t)ntohl(tcp->th_ack); - sel = aps->aps_sel; - if ((aps->aps_after[!sel] > aps->aps_after[sel]) && - (sum2 > aps->aps_after[!sel])) { - sel = aps->aps_sel = !sel; /* switch to other set */ - } - if (aps->aps_seqoff[sel] && (sum2 > aps->aps_after[sel])) { - sum1 = (u_32_t)aps->aps_seqoff[sel]; - tcp->th_ack = htonl(sum2 - sum1); - return 2; - } + tcphdr_t *tcp, tcph, *tcp2 = &tcph; + char newbuf[IPF_FTPBUFSZ], *s; + u_short a5, a6, sp, dp; + u_int a1, a2, a3, a4; + struct in_addr swip; + size_t nlen, olen; + fr_info_t fi; + int inc, off; + nat_t *ipn; + mb_t *m; +#if SOLARIS + mb_t *m1; +#endif + + tcp = (tcphdr_t *)fin->fin_dp; + off = f->ftps_seq - ntohl(tcp->th_seq); + if (off < 0) + return 0; + /* + * Check for client sending out PORT message. + */ + if (dlen < IPF_MINPORTLEN) + return 0; + /* + * Count the number of bytes in the PORT message is. + */ + if (off < 0) + return 0; + + off += fin->fin_hlen + (tcp->th_off << 2); + /* + * Skip the PORT command + space + */ + s = f->ftps_rptr + 5; + /* + * Pick out the address components, two at a time. + */ + a1 = ippr_ftp_atoi(&s); + if (!s) + return 0; + a2 = ippr_ftp_atoi(&s); + if (!s) + 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. + */ + a1 <<= 16; + a1 |= a2; + if (a1 != ntohl(nat->nat_inip.s_addr)) + return 0; + + a5 = ippr_ftp_atoi(&s); + if (!s) + return 0; + if (*s == ')') + s++; + + /* + * check for CR-LF at the end. + */ + if (*s == '\n') + s--; + if ((*s == '\r') && (*(s + 1) == '\n')) { + s += 2; + a6 = a5 & 0xff; + } else + return 0; + a5 >>= 8; + /* + * Calculate new address parts for PORT command + */ + a1 = ntohl(ip->ip_src.s_addr); + a2 = (a1 >> 16) & 0xff; + a3 = (a1 >> 8) & 0xff; + a4 = a1 & 0xff; + a1 >>= 24; + olen = s - f->ftps_rptr; + /* DO NOT change this to sprintf! */ + (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", + "PORT", a1, a2, a3, a4, a5, a6); + + nlen = strlen(newbuf); + inc = nlen - olen; + if ((inc + ip->ip_len) > 65535) + return 0; + +#if SOLARIS + m = fin->fin_qfm; + for (m1 = m; m1->b_cont; m1 = m1->b_cont) + ; + if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) { + mblk_t *nm; + + /* alloc enough to keep same trailer space for lower driver */ + nm = allocb(nlen, BPRI_MED); + PANIC((!nm),("ippr_ftp_out: allocb failed")); + + nm->b_band = m1->b_band; + nm->b_wptr += nlen; + + m1->b_wptr -= olen; + PANIC((m1->b_wptr < m1->b_rptr), + ("ippr_ftp_out: cannot handle fragmented data block")); + + 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; } - return 0; -} + copyin_mblk(m, off, nlen, newbuf); +#else + m = *((mb_t **)fin->fin_mp); + if (inc < 0) + m_adj(m, inc); + /* the mbuf chain will be extended if necessary by m_copyback() */ + m_copyback(m, off, nlen, newbuf); +#endif + if (inc != 0) { +#if SOLARIS || defined(__sgi) + register u_32_t sum1, sum2; + sum1 = ip->ip_len; + sum2 = ip->ip_len + inc; -/* - * ipf_ftp_atoi - implement a version of atoi which processes numbers in - * pairs separated by commas (which are expected to be in the range 0 - 255), - * returning a 16 bit number combining either side of the , as the MSB and - * LSB. - */ -u_short ipf_ftp_atoi(ptr) -char **ptr; -{ - register char *s = *ptr, c; - register u_char i = 0, j = 0; + /* Because ~1 == -2, We really need ~1 == -1 */ + if (sum1 > sum2) + sum2--; + sum2 -= sum1; + sum2 = (sum2 & 0xffff) + (sum2 >> 16); - while ((c = *s++) && isdigit(c)) { - i *= 10; - i += c - '0'; + fix_outcksum(&ip->ip_sum, sum2, 0); +#endif + ip->ip_len += inc; } - if (c != ',') { - *ptr = NULL; + + /* + * Add skeleton NAT entry for connection which will come back the + * other way. + */ + sp = htons(a5 << 8 | a6); + /* + * Don't allow the PORT command to specify a port < 1024 due to + * security crap. + */ + if (ntohs(sp) < 1024) return 0; + /* + * 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_p, nat->nat_inip, + ip->ip_dst, (dp << 16) | sp); + if (ipn == NULL) { + int slen; + + slen = ip->ip_len; + ip->ip_len = fin->fin_hlen + sizeof(*tcp2); + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + bzero((char *)tcp2, sizeof(*tcp2)); + tcp2->th_win = htons(8192); + tcp2->th_sport = sp; + tcp2->th_off = 5; + 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|FI_W_DPORT, + NAT_OUTBOUND); + if (ipn != NULL) { + ipn->nat_age = fr_defnatage; + (void) fr_addstate(ip, &fi, FI_W_DPORT); + } + ip->ip_len = slen; + ip->ip_src = swip; } - while ((c = *s++) && isdigit(c)) { - j *= 10; - j += c - '0'; - } - *ptr = s; - return (i << 8) | j; + return inc; } -int ippr_ftp_out(fin, ip, tcp, aps, nat) +int ippr_ftp_client(fin, ip, nat, ftp, dlen) fr_info_t *fin; -ip_t *ip; -tcphdr_t *tcp; -ap_session_t *aps; nat_t *nat; +ftpinfo_t *ftp; +ip_t *ip; +int dlen; { - register u_32_t sum1, sum2; - char newbuf[IPF_MAXPORTLEN+1]; - char portbuf[IPF_MAXPORTLEN+1], *s; - int ch = 0, off = (ip->ip_hl << 2) + (tcp->th_off << 2); - u_int a1, a2, a3, a4; - u_short a5, a6; - int olen, dlen, nlen = 0, inc = 0; - tcphdr_t tcph, *tcp2 = &tcph; - void *savep; - nat_t *ipn; - struct in_addr swip; - mb_t *m = *(mb_t **)fin->fin_mp; + char *rptr, *wptr; + ftpside_t *f; + int inc; + + inc = 0; + f = &ftp->ftp_side[0]; + rptr = f->ftps_rptr; + wptr = f->ftps_wptr; + + if ((ftp->ftp_passok == 0) && !strncmp(rptr, "USER ", 5)) + ftp->ftp_passok = 1; + else if ((ftp->ftp_passok == 2) && !strncmp(rptr, "PASS ", 5)) + ftp->ftp_passok = 3; + else if ((ftp->ftp_passok == 4) && !ippr_ftp_pasvonly && + !strncmp(rptr, "PORT ", 5)) { + inc = ippr_ftp_port(fin, ip, nat, f, dlen); + } -#if SOLARIS - mb_t *m1; + while ((*rptr++ != '\n') && (rptr < wptr)) + ; + f->ftps_seq += rptr - f->ftps_rptr; + f->ftps_rptr = rptr; + return inc; +} - /* skip any leading M_PROTOs */ - while(m && (MTYPE(m) != M_DATA)) - m = m->b_cont; - PANIC((!m),("ippr_ftp_out: no M_DATA")); - dlen = msgdsize(m) - off; - bzero(portbuf, sizeof(portbuf)); - 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); -#endif - portbuf[IPF_MAXPORTLEN] = '\0'; +int ippr_ftp_pasv(fin, ip, nat, f, dlen) +fr_info_t *fin; +ip_t *ip; +nat_t *nat; +ftpside_t *f; +int dlen; +{ + tcphdr_t *tcp, tcph, *tcp2 = &tcph; + struct in_addr swip, swip2; + u_short a5, a6, sp, dp; + u_int a1, a2, a3, a4; + fr_info_t fi; + int inc, off; + nat_t *ipn; + char *s; - if ((dlen < IPF_MINPORTLEN) || strncmp(portbuf, "PORT ", 5)) - goto adjust_seqack; + /* + * Check for PASV reply message. + */ + if (dlen < IPF_MIN227LEN) + return 0; + else if (strncmp(f->ftps_rptr, "227 Entering Passive Mode", 25)) + return 0; + + /* + * Count the number of bytes in the 227 reply is. + */ + tcp = (tcphdr_t *)fin->fin_dp; + off = f->ftps_seq - ntohl(tcp->th_seq); + if (off < 0) + return 0; + off += fin->fin_hlen + (tcp->th_off << 2); /* * Skip the PORT command + space */ - s = portbuf + 5; + s = f->ftps_rptr + 25; + while (*s && !isdigit(*s)) + s++; /* * Pick out the address components, two at a time. */ - (void) ipf_ftp_atoi(&s); + a1 = ippr_ftp_atoi(&s); if (!s) - goto adjust_seqack; - (void) ipf_ftp_atoi(&s); + return 0; + a2 = ippr_ftp_atoi(&s); if (!s) - goto adjust_seqack; - a5 = ipf_ftp_atoi(&s); + 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. + */ + a1 <<= 16; + a1 |= a2; + if (a1 != ntohl(nat->nat_oip.s_addr)) + return 0; + + a5 = ippr_ftp_atoi(&s); if (!s) - goto adjust_seqack; + return 0; + + if (*s == ')') + s++; + if (*s == '\n') + s--; /* * check for CR-LF at the end. */ - if (*s != '\n' || *(s - 1) != '\r') - goto adjust_seqack; - a6 = a5 & 0xff; + if ((*s == '\r') && (*(s + 1) == '\n')) { + s += 2; + a6 = a5 & 0xff; + } else + return 0; a5 >>= 8; /* - * Calculate new address parts for PORT command + * 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, "PORT %d,%d,%d,%d,%d,%d\r\n", - a1, a2, a3, a4, a5, a6); + inc = 0; +#if 0 + olen = s - f->ftps_rptr; + (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); inc = nlen - olen; + if ((inc + ip->ip_len) > 65535) + return 0; + #if SOLARIS + m = fin->fin_qfm; for (m1 = m; m1->b_cont; m1 = m1->b_cont) ; - if (inc > 0) { + if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) { mblk_t *nm; /* alloc enough to keep same trailer space for lower driver */ - nm = allocb(nlen + m1->b_datap->db_lim - m1->b_wptr, BPRI_MED); + nm = allocb(nlen, BPRI_MED); PANIC((!nm),("ippr_ftp_out: allocb failed")); nm->b_band = m1->b_band; nm->b_wptr += nlen; m1->b_wptr -= olen; - PANIC((m1->b_wptr < m1->b_rptr),("ippr_ftp_out: cannot handle fragmented data block")); + PANIC((m1->b_wptr < m1->b_rptr), + ("ippr_ftp_out: cannot handle fragmented data block")); linkb(m1, nm); } else { m1->b_wptr += inc; } - copyin_mblk(m, off, nlen, newbuf); + /*copyin_mblk(m, off, nlen, newbuf);*/ #else + m = *((mb_t **)fin->fin_mp); if (inc < 0) m_adj(m, inc); /* the mbuf chain will be extended if necessary by m_copyback() */ - m_copyback(m, off, nlen, newbuf); + /*m_copyback(m, off, nlen, newbuf);*/ #endif - if (inc) { + if (inc != 0) { #if SOLARIS || defined(__sgi) + register u_32_t sum1, sum2; + sum1 = ip->ip_len; sum2 = ip->ip_len + inc; @@ -218,52 +437,320 @@ 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; } - ch = 1; +#endif /* * Add skeleton NAT entry for connection which will come back the * other way. */ - savep = fin->fin_dp; - fin->fin_dp = (char *)tcp2; - bzero((char *)tcp2, sizeof(*tcp2)); - tcp2->th_sport = htons(a5 << 8 | a6); - tcp2->th_dport = htons(20); - swip = ip->ip_src; - ip->ip_src = nat->nat_inip; - if ((ipn = nat_new(nat->nat_ptr, ip, fin, IPN_TCP, NAT_OUTBOUND))) - ipn->nat_age = fr_defnatage; - (void) fr_addstate(ip, fin, FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE); - ip->ip_src = swip; - fin->fin_dp = (char *)savep; - -adjust_seqack: - if (tcp->th_dport == aps->aps_dport) { - sum2 = (u_32_t)ntohl(tcp->th_seq); - off = aps->aps_sel; - if ((aps->aps_after[!off] > aps->aps_after[off]) && - (sum2 > aps->aps_after[!off])) { - off = aps->aps_sel = !off; /* switch to other set */ + 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) { + int slen; + + slen = ip->ip_len; + ip->ip_len = fin->fin_hlen + sizeof(*tcp2); + 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 */ + tcp2->th_off = 5; + 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_len = slen; + ip->ip_src = swip; + ip->ip_dst = swip2; + } + return inc; +} + + +int ippr_ftp_server(fin, ip, nat, ftp, dlen) +fr_info_t *fin; +ip_t *ip; +nat_t *nat; +ftpinfo_t *ftp; +int dlen; +{ + char *rptr, *wptr; + ftpside_t *f; + int inc; + + inc = 0; + f = &ftp->ftp_side[1]; + rptr = f->ftps_rptr; + wptr = f->ftps_wptr; + + if ((ftp->ftp_passok == 1) && !strncmp(rptr, "331", 3)) + ftp->ftp_passok = 2; + else if ((ftp->ftp_passok == 3) && !strncmp(rptr, "230", 3)) + ftp->ftp_passok = 4; + else if ((ftp->ftp_passok == 3) && !strncmp(rptr, "530", 3)) + ftp->ftp_passok = 0; + else if ((ftp->ftp_passok == 4) && !strncmp(rptr, "227 ", 4)) { + inc = ippr_ftp_pasv(fin, ip, nat, f, dlen); + } + while ((*rptr++ != '\n') && (rptr < wptr)) + ; + f->ftps_seq += rptr - f->ftps_rptr; + f->ftps_rptr = rptr; + return inc; +} + + +/* + * Look to see if the buffer starts with something which we recognise as + * being the correct syntax for the FTP protocol. + */ +int ippr_ftp_valid(buf, len) +char *buf; +size_t len; +{ + register char *s, c; + register size_t i = len; + + if (i < 5) + return 2; + s = buf; + c = *s++; + i--; + + if (isdigit(c)) { + c = *s++; + i--; + if (isdigit(c)) { + c = *s++; + i--; + if (isdigit(c)) { + c = *s++; + i--; + if ((c != '-') && (c != ' ')) + return 1; + } else + return 1; + } else + return 1; + } else if (isupper(c)) { + c = *s++; + i--; + if (isupper(c)) { + c = *s++; + i--; + if (isupper(c)) { + c = *s++; + i--; + if (isupper(c)) { + c = *s++; + i--; + if ((c != ' ') && (c != '\r')) + return 1; + } else if ((c != ' ') && (c != '\r')) + return 1; + } else + return 1; + } else + return 1; + } else + return 1; + for (; i; i--) { + c = *s++; + if (c == '\n') + return 0; + } + return 2; +} + + +int ippr_ftp_process(fin, ip, nat, ftp, rv) +fr_info_t *fin; +ip_t *ip; +nat_t *nat; +ftpinfo_t *ftp; +int rv; +{ + int mlen, len, off, inc, i; + char *rptr, *wptr; + tcphdr_t *tcp; + ftpside_t *f; + mb_t *m; + + tcp = (tcphdr_t *)fin->fin_dp; + off = fin->fin_hlen + (tcp->th_off << 2); + +#if SOLARIS + m = fin->fin_qfm; +#else + m = *((mb_t **)fin->fin_mp); +#endif + +#if SOLARIS + mlen = msgdsize(m) - off; +#else + mlen = mbufchainlen(m) - off; +#endif + if (!mlen) + return 0; + + inc = 0; + f = &ftp->ftp_side[rv]; + rptr = f->ftps_rptr; + wptr = f->ftps_wptr; + if ((wptr == f->ftps_buf) && (f->ftps_seq <= ntohl(tcp->th_seq))) + f->ftps_seq = ntohl(tcp->th_seq); + + /* + * XXX - Ideally, this packet should get dropped because we now know + * that it is out of order (and there is no real danger in doing so + * apart from causing packets to go through here ordered). + */ + if (ntohl(tcp->th_seq) != f->ftps_seq + (wptr - rptr)) { + return APR_ERR(0); + } + + while (mlen > 0) { + len = MIN(mlen, FTP_BUFSZ / 2); + +#if SOLARIS + copyout_mblk(m, off, len, wptr); +#else + m_copydata(m, off, len, wptr); +#endif + mlen -= len; + off += len; + wptr += len; + f->ftps_wptr = wptr; + if (f->ftps_junk == 2) + f->ftps_junk = ippr_ftp_valid(rptr, wptr - rptr); + + while ((f->ftps_junk == 0) && (wptr > rptr)) { + f->ftps_junk = ippr_ftp_valid(rptr, wptr - rptr); + if (f->ftps_junk == 0) { + len = wptr - rptr; + f->ftps_rptr = rptr; + if (rv) + inc += ippr_ftp_server(fin, ip, nat, + ftp, len); + else + inc += ippr_ftp_client(fin, ip, nat, + ftp, len); + rptr = f->ftps_rptr; + } } - if (aps->aps_seqoff[off]) { - sum1 = (u_32_t)aps->aps_after[off] - - aps->aps_seqoff[off]; - if (sum2 > sum1) { - sum1 = (u_32_t)aps->aps_seqoff[off]; - sum2 += sum1; - tcp->th_seq = htonl(sum2); - ch = 1; + + while ((f->ftps_junk == 1) && (rptr < wptr)) { + while ((rptr < wptr) && (*rptr != '\r')) + rptr++; + + if ((*rptr == '\r') && (rptr + 1 < wptr)) { + if (*(rptr + 1) == '\n') { + rptr += 2; + f->ftps_junk = 0; + } else + rptr++; } + f->ftps_seq += rptr - f->ftps_rptr; + f->ftps_rptr = rptr; } - if (inc && (sum2 > aps->aps_after[!off])) { - aps->aps_after[!off] = sum2 + nlen - 1; - aps->aps_seqoff[!off] = aps->aps_seqoff[off] + inc; + if (rptr == wptr) { + rptr = wptr = f->ftps_buf; + } else { + if ((wptr > f->ftps_buf + FTP_BUFSZ / 2)) { + i = wptr - rptr; + if ((rptr == f->ftps_buf) || + (wptr - rptr > FTP_BUFSZ / 2)) { + f->ftps_seq += i; + f->ftps_junk = 1; + rptr = wptr = f->ftps_buf; + } else { + bcopy(rptr, f->ftps_buf, i); + wptr = f->ftps_buf + i; + rptr = f->ftps_buf; + } + } + f->ftps_rptr = rptr; + f->ftps_wptr = wptr; } } - return ch ? 2 : 0; + + f->ftps_rptr = rptr; + f->ftps_wptr = wptr; + return inc; +} + + +int ippr_ftp_out(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + ftpinfo_t *ftp; + + ftp = aps->aps_data; + if (ftp == NULL) + return 0; + return ippr_ftp_process(fin, ip, nat, ftp, 0); +} + + +int ippr_ftp_in(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + ftpinfo_t *ftp; + + ftp = aps->aps_data; + if (ftp == NULL) + return 0; + return ippr_ftp_process(fin, ip, nat, ftp, 1); +} + + +/* + * ippr_ftp_atoi - implement a version of atoi which processes numbers in + * pairs separated by commas (which are expected to be in the range 0 - 255), + * returning a 16 bit number combining either side of the , as the MSB and + * LSB. + */ +u_short ippr_ftp_atoi(ptr) +char **ptr; +{ + register char *s = *ptr, c; + register u_char i = 0, j = 0; + + while ((c = *s++) && isdigit(c)) { + i *= 10; + i += c - '0'; + } + if (c != ',') { + *ptr = NULL; + return 0; + } + while ((c = *s++) && isdigit(c)) { + j *= 10; + j += c - '0'; + } + *ptr = s; + return (i << 8) | j; } diff --git a/sys/contrib/ipfilter/netinet/ip_log.c b/sys/contrib/ipfilter/netinet/ip_log.c index 81e89e5..ef1af7f 100644 --- a/sys/contrib/ipfilter/netinet/ip_log.c +++ b/sys/contrib/ipfilter/netinet/ip_log.c @@ -1,27 +1,32 @@ /* - * Copyright (C) 1997 by Darren Reed. + * Copyright (C) 1997-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: ip_log.c,v 2.0.2.13.2.3 1997/11/20 12:41:40 darrenr Exp $ + * $Id: ip_log.c,v 2.5 2000/03/13 22:10:21 darrenr Exp $ */ +#include +#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) +# if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) +# include "opt_ipfilter.h" +# endif +# else +# include +# 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 -# else -# include -# endif -# endif # ifndef _KERNEL # include # include @@ -30,7 +35,6 @@ # endif # include # include -# include # include # if __FreeBSD_version >= 220000 && defined(_KERNEL) # include @@ -44,7 +48,7 @@ # endif # include # if !SOLARIS -# if (NetBSD > 199609) || (OpenBSD > 199603) +# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) # include # else # include @@ -105,6 +109,10 @@ # include "netinet/ip_frag.h" # include "netinet/ip_state.h" # include "netinet/ip_auth.h" +# if (__FreeBSD_version >= 300000) +# include +# endif + # ifndef MIN # define MIN(a,b) (((a)<(b))?(a):(b)) # endif @@ -117,13 +125,12 @@ extern kcondvar_t iplwait; # endif # endif -iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1]; -int iplused[IPL_LOGMAX+1]; -u_long iplcrc[IPL_LOGMAX+1]; -u_long iplcrcinit; -#ifdef linux +iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1], *ipll[IPL_LOGMAX+1]; +size_t iplused[IPL_LOGMAX+1]; +static fr_info_t iplcrc[IPL_LOGMAX+1]; +# ifdef linux static struct wait_queue *iplwait[IPL_LOGMAX+1]; -#endif +# endif /* @@ -132,20 +139,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; } @@ -164,11 +166,11 @@ 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]; + u_char p; # if SOLARIS ill_t *ifp = fin->fin_ifp; # else @@ -179,29 +181,37 @@ mb_t *m; * calculate header size. */ hlen = fin->fin_hlen; - if (ip->ip_p == IPPROTO_TCP) - hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen); - else if (ip->ip_p == IPPROTO_UDP) - hlen += MIN(sizeof(udphdr_t), fin->fin_dlen); - else if (ip->ip_p == IPPROTO_ICMP) { - struct icmp *icmp = (struct icmp *)((char *)ip + hlen); - - /* - * For ICMP, if the packet is an error packet, also include - * the information about the packet which caused the error. - */ - switch (icmp->icmp_type) - { - case ICMP_UNREACH : - case ICMP_SOURCEQUENCH : - case ICMP_REDIRECT : - case ICMP_TIMXCEED : - case ICMP_PARAMPROB : - hlen += MIN(sizeof(struct icmp) + 8, fin->fin_dlen); - break; - default : - hlen += MIN(sizeof(struct icmp), fin->fin_dlen); - break; + if (fin->fin_off == 0) { + p = fin->fin_fi.fi_p; + if (p == IPPROTO_TCP) + hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen); + else if (p == IPPROTO_UDP) + hlen += MIN(sizeof(udphdr_t), fin->fin_dlen); + else if (p == IPPROTO_ICMP) { + struct icmp *icmp; + + icmp = (struct icmp *)fin->fin_dp; + + /* + * For ICMP, if the packet is an error packet, also + * include the information about the packet which + * caused the error. + */ + switch (icmp->icmp_type) + { + case ICMP_UNREACH : + case ICMP_SOURCEQUENCH : + case ICMP_REDIRECT : + case ICMP_TIMXCEED : + case ICMP_PARAMPROB : + hlen += MIN(sizeof(struct icmp) + 8, + fin->fin_dlen); + break; + default : + hlen += MIN(sizeof(struct icmp), + fin->fin_dlen); + break; + } } } /* @@ -225,17 +235,21 @@ mb_t *m; if ((ipfl.fl_ifname[2] = ifp->if_name[2])) ipfl.fl_ifname[3] = ifp->if_name[3]; # endif - mlen = (flags & FR_LOGBODY) ? MIN(ip->ip_len - hlen, 128) : 0; + mlen = (flags & FR_LOGBODY) ? MIN(fin->fin_plen - hlen, 128) : 0; # endif ipfl.fl_plen = (u_char)mlen; ipfl.fl_hlen = (u_char)hlen; ipfl.fl_rule = fin->fin_rule; ipfl.fl_group = fin->fin_group; + 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 ? */ @@ -248,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. @@ -298,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); @@ -344,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 @@ -362,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 @@ -375,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; @@ -419,55 +437,63 @@ 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; + MUTEX_ENTER(&ipl_mutex); while ((ipl = iplt[unit])) { iplt[unit] = ipl->ipl_next; 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; } #endif /* IPFILTER_LOG */ diff --git a/sys/contrib/ipfilter/netinet/ip_nat.c b/sys/contrib/ipfilter/netinet/ip_nat.c index 102d57f..64f50b6 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.c +++ b/sys/contrib/ipfilter/netinet/ip_nat.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1995-1997 by Darren Reed. + * Copyright (C) 1995-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -9,24 +9,28 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.0.2.44.2.10 1998/05/23 19:05:29 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.10 2000/05/19 15:54:44 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) #define _KERNEL #endif -#if !defined(_KERNEL) && !defined(KERNEL) -# include -# include -# include -#endif #include #include #include #include #include -#if defined(KERNEL) && (__FreeBSD_version >= 220000) +#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ + defined(_KERNEL) +# include "opt_ipfilter_log.h" +#endif +#if !defined(_KERNEL) && !defined(KERNEL) +# include +# include +# include +#endif +#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) # include # include #else @@ -48,7 +52,9 @@ static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.0.2.44.2.10 1998/05/23 19:05: #else # include # include -# include +# ifdef _KERNEL +# include +# endif # include # include #endif @@ -58,9 +64,12 @@ static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.0.2.44.2.10 1998/05/23 19:05: #include #if __FreeBSD_version >= 300000 # include +# if defined(_KERNEL) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" +# endif #endif #ifdef sun -#include +# include #endif #include #include @@ -75,8 +84,8 @@ static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.0.2.44.2.10 1998/05/23 19:05: #endif #ifdef RFC1825 -#include -#include +# include +# include extern struct ifnet vpnif; #endif @@ -93,50 +102,220 @@ extern struct ifnet vpnif; #include "netinet/ip_nat.h" #include "netinet/ip_frag.h" #include "netinet/ip_state.h" +#if (__FreeBSD_version >= 300000) +# include +#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 */ -natstat_t nat_stats; +u_int ipf_nattable_sz = NAT_TABLE_SZ; +u_int ipf_natrules_sz = NAT_SIZE; +u_int ipf_rdrrules_sz = RDR_SIZE; +u_int ipf_hostmap_sz = HOSTMAP_SIZE; +u_32_t nat_masks = 0; +u_32_t rdr_masks = 0; +ipnat_t **nat_rules = NULL; +ipnat_t **rdr_rules = NULL; +hostmap_t **maptable = NULL; + +u_long fr_defnatage = DEF_NAT_AGE, + fr_defnaticmpage = 6; /* 3 seconds */ +static natstat_t nat_stats; +int fr_nat_lock = 0; #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern kmutex_t ipf_nat; +extern kmutex_t ipf_rw, ipf_hostmap; +extern KRWLOCK_T ipf_nat; #endif static int nat_flushtable __P((void)); static int nat_clearlist __P((void)); +static void nat_addnat __P((struct ipnat *)); +static void nat_addrdr __P((struct ipnat *)); 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 *)); +static int fr_natgetent __P((caddr_t)); +static int fr_natgetsz __P((caddr_t)); +static int fr_natputent __P((caddr_t)); +static int nat_match __P((fr_info_t *, ipnat_t *, ip_t *)); +static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr, + struct in_addr)); +static void nat_hostmapdel __P((struct hostmap *)); + + +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; + + 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; + + 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; + + KMALLOCS(maptable, hostmap_t **, sizeof(hostmap_t *) * ipf_hostmap_sz); + if (maptable != NULL) + bzero((char *)maptable, sizeof(hostmap_t *) * ipf_hostmap_sz); + else + return -1; + return 0; +} -#define LONG_SUM(in) (((in) & 0xffff) + ((in) >> 16)) +static void nat_addrdr(n) +ipnat_t *n; +{ + ipnat_t **np; + u_32_t j; + u_int hv; + int k; + + 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, 0, ipf_rdrrules_sz); + np = rdr_rules + hv; + while (*np != NULL) + np = &(*np)->in_rnext; + n->in_rnext = NULL; + n->in_prnext = np; + *np = n; +} + + +static void nat_addnat(n) +ipnat_t *n; +{ + ipnat_t **np; + u_32_t j; + u_int hv; + int k; + + 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, 0, ipf_natrules_sz); + np = nat_rules + hv; + while (*np != NULL) + np = &(*np)->in_mnext; + n->in_mnext = NULL; + n->in_pmnext = np; + *np = n; +} + + +static void nat_delrdr(n) +ipnat_t *n; +{ + if (n->in_rnext) + n->in_rnext->in_prnext = n->in_prnext; + *n->in_prnext = n->in_rnext; +} + + +static void nat_delnat(n) +ipnat_t *n; +{ + if (n->in_mnext) + n->in_mnext->in_pmnext = n->in_pmnext; + *n->in_pmnext = n->in_mnext; +} -#define CALC_SUMD(s1, s2, sd) { \ - /* Do it twice */ \ - (s1) = ((s1) & 0xffff) + ((s1) >> 16); \ - (s1) = ((s1) & 0xffff) + ((s1) >> 16); \ - /* Do it twice */ \ - (s2) = ((s2) & 0xffff) + ((s2) >> 16); \ - (s2) = ((s2) & 0xffff) + ((s2) >> 16); \ - /* Because ~1 == -2, We really need ~1 == -1 */ \ - if ((s1) > (s2)) (s2)--; \ - (sd) = (s2) - (s1); \ - (sd) = ((sd) & 0xffff) + ((sd) >> 16); } -void fix_outcksum(sp, n) +/* + * check if an ip address has already been allocated for a given mapping that + * is not doing port based translation. + */ +static struct hostmap *nat_hostmap(np, real, map) +ipnat_t *np; +struct in_addr real; +struct in_addr map; +{ + hostmap_t *hm; + u_int hv; + + MUTEX_ENTER(&ipf_hostmap); + hv = real.s_addr % HOSTMAP_SIZE; + for (hm = maptable[hv]; hm; hm = hm->hm_next) + if ((hm->hm_realip.s_addr == real.s_addr) && + (np == hm->hm_ipnat)) { + hm->hm_ref++; + MUTEX_EXIT(&ipf_hostmap); + return hm; + } + + KMALLOC(hm, hostmap_t *); + if (hm) { + hm->hm_next = maptable[hv]; + hm->hm_pnext = maptable + hv; + if (maptable[hv]) + maptable[hv]->hm_pnext = &hm->hm_next; + maptable[hv] = hm; + hm->hm_ipnat = np; + hm->hm_realip = real; + hm->hm_mapip = map; + hm->hm_ref = 1; + } + MUTEX_EXIT(&ipf_hostmap); + return hm; +} + + +static void nat_hostmapdel(hm) +struct hostmap *hm; +{ + MUTEX_ENTER(&ipf_hostmap); + ATOMIC_DEC32(hm->hm_ref); + if (hm->hm_ref == 0) { + if (hm->hm_next) + hm->hm_next->hm_pnext = hm->hm_pnext; + *hm->hm_pnext = hm->hm_next; + KFREE(hm); + } + MUTEX_EXIT(&ipf_hostmap); +} + + +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); @@ -147,15 +326,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 #ifdef sparc sum1 = (~(*sp)) & 0xffff; #else @@ -195,7 +381,7 @@ u_32_t n; * Handle ioctls which manipulate the NAT. */ int nat_ioctl(data, cmd, mode) -#if defined(__NetBSD__) || defined(__OpenBSD__) +#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) u_long cmd; #else int cmd; @@ -203,25 +389,39 @@ int cmd; caddr_t data; int mode; { - register ipnat_t *nat, *n = NULL, **np = NULL; + register ipnat_t *nat, *nt, *n = NULL, **np = NULL; + int error = 0, ret, arg; ipnat_t natd; - int error = 0, ret; -#if defined(_KERNEL) && !SOLARIS - int s; + u_32_t i, j; + +#if (BSD >= 199306) && defined(_KERNEL) + if ((securelevel >= 2) && (mode & FWRITE)) + return EPERM; #endif nat = NULL; /* XXX gcc -Wuninitialized */ + KMALLOC(nt, ipnat_t *); + if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) + error = IRCOPYPTR(data, (char *)&natd, sizeof(natd)); + else if (cmd == SIOCIPFFL) /* SIOCFLNAT & SIOCCNATL */ + error = IRCOPY(data, (char *)&arg, sizeof(arg)); + + if (error) + goto done; /* * For add/delete, look to see if the NAT entry is already present */ - SPL_NET(s); - MUTEX_ENTER(&ipf_nat); + WRITE_ENTER(&ipf_nat); if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) { - IRCOPY(data, (char *)&natd, sizeof(natd)); nat = &natd; - nat->in_inip &= nat->in_inmsk; - nat->in_outip &= nat->in_outmsk; + nat->in_flags &= IPN_USERFLAGS; + if ((nat->in_redir & NAT_MAPBLK) == 0) { + if ((nat->in_flags & IPN_SPLIT) == 0) + nat->in_inip &= nat->in_inmsk; + if ((nat->in_flags & IPN_IPRANGE) == 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)) @@ -230,6 +430,20 @@ int mode; switch (cmd) { +#ifdef IPFILTER_LOG + case SIOCIPFFB : + { + int tmp; + + if (!(mode & FWRITE)) + error = EPERM; + else { + tmp = ipflog_clear(IPL_LOGNAT); + IWCOPY((char *)&tmp, (char *)data, sizeof(tmp)); + } + break; + } +#endif case SIOCADNAT : if (!(mode & FWRITE)) { error = EPERM; @@ -239,25 +453,64 @@ int mode; error = EEXIST; break; } - KMALLOC(n, ipnat_t *, sizeof(*n)); - 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); + n->in_ifp = (void *)GETUNIT(n->in_ifname, 4); if (!n->in_ifp) n->in_ifp = (void *)-1; - n->in_apr = ap_match(n->in_p, n->in_plabel); - n->in_next = *np; + if (n->in_plabel[0] != '\0') { + n->in_apr = appr_match(n->in_p, n->in_plabel); + if (!n->in_apr) { + error = ENOENT; + break; + } + } + n->in_next = NULL; + *np = n; + + if (n->in_redir & NAT_REDIRECT) + nat_addrdr(n); + if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) + nat_addnat(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_IPRANGE) + n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip); + else if (n->in_flags & IPN_SPLIT) + n->in_space = 2; 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_IPRANGE) != 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_IPRANGE|IPN_SPLIT)) == 0)) n->in_nip = ntohl(n->in_outip) + 1; + else if ((n->in_flags & IPN_SPLIT) && + (n->in_redir & NAT_REDIRECT)) + n->in_nip = ntohl(n->in_inip); else n->in_nip = ntohl(n->in_outip); if (n->in_redir & NAT_MAP) { @@ -265,78 +518,432 @@ 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; case SIOCRMNAT : if (!(mode & FWRITE)) { error = EPERM; + n = NULL; break; } if (!n) { 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 { n->in_flags |= IPN_DELETE; n->in_next = NULL; } + n = NULL; break; case SIOCGNATS : + MUTEX_DOWNGRADE(&ipf_nat); nat_stats.ns_table[0] = nat_table[0]; nat_stats.ns_table[1] = nat_table[1]; nat_stats.ns_list = nat_list; - IWCOPY((char *)&nat_stats, (char *)data, sizeof(nat_stats)); + 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; + error = IWCOPYPTR((char *)&nat_stats, (char *)data, + sizeof(nat_stats)); break; case SIOCGNATL : { natlookup_t nl; - IRCOPY((char *)data, (char *)&nl, sizeof(nl)); + MUTEX_DOWNGRADE(&ipf_nat); + error = IRCOPYPTR((char *)data, (char *)&nl, sizeof(nl)); + if (error) + break; if (nat_lookupredir(&nl)) { - IWCOPY((char *)&nl, (char *)data, sizeof(nl)); + error = IWCOPYPTR((char *)&nl, (char *)data, + sizeof(nl)); } else error = ESRCH; break; } - case SIOCFLNAT : + case SIOCIPFFL : /* old SIOCFLNAT & SIOCCNATL */ if (!(mode & FWRITE)) { error = EPERM; break; } - ret = nat_flushtable(); - (void) ap_unload(); - IWCOPY((caddr_t)&ret, data, sizeof(ret)); + error = 0; + if (arg == 0) + ret = nat_flushtable(); + else if (arg == 1) + ret = nat_clearlist(); + else + error = EINVAL; + MUTEX_DOWNGRADE(&ipf_nat); + if (!error) { + error = IWCOPY((caddr_t)&ret, data, sizeof(ret)); + if (error) + error = EFAULT; + } break; - case SIOCCNATL : - if (!(mode & FWRITE)) { - error = EPERM; - break; + case SIOCSTLCK : + error = IRCOPY(data, (caddr_t)&arg, sizeof(arg)); + if (!error) { + error = IWCOPY((caddr_t)&fr_nat_lock, data, + sizeof(fr_nat_lock)); + if (!error) + fr_nat_lock = arg; } - ret = nat_clearlist(); - IWCOPY((caddr_t)&ret, data, sizeof(ret)); + break; + case SIOCSTPUT : + if (fr_nat_lock) + error = fr_natputent(data); + else + error = EACCES; + break; + case SIOCSTGSZ : + if (fr_nat_lock) + error = fr_natgetsz(data); + else + error = EACCES; + break; + case SIOCSTGET : + if (fr_nat_lock) + error = fr_natgetent(data); + else + error = EACCES; break; case FIONREAD : #ifdef IPFILTER_LOG - IWCOPY((caddr_t)&iplused[IPL_LOGNAT], (caddr_t)data, - sizeof(iplused[IPL_LOGNAT])); + MUTEX_DOWNGRADE(&ipf_nat); + error = IWCOPY((caddr_t)&iplused[IPL_LOGNAT], (caddr_t)data, + sizeof(iplused[IPL_LOGNAT])); #endif break; + default : + error = EINVAL; + break; } - MUTEX_EXIT(&ipf_nat); - SPL_X(s); + RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ +done: + if (nt) + KFREE(nt); + return error; +} + + +static int fr_natgetsz(data) +caddr_t data; +{ + ap_session_t *aps; + nat_t *nat, *n; + int error = 0; + natget_t ng; + + error = IRCOPY(data, (caddr_t)&ng, sizeof(ng)); + if (error) + return EFAULT; + + nat = ng.ng_ptr; + if (!nat) { + nat = nat_instances; + ng.ng_sz = 0; + if (nat == NULL) { + error = IWCOPY((caddr_t)&ng, data, sizeof(ng)); + if (error) + error = EFAULT; + return error; + } + } else { + /* + * Make sure the pointer we're copying from exists in the + * current list of entries. Security precaution to prevent + * copying of random kernel data. + */ + for (n = nat_instances; n; n = n->nat_next) + if (n == nat) + break; + if (!n) + return ESRCH; + } + + ng.ng_sz = sizeof(nat_save_t); + aps = nat->nat_aps; + if ((aps != NULL) && (aps->aps_data != 0)) { + ng.ng_sz += sizeof(ap_session_t); + ng.ng_sz += aps->aps_psiz; + } + + error = IWCOPY((caddr_t)&ng, data, sizeof(ng)); + if (error) + error = EFAULT; + return error; +} + + +static int fr_natgetent(data) +caddr_t data; +{ + nat_save_t ipn, *ipnp, *ipnn; + register nat_t *n, *nat; + ap_session_t *aps; + int error; + + error = IRCOPY(data, (caddr_t)&ipnp, sizeof(ipnp)); + if (error) + return EFAULT; + error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn)); + if (error) + return EFAULT; + + nat = ipn.ipn_next; + if (!nat) { + nat = nat_instances; + if (nat == NULL) { + if (nat_instances == NULL) + return ENOENT; + return 0; + } + } else { + /* + * Make sure the pointer we're copying from exists in the + * current list of entries. Security precaution to prevent + * copying of random kernel data. + */ + for (n = nat_instances; n; n = n->nat_next) + if (n == nat) + break; + if (!n) + return ESRCH; + } + + ipn.ipn_next = nat->nat_next; + ipn.ipn_dsize = 0; + bcopy((char *)nat, (char *)&ipn.ipn_nat, sizeof(ipn.ipn_nat)); + ipn.ipn_nat.nat_data = NULL; + + if (nat->nat_ptr) { + bcopy((char *)nat->nat_ptr, (char *)&ipn.ipn_ipnat, + sizeof(ipn.ipn_ipnat)); + } + + if (nat->nat_fr) + bcopy((char *)nat->nat_fr, (char *)&ipn.ipn_rule, + sizeof(ipn.ipn_rule)); + + if ((aps = nat->nat_aps)) { + ipn.ipn_dsize = sizeof(*aps); + if (aps->aps_data) + ipn.ipn_dsize += aps->aps_psiz; + KMALLOCS(ipnn, nat_save_t *, sizeof(*ipnn) + ipn.ipn_dsize); + if (ipnn == NULL) + return NULL; + bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn)); + + bcopy((char *)aps, ipn.ipn_data, sizeof(*aps)); + if (aps->aps_data) { + bcopy(aps->aps_data, ipn.ipn_data + sizeof(*aps), + aps->aps_psiz); + ipn.ipn_dsize += aps->aps_psiz; + } + error = IWCOPY((caddr_t)ipnn, ipnp, + sizeof(ipn) + ipn.ipn_dsize); + if (error) + return EFAULT; + KFREES(ipnn, sizeof(*ipnn) + ipn.ipn_dsize); + } else { + error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn)); + if (error) + return EFAULT; + } + return 0; +} + + +static int fr_natputent(data) +caddr_t data; +{ + nat_save_t ipn, *ipnp, *ipnn; + register nat_t *n, *nat; + ap_session_t *aps; + frentry_t *fr; + ipnat_t *in; + + int error; + + error = IRCOPY(data, (caddr_t)&ipnp, sizeof(ipnp)); + if (error) + return EFAULT; + error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn)); + if (error) + return EFAULT; + if (ipn.ipn_dsize) { + KMALLOCS(ipnn, nat_save_t *, sizeof(ipn) + ipn.ipn_dsize); + if (ipnn == NULL) + return ENOMEM; + bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn)); + error = IRCOPY((caddr_t)ipnp, (caddr_t)ipn.ipn_data, + ipn.ipn_dsize); + if (error) + return EFAULT; + } else + ipnn = NULL; + + KMALLOC(nat, nat_t *); + if (nat == NULL) + return ENOMEM; + + bcopy((char *)&ipn.ipn_nat, (char *)nat, sizeof(*nat)); + /* + * Initialize all these so that nat_delete() doesn't cause a crash. + */ + nat->nat_hstart[0] = NULL; + nat->nat_hstart[1] = NULL; + fr = nat->nat_fr; + nat->nat_fr = NULL; + aps = nat->nat_aps; + nat->nat_aps = NULL; + in = nat->nat_ptr; + nat->nat_ptr = NULL; + nat->nat_data = NULL; + + /* + * Restore the rule associated with this nat session + */ + if (in) { + KMALLOC(in, ipnat_t *); + if (in == NULL) { + error = ENOMEM; + goto junkput; + } + nat->nat_ptr = in; + bcopy((char *)&ipn.ipn_ipnat, (char *)in, sizeof(*in)); + in->in_use = 1; + in->in_flags |= IPN_DELETE; + in->in_next = NULL; + in->in_rnext = NULL; + in->in_prnext = NULL; + in->in_mnext = NULL; + in->in_pmnext = NULL; + in->in_ifp = GETUNIT(in->in_ifname, 4); + if (in->in_plabel[0] != '\0') { + in->in_apr = appr_match(in->in_p, in->in_plabel); + } + } + + /* + * Restore ap_session_t structure. Include the private data allocated + * if it was there. + */ + if (aps) { + KMALLOC(aps, ap_session_t *); + if (aps == NULL) { + error = ENOMEM; + goto junkput; + } + nat->nat_aps = aps; + aps->aps_next = ap_sess_list; + ap_sess_list = aps; + bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps)); + if (in) + aps->aps_apr = in->in_apr; + if (aps->aps_psiz) { + KMALLOCS(aps->aps_data, void *, aps->aps_psiz); + if (aps->aps_data == NULL) { + error = ENOMEM; + goto junkput; + } + bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data, + aps->aps_psiz); + } else { + aps->aps_psiz = 0; + aps->aps_data = NULL; + } + } + + /* + * If there was a filtering rule associated with this entry then + * build up a new one. + */ + if (fr != NULL) { + if (nat->nat_flags & FI_NEWFR) { + KMALLOC(fr, frentry_t *); + nat->nat_fr = fr; + if (fr == NULL) { + error = ENOMEM; + goto junkput; + } + bcopy((char *)&ipn.ipn_fr, (char *)fr, sizeof(*fr)); + ipn.ipn_nat.nat_fr = fr; + error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn)); + if (error) { + error = EFAULT; + goto junkput; + } + } else { + for (n = nat_instances; n; n = n->nat_next) + if (n->nat_fr == fr) + break; + if (!n) { + error = ESRCH; + goto junkput; + } + } + } + + if (ipnn) + KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize); + nat_insert(nat); + return 0; +junkput: + if (ipnn) + KFREES(ipnn, sizeof(ipn) + ipn.ipn_dsize); + if (nat) + nat_delete(nat); return error; } @@ -350,41 +957,52 @@ struct nat *natd; register struct nat **natp, *nat; struct ipnat *ipn; - for (natp = natd->nat_hstart[0]; (nat = *natp); + for (natp = natd->nat_hstart[0]; natp && (nat = *natp); natp = &nat->nat_hnext[0]) if (nat == natd) { *natp = nat->nat_hnext[0]; break; } - for (natp = natd->nat_hstart[1]; (nat = *natp); + for (natp = natd->nat_hstart[1]; natp && (nat = *natp); natp = &nat->nat_hnext[1]) if (nat == natd) { *natp = nat->nat_hnext[1]; break; } + if (natd->nat_fr != NULL) { + ATOMIC_DEC32(natd->nat_fr->fr_ref); + } + + if (natd->nat_hm != NULL) + nat_hostmapdel(natd->nat_hm); + /* * 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--; } } + MUTEX_DESTROY(&natd->nat_lock); /* * If there's a fragment table entry too for this nat entry, then * dereference that as well. */ ipfr_forget((void *)natd); + aps_free(natd->nat_aps); + nat_stats.ns_inuse--; KFREE(natd); } @@ -398,135 +1016,79 @@ static int nat_flushtable() register int j = 0; /* - * Everything will be 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; nat_delete(nat); j++; } - + nat_stats.ns_inuse = 0; return j; } /* - * nat_clearlist - delete all entries in the active NAT mapping list. + * nat_clearlist - delete all rules in the active NAT mapping list. */ 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--; - i++; } else { n->in_flags |= IPN_DELETE; n->in_next = NULL; } + i++; } - nat_stats.ns_inuse = 0; + 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 = NULL; - if (!sin) { - KFREE(nat); - return -1; - } -# endif /* (BSD < 199306) && (!__sgi && IFF_DRVLOCK) */ - in = sin->sin_addr; - in.s_addr = ntohl(in.s_addr); -# endif /* linux */ -#endif /* SOLARIS */ - *inp = in; - return 0; -} - - -/* * Create a new NAT table entry. + * NOTE: assumes write lock on ipf_nat has been obtained already. */ 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; + struct in_addr in, inb; tcphdr_t *tcp = NULL; - nat_t *nat, **natp; + hostmap_t *hm = NULL; + nat_t *nat, *natl; u_short nflags; +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) + qif_t *qf = fin->fin_qif; +#endif nflags = flags & np->in_flags; if (flags & IPN_TCPUDP) { @@ -536,96 +1098,247 @@ int direction; } /* Give me a new nat */ - KMALLOC(nat, nat_t *, sizeof(*nat)); - if (nat == NULL) + KMALLOC(nat, nat_t *); + if (nat == NULL) { + nat_stats.ns_memfail++; 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. + */ + u_32_t st_ip; + u_short st_port; + + /* * If it's an outbound packet which doesn't match any existing * record, then create a new port */ l = 0; + st_ip = np->in_nip; + st_port = np->in_pnext; + do { - l++; port = 0; - in.s_addr = np->in_nip; - if (!in.s_addr && (np->in_outmsk == 0xffffffff)) { - if ((l > 1) || - nat_ifpaddr(nat, fin->fin_ifp, &in) == -1) { - KFREE(nat); - return NULL; - } - } else if (!in.s_addr && !np->in_outmsk) { - if (l > 1) { - KFREE(nat); - return NULL; + in.s_addr = htonl(np->in_nip); + if (l == 0) { + /* + * Check to see if there is an existing NAT + * setup for this IP address pair. + */ + hm = nat_hostmap(np, ip->ip_src, in); + if (hm != NULL) + in.s_addr = hm->hm_mapip.s_addr; + } else if ((l == 1) && (hm != NULL)) { + nat_hostmapdel(hm); + hm = NULL; + } + in.s_addr = ntohl(in.s_addr); + + nat->nat_hm = hm; + + if ((np->in_outmsk == 0xffffffff) && + (np->in_pnext == 0)) { + if (l > 0) + goto badnat; + } + + if (np->in_redir & NAT_MAPBLK) { + if ((l >= np->in_ppip) || ((l > 0) && + !(flags & IPN_TCPUDP))) + goto badnat; + /* + * 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 (!np->in_outip && + (np->in_outmsk == 0xffffffff)) { + /* + * 0/32 - use the interface's IP address. + */ + if ((l > 0) || + fr_ifpaddr(4, fin->fin_ifp, &in) == -1) + goto badnat; + in.s_addr = ntohl(in.s_addr); + } else if (!np->in_outip && !np->in_outmsk) { + /* + * 0/0 - use the original source address/port. + */ + if (l > 0) + goto badnat; in.s_addr = ntohl(ip->ip_src.s_addr); - if (nflags & IPN_TCPUDP) - port = sport; - } else if (nflags & IPN_TCPUDP) { + } else if ((np->in_outmsk != 0xffffffff) && + (np->in_pnext == 0) && + ((l > 0) || (hm == 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) { + goto badnat; + } 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); - np->in_space--; if (np->in_outmsk != 0xffffffff) np->in_nip++; } - } else if (np->in_outmsk != 0xffffffff) { - np->in_space--; - np->in_nip++; + } + + if (np->in_flags & IPN_IPRANGE) { + 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; - } while (nat_inlookup(fin->fin_ifp, flags, ip->ip_dst, - dport, in, port)); + + /* + * 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_WILDP, + (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)) + goto badnat; + l++; + } while (natl != NULL); + + if (np->in_space > 0) + np->in_space--; /* Setup the NAT table */ nat->nat_inip = ip->ip_src; nat->nat_outip.s_addr = htonl(in.s_addr); nat->nat_oip = ip->ip_dst; + if (nat->nat_hm == NULL) + nat->nat_hm = nat_hostmap(np, ip->ip_src, + nat->nat_outip); - 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, * we want to rewrite to a fixed internal address and fixed * internal port. */ - in.s_addr = ntohl(np->in_inip); - if (!(nport = np->in_pnext)) + if (np->in_flags & IPN_SPLIT) { + in.s_addr = np->in_nip; + if (np->in_inip == htonl(in.s_addr)) + np->in_nip = ntohl(np->in_inmsk); + else { + np->in_nip = ntohl(np->in_inip); + if (np->in_flags & IPN_ROUNDR) { + nat_delrdr(np); + nat_addrdr(np); + } + } + } else { + in.s_addr = ntohl(np->in_inip); + if (np->in_flags & IPN_ROUNDR) { + nat_delrdr(np); + nat_addrdr(np); + } + } + if (!np->in_pnext) nport = dport; + else { + /* + * Whilst not optimized for the case where + * pmin == pmax, the gain is not significant. + */ + nport = ntohs(dport) - ntohs(np->in_pmin) + + ntohs(np->in_pnext); + nport = htons(nport); + } + + /* + * 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) { + if (nport == dport) + goto badnat; + in.s_addr = ntohl(ip->ip_dst.s_addr); + } 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; @@ -634,62 +1347,53 @@ int direction; } } - /* Do it twice */ - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - - /* Do it twice */ - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - - 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); - - sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16); - - /* Do it twice */ - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - sum1 = (sum1 & 0xffff) + (sum1 >> 16); + sum1 = LONG_SUM(ntohl(ip->ip_dst.s_addr)); - /* Do it twice */ - sum2 = (sum2 & 0xffff) + (sum2 >> 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]; - nat->nat_hstart[0] = natp; - nat->nat_hnext[0] = *natp; - *natp = nat; - natp = &nat_table[1][nat->nat_outip.s_addr % NAT_SIZE]; - nat->nat_hstart[1] = natp; - nat->nat_hnext[1] = *natp; - *natp = nat; + +#ifdef _KERNEL + strncpy(nat->nat_ifname, IFNAME(fin->fin_ifp), IFNAMSIZ); +#endif + nat_insert(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_fr = fin->fin_fr; + if (nat->nat_fr != NULL) { + ATOMIC_INC32(nat->nat_fr->fr_ref); + } if (direction == NAT_OUTBOUND) { if (flags & IPN_TCPUDP) tcp->th_sport = port; @@ -697,16 +1401,55 @@ int direction; if (flags & IPN_TCPUDP) tcp->th_dport = nport; } - nat_stats.ns_added++; - nat_stats.ns_inuse++; np->in_use++; return nat; +badnat: + nat_stats.ns_badnat++; + if ((hm = nat->nat_hm) != NULL) + nat_hostmapdel(hm); + KFREE(nat); + return NULL; +} + + +void nat_insert(nat) +nat_t *nat; +{ + nat_t **natp; + u_int hv; + + MUTEX_INIT(&nat->nat_lock, "nat entry lock", NULL); + + nat->nat_age = fr_defnatage; + nat->nat_ifname[sizeof(nat->nat_ifname) - 1] = '\0'; + if (nat->nat_ifname[0] !='\0') { + nat->nat_ifp = GETUNIT(nat->nat_ifname, 4); + } + + nat->nat_next = nat_instances; + nat_instances = nat; + hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, + ipf_nattable_sz); + natp = &nat_table[0][hv]; + nat->nat_hstart[0] = natp; + nat->nat_hnext[0] = *natp; + *natp = nat; + hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, + ipf_nattable_sz); + natp = &nat_table[1][hv]; + nat->nat_hstart[1] = natp; + nat->nat_hnext[1] = *natp; + *natp = nat; + + nat_stats.ns_added++; + nat_stats.ns_inuse++; } -nat_t *nat_icmpinlookup(ip, fin) +nat_t *nat_icmplookup(ip, fin, dir) ip_t *ip; fr_info_t *fin; +int dir; { icmphdr_t *icmp; tcphdr_t *tcp = NULL; @@ -719,7 +1462,7 @@ fr_info_t *fin; * Only a basic IP header (no options) should be with an ICMP error * header. */ - if ((ip->ip_hl != 5) || (ip->ip_len < sizeof(*icmp) + sizeof(ip_t))) + if ((ip->ip_hl != 5) || (ip->ip_len < ICMPERR_MINPKTLEN)) return NULL; type = icmp->icmp_type; /* @@ -731,16 +1474,29 @@ fr_info_t *fin; return NULL; oip = (ip_t *)((char *)fin->fin_dp + 8); + if (ip->ip_len < ICMPERR_MAXPKTLEN + ((oip->ip_hl - 5) << 2)) + return NULL; if (oip->ip_p == IPPROTO_TCP) flags = IPN_TCP; else if (oip->ip_p == IPPROTO_UDP) flags = IPN_UDP; if (flags & IPN_TCPUDP) { tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2)); - return nat_inlookup(fin->fin_ifp, flags, oip->ip_dst, - tcp->th_dport, oip->ip_src, tcp->th_sport); + if (dir == NAT_INBOUND) + 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); + else + return nat_outlookup(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_src, 0, oip->ip_dst, 0); + if (dir == NAT_INBOUND) + return nat_inlookup(fin->fin_ifp, 0, (u_int)oip->ip_p, + oip->ip_dst, oip->ip_src, 0); + else + return nat_outlookup(fin->fin_ifp, 0, (u_int)oip->ip_p, + oip->ip_dst, oip->ip_src, 0); } @@ -748,22 +1504,24 @@ fr_info_t *fin; * This should *ONLY* be used for incoming packets to make sure a NAT'd ICMP * packet gets correctly recognised. */ -nat_t *nat_icmpin(ip, fin, nflags) +nat_t *nat_icmp(ip, fin, nflags, dir) ip_t *ip; fr_info_t *fin; -int *nflags; +u_int *nflags; +int dir; { + u_32_t sum1, sum2, sumd; + struct in_addr in; icmphdr_t *icmp; nat_t *nat; ip_t *oip; int flags = 0; - if (!(nat = nat_icmpinlookup(ip, fin))) + if ((ip->ip_v != 4) || !(nat = nat_icmplookup(ip, fin, dir))) return NULL; - *nflags = IPN_ICMPERR; icmp = (icmphdr_t *)fin->fin_dp; - oip = (ip_t *)((char *)icmp + 8); + oip = (ip_t *)&icmp->icmp_ip; if (oip->ip_p == IPPROTO_TCP) flags = IPN_TCP; else if (oip->ip_p == IPPROTO_UDP) @@ -777,54 +1535,62 @@ int *nflags; * to only modify the checksum once for the port # and twice * for the IP#. */ - if (flags & IPN_TCPUDP) { - tcphdr_t *tcp = (tcphdr_t *)(oip + 1); - u_32_t sum1, sum2, sumd; - struct in_addr in; - if (nat->nat_dir == NAT_OUTBOUND) { - sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr)); - in = nat->nat_outip; - oip->ip_src = in; - tcp->th_sport = nat->nat_outport; - } else { - sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr)); - in = nat->nat_inip; - oip->ip_dst = in; - tcp->th_dport = nat->nat_inport; - } + if (nat->nat_dir == NAT_OUTBOUND) { + sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr)); + in = nat->nat_inip; + oip->ip_src = in; + } else { + sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr)); + in = nat->nat_outip; + oip->ip_dst = in; + } - sum2 = LONG_SUM(in.s_addr); + sum2 = LONG_SUM(ntohl(in.s_addr)); - CALC_SUMD(sum1, sum2, sumd); - sumd = (sumd & 0xffff) + (sumd >> 16); + CALC_SUMD(sum1, sum2, sumd); - if (nat->nat_dir == NAT_OUTBOUND) { - fix_incksum(&oip->ip_sum, sumd); - fix_incksum(&icmp->icmp_cksum, sumd); - } else { - fix_outcksum(&oip->ip_sum, sumd); - fix_outcksum(&icmp->icmp_cksum, sumd); - } + if (nat->nat_dir == NAT_OUTBOUND) { + fix_incksum(&oip->ip_sum, sumd, 0); - /* - * TCP checksum doesn't make it into the 1st eight - * bytes but UDP does. - */ - if (ip->ip_p == IPPROTO_UDP) { - udphdr_t *udp = (udphdr_t *)tcp; + sumd += (sumd & 0xffff); + while (sumd > 0xffff) + sumd = (sumd & 0xffff) + (sumd >> 16); + fix_outcksum(&icmp->icmp_cksum, sumd, 0); + } else { + fix_outcksum(&oip->ip_sum, sumd, 0); - if (udp->uh_sum) { - if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(&udp->uh_sum, - nat->nat_sumd); - else - fix_outcksum(&udp->uh_sum, - nat->nat_sumd); + 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; + + /* XXX - what if this is bogus hl and we go off the end ? */ + tcp = (tcphdr_t *)((((char *)oip) + (oip->ip_hl << 2))); + + if (nat->nat_dir == NAT_OUTBOUND) { + if (tcp->th_sport != nat->nat_inport) { + sum1 = ntohs(tcp->th_sport); + sum2 = ntohs(nat->nat_inport); + CALC_SUMD(sum1, sum2, sumd); + tcp->th_sport = nat->nat_inport; + fix_outcksum(&icmp->icmp_cksum, sumd, 0); + } + } else { + if (tcp->th_dport != nat->nat_outport) { + sum1 = ntohs(tcp->th_dport); + sum2 = ntohs(nat->nat_outport); + CALC_SUMD(sum1, sum2, sumd); + tcp->th_dport = nat->nat_outport; + fix_incksum(&icmp->icmp_cksum, sumd, 0); } } - } else - ip->ip_dst = nat->nat_outip; + } nat->nat_age = fr_defnaticmpage; return nat; } @@ -840,29 +1606,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, mapdport, 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; } @@ -873,27 +1645,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, sport, 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; @@ -901,52 +1679,21 @@ 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. - */ -#ifdef __STDC__ -nat_t *nat_lookupmapip(void *ifp, int flags, struct in_addr mapsrc, u_short mapsport, struct in_addr dst, u_short dport) -#else -nat_t *nat_lookupmapip(ifp, flags, mapsrc, mapsport, dst, dport) -void *ifp; -register int flags; -struct in_addr mapsrc , dst; -u_short mapsport, dport; -#endif -{ - register nat_t *nat; - - flags &= IPN_TCPUDP; - - 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))) - return nat; - return NULL; -} - - -/* * Lookup the NAT tables to search for a matching redirect */ 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; } @@ -954,23 +1701,63 @@ register natlookup_t *np; } +static int nat_match(fin, np, ip) +fr_info_t *fin; +ipnat_t *np; +ip_t *ip; +{ + frtuc_t *ft; + + if (ip->ip_v != 4) + return 0; + + if (np->in_p && ip->ip_p != np->in_p) + return 0; + if (fin->fin_out) { + if (!(np->in_redir && (NAT_MAP|NAT_MAPBLK))) + return 0; + if ((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip) + return 0; + if ((fin->fin_fi.fi_daddr & np->in_srcmsk) != np->in_srcip) + return 0; + } else { + if (!(np->in_redir && NAT_REDIRECT)) + return 0; + } + + ft = &np->in_tuc; + if (!(fin->fin_fi.fi_fl & FI_TCPUDP)) { + if (ft->ftu_scmp || ft->ftu_dcmp) + return 0; + return 1; + } + + return fr_tcpudpchk(ft, fin); +} + + /* * 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; + u_short sport = 0, dport = 0, *csump = NULL; struct ifnet *ifp; + int natadd = 1; frentry_t *fr; + u_int nflags = 0, hv, msk; + u_32_t iph; nat_t *nat; - int natadd = 1; + int i; + + if (nat_list == NULL || (fr_nat_lock)) + return 0; if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) && fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1) @@ -978,12 +1765,12 @@ fr_info_t *fin; else ifp = fin->fin_ifp; - if (!(ip->ip_off & 0x1fff) && !(fin->fin_fi.fi_fl & FI_SHORT)) { + if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) { if (ip->ip_p == IPPROTO_TCP) nflags = IPN_TCP; else if (ip->ip_p == IPPROTO_UDP) nflags = IPN_UDP; - if (nflags) { + if ((nflags & IPN_TCPUDP)) { tcp = (tcphdr_t *)fin->fin_dp; sport = tcp->th_sport; dport = tcp->th_dport; @@ -992,25 +1779,56 @@ fr_info_t *fin; ipa = ip->ip_src.s_addr; - MUTEX_ENTER(&ipf_nat); - 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))) + READ_ENTER(&ipf_nat); + + if ((ip->ip_p == IPPROTO_ICMP) && + (nat = nat_icmp(ip, fin, &nflags, NAT_OUTBOUND))) ; - else + else if ((ip->ip_off & (IP_OFFMASK|IP_MF)) && + (nat = ipfr_nat_knownfrag(ip, fin))) + natadd = 0; + 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) - if ((np->in_ifp == ifp) && np->in_space && - (!np->in_flags || (np->in_flags & nflags)) && - ((ipa & np->in_inmsk) == np->in_inip) && - ((np->in_redir & NAT_MAP) || - (np->in_pnext == sport))) { - if (*np->in_plabel && !ap_ok(ip, tcp, np)) + msk = 0xffffffff; + i = 32; +maskloop: + iph = ipa & htonl(msk); + hv = NAT_HASH_FN(iph, 0, ipf_natrules_sz); + for (np = nat_rules[hv]; np; np = np->in_mnext) + { + if ((np->in_ifp && (np->in_ifp != ifp)) || + !np->in_space) + continue; + if ((np->in_flags & IPN_RF) && + !(np->in_flags & nflags)) + continue; + if (np->in_flags & IPN_FILTER) { + if (!nat_match(fin, np, ip)) + continue; + } else if ((ipa & np->in_inmsk) != np->in_inip) + continue; + if (np->in_redir & (NAT_MAP|NAT_MAPBLK)) { + if (*np->in_plabel && !appr_ok(ip, tcp, np)) continue; /* * If it's a redirection, then we don't want to @@ -1018,80 +1836,109 @@ 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); - nat->nat_age = fr_defnatage; - ip->ip_src = nat->nat_outip; - nat->nat_bytes += ip->ip_len; - nat->nat_pkts++; + 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(&nat->nat_lock); + nat->nat_age = fr_defnatage; + nat->nat_bytes += ip->ip_len; + nat->nat_pkts++; + MUTEX_EXIT(&nat->nat_lock); - /* - * 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 (nflags && !(ip->ip_off & 0x1fff) && - !(fin->fin_fi.fi_fl & FI_SHORT)) { - - if (nat->nat_outport) - tcp->th_sport = nat->nat_outport; - - if (ip->ip_p == IPPROTO_TCP) { - csump = &tcp->th_sum; - 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; - } else if (ip->ip_p == IPPROTO_UDP) { - udphdr_t *udp = (udphdr_t *)tcp; - - if (udp->uh_sum) - csump = &udp->uh_sum; - } else if (ip->ip_p == IPPROTO_ICMP) { - icmphdr_t *ic = (icmphdr_t *)tcp; - - csump = &ic->icmp_cksum; - } - if (csump) { - if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(csump, - nat->nat_sumd); - else - fix_incksum(csump, - nat->nat_sumd); - } + 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 (ip->ip_p == IPPROTO_TCP) { + csump = &tcp->th_sum; + MUTEX_ENTER(&nat->nat_lock); + fr_tcp_age(&nat->nat_age, + nat->nat_tcpstate, fin, 1); + if (nat->nat_age < fr_defnaticmpage) + nat->nat_age = fr_defnaticmpage; +#ifdef LARGE_NAT + else if (nat->nat_age > fr_defnatage) + nat->nat_age = fr_defnatage; +#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(&nat->nat_lock); + } else if (ip->ip_p == IPPROTO_UDP) { + udphdr_t *udp = (udphdr_t *)tcp; + + if (udp->uh_sum) + csump = &udp->uh_sum; + } else if (ip->ip_p == IPPROTO_ICMP) { + nat->nat_age = fr_defnaticmpage; + } + 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, tcp, fin, nat); - nat_stats.ns_mapped[1]++; - MUTEX_EXIT(&ipf_nat); - return -2; } - MUTEX_EXIT(&ipf_nat); + + if ((np->in_apr != NULL) && (np->in_dport == 0 || + (tcp != NULL && dport == np->in_dport))) { + i = appr_check(ip, fin, nat); + if (i == 0) + i = 1; + } else + i = 1; + ATOMIC_INCL(nat_stats.ns_mapped[1]); + RWLOCK_EXIT(&ipf_nat); /* READ */ + return i; + } + RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ return 0; } @@ -1100,127 +1947,191 @@ 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) || (ip->ip_v != 4) || (fr_nat_lock)) + return 0; - if (!(ip->ip_off & 0x1fff) && !(fin->fin_fi.fi_fl & FI_SHORT)) { + if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) { if (ip->ip_p == IPPROTO_TCP) nflags = IPN_TCP; else if (ip->ip_p == IPPROTO_UDP) nflags = IPN_UDP; - if (nflags) { - tcp = (tcphdr_t *)((char *)ip + hlen); + if ((nflags & IPN_TCPUDP)) { + tcp = (tcphdr_t *)fin->fin_dp; dport = tcp->th_dport; sport = tcp->th_sport; } } in = ip->ip_dst; + /* make sure the source address is to be redirected */ + src = ip->ip_src; - MUTEX_ENTER(&ipf_nat); + READ_ENTER(&ipf_nat); - if ((ip->ip_p == IPPROTO_ICMP) && (nat = nat_icmpin(ip, fin, &nflags))) + if ((ip->ip_p == IPPROTO_ICMP) && + (nat = nat_icmp(ip, fin, &nflags, NAT_INBOUND))) ; 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) - if ((np->in_ifp == ifp) && - (!np->in_flags || (nflags & np->in_flags)) && - ((in.s_addr & np->in_outmsk) == np->in_outip) && - (np->in_redir & NAT_REDIRECT) && - (!np->in_pmin || np->in_pmin == dport)) { + msk = 0xffffffff; + i = 32; +maskloop: + iph = in.s_addr & htonl(msk); + hv = NAT_HASH_FN(iph, 0, ipf_rdrrules_sz); + for (np = rdr_rules[hv]; np; np = np->in_rnext) { + if ((np->in_ifp && (np->in_ifp != ifp)) || + (np->in_p && (np->in_p != ip->ip_p)) || + (np->in_flags && !(nflags & np->in_flags))) + continue; + if (np->in_flags & IPN_FILTER) { + if (!nat_match(fin, np, ip)) + continue; + } else if ((in.s_addr & np->in_outmsk) != np->in_outip) + continue; + if ((np->in_redir & NAT_REDIRECT) && + (!np->in_pmin || + ((ntohs(np->in_pmax) >= ntohs(dport)) && + (ntohs(dport) >= ntohs(np->in_pmin))))) 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, tcp, fin, nat); + 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))) { + i = appr_check(ip, fin, nat); + if (i == -1) { + RWLOCK_EXIT(&ipf_nat); + return i; + } + } - if (nflags != IPN_ICMPERR) - nat->nat_age = fr_defnatage; + MUTEX_ENTER(&nat->nat_lock); + if (nflags != IPN_ICMPERR) + nat->nat_age = fr_defnatage; - ip->ip_dst = nat->nat_inip; - nat->nat_bytes += ip->ip_len; - nat->nat_pkts++; + nat->nat_bytes += ip->ip_len; + nat->nat_pkts++; + MUTEX_EXIT(&nat->nat_lock); + ip->ip_dst = nat->nat_inip; + fin->fin_fi.fi_daddr = nat->nat_inip.s_addr; - /* - * 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 ((nflags & IPN_TCPUDP) && !(ip->ip_off & 0x1fff) && - !(fin->fin_fi.fi_fl & FI_SHORT)) { - - if (nat->nat_inport) - tcp->th_dport = nat->nat_inport; - - if (ip->ip_p == IPPROTO_TCP) { - csump = &tcp->th_sum; - 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; - } else if (ip->ip_p == IPPROTO_UDP) { - udphdr_t *udp = (udphdr_t *)tcp; - - if (udp->uh_sum) - csump = &udp->uh_sum; - } else if (ip->ip_p == IPPROTO_ICMP) { - icmphdr_t *ic = (icmphdr_t *)tcp; - - csump = &ic->icmp_cksum; - } - if (csump) { - if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(csump, - nat->nat_sumd); - else - fix_outcksum(csump, - nat->nat_sumd); - } + 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 (ip->ip_p == IPPROTO_TCP) { + csump = &tcp->th_sum; + MUTEX_ENTER(&nat->nat_lock); + fr_tcp_age(&nat->nat_age, + nat->nat_tcpstate, fin, 0); + if (nat->nat_age < fr_defnaticmpage) + nat->nat_age = fr_defnaticmpage; +#ifdef LARGE_NAT + else if (nat->nat_age > fr_defnatage) + nat->nat_age = fr_defnatage; +#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(&nat->nat_lock); + } else if (ip->ip_p == IPPROTO_UDP) { + udphdr_t *udp = (udphdr_t *)tcp; + + if (udp->uh_sum) + csump = &udp->uh_sum; + } else if (ip->ip_p == IPPROTO_ICMP) { + nat->nat_age = fr_defnaticmpage; + } + + 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); } - nat_stats.ns_mapped[0]++; - MUTEX_EXIT(&ipf_nat); - return -2; } - MUTEX_EXIT(&ipf_nat); + ATOMIC_INCL(nat_stats.ns_mapped[0]); + RWLOCK_EXIT(&ipf_nat); /* READ */ + return 1; + } + RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */ return 0; } @@ -1230,11 +2141,31 @@ fr_info_t *fin; */ void ip_natunload() { - MUTEX_ENTER(&ipf_nat); + WRITE_ENTER(&ipf_nat); (void) nat_clearlist(); (void) nat_flushtable(); - (void) ap_unload(); - MUTEX_EXIT(&ipf_nat); + 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; + } + if (maptable != NULL) { + KFREES(maptable, sizeof(hostmap_t *) * ipf_hostmap_sz); + maptable = NULL; + } } @@ -1250,9 +2181,10 @@ void ip_natexpire() #endif SPL_NET(s); - MUTEX_ENTER(&ipf_nat); + WRITE_ENTER(&ipf_nat); for (natp = &nat_instances; (nat = *natp); ) { - if (--nat->nat_age) { + nat->nat_age--; + if (nat->nat_age) { natp = &nat->nat_next; continue; } @@ -1263,79 +2195,76 @@ void ip_natexpire() nat_delete(nat); nat_stats.ns_expire++; } - - ap_expire(); - - MUTEX_EXIT(&ipf_nat); + RWLOCK_EXIT(&ipf_nat); SPL_X(s); } /* */ -#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); - MUTEX_ENTER(&ipf_nat); + 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(4, ifp2, &in) != -1) + nat->nat_outip = in; + sum2 = nat->nat_outip.s_addr; - /* - * Readjust the checksum adjustment to take - * into account the new IP#. - * - * Do it twice - */ - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - sum1 = (sum1 & 0xffff) + (sum1 >> 16); - - /* Do it twice */ - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - - /* Because ~1 == -2, We really need ~1 == -1 */ - if (sum1 > sum2) - sum2--; - sumd = sum2 - sum1; - sumd = (sumd & 0xffff) + (sumd >> 16); - sumd += nat->nat_sumd; - nat->nat_sumd = (sumd & 0xffff) + (sumd >> 16); - } - MUTEX_EXIT(&ipf_nat); + 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, 4); + 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; @@ -1351,19 +2280,22 @@ u_short type; natl.nl_origport = nat->nat_oport; natl.nl_inport = nat->nat_inport; natl.nl_outport = nat->nat_outport; + natl.nl_p = nat->nat_p; 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/contrib/ipfilter/netinet/ip_nat.h b/sys/contrib/ipfilter/netinet/ip_nat.h index 49f5d50..f1a339f 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.h +++ b/sys/contrib/ipfilter/netinet/ip_nat.h @@ -1,12 +1,12 @@ /* - * Copyright (C) 1995-1997 by Darren Reed. + * Copyright (C) 1995-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * * @(#)ip_nat.h 1.5 2/4/96 - * $Id: ip_nat.h,v 2.0.2.23.2.3 1998/05/23 18:52:44 darrenr Exp $ + * $Id: ip_nat.h,v 2.17.2.1 2000/05/15 06:50:14 darrenr Exp $ */ #ifndef __IP_NAT_H__ @@ -17,71 +17,104 @@ #endif #if defined(__STDC__) || defined(__GNUC__) -#define SIOCADNAT _IOW('r', 80, struct ipnat) -#define SIOCRMNAT _IOW('r', 81, struct ipnat) -#define SIOCGNATS _IOR('r', 82, struct natstat) -#define SIOCGNATL _IOWR('r', 83, struct natlookup) -#define SIOCGFRST _IOR('r', 84, struct ipfrstat) -#define SIOCGIPST _IOR('r', 85, struct ips_stat) -#define SIOCFLNAT _IOWR('r', 86, int) -#define SIOCCNATL _IOWR('r', 87, int) +#define SIOCADNAT _IOW('r', 60, struct ipnat *) +#define SIOCRMNAT _IOW('r', 61, struct ipnat *) +#define SIOCGNATS _IOWR('r', 62, struct natstat *) +#define SIOCGNATL _IOWR('r', 63, struct natlookup *) #else -#define SIOCADNAT _IOW(r, 80, struct ipnat) -#define SIOCRMNAT _IOW(r, 81, struct ipnat) -#define SIOCGNATS _IOR(r, 82, struct natstat) -#define SIOCGNATL _IOWR(r, 83, struct natlookup) -#define SIOCGFRST _IOR(r, 84, struct ipfrstat) -#define SIOCGIPST _IOR(r, 85, struct ips_stat) -#define SIOCFLNAT _IOWR(r, 86, int) -#define SIOCCNATL _IOWR(r, 87, int) +#define SIOCADNAT _IOW(r, 60, struct ipnat *) +#define SIOCRMNAT _IOW(r, 61, struct ipnat *) +#define SIOCGNATS _IOWR(r, 62, struct natstat *) +#define SIOCGNATL _IOWR(r, 63, struct natlookup *) #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 HOSTMAP_SIZE 127 +#define NAT_TABLE_SZ 127 +#ifdef LARGE_NAT +#undef NAT_SIZE +#undef RDR_SIZE +#undef NAT_TABLE_SZ +#undef HOSTMAP_SIZE 127 +#define NAT_SIZE 2047 +#define RDR_SIZE 2047 +#define NAT_TABLE_SZ 16383 +#define HOSTMAP_SIZE 8191 +#endif #ifndef APR_LABELLEN #define APR_LABELLEN 16 #endif +#define NAT_HW_CKSUM 0x80000000 + +#define DEF_NAT_AGE 1200 /* 10 minutes (600 seconds) */ + +struct ap_session; 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; + struct ap_session *nat_aps; /* proxy session */ + struct frentry *nat_fr; /* filter rule ptr if appropriate */ struct in_addr nat_inip; struct in_addr nat_outip; struct in_addr nat_oip; /* other ip */ U_QUAD_T nat_pkts; U_QUAD_T nat_bytes; - u_short nat_oport; /* other port */ + u_short nat_oport; /* other port */ u_short nat_inport; u_short nat_outport; u_short nat_use; - u_char nat_state[2]; - struct ipnat *nat_ptr; + u_char nat_tcpstate[2]; + u_char nat_p; /* protocol for NAT */ + struct ipnat *nat_ptr; /* pointer back to the rule */ + struct hostmap *nat_hm; struct nat *nat_next; struct nat *nat_hnext[2]; struct nat **nat_hstart[2]; void *nat_ifp; int nat_dir; + char nat_ifname[IFNAMSIZ]; +#if SOLARIS || defined(_sgi) + kmutex_t nat_lock; +#endif } nat_t; typedef struct ipnat { struct ipnat *in_next; + struct ipnat *in_rnext; + struct ipnat **in_prnext; + struct ipnat *in_mnext; + struct ipnat **in_pmnext; void *in_ifp; void *in_apr; - u_int in_space; + 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]; + struct frtuc in_tuc; 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 */ char in_p; /* protocol */ - u_short in_dport; } ipnat_t; #define in_pmin in_port[0] /* Also holds static redir port */ @@ -91,6 +124,14 @@ 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 in_scmp in_tuc.ftu_scmp +#define in_dcmp in_tuc.ftu_dcmp +#define in_stop in_tuc.ftu_stop +#define in_dtop in_tuc.ftu_dtop +#define in_sport in_tuc.ftu_sport +#define in_dport in_tuc.ftu_dport #define NAT_OUTBOUND 0 #define NAT_INBOUND 1 @@ -98,9 +139,12 @@ typedef struct ipnat { #define NAT_MAP 0x01 #define NAT_REDIRECT 0x02 #define NAT_BIMAP (NAT_MAP|NAT_REDIRECT) +#define NAT_MAPBLK 0x04 -#define IPN_CMPSIZ (sizeof(struct in_addr) * 4 + sizeof(u_short) * 3 + \ - sizeof(int) + IFNAMSIZ + APR_LABELLEN + sizeof(char)) +#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)) typedef struct natlookup { struct in_addr nl_inip; @@ -112,6 +156,34 @@ typedef struct natlookup { u_short nl_realport; } natlookup_t; + +typedef struct nat_save { + void *ipn_next; + struct nat ipn_nat; + struct ipnat ipn_ipnat; + struct frentry ipn_fr; + int ipn_dsize; + char ipn_data[4]; +} nat_save_t; + +#define ipn_rule ipn_nat.nat_fr + +typedef struct natget { + void *ng_ptr; + int ng_sz; +} natget_t; + + +typedef struct hostmap { + struct hostmap *hm_next; + struct hostmap **hm_pnext; + struct ipnat *hm_ipnat; + struct in_addr hm_realip; + struct in_addr hm_mapip; + int hm_ref; +} hostmap_t; + + typedef struct natstat { u_long ns_mapped[2]; u_long ns_rules; @@ -120,16 +192,31 @@ typedef struct natstat { u_long ns_inuse; u_long ns_logged; u_long ns_logfail; + u_long ns_memfail; + u_long ns_badnat; 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_DELETE 0x04 -#define IPN_ICMPERR 0x08 +#define IPN_ANY 0x000 +#define IPN_TCP 0x001 +#define IPN_UDP 0x002 +#define IPN_TCPUDP (IPN_TCP|IPN_UDP) +#define IPN_DELETE 0x004 +#define IPN_ICMPERR 0x008 +#define IPN_RF (IPN_TCPUDP|IPN_DELETE|IPN_ICMPERR) +#define IPN_AUTOPORTMAP 0x010 +#define IPN_IPRANGE 0x020 +#define IPN_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_IPRANGE|\ + IPN_SPLIT|IPN_ROUNDR|IPN_FILTER) +#define IPN_FILTER 0x040 +#define IPN_SPLIT 0x080 +#define IPN_ROUNDR 0x100 typedef struct natlog { @@ -143,6 +230,7 @@ typedef struct natlog { int nl_rule; U_QUAD_T nl_pkts; U_QUAD_T nl_bytes; + u_char nl_p; } natlog_t; @@ -150,32 +238,57 @@ typedef struct natlog { #define NL_NEWRDR NAT_REDIRECT #define NL_EXPIRE 0xffff +#define NAT_HASH_FN(k,l,m) (((k) + ((k) >> 12) + l) % (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 int fr_nat_lock; extern void ip_natsync __P((void *)); extern u_long fr_defnatage; extern u_long fr_defnaticmpage; -extern nat_t *nat_table[2][NAT_SIZE]; -#if defined(__NetBSD__) || defined(__OpenBSD__) +extern 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__) || (__FreeBSD_version >= 300003) extern int nat_ioctl __P((caddr_t, u_long, int)); #else extern int nat_ioctl __P((caddr_t, int, int)); #endif -extern nat_t *nat_new __P((ipnat_t *, ip_t *, fr_info_t *, u_short, int)); -extern nat_t *nat_outlookup __P((void *, int, struct in_addr, u_short, - struct in_addr, u_short)); -extern nat_t *nat_inlookup __P((void *, int, struct in_addr, u_short, - 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_icmplookup __P((ip_t *, fr_info_t *, int)); +extern nat_t *nat_icmp __P((ip_t *, fr_info_t *, u_int *, int)); +extern void nat_insert __P((nat_t *)); -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/contrib/ipfilter/netinet/ip_proxy.c b/sys/contrib/ipfilter/netinet/ip_proxy.c index 0fb7e95..e1e55f1 100644 --- a/sys/contrib/ipfilter/netinet/ip_proxy.c +++ b/sys/contrib/ipfilter/netinet/ip_proxy.c @@ -1,31 +1,33 @@ /* - * Copyright (C) 1997 by Darren Reed. + * Copyright (C) 1997-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.0.2.11.2.7 1998/05/18 11:15:22 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.9.2.1 2000/05/06 12:30:50 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) # define _KERNEL #endif -#if !defined(_KERNEL) && !defined(KERNEL) -# include -# include -# include -#endif #include #include #include #include #include -#include +#if !defined(__FreeBSD_version) +# include +#endif #include #include +#if !defined(_KERNEL) && !defined(KERNEL) +# include +# include +# include +#endif #ifndef linux # include #endif @@ -43,7 +45,9 @@ static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.0.2.11.2.7 1998/05/18 11:15 # endif #else # include -# include +# ifdef _KERNEL +# include +# endif # include # include #endif @@ -70,97 +74,100 @@ static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.0.2.11.2.7 1998/05/18 11:15 #include "netinet/ip_proxy.h" #include "netinet/ip_nat.h" #include "netinet/ip_state.h" +#if (__FreeBSD_version >= 300000) +# include +#endif + #ifndef MIN #define MIN(a,b) (((a)<(b))?(a):(b)) #endif -static ap_session_t *ap_find __P((ip_t *, tcphdr_t *)); -static ap_session_t *ap_new_session __P((aproxy_t *, ip_t *, tcphdr_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_proxylist = NULL; aproxy_t ap_proxies[] = { #ifdef IPF_FTP_PROXY - { "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, ippr_ftp_in, ippr_ftp_out }, + { NULL, "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, NULL, + ippr_ftp_new, ippr_ftp_in, ippr_ftp_out }, +#endif +#ifdef IPF_RCMD_PROXY + { NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, ippr_rcmd_init, NULL, + ippr_rcmd_new, NULL, ippr_rcmd_out }, #endif - { "", '\0', 0, 0, NULL, NULL } +#ifdef IPF_RAUDIO_PROXY + { NULL, "raudio", (char)IPPROTO_TCP, 0, 0, ippr_raudio_init, NULL, + ippr_raudio_new, ippr_raudio_in, ippr_raudio_out }, +#endif + { NULL, "", '\0', 0, 0, NULL, NULL } }; -int ap_ok(ip, tcp, nat) -ip_t *ip; -tcphdr_t *tcp; -ipnat_t *nat; +int appr_add(ap) +aproxy_t *ap; { - aproxy_t *apr = nat->in_apr; - u_short dport = nat->in_dport; - - if (!apr || (apr && (apr->apr_flags & APR_DELETE)) || - (ip->ip_p != apr->apr_p)) - return 0; - if ((tcp && (tcp->th_dport != dport)) || (!tcp && dport)) - return 0; - return 1; + aproxy_t *a; + + for (a = ap_proxies; a->apr_p; a++) + if ((a->apr_p == ap->apr_p) && + !strncmp(a->apr_label, ap->apr_label, + sizeof(ap->apr_label))) + return -1; + + for (a = ap_proxylist; a->apr_p; a = a->apr_next) + if ((a->apr_p == ap->apr_p) && + !strncmp(a->apr_label, ap->apr_label, + sizeof(ap->apr_label))) + return -1; + ap->apr_next = ap_proxylist; + ap_proxylist = ap; + return (*ap->apr_init)(); } -static int -ap_matchsrcdst(aps, src, dst, tcp, sport, dport) -ap_session_t *aps; -struct in_addr src, dst; -void *tcp; -u_short sport, dport; +int appr_del(ap) +aproxy_t *ap; { - if (aps->aps_dst.s_addr == dst.s_addr) { - if ((aps->aps_src.s_addr == src.s_addr) && - (!tcp || (sport == aps->aps_sport) && - (dport == aps->aps_dport))) - return 1; - } else if (aps->aps_dst.s_addr == src.s_addr) { - if ((aps->aps_src.s_addr == dst.s_addr) && - (!tcp || (sport == aps->aps_dport) && - (dport == aps->aps_sport))) - return 1; - } - return 0; + aproxy_t *a, **app; + + for (app = &ap_proxylist; (a = *app); app = &a->apr_next) + if (a == ap) { + if (ap->apr_ref != 0) + return 1; + *app = a->apr_next; + return 0; + } + return -1; } -static ap_session_t *ap_find(ip, tcp) +int appr_ok(ip, tcp, nat) ip_t *ip; tcphdr_t *tcp; +ipnat_t *nat; { - register u_char p = ip->ip_p; - register ap_session_t *aps; - register u_short sp, dp; - register u_long hv; - struct in_addr src, dst; - - src = ip->ip_src, dst = ip->ip_dst; - sp = dp = 0; /* XXX gcc -Wunitialized */ - - hv = ip->ip_src.s_addr ^ ip->ip_dst.s_addr; - hv *= 651733; - if (tcp) { - sp = tcp->th_sport; - dp = tcp->th_dport; - hv ^= (sp + dp); - hv *= 5; - } - hv %= AP_SESS_SIZE; + aproxy_t *apr = nat->in_apr; + u_short dport = nat->in_dport; - for (aps = ap_sess_tab[hv]; aps; aps = aps->aps_next) - if ((aps->aps_p == p) && - ap_matchsrcdst(aps, src, dst, tcp, sp, dp)) - break; - return aps; + if (!apr || (apr->apr_flags & APR_DELETE) || + (ip->ip_p != apr->apr_p)) + return 0; + if ((tcp && (tcp->th_dport != dport)) || (!tcp && dport)) + return 0; + return 1; } @@ -169,50 +176,33 @@ tcphdr_t *tcp; * relevant details. call the init function once complete, prior to * returning. */ -static ap_session_t *ap_new_session(apr, ip, tcp, fin, nat) +static ap_session_t *appr_new_session(apr, ip, fin, nat) aproxy_t *apr; ip_t *ip; -tcphdr_t *tcp; fr_info_t *fin; nat_t *nat; { register ap_session_t *aps; - u_short dport; - u_long hv; - if (!apr || (apr && (apr->apr_flags & APR_DELETE)) || - (ip->ip_p != apr->apr_p)) + if (!apr || (apr->apr_flags & APR_DELETE) || (ip->ip_p != apr->apr_p)) return NULL; - dport = nat->nat_ptr->in_dport; - if ((tcp && (tcp->th_dport != dport)) || (!tcp && dport)) - 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_p = ip->ip_p; - aps->aps_tout = 1200; /* XXX */ - 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_next = ap_sess_tab[hv]; - ap_sess_tab[hv] = aps; - (void) (*apr->apr_init)(fin, ip, tcp, aps, nat); + if (apr->apr_new != NULL) + if ((*apr->apr_new)(fin, ip, aps, nat) == -1) { + KFREE(aps); + return NULL; + } + aps->aps_nat = nat; + aps->aps_next = ap_sess_list; + ap_sess_list = aps; return aps; } @@ -221,59 +211,72 @@ nat_t *nat; * check to see if a packet should be passed through an active proxy routine * if one has been setup for it. */ -int ap_check(ip, tcp, fin, nat) +int appr_check(ip, fin, nat) ip_t *ip; -tcphdr_t *tcp; fr_info_t *fin; nat_t *nat; { ap_session_t *aps; aproxy_t *apr; + tcphdr_t *tcp = NULL; + u_32_t sum; + short rv; int err; - if (!(fin->fin_fi.fi_fl & FI_TCPUDP)) - tcp = NULL; - - if ((aps = ap_find(ip, tcp)) || - (aps = ap_new_session(nat->nat_ptr->in_apr, ip, tcp, 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; /* * verify that the checksum is correct. If not, then * don't do anything with this packet. */ - if (tcp->th_sum != fr_tcpsum(*(mb_t **)fin->fin_mp, - ip, tcp, ip->ip_len)) { +#if SOLARIS && defined(_KERNEL) + sum = fr_tcpsum(fin->fin_qfm, ip, tcp); +#else + sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp); +#endif + if (sum != tcp->th_sum) { frstats[fin->fin_out].fr_tcpbad++; return -1; } - fr_tcp_age(&aps->aps_tout, aps->aps_state, ip, fin, - tcp->th_sport == aps->aps_sport); } apr = aps->aps_apr; err = 0; - if (fin->fin_out) { - if (apr->apr_outpkt) - err = (*apr->apr_outpkt)(fin, ip, tcp, - aps, nat); + if (fin->fin_out != 0) { + if (apr->apr_outpkt != NULL) + err = (*apr->apr_outpkt)(fin, ip, aps, nat); } else { - if (apr->apr_inpkt) - err = (*apr->apr_inpkt)(fin, ip, tcp, - aps, nat); + if (apr->apr_inpkt != NULL) + err = (*apr->apr_inpkt)(fin, ip, aps, nat); } - if (err == 2) { - tcp->th_sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, - tcp, ip->ip_len); - err = 0; + + rv = APR_EXIT(err); + if (rv == -1) + return rv; + + if (tcp != NULL) { + err = appr_fixseqack(fin, ip, aps, APR_INC(err)); +#if SOLARIS && defined(_KERNEL) + tcp->th_sum = fr_tcpsum(fin->fin_qfm, ip, tcp); +#else + tcp->th_sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp); +#endif } - return err; + aps->aps_bytes += ip->ip_len; + aps->aps_pkts++; + return 1; } - return -1; + return 0; } -aproxy_t *ap_match(pr, name) -u_char pr; +aproxy_t *appr_match(pr, name) +u_int pr; char *name; { aproxy_t *ap; @@ -284,11 +287,18 @@ char *name; ap->apr_ref++; return ap; } + + for (ap = ap_proxylist; ap; ap = ap->apr_next) + if ((ap->apr_p == pr) && + !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) { + ap->apr_ref++; + return ap; + } return NULL; } -void ap_free(ap) +void appr_free(ap) aproxy_t *ap; { ap->apr_ref--; @@ -298,38 +308,144 @@ aproxy_t *ap; void aps_free(aps) ap_session_t *aps; { - if (aps->aps_data && aps->aps_psiz) + ap_session_t *a, **ap; + + if (!aps) + return; + + for (ap = &ap_sess_list; (a = *ap); ap = &a->aps_next) + if (a == aps) { + *ap = a->aps_next; + break; + } + + if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) KFREES(aps->aps_data, aps->aps_psiz); KFREE(aps); } -void ap_unload() +static int appr_fixseqack(fin, ip, aps, inc) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +int inc; { - ap_session_t *aps; - int i; + int sel, ch = 0, out, nlen; + u_32_t seq1, seq2; + tcphdr_t *tcp; + + tcp = (tcphdr_t *)fin->fin_dp; + out = fin->fin_out; + nlen = ip->ip_len; + nlen -= (ip->ip_hl << 2) + (tcp->th_off << 2); + + if (out != 0) { + seq1 = (u_32_t)ntohl(tcp->th_seq); + sel = aps->aps_sel[out]; + + /* switch to other set ? */ + if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) && + (seq1 > aps->aps_seqmin[!sel])) + sel = aps->aps_sel[out] = !sel; + + if (aps->aps_seqoff[sel]) { + seq2 = aps->aps_seqmin[sel] - aps->aps_seqoff[sel]; + if (seq1 > seq2) { + seq2 = aps->aps_seqoff[sel]; + seq1 += seq2; + tcp->th_seq = htonl(seq1); + ch = 1; + } + } + + if (inc && (seq1 > aps->aps_seqmin[!sel])) { + aps->aps_seqmin[!sel] = seq1 + nlen - 1; + aps->aps_seqoff[!sel] = aps->aps_seqoff[sel] + inc; + } + + /***/ + + seq1 = ntohl(tcp->th_ack); + sel = aps->aps_sel[1 - out]; + + /* switch to other set ? */ + if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) && + (seq1 > aps->aps_ackmin[!sel])) + sel = aps->aps_sel[1 - out] = !sel; + + if (aps->aps_ackoff[sel] && (seq1 > aps->aps_ackmin[sel])) { + seq2 = aps->aps_ackoff[sel]; + tcp->th_ack = htonl(seq1 - seq2); + ch = 1; + } + } else { + seq1 = ntohl(tcp->th_seq); + sel = aps->aps_sel[out]; + + /* switch to other set ? */ + if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) && + (seq1 > aps->aps_ackmin[!sel])) + sel = aps->aps_sel[out] = !sel; + + if (aps->aps_ackoff[sel]) { + seq2 = aps->aps_ackmin[sel] - + aps->aps_ackoff[sel]; + if (seq1 > seq2) { + seq2 = aps->aps_ackoff[sel]; + seq1 += seq2; + tcp->th_seq = htonl(seq1); + ch = 1; + } + } + + if (inc && (seq1 > aps->aps_ackmin[!sel])) { + aps->aps_ackmin[!sel] = seq1 + nlen - 1; + aps->aps_ackoff[!sel] = aps->aps_ackoff[sel] + inc; + } + + /***/ + + seq1 = ntohl(tcp->th_ack); + sel = aps->aps_sel[1 - out]; - for (i = 0; i < AP_SESS_SIZE; i++) - while ((aps = ap_sess_tab[i])) { - ap_sess_tab[i] = aps->aps_next; - aps_free(aps); + /* switch to other set ? */ + if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) && + (seq1 > aps->aps_seqmin[!sel])) + sel = aps->aps_sel[1 - out] = !sel; + + if (aps->aps_seqoff[sel] && (seq1 > aps->aps_seqmin[sel])) { + seq2 = aps->aps_seqoff[sel]; + tcp->th_ack = htonl(seq1 - seq2); + ch = 1; } + } + return ch ? 2 : 0; } -void ap_expire() +int appr_init() { - ap_session_t *aps, **apsp; - int i; - - for (i = 0; i < AP_SESS_SIZE; i++) - for (apsp = &ap_sess_tab[i]; (aps = *apsp); ) { - aps->aps_tout--; - if (!aps->aps_tout) { - ap_sess_tab[i] = aps->aps_next; - aps_free(aps); - *apsp = aps->aps_next; - } else - apsp = &aps->aps_next; - } + aproxy_t *ap; + int err = 0; + + for (ap = ap_proxies; ap->apr_p; ap++) { + err = (*ap->apr_init)(); + if (err != 0) + break; + } + return err; +} + + +void appr_unload() +{ + aproxy_t *ap; + + for (ap = ap_proxies; ap->apr_p; ap++) + if (ap->apr_fini) + (*ap->apr_fini)(); + for (ap = ap_proxylist; ap; ap = ap->apr_next) + if (ap->apr_fini) + (*ap->apr_fini)(); } diff --git a/sys/contrib/ipfilter/netinet/ip_proxy.h b/sys/contrib/ipfilter/netinet/ip_proxy.h index a361e93..933d79d 100644 --- a/sys/contrib/ipfilter/netinet/ip_proxy.h +++ b/sys/contrib/ipfilter/netinet/ip_proxy.h @@ -1,11 +1,11 @@ /* - * Copyright (C) 1997 by Darren Reed. + * Copyright (C) 1997-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: ip_proxy.h,v 2.0.2.10.2.1 1997/11/27 09:33:27 darrenr Exp $ + * $Id: ip_proxy.h,v 2.8.2.3 2000/05/06 12:32:43 darrenr Exp $ */ #ifndef __IP_PROXY_H__ @@ -26,9 +26,11 @@ struct ipnat; typedef struct ap_tcp { u_short apt_sport; /* source port */ u_short apt_dport; /* destination port */ - short apt_sel; /* seqoff/after set selector */ + short apt_sel[2]; /* {seq,ack}{off,min} set selector */ short apt_seqoff[2]; /* sequence # difference */ - tcp_seq apt_after[2]; /* don't change seq-off until after this */ + tcp_seq apt_seqmin[2]; /* don't change seq-off until after this */ + short apt_ackoff[2]; /* sequence # difference */ + tcp_seq apt_ackmin[2]; /* don't change seq-off until after this */ u_char apt_state[2]; /* connection state */ } ap_tcp_t; @@ -39,55 +41,115 @@ 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_flags; - QUAD_T aps_bytes; /* bytes sent */ - QUAD_T aps_pkts; /* packets sent */ - u_long aps_tout; /* time left before expiring */ + 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; -} ap_session_t ; +} ap_session_t; #define aps_sport aps_un.apu_tcp.apt_sport #define aps_dport aps_un.apu_tcp.apt_dport #define aps_sel aps_un.apu_tcp.apt_sel #define aps_seqoff aps_un.apu_tcp.apt_seqoff -#define aps_after aps_un.apu_tcp.apt_after +#define aps_seqmin aps_un.apu_tcp.apt_seqmin #define aps_state aps_un.apu_tcp.apt_state +#define aps_ackoff aps_un.apu_tcp.apt_ackoff +#define aps_ackmin aps_un.apu_tcp.apt_ackmin typedef struct aproxy { + struct aproxy *apr_next; char apr_label[APR_LABELLEN]; /* Proxy label # */ u_char apr_p; /* protocol */ int apr_ref; /* +1 per rule referencing it */ int apr_flags; - int (* apr_init) __P((fr_info_t *, ip_t *, tcphdr_t *, + int (* apr_init) __P((void)); + void (* apr_fini) __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_inpkt) __P((fr_info_t *, ip_t *, tcphdr_t *, - ap_session_t *, struct nat *)); - int (* apr_outpkt) __P((fr_info_t *, ip_t *, tcphdr_t *, + int (* apr_outpkt) __P((fr_info_t *, ip_t *, ap_session_t *, struct nat *)); } aproxy_t; #define APR_DELETE 1 +#define APR_ERR(x) (((x) & 0xffff) << 16) +#define APR_EXIT(x) (((x) >> 16) & 0xffff) +#define APR_INC(x) ((x) & 0xffff) + +#define FTP_BUFSZ 160 +/* + * For the ftp proxy. + */ +typedef struct ftpside { + char *ftps_rptr; + char *ftps_wptr; + u_32_t ftps_seq; + int ftps_junk; + char ftps_buf[FTP_BUFSZ]; +} ftpside_t; + +typedef struct ftpinfo { + u_int ftp_passok; + ftpside_t ftp_side[2]; +} ftpinfo_t; + +/* + * 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 ippr_ftp_pasvonly; -extern int ap_ok __P((ip_t *, tcphdr_t *, struct ipnat *)); -extern void ap_unload __P((void)); -extern void ap_free __P((aproxy_t *)); +extern int appr_add __P((aproxy_t *)); +extern int appr_del __P((aproxy_t *)); +extern int appr_init __P((void)); +extern void appr_unload __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 *, tcphdr_t *, fr_info_t *, struct nat *)); -extern aproxy_t *ap_match __P((u_char, char *)); -extern void ap_expire __P((void)); +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/contrib/ipfilter/netinet/ip_raudio_pxy.c b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c index b76eea5..18ca474 100644 --- a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c @@ -1,6 +1,5 @@ /* - * $Id$ - * $FreeBSD$ + * $Id: ip_raudio_pxy.c,v 1.7.2.1 2000/05/06 11:19:33 darrenr Exp $ */ #if SOLARIS && defined(_KERNEL) extern kmutex_t ipf_rw; @@ -42,12 +41,13 @@ nat_t *nat; KMALLOCS(aps->aps_data, void *, sizeof(raudio_t)); - if (aps->aps_data != NULL) { - bzero(aps->aps_data, sizeof(raudio_t)); - rap = aps->aps_data; - aps->aps_psiz = sizeof(raudio_t); - rap->rap_mode = RAP_M_TCP; /* default is for TCP */ - } + if (aps->aps_data == NULL) + return -1; + + bzero(aps->aps_data, sizeof(raudio_t)); + rap = aps->aps_data; + aps->aps_psiz = sizeof(raudio_t); + rap->rap_mode = RAP_M_TCP; /* default is for TCP */ return 0; } @@ -59,15 +59,12 @@ ip_t *ip; ap_session_t *aps; nat_t *nat; { - char membuf[512 + 1], *s; - int off, dlen, inc = 0; - tcphdr_t *tcp, tcph, *tcp2 = &tcph; raudio_t *rap = aps->aps_data; - u_short sp, dp, id = 0; - struct in_addr swip; - fr_info_t fi; + unsigned char membuf[512 + 1], *s; + u_short id = 0; + tcphdr_t *tcp; + int off, dlen; int len = 0; - nat_t *ipn; mb_t *m; #if SOLARIS mb_t *m1; @@ -89,14 +86,14 @@ nat_t *nat; dlen = msgdsize(m) - off; if (dlen <= 0) return 0; - copyout_mblk(m, off, MIN(sizeof(membuf), dlen), membuf); + copyout_mblk(m, off, MIN(sizeof(membuf), dlen), (char *)membuf); #else m = *(mb_t **)fin->fin_mp; dlen = mbufchainlen(m) - off; if (dlen <= 0) return 0; - m_copydata(m, off, MIN(sizeof(membuf), dlen), membuf); + m_copydata(m, off, MIN(sizeof(membuf), dlen), (char *)membuf); #endif /* * In all the startup parsing, ensure that we don't go outside @@ -106,7 +103,7 @@ nat_t *nat; * Look for the start of connection "PNA" string if not seen yet. */ if (rap->rap_seenpna == 0) { - s = memstr("PNA", membuf, 3, dlen); + s = (u_char *)memstr("PNA", (char *)membuf, 3, dlen); if (s == NULL) return 0; s += 3; @@ -160,38 +157,7 @@ nat_t *nat; rap->rap_gotid = 0; } } - - /* - * Wait until we've seen the end of the start messages and even then - * only proceed further if we're using UDP. - */ - if ((rap->rap_eos == 0) || ((rap->rap_mode & RAP_M_UDP) != RAP_M_UDP)) - return 0; - sp = rap->rap_plport; - dp = 0; - - bcopy((char *)fin, (char *)&fi, sizeof(fi)); - bzero((char *)tcp2, sizeof(*tcp2)); - tcp2->th_sport = htons(sp); - tcp2->th_dport = 0; /* XXX - don't specify remote port */ - tcp2->th_win = htons(8192); - fi.fin_dp = (char *)tcp2; - fi.fin_data[0] = sp; - fi.fin_data[1] = 0; - fi.fin_fr = &raudiofr; - swip = ip->ip_src; - ip->ip_src = nat->nat_inip; - 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, FI_W_DPORT); - } - ip->ip_src = swip; - - if ((rap->rap_mode & RAP_M_UDP_ROBUST) == RAP_M_UDP_ROBUST) { - sp = rap->rap_prport; - } - return inc; + return 0; } @@ -201,19 +167,28 @@ ip_t *ip; ap_session_t *aps; nat_t *nat; { - char membuf[IPF_MAXPORTLEN + 1], *s; - int off, dlen; + unsigned char membuf[IPF_MAXPORTLEN + 1], *s; + tcphdr_t *tcp, tcph, *tcp2 = &tcph; raudio_t *rap = aps->aps_data; + struct in_addr swa, swb; u_int a1, a2, a3, a4; - tcphdr_t *tcp; + int off, dlen, slen; + u_short sp, dp; + fr_info_t fi; tcp_seq seq; + nat_t *ipn; + u_char swp; mb_t *m; #if SOLARIS mb_t *m1; #endif - if ((rap->rap_sdone != 0) || - ((rap->rap_mode & RAP_M_UDP_ROBUST) != RAP_M_UDP_ROBUST)) + /* + * Wait until we've seen the end of the start messages and even then + * only proceed further if we're using UDP. If they want to use TCP + * then data is sent back on the same channel that is already open. + */ + if (rap->rap_sdone != 0) return 0; tcp = (tcphdr_t *)fin->fin_dp; @@ -227,13 +202,13 @@ nat_t *nat; if (dlen <= 0) return 0; bzero(membuf, sizeof(membuf)); - copyout_mblk(m, off, MIN(sizeof(membuf), dlen), membuf); + copyout_mblk(m, off, MIN(sizeof(membuf), dlen), (char *)membuf); #else dlen = mbufchainlen(m) - off; if (dlen <= 0) return 0; bzero(membuf, sizeof(membuf)); - m_copydata(m, off, MIN(sizeof(membuf), dlen), membuf); + m_copydata(m, off, MIN(sizeof(membuf), dlen), (char *)membuf); #endif seq = ntohl(tcp->th_seq); @@ -242,7 +217,7 @@ nat_t *nat; * We only care for the first 19 bytes coming back from the server. */ if (rap->rap_sseq == 0) { - s = memstr("PNA", membuf, 3, dlen); + s = (u_char *)memstr("PNA", (char *)membuf, 3, dlen); if (s == NULL) return 0; a1 = s - membuf; @@ -262,13 +237,71 @@ nat_t *nat; } else return 0; - for (a3 = a1, a4 = a2; a4 > 0; a4--, a3++) { + for (a3 = a1, a4 = a2; (a4 > 0) && (a3 < 19) && (a3 >= 0); a4--,a3++) { rap->rap_sbf |= (1 << a3); rap->rap_svr[a3] = *s++; } - if (rap->rap_sbf == 0x7ffff) { /* 19 bits */ - s = rap->rap_svr + 13; + + if ((rap->rap_sbf != 0x7ffff) || (!rap->rap_eos)) /* 19 bits */ + return 0; + rap->rap_sdone = 1; + + s = (u_char *)rap->rap_svr + 11; + if (((*s << 8) | *(s + 1)) == RA_ID_ROBUST) { + s += 2; rap->rap_srport = (*s << 8) | *(s + 1); } + + swp = ip->ip_p; + swa = ip->ip_src; + swb = ip->ip_dst; + + ip->ip_p = IPPROTO_UDP; + ip->ip_src = nat->nat_inip; + ip->ip_dst = nat->nat_oip; + + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + bzero((char *)tcp2, sizeof(*tcp2)); + tcp2->th_off = 5; + fi.fin_dp = (char *)tcp2; + fi.fin_fr = &raudiofr; + tcp2->th_win = htons(8192); + slen = ip->ip_len; + ip->ip_len = fin->fin_hlen + sizeof(*tcp); + + if (((rap->rap_mode & RAP_M_UDP_ROBUST) == RAP_M_UDP_ROBUST) && + (rap->rap_srport != 0)) { + dp = rap->rap_srport; + sp = rap->rap_prport; + tcp2->th_sport = htons(sp); + tcp2->th_dport = htons(dp); + fi.fin_data[0] = dp; + fi.fin_data[1] = sp; + ipn = nat_new(nat->nat_ptr, ip, &fi, + IPN_UDP | (sp ? 0 : FI_W_SPORT), NAT_OUTBOUND); + if (ipn != NULL) { + ipn->nat_age = fr_defnatage; + (void) fr_addstate(ip, &fi, sp ? 0 : FI_W_SPORT); + } + } + + if ((rap->rap_mode & RAP_M_UDP) == RAP_M_UDP) { + sp = rap->rap_plport; + tcp2->th_sport = htons(sp); + tcp2->th_dport = 0; /* XXX - don't specify remote port */ + fi.fin_data[0] = sp; + fi.fin_data[1] = 0; + ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_UDP|FI_W_DPORT, + NAT_OUTBOUND); + if (ipn != NULL) { + ipn->nat_age = fr_defnatage; + (void) fr_addstate(ip, &fi, FI_W_DPORT); + } + } + + ip->ip_p = swp; + ip->ip_len = slen; + ip->ip_src = swa; + ip->ip_dst = swb; return 0; } diff --git a/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c b/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c index f9dc5b3..daea94f 100644 --- a/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c @@ -1,6 +1,5 @@ /* - * $Id$ - * $FreeBSD$ + * $Id: ip_rcmd_pxy.c,v 1.4.2.1 2000/05/06 11:19:34 darrenr Exp $ */ /* * Simple RCMD transparent proxy for in-kernel use. For use with the NAT @@ -127,11 +126,16 @@ nat_t *nat; ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_p, nat->nat_inip, ip->ip_dst, (dp << 16) | sp); if (ipn == NULL) { + int slen; + + slen = ip->ip_len; + ip->ip_len = fin->fin_hlen + sizeof(*tcp); bcopy((char *)fin, (char *)&fi, sizeof(fi)); bzero((char *)tcp2, sizeof(*tcp2)); tcp2->th_win = htons(8192); tcp2->th_sport = sp; tcp2->th_dport = 0; /* XXX - don't specify remote port */ + tcp2->th_off = 5; fi.fin_data[0] = ntohs(sp); fi.fin_data[1] = 0; fi.fin_dp = (char *)tcp2; @@ -144,6 +148,7 @@ nat_t *nat; fi.fin_fr = &rcmdfr; (void) fr_addstate(ip, &fi, FI_W_DPORT); } + ip->ip_len = slen; ip->ip_src = swip; } return 0; diff --git a/sys/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c index 89a2c3b..c9a28af 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.c +++ b/sys/contrib/ipfilter/netinet/ip_state.c @@ -1,16 +1,29 @@ /* - * Copyright (C) 1995-1997 by Darren Reed. + * Copyright (C) 1995-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. */ #if !defined(lint) -static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.0.2.24.2.14 1998/05/24 03:53:04 darrenr Exp $"; +static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.9 2000/05/22 10:26:15 darrenr Exp $"; #endif +#include +#include +#include +#include +#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ + defined(_KERNEL) +# include "opt_ipfilter_log.h" +#endif +#if defined(_KERNEL) && defined(__FreeBSD_version) && \ + (__FreeBSD_version >= 400000) && !defined(KLD_MODULE) +#include "opt_inet6.h" +#endif #if !defined(_KERNEL) && !defined(KERNEL) && !defined(__KERNEL__) +# include # include # include #else @@ -19,23 +32,22 @@ static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.0.2.24.2.14 1998/05/24 03:5 # include # endif #endif -#include -#include -#include -#include -#if defined(KERNEL) && (__FreeBSD_version >= 220000) +#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000) # include # include +# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM) +# include "opt_ipfilter.h" +# endif #else # include #endif #include #include #ifndef linux -#include +# include #endif #include -#if defined(_KERNEL) && !defined(linux) +#if (defined(_KERNEL) || defined(KERNEL)) && !defined(linux) # include #endif #if !defined(__SVR4) && !defined(__svr4__) @@ -45,14 +57,16 @@ static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.0.2.24.2.14 1998/05/24 03:5 #else # include # include -# include +# ifdef _KERNEL +# include +# endif # include # include #endif #include #ifdef sun -#include +# include #endif #include #include @@ -72,40 +86,92 @@ static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.0.2.24.2.14 1998/05/24 03:5 #include "netinet/ip_frag.h" #include "netinet/ip_proxy.h" #include "netinet/ip_state.h" +#ifdef USE_INET6 +#include +#endif +#if (__FreeBSD_version >= 300000) +# include +# if (defined(_KERNEL) || defined(KERNEL)) && !defined(IPFILTER_LKM) +# include +# include +# 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]; -int ips_num = 0; -ips_stat_t ips_stats; +static ipstate_t **ips_table = NULL; +static ipstate_t *ips_list = NULL; +static int ips_num = 0; +static ips_stat_t ips_stats; #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern kmutex_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)); +#ifdef USE_INET6 +static frentry_t *fr_checkicmp6matchingstate __P((ip6_t *, fr_info_t *)); +#endif +static int fr_matchsrcdst __P((ipstate_t *, union i6addr, union i6addr, + fr_info_t *, tcphdr_t *)); +static frentry_t *fr_checkicmpmatchingstate __P((ip_t *, fr_info_t *)); +static int fr_matchicmpqueryreply __P((int, ipstate_t *, icmphdr_t *)); static int fr_state_flush __P((int)); static ips_stat_t *fr_statetstats __P((void)); +static void fr_delstate __P((ipstate_t *)); +static int fr_state_remove __P((caddr_t)); +int fr_stputent __P((caddr_t)); +int fr_stgetent __P((caddr_t)); +void fr_stinsert __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, + fr_state_lock = 0; + +static int icmpreplytype4[ICMP_MAXTYPE + 1]; + +int fr_stateinit() +{ + int i; + + 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; + + /* fill icmp reply type table */ + for (i = 0; i <= ICMP_MAXTYPE; i++) + icmpreplytype4[i] = -1; + icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY; + icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY; + icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY; + icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY; + + return 0; +} static ips_stat_t *fr_statetstats() { ips_stats.iss_active = ips_num; ips_stats.iss_table = ips_table; + ips_stats.iss_list = ips_list; return &ips_stats; } @@ -119,7 +185,6 @@ static ips_stat_t *fr_statetstats() static int fr_state_flush(which) int which; { - register int i; register ipstate_t *is, **isp; #if defined(_KERNEL) && !SOLARIS int s; @@ -127,47 +192,69 @@ int which; int delete, removed = 0; SPL_NET(s); - MUTEX_ENTER(&ipf_state); - for (i = 0; i < IPSTATE_SIZE; i++) - for (isp = &ips_table[i]; (is = *isp); ) { - delete = 0; - - switch (which) - { - case 0 : - delete = 1; - break; - case 1 : - if ((is->is_p == IPPROTO_TCP) && - (((is->is_state[0] <= TCPS_ESTABLISHED) && - (is->is_state[1] > TCPS_ESTABLISHED)) || - ((is->is_state[1] <= TCPS_ESTABLISHED) && - (is->is_state[0] > TCPS_ESTABLISHED)))) - delete = 1; + for (isp = &ips_list; (is = *isp); ) { + delete = 0; + + switch (which) + { + case 0 : + delete = 1; + break; + case 1 : + if (is->is_p != IPPROTO_TCP) break; - } + if ((is->is_state[0] != TCPS_ESTABLISHED) || + (is->is_state[1] != TCPS_ESTABLISHED)) + delete = 1; + break; + } - if (delete) { - *isp = is->is_next; - if (is->is_p == IPPROTO_TCP) - ips_stats.iss_fin++; - else - ips_stats.iss_expire++; + if (delete) { + if (is->is_p == IPPROTO_TCP) + ips_stats.iss_fin++; + else + ips_stats.iss_expire++; #ifdef IPFILTER_LOG - ipstate_log(is, ISL_FLUSH); + ipstate_log(is, ISL_FLUSH); #endif - KFREE(is); - ips_num--; - removed++; - } else - isp = &is->is_next; - } - MUTEX_EXIT(&ipf_state); + fr_delstate(is); + removed++; + } else + isp = &is->is_next; + } SPL_X(s); return removed; } +static int fr_state_remove(data) +caddr_t data; +{ + ipstate_t *sp, st; + int error; + + sp = &st; + error = IRCOPYPTR(data, (caddr_t)&st, sizeof(st)); + if (error) + return EFAULT; + + for (sp = ips_list; sp; sp = sp->is_next) + if ((sp->is_p == st.is_p) && (sp->is_v == st.is_v) && + !bcmp(&sp->is_src, &st.is_src, sizeof(st.is_src)) && + !bcmp(&sp->is_dst, &st.is_src, sizeof(st.is_dst)) && + !bcmp(&sp->is_ps, &st.is_ps, sizeof(st.is_ps))) { + WRITE_ENTER(&ipf_state); +#ifdef IPFILTER_LOG + ipstate_log(sp, ISL_REMOVE); +#endif + fr_delstate(sp); + RWLOCK_EXIT(&ipf_state); + return 0; + } + return ESRCH; +} + + int fr_state_ioctl(data, cmd, mode) caddr_t data; #if defined(__NetBSD__) || defined(__OpenBSD__) @@ -177,175 +264,412 @@ int cmd; #endif int mode; { - int arg, ret, error = 0; + int arg, ret, error = 0; switch (cmd) { + case SIOCDELST : + error = fr_state_remove(data); + break; case SIOCIPFFL : - IRCOPY(data, (caddr_t)&arg, sizeof(arg)); + error = IRCOPY(data, (caddr_t)&arg, sizeof(arg)); + if (error) + break; if (arg == 0 || arg == 1) { + WRITE_ENTER(&ipf_state); ret = fr_state_flush(arg); - IWCOPY((caddr_t)&ret, data, sizeof(ret)); + RWLOCK_EXIT(&ipf_state); + error = IWCOPY((caddr_t)&ret, data, sizeof(ret)); } else error = EINVAL; break; - case SIOCGIPST : - IWCOPY((caddr_t)fr_statetstats(), data, sizeof(ips_stat_t)); +#ifdef IPFILTER_LOG + case SIOCIPFFB : + if (!(mode & FWRITE)) + error = EPERM; + else { + int tmp; + + tmp = ipflog_clear(IPL_LOGSTATE); + IWCOPY((char *)&tmp, data, sizeof(tmp)); + } + break; +#endif + case SIOCGETFS : + error = IWCOPYPTR((caddr_t)fr_statetstats(), data, + sizeof(ips_stat_t)); break; case FIONREAD : #ifdef IPFILTER_LOG - IWCOPY((caddr_t)&iplused[IPL_LOGSTATE], (caddr_t)data, - sizeof(iplused[IPL_LOGSTATE])); + error = IWCOPY((caddr_t)&iplused[IPL_LOGSTATE], (caddr_t)data, + sizeof(iplused[IPL_LOGSTATE])); #endif break; + case SIOCSTLCK : + error = fr_lock(data, &fr_state_lock); + break; + case SIOCSTPUT : + if (!fr_state_lock) { + error = EACCES; + break; + } + error = fr_stputent(data); + break; + case SIOCSTGET : + if (!fr_state_lock) { + error = EACCES; + break; + } + error = fr_stgetent(data); + break; default : - return EINVAL; + error = EINVAL; + break; } return error; } +int fr_stgetent(data) +caddr_t data; +{ + register ipstate_t *is, *isn; + ipstate_save_t ips, *ipsp; + int error; + + error = IRCOPY(data, (caddr_t)&ipsp, sizeof(ipsp)); + if (error) + return EFAULT; + error = IRCOPY((caddr_t)ipsp, (caddr_t)&ips, sizeof(ips)); + if (error) + return EFAULT; + + isn = ips.ips_next; + if (!isn) { + isn = ips_list; + if (isn == NULL) { + if (ips.ips_next == NULL) + return ENOENT; + return 0; + } + } else { + /* + * Make sure the pointer we're copying from exists in the + * current list of entries. Security precaution to prevent + * copying of random kernel data. + */ + for (is = ips_list; is; is = is->is_next) + if (is == isn) + break; + if (!is) + return ESRCH; + } + ips.ips_next = isn->is_next; + bcopy((char *)isn, (char *)&ips.ips_is, sizeof(ips.ips_is)); + if (isn->is_rule) + bcopy((char *)isn->is_rule, (char *)&ips.ips_fr, + sizeof(ips.ips_fr)); + error = IWCOPY((caddr_t)&ips, ipsp, sizeof(ips)); + if (error) + return EFAULT; + return 0; +} + + +int fr_stputent(data) +caddr_t data; +{ + register ipstate_t *is, *isn; + ipstate_save_t ips, *ipsp; + frentry_t *fr; + int error; + + error = IRCOPY(data, (caddr_t)&ipsp, sizeof(ipsp)); + if (error) + return EFAULT; + error = IRCOPY((caddr_t)ipsp, (caddr_t)&ips, sizeof(ips)); + if (error) + return EFAULT; + + KMALLOC(isn, ipstate_t *); + if (isn == NULL) + return ENOMEM; + + bcopy((char *)&ips.ips_is, (char *)isn, sizeof(*isn)); + fr = isn->is_rule; + if (fr != NULL) { + if (isn->is_flags & FI_NEWFR) { + KMALLOC(fr, frentry_t *); + if (fr == NULL) { + KFREE(isn); + return ENOMEM; + } + bcopy((char *)&ips.ips_fr, (char *)fr, sizeof(*fr)); + isn->is_rule = fr; + ips.ips_is.is_rule = fr; + error = IWCOPY((caddr_t)&ips, ipsp, sizeof(ips)); + if (error) { + KFREE(isn); + KFREE(fr); + return EFAULT; + } + } else { + for (is = ips_list; is; is = is->is_next) + if (is->is_rule == fr) + break; + if (!is) { + KFREE(isn); + return ESRCH; + } + } + } + fr_stinsert(isn); + return 0; +} + + +void fr_stinsert(is) +register ipstate_t *is; +{ + register u_int hv = is->is_hv; + + MUTEX_INIT(&is->is_lock, "ipf state entry", NULL); + + is->is_ifname[0][sizeof(is->is_ifname[0]) - 1] = '\0'; + if (is->is_ifname[0][0] != '\0') { + is->is_ifp[0] = GETUNIT(is->is_ifname[0], is->is_v); + } + is->is_ifname[1][sizeof(is->is_ifname[0]) - 1] = '\0'; + if (is->is_ifname[1][0] != '\0') { + is->is_ifp[1] = GETUNIT(is->is_ifname[1], is->is_v); + } + + /* + * add into list table. + */ + if (ips_list) + ips_list->is_pnext = &is->is_next; + is->is_pnext = &ips_list; + is->is_next = ips_list; + ips_list = is; + if (ips_table[hv]) + ips_table[hv]->is_phnext = &is->is_hnext; + else + ips_stats.iss_inuse++; + is->is_phnext = ips_table + hv; + is->is_hnext = ips_table[hv]; + ips_table[hv] = is; +} + + /* * 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 tcphdr_t *tcp = NULL; + register ipstate_t *is; register u_int hv; + ipstate_t ips; + u_int pass; + int out; - if ((ip->ip_off & 0x1fff) || (fin->fin_fi.fi_fl & FI_SHORT)) - return -1; - if (ips_num == IPSTATE_MAX) { + if (fr_state_lock || (fin->fin_off & IP_OFFMASK) || + (fin->fin_fi.fi_fl & FI_SHORT)) + return NULL; + if (ips_num == fr_statemax) { ips_stats.iss_max++; - return -1; + fr_state_doflush = 1; + return NULL; } + out = fin->fin_out; + is = &ips; + bzero((char *)is, sizeof(*is)); ips.is_age = 1; ips.is_state[0] = 0; ips.is_state[1] = 0; /* * Copy and calculate... */ - hv = (is->is_p = ip->ip_p); - hv += (is->is_src.s_addr = ip->ip_src.s_addr); - hv += (is->is_dst.s_addr = ip->ip_dst.s_addr); + hv = (is->is_p = fin->fin_fi.fi_p); + is->is_src = fin->fin_fi.fi_src; + hv += is->is_saddr; + is->is_dst = fin->fin_fi.fi_dst; + hv += is->is_daddr; +#ifdef USE_INET6 + if (fin->fin_v == 6) { + if (is->is_p == IPPROTO_ICMPV6) { + if (IN6_IS_ADDR_MULTICAST(&is->is_dst.in6)) + flags |= FI_W_DADDR; + if (out) + hv -= is->is_daddr; + else + hv -= is->is_saddr; + } + } +#endif - switch (ip->ip_p) + switch (is->is_p) { +#ifdef USE_INET6 + case IPPROTO_ICMPV6 : +#endif case IPPROTO_ICMP : { struct icmp *ic = (struct icmp *)fin->fin_dp; +#ifdef USE_INET6 + if ((is->is_p == IPPROTO_ICMPV6) && + ((ic->icmp_type & ICMP6_INFOMSG_MASK) == 0)) + return NULL; +#endif switch (ic->icmp_type) { - case ICMP_ECHO : - is->is_icmp.ics_type = ICMP_ECHOREPLY; /* XXX */ +#ifdef USE_INET6 + case ICMP6_ECHO_REQUEST : + is->is_icmp.ics_type = ICMP6_ECHO_REPLY; hv += (is->is_icmp.ics_id = ic->icmp_id); hv += (is->is_icmp.ics_seq = ic->icmp_seq); break; + case ICMP6_MEMBERSHIP_QUERY : + case ND_ROUTER_SOLICIT : + case ND_NEIGHBOR_SOLICIT : + is->is_icmp.ics_type = ic->icmp_type + 1; + break; + break; +#endif + case ICMP_ECHO : case ICMP_TSTAMP : case ICMP_IREQ : case ICMP_MASKREQ : - is->is_icmp.ics_type = ic->icmp_type + 1; + is->is_icmp.ics_type = ic->icmp_type; + hv += (is->is_icmp.ics_id = ic->icmp_id); + hv += (is->is_icmp.ics_seq = ic->icmp_seq); break; default : - return -1; + return NULL; } - ips_stats.iss_icmp++; + ATOMIC_INCL(ips_stats.iss_icmp); is->is_age = fr_icmptimeout; break; } case IPPROTO_TCP : { - register tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; + tcp = (tcphdr_t *)fin->fin_dp; + if (tcp->th_flags & TH_RST) + return NULL; /* * 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 */ - ips_stats.iss_tcp++; + 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; + } + 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; + is->is_dend = 0; + is->is_maxdwin = 1; + 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 */ - fr_tcp_age(&is->is_age, is->is_state, ip, fin, - tcp->th_sport == is->is_sport); + ATOMIC_INCL(ips_stats.iss_tcp); break; } case IPPROTO_UDP : { - register tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; + tcp = (tcphdr_t *)fin->fin_dp; - hv += (is->is_dport = tcp->th_dport); - hv += (is->is_sport = tcp->th_sport); - ips_stats.iss_udp++; + 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_INCL(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) { - ips_stats.iss_nomem++; - return -1; + ATOMIC_INCL(ips_stats.iss_nomem); + return NULL; } bcopy((char *)&ips, (char *)is, sizeof(*is)); - hv %= IPSTATE_SIZE; - MUTEX_ENTER(&ipf_state); + hv %= fr_statesize; + is->is_hv = hv; + is->is_rule = fin->fin_fr; + if (is->is_rule != NULL) { + ATOMIC_INC32(is->is_rule->fr_ref); + pass = is->is_rule->fr_flags; + } else + pass = fr_flags; + WRITE_ENTER(&ipf_state); is->is_pass = pass; is->is_pkts = 1; - is->is_bytes = ip->ip_len; - /* - * Copy these from the rule itself. - */ - is->is_opt = fin->fin_fr->fr_ip.fi_optmsk; - is->is_optmsk = fin->fin_fr->fr_mip.fi_optmsk; - is->is_sec = fin->fin_fr->fr_ip.fi_secmsk; - is->is_secmsk = fin->fin_fr->fr_mip.fi_secmsk; - is->is_auth = fin->fin_fr->fr_ip.fi_auth; - is->is_authmsk = fin->fin_fr->fr_mip.fi_auth; - is->is_flags = fin->fin_fr->fr_ip.fi_fl; - is->is_flags |= fin->fin_fr->fr_mip.fi_fl << 4; + is->is_bytes = fin->fin_dlen + fin->fin_hlen; /* - * add into table. + * We want to check everything that is a property of this packet, + * but we don't (automatically) care about it's fragment status as + * this may change. */ - is->is_next = ips_table[hv]; - ips_table[hv] = is; - if (fin->fin_out) { - is->is_ifpin = NULL; - is->is_ifpout = fin->fin_ifp; - } else { - is->is_ifpin = fin->fin_ifp; - is->is_ifpout = NULL; - } + is->is_v = fin->fin_fi.fi_v; + is->is_opt = fin->fin_fi.fi_optmsk; + is->is_optmsk = 0xffffffff; + is->is_sec = fin->fin_fi.fi_secmsk; + is->is_secmsk = 0xffff; + is->is_auth = fin->fin_fi.fi_auth; + is->is_authmsk = 0xffff; + is->is_flags = fin->fin_fi.fi_fl & FI_CMP; + is->is_flags |= FI_CMP << 4; + is->is_flags |= flags & (FI_WILDP|FI_WILDA); + is->is_ifp[1 - out] = NULL; + is->is_ifp[out] = fin->fin_ifp; +#ifdef _KERNEL + strncpy(is->is_ifname[out], IFNAME(fin->fin_ifp), IFNAMSIZ); +#endif + is->is_ifname[1 - out][0] = '\0'; if (pass & FR_LOGFIRST) is->is_pass &= ~(FR_LOGFIRST|FR_LOG); + fr_stinsert(is); ips_num++; + if (is->is_p == IPPROTO_TCP) { + MUTEX_ENTER(&is->is_lock); + fr_tcp_age(&is->is_age, is->is_state, fin, + tcp->th_sport == is->is_sport); + MUTEX_EXIT(&is->is_lock); + } #ifdef IPFILTER_LOG ipstate_log(is, ISL_NEW); #endif - MUTEX_EXIT(&ipf_state); + RWLOCK_EXIT(&ipf_state); + fin->fin_rev = IP6NEQ(is->is_dst, fin->fin_fi.fi_dst); 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 @@ -357,263 +681,633 @@ fr_info_t *fin; ip_t *ip; tcphdr_t *tcp; { - register int seqskew, ackskew; - register u_short swin, dwin; - register tcp_seq seq, ack; + 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 = IP6EQ(fin->fin_fi.fi_src, is->is_src); + 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 + fin->fin_dlen - (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 - 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 - 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 the difference in sequence and ack numbers is within the - * window size of the connection, store these values and match - * the packet. - */ - if (source) { - swin = is->is_swin; - dwin = is->is_dwin; - } else { - dwin = is->is_swin; - swin = is->is_dwin; + if (!(tcp->th_flags & TH_ACK)) { /* Pretend an ack was sent */ + ack = tdata->td_end; + } 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 ((seqskew <= dwin) && (ackskew <= swin)) { - if (source) { - is->is_seq = seq; - is->is_ack = ack; - is->is_swin = ntohs(tcp->th_win); - } else { - is->is_seq = ack; - is->is_ack = seq; - is->is_dwin = ntohs(tcp->th_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, 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++; } - ips_stats.iss_hits++; + + ATOMIC_INCL(ips_stats.iss_hits); is->is_pkts++; - is->is_bytes += ip->ip_len; + is->is_bytes += fin->fin_dlen + fin->fin_hlen; /* * Nearing end of connection, start timeout. */ - fr_tcp_age(&is->is_age, is->is_state, ip, fin, source); - return 1; + MUTEX_ENTER(&is->is_lock); + fr_tcp_age(&is->is_age, is->is_state, fin, source); + MUTEX_EXIT(&is->is_lock); + 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; +union i6addr 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 = IP6NEQ(is->is_dst, dst); 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 = is->is_flags & FI_WILDA; + sp = 0; + dp = 0; + } + + if (rev == 0) { + if (!out) { + if (is->is_ifpin == NULL || 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 == NULL || 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 (!rev) { - if (((out && is->is_ifpout == ifp) || - (!out && is->is_ifpin == ifp)) && - (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))) { + if (ret == 0) + return 0; + ret = 0; + + if (rev == 0) { + if ( + (IP6EQ(is->is_dst, dst) || (flags & FI_W_DADDR)) && + (IP6EQ(is->is_src, src) || (flags & FI_W_SADDR)) && + (!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) && - (is->is_src.s_addr == dst.s_addr) && - (!tcp || (sp == is->is_dport) && - (dp == is->is_sport))) { + if ( + (IP6EQ(is->is_dst, src) || (flags & FI_W_DADDR)) && + (IP6EQ(is->is_src, dst) || (flags & FI_W_SADDR)) && + (!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 >> 4)) != - (is->is_flags & 0xf))) - 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; + + ret = -1; + + if (!rev) { + if (out) { + if (!is->is_ifpout) + ret = 1; + } else { + if (!is->is_ifpin) + ret = 0; + } + } else { + if (out) { + if (!is->is_ifpin) + ret = 0; + } else { + if (!is->is_ifpout) + ret = 1; + } + } + + if (ret >= 0) { + is->is_ifp[ret] = ifp; +#ifdef _KERNEL + strncpy(is->is_ifname[out], IFNAME(fin->fin_ifp), + sizeof(is->is_ifname[1])); +#endif + } +#ifdef _KERNEL + if (ret >= 0) { + strncpy(is->is_ifname[out], IFNAME(fin->fin_ifp), + sizeof(is->is_ifname[1])); + } +#endif + return 1; } +static int fr_matchicmpqueryreply(v, is, icmp) +int v; +ipstate_t *is; +icmphdr_t *icmp; +{ + if (v == 4) { + /* + * If we matched its type on the way in, then when going out + * it will still be the same type. + */ + if (((icmp->icmp_type == is->is_type) || + (icmpreplytype4[is->is_type] == icmp->icmp_type)) && + (icmp->icmp_id == is->is_icmp.ics_id) && + (icmp->icmp_seq == is->is_icmp.ics_seq)) { + return 1; + }; + } +#ifdef USE_INET6 + else if (is->is_v == 6) { + if ((is->is_type == ICMP6_ECHO_REPLY) && + (icmp->icmp_type == ICMP6_ECHO_REQUEST) && + (icmp->icmp_id == is->is_icmp.ics_id) && + (icmp->icmp_seq == is->is_icmp.ics_seq)) { + return 1; + }; + } +#endif + return 0; +} + +static frentry_t *fr_checkicmpmatchingstate(ip, fin) +ip_t *ip; +fr_info_t *fin; +{ + register ipstate_t *is, **isp; + register u_short sport, dport; + register u_char pr; + union i6addr dst, src; + struct icmp *ic; + u_short savelen; + fr_info_t ofin; + tcphdr_t *tcp; + icmphdr_t *icmp; + frentry_t *fr; + ip_t *oip; + int type; + u_int hv; + + /* + * 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_v != 4) && (ip->ip_hl != 5)) || + (fin->fin_plen < ICMPERR_MINPKTLEN)) + return NULL; + ic = (struct icmp *)fin->fin_dp; + 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 *)ic + ICMPERR_ICMPHLEN); + if (fin->fin_plen < 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); + src.in4 = oip->ip_src; + hv += src.in4.s_addr; + dst.in4 = oip->ip_dst; + hv += dst.in4.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_hnext) + if ((is->is_p == pr) && (is->is_v == 4) && + fr_matchsrcdst(is, src, dst, &ofin, NULL) && + fr_matchicmpqueryreply(is->is_v, is, icmp)) { + ips_stats.iss_hits++; + is->is_pkts++; + is->is_bytes += ip->ip_len; + fr = is->is_rule; + RWLOCK_EXIT(&ipf_state); + return fr; + } + 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); + src.in4 = oip->ip_src; + hv += src.in4.s_addr; + dst.in4 = oip->ip_dst; + hv += dst.in4.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_hnext) { + /* + * 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) && (is->is_v == 4) && + 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 + */ + is->is_pkts++; + is->is_bytes += fin->fin_plen; + /* + * 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; + union i6addr dst, src; register ipstate_t *is, **isp; register u_char pr; + u_int hv, hvm, hlen, tryagain, pass, v; struct icmp *ic; + frentry_t *fr; tcphdr_t *tcp; - u_int hv, hlen, pass; - if ((ip->ip_off & 0x1fff) || (fin->fin_fi.fi_fl & FI_SHORT)) - return 0; + if (fr_state_lock || (fin->fin_off & IP_OFFMASK) || + (fin->fin_fi.fi_fl & FI_SHORT)) + return NULL; + is = NULL; hlen = fin->fin_hlen; tcp = (tcphdr_t *)((char *)ip + hlen); ic = (struct icmp *)tcp; - hv = (pr = ip->ip_p); - hv += (src.s_addr = ip->ip_src.s_addr); - hv += (dst.s_addr = ip->ip_dst.s_addr); + hv = (pr = fin->fin_fi.fi_p); + src = fin->fin_fi.fi_src; + dst = fin->fin_fi.fi_dst; + hv += src.in4.s_addr; + hv += dst.in4.s_addr; /* * Search the hash table for matching packet header info. */ - switch (ip->ip_p) + v = fin->fin_fi.fi_v; + switch (fin->fin_fi.fi_p) { +#ifdef USE_INET6 + case IPPROTO_ICMPV6 : + if (v == 6) { + if (fin->fin_out) + hv -= dst.in4.s_addr; + else + hv -= src.in4.s_addr; + if ((ic->icmp_type == ICMP6_ECHO_REQUEST) || + (ic->icmp_type == ICMP6_ECHO_REPLY)) { + hv += ic->icmp_id; + hv += ic->icmp_seq; + } + } +#endif case IPPROTO_ICMP : - hv += ic->icmp_id; - hv += ic->icmp_seq; - hv %= IPSTATE_SIZE; - MUTEX_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) - continue; + if (v == 4) { + hv += ic->icmp_id; + hv += ic->icmp_seq; + } + hv %= fr_statesize; + READ_ENTER(&ipf_state); + for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) { + if ((is->is_p == pr) && (is->is_v == v) && + fr_matchsrcdst(is, src, dst, fin, NULL) && + fr_matchicmpqueryreply(v, is, ic)) { is->is_age = fr_icmptimeout; - is->is_pkts++; - is->is_bytes += ip->ip_len; - ips_stats.iss_hits++; - pass = is->is_pass; - MUTEX_EXIT(&ipf_state); - return pass; + break; } - MUTEX_EXIT(&ipf_state); + } + if (is != NULL) + break; + RWLOCK_EXIT(&ipf_state); + /* + * No matching icmp state entry. Perhaps this is a + * response to another state entry. + */ +#ifdef USE_INET6 + if (v == 6) + fr = fr_checkicmp6matchingstate((ip6_t *)ip, fin); + else +#endif + 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; - MUTEX_ENTER(&ipf_state); - for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_next) - if ((is->is_p == pr) && - fr_matchsrcdst(is, src, dst, fin, tcp, - sport, dport)) { - if (fr_tcpstate(is, fin, ip, tcp)) { - pass = is->is_pass; -#ifdef _KERNEL - MUTEX_EXIT(&ipf_state); -#else + tryagain = 0; +retry_tcp: + hvm = hv % fr_statesize; + WRITE_ENTER(&ipf_state); + for (isp = &ips_table[hvm]; (is = *isp); + isp = &is->is_hnext) - if (tcp->th_flags & TCP_CLOSE) { - *isp = is->is_next; - isp = &ips_table[hv]; - KFREE(is); - } -#endif - return pass; - } + + if ((is->is_p == pr) && (is->is_v == v) && + fr_matchsrcdst(is, src, dst, fin, tcp)) { + if (fr_tcpstate(is, fin, ip, tcp)) + break; + is = NULL; + break; } - MUTEX_EXIT(&ipf_state); + 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 */ - MUTEX_ENTER(&ipf_state); - for (is = ips_table[hv]; is; is = is->is_next) - if ((is->is_p == pr) && - fr_matchsrcdst(is, src, dst, fin, - tcp, sport, dport)) { - ips_stats.iss_hits++; - is->is_pkts++; - is->is_bytes += ip->ip_len; + READ_ENTER(&ipf_state); + for (is = ips_table[hvm]; is; is = is->is_hnext) + if ((is->is_p == pr) && (is->is_v == v) && + fr_matchsrcdst(is, src, dst, fin, tcp)) { is->is_age = fr_udptimeout; - pass = is->is_pass; - MUTEX_EXIT(&ipf_state); - return pass; + break; } - MUTEX_EXIT(&ipf_state); + if (is != NULL) + break; + RWLOCK_EXIT(&ipf_state); + hv += dport; + hv += sport; + if (tryagain == 0) { + tryagain = 1; + goto retry_udp; + } break; } default : break; } - ips_stats.iss_miss++; - return 0; + if (is == NULL) { + ATOMIC_INCL(ips_stats.iss_miss); + return NULL; + } + MUTEX_ENTER(&is->is_lock); + is->is_bytes += fin->fin_plen; + ips_stats.iss_hits++; + is->is_pkts++; + MUTEX_EXIT(&is->is_lock); + fr = is->is_rule; + fin->fin_fr = fr; + pass = is->is_pass; +#ifndef _KERNEL + if (tcp->th_flags & TCP_CLOSE) + fr_delstate(is); +#endif + RWLOCK_EXIT(&ipf_state); + if (fin->fin_fi.fi_fl & FI_FRAG) + ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE); + return fr; +} + + +void ip_statesync(ifp) +void *ifp; +{ + register ipstate_t *is; + + WRITE_ENTER(&ipf_state); + for (is = ips_list; is; is = is->is_next) { + if (is->is_ifpin == ifp) { + is->is_ifpin = GETUNIT(is->is_ifname[0], is->is_v); + if (!is->is_ifpin) + is->is_ifpin = (void *)-1; + } + if (is->is_ifpout == ifp) { + is->is_ifpout = GETUNIT(is->is_ifname[1], is->is_v); + if (!is->is_ifpout) + is->is_ifpout = (void *)-1; + } + } + RWLOCK_EXIT(&ipf_state); +} + + +static void fr_delstate(is) +ipstate_t *is; +{ + frentry_t *fr; + + if (is->is_next) + is->is_next->is_pnext = is->is_pnext; + *is->is_pnext = is->is_next; + if (is->is_hnext) + is->is_hnext->is_phnext = is->is_phnext; + *is->is_phnext = is->is_hnext; + if (ips_table[is->is_hv] == NULL) + ips_stats.iss_inuse--; + + fr = is->is_rule; + if (fr != NULL) { + ATOMIC_DEC32(fr->fr_ref); + if (fr->fr_ref == 0) + KFREE(fr); + } +#ifdef _KERNEL + MUTEX_DESTROY(&is->is_lock); +#endif + KFREE(is); + ips_num--; } @@ -622,16 +1316,16 @@ fr_info_t *fin; */ void fr_stateunload() { - register int i; - register ipstate_t *is, **isp; - - MUTEX_ENTER(&ipf_state); - for (i = 0; i < IPSTATE_SIZE; i++) - for (isp = &ips_table[i]; (is = *isp); ) { - *isp = is->is_next; - KFREE(is); - } - MUTEX_EXIT(&ipf_state); + register ipstate_t *is; + + WRITE_ENTER(&ipf_state); + while ((is = ips_list)) + fr_delstate(is); + ips_stats.iss_inuse = 0; + ips_num = 0; + RWLOCK_EXIT(&ipf_state); + KFREES(ips_table, fr_statesize * sizeof(ipstate_t *)); + ips_table = NULL; } @@ -641,31 +1335,31 @@ void fr_stateunload() */ void fr_timeoutstate() { - register int i; register ipstate_t *is, **isp; #if defined(_KERNEL) && !SOLARIS int s; #endif SPL_NET(s); - MUTEX_ENTER(&ipf_state); - for (i = 0; i < IPSTATE_SIZE; i++) - for (isp = &ips_table[i]; (is = *isp); ) - if (is->is_age && !--is->is_age) { - *isp = is->is_next; - if (is->is_p == IPPROTO_TCP) - ips_stats.iss_fin++; - else - ips_stats.iss_expire++; + WRITE_ENTER(&ipf_state); + for (isp = &ips_list; (is = *isp); ) + if (is->is_age && !--is->is_age) { + if (is->is_p == IPPROTO_TCP) + ips_stats.iss_fin++; + else + ips_stats.iss_expire++; #ifdef IPFILTER_LOG - ipstate_log(is, ISL_EXPIRE); + ipstate_log(is, ISL_EXPIRE); #endif - KFREE(is); - ips_num--; - } else - isp = &is->is_next; - MUTEX_EXIT(&ipf_state); + fr_delstate(is); + } else + isp = &is->is_next; + RWLOCK_EXIT(&ipf_state); SPL_X(s); + if (fr_state_doflush) { + (void) fr_state_flush(1); + fr_state_doflush = 0; + } } @@ -673,10 +1367,9 @@ void fr_timeoutstate() * Original idea freom Pradeep Krishnan for use primarily with NAT code. * (pkrishna@netcom.com) */ -void fr_tcp_age(age, state, ip, fin, dir) +void fr_tcp_age(age, state, fin, dir) u_long *age; u_char *state; -ip_t *ip; fr_info_t *fin; int dir; { @@ -686,7 +1379,7 @@ int dir; ostate = state[1 - dir]; - dlen = ip->ip_len - fin->fin_hlen - (tcp->th_off << 2); + dlen = fin->fin_plen - fin->fin_hlen - (tcp->th_off << 2); if (flags & TH_RST) { if (!(tcp->th_flags & TH_PUSH) && !dlen) { @@ -703,23 +1396,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: @@ -730,8 +1429,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 && @@ -760,23 +1461,28 @@ 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]; size_t sizes[1]; int types[1]; + ipsl.isl_type = type; ipsl.isl_pkts = is->is_pkts; ipsl.isl_bytes = is->is_bytes; ipsl.isl_src = is->is_src; ipsl.isl_dst = is->is_dst; ipsl.isl_p = is->is_p; + ipsl.isl_v = is->is_v; ipsl.isl_flags = is->is_flags; - ipsl.isl_type = type; if (ipsl.isl_p == IPPROTO_TCP || ipsl.isl_p == IPPROTO_UDP) { ipsl.isl_sport = is->is_sport; ipsl.isl_dport = is->is_dport; + if (ipsl.isl_p == IPPROTO_TCP) { + ipsl.isl_state[0] = is->is_state[0]; + ipsl.isl_state[1] = is->is_state[1]; + } } else if (ipsl.isl_p == IPPROTO_ICMP) ipsl.isl_itype = is->is_icmp.ics_type; else { @@ -787,6 +1493,166 @@ 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 + + +#ifdef USE_INET6 +frentry_t *fr_checkicmp6matchingstate(ip, fin) +ip6_t *ip; +fr_info_t *fin; +{ + register ipstate_t *is, **isp; + register u_short sport, dport; + register u_char pr; + struct icmp6_hdr *ic, *oic; + union i6addr dst, src; + u_short savelen; + fr_info_t ofin; + tcphdr_t *tcp; + frentry_t *fr; + ip6_t *oip; + int type; + u_int hv; + + /* + * 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 ((fin->fin_v != 6) || (fin->fin_plen < ICMP6ERR_MINPKTLEN)) + return NULL; + ic = (struct icmp6_hdr *)fin->fin_dp; + type = ic->icmp6_type; + /* + * If it's not an error type, then return + */ + if ((type != ICMP6_DST_UNREACH) && (type != ICMP6_PACKET_TOO_BIG) && + (type != ICMP6_TIME_EXCEEDED) && (type != ICMP6_PARAM_PROB)) + return NULL; + + oip = (ip6_t *)((char *)ic + ICMPERR_ICMPHLEN); + if (fin->fin_plen < sizeof(*oip)) + return NULL; + + if (oip->ip6_nxt == IPPROTO_ICMPV6) { + oic = (struct icmp6_hdr *)(oip + 1); + /* + * 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 (!(oic->icmp6_type & ICMP6_INFOMSG_MASK)) + return NULL; + + /* + * perform a lookup of the ICMP packet in the state table + */ + hv = (pr = oip->ip6_nxt); + src.in6 = oip->ip6_src; + hv += src.in4.s_addr; + dst.in6 = oip->ip6_dst; + hv += dst.in4.s_addr; + hv += oic->icmp6_id; + hv += oic->icmp6_seq; + hv %= fr_statesize; + + oip->ip6_plen = ntohs(oip->ip6_plen); + fr_makefrip(sizeof(*oip), (ip_t *)oip, &ofin); + oip->ip6_plen = htons(oip->ip6_plen); + 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_hnext) + if ((is->is_p == pr) && + (oic->icmp6_id == is->is_icmp.ics_id) && + (oic->icmp6_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 == ICMP6_ECHO_REPLY) && + (oic->icmp6_type == ICMP6_ECHO_REQUEST)) || + (is->is_type - 1 == oic->icmp6_type )) { + ips_stats.iss_hits++; + is->is_pkts++; + is->is_bytes += fin->fin_plen; + return is->is_rule; + } + } + RWLOCK_EXIT(&ipf_state); + + return NULL; + }; + + if ((oip->ip6_nxt != IPPROTO_TCP) && (oip->ip6_nxt != IPPROTO_UDP)) + return NULL; + tcp = (tcphdr_t *)(oip + 1); + dport = tcp->th_dport; + sport = tcp->th_sport; + + hv = (pr = oip->ip6_nxt); + src.in6 = oip->ip6_src; + hv += src.in4.s_addr; + dst.in6 = oip->ip6_dst; + hv += dst.in4.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->ip6_plen; + oip->ip6_plen = ip->ip6_plen - sizeof(*ip) - ICMPERR_ICMPHLEN; + ofin.fin_v = 6; + fr_makefrip(sizeof(*oip), (ip_t *)oip, &ofin); + oip->ip6_plen = 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_hnext) { + /* + * 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) && (is->is_v == 6) && + 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 + */ + is->is_pkts++; + is->is_bytes += fin->fin_plen; + /* + * 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; } #endif diff --git a/sys/contrib/ipfilter/netinet/ip_state.h b/sys/contrib/ipfilter/netinet/ip_state.h index f2ae94b..01c26a0 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.h +++ b/sys/contrib/ipfilter/netinet/ip_state.h @@ -1,16 +1,22 @@ /* - * Copyright (C) 1995-1997 by Darren Reed. + * Copyright (C) 1995-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * * @(#)ip_state.h 1.3 1/12/96 (C) 1995 Darren Reed - * $Id: ip_state.h,v 2.0.2.14.2.6 1998/05/24 05:18:04 darrenr Exp $ + * $Id: ip_state.h,v 2.13 2000/03/13 22:10:23 darrenr Exp $ */ #ifndef __IP_STATE_H__ #define __IP_STATE_H__ +#if defined(__STDC__) || defined(__GNUC__) +# define SIOCDELST _IOW('r', 61, struct ipstate *) +#else +# define SIOCDELST _IOW(r, 61, struct ipstate *) +#endif + #define IPSTATE_SIZE 257 #define IPSTATE_MAX 2048 /* Maximum number of states held */ @@ -31,68 +37,106 @@ 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; typedef struct ipstate { struct ipstate *is_next; + struct ipstate **is_pnext; + struct ipstate *is_hnext; + struct ipstate **is_phnext; u_long is_age; u_int is_pass; U_QUAD_T is_pkts; U_QUAD_T is_bytes; - void *is_ifpin; - void *is_ifpout; - 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; + void *is_ifp[2]; + frentry_t *is_rule; + union i6addr is_src; + union i6addr is_dst; + u_char is_p; /* Protocol */ + u_char is_v; + u_int is_hv; + 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; udpstate_t is_us; } is_ps; + char is_ifname[2][IFNAMSIZ]; +#if SOLARIS || defined(__sgi) + kmutex_t is_lock; +#endif } ipstate_t; -#define is_icmp is_ps.is_ics -#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_saddr is_src.in4.s_addr +#define is_daddr is_dst.in4.s_addr +#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_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 is_ifpin is_ifp[0] +#define is_ifpout is_ifp[1] #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 ipstate_save { + void *ips_next; + struct ipstate ips_is; + struct frentry ips_fr; +} ipstate_save_t; + +#define ips_rule ips_is.is_rule typedef struct ipslog { U_QUAD_T isl_pkts; U_QUAD_T isl_bytes; - struct in_addr isl_src; - struct in_addr isl_dst; - u_char isl_p; - u_char isl_flags; + union i6addr isl_src; + union i6addr isl_dst; u_short isl_type; union { u_short isl_filler[2]; u_short isl_ports[2]; u_short isl_icmp; } isl_ps; + u_char isl_v; + u_char isl_p; + u_char isl_flags; + u_char isl_state[2]; } ipslog_t; #define isl_sport isl_ps.isl_ports[0] @@ -102,6 +146,7 @@ typedef struct ipslog { #define ISL_NEW 0 #define ISL_EXPIRE 0xffff #define ISL_FLUSH 0xfffe +#define ISL_REMOVE 0xfffd typedef struct ips_stat { @@ -117,7 +162,9 @@ typedef struct ips_stat { u_long iss_active; u_long iss_logged; u_long iss_logfail; + u_long iss_inuse; ipstate_t **iss_table; + ipstate_t *iss_list; } ips_stat_t; @@ -128,13 +175,16 @@ extern u_long fr_tcptimeout; extern u_long fr_tcpclosed; extern u_long fr_udptimeout; extern u_long fr_icmptimeout; +extern int fr_state_lock; +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 ip_statesync __P((void *)); 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_tcp_age __P((u_long *, u_char *, 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 diff --git a/sys/contrib/ipfilter/netinet/ipl.h b/sys/contrib/ipfilter/netinet/ipl.h index d92ec79..12d866c 100644 --- a/sys/contrib/ipfilter/netinet/ipl.h +++ b/sys/contrib/ipfilter/netinet/ipl.h @@ -1,16 +1,17 @@ /* - * Copyright (C) 1993-1997 by Darren Reed. + * Copyright (C) 1993-2000 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given * to the original author and the contributors. * * @(#)ipl.h 1.21 6/5/96 + * $Id: ipl.h,v 2.15.2.5 2000/05/22 10:26:16 darrenr Exp $ */ #ifndef __IPL_H__ #define __IPL_H__ -#define IPL_VERSION "IP Filter v3.2.7" +#define IPL_VERSION "IP Filter: v3.4.4" #endif diff --git a/sys/contrib/ipfilter/netinet/mlfk_ipl.c b/sys/contrib/ipfilter/netinet/mlfk_ipl.c index 28e7c5d..4412960 100644 --- a/sys/contrib/ipfilter/netinet/mlfk_ipl.c +++ b/sys/contrib/ipfilter/netinet/mlfk_ipl.c @@ -23,9 +23,10 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD$ + * $Id: mlfk_ipl.c,v 2.1.2.1 2000/04/26 12:17:24 darrenr Exp $ */ + #include #include #include @@ -73,8 +74,8 @@ SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW, &fr_ipfrttl, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, ipl_unreach, CTLFLAG_RW, &ipl_unreach, 0, ""); -SYSCTL_INT(_net_inet_ipf, OID_AUTO, ipl_inited, CTLFLAG_RD, - &ipl_inited, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD, + &fr_running, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RD, &fr_authsize, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, @@ -108,7 +109,10 @@ ipfilter_modevent(module_t mod, int type, void *unused) switch (type) { case MOD_LOAD : + error = iplattach(); + if (error) + break; c = NULL; for(i=strlen(IPL_NAME); i>0; i--) @@ -160,7 +164,6 @@ ipfilter_modevent(module_t mod, int type, void *unused) destroy_dev(ipf_devs[IPL_LOGNAT]); destroy_dev(ipf_devs[IPL_LOGSTATE]); destroy_dev(ipf_devs[IPL_LOGAUTH]); - cdevsw_remove(&ipl_cdevsw); error = ipldetach(); break; default: -- cgit v1.1 From 89b6cd99cd8b52890fc9362c242b5b4713c47f78 Mon Sep 17 00:00:00 2001 From: darrenr Date: Wed, 19 Jul 2000 13:57:32 +0000 Subject: import ipfilter 3.4.8 --- sys/contrib/ipfilter/netinet/fil.c | 41 ++++++++----- sys/contrib/ipfilter/netinet/ip_auth.c | 4 +- sys/contrib/ipfilter/netinet/ip_fil.c | 40 ++++++++++-- sys/contrib/ipfilter/netinet/ip_fil.h | 8 +-- sys/contrib/ipfilter/netinet/ip_frag.c | 5 +- sys/contrib/ipfilter/netinet/ip_ftp_pxy.c | 98 ++++++++++++++++-------------- sys/contrib/ipfilter/netinet/ip_log.c | 8 ++- sys/contrib/ipfilter/netinet/ip_nat.c | 66 ++++++++++++++------ sys/contrib/ipfilter/netinet/ip_nat.h | 15 +++-- sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c | 17 ++++-- sys/contrib/ipfilter/netinet/ip_state.c | 26 ++++++-- sys/contrib/ipfilter/netinet/ip_state.h | 6 +- sys/contrib/ipfilter/netinet/ipl.h | 4 +- 13 files changed, 226 insertions(+), 112 deletions(-) diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index 258f76e..623e84e 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/netinet/fil.c @@ -7,13 +7,9 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.8 2000/05/22 10:26:09 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.18 2000/07/19 13:13:40 darrenr Exp $"; #endif -#if defined(_KERNEL) && defined(__FreeBSD_version) && \ - (__FreeBSD_version >= 400000) && !defined(KLD_MODULE) -#include "opt_inet6.h" -#endif #include #include #include @@ -25,6 +21,14 @@ static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.8 2000/05/22 10:26:09 darre #endif #if (defined(KERNEL) || defined(_KERNEL)) && defined(__FreeBSD_version) && \ (__FreeBSD_version >= 220000) +# if (__FreeBSD_version >= 400000) +# ifndef KLD_MODULE +# include "opt_inet6.h" +# endif +# if (__FreeBSD_version == 400019) +# define CSUM_DELAY_DATA +# endif +# endif # include # include #else @@ -115,10 +119,8 @@ extern kmutex_t ipf_rw; # if SOLARIS # define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, \ ip, qif) -# define SEND_RESET(ip, qif, if, fin) send_reset(fin, ip, qif) # else /* SOLARIS */ # define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip) -# define SEND_RESET(ip, qif, if, fin) send_reset(fin, ip) # endif /* SOLARIS || __sgi */ #endif /* _KERNEL */ @@ -659,8 +661,11 @@ void *m; * Just log this packet... */ passt = fr->fr_flags; - if ((passt & FR_CALLNOW) && fr->fr_func) - passt = (*fr->fr_func)(passt, ip, fin); +#if (BSD >= 199306) && (defined(_KERNEL) || defined(KERNEL)) + if (securelevel <= 0) +#endif + if ((passt & FR_CALLNOW) && fr->fr_func) + passt = (*fr->fr_func)(passt, ip, fin); fin->fin_fr = fr; #ifdef IPFILTER_LOG if ((passt & FR_LOGMASK) == FR_LOG) { @@ -965,8 +970,11 @@ int out; pass &= ~(FR_LOGFIRST|FR_LOG); } - if (fr && fr->fr_func && !(pass & FR_CALLNOW)) - pass = (*fr->fr_func)(pass, ip, fin); +#if (BSD >= 199306) && (defined(_KERNEL) || defined(KERNEL)) + if (securelevel <= 0) +#endif + if (fr && fr->fr_func && !(pass & FR_CALLNOW)) + pass = (*fr->fr_func)(pass, ip, fin); /* * Only count/translate packets which will be passed on, out the @@ -975,10 +983,10 @@ int out; if (out && (pass & FR_PASS)) { #ifdef USE_INET6 if (v == 6) - list = ipacct6[0][fr_active]; + list = ipacct6[1][fr_active]; else #endif - list = ipacct[0][fr_active]; + list = ipacct[1][fr_active]; if ((fin->fin_fr = list) && (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { ATOMIC_INCL(frstats[1].fr_acct); @@ -1123,11 +1131,11 @@ logit: if (((pass & FR_FASTROUTE) && !out) || (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) { - if (ipfr_fastroute(qif, ip, m, mp, fin, fdp) == 0) + if (ipfr_fastroute(ip, m, mp, fin, fdp) == 0) m = *mp = NULL; } if (mc) - ipfr_fastroute(qif, ip, mc, mp, fin, &fr->fr_dif); + ipfr_fastroute(ip, mc, mp, fin, &fr->fr_dif); } # endif /* !SOLARIS */ return (pass & FR_PASS) ? 0 : error; @@ -1359,7 +1367,7 @@ nodata: * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 - * $Id: fil.c,v 2.35.2.8 2000/05/22 10:26:09 darrenr Exp $ + * $Id: fil.c,v 2.35.2.18 2000/07/19 13:13:40 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, @@ -1807,6 +1815,7 @@ void frsync() ip_natsync(ifp); ip_statesync(ifp); } + ip_natsync((struct ifnet *)-1); # endif WRITE_ENTER(&ipf_mutex); diff --git a/sys/contrib/ipfilter/netinet/ip_auth.c b/sys/contrib/ipfilter/netinet/ip_auth.c index 78aff43..9fa24d6 100644 --- a/sys/contrib/ipfilter/netinet/ip_auth.c +++ b/sys/contrib/ipfilter/netinet/ip_auth.c @@ -6,7 +6,7 @@ * to the original author and the contributors. */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.2 2000/05/22 10:26:11 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.3 2000/06/17 06:24:31 darrenr Exp $"; #endif #include @@ -46,7 +46,7 @@ static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.2 2000/05/22 10:26:11 d # include # include #endif -#if _BSDI_VERSION >= 199802 +#if (_BSDI_VERSION >= 199802) || (__FreeBSD_Version >= 400000) # include #endif #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) diff --git a/sys/contrib/ipfilter/netinet/ip_fil.c b/sys/contrib/ipfilter/netinet/ip_fil.c index 9216b3c..fe6af66 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil.c +++ b/sys/contrib/ipfilter/netinet/ip_fil.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.9 2000/05/22 12:48:28 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.14 2000/07/18 13:57:55 darrenr Exp $"; #endif #ifndef SOLARIS @@ -692,6 +692,10 @@ caddr_t data; if (error) return EFAULT; fp->fr_ref = 0; +#if (BSD >= 199306) && defined(_KERNEL) + if ((securelevel > 0) && (fp->fr_func != NULL)) + return EPERM; +#endif /* * Check that the group number does exist and that if a head group @@ -764,7 +768,7 @@ caddr_t data; * interface pointer in the comparison (fr_next, fr_ifa). */ for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_ip, pp = &fp->fr_cksum; - p != pp; p++) + p < pp; p++) fp->fr_cksum += *p; for (; (f = *ftail); ftail = &f->fr_next) @@ -1088,6 +1092,19 @@ int dst; m = NULL; ifp = fin->fin_ifp; if (fin->fin_v == 4) { + if ((oip->ip_p == IPPROTO_ICMP) && + !(fin->fin_fi.fi_fl & FI_SHORT)) + switch (ntohs(fin->fin_data[0]) >> 8) + { + case ICMP_ECHO : + case ICMP_TSTAMP : + case ICMP_IREQ : + case ICMP_MASKREQ : + break; + default : + return 0; + } + # if (BSD < 199306) || defined(__sgi) avail = MLEN; m = m_get(M_DONTWAIT, MT_HEADER); @@ -1325,10 +1342,9 @@ frdest_t *fdp; ATOMIC_INCL(frstats[1].fr_acct); } fin->fin_fr = NULL; - if (!fr || !(fr->fr_flags & FR_RETMASK)) { + if (!fr || !(fr->fr_flags & FR_RETMASK)) (void) fr_checkstate(ip, fin); - (void) ip_natout(ip, fin); - } + (void) ip_natout(ip, fin); } else ip->ip_sum = 0; /* @@ -1585,15 +1601,29 @@ int v; if (!ifneta) { ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2); + if (!ifneta) + return NULL; ifneta[1] = NULL; ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp)); + if (!ifneta[0]) { + free(ifneta); + return NULL; + } nifs = 1; } else { nifs++; ifneta = (struct ifnet **)realloc(ifneta, (nifs + 1) * sizeof(*ifa)); + if (!ifneta) { + nifs = 0; + return NULL; + } ifneta[nifs] = NULL; ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp)); + if (!ifneta[nifs - 1]) { + nifs--; + return NULL; + } } ifp = ifneta[nifs - 1]; diff --git a/sys/contrib/ipfilter/netinet/ip_fil.h b/sys/contrib/ipfilter/netinet/ip_fil.h index 14f4861..da109b7 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil.h +++ b/sys/contrib/ipfilter/netinet/ip_fil.h @@ -6,7 +6,7 @@ * to the original author and the contributors. * * @(#)ip_fil.h 1.35 6/5/96 - * $Id: ip_fil.h,v 2.29.2.2 2000/05/22 10:26:13 darrenr Exp $ + * $Id: ip_fil.h,v 2.29.2.3 2000/06/05 13:12:42 darrenr Exp $ */ #ifndef __IP_FIL_H__ @@ -519,8 +519,8 @@ extern int iplioctl __P((dev_t, int, int *, int, cred_t *, int *)); extern int iplopen __P((dev_t *, int, int, cred_t *)); extern int iplclose __P((dev_t, int, int, cred_t *)); extern int ipfsync __P((void)); -extern int ipfr_fastroute __P((qif_t *, ip_t *, mblk_t *, mblk_t **, - fr_info_t *, frdest_t *)); +extern int ipfr_fastroute __P((ip_t *, mblk_t *, mblk_t **, + fr_info_t *, frdest_t *)); 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 *)); @@ -529,8 +529,6 @@ extern int iplread __P((dev_t, struct uio *, cred_t *)); # else /* SOLARIS */ extern int fr_check __P((ip_t *, int, void *, int, mb_t **)); extern int (*fr_checkp) __P((ip_t *, int, void *, int, mb_t **)); -extern int send_reset __P((struct ip *, fr_info_t *)); -extern int send_icmp_err __P((ip_t *, int, fr_info_t *, int)); extern int ipfr_fastroute __P((mb_t *, fr_info_t *, frdest_t *)); extern size_t mbufchainlen __P((mb_t *)); # ifdef __sgi diff --git a/sys/contrib/ipfilter/netinet/ip_frag.c b/sys/contrib/ipfilter/netinet/ip_frag.c index 3e0a7f3..5019c60 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.c +++ b/sys/contrib/ipfilter/netinet/ip_frag.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.3 2000/05/05 15:10:23 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.4 2000/06/06 15:49:15 darrenr Exp $"; #endif #if defined(KERNEL) && !defined(_KERNEL) @@ -144,6 +144,9 @@ ipfr_t *table[]; ipfr_t **fp, *fra, frag; u_int idx; + if (ipfr_inuse >= IPFT_SIZE) + return NULL; + frag.ipfr_p = ip->ip_p; idx = ip->ip_p; frag.ipfr_id = ip->ip_id; diff --git a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c index 691e0ad..5ea94a1 100644 --- a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c @@ -2,14 +2,17 @@ * Simple FTP transparent proxy for in-kernel use. For use with the NAT * code. * - * $Id: ip_ftp_pxy.c,v 2.7.2.7 2000/05/13 14:28:14 darrenr Exp $ + * $Id: ip_ftp_pxy.c,v 2.7.2.12 2000/07/19 13:06:13 darrenr Exp $ */ #if SOLARIS && defined(_KERNEL) extern kmutex_t ipf_rw; #endif #define isdigit(x) ((x) >= '0' && (x) <= '9') -#define isupper(x) ((unsigned)((x) - 'A') <= 'Z' - 'A') +#define isupper(x) (((unsigned)(x) >= 'A') && ((unsigned)(x) <= 'Z')) +#define islower(x) (((unsigned)(x) >= 'a') && ((unsigned)(x) <= 'z')) +#define isalpha(x) (isupper(x) || islower(x)) +#define toupper(x) (isupper(x) ? (x) : (x) - 'a' + 'A') #define IPF_FTP_PROXY @@ -35,6 +38,7 @@ u_short ippr_ftp_atoi __P((char **)); static frentry_t natfr; int ippr_ftp_pasvonly = 0; +int ippr_ftp_insecure = 0; /* @@ -97,21 +101,12 @@ int dlen; #endif tcp = (tcphdr_t *)fin->fin_dp; - off = f->ftps_seq - ntohl(tcp->th_seq); - if (off < 0) - return 0; /* * Check for client sending out PORT message. */ if (dlen < IPF_MINPORTLEN) return 0; - /* - * Count the number of bytes in the PORT message is. - */ - if (off < 0) - return 0; - - off += fin->fin_hlen + (tcp->th_off << 2); + off = fin->fin_hlen + (tcp->th_off << 2); /* * Skip the PORT command + space */ @@ -201,6 +196,10 @@ int dlen; m_adj(m, inc); /* the mbuf chain will be extended if necessary by m_copyback() */ m_copyback(m, off, nlen, newbuf); +# ifdef M_PKTHDR + if (!(m->m_flags & M_PKTHDR)) + m->m_pkthdr.len += inc; +# endif #endif if (inc != 0) { #if SOLARIS || defined(__sgi) @@ -275,27 +274,39 @@ ftpinfo_t *ftp; ip_t *ip; int dlen; { - char *rptr, *wptr; + char *rptr, *wptr, cmd[6], c; ftpside_t *f; - int inc; + int inc, i; inc = 0; f = &ftp->ftp_side[0]; rptr = f->ftps_rptr; wptr = f->ftps_wptr; - if ((ftp->ftp_passok == 0) && !strncmp(rptr, "USER ", 5)) + for (i = 0; (i < 5) && (i < dlen); i++) { + c = rptr[i]; + if (isalpha(c)) { + cmd[i] = toupper(c); + } else { + cmd[i] = c; + } + } + cmd[i] = '\0'; + + if ((ftp->ftp_passok == 0) && !strncmp(cmd, "USER ", 5)) ftp->ftp_passok = 1; - else if ((ftp->ftp_passok == 2) && !strncmp(rptr, "PASS ", 5)) + else if ((ftp->ftp_passok == 2) && !strncmp(cmd, "PASS ", 5)) ftp->ftp_passok = 3; else if ((ftp->ftp_passok == 4) && !ippr_ftp_pasvonly && - !strncmp(rptr, "PORT ", 5)) { + !strncmp(cmd, "PORT ", 5)) { + inc = ippr_ftp_port(fin, ip, nat, f, dlen); + } else if (ippr_ftp_insecure && !ippr_ftp_pasvonly && + !strncmp(cmd, "PORT ", 5)) { inc = ippr_ftp_port(fin, ip, nat, f, dlen); } while ((*rptr++ != '\n') && (rptr < wptr)) ; - f->ftps_seq += rptr - f->ftps_rptr; f->ftps_rptr = rptr; return inc; } @@ -313,8 +324,8 @@ int dlen; u_short a5, a6, sp, dp; u_int a1, a2, a3, a4; fr_info_t fi; - int inc, off; nat_t *ipn; + int inc; char *s; /* @@ -325,15 +336,8 @@ int dlen; else if (strncmp(f->ftps_rptr, "227 Entering Passive Mode", 25)) return 0; - /* - * Count the number of bytes in the 227 reply is. - */ tcp = (tcphdr_t *)fin->fin_dp; - off = f->ftps_seq - ntohl(tcp->th_seq); - if (off < 0) - return 0; - off += fin->fin_hlen + (tcp->th_off << 2); /* * Skip the PORT command + space */ @@ -417,13 +421,13 @@ int dlen; m1->b_wptr += inc; } /*copyin_mblk(m, off, nlen, newbuf);*/ -#else +#else /* SOLARIS */ m = *((mb_t **)fin->fin_mp); if (inc < 0) m_adj(m, inc); /* the mbuf chain will be extended if necessary by m_copyback() */ /*m_copyback(m, off, nlen, newbuf);*/ -#endif +#endif /* SOLARIS */ if (inc != 0) { #if SOLARIS || defined(__sgi) register u_32_t sum1, sum2; @@ -438,10 +442,10 @@ int dlen; sum2 = (sum2 & 0xffff) + (sum2 >> 16); fix_outcksum(&ip->ip_sum, sum2, 0); -#endif +#endif /* SOLARIS || defined(__sgi) */ ip->ip_len += inc; } -#endif +#endif /* 0 */ /* * Add skeleton NAT entry for connection which will come back the @@ -507,10 +511,11 @@ int dlen; ftp->ftp_passok = 0; else if ((ftp->ftp_passok == 4) && !strncmp(rptr, "227 ", 4)) { inc = ippr_ftp_pasv(fin, ip, nat, f, dlen); + } else if (ippr_ftp_insecure && !strncmp(rptr, "227 ", 4)) { + inc = ippr_ftp_pasv(fin, ip, nat, f, dlen); } while ((*rptr++ != '\n') && (rptr < wptr)) ; - f->ftps_seq += rptr - f->ftps_rptr; f->ftps_rptr = rptr; return inc; } @@ -548,16 +553,16 @@ size_t len; return 1; } else return 1; - } else if (isupper(c)) { + } else if (isalpha(c)) { c = *s++; i--; - if (isupper(c)) { + if (isalpha(c)) { c = *s++; i--; - if (isupper(c)) { + if (isalpha(c)) { c = *s++; i--; - if (isupper(c)) { + if (isalpha(c)) { c = *s++; i--; if ((c != ' ') && (c != '\r')) @@ -586,10 +591,10 @@ nat_t *nat; ftpinfo_t *ftp; int rv; { - int mlen, len, off, inc, i; + int mlen, len, off, inc, i, sel; char *rptr, *wptr; + ftpside_t *f, *t; tcphdr_t *tcp; - ftpside_t *f; mb_t *m; tcp = (tcphdr_t *)fin->fin_dp; @@ -606,23 +611,29 @@ int rv; #else mlen = mbufchainlen(m) - off; #endif - if (!mlen) + t = &ftp->ftp_side[1 - rv]; + if (!mlen) { + t->ftps_seq = ntohl(tcp->th_ack); return 0; + } inc = 0; f = &ftp->ftp_side[rv]; rptr = f->ftps_rptr; wptr = f->ftps_wptr; - if ((wptr == f->ftps_buf) && (f->ftps_seq <= ntohl(tcp->th_seq))) - f->ftps_seq = ntohl(tcp->th_seq); + sel = nat->nat_aps->aps_sel[1 - rv]; + if (rv) + i = nat->nat_aps->aps_ackoff[sel]; + else + i = nat->nat_aps->aps_seqoff[sel]; /* * XXX - Ideally, this packet should get dropped because we now know * that it is out of order (and there is no real danger in doing so * apart from causing packets to go through here ordered). */ - if (ntohl(tcp->th_seq) != f->ftps_seq + (wptr - rptr)) { - return APR_ERR(0); + if (ntohl(tcp->th_seq) + i != f->ftps_seq) { + return APR_ERR(-1); } while (mlen > 0) { @@ -666,7 +677,6 @@ int rv; } else rptr++; } - f->ftps_seq += rptr - f->ftps_rptr; f->ftps_rptr = rptr; } @@ -677,7 +687,6 @@ int rv; i = wptr - rptr; if ((rptr == f->ftps_buf) || (wptr - rptr > FTP_BUFSZ / 2)) { - f->ftps_seq += i; f->ftps_junk = 1; rptr = wptr = f->ftps_buf; } else { @@ -691,6 +700,7 @@ int rv; } } + t->ftps_seq = ntohl(tcp->th_ack); f->ftps_rptr = rptr; f->ftps_wptr = wptr; return inc; diff --git a/sys/contrib/ipfilter/netinet/ip_log.c b/sys/contrib/ipfilter/netinet/ip_log.c index ef1af7f..08073bb 100644 --- a/sys/contrib/ipfilter/netinet/ip_log.c +++ b/sys/contrib/ipfilter/netinet/ip_log.c @@ -5,7 +5,7 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: ip_log.c,v 2.5 2000/03/13 22:10:21 darrenr Exp $ + * $Id: ip_log.c,v 2.5.2.1 2000/07/19 13:11:47 darrenr Exp $ */ #include #if defined(KERNEL) && !defined(_KERNEL) @@ -20,7 +20,11 @@ # include "opt_ipfilter.h" # endif # else -# include +# ifdef KLD_MODULE +# include +# else +# include +# endif # endif #endif #ifdef IPFILTER_LOG diff --git a/sys/contrib/ipfilter/netinet/ip_nat.c b/sys/contrib/ipfilter/netinet/ip_nat.c index 64f50b6..d25f3f7 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.c +++ b/sys/contrib/ipfilter/netinet/ip_nat.c @@ -9,7 +9,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 2.37.2.10 2000/05/19 15:54:44 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.16 2000/07/18 13:57:40 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) @@ -473,10 +473,14 @@ int mode; n->in_next = NULL; *np = n; - if (n->in_redir & NAT_REDIRECT) + if (n->in_redir & NAT_REDIRECT) { + n->in_flags &= ~IPN_NOTDST; nat_addrdr(n); - if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) + } + if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { + n->in_flags &= ~IPN_NOTSRC; nat_addnat(n); + } n->in_use = 0; if (n->in_redir & NAT_MAPBLK) @@ -1517,6 +1521,8 @@ int dir; ip_t *oip; int flags = 0; + if ((fin->fin_fi.fi_fl & FI_SHORT) || (ip->ip_off & IP_OFFMASK)) + return NULL; if ((ip->ip_v != 4) || !(nat = nat_icmplookup(ip, fin, dir))) return NULL; *nflags = IPN_ICMPERR; @@ -1559,14 +1565,14 @@ int dir; fix_outcksum(&icmp->icmp_cksum, sumd, 0); } else { fix_outcksum(&oip->ip_sum, sumd, 0); - +#if !SOLARIS && !defined(__sgi) sumd += (sumd & 0xffff); while (sumd > 0xffff) sumd = (sumd & 0xffff) + (sumd >> 16); -/* fix_incksum(&icmp->icmp_cksum, sumd, 0); */ + fix_incksum(&icmp->icmp_cksum, sumd, 0); +#endif } - if ((flags & IPN_TCPUDP) != 0) { tcphdr_t *tcp; @@ -1714,19 +1720,28 @@ ip_t *ip; if (np->in_p && ip->ip_p != np->in_p) return 0; if (fin->fin_out) { - if (!(np->in_redir && (NAT_MAP|NAT_MAPBLK))) + if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK))) return 0; - if ((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip) + if (((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip) + ^ ((np->in_flags & IPN_NOTSRC) != 0)) return 0; - if ((fin->fin_fi.fi_daddr & np->in_srcmsk) != np->in_srcip) + if (((fin->fin_fi.fi_daddr & np->in_srcmsk) != np->in_srcip) + ^ ((np->in_flags & IPN_NOTDST) != 0)) return 0; } else { - if (!(np->in_redir && NAT_REDIRECT)) + if (!(np->in_redir & NAT_REDIRECT)) + return 0; + if (((fin->fin_fi.fi_saddr & np->in_srcmsk) != np->in_srcip) + ^ ((np->in_flags & IPN_NOTSRC) != 0)) + return 0; + if (((fin->fin_fi.fi_daddr & np->in_outmsk) != np->in_outip) + ^ ((np->in_flags & IPN_NOTDST) != 0)) return 0; } ft = &np->in_tuc; - if (!(fin->fin_fi.fi_fl & FI_TCPUDP)) { + if (!(fin->fin_fi.fi_fl & FI_TCPUDP) || + (fin->fin_fi.fi_fl & FI_SHORT) || (ip->ip_off & IP_OFFMASK)) { if (ft->ftu_scmp || ft->ftu_dcmp) return 0; return 1; @@ -1863,7 +1878,6 @@ maskloop: 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(&nat->nat_lock); nat->nat_age = fr_defnatage; nat->nat_bytes += ip->ip_len; @@ -1874,12 +1888,27 @@ maskloop: * Fix up checksums, not by recalculating them, but * simply computing adjustments. */ + if (nflags == IPN_ICMPERR) { + u_32_t s1, s2, sumd; + + s1 = LONG_SUM(ntohl(ip->ip_src.s_addr)); + s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)); + CALC_SUMD(s1, s2, sumd); + + if (nat->nat_dir == NAT_OUTBOUND) + fix_incksum(&ip->ip_sum, sumd, 0); + else + fix_outcksum(&ip->ip_sum, sumd, 0); + } #if SOLARIS || defined(__sgi) - 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); + else { + 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 + ip->ip_src = nat->nat_outip; if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) { @@ -1917,6 +1946,7 @@ maskloop: } else if (ip->ip_p == IPPROTO_ICMP) { nat->nat_age = fr_defnaticmpage; } + if (csump) { if (nat->nat_dir == NAT_OUTBOUND) fix_outcksum(csump, nat->nat_sumd[1], @@ -1986,7 +2016,7 @@ fr_info_t *fin; if ((ip->ip_p == IPPROTO_ICMP) && (nat = nat_icmp(ip, fin, &nflags, NAT_INBOUND))) ; - else if ((ip->ip_off & IP_OFFMASK) && + else if ((ip->ip_off & (IP_OFFMASK|IP_MF)) && (nat = ipfr_nat_knownfrag(ip, fin))) natadd = 0; else if ((nat = nat_inlookup(fin->fin_ifp, nflags, (u_int)ip->ip_p, @@ -2024,7 +2054,7 @@ maskloop: } else if ((in.s_addr & np->in_outmsk) != np->in_outip) continue; if ((np->in_redir & NAT_REDIRECT) && - (!np->in_pmin || + (!np->in_pmin || (np->in_flags & IPN_FILTER) || ((ntohs(np->in_pmax) >= ntohs(dport)) && (ntohs(dport) >= ntohs(np->in_pmin))))) if ((nat = nat_new(np, ip, fin, nflags, diff --git a/sys/contrib/ipfilter/netinet/ip_nat.h b/sys/contrib/ipfilter/netinet/ip_nat.h index f1a339f..26fed25 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.h +++ b/sys/contrib/ipfilter/netinet/ip_nat.h @@ -6,7 +6,7 @@ * to the original author and the contributors. * * @(#)ip_nat.h 1.5 2/4/96 - * $Id: ip_nat.h,v 2.17.2.1 2000/05/15 06:50:14 darrenr Exp $ + * $Id: ip_nat.h,v 2.17.2.6 2000/07/15 14:50:06 darrenr Exp $ */ #ifndef __IP_NAT_H__ @@ -103,9 +103,10 @@ typedef struct ipnat { u_int in_hits; struct in_addr in_nextip; u_short in_pnext; - 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_32_t in_flags; /* From here to in_dport must be reflected */ + u_short in_spare; + u_short in_ppip; /* ports per IP */ u_short in_port[2]; /* correctly in IPN_CMPSIZ */ struct in_addr in_in[2]; struct in_addr in_out[2]; @@ -212,11 +213,13 @@ typedef struct natstat { #define IPN_RF (IPN_TCPUDP|IPN_DELETE|IPN_ICMPERR) #define IPN_AUTOPORTMAP 0x010 #define IPN_IPRANGE 0x020 -#define IPN_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_IPRANGE|\ - IPN_SPLIT|IPN_ROUNDR|IPN_FILTER) +#define IPN_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_IPRANGE|IPN_SPLIT|\ + IPN_ROUNDR|IPN_FILTER|IPN_NOTSRC|IPN_NOTDST) #define IPN_FILTER 0x040 #define IPN_SPLIT 0x080 #define IPN_ROUNDR 0x100 +#define IPN_NOTSRC 0x080000 +#define IPN_NOTDST 0x100000 typedef struct natlog { @@ -236,6 +239,8 @@ typedef struct natlog { #define NL_NEWMAP NAT_MAP #define NL_NEWRDR NAT_REDIRECT +#define NL_NEWBIMAP NAT_BIMAP +#define NL_NEWBLOCK NAT_MAPBLK #define NL_EXPIRE 0xffff #define NAT_HASH_FN(k,l,m) (((k) + ((k) >> 12) + l) % (m)) diff --git a/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c b/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c index daea94f..1d6264d 100644 --- a/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c @@ -1,5 +1,5 @@ /* - * $Id: ip_rcmd_pxy.c,v 1.4.2.1 2000/05/06 11:19:34 darrenr Exp $ + * $Id: ip_rcmd_pxy.c,v 1.4.2.2 2000/07/15 12:38:30 darrenr Exp $ */ /* * Simple RCMD transparent proxy for in-kernel use. For use with the NAT @@ -93,8 +93,17 @@ nat_t *nat; #endif tcp = (tcphdr_t *)fin->fin_dp; + + if (tcp->th_flags & TH_SYN) { + *(u_32_t *)aps->aps_data = htonl(ntohl(tcp->th_seq) + 1); + return 0; + } + + if ((*(u_32_t *)aps->aps_data != 0) && + (tcp->th_seq != *(u_32_t *)aps->aps_data)) + return 0; + off = (ip->ip_hl << 2) + (tcp->th_off << 2); - m = *(mb_t **)fin->fin_mp; #if SOLARIS m = fin->fin_qfm; @@ -103,13 +112,11 @@ nat_t *nat; bzero(portbuf, sizeof(portbuf)); 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); #endif - if ((*(u_32_t *)aps->aps_data != 0) && - (tcp->th_seq != *(u_32_t *)aps->aps_data)) - return 0; portbuf[sizeof(portbuf) - 1] = '\0'; s = portbuf; diff --git a/sys/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c index c9a28af..fa8e050 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.c +++ b/sys/contrib/ipfilter/netinet/ip_state.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.9 2000/05/22 10:26:15 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.12 2000/06/19 02:38:37 darrenr Exp $"; #endif #include @@ -381,8 +381,8 @@ caddr_t data; { register ipstate_t *is, *isn; ipstate_save_t ips, *ipsp; + int error, out; frentry_t *fr; - int error; error = IRCOPY(data, (caddr_t)&ipsp, sizeof(ipsp)); if (error) @@ -405,8 +405,26 @@ caddr_t data; return ENOMEM; } bcopy((char *)&ips.ips_fr, (char *)fr, sizeof(*fr)); + out = fr->fr_flags & FR_OUTQUE ? 1 : 0; isn->is_rule = fr; ips.ips_is.is_rule = fr; + if (*fr->fr_ifname) { + fr->fr_ifa = GETUNIT(fr->fr_ifname, fr->fr_v); + if (fr->fr_ifa == NULL) + fr->fr_ifa = (void *)-1; +#ifdef _KERNEL + else { + strncpy(isn->is_ifname[out], + IFNAME(fr->fr_ifa), IFNAMSIZ); + isn->is_ifp[out] = fr->fr_ifa; + } +#endif + } else + fr->fr_ifa = NULL; + /* + * send a copy back to userland of what we ended up + * to allow for verification. + */ error = IWCOPY((caddr_t)&ips, ipsp, sizeof(ips)); if (error) { KFREE(isn); @@ -1582,8 +1600,8 @@ fr_info_t *fin; (oic->icmp6_type == ICMP6_ECHO_REQUEST)) || (is->is_type - 1 == oic->icmp6_type )) { ips_stats.iss_hits++; - is->is_pkts++; - is->is_bytes += fin->fin_plen; + is->is_pkts++; + is->is_bytes += fin->fin_plen; return is->is_rule; } } diff --git a/sys/contrib/ipfilter/netinet/ip_state.h b/sys/contrib/ipfilter/netinet/ip_state.h index 01c26a0..a5643af 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.h +++ b/sys/contrib/ipfilter/netinet/ip_state.h @@ -6,7 +6,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 2.13 2000/03/13 22:10:23 darrenr Exp $ + * $Id: ip_state.h,v 2.13.2.1 2000/07/08 02:15:35 darrenr Exp $ */ #ifndef __IP_STATE_H__ #define __IP_STATE_H__ @@ -17,8 +17,8 @@ # define SIOCDELST _IOW(r, 61, struct ipstate *) #endif -#define IPSTATE_SIZE 257 -#define IPSTATE_MAX 2048 /* Maximum number of states held */ +#define IPSTATE_SIZE 5737 +#define IPSTATE_MAX 4013 /* Maximum number of states held */ #define PAIRS(s1,d1,s2,d2) ((((s1) == (s2)) && ((d1) == (d2))) ||\ (((s1) == (d2)) && ((d1) == (s2)))) diff --git a/sys/contrib/ipfilter/netinet/ipl.h b/sys/contrib/ipfilter/netinet/ipl.h index 12d866c..bb2523d 100644 --- a/sys/contrib/ipfilter/netinet/ipl.h +++ b/sys/contrib/ipfilter/netinet/ipl.h @@ -6,12 +6,12 @@ * to the original author and the contributors. * * @(#)ipl.h 1.21 6/5/96 - * $Id: ipl.h,v 2.15.2.5 2000/05/22 10:26:16 darrenr Exp $ + * $Id: ipl.h,v 2.15.2.9 2000/07/19 13:40:04 darrenr Exp $ */ #ifndef __IPL_H__ #define __IPL_H__ -#define IPL_VERSION "IP Filter: v3.4.4" +#define IPL_VERSION "IP Filter: v3.4.8" #endif -- cgit v1.1 From 15d169cdfcc633be9595e83cac604b7637123f9b Mon Sep 17 00:00:00 2001 From: darrenr Date: Sun, 13 Aug 2000 04:28:25 +0000 Subject: Import IP Filter 3.4.9 bits into the kernel --- sys/contrib/ipfilter/netinet/fil.c | 49 +++-- sys/contrib/ipfilter/netinet/ip_auth.c | 4 +- sys/contrib/ipfilter/netinet/ip_compat.h | 6 +- sys/contrib/ipfilter/netinet/ip_fil.c | 6 +- sys/contrib/ipfilter/netinet/ip_ftp_pxy.c | 6 +- sys/contrib/ipfilter/netinet/ip_log.c | 4 +- sys/contrib/ipfilter/netinet/ip_nat.c | 88 ++++++--- sys/contrib/ipfilter/netinet/ip_state.c | 298 +++++++++++++++++++++++++----- sys/contrib/ipfilter/netinet/ipl.h | 4 +- sys/contrib/ipfilter/netinet/mlfk_ipl.c | 4 +- 10 files changed, 367 insertions(+), 102 deletions(-) diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index 623e84e..91b5108 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/netinet/fil.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.18 2000/07/19 13:13:40 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.20 2000/08/13 04:15:43 darrenr Exp $"; #endif #include @@ -820,18 +820,6 @@ int out; fin->fin_qfm = m; fin->fin_qif = qif; # endif -# ifdef USE_INET6 - if (v == 6) { - ATOMIC_INCL(frstats[0].fr_ipv6[out]); - } else -# endif - if (!out && fr_chksrc && !fr_verifysrc(ip->ip_src, ifp)) { - ATOMIC_INCL(frstats[0].fr_badsrc); -# if !SOLARIS - m_freem(m); -# endif - return error; - } #endif /* _KERNEL */ /* @@ -847,8 +835,29 @@ int out; fin->fin_out = out; fin->fin_mp = mp; fr_makefrip(hlen, ip, fin); - pass = fr_pass; +#ifdef _KERNEL +# ifdef USE_INET6 + if (v == 6) { + ATOMIC_INCL(frstats[0].fr_ipv6[out]); + } else +# endif + if (!out && fr_chksrc && !fr_verifysrc(ip->ip_src, ifp)) { + ATOMIC_INCL(frstats[0].fr_badsrc); +# ifdef IPFILTER_LOG + if (fr_chksrc == 2) { + fin->fin_group = -2; + pass = FR_INQUE|FR_NOMATCH|FR_LOGB; + (void) IPLLOG(pass, ip, fin, m); + } +# endif +# if !SOLARIS + m_freem(m); +# endif + return error; + } +#endif + pass = fr_pass; if (fin->fin_fi.fi_fl & FI_SHORT) { ATOMIC_INCL(frstats[out].fr_short); } @@ -1367,7 +1376,7 @@ nodata: * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 - * $Id: fil.c,v 2.35.2.18 2000/07/19 13:13:40 darrenr Exp $ + * $Id: fil.c,v 2.35.2.20 2000/08/13 04:15:43 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, @@ -1846,11 +1855,14 @@ size_t c; int err; #if SOLARIS - copyin(a, &ca, sizeof(ca)); + if (copyin(a, &ca, sizeof(ca))) + return EFAULT; #else bcopy(a, &ca, sizeof(ca)); #endif err = copyin(ca, b, c); + if (err) + err = EFAULT; return err; } @@ -1863,11 +1875,14 @@ size_t c; int err; #if SOLARIS - copyin(b, &ca, sizeof(ca)); + if (copyin(b, &ca, sizeof(ca))) + return EFAULT; #else bcopy(b, &ca, sizeof(ca)); #endif err = copyout(a, ca, c); + if (err) + err = EFAULT; return err; } diff --git a/sys/contrib/ipfilter/netinet/ip_auth.c b/sys/contrib/ipfilter/netinet/ip_auth.c index 9fa24d6..d737b9c 100644 --- a/sys/contrib/ipfilter/netinet/ip_auth.c +++ b/sys/contrib/ipfilter/netinet/ip_auth.c @@ -6,7 +6,7 @@ * to the original author and the contributors. */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.3 2000/06/17 06:24:31 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.4 2000/08/05 14:48:50 darrenr Exp $"; #endif #include @@ -46,7 +46,7 @@ static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.3 2000/06/17 06:24:31 d # include # include #endif -#if (_BSDI_VERSION >= 199802) || (__FreeBSD_Version >= 400000) +#if (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000) # include #endif #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h index 9b7cddf..ba9e014 100644 --- a/sys/contrib/ipfilter/netinet/ip_compat.h +++ b/sys/contrib/ipfilter/netinet/ip_compat.h @@ -6,7 +6,7 @@ * to the original author and the contributors. * * @(#)ip_compat.h 1.8 1/14/96 - * $Id: ip_compat.h,v 2.26.2.3 2000/04/28 14:56:49 darrenr Exp $ + * $Id: ip_compat.h,v 2.26.2.4 2000/08/13 03:51:03 darrenr Exp $ */ #ifndef __IP_COMPAT_H__ @@ -126,6 +126,10 @@ typedef int minor_t; #endif /* SOLARIS */ #define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h))) +#if defined(__FreeBSD__) && (__FreeBSD__ >= 5) && defined(_KERNEL) +# include +#endif + #ifndef IP_OFFMASK #define IP_OFFMASK 0x1fff #endif diff --git a/sys/contrib/ipfilter/netinet/ip_fil.c b/sys/contrib/ipfilter/netinet/ip_fil.c index fe6af66..2e8af26 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil.c +++ b/sys/contrib/ipfilter/netinet/ip_fil.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.14 2000/07/18 13:57:55 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.15 2000/08/05 14:49:08 darrenr Exp $"; #endif #ifndef SOLARIS @@ -1139,8 +1139,10 @@ int dst; return ENOBUFS; MCLGET(m, M_DONTWAIT); - if (!m) + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); return ENOBUFS; + } avail = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN; xtra = MIN(ntohs(oip6->ip6_plen) + sizeof(ip6_t), avail - hlen - sizeof(*icmp) - max_linkhdr); diff --git a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c index 5ea94a1..84dc8b9 100644 --- a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c @@ -2,7 +2,7 @@ * Simple FTP transparent proxy for in-kernel use. For use with the NAT * code. * - * $Id: ip_ftp_pxy.c,v 2.7.2.12 2000/07/19 13:06:13 darrenr Exp $ + * $Id: ip_ftp_pxy.c,v 2.7.2.13 2000/08/07 12:35:27 darrenr Exp $ */ #if SOLARIS && defined(_KERNEL) extern kmutex_t ipf_rw; @@ -263,7 +263,7 @@ int dlen; ip->ip_len = slen; ip->ip_src = swip; } - return inc; + return APR_INC(inc); } @@ -703,7 +703,7 @@ int rv; t->ftps_seq = ntohl(tcp->th_ack); f->ftps_rptr = rptr; f->ftps_wptr = wptr; - return inc; + return APR_INC(inc); } diff --git a/sys/contrib/ipfilter/netinet/ip_log.c b/sys/contrib/ipfilter/netinet/ip_log.c index 08073bb..8adc410 100644 --- a/sys/contrib/ipfilter/netinet/ip_log.c +++ b/sys/contrib/ipfilter/netinet/ip_log.c @@ -5,7 +5,7 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: ip_log.c,v 2.5.2.1 2000/07/19 13:11:47 darrenr Exp $ + * $Id: ip_log.c,v 2.5.2.2 2000/08/13 03:50:41 darrenr Exp $ */ #include #if defined(KERNEL) && !defined(_KERNEL) @@ -21,8 +21,6 @@ # endif # else # ifdef KLD_MODULE -# include -# else # include # endif # endif diff --git a/sys/contrib/ipfilter/netinet/ip_nat.c b/sys/contrib/ipfilter/netinet/ip_nat.c index d25f3f7..bbcff77 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.c +++ b/sys/contrib/ipfilter/netinet/ip_nat.c @@ -9,7 +9,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 2.37.2.16 2000/07/18 13:57:40 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.21 2000/08/12 07:32:40 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) @@ -126,7 +126,7 @@ hostmap_t **maptable = NULL; u_long fr_defnatage = DEF_NAT_AGE, fr_defnaticmpage = 6; /* 3 seconds */ -static natstat_t nat_stats; +natstat_t nat_stats; int fr_nat_lock = 0; #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) extern kmutex_t ipf_rw, ipf_hostmap; @@ -403,8 +403,11 @@ int mode; KMALLOC(nt, ipnat_t *); if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) error = IRCOPYPTR(data, (char *)&natd, sizeof(natd)); - else if (cmd == SIOCIPFFL) /* SIOCFLNAT & SIOCCNATL */ + else if (cmd == SIOCIPFFL) { /* SIOCFLNAT & SIOCCNATL */ error = IRCOPY(data, (char *)&arg, sizeof(arg)); + if (error) + error = EFAULT; + } if (error) goto done; @@ -498,7 +501,7 @@ int mode; * 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) + * (so subtract 1) * If to a range, add one. * If to a single IP address, set to 1. */ @@ -641,7 +644,8 @@ int mode; sizeof(fr_nat_lock)); if (!error) fr_nat_lock = arg; - } + } else + error = EFAULT; break; case SIOCSTPUT : if (fr_nat_lock) @@ -666,6 +670,8 @@ int mode; MUTEX_DOWNGRADE(&ipf_nat); error = IWCOPY((caddr_t)&iplused[IPL_LOGNAT], (caddr_t)data, sizeof(iplused[IPL_LOGNAT])); + if (error) + error = EFAULT; #endif break; default : @@ -732,7 +738,7 @@ caddr_t data; static int fr_natgetent(data) caddr_t data; { - nat_save_t ipn, *ipnp, *ipnn; + nat_save_t ipn, *ipnp, *ipnn = NULL; register nat_t *n, *nat; ap_session_t *aps; int error; @@ -785,33 +791,33 @@ caddr_t data; ipn.ipn_dsize += aps->aps_psiz; KMALLOCS(ipnn, nat_save_t *, sizeof(*ipnn) + ipn.ipn_dsize); if (ipnn == NULL) - return NULL; + return ENOMEM; bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn)); - bcopy((char *)aps, ipn.ipn_data, sizeof(*aps)); + bcopy((char *)aps, ipnn->ipn_data, sizeof(*aps)); if (aps->aps_data) { - bcopy(aps->aps_data, ipn.ipn_data + sizeof(*aps), + bcopy(aps->aps_data, ipnn->ipn_data + sizeof(*aps), aps->aps_psiz); - ipn.ipn_dsize += aps->aps_psiz; + ipnn->ipn_dsize += aps->aps_psiz; } error = IWCOPY((caddr_t)ipnn, ipnp, sizeof(ipn) + ipn.ipn_dsize); if (error) - return EFAULT; + error = EFAULT; KFREES(ipnn, sizeof(*ipnn) + ipn.ipn_dsize); } else { error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn)); if (error) - return EFAULT; + error = EFAULT; } - return 0; + return error; } static int fr_natputent(data) caddr_t data; { - nat_save_t ipn, *ipnp, *ipnn; + nat_save_t ipn, *ipnp, *ipnn = NULL; register nat_t *n, *nat; ap_session_t *aps; frentry_t *fr; @@ -825,6 +831,7 @@ caddr_t data; error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn)); if (error) return EFAULT; + nat = NULL; if (ipn.ipn_dsize) { KMALLOCS(ipnn, nat_save_t *, sizeof(ipn) + ipn.ipn_dsize); if (ipnn == NULL) @@ -832,14 +839,18 @@ caddr_t data; bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn)); error = IRCOPY((caddr_t)ipnp, (caddr_t)ipn.ipn_data, ipn.ipn_dsize); - if (error) - return EFAULT; + if (error) { + error = EFAULT; + goto junkput; + } } else ipnn = NULL; KMALLOC(nat, nat_t *); - if (nat == NULL) - return ENOMEM; + if (nat == NULL) { + error = EFAULT; + goto junkput; + } bcopy((char *)&ipn.ipn_nat, (char *)nat, sizeof(*nat)); /* @@ -1458,7 +1469,7 @@ int dir; icmphdr_t *icmp; tcphdr_t *tcp = NULL; ip_t *oip; - int flags = 0, type; + int flags = 0, type, minlen; icmp = (icmphdr_t *)fin->fin_dp; /* @@ -1478,13 +1489,45 @@ int dir; return NULL; oip = (ip_t *)((char *)fin->fin_dp + 8); - if (ip->ip_len < ICMPERR_MAXPKTLEN + ((oip->ip_hl - 5) << 2)) + minlen = (oip->ip_hl << 2); + if (minlen < sizeof(ip_t)) return NULL; + if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen) + return NULL; + /* + * Is the buffer big enough for all of it ? It's the size of the IP + * header claimed in the encapsulated part which is of concern. It + * may be too big to be in this buffer but not so big that it's + * outside the ICMP packet, leading to TCP deref's causing problems. + * This is possible because we don't know how big oip_hl is when we + * do the pullup early in fr_check() and thus can't gaurantee it is + * all here now. + */ +#ifdef _KERNEL + { + mb_t *m; + +# if SOLARIS + m = fin->fin_qfm; + if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr) + return NULL; +# else + m = *(mb_t **)fin->fin_mp; + if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > + (char *)ip + m->m_len) + return NULL; +# endif + } +#endif + if (oip->ip_p == IPPROTO_TCP) flags = IPN_TCP; else if (oip->ip_p == IPPROTO_UDP) flags = IPN_UDP; if (flags & IPN_TCPUDP) { + minlen += 8; /* + 64bits of data to get ports */ + if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen) + return NULL; tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2)); if (dir == NAT_INBOUND) return nat_inlookup(fin->fin_ifp, flags, @@ -1576,7 +1619,10 @@ int dir; if ((flags & IPN_TCPUDP) != 0) { tcphdr_t *tcp; - /* XXX - what if this is bogus hl and we go off the end ? */ + /* + * XXX - what if this is bogus hl and we go off the end ? + * In this case, nat_icmpinlookup() will have returned NULL. + */ tcp = (tcphdr_t *)((((char *)oip) + (oip->ip_hl << 2))); if (nat->nat_dir == NAT_OUTBOUND) { diff --git a/sys/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c index fa8e050..f05c887 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.c +++ b/sys/contrib/ipfilter/netinet/ip_state.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.12 2000/06/19 02:38:37 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.17 2000/08/08 16:01:03 darrenr Exp $"; #endif #include @@ -180,7 +180,7 @@ static ips_stat_t *fr_statetstats() * flush state tables. two actions currently defined: * which == 0 : flush all state table entries * which == 1 : flush TCP connections which have started to close but are - * stuck for some reason. + * stuck for some reason. */ static int fr_state_flush(which) int which; @@ -371,8 +371,8 @@ caddr_t data; sizeof(ips.ips_fr)); error = IWCOPY((caddr_t)&ips, ipsp, sizeof(ips)); if (error) - return EFAULT; - return 0; + error = EFAULT; + return error; } @@ -477,6 +477,7 @@ register ipstate_t *is; is->is_phnext = ips_table + hv; is->is_hnext = ips_table[hv]; ips_table[hv] = is; + ips_num++; } @@ -557,7 +558,6 @@ u_int flags; case ND_NEIGHBOR_SOLICIT : is->is_icmp.ics_type = ic->icmp_type + 1; break; - break; #endif case ICMP_ECHO : case ICMP_TSTAMP : @@ -669,11 +669,10 @@ u_int flags; if (pass & FR_LOGFIRST) is->is_pass &= ~(FR_LOGFIRST|FR_LOG); fr_stinsert(is); - ips_num++; if (is->is_p == IPPROTO_TCP) { MUTEX_ENTER(&is->is_lock); fr_tcp_age(&is->is_age, is->is_state, fin, - tcp->th_sport == is->is_sport); + 0); /* 0 = packet from the source */ MUTEX_EXIT(&is->is_lock); } #ifdef IPFILTER_LOG @@ -785,7 +784,8 @@ tcphdr_t *tcp; * Nearing end of connection, start timeout. */ MUTEX_ENTER(&is->is_lock); - fr_tcp_age(&is->is_age, is->is_state, fin, source); + /* source ? 0 : 1 -> !source */ + fr_tcp_age(&is->is_age, is->is_state, fin, !source); MUTEX_EXIT(&is->is_lock); ret = 1; } @@ -970,12 +970,12 @@ fr_info_t *fin; union i6addr dst, src; struct icmp *ic; u_short savelen; + icmphdr_t *icmp; fr_info_t ofin; + int type, len; tcphdr_t *tcp; - icmphdr_t *icmp; frentry_t *fr; ip_t *oip; - int type; u_int hv; /* @@ -1000,6 +1000,46 @@ fr_info_t *fin; if (fin->fin_plen < ICMPERR_MAXPKTLEN + ((oip->ip_hl - 5) << 2)) return NULL; + /* + * Sanity checks. + */ + len = fin->fin_dlen - ICMPERR_ICMPHLEN; + if ((len <= 0) || ((oip->ip_hl << 2) > len)) + return NULL; + + /* + * Is the buffer big enough for all of it ? It's the size of the IP + * header claimed in the encapsulated part which is of concern. It + * may be too big to be in this buffer but not so big that it's + * outside the ICMP packet, leading to TCP deref's causing problems. + * This is possible because we don't know how big oip_hl is when we + * do the pullup early in fr_check() and thus can't gaurantee it is + * all here now. + */ +#ifdef _KERNEL + { + mb_t *m; + +# if SOLARIS + m = fin->fin_qfm; + if ((char *)oip + len > (char *)m->b_wptr) + return NULL; +# else + m = *(mb_t **)fin->fin_mp; + if ((char *)oip + len > (char *)ip + m->m_len) + return NULL; +# endif + } +#endif + + /* + * in the IPv4 case we must zero the i6addr union otherwise + * the IP6EQ and IP6NEQ macros produce the wrong results because + * of the 'junk' in the unused part of the union + */ + bzero(&src, sizeof(src)); + bzero(&dst, sizeof(dst)); + if (oip->ip_p == IPPROTO_ICMP) { icmp = (icmphdr_t *)((char *)oip + (oip->ip_hl << 2)); @@ -1028,9 +1068,11 @@ fr_info_t *fin; hv += icmp->icmp_seq; hv %= fr_statesize; - oip->ip_len = ntohs(oip->ip_len); + savelen = oip->ip_len; + oip->ip_len = len; + ofin.fin_v = 4; fr_makefrip(oip->ip_hl << 2, oip, &ofin); - oip->ip_len = htons(oip->ip_len); + oip->ip_len = savelen; ofin.fin_ifp = fin->fin_ifp; ofin.fin_out = !fin->fin_out; ofin.fin_mp = NULL; /* if dereferenced, panic XXX */ @@ -1077,7 +1119,8 @@ fr_info_t *fin; * 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; + oip->ip_len = len; + ofin.fin_v = 4; fr_makefrip(oip->ip_hl << 2, oip, &ofin); oip->ip_len = savelen; ofin.fin_ifp = fin->fin_ifp; @@ -1198,7 +1241,15 @@ fr_info_t *fin; case IPPROTO_TCP : { register u_short dport = tcp->th_dport, sport = tcp->th_sport; + register int i; + i = tcp->th_flags; + /* + * Just plain ignore RST flag set with either FIN or SYN. + */ + if ((i & TH_RST) && + ((i & (TH_FIN|TH_SYN|TH_RST)) != TH_RST)) + break; tryagain = 0; retry_tcp: hvm = hv % fr_statesize; @@ -1384,6 +1435,27 @@ void fr_timeoutstate() /* * Original idea freom Pradeep Krishnan for use primarily with NAT code. * (pkrishna@netcom.com) + * + * Rewritten by Arjan de Vet , 2000-07-29: + * + * - (try to) base state transitions on real evidence only, + * i.e. packets that are sent and have been received by ipfilter; + * diagram 18.12 of TCP/IP volume 1 by W. Richard Stevens was used. + * + * - deal with half-closed connections correctly; + * + * - store the state of the source in state[0] such that ipfstat + * displays the state as source/dest instead of dest/source; the calls + * to fr_tcp_age have been changed accordingly. + * + * Parameters: + * + * state[0] = state of source (host that initiated connection) + * state[1] = state of dest (host that accepted the connection) + * + * dir == 0 : a packet from source to dest + * dir == 1 : a packet from dest to source + * */ void fr_tcp_age(age, state, fin, dir) u_long *age; @@ -1410,67 +1482,192 @@ int dir; return; } - *age = fr_tcptimeout; /* 1 min */ + *age = fr_tcptimeout; /* default 4 mins */ switch(state[dir]) { - case TCPS_CLOSED: + case TCPS_CLOSED: /* 0 */ + if ((flags & TH_OPENING) == TH_OPENING) { + /* + * 'dir' received an S and sends SA in response, + * CLOSED -> SYN_RECEIVED + */ + state[dir] = TCPS_SYN_RECEIVED; + *age = fr_tcptimeout; + } else if ((flags & (TH_SYN|TH_ACK)) == TH_SYN) { + /* 'dir' sent S, CLOSED -> SYN_SENT */ + state[dir] = TCPS_SYN_SENT; + *age = fr_tcptimeout; + } + /* + * The next piece of code makes it possible to get + * already established connections into the state table + * after a restart or reload of the filter rules; this + * does not work when a strict 'flags S keep state' is + * used for tcp connections of course + */ if ((flags & (TH_FIN|TH_SYN|TH_RST|TH_ACK)) == TH_ACK) { + /* we saw an A, guess 'dir' is in ESTABLISHED mode */ state[dir] = TCPS_ESTABLISHED; *age = fr_tcpidletimeout; } - case TCPS_FIN_WAIT_2: - if ((flags & TH_OPENING) == TH_OPENING) + /* + * TODO: besides regular ACK packets we can have other + * packets as well; it is yet to be determined how we + * should initialize the states in those cases + */ + break; + + case TCPS_LISTEN: /* 1 */ + /* NOT USED */ + break; + + case TCPS_SYN_SENT: /* 2 */ + if ((flags & (TH_SYN|TH_FIN|TH_ACK)) == TH_ACK) { + /* + * We see an A from 'dir' which is in SYN_SENT + * state: 'dir' sent an A in response to an SA + * which it received, SYN_SENT -> ESTABLISHED + */ + state[dir] = TCPS_ESTABLISHED; + *age = fr_tcpidletimeout; + } else if (flags & TH_FIN) { + /* + * We see an F from 'dir' which is in SYN_SENT + * state and wants to close its side of the + * connection; SYN_SENT -> FIN_WAIT_1 + */ + state[dir] = TCPS_FIN_WAIT_1; + *age = fr_tcpidletimeout; /* or fr_tcptimeout? */ + } else if ((flags & TH_OPENING) == TH_OPENING) { + /* + * We see an SA from 'dir' which is already in + * SYN_SENT state, this means we have a + * simultaneous open; SYN_SENT -> SYN_RECEIVED + */ state[dir] = TCPS_SYN_RECEIVED; - else if (flags & TH_SYN) - state[dir] = TCPS_SYN_SENT; + *age = fr_tcptimeout; + } break; - case TCPS_SYN_RECEIVED: - case TCPS_SYN_SENT: - if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) { + + case TCPS_SYN_RECEIVED: /* 3 */ + if ((flags & (TH_SYN|TH_FIN|TH_ACK)) == TH_ACK) { + /* + * We see an A from 'dir' which was in SYN_RECEIVED + * state so it must now be in established state, + * SYN_RECEIVED -> ESTABLISHED + */ 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; + } else if (flags & TH_FIN) { + /* + * We see an F from 'dir' which is in SYN_RECEIVED + * state and wants to close its side of the connection; + * SYN_RECEIVED -> FIN_WAIT_1 + */ + state[dir] = TCPS_FIN_WAIT_1; + *age = fr_tcpidletimeout; /* or fr_tcptimeout? */ } break; - case TCPS_ESTABLISHED: + + case TCPS_ESTABLISHED: /* 4 */ if (flags & TH_FIN) { - state[dir] = TCPS_CLOSE_WAIT; - if (!(flags & TH_PUSH) && !dlen && - ostate > TCPS_ESTABLISHED) - *age = fr_tcplastack; - else - *age = fr_tcpclosewait; - } else { - if (ostate < TCPS_CLOSE_WAIT) + /* + * 'dir' closed its side of the connection; this + * gives us a half-closed connection; + * ESTABLISHED -> FIN_WAIT_1 + */ + state[dir] = TCPS_FIN_WAIT_1; + *age = fr_tcpidletimeout; + } else if (flags & TH_ACK) { + /* an ACK, should we exclude other flags here? */ + if (ostate == TCPS_FIN_WAIT_1) { + /* + * We know the other side did an active close, + * so we are ACKing the recvd FIN packet (does + * the window matching code guarantee this?) + * and go into CLOSE_WAIT state; this gives us + * a half-closed connection + */ + state[dir] = TCPS_CLOSE_WAIT; + *age = fr_tcpidletimeout; + } else if (ostate < TCPS_CLOSE_WAIT) + /* + * Still a fully established connection, + * reset timeout + */ *age = fr_tcpidletimeout; } break; - case TCPS_CLOSE_WAIT: - if ((flags & TH_FIN) && !(flags & TH_PUSH) && !dlen && - ostate > TCPS_ESTABLISHED) { + + case TCPS_CLOSE_WAIT: /* 5 */ + if (flags & TH_FIN) { + /* + * Application closed and 'dir' sent a FIN, we're now + * going into LAST_ACK state + */ *age = fr_tcplastack; state[dir] = TCPS_LAST_ACK; + } else { + /* + * We remain in CLOSE_WAIT because the other side has + * closed already and we did not close our side yet; + * reset timeout + */ + *age = fr_tcpidletimeout; + } + break; + + case TCPS_FIN_WAIT_1: /* 6 */ + if ((flags & TH_ACK) && ostate > TCPS_CLOSE_WAIT) { + /* + * If the other side is not active anymore it has sent + * us a FIN packet that we are ack'ing now with an ACK; + * this means both sides have now closed the connection + * and we go into TIME_WAIT + */ + /* + * XXX: how do we know we really are ACKing the FIN + * packet here? does the window code guarantee that? + */ + state[dir] = TCPS_TIME_WAIT; + *age = fr_tcptimeout; } else - *age = fr_tcpclosewait; + /* + * We closed our side of the connection already but the + * other side is still active (ESTABLISHED/CLOSE_WAIT); + * continue with this half-closed connection + */ + *age = fr_tcpidletimeout; + break; + + case TCPS_CLOSING: /* 7 */ + /* NOT USED */ break; - case TCPS_LAST_ACK: + + case TCPS_LAST_ACK: /* 8 */ if (flags & TH_ACK) { - state[dir] = TCPS_FIN_WAIT_2; - if (!(flags & TH_PUSH) && !dlen && - ostate > TCPS_ESTABLISHED) + if ((flags & TH_PUSH) || dlen) + /* + * There is still data to be delivered, reset + * timeout + */ *age = fr_tcplastack; - else { - *age = fr_tcpclosewait; - state[dir] = TCPS_CLOSE_WAIT; - } } + /* + * We cannot detect when we go out of LAST_ACK state to CLOSED + * because that is based on the reception of ACK packets; + * ipfilter can only detect that a packet has been sent by a + * host + */ + break; + + case TCPS_FIN_WAIT_2: /* 9 */ + /* NOT USED */ + break; + + case TCPS_TIME_WAIT: /* 10 */ + /* we're in 2MSL timeout now */ break; } } @@ -1579,6 +1776,7 @@ fr_info_t *fin; hv %= fr_statesize; oip->ip6_plen = ntohs(oip->ip6_plen); + ofin.fin_v = 6; fr_makefrip(sizeof(*oip), (ip_t *)oip, &ofin); oip->ip6_plen = htons(oip->ip6_plen); ofin.fin_ifp = fin->fin_ifp; diff --git a/sys/contrib/ipfilter/netinet/ipl.h b/sys/contrib/ipfilter/netinet/ipl.h index bb2523d..866d34d 100644 --- a/sys/contrib/ipfilter/netinet/ipl.h +++ b/sys/contrib/ipfilter/netinet/ipl.h @@ -6,12 +6,12 @@ * to the original author and the contributors. * * @(#)ipl.h 1.21 6/5/96 - * $Id: ipl.h,v 2.15.2.9 2000/07/19 13:40:04 darrenr Exp $ + * $Id: ipl.h,v 2.15.2.10 2000/08/07 15:10:09 darrenr Exp $ */ #ifndef __IPL_H__ #define __IPL_H__ -#define IPL_VERSION "IP Filter: v3.4.8" +#define IPL_VERSION "IP Filter: v3.4.9" #endif diff --git a/sys/contrib/ipfilter/netinet/mlfk_ipl.c b/sys/contrib/ipfilter/netinet/mlfk_ipl.c index 4412960..f869149 100644 --- a/sys/contrib/ipfilter/netinet/mlfk_ipl.c +++ b/sys/contrib/ipfilter/netinet/mlfk_ipl.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: mlfk_ipl.c,v 2.1.2.1 2000/04/26 12:17:24 darrenr Exp $ + * $Id: mlfk_ipl.c,v 2.1.2.3 2000/08/13 03:42:42 darrenr Exp $ */ @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -82,6 +83,7 @@ SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, &fr_authused, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW, &fr_defaultauthage, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, ""); #define CDEV_MAJOR 79 static struct cdevsw ipl_cdevsw = { -- cgit v1.1 From e04f9f34d2852385979f4c5287f6ab24ff055648 Mon Sep 17 00:00:00 2001 From: darrenr Date: Thu, 26 Oct 2000 12:28:47 +0000 Subject: Import IP Filter 3.4.12 into kernel source tree --- sys/contrib/ipfilter/netinet/fil.c | 61 +++- sys/contrib/ipfilter/netinet/ip_auth.h | 4 +- sys/contrib/ipfilter/netinet/ip_compat.h | 38 ++- sys/contrib/ipfilter/netinet/ip_fil.c | 39 ++- sys/contrib/ipfilter/netinet/ip_frag.c | 23 +- sys/contrib/ipfilter/netinet/ip_frag.h | 4 +- sys/contrib/ipfilter/netinet/ip_ftp_pxy.c | 24 +- sys/contrib/ipfilter/netinet/ip_nat.c | 439 +++++++++++++++++++++++---- sys/contrib/ipfilter/netinet/ip_nat.h | 14 +- sys/contrib/ipfilter/netinet/ip_raudio_pxy.c | 4 +- sys/contrib/ipfilter/netinet/ip_state.c | 144 +++++---- sys/contrib/ipfilter/netinet/ip_state.h | 3 +- sys/contrib/ipfilter/netinet/ipl.h | 4 +- sys/contrib/ipfilter/netinet/mlfk_ipl.c | 4 +- 14 files changed, 613 insertions(+), 192 deletions(-) diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index 91b5108..b85dcf4 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/netinet/fil.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.20 2000/08/13 04:15:43 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.26 2000/10/24 11:58:17 darrenr Exp $"; #endif #include @@ -274,6 +274,16 @@ fr_info_t *fin; int minicmpsz = sizeof(struct icmp); icmphdr_t *icmp; + if (fin->fin_dlen > 1) + fin->fin_data[0] = *(u_short *)tcp; + + if ((!(plen >= hlen + minicmpsz) && !off) || + (off && off < sizeof(struct icmp))) { + fi->fi_fl |= FI_SHORT; + if (fin->fin_dlen < 2) + break; + } + icmp = (icmphdr_t *)tcp; if (!off && (icmp->icmp_type == ICMP_ECHOREPLY || @@ -291,11 +301,6 @@ fr_info_t *fin; icmp->icmp_type == ICMP_MASKREPLY)) minicmpsz = 12; - if ((!(plen >= hlen + minicmpsz) && !off) || - (off && off < sizeof(struct icmp))) - fi->fi_fl |= FI_SHORT; - if (fin->fin_dlen > 1) - fin->fin_data[0] = *(u_short *)tcp; break; } case IPPROTO_TCP : @@ -740,6 +745,7 @@ int out; #ifdef _KERNEL mb_t *mc = NULL; + int p, len; # if !defined(__SVR4) && !defined(__svr4__) # ifdef __sgi char hbuf[(0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8]; @@ -764,13 +770,26 @@ int out; } # endif /* CSUM_DELAY_DATA */ +# ifdef USE_INET6 + if (v == 6) { + len = ntohs(((ip6_t*)ip)->ip6_plen); + p = ((ip6_t *)ip)->ip6_nxt; + } else +# endif + { + p = ip->ip_p; + len = ip->ip_len; + } - if ((ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP || - ip->ip_p == IPPROTO_ICMP)) { + if ((p == IPPROTO_TCP || p == IPPROTO_UDP || p == IPPROTO_ICMP +# ifdef USE_INET6 + || (v == 6 && p == IPPROTO_ICMPV6) +# endif + )) { int plen = 0; - if ((ip->ip_off & IP_OFFMASK) == 0) - switch(ip->ip_p) + if ((v == 6) || (ip->ip_off & IP_OFFMASK) == 0) + switch(p) { case IPPROTO_TCP: plen = sizeof(tcphdr_t); @@ -780,10 +799,13 @@ int out; break; /* 96 - enough for complete ICMP error IP header */ case IPPROTO_ICMP: +# ifdef USE_INET6 + case IPPROTO_ICMPV6 : +# endif plen = ICMPERR_MAXPKTLEN - sizeof(ip_t); break; } - up = MIN(hlen + plen, ip->ip_len); + up = MIN(hlen + plen, len); if (up > m->m_len) { # ifdef __sgi @@ -830,8 +852,8 @@ int out; ip->ip_id = ntohs(ip->ip_id); changed = 0; - fin->fin_v = v; fin->fin_ifp = ifp; + fin->fin_v = v; fin->fin_out = out; fin->fin_mp = mp; fr_makefrip(hlen, ip, fin); @@ -1376,7 +1398,7 @@ nodata: * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 - * $Id: fil.c,v 2.35.2.20 2000/08/13 04:15:43 darrenr Exp $ + * $Id: fil.c,v 2.35.2.26 2000/10/24 11:58:17 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, @@ -1855,7 +1877,7 @@ size_t c; int err; #if SOLARIS - if (copyin(a, &ca, sizeof(ca))) + if (copyin(a, (char *)&ca, sizeof(ca))) return EFAULT; #else bcopy(a, &ca, sizeof(ca)); @@ -1875,7 +1897,7 @@ size_t c; int err; #if SOLARIS - if (copyin(b, &ca, sizeof(ca))) + if (copyin(b, (char *)&ca, sizeof(ca))) return EFAULT; #else bcopy(b, &ca, sizeof(ca)); @@ -1969,6 +1991,15 @@ friostat_t *fiop; fiop->f_acctin6[1] = ipacct6[0][1]; fiop->f_acctout6[0] = ipacct6[1][0]; fiop->f_acctout6[1] = ipacct6[1][1]; +#else + fiop->f_fin6[0] = NULL; + fiop->f_fin6[1] = NULL; + fiop->f_fout6[0] = NULL; + fiop->f_fout6[1] = NULL; + fiop->f_acctin6[0] = NULL; + fiop->f_acctin6[1] = NULL; + fiop->f_acctout6[0] = NULL; + fiop->f_acctout6[1] = NULL; #endif fiop->f_active = fr_active; fiop->f_froute[0] = ipl_frouteok[0]; diff --git a/sys/contrib/ipfilter/netinet/ip_auth.h b/sys/contrib/ipfilter/netinet/ip_auth.h index b543318..681a6e5 100644 --- a/sys/contrib/ipfilter/netinet/ip_auth.h +++ b/sys/contrib/ipfilter/netinet/ip_auth.h @@ -5,7 +5,7 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: ip_auth.h,v 2.3.2.1 2000/05/22 10:26:11 darrenr Exp $ + * $Id: ip_auth.h,v 2.3.2.2 2000/10/19 15:38:44 darrenr Exp $ * */ #ifndef __IP_AUTH_H__ @@ -46,8 +46,6 @@ typedef struct fr_authstat { extern frentry_t *ipauth; extern struct fr_authstat fr_authstats; extern int fr_defaultauthage; -extern int fr_authstart; -extern int fr_authend; extern int fr_authsize; extern int fr_authused; extern int fr_auth_lock; diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h index ba9e014..2369cf0 100644 --- a/sys/contrib/ipfilter/netinet/ip_compat.h +++ b/sys/contrib/ipfilter/netinet/ip_compat.h @@ -6,7 +6,7 @@ * to the original author and the contributors. * * @(#)ip_compat.h 1.8 1/14/96 - * $Id: ip_compat.h,v 2.26.2.4 2000/08/13 03:51:03 darrenr Exp $ + * $Id: ip_compat.h,v 2.26.2.6 2000/10/19 15:39:05 darrenr Exp $ */ #ifndef __IP_COMPAT_H__ @@ -263,6 +263,12 @@ union i6addr { #if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL)) +# ifdef IPFILTER_LKM +# include +# define ACTUALLY_LKM_NOT_KERNEL +# else +# include +# endif # if __FreeBSD__ < 3 # include # else @@ -288,6 +294,19 @@ union i6addr { # define ATOMIC_DEC32 ATOMIC_DEC # define ATOMIC_DEC16 ATOMIC_DEC #endif +#ifdef __sgi +# define hz HZ +# include +# define IPF_LOCK_PL plhi +# include +#undef kmutex_t +typedef struct { + lock_t *l; + int pl; +} kmutex_t; +# undef MUTEX_INIT +# undef MUTEX_DESTROY +#endif #ifdef KERNEL # if SOLARIS # if SOLARIS2 >= 6 @@ -337,8 +356,8 @@ union i6addr { # define MUTEX_DESTROY(x) mutex_destroy(x) # define MUTEX_EXIT(x) mutex_exit(x) # define MTOD(m,t) (t)((m)->b_rptr) -# define IRCOPY(a,b,c) copyin((a), (b), (c)) -# define IWCOPY(a,b,c) copyout((a), (b), (c)) +# define IRCOPY(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) +# define IWCOPY(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) # define IRCOPYPTR ircopyptr # define IWCOPYPTR iwcopyptr # define FREE_MB_T(m) freemsg(m) @@ -383,15 +402,6 @@ extern ill_t *get_unit __P((char *, int)); # define IFNAME(x) ((ill_t *)x)->ill_name # else /* SOLARIS */ # if defined(__sgi) -# define hz HZ -# include -# define IPF_LOCK_PL plhi -# include -#undef kmutex_t -typedef struct { - lock_t *l; - int pl; -} kmutex_t; # define ATOMIC_INC(x) { MUTEX_ENTER(&ipf_rw); \ (x)++; MUTEX_EXIT(&ipf_rw); } # define ATOMIC_DEC(x) { MUTEX_ENTER(&ipf_rw); \ @@ -404,8 +414,8 @@ typedef struct { # define MUTEX_DOWNGRADE(x) ; # define RWLOCK_EXIT(x) MUTEX_EXIT(x) # define MUTEX_EXIT(x) UNLOCK((x)->l, (x)->pl); -# define MUTEX_INIT(x,y,z) (x).l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP) -# define MUTEX_DESTROY(x) LOCK_DEALLOC((x).l) +# define MUTEX_INIT(x,y,z) (x)->l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP) +# define MUTEX_DESTROY(x) LOCK_DEALLOC((x)->l) # else /* __sgi */ # define ATOMIC_INC(x) (x)++ # define ATOMIC_DEC(x) (x)-- diff --git a/sys/contrib/ipfilter/netinet/ip_fil.c b/sys/contrib/ipfilter/netinet/ip_fil.c index 2e8af26..9253775 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil.c +++ b/sys/contrib/ipfilter/netinet/ip_fil.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.15 2000/08/05 14:49:08 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.17 2000/10/19 15:39:42 darrenr Exp $"; #endif #ifndef SOLARIS @@ -171,6 +171,9 @@ struct callout_handle ipfr_slowtimer_ch; # include struct callout ipfr_slowtimer_ch; #endif +#if defined(__sgi) && defined(_KERNEL) +toid_t ipfr_slowtimer_ch; +#endif #if (_BSDI_VERSION >= 199510) && defined(_KERNEL) # include @@ -318,7 +321,7 @@ pfil_error: callout_init(&ipfr_slowtimer_ch); callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL); # else -# if (__FreeBSD_version >= 300000) && defined(_KERNEL) +# if (__FreeBSD_version >= 300000) || defined(__sgi) ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); # else timeout(ipfr_slowtimer, NULL, hz/2); @@ -348,7 +351,7 @@ int ipldetach() untimeout(ipfr_slowtimer, NULL, ipfr_slowtimer_ch); # else # ifdef __sgi - untimeout(ipfr_slowtimer); + untimeout(ipfr_slowtimer_ch); # else untimeout(ipfr_slowtimer, NULL); # endif @@ -975,8 +978,10 @@ fr_info_t *fin; if (m == NULL) return -1; - if (tcp->th_flags & TH_SYN) - tlen = 1; + tlen = oip->ip_len - fin->fin_hlen - (tcp->th_off << 2) + + ((tcp->th_flags & TH_SYN) ? 1 : 0) + + ((tcp->th_flags & TH_FIN) ? 1 : 0); + #ifdef USE_INET6 hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); #else @@ -997,11 +1002,16 @@ fr_info_t *fin; tcp2->th_sport = tcp->th_dport; tcp2->th_dport = tcp->th_sport; - tcp2->th_ack = ntohl(tcp->th_seq); - tcp2->th_ack += tlen; - tcp2->th_ack = htonl(tcp2->th_ack); + if (tcp->th_flags & TH_ACK) { + tcp2->th_seq = tcp->th_ack; + tcp2->th_flags = TH_RST; + } else { + tcp2->th_ack = ntohl(tcp->th_seq); + tcp2->th_ack += tlen; + tcp2->th_ack = htonl(tcp2->th_ack); + tcp2->th_flags = TH_RST|TH_ACK; + } tcp2->th_off = sizeof(*tcp2) >> 2; - tcp2->th_flags = TH_RST|TH_ACK; # ifdef USE_INET6 if (fin->fin_v == 6) { ip6->ip6_plen = htons(sizeof(struct tcphdr)); @@ -1143,7 +1153,12 @@ int dst; m_freem(m); return ENOBUFS; } +# ifdef M_TRAILINGSPACE + m->m_len = 0; + avail = M_TRAILINGSPACE(m); +# else avail = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN; +# endif xtra = MIN(ntohs(oip6->ip6_plen) + sizeof(ip6_t), avail - hlen - sizeof(*icmp) - max_linkhdr); if (dst == 0) { @@ -1177,6 +1192,12 @@ int dst; icmp->icmp_type = type; icmp->icmp_code = fin->fin_icode; icmp->icmp_cksum = 0; +#ifdef icmp_nextmtu + if (type == ICMP_UNREACH && + fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp) + icmp->icmp_nextmtu = htons(((struct ifnet *) ifp)->if_mtu); +#endif + if (avail) { bcopy((char *)oip, (char *)&icmp->icmp_ip, MIN(ohlen, avail)); avail -= MIN(ohlen, avail); diff --git a/sys/contrib/ipfilter/netinet/ip_frag.c b/sys/contrib/ipfilter/netinet/ip_frag.c index 5019c60..1cb86c1 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.c +++ b/sys/contrib/ipfilter/netinet/ip_frag.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.4 2000/06/06 15:49:15 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.5 2000/10/19 15:39:58 darrenr Exp $"; #endif #if defined(KERNEL) && !defined(_KERNEL) @@ -214,7 +214,7 @@ u_int pass; ipfr_t *ipf; if ((ip->ip_v != 4) || (fr_frag_lock)) - return NULL; + return -1; WRITE_ENTER(&ipf_frag); ipf = ipfr_new(ip, fin, pass, ipfr_heads); RWLOCK_EXIT(&ipf_frag); @@ -231,7 +231,7 @@ nat_t *nat; ipfr_t *ipf; if ((ip->ip_v != 4) || (fr_frag_lock)) - return NULL; + return -1; WRITE_ENTER(&ipf_natfrag); ipf = ipfr_new(ip, fin, pass, ipfr_nattab); if (ipf != NULL) { @@ -328,13 +328,16 @@ fr_info_t *fin; ipf = ipfr_lookup(ip, fin, ipfr_nattab); if (ipf != NULL) { nat = ipf->ipfr_data; - /* - * This is the last fragment for this packet. - */ - if ((ipf->ipfr_ttl == 1) && (nat != NULL)) { - nat->nat_data = NULL; - ipf->ipfr_data = NULL; - } + if (nat->nat_ifp == fin->fin_ifp) { + /* + * This is the last fragment for this packet. + */ + if ((ipf->ipfr_ttl == 1) && (nat != NULL)) { + nat->nat_data = NULL; + ipf->ipfr_data = NULL; + } + } else + nat = NULL; } else nat = NULL; RWLOCK_EXIT(&ipf_natfrag); diff --git a/sys/contrib/ipfilter/netinet/ip_frag.h b/sys/contrib/ipfilter/netinet/ip_frag.h index 6a3bd2c..61b88aa 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.h +++ b/sys/contrib/ipfilter/netinet/ip_frag.h @@ -6,7 +6,7 @@ * to the original author and the contributors. * * @(#)ip_frag.h 1.5 3/24/96 - * $Id: ip_frag.h,v 2.4 2000/03/13 22:10:21 darrenr Exp $ + * $Id: ip_frag.h,v 2.4.2.1 2000/10/19 15:40:13 darrenr Exp $ */ #ifndef __IP_FRAG_H__ @@ -60,6 +60,6 @@ extern void ipfr_slowtimer __P((void *)); # endif #else extern int ipfr_slowtimer __P((void)); -#endif +#endif /* (BSD >= 199306) || SOLARIS */ #endif /* __IP_FIL_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c index 84dc8b9..ffa7c1b 100644 --- a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c @@ -2,7 +2,7 @@ * Simple FTP transparent proxy for in-kernel use. For use with the NAT * code. * - * $Id: ip_ftp_pxy.c,v 2.7.2.13 2000/08/07 12:35:27 darrenr Exp $ + * $Id: ip_ftp_pxy.c,v 2.7.2.17 2000/10/19 15:40:40 darrenr Exp $ */ #if SOLARIS && defined(_KERNEL) extern kmutex_t ipf_rw; @@ -146,6 +146,7 @@ int dlen; } else return 0; a5 >>= 8; + a5 &= 0xff; /* * Calculate new address parts for PORT command */ @@ -214,7 +215,7 @@ int dlen; sum2 -= sum1; sum2 = (sum2 & 0xffff) + (sum2 >> 16); - fix_outcksum(&ip->ip_sum, sum2, 0); + fix_outcksum(&ip->ip_sum, sum2); #endif ip->ip_len += inc; } @@ -441,7 +442,7 @@ int dlen; sum2 -= sum1; sum2 = (sum2 & 0xffff) + (sum2 >> 16); - fix_outcksum(&ip->ip_sum, sum2, 0); + fix_outcksum(&ip->ip_sum, sum2); #endif /* SOLARIS || defined(__sgi) */ ip->ip_len += inc; } @@ -670,15 +671,18 @@ int rv; while ((rptr < wptr) && (*rptr != '\r')) rptr++; - if ((*rptr == '\r') && (rptr + 1 < wptr)) { - if (*(rptr + 1) == '\n') { - rptr += 2; - f->ftps_junk = 0; + if (*rptr == '\r') { + if (rptr + 1 < wptr) { + if (*(rptr + 1) == '\n') { + rptr += 2; + f->ftps_junk = 0; + } else + rptr++; } else - rptr++; + break; } - f->ftps_rptr = rptr; } + f->ftps_rptr = rptr; if (rptr == wptr) { rptr = wptr = f->ftps_buf; @@ -762,5 +766,7 @@ char **ptr; j += c - '0'; } *ptr = s; + i &= 0xff; + j &= 0xff; return (i << 8) | j; } diff --git a/sys/contrib/ipfilter/netinet/ip_nat.c b/sys/contrib/ipfilter/netinet/ip_nat.c index bbcff77..d52f48d 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.c +++ b/sys/contrib/ipfilter/netinet/ip_nat.c @@ -9,7 +9,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 2.37.2.21 2000/08/12 07:32:40 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.25 2000/10/25 10:38:47 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) @@ -118,6 +118,7 @@ u_int ipf_nattable_sz = NAT_TABLE_SZ; u_int ipf_natrules_sz = NAT_SIZE; u_int ipf_rdrrules_sz = RDR_SIZE; u_int ipf_hostmap_sz = HOSTMAP_SIZE; +int nat_wilds = 0; u_32_t nat_masks = 0; u_32_t rdr_masks = 0; ipnat_t **nat_rules = NULL; @@ -143,6 +144,7 @@ static void nat_delnat __P((struct ipnat *)); static int fr_natgetent __P((caddr_t)); static int fr_natgetsz __P((caddr_t)); static int fr_natputent __P((caddr_t)); +static void nat_tabmove __P((nat_t *, u_int)); static int nat_match __P((fr_info_t *, ipnat_t *, ip_t *)); static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr, struct in_addr)); @@ -300,10 +302,9 @@ struct hostmap *hm; } -void fix_outcksum(sp, n , len) +void fix_outcksum(sp, n) u_short *sp; u_32_t n; -int len; { register u_short sumshort; register u_32_t sum1; @@ -326,10 +327,9 @@ int len; } -void fix_incksum(sp, n , len) +void fix_incksum(sp, n) u_short *sp; u_32_t n; -int len; { register u_short sumshort; register u_32_t sum1; @@ -357,6 +357,38 @@ int len; /* + * fix_datacksum is used *only* for the adjustments of checksums in the data + * section of an IP packet. + * + * The only situation in which you need to do this is when NAT'ing an + * ICMP error message. Such a message, contains in its body the IP header + * of the original IP packet, that causes the error. + * + * You can't use fix_incksum or fix_outcksum in that case, because for the + * kernel the data section of the ICMP error is just data, and no special + * processing like hardware cksum or ntohs processing have been done by the + * kernel on the data section. + */ +void fix_datacksum(sp, n) +u_short *sp; +u_32_t n; +{ + register u_short sumshort; + register u_32_t sum1; + + if (!n) + return; + + sum1 = (~ntohs(*sp)) & 0xffff; + sum1 += (n); + sum1 = (sum1 >> 16) + (sum1 & 0xffff); + /* Again */ + sum1 = (sum1 >> 16) + (sum1 & 0xffff); + sumshort = ~(u_short)sum1; + *(sp) = htons(sumshort); +} + +/* * How the NAT is organised and works. * * Inside (interface y) NAT Outside (interface x) @@ -856,8 +888,8 @@ caddr_t data; /* * Initialize all these so that nat_delete() doesn't cause a crash. */ - nat->nat_hstart[0] = NULL; - nat->nat_hstart[1] = NULL; + nat->nat_phnext[0] = NULL; + nat->nat_phnext[1] = NULL; fr = nat->nat_fr; nat->nat_fr = NULL; aps = nat->nat_aps; @@ -969,22 +1001,16 @@ junkput: static void nat_delete(natd) struct nat *natd; { - register struct nat **natp, *nat; struct ipnat *ipn; - for (natp = natd->nat_hstart[0]; natp && (nat = *natp); - natp = &nat->nat_hnext[0]) - if (nat == natd) { - *natp = nat->nat_hnext[0]; - break; - } - - for (natp = natd->nat_hstart[1]; natp && (nat = *natp); - natp = &nat->nat_hnext[1]) - if (nat == natd) { - *natp = nat->nat_hnext[1]; - break; - } + if (natd->nat_flags & FI_WILDP) + nat_wilds--; + if (natd->nat_hnext[0]) + natd->nat_hnext[0]->nat_phnext[0] = natd->nat_phnext[0]; + *natd->nat_phnext[0] = natd->nat_hnext[0]; + if (natd->nat_hnext[1]) + natd->nat_hnext[1]->nat_phnext[1] = natd->nat_phnext[1]; + *natd->nat_phnext[1] = natd->nat_hnext[1]; if (natd->nat_fr != NULL) { ATOMIC_DEC32(natd->nat_fr->fr_ref); @@ -1029,7 +1055,7 @@ static int nat_flushtable() { register nat_t *nat, **natp; register int j = 0; - + /* * ALL NAT mappings deleted, so lets just make the deletions * quicker. @@ -1121,6 +1147,8 @@ int direction; bzero((char *)nat, sizeof(*nat)); nat->nat_flags = flags; + if (flags & FI_WILDP) + nat_wilds++; /* * Search the current table for a match. */ @@ -1443,16 +1471,22 @@ nat_t *nat; nat->nat_next = nat_instances; nat_instances = nat; + hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, ipf_nattable_sz); natp = &nat_table[0][hv]; - nat->nat_hstart[0] = natp; + if (*natp) + (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; + nat->nat_phnext[0] = natp; nat->nat_hnext[0] = *natp; *natp = nat; + hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, ipf_nattable_sz); natp = &nat_table[1][hv]; - nat->nat_hstart[1] = natp; + if (*natp) + (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; + nat->nat_phnext[1] = natp; nat->nat_hnext[1] = *natp; *natp = nat; @@ -1560,12 +1594,16 @@ int dir; u_32_t sum1, sum2, sumd; struct in_addr in; icmphdr_t *icmp; + udphdr_t *udp; nat_t *nat; ip_t *oip; int flags = 0; if ((fin->fin_fi.fi_fl & FI_SHORT) || (ip->ip_off & IP_OFFMASK)) return NULL; + /* + * nat_icmplookup() will return NULL for `defective' packets. + */ if ((ip->ip_v != 4) || !(nat = nat_icmplookup(ip, fin, dir))) return NULL; *nflags = IPN_ICMPERR; @@ -1575,16 +1613,33 @@ int dir; flags = IPN_TCP; else if (oip->ip_p == IPPROTO_UDP) flags = IPN_UDP; + udp = (udphdr_t *)((((char *)oip) + (oip->ip_hl << 2))); /* * Need to adjust ICMP header to include the real IP#'s and * port #'s. Only apply a checksum change relative to the - * IP address change is it will be modified again in ip_natout + * IP address change as it will be modified again in ip_natout * for both address and port. Two checksum changes are * necessary for the two header address changes. Be careful * to only modify the checksum once for the port # and twice * for the IP#. */ + /* + * Step 1 + * Fix the IP addresses in the offending IP packet. You also need + * to adjust the IP header checksum of that offending IP packet + * and the ICMP checksum of the ICMP error message itself. + * + * Unfortunately, for UDP and TCP, the IP addresses are also contained + * in the pseudo header that is used to compute the UDP resp. TCP + * checksum. So, we must compensate that as well. Even worse, the + * change in the UDP and TCP checksums require yet another + * adjustment of the ICMP checksum of the ICMP error message. + * + * For the moment we forget about TCP, because that checksum is not + * in the first 8 bytes, so it will not be available in most cases. + */ + if (nat->nat_dir == NAT_OUTBOUND) { sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr)); in = nat->nat_inip; @@ -1600,19 +1655,117 @@ int dir; CALC_SUMD(sum1, sum2, sumd); if (nat->nat_dir == NAT_OUTBOUND) { - fix_incksum(&oip->ip_sum, sumd, 0); + /* + * Fix IP checksum of the offending IP packet to adjust for + * the change in the IP address. + * + * Normally, you would expect that the ICMP checksum of the + * ICMP error message needs to be adjusted as well for the + * IP address change in oip. + * However, this is a NOP, because the ICMP checksum is + * calculated over the complete ICMP packet, which includes the + * changed oip IP addresses and oip->ip_sum. However, these + * two changes cancel each other out (if the delta for + * the IP address is x, then the delta for ip_sum is minus x), + * so no change in the icmp_cksum is necessary. + * + * Be careful that nat_dir refers to the direction of the + * offending IP packet (oip), not to its ICMP response (icmp) + */ + fix_datacksum(&oip->ip_sum, sumd); - sumd += (sumd & 0xffff); - while (sumd > 0xffff) - sumd = (sumd & 0xffff) + (sumd >> 16); - fix_outcksum(&icmp->icmp_cksum, sumd, 0); + /* + * Fix UDP pseudo header checksum to compensate for the + * IP address change. + */ + if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + /* + * The UDP checksum is optional, only adjust it + * if it has been set. + */ + sum1 = ntohs(udp->uh_sum); + fix_datacksum(&udp->uh_sum, sumd); + sum2 = ntohs(udp->uh_sum); + + /* + * Fix ICMP checksum to compensate the UDP + * checksum adjustment. + */ + CALC_SUMD(sum1, sum2, sumd); + fix_outcksum(&icmp->icmp_cksum, sumd); + } + +#if 0 + /* + * Fix TCP pseudo header checksum to compensate for the + * IP address change. Before we can do the change, we + * must make sure that oip is sufficient large to hold + * the TCP checksum (normally it does not!). + */ + if (oip->ip_p == IPPROTO_TCP) { + + } +#endif } else { - fix_outcksum(&oip->ip_sum, sumd, 0); + + /* + * Fix IP checksum of the offending IP packet to adjust for + * the change in the IP address. + * + * Normally, you would expect that the ICMP checksum of the + * ICMP error message needs to be adjusted as well for the + * IP address change in oip. + * However, this is a NOP, because the ICMP checksum is + * calculated over the complete ICMP packet, which includes the + * changed oip IP addresses and oip->ip_sum. However, these + * two changes cancel each other out (if the delta for + * the IP address is x, then the delta for ip_sum is minus x), + * so no change in the icmp_cksum is necessary. + * + * Be careful that nat_dir refers to the direction of the + * offending IP packet (oip), not to its ICMP response (icmp) + */ + fix_datacksum(&oip->ip_sum, sumd); + +/* XXX FV : without having looked at Solaris source code, it seems unlikely + * that SOLARIS would compensate this in the kernel (a body of an IP packet + * in the data section of an ICMP packet). I have the feeling that this should + * be unconditional, but I'm not in a position to check. + */ #if !SOLARIS && !defined(__sgi) - sumd += (sumd & 0xffff); - while (sumd > 0xffff) - sumd = (sumd & 0xffff) + (sumd >> 16); - fix_incksum(&icmp->icmp_cksum, sumd, 0); + /* + * Fix UDP pseudo header checksum to compensate for the + * IP address change. + */ + if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + /* + * The UDP checksum is optional, only adjust it + * if it has been set + */ + sum1 = ntohs(udp->uh_sum); + fix_datacksum(&udp->uh_sum, sumd); + sum2 = ntohs(udp->uh_sum); + + /* + * Fix ICMP checksum to compensate the UDP + * checksum adjustment. + */ + CALC_SUMD(sum1, sum2, sumd); + fix_incksum(&icmp->icmp_cksum, sumd); + } + +#if 0 + /* + * Fix TCP pseudo header checksum to compensate for the + * IP address change. Before we can do the change, we + * must make sure that oip is sufficient large to hold + * the TCP checksum (normally it does not!). + */ + if (oip->ip_p == IPPROTO_TCP) { + + }; +#endif + #endif } @@ -1623,23 +1776,98 @@ int dir; * XXX - what if this is bogus hl and we go off the end ? * In this case, nat_icmpinlookup() will have returned NULL. */ - tcp = (tcphdr_t *)((((char *)oip) + (oip->ip_hl << 2))); + tcp = (tcphdr_t *)udp; + + /* + * Step 2 : + * For offending TCP/UDP IP packets, translate the ports as + * well, based on the NAT specification. Of course such + * a change must be reflected in the ICMP checksum as well. + * + * Advance notice : Now it becomes complicated :-) + * + * Since the port fields are part of the TCP/UDP checksum + * of the offending IP packet, you need to adjust that checksum + * as well... but, if you change, you must change the icmp + * checksum *again*, to reflect that change. + * + * To further complicate: the TCP checksum is not in the first + * 8 bytes of the offending ip packet, so it most likely is not + * available (we might have to fix that if the encounter a + * device that returns more than 8 data bytes on icmp error) + */ if (nat->nat_dir == NAT_OUTBOUND) { if (tcp->th_sport != nat->nat_inport) { + /* + * Fix ICMP checksum to compensate port + * adjustment. + */ sum1 = ntohs(tcp->th_sport); sum2 = ntohs(nat->nat_inport); CALC_SUMD(sum1, sum2, sumd); tcp->th_sport = nat->nat_inport; - fix_outcksum(&icmp->icmp_cksum, sumd, 0); + fix_outcksum(&icmp->icmp_cksum, sumd); + + /* + * Fix udp checksum to compensate port + * adjustment. NOTE : the offending IP packet + * flows the other direction compared to the + * ICMP message. + * + * The UDP checksum is optional, only adjust + * it if it has been set. + */ + if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + + sum1 = ntohs(udp->uh_sum); + fix_datacksum(&udp->uh_sum, sumd); + sum2 = ntohs(udp->uh_sum); + + /* + * Fix ICMP checksum to + * compensate UDP checksum + * adjustment. + */ + CALC_SUMD(sum1, sum2, sumd); + fix_outcksum(&icmp->icmp_cksum, sumd); + } } } else { + if (tcp->th_dport != nat->nat_outport) { + /* + * Fix ICMP checksum to compensate port + * adjustment. + */ sum1 = ntohs(tcp->th_dport); sum2 = ntohs(nat->nat_outport); CALC_SUMD(sum1, sum2, sumd); tcp->th_dport = nat->nat_outport; - fix_incksum(&icmp->icmp_cksum, sumd, 0); + fix_incksum(&icmp->icmp_cksum, sumd); + + /* + * Fix udp checksum to compensate port + * adjustment. NOTE : the offending IP + * packet flows the other direction compared + * to the ICMP message. + * + * The UDP checksum is optional, only adjust + * it if it has been set. + */ + if (oip->ip_p == IPPROTO_UDP && udp->uh_sum) { + + sum1 = ntohs(udp->uh_sum); + fix_datacksum(&udp->uh_sum, sumd); + sum2 = ntohs(udp->uh_sum); + + /* + * Fix ICMP checksum to compensate + * UDP checksum adjustment. + */ + CALC_SUMD(sum1, sum2, sumd); + fix_incksum(&icmp->icmp_cksum, sumd); + } } } } @@ -1664,30 +1892,92 @@ register u_int flags, p; struct in_addr src , mapdst; u_32_t ports; { - register u_short sport, mapdport; + register u_short sport, dport; register nat_t *nat; register int nflags; + register u_32_t dst; u_int hv; - mapdport = ports >> 16; + dst = mapdst.s_addr; + dport = ports >> 16; sport = ports & 0xffff; flags &= IPN_TCPUDP; - hv = NAT_HASH_FN(mapdst.s_addr, mapdport, ipf_nattable_sz); + hv = NAT_HASH_FN(dst, dport, 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 && + nat->nat_outip.s_addr == dst && (((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))))) + ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))))) return nat; } - return NULL; + if (!nat_wilds || !(flags & IPN_TCPUDP)) + return NULL; + RWLOCK_EXIT(&ipf_nat); + hv = NAT_HASH_FN(dst, 0, ipf_nattable_sz); + WRITE_ENTER(&ipf_nat); + nat = nat_table[1][hv]; + for (; nat; nat = nat->nat_hnext[1]) { + nflags = nat->nat_flags; + if (ifp && ifp != nat->nat_ifp) + continue; + if (!(nflags & IPN_TCPUDP)) + continue; + if (!(nflags & FI_WILDP)) + continue; + if (nat->nat_oip.s_addr != src.s_addr || + nat->nat_outip.s_addr != dst) + continue; + if (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) && + ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))) { + hv = NAT_HASH_FN(dst, dport, ipf_nattable_sz); + nat_tabmove(nat, hv); + break; + } + } + MUTEX_DOWNGRADE(&ipf_nat); + return nat; +} + + +static void nat_tabmove(nat, hv) +nat_t *nat; +u_int hv; +{ + nat_t **natp; + + /* + * Remove the NAT entry from the old location + */ + if (nat->nat_hnext[0]) + nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; + *nat->nat_phnext[0] = nat->nat_hnext[0]; + + if (nat->nat_hnext[1]) + nat->nat_hnext[0]->nat_phnext[1] = nat->nat_phnext[1]; + *nat->nat_phnext[1] = nat->nat_hnext[1]; + + natp = &nat_table[0][hv]; + if (*natp) + (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; + nat->nat_phnext[0] = natp; + nat->nat_hnext[0] = *natp; + *natp = nat; + + /* + * Add into the NAT table in the new position + */ + natp = &nat_table[1][hv]; + if (*natp) + (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; + nat->nat_phnext[1] = natp; + nat->nat_hnext[1] = *natp; + *natp = nat; } @@ -1706,19 +1996,21 @@ u_32_t ports; register u_short sport, dport; register nat_t *nat; register int nflags; + u_32_t srcip; u_int hv; sport = ports & 0xffff; dport = ports >> 16; flags &= IPN_TCPUDP; + srcip = src.s_addr; - hv = NAT_HASH_FN(src.s_addr, sport, ipf_nattable_sz); + hv = NAT_HASH_FN(srcip, sport, 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_inip.s_addr == srcip && nat->nat_oip.s_addr == dst.s_addr && (((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP))) || (p == nat->nat_p)) && (!flags || @@ -1726,7 +2018,32 @@ u_32_t ports; (nat->nat_oport == dport || nflags & FI_W_DPORT)))) return nat; } - return NULL; + if (!nat_wilds || !(flags & IPN_TCPUDP)) + return NULL; + RWLOCK_EXIT(&ipf_nat); + hv = NAT_HASH_FN(srcip, 0, ipf_nattable_sz); + WRITE_ENTER(&ipf_nat); + nat = nat_table[0][hv]; + for (; nat; nat = nat->nat_hnext[0]) { + nflags = nat->nat_flags; + if (ifp && ifp != nat->nat_ifp) + continue; + if (!(nflags & IPN_TCPUDP)) + continue; + if (!(nflags & FI_WILDP)) + continue; + if ((nat->nat_inip.s_addr != srcip) || + (nat->nat_oip.s_addr != dst.s_addr)) + continue; + if (((nat->nat_inport == sport) || (nflags & FI_W_DPORT)) && + ((nat->nat_oport == dport) || (nflags & FI_W_SPORT))) { + hv = NAT_HASH_FN(srcip, sport, ipf_nattable_sz); + nat_tabmove(nat, hv); + break; + } + } + MUTEX_DOWNGRADE(&ipf_nat); + return nat; } @@ -1862,6 +2179,7 @@ fr_info_t *fin; nat->nat_outport = sport; nat->nat_flags &= ~(FI_W_DPORT|FI_W_SPORT); nflags = nat->nat_flags; + nat_wilds--; } } else { RWLOCK_EXIT(&ipf_nat); @@ -1942,16 +2260,16 @@ maskloop: CALC_SUMD(s1, s2, sumd); if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(&ip->ip_sum, sumd, 0); + fix_incksum(&ip->ip_sum, sumd); else - fix_outcksum(&ip->ip_sum, sumd, 0); + fix_outcksum(&ip->ip_sum, sumd); } #if SOLARIS || defined(__sgi) else { if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(&ip->ip_sum, nat->nat_ipsumd, 0); + fix_outcksum(&ip->ip_sum, nat->nat_ipsumd); else - fix_incksum(&ip->ip_sum, nat->nat_ipsumd, 0); + fix_incksum(&ip->ip_sum, nat->nat_ipsumd); } #endif ip->ip_src = nat->nat_outip; @@ -1995,11 +2313,9 @@ maskloop: if (csump) { if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(csump, nat->nat_sumd[1], - ip->ip_len); + fix_outcksum(csump, nat->nat_sumd[1]); else - fix_incksum(csump, nat->nat_sumd[1], - ip->ip_len); + fix_incksum(csump, nat->nat_sumd[1]); } } @@ -2076,6 +2392,7 @@ fr_info_t *fin; nat->nat_outport = dport; nat->nat_flags &= ~(FI_W_SPORT|FI_W_DPORT); nflags = nat->nat_flags; + nat_wilds--; } } else { RWLOCK_EXIT(&ipf_nat); @@ -2153,9 +2470,9 @@ maskloop: */ #if SOLARIS || defined(__sgi) if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(&ip->ip_sum, nat->nat_ipsumd, 0); + fix_incksum(&ip->ip_sum, nat->nat_ipsumd); else - fix_outcksum(&ip->ip_sum, nat->nat_ipsumd, 0); + fix_outcksum(&ip->ip_sum, nat->nat_ipsumd); #endif if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) { @@ -2196,11 +2513,9 @@ maskloop: if (csump) { if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(csump, nat->nat_sumd[0], - 0); + fix_incksum(csump, nat->nat_sumd[0]); else - fix_outcksum(csump, nat->nat_sumd[0], - 0); + fix_outcksum(csump, nat->nat_sumd[0]); } } ATOMIC_INCL(nat_stats.ns_mapped[0]); diff --git a/sys/contrib/ipfilter/netinet/ip_nat.h b/sys/contrib/ipfilter/netinet/ip_nat.h index 26fed25..c2ff100 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.h +++ b/sys/contrib/ipfilter/netinet/ip_nat.h @@ -6,7 +6,7 @@ * to the original author and the contributors. * * @(#)ip_nat.h 1.5 2/4/96 - * $Id: ip_nat.h,v 2.17.2.6 2000/07/15 14:50:06 darrenr Exp $ + * $Id: ip_nat.h,v 2.17.2.9 2000/10/19 15:44:04 darrenr Exp $ */ #ifndef __IP_NAT_H__ @@ -81,7 +81,7 @@ typedef struct nat { struct hostmap *nat_hm; struct nat *nat_next; struct nat *nat_hnext[2]; - struct nat **nat_hstart[2]; + struct nat **nat_phnext[2]; void *nat_ifp; int nat_dir; char nat_ifname[IFNAMSIZ]; @@ -141,6 +141,11 @@ typedef struct ipnat { #define NAT_REDIRECT 0x02 #define NAT_BIMAP (NAT_MAP|NAT_REDIRECT) #define NAT_MAPBLK 0x04 +/* 0x100 reserved for FI_W_SPORT */ +/* 0x200 reserved for FI_W_DPORT */ +/* 0x400 reserved for FI_W_SADDR */ +/* 0x800 reserved for FI_W_DADDR */ +/* 0x1000 reserved for FI_W_NEWFR */ #define MAPBLK_MINPORT 1024 /* don't use reserved ports for src port */ #define USABLE_PORTS (65536 - MAPBLK_MINPORT) @@ -293,7 +298,8 @@ 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_int)); -extern void fix_incksum __P((u_short *, u_32_t, int)); -extern void fix_outcksum __P((u_short *, u_32_t, int)); +extern void fix_incksum __P((u_short *, u_32_t)); +extern void fix_outcksum __P((u_short *, u_32_t)); +extern void fix_datacksum __P((u_short *, u_32_t)); #endif /* __IP_NAT_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c index 18ca474..d801410 100644 --- a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c @@ -1,5 +1,5 @@ /* - * $Id: ip_raudio_pxy.c,v 1.7.2.1 2000/05/06 11:19:33 darrenr Exp $ + * $Id: ip_raudio_pxy.c,v 1.7.2.2 2000/09/03 00:23:12 darrenr Exp $ */ #if SOLARIS && defined(_KERNEL) extern kmutex_t ipf_rw; @@ -171,8 +171,8 @@ nat_t *nat; tcphdr_t *tcp, tcph, *tcp2 = &tcph; raudio_t *rap = aps->aps_data; struct in_addr swa, swb; - u_int a1, a2, a3, a4; int off, dlen, slen; + int a1, a2, a3, a4; u_short sp, dp; fr_info_t fi; tcp_seq seq; diff --git a/sys/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c index f05c887..4f7460e 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.c +++ b/sys/contrib/ipfilter/netinet/ip_state.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.17 2000/08/08 16:01:03 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.22 2000/10/26 10:41:29 darrenr Exp $"; #endif #include @@ -106,6 +106,7 @@ static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.17 2000/08/08 16:01:03 static ipstate_t **ips_table = NULL; static ipstate_t *ips_list = NULL; static int ips_num = 0; +static int ips_wild = 0; static ips_stat_t ips_stats; #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) extern KRWLOCK_T ipf_state, ipf_mutex; @@ -123,6 +124,7 @@ static int fr_state_flush __P((int)); static ips_stat_t *fr_statetstats __P((void)); static void fr_delstate __P((ipstate_t *)); static int fr_state_remove __P((caddr_t)); +static void fr_ipsmove __P((ipstate_t **, ipstate_t *, u_int)); int fr_stputent __P((caddr_t)); int fr_stgetent __P((caddr_t)); void fr_stinsert __P((ipstate_t *)); @@ -135,7 +137,8 @@ u_long fr_tcpidletimeout = FIVE_DAYS, fr_tcpclosewait = 2 * TCP_MSL, fr_tcplastack = 2 * TCP_MSL, fr_tcptimeout = 2 * TCP_MSL, - fr_tcpclosed = 1, + fr_tcpclosed = 120, + fr_tcphalfclosed = 2 * 2 * 3600, /* 2 hours */ fr_udptimeout = 240, fr_icmptimeout = 120; int fr_statemax = IPSTATE_MAX, @@ -240,9 +243,12 @@ caddr_t data; for (sp = ips_list; sp; sp = sp->is_next) if ((sp->is_p == st.is_p) && (sp->is_v == st.is_v) && - !bcmp(&sp->is_src, &st.is_src, sizeof(st.is_src)) && - !bcmp(&sp->is_dst, &st.is_src, sizeof(st.is_dst)) && - !bcmp(&sp->is_ps, &st.is_ps, sizeof(st.is_ps))) { + !bcmp((char *)&sp->is_src, (char *)&st.is_src, + sizeof(st.is_src)) && + !bcmp((char *)&sp->is_dst, (char *)&st.is_src, + sizeof(st.is_dst)) && + !bcmp((char *)&sp->is_ps, (char *)&st.is_ps, + sizeof(st.is_ps))) { WRITE_ENTER(&ipf_state); #ifdef IPFILTER_LOG ipstate_log(sp, ISL_REMOVE); @@ -590,8 +596,8 @@ u_int flags; hv += tcp->th_dport; hv += tcp->th_sport; } - is->is_send = ntohl(tcp->th_seq) + ip->ip_len - - fin->fin_hlen - (tcp->th_off << 2) + + is->is_send = ntohl(tcp->th_seq) + fin->fin_dlen - + (tcp->th_off << 2) + ((tcp->th_flags & TH_SYN) ? 1 : 0) + ((tcp->th_flags & TH_FIN) ? 1 : 0); is->is_maxsend = is->is_send; @@ -660,6 +666,8 @@ u_int flags; is->is_flags = fin->fin_fi.fi_fl & FI_CMP; is->is_flags |= FI_CMP << 4; is->is_flags |= flags & (FI_WILDP|FI_WILDA); + if (flags & (FI_WILDP|FI_WILDA)) + ips_wild++; is->is_ifp[1 - out] = NULL; is->is_ifp[out] = fin->fin_ifp; #ifdef _KERNEL @@ -718,6 +726,7 @@ tcphdr_t *tcp; ((tcp->th_flags & TH_SYN) ? 1 : 0) + ((tcp->th_flags & TH_FIN) ? 1 : 0); + MUTEX_ENTER(&is->is_lock); if (fdata->td_end == 0) { /* * Must be a (outgoing) SYN-ACK in reply to a SYN. @@ -783,12 +792,11 @@ tcphdr_t *tcp; /* * Nearing end of connection, start timeout. */ - MUTEX_ENTER(&is->is_lock); /* source ? 0 : 1 -> !source */ fr_tcp_age(&is->is_age, is->is_state, fin, !source); - MUTEX_EXIT(&is->is_lock); ret = 1; } + MUTEX_EXIT(&is->is_lock); return ret; } @@ -892,6 +900,7 @@ tcphdr_t *tcp; is->is_maxdend = is->is_dend + 1; } is->is_flags &= ~(FI_W_SPORT|FI_W_DPORT); + ips_wild--; } ret = -1; @@ -983,7 +992,7 @@ fr_info_t *fin; * Only a basic IP header (no options) should be with * an ICMP error header. */ - if (((ip->ip_v != 4) && (ip->ip_hl != 5)) || + if (((ip->ip_v != 4) || (ip->ip_hl != 5)) || (fin->fin_plen < ICMPERR_MINPKTLEN)) return NULL; ic = (struct icmp *)fin->fin_dp; @@ -1037,8 +1046,8 @@ fr_info_t *fin; * the IP6EQ and IP6NEQ macros produce the wrong results because * of the 'junk' in the unused part of the union */ - bzero(&src, sizeof(src)); - bzero(&dst, sizeof(dst)); + bzero((char *)&src, sizeof(src)); + bzero((char *)&dst, sizeof(dst)); if (oip->ip_p == IPPROTO_ICMP) { icmp = (icmphdr_t *)((char *)oip + (oip->ip_hl << 2)); @@ -1158,6 +1167,38 @@ fr_info_t *fin; return NULL; } + +static void fr_ipsmove(isp, is, hv) +ipstate_t **isp, *is; +u_int hv; +{ + u_int hvm; + + hvm = is->is_hv; + /* + * Remove the hash from the old location... + */ + if (is->is_hnext) + is->is_hnext->is_phnext = isp; + *isp = is->is_hnext; + if (ips_table[hvm] == NULL) + ips_stats.iss_inuse--; + + /* + * ...and put the hash in the new one. + */ + hvm = hv % fr_statesize; + isp = &ips_table[hvm]; + if (*isp) + (*isp)->is_phnext = &is->is_hnext; + else + ips_stats.iss_inuse++; + is->is_phnext = isp; + is->is_hnext = *isp; + *isp = is; +} + + /* * Check if a packet has a registered state. */ @@ -1240,7 +1281,7 @@ fr_info_t *fin; break; case IPPROTO_TCP : { - register u_short dport = tcp->th_dport, sport = tcp->th_sport; + register u_short dport, sport; register int i; i = tcp->th_flags; @@ -1250,57 +1291,42 @@ fr_info_t *fin; if ((i & TH_RST) && ((i & (TH_FIN|TH_SYN|TH_RST)) != TH_RST)) break; + case IPPROTO_UDP : + dport = tcp->th_dport; + sport = tcp->th_sport; tryagain = 0; -retry_tcp: - hvm = hv % fr_statesize; - WRITE_ENTER(&ipf_state); - for (isp = &ips_table[hvm]; (is = *isp); - isp = &is->is_hnext) - - - if ((is->is_p == pr) && (is->is_v == v) && - fr_matchsrcdst(is, src, dst, fin, tcp)) { - if (fr_tcpstate(is, fin, ip, tcp)) - 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; - - 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[hvm]; is; is = is->is_hnext) +retry_tcpudp: + hvm = hv % fr_statesize; + for (isp = &ips_table[hvm]; (is = *isp); isp = &is->is_hnext) if ((is->is_p == pr) && (is->is_v == v) && fr_matchsrcdst(is, src, dst, fin, tcp)) { - is->is_age = fr_udptimeout; + if ((pr == IPPROTO_TCP)) { + if (!fr_tcpstate(is, fin, ip, tcp)) { + continue; + } + } break; } - if (is != NULL) + if (is != NULL) { + if (tryagain && + !(is->is_flags & (FI_WILDP|FI_WILDA))) { + hv += dport; + hv += sport; + fr_ipsmove(isp, is, hv); + MUTEX_DOWNGRADE(&ipf_state); + } break; + } RWLOCK_EXIT(&ipf_state); - hv += dport; - hv += sport; - if (tryagain == 0) { + if (!tryagain && ips_wild) { + hv -= dport; + hv -= sport; tryagain = 1; - goto retry_udp; + WRITE_ENTER(&ipf_state); + goto retry_tcpudp; } break; } @@ -1357,6 +1383,8 @@ ipstate_t *is; { frentry_t *fr; + if (is->is_flags & (FI_WILDP|FI_WILDA)) + ips_wild--; if (is->is_next) is->is_next->is_pnext = is->is_pnext; *is->is_pnext = is->is_next; @@ -1566,7 +1594,7 @@ int dir; * SYN_RECEIVED -> FIN_WAIT_1 */ state[dir] = TCPS_FIN_WAIT_1; - *age = fr_tcpidletimeout; /* or fr_tcptimeout? */ + *age = fr_tcpidletimeout; } break; @@ -1578,7 +1606,7 @@ int dir; * ESTABLISHED -> FIN_WAIT_1 */ state[dir] = TCPS_FIN_WAIT_1; - *age = fr_tcpidletimeout; + *age = fr_tcphalfclosed; } else if (flags & TH_ACK) { /* an ACK, should we exclude other flags here? */ if (ostate == TCPS_FIN_WAIT_1) { @@ -1590,7 +1618,7 @@ int dir; * a half-closed connection */ state[dir] = TCPS_CLOSE_WAIT; - *age = fr_tcpidletimeout; + *age = fr_tcphalfclosed; } else if (ostate < TCPS_CLOSE_WAIT) /* * Still a fully established connection, @@ -1614,7 +1642,7 @@ int dir; * closed already and we did not close our side yet; * reset timeout */ - *age = fr_tcpidletimeout; + *age = fr_tcphalfclosed; } break; @@ -1638,7 +1666,7 @@ int dir; * other side is still active (ESTABLISHED/CLOSE_WAIT); * continue with this half-closed connection */ - *age = fr_tcpidletimeout; + *age = fr_tcphalfclosed; break; case TCPS_CLOSING: /* 7 */ diff --git a/sys/contrib/ipfilter/netinet/ip_state.h b/sys/contrib/ipfilter/netinet/ip_state.h index a5643af..1d1bc00 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.h +++ b/sys/contrib/ipfilter/netinet/ip_state.h @@ -6,7 +6,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 2.13.2.1 2000/07/08 02:15:35 darrenr Exp $ + * $Id: ip_state.h,v 2.13.2.2 2000/08/23 11:01:31 darrenr Exp $ */ #ifndef __IP_STATE_H__ #define __IP_STATE_H__ @@ -173,6 +173,7 @@ extern u_long fr_tcpclosewait; extern u_long fr_tcplastack; extern u_long fr_tcptimeout; extern u_long fr_tcpclosed; +extern u_long fr_tcphalfclosed; extern u_long fr_udptimeout; extern u_long fr_icmptimeout; extern int fr_state_lock; diff --git a/sys/contrib/ipfilter/netinet/ipl.h b/sys/contrib/ipfilter/netinet/ipl.h index 866d34d..cfec734 100644 --- a/sys/contrib/ipfilter/netinet/ipl.h +++ b/sys/contrib/ipfilter/netinet/ipl.h @@ -6,12 +6,12 @@ * to the original author and the contributors. * * @(#)ipl.h 1.21 6/5/96 - * $Id: ipl.h,v 2.15.2.10 2000/08/07 15:10:09 darrenr Exp $ + * $Id: ipl.h,v 2.15.2.13 2000/10/25 11:08:41 darrenr Exp $ */ #ifndef __IPL_H__ #define __IPL_H__ -#define IPL_VERSION "IP Filter: v3.4.9" +#define IPL_VERSION "IP Filter: v3.4.12" #endif diff --git a/sys/contrib/ipfilter/netinet/mlfk_ipl.c b/sys/contrib/ipfilter/netinet/mlfk_ipl.c index f869149..f96c57e 100644 --- a/sys/contrib/ipfilter/netinet/mlfk_ipl.c +++ b/sys/contrib/ipfilter/netinet/mlfk_ipl.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: mlfk_ipl.c,v 2.1.2.3 2000/08/13 03:42:42 darrenr Exp $ + * $Id: mlfk_ipl.c,v 2.1.2.4 2000/08/23 11:02:33 darrenr Exp $ */ @@ -65,6 +65,8 @@ SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RW, &fr_tcptimeout, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RW, &fr_tcpclosed, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RW, + &fr_tcphalfclosed, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RW, &fr_udptimeout, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RW, -- cgit v1.1 From ab46516b6b45688709410edee860bf654f15d326 Mon Sep 17 00:00:00 2001 From: darrenr Date: Sun, 29 Oct 2000 07:50:11 +0000 Subject: Import IP filter 3.4.13 --- sys/contrib/ipfilter/netinet/fil.c | 47 +++++++++++++++------------- sys/contrib/ipfilter/netinet/ip_ftp_pxy.c | 4 ++- sys/contrib/ipfilter/netinet/ip_nat.c | 39 ++++++++++++----------- sys/contrib/ipfilter/netinet/ip_nat.h | 3 +- sys/contrib/ipfilter/netinet/ip_raudio_pxy.c | 3 +- sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c | 3 +- sys/contrib/ipfilter/netinet/ip_state.c | 3 +- sys/contrib/ipfilter/netinet/ipl.h | 4 +-- 8 files changed, 58 insertions(+), 48 deletions(-) diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index b85dcf4..e0a5ed5 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/netinet/fil.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.26 2000/10/24 11:58:17 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.27 2000/10/26 21:20:54 darrenr Exp $"; #endif #include @@ -274,32 +274,35 @@ fr_info_t *fin; int minicmpsz = sizeof(struct icmp); icmphdr_t *icmp; - if (fin->fin_dlen > 1) + if (!off && (fin->fin_dlen > 1)) { fin->fin_data[0] = *(u_short *)tcp; - if ((!(plen >= hlen + minicmpsz) && !off) || - (off && off < sizeof(struct icmp))) { - fi->fi_fl |= FI_SHORT; - if (fin->fin_dlen < 2) - break; - } + icmp = (icmphdr_t *)tcp; - icmp = (icmphdr_t *)tcp; + if (icmp->icmp_type == ICMP_ECHOREPLY || + icmp->icmp_type == ICMP_ECHO) + minicmpsz = ICMP_MINLEN; - if (!off && (icmp->icmp_type == ICMP_ECHOREPLY || - icmp->icmp_type == ICMP_ECHO)) - minicmpsz = ICMP_MINLEN; + /* + * type(1) + code(1) + cksum(2) + id(2) seq(2) + + * 3*timestamp(3*4) + */ + else if (icmp->icmp_type == ICMP_TSTAMP || + icmp->icmp_type == ICMP_TSTAMPREPLY) + minicmpsz = 20; - /* type(1) + code(1) + cksum(2) + id(2) seq(2) + - * 3*timestamp(3*4) */ - else if (!off && (icmp->icmp_type == ICMP_TSTAMP || - icmp->icmp_type == ICMP_TSTAMPREPLY)) - minicmpsz = 20; + /* + * type(1) + code(1) + cksum(2) + id(2) seq(2) + + * mask(4) + */ + else if (icmp->icmp_type == ICMP_MASKREQ || + icmp->icmp_type == ICMP_MASKREPLY) + minicmpsz = 12; + } - /* type(1) + code(1) + cksum(2) + id(2) seq(2) + mask(4) */ - else if (!off && (icmp->icmp_type == ICMP_MASKREQ || - icmp->icmp_type == ICMP_MASKREPLY)) - minicmpsz = 12; + if ((!(plen >= hlen + minicmpsz) && !off) || + (off && off < sizeof(struct icmp))) + fi->fi_fl |= FI_SHORT; break; } @@ -1398,7 +1401,7 @@ nodata: * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 - * $Id: fil.c,v 2.35.2.26 2000/10/24 11:58:17 darrenr Exp $ + * $Id: fil.c,v 2.35.2.27 2000/10/26 21:20:54 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, diff --git a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c index ffa7c1b..653bbfe 100644 --- a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c @@ -2,7 +2,7 @@ * Simple FTP transparent proxy for in-kernel use. For use with the NAT * code. * - * $Id: ip_ftp_pxy.c,v 2.7.2.17 2000/10/19 15:40:40 darrenr Exp $ + * $Id: ip_ftp_pxy.c,v 2.7.2.18 2000/10/27 14:02:10 darrenr Exp $ */ #if SOLARIS && defined(_KERNEL) extern kmutex_t ipf_rw; @@ -252,6 +252,7 @@ int dlen; tcp2->th_dport = 0; /* XXX - don't specify remote port */ fi.fin_data[0] = ntohs(sp); fi.fin_data[1] = 0; + fi.fin_dlen = sizeof(*tcp2); fi.fin_dp = (char *)tcp2; swip = ip->ip_src; ip->ip_src = nat->nat_inip; @@ -467,6 +468,7 @@ int dlen; tcp2->th_sport = 0; /* XXX - fake it for nat_new */ tcp2->th_off = 5; fi.fin_data[0] = a5 << 8 | a6; + fi.fin_dlen = sizeof(*tcp2); tcp2->th_dport = htons(fi.fin_data[0]); fi.fin_data[1] = 0; fi.fin_dp = (char *)tcp2; diff --git a/sys/contrib/ipfilter/netinet/ip_nat.c b/sys/contrib/ipfilter/netinet/ip_nat.c index d52f48d..4f6921d 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.c +++ b/sys/contrib/ipfilter/netinet/ip_nat.c @@ -9,7 +9,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 2.37.2.25 2000/10/25 10:38:47 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.26 2000/10/27 14:06:48 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) @@ -118,7 +118,6 @@ u_int ipf_nattable_sz = NAT_TABLE_SZ; u_int ipf_natrules_sz = NAT_SIZE; u_int ipf_rdrrules_sz = RDR_SIZE; u_int ipf_hostmap_sz = HOSTMAP_SIZE; -int nat_wilds = 0; u_32_t nat_masks = 0; u_32_t rdr_masks = 0; ipnat_t **nat_rules = NULL; @@ -144,7 +143,7 @@ static void nat_delnat __P((struct ipnat *)); static int fr_natgetent __P((caddr_t)); static int fr_natgetsz __P((caddr_t)); static int fr_natputent __P((caddr_t)); -static void nat_tabmove __P((nat_t *, u_int)); +static void nat_tabmove __P((nat_t *)); static int nat_match __P((fr_info_t *, ipnat_t *, ip_t *)); static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr, struct in_addr)); @@ -1004,7 +1003,7 @@ struct nat *natd; struct ipnat *ipn; if (natd->nat_flags & FI_WILDP) - nat_wilds--; + nat_stats.ns_wilds--; if (natd->nat_hnext[0]) natd->nat_hnext[0]->nat_phnext[0] = natd->nat_phnext[0]; *natd->nat_phnext[0] = natd->nat_hnext[0]; @@ -1148,7 +1147,7 @@ int direction; bzero((char *)nat, sizeof(*nat)); nat->nat_flags = flags; if (flags & FI_WILDP) - nat_wilds++; + nat_stats.ns_wilds++; /* * Search the current table for a match. */ @@ -1916,7 +1915,7 @@ u_32_t ports; ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))))) return nat; } - if (!nat_wilds || !(flags & IPN_TCPUDP)) + if (!nat_stats.ns_wilds || !(flags & IPN_TCPUDP)) return NULL; RWLOCK_EXIT(&ipf_nat); hv = NAT_HASH_FN(dst, 0, ipf_nattable_sz); @@ -1935,8 +1934,7 @@ u_32_t ports; continue; if (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) && ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))) { - hv = NAT_HASH_FN(dst, dport, ipf_nattable_sz); - nat_tabmove(nat, hv); + nat_tabmove(nat); break; } } @@ -1945,11 +1943,11 @@ u_32_t ports; } -static void nat_tabmove(nat, hv) +static void nat_tabmove(nat) nat_t *nat; -u_int hv; { nat_t **natp; + u_int hv; /* * Remove the NAT entry from the old location @@ -1959,9 +1957,14 @@ u_int hv; *nat->nat_phnext[0] = nat->nat_hnext[0]; if (nat->nat_hnext[1]) - nat->nat_hnext[0]->nat_phnext[1] = nat->nat_phnext[1]; + nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; *nat->nat_phnext[1] = nat->nat_hnext[1]; + /* + * Add into the NAT table in the new position + */ + hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, + ipf_nattable_sz); natp = &nat_table[0][hv]; if (*natp) (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; @@ -1969,9 +1972,8 @@ u_int hv; nat->nat_hnext[0] = *natp; *natp = nat; - /* - * Add into the NAT table in the new position - */ + hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, + ipf_nattable_sz); natp = &nat_table[1][hv]; if (*natp) (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; @@ -2018,7 +2020,7 @@ u_32_t ports; (nat->nat_oport == dport || nflags & FI_W_DPORT)))) return nat; } - if (!nat_wilds || !(flags & IPN_TCPUDP)) + if (!nat_stats.ns_wilds || !(flags & IPN_TCPUDP)) return NULL; RWLOCK_EXIT(&ipf_nat); hv = NAT_HASH_FN(srcip, 0, ipf_nattable_sz); @@ -2037,8 +2039,7 @@ u_32_t ports; continue; if (((nat->nat_inport == sport) || (nflags & FI_W_DPORT)) && ((nat->nat_oport == dport) || (nflags & FI_W_SPORT))) { - hv = NAT_HASH_FN(srcip, sport, ipf_nattable_sz); - nat_tabmove(nat, hv); + nat_tabmove(nat); break; } } @@ -2179,7 +2180,7 @@ fr_info_t *fin; nat->nat_outport = sport; nat->nat_flags &= ~(FI_W_DPORT|FI_W_SPORT); nflags = nat->nat_flags; - nat_wilds--; + nat_stats.ns_wilds--; } } else { RWLOCK_EXIT(&ipf_nat); @@ -2392,7 +2393,7 @@ fr_info_t *fin; nat->nat_outport = dport; nat->nat_flags &= ~(FI_W_SPORT|FI_W_DPORT); nflags = nat->nat_flags; - nat_wilds--; + nat_stats.ns_wilds--; } } else { RWLOCK_EXIT(&ipf_nat); diff --git a/sys/contrib/ipfilter/netinet/ip_nat.h b/sys/contrib/ipfilter/netinet/ip_nat.h index c2ff100..8e166df 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.h +++ b/sys/contrib/ipfilter/netinet/ip_nat.h @@ -6,7 +6,7 @@ * to the original author and the contributors. * * @(#)ip_nat.h 1.5 2/4/96 - * $Id: ip_nat.h,v 2.17.2.9 2000/10/19 15:44:04 darrenr Exp $ + * $Id: ip_nat.h,v 2.17.2.10 2000/10/27 14:06:51 darrenr Exp $ */ #ifndef __IP_NAT_H__ @@ -207,6 +207,7 @@ typedef struct natstat { u_int ns_rultab_sz; u_int ns_rdrtab_sz; nat_t *ns_instances; + u_int ns_wilds; } natstat_t; #define IPN_ANY 0x000 diff --git a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c index d801410..9ea437c 100644 --- a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c @@ -1,5 +1,5 @@ /* - * $Id: ip_raudio_pxy.c,v 1.7.2.2 2000/09/03 00:23:12 darrenr Exp $ + * $Id: ip_raudio_pxy.c,v 1.7.2.3 2000/10/27 22:54:04 darrenr Exp $ */ #if SOLARIS && defined(_KERNEL) extern kmutex_t ipf_rw; @@ -265,6 +265,7 @@ nat_t *nat; tcp2->th_off = 5; fi.fin_dp = (char *)tcp2; fi.fin_fr = &raudiofr; + fi.fin_dlen = sizeof(*tcp2); tcp2->th_win = htons(8192); slen = ip->ip_len; ip->ip_len = fin->fin_hlen + sizeof(*tcp); diff --git a/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c b/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c index 1d6264d..e311b16 100644 --- a/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c @@ -1,5 +1,5 @@ /* - * $Id: ip_rcmd_pxy.c,v 1.4.2.2 2000/07/15 12:38:30 darrenr Exp $ + * $Id: ip_rcmd_pxy.c,v 1.4.2.3 2000/10/27 22:54:04 darrenr Exp $ */ /* * Simple RCMD transparent proxy for in-kernel use. For use with the NAT @@ -146,6 +146,7 @@ nat_t *nat; fi.fin_data[0] = ntohs(sp); fi.fin_data[1] = 0; fi.fin_dp = (char *)tcp2; + fi.fin_dlen = sizeof(*tcp2); swip = ip->ip_src; ip->ip_src = nat->nat_inip; ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_TCP|FI_W_DPORT, diff --git a/sys/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c index 4f7460e..7499bfd 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.c +++ b/sys/contrib/ipfilter/netinet/ip_state.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.22 2000/10/26 10:41:29 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.23 2000/10/27 14:06:08 darrenr Exp $"; #endif #include @@ -1188,6 +1188,7 @@ u_int hv; * ...and put the hash in the new one. */ hvm = hv % fr_statesize; + is->is_hv = hvm; isp = &ips_table[hvm]; if (*isp) (*isp)->is_phnext = &is->is_hnext; diff --git a/sys/contrib/ipfilter/netinet/ipl.h b/sys/contrib/ipfilter/netinet/ipl.h index cfec734..b54d6f9 100644 --- a/sys/contrib/ipfilter/netinet/ipl.h +++ b/sys/contrib/ipfilter/netinet/ipl.h @@ -6,12 +6,12 @@ * to the original author and the contributors. * * @(#)ipl.h 1.21 6/5/96 - * $Id: ipl.h,v 2.15.2.13 2000/10/25 11:08:41 darrenr Exp $ + * $Id: ipl.h,v 2.15.2.14 2000/10/27 22:54:41 darrenr Exp $ */ #ifndef __IPL_H__ #define __IPL_H__ -#define IPL_VERSION "IP Filter: v3.4.12" +#define IPL_VERSION "IP Filter: v3.4.13" #endif -- cgit v1.1 From 872f5187538a9233b140dff95807b252df84fe5e Mon Sep 17 00:00:00 2001 From: darrenr Date: Sun, 4 Feb 2001 14:15:48 +0000 Subject: Update IP Filter kernel source --- sys/contrib/ipfilter/netinet/fil.c | 85 +++++++++++++--- sys/contrib/ipfilter/netinet/ip_auth.c | 4 +- sys/contrib/ipfilter/netinet/ip_compat.h | 20 +++- sys/contrib/ipfilter/netinet/ip_fil.h | 5 +- sys/contrib/ipfilter/netinet/ip_frag.c | 21 ++-- sys/contrib/ipfilter/netinet/ip_frag.h | 3 +- sys/contrib/ipfilter/netinet/ip_ftp_pxy.c | 30 ++++-- sys/contrib/ipfilter/netinet/ip_nat.c | 152 +++++++++++++++++++---------- sys/contrib/ipfilter/netinet/ip_nat.h | 9 +- sys/contrib/ipfilter/netinet/ip_proxy.h | 3 +- sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c | 4 +- sys/contrib/ipfilter/netinet/ip_state.c | 24 +++-- sys/contrib/ipfilter/netinet/ipl.h | 4 +- sys/contrib/ipfilter/netinet/mlfk_ipl.c | 14 ++- 14 files changed, 259 insertions(+), 119 deletions(-) diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index e0a5ed5..02f075b 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/netinet/fil.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.27 2000/10/26 21:20:54 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.30 2000/12/17 05:49:22 darrenr Exp $"; #endif #include @@ -136,6 +136,8 @@ struct frgroup *ipfgroups[3][2]; int fr_flags = IPF_LOGGING; int fr_active = 0; int fr_chksrc = 0; +int fr_minttl = 3; +int fr_minttllog = 1; #if defined(IPFILTER_DEFAULT_BLOCK) int fr_pass = FR_NOMATCH|FR_BLOCK; #else @@ -269,6 +271,40 @@ fr_info_t *fin; switch (p) { +#ifdef USE_INET6 + case IPPROTO_ICMPV6 : + { + int minicmpsz = sizeof(struct icmp6_hdr); + struct icmp6_hdr *icmp6; + + if (fin->fin_dlen > 1) { + fin->fin_data[0] = *(u_short *)tcp; + + icmp6 = (struct icmp6_hdr *)tcp; + + switch (icmp6->icmp6_type) + { + case ICMP6_ECHO_REPLY : + case ICMP6_ECHO_REQUEST : + minicmpsz = ICMP6ERR_MINPKTLEN; + break; + case ICMP6_DST_UNREACH : + case ICMP6_PACKET_TOO_BIG : + case ICMP6_TIME_EXCEEDED : + case ICMP6_PARAM_PROB : + minicmpsz = ICMP6ERR_IPICMPHLEN; + break; + default : + break; + } + } + + if (!(plen >= hlen + minicmpsz)) + fi->fi_fl |= FI_SHORT; + + break; + } +#endif case IPPROTO_ICMP : { int minicmpsz = sizeof(struct icmp); @@ -747,8 +783,8 @@ int out; #endif #ifdef _KERNEL + int p, len, drop = 0, logit = 0; mb_t *mc = NULL; - int p, len; # if !defined(__SVR4) && !defined(__svr4__) # ifdef __sgi char hbuf[(0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8]; @@ -802,11 +838,17 @@ int out; break; /* 96 - enough for complete ICMP error IP header */ case IPPROTO_ICMP: + plen = ICMPERR_MAXPKTLEN - sizeof(ip_t); + break; # ifdef USE_INET6 case IPPROTO_ICMPV6 : -# endif - plen = ICMPERR_MAXPKTLEN - sizeof(ip_t); + /* + * XXX does not take intermediate header + * into account + */ + plen = ICMP6ERR_MINPKTLEN + 8 - sizeof(ip6_t); break; +# endif } up = MIN(hlen + plen, len); @@ -865,22 +907,37 @@ int out; # ifdef USE_INET6 if (v == 6) { ATOMIC_INCL(frstats[0].fr_ipv6[out]); + if (((ip6_t *)ip)->ip6_hlim < fr_minttl) { + ATOMIC_INCL(frstats[0].fr_badttl); + if (fr_minttllog) + logit = -2; + } } else # endif - if (!out && fr_chksrc && !fr_verifysrc(ip->ip_src, ifp)) { + if (!out) { + if (fr_chksrc && !fr_verifysrc(ip->ip_src, ifp)) { ATOMIC_INCL(frstats[0].fr_badsrc); + if (fr_chksrc == 2) + logit = -2; + } else if (ip->ip_ttl < fr_minttl) { + ATOMIC_INCL(frstats[0].fr_badttl); + if (fr_minttllog) + logit = -3; + } + } + if (drop) { # ifdef IPFILTER_LOG - if (fr_chksrc == 2) { - fin->fin_group = -2; - pass = FR_INQUE|FR_NOMATCH|FR_LOGB; - (void) IPLLOG(pass, ip, fin, m); - } + if (logit) { + fin->fin_group = logit; + pass = FR_INQUE|FR_NOMATCH|FR_LOGB; + (void) IPLLOG(pass, ip, fin, m); + } # endif # if !SOLARIS - m_freem(m); + m_freem(m); # endif - return error; - } + return error; + } #endif pass = fr_pass; if (fin->fin_fi.fi_fl & FI_SHORT) { @@ -1401,7 +1458,7 @@ nodata: * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 - * $Id: fil.c,v 2.35.2.27 2000/10/26 21:20:54 darrenr Exp $ + * $Id: fil.c,v 2.35.2.30 2000/12/17 05:49:22 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, diff --git a/sys/contrib/ipfilter/netinet/ip_auth.c b/sys/contrib/ipfilter/netinet/ip_auth.c index d737b9c..a453610 100644 --- a/sys/contrib/ipfilter/netinet/ip_auth.c +++ b/sys/contrib/ipfilter/netinet/ip_auth.c @@ -6,7 +6,7 @@ * to the original author and the contributors. */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.4 2000/08/05 14:48:50 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.5 2001/01/10 06:18:35 darrenr Exp $"; #endif #include @@ -352,7 +352,7 @@ fr_authioctlloop: READ_ENTER(&ipf_auth); if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) { error = IWCOPYPTR((char *)&fr_auth[fr_authnext], data, - sizeof(fr_info_t)); + sizeof(frauth_t)); RWLOCK_EXIT(&ipf_auth); if (error) break; diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h index 2369cf0..ed71f36 100644 --- a/sys/contrib/ipfilter/netinet/ip_compat.h +++ b/sys/contrib/ipfilter/netinet/ip_compat.h @@ -6,7 +6,7 @@ * to the original author and the contributors. * * @(#)ip_compat.h 1.8 1/14/96 - * $Id: ip_compat.h,v 2.26.2.6 2000/10/19 15:39:05 darrenr Exp $ + * $Id: ip_compat.h,v 2.26.2.9 2001/01/14 14:58:01 darrenr Exp $ */ #ifndef __IP_COMPAT_H__ @@ -974,8 +974,6 @@ struct ether_addr { #define A_A & #endif -#define TCPF_ALL (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG) - #ifndef ICMP_ROUTERADVERT # define ICMP_ROUTERADVERT 9 #endif @@ -995,6 +993,20 @@ struct ether_addr { #define ICMPERR_IPICMPHLEN (20 + 8) #define ICMPERR_MINPKTLEN (20 + 8 + 20) #define ICMPERR_MAXPKTLEN (20 + 8 + 20 + 8) -#define ICMP6ERR_MINPKTLEN (20 + 8) +#define ICMP6ERR_MINPKTLEN (40 + 8) +#define ICMP6ERR_IPICMPHLEN (40 + 8 + 40) + +/* + * ECN is a new addition to TCP - RFC 2481 + */ +#ifndef TH_ECN +# define TH_ECN 0x40 +#endif +#ifndef TH_CWR +# define TH_CWR 0x80 +#endif +#define TH_ECNALL (TH_ECN|TH_CWR) + +#define TCPF_ALL (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG|TH_ECN|TH_CWR) #endif /* __IP_COMPAT_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_fil.h b/sys/contrib/ipfilter/netinet/ip_fil.h index da109b7..ed1cfc4 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil.h +++ b/sys/contrib/ipfilter/netinet/ip_fil.h @@ -6,7 +6,7 @@ * to the original author and the contributors. * * @(#)ip_fil.h 1.35 6/5/96 - * $Id: ip_fil.h,v 2.29.2.3 2000/06/05 13:12:42 darrenr Exp $ + * $Id: ip_fil.h,v 2.29.2.4 2000/11/12 11:54:53 darrenr Exp $ */ #ifndef __IP_FIL_H__ @@ -335,6 +335,7 @@ typedef struct filterstats { u_long fr_tcpbad; /* TCP checksum check failures */ u_long fr_pull[2]; /* good and bad pullup attempts */ u_long fr_badsrc; /* source received doesn't match route */ + u_long fr_badttl; /* TTL in packet doesn't reach minimum */ #if SOLARIS u_long fr_notdata; /* PROTO/PCPROTO that have no data */ u_long fr_nodata; /* mblks that have no data */ @@ -612,6 +613,8 @@ extern int fr_pass; extern int fr_flags; extern int fr_active; extern int fr_chksrc; +extern int fr_minttl; +extern int fr_minttllog; extern fr_info_t frcache[2]; extern char ipfilter_version[]; extern iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1]; diff --git a/sys/contrib/ipfilter/netinet/ip_frag.c b/sys/contrib/ipfilter/netinet/ip_frag.c index 1cb86c1..556478d 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.c +++ b/sys/contrib/ipfilter/netinet/ip_frag.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.5 2000/10/19 15:39:58 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.7 2000/11/27 10:26:56 darrenr Exp $"; #endif #if defined(KERNEL) && !defined(_KERNEL) @@ -156,6 +156,7 @@ ipfr_t *table[]; idx += ip->ip_src.s_addr; frag.ipfr_dst.s_addr = ip->ip_dst.s_addr; idx += ip->ip_dst.s_addr; + frag.ipfr_ifp = fin->fin_ifp; idx *= 127; idx %= IPFT_SIZE; @@ -270,6 +271,7 @@ ipfr_t *table[]; idx += ip->ip_src.s_addr; frag.ipfr_dst.s_addr = ip->ip_dst.s_addr; idx += ip->ip_dst.s_addr; + frag.ipfr_ifp = fin->fin_ifp; idx *= 127; idx %= IPFT_SIZE; @@ -328,16 +330,13 @@ fr_info_t *fin; ipf = ipfr_lookup(ip, fin, ipfr_nattab); if (ipf != NULL) { nat = ipf->ipfr_data; - if (nat->nat_ifp == fin->fin_ifp) { - /* - * This is the last fragment for this packet. - */ - if ((ipf->ipfr_ttl == 1) && (nat != NULL)) { - nat->nat_data = NULL; - ipf->ipfr_data = NULL; - } - } else - nat = NULL; + /* + * This is the last fragment for this packet. + */ + if ((ipf->ipfr_ttl == 1) && (nat != NULL)) { + nat->nat_data = NULL; + ipf->ipfr_data = NULL; + } } else nat = NULL; RWLOCK_EXIT(&ipf_natfrag); diff --git a/sys/contrib/ipfilter/netinet/ip_frag.h b/sys/contrib/ipfilter/netinet/ip_frag.h index 61b88aa..362bcdd 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.h +++ b/sys/contrib/ipfilter/netinet/ip_frag.h @@ -6,7 +6,7 @@ * to the original author and the contributors. * * @(#)ip_frag.h 1.5 3/24/96 - * $Id: ip_frag.h,v 2.4.2.1 2000/10/19 15:40:13 darrenr Exp $ + * $Id: ip_frag.h,v 2.4.2.2 2000/11/10 13:10:54 darrenr Exp $ */ #ifndef __IP_FRAG_H__ @@ -19,6 +19,7 @@ typedef struct ipfr { void *ipfr_data; struct in_addr ipfr_src; struct in_addr ipfr_dst; + void *ipfr_ifp; u_short ipfr_id; u_char ipfr_p; u_char ipfr_tos; diff --git a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c index 653bbfe..ddca889 100644 --- a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c @@ -2,7 +2,7 @@ * Simple FTP transparent proxy for in-kernel use. For use with the NAT * code. * - * $Id: ip_ftp_pxy.c,v 2.7.2.18 2000/10/27 14:02:10 darrenr Exp $ + * $Id: ip_ftp_pxy.c,v 2.7.2.20 2000/12/02 00:15:06 darrenr Exp $ */ #if SOLARIS && defined(_KERNEL) extern kmutex_t ipf_rw; @@ -238,7 +238,7 @@ int dlen; */ 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); + ip->ip_dst, (dp << 16) | sp, 0); if (ipn == NULL) { int slen; @@ -254,7 +254,9 @@ int dlen; fi.fin_data[1] = 0; fi.fin_dlen = sizeof(*tcp2); fi.fin_dp = (char *)tcp2; + fi.fin_fr = &natfr; swip = ip->ip_src; + fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; ip->ip_src = nat->nat_inip; ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_TCP|FI_W_DPORT, NAT_OUTBOUND); @@ -456,7 +458,7 @@ int dlen; 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); + ip->ip_dst, (dp << 16) | sp, 0); if (ipn == NULL) { int slen; @@ -467,13 +469,16 @@ int dlen; tcp2->th_win = htons(8192); tcp2->th_sport = 0; /* XXX - fake it for nat_new */ tcp2->th_off = 5; - fi.fin_data[0] = a5 << 8 | a6; + fi.fin_data[1] = a5 << 8 | a6; fi.fin_dlen = sizeof(*tcp2); - tcp2->th_dport = htons(fi.fin_data[0]); - fi.fin_data[1] = 0; + tcp2->th_dport = htons(fi.fin_data[1]); + fi.fin_data[0] = 0; fi.fin_dp = (char *)tcp2; + fi.fin_fr = &natfr; swip = ip->ip_src; swip2 = ip->ip_dst; + fi.fin_fi.fi_daddr = ip->ip_src.s_addr; + fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; 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, @@ -614,14 +619,18 @@ int rv; #else mlen = mbufchainlen(m) - off; #endif + t = &ftp->ftp_side[1 - rv]; + f = &ftp->ftp_side[rv]; if (!mlen) { - t->ftps_seq = ntohl(tcp->th_ack); + if (!t->ftps_seq || + (int)ntohl(tcp->th_ack) - (int)t->ftps_seq > 0) + t->ftps_seq = ntohl(tcp->th_ack); + f->ftps_len = 0; return 0; } inc = 0; - f = &ftp->ftp_side[rv]; rptr = f->ftps_rptr; wptr = f->ftps_wptr; @@ -635,9 +644,12 @@ int rv; * that it is out of order (and there is no real danger in doing so * apart from causing packets to go through here ordered). */ - if (ntohl(tcp->th_seq) + i != f->ftps_seq) { + if (f->ftps_len + f->ftps_seq == ntohl(tcp->th_seq)) + f->ftps_seq = ntohl(tcp->th_seq); + else if (ntohl(tcp->th_seq) + i != f->ftps_seq) { return APR_ERR(-1); } + f->ftps_len = mlen; while (mlen > 0) { len = MIN(mlen, FTP_BUFSZ / 2); diff --git a/sys/contrib/ipfilter/netinet/ip_nat.c b/sys/contrib/ipfilter/netinet/ip_nat.c index 4f6921d..e7e121a 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.c +++ b/sys/contrib/ipfilter/netinet/ip_nat.c @@ -9,7 +9,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 2.37.2.26 2000/10/27 14:06:48 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.32 2001/01/10 06:19:11 darrenr Exp $"; #endif #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) @@ -129,7 +129,7 @@ u_long fr_defnatage = DEF_NAT_AGE, natstat_t nat_stats; int fr_nat_lock = 0; #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern kmutex_t ipf_rw, ipf_hostmap; +extern kmutex_t ipf_rw; extern KRWLOCK_T ipf_nat; #endif @@ -143,7 +143,7 @@ static void nat_delnat __P((struct ipnat *)); static int fr_natgetent __P((caddr_t)); static int fr_natgetsz __P((caddr_t)); static int fr_natputent __P((caddr_t)); -static void nat_tabmove __P((nat_t *)); +static void nat_tabmove __P((nat_t *, u_32_t)); static int nat_match __P((fr_info_t *, ipnat_t *, ip_t *)); static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr, struct in_addr)); @@ -250,6 +250,8 @@ ipnat_t *n; /* * check if an ip address has already been allocated for a given mapping that * is not doing port based translation. + * + * Must be called with ipf_nat held as a write lock. */ static struct hostmap *nat_hostmap(np, real, map) ipnat_t *np; @@ -259,13 +261,11 @@ struct in_addr map; hostmap_t *hm; u_int hv; - MUTEX_ENTER(&ipf_hostmap); hv = real.s_addr % HOSTMAP_SIZE; for (hm = maptable[hv]; hm; hm = hm->hm_next) if ((hm->hm_realip.s_addr == real.s_addr) && (np == hm->hm_ipnat)) { hm->hm_ref++; - MUTEX_EXIT(&ipf_hostmap); return hm; } @@ -281,15 +281,16 @@ struct in_addr map; hm->hm_mapip = map; hm->hm_ref = 1; } - MUTEX_EXIT(&ipf_hostmap); return hm; } +/* + * Must be called with ipf_nat held as a write lock. + */ static void nat_hostmapdel(hm) struct hostmap *hm; { - MUTEX_ENTER(&ipf_hostmap); ATOMIC_DEC32(hm->hm_ref); if (hm->hm_ref == 0) { if (hm->hm_next) @@ -297,7 +298,6 @@ struct hostmap *hm; *hm->hm_pnext = hm->hm_next; KFREE(hm); } - MUTEX_EXIT(&ipf_hostmap); } @@ -698,9 +698,9 @@ int mode; break; case FIONREAD : #ifdef IPFILTER_LOG + arg = (int)iplused[IPL_LOGNAT]; MUTEX_DOWNGRADE(&ipf_nat); - error = IWCOPY((caddr_t)&iplused[IPL_LOGNAT], (caddr_t)data, - sizeof(iplused[IPL_LOGNAT])); + error = IWCOPY((caddr_t)&arg, (caddr_t)data, sizeof(arg)); if (error) error = EFAULT; #endif @@ -1068,6 +1068,9 @@ static int nat_flushtable() for (natp = &nat_instances; (nat = *natp); ) { *natp = nat->nat_next; +#ifdef IPFILTER_LOG + nat_log(nat, NL_FLUSH); +#endif nat_delete(nat); j++; } @@ -1295,7 +1298,7 @@ int direction; inb.s_addr = htonl(in.s_addr); natl = nat_inlookup(fin->fin_ifp, flags & ~FI_WILDP, (u_int)ip->ip_p, ip->ip_dst, inb, - (port << 16) | dport); + (port << 16) | dport, 1); /* * Has the search wrapped around and come back to the @@ -1444,6 +1447,9 @@ int direction; tcp->th_dport = nport; } np->in_use++; +#ifdef IPFILTER_LOG + nat_log(nat, (u_int)np->in_redir); +#endif return nat; badnat: nat_stats.ns_badnat++; @@ -1565,18 +1571,18 @@ int dir; if (dir == NAT_INBOUND) 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); + (tcp->th_sport << 16) | tcp->th_dport, 0); else return nat_outlookup(fin->fin_ifp, flags, (u_int)oip->ip_p, oip->ip_dst, oip->ip_src, - (tcp->th_sport << 16) | tcp->th_dport); + (tcp->th_sport << 16) | tcp->th_dport, 0); } if (dir == NAT_INBOUND) return nat_inlookup(fin->fin_ifp, 0, (u_int)oip->ip_p, - oip->ip_dst, oip->ip_src, 0); + oip->ip_dst, oip->ip_src, 0, 0); else return nat_outlookup(fin->fin_ifp, 0, (u_int)oip->ip_p, - oip->ip_dst, oip->ip_src, 0); + oip->ip_dst, oip->ip_src, 0, 0); } @@ -1590,7 +1596,7 @@ fr_info_t *fin; u_int *nflags; int dir; { - u_32_t sum1, sum2, sumd; + u_32_t sum1, sum2, sumd, sumd2 = 0; struct in_addr in; icmphdr_t *icmp; udphdr_t *udp; @@ -1639,7 +1645,7 @@ int dir; * in the first 8 bytes, so it will not be available in most cases. */ - if (nat->nat_dir == NAT_OUTBOUND) { + if (oip->ip_dst.s_addr == nat->nat_oip.s_addr) { sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr)); in = nat->nat_inip; oip->ip_src = in; @@ -1691,7 +1697,7 @@ int dir; * checksum adjustment. */ CALC_SUMD(sum1, sum2, sumd); - fix_outcksum(&icmp->icmp_cksum, sumd); + sumd2 = sumd; } #if 0 @@ -1750,7 +1756,7 @@ int dir; * checksum adjustment. */ CALC_SUMD(sum1, sum2, sumd); - fix_incksum(&icmp->icmp_cksum, sumd); + sumd2 = sumd; } #if 0 @@ -1796,7 +1802,7 @@ int dir; * device that returns more than 8 data bytes on icmp error) */ - if (nat->nat_dir == NAT_OUTBOUND) { + if (nat->nat_oport == tcp->th_dport) { if (tcp->th_sport != nat->nat_inport) { /* * Fix ICMP checksum to compensate port @@ -1805,8 +1811,8 @@ int dir; sum1 = ntohs(tcp->th_sport); sum2 = ntohs(nat->nat_inport); CALC_SUMD(sum1, sum2, sumd); + sumd2 += sumd; tcp->th_sport = nat->nat_inport; - fix_outcksum(&icmp->icmp_cksum, sumd); /* * Fix udp checksum to compensate port @@ -1829,11 +1835,10 @@ int dir; * adjustment. */ CALC_SUMD(sum1, sum2, sumd); - fix_outcksum(&icmp->icmp_cksum, sumd); + sumd2 += sumd; } } } else { - if (tcp->th_dport != nat->nat_outport) { /* * Fix ICMP checksum to compensate port @@ -1842,8 +1847,8 @@ int dir; sum1 = ntohs(tcp->th_dport); sum2 = ntohs(nat->nat_outport); CALC_SUMD(sum1, sum2, sumd); + sumd2 += sumd; tcp->th_dport = nat->nat_outport; - fix_incksum(&icmp->icmp_cksum, sumd); /* * Fix udp checksum to compensate port @@ -1865,10 +1870,19 @@ int dir; * UDP checksum adjustment. */ CALC_SUMD(sum1, sum2, sumd); - fix_incksum(&icmp->icmp_cksum, sumd); + sumd2 += sumd; } } } + if (sumd2) { + sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); + sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); + if (nat->nat_dir == NAT_OUTBOUND) { + fix_outcksum(&icmp->icmp_cksum, sumd2); + } else { + fix_incksum(&icmp->icmp_cksum, sumd2); + } + } } nat->nat_age = fr_defnaticmpage; return nat; @@ -1885,11 +1899,12 @@ int dir; * we're looking for a table entry, based on the destination address. * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ -nat_t *nat_inlookup(ifp, flags, p, src, mapdst, ports) +nat_t *nat_inlookup(ifp, flags, p, src, mapdst, ports, rw) void *ifp; register u_int flags, p; struct in_addr src , mapdst; u_32_t ports; +int rw; { register u_short sport, dport; register nat_t *nat; @@ -1917,9 +1932,13 @@ u_32_t ports; } if (!nat_stats.ns_wilds || !(flags & IPN_TCPUDP)) return NULL; - RWLOCK_EXIT(&ipf_nat); + if (!rw) { + RWLOCK_EXIT(&ipf_nat); + } hv = NAT_HASH_FN(dst, 0, ipf_nattable_sz); - WRITE_ENTER(&ipf_nat); + if (!rw) { + WRITE_ENTER(&ipf_nat); + } nat = nat_table[1][hv]; for (; nat; nat = nat->nat_hnext[1]) { nflags = nat->nat_flags; @@ -1934,21 +1953,38 @@ u_32_t ports; continue; if (((nat->nat_oport == sport) || (nflags & FI_W_DPORT)) && ((nat->nat_outport == dport) || (nflags & FI_W_SPORT))) { - nat_tabmove(nat); + nat_tabmove(nat, ports); break; } } - MUTEX_DOWNGRADE(&ipf_nat); + if (!rw) { + MUTEX_DOWNGRADE(&ipf_nat); + } return nat; } -static void nat_tabmove(nat) +/* + * This function is only called for TCP/UDP NAT table entries where the + * original was placed in the table without hashing on the ports and we now + * want to include hashing on port numbers. + */ +static void nat_tabmove(nat, ports) nat_t *nat; +u_32_t ports; { + register u_short sport, dport; nat_t **natp; u_int hv; + dport = ports >> 16; + sport = ports & 0xffff; + + if (nat->nat_oport == dport) { + nat->nat_inport = sport; + nat->nat_outport = sport; + } + /* * Remove the NAT entry from the old location */ @@ -1963,8 +1999,7 @@ nat_t *nat; /* * Add into the NAT table in the new position */ - hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, - ipf_nattable_sz); + hv = NAT_HASH_FN(nat->nat_inip.s_addr, sport, ipf_nattable_sz); natp = &nat_table[0][hv]; if (*natp) (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; @@ -1972,8 +2007,7 @@ nat_t *nat; nat->nat_hnext[0] = *natp; *natp = nat; - hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, - ipf_nattable_sz); + hv = NAT_HASH_FN(nat->nat_outip.s_addr, sport, ipf_nattable_sz); natp = &nat_table[1][hv]; if (*natp) (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; @@ -1989,11 +2023,12 @@ nat_t *nat; * we're looking for a table entry, based on the source address. * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */ -nat_t *nat_outlookup(ifp, flags, p, src, dst, ports) +nat_t *nat_outlookup(ifp, flags, p, src, dst, ports, rw) void *ifp; register u_int flags, p; struct in_addr src , dst; u_32_t ports; +int rw; { register u_short sport, dport; register nat_t *nat; @@ -2014,7 +2049,7 @@ u_32_t ports; if ((!ifp || ifp == nat->nat_ifp) && nat->nat_inip.s_addr == srcip && nat->nat_oip.s_addr == dst.s_addr && - (((p == 0) && (flags == (nat->nat_flags & IPN_TCPUDP))) + (((p == 0) && (flags == (nflags & IPN_TCPUDP))) || (p == nat->nat_p)) && (!flags || ((nat->nat_inport == sport || nflags & FI_W_SPORT) && (nat->nat_oport == dport || nflags & FI_W_DPORT)))) @@ -2022,9 +2057,13 @@ u_32_t ports; } if (!nat_stats.ns_wilds || !(flags & IPN_TCPUDP)) return NULL; - RWLOCK_EXIT(&ipf_nat); + if (!rw) { + RWLOCK_EXIT(&ipf_nat); + } hv = NAT_HASH_FN(srcip, 0, ipf_nattable_sz); - WRITE_ENTER(&ipf_nat); + if (!rw) { + WRITE_ENTER(&ipf_nat); + } nat = nat_table[0][hv]; for (; nat; nat = nat->nat_hnext[0]) { nflags = nat->nat_flags; @@ -2037,13 +2076,15 @@ u_32_t ports; if ((nat->nat_inip.s_addr != srcip) || (nat->nat_oip.s_addr != dst.s_addr)) continue; - if (((nat->nat_inport == sport) || (nflags & FI_W_DPORT)) && - ((nat->nat_oport == dport) || (nflags & FI_W_SPORT))) { - nat_tabmove(nat); + if (((nat->nat_inport == sport) || (nflags & FI_W_SPORT)) && + ((nat->nat_oport == dport) || (nflags & FI_W_DPORT))) { + nat_tabmove(nat, ports); break; } } - MUTEX_DOWNGRADE(&ipf_nat); + if (!rw) { + MUTEX_DOWNGRADE(&ipf_nat); + } return nat; } @@ -2063,7 +2104,7 @@ register natlookup_t *np; * ip address. Else, we use the fake. */ if ((nat = nat_outlookup(NULL, np->nl_flags, 0, np->nl_inip, - np->nl_outip, ports))) { + np->nl_outip, ports, 0))) { np->nl_realip = nat->nat_outip; np->nl_realport = nat->nat_outport; } @@ -2164,10 +2205,11 @@ fr_info_t *fin; (nat = nat_icmp(ip, fin, &nflags, NAT_OUTBOUND))) ; else if ((ip->ip_off & (IP_OFFMASK|IP_MF)) && - (nat = ipfr_nat_knownfrag(ip, fin))) + (nat = ipfr_nat_knownfrag(ip, fin))) natadd = 0; - else if ((nat = nat_outlookup(ifp, nflags, (u_int)ip->ip_p, ip->ip_src, - ip->ip_dst, (dport << 16) | sport))) { + else if ((nat = nat_outlookup(ifp, nflags, (u_int)ip->ip_p, + ip->ip_src, ip->ip_dst, + (dport << 16) | sport, 0))) { nflags = nat->nat_flags; if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) { if ((nflags & FI_W_SPORT) && @@ -2221,9 +2263,6 @@ maskloop: if ((nat = nat_new(np, ip, fin, (u_int)nflags, NAT_OUTBOUND))) { np->in_hits++; -#ifdef IPFILTER_LOG - nat_log(nat, (u_int)np->in_redir); -#endif break; } } @@ -2239,6 +2278,9 @@ maskloop: MUTEX_DOWNGRADE(&ipf_nat); } + /* + * NOTE: ipf_nat must now only be held as a read lock + */ if (nat) { np = nat->nat_ptr; if (natadd && fin->fin_fi.fi_fl & FI_FRAG) @@ -2383,7 +2425,8 @@ fr_info_t *fin; (nat = ipfr_nat_knownfrag(ip, fin))) natadd = 0; else if ((nat = nat_inlookup(fin->fin_ifp, nflags, (u_int)ip->ip_p, - ip->ip_src, in, (dport << 16) | sport))) { + ip->ip_src, in, (dport << 16) | sport, + 0))) { nflags = nat->nat_flags; if ((nflags & (FI_W_SPORT|FI_W_DPORT)) != 0) { if ((nat->nat_oport != sport) && (nflags & FI_W_DPORT)) @@ -2424,9 +2467,6 @@ maskloop: if ((nat = nat_new(np, ip, fin, nflags, NAT_INBOUND))) { np->in_hits++; -#ifdef IPFILTER_LOG - nat_log(nat, (u_int)np->in_redir); -#endif break; } } @@ -2441,6 +2481,10 @@ maskloop: } MUTEX_DOWNGRADE(&ipf_nat); } + + /* + * NOTE: ipf_nat must now only be held as a read lock + */ if (nat) { np = nat->nat_ptr; fin->fin_fr = nat->nat_fr; diff --git a/sys/contrib/ipfilter/netinet/ip_nat.h b/sys/contrib/ipfilter/netinet/ip_nat.h index 8e166df..22f8503 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.h +++ b/sys/contrib/ipfilter/netinet/ip_nat.h @@ -6,7 +6,7 @@ * to the original author and the contributors. * * @(#)ip_nat.h 1.5 2/4/96 - * $Id: ip_nat.h,v 2.17.2.10 2000/10/27 14:06:51 darrenr Exp $ + * $Id: ip_nat.h,v 2.17.2.14 2000/11/18 03:58:04 darrenr Exp $ */ #ifndef __IP_NAT_H__ @@ -85,7 +85,7 @@ typedef struct nat { void *nat_ifp; int nat_dir; char nat_ifname[IFNAMSIZ]; -#if SOLARIS || defined(_sgi) +#if SOLARIS || defined(__sgi) kmutex_t nat_lock; #endif } nat_t; @@ -247,6 +247,7 @@ typedef struct natlog { #define NL_NEWRDR NAT_REDIRECT #define NL_NEWBIMAP NAT_BIMAP #define NL_NEWBLOCK NAT_MAPBLK +#define NL_FLUSH 0xfffe #define NL_EXPIRE 0xffff #define NAT_HASH_FN(k,l,m) (((k) + ((k) >> 12) + l) % (m)) @@ -285,9 +286,9 @@ extern int nat_ioctl __P((caddr_t, int, int)); 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)); + struct in_addr, u_32_t, int)); extern nat_t *nat_inlookup __P((void *, u_int, u_int, struct in_addr, - struct in_addr, u_32_t)); + struct in_addr, u_32_t, int)); extern nat_t *nat_maplookup __P((void *, u_int, struct in_addr, struct in_addr)); extern nat_t *nat_lookupredir __P((natlookup_t *)); diff --git a/sys/contrib/ipfilter/netinet/ip_proxy.h b/sys/contrib/ipfilter/netinet/ip_proxy.h index 933d79d..212900f 100644 --- a/sys/contrib/ipfilter/netinet/ip_proxy.h +++ b/sys/contrib/ipfilter/netinet/ip_proxy.h @@ -5,7 +5,7 @@ * provided that this notice is preserved and due credit is given * to the original author and the contributors. * - * $Id: ip_proxy.h,v 2.8.2.3 2000/05/06 12:32:43 darrenr Exp $ + * $Id: ip_proxy.h,v 2.8.2.4 2000/12/02 00:15:03 darrenr Exp $ */ #ifndef __IP_PROXY_H__ @@ -96,6 +96,7 @@ typedef struct ftpside { char *ftps_rptr; char *ftps_wptr; u_32_t ftps_seq; + u_32_t ftps_len; int ftps_junk; char ftps_buf[FTP_BUFSZ]; } ftpside_t; diff --git a/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c b/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c index e311b16..d017cf9 100644 --- a/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c @@ -1,5 +1,5 @@ /* - * $Id: ip_rcmd_pxy.c,v 1.4.2.3 2000/10/27 22:54:04 darrenr Exp $ + * $Id: ip_rcmd_pxy.c,v 1.4.2.4 2000/11/01 14:34:20 darrenr Exp $ */ /* * Simple RCMD transparent proxy for in-kernel use. For use with the NAT @@ -131,7 +131,7 @@ nat_t *nat; sp = htons(sp); dp = htons(fin->fin_data[1]); ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_p, nat->nat_inip, - ip->ip_dst, (dp << 16) | sp); + ip->ip_dst, (dp << 16) | sp, 0); if (ipn == NULL) { int slen; diff --git a/sys/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c index 7499bfd..5d63969 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.c +++ b/sys/contrib/ipfilter/netinet/ip_state.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.23 2000/10/27 14:06:08 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.28 2001/01/08 14:04:46 darrenr Exp $"; #endif #include @@ -307,8 +307,8 @@ int mode; break; case FIONREAD : #ifdef IPFILTER_LOG - error = IWCOPY((caddr_t)&iplused[IPL_LOGSTATE], (caddr_t)data, - sizeof(iplused[IPL_LOGSTATE])); + arg = (int)iplused[IPL_LOGSTATE]; + error = IWCOPY((caddr_t)&arg, (caddr_t)data, sizeof(arg)); #endif break; case SIOCSTLCK : @@ -787,8 +787,6 @@ tcphdr_t *tcp; } ATOMIC_INCL(ips_stats.iss_hits); - is->is_pkts++; - is->is_bytes += fin->fin_dlen + fin->fin_hlen; /* * Nearing end of connection, start timeout. */ @@ -1148,10 +1146,6 @@ fr_info_t *fin; 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 - */ is->is_pkts++; is->is_bytes += fin->fin_plen; /* @@ -1379,6 +1373,9 @@ void *ifp; } +/* + * Must always be called with fr_ipfstate held as a write lock. + */ static void fr_delstate(is) ipstate_t *is; { @@ -1397,9 +1394,10 @@ ipstate_t *is; fr = is->is_rule; if (fr != NULL) { - ATOMIC_DEC32(fr->fr_ref); - if (fr->fr_ref == 0) + fr->fr_ref--; + if (fr->fr_ref == 0) { KFREE(fr); + } } #ifdef _KERNEL MUTEX_DESTROY(&is->is_lock); @@ -1452,12 +1450,12 @@ void fr_timeoutstate() fr_delstate(is); } else isp = &is->is_next; - RWLOCK_EXIT(&ipf_state); - SPL_X(s); if (fr_state_doflush) { (void) fr_state_flush(1); fr_state_doflush = 0; } + RWLOCK_EXIT(&ipf_state); + SPL_X(s); } diff --git a/sys/contrib/ipfilter/netinet/ipl.h b/sys/contrib/ipfilter/netinet/ipl.h index b54d6f9..3529d65 100644 --- a/sys/contrib/ipfilter/netinet/ipl.h +++ b/sys/contrib/ipfilter/netinet/ipl.h @@ -6,12 +6,12 @@ * to the original author and the contributors. * * @(#)ipl.h 1.21 6/5/96 - * $Id: ipl.h,v 2.15.2.14 2000/10/27 22:54:41 darrenr Exp $ + * $Id: ipl.h,v 2.15.2.17 2001/01/14 13:47:15 darrenr Exp $ */ #ifndef __IPL_H__ #define __IPL_H__ -#define IPL_VERSION "IP Filter: v3.4.13" +#define IPL_VERSION "IP Filter: v3.4.16" #endif diff --git a/sys/contrib/ipfilter/netinet/mlfk_ipl.c b/sys/contrib/ipfilter/netinet/mlfk_ipl.c index f96c57e..0dc4ff2 100644 --- a/sys/contrib/ipfilter/netinet/mlfk_ipl.c +++ b/sys/contrib/ipfilter/netinet/mlfk_ipl.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: mlfk_ipl.c,v 2.1.2.4 2000/08/23 11:02:33 darrenr Exp $ + * $Id: mlfk_ipl.c,v 2.1.2.6 2000/11/18 03:58:29 darrenr Exp $ */ @@ -38,6 +38,12 @@ #include #include #include +#if (__FreeBSD_version >= 199511) +# include +# include +# include +# include +#endif #include @@ -47,6 +53,7 @@ #include #include #include +#include static dev_t ipf_devs[IPL_LOGMAX + 1]; @@ -86,6 +93,11 @@ SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW, &fr_defaultauthage, 0, ""); SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, ippr_ftp_pasvonly, CTLFLAG_RW, + &ippr_ftp_pasvonly, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &fr_minttl, 0, ""); +SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_minttllog, CTLFLAG_RW, + &fr_minttllog, 0, ""); #define CDEV_MAJOR 79 static struct cdevsw ipl_cdevsw = { -- cgit v1.1 From e64a51d4c6f3dd67d43458938a76082d6dc2e8ef Mon Sep 17 00:00:00 2001 From: darrenr Date: Sat, 28 Jul 2001 11:42:17 +0000 Subject: Import version 3.4.20 of IPFilter --- sys/contrib/ipfilter/netinet/fil.c | 144 +++++++++--------- sys/contrib/ipfilter/netinet/ip_auth.c | 217 ++++++++++++++++++--------- sys/contrib/ipfilter/netinet/ip_auth.h | 12 +- sys/contrib/ipfilter/netinet/ip_compat.h | 97 +++++++----- sys/contrib/ipfilter/netinet/ip_fil.c | 215 +++++++++++++++++--------- sys/contrib/ipfilter/netinet/ip_fil.h | 29 ++-- sys/contrib/ipfilter/netinet/ip_frag.c | 107 ++++++++++--- sys/contrib/ipfilter/netinet/ip_frag.h | 17 ++- sys/contrib/ipfilter/netinet/ip_ftp_pxy.c | 110 +++++++++++--- sys/contrib/ipfilter/netinet/ip_log.c | 67 +++------ sys/contrib/ipfilter/netinet/ip_nat.c | 154 +++++++++++-------- sys/contrib/ipfilter/netinet/ip_nat.h | 33 ++-- sys/contrib/ipfilter/netinet/ip_proxy.c | 34 +++-- sys/contrib/ipfilter/netinet/ip_proxy.h | 11 +- sys/contrib/ipfilter/netinet/ip_raudio_pxy.c | 22 ++- sys/contrib/ipfilter/netinet/ip_state.c | 77 ++++++---- sys/contrib/ipfilter/netinet/ip_state.h | 16 +- sys/contrib/ipfilter/netinet/ipl.h | 10 +- 18 files changed, 862 insertions(+), 510 deletions(-) diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index 02f075b..c4cd2e0 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/netinet/fil.c @@ -1,15 +1,8 @@ /* - * Copyright (C) 1993-2000 by Darren Reed. + * Copyright (C) 1993-2001 by Darren Reed. * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. + * See the IPFILTER.LICENCE file for details on licencing. */ -#if !defined(lint) -static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.30 2000/12/17 05:49:22 darrenr Exp $"; -#endif - #include #include #include @@ -100,6 +93,11 @@ static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.30 2000/12/17 05:49:22 darr #endif #include "netinet/ipl.h" +#if !defined(lint) +static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.39 2001/07/18 13:30:32 darrenr Exp $"; +#endif + #ifndef _KERNEL # include "ipf.h" # include "ipt.h" @@ -115,12 +113,6 @@ extern int opts; # if SOLARIS || defined(__sgi) 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) -# else /* SOLARIS */ -# define FR_NEWAUTH(m, fi, ip, qif) fr_newauth((mb_t *)m, fi, ip) # endif /* SOLARIS || __sgi */ #endif /* _KERNEL */ @@ -226,7 +218,7 @@ fr_info_t *fin; if (v == 4) { fin->fin_id = ip->ip_id; fi->fi_tos = ip->ip_tos; - off = (ip->ip_off & IP_OFFMASK) << 3; + off = (ip->ip_off & IP_OFFMASK); tcp = (tcphdr_t *)((char *)ip + hlen); (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4)); fi->fi_src.i6[1] = 0; @@ -239,7 +231,7 @@ fr_info_t *fin; fi->fi_daddr = ip->ip_dst.s_addr; p = ip->ip_p; fi->fi_fl = (hlen > sizeof(ip_t)) ? FI_OPTIONS : 0; - if (ip->ip_off & 0x3fff) + if (ip->ip_off & (IP_MF|IP_OFFMASK)) fi->fi_fl |= FI_FRAG; plen = ip->ip_len; fin->fin_dlen = plen - hlen; @@ -260,6 +252,7 @@ fr_info_t *fin; fi->fi_fl = 0; plen = ntohs(ip6->ip6_plen); fin->fin_dlen = plen; + plen += sizeof(*ip6); } #endif else @@ -268,6 +261,7 @@ fr_info_t *fin; fin->fin_off = off; fin->fin_plen = plen; fin->fin_dp = (void *)tcp; + off <<= 3; switch (p) { @@ -315,25 +309,34 @@ fr_info_t *fin; icmp = (icmphdr_t *)tcp; - if (icmp->icmp_type == ICMP_ECHOREPLY || - icmp->icmp_type == ICMP_ECHO) + switch (icmp->icmp_type) + { + case ICMP_ECHOREPLY : + case ICMP_ECHO : + /* Router discovery messages - RFC 1256 */ + case ICMP_ROUTERADVERT : + case ICMP_ROUTERSOLICIT : minicmpsz = ICMP_MINLEN; - + break; /* * type(1) + code(1) + cksum(2) + id(2) seq(2) + * 3*timestamp(3*4) */ - else if (icmp->icmp_type == ICMP_TSTAMP || - icmp->icmp_type == ICMP_TSTAMPREPLY) + case ICMP_TSTAMP : + case ICMP_TSTAMPREPLY : minicmpsz = 20; - + break; /* * type(1) + code(1) + cksum(2) + id(2) seq(2) + * mask(4) */ - else if (icmp->icmp_type == ICMP_MASKREQ || - icmp->icmp_type == ICMP_MASKREPLY) + case ICMP_MASKREQ : + case ICMP_MASKREPLY : minicmpsz = 12; + break; + default : + break; + } } if ((!(plen >= hlen + minicmpsz) && !off) || @@ -522,7 +525,7 @@ fr_info_t *fin; * satisfy the "short" class too). */ if (err && (fin->fin_fi.fi_p == IPPROTO_TCP)) { - if (fin->fin_fi.fi_fl & FI_SHORT) + if (fin->fin_fl & FI_SHORT) return !(ft->ftu_tcpf | ft->ftu_tcpfm); /* * Match the flags ? If not, abort this match. @@ -557,10 +560,7 @@ void *m; fin->fin_fr = NULL; fin->fin_rule = 0; fin->fin_group = 0; - if (fin->fin_v == 4) - off = ip->ip_off & IP_OFFMASK; - else - off = 0; + off = fin->fin_off; pass |= (fi->fi_fl << 24); if ((fi->fi_fl & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) @@ -787,7 +787,7 @@ int out; mb_t *mc = NULL; # if !defined(__SVR4) && !defined(__svr4__) # ifdef __sgi - char hbuf[(0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8]; + char hbuf[128]; # endif int up; @@ -812,6 +812,9 @@ int out; # ifdef USE_INET6 if (v == 6) { len = ntohs(((ip6_t*)ip)->ip6_plen); + if (!len) + return -1; /* potential jumbo gram */ + len += sizeof(ip6_t); p = ((ip6_t *)ip)->ip6_nxt; } else # endif @@ -820,7 +823,8 @@ int out; len = ip->ip_len; } - if ((p == IPPROTO_TCP || p == IPPROTO_UDP || p == IPPROTO_ICMP + if ((p == IPPROTO_TCP || p == IPPROTO_UDP || + (v == 4 && p == IPPROTO_ICMP) # ifdef USE_INET6 || (v == 6 && p == IPPROTO_ICMPV6) # endif @@ -889,13 +893,6 @@ int out; # endif #endif /* _KERNEL */ - /* - * Be careful here: ip_id is in network byte order when called - * from ip_output() - */ - if ((out) && (v == 4)) - ip->ip_id = ntohs(ip->ip_id); - changed = 0; fin->fin_ifp = ifp; fin->fin_v = v; @@ -940,15 +937,12 @@ int out; } #endif pass = fr_pass; - if (fin->fin_fi.fi_fl & FI_SHORT) { + if (fin->fin_fl & FI_SHORT) { ATOMIC_INCL(frstats[out].fr_short); } READ_ENTER(&ipf_mutex); - if (fin->fin_fi.fi_fl & FI_SHORT) - ATOMIC_INCL(frstats[out].fr_short); - /* * Check auth now. This, combined with the check below to see if apass * is 0 is to ensure that we don't count the packet twice, which can @@ -972,8 +966,18 @@ int out; } } - if (apass || (!(fr = ipfr_knownfrag(ip, fin)) && - !(fr = fr_checkstate(ip, fin)))) { + if (!apass) { + if ((fin->fin_fl & FI_FRAG) == FI_FRAG) + fr = ipfr_knownfrag(ip, fin); + if (!fr && !(fin->fin_fl & FI_SHORT)) + fr = fr_checkstate(ip, fin); + if (fr != NULL) + pass = fr->fr_flags; + if (fr && (pass & FR_LOGFIRST)) + pass &= ~(FR_LOGFIRST|FR_LOG); + } + + if (apass || !fr) { /* * If a packet is found in the auth table, then skip checking * the access lists for permission but we do need to consider @@ -1008,22 +1012,26 @@ int out; ATOMIC_INCL(frstats[out].fr_nom); } } - fr = fin->fin_fr; } else pass = apass; + fr = fin->fin_fr; /* * If we fail to add a packet to the authorization queue, * then we drop the packet later. However, if it was added * then pretend we've dropped it already. */ - if ((pass & FR_AUTH)) - if (fr_newauth((mb_t *)m, fin, ip) != 0) + if ((pass & FR_AUTH)) { + if (fr_newauth((mb_t *)m, fin, ip) != 0) { #ifdef _KERNEL m = *mp = NULL; #else ; #endif + error = 0; + } else + error = ENOSPC; + } if (pass & FR_PREAUTH) { READ_ENTER(&ipf_auth); @@ -1038,7 +1046,7 @@ int out; fin->fin_fr = fr; if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) { - if (fin->fin_fi.fi_fl & FI_FRAG) { + if (fin->fin_fl & FI_FRAG) { if (ipfr_newfrag(ip, fin, pass) == -1) { ATOMIC_INCL(frstats[out].fr_bnfr); } else { @@ -1116,9 +1124,6 @@ logit: } #endif /* IPFILTER_LOG */ - if ((out) && (v == 4)) - ip->ip_id = htons(ip->ip_id); - #ifdef _KERNEL /* * Only allow FR_DUP to work if a rule matched - it makes no sense to @@ -1160,7 +1165,7 @@ logit: send_icmp_err(ip, ICMP_UNREACH, fin, dst); ATOMIC_INCL(frstats[0].fr_ret); } else if (((pass & FR_RETMASK) == FR_RETRST) && - !(fin->fin_fi.fi_fl & FI_SHORT)) { + !(fin->fin_fl & FI_SHORT)) { if (send_reset(ip, fin) == 0) { ATOMIC_INCL(frstats[1].fr_ret); } @@ -1173,7 +1178,7 @@ logit: verbose("- forged ICMP unreachable sent\n"); ATOMIC_INCL(frstats[0].fr_ret); } else if (((pass & FR_RETMASK) == FR_RETRST) && - !(fin->fin_fi.fi_fl & FI_SHORT)) { + !(fin->fin_fl & FI_SHORT)) { verbose("- TCP RST sent\n"); ATOMIC_INCL(frstats[1].fr_ret); } @@ -1202,15 +1207,17 @@ logit: frdest_t *fdp = &fr->fr_tif; if (((pass & FR_FASTROUTE) && !out) || - (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) { - if (ipfr_fastroute(m, fin, fdp) == 0) - m = *mp = NULL; - } - if (mc) - ipfr_fastroute(mc, fin, &fr->fr_dif); + (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) + (void) ipfr_fastroute(m, mp, fin, fdp); + + if (mc != NULL) + (void) ipfr_fastroute(mc, &mc, fin, &fr->fr_dif); } - if (!(pass & FR_PASS) && m) + + if (!(pass & FR_PASS) && m) { m_freem(m); + m = *mp = NULL; + } # ifdef __sgi else if (changed && up && m) m_copyback(m, 0, up, hbuf); @@ -1221,12 +1228,11 @@ logit: frdest_t *fdp = &fr->fr_tif; if (((pass & FR_FASTROUTE) && !out) || - (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) { - if (ipfr_fastroute(ip, m, mp, fin, fdp) == 0) - m = *mp = NULL; - } - if (mc) - ipfr_fastroute(ip, mc, mp, fin, &fr->fr_dif); + (fdp->fd_ifp && fdp->fd_ifp != (struct ifnet *)-1)) + (void) ipfr_fastroute(ip, m, mp, fin, fdp); + + if (mc != NULL) + (void) ipfr_fastroute(ip, mc, &mc, fin, &fr->fr_dif); } # endif /* !SOLARIS */ return (pass & FR_PASS) ? 0 : error; @@ -1458,7 +1464,7 @@ nodata: * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 - * $Id: fil.c,v 2.35.2.30 2000/12/17 05:49:22 darrenr Exp $ + * $Id: fil.c,v 2.35.2.39 2001/07/18 13:30:32 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, @@ -1907,7 +1913,7 @@ void frsync() ip_statesync(ifp); } ip_natsync((struct ifnet *)-1); -# endif +# endif /* !SOLARIS */ WRITE_ENTER(&ipf_mutex); frsynclist(ipacct[0][fr_active]); diff --git a/sys/contrib/ipfilter/netinet/ip_auth.c b/sys/contrib/ipfilter/netinet/ip_auth.c index a453610..b22d470 100644 --- a/sys/contrib/ipfilter/netinet/ip_auth.c +++ b/sys/contrib/ipfilter/netinet/ip_auth.c @@ -1,14 +1,8 @@ /* - * Copyright (C) 1998-2000 by Darren Reed & Guido van Rooij. + * Copyright (C) 1998-2001 by Darren Reed & Guido van Rooij. * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. + * See the IPFILTER.LICENCE file for details on licencing. */ -#if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.5 2001/01/10 06:18:35 darrenr Exp $"; -#endif - #include #include #include @@ -77,7 +71,7 @@ static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.5 2001/01/10 06:18:35 d #endif #include #if defined(__sgi) && !defined(IFF_DRVRLOCK) /* IRIX < 6 */ -extern struct ifqueue ipintrq; /* ip packet input queue */ +extern struct ifqueue ipintrq; /* ip packet input queue */ #else # ifndef linux # if __FreeBSD_version >= 300000 @@ -107,10 +101,13 @@ extern struct ifqueue ipintrq; /* ip packet input queue */ # endif #endif +#if !defined(lint) +static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.12 2001/07/18 14:57:08 darrenr Exp $"; +#endif #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern KRWLOCK_T ipf_auth; +extern KRWLOCK_T ipf_auth, ipf_mutex; extern kmutex_t ipf_authmx; # if SOLARIS extern kcondvar_t ipfauthwait; @@ -129,7 +126,8 @@ static frauth_t fr_auth[FR_NUMAUTH]; mb_t *fr_authpkts[FR_NUMAUTH]; static int fr_authstart = 0, fr_authend = 0, fr_authnext = 0; static frauthent_t *fae_list = NULL; -frentry_t *ipauth = NULL; +frentry_t *ipauth = NULL, + *fr_authlist = NULL; /* @@ -142,10 +140,12 @@ ip_t *ip; fr_info_t *fin; { u_short id = ip->ip_id; + frentry_t *fr; + frauth_t *fra; u_32_t pass; int i; - if (fr_auth_lock) + if (fr_auth_lock || !fr_authused) return 0; READ_ENTER(&ipf_auth); @@ -155,24 +155,54 @@ fr_info_t *fin; * case the same packet gets sent again and it hasn't yet been * auth'd. */ - if ((fr_auth[i].fra_index == -2) && - (id == fr_auth[i].fra_info.fin_id) && - !bcmp((char *)fin,(char *)&fr_auth[i].fra_info,FI_CSIZE)) { + fra = fr_auth + i; + if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) && + !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) { /* * Avoid feedback loop. */ - if (!(pass = fr_auth[i].fra_pass) || (pass & FR_AUTH)) + if (!(pass = fra->fra_pass) || (pass & FR_AUTH)) pass = FR_BLOCK; + /* + * Create a dummy rule for the stateful checking to + * use and return. Zero out any values we don't + * trust from userland! + */ + if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) && + (fin->fin_fi.fi_fl & FI_FRAG))) { + KMALLOC(fr, frentry_t *); + if (fr) { + bcopy((char *)fra->fra_info.fin_fr, + fr, sizeof(*fr)); + fr->fr_grp = NULL; + fr->fr_ifa = fin->fin_ifp; + fr->fr_func = NULL; + fr->fr_ref = 1; + fr->fr_flags = pass; +#if BSD >= 199306 + fr->fr_oifa = NULL; +#endif + } + } else + fr = fra->fra_info.fin_fr; + fin->fin_fr = fr; RWLOCK_EXIT(&ipf_auth); WRITE_ENTER(&ipf_auth); + if (fr && fr != fra->fra_info.fin_fr) { + fr->fr_next = fr_authlist; + fr_authlist = fr; + } fr_authstats.fas_hits++; - fr_auth[i].fra_index = -1; + fra->fra_index = -1; fr_authused--; if (i == fr_authstart) { - while (fr_auth[i].fra_index == -1) { + while (fra->fra_index == -1) { i++; - if (i == FR_NUMAUTH) + fra++; + if (i == FR_NUMAUTH) { i = 0; + fra = fr_auth; + } fr_authstart = i; if (i == fr_authend) break; @@ -208,6 +238,7 @@ ip_t *ip; #if defined(_KERNEL) && SOLARIS qif_t *qif = fin->fin_qif; #endif + frauth_t *fra; int i; if (fr_auth_lock) @@ -219,7 +250,7 @@ ip_t *ip; RWLOCK_EXIT(&ipf_auth); return 0; } else { - if ((fr_authstart == 0) && (fr_authend == FR_NUMAUTH - 1)) { + if (fr_authused == FR_NUMAUTH) { fr_authstats.fas_nospace++; RWLOCK_EXIT(&ipf_auth); return 0; @@ -232,51 +263,48 @@ ip_t *ip; if (fr_authend == FR_NUMAUTH) fr_authend = 0; RWLOCK_EXIT(&ipf_auth); - fr_auth[i].fra_index = i; - fr_auth[i].fra_pass = 0; - fr_auth[i].fra_age = fr_defaultauthage; - bcopy((char *)fin, (char *)&fr_auth[i].fra_info, sizeof(*fin)); -#if !defined(sparc) && !defined(m68k) + fra = fr_auth + i; + fra->fra_index = i; + fra->fra_pass = 0; + fra->fra_age = fr_defaultauthage; + bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); +#if SOLARIS && defined(_KERNEL) +# if !defined(sparc) /* * No need to copyback here as we want to undo the changes, not keep * them. */ -# if SOLARIS && defined(_KERNEL) if ((ip == (ip_t *)m->b_rptr) && (ip->ip_v == 4)) -# endif { register u_short bo; bo = ip->ip_len; ip->ip_len = htons(bo); -# if !SOLARIS && !defined(__NetBSD__) - /* 4.4BSD converts this ip_input.c, but I don't in solaris.c */ - bo = ip->ip_id; - ip->ip_id = htons(bo); -# endif bo = ip->ip_off; ip->ip_off = htons(bo); } -#endif -#if SOLARIS && defined(_KERNEL) +# endif m->b_rptr -= qif->qf_off; fr_authpkts[i] = *(mblk_t **)fin->fin_mp; - fr_auth[i].fra_q = qif->qf_q; + fra->fra_q = qif->qf_q; cv_signal(&ipfauthwait); #else +# if defined(BSD) && !defined(sparc) && (BSD >= 199306) + if (!fin->fin_out) { + HTONS(ip->ip_len); + HTONS(ip->ip_off); + } +# endif fr_authpkts[i] = m; -# if defined(linux) && defined(_KERNEL) - wake_up_interruptible(&ipfauthwait); -# else WAKEUP(&fr_authnext); -# endif #endif return 1; } -int fr_auth_ioctl(data, cmd, fr, frptr) +int fr_auth_ioctl(data, mode, cmd, fr, frptr) caddr_t data; +int mode; #if defined(__NetBSD__) || defined(__OpenBSD__) || (FreeBSD_version >= 300003) u_long cmd; #else @@ -287,8 +315,9 @@ frentry_t *fr, **frptr; mb_t *m; #if defined(_KERNEL) && !SOLARIS struct ifqueue *ifq; + int s; #endif - frauth_t auth, *au = &auth; + frauth_t auth, *au = &auth, *fra; frauthent_t *fae, **faep; int i, error = 0; @@ -313,21 +342,26 @@ frentry_t *fr, **frptr; else faep = &fae->fae_next; if (cmd == SIOCRMAFR) { - if (!fae) + if (!fr || !frptr) + error = EINVAL; + else if (!fae) error = ESRCH; else { WRITE_ENTER(&ipf_auth); + SPL_NET(s); *faep = fae->fae_next; *frptr = fr->fr_next; + SPL_X(s); RWLOCK_EXIT(&ipf_auth); KFREE(fae); } - } else { + } else if (fr && frptr) { KMALLOC(fae, frauthent_t *); if (fae != NULL) { bcopy((char *)fr, (char *)&fae->fae_fr, sizeof(*fr)); WRITE_ENTER(&ipf_auth); + SPL_NET(s); fae->fae_age = fr_defaultauthage; fae->fae_fr.fr_hits = 0; fae->fae_fr.fr_next = *frptr; @@ -335,10 +369,12 @@ frentry_t *fr, **frptr; fae->fae_next = *faep; *faep = fae; ipauth = &fae_list->fae_fr; + SPL_X(s); RWLOCK_EXIT(&ipf_auth); } else error = ENOMEM; - } + } else + error = EINVAL; break; case SIOCATHST: READ_ENTER(&ipf_auth); @@ -348,6 +384,10 @@ frentry_t *fr, **frptr; sizeof(fr_authstats)); break; case SIOCAUTHW: + if (!(mode & FWRITE)) { + error = EPERM; + break; + } fr_authioctlloop: READ_ENTER(&ipf_auth); if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) { @@ -357,9 +397,11 @@ fr_authioctlloop: if (error) break; WRITE_ENTER(&ipf_auth); + SPL_NET(s); fr_authnext++; if (fr_authnext == FR_NUMAUTH) fr_authnext = 0; + SPL_X(s); RWLOCK_EXIT(&ipf_auth); return 0; } @@ -372,55 +414,62 @@ fr_authioctlloop: } mutex_exit(&ipf_authmx); # else -# ifdef linux - interruptible_sleep_on(&ipfauthwait); - if (current->signal & ~current->blocked) - error = -EINTR; -# else error = SLEEP(&fr_authnext, "fr_authnext"); # endif -# endif #endif RWLOCK_EXIT(&ipf_auth); if (!error) goto fr_authioctlloop; break; case SIOCAUTHR: + if (!(mode & FWRITE)) { + error = EPERM; + break; + } error = IRCOPYPTR(data, (caddr_t)&auth, sizeof(auth)); if (error) return error; WRITE_ENTER(&ipf_auth); + SPL_NET(s); i = au->fra_index; + fra = fr_auth + i; if ((i < 0) || (i > FR_NUMAUTH) || - (fr_auth[i].fra_info.fin_id != au->fra_info.fin_id)) { + (fra->fra_info.fin_id != au->fra_info.fin_id)) { + SPL_X(s); RWLOCK_EXIT(&ipf_auth); return EINVAL; } m = fr_authpkts[i]; - fr_auth[i].fra_index = -2; - fr_auth[i].fra_pass = au->fra_pass; + fra->fra_index = -2; + fra->fra_pass = au->fra_pass; fr_authpkts[i] = NULL; -#ifdef _KERNEL RWLOCK_EXIT(&ipf_auth); -# ifndef linux +#ifdef _KERNEL if (m && au->fra_info.fin_out) { -# if SOLARIS - error = fr_qout(fr_auth[i].fra_q, m); -# else /* SOLARIS */ -# if (_BSDI_VERSION >= 199802) || defined(__OpenBSD__) - error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, +# if SOLARIS + error = fr_qout(fra->fra_q, m); +# else /* SOLARIS */ + struct route ro; + + bzero((char *)&ro, sizeof(ro)); +# if ((_BSDI_VERSION >= 199802) && (_BSDI_VERSION < 200005)) || \ + defined(__OpenBSD__) + error = ip_output(m, NULL, &ro, IP_FORWARDING, NULL, NULL); -# else - error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); -# endif -# endif /* SOLARIS */ +# else + error = ip_output(m, NULL, &ro, IP_FORWARDING, NULL); +# endif + if (ro.ro_rt) { + RTFREE(ro.ro_rt); + } +# endif /* SOLARIS */ if (error) fr_authstats.fas_sendfail++; else fr_authstats.fas_sendok++; } else if (m) { # if SOLARIS - error = fr_qin(fr_auth[i].fra_q, m); + error = fr_qin(fra->fra_q, m); # else /* SOLARIS */ ifq = &ipintrq; if (IF_QFULL(ifq)) { @@ -438,7 +487,6 @@ fr_authioctlloop: fr_authstats.fas_queok++; } else error = EINVAL; -# endif # if SOLARIS if (error) error = EINVAL; @@ -449,10 +497,10 @@ fr_authioctlloop: */ if (error == ENOBUFS) { fr_authused--; - fr_auth[i].fra_index = -1; - fr_auth[i].fra_pass = 0; + fra->fra_index = -1; + fra->fra_pass = 0; if (i == fr_authstart) { - while (fr_auth[i].fra_index == -1) { + while (fra->fra_index == -1) { i++; if (i == FR_NUMAUTH) i = 0; @@ -468,6 +516,7 @@ fr_authioctlloop: } # endif #endif /* _KERNEL */ + SPL_X(s); break; default : error = EINVAL; @@ -485,6 +534,7 @@ void fr_authunload() { register int i; register frauthent_t *fae, **faep; + frentry_t *fr, **frp; mb_t *m; WRITE_ENTER(&ipf_auth); @@ -503,6 +553,26 @@ void fr_authunload() } ipauth = NULL; RWLOCK_EXIT(&ipf_auth); + + if (fr_authlist) { + /* + * We *MuST* reget ipf_auth because otherwise we won't get the + * locks in the right order and risk deadlock. + * We need ipf_mutex here to prevent a rule from using it + * inside fr_check(). + */ + WRITE_ENTER(&ipf_mutex); + WRITE_ENTER(&ipf_auth); + for (frp = &fr_authlist; (fr = *frp); ) { + if (fr->fr_ref == 1) { + *frp = fr->fr_next; + KFREE(fr); + } else + frp = &fr->fr_next; + } + RWLOCK_EXIT(&ipf_auth); + RWLOCK_EXIT(&ipf_mutex); + } } @@ -515,6 +585,7 @@ void fr_authexpire() register int i; register frauth_t *fra; register frauthent_t *fae, **faep; + register frentry_t *fr, **frp; mb_t *m; #if !SOLARIS int s; @@ -544,6 +615,14 @@ void fr_authexpire() faep = &fae->fae_next; } ipauth = &fae_list->fae_fr; + + for (frp = &fr_authlist; (fr = *frp); ) { + if (fr->fr_ref == 1) { + *frp = fr->fr_next; + KFREE(fr); + } else + frp = &fr->fr_next; + } RWLOCK_EXIT(&ipf_auth); SPL_X(s); } diff --git a/sys/contrib/ipfilter/netinet/ip_auth.h b/sys/contrib/ipfilter/netinet/ip_auth.h index 681a6e5..7d3e463 100644 --- a/sys/contrib/ipfilter/netinet/ip_auth.h +++ b/sys/contrib/ipfilter/netinet/ip_auth.h @@ -1,11 +1,9 @@ /* - * Copyright (C) 1997-2000 by Darren Reed & Guido Van Rooij. + * Copyright (C) 1997-2001 by Darren Reed & Guido Van Rooij. * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. + * See the IPFILTER.LICENCE file for details on licencing. * - * $Id: ip_auth.h,v 2.3.2.2 2000/10/19 15:38:44 darrenr Exp $ + * $Id: ip_auth.h,v 2.3.2.4 2001/07/18 14:57:08 darrenr Exp $ * */ #ifndef __IP_AUTH_H__ @@ -55,8 +53,8 @@ extern void fr_authunload __P((void)); extern mb_t *fr_authpkts[]; extern int fr_newauth __P((mb_t *, fr_info_t *, ip_t *)); #if defined(__NetBSD__) || defined(__OpenBSD__) -extern int fr_auth_ioctl __P((caddr_t, u_long, frentry_t *, frentry_t **)); +extern int fr_auth_ioctl __P((caddr_t, int, u_long, frentry_t *, frentry_t **)); #else -extern int fr_auth_ioctl __P((caddr_t, int, frentry_t *, frentry_t **)); +extern int fr_auth_ioctl __P((caddr_t, int, int, frentry_t *, frentry_t **)); #endif #endif /* __IP_AUTH_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h index ed71f36..a7d0db4 100644 --- a/sys/contrib/ipfilter/netinet/ip_compat.h +++ b/sys/contrib/ipfilter/netinet/ip_compat.h @@ -1,12 +1,10 @@ /* - * Copyright (C) 1993-2000 by Darren Reed. + * Copyright (C) 1993-2001 by Darren Reed. * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. + * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_compat.h 1.8 1/14/96 - * $Id: ip_compat.h,v 2.26.2.9 2001/01/14 14:58:01 darrenr Exp $ + * $Id: ip_compat.h,v 2.26.2.17 2001/07/23 04:22:48 darrenr Exp $ */ #ifndef __IP_COMPAT_H__ @@ -27,6 +25,9 @@ #ifndef SOLARIS #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #endif +#if SOLARIS && !defined(SOLARIS2) +# define SOLARIS2 4 /* Pick an old version */ +#endif #if SOLARIS2 >= 8 # ifndef USE_INET6 # define USE_INET6 @@ -119,10 +120,34 @@ struct ether_addr { # define V4_PART_OF_V6(v6) v6.s6_addr32[3] # endif # endif -#else + +typedef struct qif { + struct qif *qf_next; + ill_t *qf_ill; + kmutex_t qf_lock; + void *qf_iptr; + void *qf_optr; + queue_t *qf_in; + queue_t *qf_out; + struct qinit *qf_wqinfo; + struct qinit *qf_rqinfo; + struct qinit qf_wqinit; + struct qinit qf_rqinit; + mblk_t *qf_m; /* These three fields are for passing data up from */ + queue_t *qf_q; /* fr_qin and fr_qout to the packet processing. */ + 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... + */ + size_t qf_hl; /* header length */ + int qf_sap; +} qif_t; +#else /* SOLARIS */ # if !defined(__sgi) typedef int minor_t; -#endif +# endif #endif /* SOLARIS */ #define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h))) @@ -264,10 +289,26 @@ union i6addr { #if defined(__FreeBSD__) && (defined(KERNEL) || defined(_KERNEL)) # ifdef IPFILTER_LKM -# include +# ifndef __FreeBSD_cc_version +# include +# else +# if __FreeBSD_cc_version < 430000 +# include +# else +# include +# endif +# endif # define ACTUALLY_LKM_NOT_KERNEL # else -# include +# ifndef __FreeBSD_cc_version +# include +# else +# if __FreeBSD_cc_version < 430000 +# include +# else +# include +# endif +# endif # endif # if __FreeBSD__ < 3 # include @@ -325,6 +366,7 @@ typedef struct { # define ATOMIC_DEC32(x) atomic_add_32((uint32_t*)&(x), -1) # define ATOMIC_DEC16(x) atomic_add_16((uint16_t*)&(x), -1) # else +# define IRE_CACHE IRE_ROUTE # define ATOMIC_INC(x) { mutex_enter(&ipf_rw); (x)++; \ mutex_exit(&ipf_rw); } # define ATOMIC_DEC(x) { mutex_enter(&ipf_rw); (x)--; \ @@ -374,29 +416,6 @@ typedef struct { # 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; - ill_t *qf_ill; - kmutex_t qf_lock; - void *qf_iptr; - void *qf_optr; - queue_t *qf_in; - queue_t *qf_out; - struct qinit *qf_wqinfo; - struct qinit *qf_rqinfo; - struct qinit qf_wqinit; - struct qinit qf_rqinit; - mblk_t *qf_m; /* These three fields are for passing data up from */ - queue_t *qf_q; /* fr_qin and fr_qout to the packet processing. */ - 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... - */ - size_t qf_hl; /* header length */ - int qf_sap; -} qif_t; extern ill_t *get_unit __P((char *, int)); # define GETUNIT(n, v) get_unit(n, v) # define IFNAME(x) ((ill_t *)x)->ill_name @@ -452,7 +471,9 @@ extern ill_t *get_unit __P((char *, int)); (defined(OpenBSD) && (OpenBSD >= 199603)) # define IFNAME(x) ((struct ifnet *)x)->if_xname # else -# define IFNAME(x) ((struct ifnet *)x)->if_name +# define USE_GETIFNAME 1 +# define IFNAME(x) get_ifname((struct ifnet *)x) +extern char *get_ifname __P((struct ifnet *)); # endif # endif # endif /* sun */ @@ -508,7 +529,8 @@ extern vm_map_t kmem_map; # define SLEEP(id, n) tsleep((id), PPAUSE|PCATCH, n, 0) # define WAKEUP(id) wakeup(id) # endif /* BSD */ -# if defined(NetBSD) && NetBSD <= 1991011 && NetBSD >= 199407 +# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199407)) || \ + (defined(OpenBSD) && (OpenBSD >= 200006)) # define SPL_NET(x) x = splsoftnet() # define SPL_X(x) (void) splx(x) # else @@ -517,7 +539,7 @@ extern vm_map_t kmem_map; # define SPL_NET(x) x = splnet() # define SPL_X(x) (void) splx(x) # endif -# endif /* NetBSD && NetBSD <= 1991011 && NetBSD >= 199407 */ +# endif /* NetBSD && (NetBSD <= 1991011) && (NetBSD >= 199407) */ # define PANIC(x,y) if (x) panic y #else /* KERNEL */ # define SLEEP(x,y) ; @@ -576,7 +598,6 @@ typedef struct mbuf mb_t; # endif #endif /* SOLARIS */ -#if defined(linux) || defined(__sgi) /* * These #ifdef's are here mainly for linux, but who knows, they may * not be in other places or maybe one day linux will grow up and some @@ -615,6 +636,9 @@ typedef struct mbuf mb_t; #ifndef ICMP_MASKREPLY # define ICMP_MASKREPLY ICMP_ADDRESSREPLY #endif +#ifndef ICMP_PARAMPROB_OPTABSENT +# define ICMP_PARAMPROB_OPTABSENT 1 +#endif #ifndef IPVERSION # define IPVERSION 4 #endif @@ -702,7 +726,6 @@ typedef struct mbuf mb_t; #ifndef IPOPT_OLEN # define IPOPT_OLEN 1 #endif -#endif /* linux || __sgi */ #ifdef linux #include diff --git a/sys/contrib/ipfilter/netinet/ip_fil.c b/sys/contrib/ipfilter/netinet/ip_fil.c index 9253775..e15ff67 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil.c +++ b/sys/contrib/ipfilter/netinet/ip_fil.c @@ -1,15 +1,8 @@ /* - * Copyright (C) 1993-2000 by Darren Reed. + * Copyright (C) 1993-2001 by Darren Reed. * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. + * See the IPFILTER.LICENCE file for details on licencing. */ -#if !defined(lint) -static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.17 2000/10/19 15:39:42 darrenr Exp $"; -#endif - #ifndef SOLARIS #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #endif @@ -118,6 +111,11 @@ static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.17 2000/10/19 15:39:42 d extern int ip_optcopy __P((struct ip *, struct ip *)); #endif +#if !defined(lint) +static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.34 2001/07/23 13:49:57 darrenr Exp $"; +#endif + extern struct protosw inetsw[]; @@ -131,7 +129,11 @@ extern int tcp_ttl; # endif #endif +#ifdef ICMP_UNREACH_FILTER_PROHIB +int ipl_unreach = ICMP_UNREACH_FILTER_PROHIB; +#else int ipl_unreach = ICMP_UNREACH_FILTER; +#endif u_long ipl_frouteok[2] = {0, 0}; static int frzerostats __P((caddr_t)); @@ -171,6 +173,10 @@ struct callout_handle ipfr_slowtimer_ch; # include struct callout ipfr_slowtimer_ch; #endif +#if defined(__OpenBSD__) +# include +struct timeout ipfr_slowtimer_ch; +#endif #if defined(__sgi) && defined(_KERNEL) toid_t ipfr_slowtimer_ch; #endif @@ -246,12 +252,18 @@ int iplattach() # ifdef IPFILTER_LOG ipflog_init(); # endif - if (nat_init() == -1) - return -1; - if (fr_stateinit() == -1) - return -1; - if (appr_init() == -1) - return -1; + if (nat_init() == -1) { + SPL_X(s); + return EIO; + } + if (fr_stateinit() == -1) { + SPL_X(s); + return EIO; + } + if (appr_init() == -1) { + SPL_X(s); + return EIO; + } # ifdef NETBSD_PF # if __NetBSD_Version__ >= 104200000 @@ -261,6 +273,7 @@ int iplattach() # ifdef USE_INET6 goto pfil_error; # else + SPL_X(s); appr_unload(); ip_natunload(); fr_stateunload(); @@ -277,6 +290,7 @@ int iplattach() pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); pfil_error: + SPL_X(s); appr_unload(); ip_natunload(); fr_stateunload(); @@ -321,10 +335,15 @@ pfil_error: callout_init(&ipfr_slowtimer_ch); callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL); # else -# if (__FreeBSD_version >= 300000) || defined(__sgi) - ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); +# if defined(__OpenBSD__) + timeout_set(&ipfr_slowtimer_ch, ipfr_slowtimer, NULL); + timeout_add(&ipfr_slowtimer_ch, hz/2); # else +# if (__FreeBSD_version >= 300000) || defined(__sgi) + ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); +# else timeout(ipfr_slowtimer, NULL, hz/2); +# endif # endif # endif #endif @@ -353,8 +372,12 @@ int ipldetach() # ifdef __sgi untimeout(ipfr_slowtimer_ch); # else +# if defined(__OpenBSD__) + timeout_del(&ipfr_slowtimer_ch); +# else untimeout(ipfr_slowtimer, NULL); -# endif +# endif /* OpenBSD */ +# endif /* __sgi */ # endif /* FreeBSD */ # endif /* NetBSD */ #endif @@ -376,16 +399,20 @@ int ipldetach() # if __NetBSD_Version__ >= 104200000 error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); - if (error) + if (error) { + SPL_X(s); return error; + } # else pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT); # endif # ifdef USE_INET6 error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, &inetsw[ip_protox[IPPROTO_IPV6]].pr_pfh); - if (error) + if (error) { + SPL_X(s); return error; + } # endif # endif @@ -489,8 +516,9 @@ int mode; } if (unit == IPL_LOGAUTH) { if (!fr_running) - return EIO; - error = fr_auth_ioctl(data, cmd, NULL, NULL); + error = EIO; + else + error = fr_auth_ioctl(data, mode, cmd, NULL, NULL); SPL_X(s); return error; } @@ -564,7 +592,7 @@ int mode; fr_getstat(&fio); error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio)); if (error) - return EFAULT; + error = EFAULT; break; } case SIOCFRZST : @@ -607,7 +635,7 @@ int mode; error = IWCOPYPTR((caddr_t)ipfr_fragstats(), data, sizeof(ipfrstat_t)); if (error) - return EFAULT; + error = EFAULT; break; case SIOCAUTHW : case SIOCAUTHR : @@ -820,8 +848,6 @@ caddr_t data; return EBUSY; if (fg && fg->fg_head) fg->fg_head->fr_ref--; - if (unit == IPL_LOGAUTH) - return fr_auth_ioctl(data, req, f, ftail); if (f->fr_grhead) fr_delgroup((u_int)f->fr_grhead, fp->fr_flags, unit, set); @@ -835,8 +861,6 @@ caddr_t data; if (f) error = EEXIST; else { - if (unit == IPL_LOGAUTH) - return fr_auth_ioctl(data, req, fp, ftail); KMALLOC(f, frentry_t *); if (f != NULL) { if (fg && fg->fg_head) @@ -1068,7 +1092,7 @@ struct mbuf *m; # ifdef IPSEC m->m_pkthdr.rcvif = NULL; # endif - return ipfr_fastroute(m, fin, NULL); + return ipfr_fastroute(m, fin->fin_mp, fin, NULL); } @@ -1079,6 +1103,7 @@ fr_info_t *fin; int dst; { int err, hlen = 0, xtra = 0, iclen, ohlen = 0, avail, code; + u_short shlen, slen = 0, soff = 0; struct in_addr dst4; struct icmp *icmp; struct mbuf *m; @@ -1220,6 +1245,11 @@ int dst; } else #endif { + slen = oip->ip_len; + oip->ip_len = htons(oip->ip_len); + soff = oip->ip_off; + oip->ip_off = htons(ip->ip_off); + ip->ip_src.s_addr = dst4.s_addr; ip->ip_dst.s_addr = oip->ip_src.s_addr; @@ -1233,7 +1263,18 @@ int dst; ip->ip_len = iclen; ip->ip_p = IPPROTO_ICMP; } + + shlen = fin->fin_hlen; + fin->fin_hlen = hlen; err = send_ip(oip, fin, m); + fin->fin_hlen = shlen; +#ifdef USE_INET6 + if (fin->fin_v == 4) +#endif + { + oip->ip_len = slen; + oip->ip_off = soff; + } return err; } @@ -1268,8 +1309,8 @@ register struct mbuf *m0; } -int ipfr_fastroute(m0, fin, fdp) -struct mbuf *m0; +int ipfr_fastroute(m0, mpp, fin, fdp) +struct mbuf *m0, **mpp; fr_info_t *fin; frdest_t *fdp; { @@ -1282,16 +1323,49 @@ frdest_t *fdp; struct route iproute; frentry_t *fr; +#ifdef M_WRITABLE + /* + * HOT FIX/KLUDGE: + * + * If the mbuf we're about to send is not writable (because of + * a cluster reference, for example) we'll need to make a copy + * of it since this routine modifies the contents. + * + * If you have non-crappy network hardware that can transmit data + * from the mbuf, rather than making a copy, this is gonna be a + * problem. + */ + if (M_WRITABLE(m) == 0) { + if ((m0 = m_dup(m, M_DONTWAIT)) != 0) { + m_freem(m); + m = m0; + } else { + error = ENOBUFS; + m_freem(m); + ipl_frouteok[1]++; + } + } +#endif + hlen = fin->fin_hlen; ip = mtod(m0, struct ip *); +#if defined(__NetBSD__) && defined(M_CSUM_IPv4) + /* + * Clear any in-bound checksum flags for this packet. + */ + m0->m_pkthdr.csuminfo = 0; +#endif /* __NetBSD__ && M_CSUM_IPv4 */ + #ifdef USE_INET6 if (ip->ip_v == 6) { /* * currently "to " and "to :ip#" are not supported * for IPv6 */ - return ip6_output(m0, NULL, NULL, 0, NULL, NULL); + error = ip6_output(m0, NULL, NULL, 0, NULL, NULL); + *mpp = NULL; + return error; } #endif /* @@ -1316,10 +1390,15 @@ frdest_t *fdp; */ if ((fr != NULL) && (fin->fin_rev != 0)) { if ((ifp != NULL) && (fdp == &fr->fr_tif)) - return -1; + return 0; dst->sin_addr = ip->ip_dst; - } else if (fdp) - dst->sin_addr = fdp->fd_ip.s_addr ? fdp->fd_ip : ip->ip_dst; + } else if (fdp) { + if (fdp->fd_ip.s_addr) { + dst->sin_addr = fdp->fd_ip; + ip->ip_dst = fdp->fd_ip; + } else + dst->sin_addr = ip->ip_dst; + } # if BSD >= 199306 dst->sin_len = sizeof(*dst); @@ -1374,36 +1453,44 @@ frdest_t *fdp; * If small enough for interface, can just send directly. */ if (ip->ip_len <= ifp->if_mtu) { -# if BSD >= 199306 +# if defined(MCLISREFERENCED) && !defined(sparc) int i = 0; -# ifdef MCLISREFERENCED if ((m->m_flags & M_EXT) && MCLISREFERENCED(m)) -# else - if (m->m_flags & M_EXT) -# endif i = 1; # endif # ifndef sparc +# if !(_BSDI_VERSION >= 199510) ip->ip_id = htons(ip->ip_id); +# endif ip->ip_len = htons(ip->ip_len); ip->ip_off = htons(ip->ip_off); # endif +# if defined(__NetBSD__) && defined(M_CSUM_IPv4) + if (ifp->if_capabilities & IFCAP_CSUM_IPv4) + m->m_pkthdr.csuminfo |= M_CSUM_IPv4; + else if (ip->ip_sum == 0) + ip->ip_sum = in_cksum(m, hlen); +# else if (!ip->ip_sum) ip->ip_sum = in_cksum(m, hlen); +# endif /* __NetBSD__ && M_CSUM_IPv4 */ # if BSD >= 199306 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, ro->ro_rt); +# if defined(MCLISREFERENCED) && !defined(sparc) if (i) { ip->ip_id = ntohs(ip->ip_id); ip->ip_len = ntohs(ip->ip_len); ip->ip_off = ntohs(ip->ip_off); } +# endif # else error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst); # endif goto done; } + /* * Too large for interface; fragment if possible. * Must be able to put at least 8 bytes per fragment. @@ -1506,9 +1593,11 @@ done: else ipl_frouteok[1]++; - if (ro->ro_rt) + if (ro->ro_rt) { RTFREE(ro->ro_rt); - return 0; + } + *mpp = NULL; + return error; bad: if (error == EMSGSIZE) { sifp = fin->fin_ifp; @@ -1550,6 +1639,18 @@ void *ifp; return (ifp == iproute.ro_rt->rt_ifp); } + +# ifdef USE_GETIFNAME +char * +get_ifname(ifp) +struct ifnet *ifp; +{ + static char workbuf[64]; + + sprintf(workbuf, "%s%d", ifp->if_name, ifp->if_unit); + return workbuf; +} +# endif #else /* #ifdef _KERNEL */ @@ -1586,9 +1687,9 @@ ip_t *ip; # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ (defined(OpenBSD) && (OpenBSD >= 199603)) - sprintf(fname, "/tmp/%s", ifp->if_xname); + sprintf(fname, "%s", ifp->if_xname); # else - sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); + sprintf(fname, "%s%d", ifp->if_name, ifp->if_unit); # endif fd = open(fname, O_WRONLY|O_APPEND); if (fd == -1) { @@ -1605,7 +1706,7 @@ struct ifnet *get_unit(name, v) char *name; int v; { - struct ifnet *ifp, **ifa; + struct ifnet *ifp, **ifa, **old_ifneta; # if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ (defined(OpenBSD) && (OpenBSD >= 199603)) for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { @@ -1634,10 +1735,12 @@ int v; } nifs = 1; } else { + old_ifneta = ifneta; nifs++; ifneta = (struct ifnet **)realloc(ifneta, (nifs + 1) * sizeof(*ifa)); if (!ifneta) { + free(old_ifneta); nifs = 0; return NULL; } @@ -1704,28 +1807,6 @@ void init_ifp() } -int ipfr_fastroute(ip, fin, fdp) -ip_t *ip; -fr_info_t *fin; -frdest_t *fdp; -{ - struct ifnet *ifp = fdp->fd_ifp; - - if (!ifp) - 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)); - ip->ip_sum = 0; -#ifdef __sgi - (*ifp->if_output)(ifp, (void *)ip, NULL); -#else - (*ifp->if_output)(ifp, (void *)ip, NULL, 0); -#endif - return 0; -} - - int ipllog __P((void)) { verbose("l"); diff --git a/sys/contrib/ipfilter/netinet/ip_fil.h b/sys/contrib/ipfilter/netinet/ip_fil.h index ed1cfc4..6d51ced 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil.h +++ b/sys/contrib/ipfilter/netinet/ip_fil.h @@ -1,12 +1,10 @@ /* - * Copyright (C) 1993-2000 by Darren Reed. + * Copyright (C) 1993-2001 by Darren Reed. * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. + * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_fil.h 1.35 6/5/96 - * $Id: ip_fil.h,v 2.29.2.4 2000/11/12 11:54:53 darrenr Exp $ + * $Id: ip_fil.h,v 2.29.2.10 2001/07/15 13:51:42 darrenr Exp $ */ #ifndef __IP_FIL_H__ @@ -59,7 +57,7 @@ # define SIOCSTLCK _IOWR('r', 79, u_int) # define SIOCSTPUT _IOWR('r', 80, struct ipstate_save *) # define SIOCSTGET _IOWR('r', 81, struct ipstate_save *) -# define SIOCSTGSZ _IOWR('r', 82, struct natget *) +# define SIOCSTGSZ _IOWR('r', 82, struct natget) # define SIOCGFRST _IOWR('r', 83, struct ipfrstat *) #else # define SIOCADAFR _IOW(r, 60, struct frentry *) @@ -84,7 +82,7 @@ # define SIOCSTLCK _IOWR(r, 79, u_int) # define SIOCSTPUT _IOWR(r, 80, struct ipstate_save *) # define SIOCSTGET _IOWR(r, 81, struct ipstate_save *) -# define SIOCSTGSZ _IOWR(r, 82, struct natget *) +# define SIOCSTGSZ _IOWR(r, 82, struct natget) # define SIOCGFRST _IOWR(r, 83, struct ipfrstat *) #endif #define SIOCADDFR SIOCADAFR @@ -152,7 +150,10 @@ typedef struct fr_info { u_short fin_off; } fr_info_t; -#define fin_v fin_fi.fi_v +#define fin_v fin_fi.fi_v +#define fin_saddr fin_fi.fi_saddr +#define fin_daddr fin_fi.fi_daddr +#define fin_fl fin_fi.fi_fl /* * Size for compares on fr_info structures @@ -168,6 +169,9 @@ typedef struct frdest { void *fd_ifp; struct in_addr fd_ip; char fd_ifname[IFNAMSIZ]; +#if SOLARIS + mb_t *fd_mp; /* cache resolver for to/dup-to */ +#endif } frdest_t; typedef struct frpcmp { @@ -192,8 +196,6 @@ typedef struct frtuc { typedef struct frentry { struct frentry *fr_next; - u_32_t fr_group; /* group to which this rule belongs */ - u_32_t fr_grhead; /* group # which this rule starts */ struct frentry *fr_grp; int fr_ref; /* reference count - for grouping */ void *fr_ifa; @@ -217,6 +219,8 @@ typedef struct frentry { u_short fr_icmp; frtuc_t fr_tuc; + u_32_t fr_group; /* group to which this rule belongs */ + u_32_t fr_grhead; /* group # which this rule starts */ u_32_t fr_flags; /* per-rule flags && options (see below) */ u_int fr_skip; /* # of rules to skip */ u_int fr_loglevel; /* syslog log facility + priority */ @@ -436,6 +440,8 @@ typedef struct ipflog { #define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h))) #define IPLLOGSIZE 8192 +#define IPF_OPTCOPY 0x07ff00 /* bit mask of copied options */ + /* * Device filenames for reading log information. Use ipf on Solaris2 because * ipl is already a name used by something else. @@ -484,7 +490,6 @@ 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 int ipfr_fastroute __P((ip_t *, fr_info_t *, frdest_t *)); extern struct ifnet *get_unit __P((char *, int)); # if defined(__NetBSD__) || defined(__OpenBSD__) || \ (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) @@ -530,7 +535,7 @@ extern int iplread __P((dev_t, struct uio *, cred_t *)); # else /* SOLARIS */ 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 ipfr_fastroute __P((mb_t *, fr_info_t *, frdest_t *)); +extern int ipfr_fastroute __P((mb_t *, mb_t **, fr_info_t *, frdest_t *)); extern size_t mbufchainlen __P((mb_t *)); # ifdef __sgi # include diff --git a/sys/contrib/ipfilter/netinet/ip_frag.c b/sys/contrib/ipfilter/netinet/ip_frag.c index 556478d..b0e63a9 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.c +++ b/sys/contrib/ipfilter/netinet/ip_frag.c @@ -1,15 +1,8 @@ /* - * Copyright (C) 1993-2000 by Darren Reed. + * Copyright (C) 1993-2001 by Darren Reed. * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. + * See the IPFILTER.LICENCE file for details on licencing. */ -#if !defined(lint) -static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.7 2000/11/27 10:26:56 darrenr Exp $"; -#endif - #if defined(KERNEL) && !defined(_KERNEL) # define _KERNEL #endif @@ -81,7 +74,7 @@ static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.7 2000/11/27 10:26:56 d # ifndef IPFILTER_LKM # include # include -# endif +# endif extern struct callout_handle ipfr_slowtimer_ch; # endif #endif @@ -89,6 +82,15 @@ extern struct callout_handle ipfr_slowtimer_ch; # include extern struct callout ipfr_slowtimer_ch; #endif +#if defined(__OpenBSD__) +# include +extern struct timeout ipfr_slowtimer_ch; +#endif + +#if !defined(lint) +static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.14 2001/07/15 22:06:15 darrenr Exp $"; +#endif static ipfr_t *ipfr_heads[IPFT_SIZE]; @@ -141,12 +143,15 @@ fr_info_t *fin; u_int pass; ipfr_t *table[]; { - ipfr_t **fp, *fra, frag; - u_int idx; + ipfr_t **fp, *fra, frag; + u_int idx, off; if (ipfr_inuse >= IPFT_SIZE) return NULL; + if (!(fin->fin_fl & FI_FRAG)) + return NULL; + frag.ipfr_p = ip->ip_p; idx = ip->ip_p; frag.ipfr_id = ip->ip_id; @@ -160,6 +165,10 @@ ipfr_t *table[]; idx *= 127; idx %= IPFT_SIZE; + frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; + frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; + frag.ipfr_auth = fin->fin_fi.fi_auth; + /* * first, make sure it isn't already there... */ @@ -200,7 +209,10 @@ ipfr_t *table[]; /* * Compute the offset of the expected start of the next packet. */ - fra->ipfr_off = (ip->ip_off & IP_OFFMASK) + (fin->fin_dlen >> 3); + off = ip->ip_off & IP_OFFMASK; + if (!off) + fra->ipfr_seen0 = 1; + fra->ipfr_off = off + (fin->fin_dlen >> 3); ATOMIC_INCL(ipfr_stats.ifs_new); ATOMIC_INC32(ipfr_inuse); return fra; @@ -219,7 +231,12 @@ u_int pass; WRITE_ENTER(&ipf_frag); ipf = ipfr_new(ip, fin, pass, ipfr_heads); RWLOCK_EXIT(&ipf_frag); - return ipf ? 0 : -1; + if (ipf == NULL) { + ATOMIC_INCL(frstats[fin->fin_out].fr_bnfr); + return -1; + } + ATOMIC_INCL(frstats[fin->fin_out].fr_nfr); + return 0; } @@ -230,9 +247,16 @@ u_int pass; nat_t *nat; { ipfr_t *ipf; + int off; if ((ip->ip_v != 4) || (fr_frag_lock)) return -1; + + off = fin->fin_off; + off <<= 3; + if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0)) + return NULL; + WRITE_ENTER(&ipf_natfrag); ipf = ipfr_new(ip, fin, pass, ipfr_nattab); if (ipf != NULL) { @@ -254,8 +278,8 @@ fr_info_t *fin; ipfr_t *table[]; { ipfr_t *f, frag; - u_int idx; - + u_int idx; + /* * For fragments, we record protocol, packet id, TOS and both IP#'s * (these should all be the same for all fragments of a packet). @@ -275,6 +299,10 @@ ipfr_t *table[]; idx *= 127; idx %= IPFT_SIZE; + frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; + frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; + frag.ipfr_auth = fin->fin_fi.fi_auth; + /* * check the table, careful to only compare the right amount of data */ @@ -283,6 +311,20 @@ ipfr_t *table[]; IPFR_CMPSZ)) { u_short atoff, off; + off = fin->fin_off; + + /* + * XXX - We really need to be guarding against the + * retransmission of (src,dst,id,offset-range) here + * because a fragmented packet is never resent with + * the same IP ID#. + */ + if (f->ipfr_seen0) { + if (!off || (fin->fin_fl & FI_SHORT)) + continue; + } else if (!off) + f->ipfr_seen0 = 1; + if (f != table[idx]) { /* * move fragment info. to the top of the list @@ -295,7 +337,6 @@ ipfr_t *table[]; f->ipfr_prev = NULL; table[idx] = f; } - off = ip->ip_off & IP_OFFMASK; atoff = off + (fin->fin_dlen >> 3); /* * If we've follwed the fragments, and this is the @@ -321,11 +362,18 @@ nat_t *ipfr_nat_knownfrag(ip, fin) ip_t *ip; fr_info_t *fin; { - nat_t *nat; - ipfr_t *ipf; + ipfr_t *ipf; + nat_t *nat; + int off; - if ((ip->ip_v != 4) || (fr_frag_lock)) + if ((fin->fin_v != 4) || (fr_frag_lock)) + return NULL; + + off = fin->fin_off; + off <<= 3; + if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0)) return NULL; + READ_ENTER(&ipf_natfrag); ipf = ipfr_lookup(ip, fin, ipfr_nattab); if (ipf != NULL) { @@ -351,15 +399,24 @@ frentry_t *ipfr_knownfrag(ip, fin) ip_t *ip; fr_info_t *fin; { - frentry_t *fr = NULL; - ipfr_t *fra; + frentry_t *fr; + ipfr_t *fra; + int off; - if ((ip->ip_v != 4) || (fr_frag_lock)) + if ((fin->fin_v != 4) || (fr_frag_lock)) + return NULL; + + off = fin->fin_off; + off <<= 3; + if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0)) return NULL; + READ_ENTER(&ipf_frag); fra = ipfr_lookup(ip, fin, ipfr_heads); if (fra != NULL) fr = fra->ipfr_rule; + else + fr = NULL; RWLOCK_EXIT(&ipf_frag); return fr; } @@ -544,7 +601,11 @@ int ipfr_slowtimer() # if (__FreeBSD_version >= 300000) ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); # else +# if defined(__OpenBSD_) + timeout_add(&ipfr_slowtimer_ch, hz/2, ipfr_slowtimer, NULL); +# else timeout(ipfr_slowtimer, NULL, hz/2); +# endif # endif # if (BSD < 199306) && !defined(__sgi) return 0; diff --git a/sys/contrib/ipfilter/netinet/ip_frag.h b/sys/contrib/ipfilter/netinet/ip_frag.h index 362bcdd..446510f 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.h +++ b/sys/contrib/ipfilter/netinet/ip_frag.h @@ -1,12 +1,10 @@ /* - * Copyright (C) 1993-2000 by Darren Reed. + * Copyright (C) 1993-2001 by Darren Reed. * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. + * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_frag.h 1.5 3/24/96 - * $Id: ip_frag.h,v 2.4.2.2 2000/11/10 13:10:54 darrenr Exp $ + * $Id: ip_frag.h,v 2.4.2.5 2001/06/26 10:43:13 darrenr Exp $ */ #ifndef __IP_FRAG_H__ @@ -20,11 +18,15 @@ typedef struct ipfr { struct in_addr ipfr_src; struct in_addr ipfr_dst; void *ipfr_ifp; + u_32_t ipfr_optmsk; + u_short ipfr_secmsk; + u_short ipfr_auth; u_short ipfr_id; u_char ipfr_p; u_char ipfr_tos; u_short ipfr_off; - u_short ipfr_ttl; + u_char ipfr_ttl; + u_char ipfr_seen0; frentry_t *ipfr_rule; } ipfr_t; @@ -40,7 +42,8 @@ typedef struct ipfrstat { struct ipfr **ifs_nattab; } ipfrstat_t; -#define IPFR_CMPSZ (4 + 4 + 2 + 1 + 1) +#define IPFR_CMPSZ (offsetof(ipfr_t, ipfr_off) - \ + offsetof(ipfr_t, ipfr_src)) extern int fr_ipfrttl; extern int fr_frag_lock; diff --git a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c index ddca889..830a4f6 100644 --- a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c @@ -2,7 +2,7 @@ * Simple FTP transparent proxy for in-kernel use. For use with the NAT * code. * - * $Id: ip_ftp_pxy.c,v 2.7.2.20 2000/12/02 00:15:06 darrenr Exp $ + * $Id: ip_ftp_pxy.c,v 2.7.2.26 2001/07/15 13:50:54 darrenr Exp $ */ #if SOLARIS && defined(_KERNEL) extern kmutex_t ipf_rw; @@ -22,6 +22,22 @@ extern kmutex_t ipf_rw; #define IPF_MAX227LEN 51 #define IPF_FTPBUFSZ 96 /* This *MUST* be >= 53! */ +#define FTPXY_GO 0 +#define FTPXY_INIT 1 +#define FTPXY_USER_1 2 +#define FTPXY_USOK_1 3 +#define FTPXY_PASS_1 4 +#define FTPXY_PAOK_1 5 +#define FTPXY_AUTH_1 6 +#define FTPXY_AUOK_1 7 +#define FTPXY_ADAT_1 8 +#define FTPXY_ADOK_1 9 +#define FTPXY_ACCT_1 10 +#define FTPXY_ACOK_1 11 +#define FTPXY_USER_2 12 +#define FTPXY_USOK_2 13 +#define FTPXY_PASS_2 14 +#define FTPXY_PAOK_2 15 int ippr_ftp_client __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); int ippr_ftp_complete __P((char *, size_t)); @@ -75,6 +91,7 @@ nat_t *nat; f = &ftp->ftp_side[1]; f->ftps_rptr = f->ftps_buf; f->ftps_wptr = f->ftps_buf; + ftp->ftp_passok = FTPXY_INIT; return 0; } @@ -215,7 +232,7 @@ int dlen; sum2 -= sum1; sum2 = (sum2 & 0xffff) + (sum2 >> 16); - fix_outcksum(&ip->ip_sum, sum2); + fix_outcksum(fin, &ip->ip_sum, sum2); #endif ip->ip_len += inc; } @@ -255,6 +272,7 @@ int dlen; fi.fin_dlen = sizeof(*tcp2); fi.fin_dp = (char *)tcp2; fi.fin_fr = &natfr; + fi.fin_out = 1; swip = ip->ip_src; fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; ip->ip_src = nat->nat_inip; @@ -297,11 +315,36 @@ int dlen; } cmd[i] = '\0'; - if ((ftp->ftp_passok == 0) && !strncmp(cmd, "USER ", 5)) - ftp->ftp_passok = 1; - else if ((ftp->ftp_passok == 2) && !strncmp(cmd, "PASS ", 5)) - ftp->ftp_passok = 3; - else if ((ftp->ftp_passok == 4) && !ippr_ftp_pasvonly && + ftp->ftp_incok = 0; + if (!strncmp(cmd, "USER ", 5) || !strncmp(cmd, "XAUT ", 5)) { + if (ftp->ftp_passok == FTPXY_ADOK_1 || + ftp->ftp_passok == FTPXY_AUOK_1) { + ftp->ftp_passok = FTPXY_USER_2; + ftp->ftp_incok = 1; + } else { + ftp->ftp_passok = FTPXY_USER_1; + ftp->ftp_incok = 1; + } + } else if (!strncmp(cmd, "AUTH ", 5)) { + ftp->ftp_passok = FTPXY_AUTH_1; + ftp->ftp_incok = 1; + } else if (!strncmp(cmd, "PASS ", 5)) { + if (ftp->ftp_passok == FTPXY_USOK_1) { + ftp->ftp_passok = FTPXY_PASS_1; + ftp->ftp_incok = 1; + } else if (ftp->ftp_passok == FTPXY_USOK_2) { + ftp->ftp_passok = FTPXY_PASS_2; + ftp->ftp_incok = 1; + } + } else if ((ftp->ftp_passok == FTPXY_AUOK_1) && + !strncmp(cmd, "ADAT ", 5)) { + ftp->ftp_passok = FTPXY_ADAT_1; + ftp->ftp_incok = 1; + } else if ((ftp->ftp_passok == FTPXY_PAOK_2) && + !strncmp(cmd, "ACCT ", 5)) { + ftp->ftp_passok = FTPXY_ACCT_1; + ftp->ftp_incok = 1; + } else if ((ftp->ftp_passok == FTPXY_GO) && !ippr_ftp_pasvonly && !strncmp(cmd, "PORT ", 5)) { inc = ippr_ftp_port(fin, ip, nat, f, dlen); } else if (ippr_ftp_insecure && !ippr_ftp_pasvonly && @@ -332,12 +375,13 @@ int dlen; int inc; char *s; +#define PASV_REPLEN 24 /* * Check for PASV reply message. */ if (dlen < IPF_MIN227LEN) return 0; - else if (strncmp(f->ftps_rptr, "227 Entering Passive Mode", 25)) + else if (strncmp(f->ftps_rptr, "227 Entering Passive Mod", PASV_REPLEN)) return 0; tcp = (tcphdr_t *)fin->fin_dp; @@ -345,7 +389,7 @@ int dlen; /* * Skip the PORT command + space */ - s = f->ftps_rptr + 25; + s = f->ftps_rptr + PASV_REPLEN; while (*s && !isdigit(*s)) s++; /* @@ -373,6 +417,8 @@ int dlen; if (*s == ')') s++; + if (*s == '.') + s++; if (*s == '\n') s--; /* @@ -445,7 +491,7 @@ int dlen; sum2 -= sum1; sum2 = (sum2 & 0xffff) + (sum2 >> 16); - fix_outcksum(&ip->ip_sum, sum2); + fix_outcksum(fin, &ip->ip_sum, sum2); #endif /* SOLARIS || defined(__sgi) */ ip->ip_len += inc; } @@ -469,12 +515,13 @@ int dlen; tcp2->th_win = htons(8192); tcp2->th_sport = 0; /* XXX - fake it for nat_new */ tcp2->th_off = 5; - fi.fin_data[1] = a5 << 8 | a6; + fi.fin_data[0] = a5 << 8 | a6; fi.fin_dlen = sizeof(*tcp2); - tcp2->th_dport = htons(fi.fin_data[1]); - fi.fin_data[0] = 0; + tcp2->th_dport = htons(fi.fin_data[0]); + fi.fin_data[1] = 0; fi.fin_dp = (char *)tcp2; fi.fin_fr = &natfr; + fi.fin_out = 1; swip = ip->ip_src; swip2 = ip->ip_dst; fi.fin_fi.fi_daddr = ip->ip_src.s_addr; @@ -511,17 +558,38 @@ int dlen; rptr = f->ftps_rptr; wptr = f->ftps_wptr; - if ((ftp->ftp_passok == 1) && !strncmp(rptr, "331", 3)) - ftp->ftp_passok = 2; - else if ((ftp->ftp_passok == 3) && !strncmp(rptr, "230", 3)) - ftp->ftp_passok = 4; - else if ((ftp->ftp_passok == 3) && !strncmp(rptr, "530", 3)) - ftp->ftp_passok = 0; - else if ((ftp->ftp_passok == 4) && !strncmp(rptr, "227 ", 4)) { - inc = ippr_ftp_pasv(fin, ip, nat, f, dlen); + if (!isdigit(*rptr) || !isdigit(*(rptr + 1)) || !isdigit(*(rptr + 2))) + return inc; + if (ftp->ftp_passok == FTPXY_GO) { + if (!strncmp(rptr, "227 ", 4)) + inc = ippr_ftp_pasv(fin, ip, nat, f, dlen); } else if (ippr_ftp_insecure && !strncmp(rptr, "227 ", 4)) { inc = ippr_ftp_pasv(fin, ip, nat, f, dlen); + } else if (*rptr == '5' || *rptr == '4') + ftp->ftp_passok = FTPXY_INIT; + else if (ftp->ftp_incok) { + if (*rptr == '3') { + if (ftp->ftp_passok == FTPXY_ACCT_1) + ftp->ftp_passok = FTPXY_GO; + else + ftp->ftp_passok++; + } else if (*rptr == '2') { + switch (ftp->ftp_passok) + { + case FTPXY_USER_1 : + case FTPXY_USER_2 : + case FTPXY_PASS_1 : + case FTPXY_PASS_2 : + case FTPXY_ACCT_1 : + ftp->ftp_passok = FTPXY_GO; + break; + default : + ftp->ftp_passok += 3; + break; + } + } } + ftp->ftp_incok = 0; while ((*rptr++ != '\n') && (rptr < wptr)) ; f->ftps_rptr = rptr; diff --git a/sys/contrib/ipfilter/netinet/ip_log.c b/sys/contrib/ipfilter/netinet/ip_log.c index 8adc410..5968f46 100644 --- a/sys/contrib/ipfilter/netinet/ip_log.c +++ b/sys/contrib/ipfilter/netinet/ip_log.c @@ -1,11 +1,9 @@ /* - * Copyright (C) 1997-2000 by Darren Reed. + * Copyright (C) 1997-2001 by Darren Reed. * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. + * See the IPFILTER.LICENCE file for details on licencing. * - * $Id: ip_log.c,v 2.5.2.2 2000/08/13 03:50:41 darrenr Exp $ + * $Id: ip_log.c,v 2.5.2.5 2001/06/26 10:43:14 darrenr Exp $ */ #include #if defined(KERNEL) && !defined(_KERNEL) @@ -21,7 +19,13 @@ # endif # else # ifdef KLD_MODULE -# include +# ifndef __FreeBSD_cc_version +# include +# else +# if __FreeBSD_cc_version < 430000 +# include +# endif +# endif # endif # endif #endif @@ -45,7 +49,7 @@ # include # endif # include -# if defined(_KERNEL) && !defined(linux) +# if defined(_KERNEL) # include # endif # include @@ -55,9 +59,7 @@ # else # include # endif -# ifndef linux -# include -# endif +# include # else # include # include @@ -69,9 +71,7 @@ # include # include # endif -# ifndef linux -# include -# endif +# include # include # include @@ -89,7 +89,7 @@ # include # endif # endif -# if !defined(linux) && !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/ +# if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/ # include # endif # include @@ -97,9 +97,7 @@ # include # include # include -# ifndef linux -# include -# endif +# include # ifndef _KERNEL # include # endif @@ -130,9 +128,6 @@ extern kcondvar_t iplwait; iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1], *ipll[IPL_LOGMAX+1]; size_t iplused[IPL_LOGMAX+1]; static fr_info_t iplcrc[IPL_LOGMAX+1]; -# ifdef linux -static struct wait_queue *iplwait[IPL_LOGMAX+1]; -# endif /* @@ -229,9 +224,7 @@ mb_t *m; (defined(OpenBSD) && (OpenBSD >= 199603)) strncpy(ipfl.fl_ifname, ifp->if_xname, IFNAMSIZ); # else -# ifndef linux ipfl.fl_unit = (u_char)ifp->if_unit; -# endif if ((ipfl.fl_ifname[0] = ifp->if_name[0])) if ((ipfl.fl_ifname[1] = ifp->if_name[1])) if ((ipfl.fl_ifname[2] = ifp->if_name[2])) @@ -337,7 +330,7 @@ int *types, cnt; ipl->ipl_count = 1; ipl->ipl_next = NULL; ipl->ipl_dsize = len; -# if SOLARIS || defined(sun) || defined(linux) +# if SOLARIS || defined(sun) uniqtime((struct timeval *)&ipl->ipl_sec); # else # if BSD >= 199306 || defined(__FreeBSD__) || defined(__sgi) @@ -370,11 +363,7 @@ int *types, cnt; mutex_exit(&ipl_mutex); # else MUTEX_EXIT(&ipl_mutex); -# ifdef linux - wake_up_interruptible(&iplwait[dev]); -# else wakeup(&iplh[dev]); -# endif # endif return 1; } @@ -399,8 +388,7 @@ struct uio *uio; return ENXIO; if (!uio->uio_resid) return 0; - if ((uio->uio_resid < sizeof(iplog_t)) || - (uio->uio_resid > IPLLOGSIZE)) + if (uio->uio_resid < sizeof(iplog_t)) return EINVAL; /* @@ -417,19 +405,13 @@ struct uio *uio; return EINTR; } # else -# ifdef linux - interruptible_sleep_on(&iplwait[unit]); - if (current->signal & ~current->blocked) - return -EINTR; -# else MUTEX_EXIT(&ipl_mutex); - SPL_X(s); error = SLEEP(&iplh[unit], "ipl sleep"); - if (error) + if (error) { + SPL_X(s); return error; - SPL_NET(s); + } MUTEX_ENTER(&ipl_mutex); -# endif /* linux */ # endif /* SOLARIS */ } @@ -447,10 +429,8 @@ struct uio *uio; iplt[unit] = ipl->ipl_next; iplused[unit] -= dlen; MUTEX_EXIT(&ipl_mutex); - SPL_X(s); 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; @@ -458,7 +438,6 @@ struct uio *uio; break; } KFREES((caddr_t)ipl, dlen); - SPL_NET(s); MUTEX_ENTER(&ipl_mutex); } if (!iplt[unit]) { @@ -469,13 +448,7 @@ struct uio *uio; MUTEX_EXIT(&ipl_mutex); SPL_X(s); -# ifdef linux - if (!error) - return (int)copied; - return -error; -# else return error; -# endif } diff --git a/sys/contrib/ipfilter/netinet/ip_nat.c b/sys/contrib/ipfilter/netinet/ip_nat.c index e7e121a..eb6e133 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.c +++ b/sys/contrib/ipfilter/netinet/ip_nat.c @@ -1,17 +1,10 @@ /* - * Copyright (C) 1995-2000 by Darren Reed. + * Copyright (C) 1995-2001 by Darren Reed. * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. + * See the IPFILTER.LICENCE file for details on licencing. * * Added redirect stuff and a LOT of bug fixes. (mcn@EnGarde.com) */ -#if !defined(lint) -static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.32 2001/01/10 06:19:11 darrenr Exp $"; -#endif - #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) #define _KERNEL #endif @@ -91,6 +84,7 @@ extern struct ifnet vpnif; #ifndef linux # include +# include #endif #include #include @@ -111,6 +105,11 @@ extern struct ifnet vpnif; #undef SOCKADDR_IN #define SOCKADDR_IN struct sockaddr_in +#if !defined(lint) +static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; +static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.44 2001/07/21 07:17:22 darrenr Exp $"; +#endif + nat_t **nat_table[2] = { NULL, NULL }, *nat_instances = NULL; ipnat_t *nat_list = NULL; @@ -301,7 +300,8 @@ struct hostmap *hm; } -void fix_outcksum(sp, n) +void fix_outcksum(fin, sp, n) +fr_info_t *fin; u_short *sp; u_32_t n; { @@ -310,12 +310,13 @@ u_32_t n; if (!n) return; -#if SOLARIS2 >= 6 else if (n & NAT_HW_CKSUM) { + n &= 0xffff; + n += fin->fin_dlen; + n = (n & 0xffff) + (n >> 16); *sp = n & 0xffff; return; } -#endif sum1 = (~ntohs(*sp)) & 0xffff; sum1 += (n); sum1 = (sum1 >> 16) + (sum1 & 0xffff); @@ -326,7 +327,8 @@ u_32_t n; } -void fix_incksum(sp, n) +void fix_incksum(fin, sp, n) +fr_info_t *fin; u_short *sp; u_32_t n; { @@ -335,12 +337,13 @@ u_32_t n; if (!n) return; -#if SOLARIS2 >= 6 else if (n & NAT_HW_CKSUM) { + n &= 0xffff; + n += fin->fin_dlen; + n = (n & 0xffff) + (n >> 16); *sp = n & 0xffff; return; } -#endif #ifdef sparc sum1 = (~(*sp)) & 0xffff; #else @@ -625,9 +628,11 @@ 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_maptable = maptable; 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_hostmap_sz = ipf_hostmap_sz; nat_stats.ns_instances = nat_instances; nat_stats.ns_apslist = ap_sess_list; error = IWCOPYPTR((char *)&nat_stats, (char *)data, @@ -1395,14 +1400,14 @@ int direction; CALC_SUMD(sum1, sum2, sumd); nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) - if ((flags == IPN_TCP) && dohwcksum && + if ((flags & IPN_TCPUDP) && 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 += IPPROTO_TCP; sum1 = (sum1 & 0xffff) + (sum1 >> 16); nat->nat_sumd[1] = NAT_HW_CKSUM|(sum1 & 0xffff); } else @@ -1463,8 +1468,8 @@ badnat: void nat_insert(nat) nat_t *nat; { + u_int hv1, hv2; nat_t **natp; - u_int hv; MUTEX_INIT(&nat->nat_lock, "nat entry lock", NULL); @@ -1477,18 +1482,30 @@ nat_t *nat; nat->nat_next = nat_instances; nat_instances = nat; - hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, - ipf_nattable_sz); - natp = &nat_table[0][hv]; + if (!(nat->nat_flags & (FI_W_SPORT|FI_W_DPORT))) { + hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, + 0xffffffff); + hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1 + nat->nat_oport, + ipf_nattable_sz); + hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, + 0xffffffff); + hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2 + nat->nat_oport, + ipf_nattable_sz); + } else { + hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, 0, 0xffffffff); + hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1, ipf_nattable_sz); + hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, 0, 0xffffffff); + hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2, ipf_nattable_sz); + } + + natp = &nat_table[0][hv1]; if (*natp) (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; nat->nat_phnext[0] = natp; nat->nat_hnext[0] = *natp; *natp = nat; - hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, - ipf_nattable_sz); - natp = &nat_table[1][hv]; + natp = &nat_table[1][hv2]; if (*natp) (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; nat->nat_phnext[1] = natp; @@ -1604,7 +1621,7 @@ int dir; ip_t *oip; int flags = 0; - if ((fin->fin_fi.fi_fl & FI_SHORT) || (ip->ip_off & IP_OFFMASK)) + if ((fin->fin_fl & FI_SHORT) || (fin->fin_off != 0)) return NULL; /* * nat_icmplookup() will return NULL for `defective' packets. @@ -1878,13 +1895,14 @@ int dir; sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); if (nat->nat_dir == NAT_OUTBOUND) { - fix_outcksum(&icmp->icmp_cksum, sumd2); + fix_outcksum(fin, &icmp->icmp_cksum, sumd2); } else { - fix_incksum(&icmp->icmp_cksum, sumd2); + fix_incksum(fin, &icmp->icmp_cksum, sumd2); } } } - nat->nat_age = fr_defnaticmpage; + if (oip->ip_p == IPPROTO_ICMP) + nat->nat_age = fr_defnaticmpage; return nat; } @@ -1917,7 +1935,8 @@ int rw; sport = ports & 0xffff; flags &= IPN_TCPUDP; - hv = NAT_HASH_FN(dst, dport, ipf_nattable_sz); + hv = NAT_HASH_FN(dst, dport, 0xffffffff); + hv = NAT_HASH_FN(src.s_addr, hv + sport, ipf_nattable_sz); nat = nat_table[1][hv]; for (; nat; nat = nat->nat_hnext[1]) { nflags = nat->nat_flags; @@ -1935,7 +1954,8 @@ int rw; if (!rw) { RWLOCK_EXIT(&ipf_nat); } - hv = NAT_HASH_FN(dst, 0, ipf_nattable_sz); + hv = NAT_HASH_FN(dst, 0, 0xffffffff); + hv = NAT_HASH_FN(src.s_addr, hv, ipf_nattable_sz); if (!rw) { WRITE_ENTER(&ipf_nat); } @@ -1999,7 +2019,8 @@ u_32_t ports; /* * Add into the NAT table in the new position */ - hv = NAT_HASH_FN(nat->nat_inip.s_addr, sport, ipf_nattable_sz); + hv = NAT_HASH_FN(nat->nat_inip.s_addr, sport, 0xffffffff); + hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + dport, ipf_nattable_sz); natp = &nat_table[0][hv]; if (*natp) (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; @@ -2007,7 +2028,8 @@ u_32_t ports; nat->nat_hnext[0] = *natp; *natp = nat; - hv = NAT_HASH_FN(nat->nat_outip.s_addr, sport, ipf_nattable_sz); + hv = NAT_HASH_FN(nat->nat_outip.s_addr, sport, 0xffffffff); + hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + dport, ipf_nattable_sz); natp = &nat_table[1][hv]; if (*natp) (*natp)->nat_phnext[1] = &nat->nat_hnext[1]; @@ -2041,7 +2063,8 @@ int rw; flags &= IPN_TCPUDP; srcip = src.s_addr; - hv = NAT_HASH_FN(srcip, sport, ipf_nattable_sz); + hv = NAT_HASH_FN(srcip, sport, 0xffffffff); + hv = NAT_HASH_FN(dst.s_addr, hv + dport, ipf_nattable_sz); nat = nat_table[0][hv]; for (; nat; nat = nat->nat_hnext[0]) { nflags = nat->nat_flags; @@ -2061,6 +2084,7 @@ int rw; RWLOCK_EXIT(&ipf_nat); } hv = NAT_HASH_FN(srcip, 0, ipf_nattable_sz); + hv = NAT_HASH_FN(dst.s_addr, hv, ipf_nattable_sz); if (!rw) { WRITE_ENTER(&ipf_nat); } @@ -2145,8 +2169,8 @@ ip_t *ip; } ft = &np->in_tuc; - if (!(fin->fin_fi.fi_fl & FI_TCPUDP) || - (fin->fin_fi.fi_fl & FI_SHORT) || (ip->ip_off & IP_OFFMASK)) { + if (!(fin->fin_fl & FI_TCPUDP) || + (fin->fin_fl & FI_SHORT) || (fin->fin_off != 0)) { if (ft->ftu_scmp || ft->ftu_dcmp) return 0; return 1; @@ -2168,13 +2192,12 @@ fr_info_t *fin; register u_32_t ipa; tcphdr_t *tcp = NULL; u_short sport = 0, dport = 0, *csump = NULL; + int natadd = 1, i, icmpset = 1; + u_int nflags = 0, hv, msk; struct ifnet *ifp; - int natadd = 1; frentry_t *fr; - u_int nflags = 0, hv, msk; u_32_t iph; nat_t *nat; - int i; if (nat_list == NULL || (fr_nat_lock)) return 0; @@ -2185,7 +2208,7 @@ fr_info_t *fin; else ifp = fin->fin_ifp; - if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) { + if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) { if (ip->ip_p == IPPROTO_TCP) nflags = IPN_TCP; else if (ip->ip_p == IPPROTO_UDP) @@ -2203,8 +2226,8 @@ fr_info_t *fin; if ((ip->ip_p == IPPROTO_ICMP) && (nat = nat_icmp(ip, fin, &nflags, NAT_OUTBOUND))) - ; - else if ((ip->ip_off & (IP_OFFMASK|IP_MF)) && + icmpset = 1; + else if ((fin->fin_fl & FI_FRAG) && (nat = ipfr_nat_knownfrag(ip, fin))) natadd = 0; else if ((nat = nat_outlookup(ifp, nflags, (u_int)ip->ip_p, @@ -2238,8 +2261,7 @@ maskloop: hv = NAT_HASH_FN(iph, 0, ipf_natrules_sz); for (np = nat_rules[hv]; np; np = np->in_mnext) { - if ((np->in_ifp && (np->in_ifp != ifp)) || - !np->in_space) + if (np->in_ifp && (np->in_ifp != ifp)) continue; if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags)) @@ -2283,7 +2305,7 @@ maskloop: */ if (nat) { np = nat->nat_ptr; - if (natadd && fin->fin_fi.fi_fl & FI_FRAG) + if (natadd && (fin->fin_fl & FI_FRAG) && np) ipfr_nat_newfrag(ip, fin, 0, nat); MUTEX_ENTER(&nat->nat_lock); nat->nat_age = fr_defnatage; @@ -2303,22 +2325,21 @@ maskloop: CALC_SUMD(s1, s2, sumd); if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(&ip->ip_sum, sumd); + fix_incksum(fin, &ip->ip_sum, sumd); else - fix_outcksum(&ip->ip_sum, sumd); + fix_outcksum(fin, &ip->ip_sum, sumd); } #if SOLARIS || defined(__sgi) else { if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(&ip->ip_sum, nat->nat_ipsumd); + fix_outcksum(fin, &ip->ip_sum, nat->nat_ipsumd); else - fix_incksum(&ip->ip_sum, nat->nat_ipsumd); + fix_incksum(fin, &ip->ip_sum, nat->nat_ipsumd); } #endif ip->ip_src = nat->nat_outip; - if (!(ip->ip_off & IP_OFFMASK) && - !(fin->fin_fi.fi_fl & FI_SHORT)) { + if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) { if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) { tcp->th_sport = nat->nat_outport; @@ -2351,14 +2372,15 @@ maskloop: if (udp->uh_sum) csump = &udp->uh_sum; } else if (ip->ip_p == IPPROTO_ICMP) { - nat->nat_age = fr_defnaticmpage; + if (!icmpset) + nat->nat_age = fr_defnaticmpage; } if (csump) { if (nat->nat_dir == NAT_OUTBOUND) - fix_outcksum(csump, nat->nat_sumd[1]); + fix_outcksum(fin, csump, nat->nat_sumd[1]); else - fix_incksum(csump, nat->nat_sumd[1]); + fix_incksum(fin, csump, nat->nat_sumd[1]); } } @@ -2389,18 +2411,18 @@ fr_info_t *fin; register struct in_addr src; register struct in_addr in; register ipnat_t *np; + u_short sport = 0, dport = 0, *csump = NULL; 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; + int i, icmpset = 0; nat_t *nat; u_32_t iph; - int i; if ((nat_list == NULL) || (ip->ip_v != 4) || (fr_nat_lock)) return 0; - if (!(ip->ip_off & IP_OFFMASK) && !(fin->fin_fi.fi_fl & FI_SHORT)) { + if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) { if (ip->ip_p == IPPROTO_TCP) nflags = IPN_TCP; else if (ip->ip_p == IPPROTO_UDP) @@ -2420,8 +2442,8 @@ fr_info_t *fin; if ((ip->ip_p == IPPROTO_ICMP) && (nat = nat_icmp(ip, fin, &nflags, NAT_INBOUND))) - ; - else if ((ip->ip_off & (IP_OFFMASK|IP_MF)) && + icmpset = 1; + else if ((fin->fin_fl & FI_FRAG) && (nat = ipfr_nat_knownfrag(ip, fin))) natadd = 0; else if ((nat = nat_inlookup(fin->fin_ifp, nflags, (u_int)ip->ip_p, @@ -2488,7 +2510,7 @@ maskloop: if (nat) { np = nat->nat_ptr; fin->fin_fr = nat->nat_fr; - if (natadd && fin->fin_fi.fi_fl & FI_FRAG) + if (natadd && (fin->fin_fl & FI_FRAG) && np) ipfr_nat_newfrag(ip, fin, 0, nat); if ((np->in_apr != NULL) && (np->in_dport == 0 || (tcp != NULL && sport == np->in_dport))) { @@ -2515,12 +2537,11 @@ maskloop: */ #if SOLARIS || defined(__sgi) if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(&ip->ip_sum, nat->nat_ipsumd); + fix_incksum(fin, &ip->ip_sum, nat->nat_ipsumd); else - fix_outcksum(&ip->ip_sum, nat->nat_ipsumd); + fix_outcksum(fin, &ip->ip_sum, nat->nat_ipsumd); #endif - if (!(ip->ip_off & IP_OFFMASK) && - !(fin->fin_fi.fi_fl & FI_SHORT)) { + if ((fin->fin_off == 0) && !(fin->fin_fl & FI_SHORT)) { if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) { tcp->th_dport = nat->nat_inport; @@ -2553,14 +2574,15 @@ maskloop: if (udp->uh_sum) csump = &udp->uh_sum; } else if (ip->ip_p == IPPROTO_ICMP) { - nat->nat_age = fr_defnaticmpage; + if (!icmpset) + nat->nat_age = fr_defnaticmpage; } if (csump) { if (nat->nat_dir == NAT_OUTBOUND) - fix_incksum(csump, nat->nat_sumd[0]); + fix_incksum(fin, csump, nat->nat_sumd[0]); else - fix_outcksum(csump, nat->nat_sumd[0]); + fix_outcksum(fin, csump, nat->nat_sumd[0]); } } ATOMIC_INCL(nat_stats.ns_mapped[0]); diff --git a/sys/contrib/ipfilter/netinet/ip_nat.h b/sys/contrib/ipfilter/netinet/ip_nat.h index 22f8503..f712dfc 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.h +++ b/sys/contrib/ipfilter/netinet/ip_nat.h @@ -1,12 +1,10 @@ /* - * Copyright (C) 1995-2000 by Darren Reed. + * Copyright (C) 1995-2001 by Darren Reed. * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. + * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_nat.h 1.5 2/4/96 - * $Id: ip_nat.h,v 2.17.2.14 2000/11/18 03:58:04 darrenr Exp $ + * $Id: ip_nat.h,v 2.17.2.20 2001/06/26 10:43:15 darrenr Exp $ */ #ifndef __IP_NAT_H__ @@ -35,10 +33,18 @@ * 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 HOSTMAP_SIZE 127 -#define NAT_TABLE_SZ 127 +#ifndef NAT_SIZE +# define NAT_SIZE 127 +#endif +#ifndef RDR_SIZE +# define RDR_SIZE 127 +#endif +#ifndef HOSTMAP_SIZE +# define HOSTMAP_SIZE 127 +#endif +#ifndef NAT_TABLE_SZ +# define NAT_TABLE_SZ 127 +#endif #ifdef LARGE_NAT #undef NAT_SIZE #undef RDR_SIZE @@ -201,11 +207,13 @@ typedef struct natstat { u_long ns_memfail; u_long ns_badnat; nat_t **ns_table[2]; + hostmap_t **ns_maptable; ipnat_t *ns_list; void *ns_apslist; u_int ns_nattab_sz; u_int ns_rultab_sz; u_int ns_rdrtab_sz; + u_int ns_hostmap_sz; nat_t *ns_instances; u_int ns_wilds; } natstat_t; @@ -220,12 +228,13 @@ typedef struct natstat { #define IPN_AUTOPORTMAP 0x010 #define IPN_IPRANGE 0x020 #define IPN_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_IPRANGE|IPN_SPLIT|\ - IPN_ROUNDR|IPN_FILTER|IPN_NOTSRC|IPN_NOTDST) + IPN_ROUNDR|IPN_FILTER|IPN_NOTSRC|IPN_NOTDST|IPN_FRAG) #define IPN_FILTER 0x040 #define IPN_SPLIT 0x080 #define IPN_ROUNDR 0x100 #define IPN_NOTSRC 0x080000 #define IPN_NOTDST 0x100000 +#define IPN_FRAG 0x200000 typedef struct natlog { @@ -300,8 +309,8 @@ 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_int)); -extern void fix_incksum __P((u_short *, u_32_t)); -extern void fix_outcksum __P((u_short *, u_32_t)); +extern void fix_incksum __P((fr_info_t *, u_short *, u_32_t)); +extern void fix_outcksum __P((fr_info_t *, u_short *, u_32_t)); extern void fix_datacksum __P((u_short *, u_32_t)); #endif /* __IP_NAT_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_proxy.c b/sys/contrib/ipfilter/netinet/ip_proxy.c index e1e55f1..325f362 100644 --- a/sys/contrib/ipfilter/netinet/ip_proxy.c +++ b/sys/contrib/ipfilter/netinet/ip_proxy.c @@ -1,14 +1,8 @@ /* - * Copyright (C) 1997-2000 by Darren Reed. + * Copyright (C) 1997-2001 by Darren Reed. * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. + * See the IPFILTER.LICENCE file for details on licencing. */ -#if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.9.2.1 2000/05/06 12:30:50 darrenr Exp $"; -#endif - #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL) # define _KERNEL #endif @@ -78,6 +72,10 @@ static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.9.2.1 2000/05/06 12:30:50 d # include #endif +#if !defined(lint) +static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.9.2.6 2001/07/15 22:06:15 darrenr Exp $"; +#endif + #ifndef MIN #define MIN(a,b) (((a)<(b))?(a):(b)) @@ -216,9 +214,13 @@ ip_t *ip; fr_info_t *fin; nat_t *nat; { +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) + mb_t *m = fin->fin_qfm; + int dosum = 1; +#endif + tcphdr_t *tcp = NULL; ap_session_t *aps; aproxy_t *apr; - tcphdr_t *tcp = NULL; u_32_t sum; short rv; int err; @@ -234,8 +236,13 @@ nat_t *nat; * verify that the checksum is correct. If not, then * don't do anything with this packet. */ -#if SOLARIS && defined(_KERNEL) - sum = fr_tcpsum(fin->fin_qfm, ip, tcp); +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) + if (dohwcksum && (m->b_ick_flag == ICK_VALID)) { + sum = tcp->th_sum; + dosum = 0; + } + if (dosum) + sum = fr_tcpsum(fin->fin_qfm, ip, tcp); #else sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp); #endif @@ -261,8 +268,9 @@ nat_t *nat; if (tcp != NULL) { err = appr_fixseqack(fin, ip, aps, APR_INC(err)); -#if SOLARIS && defined(_KERNEL) - tcp->th_sum = fr_tcpsum(fin->fin_qfm, ip, tcp); +#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) + if (dosum) + tcp->th_sum = fr_tcpsum(fin->fin_qfm, ip, tcp); #else tcp->th_sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp); #endif diff --git a/sys/contrib/ipfilter/netinet/ip_proxy.h b/sys/contrib/ipfilter/netinet/ip_proxy.h index 212900f..b8c8eb0 100644 --- a/sys/contrib/ipfilter/netinet/ip_proxy.h +++ b/sys/contrib/ipfilter/netinet/ip_proxy.h @@ -1,11 +1,9 @@ /* - * Copyright (C) 1997-2000 by Darren Reed. + * Copyright (C) 1997-2001 by Darren Reed. * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. + * See the IPFILTER.LICENCE file for details on licencing. * - * $Id: ip_proxy.h,v 2.8.2.4 2000/12/02 00:15:03 darrenr Exp $ + * $Id: ip_proxy.h,v 2.8.2.7 2001/06/26 10:43:16 darrenr Exp $ */ #ifndef __IP_PROXY_H__ @@ -102,7 +100,8 @@ typedef struct ftpside { } ftpside_t; typedef struct ftpinfo { - u_int ftp_passok; + int ftp_passok; + int ftp_incok; ftpside_t ftp_side[2]; } ftpinfo_t; diff --git a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c index 9ea437c..476e159 100644 --- a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c @@ -1,5 +1,5 @@ /* - * $Id: ip_raudio_pxy.c,v 1.7.2.3 2000/10/27 22:54:04 darrenr Exp $ + * $Id: ip_raudio_pxy.c,v 1.7.2.6 2001/07/23 04:17:56 darrenr Exp $ */ #if SOLARIS && defined(_KERNEL) extern kmutex_t ipf_rw; @@ -62,8 +62,8 @@ nat_t *nat; raudio_t *rap = aps->aps_data; unsigned char membuf[512 + 1], *s; u_short id = 0; - tcphdr_t *tcp; int off, dlen; + tcphdr_t *tcp; int len = 0; mb_t *m; #if SOLARIS @@ -86,14 +86,16 @@ nat_t *nat; dlen = msgdsize(m) - off; if (dlen <= 0) return 0; - copyout_mblk(m, off, MIN(sizeof(membuf), dlen), (char *)membuf); + dlen = MIN(sizeof(membuf), dlen); + copyout_mblk(m, off, dlen, (char *)membuf); #else m = *(mb_t **)fin->fin_mp; dlen = mbufchainlen(m) - off; if (dlen <= 0) return 0; - m_copydata(m, off, MIN(sizeof(membuf), dlen), (char *)membuf); + dlen = MIN(sizeof(membuf), dlen); + m_copydata(m, off, dlen, (char *)membuf); #endif /* * In all the startup parsing, ensure that we don't go outside @@ -170,8 +172,8 @@ nat_t *nat; unsigned char membuf[IPF_MAXPORTLEN + 1], *s; tcphdr_t *tcp, tcph, *tcp2 = &tcph; raudio_t *rap = aps->aps_data; + int off, dlen, slen, clen; struct in_addr swa, swb; - int off, dlen, slen; int a1, a2, a3, a4; u_short sp, dp; fr_info_t fi; @@ -202,13 +204,15 @@ nat_t *nat; if (dlen <= 0) return 0; bzero(membuf, sizeof(membuf)); - copyout_mblk(m, off, MIN(sizeof(membuf), dlen), (char *)membuf); + clen = MIN(sizeof(membuf), dlen); + copyout_mblk(m, off, clen, (char *)membuf); #else dlen = mbufchainlen(m) - off; if (dlen <= 0) return 0; bzero(membuf, sizeof(membuf)); - m_copydata(m, off, MIN(sizeof(membuf), dlen), (char *)membuf); + clen = MIN(sizeof(membuf), dlen); + m_copydata(m, off, clen, (char *)membuf); #endif seq = ntohl(tcp->th_seq); @@ -217,7 +221,7 @@ nat_t *nat; * We only care for the first 19 bytes coming back from the server. */ if (rap->rap_sseq == 0) { - s = (u_char *)memstr("PNA", (char *)membuf, 3, dlen); + s = (u_char *)memstr("PNA", (char *)membuf, 3, clen); if (s == NULL) return 0; a1 = s - membuf; @@ -278,6 +282,7 @@ nat_t *nat; tcp2->th_dport = htons(dp); fi.fin_data[0] = dp; fi.fin_data[1] = sp; + fi.fin_out = 0; ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_UDP | (sp ? 0 : FI_W_SPORT), NAT_OUTBOUND); if (ipn != NULL) { @@ -292,6 +297,7 @@ nat_t *nat; tcp2->th_dport = 0; /* XXX - don't specify remote port */ fi.fin_data[0] = sp; fi.fin_data[1] = 0; + fi.fin_out = 1; ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_UDP|FI_W_DPORT, NAT_OUTBOUND); if (ipn != NULL) { diff --git a/sys/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c index 5d63969..649ad93 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.c +++ b/sys/contrib/ipfilter/netinet/ip_state.c @@ -1,15 +1,8 @@ /* - * Copyright (C) 1995-2000 by Darren Reed. + * Copyright (C) 1995-2001 by Darren Reed. * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. + * See the IPFILTER.LICENCE file for details on licencing. */ -#if !defined(lint) -static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.28 2001/01/08 14:04:46 darrenr Exp $"; -#endif - #include #include #include @@ -97,6 +90,11 @@ static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.28 2001/01/08 14:04:46 # endif #endif +#if !defined(lint) +static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.38 2001/07/23 13:49:46 darrenr Exp $"; +#endif + #ifndef MIN # define MIN(a,b) (((a)<(b))?(a):(b)) #endif @@ -140,7 +138,9 @@ u_long fr_tcpidletimeout = FIVE_DAYS, fr_tcpclosed = 120, fr_tcphalfclosed = 2 * 2 * 3600, /* 2 hours */ fr_udptimeout = 240, - fr_icmptimeout = 120; + fr_udpacktimeout = 24, + fr_icmptimeout = 120, + fr_icmpacktimeout = 12; int fr_statemax = IPSTATE_MAX, fr_statesize = IPSTATE_SIZE; int fr_state_doflush = 0, @@ -241,6 +241,7 @@ caddr_t data; if (error) return EFAULT; + WRITE_ENTER(&ipf_state); for (sp = ips_list; sp; sp = sp->is_next) if ((sp->is_p == st.is_p) && (sp->is_v == st.is_v) && !bcmp((char *)&sp->is_src, (char *)&st.is_src, @@ -249,7 +250,6 @@ caddr_t data; sizeof(st.is_dst)) && !bcmp((char *)&sp->is_ps, (char *)&st.is_ps, sizeof(st.is_ps))) { - WRITE_ENTER(&ipf_state); #ifdef IPFILTER_LOG ipstate_log(sp, ISL_REMOVE); #endif @@ -257,6 +257,7 @@ caddr_t data; RWLOCK_EXIT(&ipf_state); return 0; } + RWLOCK_EXIT(&ipf_state); return ESRCH; } @@ -502,8 +503,7 @@ u_int flags; u_int pass; int out; - if (fr_state_lock || (fin->fin_off & IP_OFFMASK) || - (fin->fin_fi.fi_fl & FI_SHORT)) + if (fr_state_lock || (fin->fin_off != 0) || (fin->fin_fl & FI_SHORT)) return NULL; if (ips_num == fr_statemax) { ips_stats.iss_max++; @@ -663,7 +663,7 @@ u_int flags; is->is_secmsk = 0xffff; is->is_auth = fin->fin_fi.fi_auth; is->is_authmsk = 0xffff; - is->is_flags = fin->fin_fi.fi_fl & FI_CMP; + is->is_flags = fin->fin_fl & FI_CMP; is->is_flags |= FI_CMP << 4; is->is_flags |= flags & (FI_WILDP|FI_WILDA); if (flags & (FI_WILDP|FI_WILDA)) @@ -688,7 +688,7 @@ u_int flags; #endif RWLOCK_EXIT(&ipf_state); fin->fin_rev = IP6NEQ(is->is_dst, fin->fin_fi.fi_dst); - if (fin->fin_fi.fi_fl & FI_FRAG) + if ((fin->fin_fl & FI_FRAG) && (pass & FR_KEEPFRAG)) ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE); return is; } @@ -717,6 +717,8 @@ tcphdr_t *tcp; * Find difference between last checked packet and this packet. */ source = IP6EQ(fin->fin_fi.fi_src, is->is_src); + if (source && (ntohs(is->is_sport) != fin->fin_data[0])) + source = 0; fdata = &is->is_tcp.ts_data[!source]; tdata = &is->is_tcp.ts_data[source]; seq = ntohl(tcp->th_seq); @@ -809,7 +811,7 @@ tcphdr_t *tcp; u_short sp, dp; void *ifp; - rev = fin->fin_rev = IP6NEQ(is->is_dst, dst); + rev = IP6NEQ(is->is_dst, dst); ifp = fin->fin_ifp; out = fin->fin_out; @@ -817,6 +819,12 @@ tcphdr_t *tcp; flags = is->is_flags; sp = tcp->th_sport; dp = tcp->th_dport; + if (!rev) { + if (!(flags & FI_W_SPORT) && (sp != is->is_sport)) + rev = 1; + else if (!(flags & FI_W_DPORT) && (dp != is->is_dport)) + rev = 1; + } } else { flags = is->is_flags & FI_WILDA; sp = 0; @@ -871,10 +879,10 @@ tcphdr_t *tcp; 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)) + if (((fin->fin_fl & (flags >> 4)) != (flags & FI_CMP)) || + (fin->fin_fi.fi_optmsk != is->is_opt) || + (fin->fin_fi.fi_secmsk != is->is_sec) || + (fin->fin_fi.fi_auth != is->is_auth)) return 0; if ((flags & (FI_W_SPORT|FI_W_DPORT))) { @@ -924,16 +932,11 @@ tcphdr_t *tcp; if (ret >= 0) { is->is_ifp[ret] = ifp; #ifdef _KERNEL - strncpy(is->is_ifname[out], IFNAME(fin->fin_ifp), - sizeof(is->is_ifname[1])); + strncpy(is->is_ifname[ret], IFNAME(fin->fin_ifp), + sizeof(is->is_ifname[ret])); #endif } -#ifdef _KERNEL - if (ret >= 0) { - strncpy(is->is_ifname[out], IFNAME(fin->fin_ifp), - sizeof(is->is_ifname[1])); - } -#endif + fin->fin_rev = rev; return 1; } @@ -1209,8 +1212,7 @@ fr_info_t *fin; frentry_t *fr; tcphdr_t *tcp; - if (fr_state_lock || (fin->fin_off & IP_OFFMASK) || - (fin->fin_fi.fi_fl & FI_SHORT)) + if (fr_state_lock || (fin->fin_off != 0) || (fin->fin_fl & FI_SHORT)) return NULL; is = NULL; @@ -1254,7 +1256,10 @@ fr_info_t *fin; if ((is->is_p == pr) && (is->is_v == v) && fr_matchsrcdst(is, src, dst, fin, NULL) && fr_matchicmpqueryreply(v, is, ic)) { - is->is_age = fr_icmptimeout; + if (fin->fin_rev) + is->is_age = fr_icmpacktimeout; + else + is->is_age = fr_icmptimeout; break; } } @@ -1302,6 +1307,11 @@ retry_tcpudp: if (!fr_tcpstate(is, fin, ip, tcp)) { continue; } + } else if ((pr == IPPROTO_UDP)) { + if (fin->fin_rev) + is->is_age = fr_udpacktimeout; + else + is->is_age = fr_udptimeout; } break; } @@ -1345,7 +1355,7 @@ retry_tcpudp: fr_delstate(is); #endif RWLOCK_EXIT(&ipf_state); - if (fin->fin_fi.fi_fl & FI_FRAG) + if ((fin->fin_fl & FI_FRAG) && (pass & FR_KEEPFRAG)) ipfr_newfrag(ip, fin, pass ^ FR_KEEPSTATE); return fr; } @@ -1420,7 +1430,8 @@ void fr_stateunload() ips_stats.iss_inuse = 0; ips_num = 0; RWLOCK_EXIT(&ipf_state); - KFREES(ips_table, fr_statesize * sizeof(ipstate_t *)); + if (ips_table) + KFREES(ips_table, fr_statesize * sizeof(ipstate_t *)); ips_table = NULL; } diff --git a/sys/contrib/ipfilter/netinet/ip_state.h b/sys/contrib/ipfilter/netinet/ip_state.h index 1d1bc00..b940d77 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.h +++ b/sys/contrib/ipfilter/netinet/ip_state.h @@ -1,12 +1,10 @@ /* - * Copyright (C) 1995-2000 by Darren Reed. + * Copyright (C) 1995-2001 by Darren Reed. * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. + * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_state.h 1.3 1/12/96 (C) 1995 Darren Reed - * $Id: ip_state.h,v 2.13.2.2 2000/08/23 11:01:31 darrenr Exp $ + * $Id: ip_state.h,v 2.13.2.4 2001/06/26 10:43:17 darrenr Exp $ */ #ifndef __IP_STATE_H__ #define __IP_STATE_H__ @@ -17,8 +15,12 @@ # define SIOCDELST _IOW(r, 61, struct ipstate *) #endif -#define IPSTATE_SIZE 5737 -#define IPSTATE_MAX 4013 /* Maximum number of states held */ +#ifndef IPSTATE_SIZE +# define IPSTATE_SIZE 5737 +#endif +#ifndef IPSTATE_MAX +# define IPSTATE_MAX 4013 /* Maximum number of states held */ +#endif #define PAIRS(s1,d1,s2,d2) ((((s1) == (s2)) && ((d1) == (d2))) ||\ (((s1) == (d2)) && ((d1) == (s2)))) diff --git a/sys/contrib/ipfilter/netinet/ipl.h b/sys/contrib/ipfilter/netinet/ipl.h index 3529d65..472bcce 100644 --- a/sys/contrib/ipfilter/netinet/ipl.h +++ b/sys/contrib/ipfilter/netinet/ipl.h @@ -1,17 +1,15 @@ /* - * Copyright (C) 1993-2000 by Darren Reed. + * Copyright (C) 1993-2001 by Darren Reed. * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. + * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ipl.h 1.21 6/5/96 - * $Id: ipl.h,v 2.15.2.17 2001/01/14 13:47:15 darrenr Exp $ + * $Id: ipl.h,v 2.15.2.23 2001/07/23 13:52:10 darrenr Exp $ */ #ifndef __IPL_H__ #define __IPL_H__ -#define IPL_VERSION "IP Filter: v3.4.16" +#define IPL_VERSION "IP Filter: v3.4.20" #endif -- cgit v1.1 From cd9921ad61ecc9f6f8e49c289401525fa244620c Mon Sep 17 00:00:00 2001 From: cvs2svn Date: Wed, 12 Sep 2001 22:00:04 +0000 Subject: This commit was manufactured by cvs2svn to create branch 'VENDOR-sys-ipfilter'. --- sys/contrib/ipfilter/netinet/IPFILTER.LICENCE | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 sys/contrib/ipfilter/netinet/IPFILTER.LICENCE diff --git a/sys/contrib/ipfilter/netinet/IPFILTER.LICENCE b/sys/contrib/ipfilter/netinet/IPFILTER.LICENCE new file mode 100644 index 0000000..dfb199c --- /dev/null +++ b/sys/contrib/ipfilter/netinet/IPFILTER.LICENCE @@ -0,0 +1,29 @@ +Copyright (C) 1993-2001 by Darren Reed. + +$FreeBSD$ + +The author accepts no responsibility for the use of this software and +provides it on an ``as is'' basis without express or implied warranty. + +Redistribution and use, with or without modification, in source and binary +forms, are permitted provided that this notice is preserved in its entirety +and due credit is given to the original author and the contributors. + +The licence and distribution terms for any publically available version or +derivative of this code cannot be changed. i.e. this code cannot simply be +copied, in part or in whole, and put under another distribution licence +[including the GNU Public Licence.] + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +I hate legalese, don't you ? -- cgit v1.1 From 556707698ec4ad5f069aadf43f197993b46fab21 Mon Sep 17 00:00:00 2001 From: darrenr Date: Tue, 19 Mar 2002 11:30:21 +0000 Subject: Import IPFilter 3.4.25 (last version 3.4.20) --- sys/contrib/ipfilter/netinet/ip_h323_pxy.c | 275 ++++++++++++++++++++++++ sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c | 292 ++++++++++++++++++++++++++ sys/contrib/ipfilter/netinet/ip_netbios_pxy.c | 109 ++++++++++ 3 files changed, 676 insertions(+) create mode 100644 sys/contrib/ipfilter/netinet/ip_h323_pxy.c create mode 100644 sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c create mode 100644 sys/contrib/ipfilter/netinet/ip_netbios_pxy.c diff --git a/sys/contrib/ipfilter/netinet/ip_h323_pxy.c b/sys/contrib/ipfilter/netinet/ip_h323_pxy.c new file mode 100644 index 0000000..14aa47b --- /dev/null +++ b/sys/contrib/ipfilter/netinet/ip_h323_pxy.c @@ -0,0 +1,275 @@ +/* + * Copyright 2001, QNX Software Systems Ltd. All Rights Reserved + * + * This source code has been published by QNX Software Systems Ltd. (QSSL). + * However, any use, reproduction, modification, distribution or transfer of + * this software, or any software which includes or is based upon any of this + * code, is only permitted under the terms of the QNX Open Community License + * version 1.0 (see licensing.qnx.com for details) or as otherwise expressly + * authorized by a written license agreement from QSSL. For more information, + * please email licensing@qnx.com. + * + */ + +/* + * Simple H.323 proxy + * + * by xtang@canada.com + * ported to ipfilter 3.4.20 by Michael Grant mg-ipf@grant.org + */ + +#if __FreeBSD_version >= 220000 && defined(_KERNEL) +# include +# include +#else +# include +#endif + +#define IPF_H323_PROXY + +int ippr_h323_init __P((void)); +int ippr_h323_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +void ippr_h323_del __P((ap_session_t *)); +int ippr_h323_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_h323_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); + +int ippr_h245_init __P((void)); +int ippr_h245_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_h245_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_h245_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); + +static frentry_t h323_fr; +#if (SOLARIS || defined(__sgi)) && defined(_KERNEL) +extern KRWLOCK_T ipf_nat; +#endif + +static int find_port __P((int, u_char *, int datlen, int *, u_short *)); + + +static int find_port(ipaddr, data, datlen, off, port) +int ipaddr; +unsigned char *data; +int datlen, *off; +unsigned short *port; +{ + if (datlen < 6) + return -1; + + *port = 0; + for (*off = 0; *off <= datlen - 6; *off = *off + 1) { + if (ipaddr == *(int *)(data + *off)) + { + *port = (*(data + *off + 4) << 8) + *(data + *off +5); + break; + } + } + return (*off > datlen - 6) ? -1 : 0; +} + +/* + * Initialize local structures. + */ +int ippr_h323_init() +{ + bzero((char *)&h323_fr, sizeof(h323_fr)); + h323_fr.fr_ref = 1; + h323_fr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + + return 0; +} + + +int ippr_h323_new(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + aps->aps_data = NULL; + aps->aps_psiz = 0; + + return 0; +} + + +void ippr_h323_del(aps) +ap_session_t *aps; +{ + int i; + ipnat_t *ipn; + + if (aps->aps_data) { + for (i = 0, ipn = aps->aps_data; + i < (aps->aps_psiz / sizeof(ipnat_t)); + i++, ipn = (ipnat_t *)((char *)ipn + sizeof(*ipn))) + { + /* + * Check the comment in ippr_h323_in() function, + * just above nat_ioctl() call. + * We are lucky here because this function is not + * called with ipf_nat locked. + */ + if (nat_ioctl((caddr_t)ipn, SIOCRMNAT, FWRITE) == -1) { + /* log the error */ + } + } + KFREES(aps->aps_data, aps->aps_psiz); + } + return; +} + + +int ippr_h323_out(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + return 0; +} + + +int ippr_h323_in(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + int ipaddr, off, datlen; + unsigned short port; + unsigned char *data; + tcphdr_t *tcp; + + tcp = (tcphdr_t *)fin->fin_dp; + ipaddr = ip->ip_src.s_addr; + + data = (unsigned char *)tcp + (tcp->th_off << 2); + datlen = ip->ip_len - (ip->ip_hl << 2) - (tcp->th_off << 2); + if (find_port(ipaddr, data, datlen, &off, &port) == 0) { + ipnat_t *ipn; + char *newarray; + + /* setup a nat rule to set a h245 proxy on tcp-port "port" + * it's like: + * map / -> / proxy port /tcp + */ + KMALLOCS(newarray, char *, aps->aps_psiz + sizeof(*ipn)); + if (newarray == NULL) { + return -1; + } + ipn = (ipnat_t *)&newarray[aps->aps_psiz]; + bcopy(nat->nat_ptr, ipn, sizeof(ipnat_t)); + strncpy(ipn->in_plabel, "h245", APR_LABELLEN); + + ipn->in_inip = nat->nat_inip.s_addr; + ipn->in_inmsk = 0xffffffff; + ipn->in_dport = htons(port); + /* + * we got a problem here. we need to call nat_ioctl() to add + * the h245 proxy rule, but since we already hold (READ locked) + * the nat table rwlock (ipf_nat), if we go into nat_ioctl(), + * it will try to WRITE lock it. This will causing dead lock + * on RTP. + * + * The quick & dirty solution here is release the read lock, + * call nat_ioctl() and re-lock it. + * A (maybe better) solution is do a UPGRADE(), and instead + * of calling nat_ioctl(), we add the nat rule ourself. + */ + RWLOCK_EXIT(&ipf_nat); + if (nat_ioctl((caddr_t)ipn, SIOCADNAT, FWRITE) == -1) { + READ_ENTER(&ipf_nat); + return -1; + } + READ_ENTER(&ipf_nat); + bcopy(aps->aps_data, newarray, aps->aps_psiz); + KFREES(aps->aps_data, aps->aps_psiz); + aps->aps_data = newarray; + aps->aps_psiz += sizeof(*ipn); + } + return 0; +} + + +int ippr_h245_init() +{ + return 0; +} + + +int ippr_h245_new(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + aps->aps_data = NULL; + aps->aps_psiz = 0; + return 0; +} + + +int ippr_h245_out(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + int ipaddr, off, datlen; + u_short port; + unsigned char *data; + tcphdr_t *tcp; + + tcp = (tcphdr_t *)fin->fin_dp; + ipaddr = nat->nat_inip.s_addr; + data = (unsigned char *)tcp + (tcp->th_off << 2); + datlen = ip->ip_len - fin->fin_hlen - (tcp->th_off << 2); + if (find_port(ipaddr, data, datlen, &off, &port) == 0) { + fr_info_t fi; + nat_t *ipn; + +/* port = htons(port); */ + ipn = nat_outlookup(fin->fin_ifp, IPN_UDP, IPPROTO_UDP, + ip->ip_src, ip->ip_dst, 1); + if (ipn == NULL) { + struct ip newip; + struct udphdr udp; + + bcopy(ip, &newip, sizeof(newip)); + newip.ip_len = fin->fin_hlen + sizeof(udp); + newip.ip_p = IPPROTO_UDP; + newip.ip_src = nat->nat_inip; + + bzero(&udp, sizeof(udp)); + udp.uh_sport = port; + + bcopy(fin, &fi, sizeof(fi)); + fi.fin_fi.fi_p = IPPROTO_UDP; + fi.fin_data[0] = port; + fi.fin_data[1] = 0; + fi.fin_dp = (char *)&udp; + + ipn = nat_new(&fi, &newip, nat->nat_ptr, NULL, + IPN_UDP|FI_W_DPORT, NAT_OUTBOUND); + if (ipn != NULL) { + ipn->nat_ptr->in_hits++; +#ifdef IPFILTER_LOG + nat_log(ipn, (u_int)(nat->nat_ptr->in_redir)); +#endif + *(int *)(data + off) = ip->ip_src.s_addr; + *(short *)(data + off + 4) = ipn->nat_outport; + } + } + } + return 0; +} + + +int ippr_h245_in(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + return 0; +} diff --git a/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c b/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c new file mode 100644 index 0000000..40ce131 --- /dev/null +++ b/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c @@ -0,0 +1,292 @@ +/* + * Simple ISAKMP transparent proxy for in-kernel use. For use with the NAT + * code. + * + * $Id: ip_ipsec_pxy.c,v 1.1.2.10 2002/01/13 04:58:29 darrenr Exp $ + * + */ +#define IPF_IPSEC_PROXY + + +int ippr_ipsec_init __P((void)); +int ippr_ipsec_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +void ippr_ipsec_del __P((ap_session_t *)); +int ippr_ipsec_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); +int ippr_ipsec_match __P((fr_info_t *, ap_session_t *, nat_t *)); + +static frentry_t ipsecfr; + + +static char ipsec_buffer[1500]; + +/* + * RCMD application proxy initialization. + */ +int ippr_ipsec_init() +{ + bzero((char *)&ipsecfr, sizeof(ipsecfr)); + ipsecfr.fr_ref = 1; + ipsecfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + return 0; +} + + +/* + * Setup for a new IPSEC proxy. + */ +int ippr_ipsec_new(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + ipsec_pxy_t *ipsec; + fr_info_t fi; + ipnat_t *ipn; + char *ptr; + int p, off, dlen; + mb_t *m; + + bzero(ipsec_buffer, sizeof(ipsec_buffer)); + off = fin->fin_hlen + sizeof(udphdr_t); +#ifdef _KERNEL +# if SOLARIS + m = fin->fin_qfm; + + dlen = msgdsize(m) - off; + if (dlen < 16) + return -1; + copyout_mblk(m, off, MIN(sizeof(ipsec_buffer), dlen), ipsec_buffer); +# else + m = *(mb_t **)fin->fin_mp; + dlen = mbufchainlen(m) - off; + if (dlen < 16) + return -1; + m_copydata(m, off, MIN(sizeof(ipsec_buffer), dlen), ipsec_buffer); +# endif +#else + m = *(mb_t **)fin->fin_mp; + dlen = ip->ip_len - off; + ptr = (char *)m; + ptr += off; + bcopy(ptr, ipsec_buffer, MIN(sizeof(ipsec_buffer), dlen)); +#endif + + /* + * Because _new() gets called from nat_new(), ipf_nat is held with a + * write lock so pass rw=1 to nat_outlookup(). + */ + if (nat_outlookup(fin, 0, IPPROTO_ESP, nat->nat_inip, + ip->ip_dst, 1) != NULL) + return -1; + + aps->aps_psiz = sizeof(*ipsec); + KMALLOCS(aps->aps_data, ipsec_pxy_t *, sizeof(*ipsec)); + if (aps->aps_data == NULL) + return -1; + + ipsec = aps->aps_data; + bzero((char *)ipsec, sizeof(*ipsec)); + + /* + * Create NAT rule against which the tunnel/transport mapping is + * created. This is required because the current NAT rule does not + * describe ESP but UDP instead. + */ + ipn = &ipsec->ipsc_rule; + ipn->in_ifp = fin->fin_ifp; + ipn->in_apr = NULL; + ipn->in_use = 1; + ipn->in_hits = 1; + ipn->in_nip = ntohl(nat->nat_outip.s_addr); + ipn->in_ippip = 1; + ipn->in_inip = nat->nat_inip.s_addr; + ipn->in_inmsk = 0xffffffff; + ipn->in_outip = nat->nat_outip.s_addr; + ipn->in_outmsk = 0xffffffff; + ipn->in_srcip = fin->fin_saddr; + ipn->in_srcmsk = 0xffffffff; + ipn->in_redir = NAT_MAP; + bcopy(nat->nat_ptr->in_ifname, ipn->in_ifname, sizeof(ipn->in_ifname)); + ipn->in_p = IPPROTO_ESP; + + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + fi.fin_fi.fi_p = IPPROTO_ESP; + fi.fin_fr = &ipsecfr; + fi.fin_data[0] = 0; + fi.fin_data[1] = 0; + p = ip->ip_p; + ip->ip_p = IPPROTO_ESP; + fi.fin_fl &= ~FI_TCPUDP; + + ptr = ipsec_buffer; + bcopy(ptr, ipsec->ipsc_icookie, sizeof(ipsec_cookie_t)); + ptr += sizeof(ipsec_cookie_t); + bcopy(ptr, ipsec->ipsc_rcookie, sizeof(ipsec_cookie_t)); + /* + * The responder cookie should only be non-zero if the initiator + * cookie is non-zero. Therefore, it is safe to assume(!) that the + * cookies are both set after copying if the responder is non-zero. + */ + if ((ipsec->ipsc_rcookie[0]|ipsec->ipsc_rcookie[1]) != 0) + ipsec->ipsc_rckset = 1; + else + nat->nat_age = 60; /* 30 seconds */ + + ipsec->ipsc_nat = nat_new(&fi, ip, ipn, &ipsec->ipsc_nat, FI_IGNOREPKT, + NAT_OUTBOUND); + if (ipsec->ipsc_nat != NULL) { + fi.fin_data[0] = 0; + fi.fin_data[1] = 0; + ipsec->ipsc_state = fr_addstate(ip, &fi, &ipsec->ipsc_state, + FI_IGNOREPKT|FI_NORULE); + } + ip->ip_p = p; + return 0; +} + + +/* + * For outgoing IKE packets. refresh timeouts for NAT & stat entries, if + * we can. If they have disappeared, recreate them. + */ +int ippr_ipsec_out(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + ipsec_pxy_t *ipsec; + fr_info_t fi; + int p; + + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + fi.fin_fi.fi_p = IPPROTO_ESP; + fi.fin_fr = &ipsecfr; + fi.fin_data[0] = 0; + fi.fin_data[1] = 0; + p = ip->ip_p; + ip->ip_p = IPPROTO_ESP; + fi.fin_fl &= ~FI_TCPUDP; + + ipsec = aps->aps_data; + if (ipsec != NULL) { + /* + * Update NAT timeout/create NAT if missing. + */ + if (ipsec->ipsc_rckset == 0) + nat->nat_age = 60; /* 30 seconds */ + if (ipsec->ipsc_nat != NULL) + ipsec->ipsc_nat->nat_age = nat->nat_age; + else + ipsec->ipsc_nat = nat_new(&fi, ip, &ipsec->ipsc_rule, + &ipsec->ipsc_nat, + FI_IGNOREPKT, NAT_OUTBOUND); + + /* + * Update state timeout/create state if missing. + */ + READ_ENTER(&ipf_state); + if (ipsec->ipsc_state != NULL) { + ipsec->ipsc_state->is_age = nat->nat_age; + RWLOCK_EXIT(&ipf_state); + } else { + RWLOCK_EXIT(&ipf_state); + fi.fin_data[0] = 0; + fi.fin_data[1] = 0; + ipsec->ipsc_state = fr_addstate(ip, &fi, + &ipsec->ipsc_state, + FI_IGNOREPKT|FI_NORULE); + } + } + ip->ip_p = p; + return 0; +} + + +/* + * This extends the NAT matching to be based on the cookies associated with + * a session and found at the front of IKE packets. The cookies are always + * in the same order (not reversed depending on packet flow direction as with + * UDP/TCP port numbers). + */ +int ippr_ipsec_match(fin, aps, nat) +fr_info_t *fin; +ap_session_t *aps; +nat_t *nat; +{ + ipsec_pxy_t *ipsec; + u_32_t cookies[4]; + mb_t *m; + int off; + + if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_fl & FI_FRAG)) + return -1; + + ipsec = aps->aps_data; + off = fin->fin_hlen + sizeof(udphdr_t); +#ifdef _KERNEL +# if SOLARIS + m = fin->fin_qfm; + + copyout_mblk(m, off, sizeof(cookies), (char *)cookies); +# else + m = *(mb_t **)fin->fin_mp; + m_copydata(m, off, sizeof(cookies), (char *)cookies); +# endif +#else + m = *(mb_t **)fin->fin_mp; + bcopy((char *)m + off, cookies, sizeof(cookies)); +#endif + + if ((cookies[0] != ipsec->ipsc_icookie[0]) || + (cookies[1] != ipsec->ipsc_icookie[1])) + return -1; + + if (ipsec->ipsc_rckset == 0) { + if ((cookies[2]|cookies[3]) == 0) { + nat->nat_age = 60; /* 30 seconds */ + return 0; + } + ipsec->ipsc_rckset = 1; + ipsec->ipsc_rcookie[0] = cookies[2]; + ipsec->ipsc_rcookie[1] = cookies[3]; + return 0; + } + + if ((cookies[2] != ipsec->ipsc_rcookie[0]) || + (cookies[3] != ipsec->ipsc_rcookie[1])) + return -1; + return 0; +} + + +/* + * clean up after ourselves. + */ +void ippr_ipsec_del(aps) +ap_session_t *aps; +{ + ipsec_pxy_t *ipsec; + + ipsec = aps->aps_data; + + if (ipsec != NULL) { + /* + * Don't delete it from here, just schedule it to be + * deleted ASAP. + */ + if (ipsec->ipsc_nat != NULL) { + ipsec->ipsc_nat->nat_age = 1; + ipsec->ipsc_nat->nat_ptr = NULL; + } + + READ_ENTER(&ipf_state); + if (ipsec->ipsc_state != NULL) + ipsec->ipsc_state->is_age = 1; + RWLOCK_EXIT(&ipf_state); + + ipsec->ipsc_state = NULL; + ipsec->ipsc_nat = NULL; + } +} diff --git a/sys/contrib/ipfilter/netinet/ip_netbios_pxy.c b/sys/contrib/ipfilter/netinet/ip_netbios_pxy.c new file mode 100644 index 0000000..ee9b0c4 --- /dev/null +++ b/sys/contrib/ipfilter/netinet/ip_netbios_pxy.c @@ -0,0 +1,109 @@ +/* + * Simple netbios-dgm transparent proxy for in-kernel use. + * For use with the NAT code. + * $Id: ip_netbios_pxy.c,v 1.1.2.3 2002/01/09 09:28:37 darrenr Exp $ + */ + +/*- + * Copyright (c) 2002 Paul J. Ledbetter III + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: ip_netbios_pxy.c,v 1.1.2.3 2002/01/09 09:28:37 darrenr Exp $ + */ + +#define IPF_NETBIOS_PROXY + +int ippr_netbios_init __P((void)); +int ippr_netbios_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); + +static frentry_t netbiosfr; + +/* + * Initialize local structures. + */ +int ippr_netbios_init() +{ + bzero((char *)&netbiosfr, sizeof(netbiosfr)); + netbiosfr.fr_ref = 1; + netbiosfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + return 0; +} + +int ippr_netbios_out(fin, ip, aps, nat) +fr_info_t *fin; +ip_t *ip; +ap_session_t *aps; +nat_t *nat; +{ + char dgmbuf[6]; + + int off, dlen; + udphdr_t *udp; + mb_t *m; + + m = *(mb_t **)fin->fin_mp; + off = fin->fin_hlen + sizeof(udphdr_t); +#if SOLARIS + dlen = msgdsize(m); +#else + dlen = mbufchainlen(m); +#endif + dlen -= off; + + /* + * no net bios datagram could possibly be shorter than this + */ + if (dlen < 11) + return 0; + + udp = (udphdr_t *)fin->fin_dp; + + /* + * move past the + * ip header; + * udp header; + * 4 bytes into the net bios dgm header. + * According to rfc1002, this should be the exact location of + * the source address/port + */ + off += 4; + + /* Copy NATed source Address/port*/ + dgmbuf[0] = (char)((ip->ip_src.s_addr ) &0xFF); + dgmbuf[1] = (char)((ip->ip_src.s_addr >> 8) &0xFF); + dgmbuf[2] = (char)((ip->ip_src.s_addr >> 16)&0xFF); + dgmbuf[3] = (char)((ip->ip_src.s_addr >> 24)&0xFF); + + dgmbuf[4] = (char)((udp->uh_sport )&0xFF); + dgmbuf[5] = (char)((udp->uh_sport >> 8)&0xFF); + + /* replace data in packet */ +#if SOLARIS + copyin_mblk(m, off, sizeof(dgmbuf), dgmbuf); +#else + m_copyback(m, off, sizeof(dgmbuf), dgmbuf); +#endif + + return 0; +} -- cgit v1.1