summaryrefslogtreecommitdiffstats
path: root/sys/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib')
-rw-r--r--sys/contrib/ipfilter/netinet/QNX_OCL.txt277
-rw-r--r--sys/contrib/ipfilter/netinet/fil.c8151
-rw-r--r--sys/contrib/ipfilter/netinet/ip_auth.c960
-rw-r--r--sys/contrib/ipfilter/netinet/ip_auth.h45
-rw-r--r--sys/contrib/ipfilter/netinet/ip_compat.h1591
-rw-r--r--sys/contrib/ipfilter/netinet/ip_dns_pxy.c402
-rw-r--r--sys/contrib/ipfilter/netinet/ip_dstlist.c1351
-rw-r--r--sys/contrib/ipfilter/netinet/ip_dstlist.h68
-rw-r--r--sys/contrib/ipfilter/netinet/ip_fil.h1444
-rw-r--r--sys/contrib/ipfilter/netinet/ip_fil_freebsd.c1035
-rw-r--r--sys/contrib/ipfilter/netinet/ip_frag.c1095
-rw-r--r--sys/contrib/ipfilter/netinet/ip_frag.h102
-rw-r--r--sys/contrib/ipfilter/netinet/ip_ftp_pxy.c1685
-rw-r--r--sys/contrib/ipfilter/netinet/ip_htable.c1219
-rw-r--r--sys/contrib/ipfilter/netinet/ip_htable.h49
-rw-r--r--sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c330
-rw-r--r--sys/contrib/ipfilter/netinet/ip_irc_pxy.c127
-rw-r--r--sys/contrib/ipfilter/netinet/ip_log.c663
-rw-r--r--sys/contrib/ipfilter/netinet/ip_lookup.c935
-rw-r--r--sys/contrib/ipfilter/netinet/ip_lookup.h77
-rw-r--r--sys/contrib/ipfilter/netinet/ip_nat.c7215
-rw-r--r--sys/contrib/ipfilter/netinet/ip_nat.h650
-rw-r--r--sys/contrib/ipfilter/netinet/ip_nat6.c4098
-rw-r--r--sys/contrib/ipfilter/netinet/ip_netbios_pxy.c28
-rw-r--r--sys/contrib/ipfilter/netinet/ip_pool.c1271
-rw-r--r--sys/contrib/ipfilter/netinet/ip_pool.h85
-rw-r--r--sys/contrib/ipfilter/netinet/ip_pptp_pxy.c296
-rw-r--r--sys/contrib/ipfilter/netinet/ip_proxy.c1197
-rw-r--r--sys/contrib/ipfilter/netinet/ip_proxy.h199
-rw-r--r--sys/contrib/ipfilter/netinet/ip_raudio_pxy.c100
-rw-r--r--sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c335
-rw-r--r--sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c335
-rw-r--r--sys/contrib/ipfilter/netinet/ip_rules.c77
-rw-r--r--sys/contrib/ipfilter/netinet/ip_scan.c220
-rw-r--r--sys/contrib/ipfilter/netinet/ip_scan.h20
-rw-r--r--sys/contrib/ipfilter/netinet/ip_state.c3625
-rw-r--r--sys/contrib/ipfilter/netinet/ip_state.h198
-rw-r--r--sys/contrib/ipfilter/netinet/ip_sync.c1003
-rw-r--r--sys/contrib/ipfilter/netinet/ip_sync.h40
-rw-r--r--sys/contrib/ipfilter/netinet/ip_tftp_pxy.c508
-rw-r--r--sys/contrib/ipfilter/netinet/ipf_rb.h364
-rw-r--r--sys/contrib/ipfilter/netinet/ipl.h8
-rw-r--r--sys/contrib/ipfilter/netinet/mlfk_ipl.c378
-rw-r--r--sys/contrib/ipfilter/netinet/radix_ipf.c1528
-rw-r--r--sys/contrib/ipfilter/netinet/radix_ipf.h95
45 files changed, 32595 insertions, 12884 deletions
diff --git a/sys/contrib/ipfilter/netinet/QNX_OCL.txt b/sys/contrib/ipfilter/netinet/QNX_OCL.txt
deleted file mode 100644
index b623776..0000000
--- a/sys/contrib/ipfilter/netinet/QNX_OCL.txt
+++ /dev/null
@@ -1,277 +0,0 @@
-$FreeBSD$
-
- End User License Certificate (EULA) End User License Certificate
- (EULA)
- Support Support
- QNX Source Licenses QNX Source Licenses
- License of the month
- Confidential Source License
- Version 1.0
-
-QNX Open Community License Version 1.0
-
- THIS QNX OPEN COMMUNITY LICENSE ( "THE OCL", OR "THIS AGREEMENT")
- APPLIES TO PROGRAMS THAT QNX SOFTWARE SYSTEMS LTD. ("QSS") EXPRESSLY
- ELECTS TO LICENSE UNDER THE OCL TERMS. IT ALSO APPLIES TO DERIVATIVE
- WORKS CREATED UNDER THIS AGREEMENT THAT CREATORS ELECT TO LICENSE TO
- OTHERS IN SOURCE CODE FORM. ANY USE, REPRODUCTION, MODIFICATION OR
- DISTRIBUTION OF SUCH PROGRAMS CONSTITUTES RECIPIENT'S ACCEPTANCE OF
- THE OCL. THE LICENSE RIGHTS GRANTED BELOW ARE CONDITIONAL UPON
- RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT AND THE FORMATION OF A
- BINDING CONTRACT. NOTHING ELSE GRANTS PERMISSION TO USE, REPRODUCE,
- MODIFY OR DISTRIBUTE SUCH PROGRAMS OR THEIR DERIVATIVE WORKS. THESE
- ACTIONS ARE OTHERWISE PROHIBITED. CONTACT QSS IF OTHER STEPS ARE
- REQUIRED LOCALLY TO CREATE A BINDING CONTRACT.
-
- The OCL is intended to promote the development, use and distribution
- of derivative works created from QSS source code. This includes
- commercial distribution of object code versions under the terms of
- Recipient's own license agreement and, at Recipient's option, sharing
- of source code modifications within the QNX developer's community. The
- license granted under the OCL is royalty free. Recipient is entitled
- to charge royalties for object code versions of derivative works that
- originate with Recipient. If Recipient elects to license source code
- for its derivative works to others, then it must be licensed under the
- OCL. The terms of the OCL are as follows:
-
-1. DEFINITIONS
-
- "Contribution" means:
-
- a. in the case of QSS: (i) the Original Program, where the Original
- Program originates from QSS, (ii) changes and/or additions to
- Unrestricted Open Source, where the Original Program originates
- from Unrestricted Open Source and where such changes and/or
- additions originate from QSS, and (iii) changes and/or additions
- to the Program where such changes and/or additions originate from
- QSS.
- b. in the case of each Contributor, changes and/or additions to the
- Program, where such changes and/or additions originate from and
- are distributed by that particular Contributor.
-
- A Contribution 'originates' from a Contributor if it was added to the
- Program by such Contributor itself or anyone acting on such
- Contributor's behalf. Contributions do not include additions to the
- Program which: (i) are separate modules of software distributed in
- conjunction with the Program under their own license agreement, and
- (ii) are not derivative works of the Program.
-
- "Contributor" means QSS and any other entity that distributes the
- Program.
-
- "Licensed Patents " mean patent claims licensable by Contributor to
- others, which are necessarily infringed by the use or sale of its
- Contribution alone or when combined with the Program.
-
- "Unrestricted Open Source" means published source code that is
- licensed for free use and distribution under an unrestricted licensing
- and distribution model, such as the Berkley Software Design ("BSD")
- and "BSD-like" licenses. It specifically excludes any source code
- licensed under any version of the GNU General Public License (GPL) or
- the GNU Lesser/Library GPL. All "Unrestricted Open Source" license
- terms appear or are clearly identified in the header of any affected
- source code for the Original Program.
-
- "Original Program" means the original version of the software
- accompanying this Agreement as released by QSS, including source code,
- object code and documentation, if any.
-
- "Program" means the Original Program and Contributions.
-
- "Recipient" means anyone who receives the Program under this
- Agreement, including all Contributors.
-
-2. GRANT OF RIGHTS
-
- a. Subject to the terms of this Agreement, each Contributor hereby
- grants Recipient a non-exclusive, worldwide, royalty-free
- copyright license to reproduce, prepare derivative works of,
- publicly display, publicly perform, and directly and indirectly
- sublicense and distribute the Contribution of such Contributor, if
- any, and such derivative works, in source code and object code
- form.
- b. Subject to the terms of this Agreement, each Contributor hereby
- grants Recipient a non-exclusive, worldwide, royalty-free patent
- license under Licensed Patents to make, use, sell, offer to sell,
- import and otherwise transfer the Contribution of such
- Contributor, if any, in source code and object code form. This
- patent license shall apply to the combination of the Contribution
- and the Program if, at the time the Contribution is added by the
- Contributor, such addition of the Contribution causes such
- combination to be covered by the Licensed Patents. The patent
- license shall not apply to any other combinations which include
- the Contribution.
- c. Recipient understands that although each Contributor grants the
- licenses to its Contributions set forth herein, no assurances are
- provided by any Contributor that the Program does not infringe the
- patent or other intellectual property rights of any other entity.
- Each Contributor disclaims any liability to Recipient for claims
- brought by any other entity based on infringement of intellectual
- property rights or otherwise. As a condition to exercising the
- rights and licenses granted hereunder, each Recipient hereby
- assumes sole responsibility to secure any other intellectual
- property rights needed, if any. For example, if a third party
- patent license is required to allow Recipient to distribute the
- Program, it is Recipient's responsibility to acquire that license
- before distributing the Program.
- d. Each Contributor represents that to its knowledge it has
- sufficient copyright rights in its Contribution, if any, to grant
- the copyright license set forth in this Agreement.
-
- 3. REQUIREMENTS
-
- A Contributor may choose to distribute the Program in object code form
- under its own license agreement, provided that:
-
- a. it complies with the terms and conditions of this Agreement; and
- b. its license agreement:
- i. effectively disclaims on behalf of all Contributors all
- warranties and conditions, express and implied, including
- warranties or conditions of title and non-infringement, and
- implied warranties or conditions of merchantability and
- fitness for a particular purpose;
- ii. effectively excludes on behalf of all Contributors all
- liability for damages, including direct, indirect, special,
- incidental and consequential damages, such as lost profits;
- and
- iii. states that any provisions which differ from this Agreement
- are offered by that Contributor alone and not by any other
- party.
-
- If the Program is made available in source code form:
-
- a. it must be made available under this Agreement; and
- b. a copy of this Agreement must be included with each copy of the
- Program. Each Contributor must include the following in a
- conspicuous location in the Program along with any other copyright
- or attribution statements required by the terms of any applicable
- Unrestricted Open Source license:
- Copyright {date here}, QNX Software Systems Ltd. and others. All
- Rights Reserved.
-
- In addition, each Contributor must identify itself as the originator
- of its Contribution, if any, in a manner that reasonably allows
- subsequent Recipients to identify the originator of the Contribution.
-
- 4. COMMERCIAL DISTRIBUTION
-
- Commercial distributors of software may accept certain
- responsibilities with respect to end users, business partners and the
- like. While this license is intended to facilitate the commercial use
- of the Program, the Contributor who includes the Program in a
- commercial product offering should do so in a manner which does not
- create potential liability for other Contributors. Therefore, if a
- Contributor includes the Program in a commercial product offering,
- such Contributor ("Commercial Contributor") hereby agrees to defend
- and indemnify every other Contributor ("Indemnified Contributor")
- against any losses, damages and costs (collectively "Losses") arising
- from claims, lawsuits and other legal actions brought by a third party
- against the Indemnified Contributor to the extent caused by the acts
- or omissions of such Commercial Contributor in connection with its
- distribution of the Program in a commercial product offering. The
- obligations in this section do not apply to any claims or Losses
- relating to any actual or alleged intellectual property infringement.
- In order to qualify, an Indemnified Contributor must: a) promptly
- notify the Commercial Contributor in writing of such claim, and b)
- allow the Commercial Contributor to control, and cooperate with the
- Commercial Contributor in, the defense and any related settlement
- negotiations. The Indemnified Contributor may participate in any such
- claim at its own expense.
-
- For example, a Contributor might include the Program in a commercial
- product offering, Product X. That Contributor is then a Commercial
- Contributor. If that Commercial Contributor then makes performance
- claims, or offers warranties related to Product X, those performance
- claims and warranties are such Commercial Contributor's responsibility
- alone. Under this section, the Commercial Contributor would have to
- defend claims against the other Contributors related to those
- performance claims and warranties, and if a court requires any other
- Contributor to pay any damages as a result, the Commercial Contributor
- must pay those damages.
-
- 5. NO WARRANTY
-
- Recipient acknowledges that there may be errors or bugs in the Program
- and that it is imperative that Recipient conduct thorough testing to
- identify and correct any problems prior to the productive use or
- commercial release of any products that use the Program, and prior to
- the release of any modifications, updates or enhancements thereto.
-
- EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
- PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
- WARRANTIES OR CONDITIONS OF TITLE, NON- INFRINGEMENT, MERCHANTABILITY
- OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
- responsible for determining the appropriateness of using and
- distributing the Program and assumes all risks associated with its
- exercise of rights under this Agreement, including but not limited to
- the risks and costs of program errors, compliance with applicable
- laws, damage to or loss of data, programs or equipment, and
- unavailability or interruption of operations.
-
- 6. DISCLAIMER OF LIABILITY
-
- EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR
- ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
- WITHOUT LIMITATION LOST PROFITS), 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 OR
- DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-
- 7. GENERAL
-
- If any provision of this Agreement is invalid or unenforceable under
- applicable law, it shall not affect the validity or enforceability of
- the remainder of the terms of this Agreement, and without further
- action by the parties hereto, such provision shall be reformed to the
- minimum extent necessary to make such provision valid and enforceable.
-
- If Recipient institutes patent litigation against a Contributor with
- respect to a patent applicable to software (including a cross-claim or
- counterclaim in a lawsuit), then any patent licenses granted by that
- Contributor to such recipient under this Agreement shall terminate as
- of the date such litigation is filed. In addition, If Recipient
- institutes patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Program
- itself (excluding combinations of the Program with other software or
- hardware) infringes such Recipient's patent(s), then such Recipient's
- rights granted under Section 2(b) shall terminate as of the date such
- litigation is filed.
-
- All Recipient's rights under this Agreement shall terminate if it
- fails to comply with any of the material terms or conditions of this
- Agreement and does not cure such failure in a reasonable period of
- time after becoming aware of such noncompliance. If all Recipient's
- rights under this Agreement terminate, Recipient agrees to cease use
- and distribution of the Program as soon as reasonably practicable.
- However, Recipient's obligations under this Agreement and any licenses
- granted by Recipient relating to the Program shall continue and
- survive.
-
- QSS may publish new versions (including revisions) of this Agreement
- from time to time. Each new version of the Agreement will be given a
- distinguishing version number. The Program (including Contributions)
- may always be distributed subject to the version of the Agreement
- under which it was received. In addition, after a new version of the
- Agreement is published, Contributor may elect to distribute the
- Program (including its Contributions) under the new version. No one
- other than QSS has the right to modify this Agreement. Except as
- expressly stated in Sections 2(a) and 2(b) above, Recipient receives
- no rights or licenses to the intellectual property of any Contributor
- under this Agreement, whether expressly, by implication, estoppel or
- otherwise. All rights in the Program not expressly granted under this
- Agreement are reserved.
-
- This Agreement is governed by the laws in force in the Province of
- Ontario, Canada without regard to the conflict of law provisions
- therein. The parties expressly disclaim the provisions of the United
- Nations Convention on Contracts for the International Sale of Goods.
- No party to this Agreement will bring a legal action under this
- Agreement more than one year after the cause of action arose. Each
- party waives its rights to a jury trial in any resulting litigation.
-
- * QNX is a registered trademark of QNX Software Systems Ltd.
-
- Document Version: ocl1_00
diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c
index e8e543a..b392397 100644
--- a/sys/contrib/ipfilter/netinet/fil.c
+++ b/sys/contrib/ipfilter/netinet/fil.c
@@ -1,9 +1,14 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1993-2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Copyright 2008 Sun Microsystems.
+ *
+ * $Id$
+ *
*/
#if defined(KERNEL) || defined(_KERNEL)
# undef KERNEL
@@ -15,15 +20,6 @@
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
-#if defined(__NetBSD__)
-# if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL)
-# if (__NetBSD_Version__ < 301000000)
-# include "opt_ipfilter_log.h"
-# else
-# include "opt_ipfilter.h"
-# endif
-# endif
-#endif
#if defined(_KERNEL) && defined(__FreeBSD_version) && \
(__FreeBSD_version >= 220000)
# if (__FreeBSD_version >= 400000)
@@ -82,23 +78,9 @@ struct file;
#ifdef sun
# include <net/af.h>
#endif
-#if !defined(_KERNEL) && (defined(__FreeBSD__) || defined(SOLARIS2))
-# if (__FreeBSD_version >= 504000)
-# undef _RADIX_H_
-# endif
-# include "radix_ipf.h"
-#endif
-#ifdef __osf__
-# include "radix_ipf.h"
-#else
-# include <net/route.h>
-#endif
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
-#if !defined(linux)
-# include <netinet/ip_var.h>
-#endif
#if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */
# include <sys/hashing.h>
# include <netinet/in_var.h>
@@ -121,7 +103,6 @@ struct file;
# include <netinet6/in6_var.h>
# endif
#endif
-#include <netinet/tcpip.h>
#include "netinet/ip_fil.h"
#include "netinet/ip_nat.h"
#include "netinet/ip_frag.h"
@@ -131,9 +112,8 @@ struct file;
#ifdef IPFILTER_SCAN
# include "netinet/ip_scan.h"
#endif
-#ifdef IPFILTER_SYNC
-# include "netinet/ip_sync.h"
-#endif
+#include "netinet/ip_sync.h"
+#include "netinet/ip_lookup.h"
#include "netinet/ip_pool.h"
#include "netinet/ip_htable.h"
#ifdef IPFILTER_COMPILED
@@ -144,14 +124,18 @@ struct file;
#endif
#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
# include <sys/malloc.h>
-# if defined(_KERNEL) && !defined(IPFILTER_LKM)
-# include "opt_ipfilter.h"
-# endif
#endif
#include "netinet/ipl.h"
-/* END OF INCLUDES */
-#include <machine/in_cksum.h>
+#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
+# include <sys/callout.h>
+extern struct callout ipf_slowtimer_ch;
+#endif
+#if defined(__OpenBSD__)
+# include <sys/timeout.h>
+extern struct timeout ipf_slowtimer_ch;
+#endif
+/* END OF INCLUDES */
#if !defined(lint)
static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed";
@@ -162,101 +146,80 @@ static const char rcsid[] = "@(#)$FreeBSD$";
#ifndef _KERNEL
# include "ipf.h"
# include "ipt.h"
-# include "bpf-ipf.h"
extern int opts;
+extern int blockreason;
#endif /* _KERNEL */
+#define LBUMP(x) softc->x++
+#define LBUMPD(x, y) do { softc->x.y++; DT(y); } while (0)
-fr_info_t frcache[2][8];
-struct filterstats frstats[2];
-struct frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } },
- *ipfilter6[2][2] = { { NULL, NULL }, { NULL, NULL } },
- *ipacct6[2][2] = { { NULL, NULL }, { NULL, NULL } },
- *ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } },
- *ipnatrules[2][2] = { { NULL, NULL }, { NULL, NULL } };
-struct frgroup *ipfgroups[IPL_LOGSIZE][2];
-char ipfilter_version[] = IPL_VERSION;
-int fr_refcnt = 0;
-/*
- * For fr_running:
- * 0 == loading, 1 = running, -1 = disabled, -2 = unloading
- */
-int fr_running = 0;
-int fr_flags = IPF_LOGGING;
-int fr_active = 0;
-int fr_control_forwarding = 0;
-int fr_update_ipid = 0;
-u_short fr_ip_id = 0;
-int fr_chksrc = 0; /* causes a system crash if enabled */
-int fr_minttl = 4;
-int fr_icmpminfragmtu = 68;
-u_long fr_frouteok[2] = {0, 0};
-u_long fr_userifqs = 0;
-u_long fr_badcoalesces[2] = {0, 0};
-u_char ipf_iss_secret[32];
-#if defined(IPFILTER_DEFAULT_BLOCK)
-int fr_pass = FR_BLOCK|FR_NOMATCH;
-#else
-int fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH;
-#endif
-int fr_features = 0
-#ifdef IPFILTER_LKM
- | IPF_FEAT_LKM
-#endif
-#ifdef IPFILTER_LOG
- | IPF_FEAT_LOG
-#endif
-#ifdef IPFILTER_LOOKUP
- | IPF_FEAT_LOOKUP
-#endif
-#ifdef IPFILTER_BPF
- | IPF_FEAT_BPF
-#endif
-#ifdef IPFILTER_COMPILED
- | IPF_FEAT_COMPILED
-#endif
-#ifdef IPFILTER_CKSUM
- | IPF_FEAT_CKSUM
-#endif
-#ifdef IPFILTER_SYNC
- | IPF_FEAT_SYNC
-#endif
-#ifdef IPFILTER_SCAN
- | IPF_FEAT_SCAN
-#endif
-#ifdef USE_INET6
- | IPF_FEAT_IPV6
+static INLINE int ipf_check_ipf __P((fr_info_t *, frentry_t *, int));
+static u_32_t ipf_checkcipso __P((fr_info_t *, u_char *, int));
+static u_32_t ipf_checkripso __P((u_char *));
+static u_32_t ipf_decaps __P((fr_info_t *, u_32_t, int));
+#ifdef IPFILTER_LOG
+static frentry_t *ipf_dolog __P((fr_info_t *, u_32_t *));
#endif
- ;
-
-static INLINE int fr_ipfcheck __P((fr_info_t *, frentry_t *, int));
-static int fr_portcheck __P((frpcmp_t *, u_short *));
-static int frflushlist __P((int, minor_t, int *, frentry_t **));
-static ipfunc_t fr_findfunc __P((ipfunc_t));
-static frentry_t *fr_firewall __P((fr_info_t *, u_32_t *));
-static int fr_funcinit __P((frentry_t *fr));
-static INLINE void frpr_ah __P((fr_info_t *));
-static INLINE void frpr_esp __P((fr_info_t *));
-static INLINE void frpr_gre __P((fr_info_t *));
-static INLINE void frpr_udp __P((fr_info_t *));
-static INLINE void frpr_tcp __P((fr_info_t *));
-static INLINE void frpr_icmp __P((fr_info_t *));
-static INLINE void frpr_ipv4hdr __P((fr_info_t *));
-static INLINE int frpr_pullup __P((fr_info_t *, int));
-static INLINE void frpr_short __P((fr_info_t *, int));
-static INLINE int frpr_tcpcommon __P((fr_info_t *));
-static INLINE int frpr_udpcommon __P((fr_info_t *));
-static int fr_updateipid __P((fr_info_t *));
-#ifdef IPFILTER_LOOKUP
-static int fr_grpmapinit __P((frentry_t *fr));
-static INLINE void *fr_resolvelookup __P((u_int, u_int, i6addr_t *, lookupfunc_t *));
+static int ipf_flushlist __P((ipf_main_softc_t *, int *,
+ frentry_t **));
+static int ipf_flush_groups __P((ipf_main_softc_t *, frgroup_t **,
+ int));
+static ipfunc_t ipf_findfunc __P((ipfunc_t));
+static void *ipf_findlookup __P((ipf_main_softc_t *, int,
+ frentry_t *,
+ i6addr_t *, i6addr_t *));
+static frentry_t *ipf_firewall __P((fr_info_t *, u_32_t *));
+static int ipf_fr_matcharray __P((fr_info_t *, int *));
+static int ipf_frruleiter __P((ipf_main_softc_t *, void *, int,
+ void *));
+static void ipf_funcfini __P((ipf_main_softc_t *, frentry_t *));
+static int ipf_funcinit __P((ipf_main_softc_t *, frentry_t *));
+static int ipf_geniter __P((ipf_main_softc_t *, ipftoken_t *,
+ ipfgeniter_t *));
+static void ipf_getstat __P((ipf_main_softc_t *,
+ struct friostat *, int));
+static int ipf_group_flush __P((ipf_main_softc_t *, frgroup_t *));
+static void ipf_group_free __P((frgroup_t *));
+static int ipf_grpmapfini __P((struct ipf_main_softc_s *,
+ frentry_t *));
+static int ipf_grpmapinit __P((struct ipf_main_softc_s *,
+ frentry_t *));
+static frentry_t *ipf_nextrule __P((ipf_main_softc_t *, int, int,
+ frentry_t *, int));
+static int ipf_portcheck __P((frpcmp_t *, u_32_t));
+static INLINE int ipf_pr_ah __P((fr_info_t *));
+static INLINE void ipf_pr_esp __P((fr_info_t *));
+static INLINE void ipf_pr_gre __P((fr_info_t *));
+static INLINE void ipf_pr_udp __P((fr_info_t *));
+static INLINE void ipf_pr_tcp __P((fr_info_t *));
+static INLINE void ipf_pr_icmp __P((fr_info_t *));
+static INLINE void ipf_pr_ipv4hdr __P((fr_info_t *));
+static INLINE void ipf_pr_short __P((fr_info_t *, int));
+static INLINE int ipf_pr_tcpcommon __P((fr_info_t *));
+static INLINE int ipf_pr_udpcommon __P((fr_info_t *));
+static void ipf_rule_delete __P((ipf_main_softc_t *, frentry_t *f,
+ int, int));
+static void ipf_rule_expire_insert __P((ipf_main_softc_t *,
+ frentry_t *, int));
+static int ipf_synclist __P((ipf_main_softc_t *, frentry_t *,
+ void *));
+static void ipf_token_flush __P((ipf_main_softc_t *));
+static void ipf_token_unlink __P((ipf_main_softc_t *,
+ ipftoken_t *));
+static ipftuneable_t *ipf_tune_findbyname __P((ipftuneable_t *,
+ const char *));
+static ipftuneable_t *ipf_tune_findbycookie __P((ipftuneable_t **, void *,
+ void **));
+static int ipf_updateipid __P((fr_info_t *));
+static int ipf_settimeout __P((struct ipf_main_softc_s *,
+ struct ipftuneable *,
+ ipftuneval_t *));
+#if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && \
+ !defined(__FreeBSD__)) || \
+ FREEBSD_LT_REV(501000) || NETBSD_LT_REV(105000000) || \
+ OPENBSD_LT_REV(200006)
+static int ppsratecheck(struct timeval *, int *, int);
#endif
-static void frsynclist __P((frentry_t *, void *));
-static ipftuneable_t *fr_findtunebyname __P((const char *));
-static ipftuneable_t *fr_findtunebycookie __P((void *, void **));
-static int ipf_geniter __P((ipftoken_t *, ipfgeniter_t *));
-static int ipf_frruleiter __P((void *, int, void *));
-static void ipf_unlinktoken __P((ipftoken_t *));
/*
@@ -265,7 +228,7 @@ static void ipf_unlinktoken __P((ipftoken_t *));
* hand side to allow for binary searching of the array and include a trailer
* with a 0 for the bitmask for linear searches to easily find the end with.
*/
-const struct optlist ipopts[20] = {
+static const struct optlist ipopts[20] = {
{ IPOPT_NOP, 0x000001 },
{ IPOPT_RR, 0x000002 },
{ IPOPT_ZSU, 0x000004 },
@@ -289,7 +252,7 @@ const struct optlist ipopts[20] = {
};
#ifdef USE_INET6
-struct optlist ip6exthdr[] = {
+static struct optlist ip6exthdr[] = {
{ IPPROTO_HOPOPTS, 0x000001 },
{ IPPROTO_IPV6, 0x000002 },
{ IPPROTO_ROUTING, 0x000004 },
@@ -303,20 +266,10 @@ struct optlist ip6exthdr[] = {
};
#endif
-struct optlist tcpopts[] = {
- { TCPOPT_NOP, 0x000001 },
- { TCPOPT_MAXSEG, 0x000002 },
- { TCPOPT_WINDOW, 0x000004 },
- { TCPOPT_SACK_PERMITTED, 0x000008 },
- { TCPOPT_SACK, 0x000010 },
- { TCPOPT_TIMESTAMP, 0x000020 },
- { 0, 0x000000 }
-};
-
/*
* bit values for identifying presence of individual IP security options
*/
-const struct optlist secopt[8] = {
+static const struct optlist secopt[8] = {
{ IPSO_CLASS_RES4, 0x01 },
{ IPSO_CLASS_TOPS, 0x02 },
{ IPSO_CLASS_SECR, 0x04 },
@@ -327,16 +280,143 @@ const struct optlist secopt[8] = {
{ IPSO_CLASS_RES1, 0x80 }
};
+char ipfilter_version[] = IPL_VERSION;
+
+int ipf_features = 0
+#ifdef IPFILTER_LKM
+ | IPF_FEAT_LKM
+#endif
+#ifdef IPFILTER_LOG
+ | IPF_FEAT_LOG
+#endif
+ | IPF_FEAT_LOOKUP
+#ifdef IPFILTER_BPF
+ | IPF_FEAT_BPF
+#endif
+#ifdef IPFILTER_COMPILED
+ | IPF_FEAT_COMPILED
+#endif
+#ifdef IPFILTER_CKSUM
+ | IPF_FEAT_CKSUM
+#endif
+ | IPF_FEAT_SYNC
+#ifdef IPFILTER_SCAN
+ | IPF_FEAT_SCAN
+#endif
+#ifdef USE_INET6
+ | IPF_FEAT_IPV6
+#endif
+ ;
+
/*
* Table of functions available for use with call rules.
*/
-static ipfunc_resolve_t fr_availfuncs[] = {
-#ifdef IPFILTER_LOOKUP
- { "fr_srcgrpmap", fr_srcgrpmap, fr_grpmapinit },
- { "fr_dstgrpmap", fr_dstgrpmap, fr_grpmapinit },
+static ipfunc_resolve_t ipf_availfuncs[] = {
+ { "srcgrpmap", ipf_srcgrpmap, ipf_grpmapinit, ipf_grpmapfini },
+ { "dstgrpmap", ipf_dstgrpmap, ipf_grpmapinit, ipf_grpmapfini },
+ { "", NULL, NULL, NULL }
+};
+
+static ipftuneable_t ipf_main_tuneables[] = {
+ { { (void *)offsetof(struct ipf_main_softc_s, ipf_flags) },
+ "ipf_flags", 0, 0xffffffff,
+ stsizeof(ipf_main_softc_t, ipf_flags),
+ 0, NULL, NULL },
+ { { (void *)offsetof(struct ipf_main_softc_s, ipf_active) },
+ "active", 0, 0,
+ stsizeof(ipf_main_softc_t, ipf_active),
+ IPFT_RDONLY, NULL, NULL },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_control_forwarding) },
+ "control_forwarding", 0, 1,
+ stsizeof(ipf_main_softc_t, ipf_control_forwarding),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_update_ipid) },
+ "update_ipid", 0, 1,
+ stsizeof(ipf_main_softc_t, ipf_update_ipid),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_chksrc) },
+ "chksrc", 0, 1,
+ stsizeof(ipf_main_softc_t, ipf_chksrc),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_minttl) },
+ "min_ttl", 0, 1,
+ stsizeof(ipf_main_softc_t, ipf_minttl),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_icmpminfragmtu) },
+ "icmp_minfragmtu", 0, 1,
+ stsizeof(ipf_main_softc_t, ipf_icmpminfragmtu),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_pass) },
+ "default_pass", 0, 0xffffffff,
+ stsizeof(ipf_main_softc_t, ipf_pass),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcpidletimeout) },
+ "tcp_idle_timeout", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcpidletimeout),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosewait) },
+ "tcp_close_wait", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcpclosewait),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcplastack) },
+ "tcp_last_ack", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcplastack),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimeout) },
+ "tcp_timeout", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcptimeout),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynsent) },
+ "tcp_syn_sent", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcpsynsent),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynrecv) },
+ "tcp_syn_received", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcpsynrecv),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosed) },
+ "tcp_closed", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcpclosed),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcphalfclosed) },
+ "tcp_half_closed", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcphalfclosed),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimewait) },
+ "tcp_time_wait", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcptimewait),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_udptimeout) },
+ "udp_timeout", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_udptimeout),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_udpacktimeout) },
+ "udp_ack_timeout", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_udpacktimeout),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_icmptimeout) },
+ "icmp_timeout", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_icmptimeout),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_icmpacktimeout) },
+ "icmp_ack_timeout", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_icmpacktimeout),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_iptimeout) },
+ "ip_timeout", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_iptimeout),
+ 0, NULL, ipf_settimeout },
+#if defined(INSTANCES) && defined(_KERNEL)
+ { { (void *)offsetof(ipf_main_softc_t, ipf_get_loopback) },
+ "intercept_loopback", 0, 1,
+ stsizeof(ipf_main_softc_t, ipf_get_loopback),
+ 0, NULL, ipf_set_loopback },
#endif
- { "", NULL, NULL }
+ { { 0 },
+ NULL, 0, 0,
+ 0,
+ 0, NULL, NULL }
};
@@ -346,39 +426,41 @@ static ipfunc_resolve_t fr_availfuncs[] = {
* current packet. There are different routines for the same protocol
* for each of IPv4 and IPv6. Adding a new protocol, for which there
* will "special" inspection for setup, is now more easily done by adding
- * a new routine and expanding the frpr_ipinit*() function rather than by
+ * a new routine and expanding the ipf_pr_ipinit*() function rather than by
* adding more code to a growing switch statement.
*/
#ifdef USE_INET6
-static INLINE int frpr_ah6 __P((fr_info_t *));
-static INLINE void frpr_esp6 __P((fr_info_t *));
-static INLINE void frpr_gre6 __P((fr_info_t *));
-static INLINE void frpr_udp6 __P((fr_info_t *));
-static INLINE void frpr_tcp6 __P((fr_info_t *));
-static INLINE void frpr_icmp6 __P((fr_info_t *));
-static INLINE int frpr_ipv6hdr __P((fr_info_t *));
-static INLINE void frpr_short6 __P((fr_info_t *, int));
-static INLINE int frpr_hopopts6 __P((fr_info_t *));
-static INLINE int frpr_mobility6 __P((fr_info_t *));
-static INLINE int frpr_routing6 __P((fr_info_t *));
-static INLINE int frpr_dstopts6 __P((fr_info_t *));
-static INLINE int frpr_fragment6 __P((fr_info_t *));
-static INLINE int frpr_ipv6exthdr __P((fr_info_t *, int, int));
-
-
-/* ------------------------------------------------------------------------ */
-/* Function: frpr_short6 */
+static INLINE int ipf_pr_ah6 __P((fr_info_t *));
+static INLINE void ipf_pr_esp6 __P((fr_info_t *));
+static INLINE void ipf_pr_gre6 __P((fr_info_t *));
+static INLINE void ipf_pr_udp6 __P((fr_info_t *));
+static INLINE void ipf_pr_tcp6 __P((fr_info_t *));
+static INLINE void ipf_pr_icmp6 __P((fr_info_t *));
+static INLINE void ipf_pr_ipv6hdr __P((fr_info_t *));
+static INLINE void ipf_pr_short6 __P((fr_info_t *, int));
+static INLINE int ipf_pr_hopopts6 __P((fr_info_t *));
+static INLINE int ipf_pr_mobility6 __P((fr_info_t *));
+static INLINE int ipf_pr_routing6 __P((fr_info_t *));
+static INLINE int ipf_pr_dstopts6 __P((fr_info_t *));
+static INLINE int ipf_pr_fragment6 __P((fr_info_t *));
+static INLINE struct ip6_ext *ipf_pr_ipv6exthdr __P((fr_info_t *, int, int));
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_pr_short6 */
/* Returns: void */
-/* Parameters: fin(I) - pointer to packet information */
+/* Parameters: fin(I) - pointer to packet information */
+/* xmin(I) - minimum header size */
/* */
/* IPv6 Only */
/* This is function enforces the 'is a packet too short to be legit' rule */
/* for IPv6 and marks the packet with FI_SHORT if so. See function comment */
-/* for frpr_short() for more details. */
+/* for ipf_pr_short() for more details. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_short6(fin, xmin)
-fr_info_t *fin;
-int xmin;
+static INLINE void
+ipf_pr_short6(fin, xmin)
+ fr_info_t *fin;
+ int xmin;
{
if (fin->fin_dlen < xmin)
@@ -387,8 +469,8 @@ int xmin;
/* ------------------------------------------------------------------------ */
-/* Function: frpr_ipv6hdr */
-/* Returns: int - 0 = IPv6 packet intact, -1 = packet lost */
+/* Function: ipf_pr_ipv6hdr */
+/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* IPv6 Only */
@@ -397,8 +479,9 @@ int xmin;
/* analyzer may pullup or free the packet itself so we need to be vigiliant */
/* of that possibility arising. */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_ipv6hdr(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_ipv6hdr(fin)
+ fr_info_t *fin;
{
ip6_t *ip6 = (ip6_t *)fin->fin_ip;
int p, go = 1, i, hdrcount;
@@ -412,57 +495,68 @@ fr_info_t *fin;
fi->fi_auth = 0;
p = ip6->ip6_nxt;
+ fin->fin_crc = p;
fi->fi_ttl = ip6->ip6_hlim;
fi->fi_src.in6 = ip6->ip6_src;
+ fin->fin_crc += fi->fi_src.i6[0];
+ fin->fin_crc += fi->fi_src.i6[1];
+ fin->fin_crc += fi->fi_src.i6[2];
+ fin->fin_crc += fi->fi_src.i6[3];
fi->fi_dst.in6 = ip6->ip6_dst;
- fin->fin_id = (u_short)(ip6->ip6_flow & 0xffff);
+ fin->fin_crc += fi->fi_dst.i6[0];
+ fin->fin_crc += fi->fi_dst.i6[1];
+ fin->fin_crc += fi->fi_dst.i6[2];
+ fin->fin_crc += fi->fi_dst.i6[3];
+ fin->fin_id = 0;
+ if (IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6))
+ fin->fin_flx |= FI_MULTICAST|FI_MBCAST;
hdrcount = 0;
- while (go && !(fin->fin_flx & (FI_BAD|FI_SHORT))) {
+ while (go && !(fin->fin_flx & FI_SHORT)) {
switch (p)
{
case IPPROTO_UDP :
- frpr_udp6(fin);
+ ipf_pr_udp6(fin);
go = 0;
break;
case IPPROTO_TCP :
- frpr_tcp6(fin);
+ ipf_pr_tcp6(fin);
go = 0;
break;
case IPPROTO_ICMPV6 :
- frpr_icmp6(fin);
+ ipf_pr_icmp6(fin);
go = 0;
break;
case IPPROTO_GRE :
- frpr_gre6(fin);
+ ipf_pr_gre6(fin);
go = 0;
break;
case IPPROTO_HOPOPTS :
- p = frpr_hopopts6(fin);
+ p = ipf_pr_hopopts6(fin);
break;
case IPPROTO_MOBILITY :
- p = frpr_mobility6(fin);
+ p = ipf_pr_mobility6(fin);
break;
case IPPROTO_DSTOPTS :
- p = frpr_dstopts6(fin);
+ p = ipf_pr_dstopts6(fin);
break;
case IPPROTO_ROUTING :
- p = frpr_routing6(fin);
+ p = ipf_pr_routing6(fin);
break;
case IPPROTO_AH :
- p = frpr_ah6(fin);
+ p = ipf_pr_ah6(fin);
break;
case IPPROTO_ESP :
- frpr_esp6(fin);
+ ipf_pr_esp6(fin);
go = 0;
break;
@@ -480,7 +574,13 @@ fr_info_t *fin;
break;
case IPPROTO_FRAGMENT :
- p = frpr_fragment6(fin);
+ p = ipf_pr_fragment6(fin);
+ /*
+ * Given that the only fragments we want to let through
+ * (where fin_off != 0) are those where the non-first
+ * fragments only have data, we can safely stop looking
+ * at headers if this is a non-leading fragment.
+ */
if (fin->fin_off != 0)
go = 0;
break;
@@ -501,39 +601,61 @@ fr_info_t *fin;
* header.
*/
if ((go != 0) && (p != IPPROTO_NONE) &&
- (frpr_pullup(fin, 0) == -1)) {
+ (ipf_pr_pullup(fin, 0) == -1)) {
p = IPPROTO_NONE;
- go = 0;
+ break;
}
}
- fi->fi_p = p;
/*
- * Some of the above functions, like frpr_esp6(), can call fr_pullup
+ * Some of the above functions, like ipf_pr_esp6(), can call ipf_pullup
* and destroy whatever packet was here. The caller of this function
- * expects us to return -1 if there is a problem with fr_pullup.
+ * expects us to return if there is a problem with ipf_pullup.
*/
- if (fin->fin_m == NULL)
- return -1;
+ if (fin->fin_m == NULL) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
- return 0;
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_bad);
+ return;
+ }
+
+ fi->fi_p = p;
+
+ /*
+ * IPv6 fragment case 1 - see comment for ipf_pr_fragment6().
+ * "go != 0" imples the above loop hasn't arrived at a layer 4 header.
+ */
+ if ((go != 0) && (fin->fin_flx & FI_FRAG) && (fin->fin_off == 0)) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+
+ fin->fin_flx |= FI_BAD;
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_badfrag);
+ LBUMP(ipf_stats[fin->fin_out].fr_v6_bad);
+ }
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_ipv6exthdr */
-/* Returns: int - value of the next header or IPPROTO_NONE if error */
+/* Function: ipf_pr_ipv6exthdr */
+/* Returns: struct ip6_ext * - pointer to the start of the next header */
+/* or NULL if there is a prolblem. */
/* Parameters: fin(I) - pointer to packet information */
/* multiple(I) - flag indicating yes/no if multiple occurances */
/* of this extension header are allowed. */
/* proto(I) - protocol number for this extension header */
/* */
/* IPv6 Only */
-/* ------------------------------------------------------------------------ */
-static INLINE int frpr_ipv6exthdr(fin, multiple, proto)
-fr_info_t *fin;
-int multiple, proto;
+/* This function embodies a number of common checks that all IPv6 extension */
+/* headers must be subjected to. For example, making sure the packet is */
+/* big enough for it to be in, checking if it is repeated and setting a */
+/* flag to indicate its presence. */
+/* ------------------------------------------------------------------------ */
+static INLINE struct ip6_ext *
+ipf_pr_ipv6exthdr(fin, multiple, proto)
+ fr_info_t *fin;
+ int multiple, proto;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
struct ip6_ext *hdr;
u_short shift;
int i;
@@ -543,11 +665,14 @@ int multiple, proto;
/* 8 is default length of extension hdr */
if ((fin->fin_dlen - 8) < 0) {
fin->fin_flx |= FI_SHORT;
- return IPPROTO_NONE;
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_short);
+ return NULL;
}
- if (frpr_pullup(fin, 8) == -1)
- return IPPROTO_NONE;
+ if (ipf_pr_pullup(fin, 8) == -1) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_pullup);
+ return NULL;
+ }
hdr = fin->fin_dp;
switch (proto)
@@ -562,9 +687,21 @@ int multiple, proto;
if (shift > fin->fin_dlen) { /* Nasty extension header length? */
fin->fin_flx |= FI_BAD;
- return IPPROTO_NONE;
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_hlen);
+ return NULL;
}
+ fin->fin_dp = (char *)fin->fin_dp + shift;
+ fin->fin_dlen -= shift;
+
+ /*
+ * If we have seen a fragment header, do not set any flags to indicate
+ * the presence of this extension header as it has no impact on the
+ * end result until after it has been defragmented.
+ */
+ if (fin->fin_flx & FI_FRAG)
+ return hdr;
+
for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
if (ip6exthdr[i].ol_val == proto) {
/*
@@ -578,149 +715,196 @@ int multiple, proto;
break;
}
- fin->fin_exthdr = fin->fin_dp;
- fin->fin_dp = (char *)fin->fin_dp + shift;
- fin->fin_dlen -= shift;
-
- return hdr->ip6e_nxt;
+ return hdr;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_hopopts6 */
+/* Function: ipf_pr_hopopts6 */
/* Returns: int - value of the next header or IPPROTO_NONE if error */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* IPv6 Only */
/* This is function checks pending hop by hop options extension header */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_hopopts6(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_hopopts6(fin)
+ fr_info_t *fin;
{
- return frpr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
+ struct ip6_ext *hdr;
+
+ hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
+ if (hdr == NULL)
+ return IPPROTO_NONE;
+ return hdr->ip6e_nxt;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_mobility6 */
+/* Function: ipf_pr_mobility6 */
/* Returns: int - value of the next header or IPPROTO_NONE if error */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* IPv6 Only */
/* This is function checks the IPv6 mobility extension header */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_mobility6(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_mobility6(fin)
+ fr_info_t *fin;
{
- return frpr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY);
+ struct ip6_ext *hdr;
+
+ hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY);
+ if (hdr == NULL)
+ return IPPROTO_NONE;
+ return hdr->ip6e_nxt;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_routing6 */
+/* Function: ipf_pr_routing6 */
/* Returns: int - value of the next header or IPPROTO_NONE if error */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* IPv6 Only */
/* This is function checks pending routing extension header */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_routing6(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_routing6(fin)
+ fr_info_t *fin;
{
- struct ip6_ext *hdr;
+ struct ip6_routing *hdr;
- if (frpr_ipv6exthdr(fin, 0, IPPROTO_ROUTING) == IPPROTO_NONE)
+ hdr = (struct ip6_routing *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_ROUTING);
+ if (hdr == NULL)
return IPPROTO_NONE;
- hdr = fin->fin_exthdr;
- if ((hdr->ip6e_len & 1) != 0) {
- /*
- * The routing header data is made up of 128 bit IPv6 addresses
- * which means it must be a multiple of 2 lots of 8 in length.
- */
- fin->fin_flx |= FI_BAD;
+ switch (hdr->ip6r_type)
+ {
+ case 0 :
/*
- * Compensate for the changes made in frpr_ipv6exthdr()
+ * Nasty extension header length?
*/
- fin->fin_dlen += 8 + (hdr->ip6e_len << 3);
- fin->fin_dp = hdr;
- return IPPROTO_NONE;
+ if (((hdr->ip6r_len >> 1) < hdr->ip6r_segleft) ||
+ (hdr->ip6r_segleft && (hdr->ip6r_len & 1))) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+
+ fin->fin_flx |= FI_BAD;
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_rh_bad);
+ return IPPROTO_NONE;
+ }
+ break;
+
+ default :
+ break;
}
- return hdr->ip6e_nxt;
+ return hdr->ip6r_nxt;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_fragment6 */
+/* Function: ipf_pr_fragment6 */
/* Returns: int - value of the next header or IPPROTO_NONE if error */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* IPv6 Only */
/* Examine the IPv6 fragment header and extract fragment offset information.*/
/* */
-/* We don't know where the transport layer header (or whatever is next is), */
-/* as it could be behind destination options (amongst others). Because */
-/* there is no fragment cache, there is no knowledge about whether or not an*/
-/* upper layer header has been seen (or where it ends) and thus we are not */
-/* able to continue processing beyond this header with any confidence. */
-/* ------------------------------------------------------------------------ */
-static INLINE int frpr_fragment6(fin)
-fr_info_t *fin;
+/* Fragments in IPv6 are extraordinarily difficult to deal with - much more */
+/* so than in IPv4. There are 5 cases of fragments with IPv6 that all */
+/* packets with a fragment header can fit into. They are as follows: */
+/* */
+/* 1. [IPv6][0-n EH][FH][0-n EH] (no L4HDR present) */
+/* 2. [IPV6][0-n EH][FH][0-n EH][L4HDR part] (short) */
+/* 3. [IPV6][0-n EH][FH][L4HDR part][0-n data] (short) */
+/* 4. [IPV6][0-n EH][FH][0-n EH][L4HDR][0-n data] */
+/* 5. [IPV6][0-n EH][FH][data] */
+/* */
+/* IPV6 = IPv6 header, FH = Fragment Header, */
+/* 0-n EH = 0 or more extension headers, 0-n data = 0 or more bytes of data */
+/* */
+/* Packets that match 1, 2, 3 will be dropped as the only reasonable */
+/* scenario in which they happen is in extreme circumstances that are most */
+/* likely to be an indication of an attack rather than normal traffic. */
+/* A type 3 packet may be sent by an attacked after a type 4 packet. There */
+/* are two rules that can be used to guard against type 3 packets: L4 */
+/* headers must always be in a packet that has the offset field set to 0 */
+/* and no packet is allowed to overlay that where offset = 0. */
+/* ------------------------------------------------------------------------ */
+static INLINE int
+ipf_pr_fragment6(fin)
+ fr_info_t *fin;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
struct ip6_frag *frag;
- int extoff;
fin->fin_flx |= FI_FRAG;
- if (frpr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT) == IPPROTO_NONE)
- return IPPROTO_NONE;
-
- extoff = (char *)fin->fin_exthdr - (char *)fin->fin_dp;
-
- if (frpr_pullup(fin, sizeof(*frag)) == -1)
+ frag = (struct ip6_frag *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT);
+ if (frag == NULL) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_frag_bad);
return IPPROTO_NONE;
+ }
- fin->fin_exthdr = (char *)fin->fin_dp + extoff;
- frag = fin->fin_exthdr;
- /*
- * Fragment but no fragmentation info set? Bad packet...
- */
- if (frag->ip6f_offlg == 0) {
- fin->fin_flx |= FI_BAD;
- return IPPROTO_NONE;
+ if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0) {
+ /*
+ * Any fragment that isn't the last fragment must have its
+ * length as a multiple of 8.
+ */
+ if ((fin->fin_plen & 7) != 0)
+ fin->fin_flx |= FI_BAD;
}
+ fin->fin_fraghdr = frag;
+ fin->fin_id = frag->ip6f_ident;
fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK);
- fin->fin_off <<= 3;
if (fin->fin_off != 0)
fin->fin_flx |= FI_FRAGBODY;
- fin->fin_dp = (char *)fin->fin_dp + sizeof(*frag);
- fin->fin_dlen -= sizeof(*frag);
+ /*
+ * Jumbograms aren't handled, so the max. length is 64k
+ */
+ if ((fin->fin_off << 3) + fin->fin_dlen > 65535)
+ fin->fin_flx |= FI_BAD;
+ /*
+ * We don't know where the transport layer header (or whatever is next
+ * is), as it could be behind destination options (amongst others) so
+ * return the fragment header as the type of packet this is. Note that
+ * this effectively disables the fragment cache for > 1 protocol at a
+ * time.
+ */
return frag->ip6f_nxt;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_dstopts6 */
+/* Function: ipf_pr_dstopts6 */
/* Returns: int - value of the next header or IPPROTO_NONE if error */
/* Parameters: fin(I) - pointer to packet information */
-/* nextheader(I) - stores next header value */
/* */
/* IPv6 Only */
/* This is function checks pending destination options extension header */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_dstopts6(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_dstopts6(fin)
+ fr_info_t *fin;
{
- return frpr_ipv6exthdr(fin, 1, IPPROTO_DSTOPTS);
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ struct ip6_ext *hdr;
+
+ hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_DSTOPTS);
+ if (hdr == NULL) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_dst_bad);
+ return IPPROTO_NONE;
+ }
+ return hdr->ip6e_nxt;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_icmp6 */
+/* Function: ipf_pr_icmp6 */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -728,14 +912,19 @@ fr_info_t *fin;
/* This routine is mainly concerned with determining the minimum valid size */
/* for an ICMPv6 packet. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_icmp6(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_icmp6(fin)
+ fr_info_t *fin;
{
int minicmpsz = sizeof(struct icmp6_hdr);
struct icmp6_hdr *icmp6;
- if (frpr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1)
+ if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_icmp6_pullup);
return;
+ }
if (fin->fin_dlen > 1) {
ip6_t *ip6;
@@ -744,12 +933,18 @@ fr_info_t *fin;
fin->fin_data[0] = *(u_short *)icmp6;
+ if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0)
+ fin->fin_flx |= FI_ICMPQUERY;
+
switch (icmp6->icmp6_type)
{
case ICMP6_ECHO_REPLY :
case ICMP6_ECHO_REQUEST :
+ if (fin->fin_dlen >= 6)
+ fin->fin_data[1] = icmp6->icmp6_id;
minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t);
break;
+
case ICMP6_DST_UNREACH :
case ICMP6_PACKET_TOO_BIG :
case ICMP6_TIME_EXCEEDED :
@@ -760,10 +955,13 @@ fr_info_t *fin;
break;
if (M_LEN(fin->fin_m) < fin->fin_plen) {
- if (fr_coalesce(fin) != 1)
+ if (ipf_coalesce(fin) != 1)
return;
}
+ if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN) == -1)
+ return;
+
/*
* If the destination of this packet doesn't match the
* source of the original packet then this packet is
@@ -774,19 +972,25 @@ fr_info_t *fin;
if (IP6_NEQ(&fin->fin_fi.fi_dst,
(i6addr_t *)&ip6->ip6_src))
fin->fin_flx |= FI_BAD;
-
break;
default :
break;
}
}
- frpr_short6(fin, minicmpsz);
+ ipf_pr_short6(fin, minicmpsz);
+ if ((fin->fin_flx & (FI_SHORT|FI_BAD)) == 0) {
+ u_char p = fin->fin_p;
+
+ fin->fin_p = IPPROTO_ICMPV6;
+ ipf_checkv6sum(fin);
+ fin->fin_p = p;
+ }
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_udp6 */
+/* Function: ipf_pr_udp6 */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -794,24 +998,23 @@ fr_info_t *fin;
/* Analyse the packet for IPv6/UDP properties. */
/* Is not expected to be called for fragmented packets. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_udp6(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_udp6(fin)
+ fr_info_t *fin;
{
- frpr_short6(fin, sizeof(struct udphdr));
-
- if (frpr_udpcommon(fin) == 0) {
+ if (ipf_pr_udpcommon(fin) == 0) {
u_char p = fin->fin_p;
fin->fin_p = IPPROTO_UDP;
- fr_checkv6sum(fin);
+ ipf_checkv6sum(fin);
fin->fin_p = p;
}
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_tcp6 */
+/* Function: ipf_pr_tcp6 */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -819,24 +1022,23 @@ fr_info_t *fin;
/* Analyse the packet for IPv6/TCP properties. */
/* Is not expected to be called for fragmented packets. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_tcp6(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_tcp6(fin)
+ fr_info_t *fin;
{
- frpr_short6(fin, sizeof(struct tcphdr));
-
- if (frpr_tcpcommon(fin) == 0) {
+ if (ipf_pr_tcpcommon(fin) == 0) {
u_char p = fin->fin_p;
fin->fin_p = IPPROTO_TCP;
- fr_checkv6sum(fin);
+ ipf_checkv6sum(fin);
fin->fin_p = p;
}
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_esp6 */
+/* Function: ipf_pr_esp6 */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -847,19 +1049,23 @@ fr_info_t *fin;
/* is 32bits as well, it is not possible(?) to determine the version from a */
/* simple packet header. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_esp6(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_esp6(fin)
+ fr_info_t *fin;
{
- frpr_short6(fin, sizeof(grehdr_t));
+ if ((fin->fin_off == 0) && (ipf_pr_pullup(fin, 8) == -1)) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
- (void) frpr_pullup(fin, 8);
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_esp_pullup);
+ return;
+ }
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_ah6 */
-/* Returns: void */
+/* Function: ipf_pr_ah6 */
+/* Returns: int - value of the next header or IPPROTO_NONE if error */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* IPv6 Only */
@@ -867,37 +1073,51 @@ fr_info_t *fin;
/* The minimum length is taken to be the combination of all fields in the */
/* header being present and no authentication data (null algorithm used.) */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_ah6(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_ah6(fin)
+ fr_info_t *fin;
{
authhdr_t *ah;
- frpr_short6(fin, 12);
+ fin->fin_flx |= FI_AH;
+
+ ah = (authhdr_t *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
+ if (ah == NULL) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
- if (frpr_pullup(fin, sizeof(*ah)) == -1)
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_ah_bad);
return IPPROTO_NONE;
+ }
- ah = (authhdr_t *)fin->fin_dp;
+ ipf_pr_short6(fin, sizeof(*ah));
+
+ /*
+ * No need for another pullup, ipf_pr_ipv6exthdr() will pullup
+ * enough data to satisfy ah_next (the very first one.)
+ */
return ah->ah_next;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_gre6 */
+/* Function: ipf_pr_gre6 */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* Analyse the packet for GRE properties. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_gre6(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_gre6(fin)
+ fr_info_t *fin;
{
grehdr_t *gre;
- frpr_short6(fin, sizeof(grehdr_t));
+ if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
- if (frpr_pullup(fin, sizeof(grehdr_t)) == -1)
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_gre_pullup);
return;
+ }
gre = fin->fin_dp;
if (GRE_REV(gre->gr_flags) == 1)
@@ -907,13 +1127,13 @@ fr_info_t *fin;
/* ------------------------------------------------------------------------ */
-/* Function: frpr_pullup */
+/* Function: ipf_pr_pullup */
/* Returns: int - 0 == pullup succeeded, -1 == failure */
/* Parameters: fin(I) - pointer to packet information */
/* plen(I) - length (excluding L3 header) to pullup */
/* */
/* Short inline function to cut down on code duplication to perform a call */
-/* to fr_pullup to ensure there is the required amount of data, */
+/* to ipf_pullup to ensure there is the required amount of data, */
/* consecutively in the packet buffer. */
/* */
/* This function pulls up 'extra' data at the location of fin_dp. fin_dp */
@@ -924,23 +1144,32 @@ fr_info_t *fin;
/* is necessary to add those we can already assume to be pulled up (fin_dp */
/* - fin_ip) to what is passed through. */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_pullup(fin, plen)
-fr_info_t *fin;
-int plen;
+int
+ipf_pr_pullup(fin, plen)
+ fr_info_t *fin;
+ int plen;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+
if (fin->fin_m != NULL) {
if (fin->fin_dp != NULL)
plen += (char *)fin->fin_dp -
((char *)fin->fin_ip + fin->fin_hlen);
plen += fin->fin_hlen;
- if (M_LEN(fin->fin_m) < plen) {
+ if (M_LEN(fin->fin_m) < plen + fin->fin_ipoff) {
#if defined(_KERNEL)
- if (fr_pullup(fin->fin_m, fin, plen) == NULL)
+ if (ipf_pullup(fin->fin_m, fin, plen) == NULL) {
+ DT(ipf_pullup_fail);
+ LBUMP(ipf_stats[fin->fin_out].fr_pull[1]);
return -1;
+ }
+ LBUMP(ipf_stats[fin->fin_out].fr_pull[0]);
#else
+ LBUMP(ipf_stats[fin->fin_out].fr_pull[1]);
/*
- * Fake fr_pullup failing
+ * Fake ipf_pullup failing
*/
+ fin->fin_reason = FRB_PULLUP;
*fin->fin_mp = NULL;
fin->fin_m = NULL;
fin->fin_ip = NULL;
@@ -953,7 +1182,7 @@ int plen;
/* ------------------------------------------------------------------------ */
-/* Function: frpr_short */
+/* Function: ipf_pr_short */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* xmin(I) - minimum header size */
@@ -964,9 +1193,10 @@ int plen;
/* start within the layer 4 header (hdrmin) or if it is at offset 0, the */
/* entire layer 4 header must be present (min). */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_short(fin, xmin)
-fr_info_t *fin;
-int xmin;
+static INLINE void
+ipf_pr_short(fin, xmin)
+ fr_info_t *fin;
+ int xmin;
{
if (fin->fin_off == 0) {
@@ -979,7 +1209,7 @@ int xmin;
/* ------------------------------------------------------------------------ */
-/* Function: frpr_icmp */
+/* Function: ipf_pr_icmp */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -991,110 +1221,111 @@ int xmin;
/* */
/* XXX - other ICMP sanity checks? */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_icmp(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_icmp(fin)
+ fr_info_t *fin;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
int minicmpsz = sizeof(struct icmp);
icmphdr_t *icmp;
ip_t *oip;
+ ipf_pr_short(fin, ICMPERR_ICMPHLEN);
+
if (fin->fin_off != 0) {
- frpr_short(fin, ICMPERR_ICMPHLEN);
+ LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_frag);
return;
}
- if (frpr_pullup(fin, ICMPERR_ICMPHLEN) == -1)
+ if (ipf_pr_pullup(fin, ICMPERR_ICMPHLEN) == -1) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_pullup);
return;
+ }
- if (fin->fin_dlen > 1) {
- icmp = fin->fin_dp;
+ icmp = fin->fin_dp;
- fin->fin_data[0] = *(u_short *)icmp;
+ fin->fin_data[0] = *(u_short *)icmp;
+ fin->fin_data[1] = icmp->icmp_id;
- if (fin->fin_dlen >= 6) /* ID field */
- fin->fin_data[1] = icmp->icmp_id;
+ switch (icmp->icmp_type)
+ {
+ case ICMP_ECHOREPLY :
+ case ICMP_ECHO :
+ /* Router discovery messaes - RFC 1256 */
+ case ICMP_ROUTERADVERT :
+ case ICMP_ROUTERSOLICIT :
+ fin->fin_flx |= FI_ICMPQUERY;
+ minicmpsz = ICMP_MINLEN;
+ break;
+ /*
+ * type(1) + code(1) + cksum(2) + id(2) seq(2) +
+ * 3 * timestamp(3 * 4)
+ */
+ case ICMP_TSTAMP :
+ case ICMP_TSTAMPREPLY :
+ fin->fin_flx |= FI_ICMPQUERY;
+ minicmpsz = 20;
+ break;
+ /*
+ * type(1) + code(1) + cksum(2) + id(2) seq(2) +
+ * mask(4)
+ */
+ case ICMP_IREQ :
+ case ICMP_IREQREPLY :
+ case ICMP_MASKREQ :
+ case ICMP_MASKREPLY :
+ fin->fin_flx |= FI_ICMPQUERY;
+ minicmpsz = 12;
+ break;
+ /*
+ * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+)
+ */
+ case ICMP_UNREACH :
+#ifdef icmp_nextmtu
+ if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) {
+ if (icmp->icmp_nextmtu < softc->ipf_icmpminfragmtu)
+ fin->fin_flx |= FI_BAD;
+ }
+#endif
+ case ICMP_SOURCEQUENCH :
+ case ICMP_REDIRECT :
+ case ICMP_TIMXCEED :
+ case ICMP_PARAMPROB :
+ fin->fin_flx |= FI_ICMPERR;
+ if (ipf_coalesce(fin) != 1) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_icmp_coalesce);
+ return;
+ }
- switch (icmp->icmp_type)
- {
- case ICMP_ECHOREPLY :
- case ICMP_ECHO :
- /* Router discovery messaes - 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)
+ * ICMP error packets should not be generated for IP
+ * packets that are a fragment that isn't the first
+ * fragment.
*/
- case ICMP_TSTAMP :
- case ICMP_TSTAMPREPLY :
- minicmpsz = 20;
- break;
- /*
- * type(1) + code(1) + cksum(2) + id(2) seq(2) +
- * mask(4)
- */
- case ICMP_MASKREQ :
- case ICMP_MASKREPLY :
- minicmpsz = 12;
- break;
+ oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN);
+ if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0)
+ fin->fin_flx |= FI_BAD;
+
/*
- * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+)
+ * If the destination of this packet doesn't match the
+ * source of the original packet then this packet is
+ * not correct.
*/
- case ICMP_UNREACH :
-#ifdef icmp_nextmtu
- if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) {
- if (icmp->icmp_nextmtu < fr_icmpminfragmtu)
- fin->fin_flx |= FI_BAD;
- }
-#endif
- case ICMP_SOURCEQUENCH :
- case ICMP_REDIRECT :
- case ICMP_TIMXCEED :
- case ICMP_PARAMPROB :
- fin->fin_flx |= FI_ICMPERR;
- if (fr_coalesce(fin) != 1)
- return;
- /*
- * ICMP error packets should not be generated for IP
- * packets that are a fragment that isn't the first
- * fragment.
- */
- oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN);
- if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0)
- fin->fin_flx |= FI_BAD;
-
- /*
- * If the destination of this packet doesn't match the
- * source of the original packet then this packet is
- * not correct.
- */
- if (oip->ip_src.s_addr != fin->fin_daddr)
- fin->fin_flx |= FI_BAD;
-
- /*
- * If the destination of this packet doesn't match the
- * source of the original packet then this packet is
- * not correct.
- */
- if (oip->ip_src.s_addr != fin->fin_daddr)
- fin->fin_flx |= FI_BAD;
- break;
- default :
- break;
- }
+ if (oip->ip_src.s_addr != fin->fin_daddr)
+ fin->fin_flx |= FI_BAD;
+ break;
+ default :
+ break;
}
- frpr_short(fin, minicmpsz);
+ ipf_pr_short(fin, minicmpsz);
- if ((fin->fin_flx & FI_FRAG) == 0)
- fr_checkv4sum(fin);
+ ipf_checkv4sum(fin);
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_tcpcommon */
+/* Function: ipf_pr_tcpcommon */
/* Returns: int - 0 = header ok, 1 = bad packet, -1 = buffer error */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -1103,27 +1334,35 @@ fr_info_t *fin;
/* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */
/* valid and mark the packet as bad if not. */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_tcpcommon(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_tcpcommon(fin)
+ fr_info_t *fin;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
int flags, tlen;
tcphdr_t *tcp;
fin->fin_flx |= FI_TCPUDP;
- if (fin->fin_off != 0)
+ if (fin->fin_off != 0) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_tcp_frag);
return 0;
+ }
- if (frpr_pullup(fin, sizeof(*tcp)) == -1)
+ if (ipf_pr_pullup(fin, sizeof(*tcp)) == -1) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup);
return -1;
- tcp = fin->fin_dp;
+ }
+ tcp = fin->fin_dp;
if (fin->fin_dlen > 3) {
fin->fin_sport = ntohs(tcp->th_sport);
fin->fin_dport = ntohs(tcp->th_dport);
}
- if ((fin->fin_flx & FI_SHORT) != 0)
+ if ((fin->fin_flx & FI_SHORT) != 0) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_tcp_short);
return 1;
+ }
/*
* Use of the TCP data offset *must* result in a value that is at
@@ -1131,6 +1370,7 @@ fr_info_t *fin;
*/
tlen = TCP_OFF(tcp) << 2;
if (tlen < sizeof(tcphdr_t)) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_tcp_small);
fin->fin_flx |= FI_BAD;
return 1;
}
@@ -1189,6 +1429,10 @@ fr_info_t *fin;
fin->fin_flx |= FI_BAD;
}
}
+ if (fin->fin_flx & FI_BAD) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_tcp_bad_flags);
+ return 1;
+ }
/*
* At this point, it's not exactly clear what is to be gained by
@@ -1198,11 +1442,14 @@ fr_info_t *fin;
* Now if we were to analyse the header for passive fingerprinting,
* then that might add some weight to adding this...
*/
- if (tlen == sizeof(tcphdr_t))
+ if (tlen == sizeof(tcphdr_t)) {
return 0;
+ }
- if (frpr_pullup(fin, tlen) == -1)
+ if (ipf_pr_pullup(fin, tlen) == -1) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup);
return -1;
+ }
#if 0
tcp = fin->fin_dp;
@@ -1249,23 +1496,27 @@ fr_info_t *fin;
/* ------------------------------------------------------------------------ */
-/* Function: frpr_udpcommon */
+/* Function: ipf_pr_udpcommon */
/* Returns: int - 0 = header ok, 1 = bad packet */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* Extract the UDP source and destination ports, if present. If compiled */
/* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_udpcommon(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_udpcommon(fin)
+ fr_info_t *fin;
{
udphdr_t *udp;
fin->fin_flx |= FI_TCPUDP;
if (!fin->fin_off && (fin->fin_dlen > 3)) {
- if (frpr_pullup(fin, sizeof(*udp)) == -1) {
+ if (ipf_pr_pullup(fin, sizeof(*udp)) == -1) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+
fin->fin_flx |= FI_SHORT;
+ LBUMPD(ipf_stats[fin->fin_out], fr_udp_pullup);
return 1;
}
@@ -1280,49 +1531,47 @@ fr_info_t *fin;
/* ------------------------------------------------------------------------ */
-/* Function: frpr_tcp */
+/* Function: ipf_pr_tcp */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* IPv4 Only */
/* Analyse the packet for IPv4/TCP properties. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_tcp(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_tcp(fin)
+ fr_info_t *fin;
{
- frpr_short(fin, sizeof(tcphdr_t));
+ ipf_pr_short(fin, sizeof(tcphdr_t));
- if (frpr_tcpcommon(fin) == 0) {
- if ((fin->fin_flx & FI_FRAG) == 0)
- fr_checkv4sum(fin);
- }
+ if (ipf_pr_tcpcommon(fin) == 0)
+ ipf_checkv4sum(fin);
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_udp */
+/* Function: ipf_pr_udp */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* IPv4 Only */
/* Analyse the packet for IPv4/UDP properties. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_udp(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_udp(fin)
+ fr_info_t *fin;
{
- frpr_short(fin, sizeof(udphdr_t));
+ ipf_pr_short(fin, sizeof(udphdr_t));
- if (frpr_udpcommon(fin) == 0) {
- if ((fin->fin_flx & FI_FRAG) == 0)
- fr_checkv4sum(fin);
- }
+ if (ipf_pr_udpcommon(fin) == 0)
+ ipf_checkv4sum(fin);
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_esp */
+/* Function: ipf_pr_esp */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -1332,78 +1581,107 @@ fr_info_t *fin;
/* is 32bits as well, it is not possible(?) to determine the version from a */
/* simple packet header. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_esp(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_esp(fin)
+ fr_info_t *fin;
{
if (fin->fin_off == 0) {
- frpr_short(fin, 8);
- (void) frpr_pullup(fin, 8);
- }
+ ipf_pr_short(fin, 8);
+ if (ipf_pr_pullup(fin, 8) == -1) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ LBUMPD(ipf_stats[fin->fin_out], fr_v4_esp_pullup);
+ }
+ }
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_ah */
-/* Returns: void */
+/* Function: ipf_pr_ah */
+/* Returns: int - value of the next header or IPPROTO_NONE if error */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* Analyse the packet for AH properties. */
/* The minimum length is taken to be the combination of all fields in the */
/* header being present and no authentication data (null algorithm used.) */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_ah(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_ah(fin)
+ fr_info_t *fin;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
authhdr_t *ah;
int len;
- frpr_short(fin, sizeof(*ah));
+ fin->fin_flx |= FI_AH;
+ ipf_pr_short(fin, sizeof(*ah));
- if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0))
- return;
+ if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0)) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v4_ah_bad);
+ return IPPROTO_NONE;
+ }
- if (frpr_pullup(fin, sizeof(*ah)) == -1)
- return;
+ if (ipf_pr_pullup(fin, sizeof(*ah)) == -1) {
+ DT(fr_v4_ah_pullup_1);
+ LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup);
+ return IPPROTO_NONE;
+ }
ah = (authhdr_t *)fin->fin_dp;
len = (ah->ah_plen + 2) << 2;
- frpr_short(fin, len);
+ ipf_pr_short(fin, len);
+ if (ipf_pr_pullup(fin, len) == -1) {
+ DT(fr_v4_ah_pullup_2);
+ LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup);
+ return IPPROTO_NONE;
+ }
+
+ /*
+ * Adjust fin_dp and fin_dlen for skipping over the authentication
+ * header.
+ */
+ fin->fin_dp = (char *)fin->fin_dp + len;
+ fin->fin_dlen -= len;
+ return ah->ah_next;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_gre */
+/* Function: ipf_pr_gre */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* Analyse the packet for GRE properties. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_gre(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_gre(fin)
+ fr_info_t *fin;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
grehdr_t *gre;
- frpr_short(fin, sizeof(*gre));
+ ipf_pr_short(fin, sizeof(grehdr_t));
- if (fin->fin_off != 0)
+ if (fin->fin_off != 0) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_frag);
return;
+ }
- if (frpr_pullup(fin, sizeof(*gre)) == -1)
+ if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_pullup);
return;
-
- if (fin->fin_off == 0) {
- gre = fin->fin_dp;
- if (GRE_REV(gre->gr_flags) == 1)
- fin->fin_data[0] = gre->gr_call;
}
+
+ gre = fin->fin_dp;
+ if (GRE_REV(gre->gr_flags) == 1)
+ fin->fin_data[0] = gre->gr_call;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_ipv4hdr */
+/* Function: ipf_pr_ipv4hdr */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -1411,8 +1689,9 @@ fr_info_t *fin;
/* Analyze the IPv4 header and set fields in the fr_info_t structure. */
/* Check all options present and flag their presence if any exist. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_ipv4hdr(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_ipv4hdr(fin)
+ fr_info_t *fin;
{
u_short optmsk = 0, secmsk = 0, auth = 0;
int hlen, ol, mv, p, i;
@@ -1428,16 +1707,14 @@ fr_info_t *fin;
ip = fin->fin_ip;
p = ip->ip_p;
fi->fi_p = p;
+ fin->fin_crc = p;
fi->fi_tos = ip->ip_tos;
fin->fin_id = ip->ip_id;
- off = ip->ip_off;
+ off = ntohs(ip->ip_off);
/* Get both TTL and protocol */
fi->fi_p = ip->ip_p;
fi->fi_ttl = ip->ip_ttl;
-#if 0
- (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4));
-#endif
/* Zero out bits not used in IPv6 address */
fi->fi_src.i6[1] = 0;
@@ -1448,7 +1725,11 @@ fr_info_t *fin;
fi->fi_dst.i6[3] = 0;
fi->fi_saddr = ip->ip_src.s_addr;
+ fin->fin_crc += fi->fi_saddr;
fi->fi_daddr = ip->ip_dst.s_addr;
+ fin->fin_crc += fi->fi_daddr;
+ if (IN_CLASSD(ntohl(fi->fi_daddr)))
+ fin->fin_flx |= FI_MULTICAST|FI_MBCAST;
/*
* set packet attribute flags based on the offset and
@@ -1463,12 +1744,12 @@ fr_info_t *fin;
if (off != 0) {
fin->fin_flx |= FI_FRAGBODY;
off <<= 3;
- if ((off + fin->fin_dlen > 65535) ||
+ if ((off + fin->fin_dlen > 65535) ||
(fin->fin_dlen == 0) ||
((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) {
- /*
+ /*
* The length of the packet, starting at its
- * offset cannot exceed 65535 (0xffff) as the
+ * offset cannot exceed 65535 (0xffff) as the
* length of an IP packet is only 16 bits.
*
* Any fragment that isn't the last fragment
@@ -1484,25 +1765,30 @@ fr_info_t *fin;
/*
* Call per-protocol setup and checking
*/
+ if (p == IPPROTO_AH) {
+ /*
+ * Treat AH differently because we expect there to be another
+ * layer 4 header after it.
+ */
+ p = ipf_pr_ah(fin);
+ }
+
switch (p)
{
case IPPROTO_UDP :
- frpr_udp(fin);
+ ipf_pr_udp(fin);
break;
case IPPROTO_TCP :
- frpr_tcp(fin);
+ ipf_pr_tcp(fin);
break;
case IPPROTO_ICMP :
- frpr_icmp(fin);
- break;
- case IPPROTO_AH :
- frpr_ah(fin);
+ ipf_pr_icmp(fin);
break;
case IPPROTO_ESP :
- frpr_esp(fin);
+ ipf_pr_esp(fin);
break;
case IPPROTO_GRE :
- frpr_gre(fin);
+ ipf_pr_gre(fin);
break;
}
@@ -1545,32 +1831,37 @@ fr_info_t *fin;
}
for (i = 9, mv = 4; mv >= 0; ) {
op = ipopts + i;
+
if ((opt == (u_char)op->ol_val) && (ol > 4)) {
- optmsk |= op->ol_bit;
- if (opt == IPOPT_SECURITY) {
- const struct optlist *sp;
- u_char sec;
- int j, m;
-
- sec = *(s + 2); /* classification */
- for (j = 3, m = 2; m >= 0; ) {
- sp = secopt + j;
- if (sec == sp->ol_val) {
- secmsk |= sp->ol_bit;
- auth = *(s + 3);
- auth *= 256;
- auth += *(s + 4);
- break;
- }
- if (sec < sp->ol_val)
- j -= m;
- else
- j += m;
- m--;
+ u_32_t doi;
+
+ switch (opt)
+ {
+ case IPOPT_SECURITY :
+ if (optmsk & op->ol_bit) {
+ fin->fin_flx |= FI_BAD;
+ } else {
+ doi = ipf_checkripso(s);
+ secmsk = doi >> 16;
+ auth = doi & 0xffff;
}
+ break;
+
+ case IPOPT_CIPSO :
+
+ if (optmsk & op->ol_bit) {
+ fin->fin_flx |= FI_BAD;
+ } else {
+ doi = ipf_checkcipso(fin,
+ s, ol);
+ secmsk = doi >> 16;
+ auth = doi & 0xffff;
+ }
+ break;
}
- break;
+ optmsk |= op->ol_bit;
}
+
if (opt < op->ol_val)
i -= mv;
else
@@ -1593,8 +1884,142 @@ fr_info_t *fin;
/* ------------------------------------------------------------------------ */
-/* Function: fr_makefrip */
+/* Function: ipf_checkripso */
/* Returns: void */
+/* Parameters: s(I) - pointer to start of RIPSO option */
+/* */
+/* ------------------------------------------------------------------------ */
+static u_32_t
+ipf_checkripso(s)
+ u_char *s;
+{
+ const struct optlist *sp;
+ u_short secmsk = 0, auth = 0;
+ u_char sec;
+ int j, m;
+
+ sec = *(s + 2); /* classification */
+ for (j = 3, m = 2; m >= 0; ) {
+ sp = secopt + j;
+ if (sec == sp->ol_val) {
+ secmsk |= sp->ol_bit;
+ auth = *(s + 3);
+ auth *= 256;
+ auth += *(s + 4);
+ break;
+ }
+ if (sec < sp->ol_val)
+ j -= m;
+ else
+ j += m;
+ m--;
+ }
+
+ return (secmsk << 16) | auth;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_checkcipso */
+/* Returns: u_32_t - 0 = failure, else the doi from the header */
+/* Parameters: fin(IO) - pointer to packet information */
+/* s(I) - pointer to start of CIPSO option */
+/* ol(I) - length of CIPSO option field */
+/* */
+/* This function returns the domain of integrity (DOI) field from the CIPSO */
+/* header and returns that whilst also storing the highest sensitivity */
+/* value found in the fr_info_t structure. */
+/* */
+/* No attempt is made to extract the category bitmaps as these are defined */
+/* by the user (rather than the protocol) and can be rather numerous on the */
+/* end nodes. */
+/* ------------------------------------------------------------------------ */
+static u_32_t
+ipf_checkcipso(fin, s, ol)
+ fr_info_t *fin;
+ u_char *s;
+ int ol;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ fr_ip_t *fi;
+ u_32_t doi;
+ u_char *t, tag, tlen, sensitivity;
+ int len;
+
+ if (ol < 6 || ol > 40) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_bad);
+ fin->fin_flx |= FI_BAD;
+ return 0;
+ }
+
+ fi = &fin->fin_fi;
+ fi->fi_sensitivity = 0;
+ /*
+ * The DOI field MUST be there.
+ */
+ bcopy(s + 2, &doi, sizeof(doi));
+
+ t = (u_char *)s + 6;
+ for (len = ol - 6; len >= 2; len -= tlen, t+= tlen) {
+ tag = *t;
+ tlen = *(t + 1);
+ if (tlen > len || tlen < 4 || tlen > 34) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_tlen);
+ fin->fin_flx |= FI_BAD;
+ return 0;
+ }
+
+ sensitivity = 0;
+ /*
+ * Tag numbers 0, 1, 2, 5 are laid out in the CIPSO Internet
+ * draft (16 July 1992) that has expired.
+ */
+ if (tag == 0) {
+ fin->fin_flx |= FI_BAD;
+ continue;
+ } else if (tag == 1) {
+ if (*(t + 2) != 0) {
+ fin->fin_flx |= FI_BAD;
+ continue;
+ }
+ sensitivity = *(t + 3);
+ /* Category bitmap for categories 0-239 */
+
+ } else if (tag == 4) {
+ if (*(t + 2) != 0) {
+ fin->fin_flx |= FI_BAD;
+ continue;
+ }
+ sensitivity = *(t + 3);
+ /* Enumerated categories, 16bits each, upto 15 */
+
+ } else if (tag == 5) {
+ if (*(t + 2) != 0) {
+ fin->fin_flx |= FI_BAD;
+ continue;
+ }
+ sensitivity = *(t + 3);
+ /* Range of categories (2*16bits), up to 7 pairs */
+
+ } else if (tag > 127) {
+ /* Custom defined DOI */
+ ;
+ } else {
+ fin->fin_flx |= FI_BAD;
+ continue;
+ }
+
+ if (sensitivity > fi->fi_sensitivity)
+ fi->fi_sensitivity = sensitivity;
+ }
+
+ return doi;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_makefrip */
+/* Returns: int - 0 == packet ok, -1 == packet freed */
/* Parameters: hlen(I) - length of IP packet header */
/* ip(I) - pointer to the IP header */
/* fin(IO) - pointer to packet information */
@@ -1604,15 +2029,15 @@ fr_info_t *fin;
/* in the fr_info_t structure pointer to by fin. At present, it is assumed */
/* this function will be called with either an IPv4 or IPv6 packet. */
/* ------------------------------------------------------------------------ */
-int fr_makefrip(hlen, ip, fin)
-int hlen;
-ip_t *ip;
-fr_info_t *fin;
+int
+ipf_makefrip(hlen, ip, fin)
+ int hlen;
+ ip_t *ip;
+ fr_info_t *fin;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
int v;
- fin->fin_nat = NULL;
- fin->fin_state = NULL;
fin->fin_depth = 0;
fin->fin_hlen = (u_short)hlen;
fin->fin_ip = ip;
@@ -1623,43 +2048,43 @@ fr_info_t *fin;
v = fin->fin_v;
if (v == 4) {
- fin->fin_plen = ip->ip_len;
+ fin->fin_plen = ntohs(ip->ip_len);
fin->fin_dlen = fin->fin_plen - hlen;
-
- frpr_ipv4hdr(fin);
+ ipf_pr_ipv4hdr(fin);
#ifdef USE_INET6
} else if (v == 6) {
fin->fin_plen = ntohs(((ip6_t *)ip)->ip6_plen);
fin->fin_dlen = fin->fin_plen;
fin->fin_plen += hlen;
- if (frpr_ipv6hdr(fin) == -1)
- return -1;
+ ipf_pr_ipv6hdr(fin);
#endif
}
- if (fin->fin_ip == NULL)
+ if (fin->fin_ip == NULL) {
+ LBUMP(ipf_stats[fin->fin_out].fr_ip_freed);
return -1;
+ }
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_portcheck */
+/* Function: ipf_portcheck */
/* Returns: int - 1 == port matched, 0 == port match failed */
/* Parameters: frp(I) - pointer to port check `expression' */
-/* pop(I) - pointer to port number to evaluate */
+/* pop(I) - port number to evaluate */
/* */
/* Perform a comparison of a port number against some other(s), using a */
/* structure with compare information stored in it. */
/* ------------------------------------------------------------------------ */
-static INLINE int fr_portcheck(frp, pop)
-frpcmp_t *frp;
-u_short *pop;
+static INLINE int
+ipf_portcheck(frp, pop)
+ frpcmp_t *frp;
+ u_32_t pop;
{
- u_short tup, po;
int err = 1;
+ u_32_t po;
- tup = *pop;
po = frp->frp_port;
/*
@@ -1668,39 +2093,39 @@ u_short *pop;
switch (frp->frp_cmp)
{
case FR_EQUAL :
- if (tup != po) /* EQUAL */
+ if (pop != po) /* EQUAL */
err = 0;
break;
case FR_NEQUAL :
- if (tup == po) /* NOTEQUAL */
+ if (pop == po) /* NOTEQUAL */
err = 0;
break;
case FR_LESST :
- if (tup >= po) /* LESSTHAN */
+ if (pop >= po) /* LESSTHAN */
err = 0;
break;
case FR_GREATERT :
- if (tup <= po) /* GREATERTHAN */
+ if (pop <= po) /* GREATERTHAN */
err = 0;
break;
case FR_LESSTE :
- if (tup > po) /* LT or EQ */
+ if (pop > po) /* LT or EQ */
err = 0;
break;
case FR_GREATERTE :
- if (tup < po) /* GT or EQ */
+ if (pop < po) /* GT or EQ */
err = 0;
break;
case FR_OUTRANGE :
- if (tup >= po && tup <= frp->frp_top) /* Out of range */
+ if (pop >= po && pop <= frp->frp_top) /* Out of range */
err = 0;
break;
case FR_INRANGE :
- if (tup <= po || tup >= frp->frp_top) /* In range */
+ if (pop <= po || pop >= frp->frp_top) /* In range */
err = 0;
break;
case FR_INCRANGE :
- if (tup < po || tup > frp->frp_top) /* Inclusive range */
+ if (pop < po || pop > frp->frp_top) /* Inclusive range */
err = 0;
break;
default :
@@ -1711,17 +2136,18 @@ u_short *pop;
/* ------------------------------------------------------------------------ */
-/* Function: fr_tcpudpchk */
+/* Function: ipf_tcpudpchk */
/* Returns: int - 1 == protocol matched, 0 == check failed */
-/* Parameters: fin(I) - pointer to packet information */
+/* Parameters: fda(I) - pointer to packet information */
/* ft(I) - pointer to structure with comparison data */
/* */
/* Compares the current pcket (assuming it is TCP/UDP) information with a */
/* structure containing information that we want to match against. */
/* ------------------------------------------------------------------------ */
-int fr_tcpudpchk(fin, ft)
-fr_info_t *fin;
-frtuc_t *ft;
+int
+ipf_tcpudpchk(fi, ft)
+ fr_ip_t *fi;
+ frtuc_t *ft;
{
int err = 1;
@@ -1732,13 +2158,13 @@ frtuc_t *ft;
* compare destination ports
*/
if (ft->ftu_dcmp)
- err = fr_portcheck(&ft->ftu_dst, &fin->fin_dport);
+ err = ipf_portcheck(&ft->ftu_dst, fi->fi_ports[1]);
/*
* compare source ports
*/
if (err && ft->ftu_scmp)
- err = fr_portcheck(&ft->ftu_src, &fin->fin_sport);
+ err = ipf_portcheck(&ft->ftu_src, fi->fi_ports[0]);
/*
* If we don't have all the TCP/UDP header, then how can we
@@ -1746,15 +2172,15 @@ frtuc_t *ft;
* TCP flags, then NO match. If not, then match (which should
* satisfy the "short" class too).
*/
- if (err && (fin->fin_p == IPPROTO_TCP)) {
- if (fin->fin_flx & FI_SHORT)
+ if (err && (fi->fi_p == IPPROTO_TCP)) {
+ if (fi->fi_flx & FI_SHORT)
return !(ft->ftu_tcpf | ft->ftu_tcpfm);
/*
* Match the flags ? If not, abort this match.
*/
if (ft->ftu_tcpfm &&
- ft->ftu_tcpf != (fin->fin_tcpf & ft->ftu_tcpfm)) {
- FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf,
+ ft->ftu_tcpf != (fi->fi_tcpf & ft->ftu_tcpfm)) {
+ FR_DEBUG(("f. %#x & %#x != %#x\n", fi->fi_tcpf,
ft->ftu_tcpfm, ft->ftu_tcpf));
err = 0;
}
@@ -1763,10 +2189,9 @@ frtuc_t *ft;
}
-
/* ------------------------------------------------------------------------ */
-/* Function: fr_ipfcheck */
-/* Returns: int - 0 == match, 1 == no match */
+/* Function: ipf_check_ipf */
+/* Returns: int - 0 == match, else no match */
/* Parameters: fin(I) - pointer to packet information */
/* fr(I) - pointer to filter rule */
/* portcmp(I) - flag indicating whether to attempt matching on */
@@ -1776,10 +2201,11 @@ frtuc_t *ft;
/* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */
/* this function. */
/* ------------------------------------------------------------------------ */
-static INLINE int fr_ipfcheck(fin, fr, portcmp)
-fr_info_t *fin;
-frentry_t *fr;
-int portcmp;
+static INLINE int
+ipf_check_ipf(fin, fr, portcmp)
+ fr_info_t *fin;
+ frentry_t *fr;
+ int portcmp;
{
u_32_t *ld, *lm, *lip;
fripf_t *fri;
@@ -1807,10 +2233,10 @@ int portcmp;
* are present (if any) in this packet.
*/
lip++, lm++, ld++;
- i |= ((*lip & *lm) != *ld);
+ i = ((*lip & *lm) != *ld);
FR_DEBUG(("1. %#08x & %#08x != %#08x\n",
ntohl(*lip), ntohl(*lm), ntohl(*ld)));
- if (i)
+ if (i != 0)
return 1;
lip++, lm++, ld++;
@@ -1820,16 +2246,15 @@ int portcmp;
/*
* Check the source address.
*/
-#ifdef IPFILTER_LOOKUP
if (fr->fr_satype == FRI_LOOKUP) {
- i = (*fr->fr_srcfunc)(fr->fr_srcptr, fi->fi_v, lip);
+ i = (*fr->fr_srcfunc)(fin->fin_main_soft, fr->fr_srcptr,
+ fi->fi_v, lip, fin->fin_plen);
if (i == -1)
return 1;
lip += 3;
lm += 3;
ld += 3;
} else {
-#endif
i = ((*lip & *lm) != *ld);
FR_DEBUG(("2a. %#08x & %#08x != %#08x\n",
ntohl(*lip), ntohl(*lm), ntohl(*ld)));
@@ -1851,27 +2276,24 @@ int portcmp;
lm += 3;
ld += 3;
}
-#ifdef IPFILTER_LOOKUP
}
-#endif
i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6;
- if (i)
+ if (i != 0)
return 1;
/*
* Check the destination address.
*/
lip++, lm++, ld++;
-#ifdef IPFILTER_LOOKUP
if (fr->fr_datype == FRI_LOOKUP) {
- i = (*fr->fr_dstfunc)(fr->fr_dstptr, fi->fi_v, lip);
+ i = (*fr->fr_dstfunc)(fin->fin_main_soft, fr->fr_dstptr,
+ fi->fi_v, lip, fin->fin_plen);
if (i == -1)
return 1;
lip += 3;
lm += 3;
ld += 3;
} else {
-#endif
i = ((*lip & *lm) != *ld);
FR_DEBUG(("3a. %#08x & %#08x != %#08x\n",
ntohl(*lip), ntohl(*lm), ntohl(*ld)));
@@ -1893,28 +2315,24 @@ int portcmp;
lm += 3;
ld += 3;
}
-#ifdef IPFILTER_LOOKUP
}
-#endif
i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7;
- if (i)
+ if (i != 0)
return 1;
/*
* IP addresses matched. The next 32bits contains:
* mast of old IP header security & authentication bits.
*/
lip++, lm++, ld++;
- i |= ((*lip & *lm) != *ld);
- FR_DEBUG(("4. %#08x & %#08x != %#08x\n",
- *lip, *lm, *ld));
+ i = (*ld - (*lip & *lm));
+ FR_DEBUG(("4. %#08x & %#08x != %#08x\n", *lip, *lm, *ld));
/*
* Next we have 32 bits of packet flags.
*/
lip++, lm++, ld++;
- i |= ((*lip & *lm) != *ld);
- FR_DEBUG(("5. %#08x & %#08x != %#08x\n",
- *lip, *lm, *ld));
+ i |= (*ld - (*lip & *lm));
+ FR_DEBUG(("5. %#08x & %#08x != %#08x\n", *lip, *lm, *ld));
if (i == 0) {
/*
@@ -1922,7 +2340,7 @@ int portcmp;
* looking for here...
*/
if (portcmp) {
- if (!fr_tcpudpchk(fin, &fr->fr_tuc))
+ if (!ipf_tcpudpchk(&fin->fin_fi, &fr->fr_tuc))
i = 1;
} else {
if (fr->fr_dcmp || fr->fr_scmp ||
@@ -1948,7 +2366,7 @@ int portcmp;
/* ------------------------------------------------------------------------ */
-/* Function: fr_scanlist */
+/* Function: ipf_scanlist */
/* Returns: int - result flags of scanning filter list */
/* Parameters: fin(I) - pointer to packet information */
/* pass(I) - default result to return for filtering */
@@ -1963,10 +2381,12 @@ int portcmp;
/* Could be per interface, but this gets real nasty when you don't have, */
/* or can't easily change, the kernel source code to . */
/* ------------------------------------------------------------------------ */
-int fr_scanlist(fin, pass)
-fr_info_t *fin;
-u_32_t pass;
+int
+ipf_scanlist(fin, pass)
+ fr_info_t *fin;
+ u_32_t pass;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
int rulen, portcmp, off, skip;
struct frentry *fr, *fnext;
u_32_t passt, passo;
@@ -1997,7 +2417,7 @@ u_32_t pass;
for (rulen = 0; fr; fr = fnext, rulen++) {
fnext = fr->fr_next;
if (skip != 0) {
- FR_VERBOSE(("%d (%#x)\n", skip, fr->fr_flags));
+ FR_VERBOSE(("SKIP %d (%#x)\n", skip, fr->fr_flags));
skip--;
continue;
}
@@ -2027,27 +2447,29 @@ u_32_t pass;
switch (fr->fr_type)
{
case FR_T_IPF :
- case FR_T_IPF|FR_T_BUILTIN :
- if (fr_ipfcheck(fin, fr, portcmp))
+ case FR_T_IPF_BUILTIN :
+ if (ipf_check_ipf(fin, fr, portcmp))
continue;
break;
#if defined(IPFILTER_BPF)
case FR_T_BPFOPC :
- case FR_T_BPFOPC|FR_T_BUILTIN :
+ case FR_T_BPFOPC_BUILTIN :
{
u_char *mc;
+ int wlen;
if (*fin->fin_mp == NULL)
continue;
- if (fin->fin_v != fr->fr_v)
+ if (fin->fin_family != fr->fr_family)
continue;
mc = (u_char *)fin->fin_m;
- if (!bpf_filter(fr->fr_data, mc, fin->fin_plen, 0))
+ wlen = fin->fin_dlen + fin->fin_hlen;
+ if (!bpf_filter(fr->fr_data, mc, wlen, 0))
continue;
break;
}
#endif
- case FR_T_CALLFUNC|FR_T_BUILTIN :
+ case FR_T_CALLFUNC_BUILTIN :
{
frentry_t *f;
@@ -2058,6 +2480,15 @@ u_32_t pass;
continue;
break;
}
+
+ case FR_T_IPFEXPR :
+ case FR_T_IPFEXPR_BUILTIN :
+ if (fin->fin_family != fr->fr_family)
+ continue;
+ if (ipf_fr_matcharray(fin, fr->fr_data) == 0)
+ continue;
+ break;
+
default :
break;
}
@@ -2065,23 +2496,14 @@ u_32_t pass;
if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) {
if (fin->fin_nattag == NULL)
continue;
- if (fr_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0)
+ if (ipf_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0)
continue;
}
- FR_VERBOSE(("=%s.%d *", fr->fr_group, rulen));
+ FR_VERBOSE(("=%d/%d.%d *", fr->fr_grhead, fr->fr_group, rulen));
passt = fr->fr_flags;
/*
- * Allowing a rule with the "keep state" flag set to match
- * packets that have been tagged "out of window" by the TCP
- * state tracking is foolish as the attempt to add a new
- * state entry to the table will fail.
- */
- if ((passt & FR_KEEPSTATE) && (fin->fin_flx & FI_OOW))
- continue;
-
- /*
* If the rule is a "call now" rule, then call the function
* in the rule, if it exists and use the results from that.
* If the function pointer is bad, just make like we ignore
@@ -2091,7 +2513,7 @@ u_32_t pass;
frentry_t *frs;
ATOMIC_INC64(fr->fr_hits);
- if ((fr->fr_func != NULL) &&
+ if ((fr->fr_func == NULL) ||
(fr->fr_func == (ipfunc_t)-1))
continue;
@@ -2111,43 +2533,69 @@ u_32_t pass;
* Just log this packet...
*/
if ((passt & FR_LOGMASK) == FR_LOG) {
- if (ipflog(fin, passt) == -1) {
+ if (ipf_log_pkt(fin, passt) == -1) {
if (passt & FR_LOGORBLOCK) {
+ DT(frb_logfail);
passt &= ~FR_CMDMASK;
passt |= FR_BLOCK|FR_QUICK;
+ fin->fin_reason = FRB_LOGFAIL;
}
- ATOMIC_INCL(frstats[fin->fin_out].fr_skip);
}
- ATOMIC_INCL(frstats[fin->fin_out].fr_pkl);
- fin->fin_flx |= FI_DONTCACHE;
}
#endif /* IPFILTER_LOG */
+
+ MUTEX_ENTER(&fr->fr_lock);
fr->fr_bytes += (U_QUAD_T)fin->fin_plen;
+ fr->fr_hits++;
+ MUTEX_EXIT(&fr->fr_lock);
+ fin->fin_rule = rulen;
+
passo = pass;
- if (FR_ISSKIP(passt))
+ if (FR_ISSKIP(passt)) {
skip = fr->fr_arg;
- else if ((passt & FR_LOGMASK) != FR_LOG)
+ continue;
+ } else if (((passt & FR_LOGMASK) != FR_LOG) &&
+ ((passt & FR_LOGMASK) != FR_DECAPSULATE)) {
pass = passt;
+ }
+
if (passt & (FR_RETICMP|FR_FAKEICMP))
fin->fin_icode = fr->fr_icode;
- FR_DEBUG(("pass %#x\n", pass));
- ATOMIC_INC64(fr->fr_hits);
- fin->fin_rule = rulen;
- (void) strncpy(fin->fin_group, fr->fr_group, FR_GROUPLEN);
- if (fr->fr_grp != NULL) {
- fin->fin_fr = *fr->fr_grp;
- passt = fr_scanlist(fin, pass);
+
+ if (fr->fr_group != -1) {
+ (void) strncpy(fin->fin_group,
+ FR_NAME(fr, fr_group),
+ strlen(FR_NAME(fr, fr_group)));
+ } else {
+ fin->fin_group[0] = '\0';
+ }
+
+ FR_DEBUG(("pass %#x/%#x/%x\n", passo, pass, passt));
+
+ if (fr->fr_grphead != NULL) {
+ fin->fin_fr = fr->fr_grphead->fg_start;
+ FR_VERBOSE(("group %s\n", FR_NAME(fr, fr_grhead)));
+
+ if (FR_ISDECAPS(passt))
+ passt = ipf_decaps(fin, pass, fr->fr_icode);
+ else
+ passt = ipf_scanlist(fin, pass);
+
if (fin->fin_fr == NULL) {
fin->fin_rule = rulen;
- (void) strncpy(fin->fin_group, fr->fr_group,
- FR_GROUPLEN);
+ if (fr->fr_group != -1)
+ (void) strncpy(fin->fin_group,
+ fr->fr_names +
+ fr->fr_group,
+ strlen(fr->fr_names +
+ fr->fr_group));
fin->fin_fr = fr;
passt = pass;
}
pass = passt;
}
- if (passt & FR_QUICK) {
+ if (pass & FR_QUICK) {
/*
* Finally, if we've asked to track state for this
* packet, set it up. Add state for "quick" rules
@@ -2155,15 +2603,15 @@ u_32_t pass;
* the rule to "not match" and keep on processing
* filter rules.
*/
- if ((pass & FR_KEEPSTATE) &&
+ if ((pass & FR_KEEPSTATE) && !FR_ISAUTH(pass) &&
!(fin->fin_flx & FI_STATE)) {
int out = fin->fin_out;
fin->fin_fr = fr;
- if (fr_addstate(fin, NULL, 0) != NULL) {
- ATOMIC_INCL(frstats[out].fr_ads);
+ if (ipf_state_add(softc, fin, NULL, 0) == 0) {
+ LBUMPD(ipf_stats[out], fr_ads);
} else {
- ATOMIC_INCL(frstats[out].fr_bads);
+ LBUMPD(ipf_stats[out], fr_bads);
pass = passo;
continue;
}
@@ -2177,7 +2625,7 @@ u_32_t pass;
/* ------------------------------------------------------------------------ */
-/* Function: fr_acctpkt */
+/* Function: ipf_acctpkt */
/* Returns: frentry_t* - always returns NULL */
/* Parameters: fin(I) - pointer to packet information */
/* passp(IO) - pointer to current/new filter decision (unused) */
@@ -2186,32 +2634,29 @@ u_32_t pass;
/* IP protocol version. */
/* */
/* N.B.: this function returns NULL to match the prototype used by other */
-/* functions called from the IPFilter "mainline" in fr_check(). */
+/* functions called from the IPFilter "mainline" in ipf_check(). */
/* ------------------------------------------------------------------------ */
-frentry_t *fr_acctpkt(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+frentry_t *
+ipf_acctpkt(fin, passp)
+ fr_info_t *fin;
+ u_32_t *passp;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
char group[FR_GROUPLEN];
frentry_t *fr, *frsave;
u_32_t pass, rulen;
passp = passp;
-#ifdef USE_INET6
- if (fin->fin_v == 6)
- fr = ipacct6[fin->fin_out][fr_active];
- else
-#endif
- fr = ipacct[fin->fin_out][fr_active];
+ fr = softc->ipf_acct[fin->fin_out][softc->ipf_active];
if (fr != NULL) {
frsave = fin->fin_fr;
bcopy(fin->fin_group, group, FR_GROUPLEN);
rulen = fin->fin_rule;
fin->fin_fr = fr;
- pass = fr_scanlist(fin, FR_NOMATCH);
+ pass = ipf_scanlist(fin, FR_NOMATCH);
if (FR_ISACCOUNT(pass)) {
- ATOMIC_INCL(frstats[0].fr_acct);
+ LBUMPD(ipf_stats[0], fr_acct);
}
fin->fin_fr = frsave;
bcopy(group, fin->fin_group, FR_GROUPLEN);
@@ -2222,7 +2667,7 @@ u_32_t *passp;
/* ------------------------------------------------------------------------ */
-/* Function: fr_firewall */
+/* Function: ipf_firewall */
/* Returns: frentry_t* - returns pointer to matched rule, if no matches */
/* were found, returns NULL. */
/* Parameters: fin(I) - pointer to packet information */
@@ -2234,12 +2679,13 @@ u_32_t *passp;
/* matching rule is found, take any appropriate actions as defined by the */
/* rule - except logging. */
/* ------------------------------------------------------------------------ */
-static frentry_t *fr_firewall(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+static frentry_t *
+ipf_firewall(fin, passp)
+ fr_info_t *fin;
+ u_32_t *passp;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
frentry_t *fr;
- fr_info_t *fc;
u_32_t pass;
int out;
@@ -2247,56 +2693,28 @@ u_32_t *passp;
pass = *passp;
/*
- * If a packet is found in the auth table, then skip checking
- * the access lists for permission but we do need to consider
- * the result as if it were from the ACL's.
+ * This rule cache will only affect packets that are not being
+ * statefully filtered.
*/
- fc = &frcache[out][CACHE_HASH(fin)];
- READ_ENTER(&ipf_frcache);
- if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) {
- /*
- * copy cached data so we can unlock the mutexes earlier.
- */
- bcopy((char *)fc, (char *)fin, FI_COPYSIZE);
- RWLOCK_EXIT(&ipf_frcache);
- ATOMIC_INCL(frstats[out].fr_chit);
-
- if ((fr = fin->fin_fr) != NULL) {
- ATOMIC_INC64(fr->fr_hits);
- pass = fr->fr_flags;
- }
- } else {
- RWLOCK_EXIT(&ipf_frcache);
+ fin->fin_fr = softc->ipf_rules[out][softc->ipf_active];
+ if (fin->fin_fr != NULL)
+ pass = ipf_scanlist(fin, softc->ipf_pass);
-#ifdef USE_INET6
- if (fin->fin_v == 6)
- fin->fin_fr = ipfilter6[out][fr_active];
- else
-#endif
- fin->fin_fr = ipfilter[out][fr_active];
- if (fin->fin_fr != NULL)
- pass = fr_scanlist(fin, fr_pass);
-
- if (((pass & FR_KEEPSTATE) == 0) &&
- ((fin->fin_flx & FI_DONTCACHE) == 0)) {
- WRITE_ENTER(&ipf_frcache);
- bcopy((char *)fin, (char *)fc, FI_COPYSIZE);
- RWLOCK_EXIT(&ipf_frcache);
- }
- if ((pass & FR_NOMATCH)) {
- ATOMIC_INCL(frstats[out].fr_nom);
- }
- fr = fin->fin_fr;
+ if ((pass & FR_NOMATCH)) {
+ LBUMPD(ipf_stats[out], fr_nom);
}
+ fr = fin->fin_fr;
/*
* Apply packets per second rate-limiting to a rule as required.
*/
if ((fr != NULL) && (fr->fr_pps != 0) &&
!ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) {
- pass &= ~(FR_CMDMASK|FR_DUP|FR_RETICMP|FR_RETRST);
+ DT2(frb_ppsrate, fr_info_t *, fin, frentry_t *, fr);
+ pass &= ~(FR_CMDMASK|FR_RETICMP|FR_RETRST);
pass |= FR_BLOCK;
- ATOMIC_INCL(frstats[out].fr_ppshit);
+ LBUMPD(ipf_stats[out], fr_ppshit);
+ fin->fin_reason = FRB_PPSRATE;
}
/*
@@ -2305,15 +2723,15 @@ u_32_t *passp;
* we've dropped it already.
*/
if (FR_ISAUTH(pass)) {
- if (fr_newauth(fin->fin_m, fin) != 0) {
-#ifdef _KERNEL
+ if (ipf_auth_new(fin->fin_m, fin) != 0) {
+ DT1(frb_authnew, fr_info_t *, fin);
fin->fin_m = *fin->fin_mp = NULL;
-#else
- ;
-#endif
+ fin->fin_reason = FRB_AUTHNEW;
fin->fin_error = 0;
- } else
+ } else {
+ IPFERROR(1);
fin->fin_error = ENOSPC;
+ }
}
if ((fr != NULL) && (fr->fr_func != NULL) &&
@@ -2327,8 +2745,7 @@ u_32_t *passp;
* is treated as "not a pass", hence the packet is blocked.
*/
if (FR_ISPREAUTH(pass)) {
- if ((fin->fin_fr = ipauth) != NULL)
- pass = fr_scanlist(fin, fr_pass);
+ pass = ipf_auth_pre_scanlist(softc, fin, pass);
}
/*
@@ -2337,27 +2754,25 @@ u_32_t *passp;
*/
if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) {
if (fin->fin_flx & FI_FRAG) {
- if (fr_newfrag(fin, pass) == -1) {
- ATOMIC_INCL(frstats[out].fr_bnfr);
+ if (ipf_frag_new(softc, fin, pass) == -1) {
+ LBUMP(ipf_stats[out].fr_bnfr);
} else {
- ATOMIC_INCL(frstats[out].fr_nfr);
+ LBUMP(ipf_stats[out].fr_nfr);
}
} else {
- ATOMIC_INCL(frstats[out].fr_cfr);
+ LBUMP(ipf_stats[out].fr_cfr);
}
}
fr = fin->fin_fr;
-
- if (passp != NULL)
- *passp = pass;
+ *passp = pass;
return fr;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_check */
+/* Function: ipf_check */
/* Returns: int - 0 == packet allowed through, */
/* User space: */
/* -1 == packet blocked */
@@ -2375,7 +2790,7 @@ u_32_t *passp;
/* qpi(I) - pointer to STREAMS queue information for this */
/* interface & direction. */
/* */
-/* fr_check() is the master function for all IPFilter packet processing. */
+/* ipf_check() is the master function for all IPFilter packet processing. */
/* It orchestrates: Network Address Translation (NAT), checking for packet */
/* authorisation (or pre-authorisation), presence of related state info., */
/* generating log entries, IP packet accounting, routing of packets as */
@@ -2386,31 +2801,34 @@ u_32_t *passp;
/* freed. Packets passed may be returned with the pointer pointed to by */
/* by "mp" changed to a new buffer. */
/* ------------------------------------------------------------------------ */
-int fr_check(ip, hlen, ifp, out
+int
+ipf_check(ctx, ip, hlen, ifp, out
#if defined(_KERNEL) && defined(MENTAT)
-, qif, mp)
-void *qif;
+ , qif, mp)
+ void *qif;
#else
-, mp)
+ , mp)
#endif
-mb_t **mp;
-ip_t *ip;
-int hlen;
-void *ifp;
-int out;
+ mb_t **mp;
+ ip_t *ip;
+ int hlen;
+ void *ifp;
+ int out;
+ void *ctx;
{
/*
* The above really sucks, but short of writing a diff
*/
+ ipf_main_softc_t *softc = ctx;
fr_info_t frinfo;
fr_info_t *fin = &frinfo;
- u_32_t pass = fr_pass;
+ u_32_t pass = softc->ipf_pass;
frentry_t *fr = NULL;
int v = IP_V(ip);
mb_t *mc = NULL;
mb_t *m;
/*
- * The first part of fr_check() deals with making sure that what goes
+ * The first part of ipf_check() deals with making sure that what goes
* into the filtering engine makes some sense. Information about the
* the packet is distilled, collected into a fr_info_t structure and
* the an attempt to ensure the buffer the packet is in is big enough
@@ -2420,7 +2838,7 @@ int out;
# ifdef MENTAT
qpktinfo_t *qpi = qif;
-# if !defined(_INET_IP_STACK_H)
+# ifdef __sparc
if ((u_int)ip & 0x3)
return 2;
# endif
@@ -2428,18 +2846,17 @@ int out;
SPL_INT(s);
# endif
- READ_ENTER(&ipf_global);
-
- if (fr_running <= 0) {
- RWLOCK_EXIT(&ipf_global);
+ if (softc->ipf_running <= 0) {
return 0;
}
bzero((char *)fin, sizeof(*fin));
# ifdef MENTAT
- if (qpi->qpi_flags & QF_GROUP)
- fin->fin_flx |= FI_MBCAST;
+ if (qpi->qpi_flags & QF_BROADCAST)
+ fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
+ if (qpi->qpi_flags & QF_MULTICAST)
+ fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
m = qpi->qpi_m;
fin->fin_qfm = m;
fin->fin_qpi = qpi;
@@ -2467,7 +2884,8 @@ int out;
*/
m->m_flags &= ~M_CANFASTFWD;
# endif /* M_CANFASTFWD */
-# ifdef CSUM_DELAY_DATA
+# if defined(CSUM_DELAY_DATA) && (!defined(__FreeBSD_version) || \
+ (__FreeBSD_version < 501108))
/*
* disable delayed checksums.
*/
@@ -2478,10 +2896,20 @@ int out;
# endif /* CSUM_DELAY_DATA */
# endif /* MENTAT */
#else
- READ_ENTER(&ipf_global);
-
bzero((char *)fin, sizeof(*fin));
m = *mp;
+# if defined(M_MCAST)
+ if ((m->m_flags & M_MCAST) != 0)
+ fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
+# endif
+# if defined(M_MLOOP)
+ if ((m->m_flags & M_MLOOP) != 0)
+ fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
+# endif
+# if defined(M_BCAST)
+ if ((m->m_flags & M_BCAST) != 0)
+ fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
+# endif
#endif /* _KERNEL */
fin->fin_v = v;
@@ -2493,6 +2921,7 @@ int out;
fin->fin_error = ENETUNREACH;
fin->fin_hlen = (u_short)hlen;
fin->fin_dp = (char *)ip + hlen;
+ fin->fin_main_soft = softc;
fin->fin_ipoff = (char *)ip - MTOD(m, char *);
@@ -2500,27 +2929,29 @@ int out;
#ifdef USE_INET6
if (v == 6) {
- ATOMIC_INCL(frstats[out].fr_ipv6);
+ LBUMP(ipf_stats[out].fr_ipv6);
/*
* Jumbo grams are quite likely too big for internal buffer
* structures to handle comfortably, for now, so just drop
* them.
*/
if (((ip6_t *)ip)->ip6_plen == 0) {
+ DT1(frb_jumbo, ip6_t *, (ip6_t *)ip);
pass = FR_BLOCK|FR_NOMATCH;
+ fin->fin_reason = FRB_JUMBO;
goto finished;
}
+ fin->fin_family = AF_INET6;
} else
#endif
{
-#if ((defined(OpenBSD) && (OpenBSD >= 200311)) || (__FreeBSD_version >= 1000019)) && defined(_KERNEL)
- ip->ip_len = ntohs(ip->ip_len);
- ip->ip_off = ntohs(ip->ip_off);
-#endif
+ fin->fin_family = AF_INET;
}
- if (fr_makefrip(hlen, ip, fin) == -1) {
+ if (ipf_makefrip(hlen, ip, fin) == -1) {
+ DT1(frb_makefrip, fr_info_t *, fin);
pass = FR_BLOCK|FR_NOMATCH;
+ fin->fin_reason = FRB_MAKEFRIP;
goto finished;
}
@@ -2533,21 +2964,19 @@ int out;
if (!out) {
if (v == 4) {
-#ifdef _KERNEL
- if (fr_chksrc && !fr_verifysrc(fin)) {
- ATOMIC_INCL(frstats[0].fr_badsrc);
+ if (softc->ipf_chksrc && !ipf_verifysrc(fin)) {
+ LBUMPD(ipf_stats[0], fr_v4_badsrc);
fin->fin_flx |= FI_BADSRC;
}
-#endif
- if (fin->fin_ip->ip_ttl < fr_minttl) {
- ATOMIC_INCL(frstats[0].fr_badttl);
+ if (fin->fin_ip->ip_ttl < softc->ipf_minttl) {
+ LBUMPD(ipf_stats[0], fr_v4_badttl);
fin->fin_flx |= FI_LOWTTL;
}
}
#ifdef USE_INET6
else if (v == 6) {
- if (((ip6_t *)ip)->ip6_hlim < fr_minttl) {
- ATOMIC_INCL(frstats[0].fr_badttl);
+ if (((ip6_t *)ip)->ip6_hlim < softc->ipf_minttl) {
+ LBUMPD(ipf_stats[0], fr_v6_badttl);
fin->fin_flx |= FI_LOWTTL;
}
}
@@ -2555,120 +2984,135 @@ int out;
}
if (fin->fin_flx & FI_SHORT) {
- ATOMIC_INCL(frstats[out].fr_short);
+ LBUMPD(ipf_stats[out], fr_short);
}
- READ_ENTER(&ipf_mutex);
+ READ_ENTER(&softc->ipf_mutex);
- /*
- * Check auth now. This, combined with the check below to see if apass
- * is 0 is to ensure that we don't count the packet twice, which can
- * otherwise occur when we reprocess it. As it is, we only count it
- * after it has no auth. table matchup. This also stops NAT from
- * occuring until after the packet has been auth'd.
- */
- fr = fr_checkauth(fin, &pass);
if (!out) {
- if (fr_checknatin(fin, &pass) == -1) {
- goto filterdone;
+ switch (fin->fin_v)
+ {
+ case 4 :
+ if (ipf_nat_checkin(fin, &pass) == -1) {
+ goto filterdone;
+ }
+ break;
+#ifdef USE_INET6
+ case 6 :
+ if (ipf_nat6_checkin(fin, &pass) == -1) {
+ goto filterdone;
+ }
+ break;
+#endif
+ default :
+ break;
}
}
- if (!out)
- (void) fr_acctpkt(fin, NULL);
+ /*
+ * Check auth now.
+ * If a packet is found in the auth table, then skip checking
+ * the access lists for permission but we do need to consider
+ * the result as if it were from the ACL's. In addition, being
+ * found in the auth table means it has been seen before, so do
+ * not pass it through accounting (again), lest it be counted twice.
+ */
+ fr = ipf_auth_check(fin, &pass);
+ if (!out && (fr == NULL))
+ (void) ipf_acctpkt(fin, NULL);
if (fr == NULL) {
- if ((fin->fin_flx & (FI_FRAG|FI_BAD)) == FI_FRAG) {
- fr = fr_knownfrag(fin, &pass);
- /*
- * Reset the keep state flag here so that we don't
- * try and add a new state entry because of it, leading
- * to a blocked packet because the add will fail.
- */
- if (fr != NULL)
- pass &= ~FR_KEEPSTATE;
- }
+ if ((fin->fin_flx & FI_FRAG) != 0)
+ fr = ipf_frag_known(fin, &pass);
+
if (fr == NULL)
- fr = fr_checkstate(fin, &pass);
+ fr = ipf_state_check(fin, &pass);
}
if ((pass & FR_NOMATCH) || (fr == NULL))
- fr = fr_firewall(fin, &pass);
+ fr = ipf_firewall(fin, &pass);
/*
* If we've asked to track state for this packet, set it up.
- * Here rather than fr_firewall because fr_checkauth may decide
+ * Here rather than ipf_firewall because ipf_checkauth may decide
* to return a packet for "keep state"
*/
if ((pass & FR_KEEPSTATE) && (fin->fin_m != NULL) &&
!(fin->fin_flx & FI_STATE)) {
- if (fr_addstate(fin, NULL, 0) != NULL) {
- ATOMIC_INCL(frstats[out].fr_ads);
+ if (ipf_state_add(softc, fin, NULL, 0) == 0) {
+ LBUMP(ipf_stats[out].fr_ads);
} else {
- ATOMIC_INCL(frstats[out].fr_bads);
+ LBUMP(ipf_stats[out].fr_bads);
if (FR_ISPASS(pass)) {
+ DT(frb_stateadd);
pass &= ~FR_CMDMASK;
pass |= FR_BLOCK;
+ fin->fin_reason = FRB_STATEADD;
}
}
}
fin->fin_fr = fr;
+ if ((fr != NULL) && !(fin->fin_flx & FI_STATE)) {
+ fin->fin_dif = &fr->fr_dif;
+ fin->fin_tif = &fr->fr_tifs[fin->fin_rev];
+ }
/*
* Only count/translate packets which will be passed on, out the
* interface.
*/
if (out && FR_ISPASS(pass)) {
- (void) fr_acctpkt(fin, NULL);
+ (void) ipf_acctpkt(fin, NULL);
- if (fr_checknatout(fin, &pass) == -1) {
- ;
- } else if ((fr_update_ipid != 0) && (v == 4)) {
- if (fr_updateipid(fin) == -1) {
- ATOMIC_INCL(frstats[1].fr_ipud);
- pass &= ~FR_CMDMASK;
- pass |= FR_BLOCK;
- } else {
- ATOMIC_INCL(frstats[0].fr_ipud);
+ switch (fin->fin_v)
+ {
+ case 4 :
+ if (ipf_nat_checkout(fin, &pass) == -1) {
+ ;
+ } else if ((softc->ipf_update_ipid != 0) && (v == 4)) {
+ if (ipf_updateipid(fin) == -1) {
+ DT(frb_updateipid);
+ LBUMP(ipf_stats[1].fr_ipud);
+ pass &= ~FR_CMDMASK;
+ pass |= FR_BLOCK;
+ fin->fin_reason = FRB_UPDATEIPID;
+ } else {
+ LBUMP(ipf_stats[0].fr_ipud);
+ }
}
+ break;
+#ifdef USE_INET6
+ case 6 :
+ (void) ipf_nat6_checkout(fin, &pass);
+ break;
+#endif
+ default :
+ break;
}
}
filterdone:
#ifdef IPFILTER_LOG
- if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
- (void) fr_dolog(fin, &pass);
+ if ((softc->ipf_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
+ (void) ipf_dolog(fin, &pass);
}
#endif
/*
- * The FI_STATE flag is cleared here so that calling fr_checkstate
+ * The FI_STATE flag is cleared here so that calling ipf_state_check
* will work when called from inside of fr_fastroute. Although
* there is a similar flag, FI_NATED, for NAT, it does have the same
* impact on code execution.
*/
- if (fin->fin_state != NULL) {
- fr_statederef((ipstate_t **)&fin->fin_state);
- fin->fin_flx ^= FI_STATE;
- }
-
- if (fin->fin_nat != NULL) {
- if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT)) {
- WRITE_ENTER(&ipf_nat);
- nat_delete((nat_t *)fin->fin_nat, NL_DESTROY);
- RWLOCK_EXIT(&ipf_nat);
- fin->fin_nat = NULL;
- } else {
- fr_natderef((nat_t **)&fin->fin_nat);
- }
- }
+ fin->fin_flx &= ~FI_STATE;
+#if defined(FASTROUTE_RECURSION)
/*
- * Up the reference on fr_lock and exit ipf_mutex. fr_fastroute
- * only frees up the lock on ipf_global and the generation of a
- * packet below could cause a recursive call into IPFilter.
- * Hang onto the filter rule just in case someone decides to remove
- * or flush it in the meantime.
+ * Up the reference on fr_lock and exit ipf_mutex. The generation of
+ * a packet below can sometimes cause a recursive call into IPFilter.
+ * On those platforms where that does happen, we need to hang onto
+ * the filter rule just in case someone decides to remove or flush it
+ * in the meantime.
*/
if (fr != NULL) {
MUTEX_ENTER(&fr->fr_lock);
@@ -2676,16 +3120,17 @@ filterdone:
MUTEX_EXIT(&fr->fr_lock);
}
- RWLOCK_EXIT(&ipf_mutex);
+ RWLOCK_EXIT(&softc->ipf_mutex);
+#endif
if ((pass & FR_RETMASK) != 0) {
/*
* Should we return an ICMP packet to indicate error
* status passing through the packet filter ?
* WARNING: ICMP error packets AND TCP RST packets should
- * ONLY be sent in repsonse to incoming packets. Sending them
- * in response to outbound packets can result in a panic on
- * some operating systems.
+ * ONLY be sent in repsonse to incoming packets. Sending
+ * them in response to outbound packets can result in a
+ * panic on some operating systems.
*/
if (!out) {
if (pass & FR_RETICMP) {
@@ -2695,13 +3140,14 @@ filterdone:
dst = 1;
else
dst = 0;
- (void) fr_send_icmp_err(ICMP_UNREACH, fin, dst);
- ATOMIC_INCL(frstats[0].fr_ret);
+ (void) ipf_send_icmp_err(ICMP_UNREACH, fin,
+ dst);
+ LBUMP(ipf_stats[0].fr_ret);
} else if (((pass & FR_RETMASK) == FR_RETRST) &&
!(fin->fin_flx & FI_SHORT)) {
if (((fin->fin_flx & FI_OOW) != 0) ||
- (fr_send_reset(fin) == 0)) {
- ATOMIC_INCL(frstats[1].fr_ret);
+ (ipf_send_reset(fin) == 0)) {
+ LBUMP(ipf_stats[1].fr_ret);
}
}
@@ -2710,61 +3156,81 @@ filterdone:
* takes over disposing of this packet.
*/
if (FR_ISAUTH(pass) && (fin->fin_m != NULL)) {
+ DT1(frb_authcapture, fr_info_t *, fin);
fin->fin_m = *fin->fin_mp = NULL;
+ fin->fin_reason = FRB_AUTHCAPTURE;
+ m = NULL;
}
} else {
- if (pass & FR_RETRST)
+ if (pass & FR_RETRST) {
fin->fin_error = ECONNRESET;
+ }
}
}
/*
+ * After the above so that ICMP unreachables and TCP RSTs get
+ * created properly.
+ */
+ if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT))
+ ipf_nat_uncreate(fin);
+
+ /*
* If we didn't drop off the bottom of the list of rules (and thus
* the 'current' rule fr is not NULL), then we may have some extra
* instructions about what to do with a packet.
* Once we're finished return to our caller, freeing the packet if
- * we are dropping it (* BSD ONLY *).
+ * we are dropping it.
*/
if (fr != NULL) {
frdest_t *fdp;
- fdp = &fr->fr_tifs[fin->fin_rev];
+ /*
+ * Generate a duplicated packet first because ipf_fastroute
+ * can lead to fin_m being free'd... not good.
+ */
+ fdp = fin->fin_dif;
+ if ((fdp != NULL) && (fdp->fd_ptr != NULL) &&
+ (fdp->fd_ptr != (void *)-1)) {
+ mc = M_COPY(fin->fin_m);
+ if (mc != NULL)
+ ipf_fastroute(mc, &mc, fin, fdp);
+ }
+ fdp = fin->fin_tif;
if (!out && (pass & FR_FASTROUTE)) {
/*
- * For fastroute rule, no destioation interface defined
+ * For fastroute rule, no destination interface defined
* so pass NULL as the frdest_t parameter
*/
- (void) fr_fastroute(fin->fin_m, mp, fin, NULL);
+ (void) ipf_fastroute(fin->fin_m, mp, fin, NULL);
m = *mp = NULL;
- } else if ((fdp->fd_ifp != NULL) &&
- (fdp->fd_ifp != (struct ifnet *)-1)) {
+ } else if ((fdp != NULL) && (fdp->fd_ptr != NULL) &&
+ (fdp->fd_ptr != (struct ifnet *)-1)) {
/* this is for to rules: */
- (void) fr_fastroute(fin->fin_m, mp, fin, fdp);
+ ipf_fastroute(fin->fin_m, mp, fin, fdp);
m = *mp = NULL;
}
- /*
- * Generate a duplicated packet.
- */
- if ((pass & FR_DUP) != 0) {
- mc = M_DUPLICATE(fin->fin_m);
- if (mc != NULL)
- (void) fr_fastroute(mc, &mc, fin, &fr->fr_dif);
- }
-
- (void) fr_derefrule(&fr);
+#if defined(FASTROUTE_RECURSION)
+ (void) ipf_derefrule(softc, &fr);
+#endif
}
+#if !defined(FASTROUTE_RECURSION)
+ RWLOCK_EXIT(&softc->ipf_mutex);
+#endif
finished:
if (!FR_ISPASS(pass)) {
- ATOMIC_INCL(frstats[out].fr_block);
+ LBUMP(ipf_stats[out].fr_block);
if (*mp != NULL) {
+#ifdef _KERNEL
FREE_MB_T(*mp);
+#endif
m = *mp = NULL;
}
} else {
- ATOMIC_INCL(frstats[out].fr_pass);
+ LBUMP(ipf_stats[out].fr_pass);
#if defined(_KERNEL) && defined(__sgi)
if ((fin->fin_hbuf != NULL) &&
(mtod(fin->fin_m, struct ip *) != fin->fin_ip)) {
@@ -2774,21 +3240,20 @@ finished:
}
SPL_X(s);
- RWLOCK_EXIT(&ipf_global);
#ifdef _KERNEL
-# if (defined(OpenBSD) && (OpenBSD >= 200311)) || (__FreeBSD_version >= 1000019)
- if (FR_ISPASS(pass) && (v == 4)) {
- ip = fin->fin_ip;
- ip->ip_len = ntohs(ip->ip_len);
- ip->ip_off = ntohs(ip->ip_off);
- }
-# endif
- return (FR_ISPASS(pass)) ? 0 : fin->fin_error;
+ if (FR_ISPASS(pass))
+ return 0;
+ LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]);
+ return fin->fin_error;
#else /* _KERNEL */
+ if (*mp != NULL)
+ (*mp)->mb_ifp = fin->fin_ifp;
+ blockreason = fin->fin_reason;
FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass));
- if ((pass & FR_NOMATCH) != 0)
- return 1;
+ /*if ((pass & FR_CMDMASK) == (softc->ipf_pass & FR_CMDMASK))*/
+ if ((pass & FR_NOMATCH) != 0)
+ return 1;
if ((pass & FR_RETMASK) != 0)
switch (pass & FR_RETMASK)
@@ -2821,7 +3286,7 @@ finished:
#ifdef IPFILTER_LOG
/* ------------------------------------------------------------------------ */
-/* Function: fr_dolog */
+/* Function: ipf_dolog */
/* Returns: frentry_t* - returns contents of fin_fr (no change made) */
/* Parameters: fin(I) - pointer to packet information */
/* passp(IO) - pointer to current/new filter decision (unused) */
@@ -2829,43 +3294,47 @@ finished:
/* Checks flags set to see how a packet should be logged, if it is to be */
/* logged. Adjust statistics based on its success or not. */
/* ------------------------------------------------------------------------ */
-frentry_t *fr_dolog(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+frentry_t *
+ipf_dolog(fin, passp)
+ fr_info_t *fin;
+ u_32_t *passp;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
u_32_t pass;
int out;
out = fin->fin_out;
pass = *passp;
- if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
+ if ((softc->ipf_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
pass |= FF_LOGNOMATCH;
- ATOMIC_INCL(frstats[out].fr_npkl);
+ LBUMPD(ipf_stats[out], fr_npkl);
goto logit;
+
} else if (((pass & FR_LOGMASK) == FR_LOGP) ||
- (FR_ISPASS(pass) && (fr_flags & FF_LOGPASS))) {
+ (FR_ISPASS(pass) && (softc->ipf_flags & FF_LOGPASS))) {
if ((pass & FR_LOGMASK) != FR_LOGP)
pass |= FF_LOGPASS;
- ATOMIC_INCL(frstats[out].fr_ppkl);
+ LBUMPD(ipf_stats[out], fr_ppkl);
goto logit;
+
} else if (((pass & FR_LOGMASK) == FR_LOGB) ||
- (FR_ISBLOCK(pass) && (fr_flags & FF_LOGBLOCK))) {
+ (FR_ISBLOCK(pass) && (softc->ipf_flags & FF_LOGBLOCK))) {
if ((pass & FR_LOGMASK) != FR_LOGB)
pass |= FF_LOGBLOCK;
- ATOMIC_INCL(frstats[out].fr_bpkl);
-logit:
- if (ipflog(fin, pass) == -1) {
- ATOMIC_INCL(frstats[out].fr_skip);
+ LBUMPD(ipf_stats[out], fr_bpkl);
+logit:
+ if (ipf_log_pkt(fin, pass) == -1) {
/*
* If the "or-block" option has been used then
* block the packet if we failed to log it.
*/
- if ((pass & FR_LOGORBLOCK) &&
- FR_ISPASS(pass)) {
+ if ((pass & FR_LOGORBLOCK) && FR_ISPASS(pass)) {
+ DT1(frb_logfail2, u_int, pass);
pass &= ~FR_CMDMASK;
pass |= FR_BLOCK;
+ fin->fin_reason = FRB_LOGFAIL2;
}
}
*passp = pass;
@@ -2886,9 +3355,10 @@ logit:
/* */
/* N.B.: addr should be 16bit aligned. */
/* ------------------------------------------------------------------------ */
-u_short ipf_cksum(addr, len)
-u_short *addr;
-int len;
+u_short
+ipf_cksum(addr, len)
+ u_short *addr;
+ int len;
{
u_32_t sum = 0;
@@ -2911,11 +3381,10 @@ int len;
/* ------------------------------------------------------------------------ */
/* Function: fr_cksum */
/* Returns: u_short - layer 4 checksum */
-/* Parameters: m(I ) - pointer to buffer holding packet */
+/* Parameters: fin(I) - pointer to packet information */
/* ip(I) - pointer to IP header */
/* l4proto(I) - protocol to caclulate checksum for */
/* l4hdr(I) - pointer to layer 4 header */
-/* l3len(I) - length of layer 4 data plus layer 3 header */
/* */
/* Calculates the TCP checksum for the packet held in "m", using the data */
/* in the IP header "ip" to seed it. */
@@ -2924,31 +3393,31 @@ int len;
/* and the TCP header. We also assume that data blocks aren't allocated in */
/* odd sizes. */
/* */
-/* For IPv6, l3len excludes extension header size. */
-/* */
-/* Expects ip_len to be in host byte order when called. */
+/* Expects ip_len and ip_off to be in network byte order when called. */
/* ------------------------------------------------------------------------ */
-u_short fr_cksum(m, ip, l4proto, l4hdr, l3len)
-mb_t *m;
-ip_t *ip;
-int l4proto, l3len;
-void *l4hdr;
+u_short
+fr_cksum(fin, ip, l4proto, l4hdr)
+ fr_info_t *fin;
+ ip_t *ip;
+ int l4proto;
+ void *l4hdr;
{
- u_short *sp, slen, sumsave, l4hlen, *csump;
+ u_short *sp, slen, sumsave, *csump;
u_int sum, sum2;
int hlen;
+ int off;
#ifdef USE_INET6
ip6_t *ip6;
#endif
csump = NULL;
sumsave = 0;
- l4hlen = 0;
sp = NULL;
slen = 0;
hlen = 0;
sum = 0;
+ sum = htons((u_short)l4proto);
/*
* Add up IP Header portion
*/
@@ -2956,9 +3425,7 @@ void *l4hdr;
if (IP_V(ip) == 4) {
#endif
hlen = IP_HL(ip) << 2;
- slen = l3len - hlen;
- sum = htons((u_short)l4proto);
- sum += htons(slen);
+ off = hlen;
sp = (u_short *)&ip->ip_src;
sum += *sp++; /* ip_src */
sum += *sp++;
@@ -2968,9 +3435,7 @@ void *l4hdr;
} else if (IP_V(ip) == 6) {
ip6 = (ip6_t *)ip;
hlen = sizeof(*ip6);
- slen = l3len - hlen;
- sum = htons((u_short)l4proto);
- sum += htons(slen);
+ off = ((char *)fin->fin_dp - (char *)fin->fin_ip);
sp = (u_short *)&ip6->ip6_src;
sum += *sp++; /* ip6_src */
sum += *sp++;
@@ -2980,6 +3445,7 @@ void *l4hdr;
sum += *sp++;
sum += *sp++;
sum += *sp++;
+ /* This needs to be routing header aware. */
sum += *sp++; /* ip6_dst */
sum += *sp++;
sum += *sp++;
@@ -2988,25 +3454,31 @@ void *l4hdr;
sum += *sp++;
sum += *sp++;
sum += *sp++;
+ } else {
+ return 0xffff;
}
#endif
+ slen = fin->fin_plen - off;
+ sum += htons(slen);
switch (l4proto)
{
case IPPROTO_UDP :
csump = &((udphdr_t *)l4hdr)->uh_sum;
- l4hlen = sizeof(udphdr_t);
break;
case IPPROTO_TCP :
csump = &((tcphdr_t *)l4hdr)->th_sum;
- l4hlen = sizeof(tcphdr_t);
break;
case IPPROTO_ICMP :
csump = &((icmphdr_t *)l4hdr)->icmp_cksum;
- l4hlen = 4;
- sum = 0;
+ sum = 0; /* Pseudo-checksum is not included */
+ break;
+#ifdef USE_INET6
+ case IPPROTO_ICMPV6 :
+ csump = &((struct icmp6_hdr *)l4hdr)->icmp6_cksum;
break;
+#endif
default :
break;
}
@@ -3016,298 +3488,18 @@ void *l4hdr;
*csump = 0;
}
- l4hlen = l4hlen; /* LINT */
-
-#ifdef _KERNEL
-# ifdef MENTAT
- {
- void *rp = m->b_rptr;
-
- if ((unsigned char *)ip > m->b_rptr && (unsigned char *)ip < m->b_wptr)
- m->b_rptr = (u_char *)ip;
- sum2 = ip_cksum(m, hlen, sum); /* hlen == offset */
- m->b_rptr = rp;
- sum2 = (u_short)(~sum2 & 0xffff);
- }
-# else /* MENTAT */
-# if defined(BSD) || defined(sun)
-# if BSD >= 199103
- 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 >= 199103
- m->m_data -= hlen;
-# else
- m->m_off -= hlen;
-# endif
- /*
- * Both sum and sum2 are partial sums, so combine them together.
- */
- sum += ~sum2 & 0xffff;
- while (sum > 0xffff)
- sum = (sum & 0xffff) + (sum >> 16);
- sum2 = ~sum & 0xffff;
-# else /* defined(BSD) || defined(sun) */
-{
- union {
- u_char c[2];
- u_short s;
- } bytes;
- u_short len = ip->ip_len;
-# if defined(__sgi)
- int add;
-# endif
-
- /*
- * Add up IP Header portion
- */
- if (sp != (u_short *)l4hdr)
- sp = (u_short *)l4hdr;
-
- switch (l4proto)
- {
- case IPPROTO_UDP :
- sum += *sp++; /* sport */
- sum += *sp++; /* dport */
- sum += *sp++; /* udp length */
- sum += *sp++; /* checksum */
- break;
-
- case IPPROTO_TCP :
- sum += *sp++; /* sport */
- sum += *sp++; /* dport */
- sum += *sp++; /* seq */
- sum += *sp++;
- sum += *sp++; /* ack */
- sum += *sp++;
- sum += *sp++; /* off */
- sum += *sp++; /* win */
- sum += *sp++; /* checksum */
- sum += *sp++; /* urp */
- break;
- case IPPROTO_ICMP :
- sum = *sp++; /* type/code */
- sum += *sp++; /* checksum */
- break;
- }
-
-# ifdef __sgi
- /*
- * In case we had to copy the IP & TCP header out of mbufs,
- * skip over the mbuf bits which are the header
- */
- if ((char *)ip != mtod(m, char *)) {
- hlen = (char *)sp - (char *)ip;
- while (hlen) {
- add = MIN(hlen, m->m_len);
- sp = (u_short *)(mtod(m, caddr_t) + add);
- hlen -= add;
- if (add == m->m_len) {
- m = m->m_next;
- if (!hlen) {
- if (!m)
- break;
- sp = mtod(m, u_short *);
- }
- PANIC((!m),("fr_cksum(1): not enough data"));
- }
- }
- }
-# endif
-
- len -= (l4hlen + hlen);
- if (len <= 0)
- goto nodata;
-
- while (len > 1) {
- if (((char *)sp - mtod(m, char *)) >= m->m_len) {
- m = m->m_next;
- PANIC((!m),("fr_cksum(2): not enough data"));
- sp = mtod(m, u_short *);
- }
- if (((char *)(sp + 1) - mtod(m, char *)) > m->m_len) {
- bytes.c[0] = *(u_char *)sp;
- m = m->m_next;
- PANIC((!m),("fr_cksum(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);
- }
- if ((u_long)sp & 1) {
- bcopy((char *)sp++, (char *)&bytes.s, sizeof(bytes.s));
- sum += bytes.s;
- } else
- sum += *sp++;
- len -= 2;
- }
-
- if (len != 0)
- sum += ntohs(*(u_char *)sp << 8);
-nodata:
- while (sum > 0xffff)
- sum = (sum & 0xffff) + (sum >> 16);
- sum2 = (u_short)(~sum & 0xffff);
-}
-# endif /* defined(BSD) || defined(sun) */
-# endif /* MENTAT */
-#else /* _KERNEL */
- /*
- * Add up IP Header portion
- */
- if (sp != (u_short *)l4hdr)
- sp = (u_short *)l4hdr;
-
- for (; slen > 1; slen -= 2)
- sum += *sp++;
- if (slen)
- sum += ntohs(*(u_char *)sp << 8);
- while (sum > 0xffff)
- sum = (sum & 0xffff) + (sum >> 16);
- sum2 = (u_short)(~sum & 0xffff);
-#endif /* _KERNEL */
+ sum2 = ipf_pcksum(fin, off, sum);
if (csump != NULL)
*csump = sumsave;
return sum2;
}
-#if defined(_KERNEL) && ( ((BSD < 199103) && !defined(MENTAT)) || \
- defined(__sgi) ) && !defined(linux) && !defined(_AIX51)
-/*
- * Copyright (c) 1982, 1986, 1988, 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
- * $Id: fil.c,v 2.243.2.125 2007/10/10 09:27:20 darrenr Exp $
- */
-/*
- * Copy data from an mbuf chain starting "off" bytes from the beginning,
- * continuing for "len" bytes, into the indicated buffer.
- */
-void
-m_copydata(m, off, len, cp)
- mb_t *m;
- int off;
- int len;
- caddr_t cp;
-{
- unsigned count;
-
- if (off < 0 || len < 0)
- panic("m_copydata");
- while (off > 0) {
- if (m == 0)
- panic("m_copydata");
- if (off < m->m_len)
- break;
- off -= m->m_len;
- m = m->m_next;
- }
- while (len > 0) {
- if (m == 0)
- panic("m_copydata");
- count = MIN(m->m_len - off, len);
- bcopy(mtod(m, caddr_t) + off, cp, count);
- len -= count;
- cp += count;
- off = 0;
- m = m->m_next;
- }
-}
-
-
-/*
- * Copy data from a buffer back into the indicated mbuf chain,
- * starting "off" bytes from the beginning, extending the mbuf
- * chain if necessary.
- */
-void
-m_copyback(m0, off, len, cp)
- struct mbuf *m0;
- int off;
- int len;
- caddr_t cp;
-{
- int mlen;
- struct mbuf *m = m0, *n;
- int totlen = 0;
-
- if (m0 == 0)
- return;
- while (off > (mlen = m->m_len)) {
- off -= mlen;
- totlen += mlen;
- if (m->m_next == 0) {
- n = m_getclr(M_DONTWAIT, m->m_type);
- if (n == 0)
- goto out;
- n->m_len = min(MLEN, len + off);
- m->m_next = n;
- }
- m = m->m_next;
- }
- while (len > 0) {
- mlen = min(m->m_len - off, len);
- bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
- cp += mlen;
- len -= mlen;
- mlen += off;
- off = 0;
- totlen += mlen;
- if (len == 0)
- break;
- if (m->m_next == 0) {
- n = m_get(M_DONTWAIT, m->m_type);
- if (n == 0)
- break;
- n->m_len = min(MLEN, len);
- m->m_next = n;
- }
- m = m->m_next;
- }
-out:
-#if 0
- if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
- m->m_pkthdr.len = totlen;
-#endif
- return;
-}
-#endif /* (_KERNEL) && ( ((BSD < 199103) && !MENTAT) || __sgi) */
-
-
/* ------------------------------------------------------------------------ */
-/* Function: fr_findgroup */
+/* Function: ipf_findgroup */
/* Returns: frgroup_t * - NULL = group not found, else pointer to group */
-/* Parameters: group(I) - group name to search for */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* group(I) - group name to search for */
/* unit(I) - device to which this group belongs */
/* set(I) - which set of rules (inactive/inactive) this is */
/* fgpp(O) - pointer to place to store pointer to the pointer */
@@ -3316,11 +3508,13 @@ out:
/* */
/* Search amongst the defined groups for a particular group number. */
/* ------------------------------------------------------------------------ */
-frgroup_t *fr_findgroup(group, unit, set, fgpp)
-char *group;
-minor_t unit;
-int set;
-frgroup_t ***fgpp;
+frgroup_t *
+ipf_findgroup(softc, group, unit, set, fgpp)
+ ipf_main_softc_t *softc;
+ char *group;
+ minor_t unit;
+ int set;
+ frgroup_t ***fgpp;
{
frgroup_t *fg, **fgp;
@@ -3328,7 +3522,7 @@ frgroup_t ***fgpp;
* Which list of groups to search in is dependent on which list of
* rules are being operated on.
*/
- fgp = &ipfgroups[unit][set];
+ fgp = &softc->ipf_groups[unit][set];
while ((fg = *fgp) != NULL) {
if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0)
@@ -3343,10 +3537,11 @@ frgroup_t ***fgpp;
/* ------------------------------------------------------------------------ */
-/* Function: fr_addgroup */
+/* Function: ipf_group_add */
/* Returns: frgroup_t * - NULL == did not create group, */
/* != NULL == pointer to the group */
-/* Parameters: num(I) - group number to add */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* num(I) - group number to add */
/* head(I) - rule pointer that is using this as the head */
/* flags(I) - rule flags which describe the type of rule it is */
/* unit(I) - device to which this group will belong to */
@@ -3356,12 +3551,14 @@ frgroup_t ***fgpp;
/* Add a new group head, or if it already exists, increase the reference */
/* count to it. */
/* ------------------------------------------------------------------------ */
-frgroup_t *fr_addgroup(group, head, flags, unit, set)
-char *group;
-void *head;
-u_32_t flags;
-minor_t unit;
-int set;
+frgroup_t *
+ipf_group_add(softc, group, head, flags, unit, set)
+ ipf_main_softc_t *softc;
+ char *group;
+ void *head;
+ u_32_t flags;
+ minor_t unit;
+ int set;
{
frgroup_t *fg, **fgp;
u_32_t gflags;
@@ -3375,8 +3572,10 @@ int set;
fgp = NULL;
gflags = flags & FR_INOUT;
- fg = fr_findgroup(group, unit, set, &fgp);
+ fg = ipf_findgroup(softc, group, unit, set, &fgp);
if (fg != NULL) {
+ if (fg->fg_head == NULL && head != NULL)
+ fg->fg_head = head;
if (fg->fg_flags == 0)
fg->fg_flags = gflags;
else if (gflags != fg->fg_flags)
@@ -3384,14 +3583,16 @@ int set;
fg->fg_ref++;
return fg;
}
+
KMALLOC(fg, frgroup_t *);
if (fg != NULL) {
fg->fg_head = head;
fg->fg_start = NULL;
fg->fg_next = *fgp;
- bcopy(group, fg->fg_name, FR_GROUPLEN);
+ bcopy(group, fg->fg_name, strlen(group) + 1);
fg->fg_flags = gflags;
fg->fg_ref = 1;
+ fg->fg_set = &softc->ipf_groups[unit][set];
*fgp = fg;
}
return fg;
@@ -3399,38 +3600,82 @@ int set;
/* ------------------------------------------------------------------------ */
-/* Function: fr_delgroup */
-/* Returns: Nil */
-/* Parameters: group(I) - group name to delete */
-/* unit(I) - device to which this group belongs */
-/* set(I) - which set of rules (inactive/inactive) this is */
+/* Function: ipf_group_del */
+/* Returns: int - number of rules deleted */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* group(I) - group name to delete */
+/* fr(I) - filter rule from which group is referenced */
/* Write Locks: ipf_mutex */
/* */
-/* Attempt to delete a group head. */
-/* Only do this when its reference count reaches 0. */
+/* This function is called whenever a reference to a group is to be dropped */
+/* and thus its reference count needs to be lowered and the group free'd if */
+/* the reference count reaches zero. Passing in fr is really for the sole */
+/* purpose of knowing when the head rule is being deleted. */
/* ------------------------------------------------------------------------ */
-void fr_delgroup(group, unit, set)
-char *group;
-minor_t unit;
-int set;
+void
+ipf_group_del(softc, group, fr)
+ ipf_main_softc_t *softc;
+ frgroup_t *group;
+ frentry_t *fr;
{
- frgroup_t *fg, **fgp;
- fg = fr_findgroup(group, unit, set, &fgp);
- if (fg == NULL)
- return;
+ if (group->fg_head == fr)
+ group->fg_head = NULL;
+
+ group->fg_ref--;
+ if ((group->fg_ref == 0) && (group->fg_start == NULL))
+ ipf_group_free(group);
+}
+
- fg->fg_ref--;
- if (fg->fg_ref == 0) {
- *fgp = fg->fg_next;
- KFREE(fg);
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_group_free */
+/* Returns: Nil */
+/* Parameters: group(I) - pointer to filter rule group */
+/* */
+/* Remove the group from the list of groups and free it. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_group_free(group)
+ frgroup_t *group;
+{
+ frgroup_t **gp;
+
+ for (gp = group->fg_set; *gp != NULL; gp = &(*gp)->fg_next) {
+ if (*gp == group) {
+ *gp = group->fg_next;
+ break;
+ }
}
+ KFREE(group);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_getrulen */
+/* Function: ipf_group_flush */
+/* Returns: int - number of rules flush from group */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* Parameters: group(I) - pointer to filter rule group */
+/* */
+/* Remove all of the rules that currently are listed under the given group. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_group_flush(softc, group)
+ ipf_main_softc_t *softc;
+ frgroup_t *group;
+{
+ int gone = 0;
+
+ (void) ipf_flushlist(softc, &gone, &group->fg_start);
+
+ return gone;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_getrulen */
/* Returns: frentry_t * - NULL == not found, else pointer to rule n */
+/* Parameters: softc(I) - pointer to soft context main structure */
/* Parameters: unit(I) - device for which to count the rule's number */
/* flags(I) - which set of rules to find the rule in */
/* group(I) - group name */
@@ -3439,18 +3684,20 @@ int set;
/* Find rule # n in group # g and return a pointer to it. Return NULl if */
/* group # g doesn't exist or there are less than n rules in the group. */
/* ------------------------------------------------------------------------ */
-frentry_t *fr_getrulen(unit, group, n)
-int unit;
-char *group;
-u_32_t n;
+frentry_t *
+ipf_getrulen(softc, unit, group, n)
+ ipf_main_softc_t *softc;
+ int unit;
+ char *group;
+ u_32_t n;
{
frentry_t *fr;
frgroup_t *fg;
- fg = fr_findgroup(group, unit, fr_active, NULL);
+ fg = ipf_findgroup(softc, group, unit, softc->ipf_active, NULL);
if (fg == NULL)
return NULL;
- for (fr = fg->fg_head; fr && n; fr = fr->fr_next, n--)
+ for (fr = fg->fg_start; fr && n; fr = fr->fr_next, n--)
;
if (n != 0)
return NULL;
@@ -3459,41 +3706,9 @@ u_32_t n;
/* ------------------------------------------------------------------------ */
-/* Function: fr_rulen */
-/* Returns: int - >= 0 - rule number, -1 == search failed */
-/* Parameters: unit(I) - device for which to count the rule's number */
-/* fr(I) - pointer to rule to match */
-/* */
-/* Return the number for a rule on a specific filtering device. */
-/* ------------------------------------------------------------------------ */
-int fr_rulen(unit, fr)
-int unit;
-frentry_t *fr;
-{
- frentry_t *fh;
- frgroup_t *fg;
- u_32_t n = 0;
-
- if (fr == NULL)
- return -1;
- fg = fr_findgroup(fr->fr_group, unit, fr_active, NULL);
- if (fg == NULL)
- return -1;
- for (fh = fg->fg_head; fh; n++, fh = fh->fr_next)
- if (fh == fr)
- break;
- if (fh == NULL)
- return -1;
- return n;
-}
-
-
-/* ------------------------------------------------------------------------ */
-/* Function: frflushlist */
+/* Function: ipf_flushlist */
/* Returns: int - >= 0 - number of flushed rules */
-/* Parameters: set(I) - which set of rules (inactive/inactive) this is */
-/* unit(I) - device for which to flush rules */
-/* flags(I) - which set of rules to flush */
+/* Parameters: softc(I) - pointer to soft context main structure */
/* nfreedp(O) - pointer to int where flush count is stored */
/* listp(I) - pointer to list to flush pointer */
/* Write Locks: ipf_mutex */
@@ -3507,11 +3722,11 @@ frentry_t *fr;
/* */
/* NOTE: Rules not loaded from user space cannot be flushed. */
/* ------------------------------------------------------------------------ */
-static int frflushlist(set, unit, nfreedp, listp)
-int set;
-minor_t unit;
-int *nfreedp;
-frentry_t **listp;
+static int
+ipf_flushlist(softc, nfreedp, listp)
+ ipf_main_softc_t *softc;
+ int *nfreedp;
+ frentry_t **listp;
{
int freed = 0;
frentry_t *fp;
@@ -3523,18 +3738,27 @@ frentry_t **listp;
continue;
}
*listp = fp->fr_next;
- if (fp->fr_grp != NULL) {
- (void) frflushlist(set, unit, nfreedp, fp->fr_grp);
+ if (fp->fr_next != NULL)
+ fp->fr_next->fr_pnext = fp->fr_pnext;
+ fp->fr_pnext = NULL;
+
+ if (fp->fr_grphead != NULL) {
+ freed += ipf_group_flush(softc, fp->fr_grphead);
+ fp->fr_names[fp->fr_grhead] = '\0';
}
- if (fp->fr_grhead != NULL) {
- fr_delgroup(fp->fr_grhead, unit, set);
- *fp->fr_grhead = '\0';
+ if (fp->fr_icmpgrp != NULL) {
+ freed += ipf_group_flush(softc, fp->fr_icmpgrp);
+ fp->fr_names[fp->fr_icmphead] = '\0';
}
- ASSERT(fp->fr_ref > 0);
+ if (fp->fr_srctrack.ht_max_nodes)
+ ipf_rb_ht_flush(&fp->fr_srctrack);
+
fp->fr_next = NULL;
- if (fr_derefrule(&fp) == 0)
+
+ ASSERT(fp->fr_ref > 0);
+ if (ipf_derefrule(softc, &fp) == 0)
freed++;
}
*nfreedp += freed;
@@ -3543,61 +3767,47 @@ frentry_t **listp;
/* ------------------------------------------------------------------------ */
-/* Function: frflush */
+/* Function: ipf_flush */
/* Returns: int - >= 0 - number of flushed rules */
-/* Parameters: unit(I) - device for which to flush rules */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* unit(I) - device for which to flush rules */
/* flags(I) - which set of rules to flush */
/* */
/* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */
/* and IPv6) as defined by the value of flags. */
/* ------------------------------------------------------------------------ */
-int frflush(unit, proto, flags)
-minor_t unit;
-int proto, flags;
+int
+ipf_flush(softc, unit, flags)
+ ipf_main_softc_t *softc;
+ minor_t unit;
+ int flags;
{
int flushed = 0, set;
- WRITE_ENTER(&ipf_mutex);
- bzero((char *)frcache, sizeof(frcache));
+ WRITE_ENTER(&softc->ipf_mutex);
- set = fr_active;
+ set = softc->ipf_active;
if ((flags & FR_INACTIVE) == FR_INACTIVE)
set = 1 - set;
if (flags & FR_OUTQUE) {
- if (proto == 0 || proto == 6) {
- (void) frflushlist(set, unit,
- &flushed, &ipfilter6[1][set]);
- (void) frflushlist(set, unit,
- &flushed, &ipacct6[1][set]);
- }
- if (proto == 0 || proto == 4) {
- (void) frflushlist(set, unit,
- &flushed, &ipfilter[1][set]);
- (void) frflushlist(set, unit,
- &flushed, &ipacct[1][set]);
- }
+ ipf_flushlist(softc, &flushed, &softc->ipf_rules[1][set]);
+ ipf_flushlist(softc, &flushed, &softc->ipf_acct[1][set]);
}
if (flags & FR_INQUE) {
- if (proto == 0 || proto == 6) {
- (void) frflushlist(set, unit,
- &flushed, &ipfilter6[0][set]);
- (void) frflushlist(set, unit,
- &flushed, &ipacct6[0][set]);
- }
- if (proto == 0 || proto == 4) {
- (void) frflushlist(set, unit,
- &flushed, &ipfilter[0][set]);
- (void) frflushlist(set, unit,
- &flushed, &ipacct[0][set]);
- }
+ ipf_flushlist(softc, &flushed, &softc->ipf_rules[0][set]);
+ ipf_flushlist(softc, &flushed, &softc->ipf_acct[0][set]);
}
- RWLOCK_EXIT(&ipf_mutex);
+
+ flushed += ipf_flush_groups(softc, &softc->ipf_groups[unit][set],
+ flags & (FR_INQUE|FR_OUTQUE));
+
+ RWLOCK_EXIT(&softc->ipf_mutex);
if (unit == IPL_LOGIPF) {
int tmp;
- tmp = frflush(IPL_LOGCOUNT, proto, flags);
+ tmp = ipf_flush(softc, IPL_LOGCOUNT, flags);
if (tmp >= 0)
flushed += tmp;
}
@@ -3606,6 +3816,59 @@ int proto, flags;
/* ------------------------------------------------------------------------ */
+/* Function: ipf_flush_groups */
+/* Returns: int - >= 0 - number of flushed rules */
+/* Parameters: softc(I) - soft context pointerto work with */
+/* grhead(I) - pointer to the start of the group list to flush */
+/* flags(I) - which set of rules to flush */
+/* */
+/* Walk through all of the groups under the given group head and remove all */
+/* of those that match the flags passed in. The for loop here is bit more */
+/* complicated than usual because the removal of a rule with ipf_derefrule */
+/* may end up removing not only the structure pointed to by "fg" but also */
+/* what is fg_next and fg_next after that. So if a filter rule is actually */
+/* removed from the group then it is necessary to start again. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_flush_groups(softc, grhead, flags)
+ ipf_main_softc_t *softc;
+ frgroup_t **grhead;
+ int flags;
+{
+ frentry_t *fr, **frp;
+ frgroup_t *fg, **fgp;
+ int flushed = 0;
+ int removed = 0;
+
+ for (fgp = grhead; (fg = *fgp) != NULL; ) {
+ while ((fg != NULL) && ((fg->fg_flags & flags) == 0))
+ fg = fg->fg_next;
+ if (fg == NULL)
+ break;
+ removed = 0;
+ frp = &fg->fg_start;
+ while ((removed == 0) && ((fr = *frp) != NULL)) {
+ if ((fr->fr_flags & flags) == 0) {
+ frp = &fr->fr_next;
+ } else {
+ if (fr->fr_next != NULL)
+ fr->fr_next->fr_pnext = fr->fr_pnext;
+ *frp = fr->fr_next;
+ fr->fr_pnext = NULL;
+ fr->fr_next = NULL;
+ (void) ipf_derefrule(softc, &fr);
+ flushed++;
+ removed++;
+ }
+ }
+ if (removed == 0)
+ fgp = &fg->fg_next;
+ }
+ return flushed;
+}
+
+
+/* ------------------------------------------------------------------------ */
/* Function: memstr */
/* Returns: char * - NULL if failed, != NULL pointer to matching bytes */
/* Parameters: src(I) - pointer to byte sequence to match */
@@ -3616,10 +3879,11 @@ int proto, flags;
/* Search dst for a sequence of bytes matching those at src and extend for */
/* slen bytes. */
/* ------------------------------------------------------------------------ */
-char *memstr(src, dst, slen, dlen)
-const char *src;
-char *dst;
-size_t slen, dlen;
+char *
+memstr(src, dst, slen, dlen)
+ const char *src;
+ char *dst;
+ size_t slen, dlen;
{
char *s = NULL;
@@ -3634,7 +3898,7 @@ size_t slen, dlen;
return s;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_fixskip */
+/* Function: ipf_fixskip */
/* Returns: Nil */
/* Parameters: listp(IO) - pointer to start of list with skip rule */
/* rp(I) - rule added/removed with skip in it. */
@@ -3645,9 +3909,10 @@ size_t slen, dlen;
/* Adjust all the rules in a list which would have skip'd past the position */
/* where we are inserting to skip to the right place given the change. */
/* ------------------------------------------------------------------------ */
-void fr_fixskip(listp, rp, addremove)
-frentry_t **listp, *rp;
-int addremove;
+void
+ipf_fixskip(listp, rp, addremove)
+ frentry_t **listp, *rp;
+ int addremove;
{
int rules, rn;
frentry_t *fp;
@@ -3676,8 +3941,9 @@ int addremove;
/* consecutive 1's is different to that passed, return -1, else return # */
/* of bits. */
/* ------------------------------------------------------------------------ */
-int count4bits(ip)
-u_32_t ip;
+int
+count4bits(ip)
+ u_32_t ip;
{
u_32_t ipn;
int cnt = 0, i, j;
@@ -3700,7 +3966,6 @@ u_32_t ip;
}
-# if 0
/* ------------------------------------------------------------------------ */
/* Function: count6bits */
/* Returns: int - >= 0 - number of consecutive bits in input */
@@ -3709,8 +3974,10 @@ u_32_t ip;
/* IPv6 ONLY */
/* count consecutive 1's in bit mask. */
/* ------------------------------------------------------------------------ */
-int count6bits(msk)
-u_32_t *msk;
+# ifdef USE_INET6
+int
+count6bits(msk)
+ u_32_t *msk;
{
int i = 0, k;
u_32_t j;
@@ -3730,8 +3997,8 @@ u_32_t *msk;
/* ------------------------------------------------------------------------ */
-/* Function: frsynclist */
-/* Returns: void */
+/* Function: ipf_synclist */
+/* Returns: int - 0 = no failures, else indication of first failure */
/* Parameters: fr(I) - start of filter list to sync interface names for */
/* ifp(I) - interface pointer for limiting sync lookups */
/* Write Locks: ipf_mutex */
@@ -3740,16 +4007,33 @@ u_32_t *msk;
/* pointers. Where dynamic addresses are used, also update the IP address */
/* used in the rule. The interface pointer is used to limit the lookups to */
/* a specific set of matching names if it is non-NULL. */
-/* ------------------------------------------------------------------------ */
-static void frsynclist(fr, ifp)
-frentry_t *fr;
-void *ifp;
+/* Errors can occur when resolving the destination name of to/dup-to fields */
+/* when the name points to a pool and that pool doest not exist. If this */
+/* does happen then it is necessary to check if there are any lookup refs */
+/* that need to be dropped before returning with an error. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_synclist(softc, fr, ifp)
+ ipf_main_softc_t *softc;
+ frentry_t *fr;
+ void *ifp;
{
+ frentry_t *frt, *start = fr;
frdest_t *fdp;
+ char *name;
+ int error;
+ void *ifa;
int v, i;
+ error = 0;
+
for (; fr; fr = fr->fr_next) {
- v = fr->fr_v;
+ if (fr->fr_family == AF_INET)
+ v = 4;
+ else if (fr->fr_family == AF_INET6)
+ v = 6;
+ else
+ v = 0;
/*
* Lookup all the interface names that are part of the rule.
@@ -3757,102 +4041,124 @@ void *ifp;
for (i = 0; i < 4; i++) {
if ((ifp != NULL) && (fr->fr_ifas[i] != ifp))
continue;
- fr->fr_ifas[i] = fr_resolvenic(fr->fr_ifnames[i], v);
+ if (fr->fr_ifnames[i] == -1)
+ continue;
+ name = FR_NAME(fr, fr_ifnames[i]);
+ fr->fr_ifas[i] = ipf_resolvenic(softc, name, v);
}
- if (fr->fr_type == FR_T_IPF) {
+ if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) {
if (fr->fr_satype != FRI_NORMAL &&
fr->fr_satype != FRI_LOOKUP) {
- (void)fr_ifpaddr(v, fr->fr_satype,
- fr->fr_ifas[fr->fr_sifpidx],
- &fr->fr_src, &fr->fr_smsk);
+ ifa = ipf_resolvenic(softc, fr->fr_names +
+ fr->fr_sifpidx, v);
+ ipf_ifpaddr(softc, v, fr->fr_satype, ifa,
+ &fr->fr_src6, &fr->fr_smsk6);
}
if (fr->fr_datype != FRI_NORMAL &&
fr->fr_datype != FRI_LOOKUP) {
- (void)fr_ifpaddr(v, fr->fr_datype,
- fr->fr_ifas[fr->fr_difpidx],
- &fr->fr_dst, &fr->fr_dmsk);
+ ifa = ipf_resolvenic(softc, fr->fr_names +
+ fr->fr_sifpidx, v);
+ ipf_ifpaddr(softc, v, fr->fr_datype, ifa,
+ &fr->fr_dst6, &fr->fr_dmsk6);
}
}
fdp = &fr->fr_tifs[0];
- if ((ifp == NULL) || (fdp->fd_ifp == ifp))
- fr_resolvedest(fdp, v);
+ if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
+ error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
+ if (error != 0)
+ goto unwind;
+ }
fdp = &fr->fr_tifs[1];
- if ((ifp == NULL) || (fdp->fd_ifp == ifp))
- fr_resolvedest(fdp, v);
+ if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
+ error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
+ if (error != 0)
+ goto unwind;
+ }
fdp = &fr->fr_dif;
- if ((ifp == NULL) || (fdp->fd_ifp == ifp)) {
- fr_resolvedest(fdp, v);
-
- fr->fr_flags &= ~FR_DUP;
- if ((fdp->fd_ifp != (void *)-1) &&
- (fdp->fd_ifp != NULL))
- fr->fr_flags |= FR_DUP;
- }
-
-#ifdef IPFILTER_LOOKUP
- if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP &&
- fr->fr_srcptr == NULL) {
- fr->fr_srcptr = fr_resolvelookup(fr->fr_srctype,
- fr->fr_srcsubtype,
- &fr->fr_slookup,
- &fr->fr_srcfunc);
- }
- if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP &&
- fr->fr_dstptr == NULL) {
- fr->fr_dstptr = fr_resolvelookup(fr->fr_dsttype,
- fr->fr_dstsubtype,
- &fr->fr_dlookup,
- &fr->fr_dstfunc);
+ if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
+ error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
+ if (error != 0)
+ goto unwind;
+ }
+
+ if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
+ (fr->fr_satype == FRI_LOOKUP) && (fr->fr_srcptr == NULL)) {
+ fr->fr_srcptr = ipf_lookup_res_num(softc,
+ fr->fr_srctype,
+ IPL_LOGIPF,
+ fr->fr_srcnum,
+ &fr->fr_srcfunc);
+ }
+ if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
+ (fr->fr_datype == FRI_LOOKUP) && (fr->fr_dstptr == NULL)) {
+ fr->fr_dstptr = ipf_lookup_res_num(softc,
+ fr->fr_dsttype,
+ IPL_LOGIPF,
+ fr->fr_dstnum,
+ &fr->fr_dstfunc);
}
-#endif
}
+ return 0;
+
+unwind:
+ for (frt = start; frt != fr; fr = fr->fr_next) {
+ if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
+ (frt->fr_satype == FRI_LOOKUP) && (frt->fr_srcptr != NULL))
+ ipf_lookup_deref(softc, frt->fr_srctype,
+ frt->fr_srcptr);
+ if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
+ (frt->fr_datype == FRI_LOOKUP) && (frt->fr_dstptr != NULL))
+ ipf_lookup_deref(softc, frt->fr_dsttype,
+ frt->fr_dstptr);
+ }
+ return error;
}
-#ifdef _KERNEL
/* ------------------------------------------------------------------------ */
-/* Function: frsync */
+/* Function: ipf_sync */
/* Returns: void */
/* Parameters: Nil */
/* */
-/* frsync() is called when we suspect that the interface list or */
+/* ipf_sync() is called when we suspect that the interface list or */
/* information about interfaces (like IP#) has changed. Go through all */
/* filter rules, NAT entries and the state table and check if anything */
/* needs to be changed/updated. */
/* ------------------------------------------------------------------------ */
-void frsync(ifp)
-void *ifp;
+int
+ipf_sync(softc, ifp)
+ ipf_main_softc_t *softc;
+ void *ifp;
{
int i;
# if !SOLARIS
- fr_natsync(ifp);
- fr_statesync(ifp);
+ ipf_nat_sync(softc, ifp);
+ ipf_state_sync(softc, ifp);
+ ipf_lookup_sync(softc, ifp);
# endif
- WRITE_ENTER(&ipf_mutex);
- frsynclist(ipacct[0][fr_active], ifp);
- frsynclist(ipacct[1][fr_active], ifp);
- frsynclist(ipfilter[0][fr_active], ifp);
- frsynclist(ipfilter[1][fr_active], ifp);
- frsynclist(ipacct6[0][fr_active], ifp);
- frsynclist(ipacct6[1][fr_active], ifp);
- frsynclist(ipfilter6[0][fr_active], ifp);
- frsynclist(ipfilter6[1][fr_active], ifp);
+ WRITE_ENTER(&softc->ipf_mutex);
+ (void) ipf_synclist(softc, softc->ipf_acct[0][softc->ipf_active], ifp);
+ (void) ipf_synclist(softc, softc->ipf_acct[1][softc->ipf_active], ifp);
+ (void) ipf_synclist(softc, softc->ipf_rules[0][softc->ipf_active], ifp);
+ (void) ipf_synclist(softc, softc->ipf_rules[1][softc->ipf_active], ifp);
for (i = 0; i < IPL_LOGSIZE; i++) {
frgroup_t *g;
- for (g = ipfgroups[i][0]; g != NULL; g = g->fg_next)
- frsynclist(g->fg_start, ifp);
- for (g = ipfgroups[i][1]; g != NULL; g = g->fg_next)
- frsynclist(g->fg_start, ifp);
+ for (g = softc->ipf_groups[i][0]; g != NULL; g = g->fg_next)
+ (void) ipf_synclist(softc, g->fg_start, ifp);
+ for (g = softc->ipf_groups[i][1]; g != NULL; g = g->fg_next)
+ (void) ipf_synclist(softc, g->fg_start, ifp);
}
- RWLOCK_EXIT(&ipf_mutex);
+ RWLOCK_EXIT(&softc->ipf_mutex);
+
+ return 0;
}
@@ -3872,9 +4178,11 @@ void *ifp;
/* to start copying from (src) and a pointer to where to store it (dst). */
/* NB: src - pointer to user space pointer, dst - kernel space pointer */
/* ------------------------------------------------------------------------ */
-int copyinptr(src, dst, size)
-void *src, *dst;
-size_t size;
+int
+copyinptr(softc, src, dst, size)
+ ipf_main_softc_t *softc;
+ void *src, *dst;
+ size_t size;
{
caddr_t ca;
int error;
@@ -3887,8 +4195,10 @@ size_t size;
bcopy(src, (caddr_t)&ca, sizeof(ca));
# endif
error = COPYIN(ca, dst, size);
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(3);
error = EFAULT;
+ }
return error;
}
@@ -3904,24 +4214,29 @@ size_t size;
/* to start copying from (src) and a pointer to where to store it (dst). */
/* NB: src - kernel space pointer, dst - pointer to user space pointer. */
/* ------------------------------------------------------------------------ */
-int copyoutptr(src, dst, size)
-void *src, *dst;
-size_t size;
+int
+copyoutptr(softc, src, dst, size)
+ ipf_main_softc_t *softc;
+ void *src, *dst;
+ size_t size;
{
caddr_t ca;
int error;
bcopy(dst, (caddr_t)&ca, sizeof(ca));
error = COPYOUT(src, ca, size);
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(4);
error = EFAULT;
+ }
return error;
}
+#ifdef _KERNEL
#endif
/* ------------------------------------------------------------------------ */
-/* Function: fr_lock */
+/* Function: ipf_lock */
/* Returns: int - 0 = success, else error */
/* Parameters: data(I) - pointer to lock value to set */
/* lockp(O) - pointer to location to store old lock value */
@@ -3929,9 +4244,10 @@ size_t size;
/* Get the new value for the lock integer, set it and return the old value */
/* in *lockp. */
/* ------------------------------------------------------------------------ */
-int fr_lock(data, lockp)
-caddr_t data;
-int *lockp;
+int
+ipf_lock(data, lockp)
+ caddr_t data;
+ int *lockp;
{
int arg, err;
@@ -3947,51 +4263,78 @@ int *lockp;
/* ------------------------------------------------------------------------ */
-/* Function: fr_getstat */
+/* Function: ipf_getstat */
/* Returns: Nil */
-/* Parameters: fiop(I) - pointer to ipfilter stats structure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* fiop(I) - pointer to ipfilter stats structure */
+/* rev(I) - version claim by program doing ioctl */
/* */
/* Stores a copy of current pointers, counters, etc, in the friostat */
/* structure. */
-/* ------------------------------------------------------------------------ */
-void fr_getstat(fiop)
-friostat_t *fiop;
+/* If IPFILTER_COMPAT is compiled, we pretend to be whatever version the */
+/* program is looking for. This ensure that validation of the version it */
+/* expects will always succeed. Thus kernels with IPFILTER_COMPAT will */
+/* allow older binaries to work but kernels without it will not. */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+static void
+ipf_getstat(softc, fiop, rev)
+ ipf_main_softc_t *softc;
+ friostat_t *fiop;
+ int rev;
{
- int i, j;
-
- bcopy((char *)frstats, (char *)fiop->f_st, sizeof(filterstats_t) * 2);
- fiop->f_locks[IPL_LOGSTATE] = fr_state_lock;
- fiop->f_locks[IPL_LOGNAT] = fr_nat_lock;
- fiop->f_locks[IPL_LOGIPF] = fr_frag_lock;
- fiop->f_locks[IPL_LOGAUTH] = fr_auth_lock;
-
- for (i = 0; i < 2; i++)
- for (j = 0; j < 2; j++) {
- fiop->f_ipf[i][j] = ipfilter[i][j];
- fiop->f_acct[i][j] = ipacct[i][j];
- fiop->f_ipf6[i][j] = ipfilter6[i][j];
- fiop->f_acct6[i][j] = ipacct6[i][j];
- }
-
- fiop->f_ticks = fr_ticks;
- fiop->f_active = fr_active;
- fiop->f_froute[0] = fr_frouteok[0];
- fiop->f_froute[1] = fr_frouteok[1];
+ int i;
- fiop->f_running = fr_running;
+ bcopy((char *)softc->ipf_stats, (char *)fiop->f_st,
+ sizeof(ipf_statistics_t) * 2);
+ fiop->f_locks[IPL_LOGSTATE] = -1;
+ fiop->f_locks[IPL_LOGNAT] = -1;
+ fiop->f_locks[IPL_LOGIPF] = -1;
+ fiop->f_locks[IPL_LOGAUTH] = -1;
+
+ fiop->f_ipf[0][0] = softc->ipf_rules[0][0];
+ fiop->f_acct[0][0] = softc->ipf_acct[0][0];
+ fiop->f_ipf[0][1] = softc->ipf_rules[0][1];
+ fiop->f_acct[0][1] = softc->ipf_acct[0][1];
+ fiop->f_ipf[1][0] = softc->ipf_rules[1][0];
+ fiop->f_acct[1][0] = softc->ipf_acct[1][0];
+ fiop->f_ipf[1][1] = softc->ipf_rules[1][1];
+ fiop->f_acct[1][1] = softc->ipf_acct[1][1];
+
+ fiop->f_ticks = softc->ipf_ticks;
+ fiop->f_active = softc->ipf_active;
+ fiop->f_froute[0] = softc->ipf_frouteok[0];
+ fiop->f_froute[1] = softc->ipf_frouteok[1];
+ fiop->f_rb_no_mem = softc->ipf_rb_no_mem;
+ fiop->f_rb_node_max = softc->ipf_rb_node_max;
+
+ fiop->f_running = softc->ipf_running;
for (i = 0; i < IPL_LOGSIZE; i++) {
- fiop->f_groups[i][0] = ipfgroups[i][0];
- fiop->f_groups[i][1] = ipfgroups[i][1];
+ fiop->f_groups[i][0] = softc->ipf_groups[i][0];
+ fiop->f_groups[i][1] = softc->ipf_groups[i][1];
}
#ifdef IPFILTER_LOG
+ fiop->f_log_ok = ipf_log_logok(softc, IPL_LOGIPF);
+ fiop->f_log_fail = ipf_log_failures(softc, IPL_LOGIPF);
fiop->f_logging = 1;
#else
+ fiop->f_log_ok = 0;
+ fiop->f_log_fail = 0;
fiop->f_logging = 0;
#endif
- fiop->f_defpass = fr_pass;
- fiop->f_features = fr_features;
+ fiop->f_defpass = softc->ipf_pass;
+ fiop->f_features = ipf_features;
+
+#ifdef IPFILTER_COMPAT
+ sprintf(fiop->f_version, "IP Filter: v%d.%d.%d",
+ (rev / 1000000) % 100,
+ (rev / 10000) % 100,
+ (rev / 100) % 100);
+#else
+ rev = rev;
(void) strncpy(fiop->f_version, ipfilter_version,
sizeof(fiop->f_version));
+#endif
}
@@ -4042,7 +4385,7 @@ int icmpreplytype4[ICMP_MAXTYPE + 1];
/* ------------------------------------------------------------------------ */
-/* Function: fr_matchicmpqueryreply */
+/* Function: ipf_matchicmpqueryreply */
/* Returns: int - 1 if "icmp" is a valid reply to "ic" else 0. */
/* Parameters: v(I) - IP protocol version (4 or 6) */
/* ic(I) - ICMP information */
@@ -4053,11 +4396,12 @@ int icmpreplytype4[ICMP_MAXTYPE + 1];
/* reply to one as described by what's in ic. If it is a match, return 1, */
/* else return 0 for no match. */
/* ------------------------------------------------------------------------ */
-int fr_matchicmpqueryreply(v, ic, icmp, rev)
-int v;
-icmpinfo_t *ic;
-icmphdr_t *icmp;
-int rev;
+int
+ipf_matchicmpqueryreply(v, ic, icmp, rev)
+ int v;
+ icmpinfo_t *ic;
+ icmphdr_t *icmp;
+ int rev;
{
int ictype;
@@ -4091,88 +4435,6 @@ int rev;
}
-#ifdef IPFILTER_LOOKUP
-/* ------------------------------------------------------------------------ */
-/* Function: fr_resolvelookup */
-/* Returns: void * - NULL = failure, else success. */
-/* Parameters: type(I) - type of lookup these parameters are for. */
-/* subtype(I) - whether the info below contains number/name */
-/* info(I) - pointer to name/number of the lookup data */
-/* funcptr(IO) - pointer to pointer for storing IP address */
-/* searching function. */
-/* */
-/* Search for the "table" number passed in amongst those configured for */
-/* that particular type. If the type is recognised then the function to */
-/* call to do the IP address search will be change, regardless of whether */
-/* or not the "table" number exists. */
-/* ------------------------------------------------------------------------ */
-static void *fr_resolvelookup(type, subtype, info, funcptr)
-u_int type, subtype;
-i6addr_t *info;
-lookupfunc_t *funcptr;
-{
- char label[FR_GROUPLEN], *name;
- iphtable_t *iph;
- ip_pool_t *ipo;
- void *ptr;
-
- if (subtype == 0) {
-#if defined(SNPRINTF) && defined(_KERNEL)
- SNPRINTF(label, sizeof(label), "%u", info->iplookupnum);
-#else
- (void) sprintf(label, "%u", info->iplookupnum);
-#endif
- name = label;
- } else if (subtype == 1) {
- /*
- * Because iplookupname is currently only a 12 character
- * string and FR_GROUPLEN is 16, copy all of it into the
- * label buffer and add on a NULL at the end.
- */
- strncpy(label, info->iplookupname, sizeof(info->iplookupname));
- label[sizeof(info->iplookupname)] = '\0';
- name = label;
- } else {
- return NULL;
- }
-
- READ_ENTER(&ip_poolrw);
-
- switch (type)
- {
- case IPLT_POOL :
-# if (defined(__osf__) && defined(_KERNEL))
- ptr = NULL;
- *funcptr = NULL;
-# else
- ipo = ip_pool_find(IPL_LOGIPF, name);
- ptr = ipo;
- if (ipo != NULL) {
- ATOMIC_INC32(ipo->ipo_ref);
- }
- *funcptr = ip_pool_search;
-# endif
- break;
- case IPLT_HASH :
- iph = fr_findhtable(IPL_LOGIPF, name);
- ptr = iph;
- if (iph != NULL) {
- ATOMIC_INC32(iph->iph_ref);
- }
- *funcptr = fr_iphmfindip;
- break;
- default:
- ptr = NULL;
- *funcptr = NULL;
- break;
- }
- RWLOCK_EXIT(&ip_poolrw);
-
- return ptr;
-}
-#endif
-
-
/* ------------------------------------------------------------------------ */
/* Function: frrequest */
/* Returns: int - 0 == success, > 0 == errno value */
@@ -4190,54 +4452,98 @@ lookupfunc_t *funcptr;
/* of the rule structure being loaded. If a rule has user defined timeouts */
/* then make sure they are created and initialised before exiting. */
/* ------------------------------------------------------------------------ */
-int frrequest(unit, req, data, set, makecopy)
-int unit;
-ioctlcmd_t req;
-int set, makecopy;
-caddr_t data;
+int
+frrequest(softc, unit, req, data, set, makecopy)
+ ipf_main_softc_t *softc;
+ int unit;
+ ioctlcmd_t req;
+ int set, makecopy;
+ caddr_t data;
{
+ int error = 0, in, family, addrem, need_free = 0;
frentry_t frd, *fp, *f, **fprev, **ftail;
- int error = 0, in, v;
- void *ptr, *uptr;
+ void *ptr, *uptr, *cptr;
u_int *p, *pp;
frgroup_t *fg;
char *group;
+ ptr = NULL;
+ cptr = NULL;
fg = NULL;
fp = &frd;
if (makecopy != 0) {
- error = fr_inobj(data, fp, IPFOBJ_FRENTRY);
- if (error)
- return EFAULT;
- if ((fp->fr_flags & FR_T_BUILTIN) != 0)
+ bzero(fp, sizeof(frd));
+ error = ipf_inobj(softc, data, NULL, fp, IPFOBJ_FRENTRY);
+ if (error) {
+ return error;
+ }
+ if ((fp->fr_type & FR_T_BUILTIN) != 0) {
+ IPFERROR(6);
return EINVAL;
+ }
+ KMALLOCS(f, frentry_t *, fp->fr_size);
+ if (f == NULL) {
+ IPFERROR(131);
+ return ENOMEM;
+ }
+ bzero(f, fp->fr_size);
+ error = ipf_inobjsz(softc, data, f, IPFOBJ_FRENTRY,
+ fp->fr_size);
+ if (error) {
+ KFREES(f, fp->fr_size);
+ return error;
+ }
+
+ fp = f;
+ f = NULL;
+ fp->fr_dnext = NULL;
fp->fr_ref = 0;
fp->fr_flags |= FR_COPIED;
} else {
fp = (frentry_t *)data;
- if ((fp->fr_type & FR_T_BUILTIN) == 0)
+ if ((fp->fr_type & FR_T_BUILTIN) == 0) {
+ IPFERROR(7);
return EINVAL;
+ }
fp->fr_flags &= ~FR_COPIED;
}
if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) ||
- ((fp->fr_dsize != 0) && (fp->fr_data == NULL)))
- return EINVAL;
+ ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) {
+ IPFERROR(8);
+ error = EINVAL;
+ goto donenolock;
+ }
- v = fp->fr_v;
+ family = fp->fr_family;
uptr = fp->fr_data;
+ if (req == (ioctlcmd_t)SIOCINAFR || req == (ioctlcmd_t)SIOCINIFR ||
+ req == (ioctlcmd_t)SIOCADAFR || req == (ioctlcmd_t)SIOCADIFR)
+ addrem = 0;
+ else if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR)
+ addrem = 1;
+ else if (req == (ioctlcmd_t)SIOCZRLST)
+ addrem = 2;
+ else {
+ IPFERROR(9);
+ error = EINVAL;
+ goto donenolock;
+ }
+
/*
* Only filter rules for IPv4 or IPv6 are accepted.
*/
- if (v == 4)
+ if (family == AF_INET) {
/*EMPTY*/;
#ifdef USE_INET6
- else if (v == 6)
+ } else if (family == AF_INET6) {
/*EMPTY*/;
#endif
- else {
- return EINVAL;
+ } else if (family != 0) {
+ IPFERROR(10);
+ error = EINVAL;
+ goto donenolock;
}
/*
@@ -4246,37 +4552,110 @@ caddr_t data;
* rule.
*/
if ((makecopy == 1) && (fp->fr_func != NULL)) {
- if (fr_findfunc(fp->fr_func) == NULL)
- return ESRCH;
- error = fr_funcinit(fp);
- if (error != 0)
- return error;
+ if (ipf_findfunc(fp->fr_func) == NULL) {
+ IPFERROR(11);
+ error = ESRCH;
+ goto donenolock;
+ }
+
+ if (addrem == 0) {
+ error = ipf_funcinit(softc, fp);
+ if (error != 0)
+ goto donenolock;
+ }
+ }
+ if ((fp->fr_flags & FR_CALLNOW) &&
+ ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) {
+ IPFERROR(142);
+ error = ESRCH;
+ goto donenolock;
+ }
+ if (((fp->fr_flags & FR_CMDMASK) == FR_CALL) &&
+ ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) {
+ IPFERROR(143);
+ error = ESRCH;
+ goto donenolock;
}
ptr = NULL;
- /*
- * Check that the group number does exist and that its use (in/out)
- * matches what the rule is.
- */
- if (!strncmp(fp->fr_grhead, "0", FR_GROUPLEN))
- *fp->fr_grhead = '\0';
- group = fp->fr_group;
- if (!strncmp(group, "0", FR_GROUPLEN))
- *group = '\0';
+ cptr = NULL;
if (FR_ISACCOUNT(fp->fr_flags))
unit = IPL_LOGCOUNT;
- if ((req != (int)SIOCZRLST) && (*group != '\0')) {
- fg = fr_findgroup(group, unit, set, NULL);
- if (fg == NULL)
- return ESRCH;
- if (fg->fg_flags == 0)
- fg->fg_flags = fp->fr_flags & FR_INOUT;
- else if (fg->fg_flags != (fp->fr_flags & FR_INOUT))
- return ESRCH;
+ /*
+ * Check that each group name in the rule has a start index that
+ * is valid.
+ */
+ if (fp->fr_icmphead != -1) {
+ if ((fp->fr_icmphead < 0) ||
+ (fp->fr_icmphead >= fp->fr_namelen)) {
+ IPFERROR(136);
+ error = EINVAL;
+ goto donenolock;
+ }
+ if (!strcmp(FR_NAME(fp, fr_icmphead), "0"))
+ fp->fr_names[fp->fr_icmphead] = '\0';
}
+ if (fp->fr_grhead != -1) {
+ if ((fp->fr_grhead < 0) ||
+ (fp->fr_grhead >= fp->fr_namelen)) {
+ IPFERROR(137);
+ error = EINVAL;
+ goto donenolock;
+ }
+ if (!strcmp(FR_NAME(fp, fr_grhead), "0"))
+ fp->fr_names[fp->fr_grhead] = '\0';
+ }
+
+ if (fp->fr_group != -1) {
+ if ((fp->fr_group < 0) ||
+ (fp->fr_group >= fp->fr_namelen)) {
+ IPFERROR(138);
+ error = EINVAL;
+ goto donenolock;
+ }
+ if ((req != (int)SIOCZRLST) && (fp->fr_group != -1)) {
+ /*
+ * Allow loading rules that are in groups to cause
+ * them to be created if they don't already exit.
+ */
+ group = FR_NAME(fp, fr_group);
+ if (addrem == 0) {
+ fg = ipf_group_add(softc, group, NULL,
+ fp->fr_flags, unit, set);
+ fp->fr_grp = fg;
+ } else {
+ fg = ipf_findgroup(softc, group, unit,
+ set, NULL);
+ if (fg == NULL) {
+ IPFERROR(12);
+ error = ESRCH;
+ goto donenolock;
+ }
+ }
+
+ if (fg->fg_flags == 0) {
+ fg->fg_flags = fp->fr_flags & FR_INOUT;
+ } else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) {
+ IPFERROR(13);
+ error = ESRCH;
+ goto donenolock;
+ }
+ }
+ } else {
+ /*
+ * If a rule is going to be part of a group then it does
+ * not matter whether it is an in or out rule, but if it
+ * isn't in a group, then it does...
+ */
+ if ((fp->fr_flags & (FR_INQUE|FR_OUTQUE)) == 0) {
+ IPFERROR(14);
+ error = EINVAL;
+ goto donenolock;
+ }
+ }
in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
/*
@@ -4284,27 +4663,30 @@ caddr_t data;
*/
ftail = NULL;
fprev = NULL;
- if (unit == IPL_LOGAUTH)
- fprev = &ipauth;
- else if (v == 4) {
- if (FR_ISACCOUNT(fp->fr_flags))
- fprev = &ipacct[in][set];
- else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0)
- fprev = &ipfilter[in][set];
- } else if (v == 6) {
+ if (unit == IPL_LOGAUTH) {
+ if ((fp->fr_tifs[0].fd_ptr != NULL) ||
+ (fp->fr_tifs[1].fd_ptr != NULL) ||
+ (fp->fr_dif.fd_ptr != NULL) ||
+ (fp->fr_flags & FR_FASTROUTE)) {
+ softc->ipf_interror = 145;
+ error = EINVAL;
+ goto donenolock;
+ }
+ fprev = ipf_auth_rulehead(softc);
+ } else {
if (FR_ISACCOUNT(fp->fr_flags))
- fprev = &ipacct6[in][set];
+ fprev = &softc->ipf_acct[in][set];
else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0)
- fprev = &ipfilter6[in][set];
+ fprev = &softc->ipf_rules[in][set];
+ }
+ if (fprev == NULL) {
+ IPFERROR(15);
+ error = ESRCH;
+ goto donenolock;
}
- if (fprev == NULL)
- return ESRCH;
- if (*group != '\0') {
- if (!fg && !(fg = fr_findgroup(group, unit, set, NULL)))
- return ESRCH;
+ if (fg != NULL)
fprev = &fg->fg_start;
- }
/*
* Copy in extra data for the rule.
@@ -4312,51 +4694,82 @@ caddr_t data;
if (fp->fr_dsize != 0) {
if (makecopy != 0) {
KMALLOCS(ptr, void *, fp->fr_dsize);
- if (!ptr)
- return ENOMEM;
- error = COPYIN(uptr, ptr, fp->fr_dsize);
- if (error != 0)
- error = EFAULT;
+ if (ptr == NULL) {
+ IPFERROR(16);
+ error = ENOMEM;
+ goto donenolock;
+ }
+
+ /*
+ * The bcopy case is for when the data is appended
+ * to the rule by ipf_in_compat().
+ */
+ if (uptr >= (void *)fp &&
+ uptr < (void *)((char *)fp + fp->fr_size)) {
+ bcopy(uptr, ptr, fp->fr_dsize);
+ error = 0;
+ } else {
+ error = COPYIN(uptr, ptr, fp->fr_dsize);
+ if (error != 0) {
+ IPFERROR(17);
+ error = EFAULT;
+ goto donenolock;
+ }
+ }
} else {
ptr = uptr;
- error = 0;
- }
- if (error != 0) {
- KFREES(ptr, fp->fr_dsize);
- return ENOMEM;
}
fp->fr_data = ptr;
- } else
+ } else {
fp->fr_data = NULL;
+ }
/*
* Perform per-rule type sanity checks of their members.
+ * All code after this needs to be aware that allocated memory
+ * may need to be free'd before exiting.
*/
switch (fp->fr_type & ~FR_T_BUILTIN)
{
#if defined(IPFILTER_BPF)
case FR_T_BPFOPC :
- if (fp->fr_dsize == 0)
- return EINVAL;
+ if (fp->fr_dsize == 0) {
+ IPFERROR(19);
+ error = EINVAL;
+ break;
+ }
if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) {
- if (makecopy && fp->fr_data != NULL) {
- KFREES(fp->fr_data, fp->fr_dsize);
- }
- return EINVAL;
+ IPFERROR(20);
+ error = EINVAL;
+ break;
}
break;
#endif
case FR_T_IPF :
- if (fp->fr_dsize != sizeof(fripf_t))
- return EINVAL;
+ /*
+ * Preparation for error case at the bottom of this function.
+ */
+ if (fp->fr_datype == FRI_LOOKUP)
+ fp->fr_dstptr = NULL;
+ if (fp->fr_satype == FRI_LOOKUP)
+ fp->fr_srcptr = NULL;
+
+ if (fp->fr_dsize != sizeof(fripf_t)) {
+ IPFERROR(21);
+ error = EINVAL;
+ break;
+ }
/*
* Allowing a rule with both "keep state" and "with oow" is
* pointless because adding a state entry to the table will
* fail with the out of window (oow) flag set.
*/
- if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW))
- return EINVAL;
+ if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) {
+ IPFERROR(22);
+ error = EINVAL;
+ break;
+ }
switch (fp->fr_satype)
{
@@ -4365,26 +4778,30 @@ caddr_t data;
case FRI_NETWORK :
case FRI_NETMASKED :
case FRI_PEERADDR :
- if (fp->fr_sifpidx < 0 || fp->fr_sifpidx > 3) {
- if (makecopy && fp->fr_data != NULL) {
- KFREES(fp->fr_data, fp->fr_dsize);
- }
- return EINVAL;
+ if (fp->fr_sifpidx < 0) {
+ IPFERROR(23);
+ error = EINVAL;
}
break;
-#ifdef IPFILTER_LOOKUP
case FRI_LOOKUP :
- fp->fr_srcptr = fr_resolvelookup(fp->fr_srctype,
- fp->fr_srcsubtype,
- &fp->fr_slookup,
- &fp->fr_srcfunc);
- if (fp->fr_srcptr == NULL)
- return ESRCH;
+ fp->fr_srcptr = ipf_findlookup(softc, unit, fp,
+ &fp->fr_src6,
+ &fp->fr_smsk6);
+ if (fp->fr_srcfunc == NULL) {
+ IPFERROR(132);
+ error = ESRCH;
+ break;
+ }
+ break;
+ case FRI_NORMAL :
break;
-#endif
default :
+ IPFERROR(133);
+ error = EINVAL;
break;
}
+ if (error != 0)
+ break;
switch (fp->fr_datype)
{
@@ -4393,45 +4810,84 @@ caddr_t data;
case FRI_NETWORK :
case FRI_NETMASKED :
case FRI_PEERADDR :
- if (fp->fr_difpidx < 0 || fp->fr_difpidx > 3) {
- if (makecopy && fp->fr_data != NULL) {
- KFREES(fp->fr_data, fp->fr_dsize);
- }
- return EINVAL;
+ if (fp->fr_difpidx < 0) {
+ IPFERROR(24);
+ error = EINVAL;
}
break;
-#ifdef IPFILTER_LOOKUP
case FRI_LOOKUP :
- fp->fr_dstptr = fr_resolvelookup(fp->fr_dsttype,
- fp->fr_dstsubtype,
- &fp->fr_dlookup,
- &fp->fr_dstfunc);
- if (fp->fr_dstptr == NULL)
- return ESRCH;
+ fp->fr_dstptr = ipf_findlookup(softc, unit, fp,
+ &fp->fr_dst6,
+ &fp->fr_dmsk6);
+ if (fp->fr_dstfunc == NULL) {
+ IPFERROR(134);
+ error = ESRCH;
+ }
break;
-#endif
- default :
+ case FRI_NORMAL :
break;
+ default :
+ IPFERROR(135);
+ error = EINVAL;
}
break;
+
case FR_T_NONE :
- break;
case FR_T_CALLFUNC :
- break;
case FR_T_COMPIPF :
break;
+
+ case FR_T_IPFEXPR :
+ if (ipf_matcharray_verify(fp->fr_data, fp->fr_dsize) == -1) {
+ IPFERROR(25);
+ error = EINVAL;
+ }
+ break;
+
default :
- if (makecopy && fp->fr_data != NULL) {
- KFREES(fp->fr_data, fp->fr_dsize);
+ IPFERROR(26);
+ error = EINVAL;
+ break;
+ }
+ if (error != 0)
+ goto donenolock;
+
+ if (fp->fr_tif.fd_name != -1) {
+ if ((fp->fr_tif.fd_name < 0) ||
+ (fp->fr_tif.fd_name >= fp->fr_namelen)) {
+ IPFERROR(139);
+ error = EINVAL;
+ goto donenolock;
+ }
+ }
+
+ if (fp->fr_dif.fd_name != -1) {
+ if ((fp->fr_dif.fd_name < 0) ||
+ (fp->fr_dif.fd_name >= fp->fr_namelen)) {
+ IPFERROR(140);
+ error = EINVAL;
+ goto donenolock;
+ }
+ }
+
+ if (fp->fr_rif.fd_name != -1) {
+ if ((fp->fr_rif.fd_name < 0) ||
+ (fp->fr_rif.fd_name >= fp->fr_namelen)) {
+ IPFERROR(141);
+ error = EINVAL;
+ goto donenolock;
}
- return EINVAL;
}
/*
* Lookup all the interface names that are part of the rule.
*/
- frsynclist(fp, NULL);
+ error = ipf_synclist(softc, fp, NULL);
+ if (error != 0)
+ goto donenolock;
fp->fr_statecnt = 0;
+ if (fp->fr_srctrack.ht_max_nodes != 0)
+ ipf_rb_ht_init(&fp->fr_srctrack);
/*
* Look for an existing matching filter rule, but don't include the
@@ -4447,7 +4903,7 @@ caddr_t data;
for (p = (u_int *)fp->fr_data; p < pp; p++)
fp->fr_cksum += *p;
- WRITE_ENTER(&ipf_mutex);
+ WRITE_ENTER(&softc->ipf_mutex);
/*
* Now that the filter rule lists are locked, we can walk the
@@ -4462,13 +4918,15 @@ caddr_t data;
}
fprev = ftail;
}
- bzero((char *)frcache, sizeof(frcache));
for (; (f = *ftail) != NULL; ftail = &f->fr_next) {
+ DT2(rule_cmp, frentry_t *, fp, frentry_t *, f);
if ((fp->fr_cksum != f->fr_cksum) ||
+ (fp->fr_size != f->fr_size) ||
(f->fr_dsize != fp->fr_dsize))
continue;
- if (bcmp((char *)&f->fr_func, (char *)&fp->fr_func, FR_CMPSIZ))
+ if (bcmp((char *)&f->fr_func, (char *)&fp->fr_func,
+ fp->fr_size - offsetof(struct frentry, fr_func)) != 0)
continue;
if ((!ptr && !f->fr_data) ||
(ptr && f->fr_data &&
@@ -4479,10 +4937,11 @@ caddr_t data;
/*
* If zero'ing statistics, copy current to caller and zero.
*/
- if (req == (ioctlcmd_t)SIOCZRLST) {
- if (f == NULL)
+ if (addrem == 2) {
+ if (f == NULL) {
+ IPFERROR(27);
error = ESRCH;
- else {
+ } else {
/*
* Copy and reduce lock because of impending copyout.
* Well we should, but if we do then the atomicity of
@@ -4491,22 +4950,24 @@ caddr_t data;
* only resets them to 0 if they are successfully
* copied out into user space.
*/
- bcopy((char *)f, (char *)fp, sizeof(*f));
- /* MUTEX_DOWNGRADE(&ipf_mutex); */
+ bcopy((char *)f, (char *)fp, f->fr_size);
+ /* MUTEX_DOWNGRADE(&softc->ipf_mutex); */
/*
* When we copy this rule back out, set the data
* pointer to be what it was in user space.
*/
fp->fr_data = uptr;
- error = fr_outobj(data, fp, IPFOBJ_FRENTRY);
+ error = ipf_outobj(softc, data, fp, IPFOBJ_FRENTRY);
if (error == 0) {
if ((f->fr_dsize != 0) && (uptr != NULL))
error = COPYOUT(f->fr_data, uptr,
f->fr_dsize);
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(28);
error = EFAULT;
+ }
if (error == 0) {
f->fr_hits = 0;
f->fr_bytes = 0;
@@ -4514,14 +4975,17 @@ caddr_t data;
}
}
- if ((ptr != NULL) && (makecopy != 0)) {
- KFREES(ptr, fp->fr_dsize);
+ if (makecopy != 0) {
+ if (ptr != NULL) {
+ KFREES(ptr, fp->fr_dsize);
+ }
+ KFREES(fp, fp->fr_size);
}
- RWLOCK_EXIT(&ipf_mutex);
+ RWLOCK_EXIT(&softc->ipf_mutex);
return error;
}
- if (!f) {
+ if (!f) {
/*
* At the end of this, ftail must point to the place where the
* new rule is to be saved/inserted/added.
@@ -4539,7 +5003,6 @@ caddr_t data;
}
f = NULL;
ptr = NULL;
- error = 0;
} else if (req == (ioctlcmd_t)SIOCINAFR ||
req == (ioctlcmd_t)SIOCINIFR) {
while ((f = *fprev) != NULL) {
@@ -4547,34 +5010,35 @@ caddr_t data;
break;
fprev = &f->fr_next;
}
- ftail = fprev;
- if (fp->fr_hits != 0) {
+ ftail = fprev;
+ if (fp->fr_hits != 0) {
while (fp->fr_hits && (f = *ftail)) {
if (f->fr_collect != fp->fr_collect)
break;
fprev = ftail;
- ftail = &f->fr_next;
+ ftail = &f->fr_next;
fp->fr_hits--;
}
- }
- f = NULL;
- ptr = NULL;
- error = 0;
+ }
+ f = NULL;
+ ptr = NULL;
}
}
/*
* Request to remove a rule.
*/
- if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR) {
- if (!f)
+ if (addrem == 1) {
+ if (!f) {
+ IPFERROR(29);
error = ESRCH;
- else {
+ } else {
/*
* Do not allow activity from user space to interfere
* with rules not loaded that way.
*/
if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) {
+ IPFERROR(30);
error = EPERM;
goto done;
}
@@ -4584,101 +5048,265 @@ caddr_t data;
* something else (eg state information.)
*/
if (f->fr_ref > 1) {
+ IPFERROR(31);
error = EBUSY;
goto done;
}
#ifdef IPFILTER_SCAN
- if (f->fr_isctag[0] != '\0' &&
+ if (f->fr_isctag != -1 &&
(f->fr_isc != (struct ipscan *)-1))
- ipsc_detachfr(f);
+ ipf_scan_detachfr(f);
#endif
+
if (unit == IPL_LOGAUTH) {
- error = fr_preauthcmd(req, f, ftail);
+ error = ipf_auth_precmd(softc, req, f, ftail);
goto done;
}
- if (*f->fr_grhead != '\0')
- fr_delgroup(f->fr_grhead, unit, set);
- fr_fixskip(ftail, f, -1);
- *ftail = f->fr_next;
- f->fr_next = NULL;
- (void) fr_derefrule(&f);
+
+ ipf_rule_delete(softc, f, unit, set);
+
+ need_free = makecopy;
}
} else {
/*
* Not removing, so we must be adding/inserting a rule.
*/
- if (f)
+ if (f != NULL) {
+ IPFERROR(32);
error = EEXIST;
- else {
- if (unit == IPL_LOGAUTH) {
- error = fr_preauthcmd(req, fp, ftail);
- goto done;
- }
- if (makecopy) {
- KMALLOC(f, frentry_t *);
- } else
- f = fp;
- if (f != NULL) {
- if (fp != f)
- bcopy((char *)fp, (char *)f,
- sizeof(*f));
- MUTEX_NUKE(&f->fr_lock);
- MUTEX_INIT(&f->fr_lock, "filter rule lock");
-#ifdef IPFILTER_SCAN
- if (f->fr_isctag[0] != '\0' &&
- ipsc_attachfr(f))
- f->fr_isc = (struct ipscan *)-1;
-#endif
- f->fr_hits = 0;
- if (makecopy != 0)
- f->fr_ref = 1;
- f->fr_next = *ftail;
- *ftail = f;
- if (req == (ioctlcmd_t)SIOCINIFR ||
- req == (ioctlcmd_t)SIOCINAFR)
- fr_fixskip(ftail, f, 1);
- f->fr_grp = NULL;
- group = f->fr_grhead;
- if (*group != '\0') {
- fg = fr_addgroup(group, f, f->fr_flags,
- unit, set);
- if (fg != NULL)
- f->fr_grp = &fg->fg_start;
- }
- } else
- error = ENOMEM;
+ goto done;
+ }
+ if (unit == IPL_LOGAUTH) {
+ error = ipf_auth_precmd(softc, req, fp, ftail);
+ goto done;
+ }
+
+ MUTEX_NUKE(&fp->fr_lock);
+ MUTEX_INIT(&fp->fr_lock, "filter rule lock");
+ if (fp->fr_die != 0)
+ ipf_rule_expire_insert(softc, fp, set);
+
+ fp->fr_hits = 0;
+ if (makecopy != 0)
+ fp->fr_ref = 1;
+ fp->fr_pnext = ftail;
+ fp->fr_next = *ftail;
+ *ftail = fp;
+ if (addrem == 0)
+ ipf_fixskip(ftail, fp, 1);
+
+ fp->fr_icmpgrp = NULL;
+ if (fp->fr_icmphead != -1) {
+ group = FR_NAME(fp, fr_icmphead);
+ fg = ipf_group_add(softc, group, fp, 0, unit, set);
+ fp->fr_icmpgrp = fg;
+ }
+
+ fp->fr_grphead = NULL;
+ if (fp->fr_grhead != -1) {
+ group = FR_NAME(fp, fr_grhead);
+ fg = ipf_group_add(softc, group, fp, fp->fr_flags,
+ unit, set);
+ fp->fr_grphead = fg;
}
}
done:
- RWLOCK_EXIT(&ipf_mutex);
- if ((ptr != NULL) && (error != 0) && (makecopy != 0)) {
- KFREES(ptr, fp->fr_dsize);
+ RWLOCK_EXIT(&softc->ipf_mutex);
+donenolock:
+ if (need_free || (error != 0)) {
+ if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) {
+ if ((fp->fr_satype == FRI_LOOKUP) &&
+ (fp->fr_srcptr != NULL))
+ ipf_lookup_deref(softc, fp->fr_srctype,
+ fp->fr_srcptr);
+ if ((fp->fr_datype == FRI_LOOKUP) &&
+ (fp->fr_dstptr != NULL))
+ ipf_lookup_deref(softc, fp->fr_dsttype,
+ fp->fr_dstptr);
+ }
+ if (fp->fr_grp != NULL) {
+ WRITE_ENTER(&softc->ipf_mutex);
+ ipf_group_del(softc, fp->fr_grp, fp);
+ RWLOCK_EXIT(&softc->ipf_mutex);
+ }
+ if ((ptr != NULL) && (makecopy != 0)) {
+ KFREES(ptr, fp->fr_dsize);
+ }
+ KFREES(fp, fp->fr_size);
}
return (error);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_funcinit */
+/* Function: ipf_rule_delete */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* f(I) - pointer to the rule being deleted */
+/* ftail(I) - pointer to the pointer to f */
+/* unit(I) - device for which this is for */
+/* set(I) - 1 or 0 (filter set) */
+/* */
+/* This function attempts to do what it can to delete a filter rule: remove */
+/* it from any linked lists and remove any groups it is responsible for. */
+/* But in the end, removing a rule can only drop the reference count - we */
+/* must use that as the guide for whether or not it can be freed. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_rule_delete(softc, f, unit, set)
+ ipf_main_softc_t *softc;
+ frentry_t *f;
+ int unit, set;
+{
+
+ /*
+ * If fr_pdnext is set, then the rule is on the expire list, so
+ * remove it from there.
+ */
+ if (f->fr_pdnext != NULL) {
+ *f->fr_pdnext = f->fr_dnext;
+ if (f->fr_dnext != NULL)
+ f->fr_dnext->fr_pdnext = f->fr_pdnext;
+ f->fr_pdnext = NULL;
+ f->fr_dnext = NULL;
+ }
+
+ ipf_fixskip(f->fr_pnext, f, -1);
+ if (f->fr_pnext != NULL)
+ *f->fr_pnext = f->fr_next;
+ if (f->fr_next != NULL)
+ f->fr_next->fr_pnext = f->fr_pnext;
+ f->fr_pnext = NULL;
+ f->fr_next = NULL;
+
+ (void) ipf_derefrule(softc, &f);
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rule_expire_insert */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* f(I) - pointer to rule to be added to expire list */
+/* set(I) - 1 or 0 (filter set) */
+/* */
+/* If the new rule has a given expiration time, insert it into the list of */
+/* expiring rules with the ones to be removed first added to the front of */
+/* the list. The insertion is O(n) but it is kept sorted for quick scans at */
+/* expiration interval checks. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_rule_expire_insert(softc, f, set)
+ ipf_main_softc_t *softc;
+ frentry_t *f;
+ int set;
+{
+ frentry_t *fr;
+
+ /*
+ */
+
+ f->fr_die = softc->ipf_ticks + IPF_TTLVAL(f->fr_die);
+ for (fr = softc->ipf_rule_explist[set]; fr != NULL;
+ fr = fr->fr_dnext) {
+ if (f->fr_die < fr->fr_die)
+ break;
+ if (fr->fr_dnext == NULL) {
+ /*
+ * We've got to the last rule and everything
+ * wanted to be expired before this new node,
+ * so we have to tack it on the end...
+ */
+ fr->fr_dnext = f;
+ f->fr_pdnext = &fr->fr_dnext;
+ fr = NULL;
+ break;
+ }
+ }
+
+ if (softc->ipf_rule_explist[set] == NULL) {
+ softc->ipf_rule_explist[set] = f;
+ f->fr_pdnext = &softc->ipf_rule_explist[set];
+ } else if (fr != NULL) {
+ f->fr_dnext = fr;
+ f->fr_pdnext = fr->fr_pdnext;
+ fr->fr_pdnext = &f->fr_dnext;
+ }
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_findlookup */
+/* Returns: NULL = failure, else success */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* unit(I) - ipf device we want to find match for */
+/* fp(I) - rule for which lookup is for */
+/* addrp(I) - pointer to lookup information in address struct */
+/* maskp(O) - pointer to lookup information for storage */
+/* */
+/* When using pools and hash tables to store addresses for matching in */
+/* rules, it is necessary to resolve both the object referred to by the */
+/* name or address (and return that pointer) and also provide the means by */
+/* which to determine if an address belongs to that object to make the */
+/* packet matching quicker. */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_findlookup(softc, unit, fr, addrp, maskp)
+ ipf_main_softc_t *softc;
+ int unit;
+ frentry_t *fr;
+ i6addr_t *addrp, *maskp;
+{
+ void *ptr = NULL;
+
+ switch (addrp->iplookupsubtype)
+ {
+ case 0 :
+ ptr = ipf_lookup_res_num(softc, unit, addrp->iplookuptype,
+ addrp->iplookupnum,
+ &maskp->iplookupfunc);
+ break;
+ case 1 :
+ if (addrp->iplookupname < 0)
+ break;
+ if (addrp->iplookupname >= fr->fr_namelen)
+ break;
+ ptr = ipf_lookup_res_name(softc, unit, addrp->iplookuptype,
+ fr->fr_names + addrp->iplookupname,
+ &maskp->iplookupfunc);
+ break;
+ default :
+ break;
+ }
+
+ return ptr;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_funcinit */
/* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */
-/* Parameters: fr(I) - pointer to filter rule */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* fr(I) - pointer to filter rule */
/* */
/* If a rule is a call rule, then check if the function it points to needs */
/* an init function to be called now the rule has been loaded. */
/* ------------------------------------------------------------------------ */
-static int fr_funcinit(fr)
-frentry_t *fr;
+static int
+ipf_funcinit(softc, fr)
+ ipf_main_softc_t *softc;
+ frentry_t *fr;
{
ipfunc_resolve_t *ft;
int err;
+ IPFERROR(34);
err = ESRCH;
- for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++)
+ for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
if (ft->ipfu_addr == fr->fr_func) {
err = 0;
if (ft->ipfu_init != NULL)
- err = (*ft->ipfu_init)(fr);
+ err = (*ft->ipfu_init)(softc, fr);
break;
}
return err;
@@ -4686,18 +5314,45 @@ frentry_t *fr;
/* ------------------------------------------------------------------------ */
-/* Function: fr_findfunc */
+/* Function: ipf_funcfini */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* fr(I) - pointer to filter rule */
+/* */
+/* For a given filter rule, call the matching "fini" function if the rule */
+/* is using a known function that would have resulted in the "init" being */
+/* called for ealier. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_funcfini(softc, fr)
+ ipf_main_softc_t *softc;
+ frentry_t *fr;
+{
+ ipfunc_resolve_t *ft;
+
+ for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
+ if (ft->ipfu_addr == fr->fr_func) {
+ if (ft->ipfu_fini != NULL)
+ (void) (*ft->ipfu_fini)(softc, fr);
+ break;
+ }
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_findfunc */
/* Returns: ipfunc_t - pointer to function if found, else NULL */
/* Parameters: funcptr(I) - function pointer to lookup */
/* */
/* Look for a function in the table of known functions. */
/* ------------------------------------------------------------------------ */
-static ipfunc_t fr_findfunc(funcptr)
-ipfunc_t funcptr;
+static ipfunc_t
+ipf_findfunc(funcptr)
+ ipfunc_t funcptr;
{
ipfunc_resolve_t *ft;
- for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++)
+ for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
if (ft->ipfu_addr == funcptr)
return funcptr;
return NULL;
@@ -4705,7 +5360,7 @@ ipfunc_t funcptr;
/* ------------------------------------------------------------------------ */
-/* Function: fr_resolvefunc */
+/* Function: ipf_resolvefunc */
/* Returns: int - 0 == success, else error */
/* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */
/* */
@@ -4714,46 +5369,55 @@ ipfunc_t funcptr;
/* function pointer if the name is set. When found, fill in the other one */
/* so that the entire, complete, structure can be copied back to user space.*/
/* ------------------------------------------------------------------------ */
-int fr_resolvefunc(data)
-void *data;
+int
+ipf_resolvefunc(softc, data)
+ ipf_main_softc_t *softc;
+ void *data;
{
ipfunc_resolve_t res, *ft;
- int err;
+ int error;
- err = BCOPYIN(data, &res, sizeof(res));
- if (err != 0)
+ error = BCOPYIN(data, &res, sizeof(res));
+ if (error != 0) {
+ IPFERROR(123);
return EFAULT;
+ }
if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') {
- for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++)
+ for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
if (strncmp(res.ipfu_name, ft->ipfu_name,
sizeof(res.ipfu_name)) == 0) {
res.ipfu_addr = ft->ipfu_addr;
res.ipfu_init = ft->ipfu_init;
- if (COPYOUT(&res, data, sizeof(res)) != 0)
+ if (COPYOUT(&res, data, sizeof(res)) != 0) {
+ IPFERROR(35);
return EFAULT;
+ }
return 0;
}
}
if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') {
- for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++)
+ for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
if (ft->ipfu_addr == res.ipfu_addr) {
(void) strncpy(res.ipfu_name, ft->ipfu_name,
sizeof(res.ipfu_name));
res.ipfu_init = ft->ipfu_init;
- if (COPYOUT(&res, data, sizeof(res)) != 0)
+ if (COPYOUT(&res, data, sizeof(res)) != 0) {
+ IPFERROR(36);
return EFAULT;
+ }
return 0;
}
}
+ IPFERROR(37);
return ESRCH;
}
-#if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__FreeBSD__)) || \
- (defined(__FreeBSD__) && (__FreeBSD_version < 501000)) || \
- (defined(__NetBSD__) && (__NetBSD_Version__ < 105000000)) || \
- (defined(__OpenBSD__) && (OpenBSD < 200006))
+#if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && \
+ !defined(__FreeBSD__)) || \
+ FREEBSD_LT_REV(501000) || NETBSD_LT_REV(105000000) || \
+ OPENBSD_LT_REV(200006)
/*
* From: NetBSD
* ppsratecheck(): packets (or events) per second limitation.
@@ -4803,17 +5467,20 @@ ppsratecheck(lasttime, curpps, maxpps)
/* ------------------------------------------------------------------------ */
-/* Function: fr_derefrule */
+/* Function: ipf_derefrule */
/* Returns: int - 0 == rule freed up, else rule not freed */
/* Parameters: fr(I) - pointer to filter rule */
/* */
/* Decrement the reference counter to a rule by one. If it reaches zero, */
/* free it and any associated storage space being used by it. */
/* ------------------------------------------------------------------------ */
-int fr_derefrule(frp)
-frentry_t **frp;
+int
+ipf_derefrule(softc, frp)
+ ipf_main_softc_t *softc;
+ frentry_t **frp;
{
frentry_t *fr;
+ frdest_t *fdp;
fr = *frp;
*frp = NULL;
@@ -4824,18 +5491,41 @@ frentry_t **frp;
MUTEX_EXIT(&fr->fr_lock);
MUTEX_DESTROY(&fr->fr_lock);
-#ifdef IPFILTER_LOOKUP
- if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP)
- ip_lookup_deref(fr->fr_srctype, fr->fr_srcptr);
- if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP)
- ip_lookup_deref(fr->fr_dsttype, fr->fr_dstptr);
-#endif
+ ipf_funcfini(softc, fr);
+
+ fdp = &fr->fr_tif;
+ if (fdp->fd_type == FRD_DSTLIST)
+ ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
+
+ fdp = &fr->fr_rif;
+ if (fdp->fd_type == FRD_DSTLIST)
+ ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
+
+ fdp = &fr->fr_dif;
+ if (fdp->fd_type == FRD_DSTLIST)
+ ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
+
+ if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
+ fr->fr_satype == FRI_LOOKUP)
+ ipf_lookup_deref(softc, fr->fr_srctype, fr->fr_srcptr);
+ if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
+ fr->fr_datype == FRI_LOOKUP)
+ ipf_lookup_deref(softc, fr->fr_dsttype, fr->fr_dstptr);
+
+ if (fr->fr_grp != NULL)
+ ipf_group_del(softc, fr->fr_grp, fr);
+
+ if (fr->fr_grphead != NULL)
+ ipf_group_del(softc, fr->fr_grphead, fr);
+
+ if (fr->fr_icmpgrp != NULL)
+ ipf_group_del(softc, fr->fr_icmpgrp, fr);
- if (fr->fr_dsize) {
- KFREES(fr->fr_data, fr->fr_dsize);
- }
if ((fr->fr_flags & FR_COPIED) != 0) {
- KFREE(fr);
+ if (fr->fr_dsize) {
+ KFREES(fr->fr_data, fr->fr_dsize);
+ }
+ KFREES(fr, fr->fr_size);
return 0;
}
return 1;
@@ -4846,17 +5536,18 @@ frentry_t **frp;
}
-#ifdef IPFILTER_LOOKUP
/* ------------------------------------------------------------------------ */
-/* Function: fr_grpmapinit */
+/* Function: ipf_grpmapinit */
/* Returns: int - 0 == success, else ESRCH because table entry not found*/
/* Parameters: fr(I) - pointer to rule to find hash table for */
/* */
/* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr. */
-/* fr_ptr is later used by fr_srcgrpmap and fr_dstgrpmap. */
+/* fr_ptr is later used by ipf_srcgrpmap and ipf_dstgrpmap. */
/* ------------------------------------------------------------------------ */
-static int fr_grpmapinit(fr)
-frentry_t *fr;
+static int
+ipf_grpmapinit(softc, fr)
+ ipf_main_softc_t *softc;
+ frentry_t *fr;
{
char name[FR_GROUPLEN];
iphtable_t *iph;
@@ -4866,18 +5557,45 @@ frentry_t *fr;
#else
(void) sprintf(name, "%d", fr->fr_arg);
#endif
- iph = fr_findhtable(IPL_LOGIPF, name);
- if (iph == NULL)
+ iph = ipf_lookup_find_htable(softc, IPL_LOGIPF, name);
+ if (iph == NULL) {
+ IPFERROR(38);
return ESRCH;
- if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT))
+ }
+ if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) {
+ IPFERROR(39);
return ESRCH;
+ }
+ iph->iph_ref++;
fr->fr_ptr = iph;
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_srcgrpmap */
+/* Function: ipf_grpmapfini */
+/* Returns: int - 0 == success, else ESRCH because table entry not found*/
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* fr(I) - pointer to rule to release hash table for */
+/* */
+/* For rules that have had ipf_grpmapinit called, ipf_lookup_deref needs to */
+/* be called to undo what ipf_grpmapinit caused to be done. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_grpmapfini(softc, fr)
+ ipf_main_softc_t *softc;
+ frentry_t *fr;
+{
+ iphtable_t *iph;
+ iph = fr->fr_ptr;
+ if (iph != NULL)
+ ipf_lookup_deref(softc, IPLT_HASH, iph);
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_srcgrpmap */
/* Returns: frentry_t * - pointer to "new last matching" rule or NULL */
/* Parameters: fin(I) - pointer to packet information */
/* passp(IO) - pointer to current/new filter decision (unused) */
@@ -4886,26 +5604,28 @@ frentry_t *fr;
/* the key, and descend into that group and continue matching rules against */
/* the packet. */
/* ------------------------------------------------------------------------ */
-frentry_t *fr_srcgrpmap(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+frentry_t *
+ipf_srcgrpmap(fin, passp)
+ fr_info_t *fin;
+ u_32_t *passp;
{
frgroup_t *fg;
void *rval;
- rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, &fin->fin_src);
+ rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr,
+ &fin->fin_src);
if (rval == NULL)
return NULL;
fg = rval;
fin->fin_fr = fg->fg_start;
- (void) fr_scanlist(fin, *passp);
+ (void) ipf_scanlist(fin, *passp);
return fin->fin_fr;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_dstgrpmap */
+/* Function: ipf_dstgrpmap */
/* Returns: frentry_t * - pointer to "new last matching" rule or NULL */
/* Parameters: fin(I) - pointer to packet information */
/* passp(IO) - pointer to current/new filter decision (unused) */
@@ -4914,37 +5634,39 @@ u_32_t *passp;
/* address as the key, and descend into that group and continue matching */
/* rules against the packet. */
/* ------------------------------------------------------------------------ */
-frentry_t *fr_dstgrpmap(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+frentry_t *
+ipf_dstgrpmap(fin, passp)
+ fr_info_t *fin;
+ u_32_t *passp;
{
frgroup_t *fg;
void *rval;
- rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, &fin->fin_dst);
+ rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr,
+ &fin->fin_dst);
if (rval == NULL)
return NULL;
fg = rval;
fin->fin_fr = fg->fg_start;
- (void) fr_scanlist(fin, *passp);
+ (void) ipf_scanlist(fin, *passp);
return fin->fin_fr;
}
-#endif /* IPFILTER_LOOKUP */
/*
* Queue functions
* ===============
- * These functions manage objects on queues for efficient timeouts. There are
- * a number of system defined queues as well as user defined timeouts. It is
- * expected that a lock is held in the domain in which the queue belongs
- * (i.e. either state or NAT) when calling any of these functions that prevents
- * fr_freetimeoutqueue() from being called at the same time as any other.
+ * These functions manage objects on queues for efficient timeouts. There
+ * are a number of system defined queues as well as user defined timeouts.
+ * It is expected that a lock is held in the domain in which the queue
+ * belongs (i.e. either state or NAT) when calling any of these functions
+ * that prevents ipf_freetimeoutqueue() from being called at the same time
+ * as any other.
*/
/* ------------------------------------------------------------------------ */
-/* Function: fr_addtimeoutqueue */
+/* Function: ipf_addtimeoutqueue */
/* Returns: struct ifqtq * - NULL if malloc fails, else pointer to */
/* timeout queue with given interval. */
/* Parameters: parent(I) - pointer to pointer to parent node of this list */
@@ -4960,16 +5682,18 @@ u_32_t *passp;
/* It is assumed that the caller of this function has an appropriate lock */
/* held (exclusively) in the domain that encompases 'parent'. */
/* ------------------------------------------------------------------------ */
-ipftq_t *fr_addtimeoutqueue(parent, seconds)
-ipftq_t **parent;
-u_int seconds;
+ipftq_t *
+ipf_addtimeoutqueue(softc, parent, seconds)
+ ipf_main_softc_t *softc;
+ ipftq_t **parent;
+ u_int seconds;
{
ipftq_t *ifq;
u_int period;
period = seconds * IPF_HZ_DIVIDE;
- MUTEX_ENTER(&ipf_timeoutlock);
+ MUTEX_ENTER(&softc->ipf_timeoutlock);
for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) {
if (ifq->ifq_ttl == period) {
/*
@@ -4980,7 +5704,7 @@ u_int seconds;
ifq->ifq_flags &= ~IFQF_DELETE;
ifq->ifq_ref++;
MUTEX_EXIT(&ifq->ifq_lock);
- MUTEX_EXIT(&ipf_timeoutlock);
+ MUTEX_EXIT(&softc->ipf_timeoutlock);
return ifq;
}
@@ -4988,25 +5712,22 @@ u_int seconds;
KMALLOC(ifq, ipftq_t *);
if (ifq != NULL) {
- ifq->ifq_ttl = period;
- ifq->ifq_head = NULL;
- ifq->ifq_tail = &ifq->ifq_head;
+ MUTEX_NUKE(&ifq->ifq_lock);
+ IPFTQ_INIT(ifq, period, "ipftq mutex");
ifq->ifq_next = *parent;
ifq->ifq_pnext = parent;
- ifq->ifq_ref = 1;
ifq->ifq_flags = IFQF_USER;
+ ifq->ifq_ref++;
*parent = ifq;
- fr_userifqs++;
- MUTEX_NUKE(&ifq->ifq_lock);
- MUTEX_INIT(&ifq->ifq_lock, "ipftq mutex");
+ softc->ipf_userifqs++;
}
- MUTEX_EXIT(&ipf_timeoutlock);
+ MUTEX_EXIT(&softc->ipf_timeoutlock);
return ifq;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_deletetimeoutqueue */
+/* Function: ipf_deletetimeoutqueue */
/* Returns: int - new reference count value of the timeout queue */
/* Parameters: ifq(I) - timeout queue which is losing a reference. */
/* Locks: ifq->ifq_lock */
@@ -5020,8 +5741,9 @@ u_int seconds;
/* way because the locking may not be sufficient to safely do a free when */
/* this function is called. */
/* ------------------------------------------------------------------------ */
-int fr_deletetimeoutqueue(ifq)
-ipftq_t *ifq;
+int
+ipf_deletetimeoutqueue(ifq)
+ ipftq_t *ifq;
{
ifq->ifq_ref--;
@@ -5034,7 +5756,7 @@ ipftq_t *ifq;
/* ------------------------------------------------------------------------ */
-/* Function: fr_freetimeoutqueue */
+/* Function: ipf_freetimeoutqueue */
/* Parameters: ifq(I) - timeout queue which is losing a reference. */
/* Returns: Nil */
/* */
@@ -5043,17 +5765,18 @@ ipftq_t *ifq;
/* held (exclusively) in the domain that encompases the callers "domain". */
/* The ifq_lock for this structure should not be held. */
/* */
-/* Remove a user definde timeout queue from the list of queues it is in and */
+/* Remove a user defined timeout queue from the list of queues it is in and */
/* tidy up after this is done. */
/* ------------------------------------------------------------------------ */
-void fr_freetimeoutqueue(ifq)
-ipftq_t *ifq;
+void
+ipf_freetimeoutqueue(softc, ifq)
+ ipf_main_softc_t *softc;
+ ipftq_t *ifq;
{
-
if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) ||
((ifq->ifq_flags & IFQF_USER) == 0)) {
- printf("fr_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n",
+ printf("ipf_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n",
(u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl,
ifq->ifq_ref);
return;
@@ -5065,26 +5788,28 @@ ipftq_t *ifq;
*ifq->ifq_pnext = ifq->ifq_next;
if (ifq->ifq_next != NULL)
ifq->ifq_next->ifq_pnext = ifq->ifq_pnext;
+ ifq->ifq_next = NULL;
+ ifq->ifq_pnext = NULL;
MUTEX_DESTROY(&ifq->ifq_lock);
- ATOMIC_DEC(fr_userifqs);
+ ATOMIC_DEC(softc->ipf_userifqs);
KFREE(ifq);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_deletequeueentry */
+/* Function: ipf_deletequeueentry */
/* Returns: Nil */
/* Parameters: tqe(I) - timeout queue entry to delete */
-/* ifq(I) - timeout queue to remove entry from */
/* */
/* Remove a tail queue entry from its queue and make it an orphan. */
-/* fr_deletetimeoutqueue is called to make sure the reference count on the */
-/* queue is correct. We can't, however, call fr_freetimeoutqueue because */
+/* ipf_deletetimeoutqueue is called to make sure the reference count on the */
+/* queue is correct. We can't, however, call ipf_freetimeoutqueue because */
/* the correct lock(s) may not be held that would make it safe to do so. */
/* ------------------------------------------------------------------------ */
-void fr_deletequeueentry(tqe)
-ipftqent_t *tqe;
+void
+ipf_deletequeueentry(tqe)
+ ipftqent_t *tqe;
{
ipftq_t *ifq;
@@ -5103,21 +5828,23 @@ ipftqent_t *tqe;
tqe->tqe_ifq = NULL;
}
- (void) fr_deletetimeoutqueue(ifq);
+ (void) ipf_deletetimeoutqueue(ifq);
+ ASSERT(ifq->ifq_ref > 0);
MUTEX_EXIT(&ifq->ifq_lock);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_queuefront */
+/* Function: ipf_queuefront */
/* Returns: Nil */
/* Parameters: tqe(I) - pointer to timeout queue entry */
/* */
/* Move a queue entry to the front of the queue, if it isn't already there. */
/* ------------------------------------------------------------------------ */
-void fr_queuefront(tqe)
-ipftqent_t *tqe;
+void
+ipf_queuefront(tqe)
+ ipftqent_t *tqe;
{
ipftq_t *ifq;
@@ -5143,21 +5870,27 @@ ipftqent_t *tqe;
/* ------------------------------------------------------------------------ */
-/* Function: fr_queueback */
+/* Function: ipf_queueback */
/* Returns: Nil */
-/* Parameters: tqe(I) - pointer to timeout queue entry */
+/* Parameters: ticks(I) - ipf tick time to use with this call */
+/* tqe(I) - pointer to timeout queue entry */
/* */
/* Move a queue entry to the back of the queue, if it isn't already there. */
+/* We use use ticks to calculate the expiration and mark for when we last */
+/* touched the structure. */
/* ------------------------------------------------------------------------ */
-void fr_queueback(tqe)
-ipftqent_t *tqe;
+void
+ipf_queueback(ticks, tqe)
+ u_long ticks;
+ ipftqent_t *tqe;
{
ipftq_t *ifq;
ifq = tqe->tqe_ifq;
if (ifq == NULL)
return;
- tqe->tqe_die = fr_ticks + ifq->ifq_ttl;
+ tqe->tqe_die = ticks + ifq->ifq_ttl;
+ tqe->tqe_touched = ticks;
MUTEX_ENTER(&ifq->ifq_lock);
if (tqe->tqe_next != NULL) { /* at the end already ? */
@@ -5180,18 +5913,23 @@ ipftqent_t *tqe;
/* ------------------------------------------------------------------------ */
-/* Function: fr_queueappend */
+/* Function: ipf_queueappend */
/* Returns: Nil */
-/* Parameters: tqe(I) - pointer to timeout queue entry */
+/* Parameters: ticks(I) - ipf tick time to use with this call */
+/* tqe(I) - pointer to timeout queue entry */
/* ifq(I) - pointer to timeout queue */
/* parent(I) - owing object pointer */
/* */
/* Add a new item to this queue and put it on the very end. */
+/* We use use ticks to calculate the expiration and mark for when we last */
+/* touched the structure. */
/* ------------------------------------------------------------------------ */
-void fr_queueappend(tqe, ifq, parent)
-ipftqent_t *tqe;
-ipftq_t *ifq;
-void *parent;
+void
+ipf_queueappend(ticks, tqe, ifq, parent)
+ u_long ticks;
+ ipftqent_t *tqe;
+ ipftq_t *ifq;
+ void *parent;
{
MUTEX_ENTER(&ifq->ifq_lock);
@@ -5201,14 +5939,15 @@ void *parent;
ifq->ifq_tail = &tqe->tqe_next;
tqe->tqe_next = NULL;
tqe->tqe_ifq = ifq;
- tqe->tqe_die = fr_ticks + ifq->ifq_ttl;
+ tqe->tqe_die = ticks + ifq->ifq_ttl;
+ tqe->tqe_touched = ticks;
ifq->ifq_ref++;
MUTEX_EXIT(&ifq->ifq_lock);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_movequeue */
+/* Function: ipf_movequeue */
/* Returns: Nil */
/* Parameters: tq(I) - pointer to timeout queue information */
/* oifp(I) - old timeout queue entry was on */
@@ -5218,58 +5957,82 @@ void *parent;
/* If it notices that the current entry is already last and does not need */
/* to move queue, the return. */
/* ------------------------------------------------------------------------ */
-void fr_movequeue(tqe, oifq, nifq)
-ipftqent_t *tqe;
-ipftq_t *oifq, *nifq;
+void
+ipf_movequeue(ticks, tqe, oifq, nifq)
+ u_long ticks;
+ ipftqent_t *tqe;
+ ipftq_t *oifq, *nifq;
{
+
/*
- * Is the operation here going to be a no-op ?
+ * If the queue hasn't changed and we last touched this entry at the
+ * same ipf time, then we're not going to achieve anything by either
+ * changing the ttl or moving it on the queue.
+ */
+ if (oifq == nifq && tqe->tqe_touched == ticks)
+ return;
+
+ /*
+ * For any of this to be outside the lock, there is a risk that two
+ * packets entering simultaneously, with one changing to a different
+ * queue and one not, could end up with things in a bizarre state.
*/
MUTEX_ENTER(&oifq->ifq_lock);
- if ((oifq != nifq) || (*oifq->ifq_tail != tqe)) {
- /*
- * Remove from the old queue
- */
- *tqe->tqe_pnext = tqe->tqe_next;
- if (tqe->tqe_next)
- tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
- else
- oifq->ifq_tail = tqe->tqe_pnext;
- tqe->tqe_next = NULL;
- /*
- * If we're moving from one queue to another, release the
- * lock on the old queue and get a lock on the new queue.
- * For user defined queues, if we're moving off it, call
- * delete in case it can now be freed.
- */
- if (oifq != nifq) {
- tqe->tqe_ifq = NULL;
+ tqe->tqe_touched = ticks;
+ tqe->tqe_die = ticks + nifq->ifq_ttl;
+ /*
+ * Is the operation here going to be a no-op ?
+ */
+ if (oifq == nifq) {
+ if ((tqe->tqe_next == NULL) ||
+ (tqe->tqe_next->tqe_die == tqe->tqe_die)) {
+ MUTEX_EXIT(&oifq->ifq_lock);
+ return;
+ }
+ }
- (void) fr_deletetimeoutqueue(oifq);
+ /*
+ * Remove from the old queue
+ */
+ *tqe->tqe_pnext = tqe->tqe_next;
+ if (tqe->tqe_next)
+ tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
+ else
+ oifq->ifq_tail = tqe->tqe_pnext;
+ tqe->tqe_next = NULL;
- MUTEX_EXIT(&oifq->ifq_lock);
+ /*
+ * If we're moving from one queue to another, release the
+ * lock on the old queue and get a lock on the new queue.
+ * For user defined queues, if we're moving off it, call
+ * delete in case it can now be freed.
+ */
+ if (oifq != nifq) {
+ tqe->tqe_ifq = NULL;
- MUTEX_ENTER(&nifq->ifq_lock);
+ (void) ipf_deletetimeoutqueue(oifq);
- tqe->tqe_ifq = nifq;
- nifq->ifq_ref++;
- }
+ MUTEX_EXIT(&oifq->ifq_lock);
- /*
- * Add to the bottom of the new queue
- */
- tqe->tqe_die = fr_ticks + nifq->ifq_ttl;
- tqe->tqe_pnext = nifq->ifq_tail;
- *nifq->ifq_tail = tqe;
- nifq->ifq_tail = &tqe->tqe_next;
+ MUTEX_ENTER(&nifq->ifq_lock);
+
+ tqe->tqe_ifq = nifq;
+ nifq->ifq_ref++;
}
+
+ /*
+ * Add to the bottom of the new queue
+ */
+ tqe->tqe_pnext = nifq->ifq_tail;
+ *nifq->ifq_tail = tqe;
+ nifq->ifq_tail = &tqe->tqe_next;
MUTEX_EXIT(&nifq->ifq_lock);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_updateipid */
+/* Function: ipf_updateipid */
/* Returns: int - 0 == success, -1 == error (packet should be droppped) */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -5280,23 +6043,24 @@ ipftq_t *oifq, *nifq;
/* the fragment cache for non-leading fragments. If a non-leading fragment */
/* has no match in the cache, return an error. */
/* ------------------------------------------------------------------------ */
-static int fr_updateipid(fin)
-fr_info_t *fin;
+static int
+ipf_updateipid(fin)
+ fr_info_t *fin;
{
u_short id, ido, sums;
u_32_t sumd, sum;
ip_t *ip;
if (fin->fin_off != 0) {
- sum = fr_ipid_knownfrag(fin);
+ sum = ipf_frag_ipidknown(fin);
if (sum == 0xffffffff)
return -1;
sum &= 0xffff;
id = (u_short)sum;
} else {
- id = fr_nextipid(fin);
+ id = ipf_nextipid(fin);
if (fin->fin_off == 0 && (fin->fin_flx & FI_FRAG) != 0)
- (void) fr_ipid_newfrag(fin, (u_32_t)id);
+ (void) ipf_frag_ipidnew(fin, (u_32_t)id);
}
ip = fin->fin_ip;
@@ -5317,7 +6081,7 @@ fr_info_t *fin;
#ifdef NEED_FRGETIFNAME
/* ------------------------------------------------------------------------ */
-/* Function: fr_getifname */
+/* Function: ipf_getifname */
/* Returns: char * - pointer to interface name */
/* Parameters: ifp(I) - pointer to network interface */
/* buffer(O) - pointer to where to store interface name */
@@ -5326,9 +6090,10 @@ fr_info_t *fin;
/* expected to be at least LIFNAMSIZ in bytes big. If buffer is passed in */
/* as a NULL pointer then return a pointer to a static array. */
/* ------------------------------------------------------------------------ */
-char *fr_getifname(ifp, buffer)
-struct ifnet *ifp;
-char *buffer;
+char *
+ipf_getifname(ifp, buffer)
+ struct ifnet *ifp;
+ char *buffer;
{
static char namebuf[LIFNAMSIZ];
# if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \
@@ -5350,7 +6115,7 @@ char *buffer;
;
unit = ifp->if_unit;
space = LIFNAMSIZ - (s - buffer);
- if (space > 0) {
+ if ((space > 0) && (unit >= 0)) {
# if defined(SNPRINTF) && defined(_KERNEL)
SNPRINTF(temp, sizeof(temp), "%d", unit);
# else
@@ -5365,7 +6130,7 @@ char *buffer;
/* ------------------------------------------------------------------------ */
-/* Function: fr_ioctlswitch */
+/* Function: ipf_ioctlswitch */
/* Returns: int - -1 continue processing, else ioctl return value */
/* Parameters: unit(I) - device unit opened */
/* data(I) - pointer to ioctl data */
@@ -5376,63 +6141,99 @@ char *buffer;
/* */
/* Based on the value of unit, call the appropriate ioctl handler or return */
/* EIO if ipfilter is not running. Also checks if write perms are req'd */
-/* for the device in order to execute the ioctl. */
+/* for the device in order to execute the ioctl. A special case is made */
+/* SIOCIPFINTERROR so that the same code isn't required in every handler. */
+/* The context data pointer is passed through as this is used as the key */
+/* for locating a matching token for continued access for walking lists, */
+/* etc. */
/* ------------------------------------------------------------------------ */
-int fr_ioctlswitch(unit, data, cmd, mode, uid, ctx)
-int unit, mode, uid;
-ioctlcmd_t cmd;
-void *data, *ctx;
+int
+ipf_ioctlswitch(softc, unit, data, cmd, mode, uid, ctx)
+ ipf_main_softc_t *softc;
+ int unit, mode, uid;
+ ioctlcmd_t cmd;
+ void *data, *ctx;
{
int error = 0;
+ switch (cmd)
+ {
+ case SIOCIPFINTERROR :
+ error = BCOPYOUT(&softc->ipf_interror, data,
+ sizeof(softc->ipf_interror));
+ if (error != 0) {
+ IPFERROR(40);
+ error = EFAULT;
+ }
+ return error;
+ default :
+ break;
+ }
+
switch (unit)
{
case IPL_LOGIPF :
- error = fr_ipf_ioctl(data, cmd, mode, uid, ctx);
+ error = ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx);
break;
case IPL_LOGNAT :
- if (fr_running > 0)
- error = fr_nat_ioctl(data, cmd, mode, uid, ctx);
- else
+ if (softc->ipf_running > 0) {
+ error = ipf_nat_ioctl(softc, data, cmd, mode,
+ uid, ctx);
+ } else {
+ IPFERROR(42);
error = EIO;
+ }
break;
case IPL_LOGSTATE :
- if (fr_running > 0)
- error = fr_state_ioctl(data, cmd, mode, uid, ctx);
- else
+ if (softc->ipf_running > 0) {
+ error = ipf_state_ioctl(softc, data, cmd, mode,
+ uid, ctx);
+ } else {
+ IPFERROR(43);
error = EIO;
+ }
break;
case IPL_LOGAUTH :
- if (fr_running > 0)
- error = fr_auth_ioctl(data, cmd, mode, uid, ctx);
- else
+ if (softc->ipf_running > 0) {
+ error = ipf_auth_ioctl(softc, data, cmd, mode,
+ uid, ctx);
+ } else {
+ IPFERROR(44);
error = EIO;
+ }
break;
case IPL_LOGSYNC :
-#ifdef IPFILTER_SYNC
- if (fr_running > 0)
- error = fr_sync_ioctl(data, cmd, mode, uid, ctx);
- else
-#endif
+ if (softc->ipf_running > 0) {
+ error = ipf_sync_ioctl(softc, data, cmd, mode,
+ uid, ctx);
+ } else {
error = EIO;
+ IPFERROR(45);
+ }
break;
case IPL_LOGSCAN :
#ifdef IPFILTER_SCAN
- if (fr_running > 0)
- error = fr_scan_ioctl(data, cmd, mode, uid, ctx);
+ if (softc->ipf_running > 0)
+ error = ipf_scan_ioctl(softc, data, cmd, mode,
+ uid, ctx);
else
#endif
+ {
error = EIO;
+ IPFERROR(46);
+ }
break;
case IPL_LOGLOOKUP :
-#ifdef IPFILTER_LOOKUP
- if (fr_running > 0)
- error = ip_lookup_ioctl(data, cmd, mode, uid, ctx);
- else
-#endif
+ if (softc->ipf_running > 0) {
+ error = ipf_lookup_ioctl(softc, data, cmd, mode,
+ uid, ctx);
+ } else {
error = EIO;
+ IPFERROR(47);
+ }
break;
default :
+ IPFERROR(48);
error = EIO;
break;
}
@@ -5443,200 +6244,244 @@ void *data, *ctx;
/*
* This array defines the expected size of objects coming into the kernel
- * for the various recognised object types.
+ * for the various recognised object types. The first column is flags (see
+ * below), 2nd column is current size, 3rd column is the version number of
+ * when the current size became current.
+ * Flags:
+ * 1 = minimum size, not absolute size
*/
-static int fr_objbytes[IPFOBJ_COUNT][2] = {
- { 1, sizeof(struct frentry) }, /* frentry */
- { 0, sizeof(struct friostat) },
- { 0, sizeof(struct fr_info) },
- { 0, sizeof(struct fr_authstat) },
- { 0, sizeof(struct ipfrstat) },
- { 0, sizeof(struct ipnat) },
- { 0, sizeof(struct natstat) },
- { 0, sizeof(struct ipstate_save) },
- { 1, sizeof(struct nat_save) }, /* nat_save */
- { 0, sizeof(struct natlookup) },
- { 1, sizeof(struct ipstate) }, /* ipstate */
- { 0, sizeof(struct ips_stat) },
- { 0, sizeof(struct frauth) },
- { 0, sizeof(struct ipftune) },
- { 0, sizeof(struct nat) }, /* nat_t */
- { 0, sizeof(struct ipfruleiter) },
- { 0, sizeof(struct ipfgeniter) },
- { 0, sizeof(struct ipftable) },
- { 0, sizeof(struct ipflookupiter) },
+static int ipf_objbytes[IPFOBJ_COUNT][3] = {
+ { 1, sizeof(struct frentry), 5010000 }, /* 0 */
+ { 1, sizeof(struct friostat), 5010000 },
+ { 0, sizeof(struct fr_info), 5010000 },
+ { 0, sizeof(struct ipf_authstat), 4010100 },
+ { 0, sizeof(struct ipfrstat), 5010000 },
+ { 1, sizeof(struct ipnat), 5010000 }, /* 5 */
+ { 0, sizeof(struct natstat), 5010000 },
+ { 0, sizeof(struct ipstate_save), 5010000 },
+ { 1, sizeof(struct nat_save), 5010000 },
+ { 0, sizeof(struct natlookup), 5010000 },
+ { 1, sizeof(struct ipstate), 5010000 }, /* 10 */
+ { 0, sizeof(struct ips_stat), 5010000 },
+ { 0, sizeof(struct frauth), 5010000 },
+ { 0, sizeof(struct ipftune), 4010100 },
+ { 0, sizeof(struct nat), 5010000 },
+ { 0, sizeof(struct ipfruleiter), 4011400 }, /* 15 */
+ { 0, sizeof(struct ipfgeniter), 4011400 },
+ { 0, sizeof(struct ipftable), 4011400 },
+ { 0, sizeof(struct ipflookupiter), 4011400 },
{ 0, sizeof(struct ipftq) * IPF_TCP_NSTATES },
+ { 1, 0, 0 }, /* IPFEXPR */
+ { 0, 0, 0 }, /* PROXYCTL */
+ { 0, sizeof (struct fripf), 5010000 }
};
/* ------------------------------------------------------------------------ */
-/* Function: fr_inobj */
+/* Function: ipf_inobj */
/* Returns: int - 0 = success, else failure */
-/* Parameters: data(I) - pointer to ioctl data */
-/* ptr(I) - pointer to store real data in */
-/* type(I) - type of structure being moved */
+/* Parameters: softc(I) - soft context pointerto work with */
+/* data(I) - pointer to ioctl data */
+/* objp(O) - where to store ipfobj structure */
+/* ptr(I) - pointer to data to copy out */
+/* type(I) - type of structure being moved */
/* */
/* Copy in the contents of what the ipfobj_t points to. In future, we */
/* add things to check for version numbers, sizes, etc, to make it backward */
/* compatible at the ABI for user land. */
+/* If objp is not NULL then we assume that the caller wants to see what is */
+/* in the ipfobj_t structure being copied in. As an example, this can tell */
+/* the caller what version of ipfilter the ioctl program was written to. */
/* ------------------------------------------------------------------------ */
-int fr_inobj(data, ptr, type)
-void *data;
-void *ptr;
-int type;
+int
+ipf_inobj(softc, data, objp, ptr, type)
+ ipf_main_softc_t *softc;
+ void *data;
+ ipfobj_t *objp;
+ void *ptr;
+ int type;
{
ipfobj_t obj;
- int error = 0;
+ int error;
+ int size;
- if ((type < 0) || (type >= IPFOBJ_COUNT))
+ if ((type < 0) || (type >= IPFOBJ_COUNT)) {
+ IPFERROR(49);
return EINVAL;
+ }
- error = BCOPYIN(data, &obj, sizeof(obj));
- if (error != 0)
+ if (objp == NULL)
+ objp = &obj;
+ error = BCOPYIN(data, objp, sizeof(*objp));
+ if (error != 0) {
+ IPFERROR(124);
return EFAULT;
+ }
- if (obj.ipfo_type != type)
+ if (objp->ipfo_type != type) {
+ IPFERROR(50);
return EINVAL;
+ }
-#ifndef IPFILTER_COMPAT
- if ((fr_objbytes[type][0] & 1) != 0) {
- if (obj.ipfo_size < fr_objbytes[type][1])
+ if (objp->ipfo_rev >= ipf_objbytes[type][2]) {
+ if ((ipf_objbytes[type][0] & 1) != 0) {
+ if (objp->ipfo_size < ipf_objbytes[type][1]) {
+ IPFERROR(51);
+ return EINVAL;
+ }
+ size = ipf_objbytes[type][1];
+ } else if (objp->ipfo_size == ipf_objbytes[type][1]) {
+ size = objp->ipfo_size;
+ } else {
+ IPFERROR(52);
return EINVAL;
- } else if (obj.ipfo_size != fr_objbytes[type][1]) {
- return EINVAL;
- }
+ }
+ error = COPYIN(objp->ipfo_ptr, ptr, size);
+ if (error != 0) {
+ IPFERROR(55);
+ error = EFAULT;
+ }
+ } else {
+#ifdef IPFILTER_COMPAT
+ error = ipf_in_compat(softc, objp, ptr, 0);
#else
- if (obj.ipfo_rev != IPFILTER_VERSION)
- /* XXX compatibility hook here */
- ;
- if ((fr_objbytes[type][0] & 1) != 0) {
- if (obj.ipfo_size < fr_objbytes[type][1])
- /* XXX compatibility hook here */
- return EINVAL;
- } else if (obj.ipfo_size != fr_objbytes[type][1])
- /* XXX compatibility hook here */
- return EINVAL;
+ IPFERROR(54);
+ error = EINVAL;
#endif
-
- if ((fr_objbytes[type][0] & 1) != 0) {
- error = COPYIN(obj.ipfo_ptr, ptr, fr_objbytes[type][1]);
- } else {
- error = COPYIN(obj.ipfo_ptr, ptr, obj.ipfo_size);
}
- if (error != 0)
- error = EFAULT;
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_inobjsz */
+/* Function: ipf_inobjsz */
/* Returns: int - 0 = success, else failure */
-/* Parameters: data(I) - pointer to ioctl data */
-/* ptr(I) - pointer to store real data in */
-/* type(I) - type of structure being moved */
-/* sz(I) - size of data to copy */
+/* Parameters: softc(I) - soft context pointerto work with */
+/* data(I) - pointer to ioctl data */
+/* ptr(I) - pointer to store real data in */
+/* type(I) - type of structure being moved */
+/* sz(I) - size of data to copy */
/* */
-/* As per fr_inobj, except the size of the object to copy in is passed in */
+/* As per ipf_inobj, except the size of the object to copy in is passed in */
/* but it must not be smaller than the size defined for the type and the */
/* type must allow for varied sized objects. The extra requirement here is */
/* that sz must match the size of the object being passed in - this is not */
-/* not possible nor required in fr_inobj(). */
+/* not possible nor required in ipf_inobj(). */
/* ------------------------------------------------------------------------ */
-int fr_inobjsz(data, ptr, type, sz)
-void *data;
-void *ptr;
-int type, sz;
+int
+ipf_inobjsz(softc, data, ptr, type, sz)
+ ipf_main_softc_t *softc;
+ void *data;
+ void *ptr;
+ int type, sz;
{
ipfobj_t obj;
int error;
- if ((type < 0) || (type >= IPFOBJ_COUNT))
- return EINVAL;
- if (((fr_objbytes[type][0] & 1) == 0) || (sz < fr_objbytes[type][1]))
+ if ((type < 0) || (type >= IPFOBJ_COUNT)) {
+ IPFERROR(56);
return EINVAL;
+ }
error = BCOPYIN(data, &obj, sizeof(obj));
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(125);
return EFAULT;
+ }
- if (obj.ipfo_type != type)
+ if (obj.ipfo_type != type) {
+ IPFERROR(58);
return EINVAL;
+ }
-#ifndef IPFILTER_COMPAT
- if (obj.ipfo_size != sz)
- return EINVAL;
+ if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
+ if (((ipf_objbytes[type][0] & 1) == 0) ||
+ (sz < ipf_objbytes[type][1])) {
+ IPFERROR(57);
+ return EINVAL;
+ }
+ error = COPYIN(obj.ipfo_ptr, ptr, sz);
+ if (error != 0) {
+ IPFERROR(61);
+ error = EFAULT;
+ }
+ } else {
+#ifdef IPFILTER_COMPAT
+ error = ipf_in_compat(softc, &obj, ptr, sz);
#else
- if (obj.ipfo_rev != IPFILTER_VERSION)
- /* XXX compatibility hook here */
- ;
- if (obj.ipfo_size != sz)
- /* XXX compatibility hook here */
- return EINVAL;
+ IPFERROR(60);
+ error = EINVAL;
#endif
-
- error = COPYIN(obj.ipfo_ptr, ptr, sz);
- if (error != 0)
- error = EFAULT;
+ }
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_outobjsz */
+/* Function: ipf_outobjsz */
/* Returns: int - 0 = success, else failure */
/* Parameters: data(I) - pointer to ioctl data */
/* ptr(I) - pointer to store real data in */
/* type(I) - type of structure being moved */
/* sz(I) - size of data to copy */
/* */
-/* As per fr_outobj, except the size of the object to copy out is passed in */
+/* As per ipf_outobj, except the size of the object to copy out is passed in*/
/* but it must not be smaller than the size defined for the type and the */
/* type must allow for varied sized objects. The extra requirement here is */
/* that sz must match the size of the object being passed in - this is not */
-/* not possible nor required in fr_outobj(). */
+/* not possible nor required in ipf_outobj(). */
/* ------------------------------------------------------------------------ */
-int fr_outobjsz(data, ptr, type, sz)
-void *data;
-void *ptr;
-int type, sz;
+int
+ipf_outobjsz(softc, data, ptr, type, sz)
+ ipf_main_softc_t *softc;
+ void *data;
+ void *ptr;
+ int type, sz;
{
ipfobj_t obj;
int error;
- if ((type < 0) || (type >= IPFOBJ_COUNT) ||
- ((fr_objbytes[type][0] & 1) == 0) ||
- (sz < fr_objbytes[type][1]))
+ if ((type < 0) || (type >= IPFOBJ_COUNT)) {
+ IPFERROR(62);
return EINVAL;
+ }
error = BCOPYIN(data, &obj, sizeof(obj));
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(127);
return EFAULT;
+ }
- if (obj.ipfo_type != type)
+ if (obj.ipfo_type != type) {
+ IPFERROR(63);
return EINVAL;
+ }
-#ifndef IPFILTER_COMPAT
- if (obj.ipfo_size != sz)
- return EINVAL;
+ if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
+ if (((ipf_objbytes[type][0] & 1) == 0) ||
+ (sz < ipf_objbytes[type][1])) {
+ IPFERROR(146);
+ return EINVAL;
+ }
+ error = COPYOUT(ptr, obj.ipfo_ptr, sz);
+ if (error != 0) {
+ IPFERROR(66);
+ error = EFAULT;
+ }
+ } else {
+#ifdef IPFILTER_COMPAT
+ error = ipf_out_compat(softc, &obj, ptr);
#else
- if (obj.ipfo_rev != IPFILTER_VERSION)
- /* XXX compatibility hook here */
- ;
- if (obj.ipfo_size != sz)
- /* XXX compatibility hook here */
- return EINVAL;
+ IPFERROR(65);
+ error = EINVAL;
#endif
-
- error = COPYOUT(ptr, obj.ipfo_ptr, sz);
- if (error != 0)
- error = EFAULT;
+ }
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_outobj */
+/* Function: ipf_outobj */
/* Returns: int - 0 = success, else failure */
/* Parameters: data(I) - pointer to ioctl data */
/* ptr(I) - pointer to store real data in */
@@ -5646,75 +6491,134 @@ int type, sz;
/* future, we add things to check for version numbers, sizes, etc, to make */
/* it backward compatible at the ABI for user land. */
/* ------------------------------------------------------------------------ */
-int fr_outobj(data, ptr, type)
-void *data;
-void *ptr;
-int type;
+int
+ipf_outobj(softc, data, ptr, type)
+ ipf_main_softc_t *softc;
+ void *data;
+ void *ptr;
+ int type;
{
ipfobj_t obj;
int error;
- if ((type < 0) || (type >= IPFOBJ_COUNT))
+ if ((type < 0) || (type >= IPFOBJ_COUNT)) {
+ IPFERROR(67);
return EINVAL;
+ }
error = BCOPYIN(data, &obj, sizeof(obj));
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(126);
return EFAULT;
+ }
- if (obj.ipfo_type != type)
+ if (obj.ipfo_type != type) {
+ IPFERROR(68);
return EINVAL;
+ }
-#ifndef IPFILTER_COMPAT
- if ((fr_objbytes[type][0] & 1) != 0) {
- if (obj.ipfo_size < fr_objbytes[type][1])
+ if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
+ if ((ipf_objbytes[type][0] & 1) != 0) {
+ if (obj.ipfo_size < ipf_objbytes[type][1]) {
+ IPFERROR(69);
+ return EINVAL;
+ }
+ } else if (obj.ipfo_size != ipf_objbytes[type][1]) {
+ IPFERROR(70);
return EINVAL;
- } else if (obj.ipfo_size != fr_objbytes[type][1])
- return EINVAL;
+ }
+
+ error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size);
+ if (error != 0) {
+ IPFERROR(73);
+ error = EFAULT;
+ }
+ } else {
+#ifdef IPFILTER_COMPAT
+ error = ipf_out_compat(softc, &obj, ptr);
#else
- if (obj.ipfo_rev != IPFILTER_VERSION)
- /* XXX compatibility hook here */
- ;
- if ((fr_objbytes[type][0] & 1) != 0) {
- if (obj.ipfo_size < fr_objbytes[type][1])
- /* XXX compatibility hook here */
- return EINVAL;
- } else if (obj.ipfo_size != fr_objbytes[type][1])
- /* XXX compatibility hook here */
- return EINVAL;
+ IPFERROR(72);
+ error = EINVAL;
#endif
+ }
+ return error;
+}
- error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size);
- if (error != 0)
- error = EFAULT;
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_outobjk */
+/* Returns: int - 0 = success, else failure */
+/* Parameters: obj(I) - pointer to data description structure */
+/* ptr(I) - pointer to kernel data to copy out */
+/* */
+/* In the above functions, the ipfobj_t structure is copied into the kernel,*/
+/* telling ipfilter how to copy out data. In this instance, the ipfobj_t is */
+/* already populated with information and now we just need to use it. */
+/* There is no need for this function to have a "type" parameter as there */
+/* is no point in validating information that comes from the kernel with */
+/* itself. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_outobjk(softc, obj, ptr)
+ ipf_main_softc_t *softc;
+ ipfobj_t *obj;
+ void *ptr;
+{
+ int type = obj->ipfo_type;
+ int error;
+
+ if ((type < 0) || (type >= IPFOBJ_COUNT)) {
+ IPFERROR(147);
+ return EINVAL;
+ }
+
+ if (obj->ipfo_rev >= ipf_objbytes[type][2]) {
+ if ((ipf_objbytes[type][0] & 1) != 0) {
+ if (obj->ipfo_size < ipf_objbytes[type][1]) {
+ IPFERROR(148);
+ return EINVAL;
+ }
+
+ } else if (obj->ipfo_size != ipf_objbytes[type][1]) {
+ IPFERROR(149);
+ return EINVAL;
+ }
+
+ error = COPYOUT(ptr, obj->ipfo_ptr, obj->ipfo_size);
+ if (error != 0) {
+ IPFERROR(150);
+ error = EFAULT;
+ }
+ } else {
+#ifdef IPFILTER_COMPAT
+ error = ipf_out_compat(softc, obj, ptr);
+#else
+ IPFERROR(151);
+ error = EINVAL;
+#endif
+ }
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_checkl4sum */
+/* Function: ipf_checkl4sum */
/* Returns: int - 0 = good, -1 = bad, 1 = cannot check */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* If possible, calculate the layer 4 checksum for the packet. If this is */
/* not possible, return without indicating a failure or success but in a */
-/* way that is ditinguishable. */
+/* way that is ditinguishable. This function should only be called by the */
+/* ipf_checkv6sum() for each platform. */
/* ------------------------------------------------------------------------ */
-int fr_checkl4sum(fin)
-fr_info_t *fin;
+INLINE int
+ipf_checkl4sum(fin)
+ fr_info_t *fin;
{
u_short sum, hdrsum, *csump;
udphdr_t *udp;
int dosum;
- if ((fin->fin_flx & FI_NOCKSUM) != 0)
- return 0;
-
- if (fin->fin_cksum == 1)
- return 0;
-
- if (fin->fin_cksum == -1)
- return -1;
-
/*
* If the TCP packet isn't a fragment, isn't too short and otherwise
* isn't already considered "bad", then validate the checksum. If
@@ -5728,48 +6632,44 @@ fr_info_t *fin;
dosum = 0;
sum = 0;
-#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID)
- if (dohwcksum && ((*fin->fin_mp)->b_ick_flag == ICK_VALID)) {
- hdrsum = 0;
- sum = 0;
- } else {
-#endif
- switch (fin->fin_p)
- {
- case IPPROTO_TCP :
- csump = &((tcphdr_t *)fin->fin_dp)->th_sum;
+ switch (fin->fin_p)
+ {
+ case IPPROTO_TCP :
+ csump = &((tcphdr_t *)fin->fin_dp)->th_sum;
+ dosum = 1;
+ break;
+
+ case IPPROTO_UDP :
+ udp = fin->fin_dp;
+ if (udp->uh_sum != 0) {
+ csump = &udp->uh_sum;
dosum = 1;
- break;
+ }
+ break;
- case IPPROTO_UDP :
- udp = fin->fin_dp;
- if (udp->uh_sum != 0) {
- csump = &udp->uh_sum;
- dosum = 1;
- }
- break;
+#ifdef USE_INET6
+ case IPPROTO_ICMPV6 :
+ csump = &((struct icmp6_hdr *)fin->fin_dp)->icmp6_cksum;
+ dosum = 1;
+ break;
+#endif
- case IPPROTO_ICMP :
- csump = &((struct icmp *)fin->fin_dp)->icmp_cksum;
- dosum = 1;
- break;
+ case IPPROTO_ICMP :
+ csump = &((struct icmp *)fin->fin_dp)->icmp_cksum;
+ dosum = 1;
+ break;
- default :
- return 1;
- /*NOTREACHED*/
- }
+ default :
+ return 1;
+ /*NOTREACHED*/
+ }
- if (csump != NULL)
- hdrsum = *csump;
+ if (csump != NULL)
+ hdrsum = *csump;
- if (dosum) {
- sum = fr_cksum(fin->fin_m, fin->fin_ip,
- fin->fin_p, fin->fin_dp,
- fin->fin_dlen + fin->fin_hlen);
- }
-#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID)
+ if (dosum) {
+ sum = fr_cksum(fin, fin->fin_ip, fin->fin_p, fin->fin_dp);
}
-#endif
#if !defined(_KERNEL)
if (sum == hdrsum) {
FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum));
@@ -5777,17 +6677,18 @@ fr_info_t *fin;
FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum));
}
#endif
+ DT2(l4sums, u_short, hdrsum, u_short, sum);
if (hdrsum == sum) {
- fin->fin_cksum = 1;
+ fin->fin_cksum = FI_CK_SUMOK;
return 0;
}
- fin->fin_cksum = -1;
+ fin->fin_cksum = FI_CK_BAD;
return -1;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_ifpfillv4addr */
+/* Function: ipf_ifpfillv4addr */
/* Returns: int - 0 = address update, -1 = address not updated */
/* Parameters: atype(I) - type of network address update to perform */
/* sin(I) - pointer to source of address information */
@@ -5802,10 +6703,11 @@ fr_info_t *fin;
/* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */
/* value. */
/* ------------------------------------------------------------------------ */
-int fr_ifpfillv4addr(atype, sin, mask, inp, inpmask)
-int atype;
-struct sockaddr_in *sin, *mask;
-struct in_addr *inp, *inpmask;
+int
+ipf_ifpfillv4addr(atype, sin, mask, inp, inpmask)
+ int atype;
+ struct sockaddr_in *sin, *mask;
+ struct in_addr *inp, *inpmask;
{
if (inpmask != NULL && atype != FRI_NETMASKED)
inpmask->s_addr = 0xffffffff;
@@ -5826,7 +6728,7 @@ struct in_addr *inp, *inpmask;
#ifdef USE_INET6
/* ------------------------------------------------------------------------ */
-/* Function: fr_ifpfillv6addr */
+/* Function: ipf_ifpfillv6addr */
/* Returns: int - 0 = address update, -1 = address not updated */
/* Parameters: atype(I) - type of network address update to perform */
/* sin(I) - pointer to source of address information */
@@ -5841,44 +6743,43 @@ struct in_addr *inp, *inpmask;
/* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */
/* value. */
/* ------------------------------------------------------------------------ */
-int fr_ifpfillv6addr(atype, sin, mask, inp, inpmask)
-int atype;
-struct sockaddr_in6 *sin, *mask;
-struct in_addr *inp, *inpmask;
+int
+ipf_ifpfillv6addr(atype, sin, mask, inp, inpmask)
+ int atype;
+ struct sockaddr_in6 *sin, *mask;
+ i6addr_t *inp, *inpmask;
{
- i6addr_t *src, *dst, *and, *dmask;
+ i6addr_t *src, *and;
src = (i6addr_t *)&sin->sin6_addr;
and = (i6addr_t *)&mask->sin6_addr;
- dst = (i6addr_t *)inp;
- dmask = (i6addr_t *)inpmask;
if (inpmask != NULL && atype != FRI_NETMASKED) {
- dmask->i6[0] = 0xffffffff;
- dmask->i6[1] = 0xffffffff;
- dmask->i6[2] = 0xffffffff;
- dmask->i6[3] = 0xffffffff;
+ inpmask->i6[0] = 0xffffffff;
+ inpmask->i6[1] = 0xffffffff;
+ inpmask->i6[2] = 0xffffffff;
+ inpmask->i6[3] = 0xffffffff;
}
if (atype == FRI_NETWORK || atype == FRI_NETMASKED) {
if (atype == FRI_NETMASKED) {
if (inpmask == NULL)
return -1;
- dmask->i6[0] = and->i6[0];
- dmask->i6[1] = and->i6[1];
- dmask->i6[2] = and->i6[2];
- dmask->i6[3] = and->i6[3];
+ inpmask->i6[0] = and->i6[0];
+ inpmask->i6[1] = and->i6[1];
+ inpmask->i6[2] = and->i6[2];
+ inpmask->i6[3] = and->i6[3];
}
- dst->i6[0] = src->i6[0] & and->i6[0];
- dst->i6[1] = src->i6[1] & and->i6[1];
- dst->i6[2] = src->i6[2] & and->i6[2];
- dst->i6[3] = src->i6[3] & and->i6[3];
+ inp->i6[0] = src->i6[0] & and->i6[0];
+ inp->i6[1] = src->i6[1] & and->i6[1];
+ inp->i6[2] = src->i6[2] & and->i6[2];
+ inp->i6[3] = src->i6[3] & and->i6[3];
} else {
- dst->i6[0] = src->i6[0];
- dst->i6[1] = src->i6[1];
- dst->i6[2] = src->i6[2];
- dst->i6[3] = src->i6[3];
+ inp->i6[0] = src->i6[0];
+ inp->i6[1] = src->i6[1];
+ inp->i6[2] = src->i6[2];
+ inp->i6[3] = src->i6[3];
}
return 0;
}
@@ -5886,7 +6787,7 @@ struct in_addr *inp, *inpmask;
/* ------------------------------------------------------------------------ */
-/* Function: fr_matchtag */
+/* Function: ipf_matchtag */
/* Returns: 0 == mismatch, 1 == match. */
/* Parameters: tag1(I) - pointer to first tag to compare */
/* tag2(I) - pointer to second tag to compare */
@@ -5898,8 +6799,9 @@ struct in_addr *inp, *inpmask;
/* comparison. This function should only be called with both tag1 and tag2 */
/* as non-NULL pointers. */
/* ------------------------------------------------------------------------ */
-int fr_matchtag(tag1, tag2)
-ipftag_t *tag1, *tag2;
+int
+ipf_matchtag(tag1, tag2)
+ ipftag_t *tag1, *tag2;
{
if (tag1 == tag2)
return 1;
@@ -5917,16 +6819,18 @@ ipftag_t *tag1, *tag2;
/* ------------------------------------------------------------------------ */
-/* Function: fr_coalesce */
+/* Function: ipf_coalesce */
/* Returns: 1 == success, -1 == failure, 0 == no change */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* Attempt to get all of the packet data into a single, contiguous buffer. */
/* If this call returns a failure then the buffers have also been freed. */
/* ------------------------------------------------------------------------ */
-int fr_coalesce(fin)
-fr_info_t *fin;
+int
+ipf_coalesce(fin)
+ fr_info_t *fin;
{
+
if ((fin->fin_flx & FI_COALESCE) != 0)
return 1;
@@ -5938,11 +6842,15 @@ fr_info_t *fin;
return 0;
#if defined(_KERNEL)
- if (fr_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) {
- ATOMIC_INCL(fr_badcoalesces[fin->fin_out]);
+ if (ipf_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+
+ DT1(frb_coalesce, fr_info_t *, fin);
+ LBUMP(ipf_stats[fin->fin_out].fr_badcoalesces);
# ifdef MENTAT
FREE_MB_T(*fin->fin_mp);
# endif
+ fin->fin_reason = FRB_COALESCE;
*fin->fin_mp = NULL;
fin->fin_m = NULL;
return -1;
@@ -5967,114 +6875,10 @@ fr_info_t *fin;
* The obvious implication is if neither of these are set then the value can be
* changed at any time without harm.
*/
-ipftuneable_t ipf_tuneables[] = {
- /* filtering */
- { { &fr_flags }, "fr_flags", 0, 0xffffffff,
- sizeof(fr_flags), 0, NULL },
- { { &fr_active }, "fr_active", 0, 0,
- sizeof(fr_active), IPFT_RDONLY, NULL },
- { { &fr_control_forwarding }, "fr_control_forwarding", 0, 1,
- sizeof(fr_control_forwarding), 0, NULL },
- { { &fr_update_ipid }, "fr_update_ipid", 0, 1,
- sizeof(fr_update_ipid), 0, NULL },
- { { &fr_chksrc }, "fr_chksrc", 0, 1,
- sizeof(fr_chksrc), 0, NULL },
- { { &fr_minttl }, "fr_minttl", 0, 1,
- sizeof(fr_minttl), 0, NULL },
- { { &fr_icmpminfragmtu }, "fr_icmpminfragmtu", 0, 1,
- sizeof(fr_icmpminfragmtu), 0, NULL },
- { { &fr_pass }, "fr_pass", 0, 0xffffffff,
- sizeof(fr_pass), 0, NULL },
- /* state */
- { { &fr_tcpidletimeout }, "fr_tcpidletimeout", 1, 0x7fffffff,
- sizeof(fr_tcpidletimeout), IPFT_WRDISABLED, NULL },
- { { &fr_tcpclosewait }, "fr_tcpclosewait", 1, 0x7fffffff,
- sizeof(fr_tcpclosewait), IPFT_WRDISABLED, NULL },
- { { &fr_tcplastack }, "fr_tcplastack", 1, 0x7fffffff,
- sizeof(fr_tcplastack), IPFT_WRDISABLED, NULL },
- { { &fr_tcptimeout }, "fr_tcptimeout", 1, 0x7fffffff,
- sizeof(fr_tcptimeout), IPFT_WRDISABLED, NULL },
- { { &fr_tcpclosed }, "fr_tcpclosed", 1, 0x7fffffff,
- sizeof(fr_tcpclosed), IPFT_WRDISABLED, NULL },
- { { &fr_tcphalfclosed }, "fr_tcphalfclosed", 1, 0x7fffffff,
- sizeof(fr_tcphalfclosed), IPFT_WRDISABLED, NULL },
- { { &fr_udptimeout }, "fr_udptimeout", 1, 0x7fffffff,
- sizeof(fr_udptimeout), IPFT_WRDISABLED, NULL },
- { { &fr_udpacktimeout }, "fr_udpacktimeout", 1, 0x7fffffff,
- sizeof(fr_udpacktimeout), IPFT_WRDISABLED, NULL },
- { { &fr_icmptimeout }, "fr_icmptimeout", 1, 0x7fffffff,
- sizeof(fr_icmptimeout), IPFT_WRDISABLED, NULL },
- { { &fr_icmpacktimeout }, "fr_icmpacktimeout", 1, 0x7fffffff,
- sizeof(fr_icmpacktimeout), IPFT_WRDISABLED, NULL },
- { { &fr_iptimeout }, "fr_iptimeout", 1, 0x7fffffff,
- sizeof(fr_iptimeout), IPFT_WRDISABLED, NULL },
- { { &fr_statemax }, "fr_statemax", 1, 0x7fffffff,
- sizeof(fr_statemax), 0, NULL },
- { { &fr_statesize }, "fr_statesize", 1, 0x7fffffff,
- sizeof(fr_statesize), IPFT_WRDISABLED, NULL },
- { { &fr_state_lock }, "fr_state_lock", 0, 1,
- sizeof(fr_state_lock), IPFT_RDONLY, NULL },
- { { &fr_state_maxbucket }, "fr_state_maxbucket", 1, 0x7fffffff,
- sizeof(fr_state_maxbucket), IPFT_WRDISABLED, NULL },
- { { &fr_state_maxbucket_reset }, "fr_state_maxbucket_reset", 0, 1,
- sizeof(fr_state_maxbucket_reset), IPFT_WRDISABLED, NULL },
- { { &ipstate_logging }, "ipstate_logging", 0, 1,
- sizeof(ipstate_logging), 0, NULL },
- /* nat */
- { { &fr_nat_lock }, "fr_nat_lock", 0, 1,
- sizeof(fr_nat_lock), IPFT_RDONLY, NULL },
- { { &ipf_nattable_sz }, "ipf_nattable_sz", 1, 0x7fffffff,
- sizeof(ipf_nattable_sz), IPFT_WRDISABLED, NULL },
- { { &ipf_nattable_max }, "ipf_nattable_max", 1, 0x7fffffff,
- sizeof(ipf_nattable_max), 0, NULL },
- { { &ipf_natrules_sz }, "ipf_natrules_sz", 1, 0x7fffffff,
- sizeof(ipf_natrules_sz), IPFT_WRDISABLED, NULL },
- { { &ipf_rdrrules_sz }, "ipf_rdrrules_sz", 1, 0x7fffffff,
- sizeof(ipf_rdrrules_sz), IPFT_WRDISABLED, NULL },
- { { &ipf_hostmap_sz }, "ipf_hostmap_sz", 1, 0x7fffffff,
- sizeof(ipf_hostmap_sz), IPFT_WRDISABLED, NULL },
- { { &fr_nat_maxbucket }, "fr_nat_maxbucket", 1, 0x7fffffff,
- sizeof(fr_nat_maxbucket), 0, NULL },
- { { &fr_nat_maxbucket_reset }, "fr_nat_maxbucket_reset", 0, 1,
- sizeof(fr_nat_maxbucket_reset), IPFT_WRDISABLED, NULL },
- { { &nat_logging }, "nat_logging", 0, 1,
- sizeof(nat_logging), 0, NULL },
- { { &fr_defnatage }, "fr_defnatage", 1, 0x7fffffff,
- sizeof(fr_defnatage), IPFT_WRDISABLED, NULL },
- { { &fr_defnatipage }, "fr_defnatipage", 1, 0x7fffffff,
- sizeof(fr_defnatipage), IPFT_WRDISABLED, NULL },
- { { &fr_defnaticmpage }, "fr_defnaticmpage", 1, 0x7fffffff,
- sizeof(fr_defnaticmpage), IPFT_WRDISABLED, NULL },
- { { &fr_nat_doflush }, "fr_nat_doflush", 0, 1,
- sizeof(fr_nat_doflush), 0, NULL },
- /* proxy */
- { { &ipf_proxy_debug }, "ipf_proxy_debug", 0, 10,
- sizeof(ipf_proxy_debug), 0, 0 },
- /* frag */
- { { &ipfr_size }, "ipfr_size", 1, 0x7fffffff,
- sizeof(ipfr_size), IPFT_WRDISABLED, NULL },
- { { &fr_ipfrttl }, "fr_ipfrttl", 1, 0x7fffffff,
- sizeof(fr_ipfrttl), IPFT_WRDISABLED, NULL },
-#ifdef IPFILTER_LOG
- /* log */
- { { &ipl_suppress }, "ipl_suppress", 0, 1,
- sizeof(ipl_suppress), 0, NULL },
- { { &ipl_logmax }, "ipl_logmax", 0, 0x7fffffff,
- sizeof(ipl_logmax), IPFT_WRDISABLED, NULL },
- { { &ipl_logall }, "ipl_logall", 0, 1,
- sizeof(ipl_logall), 0, NULL },
- { { &ipl_logsize }, "ipl_logsize", 0, 0x80000,
- sizeof(ipl_logsize), 0, NULL },
-#endif
- { { NULL }, NULL, 0, 0,
- 0, 0, NULL }
-};
-
-static ipftuneable_t *ipf_tunelist = NULL;
/* ------------------------------------------------------------------------ */
-/* Function: fr_findtunebycookie */
+/* Function: ipf_tune_findbycookie */
/* Returns: NULL = search failed, else pointer to tune struct */
/* Parameters: cookie(I) - cookie value to search for amongst tuneables */
/* next(O) - pointer to place to store the cookie for the */
@@ -6085,12 +6889,14 @@ static ipftuneable_t *ipf_tunelist = NULL;
/* a matching value for "cookie" - ie its address. When returning a match, */
/* the next one to be found may be returned inside next. */
/* ------------------------------------------------------------------------ */
-static ipftuneable_t *fr_findtunebycookie(cookie, next)
-void *cookie, **next;
+static ipftuneable_t *
+ipf_tune_findbycookie(ptop, cookie, next)
+ ipftuneable_t **ptop;
+ void *cookie, **next;
{
ipftuneable_t *ta, **tap;
- for (ta = ipf_tuneables; ta->ipft_name != NULL; ta++)
+ for (ta = *ptop; ta->ipft_name != NULL; ta++)
if (ta == cookie) {
if (next != NULL) {
/*
@@ -6104,12 +6910,12 @@ void *cookie, **next;
if ((ta + 1)->ipft_name != NULL)
*next = ta + 1;
else
- *next = &ipf_tunelist;
+ *next = ptop;
}
return ta;
}
- for (tap = &ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next)
+ for (tap = ptop; (ta = *tap) != NULL; tap = &ta->ipft_next)
if (tap == cookie) {
if (next != NULL)
*next = &ta->ipft_next;
@@ -6123,7 +6929,7 @@ void *cookie, **next;
/* ------------------------------------------------------------------------ */
-/* Function: fr_findtunebyname */
+/* Function: ipf_tune_findbyname */
/* Returns: NULL = search failed, else pointer to tune struct */
/* Parameters: name(I) - name of the tuneable entry to find. */
/* */
@@ -6131,44 +6937,192 @@ void *cookie, **next;
/* for an entry with a matching name. If we can find one, return a pointer */
/* to the matching structure. */
/* ------------------------------------------------------------------------ */
-static ipftuneable_t *fr_findtunebyname(name)
-const char *name;
+static ipftuneable_t *
+ipf_tune_findbyname(top, name)
+ ipftuneable_t *top;
+ const char *name;
{
ipftuneable_t *ta;
- for (ta = ipf_tuneables; ta->ipft_name != NULL; ta++)
+ for (ta = top; ta != NULL; ta = ta->ipft_next)
if (!strcmp(ta->ipft_name, name)) {
return ta;
}
- for (ta = ipf_tunelist; ta != NULL; ta = ta->ipft_next)
- if (!strcmp(ta->ipft_name, name)) {
- return ta;
+ return NULL;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_tune_add_array */
+/* Returns: int - 0 == success, else failure */
+/* Parameters: newtune - pointer to new tune array to add to tuneables */
+/* */
+/* Appends tune structures from the array passed in (newtune) to the end of */
+/* the current list of "dynamic" tuneable parameters. */
+/* If any entry to be added is already present (by name) then the operation */
+/* is aborted - entries that have been added are removed before returning. */
+/* An entry with no name (NULL) is used as the indication that the end of */
+/* the array has been reached. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_tune_add_array(softc, newtune)
+ ipf_main_softc_t *softc;
+ ipftuneable_t *newtune;
+{
+ ipftuneable_t *nt, *dt;
+ int error = 0;
+
+ for (nt = newtune; nt->ipft_name != NULL; nt++) {
+ error = ipf_tune_add(softc, nt);
+ if (error != 0) {
+ for (dt = newtune; dt != nt; dt++) {
+ (void) ipf_tune_del(softc, dt);
+ }
}
+ }
- return NULL;
+ return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_addipftune */
+/* Function: ipf_tune_array_link */
+/* Returns: 0 == success, -1 == failure */
+/* Parameters: softc(I) - soft context pointerto work with */
+/* array(I) - pointer to an array of tuneables */
+/* */
+/* Given an array of tunables (array), append them to the current list of */
+/* tuneables for this context (softc->ipf_tuners.) To properly prepare the */
+/* the array for being appended to the list, initialise all of the next */
+/* pointers so we don't need to walk parts of it with ++ and others with */
+/* next. The array is expected to have an entry with a NULL name as the */
+/* terminator. Trying to add an array with no non-NULL names will return as */
+/* a failure. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_tune_array_link(softc, array)
+ ipf_main_softc_t *softc;
+ ipftuneable_t *array;
+{
+ ipftuneable_t *t, **p;
+
+ t = array;
+ if (t->ipft_name == NULL)
+ return -1;
+
+ for (; t[1].ipft_name != NULL; t++)
+ t[0].ipft_next = &t[1];
+ t->ipft_next = NULL;
+
+ /*
+ * Since a pointer to the last entry isn't kept, we need to find it
+ * each time we want to add new variables to the list.
+ */
+ for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next)
+ if (t->ipft_name == NULL)
+ break;
+ *p = array;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_tune_array_unlink */
+/* Returns: 0 == success, -1 == failure */
+/* Parameters: softc(I) - soft context pointerto work with */
+/* array(I) - pointer to an array of tuneables */
+/* */
+/* ------------------------------------------------------------------------ */
+int
+ipf_tune_array_unlink(softc, array)
+ ipf_main_softc_t *softc;
+ ipftuneable_t *array;
+{
+ ipftuneable_t *t, **p;
+
+ for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next)
+ if (t == array)
+ break;
+ if (t == NULL)
+ return -1;
+
+ for (; t[1].ipft_name != NULL; t++)
+ ;
+
+ *p = t->ipft_next;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_tune_array_copy */
+/* Returns: NULL = failure, else pointer to new array */
+/* Parameters: base(I) - pointer to structure base */
+/* size(I) - size of the array at template */
+/* template(I) - original array to copy */
+/* */
+/* Allocate memory for a new set of tuneable values and copy everything */
+/* from template into the new region of memory. The new region is full of */
+/* uninitialised pointers (ipft_next) so set them up. Now, ipftp_offset... */
+/* */
+/* NOTE: the following assumes that sizeof(long) == sizeof(void *) */
+/* In the array template, ipftp_offset is the offset (in bytes) of the */
+/* location of the tuneable value inside the structure pointed to by base. */
+/* As ipftp_offset is a union over the pointers to the tuneable values, if */
+/* we add base to the copy's ipftp_offset, copy ends up with a pointer in */
+/* ipftp_void that points to the stored value. */
+/* ------------------------------------------------------------------------ */
+ipftuneable_t *
+ipf_tune_array_copy(base, size, template)
+ void *base;
+ size_t size;
+ ipftuneable_t *template;
+{
+ ipftuneable_t *copy;
+ int i;
+
+
+ KMALLOCS(copy, ipftuneable_t *, size);
+ if (copy == NULL) {
+ return NULL;
+ }
+ bcopy(template, copy, size);
+
+ for (i = 0; copy[i].ipft_name; i++) {
+ copy[i].ipft_una.ipftp_offset += (u_long)base;
+ copy[i].ipft_next = copy + i + 1;
+ }
+
+ return copy;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_tune_add */
/* Returns: int - 0 == success, else failure */
-/* Parameters: newtune - pointer to new tune struct to add to tuneables */
+/* Parameters: newtune - pointer to new tune entry to add to tuneables */
/* */
-/* Appends the tune structure pointer to by "newtune" to the end of the */
-/* current list of "dynamic" tuneable parameters. Once added, the owner */
-/* of the object is not expected to ever change "ipft_next". */
+/* Appends tune structures from the array passed in (newtune) to the end of */
+/* the current list of "dynamic" tuneable parameters. Once added, the */
+/* owner of the object is not expected to ever change "ipft_next". */
/* ------------------------------------------------------------------------ */
-int fr_addipftune(newtune)
-ipftuneable_t *newtune;
+int
+ipf_tune_add(softc, newtune)
+ ipf_main_softc_t *softc;
+ ipftuneable_t *newtune;
{
ipftuneable_t *ta, **tap;
- ta = fr_findtunebyname(newtune->ipft_name);
- if (ta != NULL)
+ ta = ipf_tune_findbyname(softc->ipf_tuners, newtune->ipft_name);
+ if (ta != NULL) {
+ IPFERROR(74);
return EEXIST;
+ }
- for (tap = &ipf_tunelist; *tap != NULL; tap = &(*tap)->ipft_next)
+ for (tap = &softc->ipf_tuners; *tap != NULL; tap = &(*tap)->ipft_next)
;
newtune->ipft_next = NULL;
@@ -6178,33 +7132,72 @@ ipftuneable_t *newtune;
/* ------------------------------------------------------------------------ */
-/* Function: fr_delipftune */
+/* Function: ipf_tune_del */
/* Returns: int - 0 == success, else failure */
-/* Parameters: oldtune - pointer to tune struct to remove from the list of */
+/* Parameters: oldtune - pointer to tune entry to remove from the list of */
/* current dynamic tuneables */
/* */
/* Search for the tune structure, by pointer, in the list of those that are */
/* dynamically added at run time. If found, adjust the list so that this */
/* structure is no longer part of it. */
/* ------------------------------------------------------------------------ */
-int fr_delipftune(oldtune)
-ipftuneable_t *oldtune;
+int
+ipf_tune_del(softc, oldtune)
+ ipf_main_softc_t *softc;
+ ipftuneable_t *oldtune;
{
ipftuneable_t *ta, **tap;
+ int error = 0;
- for (tap = &ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next)
+ for (tap = &softc->ipf_tuners; (ta = *tap) != NULL;
+ tap = &ta->ipft_next) {
if (ta == oldtune) {
*tap = oldtune->ipft_next;
oldtune->ipft_next = NULL;
- return 0;
+ break;
}
+ }
- return ESRCH;
+ if (ta == NULL) {
+ error = ESRCH;
+ IPFERROR(75);
+ }
+ return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_ipftune */
+/* Function: ipf_tune_del_array */
+/* Returns: int - 0 == success, else failure */
+/* Parameters: oldtune - pointer to tuneables array */
+/* */
+/* Remove each tuneable entry in the array from the list of "dynamic" */
+/* tunables. If one entry should fail to be found, an error will be */
+/* returned and no further ones removed. */
+/* An entry with a NULL name is used as the indicator of the last entry in */
+/* the array. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_tune_del_array(softc, oldtune)
+ ipf_main_softc_t *softc;
+ ipftuneable_t *oldtune;
+{
+ ipftuneable_t *ot;
+ int error = 0;
+
+ for (ot = oldtune; ot->ipft_name != NULL; ot++) {
+ error = ipf_tune_del(softc, ot);
+ if (error != 0)
+ break;
+ }
+
+ return error;
+
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_tune */
/* Returns: int - 0 == success, else failure */
/* Parameters: cmd(I) - ioctl command number */
/* data(I) - pointer to ioctl data structure */
@@ -6216,16 +7209,18 @@ ipftuneable_t *oldtune;
/* and 'destruction' routines of the various components of ipfilter are all */
/* each responsible for handling their own values being too big. */
/* ------------------------------------------------------------------------ */
-int fr_ipftune(cmd, data)
-ioctlcmd_t cmd;
-void *data;
+int
+ipf_ipftune(softc, cmd, data)
+ ipf_main_softc_t *softc;
+ ioctlcmd_t cmd;
+ void *data;
{
ipftuneable_t *ta;
ipftune_t tu;
void *cookie;
int error;
- error = fr_inobj(data, &tu, IPFOBJ_TUNEABLE);
+ error = ipf_inobj(softc, data, NULL, &tu, IPFOBJ_TUNEABLE);
if (error != 0)
return error;
@@ -6246,9 +7241,10 @@ void *data;
* at the front of the list.
*/
if (cookie != NULL) {
- ta = fr_findtunebycookie(cookie, &tu.ipft_cookie);
+ ta = ipf_tune_findbycookie(&softc->ipf_tuners,
+ cookie, &tu.ipft_cookie);
} else {
- ta = ipf_tuneables;
+ ta = softc->ipf_tuners;
tu.ipft_cookie = ta + 1;
}
if (ta != NULL) {
@@ -6256,8 +7252,10 @@ void *data;
* Entry found, but does the data pointed to by that
* row fit in what we can return?
*/
- if (ta->ipft_sz > sizeof(tu.ipft_un))
+ if (ta->ipft_sz > sizeof(tu.ipft_un)) {
+ IPFERROR(76);
return EINVAL;
+ }
tu.ipft_vlong = 0;
if (ta->ipft_sz == sizeof(u_long))
@@ -6277,7 +7275,7 @@ void *data;
MIN(sizeof(tu.ipft_name),
strlen(ta->ipft_name) + 1));
}
- error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE);
+ error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
break;
case SIOCIPFGET :
@@ -6286,13 +7284,16 @@ void *data;
* Search by name or by cookie value for a particular entry
* in the tuning paramter table.
*/
+ IPFERROR(77);
error = ESRCH;
if (cookie != NULL) {
- ta = fr_findtunebycookie(cookie, NULL);
+ ta = ipf_tune_findbycookie(&softc->ipf_tuners,
+ cookie, NULL);
if (ta != NULL)
error = 0;
} else if (tu.ipft_name[0] != '\0') {
- ta = fr_findtunebyname(tu.ipft_name);
+ ta = ipf_tune_findbyname(softc->ipf_tuners,
+ tu.ipft_name);
if (ta != NULL)
error = 0;
}
@@ -6317,7 +7318,7 @@ void *data;
tu.ipft_min = ta->ipft_min;
tu.ipft_max = ta->ipft_max;
tu.ipft_flags = ta->ipft_flags;
- error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE);
+ error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
} else if (cmd == (ioctlcmd_t)SIOCIPFSET) {
/*
@@ -6328,35 +7329,49 @@ void *data;
u_long in;
if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) &&
- (fr_running > 0)) {
+ (softc->ipf_running > 0)) {
+ IPFERROR(78);
error = EBUSY;
break;
}
in = tu.ipft_vlong;
if (in < ta->ipft_min || in > ta->ipft_max) {
+ IPFERROR(79);
error = EINVAL;
break;
}
- if (ta->ipft_sz == sizeof(u_long)) {
+ if (ta->ipft_func != NULL) {
+ SPL_INT(s);
+
+ SPL_NET(s);
+ error = (*ta->ipft_func)(softc, ta,
+ &tu.ipft_un);
+ SPL_X(s);
+
+ } else if (ta->ipft_sz == sizeof(u_long)) {
tu.ipft_vlong = *ta->ipft_plong;
*ta->ipft_plong = in;
+
} else if (ta->ipft_sz == sizeof(u_int)) {
tu.ipft_vint = *ta->ipft_pint;
*ta->ipft_pint = (u_int)(in & 0xffffffff);
+
} else if (ta->ipft_sz == sizeof(u_short)) {
tu.ipft_vshort = *ta->ipft_pshort;
*ta->ipft_pshort = (u_short)(in & 0xffff);
+
} else if (ta->ipft_sz == sizeof(u_char)) {
tu.ipft_vchar = *ta->ipft_pchar;
*ta->ipft_pchar = (u_char)(in & 0xff);
}
- error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE);
+ error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
}
break;
default :
+ IPFERROR(80);
error = EINVAL;
break;
}
@@ -6366,109 +7381,7 @@ void *data;
/* ------------------------------------------------------------------------ */
-/* Function: fr_initialise */
-/* Returns: int - 0 == success, < 0 == failure */
-/* Parameters: None. */
-/* */
-/* Call of the initialise functions for all the various subsystems inside */
-/* of IPFilter. If any of them should fail, return immeadiately a failure */
-/* BUT do not try to recover from the error here. */
-/* ------------------------------------------------------------------------ */
-int fr_initialise()
-{
- int i;
-
- bzero(&frstats, sizeof(frstats));
-
-#ifdef IPFILTER_LOG
- i = fr_loginit();
- if (i < 0)
- return -10 + i;
-#endif
- i = fr_natinit();
- if (i < 0)
- return -20 + i;
-
- i = fr_stateinit();
- if (i < 0)
- return -30 + i;
-
- i = fr_authinit();
- if (i < 0)
- return -40 + i;
-
- i = fr_fraginit();
- if (i < 0)
- return -50 + i;
-
- i = appr_init();
- if (i < 0)
- return -60 + i;
-
-#ifdef IPFILTER_SYNC
- i = ipfsync_init();
- if (i < 0)
- return -70 + i;
-#endif
-#ifdef IPFILTER_SCAN
- i = ipsc_init();
- if (i < 0)
- return -80 + i;
-#endif
-#ifdef IPFILTER_LOOKUP
- i = ip_lookup_init();
- if (i < 0)
- return -90 + i;
-#endif
-#ifdef IPFILTER_COMPILED
- ipfrule_add();
-#endif
- return 0;
-}
-
-
-/* ------------------------------------------------------------------------ */
-/* Function: fr_deinitialise */
-/* Returns: None. */
-/* Parameters: None. */
-/* */
-/* Call all the various subsystem cleanup routines to deallocate memory or */
-/* destroy locks or whatever they've done that they need to now undo. */
-/* The order here IS important as there are some cross references of */
-/* internal data structures. */
-/* ------------------------------------------------------------------------ */
-void fr_deinitialise()
-{
- fr_fragunload();
- fr_authunload();
- fr_natunload();
- fr_stateunload();
-#ifdef IPFILTER_SCAN
- fr_scanunload();
-#endif
- appr_unload();
-
-#ifdef IPFILTER_COMPILED
- ipfrule_remove();
-#endif
-
- (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
- (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE);
- (void) frflush(IPL_LOGCOUNT, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
- (void) frflush(IPL_LOGCOUNT, 0, FR_INQUE|FR_OUTQUE);
-
-#ifdef IPFILTER_LOOKUP
- ip_lookup_unload();
-#endif
-
-#ifdef IPFILTER_LOG
- fr_logunload();
-#endif
-}
-
-
-/* ------------------------------------------------------------------------ */
-/* Function: fr_zerostats */
+/* Function: ipf_zerostats */
/* Returns: int - 0 = success, else failure */
/* Parameters: data(O) - pointer to pointer for copying data back to */
/* */
@@ -6476,30 +7389,38 @@ void fr_deinitialise()
/* current ones in the kernel. The lock is only held across the bzero() as */
/* the copyout may result in paging (ie network activity.) */
/* ------------------------------------------------------------------------ */
-int fr_zerostats(data)
-void *data;
+int
+ipf_zerostats(softc, data)
+ ipf_main_softc_t *softc;
+ caddr_t data;
{
friostat_t fio;
+ ipfobj_t obj;
int error;
- fr_getstat(&fio);
- error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT);
- if (error)
- return EFAULT;
+ error = ipf_inobj(softc, data, &obj, &fio, IPFOBJ_IPFSTAT);
+ if (error != 0)
+ return error;
+ ipf_getstat(softc, &fio, obj.ipfo_rev);
+ error = ipf_outobj(softc, data, &fio, IPFOBJ_IPFSTAT);
+ if (error != 0)
+ return error;
- WRITE_ENTER(&ipf_mutex);
- bzero(&frstats, sizeof(frstats));
- RWLOCK_EXIT(&ipf_mutex);
+ WRITE_ENTER(&softc->ipf_mutex);
+ bzero(&softc->ipf_stats, sizeof(softc->ipf_stats));
+ RWLOCK_EXIT(&softc->ipf_mutex);
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_resolvedest */
+/* Function: ipf_resolvedest */
/* Returns: Nil */
-/* Parameters: fdp(IO) - pointer to destination information to resolve */
-/* v(I) - IP protocol version to match */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* base(I) - where strings are stored */
+/* fdp(IO) - pointer to destination information to resolve */
+/* v(I) - IP protocol version to match */
/* */
/* Looks up an interface name in the frdest structure pointed to by fdp and */
/* if a matching name can be found for the particular IP protocol version */
@@ -6507,52 +7428,66 @@ void *data;
/* found, then set the interface pointer to be -1 as NULL is considered to */
/* indicate there is no information at all in the structure. */
/* ------------------------------------------------------------------------ */
-void fr_resolvedest(fdp, v)
-frdest_t *fdp;
-int v;
+int
+ipf_resolvedest(softc, base, fdp, v)
+ ipf_main_softc_t *softc;
+ char *base;
+ frdest_t *fdp;
+ int v;
{
+ int errval = 0;
void *ifp;
ifp = NULL;
- v = v; /* LINT */
- if (*fdp->fd_ifname != '\0') {
- ifp = GETIFP(fdp->fd_ifname, v);
- if (ifp == NULL)
- ifp = (void *)-1;
+ if (fdp->fd_name != -1) {
+ if (fdp->fd_type == FRD_DSTLIST) {
+ ifp = ipf_lookup_res_name(softc, IPL_LOGIPF,
+ IPLT_DSTLIST,
+ base + fdp->fd_name,
+ NULL);
+ if (ifp == NULL) {
+ IPFERROR(144);
+ errval = ESRCH;
+ }
+ } else {
+ ifp = GETIFP(base + fdp->fd_name, v);
+ if (ifp == NULL)
+ ifp = (void *)-1;
+ }
}
- fdp->fd_ifp = ifp;
+ fdp->fd_ptr = ifp;
+
+ if ((ifp != NULL) && (ifp != (void *)-1)) {
+ fdp->fd_local = ipf_deliverlocal(softc, v, ifp, &fdp->fd_ip6);
+ }
+
+ return errval;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_resolvenic */
+/* Function: ipf_resolvenic */
/* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */
/* pointer to interface structure for NIC */
-/* Parameters: name(I) - complete interface name */
+/* Parameters: softc(I)- pointer to soft context main structure */
+/* name(I) - complete interface name */
/* v(I) - IP protocol version */
/* */
/* Look for a network interface structure that firstly has a matching name */
/* to that passed in and that is also being used for that IP protocol */
/* version (necessary on some platforms where there are separate listings */
/* for both IPv4 and IPv6 on the same physical NIC. */
-/* */
-/* One might wonder why name gets terminated with a \0 byte in here. The */
-/* reason is an interface name could get into the kernel structures of ipf */
-/* in any number of ways and so long as they all use the same sized array */
-/* to put the name in, it makes sense to ensure it gets null terminated */
-/* before it is used for its intended purpose - finding its match in the */
-/* kernel's list of configured interfaces. */
-/* */
-/* NOTE: This SHOULD ONLY be used with IPFilter structures that have an */
-/* array for the name that is LIFNAMSIZ bytes (at least) in length. */
/* ------------------------------------------------------------------------ */
-void *fr_resolvenic(name, v)
-char *name;
-int v;
+void *
+ipf_resolvenic(softc, name, v)
+ ipf_main_softc_t *softc;
+ char *name;
+ int v;
{
void *nic;
+ softc = softc; /* gcc -Wextra */
if (name[0] == '\0')
return NULL;
@@ -6560,8 +7495,6 @@ int v;
return NULL;
}
- name[LIFNAMSIZ - 1] = '\0';
-
nic = GETIFP(name, v);
if (nic == NULL)
nic = (void *)-1;
@@ -6569,68 +7502,121 @@ int v;
}
-ipftoken_t *ipftokenhead = NULL, **ipftokentail = &ipftokenhead;
-
-
/* ------------------------------------------------------------------------ */
-/* Function: ipf_expiretokens */
+/* Function: ipf_token_expire */
/* Returns: None. */
-/* Parameters: None. */
+/* Parameters: softc(I) - pointer to soft context main structure */
/* */
/* This function is run every ipf tick to see if there are any tokens that */
/* have been held for too long and need to be freed up. */
/* ------------------------------------------------------------------------ */
-void ipf_expiretokens()
+void
+ipf_token_expire(softc)
+ ipf_main_softc_t *softc;
{
ipftoken_t *it;
- WRITE_ENTER(&ipf_tokens);
- while ((it = ipftokenhead) != NULL) {
- if (it->ipt_die > fr_ticks)
+ WRITE_ENTER(&softc->ipf_tokens);
+ while ((it = softc->ipf_token_head) != NULL) {
+ if (it->ipt_die > softc->ipf_ticks)
break;
- ipf_freetoken(it);
+ ipf_token_deref(softc, it);
+ }
+ RWLOCK_EXIT(&softc->ipf_tokens);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_token_flush */
+/* Returns: None. */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Loop through all of the existing tokens and call deref to see if they */
+/* can be freed. Normally a function like this might just loop on */
+/* ipf_token_head but there is a chance that a token might have a ref count */
+/* of greater than one and in that case the the reference would drop twice */
+/* by code that is only entitled to drop it once. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_token_flush(softc)
+ ipf_main_softc_t *softc;
+{
+ ipftoken_t *it, *next;
+
+ WRITE_ENTER(&softc->ipf_tokens);
+ for (it = softc->ipf_token_head; it != NULL; it = next) {
+ next = it->ipt_next;
+ (void) ipf_token_deref(softc, it);
}
- RWLOCK_EXIT(&ipf_tokens);
+ RWLOCK_EXIT(&softc->ipf_tokens);
}
/* ------------------------------------------------------------------------ */
-/* Function: ipf_deltoken */
+/* Function: ipf_token_del */
/* Returns: int - 0 = success, else error */
-/* Parameters: type(I) - the token type to match */
+/* Parameters: softc(I)- pointer to soft context main structure */
+/* type(I) - the token type to match */
/* uid(I) - uid owning the token */
/* ptr(I) - context pointer for the token */
/* */
/* This function looks for a a token in the current list that matches up */
/* the fields (type, uid, ptr). If none is found, ESRCH is returned, else */
-/* call ipf_freetoken() to remove it from the list. */
+/* call ipf_token_dewref() to remove it from the list. In the event that */
+/* the token has a reference held elsewhere, setting ipt_complete to 2 */
+/* enables debugging to distinguish between the two paths that ultimately */
+/* lead to a token to be deleted. */
/* ------------------------------------------------------------------------ */
-int ipf_deltoken(type, uid, ptr)
-int type, uid;
-void *ptr;
+int
+ipf_token_del(softc, type, uid, ptr)
+ ipf_main_softc_t *softc;
+ int type, uid;
+ void *ptr;
{
ipftoken_t *it;
- int error = ESRCH;
+ int error;
- WRITE_ENTER(&ipf_tokens);
- for (it = ipftokenhead; it != NULL; it = it->ipt_next)
+ IPFERROR(82);
+ error = ESRCH;
+
+ WRITE_ENTER(&softc->ipf_tokens);
+ for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) {
if (ptr == it->ipt_ctx && type == it->ipt_type &&
uid == it->ipt_uid) {
- ipf_freetoken(it);
+ it->ipt_complete = 2;
+ ipf_token_deref(softc, it);
error = 0;
break;
+ }
}
- RWLOCK_EXIT(&ipf_tokens);
+ RWLOCK_EXIT(&softc->ipf_tokens);
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: ipf_findtoken */
+/* Function: ipf_token_mark_complete */
+/* Returns: None. */
+/* Parameters: token(I) - pointer to token structure */
+/* */
+/* Mark a token as being ineligable for being found with ipf_token_find. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_token_mark_complete(token)
+ ipftoken_t *token;
+{
+ if (token->ipt_complete == 0)
+ token->ipt_complete = 1;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_token_find */
/* Returns: ipftoken_t * - NULL if no memory, else pointer to token */
-/* Parameters: type(I) - the token type to match */
+/* Parameters: softc(I)- pointer to soft context main structure */
+/* type(I) - the token type to match */
/* uid(I) - uid owning the token */
/* ptr(I) - context pointer for the token */
/* */
@@ -6638,97 +7624,115 @@ void *ptr;
/* matches the tuple (type, uid, ptr). If one cannot be found then one is */
/* allocated. If one is found then it is moved to the top of the list of */
/* currently active tokens. */
-/* */
-/* NOTE: It is by design that this function returns holding a read lock on */
-/* ipf_tokens. Callers must make sure they release it! */
/* ------------------------------------------------------------------------ */
-ipftoken_t *ipf_findtoken(type, uid, ptr)
-int type, uid;
-void *ptr;
+ipftoken_t *
+ipf_token_find(softc, type, uid, ptr)
+ ipf_main_softc_t *softc;
+ int type, uid;
+ void *ptr;
{
ipftoken_t *it, *new;
KMALLOC(new, ipftoken_t *);
+ if (new != NULL)
+ bzero((char *)new, sizeof(*new));
- WRITE_ENTER(&ipf_tokens);
- for (it = ipftokenhead; it != NULL; it = it->ipt_next) {
- if (it->ipt_alive == 0)
- continue;
- if (ptr == it->ipt_ctx && type == it->ipt_type &&
- uid == it->ipt_uid)
+ WRITE_ENTER(&softc->ipf_tokens);
+ for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) {
+ if ((ptr == it->ipt_ctx) && (type == it->ipt_type) &&
+ (uid == it->ipt_uid) && (it->ipt_complete < 2))
break;
}
if (it == NULL) {
it = new;
new = NULL;
- if (it == NULL)
+ if (it == NULL) {
+ RWLOCK_EXIT(&softc->ipf_tokens);
return NULL;
- it->ipt_data = NULL;
+ }
it->ipt_ctx = ptr;
it->ipt_uid = uid;
it->ipt_type = type;
- it->ipt_next = NULL;
- it->ipt_alive = 1;
+ it->ipt_ref = 1;
} else {
if (new != NULL) {
KFREE(new);
new = NULL;
}
- ipf_unlinktoken(it);
+ if (it->ipt_complete > 0)
+ it = NULL;
+ else
+ ipf_token_unlink(softc, it);
}
- it->ipt_pnext = ipftokentail;
- *ipftokentail = it;
- ipftokentail = &it->ipt_next;
- it->ipt_next = NULL;
- it->ipt_die = fr_ticks + 2;
+ if (it != NULL) {
+ it->ipt_pnext = softc->ipf_token_tail;
+ *softc->ipf_token_tail = it;
+ softc->ipf_token_tail = &it->ipt_next;
+ it->ipt_next = NULL;
+ it->ipt_ref++;
- MUTEX_DOWNGRADE(&ipf_tokens);
+ it->ipt_die = softc->ipf_ticks + 20;
+ }
+
+ RWLOCK_EXIT(&softc->ipf_tokens);
return it;
}
/* ------------------------------------------------------------------------ */
-/* Function: ipf_unlinktoken */
+/* Function: ipf_token_unlink */
/* Returns: None. */
-/* Parameters: token(I) - pointer to token structure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* token(I) - pointer to token structure */
+/* Write Locks: ipf_tokens */
/* */
/* This function unlinks a token structure from the linked list of tokens */
/* that "own" it. The head pointer never needs to be explicitly adjusted */
/* but the tail does due to the linked list implementation. */
/* ------------------------------------------------------------------------ */
-static void ipf_unlinktoken(token)
-ipftoken_t *token;
+static void
+ipf_token_unlink(softc, token)
+ ipf_main_softc_t *softc;
+ ipftoken_t *token;
{
- if (ipftokentail == &token->ipt_next)
- ipftokentail = token->ipt_pnext;
+ if (softc->ipf_token_tail == &token->ipt_next)
+ softc->ipf_token_tail = token->ipt_pnext;
*token->ipt_pnext = token->ipt_next;
if (token->ipt_next != NULL)
token->ipt_next->ipt_pnext = token->ipt_pnext;
+ token->ipt_next = NULL;
+ token->ipt_pnext = NULL;
}
/* ------------------------------------------------------------------------ */
-/* Function: ipf_freetoken */
-/* Returns: None. */
-/* Parameters: token(I) - pointer to token structure */
+/* Function: ipf_token_deref */
+/* Returns: int - 0 == token freed, else reference count */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* token(I) - pointer to token structure */
+/* Write Locks: ipf_tokens */
/* */
-/* This function unlinks a token from the linked list and on the path to */
-/* free'ing the data, it calls the dereference function that is associated */
-/* with the type of data pointed to by the token as it is considered to */
-/* hold a reference to it. */
+/* Drop the reference count on the token structure and if it drops to zero, */
+/* call the dereference function for the token type because it is then */
+/* possible to free the token data structure. */
/* ------------------------------------------------------------------------ */
-void ipf_freetoken(token)
-ipftoken_t *token;
+int
+ipf_token_deref(softc, token)
+ ipf_main_softc_t *softc;
+ ipftoken_t *token;
{
void *data, **datap;
- ipf_unlinktoken(token);
+ ASSERT(token->ipt_ref > 0);
+ token->ipt_ref--;
+ if (token->ipt_ref > 0)
+ return token->ipt_ref;
data = token->ipt_data;
datap = &data;
@@ -6737,54 +7741,96 @@ ipftoken_t *token;
switch (token->ipt_type)
{
case IPFGENITER_IPF :
- (void) fr_derefrule((frentry_t **)datap);
+ (void) ipf_derefrule(softc, (frentry_t **)datap);
break;
case IPFGENITER_IPNAT :
- WRITE_ENTER(&ipf_nat);
- fr_ipnatderef((ipnat_t **)datap);
- RWLOCK_EXIT(&ipf_nat);
+ WRITE_ENTER(&softc->ipf_nat);
+ ipf_nat_rule_deref(softc, (ipnat_t **)datap);
+ RWLOCK_EXIT(&softc->ipf_nat);
break;
case IPFGENITER_NAT :
- fr_natderef((nat_t **)datap);
+ ipf_nat_deref(softc, (nat_t **)datap);
break;
case IPFGENITER_STATE :
- fr_statederef((ipstate_t **)datap);
+ ipf_state_deref(softc, (ipstate_t **)datap);
break;
case IPFGENITER_FRAG :
-#ifdef USE_MUTEXES
- fr_fragderef((ipfr_t **)datap, &ipf_frag);
-#else
- fr_fragderef((ipfr_t **)datap);
-#endif
+ ipf_frag_pkt_deref(softc, (ipfr_t **)datap);
break;
case IPFGENITER_NATFRAG :
-#ifdef USE_MUTEXES
- fr_fragderef((ipfr_t **)datap, &ipf_natfrag);
-#else
- fr_fragderef((ipfr_t **)datap);
-#endif
+ ipf_frag_nat_deref(softc, (ipfr_t **)datap);
break;
case IPFGENITER_HOSTMAP :
- WRITE_ENTER(&ipf_nat);
- fr_hostmapdel((hostmap_t **)datap);
- RWLOCK_EXIT(&ipf_nat);
+ WRITE_ENTER(&softc->ipf_nat);
+ ipf_nat_hostmapdel(softc, (hostmap_t **)datap);
+ RWLOCK_EXIT(&softc->ipf_nat);
break;
default :
-#ifdef IPFILTER_LOOKUP
- ip_lookup_iterderef(token->ipt_type, data);
-#endif
+ ipf_lookup_iterderef(softc, token->ipt_type, data);
break;
}
}
+ ipf_token_unlink(softc, token);
KFREE(token);
+ return 0;
}
/* ------------------------------------------------------------------------ */
+/* Function: ipf_nextrule */
+/* Returns: frentry_t * - NULL == no more rules, else pointer to next */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* fr(I) - pointer to filter rule */
+/* out(I) - 1 == out rules, 0 == input rules */
+/* */
+/* Starting with "fr", find the next rule to visit. This includes visiting */
+/* the list of rule groups if either fr is NULL (empty list) or it is the */
+/* last rule in the list. When walking rule lists, it is either input or */
+/* output rules that are returned, never both. */
+/* ------------------------------------------------------------------------ */
+static frentry_t *
+ipf_nextrule(softc, active, unit, fr, out)
+ ipf_main_softc_t *softc;
+ int active, unit;
+ frentry_t *fr;
+ int out;
+{
+ frentry_t *next;
+ frgroup_t *fg;
+
+ if (fr != NULL && fr->fr_group != -1) {
+ fg = ipf_findgroup(softc, fr->fr_names + fr->fr_group,
+ unit, active, NULL);
+ if (fg != NULL)
+ fg = fg->fg_next;
+ } else {
+ fg = softc->ipf_groups[unit][active];
+ }
+
+ while (fg != NULL) {
+ next = fg->fg_start;
+ while (next != NULL) {
+ if (out) {
+ if (next->fr_flags & FR_OUTQUE)
+ return next;
+ } else if (next->fr_flags & FR_INQUE) {
+ return next;
+ }
+ next = next->fr_next;
+ }
+ if (next == NULL)
+ fg = fg->fg_next;
+ }
+
+ return NULL;
+}
+
+/* ------------------------------------------------------------------------ */
/* Function: ipf_getnextrule */
/* Returns: int - 0 = success, else error */
-/* Parameters: t(I) - pointer to destination information to resolve */
+/* Parameters: softc(I)- pointer to soft context main structure */
+/* t(I) - pointer to destination information to resolve */
/* ptr(I) - pointer to ipfobj_t to copyin from user space */
/* */
/* This function's first job is to bring in the ipfruleiter_t structure via */
@@ -6795,47 +7841,72 @@ ipftoken_t *token;
/* When we have found the rule to return, increase its reference count and */
/* if we used an existing rule to get here, decrease its reference count. */
/* ------------------------------------------------------------------------ */
-int ipf_getnextrule(ipftoken_t *t, void *ptr)
+int
+ipf_getnextrule(softc, t, ptr)
+ ipf_main_softc_t *softc;
+ ipftoken_t *t;
+ void *ptr;
{
frentry_t *fr, *next, zero;
- int error, count, out;
ipfruleiter_t it;
+ int error, out;
frgroup_t *fg;
+ ipfobj_t obj;
+ int predict;
char *dst;
+ int unit;
- if (t == NULL || ptr == NULL)
+ if (t == NULL || ptr == NULL) {
+ IPFERROR(84);
return EFAULT;
- error = fr_inobj(ptr, &it, IPFOBJ_IPFITER);
+ }
+
+ error = ipf_inobj(softc, ptr, &obj, &it, IPFOBJ_IPFITER);
if (error != 0)
return error;
- if ((it.iri_inout < 0) || (it.iri_inout > 3))
+
+ if ((it.iri_inout < 0) || (it.iri_inout > 3)) {
+ IPFERROR(85);
return EINVAL;
- if ((it.iri_active != 0) && (it.iri_active != 1))
+ }
+ if ((it.iri_active != 0) && (it.iri_active != 1)) {
+ IPFERROR(86);
return EINVAL;
- if (it.iri_nrules == 0)
+ }
+ if (it.iri_nrules == 0) {
+ IPFERROR(87);
return ENOSPC;
- if (it.iri_rule == NULL)
+ }
+ if (it.iri_rule == NULL) {
+ IPFERROR(88);
return EFAULT;
+ }
- out = it.iri_inout & F_OUT;
+ fg = NULL;
fr = t->ipt_data;
- READ_ENTER(&ipf_mutex);
+ if ((it.iri_inout & F_OUT) != 0)
+ out = 1;
+ else
+ out = 0;
+ if ((it.iri_inout & F_ACIN) != 0)
+ unit = IPL_LOGCOUNT;
+ else
+ unit = IPL_LOGIPF;
+
+ READ_ENTER(&softc->ipf_mutex);
if (fr == NULL) {
if (*it.iri_group == '\0') {
- if ((it.iri_inout & F_ACIN) != 0) {
- if (it.iri_v == 4)
- next = ipacct[out][it.iri_active];
- else
- next = ipacct6[out][it.iri_active];
+ if (unit == IPL_LOGCOUNT) {
+ next = softc->ipf_acct[out][it.iri_active];
} else {
- if (it.iri_v == 4)
- next = ipfilter[out][it.iri_active];
- else
- next = ipfilter6[out][it.iri_active];
+ next = softc->ipf_rules[out][it.iri_active];
}
+ if (next == NULL)
+ next = ipf_nextrule(softc, it.iri_active,
+ unit, NULL, out);
} else {
- fg = fr_findgroup(it.iri_group, IPL_LOGIPF,
- it.iri_active, NULL);
+ fg = ipf_findgroup(softc, it.iri_group, unit,
+ it.iri_active, NULL);
if (fg != NULL)
next = fg->fg_start;
else
@@ -6843,113 +7914,133 @@ int ipf_getnextrule(ipftoken_t *t, void *ptr)
}
} else {
next = fr->fr_next;
+ if (next == NULL)
+ next = ipf_nextrule(softc, it.iri_active, unit,
+ fr, out);
}
+ if (next != NULL && next->fr_next != NULL)
+ predict = 1;
+ else if (ipf_nextrule(softc, it.iri_active, unit, next, out) != NULL)
+ predict = 1;
+ else
+ predict = 0;
+
+ if (fr != NULL)
+ (void) ipf_derefrule(softc, &fr);
+
+ obj.ipfo_type = IPFOBJ_FRENTRY;
dst = (char *)it.iri_rule;
- count = it.iri_nrules;
- /*
- * The ipfruleiter may ask for more than 1 rule at a time to be
- * copied out, so long as that many exist in the list to start with!
- */
- for (;;) {
- if (next != NULL) {
- if (count == 1) {
- MUTEX_ENTER(&next->fr_lock);
- next->fr_ref++;
- MUTEX_EXIT(&next->fr_lock);
- t->ipt_data = next;
- }
- } else {
- bzero(&zero, sizeof(zero));
- next = &zero;
- count = 1;
- t->ipt_data = NULL;
- }
- RWLOCK_EXIT(&ipf_mutex);
- error = COPYOUT(next, dst, sizeof(*next));
- if (error != 0)
- return EFAULT;
+ if (next != NULL) {
+ obj.ipfo_size = next->fr_size;
+ MUTEX_ENTER(&next->fr_lock);
+ next->fr_ref++;
+ MUTEX_EXIT(&next->fr_lock);
+ t->ipt_data = next;
+ } else {
+ obj.ipfo_size = sizeof(frentry_t);
+ bzero(&zero, sizeof(zero));
+ next = &zero;
+ t->ipt_data = NULL;
+ }
+ it.iri_rule = predict ? next : NULL;
+ if (predict == 0)
+ ipf_token_mark_complete(t);
+
+ RWLOCK_EXIT(&softc->ipf_mutex);
+ obj.ipfo_ptr = dst;
+ error = ipf_outobjk(softc, &obj, next);
+ if (error == 0 && t->ipt_data != NULL) {
+ dst += obj.ipfo_size;
if (next->fr_data != NULL) {
- dst += sizeof(*next);
- error = COPYOUT(next->fr_data, dst, next->fr_dsize);
- if (error != 0)
- error = EFAULT;
+ ipfobj_t dobj;
+
+ if (next->fr_type == FR_T_IPFEXPR)
+ dobj.ipfo_type = IPFOBJ_IPFEXPR;
else
- dst += next->fr_dsize;
+ dobj.ipfo_type = IPFOBJ_FRIPF;
+ dobj.ipfo_size = next->fr_dsize;
+ dobj.ipfo_rev = obj.ipfo_rev;
+ dobj.ipfo_ptr = dst;
+ error = ipf_outobjk(softc, &dobj, next->fr_data);
}
-
- if ((count == 1) || (error != 0))
- break;
-
- count--;
-
- READ_ENTER(&ipf_mutex);
- next = next->fr_next;
}
- if (fr != NULL) {
- (void) fr_derefrule(&fr);
- }
+ if ((fr != NULL) && (next == &zero))
+ (void) ipf_derefrule(softc, &fr);
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_frruleiter */
+/* Function: ipf_frruleiter */
/* Returns: int - 0 = success, else error */
-/* Parameters: data(I) - the token type to match */
+/* Parameters: softc(I)- pointer to soft context main structure */
+/* data(I) - the token type to match */
/* uid(I) - uid owning the token */
/* ptr(I) - context pointer for the token */
/* */
-/* This function serves as a stepping stone between fr_ipf_ioctl and */
+/* This function serves as a stepping stone between ipf_ipf_ioctl and */
/* ipf_getnextrule. It's role is to find the right token in the kernel for */
/* the process doing the ioctl and use that to ask for the next rule. */
/* ------------------------------------------------------------------------ */
-static int ipf_frruleiter(data, uid, ctx)
-void *data, *ctx;
-int uid;
+static int
+ipf_frruleiter(softc, data, uid, ctx)
+ ipf_main_softc_t *softc;
+ void *data, *ctx;
+ int uid;
{
ipftoken_t *token;
+ ipfruleiter_t it;
+ ipfobj_t obj;
int error;
- token = ipf_findtoken(IPFGENITER_IPF, uid, ctx);
- if (token != NULL)
- error = ipf_getnextrule(token, data);
- else
- error = EFAULT;
- RWLOCK_EXIT(&ipf_tokens);
+ token = ipf_token_find(softc, IPFGENITER_IPF, uid, ctx);
+ if (token != NULL) {
+ error = ipf_getnextrule(softc, token, data);
+ WRITE_ENTER(&softc->ipf_tokens);
+ ipf_token_deref(softc, token);
+ RWLOCK_EXIT(&softc->ipf_tokens);
+ } else {
+ error = ipf_inobj(softc, data, &obj, &it, IPFOBJ_IPFITER);
+ if (error != 0)
+ return error;
+ it.iri_rule = NULL;
+ error = ipf_outobj(softc, data, &it, IPFOBJ_IPFITER);
+ }
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_geniter */
+/* Function: ipf_geniter */
/* Returns: int - 0 = success, else error */
-/* Parameters: token(I) - pointer to ipftoken_t structure */
-/* itp(I) - */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* token(I) - pointer to ipftoken_t structure */
+/* itp(I) - pointer to iterator data */
/* */
+/* Decide which iterator function to call using information passed through */
+/* the ipfgeniter_t structure at itp. */
/* ------------------------------------------------------------------------ */
-static int ipf_geniter(token, itp)
-ipftoken_t *token;
-ipfgeniter_t *itp;
+static int
+ipf_geniter(softc, token, itp)
+ ipf_main_softc_t *softc;
+ ipftoken_t *token;
+ ipfgeniter_t *itp;
{
int error;
switch (itp->igi_type)
{
case IPFGENITER_FRAG :
-#ifdef USE_MUTEXES
- error = fr_nextfrag(token, itp,
- &ipfr_list, &ipfr_tail, &ipf_frag);
-#else
- error = fr_nextfrag(token, itp, &ipfr_list, &ipfr_tail);
-#endif
+ error = ipf_frag_pkt_next(softc, token, itp);
break;
default :
+ IPFERROR(92);
error = EINVAL;
break;
}
@@ -6959,41 +8050,50 @@ ipfgeniter_t *itp;
/* ------------------------------------------------------------------------ */
-/* Function: fr_genericiter */
+/* Function: ipf_genericiter */
/* Returns: int - 0 = success, else error */
-/* Parameters: data(I) - the token type to match */
+/* Parameters: softc(I)- pointer to soft context main structure */
+/* data(I) - the token type to match */
/* uid(I) - uid owning the token */
/* ptr(I) - context pointer for the token */
/* */
+/* Handle the SIOCGENITER ioctl for the ipfilter device. The primary role */
/* ------------------------------------------------------------------------ */
-int ipf_genericiter(data, uid, ctx)
-void *data, *ctx;
-int uid;
+int
+ipf_genericiter(softc, data, uid, ctx)
+ ipf_main_softc_t *softc;
+ void *data, *ctx;
+ int uid;
{
ipftoken_t *token;
ipfgeniter_t iter;
int error;
- error = fr_inobj(data, &iter, IPFOBJ_GENITER);
+ error = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_GENITER);
if (error != 0)
return error;
- token = ipf_findtoken(iter.igi_type, uid, ctx);
+ token = ipf_token_find(softc, iter.igi_type, uid, ctx);
if (token != NULL) {
token->ipt_subtype = iter.igi_type;
- error = ipf_geniter(token, &iter);
- } else
- error = EFAULT;
- RWLOCK_EXIT(&ipf_tokens);
+ error = ipf_geniter(softc, token, &iter);
+ WRITE_ENTER(&softc->ipf_tokens);
+ ipf_token_deref(softc, token);
+ RWLOCK_EXIT(&softc->ipf_tokens);
+ } else {
+ IPFERROR(93);
+ error = 0;
+ }
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_ipf_ioctl */
+/* Function: ipf_ipf_ioctl */
/* Returns: int - 0 = success, else error */
-/* Parameters: data(I) - the token type to match */
+/* Parameters: softc(I)- pointer to soft context main structure */
+/* data(I) - the token type to match */
/* cmd(I) - the ioctl command number */
/* mode(I) - mode flags for the ioctl */
/* uid(I) - uid owning the token */
@@ -7002,231 +8102,283 @@ int uid;
/* This function handles all of the ioctl command that are actually isssued */
/* to the /dev/ipl device. */
/* ------------------------------------------------------------------------ */
-int fr_ipf_ioctl(data, cmd, mode, uid, ctx)
-caddr_t data;
-ioctlcmd_t cmd;
-int mode, uid;
-void *ctx;
+int
+ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx)
+ ipf_main_softc_t *softc;
+ caddr_t data;
+ ioctlcmd_t cmd;
+ int mode, uid;
+ void *ctx;
{
friostat_t fio;
int error, tmp;
+ ipfobj_t obj;
SPL_INT(s);
switch (cmd)
{
case SIOCFRENB :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(94);
error = EPERM;
- else {
+ } else {
error = BCOPYIN(data, &tmp, sizeof(tmp));
if (error != 0) {
+ IPFERROR(95);
error = EFAULT;
break;
}
- WRITE_ENTER(&ipf_global);
+ WRITE_ENTER(&softc->ipf_global);
if (tmp) {
- if (fr_running > 0)
+ if (softc->ipf_running > 0)
error = 0;
else
- error = ipfattach();
+ error = ipfattach(softc);
if (error == 0)
- fr_running = 1;
+ softc->ipf_running = 1;
else
- (void) ipfdetach();
+ (void) ipfdetach(softc);
} else {
- error = ipfdetach();
+ if (softc->ipf_running == 1)
+ error = ipfdetach(softc);
+ else
+ error = 0;
if (error == 0)
- fr_running = -1;
+ softc->ipf_running = -1;
}
- RWLOCK_EXIT(&ipf_global);
+ RWLOCK_EXIT(&softc->ipf_global);
}
break;
case SIOCIPFSET :
if (!(mode & FWRITE)) {
+ IPFERROR(96);
error = EPERM;
break;
}
/* FALLTHRU */
case SIOCIPFGETNEXT :
case SIOCIPFGET :
- error = fr_ipftune(cmd, (void *)data);
+ error = ipf_ipftune(softc, cmd, (void *)data);
break;
case SIOCSETFF :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(97);
error = EPERM;
- else {
- error = BCOPYIN(data, &fr_flags, sizeof(fr_flags));
- if (error != 0)
+ } else {
+ error = BCOPYIN(data, &softc->ipf_flags,
+ sizeof(softc->ipf_flags));
+ if (error != 0) {
+ IPFERROR(98);
error = EFAULT;
+ }
}
break;
case SIOCGETFF :
- error = BCOPYOUT(&fr_flags, data, sizeof(fr_flags));
- if (error != 0)
+ error = BCOPYOUT(&softc->ipf_flags, data,
+ sizeof(softc->ipf_flags));
+ if (error != 0) {
+ IPFERROR(99);
error = EFAULT;
+ }
break;
case SIOCFUNCL :
- error = fr_resolvefunc((void *)data);
+ error = ipf_resolvefunc(softc, (void *)data);
break;
case SIOCINAFR :
case SIOCRMAFR :
case SIOCADAFR :
case SIOCZRLST :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(100);
error = EPERM;
- else
- error = frrequest(IPL_LOGIPF, cmd, data, fr_active, 1);
+ } else {
+ error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data,
+ softc->ipf_active, 1);
+ }
break;
case SIOCINIFR :
case SIOCRMIFR :
case SIOCADIFR :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(101);
error = EPERM;
- else
- error = frrequest(IPL_LOGIPF, cmd, data,
- 1 - fr_active, 1);
+ } else {
+ error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data,
+ 1 - softc->ipf_active, 1);
+ }
break;
case SIOCSWAPA :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(102);
error = EPERM;
- else {
- WRITE_ENTER(&ipf_mutex);
- bzero((char *)frcache, sizeof(frcache[0]) * 2);
- error = BCOPYOUT(&fr_active, data, sizeof(fr_active));
- if (error != 0)
+ } else {
+ WRITE_ENTER(&softc->ipf_mutex);
+ error = BCOPYOUT(&softc->ipf_active, data,
+ sizeof(softc->ipf_active));
+ if (error != 0) {
+ IPFERROR(103);
error = EFAULT;
- else
- fr_active = 1 - fr_active;
- RWLOCK_EXIT(&ipf_mutex);
+ } else {
+ softc->ipf_active = 1 - softc->ipf_active;
+ }
+ RWLOCK_EXIT(&softc->ipf_mutex);
}
break;
case SIOCGETFS :
- fr_getstat(&fio);
- error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT);
+ error = ipf_inobj(softc, (void *)data, &obj, &fio,
+ IPFOBJ_IPFSTAT);
+ if (error != 0)
+ break;
+ ipf_getstat(softc, &fio, obj.ipfo_rev);
+ error = ipf_outobj(softc, (void *)data, &fio, IPFOBJ_IPFSTAT);
break;
case SIOCFRZST :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(104);
error = EPERM;
- else
- error = fr_zerostats(data);
+ } else
+ error = ipf_zerostats(softc, (caddr_t)data);
break;
case SIOCIPFFL :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(105);
error = EPERM;
- else {
+ } else {
error = BCOPYIN(data, &tmp, sizeof(tmp));
if (!error) {
- tmp = frflush(IPL_LOGIPF, 4, tmp);
+ tmp = ipf_flush(softc, IPL_LOGIPF, tmp);
error = BCOPYOUT(&tmp, data, sizeof(tmp));
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(106);
error = EFAULT;
- } else
+ }
+ } else {
+ IPFERROR(107);
error = EFAULT;
+ }
}
break;
#ifdef USE_INET6
case SIOCIPFL6 :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(108);
error = EPERM;
- else {
+ } else {
error = BCOPYIN(data, &tmp, sizeof(tmp));
if (!error) {
- tmp = frflush(IPL_LOGIPF, 6, tmp);
+ tmp = ipf_flush(softc, IPL_LOGIPF, tmp);
error = BCOPYOUT(&tmp, data, sizeof(tmp));
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(109);
error = EFAULT;
- } else
+ }
+ } else {
+ IPFERROR(110);
error = EFAULT;
+ }
}
break;
#endif
case SIOCSTLCK :
- error = BCOPYIN(data, &tmp, sizeof(tmp));
- if (error == 0) {
- fr_state_lock = tmp;
- fr_nat_lock = tmp;
- fr_frag_lock = tmp;
- fr_auth_lock = tmp;
- } else
- error = EFAULT;
+ if (!(mode & FWRITE)) {
+ IPFERROR(122);
+ error = EPERM;
+ } else {
+ error = BCOPYIN(data, &tmp, sizeof(tmp));
+ if (error == 0) {
+ ipf_state_setlock(softc->ipf_state_soft, tmp);
+ ipf_nat_setlock(softc->ipf_nat_soft, tmp);
+ ipf_frag_setlock(softc->ipf_frag_soft, tmp);
+ ipf_auth_setlock(softc->ipf_auth_soft, tmp);
+ } else {
+ IPFERROR(111);
+ error = EFAULT;
+ }
+ }
break;
#ifdef IPFILTER_LOG
case SIOCIPFFB :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(112);
error = EPERM;
- else {
- tmp = ipflog_clear(IPL_LOGIPF);
+ } else {
+ tmp = ipf_log_clear(softc, IPL_LOGIPF);
error = BCOPYOUT(&tmp, data, sizeof(tmp));
- if (error)
+ if (error) {
+ IPFERROR(113);
error = EFAULT;
+ }
}
break;
#endif /* IPFILTER_LOG */
case SIOCFRSYN :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(114);
error = EPERM;
- else {
- WRITE_ENTER(&ipf_global);
-#ifdef MENTAT
+ } else {
+ WRITE_ENTER(&softc->ipf_global);
+#if (defined(MENTAT) && defined(_KERNEL)) && !defined(INSTANCES)
error = ipfsync();
#else
- frsync(NULL);
+ ipf_sync(softc, NULL);
error = 0;
#endif
- RWLOCK_EXIT(&ipf_global);
+ RWLOCK_EXIT(&softc->ipf_global);
}
break;
case SIOCGFRST :
- error = fr_outobj((void *)data, fr_fragstats(),
- IPFOBJ_FRAGSTAT);
+ error = ipf_outobj(softc, (void *)data,
+ ipf_frag_stats(softc->ipf_frag_soft),
+ IPFOBJ_FRAGSTAT);
break;
#ifdef IPFILTER_LOG
case FIONREAD :
- tmp = (int)iplused[IPL_LOGIPF];
-
+ tmp = ipf_log_bytesused(softc, IPL_LOGIPF);
error = BCOPYOUT(&tmp, data, sizeof(tmp));
break;
#endif
case SIOCIPFITER :
SPL_SCHED(s);
- error = ipf_frruleiter(data, uid, ctx);
+ error = ipf_frruleiter(softc, data, uid, ctx);
SPL_X(s);
break;
case SIOCGENITER :
SPL_SCHED(s);
- error = ipf_genericiter(data, uid, ctx);
+ error = ipf_genericiter(softc, data, uid, ctx);
SPL_X(s);
break;
case SIOCIPFDELTOK :
- SPL_SCHED(s);
error = BCOPYIN(data, &tmp, sizeof(tmp));
- if (error == 0)
- error = ipf_deltoken(tmp, uid, ctx);
- SPL_X(s);
+ if (error == 0) {
+ SPL_SCHED(s);
+ error = ipf_token_del(softc, tmp, uid, ctx);
+ SPL_X(s);
+ }
break;
default :
+ IPFERROR(115);
error = EINVAL;
break;
}
@@ -7236,90 +8388,610 @@ void *ctx;
/* ------------------------------------------------------------------------ */
+/* Function: ipf_decaps */
+/* Returns: int - -1 == decapsulation failed, else bit mask of */
+/* flags indicating packet filtering decision. */
+/* Parameters: fin(I) - pointer to packet information */
+/* pass(I) - IP protocol version to match */
+/* l5proto(I) - layer 5 protocol to decode UDP data as. */
+/* */
+/* This function is called for packets that are wrapt up in other packets, */
+/* for example, an IP packet that is the entire data segment for another IP */
+/* packet. If the basic constraints for this are satisfied, change the */
+/* buffer to point to the start of the inner packet and start processing */
+/* rules belonging to the head group this rule specifies. */
+/* ------------------------------------------------------------------------ */
+u_32_t
+ipf_decaps(fin, pass, l5proto)
+ fr_info_t *fin;
+ u_32_t pass;
+ int l5proto;
+{
+ fr_info_t fin2, *fino = NULL;
+ int elen, hlen, nh;
+ grehdr_t gre;
+ ip_t *ip;
+ mb_t *m;
+
+ if ((fin->fin_flx & FI_COALESCE) == 0)
+ if (ipf_coalesce(fin) == -1)
+ goto cantdecaps;
+
+ m = fin->fin_m;
+ hlen = fin->fin_hlen;
+
+ switch (fin->fin_p)
+ {
+ case IPPROTO_UDP :
+ /*
+ * In this case, the specific protocol being decapsulated
+ * inside UDP frames comes from the rule.
+ */
+ nh = fin->fin_fr->fr_icode;
+ break;
+
+ case IPPROTO_GRE : /* 47 */
+ bcopy(fin->fin_dp, (char *)&gre, sizeof(gre));
+ hlen += sizeof(grehdr_t);
+ if (gre.gr_R|gre.gr_s)
+ goto cantdecaps;
+ if (gre.gr_C)
+ hlen += 4;
+ if (gre.gr_K)
+ hlen += 4;
+ if (gre.gr_S)
+ hlen += 4;
+
+ nh = IPPROTO_IP;
+
+ /*
+ * If the routing options flag is set, validate that it is
+ * there and bounce over it.
+ */
+#if 0
+ /* This is really heavy weight and lots of room for error, */
+ /* so for now, put it off and get the simple stuff right. */
+ if (gre.gr_R) {
+ u_char off, len, *s;
+ u_short af;
+ int end;
+
+ end = 0;
+ s = fin->fin_dp;
+ s += hlen;
+ aplen = fin->fin_plen - hlen;
+ while (aplen > 3) {
+ af = (s[0] << 8) | s[1];
+ off = s[2];
+ len = s[3];
+ aplen -= 4;
+ s += 4;
+ if (af == 0 && len == 0) {
+ end = 1;
+ break;
+ }
+ if (aplen < len)
+ break;
+ s += len;
+ aplen -= len;
+ }
+ if (end != 1)
+ goto cantdecaps;
+ hlen = s - (u_char *)fin->fin_dp;
+ }
+#endif
+ break;
+
+#ifdef IPPROTO_IPIP
+ case IPPROTO_IPIP : /* 4 */
+#endif
+ nh = IPPROTO_IP;
+ break;
+
+ default : /* Includes ESP, AH is special for IPv4 */
+ goto cantdecaps;
+ }
+
+ switch (nh)
+ {
+ case IPPROTO_IP :
+ case IPPROTO_IPV6 :
+ break;
+ default :
+ goto cantdecaps;
+ }
+
+ bcopy((char *)fin, (char *)&fin2, sizeof(fin2));
+ fino = fin;
+ fin = &fin2;
+ elen = hlen;
+#if defined(MENTAT) && defined(_KERNEL)
+ m->b_rptr += elen;
+#else
+ m->m_data += elen;
+ m->m_len -= elen;
+#endif
+ fin->fin_plen -= elen;
+
+ ip = (ip_t *)((char *)fin->fin_ip + elen);
+
+ /*
+ * Make sure we have at least enough data for the network layer
+ * header.
+ */
+ if (IP_V(ip) == 4)
+ hlen = IP_HL(ip) << 2;
+#ifdef USE_INET6
+ else if (IP_V(ip) == 6)
+ hlen = sizeof(ip6_t);
+#endif
+ else
+ goto cantdecaps2;
+
+ if (fin->fin_plen < hlen)
+ goto cantdecaps2;
+
+ fin->fin_dp = (char *)ip + hlen;
+
+ if (IP_V(ip) == 4) {
+ /*
+ * Perform IPv4 header checksum validation.
+ */
+ if (ipf_cksum((u_short *)ip, hlen))
+ goto cantdecaps2;
+ }
+
+ if (ipf_makefrip(hlen, ip, fin) == -1) {
+cantdecaps2:
+ if (m != NULL) {
+#if defined(MENTAT) && defined(_KERNEL)
+ m->b_rptr -= elen;
+#else
+ m->m_data -= elen;
+ m->m_len += elen;
+#endif
+ }
+cantdecaps:
+ DT1(frb_decapfrip, fr_info_t *, fin);
+ pass &= ~FR_CMDMASK;
+ pass |= FR_BLOCK|FR_QUICK;
+ fin->fin_reason = FRB_DECAPFRIP;
+ return -1;
+ }
+
+ pass = ipf_scanlist(fin, pass);
+
+ /*
+ * Copy the packet filter "result" fields out of the fr_info_t struct
+ * that is local to the decapsulation processing and back into the
+ * one we were called with.
+ */
+ fino->fin_flx = fin->fin_flx;
+ fino->fin_rev = fin->fin_rev;
+ fino->fin_icode = fin->fin_icode;
+ fino->fin_rule = fin->fin_rule;
+ (void) strncpy(fino->fin_group, fin->fin_group, FR_GROUPLEN);
+ fino->fin_fr = fin->fin_fr;
+ fino->fin_error = fin->fin_error;
+ fino->fin_mp = fin->fin_mp;
+ fino->fin_m = fin->fin_m;
+ m = fin->fin_m;
+ if (m != NULL) {
+#if defined(MENTAT) && defined(_KERNEL)
+ m->b_rptr -= elen;
+#else
+ m->m_data -= elen;
+ m->m_len += elen;
+#endif
+ }
+ return pass;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_matcharray_load */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* data(I) - pointer to ioctl data */
+/* objp(I) - ipfobj_t structure to load data into */
+/* arrayptr(I) - pointer to location to store array pointer */
+/* */
+/* This function loads in a mathing array through the ipfobj_t struct that */
+/* describes it. Sanity checking and array size limitations are enforced */
+/* in this function to prevent userspace from trying to load in something */
+/* that is insanely big. Once the size of the array is known, the memory */
+/* required is malloc'd and returned through changing *arrayptr. The */
+/* contents of the array are verified before returning. Only in the event */
+/* of a successful call is the caller required to free up the malloc area. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_matcharray_load(softc, data, objp, arrayptr)
+ ipf_main_softc_t *softc;
+ caddr_t data;
+ ipfobj_t *objp;
+ int **arrayptr;
+{
+ int arraysize, *array, error;
+
+ *arrayptr = NULL;
+
+ error = BCOPYIN(data, objp, sizeof(*objp));
+ if (error != 0) {
+ IPFERROR(116);
+ return EFAULT;
+ }
+
+ if (objp->ipfo_type != IPFOBJ_IPFEXPR) {
+ IPFERROR(117);
+ return EINVAL;
+ }
+
+ if (((objp->ipfo_size & 3) != 0) || (objp->ipfo_size == 0) ||
+ (objp->ipfo_size > 1024)) {
+ IPFERROR(118);
+ return EINVAL;
+ }
+
+ arraysize = objp->ipfo_size * sizeof(*array);
+ KMALLOCS(array, int *, arraysize);
+ if (array == NULL) {
+ IPFERROR(119);
+ return ENOMEM;
+ }
+
+ error = COPYIN(objp->ipfo_ptr, array, arraysize);
+ if (error != 0) {
+ KFREES(array, arraysize);
+ IPFERROR(120);
+ return EFAULT;
+ }
+
+ if (ipf_matcharray_verify(array, arraysize) != 0) {
+ KFREES(array, arraysize);
+ IPFERROR(121);
+ return EINVAL;
+ }
+
+ *arrayptr = array;
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_matcharray_verify */
+/* Returns: Nil */
+/* Parameters: array(I) - pointer to matching array */
+/* arraysize(I) - number of elements in the array */
+/* */
+/* Verify the contents of a matching array by stepping through each element */
+/* in it. The actual commands in the array are not verified for */
+/* correctness, only that all of the sizes are correctly within limits. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_matcharray_verify(array, arraysize)
+ int *array, arraysize;
+{
+ int i, nelem, maxidx;
+ ipfexp_t *e;
+
+ nelem = arraysize / sizeof(*array);
+
+ /*
+ * Currently, it makes no sense to have an array less than 6
+ * elements long - the initial size at the from, a single operation
+ * (minimum 4 in length) and a trailer, for a total of 6.
+ */
+ if ((array[0] < 6) || (arraysize < 24) || (arraysize > 4096)) {
+ return -1;
+ }
+
+ /*
+ * Verify the size of data pointed to by array with how long
+ * the array claims to be itself.
+ */
+ if (array[0] * sizeof(*array) != arraysize) {
+ return -1;
+ }
+
+ maxidx = nelem - 1;
+ /*
+ * The last opcode in this array should be an IPF_EXP_END.
+ */
+ if (array[maxidx] != IPF_EXP_END) {
+ return -1;
+ }
+
+ for (i = 1; i < maxidx; ) {
+ e = (ipfexp_t *)(array + i);
+
+ /*
+ * The length of the bits to check must be at least 1
+ * (or else there is nothing to comapre with!) and it
+ * cannot exceed the length of the data present.
+ */
+ if ((e->ipfe_size < 1 ) ||
+ (e->ipfe_size + i > maxidx)) {
+ return -1;
+ }
+ i += e->ipfe_size;
+ }
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_fr_matcharray */
+/* Returns: int - 0 = match failed, else positive match */
+/* Parameters: fin(I) - pointer to packet information */
+/* array(I) - pointer to matching array */
+/* */
+/* This function is used to apply a matching array against a packet and */
+/* return an indication of whether or not the packet successfully matches */
+/* all of the commands in it. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_fr_matcharray(fin, array)
+ fr_info_t *fin;
+ int *array;
+{
+ int i, n, *x, rv, p;
+ ipfexp_t *e;
+
+ rv = 0;
+ n = array[0];
+ x = array + 1;
+
+ for (; n > 0; x += 3 + x[3], rv = 0) {
+ e = (ipfexp_t *)x;
+ if (e->ipfe_cmd == IPF_EXP_END)
+ break;
+ n -= e->ipfe_size;
+
+ /*
+ * The upper 16 bits currently store the protocol value.
+ * This is currently used with TCP and UDP port compares and
+ * allows "tcp.port = 80" without requiring an explicit
+ " "ip.pr = tcp" first.
+ */
+ p = e->ipfe_cmd >> 16;
+ if ((p != 0) && (p != fin->fin_p))
+ break;
+
+ switch (e->ipfe_cmd)
+ {
+ case IPF_EXP_IP_PR :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (fin->fin_p == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_IP_SRCADDR :
+ if (fin->fin_v != 4)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= ((fin->fin_saddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]);
+ }
+ break;
+
+ case IPF_EXP_IP_DSTADDR :
+ if (fin->fin_v != 4)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= ((fin->fin_daddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]);
+ }
+ break;
+
+ case IPF_EXP_IP_ADDR :
+ if (fin->fin_v != 4)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= ((fin->fin_saddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]) ||
+ ((fin->fin_daddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]);
+ }
+ break;
+
+#ifdef USE_INET6
+ case IPF_EXP_IP6_SRCADDR :
+ if (fin->fin_v != 6)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= IP6_MASKEQ(&fin->fin_src6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]);
+ }
+ break;
+
+ case IPF_EXP_IP6_DSTADDR :
+ if (fin->fin_v != 6)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= IP6_MASKEQ(&fin->fin_dst6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]);
+ }
+ break;
+
+ case IPF_EXP_IP6_ADDR :
+ if (fin->fin_v != 6)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= IP6_MASKEQ(&fin->fin_src6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]) ||
+ IP6_MASKEQ(&fin->fin_dst6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]);
+ }
+ break;
+#endif
+
+ case IPF_EXP_UDP_PORT :
+ case IPF_EXP_TCP_PORT :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (fin->fin_sport == e->ipfe_arg0[i]) ||
+ (fin->fin_dport == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_UDP_SPORT :
+ case IPF_EXP_TCP_SPORT :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (fin->fin_sport == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_UDP_DPORT :
+ case IPF_EXP_TCP_DPORT :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (fin->fin_dport == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_TCP_FLAGS :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= ((fin->fin_tcpf &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]);
+ }
+ break;
+ }
+ rv ^= e->ipfe_not;
+
+ if (rv == 0)
+ break;
+ }
+
+ return rv;
+}
+
+
+/* ------------------------------------------------------------------------ */
/* Function: ipf_queueflush */
/* Returns: int - number of entries flushed (0 = none) */
-/* Parameters: deletefn(I) - function to call to delete entry */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* deletefn(I) - function to call to delete entry */
/* ipfqs(I) - top of the list of ipf internal queues */
/* userqs(I) - top of the list of user defined timeouts */
/* */
/* This fucntion gets called when the state/NAT hash tables fill up and we */
-/* need to try a bit harder to free up some space. The algorithm used is */
-/* to look for the oldest entries on each timeout queue and free them if */
-/* they are within the given window we are considering. Where the window */
-/* starts and the steps taken to increase its size depend upon how long ipf */
-/* has been running (fr_ticks.) Anything modified in the last 30 seconds */
-/* is not touched. */
+/* need to try a bit harder to free up some space. The algorithm used here */
+/* split into two parts but both halves have the same goal: to reduce the */
+/* number of connections considered to be "active" to the low watermark. */
+/* There are two steps in doing this: */
+/* 1) Remove any TCP connections that are already considered to be "closed" */
+/* but have not yet been removed from the state table. The two states */
+/* TCPS_TIME_WAIT and TCPS_CLOSED are considered to be the perfect */
+/* candidates for this style of removal. If freeing up entries in */
+/* CLOSED or both CLOSED and TIME_WAIT brings us to the low watermark, */
+/* we do not go on to step 2. */
+/* */
+/* 2) Look for the oldest entries on each timeout queue and free them if */
+/* they are within the given window we are considering. Where the */
+/* window starts and the steps taken to increase its size depend upon */
+/* how long ipf has been running (ipf_ticks.) Anything modified in the */
+/* last 30 seconds is not touched. */
/* touched */
-/* die fr_ticks 30*1.5 1800*1.5 | 43200*1.5 */
+/* die ipf_ticks 30*1.5 1800*1.5 | 43200*1.5 */
/* | | | | | | */
/* future <--+----------+--------+-----------+-----+-----+-----------> past */
/* now \_int=30s_/ \_int=1hr_/ \_int=12hr */
/* */
/* Points to note: */
/* - tqe_die is the time, in the future, when entries die. */
-/* - tqe_die - fr_ticks is how long left the connection has to live in ipf */
+/* - tqe_die - ipf_ticks is how long left the connection has to live in ipf */
/* ticks. */
/* - tqe_touched is when the entry was last used by NAT/state */
-/* - the closer tqe_touched is to fr_ticks, the further tqe_die will be for */
-/* any given timeout queue and vice versa. */
+/* - the closer tqe_touched is to ipf_ticks, the further tqe_die will be */
+/* ipf_ticks any given timeout queue and vice versa. */
/* - both tqe_die and tqe_touched increase over time */
/* - timeout queues are sorted with the highest value of tqe_die at the */
/* bottom and therefore the smallest values of each are at the top */
+/* - the pointer passed in as ipfqs should point to an array of timeout */
+/* queues representing each of the TCP states */
/* */
/* We start by setting up a maximum range to scan for things to move of */
/* iend (newest) to istart (oldest) in chunks of "interval". If nothing is */
/* found in that range, "interval" is adjusted (so long as it isn't 30) and */
-/* we start again with a new value for "iend" and "istart". The downside */
-/* of the current implementation is that it may return removing just 1 entry*/
-/* every time (pathological case) where it could remove more. */
+/* we start again with a new value for "iend" and "istart". This is */
+/* continued until we either finish the scan of 30 second intervals or the */
+/* low water mark is reached. */
/* ------------------------------------------------------------------------ */
-int ipf_queueflush(deletefn, ipfqs, userqs)
-ipftq_delete_fn_t deletefn;
-ipftq_t *ipfqs, *userqs;
+int
+ipf_queueflush(softc, deletefn, ipfqs, userqs, activep, size, low)
+ ipf_main_softc_t *softc;
+ ipftq_delete_fn_t deletefn;
+ ipftq_t *ipfqs, *userqs;
+ u_int *activep;
+ int size, low;
{
u_long interval, istart, iend;
ipftq_t *ifq, *ifqnext;
ipftqent_t *tqe, *tqn;
- int removed;
+ int removed = 0;
+
+ for (tqn = ipfqs[IPF_TCPS_CLOSED].ifq_head; ((tqe = tqn) != NULL); ) {
+ tqn = tqe->tqe_next;
+ if ((*deletefn)(softc, tqe->tqe_parent) == 0)
+ removed++;
+ }
+ if ((*activep * 100 / size) > low) {
+ for (tqn = ipfqs[IPF_TCPS_TIME_WAIT].ifq_head;
+ ((tqe = tqn) != NULL); ) {
+ tqn = tqe->tqe_next;
+ if ((*deletefn)(softc, tqe->tqe_parent) == 0)
+ removed++;
+ }
+ }
+
+ if ((*activep * 100 / size) <= low) {
+ return removed;
+ }
/*
* NOTE: Use of "* 15 / 10" is required here because if "* 1.5" is
* used then the operations are upgraded to floating point
* and kernels don't like floating point...
*/
- if (fr_ticks > IPF_TTLVAL(43200 * 15 / 10)) {
+ if (softc->ipf_ticks > IPF_TTLVAL(43200 * 15 / 10)) {
istart = IPF_TTLVAL(86400 * 4);
interval = IPF_TTLVAL(43200);
- } else if (fr_ticks > IPF_TTLVAL(1800 * 15 / 10)) {
+ } else if (softc->ipf_ticks > IPF_TTLVAL(1800 * 15 / 10)) {
istart = IPF_TTLVAL(43200);
interval = IPF_TTLVAL(1800);
- } else if (fr_ticks > IPF_TTLVAL(30 * 15 / 10)) {
+ } else if (softc->ipf_ticks > IPF_TTLVAL(30 * 15 / 10)) {
istart = IPF_TTLVAL(1800);
interval = IPF_TTLVAL(30);
} else {
return 0;
}
- if (istart > fr_ticks) {
- if (fr_ticks - interval < interval)
+ if (istart > softc->ipf_ticks) {
+ if (softc->ipf_ticks - interval < interval)
istart = interval;
else
- istart = (fr_ticks / interval) * interval;
+ istart = (softc->ipf_ticks / interval) * interval;
}
- iend = fr_ticks - interval;
- removed = 0;
+ iend = softc->ipf_ticks - interval;
- for (;;) {
+ while ((*activep * 100 / size) > low) {
u_long try;
- try = fr_ticks - istart;
+ try = softc->ipf_ticks - istart;
for (ifq = ipfqs; ifq != NULL; ifq = ifq->ifq_next) {
for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
if (try < tqe->tqe_touched)
break;
tqn = tqe->tqe_next;
- if ((*deletefn)(tqe->tqe_parent) == 0)
+ if ((*deletefn)(softc, tqe->tqe_parent) == 0)
removed++;
}
}
@@ -7331,14 +9003,12 @@ ipftq_t *ipfqs, *userqs;
if (try < tqe->tqe_touched)
break;
tqn = tqe->tqe_next;
- if ((*deletefn)(tqe->tqe_parent) == 0)
+ if ((*deletefn)(softc, tqe->tqe_parent) == 0)
removed++;
}
}
if (try >= iend) {
- if (removed > 0)
- break;
if (interval == IPF_TTLVAL(43200)) {
interval = IPF_TTLVAL(1800);
} else if (interval == IPF_TTLVAL(1800)) {
@@ -7346,13 +9016,1200 @@ ipftq_t *ipfqs, *userqs;
} else {
break;
}
- if (interval >= fr_ticks)
+ if (interval >= softc->ipf_ticks)
break;
- iend = fr_ticks - interval;
+ iend = softc->ipf_ticks - interval;
}
istart -= interval;
}
return removed;
}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_deliverlocal */
+/* Returns: int - 1 = local address, 0 = non-local address */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* ipversion(I) - IP protocol version (4 or 6) */
+/* ifp(I) - network interface pointer */
+/* ipaddr(I) - IPv4/6 destination address */
+/* */
+/* This fucntion is used to determine in the address "ipaddr" belongs to */
+/* the network interface represented by ifp. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_deliverlocal(softc, ipversion, ifp, ipaddr)
+ ipf_main_softc_t *softc;
+ int ipversion;
+ void *ifp;
+ i6addr_t *ipaddr;
+{
+ i6addr_t addr;
+ int islocal = 0;
+
+ if (ipversion == 4) {
+ if (ipf_ifpaddr(softc, 4, FRI_NORMAL, ifp, &addr, NULL) == 0) {
+ if (addr.in4.s_addr == ipaddr->in4.s_addr)
+ islocal = 1;
+ }
+
+#ifdef USE_INET6
+ } else if (ipversion == 6) {
+ if (ipf_ifpaddr(softc, 6, FRI_NORMAL, ifp, &addr, NULL) == 0) {
+ if (IP6_EQ(&addr, ipaddr))
+ islocal = 1;
+ }
+#endif
+ }
+
+ return islocal;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_settimeout */
+/* Returns: int - 0 = success, -1 = failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* t(I) - pointer to tuneable array entry */
+/* p(I) - pointer to values passed in to apply */
+/* */
+/* This function is called to set the timeout values for each distinct */
+/* queue timeout that is available. When called, it calls into both the */
+/* state and NAT code, telling them to update their timeout queues. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_settimeout(softc, t, p)
+ struct ipf_main_softc_s *softc;
+ ipftuneable_t *t;
+ ipftuneval_t *p;
+{
+
+ /*
+ * ipf_interror should be set by the functions called here, not
+ * by this function - it's just a middle man.
+ */
+ if (ipf_state_settimeout(softc, t, p) == -1)
+ return -1;
+ if (ipf_nat_settimeout(softc, t, p) == -1)
+ return -1;
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_apply_timeout */
+/* Returns: int - 0 = success, -1 = failure */
+/* Parameters: head(I) - pointer to tuneable array entry */
+/* seconds(I) - pointer to values passed in to apply */
+/* */
+/* This function applies a timeout of "seconds" to the timeout queue that */
+/* is pointed to by "head". All entries on this list have an expiration */
+/* set to be the current tick value of ipf plus the ttl. Given that this */
+/* function should only be called when the delta is non-zero, the task is */
+/* to walk the entire list and apply the change. The sort order will not */
+/* change. The only catch is that this is O(n) across the list, so if the */
+/* queue has lots of entries (10s of thousands or 100s of thousands), it */
+/* could take a relatively long time to work through them all. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_apply_timeout(head, seconds)
+ ipftq_t *head;
+ u_int seconds;
+{
+ u_int oldtimeout, newtimeout;
+ ipftqent_t *tqe;
+ int delta;
+
+ MUTEX_ENTER(&head->ifq_lock);
+ oldtimeout = head->ifq_ttl;
+ newtimeout = IPF_TTLVAL(seconds);
+ delta = oldtimeout - newtimeout;
+
+ head->ifq_ttl = newtimeout;
+
+ for (tqe = head->ifq_head; tqe != NULL; tqe = tqe->tqe_next) {
+ tqe->tqe_die += delta;
+ }
+ MUTEX_EXIT(&head->ifq_lock);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_settimeout_tcp */
+/* Returns: int - 0 = successfully applied, -1 = failed */
+/* Parameters: t(I) - pointer to tuneable to change */
+/* p(I) - pointer to new timeout information */
+/* tab(I) - pointer to table of TCP queues */
+/* */
+/* This function applies the new timeout (p) to the TCP tunable (t) and */
+/* updates all of the entries on the relevant timeout queue by calling */
+/* ipf_apply_timeout(). */
+/* ------------------------------------------------------------------------ */
+int
+ipf_settimeout_tcp(t, p, tab)
+ ipftuneable_t *t;
+ ipftuneval_t *p;
+ ipftq_t *tab;
+{
+ if (!strcmp(t->ipft_name, "tcp_idle_timeout") ||
+ !strcmp(t->ipft_name, "tcp_established")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_ESTABLISHED], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_close_wait")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_CLOSE_WAIT], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_last_ack")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_LAST_ACK], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_timeout")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int);
+ ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int);
+ ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_listen")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_half_established")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_closing")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_syn_received")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_SYN_RECEIVED], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_syn_sent")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_SYN_SENT], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_closed")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_half_closed")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_time_wait")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_TIME_WAIT], p->ipftu_int);
+ } else {
+ /*
+ * ipf_interror isn't set here because it should be set
+ * by whatever called this function.
+ */
+ return -1;
+ }
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_main_soft_create */
+/* Returns: NULL = failure, else success */
+/* Parameters: arg(I) - pointer to soft context structure if already allocd */
+/* */
+/* Create the foundation soft context structure. In circumstances where it */
+/* is not required to dynamically allocate the context, a pointer can be */
+/* passed in (rather than NULL) to a structure to be initialised. */
+/* The main thing of interest is that a number of locks are initialised */
+/* here instead of in the where might be expected - in the relevant create */
+/* function elsewhere. This is done because the current locking design has */
+/* some areas where these locks are used outside of their module. */
+/* Possibly the most important exercise that is done here is setting of all */
+/* the timeout values, allowing them to be changed before init(). */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_main_soft_create(arg)
+ void *arg;
+{
+ ipf_main_softc_t *softc;
+
+ if (arg == NULL) {
+ KMALLOC(softc, ipf_main_softc_t *);
+ if (softc == NULL)
+ return NULL;
+ } else {
+ softc = arg;
+ }
+
+ bzero((char *)softc, sizeof(*softc));
+
+ /*
+ * This serves as a flag as to whether or not the softc should be
+ * free'd when _destroy is called.
+ */
+ softc->ipf_dynamic_softc = (arg == NULL) ? 1 : 0;
+
+ softc->ipf_tuners = ipf_tune_array_copy(softc,
+ sizeof(ipf_main_tuneables),
+ ipf_main_tuneables);
+ if (softc->ipf_tuners == NULL) {
+ ipf_main_soft_destroy(softc);
+ return NULL;
+ }
+
+ MUTEX_INIT(&softc->ipf_rw, "ipf rw mutex");
+ MUTEX_INIT(&softc->ipf_timeoutlock, "ipf timeout lock");
+ RWLOCK_INIT(&softc->ipf_global, "ipf filter load/unload mutex");
+ RWLOCK_INIT(&softc->ipf_mutex, "ipf filter rwlock");
+ RWLOCK_INIT(&softc->ipf_tokens, "ipf token rwlock");
+ RWLOCK_INIT(&softc->ipf_state, "ipf state rwlock");
+ RWLOCK_INIT(&softc->ipf_nat, "ipf IP NAT rwlock");
+ RWLOCK_INIT(&softc->ipf_poolrw, "ipf pool rwlock");
+ RWLOCK_INIT(&softc->ipf_frag, "ipf frag rwlock");
+
+ softc->ipf_token_head = NULL;
+ softc->ipf_token_tail = &softc->ipf_token_head;
+
+ softc->ipf_tcpidletimeout = FIVE_DAYS;
+ softc->ipf_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL);
+ softc->ipf_tcplastack = IPF_TTLVAL(30);
+ softc->ipf_tcptimewait = IPF_TTLVAL(2 * TCP_MSL);
+ softc->ipf_tcptimeout = IPF_TTLVAL(2 * TCP_MSL);
+ softc->ipf_tcpsynsent = IPF_TTLVAL(2 * TCP_MSL);
+ softc->ipf_tcpsynrecv = IPF_TTLVAL(2 * TCP_MSL);
+ softc->ipf_tcpclosed = IPF_TTLVAL(30);
+ softc->ipf_tcphalfclosed = IPF_TTLVAL(2 * 3600);
+ softc->ipf_udptimeout = IPF_TTLVAL(120);
+ softc->ipf_udpacktimeout = IPF_TTLVAL(12);
+ softc->ipf_icmptimeout = IPF_TTLVAL(60);
+ softc->ipf_icmpacktimeout = IPF_TTLVAL(6);
+ softc->ipf_iptimeout = IPF_TTLVAL(60);
+
+#if defined(IPFILTER_DEFAULT_BLOCK)
+ softc->ipf_pass = FR_BLOCK|FR_NOMATCH;
+#else
+ softc->ipf_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH;
+#endif
+ softc->ipf_minttl = 4;
+ softc->ipf_icmpminfragmtu = 68;
+ softc->ipf_flags = IPF_LOGGING;
+
+ return softc;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_main_soft_init */
+/* Returns: 0 = success, -1 = failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* A null-op function that exists as a placeholder so that the flow in */
+/* other functions is obvious. */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+int
+ipf_main_soft_init(softc)
+ ipf_main_softc_t *softc;
+{
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_main_soft_destroy */
+/* Returns: void */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Undo everything that we did in ipf_main_soft_create. */
+/* */
+/* The most important check that needs to be made here is whether or not */
+/* the structure was allocated by ipf_main_soft_create() by checking what */
+/* value is stored in ipf_dynamic_main. */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+void
+ipf_main_soft_destroy(softc)
+ ipf_main_softc_t *softc;
+{
+
+ RW_DESTROY(&softc->ipf_frag);
+ RW_DESTROY(&softc->ipf_poolrw);
+ RW_DESTROY(&softc->ipf_nat);
+ RW_DESTROY(&softc->ipf_state);
+ RW_DESTROY(&softc->ipf_tokens);
+ RW_DESTROY(&softc->ipf_mutex);
+ RW_DESTROY(&softc->ipf_global);
+ MUTEX_DESTROY(&softc->ipf_timeoutlock);
+ MUTEX_DESTROY(&softc->ipf_rw);
+
+ if (softc->ipf_tuners != NULL) {
+ KFREES(softc->ipf_tuners, sizeof(ipf_main_tuneables));
+ }
+ if (softc->ipf_dynamic_softc == 1) {
+ KFREE(softc);
+ }
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_main_soft_fini */
+/* Returns: 0 = success, -1 = failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Clean out the rules which have been added since _init was last called, */
+/* the only dynamic part of the mainline. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_main_soft_fini(softc)
+ ipf_main_softc_t *softc;
+{
+ (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
+ (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE);
+ (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
+ (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_main_load */
+/* Returns: 0 = success, -1 = failure */
+/* Parameters: none */
+/* */
+/* Handle global initialisation that needs to be done for the base part of */
+/* IPFilter. At present this just amounts to initialising some ICMP lookup */
+/* arrays that get used by the state/NAT code. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_main_load()
+{
+ int i;
+
+ /* 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;
+
+#ifdef USE_INET6
+ /* fill icmp reply type table */
+ for (i = 0; i <= ICMP6_MAXTYPE; i++)
+ icmpreplytype6[i] = -1;
+ icmpreplytype6[ICMP6_ECHO_REQUEST] = ICMP6_ECHO_REPLY;
+ icmpreplytype6[ICMP6_MEMBERSHIP_QUERY] = ICMP6_MEMBERSHIP_REPORT;
+ icmpreplytype6[ICMP6_NI_QUERY] = ICMP6_NI_REPLY;
+ icmpreplytype6[ND_ROUTER_SOLICIT] = ND_ROUTER_ADVERT;
+ icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT;
+#endif
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_main_unload */
+/* Returns: 0 = success, -1 = failure */
+/* Parameters: none */
+/* */
+/* A null-op function that exists as a placeholder so that the flow in */
+/* other functions is obvious. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_main_unload()
+{
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_load_all */
+/* Returns: 0 = success, -1 = failure */
+/* Parameters: none */
+/* */
+/* Work through all of the subsystems inside IPFilter and call the load */
+/* function for each in an order that won't lead to a crash :) */
+/* ------------------------------------------------------------------------ */
+int
+ipf_load_all()
+{
+ if (ipf_main_load() == -1)
+ return -1;
+
+ if (ipf_state_main_load() == -1)
+ return -1;
+
+ if (ipf_nat_main_load() == -1)
+ return -1;
+
+ if (ipf_frag_main_load() == -1)
+ return -1;
+
+ if (ipf_auth_main_load() == -1)
+ return -1;
+
+ if (ipf_proxy_main_load() == -1)
+ return -1;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_unload_all */
+/* Returns: 0 = success, -1 = failure */
+/* Parameters: none */
+/* */
+/* Work through all of the subsystems inside IPFilter and call the unload */
+/* function for each in an order that won't lead to a crash :) */
+/* ------------------------------------------------------------------------ */
+int
+ipf_unload_all()
+{
+ if (ipf_proxy_main_unload() == -1)
+ return -1;
+
+ if (ipf_auth_main_unload() == -1)
+ return -1;
+
+ if (ipf_frag_main_unload() == -1)
+ return -1;
+
+ if (ipf_nat_main_unload() == -1)
+ return -1;
+
+ if (ipf_state_main_unload() == -1)
+ return -1;
+
+ if (ipf_main_unload() == -1)
+ return -1;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_create_all */
+/* Returns: NULL = failure, else success */
+/* Parameters: arg(I) - pointer to soft context main structure */
+/* */
+/* Work through all of the subsystems inside IPFilter and call the create */
+/* function for each in an order that won't lead to a crash :) */
+/* ------------------------------------------------------------------------ */
+ipf_main_softc_t *
+ipf_create_all(arg)
+ void *arg;
+{
+ ipf_main_softc_t *softc;
+
+ softc = ipf_main_soft_create(arg);
+ if (softc == NULL)
+ return NULL;
+
+#ifdef IPFILTER_LOG
+ softc->ipf_log_soft = ipf_log_soft_create(softc);
+ if (softc->ipf_log_soft == NULL) {
+ ipf_destroy_all(softc);
+ return NULL;
+ }
+#endif
+
+ softc->ipf_lookup_soft = ipf_lookup_soft_create(softc);
+ if (softc->ipf_lookup_soft == NULL) {
+ ipf_destroy_all(softc);
+ return NULL;
+ }
+
+ softc->ipf_sync_soft = ipf_sync_soft_create(softc);
+ if (softc->ipf_sync_soft == NULL) {
+ ipf_destroy_all(softc);
+ return NULL;
+ }
+
+ softc->ipf_state_soft = ipf_state_soft_create(softc);
+ if (softc->ipf_state_soft == NULL) {
+ ipf_destroy_all(softc);
+ return NULL;
+ }
+
+ softc->ipf_nat_soft = ipf_nat_soft_create(softc);
+ if (softc->ipf_nat_soft == NULL) {
+ ipf_destroy_all(softc);
+ return NULL;
+ }
+
+ softc->ipf_frag_soft = ipf_frag_soft_create(softc);
+ if (softc->ipf_frag_soft == NULL) {
+ ipf_destroy_all(softc);
+ return NULL;
+ }
+
+ softc->ipf_auth_soft = ipf_auth_soft_create(softc);
+ if (softc->ipf_auth_soft == NULL) {
+ ipf_destroy_all(softc);
+ return NULL;
+ }
+
+ softc->ipf_proxy_soft = ipf_proxy_soft_create(softc);
+ if (softc->ipf_proxy_soft == NULL) {
+ ipf_destroy_all(softc);
+ return NULL;
+ }
+
+ return softc;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_destroy_all */
+/* Returns: void */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Work through all of the subsystems inside IPFilter and call the destroy */
+/* function for each in an order that won't lead to a crash :) */
+/* */
+/* Every one of these functions is expected to succeed, so there is no */
+/* checking of return values. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_destroy_all(softc)
+ ipf_main_softc_t *softc;
+{
+
+ if (softc->ipf_state_soft != NULL) {
+ ipf_state_soft_destroy(softc, softc->ipf_state_soft);
+ softc->ipf_state_soft = NULL;
+ }
+
+ if (softc->ipf_nat_soft != NULL) {
+ ipf_nat_soft_destroy(softc, softc->ipf_nat_soft);
+ softc->ipf_nat_soft = NULL;
+ }
+
+ if (softc->ipf_frag_soft != NULL) {
+ ipf_frag_soft_destroy(softc, softc->ipf_frag_soft);
+ softc->ipf_frag_soft = NULL;
+ }
+
+ if (softc->ipf_auth_soft != NULL) {
+ ipf_auth_soft_destroy(softc, softc->ipf_auth_soft);
+ softc->ipf_auth_soft = NULL;
+ }
+
+ if (softc->ipf_proxy_soft != NULL) {
+ ipf_proxy_soft_destroy(softc, softc->ipf_proxy_soft);
+ softc->ipf_proxy_soft = NULL;
+ }
+
+ if (softc->ipf_sync_soft != NULL) {
+ ipf_sync_soft_destroy(softc, softc->ipf_sync_soft);
+ softc->ipf_sync_soft = NULL;
+ }
+
+ if (softc->ipf_lookup_soft != NULL) {
+ ipf_lookup_soft_destroy(softc, softc->ipf_lookup_soft);
+ softc->ipf_lookup_soft = NULL;
+ }
+
+#ifdef IPFILTER_LOG
+ if (softc->ipf_log_soft != NULL) {
+ ipf_log_soft_destroy(softc, softc->ipf_log_soft);
+ softc->ipf_log_soft = NULL;
+ }
+#endif
+
+ ipf_main_soft_destroy(softc);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_init_all */
+/* Returns: 0 = success, -1 = failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Work through all of the subsystems inside IPFilter and call the init */
+/* function for each in an order that won't lead to a crash :) */
+/* ------------------------------------------------------------------------ */
+int
+ipf_init_all(softc)
+ ipf_main_softc_t *softc;
+{
+
+ if (ipf_main_soft_init(softc) == -1)
+ return -1;
+
+#ifdef IPFILTER_LOG
+ if (ipf_log_soft_init(softc, softc->ipf_log_soft) == -1)
+ return -1;
+#endif
+
+ if (ipf_lookup_soft_init(softc, softc->ipf_lookup_soft) == -1)
+ return -1;
+
+ if (ipf_sync_soft_init(softc, softc->ipf_sync_soft) == -1)
+ return -1;
+
+ if (ipf_state_soft_init(softc, softc->ipf_state_soft) == -1)
+ return -1;
+
+ if (ipf_nat_soft_init(softc, softc->ipf_nat_soft) == -1)
+ return -1;
+
+ if (ipf_frag_soft_init(softc, softc->ipf_frag_soft) == -1)
+ return -1;
+
+ if (ipf_auth_soft_init(softc, softc->ipf_auth_soft) == -1)
+ return -1;
+
+ if (ipf_proxy_soft_init(softc, softc->ipf_proxy_soft) == -1)
+ return -1;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_fini_all */
+/* Returns: 0 = success, -1 = failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Work through all of the subsystems inside IPFilter and call the fini */
+/* function for each in an order that won't lead to a crash :) */
+/* ------------------------------------------------------------------------ */
+int
+ipf_fini_all(softc)
+ ipf_main_softc_t *softc;
+{
+
+ ipf_token_flush(softc);
+
+ if (ipf_proxy_soft_fini(softc, softc->ipf_proxy_soft) == -1)
+ return -1;
+
+ if (ipf_auth_soft_fini(softc, softc->ipf_auth_soft) == -1)
+ return -1;
+
+ if (ipf_frag_soft_fini(softc, softc->ipf_frag_soft) == -1)
+ return -1;
+
+ if (ipf_nat_soft_fini(softc, softc->ipf_nat_soft) == -1)
+ return -1;
+
+ if (ipf_state_soft_fini(softc, softc->ipf_state_soft) == -1)
+ return -1;
+
+ if (ipf_sync_soft_fini(softc, softc->ipf_sync_soft) == -1)
+ return -1;
+
+ if (ipf_lookup_soft_fini(softc, softc->ipf_lookup_soft) == -1)
+ return -1;
+
+#ifdef IPFILTER_LOG
+ if (ipf_log_soft_fini(softc, softc->ipf_log_soft) == -1)
+ return -1;
+#endif
+
+ if (ipf_main_soft_fini(softc) == -1)
+ return -1;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rule_expire */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* At present this function exists just to support temporary addition of */
+/* firewall rules. Both inactive and active lists are scanned for items to */
+/* purge, as by rights, the expiration is computed as soon as the rule is */
+/* loaded in. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rule_expire(softc)
+ ipf_main_softc_t *softc;
+{
+ frentry_t *fr;
+
+ if ((softc->ipf_rule_explist[0] == NULL) &&
+ (softc->ipf_rule_explist[1] == NULL))
+ return;
+
+ WRITE_ENTER(&softc->ipf_mutex);
+
+ while ((fr = softc->ipf_rule_explist[0]) != NULL) {
+ /*
+ * Because the list is kept sorted on insertion, the fist
+ * one that dies in the future means no more work to do.
+ */
+ if (fr->fr_die > softc->ipf_ticks)
+ break;
+ ipf_rule_delete(softc, fr, IPL_LOGIPF, 0);
+ }
+
+ while ((fr = softc->ipf_rule_explist[1]) != NULL) {
+ /*
+ * Because the list is kept sorted on insertion, the fist
+ * one that dies in the future means no more work to do.
+ */
+ if (fr->fr_die > softc->ipf_ticks)
+ break;
+ ipf_rule_delete(softc, fr, IPL_LOGIPF, 1);
+ }
+
+ RWLOCK_EXIT(&softc->ipf_mutex);
+}
+
+
+static int ipf_ht_node_cmp __P((struct host_node_s *, struct host_node_s *));
+static void ipf_ht_node_make_key __P((host_track_t *, host_node_t *, int,
+ i6addr_t *));
+
+host_node_t RBI_ZERO(ipf_rb);
+RBI_CODE(ipf_rb, host_node_t, hn_entry, ipf_ht_node_cmp)
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_ht_node_cmp */
+/* Returns: int - 0 == nodes are the same, .. */
+/* Parameters: k1(I) - pointer to first key to compare */
+/* k2(I) - pointer to second key to compare */
+/* */
+/* The "key" for the node is a combination of two fields: the address */
+/* family and the address itself. */
+/* */
+/* Because we're not actually interpreting the address data, it isn't */
+/* necessary to convert them to/from network/host byte order. The mask is */
+/* just used to remove bits that aren't significant - it doesn't matter */
+/* where they are, as long as they're always in the same place. */
+/* */
+/* As with IP6_EQ, comparing IPv6 addresses starts at the bottom because */
+/* this is where individual ones will differ the most - but not true for */
+/* for /48's, etc. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_ht_node_cmp(k1, k2)
+ struct host_node_s *k1, *k2;
+{
+ int i;
+
+ i = (k2->hn_addr.adf_family - k1->hn_addr.adf_family);
+ if (i != 0)
+ return i;
+
+ if (k1->hn_addr.adf_family == AF_INET)
+ return (k2->hn_addr.adf_addr.in4.s_addr -
+ k1->hn_addr.adf_addr.in4.s_addr);
+
+ i = k2->hn_addr.adf_addr.i6[3] - k1->hn_addr.adf_addr.i6[3];
+ if (i != 0)
+ return i;
+ i = k2->hn_addr.adf_addr.i6[2] - k1->hn_addr.adf_addr.i6[2];
+ if (i != 0)
+ return i;
+ i = k2->hn_addr.adf_addr.i6[1] - k1->hn_addr.adf_addr.i6[1];
+ if (i != 0)
+ return i;
+ i = k2->hn_addr.adf_addr.i6[0] - k1->hn_addr.adf_addr.i6[0];
+ return i;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_ht_node_make_key */
+/* Returns: Nil */
+/* parameters: htp(I) - pointer to address tracking structure */
+/* key(I) - where to store masked address for lookup */
+/* family(I) - protocol family of address */
+/* addr(I) - pointer to network address */
+/* */
+/* Using the "netmask" (number of bits) stored parent host tracking struct, */
+/* copy the address passed in into the key structure whilst masking out the */
+/* bits that we don't want. */
+/* */
+/* Because the parser will set ht_netmask to 128 if there is no protocol */
+/* specified (the parser doesn't know if it should be a v4 or v6 rule), we */
+/* have to be wary of that and not allow 32-128 to happen. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_ht_node_make_key(htp, key, family, addr)
+ host_track_t *htp;
+ host_node_t *key;
+ int family;
+ i6addr_t *addr;
+{
+ key->hn_addr.adf_family = family;
+ if (family == AF_INET) {
+ u_32_t mask;
+ int bits;
+
+ key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in4);
+ bits = htp->ht_netmask;
+ if (bits >= 32) {
+ mask = 0xffffffff;
+ } else {
+ mask = htonl(0xffffffff << (32 - bits));
+ }
+ key->hn_addr.adf_addr.in4.s_addr = addr->in4.s_addr & mask;
+#ifdef USE_INET6
+ } else {
+ int bits = htp->ht_netmask;
+
+ key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in6);
+ if (bits > 96) {
+ key->hn_addr.adf_addr.i6[3] = addr->i6[3] &
+ htonl(0xffffffff << (128 - bits));
+ key->hn_addr.adf_addr.i6[2] = addr->i6[2];
+ key->hn_addr.adf_addr.i6[1] = addr->i6[2];
+ key->hn_addr.adf_addr.i6[0] = addr->i6[2];
+ } else if (bits > 64) {
+ key->hn_addr.adf_addr.i6[3] = 0;
+ key->hn_addr.adf_addr.i6[2] = addr->i6[2] &
+ htonl(0xffffffff << (96 - bits));
+ key->hn_addr.adf_addr.i6[1] = addr->i6[1];
+ key->hn_addr.adf_addr.i6[0] = addr->i6[0];
+ } else if (bits > 32) {
+ key->hn_addr.adf_addr.i6[3] = 0;
+ key->hn_addr.adf_addr.i6[2] = 0;
+ key->hn_addr.adf_addr.i6[1] = addr->i6[1] &
+ htonl(0xffffffff << (64 - bits));
+ key->hn_addr.adf_addr.i6[0] = addr->i6[0];
+ } else {
+ key->hn_addr.adf_addr.i6[3] = 0;
+ key->hn_addr.adf_addr.i6[2] = 0;
+ key->hn_addr.adf_addr.i6[1] = 0;
+ key->hn_addr.adf_addr.i6[0] = addr->i6[0] &
+ htonl(0xffffffff << (32 - bits));
+ }
+ }
+#endif
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_ht_node_add */
+/* Returns: int - 0 == success, -1 == failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* htp(I) - pointer to address tracking structure */
+/* family(I) - protocol family of address */
+/* addr(I) - pointer to network address */
+/* */
+/* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */
+/* ipf_ht_node_del FROM RUNNING CONCURRENTLY ON THE SAME htp. */
+/* */
+/* After preparing the key with the address information to find, look in */
+/* the red-black tree to see if the address is known. A successful call to */
+/* this function can mean one of two things: a new node was added to the */
+/* tree or a matching node exists and we're able to bump up its activity. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_ht_node_add(softc, htp, family, addr)
+ ipf_main_softc_t *softc;
+ host_track_t *htp;
+ int family;
+ i6addr_t *addr;
+{
+ host_node_t *h;
+ host_node_t k;
+
+ ipf_ht_node_make_key(htp, &k, family, addr);
+
+ h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k);
+ if (h == NULL) {
+ if (htp->ht_cur_nodes >= htp->ht_max_nodes)
+ return -1;
+ KMALLOC(h, host_node_t *);
+ if (h == NULL) {
+ DT(ipf_rb_no_mem);
+ LBUMP(ipf_rb_no_mem);
+ return -1;
+ }
+
+ /*
+ * If there was a macro to initialise the RB node then that
+ * would get used here, but there isn't...
+ */
+ bzero((char *)h, sizeof(*h));
+ h->hn_addr = k.hn_addr;
+ h->hn_addr.adf_family = k.hn_addr.adf_family;
+ RBI_INSERT(ipf_rb, &htp->ht_root, h);
+ htp->ht_cur_nodes++;
+ } else {
+ if ((htp->ht_max_per_node != 0) &&
+ (h->hn_active >= htp->ht_max_per_node)) {
+ DT(ipf_rb_node_max);
+ LBUMP(ipf_rb_node_max);
+ return -1;
+ }
+ }
+
+ h->hn_active++;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_ht_node_del */
+/* Returns: int - 0 == success, -1 == failure */
+/* parameters: htp(I) - pointer to address tracking structure */
+/* family(I) - protocol family of address */
+/* addr(I) - pointer to network address */
+/* */
+/* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */
+/* ipf_ht_node_add FROM RUNNING CONCURRENTLY ON THE SAME htp. */
+/* */
+/* Try and find the address passed in amongst the leavese on this tree to */
+/* be friend. If found then drop the active account for that node drops by */
+/* one. If that count reaches 0, it is time to free it all up. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_ht_node_del(htp, family, addr)
+ host_track_t *htp;
+ int family;
+ i6addr_t *addr;
+{
+ host_node_t *h;
+ host_node_t k;
+
+ ipf_ht_node_make_key(htp, &k, family, addr);
+
+ h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k);
+ if (h == NULL) {
+ return -1;
+ } else {
+ h->hn_active--;
+ if (h->hn_active == 0) {
+ (void) RBI_DELETE(ipf_rb, &htp->ht_root, h);
+ htp->ht_cur_nodes--;
+ KFREE(h);
+ }
+ }
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rb_ht_init */
+/* Returns: Nil */
+/* Parameters: head(I) - pointer to host tracking structure */
+/* */
+/* Initialise the host tracking structure to be ready for use above. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rb_ht_init(head)
+ host_track_t *head;
+{
+ RBI_INIT(ipf_rb, &head->ht_root);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rb_ht_freenode */
+/* Returns: Nil */
+/* Parameters: head(I) - pointer to host tracking structure */
+/* arg(I) - additional argument from walk caller */
+/* */
+/* Free an actual host_node_t structure. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rb_ht_freenode(node, arg)
+ host_node_t *node;
+ void *arg;
+{
+ KFREE(node);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rb_ht_flush */
+/* Returns: Nil */
+/* Parameters: head(I) - pointer to host tracking structure */
+/* */
+/* Remove all of the nodes in the tree tracking hosts by calling a walker */
+/* and free'ing each one. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rb_ht_flush(head)
+ host_track_t *head;
+{
+ RBI_WALK(ipf_rb, &head->ht_root, ipf_rb_ht_freenode, NULL);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_slowtimer */
+/* Returns: Nil */
+/* Parameters: ptr(I) - pointer to main ipf soft context structure */
+/* */
+/* Slowly expire held state for fragments. Timeouts are set * in */
+/* expectation of this being called twice per second. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_slowtimer(softc)
+ ipf_main_softc_t *softc;
+{
+
+ ipf_token_expire(softc);
+ ipf_frag_expire(softc);
+ ipf_state_expire(softc);
+ ipf_nat_expire(softc);
+ ipf_auth_expire(softc);
+ ipf_lookup_expire(softc);
+ ipf_rule_expire(softc);
+ ipf_sync_expire(softc);
+ softc->ipf_ticks++;
+# if defined(__OpenBSD__)
+ timeout_add(&ipf_slowtimer_ch, hz/2);
+# endif
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_inet_mask_add */
+/* Returns: Nil */
+/* Parameters: bits(I) - pointer to nat context information */
+/* mtab(I) - pointer to mask hash table structure */
+/* */
+/* When called, bits represents the mask of a new NAT rule that has just */
+/* been added. This function inserts a bitmask into the array of masks to */
+/* search when searching for a matching NAT rule for a packet. */
+/* Prevention of duplicate masks is achieved by checking the use count for */
+/* a given netmask. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_inet_mask_add(bits, mtab)
+ int bits;
+ ipf_v4_masktab_t *mtab;
+{
+ u_32_t mask;
+ int i, j;
+
+ mtab->imt4_masks[bits]++;
+ if (mtab->imt4_masks[bits] > 1)
+ return;
+
+ if (bits == 0)
+ mask = 0;
+ else
+ mask = 0xffffffff << (32 - bits);
+
+ for (i = 0; i < 33; i++) {
+ if (ntohl(mtab->imt4_active[i]) < mask) {
+ for (j = 32; j > i; j--)
+ mtab->imt4_active[j] = mtab->imt4_active[j - 1];
+ mtab->imt4_active[i] = htonl(mask);
+ break;
+ }
+ }
+ mtab->imt4_max++;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_inet_mask_del */
+/* Returns: Nil */
+/* Parameters: bits(I) - number of bits set in the netmask */
+/* mtab(I) - pointer to mask hash table structure */
+/* */
+/* Remove the 32bit bitmask represented by "bits" from the collection of */
+/* netmasks stored inside of mtab. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_inet_mask_del(bits, mtab)
+ int bits;
+ ipf_v4_masktab_t *mtab;
+{
+ u_32_t mask;
+ int i, j;
+
+ mtab->imt4_masks[bits]--;
+ if (mtab->imt4_masks[bits] > 0)
+ return;
+
+ mask = htonl(0xffffffff << (32 - bits));
+ for (i = 0; i < 33; i++) {
+ if (mtab->imt4_active[i] == mask) {
+ for (j = i + 1; j < 33; j++)
+ mtab->imt4_active[j - 1] = mtab->imt4_active[j];
+ break;
+ }
+ }
+ mtab->imt4_max--;
+ ASSERT(mtab->imt4_max >= 0);
+}
+
+
+#ifdef USE_INET6
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_inet6_mask_add */
+/* Returns: Nil */
+/* Parameters: bits(I) - number of bits set in mask */
+/* mask(I) - pointer to mask to add */
+/* mtab(I) - pointer to mask hash table structure */
+/* */
+/* When called, bitcount represents the mask of a IPv6 NAT map rule that */
+/* has just been added. This function inserts a bitmask into the array of */
+/* masks to search when searching for a matching NAT rule for a packet. */
+/* Prevention of duplicate masks is achieved by checking the use count for */
+/* a given netmask. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_inet6_mask_add(bits, mask, mtab)
+ int bits;
+ i6addr_t *mask;
+ ipf_v6_masktab_t *mtab;
+{
+ i6addr_t zero;
+ int i, j;
+
+ mtab->imt6_masks[bits]++;
+ if (mtab->imt6_masks[bits] > 1)
+ return;
+
+ if (bits == 0) {
+ mask = &zero;
+ zero.i6[0] = 0;
+ zero.i6[1] = 0;
+ zero.i6[2] = 0;
+ zero.i6[3] = 0;
+ }
+
+ for (i = 0; i < 129; i++) {
+ if (IP6_LT(&mtab->imt6_active[i], mask)) {
+ for (j = 128; j > i; j--)
+ mtab->imt6_active[j] = mtab->imt6_active[j - 1];
+ mtab->imt6_active[i] = *mask;
+ break;
+ }
+ }
+ mtab->imt6_max++;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_inet6_mask_del */
+/* Returns: Nil */
+/* Parameters: bits(I) - number of bits set in mask */
+/* mask(I) - pointer to mask to remove */
+/* mtab(I) - pointer to mask hash table structure */
+/* */
+/* Remove the 128bit bitmask represented by "bits" from the collection of */
+/* netmasks stored inside of mtab. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_inet6_mask_del(bits, mask, mtab)
+ int bits;
+ i6addr_t *mask;
+ ipf_v6_masktab_t *mtab;
+{
+ i6addr_t zero;
+ int i, j;
+
+ mtab->imt6_masks[bits]--;
+ if (mtab->imt6_masks[bits] > 0)
+ return;
+
+ if (bits == 0)
+ mask = &zero;
+ zero.i6[0] = 0;
+ zero.i6[1] = 0;
+ zero.i6[2] = 0;
+ zero.i6[3] = 0;
+
+ for (i = 0; i < 129; i++) {
+ if (IP6_EQ(&mtab->imt6_active[i], mask)) {
+ for (j = i + 1; j < 129; j++) {
+ mtab->imt6_active[j - 1] = mtab->imt6_active[j];
+ if (IP6_EQ(&mtab->imt6_active[j - 1], &zero))
+ break;
+ }
+ break;
+ }
+ }
+ mtab->imt6_max--;
+ ASSERT(mtab->imt6_max >= 0);
+}
+#endif
diff --git a/sys/contrib/ipfilter/netinet/ip_auth.c b/sys/contrib/ipfilter/netinet/ip_auth.c
index fcd891f..5a2ebec 100644
--- a/sys/contrib/ipfilter/netinet/ip_auth.c
+++ b/sys/contrib/ipfilter/netinet/ip_auth.c
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*/
@@ -19,6 +19,9 @@
#if !defined(_KERNEL)
# include <stdio.h>
# include <stdlib.h>
+# ifdef _STDC_C99
+# include <stdbool.h>
+# endif
# include <string.h>
# define _KERNEL
# ifdef __OpenBSD__
@@ -52,7 +55,7 @@ struct file;
# include <sys/stream.h>
# include <sys/kmem.h>
#endif
-#if (defined(_BSDI_VERSION) && _BSDI_VERSION >= 199802) || \
+#if (defined(_BSDI_VERSION) && (_BSDI_VERSION >= 199802)) || \
(defined(__FreeBSD_version) &&(__FreeBSD_version >= 400000))
# include <sys/queue.h>
#endif
@@ -62,11 +65,14 @@ struct file;
#if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000)
# include <sys/proc.h>
#endif
+#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 400000) && \
+ !defined(_KERNEL)
+# include <stdbool.h>
+#endif
#include <net/if.h>
#ifdef sun
# include <net/af.h>
#endif
-#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
@@ -125,71 +131,249 @@ static const char rcsid[] = "@(#)$FreeBSD$";
#endif
+
+typedef struct ipf_auth_softc_s {
#if SOLARIS && defined(_KERNEL)
-extern kcondvar_t ipfauthwait;
-extern struct pollhead iplpollhead[IPL_LOGSIZE];
+ kcondvar_t ipf_auth_wait;
#endif /* SOLARIS */
#if defined(linux) && defined(_KERNEL)
-wait_queue_head_t fr_authnext_linux;
+ wait_queue_head_t ipf_auth_next_linux;
#endif
+ ipfrwlock_t ipf_authlk;
+ ipfmutex_t ipf_auth_mx;
+ int ipf_auth_size;
+ int ipf_auth_used;
+ int ipf_auth_replies;
+ int ipf_auth_defaultage;
+ int ipf_auth_lock;
+ ipf_authstat_t ipf_auth_stats;
+ frauth_t *ipf_auth;
+ mb_t **ipf_auth_pkts;
+ int ipf_auth_start;
+ int ipf_auth_end;
+ int ipf_auth_next;
+ frauthent_t *ipf_auth_entries;
+ frentry_t *ipf_auth_ip;
+ frentry_t *ipf_auth_rules;
+} ipf_auth_softc_t;
+
+
+static void ipf_auth_deref __P((frauthent_t **));
+static void ipf_auth_deref_unlocked __P((ipf_auth_softc_t *, frauthent_t **));
+static int ipf_auth_geniter __P((ipf_main_softc_t *, ipftoken_t *,
+ ipfgeniter_t *, ipfobj_t *));
+static int ipf_auth_reply __P((ipf_main_softc_t *, ipf_auth_softc_t *, char *));
+static int ipf_auth_wait __P((ipf_main_softc_t *, ipf_auth_softc_t *, char *));
+static int ipf_auth_flush __P((void *));
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_auth_main_load */
+/* Returns: int - 0 == success, else error */
+/* Parameters: None */
+/* */
+/* A null-op function that exists as a placeholder so that the flow in */
+/* other functions is obvious. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_auth_main_load()
+{
+ return 0;
+}
-int fr_authsize = FR_NUMAUTH;
-int fr_authused = 0;
-int fr_defaultauthage = 600;
-int fr_auth_lock = 0;
-int fr_auth_init = 0;
-fr_authstat_t fr_authstats;
-static frauth_t *fr_auth = NULL;
-mb_t **fr_authpkts = NULL;
-int fr_authstart = 0, fr_authend = 0, fr_authnext = 0;
-frauthent_t *fae_list = NULL;
-frentry_t *ipauth = NULL,
- *fr_authlist = NULL;
-
-void fr_authderef __P((frauthent_t **));
-int fr_authgeniter __P((ipftoken_t *, ipfgeniter_t *));
-int fr_authreply __P((char *));
-int fr_authwait __P((char *));
/* ------------------------------------------------------------------------ */
-/* Function: fr_authinit */
+/* Function: ipf_auth_main_unload */
/* Returns: int - 0 == success, else error */
/* Parameters: None */
/* */
+/* A null-op function that exists as a placeholder so that the flow in */
+/* other functions is obvious. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_auth_main_unload()
+{
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_auth_soft_create */
+/* Returns: int - NULL = failure, else success */
+/* Parameters: softc(I) - pointer to soft context data */
+/* */
+/* Create a structre to store all of the run-time data for packet auth in */
+/* and initialise some fields to their defaults. */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_auth_soft_create(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_auth_softc_t *softa;
+
+ KMALLOC(softa, ipf_auth_softc_t *);
+ if (softa == NULL)
+ return NULL;
+
+ bzero((char *)softa, sizeof(*softa));
+
+ softa->ipf_auth_size = FR_NUMAUTH;
+ softa->ipf_auth_defaultage = 600;
+
+ RWLOCK_INIT(&softa->ipf_authlk, "ipf IP User-Auth rwlock");
+ MUTEX_INIT(&softa->ipf_auth_mx, "ipf auth log mutex");
+#if SOLARIS && defined(_KERNEL)
+ cv_init(&softa->ipf_auth_wait, "ipf auth condvar", CV_DRIVER, NULL);
+#endif
+
+ return softa;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_auth_soft_init */
+/* Returns: int - 0 == success, else error */
+/* Parameters: softc(I) - pointer to soft context data */
+/* arg(I) - opaque pointer to auth context data */
+/* */
/* Allocate memory and initialise data structures used in handling auth */
/* rules. */
/* ------------------------------------------------------------------------ */
-int fr_authinit()
+int
+ipf_auth_soft_init(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
{
- KMALLOCS(fr_auth, frauth_t *, fr_authsize * sizeof(*fr_auth));
- if (fr_auth != NULL)
- bzero((char *)fr_auth, fr_authsize * sizeof(*fr_auth));
- else
+ ipf_auth_softc_t *softa = arg;
+
+ KMALLOCS(softa->ipf_auth, frauth_t *,
+ softa->ipf_auth_size * sizeof(*softa->ipf_auth));
+ if (softa->ipf_auth == NULL)
return -1;
+ bzero((char *)softa->ipf_auth,
+ softa->ipf_auth_size * sizeof(*softa->ipf_auth));
- KMALLOCS(fr_authpkts, mb_t **, fr_authsize * sizeof(*fr_authpkts));
- if (fr_authpkts != NULL)
- bzero((char *)fr_authpkts, fr_authsize * sizeof(*fr_authpkts));
- else
+ KMALLOCS(softa->ipf_auth_pkts, mb_t **,
+ softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts));
+ if (softa->ipf_auth_pkts == NULL)
return -2;
+ bzero((char *)softa->ipf_auth_pkts,
+ softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts));
- MUTEX_INIT(&ipf_authmx, "ipf auth log mutex");
- RWLOCK_INIT(&ipf_auth, "ipf IP User-Auth rwlock");
-#if SOLARIS && defined(_KERNEL)
- cv_init(&ipfauthwait, "ipf auth condvar", CV_DRIVER, NULL);
-#endif
#if defined(linux) && defined(_KERNEL)
- init_waitqueue_head(&fr_authnext_linux);
+ init_waitqueue_head(&softa->ipf_auth_next_linux);
#endif
- fr_auth_init = 1;
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_auth_soft_fini */
+/* Returns: int - 0 == success, else error */
+/* Parameters: softc(I) - pointer to soft context data */
+/* arg(I) - opaque pointer to auth context data */
+/* */
+/* Free all network buffer memory used to keep saved packets that have been */
+/* connectedd to the soft soft context structure *but* do not free that: it */
+/* is free'd by _destroy(). */
+/* ------------------------------------------------------------------------ */
+int
+ipf_auth_soft_fini(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_auth_softc_t *softa = arg;
+ frauthent_t *fae, **faep;
+ frentry_t *fr, **frp;
+ mb_t *m;
+ int i;
+
+ if (softa->ipf_auth != NULL) {
+ KFREES(softa->ipf_auth,
+ softa->ipf_auth_size * sizeof(*softa->ipf_auth));
+ softa->ipf_auth = NULL;
+ }
+
+ if (softa->ipf_auth_pkts != NULL) {
+ for (i = 0; i < softa->ipf_auth_size; i++) {
+ m = softa->ipf_auth_pkts[i];
+ if (m != NULL) {
+ FREE_MB_T(m);
+ softa->ipf_auth_pkts[i] = NULL;
+ }
+ }
+ KFREES(softa->ipf_auth_pkts,
+ softa->ipf_auth_size * sizeof(*softa->ipf_auth_pkts));
+ softa->ipf_auth_pkts = NULL;
+ }
+
+ faep = &softa->ipf_auth_entries;
+ while ((fae = *faep) != NULL) {
+ *faep = fae->fae_next;
+ KFREE(fae);
+ }
+ softa->ipf_auth_ip = NULL;
+
+ if (softa->ipf_auth_rules != NULL) {
+ for (frp = &softa->ipf_auth_rules; ((fr = *frp) != NULL); ) {
+ if (fr->fr_ref == 1) {
+ *frp = fr->fr_next;
+ MUTEX_DESTROY(&fr->fr_lock);
+ KFREE(fr);
+ } else
+ frp = &fr->fr_next;
+ }
+ }
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_checkauth */
+/* Function: ipf_auth_soft_destroy */
+/* Returns: void */
+/* Parameters: softc(I) - pointer to soft context data */
+/* arg(I) - opaque pointer to auth context data */
+/* */
+/* Undo what was done in _create() - i.e. free the soft context data. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_auth_soft_destroy(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_auth_softc_t *softa = arg;
+
+# if SOLARIS && defined(_KERNEL)
+ cv_destroy(&softa->ipf_auth_wait);
+# endif
+ MUTEX_DESTROY(&softa->ipf_auth_mx);
+ RW_DESTROY(&softa->ipf_authlk);
+
+ KFREE(softa);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_auth_setlock */
+/* Returns: void */
+/* Paramters: arg(I) - pointer to soft context data */
+/* tmp(I) - value to assign to auth lock */
+/* */
+/* ------------------------------------------------------------------------ */
+void
+ipf_auth_setlock(arg, tmp)
+ void *arg;
+ int tmp;
+{
+ ipf_auth_softc_t *softa = arg;
+
+ softa->ipf_auth_lock = tmp;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_auth_check */
/* Returns: frentry_t* - pointer to ipf rule if match found, else NULL */
/* Parameters: fin(I) - pointer to ipftoken structure */
/* passp(I) - pointer to ipfgeniter structure */
@@ -198,10 +382,13 @@ int fr_authinit()
/* authorization result and that would result in a feedback loop (i.e. it */
/* will end up returning FR_AUTH) then return FR_BLOCK instead. */
/* ------------------------------------------------------------------------ */
-frentry_t *fr_checkauth(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+frentry_t *
+ipf_auth_check(fin, passp)
+ fr_info_t *fin;
+ u_32_t *passp;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_auth_softc_t *softa = softc->ipf_auth_soft;
frentry_t *fr;
frauth_t *fra;
u_32_t pass;
@@ -209,27 +396,29 @@ u_32_t *passp;
ip_t *ip;
int i;
- if (fr_auth_lock || !fr_authused)
+ if (softa->ipf_auth_lock || !softa->ipf_auth_used)
return NULL;
ip = fin->fin_ip;
id = ip->ip_id;
- READ_ENTER(&ipf_auth);
- for (i = fr_authstart; i != fr_authend; ) {
+ READ_ENTER(&softa->ipf_authlk);
+ for (i = softa->ipf_auth_start; i != softa->ipf_auth_end; ) {
/*
* index becomes -2 only after an SIOCAUTHW. Check this in
* case the same packet gets sent again and it hasn't yet been
* auth'd.
*/
- fra = fr_auth + i;
+ fra = softa->ipf_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 = fra->fra_pass) || (FR_ISAUTH(pass)))
+ if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) {
pass = FR_BLOCK;
+ fin->fin_reason = FRB_AUTHFEEDBACK;
+ }
/*
* Create a dummy rule for the stateful checking to
* use and return. Zero out any values we don't
@@ -249,60 +438,65 @@ u_32_t *passp;
fr->fr_ifas[1] = NULL;
fr->fr_ifas[2] = NULL;
fr->fr_ifas[3] = NULL;
+ MUTEX_INIT(&fr->fr_lock,
+ "ipf auth rule");
}
} else
fr = fra->fra_info.fin_fr;
fin->fin_fr = fr;
- RWLOCK_EXIT(&ipf_auth);
+ fin->fin_flx |= fra->fra_flx;
+ RWLOCK_EXIT(&softa->ipf_authlk);
- WRITE_ENTER(&ipf_auth);
+ WRITE_ENTER(&softa->ipf_authlk);
/*
- * fr_authlist is populated with the rules malloc'd
+ * ipf_auth_rules is populated with the rules malloc'd
* above and only those.
*/
if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) {
- fr->fr_next = fr_authlist;
- fr_authlist = fr;
+ fr->fr_next = softa->ipf_auth_rules;
+ softa->ipf_auth_rules = fr;
}
- fr_authstats.fas_hits++;
+ softa->ipf_auth_stats.fas_hits++;
fra->fra_index = -1;
- fr_authused--;
- if (i == fr_authstart) {
+ softa->ipf_auth_used--;
+ softa->ipf_auth_replies--;
+ if (i == softa->ipf_auth_start) {
while (fra->fra_index == -1) {
i++;
fra++;
- if (i == fr_authsize) {
+ if (i == softa->ipf_auth_size) {
i = 0;
- fra = fr_auth;
+ fra = softa->ipf_auth;
}
- fr_authstart = i;
- if (i == fr_authend)
+ softa->ipf_auth_start = i;
+ if (i == softa->ipf_auth_end)
break;
}
- if (fr_authstart == fr_authend) {
- fr_authnext = 0;
- fr_authstart = fr_authend = 0;
+ if (softa->ipf_auth_start ==
+ softa->ipf_auth_end) {
+ softa->ipf_auth_next = 0;
+ softa->ipf_auth_start = 0;
+ softa->ipf_auth_end = 0;
}
}
- RWLOCK_EXIT(&ipf_auth);
+ RWLOCK_EXIT(&softa->ipf_authlk);
if (passp != NULL)
*passp = pass;
- ATOMIC_INC64(fr_authstats.fas_hits);
+ softa->ipf_auth_stats.fas_hits++;
return fr;
}
i++;
- if (i == fr_authsize)
+ if (i == softa->ipf_auth_size)
i = 0;
}
- fr_authstats.fas_miss++;
- RWLOCK_EXIT(&ipf_auth);
- ATOMIC_INC64(fr_authstats.fas_miss);
+ RWLOCK_EXIT(&softa->ipf_authlk);
+ softa->ipf_auth_stats.fas_miss++;
return NULL;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_newauth */
+/* Function: ipf_auth_new */
/* Returns: int - 1 == success, 0 = did not put packet on auth queue */
/* Parameters: m(I) - pointer to mb_t with packet in it */
/* fin(I) - pointer to packet information */
@@ -311,10 +505,13 @@ u_32_t *passp;
/* packet. If we do, store it and wake up any user programs which are */
/* waiting to hear about these events. */
/* ------------------------------------------------------------------------ */
-int fr_newauth(m, fin)
-mb_t *m;
-fr_info_t *fin;
+int
+ipf_auth_new(m, fin)
+ mb_t *m;
+ fr_info_t *fin;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_auth_softc_t *softa = softc->ipf_auth_soft;
#if defined(_KERNEL) && defined(MENTAT)
qpktinfo_t *qpi = fin->fin_qpi;
#endif
@@ -324,31 +521,33 @@ fr_info_t *fin;
#endif
int i;
- if (fr_auth_lock)
+ if (softa->ipf_auth_lock)
return 0;
- WRITE_ENTER(&ipf_auth);
- if (((fr_authend + 1) % fr_authsize) == fr_authstart) {
- fr_authstats.fas_nospace++;
- RWLOCK_EXIT(&ipf_auth);
+ WRITE_ENTER(&softa->ipf_authlk);
+ if (((softa->ipf_auth_end + 1) % softa->ipf_auth_size) ==
+ softa->ipf_auth_start) {
+ softa->ipf_auth_stats.fas_nospace++;
+ RWLOCK_EXIT(&softa->ipf_authlk);
return 0;
}
- fr_authstats.fas_added++;
- fr_authused++;
- i = fr_authend++;
- if (fr_authend == fr_authsize)
- fr_authend = 0;
- fra = fr_auth + i;
- fra->fra_index = i;
- RWLOCK_EXIT(&ipf_auth);
+ softa->ipf_auth_stats.fas_added++;
+ softa->ipf_auth_used++;
+ i = softa->ipf_auth_end++;
+ if (softa->ipf_auth_end == softa->ipf_auth_size)
+ softa->ipf_auth_end = 0;
+ fra = softa->ipf_auth + i;
+ fra->fra_index = i;
if (fin->fin_fr != NULL)
fra->fra_pass = fin->fin_fr->fr_flags;
else
fra->fra_pass = 0;
- fra->fra_age = fr_defaultauthage;
+ fra->fra_age = softa->ipf_auth_defaultage;
bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin));
+ fra->fra_flx = fra->fra_info.fin_flx & (FI_STATE|FI_NATED);
+ fra->fra_info.fin_flx &= ~(FI_STATE|FI_NATED);
#if !defined(sparc) && !defined(m68k)
/*
* No need to copyback here as we want to undo the changes, not keep
@@ -370,24 +569,24 @@ fr_info_t *fin;
#if SOLARIS && defined(_KERNEL)
COPYIFNAME(fin->fin_v, fin->fin_ifp, fra->fra_info.fin_ifname);
m->b_rptr -= qpi->qpi_off;
- fr_authpkts[i] = *(mblk_t **)fin->fin_mp;
-# if !defined(_INET_IP_STACK_H)
fra->fra_q = qpi->qpi_q; /* The queue can disappear! */
-# endif
fra->fra_m = *fin->fin_mp;
fra->fra_info.fin_mp = &fra->fra_m;
- cv_signal(&ipfauthwait);
- pollwakeup(&iplpollhead[IPL_LOGAUTH], POLLIN|POLLRDNORM);
+ softa->ipf_auth_pkts[i] = *(mblk_t **)fin->fin_mp;
+ RWLOCK_EXIT(&softa->ipf_authlk);
+ cv_signal(&softa->ipf_auth_wait);
+ pollwakeup(&softc->ipf_poll_head[IPL_LOGAUTH], POLLIN|POLLRDNORM);
#else
- fr_authpkts[i] = m;
- WAKEUP(&fr_authnext,0);
+ softa->ipf_auth_pkts[i] = m;
+ RWLOCK_EXIT(&softa->ipf_authlk);
+ WAKEUP(&softa->ipf_auth_next, 0);
#endif
return 1;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_auth_ioctl */
+/* Function: ipf_auth_ioctl */
/* Returns: int - 0 == success, else error */
/* Parameters: data(IO) - pointer to ioctl data */
/* cmd(I) - ioctl command */
@@ -396,14 +595,17 @@ fr_info_t *fin;
/* ctx(I) - pointer for context */
/* */
/* This function handles all of the ioctls recognised by the auth component */
-/* in IPFilter - ie ioctls called on an open fd for /dev/ipauth */
+/* in IPFilter - ie ioctls called on an open fd for /dev/ipf_auth */
/* ------------------------------------------------------------------------ */
-int fr_auth_ioctl(data, cmd, mode, uid, ctx)
-caddr_t data;
-ioctlcmd_t cmd;
-int mode, uid;
-void *ctx;
+int
+ipf_auth_ioctl(softc, data, cmd, mode, uid, ctx)
+ ipf_main_softc_t *softc;
+ caddr_t data;
+ ioctlcmd_t cmd;
+ int mode, uid;
+ void *ctx;
{
+ ipf_auth_softc_t *softa = softc->ipf_auth_soft;
int error = 0, i;
SPL_INT(s);
@@ -413,18 +615,23 @@ void *ctx;
{
ipftoken_t *token;
ipfgeniter_t iter;
+ ipfobj_t obj;
- error = fr_inobj(data, &iter, IPFOBJ_GENITER);
+ error = ipf_inobj(softc, data, &obj, &iter, IPFOBJ_GENITER);
if (error != 0)
break;
SPL_SCHED(s);
- token = ipf_findtoken(IPFGENITER_AUTH, uid, ctx);
+ token = ipf_token_find(softc, IPFGENITER_AUTH, uid, ctx);
if (token != NULL)
- error = fr_authgeniter(token, &iter);
- else
+ error = ipf_auth_geniter(softc, token, &iter, &obj);
+ else {
+ WRITE_ENTER(&softc->ipf_tokens);
+ ipf_token_deref(softc, token);
+ RWLOCK_EXIT(&softc->ipf_tokens);
+ IPFERROR(10001);
error = ESRCH;
- RWLOCK_EXIT(&ipf_tokens);
+ }
SPL_X(s);
break;
@@ -432,46 +639,52 @@ void *ctx;
case SIOCADAFR :
case SIOCRMAFR :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(10002);
error = EPERM;
- else
- error = frrequest(IPL_LOGAUTH, cmd, data,
- fr_active, 1);
+ } else
+ error = frrequest(softc, IPL_LOGAUTH, cmd, data,
+ softc->ipf_active, 1);
break;
case SIOCSTLCK :
if (!(mode & FWRITE)) {
+ IPFERROR(10003);
error = EPERM;
- break;
+ } else {
+ error = ipf_lock(data, &softa->ipf_auth_lock);
}
- error = fr_lock(data, &fr_auth_lock);
break;
case SIOCATHST:
- fr_authstats.fas_faelist = fae_list;
- error = fr_outobj(data, &fr_authstats, IPFOBJ_AUTHSTAT);
+ softa->ipf_auth_stats.fas_faelist = softa->ipf_auth_entries;
+ error = ipf_outobj(softc, data, &softa->ipf_auth_stats,
+ IPFOBJ_AUTHSTAT);
break;
case SIOCIPFFL:
SPL_NET(s);
- WRITE_ENTER(&ipf_auth);
- i = fr_authflush();
- RWLOCK_EXIT(&ipf_auth);
+ WRITE_ENTER(&softa->ipf_authlk);
+ i = ipf_auth_flush(softa);
+ RWLOCK_EXIT(&softa->ipf_authlk);
SPL_X(s);
- error = BCOPYOUT((char *)&i, data, sizeof(i));
- if (error != 0)
+ error = BCOPYOUT(&i, data, sizeof(i));
+ if (error != 0) {
+ IPFERROR(10004);
error = EFAULT;
+ }
break;
case SIOCAUTHW:
- error = fr_authwait(data);
+ error = ipf_auth_wait(softc, softa, data);
break;
case SIOCAUTHR:
- error = fr_authreply(data);
+ error = ipf_auth_reply(softc, softa, data);
break;
default :
+ IPFERROR(10005);
error = EINVAL;
break;
}
@@ -480,75 +693,18 @@ void *ctx;
/* ------------------------------------------------------------------------ */
-/* Function: fr_authunload */
-/* Returns: None */
-/* Parameters: None */
-/* */
-/* Free all network buffer memory used to keep saved packets. */
-/* ------------------------------------------------------------------------ */
-void fr_authunload()
-{
- register int i;
- register frauthent_t *fae, **faep;
- frentry_t *fr, **frp;
- mb_t *m;
-
- if (fr_auth != NULL) {
- KFREES(fr_auth, fr_authsize * sizeof(*fr_auth));
- fr_auth = NULL;
- }
-
- if (fr_authpkts != NULL) {
- for (i = 0; i < fr_authsize; i++) {
- m = fr_authpkts[i];
- if (m != NULL) {
- FREE_MB_T(m);
- fr_authpkts[i] = NULL;
- }
- }
- KFREES(fr_authpkts, fr_authsize * sizeof(*fr_authpkts));
- fr_authpkts = NULL;
- }
-
- faep = &fae_list;
- while ((fae = *faep) != NULL) {
- *faep = fae->fae_next;
- KFREE(fae);
- }
- ipauth = NULL;
-
- if (fr_authlist != NULL) {
- for (frp = &fr_authlist; ((fr = *frp) != NULL); ) {
- if (fr->fr_ref == 1) {
- *frp = fr->fr_next;
- KFREE(fr);
- } else
- frp = &fr->fr_next;
- }
- }
-
- if (fr_auth_init == 1) {
-# if SOLARIS && defined(_KERNEL)
- cv_destroy(&ipfauthwait);
-# endif
- MUTEX_DESTROY(&ipf_authmx);
- RW_DESTROY(&ipf_auth);
-
- fr_auth_init = 0;
- }
-}
-
-
-/* ------------------------------------------------------------------------ */
-/* Function: fr_authexpire */
+/* Function: ipf_auth_expire */
/* Returns: None */
/* Parameters: None */
/* */
/* Slowly expire held auth records. Timeouts are set in expectation of */
/* this being called twice per second. */
/* ------------------------------------------------------------------------ */
-void fr_authexpire()
+void
+ipf_auth_expire(softc)
+ ipf_main_softc_t *softc;
{
+ ipf_auth_softc_t *softa = softc->ipf_auth_soft;
frauthent_t *fae, **faep;
frentry_t *fr, **frp;
frauth_t *fra;
@@ -556,70 +712,81 @@ void fr_authexpire()
int i;
SPL_INT(s);
- if (fr_auth_lock)
+ if (softa->ipf_auth_lock)
return;
-
SPL_NET(s);
- WRITE_ENTER(&ipf_auth);
- for (i = 0, fra = fr_auth; i < fr_authsize; i++, fra++) {
+ WRITE_ENTER(&softa->ipf_authlk);
+ for (i = 0, fra = softa->ipf_auth; i < softa->ipf_auth_size;
+ i++, fra++) {
fra->fra_age--;
- if ((fra->fra_age == 0) && (m = fr_authpkts[i])) {
- FREE_MB_T(m);
- fr_authpkts[i] = NULL;
- fr_auth[i].fra_index = -1;
- fr_authstats.fas_expire++;
- fr_authused--;
+ if ((fra->fra_age == 0) &&
+ (softa->ipf_auth[i].fra_index != -1)) {
+ if ((m = softa->ipf_auth_pkts[i]) != NULL) {
+ FREE_MB_T(m);
+ softa->ipf_auth_pkts[i] = NULL;
+ } else if (softa->ipf_auth[i].fra_index == -2) {
+ softa->ipf_auth_replies--;
+ }
+ softa->ipf_auth[i].fra_index = -1;
+ softa->ipf_auth_stats.fas_expire++;
+ softa->ipf_auth_used--;
}
}
/*
* Expire pre-auth rules
*/
- for (faep = &fae_list; ((fae = *faep) != NULL); ) {
+ for (faep = &softa->ipf_auth_entries; ((fae = *faep) != NULL); ) {
fae->fae_age--;
if (fae->fae_age == 0) {
- fr_authderef(&fae);
- fr_authstats.fas_expire++;
+ ipf_auth_deref(&fae);
+ softa->ipf_auth_stats.fas_expire++;
} else
faep = &fae->fae_next;
}
- if (fae_list != NULL)
- ipauth = &fae_list->fae_fr;
+ if (softa->ipf_auth_entries != NULL)
+ softa->ipf_auth_ip = &softa->ipf_auth_entries->fae_fr;
else
- ipauth = NULL;
+ softa->ipf_auth_ip = NULL;
- for (frp = &fr_authlist; ((fr = *frp) != NULL); ) {
+ for (frp = &softa->ipf_auth_rules; ((fr = *frp) != NULL); ) {
if (fr->fr_ref == 1) {
*frp = fr->fr_next;
+ MUTEX_DESTROY(&fr->fr_lock);
KFREE(fr);
} else
frp = &fr->fr_next;
}
- RWLOCK_EXIT(&ipf_auth);
+ RWLOCK_EXIT(&softa->ipf_authlk);
SPL_X(s);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_preauthcmd */
+/* Function: ipf_auth_precmd */
/* Returns: int - 0 == success, else error */
/* Parameters: cmd(I) - ioctl command for rule */
/* fr(I) - pointer to ipf rule */
/* fptr(I) - pointer to caller's 'fr' */
/* */
/* ------------------------------------------------------------------------ */
-int fr_preauthcmd(cmd, fr, frptr)
-ioctlcmd_t cmd;
-frentry_t *fr, **frptr;
+int
+ipf_auth_precmd(softc, cmd, fr, frptr)
+ ipf_main_softc_t *softc;
+ ioctlcmd_t cmd;
+ frentry_t *fr, **frptr;
{
+ ipf_auth_softc_t *softa = softc->ipf_auth_soft;
frauthent_t *fae, **faep;
int error = 0;
SPL_INT(s);
- if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR))
+ if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) {
+ IPFERROR(10006);
return EIO;
+ }
- for (faep = &fae_list; ((fae = *faep) != NULL); ) {
+ for (faep = &softa->ipf_auth_entries; ((fae = *faep) != NULL); ) {
if (&fae->fae_fr == fr)
break;
else
@@ -627,17 +794,22 @@ frentry_t *fr, **frptr;
}
if (cmd == (ioctlcmd_t)SIOCRMAFR) {
- if (fr == NULL || frptr == NULL)
+ if (fr == NULL || frptr == NULL) {
+ IPFERROR(10007);
error = EINVAL;
- else if (fae == NULL)
+
+ } else if (fae == NULL) {
+ IPFERROR(10008);
error = ESRCH;
- else {
+
+ } else {
SPL_NET(s);
- WRITE_ENTER(&ipf_auth);
+ WRITE_ENTER(&softa->ipf_authlk);
*faep = fae->fae_next;
- if (ipauth == &fae->fae_fr)
- ipauth = fae_list ? &fae_list->fae_fr : NULL;
- RWLOCK_EXIT(&ipf_auth);
+ if (softa->ipf_auth_ip == &fae->fae_fr)
+ softa->ipf_auth_ip = softa->ipf_auth_entries ?
+ &softa->ipf_auth_entries->fae_fr : NULL;
+ RWLOCK_EXIT(&softa->ipf_authlk);
SPL_X(s);
KFREE(fae);
@@ -648,161 +820,199 @@ frentry_t *fr, **frptr;
bcopy((char *)fr, (char *)&fae->fae_fr,
sizeof(*fr));
SPL_NET(s);
- WRITE_ENTER(&ipf_auth);
- fae->fae_age = fr_defaultauthage;
+ WRITE_ENTER(&softa->ipf_authlk);
+ fae->fae_age = softa->ipf_auth_defaultage;
fae->fae_fr.fr_hits = 0;
fae->fae_fr.fr_next = *frptr;
fae->fae_ref = 1;
*frptr = &fae->fae_fr;
fae->fae_next = *faep;
*faep = fae;
- ipauth = &fae_list->fae_fr;
- RWLOCK_EXIT(&ipf_auth);
+ softa->ipf_auth_ip = &softa->ipf_auth_entries->fae_fr;
+ RWLOCK_EXIT(&softa->ipf_authlk);
SPL_X(s);
- } else
+ } else {
+ IPFERROR(10009);
error = ENOMEM;
- } else
+ }
+ } else {
+ IPFERROR(10010);
error = EINVAL;
+ }
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_authflush */
+/* Function: ipf_auth_flush */
/* Returns: int - number of auth entries flushed */
/* Parameters: None */
-/* Locks: WRITE(ipf_auth) */
+/* Locks: WRITE(ipf_authlk) */
/* */
-/* This function flushs the fr_authpkts array of any packet data with */
+/* This function flushs the ipf_auth_pkts array of any packet data with */
/* references still there. */
/* It is expected that the caller has already acquired the correct locks or */
/* set the priority level correctly for this to block out other code paths */
/* into these data structures. */
/* ------------------------------------------------------------------------ */
-int fr_authflush()
+static int
+ipf_auth_flush(arg)
+ void *arg;
{
- register int i, num_flushed;
+ ipf_auth_softc_t *softa = arg;
+ int i, num_flushed;
mb_t *m;
- if (fr_auth_lock)
+ if (softa->ipf_auth_lock)
return -1;
num_flushed = 0;
- for (i = 0 ; i < fr_authsize; i++) {
- m = fr_authpkts[i];
- if (m != NULL) {
- FREE_MB_T(m);
- fr_authpkts[i] = NULL;
- fr_auth[i].fra_index = -1;
+ for (i = 0 ; i < softa->ipf_auth_size; i++) {
+ if (softa->ipf_auth[i].fra_index != -1) {
+ m = softa->ipf_auth_pkts[i];
+ if (m != NULL) {
+ FREE_MB_T(m);
+ softa->ipf_auth_pkts[i] = NULL;
+ }
+
+ softa->ipf_auth[i].fra_index = -1;
/* perhaps add & use a flush counter inst.*/
- fr_authstats.fas_expire++;
- fr_authused--;
+ softa->ipf_auth_stats.fas_expire++;
num_flushed++;
}
}
- fr_authstart = 0;
- fr_authend = 0;
- fr_authnext = 0;
+ softa->ipf_auth_start = 0;
+ softa->ipf_auth_end = 0;
+ softa->ipf_auth_next = 0;
+ softa->ipf_auth_used = 0;
+ softa->ipf_auth_replies = 0;
return num_flushed;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_auth_waiting */
-/* Returns: int - 0 = no packets waiting, 1 = packets waiting. */
+/* Function: ipf_auth_waiting */
+/* Returns: int - number of packets in the auth queue */
/* Parameters: None */
/* */
/* Simple truth check to see if there are any packets waiting in the auth */
/* queue. */
/* ------------------------------------------------------------------------ */
-int fr_auth_waiting()
+int
+ipf_auth_waiting(softc)
+ ipf_main_softc_t *softc;
{
- return (fr_authused != 0);
+ ipf_auth_softc_t *softa = softc->ipf_auth_soft;
+
+ return (softa->ipf_auth_used != 0);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_authgeniter */
+/* Function: ipf_auth_geniter */
/* Returns: int - 0 == success, else error */
/* Parameters: token(I) - pointer to ipftoken structure */
/* itp(I) - pointer to ipfgeniter structure */
+/* objp(I) - pointer to ipf object destription */
/* */
+/* Iterate through the list of entries in the auth queue list. */
+/* objp is used here to get the location of where to do the copy out to. */
+/* Stomping over various fields with new information will not harm anything */
/* ------------------------------------------------------------------------ */
-int fr_authgeniter(token, itp)
-ipftoken_t *token;
-ipfgeniter_t *itp;
+static int
+ipf_auth_geniter(softc, token, itp, objp)
+ ipf_main_softc_t *softc;
+ ipftoken_t *token;
+ ipfgeniter_t *itp;
+ ipfobj_t *objp;
{
+ ipf_auth_softc_t *softa = softc->ipf_auth_soft;
frauthent_t *fae, *next, zero;
int error;
- if (itp->igi_data == NULL)
+ if (itp->igi_data == NULL) {
+ IPFERROR(10011);
return EFAULT;
+ }
- if (itp->igi_type != IPFGENITER_AUTH)
+ if (itp->igi_type != IPFGENITER_AUTH) {
+ IPFERROR(10012);
return EINVAL;
+ }
+
+ objp->ipfo_type = IPFOBJ_FRAUTH;
+ objp->ipfo_ptr = itp->igi_data;
+ objp->ipfo_size = sizeof(frauth_t);
+
+ READ_ENTER(&softa->ipf_authlk);
fae = token->ipt_data;
- READ_ENTER(&ipf_auth);
if (fae == NULL) {
- next = fae_list;
+ next = softa->ipf_auth_entries;
} else {
next = fae->fae_next;
}
+ /*
+ * If we found an auth entry to use, bump its reference count
+ * so that it can be used for is_next when we come back.
+ */
if (next != NULL) {
- /*
- * If we find an auth entry to use, bump its reference count
- * so that it can be used for is_next when we come back.
- */
ATOMIC_INC(next->fae_ref);
- if (next->fae_next == NULL) {
- ipf_freetoken(token);
- token = NULL;
- } else {
- token->ipt_data = next;
- }
+ token->ipt_data = next;
} else {
bzero(&zero, sizeof(zero));
next = &zero;
+ token->ipt_data = NULL;
}
- RWLOCK_EXIT(&ipf_auth);
- /*
- * If we had a prior pointer to an auth entry, release it.
- */
- if (fae != NULL) {
- WRITE_ENTER(&ipf_auth);
- fr_authderef(&fae);
- RWLOCK_EXIT(&ipf_auth);
- }
+ RWLOCK_EXIT(&softa->ipf_authlk);
- /*
- * This should arguably be via fr_outobj() so that the auth
- * structure can (if required) be massaged going out.
- */
- error = COPYOUT(next, itp->igi_data, sizeof(*next));
- if (error != 0)
- error = EFAULT;
+ error = ipf_outobjk(softc, objp, next);
+ if (fae != NULL)
+ ipf_auth_deref_unlocked(softa, &fae);
+ if (next->fae_next == NULL)
+ ipf_token_mark_complete(token);
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_authderef */
+/* Function: ipf_auth_deref_unlocked */
/* Returns: None */
/* Parameters: faep(IO) - pointer to caller's frauthent_t pointer */
-/* Locks: WRITE(ipf_auth) */
+/* */
+/* Wrapper for ipf_auth_deref for when a write lock on ipf_authlk is not */
+/* held. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_auth_deref_unlocked(softa, faep)
+ ipf_auth_softc_t *softa;
+ frauthent_t **faep;
+{
+ WRITE_ENTER(&softa->ipf_authlk);
+ ipf_auth_deref(faep);
+ RWLOCK_EXIT(&softa->ipf_authlk);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_auth_deref */
+/* Returns: None */
+/* Parameters: faep(IO) - pointer to caller's frauthent_t pointer */
+/* Locks: WRITE(ipf_authlk) */
/* */
/* This function unconditionally sets the pointer in the caller to NULL, */
/* to make it clear that it should no longer use that pointer, and drops */
/* the reference count on the structure by 1. If it reaches 0, free it up. */
/* ------------------------------------------------------------------------ */
-void fr_authderef(faep)
-frauthent_t **faep;
+static void
+ipf_auth_deref(faep)
+ frauthent_t **faep;
{
frauthent_t *fae;
@@ -817,30 +1027,30 @@ frauthent_t **faep;
/* ------------------------------------------------------------------------ */
-/* Function: fr_authwait */
+/* Function: ipf_auth_wait_pkt */
/* Returns: int - 0 == success, else error */
/* Parameters: data(I) - pointer to data from ioctl call */
/* */
/* This function is called when an application is waiting for a packet to */
/* match an "auth" rule by issuing an SIOCAUTHW ioctl. If there is already */
/* a packet waiting on the queue then we will return that _one_ immediately.*/
-/* If there are no packets present in the queue (fr_authpkts) then we go to */
-/* sleep. */
+/* If there are no packets present in the queue (ipf_auth_pkts) then we go */
+/* to sleep. */
/* ------------------------------------------------------------------------ */
-int fr_authwait(data)
-char *data;
+static int
+ipf_auth_wait(softc, softa, data)
+ ipf_main_softc_t *softc;
+ ipf_auth_softc_t *softa;
+ char *data;
{
frauth_t auth, *au = &auth;
int error, len, i;
mb_t *m;
char *t;
-#if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \
- (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000))
SPL_INT(s);
-#endif
-fr_authioctlloop:
- error = fr_inobj(data, au, IPFOBJ_FRAUTH);
+ipf_auth_ioctlloop:
+ error = ipf_inobj(softc, data, NULL, au, IPFOBJ_FRAUTH);
if (error != 0)
return error;
@@ -850,30 +1060,36 @@ fr_authioctlloop:
* we are trying to guard against here is an error in the copyout
* steps should not cause the packet to "disappear" from the queue.
*/
- READ_ENTER(&ipf_auth);
+ SPL_NET(s);
+ READ_ENTER(&softa->ipf_authlk);
/*
- * If fr_authnext is not equal to fr_authend it will be because there
- * is a packet waiting to be delt with in the fr_authpkts array. We
- * copy as much of that out to user space as requested.
+ * If ipf_auth_next is not equal to ipf_auth_end it will be because
+ * there is a packet waiting to be delt with in the ipf_auth_pkts
+ * array. We copy as much of that out to user space as requested.
*/
- if (fr_authused > 0) {
- while (fr_authpkts[fr_authnext] == NULL) {
- fr_authnext++;
- if (fr_authnext == fr_authsize)
- fr_authnext = 0;
+ if (softa->ipf_auth_used > 0) {
+ while (softa->ipf_auth_pkts[softa->ipf_auth_next] == NULL) {
+ softa->ipf_auth_next++;
+ if (softa->ipf_auth_next == softa->ipf_auth_size)
+ softa->ipf_auth_next = 0;
}
- error = fr_outobj(data, &fr_auth[fr_authnext], IPFOBJ_FRAUTH);
- if (error != 0)
+ error = ipf_outobj(softc, data,
+ &softa->ipf_auth[softa->ipf_auth_next],
+ IPFOBJ_FRAUTH);
+ if (error != 0) {
+ RWLOCK_EXIT(&softa->ipf_authlk);
+ SPL_X(s);
return error;
+ }
if (auth.fra_len != 0 && auth.fra_buf != NULL) {
/*
* Copy packet contents out to user space if
* requested. Bail on an error.
*/
- m = fr_authpkts[fr_authnext];
+ m = softa->ipf_auth_pkts[softa->ipf_auth_next];
len = MSGDSIZE(m);
if (len > auth.fra_len)
len = auth.fra_len;
@@ -881,62 +1097,69 @@ fr_authioctlloop:
for (t = auth.fra_buf; m && (len > 0); ) {
i = MIN(M_LEN(m), len);
- error = copyoutptr(MTOD(m, char *), &t, i);
+ error = copyoutptr(softc, MTOD(m, char *),
+ &t, i);
len -= i;
t += i;
- if (error != 0)
+ if (error != 0) {
+ RWLOCK_EXIT(&softa->ipf_authlk);
+ SPL_X(s);
return error;
+ }
m = m->m_next;
}
}
- RWLOCK_EXIT(&ipf_auth);
+ RWLOCK_EXIT(&softa->ipf_authlk);
SPL_NET(s);
- WRITE_ENTER(&ipf_auth);
- fr_authnext++;
- if (fr_authnext == fr_authsize)
- fr_authnext = 0;
- RWLOCK_EXIT(&ipf_auth);
+ WRITE_ENTER(&softa->ipf_authlk);
+ softa->ipf_auth_next++;
+ if (softa->ipf_auth_next == softa->ipf_auth_size)
+ softa->ipf_auth_next = 0;
+ RWLOCK_EXIT(&softa->ipf_authlk);
SPL_X(s);
return 0;
}
- RWLOCK_EXIT(&ipf_auth);
+ RWLOCK_EXIT(&softa->ipf_authlk);
+ SPL_X(s);
- MUTEX_ENTER(&ipf_authmx);
+ MUTEX_ENTER(&softa->ipf_auth_mx);
#ifdef _KERNEL
# if SOLARIS
error = 0;
- if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk))
+ if (!cv_wait_sig(&softa->ipf_auth_wait, &softa->ipf_auth_mx.ipf_lk)) {
+ IPFERROR(10014);
error = EINTR;
+ }
# else /* SOLARIS */
# ifdef __hpux
{
lock_t *l;
- l = get_sleep_lock(&fr_authnext);
- error = sleep(&fr_authnext, PZERO+1);
+ l = get_sleep_lock(&softa->ipf_auth_next);
+ error = sleep(&softa->ipf_auth_next, PZERO+1);
spinunlock(l);
}
# else
# ifdef __osf__
- error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0,
- &ipf_authmx, MS_LOCK_SIMPLE);
+ error = mpsleep(&softa->ipf_auth_next, PSUSP|PCATCH, "ipf_auth_next",
+ 0, &softa->ipf_auth_mx, MS_LOCK_SIMPLE);
# else
- error = SLEEP(&fr_authnext, "fr_authnext");
+ error = SLEEP(&softa->ipf_auth_next, "ipf_auth_next");
# endif /* __osf__ */
# endif /* __hpux */
# endif /* SOLARIS */
#endif
- MUTEX_EXIT(&ipf_authmx);
+ MUTEX_EXIT(&softa->ipf_auth_mx);
if (error == 0)
- goto fr_authioctlloop;
+ goto ipf_auth_ioctlloop;
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_authreply */
+/* Function: ipf_auth_reply */
/* Returns: int - 0 == success, else error */
/* Parameters: data(I) - pointer to data from ioctl call */
/* */
@@ -945,23 +1168,27 @@ fr_authioctlloop:
/* received information using an SIOCAUTHW. The decision returned in the */
/* form of flags, the same as those used in each rule. */
/* ------------------------------------------------------------------------ */
-int fr_authreply(data)
-char *data;
+static int
+ipf_auth_reply(softc, softa, data)
+ ipf_main_softc_t *softc;
+ ipf_auth_softc_t *softa;
+ char *data;
{
frauth_t auth, *au = &auth, *fra;
+ fr_info_t fin;
int error, i;
mb_t *m;
SPL_INT(s);
- error = fr_inobj(data, &auth, IPFOBJ_FRAUTH);
+ error = ipf_inobj(softc, data, NULL, &auth, IPFOBJ_FRAUTH);
if (error != 0)
return error;
SPL_NET(s);
- WRITE_ENTER(&ipf_auth);
+ WRITE_ENTER(&softa->ipf_authlk);
i = au->fra_index;
- fra = fr_auth + i;
+ fra = softa->ipf_auth + i;
error = 0;
/*
@@ -969,19 +1196,27 @@ char *data;
* checks. First, the auth index value should be within the size of
* the array and second the packet id being returned should also match.
*/
- if ((i < 0) || (i >= fr_authsize) ||
- (fra->fra_info.fin_id != au->fra_info.fin_id)) {
- RWLOCK_EXIT(&ipf_auth);
+ if ((i < 0) || (i >= softa->ipf_auth_size)) {
+ RWLOCK_EXIT(&softa->ipf_authlk);
+ SPL_X(s);
+ IPFERROR(10015);
+ return ESRCH;
+ }
+ if (fra->fra_info.fin_id != au->fra_info.fin_id) {
+ RWLOCK_EXIT(&softa->ipf_authlk);
SPL_X(s);
+ IPFERROR(10019);
return ESRCH;
}
- m = fr_authpkts[i];
+ m = softa->ipf_auth_pkts[i];
fra->fra_index = -2;
fra->fra_pass = au->fra_pass;
- fr_authpkts[i] = NULL;
+ softa->ipf_auth_pkts[i] = NULL;
+ softa->ipf_auth_replies++;
+ bcopy(&fra->fra_info, &fin, sizeof(fin));
- RWLOCK_EXIT(&ipf_auth);
+ RWLOCK_EXIT(&softa->ipf_authlk);
/*
* Re-insert the packet back into the packet stream flowing through
@@ -992,22 +1227,25 @@ char *data;
*/
#ifdef _KERNEL
if ((m != NULL) && (au->fra_info.fin_out != 0)) {
- error = ipf_inject(&fra->fra_info, m);
+ error = ipf_inject(&fin, m);
if (error != 0) {
+ IPFERROR(10016);
error = ENOBUFS;
- fr_authstats.fas_sendfail++;
+ softa->ipf_auth_stats.fas_sendfail++;
} else {
- fr_authstats.fas_sendok++;
+ softa->ipf_auth_stats.fas_sendok++;
}
} else if (m) {
- error = ipf_inject(&fra->fra_info, m);
+ error = ipf_inject(&fin, m);
if (error != 0) {
+ IPFERROR(10017);
error = ENOBUFS;
- fr_authstats.fas_quefail++;
+ softa->ipf_auth_stats.fas_quefail++;
} else {
- fr_authstats.fas_queok++;
+ softa->ipf_auth_stats.fas_queok++;
}
} else {
+ IPFERROR(10018);
error = EINVAL;
}
@@ -1016,28 +1254,54 @@ char *data;
* not being processed, make sure we advance to the next one.
*/
if (error == ENOBUFS) {
- WRITE_ENTER(&ipf_auth);
- fr_authused--;
+ WRITE_ENTER(&softa->ipf_authlk);
+ softa->ipf_auth_used--;
fra->fra_index = -1;
fra->fra_pass = 0;
- if (i == fr_authstart) {
+ if (i == softa->ipf_auth_start) {
while (fra->fra_index == -1) {
i++;
- if (i == fr_authsize)
+ if (i == softa->ipf_auth_size)
i = 0;
- fr_authstart = i;
- if (i == fr_authend)
+ softa->ipf_auth_start = i;
+ if (i == softa->ipf_auth_end)
break;
}
- if (fr_authstart == fr_authend) {
- fr_authnext = 0;
- fr_authstart = fr_authend = 0;
+ if (softa->ipf_auth_start == softa->ipf_auth_end) {
+ softa->ipf_auth_next = 0;
+ softa->ipf_auth_start = 0;
+ softa->ipf_auth_end = 0;
}
}
- RWLOCK_EXIT(&ipf_auth);
+ RWLOCK_EXIT(&softa->ipf_authlk);
}
#endif /* _KERNEL */
SPL_X(s);
return 0;
}
+
+
+u_32_t
+ipf_auth_pre_scanlist(softc, fin, pass)
+ ipf_main_softc_t *softc;
+ fr_info_t *fin;
+ u_32_t pass;
+{
+ ipf_auth_softc_t *softa = softc->ipf_auth_soft;
+
+ if (softa->ipf_auth_ip != NULL)
+ return ipf_scanlist(fin, softc->ipf_pass);
+
+ return pass;
+}
+
+
+frentry_t **
+ipf_auth_rulehead(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_auth_softc_t *softa = softc->ipf_auth_soft;
+
+ return &softa->ipf_auth_ip;
+}
diff --git a/sys/contrib/ipfilter/netinet/ip_auth.h b/sys/contrib/ipfilter/netinet/ip_auth.h
index 36c4bac..914f999 100644
--- a/sys/contrib/ipfilter/netinet/ip_auth.h
+++ b/sys/contrib/ipfilter/netinet/ip_auth.h
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1997-2001 by Darren Reed & Guido Van Rooij.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
@@ -21,6 +21,7 @@ typedef struct frauth {
u_32_t fra_pass;
fr_info_t fra_info;
char *fra_buf;
+ u_32_t fra_flx;
#ifdef MENTAT
queue_t *fra_q;
mb_t *fra_m;
@@ -35,7 +36,7 @@ typedef struct frauthent {
int fae_ref;
} frauthent_t;
-typedef struct fr_authstat {
+typedef struct ipf_authstat {
U_QUAD_T fas_hits;
U_QUAD_T fas_miss;
u_long fas_nospace;
@@ -46,26 +47,28 @@ typedef struct fr_authstat {
u_long fas_quefail;
u_long fas_expire;
frauthent_t *fas_faelist;
-} fr_authstat_t;
+} ipf_authstat_t;
-extern frentry_t *ipauth;
-extern struct fr_authstat fr_authstats;
-extern int fr_defaultauthage;
-extern int fr_authstart;
-extern int fr_authend;
-extern int fr_authsize;
-extern int fr_authused;
-extern int fr_auth_lock;
-extern frentry_t *fr_checkauth __P((fr_info_t *, u_32_t *));
-extern void fr_authexpire __P((void));
-extern int fr_authinit __P((void));
-extern void fr_authunload __P((void));
-extern int fr_authflush __P((void));
-extern mb_t **fr_authpkts;
-extern int fr_newauth __P((mb_t *, fr_info_t *));
-extern int fr_preauthcmd __P((ioctlcmd_t, frentry_t *, frentry_t **));
-extern int fr_auth_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *));
-extern int fr_auth_waiting __P((void));
+extern frentry_t *ipf_auth_check __P((fr_info_t *, u_32_t *));
+extern void ipf_auth_expire __P((ipf_main_softc_t *));
+extern int ipf_auth_ioctl __P((ipf_main_softc_t *, caddr_t, ioctlcmd_t,
+ int, int, void *));
+extern int ipf_auth_init __P((void));
+extern int ipf_auth_main_load __P((void));
+extern int ipf_auth_main_unload __P((void));
+extern void ipf_auth_soft_destroy __P((ipf_main_softc_t *, void *));
+extern void *ipf_auth_soft_create __P((ipf_main_softc_t *));
+extern int ipf_auth_new __P((mb_t *, fr_info_t *));
+extern int ipf_auth_precmd __P((ipf_main_softc_t *, ioctlcmd_t,
+ frentry_t *, frentry_t **));
+extern void ipf_auth_unload __P((ipf_main_softc_t *));
+extern int ipf_auth_waiting __P((ipf_main_softc_t *));
+extern void ipf_auth_setlock __P((void *, int));
+extern int ipf_auth_soft_init __P((ipf_main_softc_t *, void *));
+extern int ipf_auth_soft_fini __P((ipf_main_softc_t *, void *));
+extern u_32_t ipf_auth_pre_scanlist __P((ipf_main_softc_t *, fr_info_t *,
+ u_32_t));
+extern frentry_t **ipf_auth_rulehead __P((ipf_main_softc_t *));
#endif /* __IP_AUTH_H__ */
diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h
index 4305c48..6cce591 100644
--- a/sys/contrib/ipfilter/netinet/ip_compat.h
+++ b/sys/contrib/ipfilter/netinet/ip_compat.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1993-2001, 2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
@@ -32,14 +32,7 @@
# define __KERNEL__
#endif
-#ifndef SOLARIS
#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
-#endif
-#if (defined(SOLARIS2) && (SOLARIS2 >= 8))
-# ifndef USE_INET6
-# define USE_INET6
-# endif
-#endif
#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \
!defined(_KERNEL) && !defined(USE_INET6) && !defined(NOINET6)
# define USE_INET6
@@ -47,26 +40,22 @@
#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105000000) && \
!defined(_KERNEL) && !defined(USE_INET6)
# define USE_INET6
+#endif
+#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 106140000) && \
+ defined(_KERNEL) && \
+ (!defined(IPFILTER_LKM) || (__NetBSD_Version__ >= 399000100))
# define IPFILTER_M_IPFILTER
#endif
-#if defined(OpenBSD) && (OpenBSD >= 200206) && \
+#if !defined(USE_INET6)
+# if defined(OpenBSD) && (OpenBSD >= 200206) && \
!defined(_KERNEL) && !defined(USE_INET6)
-# define USE_INET6
-#endif
-#if defined(__osf__)
-# define USE_INET6
-#endif
-#if defined(linux) && (!defined(_KERNEL) || defined(CONFIG_IPV6))
-# define USE_INET6
-#endif
-#if defined(HPUXREV) && (HPUXREV >= 1111)
-# define USE_INET6
+# define USE_INET6
+# endif
+# if defined(HPUXREV) && (HPUXREV >= 1111)
+# define USE_INET6
+# endif
#endif
-#if defined(BSD) && (BSD < 199103) && defined(__osf__)
-# undef BSD
-# define BSD 199103
-#endif
#if defined(__SVR4) || defined(__svr4__) || defined(__sgi)
# define index strchr
@@ -95,862 +84,120 @@ struct ether_addr {
};
#endif
-#if defined(__sgi) && !defined(IPFILTER_LKM)
-# ifdef __STDC__
-# define IPL_EXTERN(ep) ipfilter##ep
-# else
-# define IPL_EXTERN(ep) ipfilter/**/ep
-# endif
-#else
# ifdef __STDC__
# define IPL_EXTERN(ep) ipl##ep
# else
# define IPL_EXTERN(ep) ipl/**/ep
# endif
-#endif
/*
* This is a workaround for <sys/uio.h> troubles on FreeBSD and OpenBSD.
*/
-#ifndef linux
# ifndef _KERNEL
# define ADD_KERNEL
# define _KERNEL
# define KERNEL
# endif
-# ifdef __OpenBSD__
-struct file;
-# endif
# include <sys/uio.h>
# ifdef ADD_KERNEL
# undef _KERNEL
# undef KERNEL
# endif
-#endif
-
-
-/* ----------------------------------------------------------------------- */
-/* S O L A R I S */
-/* ----------------------------------------------------------------------- */
-#if SOLARIS
-# define MENTAT 1
-# include <sys/cmn_err.h>
-# include <sys/isa_defs.h>
-# include <sys/stream.h>
-# include <sys/ioccom.h>
-# include <sys/sysmacros.h>
-# include <sys/kmem.h>
-# if defined(SOLARIS2) && SOLARIS2 >= 10
-# include <sys/procset.h>
-# include <sys/proc.h>
-# include <sys/devops.h>
-# include <sys/ddi_impldefs.h>
-# endif
-/*
- * because Solaris 2 defines these in two places :-/
- */
-# ifndef KERNEL
-# define _KERNEL
-# undef RES_INIT
-# endif /* _KERNEL */
-
-# if defined(SOLARIS2) && SOLARIS2 >= 8
-# include <netinet/ip6.h>
-# include <netinet/icmp6.h>
-# endif
-
-# include <inet/common.h>
-/* These 5 are defined in <inet/ip.h> and <netinet/ip.h> */
-# undef IPOPT_EOL
-# undef IPOPT_NOP
-# undef IPOPT_LSRR
-# undef IPOPT_RR
-# undef IPOPT_SSRR
-# ifdef i386
-# define _SYS_PROMIF_H
-# endif
-# ifndef _KERNEL
-# include "radix_ipf.h"
-# else
-# include "radix_ipf_local.h"
-# endif
-# include <inet/ip.h>
-# undef COPYOUT
-# include <inet/ip_ire.h>
-# ifndef KERNEL
-# undef _KERNEL
-# endif
-# if defined(SOLARIS2) && SOLARIS2 >= 8
-# define SNPRINTF snprintf
-
-# include <inet/ip_if.h>
-# 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
-struct ip6_ext {
- u_char ip6e_nxt;
- u_char ip6e_len;
-};
-# endif /* SOLARIS2 >= 8 */
-
-# if defined(SOLARIS2) && SOLARIS2 >= 6
-# include <sys/atomic.h>
-typedef uint32_t u_32_t;
-# else
-typedef unsigned int u_32_t;
-# endif
-# define U_32_T 1
-
-# ifdef _KERNEL
-# define NEED_LOCAL_RAND 1
-# define ipf_random arc4random
-# define KRWLOCK_T krwlock_t
-# define KMUTEX_T kmutex_t
-
-# if !defined(FW_HOOKS)
-# include "qif.h"
-# include "pfil.h"
-# else
-# include <sys/neti.h>
-
-extern net_data_t ipfipv4;
-extern net_data_t ipfipv6;
-
-typedef struct qpktinfo {
- void *qpi_data;
- mblk_t **qpi_mp;
- mblk_t *qpi_m;
- uintptr_t qpi_real;
- int qpi_flags;
- int qpi_num;
- int qpi_off;
-} qpktinfo_t;
-# define QF_GROUP 0x01
-# endif
-
-# if SOLARIS2 >= 6
-# 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 /* SOLARIS2 == 6 */
-# 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 /* SOLARIS2 >= 6 */
-# define USE_MUTEXES
-# define MUTEX_ENTER(x) mutex_enter(&(x)->ipf_lk)
-# define READ_ENTER(x) rw_enter(&(x)->ipf_lk, RW_READER)
-# define WRITE_ENTER(x) rw_enter(&(x)->ipf_lk, RW_WRITER)
-# define MUTEX_DOWNGRADE(x) rw_downgrade(&(x)->ipf_lk)
-# define RWLOCK_INIT(x, y) rw_init(&(x)->ipf_lk, (y), \
- RW_DRIVER, NULL)
-# define RWLOCK_EXIT(x) rw_exit(&(x)->ipf_lk)
-# define RW_DESTROY(x) rw_destroy(&(x)->ipf_lk)
-# define MUTEX_INIT(x, y) mutex_init(&(x)->ipf_lk, (y), \
- MUTEX_DRIVER, NULL)
-# define MUTEX_DESTROY(x) mutex_destroy(&(x)->ipf_lk)
-# define MUTEX_NUKE(x) bzero((x), sizeof(*(x)))
-# define MUTEX_EXIT(x) mutex_exit(&(x)->ipf_lk)
-# define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c))
-# define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c))
-# define BCOPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c))
-# define BCOPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c))
-# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d)
-# define KFREE(x) kmem_free((char *)(x), sizeof(*(x)))
-# define KFREES(x,s) kmem_free((char *)(x), (s))
-# define SPL_SCHED(x) ;
-# define SPL_NET(x) ;
-# define SPL_IMP(x) ;
-# undef SPL_X
-# define SPL_X(x) ;
-# ifdef sparc
-# define ntohs(x) (x)
-# define ntohl(x) (x)
-# define htons(x) (x)
-# define htonl(x) (x)
-# endif /* sparc */
-# define KMALLOC(a,b) (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)
-extern void *get_unit __P((char *, int));
-# define GETIFP(n, v) get_unit(n, v)
-# if defined(_INET_IP_STACK_H)
-# define COPYIFNAME(v, x, b) \
- do { \
- if ((v) == 4) { \
- (void) net_getifname(ipfipv4,\
- (uintptr_t)x, b, \
- LIFNAMSIZ); \
- } else { \
- (void) net_getifname(ipfipv6,\
- (uintptr_t)x, b, \
- LIFNAMSIZ); \
- } \
- } while (0)
-# else
-# define COPYIFNAME(v, x, b) \
- (void) strncpy(b, ((qif_t *)x)->qf_name, \
- LIFNAMSIZ)
-# endif
-# define GETKTIME(x) uniqtime((struct timeval *)x)
-# define MSGDSIZE(x) msgdsize(x)
-# define M_LEN(x) ((x)->b_wptr - (x)->b_rptr)
-# define M_DUPLICATE(x) dupmsg((x))
-# define MTOD(m,t) ((t)((m)->b_rptr))
-# define MTYPE(m) ((m)->b_datap->db_type)
-# define FREE_MB_T(m) freemsg(m)
-# define m_next b_cont
-# if !defined(_INET_IP_STACK_H)
-# define CACHE_HASH(x) (((qpktinfo_t *)(x)->fin_qpi)->qpi_num & 7)
-# else
-# define CACHE_HASH(x) ((uintptr_t)(x)->fin_ifp & 7)
-# endif
-# define IPF_PANIC(x,y) if (x) { printf y; cmn_err(CE_PANIC, "ipf_panic"); }
-typedef mblk_t mb_t;
-# endif /* _KERNEL */
-
-# if defined(SOLARIS2) && (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
-# if defined(SOLARIS2) && SOLARIS2 < 6
-typedef struct uio uio_t;
-# endif
-typedef int ioctlcmd_t;
-typedef uint8_t u_int8_t;
-
-# define OS_RECOGNISED 1
-
-#endif /* SOLARIS */
-
-/* ----------------------------------------------------------------------- */
-/* H P U X */
-/* ----------------------------------------------------------------------- */
-#ifdef __hpux
-# define MENTAT 1
-# include <sys/sysmacros.h>
-# include <sys/spinlock.h>
-# include <sys/lock.h>
-# include <sys/stream.h>
-# ifdef USE_INET6
-# include <netinet/if_ether.h>
-# include <netinet/ip6.h>
-# include <netinet/icmp6.h>
-typedef struct ip6_hdr ip6_t;
-# endif
-
-# ifdef _KERNEL
-# define SNPRINTF sprintf
-# if (HPUXREV >= 1111)
-# define IPL_SELECT
-# ifdef IPL_SELECT
-# include <machine/sys/user.h>
-# include <sys/kthread_iface.h>
-# define READ_COLLISION 0x01
-
-typedef struct iplog_select_s {
- kthread_t *read_waiter;
- int state;
-} iplog_select_t;
-# endif
-# endif
-
-# define GETKTIME(x) uniqtime((struct timeval *)x)
-
-# if HPUXREV == 1111
-# include "kern_svcs.h"
-# else
-# include <sys/kern_svcs.h>
-# endif
-# undef ti_flags
-# undef TCP_NODELAY
-# undef TCP_MAXSEG
-# include <sys/reg.h>
-# include "../netinet/ip_info.h"
-/*
- * According to /usr/include/sys/spinlock.h on HP-UX 11.00, these functions
- * are available. Attempting to use them actually results in unresolved
- * symbols when it comes time to load the module.
- * This has been fixed! Yipee!
- */
-# if 1
-# ifdef __LP64__
-# define ATOMIC_INCL(x) lock_and_incr_int64(&ipf_rw.ipf_lk, &(x), 1)
-# define ATOMIC_DECL(x) lock_and_incr_int64(&ipf_rw.ipf_lk, &(x), -1)
-# else
-# define ATOMIC_INCL(x) lock_and_incr_int32(&ipf_rw.ipf_lk, &(x), 1)
-# define ATOMIC_DECL(x) lock_and_incr_int32(&ipf_rw.ipf_lk, &(x), -1)
-# endif
-# define ATOMIC_INC64(x) lock_and_incr_int64(&ipf_rw.ipf_lk, &(x), 1)
-# define ATOMIC_INC32(x) lock_and_incr_int32(&ipf_rw.ipf_lk, &(x), 1)
-# define ATOMIC_INC16(x) lock_and_incr_int16(&ipf_rw.ipf_lk, &(x), 1)
-# define ATOMIC_DEC64(x) lock_and_incr_int64(&ipf_rw.ipf_lk, &(x), -1)
-# define ATOMIC_DEC32(x) lock_and_incr_int32(&ipf_rw.ipf_lk, &(x), -1)
-# define ATOMIC_DEC16(x) lock_and_incr_int16(&ipf_rw.ipf_lk, &(x), -1)
-# else /* 0 */
-# define ATOMIC_INC64(x) { MUTEX_ENTER(&ipf_rw); (x)++; \
- MUTEX_EXIT(&ipf_rw); }
-# define ATOMIC_DEC64(x) { MUTEX_ENTER(&ipf_rw); (x)--; \
- MUTEX_EXIT(&ipf_rw); }
-# define ATOMIC_INC32(x) { MUTEX_ENTER(&ipf_rw); (x)++; \
- MUTEX_EXIT(&ipf_rw); }
-# define ATOMIC_DEC32(x) { MUTEX_ENTER(&ipf_rw); (x)--; \
- MUTEX_EXIT(&ipf_rw); }
-# define ATOMIC_INCL(x) { MUTEX_ENTER(&ipf_rw); (x)++; \
- MUTEX_EXIT(&ipf_rw); }
-# define ATOMIC_DECL(x) { MUTEX_ENTER(&ipf_rw); (x)--; \
- MUTEX_EXIT(&ipf_rw); }
-# 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 ip_cksum ip_csuma
-# define memcpy(a,b,c) bcopy((caddr_t)b, (caddr_t)a, c)
-# define USE_MUTEXES
-# define MUTEX_INIT(x, y) initlock(&(x)->ipf_lk, 0, 0, (y))
-# define MUTEX_ENTER(x) spinlock(&(x)->ipf_lk)
-# define MUTEX_EXIT(x) spinunlock(&(x)->ipf_lk);
-# define MUTEX_DESTROY(x)
-# define MUTEX_NUKE(x) bzero((char *)(x), sizeof(*(x)))
-# define KMUTEX_T lock_t
-# define kmutex_t lock_t /* for pfil.h */
-# define krwlock_t lock_t /* for pfil.h */
-/*
- * The read-write lock implementation in HP-UX 11.0 is crippled - it can
- * only be used by threads working in a user context!
- * This has been fixed! Yipee! (Or at least it does in 11.00, not 11.11..)
- */
-# if HPUXREV < 1111
-# define MUTEX_DOWNGRADE(x) lock_write_to_read(x)
-# define KRWLOCK_T struct rw_lock
-# define READ_ENTER(x) lock_read(&(x)->ipf_lk)
-# define WRITE_ENTER(x) lock_write(&(x)->ipf_lk)
-# if HPUXREV >= 1111
-# define RWLOCK_INIT(x, y) rwlock_init4(&(x)->ipf_lk, 0, RWLCK_CANSLEEP, 0, y)
-# else
-# define RWLOCK_INIT(x, y) lock_init3(&(x)->ipf_lk, 0, 1, 0, 0, y)
-# endif
-# define RWLOCK_EXIT(x) lock_done(&(x)->ipf_lk)
-# else
-# define KRWLOCK_T lock_t
-# define KMUTEX_T lock_t
-# define READ_ENTER(x) MUTEX_ENTER(x)
-# define WRITE_ENTER(x) MUTEX_ENTER(x)
-# define MUTEX_DOWNGRADE(x)
-# define RWLOCK_INIT(x, y) initlock(&(x)->ipf_lk, 0, 0, y)
-# define RWLOCK_EXIT(x) MUTEX_EXIT(x)
-# endif
-# define RW_DESTROY(x)
-# define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c))
-# define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c))
-# define SPL_SCHED(x) ;
-# define SPL_NET(x) ;
-# define SPL_IMP(x) ;
-# undef SPL_X
-# define SPL_X(x) ;
-extern void *get_unit __P((char *, int));
-# define GETIFP(n, v) get_unit(n, v)
-# define COPYIFNAME(v, x, b) \
- (void) strncpy(b, ((qif_t *)x)->qf_name, \
- LIFNAMSIZ)
-# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d)
-# define SLEEP(id, n) { lock_t *_l = get_sleep_lock((caddr_t)id); \
- sleep(id, PZERO+1); \
- spinunlock(_l); \
- }
-# define WAKEUP(id,x) { lock_t *_l = get_sleep_lock((caddr_t)id); \
- wakeup(id + x); \
- spinunlock(_l); \
- }
-# define POLLWAKEUP(x) ;
-# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_IOSYS, M_NOWAIT)
-# define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_IOSYS, M_NOWAIT)
-# define KFREE(x) kmem_free((char *)(x), sizeof(*(x)))
-# define KFREES(x,s) kmem_free((char *)(x), (s))
-# define MSGDSIZE(x) msgdsize(x)
-# define M_LEN(x) ((x)->b_wptr - (x)->b_rptr)
-# define M_DUPLICATE(x) dupmsg((x))
-# define MTOD(m,t) ((t)((m)->b_rptr))
-# define MTYPE(m) ((m)->b_datap->db_type)
-# define FREE_MB_T(m) freemsg(m)
-# define m_next b_cont
-# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); }
-typedef mblk_t mb_t;
-
-# define CACHE_HASH(x) (((qpktinfo_t *)(x)->fin_qpi)->qpi_num & 7)
-
-# include "qif.h"
-# include "pfil.h"
-
-# else /* _KERNEL */
-
-typedef unsigned char uchar_t;
-
-# ifndef _SYS_STREAM_INCLUDED
-typedef char * mblk_t;
-typedef void * queue_t;
-typedef u_long ulong;
-# endif
-# include <netinet/ip_info.h>
-
-# endif /* _KERNEL */
-
-# ifdef lint
-# define ALIGN32(ptr) (ptr ? 0L : 0L)
-# define ALIGN16(ptr) (ptr ? 0L : 0L)
-# else
-# define ALIGN32(ptr) (ptr)
-# define ALIGN16(ptr) (ptr)
-# endif
-
-typedef struct uio uio_t;
-typedef int ioctlcmd_t;
-typedef int minor_t;
-typedef unsigned int u_32_t;
-# define U_32_T 1
-
-# define OS_RECOGNISED 1
-
-#endif /* __hpux */
-
-/* ----------------------------------------------------------------------- */
-/* I R I X */
-/* ----------------------------------------------------------------------- */
-#ifdef __sgi
-# undef MENTAT
-# if IRIX < 60500
-typedef struct uio uio_t;
-# endif
-typedef int ioctlcmd_t;
-typedef u_int32_t u_32_t;
-# define U_32_T 1
-
-# ifdef INET6
-# define USE_INET6
-# endif
-
-# define hz HZ
-# include <sys/ksynch.h>
-# define IPF_LOCK_PL plhi
-# include <sys/sema.h>
-# undef kmutex_t
-typedef struct {
- lock_t *l;
- int pl;
-} kmutex_t;
-
-# ifdef MUTEX_INIT
-# define KMUTEX_T mutex_t
-# else
-# define KMUTEX_T kmutex_t
-# define KRWLOCK_T kmutex_t
-# endif
-
-# ifdef _KERNEL
-# define NEED_LOCAL_RAND 1
-# define ipf_random arc4random
-# 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 USE_MUTEXES
-# ifdef MUTEX_INIT
-# include <sys/atomic_ops.h>
-# define ATOMIC_INCL(x) atomicAddUlong(&(x), 1)
-# define ATOMIC_INC64(x) atomicAddUint64(&(x), 1)
-# define ATOMIC_INC32(x) atomicAddUint(&(x), 1)
-# define ATOMIC_INC16 ATOMIC_INC
-# define ATOMIC_DECL(x) atomicAddUlong(&(x), -1)
-# define ATOMIC_DEC64(x) atomicAddUint64(&(x), -1)
-# define ATOMIC_DEC32(x) atomicAddUint(&(x), -1)
-# define ATOMIC_DEC16 ATOMIC_DEC
-# undef MUTEX_INIT
-# define MUTEX_INIT(x, y) mutex_init(&(x)->ipf_lk, \
- MUTEX_DEFAULT, y)
-# undef MUTEX_ENTER
-# define MUTEX_ENTER(x) mutex_lock(&(x)->ipf_lk, 0)
-# undef MUTEX_EXIT
-# define MUTEX_EXIT(x) mutex_unlock(&(x)->ipf_lk)
-# undef MUTEX_DESTROY
-# define MUTEX_DESTROY(x) mutex_destroy(&(x)->ipf_lk)
-# define MUTEX_DOWNGRADE(x) mrdemote(&(x)->ipf_lk)
-# define KRWLOCK_T mrlock_t
-# define RWLOCK_INIT(x, y) mrinit(&(x)->ipf_lk, y)
-# undef RW_DESTROY
-# define RW_DESTROY(x) mrfree(&(x)->ipf_lk)
-# define READ_ENTER(x) RW_RDLOCK(&(x)->ipf_lk)
-# define WRITE_ENTER(x) RW_WRLOCK(&(x)->ipf_lk)
-# define RWLOCK_EXIT(x) RW_UNLOCK(&(x)->ipf_lk)
-# else
-# define READ_ENTER(x) MUTEX_ENTER(&(x)->ipf_lk)
-# define WRITE_ENTER(x) MUTEX_ENTER(&(x)->ipf_lk)
-# define MUTEX_DOWNGRADE(x) ;
-# define RWLOCK_EXIT(x) MUTEX_EXIT(&(x)->ipf_lk)
-# define MUTEX_EXIT(x) UNLOCK((x)->ipf_lk.l, (x)->ipf_lk.pl);
-# define MUTEX_INIT(x,y) (x)->ipf_lk.l = LOCK_ALLOC((uchar_t)-1, IPF_LOCK_PL, (lkinfo_t *)-1, KM_NOSLEEP)
-# define MUTEX_DESTROY(x) LOCK_DEALLOC((x)->ipf_lk.l)
-# define MUTEX_ENTER(x) (x)->ipf_lk.pl = LOCK((x)->ipf_lk.l, \
- IPF_LOCK_PL);
-# endif
-# define MUTEX_NUKE(x) bzero((x), sizeof(*(x)))
-# define FREE_MB_T(m) m_freem(m)
-# define MTOD(m,t) mtod(m,t)
-# define COPYIN(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0)
-# define COPYOUT(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0)
-# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d)
-# define SLEEP(id, n) sleep((id), PZERO+1)
-# define WAKEUP(id,x) wakeup(id+x)
-# define POLLWAKEUP(x) ;
-# define KFREE(x) kmem_free((char *)(x), sizeof(*(x)))
-# define KFREES(x,s) kmem_free((char *)(x), (s))
-# define GETIFP(n,v) ifunit(n)
-# include <sys/kmem.h>
-# include <sys/ddi.h>
-# 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)
-# define USE_SPL 1
-# define SPL_IMP(x) (x) = splimp()
-# define SPL_NET(x) (x) = splnet()
-# define SPL_SCHED(x) (x) = splsched()
-# define SPL_X(x) (void) splx(x)
-extern void m_copydata __P((struct mbuf *, int, int, caddr_t));
-extern void m_copyback __P((struct mbuf *, int, int, caddr_t));
-# define MSGDSIZE(x) mbufchainlen(x)
-# define M_LEN(x) (x)->m_len
-# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL)
-# define GETKTIME(x) microtime((struct timeval *)x)
-# define IFNAME(x) ((struct ifnet *)x)->if_name
-# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \
- ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
-# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); }
-typedef struct mbuf mb_t;
-# else
-# undef RW_DESTROY
-# undef MUTEX_INIT
-# undef MUTEX_DESTROY
-# endif /* _KERNEL */
-
-# define OS_RECOGNISED 1
-
-#endif /* __sgi */
-
-/* ----------------------------------------------------------------------- */
-/* T R U 6 4 */
-/* ----------------------------------------------------------------------- */
-#ifdef __osf__
-# undef MENTAT
-
-# include <kern/lock.h>
-# include <sys/sysmacros.h>
-
-# ifdef _KERNEL
-# define NEED_LOCAL_RAND 1
-# define ipf_random arc4random
-# define KMUTEX_T simple_lock_data_t
-# define KRWLOCK_T lock_data_t
-# include <net/net_globals.h>
-# define USE_MUTEXES
-# define READ_ENTER(x) lock_read(&(x)->ipf_lk)
-# define WRITE_ENTER(x) lock_write(&(x)->ipf_lk)
-# define MUTEX_DOWNGRADE(x) lock_write_to_read(&(x)->ipf_lk)
-# define RWLOCK_INIT(x, y) lock_init(&(x)->ipf_lk, TRUE)
-# define RWLOCK_EXIT(x) lock_done(&(x)->ipf_lk)
-# define RW_DESTROY(x) lock_terminate(&(x)->ipf_lk)
-# define MUTEX_ENTER(x) simple_lock(&(x)->ipf_lk)
-# define MUTEX_INIT(x, y) simple_lock_init(&(x)->ipf_lk)
-# define MUTEX_DESTROY(x) simple_lock_terminate(&(x)->ipf_lk)
-# define MUTEX_EXIT(x) simple_unlock(&(x)->ipf_lk)
-# define MUTEX_NUKE(x) bzero(x, sizeof(*(x)))
-# define ATOMIC_INC64(x) atomic_incq((uint64_t*)&(x))
-# define ATOMIC_DEC64(x) atomic_decq((uint64_t*)&(x))
-# define ATOMIC_INC32(x) atomic_incl((uint32_t*)&(x))
-# define ATOMIC_DEC32(x) atomic_decl((uint32_t*)&(x))
-# define ATOMIC_INC16(x) { simple_lock(&ipf_rw); (x)++; \
- simple_unlock(&ipf_rw); }
-# define ATOMIC_DEC16(x) { simple_lock(&ipf_rw); (x)--; \
- simple_unlock(&ipf_rw); }
-# define ATOMIC_INCL(x) atomic_incl((uint32_t*)&(x))
-# define ATOMIC_DECL(x) atomic_decl((uint32_t*)&(x))
-# define ATOMIC_INC(x) { simple_lock(&ipf_rw); (x)++; \
- simple_unlock(&ipf_rw); }
-# define ATOMIC_DEC(x) { simple_lock(&ipf_rw); (x)--; \
- simple_unlock(&ipf_rw); }
-# define SPL_SCHED(x) ;
-# define SPL_NET(x) ;
-# define SPL_IMP(x) ;
-# undef SPL_X
-# define SPL_X(x) ;
-# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a, b, d)
-# define FREE_MB_T(m) m_freem(m)
-# define MTOD(m,t) mtod(m,t)
-# define GETIFP(n, v) ifunit(n)
-# define GET_MINOR getminor
-# define WAKEUP(id,x) wakeup(id + x)
-# define POLLWAKEUP(x) ;
-# define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c))
-# define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c))
-# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_PFILT, M_NOWAIT)
-# define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_PFILT, \
- ((c) > 4096) ? M_WAITOK : M_NOWAIT)
-# define KFREE(x) FREE((x), M_PFILT)
-# define KFREES(x,s) FREE((x), M_PFILT)
-# define MSGDSIZE(x) mbufchainlen(x)
-# define M_LEN(x) (x)->m_len
-# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL)
-# define GETKTIME(x) microtime((struct timeval *)x)
-# define IFNAME(x) ((struct ifnet *)x)->if_name
-# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \
- ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
-# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); }
-typedef struct mbuf mb_t;
-# endif /* _KERNEL */
-
-# if (defined(_KERNEL) || defined(_NO_BITFIELDS) || (__STDC__ == 1))
-# define IP_V(x) ((x)->ip_vhl >> 4)
-# define IP_HL(x) ((x)->ip_vhl & 0xf)
-# define IP_V_A(x,y) (x)->ip_vhl |= (((y) << 4) & 0xf0)
-# define IP_HL_A(x,y) (x)->ip_vhl |= ((y) & 0xf)
-# define TCP_X2(x) ((x)->th_xoff & 0xf)
-# define TCP_X2_A(x,y) (x)->th_xoff |= ((y) & 0xf)
-# define TCP_OFF(x) ((x)->th_xoff >> 4)
-# define TCP_OFF_A(x,y) (x)->th_xoff |= (((y) << 4) & 0xf0)
-# endif
-
-/*
- * These are from's Solaris' #defines for little endian.
- */
-#define IP6F_MORE_FRAG 0x0100
-#define IP6F_RESERVED_MASK 0x0600
-#define IP6F_OFF_MASK 0xf8ff
-
-struct ip6_ext {
- u_char ip6e_nxt;
- u_char ip6e_len;
-};
-
-typedef int ioctlcmd_t;
-/*
- * Really, any arch where sizeof(long) != sizeof(int).
- */
-typedef unsigned int u_32_t;
-# define U_32_T 1
-
-# define OS_RECOGNISED 1
-#endif /* __osf__ */
-
-/* ----------------------------------------------------------------------- */
-/* N E T B S D */
-/* ----------------------------------------------------------------------- */
-#ifdef __NetBSD__
-# if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL)
-# include "opt_ipfilter.h"
-# endif
-# if defined(_KERNEL)
-# include <sys/systm.h>
-# else
-# include <stddef.h>
-# endif
-# if defined(_KERNEL) && !defined(IPFILTER_LKM)
-# include "bpfilter.h"
-# if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 104110000)
-# include "opt_inet.h"
-# endif
-# ifdef INET6
-# define USE_INET6
-# endif
-# if (__NetBSD_Version__ >= 105000000)
-# define HAVE_M_PULLDOWN 1
-# endif
-# endif
-
-# if (__NetBSD_Version__ >= 499000000)
-typedef char * caddr_t;
-# endif
-
-# define ipf_random arc4random
-
-# ifdef _KERNEL
-# if (__NetBSD_Version__ >= 399001400)
-# define KMALLOCS(a, b, c) (a) = (b)malloc((c), _M_IPF, M_NOWAIT)
-# endif
-# define MSGDSIZE(x) mbufchainlen(x)
-# define M_LEN(x) (x)->m_len
-# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL)
-# define GETKTIME(x) microtime((struct timeval *)x)
-# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); }
-# define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c))
-# define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c))
-typedef struct mbuf mb_t;
-# endif /* _KERNEL */
-# if (NetBSD <= 1991011) && (NetBSD >= 199606)
-# define IFNAME(x) ((struct ifnet *)x)->if_xname
-# define COPYIFNAME(v, x, b) \
- (void) strncpy(b, \
- ((struct ifnet *)x)->if_xname, \
- LIFNAMSIZ)
-# define CACHE_HASH(x) ((((struct ifnet *)fin->fin_ifp)->if_index)&7)
-# else
-# define IFNAME(x) ((struct ifnet *)x)->if_name
-# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \
- ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
-# endif
-typedef struct uio uio_t;
-typedef u_long ioctlcmd_t;
-typedef int minor_t;
-typedef u_int32_t u_32_t;
-# define U_32_T 1
-
-# define OS_RECOGNISED 1
-#endif /* __NetBSD__ */
+#define NETBSD_GE_REV(x) (defined(__NetBSD_Version__) && \
+ (__NetBSD_Version__ >= (x)))
+#define NETBSD_GT_REV(x) (defined(__NetBSD_Version__) && \
+ (__NetBSD_Version__ > (x)))
+#define NETBSD_LT_REV(x) (defined(__NetBSD_Version__) && \
+ (__NetBSD_Version__ < (x)))
+#define FREEBSD_GE_REV(x) (defined(__FreeBSD_version) && \
+ (__FreeBSD_version >= (x)))
+#define FREEBSD_GT_REV(x) (defined(__FreeBSD_version) && \
+ (__FreeBSD_version > (x)))
+#define FREEBSD_LT_REV(x) (defined(__FreeBSD_version) && \
+ (__FreeBSD_version < (x)))
+#define BSDOS_GE_REV(x) (defined(_BSDI_VERSION) && \
+ (_BSDI_VERSION >= (x)))
+#define BSDOS_GT_REV(x) (defined(_BSDI_VERSION) && \
+ (_BSDI_VERSION > (x)))
+#define BSDOS_LT_REV(x) (defined(_BSDI_VERSION) && \
+ (_BSDI_VERSION < (x)))
+#define OPENBSD_GE_REV(x) (defined(OpenBSD) && (OpenBSD >= (x)))
+#define OPENBSD_GT_REV(x) (defined(OpenBSD) && (OpenBSD > (x)))
+#define OPENBSD_LT_REV(x) (defined(OpenBSD) && (OpenBSD < (x)))
+#define BSD_GE_YEAR(x) (defined(BSD) && (BSD >= (x)))
+#define BSD_GT_YEAR(x) (defined(BSD) && (BSD > (x)))
+#define BSD_LT_YEAR(x) (defined(BSD) && (BSD < (x)))
/* ----------------------------------------------------------------------- */
/* F R E E B S D */
/* ----------------------------------------------------------------------- */
-#ifdef __FreeBSD__
-# if (__FreeBSD_version < 400000)
-# define NEED_LOCAL_RAND 1
-# else
-# define ipf_random arc4random
-# endif
+# define HAS_SYS_MD5_H 1
# if defined(_KERNEL)
-# if (__FreeBSD_version >= 500000)
# include "opt_bpf.h"
-# else
-# include "bpf.h"
-# endif
-# if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000)
# include "opt_inet6.h"
-# endif
# if defined(INET6) && !defined(USE_INET6)
# define USE_INET6
# endif
# endif
# if defined(_KERNEL)
-# if (__FreeBSD_version >= 400000)
+# include <netinet/ip_var.h>
+# define p_cred td_ucred
+# define p_uid td_ucred->cr_ruid
+
/*
* When #define'd, the 5.2.1 kernel panics when used with the ftp proxy.
* There may be other, safe, kernels but this is not extensively tested yet.
*/
# define HAVE_M_PULLDOWN
-# endif
# if !defined(IPFILTER_LKM) && (__FreeBSD_version >= 300000)
# include "opt_ipfilter.h"
# endif
# define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c))
# define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c))
-# if (__FreeBSD_version >= 500043)
# define NETBSD_PF
-# endif
+# else
+# include <inttypes.h>
# endif /* _KERNEL */
-# if (__FreeBSD_version >= 500043)
+# include <sys/selinfo.h>
# include <sys/mutex.h>
-# if (__FreeBSD_version > 700014)
+# define KRWLOCK_FILL_SZ 56
+# define KMUTEX_FILL_SZ 56
# include <sys/rwlock.h>
-# define KRWLOCK_T struct rwlock
-# ifdef _KERNEL
-# define READ_ENTER(x) rw_rlock(&(x)->ipf_lk)
-# define WRITE_ENTER(x) rw_wlock(&(x)->ipf_lk)
-# define MUTEX_DOWNGRADE(x) rw_downgrade(&(x)->ipf_lk)
-# define RWLOCK_INIT(x, y) rw_init(&(x)->ipf_lk, (y))
-# define RW_DESTROY(x) rw_destroy(&(x)->ipf_lk)
-# define RWLOCK_EXIT(x) do { \
- if (rw_wowned(&(x)->ipf_lk)) \
- rw_wunlock(&(x)->ipf_lk); \
- else \
- rw_runlock(&(x)->ipf_lk); \
- } while (0)
-# endif
-# else
-# include <sys/sx.h>
-/*
- * Whilst the sx(9) locks on FreeBSD have the right semantics and interface
- * for what we want to use them for, despite testing showing they work -
- * with a WITNESS kernel, it generates LOR messages.
- */
+# define KMUTEX_T struct mtx
+# define KRWLOCK_T struct rwlock
# ifdef _KERNEL
-# if (__FreeBSD_version < 700000)
-# define KRWLOCK_T struct mtx
-# define READ_ENTER(x) mtx_lock(&(x)->ipf_lk)
-# define WRITE_ENTER(x) mtx_lock(&(x)->ipf_lk)
-# define RWLOCK_EXIT(x) mtx_unlock(&(x)->ipf_lk)
-# define MUTEX_DOWNGRADE(x) ;
-# define RWLOCK_INIT(x,y) mtx_init(&(x)->ipf_lk, (y), NULL,\
- MTX_DEF)
-# define RW_DESTROY(x) mtx_destroy(&(x)->ipf_lk)
-# else
-# define KRWLOCK_T struct sx
-# define READ_ENTER(x) sx_slock(&(x)->ipf_lk)
-# define WRITE_ENTER(x) sx_xlock(&(x)->ipf_lk)
-# define MUTEX_DOWNGRADE(x) sx_downgrade(&(x)->ipf_lk)
-# define RWLOCK_INIT(x, y) sx_init(&(x)->ipf_lk, (y))
-# define RW_DESTROY(x) sx_destroy(&(x)->ipf_lk)
-# ifdef sx_unlock
-# define RWLOCK_EXIT(x) sx_unlock(&(x)->ipf_lk)
-# else
-# define RWLOCK_EXIT(x) do { \
- if ((x)->ipf_lk.sx_cnt < 0) \
- sx_xunlock(&(x)->ipf_lk); \
+# define READ_ENTER(x) rw_rlock(&(x)->ipf_lk)
+# define WRITE_ENTER(x) rw_wlock(&(x)->ipf_lk)
+# define MUTEX_DOWNGRADE(x) rw_downgrade(&(x)->ipf_lk)
+# define RWLOCK_INIT(x,y) rw_init(&(x)->ipf_lk, (y))
+# define RW_DESTROY(x) rw_destroy(&(x)->ipf_lk)
+# define RWLOCK_EXIT(x) do { \
+ if (rw_wowned(&(x)->ipf_lk)) \
+ rw_wunlock(&(x)->ipf_lk); \
else \
- sx_sunlock(&(x)->ipf_lk); \
+ rw_runlock(&(x)->ipf_lk); \
} while (0)
-# endif
-# endif
# endif
-# endif
-# define KMUTEX_T struct mtx
-# endif
-# if (__FreeBSD_version >= 501113)
# include <net/if_var.h>
# define IFNAME(x) ((struct ifnet *)x)->if_xname
# define COPYIFNAME(v, x, b) \
(void) strncpy(b, \
((struct ifnet *)x)->if_xname, \
LIFNAMSIZ)
-# endif
-# if (__FreeBSD_version >= 500043)
-# define CACHE_HASH(x) ((((struct ifnet *)fin->fin_ifp)->if_index) & 7)
-# else
-# define IFNAME(x) ((struct ifnet *)x)->if_name
-# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \
- ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
-# endif
# ifdef _KERNEL
# define GETKTIME(x) microtime((struct timeval *)x)
-# if (__FreeBSD_version >= 500002)
# include <netinet/in_systm.h>
# include <netinet/ip.h>
# include <machine/in_cksum.h>
-# endif
-# if (__FreeBSD_version >= 500043)
# define USE_MUTEXES
# define MUTEX_ENTER(x) mtx_lock(&(x)->ipf_lk)
# define MUTEX_EXIT(x) mtx_unlock(&(x)->ipf_lk)
@@ -958,460 +205,47 @@ typedef u_int32_t u_32_t;
MTX_DEF)
# define MUTEX_DESTROY(x) mtx_destroy(&(x)->ipf_lk)
# define MUTEX_NUKE(x) bzero((x), sizeof(*(x)))
+/*
+ * Whilst the sx(9) locks on FreeBSD have the right semantics and interface
+ * for what we want to use them for, despite testing showing they work -
+ * with a WITNESS kernel, it generates LOR messages.
+ */
# include <machine/atomic.h>
-# define ATOMIC_INC(x) { mtx_lock(&ipf_rw.ipf_lk); (x)++; \
- mtx_unlock(&ipf_rw.ipf_lk); }
-# define ATOMIC_DEC(x) { mtx_lock(&ipf_rw.ipf_lk); (x)--; \
- mtx_unlock(&ipf_rw.ipf_lk); }
+# define ATOMIC_INC(x) { mtx_lock(&softc->ipf_rw.ipf_lk); (x)++; \
+ mtx_unlock(&softc->ipf_rw.ipf_lk); }
+# define ATOMIC_DEC(x) { mtx_lock(&softc->ipf_rw.ipf_lk); (x)--; \
+ mtx_unlock(&softc->ipf_rw.ipf_lk); }
# define ATOMIC_INCL(x) atomic_add_long(&(x), 1)
# define ATOMIC_INC64(x) ATOMIC_INC(x)
# define ATOMIC_INC32(x) atomic_add_32((u_int *)&(x), 1)
-# define ATOMIC_INC16(x) atomic_add_16(&(x), 1)
# define ATOMIC_DECL(x) atomic_add_long(&(x), -1)
# define ATOMIC_DEC64(x) ATOMIC_DEC(x)
# define ATOMIC_DEC32(x) atomic_add_32((u_int *)&(x), -1)
-# define ATOMIC_DEC16(x) atomic_add_16(&(x), -1)
# define SPL_X(x) ;
# define SPL_NET(x) ;
# define SPL_IMP(x) ;
# define SPL_SCHED(x) ;
-# else
-# define SPL_SCHED(x) x = splhigh()
-# endif /* __FreeBSD_version >= 500043 */
-# define MSGDSIZE(x) mbufchainlen(x)
-# define M_LEN(x) (x)->m_len
-# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL)
+# define GET_MINOR dev2unit
+# define MSGDSIZE(m) mbufchainlen(m)
+# define M_LEN(m) (m)->m_len
+# define M_ADJ(m,x) m_adj(m, x)
+# define M_COPY(x) m_copy((x), 0, M_COPYALL)
+# define M_DUP(m) m_dup(m, M_NOWAIT)
# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); }
typedef struct mbuf mb_t;
# endif /* _KERNEL */
-# if __FreeBSD_version < 300000
-# include <machine/spl.h>
-# else
-# if __FreeBSD_version < 400000
-# if defined(IPFILTER_LKM) && !defined(ACTUALLY_LKM_NOT_KERNEL)
-# define ACTUALLY_LKM_NOT_KERNEL
-# endif
-# endif
-# endif
-# if (__FreeBSD_version >= 300000)
typedef u_long ioctlcmd_t;
-# else
-typedef int ioctlcmd_t;
-# endif
-typedef struct uio uio_t;
-typedef int minor_t;
-typedef u_int32_t u_32_t;
-# define U_32_T 1
-
-# define OS_RECOGNISED 1
-#endif /* __FreeBSD__ */
-
-
-/* ----------------------------------------------------------------------- */
-/* O P E N B S D */
-/* ----------------------------------------------------------------------- */
-#ifdef __OpenBSD__
-# ifdef INET6
-# define USE_INET6
-# endif
-
-# ifdef _KERNEL
-# if !defined(IPFILTER_LKM)
-# include "bpfilter.h"
-# endif
-# if (OpenBSD >= 200311)
-# define SNPRINTF snprintf
-# if defined(USE_INET6)
-# include "netinet6/in6_var.h"
-# include "netinet6/nd6.h"
-# endif
-# endif
-# if (OpenBSD >= 200012)
-# define HAVE_M_PULLDOWN 1
-# endif
-# define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c))
-# define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c))
-# define GETKTIME(x) microtime((struct timeval *)x)
-# define MSGDSIZE(x) mbufchainlen(x)
-# define M_LEN(x) (x)->m_len
-# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL)
-# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); }
-typedef struct mbuf mb_t;
-# endif /* _KERNEL */
-# if (OpenBSD >= 199603)
-# define IFNAME(x, b) ((struct ifnet *)x)->if_xname
-# define COPYIFNAME(v, x, b) \
- (void) strncpy(b, \
- ((struct ifnet *)x)->if_xname, \
- LIFNAMSIZ)
-# define CACHE_HASH(x) ((((struct ifnet *)fin->fin_ifp)->if_index)&7)
-# else
-# define IFNAME(x, b) ((struct ifnet *)x)->if_name
-# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \
- ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
-# endif
-
typedef struct uio uio_t;
-typedef u_long ioctlcmd_t;
typedef int minor_t;
typedef u_int32_t u_32_t;
# define U_32_T 1
-# define OS_RECOGNISED 1
-#endif /* __OpenBSD__ */
-
-
-/* ----------------------------------------------------------------------- */
-/* B S D O S */
-/* ----------------------------------------------------------------------- */
-#ifdef _BSDI_VERSION
-# ifdef INET6
-# define USE_INET6
-# endif
-
-# ifdef _KERNEL
-# define GETKTIME(x) microtime((struct timeval *)x)
-# define MSGDSIZE(x) mbufchainlen(x)
-# define M_LEN(x) (x)->m_len
-# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL)
-# define IFNAME(x, b) ((struct ifnet *)x)->if_name
-# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \
- ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
-typedef struct mbuf mb_t;
-# endif /* _KERNEL */
-
-# if (_BSDI_VERSION >= 199701)
-typedef u_long ioctlcmd_t;
-# else
-typedef int ioctlcmd_t;
-# endif
-typedef u_int32_t u_32_t;
-# define U_32_T 1
-
-#endif /* _BSDI_VERSION */
-
-
-/* ----------------------------------------------------------------------- */
-/* S U N O S 4 */
-/* ----------------------------------------------------------------------- */
-#if defined(sun) && !defined(OS_RECOGNISED) /* SunOS4 */
-# ifdef _KERNEL
-# include <sys/kmem_alloc.h>
-# define GETKTIME(x) uniqtime((struct timeval *)x)
-# define MSGDSIZE(x) mbufchainlen(x)
-# define M_LEN(x) (x)->m_len
-# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL)
-# define IFNAME(x, b) ((struct ifnet *)x)->if_name
-# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \
- ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
-# define GETIFP(n, v) ifunit(n, IFNAMSIZ)
-# define KFREE(x) kmem_free((char *)(x), sizeof(*(x)))
-# define KFREES(x,s) kmem_free((char *)(x), (s))
-# define SLEEP(id, n) sleep((id), PZERO+1)
-# define WAKEUP(id,x) wakeup(id + x)
-# define POLLWAKEUP(x) ;
-# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d)
-# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); }
-
-extern void m_copydata __P((struct mbuf *, int, int, caddr_t));
-extern void m_copyback __P((struct mbuf *, int, int, caddr_t));
-
-typedef struct mbuf mb_t;
-# endif
-
-typedef struct uio uio_t;
-typedef int ioctlcmd_t;
-typedef int minor_t;
-typedef unsigned int u_32_t;
-# define U_32_T 1
-
-# define OS_RECOGNISED 1
-
-#endif /* SunOS 4 */
-
-/* ----------------------------------------------------------------------- */
-/* L I N U X */
-/* ----------------------------------------------------------------------- */
-#if defined(linux) && !defined(OS_RECOGNISED)
-#include <linux/config.h>
-#include <linux/version.h>
-# if (LINUX >= 20600) && defined(_KERNEL)
-# define HDR_T_PRIVATE 1
-# endif
-# undef USE_INET6
-# ifdef USE_INET6
-struct ip6_ext {
- u_char ip6e_nxt;
- u_char ip6e_len;
-};
-# endif
-
-# ifdef _KERNEL
-# define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); }
-# define COPYIN(a,b,c) copy_from_user((caddr_t)(b), (caddr_t)(a), (c))
-# define COPYOUT(a,b,c) copy_to_user((caddr_t)(b), (caddr_t)(a), (c))
-# define FREE_MB_T(m) kfree_skb(m)
-# define GETKTIME(x) do_gettimeofday((struct timeval *)x)
-# define POLLWAKEUP(x) ;
-# ifdef wait_event_interruptible
-# define SLEEP(x,s) wait_event_interruptible((*(x##_linux)), 0)
-# else
-# define SLEEP(x,s) 0, interruptible_sleep_on(x##_linux)
-# endif
-# define WAKEUP(x,y) wake_up(x##_linux + y)
-# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d)
-# define USE_MUTEXES
-# define KRWLOCK_T rwlock_t
-# define KMUTEX_T spinlock_t
-# define MUTEX_INIT(x,y) spin_lock_init(&(x)->ipf_lk)
-# define MUTEX_ENTER(x) spin_lock(&(x)->ipf_lk)
-# define MUTEX_EXIT(x) spin_unlock(&(x)->ipf_lk)
-# define MUTEX_DESTROY(x) do { } while (0)
-# define MUTEX_NUKE(x) bzero(&(x)->ipf_lk, sizeof((x)->ipf_lk))
-# define READ_ENTER(x) ipf_read_enter(x)
-# define WRITE_ENTER(x) ipf_write_enter(x)
-# define RWLOCK_INIT(x,y) ipf_rw_init(x, y)
-# define RW_DESTROY(x) do { } while (0)
-# define RWLOCK_EXIT(x) ipf_rw_exit(x)
-# define MUTEX_DOWNGRADE(x) ipf_rw_downgrade(x)
-# define ATOMIC_INCL(x) MUTEX_ENTER(&ipf_rw); (x)++; \
- MUTEX_EXIT(&ipf_rw)
-# define ATOMIC_DECL(x) MUTEX_ENTER(&ipf_rw); (x)--; \
- MUTEX_EXIT(&ipf_rw)
-# define ATOMIC_INC64(x) MUTEX_ENTER(&ipf_rw); (x)++; \
- MUTEX_EXIT(&ipf_rw)
-# define ATOMIC_INC32(x) MUTEX_ENTER(&ipf_rw); (x)++; \
- MUTEX_EXIT(&ipf_rw)
-# define ATOMIC_INC16(x) MUTEX_ENTER(&ipf_rw); (x)++; \
- MUTEX_EXIT(&ipf_rw)
-# define ATOMIC_DEC64(x) MUTEX_ENTER(&ipf_rw); (x)--; \
- MUTEX_EXIT(&ipf_rw)
-# define ATOMIC_DEC32(x) MUTEX_ENTER(&ipf_rw); (x)--; \
- MUTEX_EXIT(&ipf_rw)
-# define ATOMIC_DEC16(x) MUTEX_ENTER(&ipf_rw); (x)--; \
- MUTEX_EXIT(&ipf_rw)
-# define SPL_SCHED(x) do { } while (0)
-# define SPL_IMP(x) do { } while (0)
-# define SPL_NET(x) do { } while (0)
-# define SPL_X(x) do { } while (0)
-# define IFNAME(x) ((struct net_device*)x)->name
-# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \
- ((struct net_device *)fin->fin_ifp)->ifindex) & 7)
-typedef struct sk_buff mb_t;
-extern void m_copydata __P((mb_t *, int, int, caddr_t));
-extern void m_copyback __P((mb_t *, int, int, caddr_t));
-extern void m_adj __P((mb_t *, int));
-extern mb_t *m_pullup __P((mb_t *, int));
-# define mbuf sk_buff
-
-# define mtod(m, t) ((t)(m)->data)
-# define m_data data
-# define m_len len
-# define m_next next
-# define M_DUPLICATE(m) skb_clone((m), in_interrupt() ? GFP_ATOMIC : \
- GFP_KERNEL)
-# define MSGDSIZE(m) (m)->len
-# define M_LEN(m) (m)->len
-
-# define splnet(x) ;
-# define printf printk
-# define bcopy(s,d,z) memmove(d, s, z)
-# define bzero(s,z) memset(s, 0, z)
-# define bcmp(a,b,z) memcmp(a, b, z)
-
-# define ifnet net_device
-# define if_xname name
-# define if_unit ifindex
-
-# define KMALLOC(x,t) (x) = (t)kmalloc(sizeof(*(x)), \
- in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)
-# define KFREE(x) kfree(x)
-# define KMALLOCS(x,t,s) (x) = (t)kmalloc((s), \
- in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)
-# define KFREES(x,s) kfree(x)
-
-# define GETIFP(n,v) dev_get_by_name(n)
-
-# else
-# include <net/ethernet.h>
-
-struct mbuf {
-};
-
-# ifndef _NET_ROUTE_H
-struct rtentry {
-};
-# endif
-
-struct ifnet {
- char if_xname[IFNAMSIZ];
- int if_unit;
- int (* if_output) __P((struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *));
- struct ifaddr *if_addrlist;
-};
-# define IFNAME(x) ((struct ifnet *)x)->if_xname
-
-# endif /* _KERNEL */
-
-# define COPYIFNAME(v, x, b) \
- (void) strncpy(b, \
- ((struct ifnet *)x)->if_xname, \
- LIFNAMSIZ)
-
-# include <linux/fs.h>
-# define FWRITE FMODE_WRITE
-# define FREAD FMODE_READ
-
-# define __USE_MISC 1
-# define __FAVOR_BSD 1
-
-typedef struct uio {
- struct iovec *uio_iov;
- void *uio_file;
- char *uio_buf;
- int uio_iovcnt;
- int uio_offset;
- size_t uio_resid;
- int uio_rw;
-} uio_t;
-
-extern int uiomove __P((caddr_t, size_t, int, struct uio *));
-
-# define UIO_READ 1
-# define UIO_WRITE 2
-
-typedef u_long ioctlcmd_t;
-typedef int minor_t;
-typedef u_int32_t u_32_t;
-# define U_32_T 1
-
-# define OS_RECOGNISED 1
-
-#endif
-
-
-/* ----------------------------------------------------------------------- */
-/* A I X */
-/* ----------------------------------------------------------------------- */
-#if defined(_AIX51)
-# undef MENTAT
-
-# include <sys/lock.h>
-# include <sys/sysmacros.h>
-
-# ifdef _KERNEL
-# define rw_read_locked(x) 0
-# include <net/net_globals.h>
-# include <net/net_malloc.h>
-# define KMUTEX_T simple_lock_t
-# define KRWLOCK_T complex_lock_t
-# define USE_MUTEXES 1
-# define USE_SPL 1
-# define READ_ENTER(x) lock_read((x)->ipf_lk)
-# define WRITE_ENTER(x) lock_write((x)->ipf_lk)
-# define MUTEX_DOWNGRADE(x) lock_write_to_read((x)->ipf_lk)
-# define RWLOCK_INIT(x, y) lock_alloc(&(x)->ipf_lk, \
- LOCK_ALLOC_PIN, \
- (u_short)y, 0); \
- lock_init((x)->ipf_lk, TRUE)
-# define RWLOCK_EXIT(x) lock_done((x)->ipf_lk)
-# define RW_DESTROY(x) lock_free(&(x)->ipf_lk)
-# define MUTEX_ENTER(x) simple_lock((x)->ipf_lk)
-# define MUTEX_INIT(x, y) lock_alloc(&(x)->ipf_lk, \
- LOCK_ALLOC_PIN, \
- (u_short)y, 0); \
- simple_lock_init((x)->ipf_lk)
-# define MUTEX_DESTROY(x) lock_free(&(x)->ipf_lk)
-# define MUTEX_EXIT(x) simple_unlock((x)->ipf_lk)
-# define MUTEX_NUKE(x) bzero(&(x)->ipf_lk, sizeof((x)->ipf_lk))
-# define ATOMIC_INC64(x) { MUTEX_ENTER(&ipf_rw); (x)++; \
- MUTEX_EXIT(&ipf_rw); }
-# define ATOMIC_DEC64(x) { MUTEX_ENTER(&ipf_rw); (x)--; \
- MUTEX_EXIT(&ipf_rw); }
-# define ATOMIC_INC32(x) { MUTEX_ENTER(&ipf_rw); (x)++; \
- MUTEX_EXIT(&ipf_rw); }
-# define ATOMIC_DEC32(x) { MUTEX_ENTER(&ipf_rw); (x)--; \
- MUTEX_EXIT(&ipf_rw); }
-# define ATOMIC_INCL(x) { MUTEX_ENTER(&ipf_rw); (x)++; \
- MUTEX_EXIT(&ipf_rw); }
-# define ATOMIC_DECL(x) { MUTEX_ENTER(&ipf_rw); (x)--; \
- MUTEX_EXIT(&ipf_rw); }
-# 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 SPL_SCHED(x) x = splsched()
-# define SPL_NET(x) x = splnet()
-# define SPL_IMP(x) x = splimp()
-# undef SPL_X
-# define SPL_X(x) splx(x)
-# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d)
-extern void* getifp __P((char *, int));
-# define GETIFP(n, v) getifp(n, v)
-# define GET_MINOR minor
-# define SLEEP(id, n) sleepx((id), PZERO+1, 0)
-# define WAKEUP(id,x) wakeup(id)
-# define POLLWAKEUP(x) ;
-# define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c))
-# define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c))
-# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_TEMP, M_NOWAIT)
-# define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_TEMP, \
- ((c) > 4096) ? M_WAITOK : M_NOWAIT)
-# define KFREE(x) FREE((x), M_TEMP)
-# define KFREES(x,s) FREE((x), M_TEMP)
-# define MSGDSIZE(x) mbufchainlen(x)
-# define M_LEN(x) (x)->m_len
-# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL)
-# define GETKTIME(x)
-# define IFNAME(x, b) ((struct ifnet *)x)->if_name
-# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \
- ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
-# define IPF_PANIC(x,y)
-typedef struct mbuf mb_t;
-# endif /* _KERNEL */
-
-/*
- * These are from's Solaris' #defines for little endian.
- */
-#if !defined(IP6F_MORE_FRAG)
-# define IP6F_MORE_FRAG 0x0100
-#endif
-#if !defined(IP6F_RESERVED_MASK)
-# define IP6F_RESERVED_MASK 0x0600
-#endif
-#if !defined(IP6F_OFF_MASK)
-# define IP6F_OFF_MASK 0xf8ff
-#endif
-
-struct ip6_ext {
- u_char ip6e_nxt;
- u_char ip6e_len;
-};
-
-typedef int ioctlcmd_t;
-typedef int minor_t;
-/*
- * Really, any arch where sizeof(long) != sizeof(int).
- */
-typedef unsigned int u_32_t;
-# define U_32_T 1
-
-# define OS_RECOGNISED 1
-#endif /* _AIX51 */
-
-
-#ifndef OS_RECOGNISED
-#error ip_compat.h does not recognise this platform/OS.
-#endif
-
/* ----------------------------------------------------------------------- */
/* G E N E R I C */
/* ----------------------------------------------------------------------- */
-#ifndef OS_RECOGNISED
-#endif
/*
* For BSD kernels, if bpf is in the kernel, enable ipfilter to use bpf in
@@ -1427,15 +261,21 @@ typedef unsigned int u_32_t;
/*
* Userland locking primitives
*/
+#ifndef _KERNEL
+#if !defined(KMUTEX_FILL_SZ)
+# define KMUTEX_FILL_SZ 1
+#endif
+#if !defined(KRWLOCK_FILL_SZ)
+# define KRWLOCK_FILL_SZ 1
+#endif
+#endif
+
typedef struct {
char *eMm_owner;
char *eMm_heldin;
u_int eMm_magic;
int eMm_held;
int eMm_heldat;
-#if defined(__hpux) || defined(__linux)
- char eMm_fill[8];
-#endif
} eMmutex_t;
typedef struct {
@@ -1445,26 +285,25 @@ typedef struct {
short eMrw_read;
short eMrw_write;
int eMrw_heldat;
-#ifdef __hpux
- char eMm_fill[24];
-#endif
} eMrwlock_t;
typedef union {
+ char _fill[KMUTEX_FILL_SZ];
#ifdef KMUTEX_T
struct {
KMUTEX_T ipf_slk;
- char *ipf_lname;
+ const char *ipf_lname;
} ipf_lkun_s;
#endif
eMmutex_t ipf_emu;
} ipfmutex_t;
typedef union {
+ char _fill[KRWLOCK_FILL_SZ];
#ifdef KRWLOCK_T
struct {
KRWLOCK_T ipf_slk;
- char *ipf_lname;
+ const char *ipf_lname;
int ipf_sr;
int ipf_sw;
u_int ipf_magic;
@@ -1488,14 +327,12 @@ typedef union {
# define INLINE __inline__
#endif
-#if defined(linux) && defined(_KERNEL)
-extern void ipf_read_enter __P((ipfrwlock_t *));
-extern void ipf_write_enter __P((ipfrwlock_t *));
-extern void ipf_rw_exit __P((ipfrwlock_t *));
-extern void ipf_rw_init __P((ipfrwlock_t *, char *));
-extern void ipf_rw_downgrade __P((ipfrwlock_t *));
+#if defined(__FreeBSD_version) && defined(_KERNEL)
+ CTASSERT(sizeof(ipfrwlock_t) == KRWLOCK_FILL_SZ);
+ CTASSERT(sizeof(ipfmutex_t) == KMUTEX_FILL_SZ);
#endif
+
/*
* In a non-kernel environment, there are a lot of macros that need to be
* filled in to be null-ops or to point to some compatibility function,
@@ -1504,18 +341,40 @@ extern void ipf_rw_downgrade __P((ipfrwlock_t *));
#ifndef _KERNEL
typedef struct mb_s {
struct mb_s *mb_next;
+ char *mb_data;
+ void *mb_ifp;
int mb_len;
+ int mb_flags;
u_long mb_buf[2048];
} mb_t;
# undef m_next
# define m_next mb_next
-# define MSGDSIZE(x) (x)->mb_len /* XXX - from ipt.c */
-# define M_LEN(x) (x)->mb_len
-# define M_DUPLICATE(x) (x)
+# undef m_len
+# define m_len mb_len
+# undef m_flags
+# define m_flags mb_flags
+# undef m_data
+# define m_data mb_data
+# undef M_MCAST
+# define M_MCAST 0x01
+# undef M_BCAST
+# define M_BCAST 0x02
+# undef M_MBCAST
+# define M_MBCAST 0x04
+# define MSGDSIZE(m) msgdsize(m)
+# define M_LEN(m) (m)->mb_len
+# define M_ADJ(m,x) (m)->mb_len += x
+# define M_COPY(m) dupmbt(m)
+# define M_DUP(m) dupmbt(m)
# define GETKTIME(x) gettimeofday((struct timeval *)(x), NULL)
-# undef MTOD
-# define MTOD(m, t) ((t)(m)->mb_buf)
-# define FREE_MB_T(x)
+# define MTOD(m, t) ((t)(m)->mb_data)
+# define FREE_MB_T(m) freembt(m)
+# define ALLOC_MB_T(m,l) (m) = allocmbt(l)
+# define PREP_MB_T(f, m) do { \
+ (m)->mb_next = *(f)->fin_mp; \
+ *(fin)->fin_mp = (m); \
+ (f)->fin_m = (m); \
+ } while (0)
# define SLEEP(x,y) 1;
# define WAKEUP(x,y) ;
# define POLLWAKEUP(y) ;
@@ -1530,6 +389,8 @@ typedef struct mb_s {
# define KFREE(x) free(x)
# define KFREES(x,s) free(x)
# define GETIFP(x, v) get_unit(x,v)
+# define GETIFMTU_4(x) 2048
+# define GETIFMTU_6(x) 2048
# define COPYIN(a,b,c) bcopywrap((a), (b), (c))
# define COPYOUT(a,b,c) bcopywrap((a), (b), (c))
# define COPYDATA(m, o, l, b) bcopy(MTOD((mb_t *)m, char *) + (o), \
@@ -1541,16 +402,18 @@ typedef struct mb_s {
extern void m_copydata __P((mb_t *, int, int, caddr_t));
extern int ipfuiomove __P((caddr_t, int, int, struct uio *));
extern int bcopywrap __P((void *, void *, size_t));
-# ifndef CACHE_HASH
-# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \
- ((struct ifnet *)fin->fin_ifp)->if_unit) & 7)
-# endif
+extern mb_t *allocmbt __P((size_t));
+extern mb_t *dupmbt __P((mb_t *));
+extern void freembt __P((mb_t *));
-# define MUTEX_DESTROY(x) eMmutex_destroy(&(x)->ipf_emu)
+# define MUTEX_DESTROY(x) eMmutex_destroy(&(x)->ipf_emu, \
+ __FILE__, __LINE__)
# define MUTEX_ENTER(x) eMmutex_enter(&(x)->ipf_emu, \
__FILE__, __LINE__)
-# define MUTEX_EXIT(x) eMmutex_exit(&(x)->ipf_emu)
-# define MUTEX_INIT(x,y) eMmutex_init(&(x)->ipf_emu, y)
+# define MUTEX_EXIT(x) eMmutex_exit(&(x)->ipf_emu, \
+ __FILE__, __LINE__)
+# define MUTEX_INIT(x,y) eMmutex_init(&(x)->ipf_emu, y, \
+ __FILE__, __LINE__)
# define MUTEX_NUKE(x) bzero((x), sizeof(*(x)))
# define MUTEX_DOWNGRADE(x) eMrwlock_downgrade(&(x)->ipf_emu, \
@@ -1566,10 +429,10 @@ extern int bcopywrap __P((void *, void *, size_t));
# define USE_MUTEXES 1
-extern void eMmutex_destroy __P((eMmutex_t *));
+extern void eMmutex_destroy __P((eMmutex_t *, char *, int));
extern void eMmutex_enter __P((eMmutex_t *, char *, int));
-extern void eMmutex_exit __P((eMmutex_t *));
-extern void eMmutex_init __P((eMmutex_t *, char *));
+extern void eMmutex_exit __P((eMmutex_t *, char *, int));
+extern void eMmutex_init __P((eMmutex_t *, char *, char *, int));
extern void eMrwlock_destroy __P((eMrwlock_t *));
extern void eMrwlock_exit __P((eMrwlock_t *));
extern void eMrwlock_init __P((eMrwlock_t *, char *));
@@ -1579,6 +442,8 @@ extern void eMrwlock_downgrade __P((eMrwlock_t *, char *, int));
#endif
+extern mb_t *allocmbt(size_t);
+
#define MAX_IPV4HDR ((0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8)
#ifndef IP_OFFMASK
@@ -1590,13 +455,15 @@ extern void eMrwlock_downgrade __P((eMrwlock_t *, char *, int));
* On BSD's use quad_t as a guarantee for getting at least a 64bit sized
* object.
*/
-#if (BSD > 199306)
+#if !defined(__amd64__) && BSD_GT_YEAR(199306)
# define USE_QUAD_T
# define U_QUAD_T unsigned long long
# define QUAD_T long long
#else /* BSD > 199306 */
-# define U_QUAD_T u_long
-# define QUAD_T long
+# if !defined(U_QUAD_T)
+# define U_QUAD_T u_long
+# define QUAD_T long
+# endif
#endif /* BSD > 199306 */
@@ -1605,11 +472,9 @@ extern void eMrwlock_downgrade __P((eMrwlock_t *, char *, int));
defined(__osf__) || defined(linux)
# include <netinet/ip6.h>
# include <netinet/icmp6.h>
-# if !defined(linux)
# if defined(_KERNEL) && !defined(__osf__)
# include <netinet6/ip6_var.h>
# endif
-# endif
typedef struct ip6_hdr ip6_t;
# endif
#endif
@@ -1619,23 +484,20 @@ typedef struct ip6_hdr ip6_t;
#endif
#if defined(_KERNEL)
-# ifdef MENTAT
+# if defined(MENTAT) && !defined(INSTANCES)
# define COPYDATA mb_copydata
# define COPYBACK mb_copyback
# else
# define COPYDATA m_copydata
# define COPYBACK m_copyback
# endif
-# if (BSD >= 199306) || defined(__FreeBSD__)
# if (defined(__NetBSD_Version__) && (__NetBSD_Version__ < 105180000)) || \
defined(__FreeBSD__) || (defined(OpenBSD) && (OpenBSD < 200206)) || \
defined(_BSDI_VERSION)
# include <vm/vm.h>
# endif
-# if !defined(__FreeBSD__) || (defined (__FreeBSD_version) && \
- (__FreeBSD_version >= 300000))
-# if (defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105180000)) || \
- (defined(OpenBSD) && (OpenBSD >= 200111))
+# if !defined(__FreeBSD__) || FREEBSD_GE_REV(300000)
+# if NETBSD_GE_REV(105180000) || OPENBSD_GE_REV(200111)
# include <uvm/uvm_extern.h>
# else
# include <vm/vm_extern.h>
@@ -1661,33 +523,31 @@ MALLOC_DECLARE(M_IPFILTER);
# endif /* M_IPFILTER */
# endif /* M_PFIL */
# endif /* IPFILTER_M_IPFILTER */
-# if defined(__FreeBSD__) && __FreeBSD_version >= 800051
-# define KMALLOC(a, b) do { \
- a = (b)malloc(sizeof(*(a)), _M_IPF, M_NOWAIT); \
- } while (0)
-# define KMALLOCS(a, b, c) do { \
- a = (b)malloc((c), _M_IPF, ((c) > 4096) ? M_WAITOK : M_NOWAIT); \
- } while (0)
-# define KFREE(x) free((x), _M_IPF)
-# define KFREES(x,s) free((x), _M_IPF)
-# else
+# if !defined(KMALLOC)
# define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), _M_IPF, M_NOWAIT)
-# if !defined(KMALLOCS)
-# define KMALLOCS(a, b, c) MALLOC((a), b, (c), _M_IPF, M_NOWAIT)
-# endif
+# endif
+# if !defined(KMALLOCS)
+# define KMALLOCS(a, b, c) MALLOC((a), b, (c), _M_IPF, M_NOWAIT)
+# endif
+# if !defined(KFREE)
# define KFREE(x) FREE((x), _M_IPF)
-# define KFREES(x,s) FREE((x), _M_IPF)
+# endif
+# if !defined(KFREES)
+# define KFREES(x,s) FREE((x), _M_IPF)
# endif
# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,d)
# define SLEEP(id, n) tsleep((id), PPAUSE|PCATCH, n, 0)
# define WAKEUP(id,x) wakeup(id+x)
-# define POLLWAKEUP(x) selwakeup(ipfselwait+x)
+# if !defined(POLLWAKEUP)
+# define POLLWAKEUP(x) selwakeup(softc->ipf_selwait+x)
+# endif
# define GETIFP(n, v) ifunit(n)
-# endif /* (Free)BSD */
+# define GETIFMTU_4(x) ((struct ifnet *)x)->if_mtu
+# define GETIFMTU_6(x) ((struct ifnet *)x)->if_mtu
# if !defined(USE_MUTEXES) && !defined(SPL_NET)
# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199407)) || \
- (defined(OpenBSD) && (OpenBSD >= 200006))
+ OPENBSD_GE_REV(200006)
# define SPL_NET(x) x = splsoftnet()
# else
# define SPL_IMP(x) x = splimp()
@@ -1702,6 +562,45 @@ MALLOC_DECLARE(M_IPFILTER);
# ifndef FREE_MB_T
# define FREE_MB_T(m) m_freem(m)
# endif
+# ifndef ALLOC_MB_T
+# ifdef MGETHDR
+# define ALLOC_MB_T(m,l) do { \
+ MGETHDR((m), M_DONTWAIT, MT_HEADER); \
+ if ((m) != NULL) { \
+ (m)->m_len = (l); \
+ (m)->m_pkthdr.len = (l); \
+ } \
+ } while (0)
+# else
+# define ALLOC_MB_T(m,l) do { \
+ MGET((m), M_DONTWAIT, MT_HEADER); \
+ if ((m) != NULL) { \
+ (m)->m_len = (l); \
+ (m)->m_pkthdr.len = (l); \
+ } \
+ } while (0)
+# endif
+# endif
+# ifndef PREP_MB_T
+# define PREP_MB_T(f, m) do { \
+ mb_t *_o = *(f)->fin_mp; \
+ (m)->m_next = _o; \
+ *(fin)->fin_mp = (m); \
+ if (_o->m_flags & M_PKTHDR) { \
+ (m)->m_pkthdr.len += \
+ _o->m_pkthdr.len; \
+ (m)->m_pkthdr.rcvif = \
+ _o->m_pkthdr.rcvif; \
+ } \
+ } while (0)
+# endif
+# ifndef M_DUP
+# ifdef M_COPYALL
+# define M_DUP(m) m_dup(m, 0, M_COPYALL, 0)
+# else
+# define M_DUP(m) m_dup(m)
+# endif
+# endif
# ifndef MTOD
# define MTOD(m,t) mtod(m,t)
@@ -1725,13 +624,13 @@ MALLOC_DECLARE(M_IPFILTER);
#endif /* _KERNEL */
#if !defined(IFNAME) && !defined(_KERNEL)
-# define IFNAME(x) ((struct ifnet *)x)->if_name
+# define IFNAME(x) get_ifname((struct ifnet *)x)
#endif
#ifndef COPYIFNAME
# define NEED_FRGETIFNAME
-extern char *fr_getifname __P((struct ifnet *, char *));
+extern char *ipf_getifname __P((struct ifnet *, char *));
# define COPYIFNAME(v, x, b) \
- fr_getifname((struct ifnet *)x, b)
+ ipf_getifname((struct ifnet *)x, b)
#endif
#ifndef ASSERT
@@ -1753,9 +652,7 @@ extern char *fr_getifname __P((struct ifnet *, char *));
*/
#define ISALNUM(x) isalnum((u_char)(x))
#define ISALPHA(x) isalpha((u_char)(x))
-#define ISASCII(x) isascii((u_char)(x))
#define ISDIGIT(x) isdigit((u_char)(x))
-#define ISPRINT(x) isprint((u_char)(x))
#define ISSPACE(x) isspace((u_char)(x))
#define ISUPPER(x) isupper((u_char)(x))
#define ISXDIGIT(x) isxdigit((u_char)(x))
@@ -1803,11 +700,9 @@ extern char *fr_getifname __P((struct ifnet *, char *));
# 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
#ifndef HDR_T_PRIVATE
@@ -1824,7 +719,10 @@ typedef struct tcpiphdr tcpiphdr_t;
#endif
#ifndef offsetof
-# define offsetof(t,m) (int)((&((t *)0L)->m))
+# define offsetof(t,m) (size_t)((&((t *)0L)->m))
+#endif
+#ifndef stsizeof
+# define stsizeof(t,m) sizeof(((t *)0L)->m)
#endif
/*
@@ -1871,9 +769,9 @@ typedef struct tcpiphdr tcpiphdr_t;
#define TCPF_ALL (TH_FIN|TH_SYN|TH_RST|TH_PUSH|TH_ACK|TH_URG|\
TH_ECN|TH_CWR)
-#if (BSD >= 199306) && !defined(m_act)
+#if BSD_GE_YEAR(199306) && !defined(m_act)
# define m_act m_nextpkt
-#endif
+#endif
/*
* Security Options for Intenet Protocol (IPSO) as defined in RFC 1108.
@@ -1910,7 +808,7 @@ typedef struct tcpiphdr tcpiphdr_t;
* IP option #defines
*/
#undef IPOPT_RR
-#define IPOPT_RR 7
+#define IPOPT_RR 7
#undef IPOPT_ZSU
#define IPOPT_ZSU 10 /* ZSU */
#undef IPOPT_MTUP
@@ -1958,6 +856,8 @@ typedef struct tcpiphdr tcpiphdr_t;
#define IPOPT_UMP 152
#undef IPOPT_FINN
#define IPOPT_FINN 205 /* FINN */
+#undef IPOPT_AH
+#define IPOPT_AH 256+IPPROTO_AH
#ifndef TCPOPT_EOL
# define TCPOPT_EOL 0
@@ -2236,8 +1136,11 @@ typedef struct tcpiphdr tcpiphdr_t;
#ifndef IPPROTO_HOPOPTS
# define IPPROTO_HOPOPTS 0
#endif
+#ifndef IPPROTO_IPIP
+# define IPPROTO_IPIP 4
+#endif
#ifndef IPPROTO_ENCAP
-# define IPPROTO_ENCAP 4
+# define IPPROTO_ENCAP 98
#endif
#ifndef IPPROTO_IPV6
# define IPPROTO_IPV6 41
@@ -2436,6 +1339,38 @@ typedef struct tcpiphdr tcpiphdr_t;
# define ICMP6_NI_SUBJ_IPV4 2
#endif
+#ifndef MLD_MTRACE_RESP
+# define MLD_MTRACE_RESP 200
+#endif
+#ifndef MLD_MTRACE
+# define MLD_MTRACE 201
+#endif
+#ifndef MLD6_MTRACE_RESP
+# define MLD6_MTRACE_RESP MLD_MTRACE_RESP
+#endif
+#ifndef MLD6_MTRACE
+# define MLD6_MTRACE MLD_MTRACE
+#endif
+
+#if !defined(IPV6_FLOWINFO_MASK)
+# if (BYTE_ORDER == BIG_ENDIAN) || defined(_BIG_ENDIAN)
+# define IPV6_FLOWINFO_MASK 0x0fffffff /* flow info (28 bits) */
+# else
+# if(BYTE_ORDER == LITTLE_ENDIAN) || !defined(_BIG_ENDIAN)
+# define IPV6_FLOWINFO_MASK 0xffffff0f /* flow info (28 bits) */
+# endif /* LITTLE_ENDIAN */
+# endif
+#endif
+#if !defined(IPV6_FLOWLABEL_MASK)
+# if (BYTE_ORDER == BIG_ENDIAN) || defined(_BIG_ENDIAN)
+# define IPV6_FLOWLABEL_MASK 0x000fffff /* flow label (20 bits) */
+# else
+# if (BYTE_ORDER == LITTLE_ENDIAN) || !defined(_BIG_ENDIAN)
+# define IPV6_FLOWLABEL_MASK 0xffff0f00 /* flow label (20 bits) */
+# endif /* LITTLE_ENDIAN */
+# endif
+#endif
+
/*
* ECN is a new addition to TCP - RFC 2481
*/
@@ -2516,14 +1451,50 @@ typedef struct tcpiphdr tcpiphdr_t;
# define MIN(a,b) (((a)<(b))?(a):(b))
#endif
+#ifdef RESCUE
+# undef IPFILTER_BPF
+#endif
+
#ifdef IPF_DEBUG
# define DPRINT(x) printf x
#else
# define DPRINT(x)
#endif
-#ifdef RESCUE
-# undef IPFILTER_BPF
+#ifndef AF_INET6
+# define AF_INET6 26
#endif
+#ifdef DTRACE_PROBE
+# ifdef _KERNEL
+# define DT(_n) DTRACE_PROBE(_n)
+# define DT1(_n,_a,_b) DTRACE_PROBE1(_n,_a,_b)
+# define DT2(_n,_a,_b,_c,_d) DTRACE_PROBE2(_n,_a,_b,_c,_d)
+# define DT3(_n,_a,_b,_c,_d,_e,_f) \
+ DTRACE_PROBE3(_n,_a,_b,_c,_d,_e,_f)
+# define DT4(_n,_a,_b,_c,_d,_e,_f,_g,_h) \
+ DTRACE_PROBE4(_n,_a,_b,_c,_d,_e,_f,_g,_h)
+# else
+# define DT(_n)
+# define DT1(_n,_a,_b)
+# define DT2(_n,_a,_b,_c,_d)
+# define DT3(_n,_a,_b,_c,_d,_e,_f)
+# define DT4(_n,_a,_b,_c,_d,_e,_f,_g,_h)
+# endif
+#else
+# define DT(_n)
+# define DT1(_n,_a,_b)
+# define DT2(_n,_a,_b,_c,_d)
+# define DT3(_n,_a,_b,_c,_d,_e,_f)
+# define DT4(_n,_a,_b,_c,_d,_e,_f,_g,_h)
+#endif
+
+struct ip6_routing {
+ u_char ip6r_nxt; /* next header */
+ u_char ip6r_len; /* length in units of 8 octets */
+ u_char ip6r_type; /* always zero */
+ u_char ip6r_segleft; /* segments left */
+ u_32_t ip6r_reserved; /* reserved field */
+};
+
#endif /* __IP_COMPAT_H__ */
diff --git a/sys/contrib/ipfilter/netinet/ip_dns_pxy.c b/sys/contrib/ipfilter/netinet/ip_dns_pxy.c
new file mode 100644
index 0000000..df863b8
--- /dev/null
+++ b/sys/contrib/ipfilter/netinet/ip_dns_pxy.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: ip_dns_pxy.c,v 1.1.2.10 2012/07/22 08:04:23 darren_r Exp $
+ */
+
+#define IPF_DNS_PROXY
+
+/*
+ * map ... proxy port dns/udp 53 { block .cnn.com; }
+ */
+typedef struct ipf_dns_filter {
+ struct ipf_dns_filter *idns_next;
+ char *idns_name;
+ int idns_namelen;
+ int idns_pass;
+} ipf_dns_filter_t;
+
+
+typedef struct ipf_dns_softc_s {
+ ipf_dns_filter_t *ipf_p_dns_list;
+ ipfrwlock_t ipf_p_dns_rwlock;
+ u_long ipf_p_dns_compress;
+ u_long ipf_p_dns_toolong;
+ u_long ipf_p_dns_nospace;
+} ipf_dns_softc_t;
+
+int ipf_p_dns_allow_query __P((ipf_dns_softc_t *, dnsinfo_t *));
+int ipf_p_dns_ctl __P((ipf_main_softc_t *, void *, ap_ctl_t *));
+int ipf_p_dns_del __P((ipf_main_softc_t *, ap_session_t *));
+int ipf_p_dns_get_name __P((ipf_dns_softc_t *, char *, int, char *, int));
+int ipf_p_dns_inout __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_dns_match __P((fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_dns_match_names __P((ipf_dns_filter_t *, char *, int));
+int ipf_p_dns_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+void *ipf_p_dns_soft_create __P((ipf_main_softc_t *));
+void ipf_p_dns_soft_destroy __P((ipf_main_softc_t *, void *));
+
+typedef struct {
+ u_char dns_id[2];
+ u_short dns_ctlword;
+ u_short dns_qdcount;
+ u_short dns_ancount;
+ u_short dns_nscount;
+ u_short dns_arcount;
+} ipf_dns_hdr_t;
+
+#define DNS_QR(x) ((ntohs(x) & 0x8000) >> 15)
+#define DNS_OPCODE(x) ((ntohs(x) & 0x7800) >> 11)
+#define DNS_AA(x) ((ntohs(x) & 0x0400) >> 10)
+#define DNS_TC(x) ((ntohs(x) & 0x0200) >> 9)
+#define DNS_RD(x) ((ntohs(x) & 0x0100) >> 8)
+#define DNS_RA(x) ((ntohs(x) & 0x0080) >> 7)
+#define DNS_Z(x) ((ntohs(x) & 0x0070) >> 4)
+#define DNS_RCODE(x) ((ntohs(x) & 0x000f) >> 0)
+
+
+void *
+ipf_p_dns_soft_create(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_dns_softc_t *softd;
+
+ KMALLOC(softd, ipf_dns_softc_t *);
+ if (softd == NULL)
+ return NULL;
+
+ bzero((char *)softd, sizeof(*softd));
+ RWLOCK_INIT(&softd->ipf_p_dns_rwlock, "ipf dns rwlock");
+
+ return softd;
+}
+
+
+void
+ipf_p_dns_soft_destroy(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_dns_softc_t *softd = arg;
+ ipf_dns_filter_t *idns;
+
+ while ((idns = softd->ipf_p_dns_list) != NULL) {
+ KFREES(idns->idns_name, idns->idns_namelen);
+ idns->idns_name = NULL;
+ idns->idns_namelen = 0;
+ softd->ipf_p_dns_list = idns->idns_next;
+ KFREE(idns);
+ }
+ RW_DESTROY(&softd->ipf_p_dns_rwlock);
+
+ KFREE(softd);
+}
+
+
+int
+ipf_p_dns_ctl(softc, arg, ctl)
+ ipf_main_softc_t *softc;
+ void *arg;
+ ap_ctl_t *ctl;
+{
+ ipf_dns_softc_t *softd = arg;
+ ipf_dns_filter_t *tmp, *idns, **idnsp;
+ int error = 0;
+
+ /*
+ * To make locking easier.
+ */
+ KMALLOC(tmp, ipf_dns_filter_t *);
+
+ WRITE_ENTER(&softd->ipf_p_dns_rwlock);
+ for (idnsp = &softd->ipf_p_dns_list; (idns = *idnsp) != NULL;
+ idnsp = &idns->idns_next) {
+ if (idns->idns_namelen != ctl->apc_dsize)
+ continue;
+ if (!strncmp(ctl->apc_data, idns->idns_name,
+ idns->idns_namelen))
+ break;
+ }
+
+ switch (ctl->apc_cmd)
+ {
+ case APC_CMD_DEL :
+ if (idns == NULL) {
+ IPFERROR(80006);
+ error = ESRCH;
+ break;
+ }
+ *idnsp = idns->idns_next;
+ idns->idns_next = NULL;
+ KFREES(idns->idns_name, idns->idns_namelen);
+ idns->idns_name = NULL;
+ idns->idns_namelen = 0;
+ KFREE(idns);
+ break;
+ case APC_CMD_ADD :
+ if (idns != NULL) {
+ IPFERROR(80007);
+ error = EEXIST;
+ break;
+ }
+ if (tmp == NULL) {
+ IPFERROR(80008);
+ error = ENOMEM;
+ break;
+ }
+ idns = tmp;
+ tmp = NULL;
+ idns->idns_namelen = ctl->apc_dsize;
+ idns->idns_name = ctl->apc_data;
+ idns->idns_pass = ctl->apc_arg;
+ idns->idns_next = NULL;
+ *idnsp = idns;
+ ctl->apc_data = NULL;
+ ctl->apc_dsize = 0;
+ break;
+ default :
+ IPFERROR(80009);
+ error = EINVAL;
+ break;
+ }
+ RWLOCK_EXIT(&softd->ipf_p_dns_rwlock);
+
+ if (tmp != NULL) {
+ KFREE(tmp);
+ tmp = NULL;
+ }
+
+ return error;
+}
+
+
+/* ARGSUSED */
+int
+ipf_p_dns_new(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
+{
+ dnsinfo_t *di;
+ int dlen;
+
+ if (fin->fin_v != 4)
+ return -1;
+
+ dlen = fin->fin_dlen - sizeof(udphdr_t);
+ if (dlen < sizeof(ipf_dns_hdr_t)) {
+ /*
+ * No real DNS packet is smaller than that.
+ */
+ return -1;
+ }
+
+ aps->aps_psiz = sizeof(dnsinfo_t);
+ KMALLOCS(di, dnsinfo_t *, sizeof(dnsinfo_t));
+ if (di == NULL) {
+ printf("ipf_dns_new:KMALLOCS(%d) failed\n", sizeof(*di));
+ return -1;
+ }
+
+ MUTEX_INIT(&di->dnsi_lock, "dns lock");
+
+ aps->aps_data = di;
+
+ dlen = fin->fin_dlen - sizeof(udphdr_t);
+ COPYDATA(fin->fin_m, fin->fin_hlen + sizeof(udphdr_t),
+ MIN(dlen, sizeof(di->dnsi_buffer)), di->dnsi_buffer);
+ di->dnsi_id = (di->dnsi_buffer[0] << 8) | di->dnsi_buffer[1];
+ return 0;
+}
+
+
+/* ARGSUSED */
+int
+ipf_p_dns_del(softc, aps)
+ ipf_main_softc_t *softc;
+ ap_session_t *aps;
+{
+#ifdef USE_MUTEXES
+ dnsinfo_t *di = aps->aps_data;
+
+ MUTEX_DESTROY(&di->dnsi_lock);
+#endif
+ KFREES(aps->aps_data, aps->aps_psiz);
+ aps->aps_data = NULL;
+ aps->aps_psiz = 0;
+ return 0;
+}
+
+
+/*
+ * Tries to match the base string (in our ACL) with the query from a packet.
+ */
+int
+ipf_p_dns_match_names(idns, query, qlen)
+ ipf_dns_filter_t *idns;
+ char *query;
+ int qlen;
+{
+ int blen;
+ char *base;
+
+ blen = idns->idns_namelen;
+ base = idns->idns_name;
+
+ if (blen > qlen)
+ return 1;
+
+ if (blen == qlen)
+ return strncasecmp(base, query, qlen);
+
+ /*
+ * If the base string string is shorter than the query, allow the
+ * tail of the base to match the same length tail of the query *if*:
+ * - the base string starts with a '*' (*cnn.com)
+ * - the base string represents a domain (.cnn.com)
+ * as otherwise it would not be possible to block just "cnn.com"
+ * without also impacting "foocnn.com", etc.
+ */
+ if (*base == '*') {
+ base++;
+ blen--;
+ } else if (*base != '.')
+ return 1;
+
+ return strncasecmp(base, query + qlen - blen, blen);
+}
+
+
+int
+ipf_p_dns_get_name(softd, start, len, buffer, buflen)
+ ipf_dns_softc_t *softd;
+ char *start;
+ int len;
+ char *buffer;
+ int buflen;
+{
+ char *s, *t, clen;
+ int slen, blen;
+
+ s = start;
+ t = buffer;
+ slen = len;
+ blen = buflen - 1; /* Always make room for trailing \0 */
+
+ while (*s != '\0') {
+ clen = *s;
+ if ((clen & 0xc0) == 0xc0) { /* Doesn't do compression */
+ softd->ipf_p_dns_compress++;
+ return 0;
+ }
+ if (clen > slen) {
+ softd->ipf_p_dns_toolong++;
+ return 0; /* Does the name run off the end? */
+ }
+ if ((clen + 1) > blen) {
+ softd->ipf_p_dns_nospace++;
+ return 0; /* Enough room for name+.? */
+ }
+ s++;
+ bcopy(s, t, clen);
+ t += clen;
+ s += clen;
+ *t++ = '.';
+ slen -= clen;
+ blen -= (clen + 1);
+ }
+
+ *(t - 1) = '\0';
+ return s - start;
+}
+
+
+int
+ipf_p_dns_allow_query(softd, dnsi)
+ ipf_dns_softc_t *softd;
+ dnsinfo_t *dnsi;
+{
+ ipf_dns_filter_t *idns;
+ int len;
+
+ len = strlen(dnsi->dnsi_buffer);
+
+ for (idns = softd->ipf_p_dns_list; idns != NULL; idns = idns->idns_next)
+ if (ipf_p_dns_match_names(idns, dnsi->dnsi_buffer, len) == 0)
+ return idns->idns_pass;
+ return 0;
+}
+
+
+/* ARGSUSED */
+int
+ipf_p_dns_inout(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
+{
+ ipf_dns_softc_t *softd = arg;
+ ipf_dns_hdr_t *dns;
+ dnsinfo_t *di;
+ char *data;
+ int dlen, q, rc = 0;
+
+ if (fin->fin_dlen < sizeof(*dns))
+ return APR_ERR(1);
+
+ dns = (ipf_dns_hdr_t *)((char *)fin->fin_dp + sizeof(udphdr_t));
+
+ q = dns->dns_qdcount;
+
+ data = (char *)(dns + 1);
+ dlen = fin->fin_dlen - sizeof(*dns) - sizeof(udphdr_t);
+
+ di = aps->aps_data;
+
+ READ_ENTER(&softd->ipf_p_dns_rwlock);
+ MUTEX_ENTER(&di->dnsi_lock);
+
+ for (; (dlen > 0) && (q > 0); q--) {
+ int len;
+
+ len = ipf_p_dns_get_name(softd, data, dlen, di->dnsi_buffer,
+ sizeof(di->dnsi_buffer));
+ if (len == 0) {
+ rc = 1;
+ break;
+ }
+ rc = ipf_p_dns_allow_query(softd, di);
+ if (rc != 0)
+ break;
+ data += len;
+ dlen -= len;
+ }
+ MUTEX_EXIT(&di->dnsi_lock);
+ RWLOCK_EXIT(&softd->ipf_p_dns_rwlock);
+
+ return APR_ERR(rc);
+}
+
+
+/* ARGSUSED */
+int
+ipf_p_dns_match(fin, aps, nat)
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
+{
+ dnsinfo_t *di = aps->aps_data;
+ ipf_dns_hdr_t *dnh;
+
+ if ((fin->fin_dlen < sizeof(u_short)) || (fin->fin_flx & FI_FRAG))
+ return -1;
+
+ dnh = (ipf_dns_hdr_t *)((char *)fin->fin_dp + sizeof(udphdr_t));
+ if (((dnh->dns_id[0] << 8) | dnh->dns_id[1]) != di->dnsi_id)
+ return -1;
+ return 0;
+}
diff --git a/sys/contrib/ipfilter/netinet/ip_dstlist.c b/sys/contrib/ipfilter/netinet/ip_dstlist.c
new file mode 100644
index 0000000..ce2e72e
--- /dev/null
+++ b/sys/contrib/ipfilter/netinet/ip_dstlist.c
@@ -0,0 +1,1351 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if defined(KERNEL) || defined(_KERNEL)
+# undef KERNEL
+# undef _KERNEL
+# define KERNEL 1
+# define _KERNEL 1
+#endif
+#if defined(__osf__)
+# define _PROTO_NET_H_
+#endif
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#if !defined(_KERNEL) && !defined(__KERNEL__)
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# define _KERNEL
+# ifdef __OpenBSD__
+struct file;
+# endif
+# include <sys/uio.h>
+# undef _KERNEL
+#else
+# include <sys/systm.h>
+# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000)
+# include <sys/proc.h>
+# endif
+#endif
+#include <sys/time.h>
+#if !defined(linux)
+# include <sys/protosw.h>
+#endif
+#include <sys/socket.h>
+#if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__))
+# include <sys/mbuf.h>
+#endif
+#if defined(__SVR4) || defined(__svr4__)
+# include <sys/filio.h>
+# include <sys/byteorder.h>
+# ifdef _KERNEL
+# include <sys/dditypes.h>
+# endif
+# include <sys/stream.h>
+# include <sys/kmem.h>
+#endif
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
+# include <sys/malloc.h>
+#endif
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_dstlist.h"
+
+/* END OF INCLUDES */
+
+#ifdef HAS_SYS_MD5_H
+# include <sys/md5.h>
+#else
+# include "md5.h"
+#endif
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id: ip_dstlist.c,v 1.13.2.12 2012/07/20 08:40:19 darren_r Exp $";
+#endif
+
+typedef struct ipf_dstl_softc_s {
+ ippool_dst_t *dstlist[LOOKUP_POOL_SZ];
+ ippool_dst_t **tails[LOOKUP_POOL_SZ];
+ ipf_dstl_stat_t stats;
+} ipf_dstl_softc_t;
+
+
+static void *ipf_dstlist_soft_create __P((ipf_main_softc_t *));
+static void ipf_dstlist_soft_destroy __P((ipf_main_softc_t *, void *));
+static int ipf_dstlist_soft_init __P((ipf_main_softc_t *, void *));
+static void ipf_dstlist_soft_fini __P((ipf_main_softc_t *, void *));
+static int ipf_dstlist_addr_find __P((ipf_main_softc_t *, void *, int,
+ void *, u_int));
+static size_t ipf_dstlist_flush __P((ipf_main_softc_t *, void *,
+ iplookupflush_t *));
+static int ipf_dstlist_iter_deref __P((ipf_main_softc_t *, void *, int, int,
+ void *));
+static int ipf_dstlist_iter_next __P((ipf_main_softc_t *, void *, ipftoken_t *,
+ ipflookupiter_t *));
+static int ipf_dstlist_node_add __P((ipf_main_softc_t *, void *,
+ iplookupop_t *, int));
+static int ipf_dstlist_node_del __P((ipf_main_softc_t *, void *,
+ iplookupop_t *, int));
+static int ipf_dstlist_stats_get __P((ipf_main_softc_t *, void *,
+ iplookupop_t *));
+static int ipf_dstlist_table_add __P((ipf_main_softc_t *, void *,
+ iplookupop_t *));
+static int ipf_dstlist_table_del __P((ipf_main_softc_t *, void *,
+ iplookupop_t *));
+static int ipf_dstlist_table_deref __P((ipf_main_softc_t *, void *, void *));
+static void *ipf_dstlist_table_find __P((void *, int, char *));
+static void ipf_dstlist_table_free __P((ipf_dstl_softc_t *, ippool_dst_t *));
+static void ipf_dstlist_table_remove __P((ipf_main_softc_t *,
+ ipf_dstl_softc_t *, ippool_dst_t *));
+static void ipf_dstlist_table_clearnodes __P((ipf_dstl_softc_t *,
+ ippool_dst_t *));
+static ipf_dstnode_t *ipf_dstlist_select __P((fr_info_t *, ippool_dst_t *));
+static void *ipf_dstlist_select_ref __P((void *, int, char *));
+static void ipf_dstlist_node_free __P((ipf_dstl_softc_t *, ippool_dst_t *, ipf_dstnode_t *));
+static int ipf_dstlist_node_deref __P((void *, ipf_dstnode_t *));
+static void ipf_dstlist_expire __P((ipf_main_softc_t *, void *));
+static void ipf_dstlist_sync __P((ipf_main_softc_t *, void *));
+
+ipf_lookup_t ipf_dstlist_backend = {
+ IPLT_DSTLIST,
+ ipf_dstlist_soft_create,
+ ipf_dstlist_soft_destroy,
+ ipf_dstlist_soft_init,
+ ipf_dstlist_soft_fini,
+ ipf_dstlist_addr_find,
+ ipf_dstlist_flush,
+ ipf_dstlist_iter_deref,
+ ipf_dstlist_iter_next,
+ ipf_dstlist_node_add,
+ ipf_dstlist_node_del,
+ ipf_dstlist_stats_get,
+ ipf_dstlist_table_add,
+ ipf_dstlist_table_del,
+ ipf_dstlist_table_deref,
+ ipf_dstlist_table_find,
+ ipf_dstlist_select_ref,
+ ipf_dstlist_select_node,
+ ipf_dstlist_expire,
+ ipf_dstlist_sync
+};
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_soft_create */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Allocating a chunk of memory filled with 0's is enough for the current */
+/* soft context used with destination lists. */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_dstlist_soft_create(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_dstl_softc_t *softd;
+ int i;
+
+ KMALLOC(softd, ipf_dstl_softc_t *);
+ if (softd == NULL) {
+ IPFERROR(120028);
+ return NULL;
+ }
+
+ bzero((char *)softd, sizeof(*softd));
+ for (i = 0; i <= IPL_LOGMAX; i++)
+ softd->tails[i] = &softd->dstlist[i];
+
+ return softd;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_soft_destroy */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* For destination lists, the only thing we have to do when destroying the */
+/* soft context is free it! */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_soft_destroy(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_dstl_softc_t *softd = arg;
+
+ KFREE(softd);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_soft_init */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* There is currently no soft context for destination list management. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_soft_init(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_soft_fini */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* There is currently no soft context for destination list management. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_soft_fini(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_dstl_softc_t *softd = arg;
+ int i;
+
+ for (i = -1; i <= IPL_LOGMAX; i++) {
+ while (softd->dstlist[i + 1] != NULL) {
+ ipf_dstlist_table_remove(softc, softd,
+ softd->dstlist[i + 1]);
+ }
+ }
+
+ ASSERT(softd->stats.ipls_numderefnodes == 0);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_addr_find */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg1(I) - pointer to local context to use */
+/* arg2(I) - pointer to local context to use */
+/* arg3(I) - pointer to local context to use */
+/* arg4(I) - pointer to local context to use */
+/* */
+/* There is currently no such thing as searching a destination list for an */
+/* address so this function becomes a no-op. Its presence is required as */
+/* ipf_lookup_res_name() stores the "addr_find" function pointer in the */
+/* pointer passed in to it as funcptr, although it could be a generic null- */
+/* op function rather than a specific one. */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+static int
+ipf_dstlist_addr_find(softc, arg1, arg2, arg3, arg4)
+ ipf_main_softc_t *softc;
+ void *arg1, *arg3;
+ int arg2;
+ u_int arg4;
+{
+ return -1;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_flush */
+/* Returns: int - number of objects deleted */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* fop(I) - pointer to lookup flush operation data */
+/* */
+/* Flush all of the destination tables that match the data passed in with */
+/* the iplookupflush_t. There are two ways to match objects: the device for */
+/* which they are to be used with and their name. */
+/* ------------------------------------------------------------------------ */
+static size_t
+ipf_dstlist_flush(softc, arg, fop)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupflush_t *fop;
+{
+ ipf_dstl_softc_t *softd = arg;
+ ippool_dst_t *node, *next;
+ int n, i;
+
+ for (n = 0, i = -1; i <= IPL_LOGMAX; i++) {
+ if (fop->iplf_unit != IPLT_ALL && fop->iplf_unit != i)
+ continue;
+ for (node = softd->dstlist[i + 1]; node != NULL; node = next) {
+ next = node->ipld_next;
+
+ if ((*fop->iplf_name != '\0') &&
+ strncmp(fop->iplf_name, node->ipld_name,
+ FR_GROUPLEN))
+ continue;
+
+ ipf_dstlist_table_remove(softc, softd, node);
+ n++;
+ }
+ }
+ return n;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_iter_deref */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* otype(I) - type of data structure to iterate through */
+/* unit(I) - device we are working with */
+/* data(I) - address of object in kernel space */
+/* */
+/* This function is called when the iteration token is being free'd and is */
+/* responsible for dropping the reference count of the structure it points */
+/* to. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_iter_deref(softc, arg, otype, unit, data)
+ ipf_main_softc_t *softc;
+ void *arg;
+ int otype, unit;
+ void *data;
+{
+ if (data == NULL) {
+ IPFERROR(120001);
+ return EINVAL;
+ }
+
+ if (unit < -1 || unit > IPL_LOGMAX) {
+ IPFERROR(120002);
+ return EINVAL;
+ }
+
+ switch (otype)
+ {
+ case IPFLOOKUPITER_LIST :
+ ipf_dstlist_table_deref(softc, arg, (ippool_dst_t *)data);
+ break;
+
+ case IPFLOOKUPITER_NODE :
+ ipf_dstlist_node_deref(arg, (ipf_dstnode_t *)data);
+ break;
+ }
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_iter_next */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* uid(I) - uid of process doing the ioctl */
+/* */
+/* This function is responsible for either selecting the next destination */
+/* list or node on a destination list to be returned as a user process */
+/* iterates through the list of destination lists or nodes. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_iter_next(softc, arg, token, iter)
+ ipf_main_softc_t *softc;
+ void *arg;
+ ipftoken_t *token;
+ ipflookupiter_t *iter;
+{
+ ipf_dstnode_t zn, *nextnode = NULL, *node = NULL;
+ ippool_dst_t zero, *next = NULL, *dsttab = NULL;
+ ipf_dstl_softc_t *softd = arg;
+ int err = 0;
+ void *hint;
+
+ switch (iter->ili_otype)
+ {
+ case IPFLOOKUPITER_LIST :
+ dsttab = token->ipt_data;
+ if (dsttab == NULL) {
+ next = softd->dstlist[(int)iter->ili_unit + 1];
+ } else {
+ next = dsttab->ipld_next;
+ }
+
+ if (next != NULL) {
+ ATOMIC_INC32(next->ipld_ref);
+ token->ipt_data = next;
+ hint = next->ipld_next;
+ } else {
+ bzero((char *)&zero, sizeof(zero));
+ next = &zero;
+ token->ipt_data = NULL;
+ hint = NULL;
+ }
+ break;
+
+ case IPFLOOKUPITER_NODE :
+ node = token->ipt_data;
+ if (node == NULL) {
+ dsttab = ipf_dstlist_table_find(arg, iter->ili_unit,
+ iter->ili_name);
+ if (dsttab == NULL) {
+ IPFERROR(120004);
+ err = ESRCH;
+ nextnode = NULL;
+ } else {
+ if (dsttab->ipld_dests == NULL)
+ nextnode = NULL;
+ else
+ nextnode = *dsttab->ipld_dests;
+ dsttab = NULL;
+ }
+ } else {
+ nextnode = node->ipfd_next;
+ }
+
+ if (nextnode != NULL) {
+ MUTEX_ENTER(&nextnode->ipfd_lock);
+ nextnode->ipfd_ref++;
+ MUTEX_EXIT(&nextnode->ipfd_lock);
+ token->ipt_data = nextnode;
+ hint = nextnode->ipfd_next;
+ } else {
+ bzero((char *)&zn, sizeof(zn));
+ nextnode = &zn;
+ token->ipt_data = NULL;
+ hint = NULL;
+ }
+ break;
+ default :
+ IPFERROR(120003);
+ err = EINVAL;
+ break;
+ }
+
+ if (err != 0)
+ return err;
+
+ switch (iter->ili_otype)
+ {
+ case IPFLOOKUPITER_LIST :
+ if (dsttab != NULL)
+ ipf_dstlist_table_deref(softc, arg, dsttab);
+ err = COPYOUT(next, iter->ili_data, sizeof(*next));
+ if (err != 0) {
+ IPFERROR(120005);
+ err = EFAULT;
+ }
+ break;
+
+ case IPFLOOKUPITER_NODE :
+ if (node != NULL)
+ ipf_dstlist_node_deref(arg, node);
+ err = COPYOUT(nextnode, iter->ili_data, sizeof(*nextnode));
+ if (err != 0) {
+ IPFERROR(120006);
+ err = EFAULT;
+ }
+ break;
+ }
+
+ if (hint == NULL)
+ ipf_token_mark_complete(token);
+
+ return err;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_node_add */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* uid(I) - uid of process doing the ioctl */
+/* Locks: WRITE(ipf_poolrw) */
+/* */
+/* Add a new node to a destination list. To do this, we only copy in the */
+/* frdest_t structure because that contains the only data required from the */
+/* application to create a new node. The frdest_t doesn't contain the name */
+/* itself. When loading filter rules, fd_name is a 'pointer' to the name. */
+/* In this case, the 'pointer' does not work, instead it is the length of */
+/* the name and the name is immediately following the frdest_t structure. */
+/* fd_name must include the trailing \0, so it should be strlen(str) + 1. */
+/* For simple sanity checking, an upper bound on the size of fd_name is */
+/* imposed - 128. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_node_add(softc, arg, op, uid)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
+ int uid;
+{
+ ipf_dstl_softc_t *softd = arg;
+ ipf_dstnode_t *node, **nodes;
+ ippool_dst_t *d;
+ frdest_t dest;
+ int err;
+
+ if (op->iplo_size < sizeof(frdest_t)) {
+ IPFERROR(120007);
+ return EINVAL;
+ }
+
+ err = COPYIN(op->iplo_struct, &dest, sizeof(dest));
+ if (err != 0) {
+ IPFERROR(120009);
+ return EFAULT;
+ }
+
+ d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
+ if (d == NULL) {
+ IPFERROR(120010);
+ return ESRCH;
+ }
+
+ switch (dest.fd_addr.adf_family)
+ {
+ case AF_INET :
+ case AF_INET6 :
+ break;
+ default :
+ IPFERROR(120019);
+ return EINVAL;
+ }
+
+ if (dest.fd_name < -1 || dest.fd_name > 128) {
+ IPFERROR(120018);
+ return EINVAL;
+ }
+
+ KMALLOCS(node, ipf_dstnode_t *, sizeof(*node) + dest.fd_name);
+ if (node == NULL) {
+ softd->stats.ipls_nomem++;
+ IPFERROR(120008);
+ return ENOMEM;
+ }
+ bzero((char *)node, sizeof(*node) + dest.fd_name);
+
+ bcopy(&dest, &node->ipfd_dest, sizeof(dest));
+ node->ipfd_size = sizeof(*node) + dest.fd_name;
+
+ if (dest.fd_name > 0) {
+ /*
+ * fd_name starts out as the length of the string to copy
+ * in (including \0) and ends up being the offset from
+ * fd_names (0).
+ */
+ err = COPYIN((char *)op->iplo_struct + sizeof(dest),
+ node->ipfd_names, dest.fd_name);
+ if (err != 0) {
+ IPFERROR(120017);
+ KFREES(node, node->ipfd_size);
+ return EFAULT;
+ }
+ node->ipfd_dest.fd_name = 0;
+ } else {
+ node->ipfd_dest.fd_name = -1;
+ }
+
+ if (d->ipld_nodes == d->ipld_maxnodes) {
+ KMALLOCS(nodes, ipf_dstnode_t **,
+ sizeof(*nodes) * (d->ipld_maxnodes + 1));
+ if (nodes == NULL) {
+ softd->stats.ipls_nomem++;
+ IPFERROR(120022);
+ KFREES(node, node->ipfd_size);
+ return ENOMEM;
+ }
+ if (d->ipld_dests != NULL) {
+ bcopy(d->ipld_dests, nodes,
+ sizeof(*nodes) * d->ipld_maxnodes);
+ KFREES(d->ipld_dests, sizeof(*nodes) * d->ipld_nodes);
+ nodes[0]->ipfd_pnext = nodes;
+ }
+ d->ipld_dests = nodes;
+ d->ipld_maxnodes++;
+ }
+ d->ipld_dests[d->ipld_nodes] = node;
+ d->ipld_nodes++;
+
+ if (d->ipld_nodes == 1) {
+ node->ipfd_pnext = d->ipld_dests;
+ } else if (d->ipld_nodes > 1) {
+ node->ipfd_pnext = &d->ipld_dests[d->ipld_nodes - 2]->ipfd_next;
+ }
+ *node->ipfd_pnext = node;
+
+ MUTEX_INIT(&node->ipfd_lock, "ipf dst node lock");
+ node->ipfd_uid = uid;
+ node->ipfd_ref = 1;
+ if (node->ipfd_dest.fd_name == 0)
+ (void) ipf_resolvedest(softc, node->ipfd_names,
+ &node->ipfd_dest, AF_INET);
+#ifdef USE_INET6
+ if (node->ipfd_dest.fd_name == 0 &&
+ node->ipfd_dest.fd_ptr == (void *)-1)
+ (void) ipf_resolvedest(softc, node->ipfd_names,
+ &node->ipfd_dest, AF_INET6);
+#endif
+
+ softd->stats.ipls_numnodes++;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_node_deref */
+/* Returns: int - 0 = success, else error */
+/* Parameters: arg(I) - pointer to local context to use */
+/* node(I) - pointer to destionation node to free */
+/* */
+/* Dereference the use count by one. If it drops to zero then we can assume */
+/* that it has been removed from any lists/tables and is ripe for freeing. */
+/* The pointer to context is required for the purpose of maintaining */
+/* statistics. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_node_deref(arg, node)
+ void *arg;
+ ipf_dstnode_t *node;
+{
+ ipf_dstl_softc_t *softd = arg;
+ int ref;
+
+ MUTEX_ENTER(&node->ipfd_lock);
+ ref = --node->ipfd_ref;
+ MUTEX_EXIT(&node->ipfd_lock);
+
+ if (ref > 0)
+ return 0;
+
+ if ((node->ipfd_flags & IPDST_DELETE) != 0)
+ softd->stats.ipls_numderefnodes--;
+ MUTEX_DESTROY(&node->ipfd_lock);
+ KFREES(node, node->ipfd_size);
+ softd->stats.ipls_numnodes--;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_node_del */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* uid(I) - uid of process doing the ioctl */
+/* */
+/* Look for a matching destination node on the named table and free it if */
+/* found. Because the name embedded in the frdest_t is variable in length, */
+/* it is necessary to allocate some memory locally, to complete this op. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_node_del(softc, arg, op, uid)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
+ int uid;
+{
+ ipf_dstl_softc_t *softd = arg;
+ ipf_dstnode_t *node;
+ frdest_t frd, *temp;
+ ippool_dst_t *d;
+ size_t size;
+ int err;
+
+ d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
+ if (d == NULL) {
+ IPFERROR(120012);
+ return ESRCH;
+ }
+
+ err = COPYIN(op->iplo_struct, &frd, sizeof(frd));
+ if (err != 0) {
+ IPFERROR(120011);
+ return EFAULT;
+ }
+
+ size = sizeof(*temp) + frd.fd_name;
+ KMALLOCS(temp, frdest_t *, size);
+ if (temp == NULL) {
+ softd->stats.ipls_nomem++;
+ IPFERROR(120026);
+ return ENOMEM;
+ }
+
+ err = COPYIN(op->iplo_struct, temp, size);
+ if (err != 0) {
+ IPFERROR(120027);
+ return EFAULT;
+ }
+
+ MUTEX_ENTER(&d->ipld_lock);
+ for (node = *d->ipld_dests; node != NULL; node = node->ipfd_next) {
+ if ((uid != 0) && (node->ipfd_uid != uid))
+ continue;
+ if (node->ipfd_size != size)
+ continue;
+ if (!bcmp(&node->ipfd_dest.fd_ip6, &frd.fd_ip6,
+ size - offsetof(frdest_t, fd_ip6))) {
+ ipf_dstlist_node_free(softd, d, node);
+ MUTEX_EXIT(&d->ipld_lock);
+ KFREES(temp, size);
+ return 0;
+ }
+ }
+ MUTEX_EXIT(&d->ipld_lock);
+ KFREES(temp, size);
+
+ return ESRCH;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_node_free */
+/* Returns: Nil */
+/* Parameters: softd(I) - pointer to the destination list context */
+/* d(I) - pointer to destination list */
+/* node(I) - pointer to node to free */
+/* Locks: MUTEX(ipld_lock) or WRITE(ipf_poolrw) */
+/* */
+/* Free the destination node by first removing it from any lists and then */
+/* checking if this was the last reference held to the object. While the */
+/* array of pointers to nodes is compacted, its size isn't reduced (by way */
+/* of allocating a new smaller one and copying) because the belief is that */
+/* it is likely the array will again reach that size. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_node_free(softd, d, node)
+ ipf_dstl_softc_t *softd;
+ ippool_dst_t *d;
+ ipf_dstnode_t *node;
+{
+ int i;
+
+ /*
+ * Compact the array of pointers to nodes.
+ */
+ for (i = 0; i < d->ipld_nodes; i++)
+ if (d->ipld_dests[i] == node)
+ break;
+ if (d->ipld_nodes - i > 1) {
+ bcopy(&d->ipld_dests[i + 1], &d->ipld_dests[i],
+ sizeof(*d->ipld_dests) * (d->ipld_nodes - i - 1));
+ }
+ d->ipld_nodes--;
+
+ if (node->ipfd_pnext != NULL)
+ *node->ipfd_pnext = node->ipfd_next;
+ if (node->ipfd_next != NULL)
+ node->ipfd_next->ipfd_pnext = node->ipfd_pnext;
+ node->ipfd_pnext = NULL;
+ node->ipfd_next = NULL;
+
+ if ((node->ipfd_flags & IPDST_DELETE) == 0) {
+ softd->stats.ipls_numderefnodes++;
+ node->ipfd_flags |= IPDST_DELETE;
+ }
+
+ ipf_dstlist_node_deref(softd, node);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_stats_get */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* */
+/* Return the current statistics for destination lists. This may be for all */
+/* of them or just information pertaining to a particular table. */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+static int
+ipf_dstlist_stats_get(softc, arg, op)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
+{
+ ipf_dstl_softc_t *softd = arg;
+ ipf_dstl_stat_t stats;
+ int unit, i, err = 0;
+
+ if (op->iplo_size != sizeof(ipf_dstl_stat_t)) {
+ IPFERROR(120023);
+ return EINVAL;
+ }
+
+ stats = softd->stats;
+ unit = op->iplo_unit;
+ if (unit == IPL_LOGALL) {
+ for (i = 0; i <= IPL_LOGMAX; i++)
+ stats.ipls_list[i] = softd->dstlist[i];
+ } else if (unit >= 0 && unit <= IPL_LOGMAX) {
+ void *ptr;
+
+ if (op->iplo_name[0] != '\0')
+ ptr = ipf_dstlist_table_find(softd, unit,
+ op->iplo_name);
+ else
+ ptr = softd->dstlist[unit + 1];
+ stats.ipls_list[unit] = ptr;
+ } else {
+ IPFERROR(120024);
+ err = EINVAL;
+ }
+
+ if (err == 0) {
+ err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
+ if (err != 0) {
+ IPFERROR(120025);
+ return EFAULT;
+ }
+ }
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_table_add */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* */
+/* Add a new destination table to the list of those available for the given */
+/* device. Because we seldom operate on these objects (find/add/delete), */
+/* they are just kept in a simple linked list. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_table_add(softc, arg, op)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
+{
+ ipf_dstl_softc_t *softd = arg;
+ ippool_dst_t user, *d, *new;
+ int unit, err;
+
+ d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
+ if (d != NULL) {
+ IPFERROR(120013);
+ return EEXIST;
+ }
+
+ err = COPYIN(op->iplo_struct, &user, sizeof(user));
+ if (err != 0) {
+ IPFERROR(120021);
+ return EFAULT;
+ }
+
+ KMALLOC(new, ippool_dst_t *);
+ if (new == NULL) {
+ softd->stats.ipls_nomem++;
+ IPFERROR(120014);
+ return ENOMEM;
+ }
+ bzero((char *)new, sizeof(*new));
+
+ MUTEX_INIT(&new->ipld_lock, "ipf dst table lock");
+
+ strncpy(new->ipld_name, op->iplo_name, FR_GROUPLEN);
+ unit = op->iplo_unit;
+ new->ipld_unit = unit;
+ new->ipld_policy = user.ipld_policy;
+ new->ipld_seed = ipf_random();
+ new->ipld_ref = 1;
+
+ new->ipld_pnext = softd->tails[unit + 1];
+ *softd->tails[unit + 1] = new;
+ softd->tails[unit + 1] = &new->ipld_next;
+ softd->stats.ipls_numlists++;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_table_del */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* */
+/* Find a named destinstion list table and delete it. If there are other */
+/* references to it, the caller isn't told. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_table_del(softc, arg, op)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
+{
+ ippool_dst_t *d;
+
+ d = ipf_dstlist_table_find(arg, op->iplo_unit, op->iplo_name);
+ if (d == NULL) {
+ IPFERROR(120015);
+ return ESRCH;
+ }
+
+ if (d->ipld_dests != NULL) {
+ IPFERROR(120016);
+ return EBUSY;
+ }
+
+ ipf_dstlist_table_remove(softc, arg, d);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_table_remove */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softd(I) - pointer to the destination list context */
+/* d(I) - pointer to destination list */
+/* */
+/* Remove a given destination list from existance. While the IPDST_DELETE */
+/* flag is set every time we call this function and the reference count is */
+/* non-zero, the "numdereflists" counter is always incremented because the */
+/* decision about whether it will be freed or not is not made here. This */
+/* means that the only action the code can take here is to treat it as if */
+/* it will become a detached. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_table_remove(softc, softd, d)
+ ipf_main_softc_t *softc;
+ ipf_dstl_softc_t *softd;
+ ippool_dst_t *d;
+{
+
+ if (softd->tails[d->ipld_unit + 1] == &d->ipld_next)
+ softd->tails[d->ipld_unit + 1] = d->ipld_pnext;
+
+ if (d->ipld_pnext != NULL)
+ *d->ipld_pnext = d->ipld_next;
+ if (d->ipld_next != NULL)
+ d->ipld_next->ipld_pnext = d->ipld_pnext;
+ d->ipld_pnext = NULL;
+ d->ipld_next = NULL;
+
+ ipf_dstlist_table_clearnodes(softd, d);
+
+ softd->stats.ipls_numdereflists++;
+ d->ipld_flags |= IPDST_DELETE;
+
+ ipf_dstlist_table_deref(softc, softd, d);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_table_free */
+/* Returns: Nil */
+/* Parameters: softd(I) - pointer to the destination list context */
+/* d(I) - pointer to destination list */
+/* */
+/* Free up a destination list data structure and any other memory that was */
+/* directly allocated as part of creating it. Individual destination list */
+/* nodes are not freed. It is assumed the caller will have already emptied */
+/* the destination list. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_table_free(softd, d)
+ ipf_dstl_softc_t *softd;
+ ippool_dst_t *d;
+{
+ MUTEX_DESTROY(&d->ipld_lock);
+
+ if ((d->ipld_flags & IPDST_DELETE) != 0)
+ softd->stats.ipls_numdereflists--;
+ softd->stats.ipls_numlists--;
+
+ if (d->ipld_dests != NULL) {
+ KFREES(d->ipld_dests,
+ d->ipld_maxnodes * sizeof(*d->ipld_dests));
+ }
+
+ KFREE(d);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_table_deref */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* */
+/* Drops the reference count on a destination list table object and free's */
+/* it if 0 has been reached. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_dstlist_table_deref(softc, arg, table)
+ ipf_main_softc_t *softc;
+ void *arg;
+ void *table;
+{
+ ippool_dst_t *d = table;
+
+ d->ipld_ref--;
+ if (d->ipld_ref > 0)
+ return d->ipld_ref;
+
+ ipf_dstlist_table_free(arg, d);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_table_clearnodes */
+/* Returns: Nil */
+/* Parameters: softd(I) - pointer to the destination list context */
+/* dst(I) - pointer to destination list */
+/* */
+/* Free all of the destination nodes attached to the given table. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_table_clearnodes(softd, dst)
+ ipf_dstl_softc_t *softd;
+ ippool_dst_t *dst;
+{
+ ipf_dstnode_t *node;
+
+ if (dst->ipld_dests == NULL)
+ return;
+
+ while ((node = *dst->ipld_dests) != NULL) {
+ ipf_dstlist_node_free(softd, dst, node);
+ }
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_table_find */
+/* Returns: int - 0 = success, else error */
+/* Parameters: arg(I) - pointer to local context to use */
+/* unit(I) - device we are working with */
+/* name(I) - destination table name to find */
+/* */
+/* Return a pointer to a destination table that matches the unit+name that */
+/* is passed in. */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_dstlist_table_find(arg, unit, name)
+ void *arg;
+ int unit;
+ char *name;
+{
+ ipf_dstl_softc_t *softd = arg;
+ ippool_dst_t *d;
+
+ for (d = softd->dstlist[unit + 1]; d != NULL; d = d->ipld_next) {
+ if ((d->ipld_unit == unit) &&
+ !strncmp(d->ipld_name, name, FR_GROUPLEN)) {
+ return d;
+ }
+ }
+
+ return NULL;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_select_ref */
+/* Returns: void * - NULL = failure, else pointer to table */
+/* Parameters: arg(I) - pointer to local context to use */
+/* unit(I) - device we are working with */
+/* name(I) - destination table name to find */
+/* */
+/* Attempt to find a destination table that matches the name passed in and */
+/* if successful, bump up the reference count on it because we intend to */
+/* store the pointer to it somewhere else. */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_dstlist_select_ref(arg, unit, name)
+ void *arg;
+ int unit;
+ char *name;
+{
+ ippool_dst_t *d;
+
+ d = ipf_dstlist_table_find(arg, unit, name);
+ if (d != NULL) {
+ MUTEX_ENTER(&d->ipld_lock);
+ d->ipld_ref++;
+ MUTEX_EXIT(&d->ipld_lock);
+ }
+ return d;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_select */
+/* Returns: void * - NULL = failure, else pointer to table */
+/* Parameters: fin(I) - pointer to packet information */
+/* d(I) - pointer to destination list */
+/* */
+/* Find the next node in the destination list to be used according to the */
+/* defined policy. Of these, "connection" is the most expensive policy to */
+/* implement as it always looks for the node with the least number of */
+/* connections associated with it. */
+/* */
+/* The hashes exclude the port numbers so that all protocols map to the */
+/* same destination. Otherwise, someone doing a ping would target a */
+/* different server than their TCP connection, etc. MD-5 is used to */
+/* transform the addressese into something random that the other end could */
+/* not easily guess and use in an attack. ipld_seed introduces an unknown */
+/* into the hash calculation to increase the difficult of an attacker */
+/* guessing the bucket. */
+/* */
+/* One final comment: mixing different address families in a single pool */
+/* will currently result in failures as the address family of the node is */
+/* only matched up with that in the packet as the last step. While this can */
+/* be coded around for the weighted connection and round-robin models, it */
+/* cannot be supported for the hash/random models as they do not search and */
+/* nor is the algorithm conducive to searching. */
+/* ------------------------------------------------------------------------ */
+static ipf_dstnode_t *
+ipf_dstlist_select(fin, d)
+ fr_info_t *fin;
+ ippool_dst_t *d;
+{
+ ipf_dstnode_t *node, *sel;
+ int connects;
+ u_32_t hash[4];
+ MD5_CTX ctx;
+ int family;
+ int x;
+
+ if (d->ipld_dests == NULL || *d->ipld_dests == NULL)
+ return NULL;
+
+ family = fin->fin_family;
+
+ MUTEX_ENTER(&d->ipld_lock);
+
+ switch (d->ipld_policy)
+ {
+ case IPLDP_ROUNDROBIN:
+ sel = d->ipld_selected;
+ if (sel == NULL) {
+ sel = *d->ipld_dests;
+ } else {
+ sel = sel->ipfd_next;
+ if (sel == NULL)
+ sel = *d->ipld_dests;
+ }
+ break;
+
+ case IPLDP_CONNECTION:
+ if (d->ipld_selected == NULL) {
+ sel = *d->ipld_dests;
+ break;
+ }
+
+ sel = d->ipld_selected;
+ connects = 0x7fffffff;
+ node = sel->ipfd_next;
+ if (node == NULL)
+ node = *d->ipld_dests;
+ while (node != d->ipld_selected) {
+ if (node->ipfd_states == 0) {
+ sel = node;
+ break;
+ }
+ if (node->ipfd_states < connects) {
+ sel = node;
+ connects = node->ipfd_states;
+ }
+ node = node->ipfd_next;
+ if (node == NULL)
+ node = *d->ipld_dests;
+ }
+ break;
+
+ case IPLDP_RANDOM :
+ x = ipf_random() % d->ipld_nodes;
+ sel = d->ipld_dests[x];
+ break;
+
+ case IPLDP_HASHED :
+ MD5Init(&ctx);
+ MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed));
+ MD5Update(&ctx, (u_char *)&fin->fin_src6,
+ sizeof(fin->fin_src6));
+ MD5Update(&ctx, (u_char *)&fin->fin_dst6,
+ sizeof(fin->fin_dst6));
+ MD5Final((u_char *)hash, &ctx);
+ x = hash[0] % d->ipld_nodes;
+ sel = d->ipld_dests[x];
+ break;
+
+ case IPLDP_SRCHASH :
+ MD5Init(&ctx);
+ MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed));
+ MD5Update(&ctx, (u_char *)&fin->fin_src6,
+ sizeof(fin->fin_src6));
+ MD5Final((u_char *)hash, &ctx);
+ x = hash[0] % d->ipld_nodes;
+ sel = d->ipld_dests[x];
+ break;
+
+ case IPLDP_DSTHASH :
+ MD5Init(&ctx);
+ MD5Update(&ctx, (u_char *)&d->ipld_seed, sizeof(d->ipld_seed));
+ MD5Update(&ctx, (u_char *)&fin->fin_dst6,
+ sizeof(fin->fin_dst6));
+ MD5Final((u_char *)hash, &ctx);
+ x = hash[0] % d->ipld_nodes;
+ sel = d->ipld_dests[x];
+ break;
+
+ default :
+ sel = NULL;
+ break;
+ }
+
+ if (sel->ipfd_dest.fd_addr.adf_family != family)
+ sel = NULL;
+ d->ipld_selected = sel;
+
+ MUTEX_EXIT(&d->ipld_lock);
+
+ return sel;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_select_node */
+/* Returns: int - -1 == failure, 0 == success */
+/* Parameters: fin(I) - pointer to packet information */
+/* group(I) - destination pool to search */
+/* addr(I) - pointer to store selected address */
+/* pfdp(O) - pointer to storage for selected destination node */
+/* */
+/* This function is only responsible for obtaining the next IP address for */
+/* use and storing it in the caller's address space (addr). "addr" is only */
+/* used for storage if pfdp is NULL. No permanent reference is currently */
+/* kept on the node. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_dstlist_select_node(fin, group, addr, pfdp)
+ fr_info_t *fin;
+ void *group;
+ u_32_t *addr;
+ frdest_t *pfdp;
+{
+#ifdef USE_MUTEXES
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+#endif
+ ippool_dst_t *d = group;
+ ipf_dstnode_t *node;
+ frdest_t *fdp;
+
+ READ_ENTER(&softc->ipf_poolrw);
+
+ node = ipf_dstlist_select(fin, d);
+ if (node == NULL) {
+ RWLOCK_EXIT(&softc->ipf_poolrw);
+ return -1;
+ }
+
+ if (pfdp != NULL) {
+ bcopy(&node->ipfd_dest, pfdp, sizeof(*pfdp));
+ } else {
+ if (fin->fin_family == AF_INET) {
+ addr[0] = node->ipfd_dest.fd_addr.adf_addr.i6[0];
+ } else if (fin->fin_family == AF_INET6) {
+ addr[0] = node->ipfd_dest.fd_addr.adf_addr.i6[0];
+ addr[1] = node->ipfd_dest.fd_addr.adf_addr.i6[1];
+ addr[2] = node->ipfd_dest.fd_addr.adf_addr.i6[2];
+ addr[3] = node->ipfd_dest.fd_addr.adf_addr.i6[3];
+ }
+ }
+
+ fdp = &node->ipfd_dest;
+ if (fdp->fd_ptr == NULL)
+ fdp->fd_ptr = fin->fin_ifp;
+
+ MUTEX_ENTER(&node->ipfd_lock);
+ node->ipfd_states++;
+ MUTEX_EXIT(&node->ipfd_lock);
+
+ RWLOCK_EXIT(&softc->ipf_poolrw);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_expire */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* There are currently no objects to expire in destination lists. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_dstlist_expire(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ return;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_dstlist_sync */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* When a network interface appears or disappears, we need to revalidate */
+/* all of the network interface names that have been configured as a target */
+/* in a destination list. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_dstlist_sync(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_dstl_softc_t *softd = arg;
+ ipf_dstnode_t *node;
+ ippool_dst_t *list;
+ int i;
+ int j;
+
+ for (i = 0; i < IPL_LOGMAX; i++) {
+ for (list = softd->dstlist[i]; list != NULL;
+ list = list->ipld_next) {
+ for (j = 0; j < list->ipld_maxnodes; j++) {
+ node = list->ipld_dests[j];
+ if (node == NULL)
+ continue;
+ if (node->ipfd_dest.fd_name == -1)
+ continue;
+ (void) ipf_resolvedest(softc,
+ node->ipfd_names,
+ &node->ipfd_dest,
+ AF_INET);
+ }
+ }
+ }
+}
diff --git a/sys/contrib/ipfilter/netinet/ip_dstlist.h b/sys/contrib/ipfilter/netinet/ip_dstlist.h
new file mode 100644
index 0000000..e2885e5
--- /dev/null
+++ b/sys/contrib/ipfilter/netinet/ip_dstlist.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: ip_dstlist.h,v 1.5.2.6 2012/07/22 08:04:23 darren_r Exp $
+ */
+
+#ifndef __IP_DSTLIST_H__
+#define __IP_DSTLIST_H__
+
+typedef struct ipf_dstnode {
+ struct ipf_dstnode *ipfd_next;
+ struct ipf_dstnode **ipfd_pnext;
+ ipfmutex_t ipfd_lock;
+ frdest_t ipfd_dest;
+ u_long ipfd_syncat;
+ int ipfd_flags;
+ int ipfd_size;
+ int ipfd_states;
+ int ipfd_ref;
+ int ipfd_uid;
+ char ipfd_names[1];
+} ipf_dstnode_t;
+
+typedef enum ippool_policy_e {
+ IPLDP_NONE = 0,
+ IPLDP_ROUNDROBIN,
+ IPLDP_CONNECTION,
+ IPLDP_RANDOM,
+ IPLDP_HASHED,
+ IPLDP_SRCHASH,
+ IPLDP_DSTHASH
+} ippool_policy_t;
+
+typedef struct ippool_dst {
+ struct ippool_dst *ipld_next;
+ struct ippool_dst **ipld_pnext;
+ ipfmutex_t ipld_lock;
+ int ipld_seed;
+ int ipld_unit;
+ int ipld_ref;
+ int ipld_flags;
+ int ipld_nodes;
+ int ipld_maxnodes;
+ ippool_policy_t ipld_policy;
+ ipf_dstnode_t **ipld_dests;
+ ipf_dstnode_t *ipld_selected;
+ char ipld_name[FR_GROUPLEN];
+} ippool_dst_t;
+
+#define IPDST_DELETE 0x01
+
+typedef struct dstlist_stat_s {
+ void *ipls_list[LOOKUP_POOL_SZ];
+ int ipls_numlists;
+ u_long ipls_nomem;
+ int ipls_numnodes;
+ int ipls_numdereflists;
+ int ipls_numderefnodes;
+} ipf_dstl_stat_t;
+
+extern ipf_lookup_t ipf_dstlist_backend;
+
+extern int ipf_dstlist_select_node __P((fr_info_t *, void *, u_32_t *,
+ frdest_t *));
+
+#endif /* __IP_DSTLIST_H__ */
diff --git a/sys/contrib/ipfilter/netinet/ip_fil.h b/sys/contrib/ipfilter/netinet/ip_fil.h
index 0cd84b9..22a11c3 100644
--- a/sys/contrib/ipfilter/netinet/ip_fil.h
+++ b/sys/contrib/ipfilter/netinet/ip_fil.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1993-2001, 2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
@@ -12,6 +12,21 @@
#define __IP_FIL_H__
#include "netinet/ip_compat.h"
+#include "netinet/ipf_rb.h"
+#if NETBSD_GE_REV(104040000)
+# include <sys/callout.h>
+#endif
+#if defined(BSD) && defined(_KERNEL)
+# if NETBSD_LT_REV(399000000) || defined(__osf__) || FREEBSD_LT_REV(500043)
+# include <sys/select.h>
+# else
+# include <sys/selinfo.h>
+# endif
+#endif
+
+#if !defined(linux) || !defined(_KERNEL)
+# include <netinet/in.h>
+#endif
#ifndef SOLARIS
# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
@@ -63,6 +78,8 @@
# define SIOCIPFDELTOK _IOWR('r', 94, int)
# define SIOCLOOKUPITER _IOWR('r', 95, struct ipfobj)
# define SIOCGTQTAB _IOWR('r', 96, struct ipfobj)
+# define SIOCMATCHFLUSH _IOWR('r', 97, struct ipfobj)
+# define SIOCIPFINTERROR _IOR('r', 98, int)
#else
# define SIOCADAFR _IOW(r, 60, struct ipfobj)
# define SIOCRMAFR _IOW(r, 61, struct ipfobj)
@@ -101,6 +118,8 @@
# define SIOCIPFDELTOK _IOWR(r, 94, int)
# define SIOCLOOKUPITER _IOWR(r, 95, struct ipfobj)
# define SIOCGTQTAB _IOWR(r, 96, struct ipfobj)
+# define SIOCMATCHFLUSH _IOWR(r, 97, struct ipfobj)
+# define SIOCIPFINTERROR _IOR(r, 98, int)
#endif
#define SIOCADDFR SIOCADAFR
#define SIOCDELFR SIOCRMAFR
@@ -111,9 +130,10 @@
struct ipscan;
struct ifnet;
+struct ipf_main_softc_s;
-
-typedef int (* lookupfunc_t) __P((void *, int, void *));
+typedef int (* lookupfunc_t) __P((struct ipf_main_softc_s *, void *,
+ int, void *, u_int));
/*
* i6addr is used as a container for both IPv4 and IPv6 addresses, as well
@@ -129,7 +149,7 @@ typedef union i6addr {
struct {
u_short type;
u_short subtype;
- char label[12];
+ int name;
} i6un;
} i6addr_t;
#else
@@ -141,14 +161,14 @@ typedef union i6addr {
struct {
u_short type;
u_short subtype;
- char label[12];
+ int name;
} i6un;
} i6addr_t;
#endif
#define in4_addr in4.s_addr
#define iplookupnum i6[1]
-#define iplookupname i6un.label
+#define iplookupname i6un.name
#define iplookuptype i6un.type
#define iplookupsubtype i6un.subtype
/*
@@ -172,17 +192,25 @@ typedef union i6addr {
(I61(a) != I61(b)) || (I60(a) != I60(b)))
#define IP6_ISZERO(a) ((I60(a) | I61(a) | I62(a) | I63(a)) == 0)
#define IP6_NOTZERO(a) ((I60(a) | I61(a) | I62(a) | I63(a)) != 0)
-#define IP6_GT(a,b) (HI60(a) > HI60(b) || (HI60(a) == HI60(b) && \
- (HI61(a) > HI61(b) || (HI61(a) == HI61(b) && \
- (HI62(a) > HI62(b) || (HI62(a) == HI62(b) && \
- HI63(a) > HI63(b)))))))
-#define IP6_LT(a,b) (HI60(a) < HI60(b) || (HI60(a) == HI60(b) && \
- (HI61(a) < HI61(b) || (HI61(a) == HI61(b) && \
- (HI62(a) < HI62(b) || (HI62(a) == HI62(b) && \
- HI63(a) < HI63(b)))))))
+#define IP6_ISONES(a) ((I63(a) == 0xffffffff) && (I62(a) == 0xffffffff) && \
+ (I61(a) == 0xffffffff) && (I60(a) == 0xffffffff))
+#define IP6_GT(a,b) (ntohl(HI60(a)) > ntohl(HI60(b)) || \
+ (HI60(a) == HI60(b) && \
+ (ntohl(HI61(a)) > ntohl(HI61(b)) || \
+ (HI61(a) == HI61(b) && \
+ (ntohl(HI62(a)) > ntohl(HI62(b)) || \
+ (HI62(a) == HI62(b) && \
+ ntohl(HI63(a)) > ntohl(HI63(b))))))))
+#define IP6_LT(a,b) (ntohl(HI60(a)) < ntohl(HI60(b)) || \
+ (HI60(a) == HI60(b) && \
+ (ntohl(HI61(a)) < ntohl(HI61(b)) || \
+ (HI61(a) == HI61(b) && \
+ (ntohl(HI62(a)) < ntohl(HI62(b)) || \
+ (HI62(a) == HI62(b) && \
+ ntohl(HI63(a)) < ntohl(HI63(b))))))))
#define NLADD(n,x) htonl(ntohl(n) + (x))
#define IP6_INC(a) \
- { u_32_t *_i6 = (u_32_t *)(a); \
+ do { u_32_t *_i6 = (u_32_t *)(a); \
_i6[3] = NLADD(_i6[3], 1); \
if (_i6[3] == 0) { \
_i6[2] = NLADD(_i6[2], 1); \
@@ -193,9 +221,9 @@ typedef union i6addr {
} \
} \
} \
- }
+ } while (0)
#define IP6_ADD(a,x,d) \
- { i6addr_t *_s = (i6addr_t *)(a); \
+ do { i6addr_t *_s = (i6addr_t *)(a); \
i6addr_t *_d = (i6addr_t *)(d); \
_d->i6[0] = NLADD(_s->i6[0], x); \
if (ntohl(_d->i6[0]) < ntohl(_s->i6[0])) { \
@@ -207,26 +235,65 @@ typedef union i6addr {
} \
} \
} \
- }
-#define IP6_AND(a,b,d) { i6addr_t *_s1 = (i6addr_t *)(a); \
- i6addr_t *_s2 = (i6addr_t *)(d); \
+ } while (0)
+#define IP6_AND(a,b,d) do { i6addr_t *_s1 = (i6addr_t *)(a); \
+ i6addr_t *_s2 = (i6addr_t *)(b); \
i6addr_t *_d = (i6addr_t *)(d); \
_d->i6[0] = _s1->i6[0] & _s2->i6[0]; \
_d->i6[1] = _s1->i6[1] & _s2->i6[1]; \
_d->i6[2] = _s1->i6[2] & _s2->i6[2]; \
_d->i6[3] = _s1->i6[3] & _s2->i6[3]; \
- }
+ } while (0)
+#define IP6_ANDASSIGN(a,m) \
+ do { i6addr_t *_d = (i6addr_t *)(a); \
+ i6addr_t *_m = (i6addr_t *)(m); \
+ _d->i6[0] &= _m->i6[0]; \
+ _d->i6[1] &= _m->i6[1]; \
+ _d->i6[2] &= _m->i6[2]; \
+ _d->i6[3] &= _m->i6[3]; \
+ } while (0)
+#define IP6_MASKEQ(a,m,b) \
+ (((I60(a) & I60(m)) == I60(b)) && \
+ ((I61(a) & I61(m)) == I61(b)) && \
+ ((I62(a) & I62(m)) == I62(b)) && \
+ ((I63(a) & I63(m)) == I63(b)))
+#define IP6_MASKNEQ(a,m,b) \
+ (((I60(a) & I60(m)) != I60(b)) || \
+ ((I61(a) & I61(m)) != I61(b)) || \
+ ((I62(a) & I62(m)) != I62(b)) || \
+ ((I63(a) & I63(m)) != I63(b)))
#define IP6_MERGE(a,b,c) \
- { i6addr_t *_d, *_s1, *_s2; \
+ do { i6addr_t *_d, *_s1, *_s2; \
_d = (i6addr_t *)(a); \
_s1 = (i6addr_t *)(b); \
_s2 = (i6addr_t *)(c); \
_d->i6[0] |= _s1->i6[0] & ~_s2->i6[0]; \
_d->i6[1] |= _s1->i6[1] & ~_s2->i6[1]; \
_d->i6[2] |= _s1->i6[2] & ~_s2->i6[2]; \
- _d->i6[2] |= _s1->i6[3] & ~_s2->i6[3]; \
- }
-
+ _d->i6[3] |= _s1->i6[3] & ~_s2->i6[3]; \
+ } while (0)
+#define IP6_MASK(a,b,c) \
+ do { i6addr_t *_d, *_s1, *_s2; \
+ _d = (i6addr_t *)(a); \
+ _s1 = (i6addr_t *)(b); \
+ _s2 = (i6addr_t *)(c); \
+ _d->i6[0] = _s1->i6[0] & ~_s2->i6[0]; \
+ _d->i6[1] = _s1->i6[1] & ~_s2->i6[1]; \
+ _d->i6[2] = _s1->i6[2] & ~_s2->i6[2]; \
+ _d->i6[3] = _s1->i6[3] & ~_s2->i6[3]; \
+ } while (0)
+#define IP6_SETONES(a) \
+ do { i6addr_t *_d = (i6addr_t *)(a); \
+ _d->i6[0] = 0xffffffff; \
+ _d->i6[1] = 0xffffffff; \
+ _d->i6[2] = 0xffffffff; \
+ _d->i6[3] = 0xffffffff; \
+ } while (0)
+
+typedef union ipso_u {
+ u_short ipso_ripso[2];
+ u_32_t ipso_doi;
+} ipso_t;
typedef struct fr_ip {
u_32_t fi_v:4; /* IP version */
@@ -237,11 +304,13 @@ typedef struct fr_ip {
u_32_t fi_optmsk; /* bitmask composed from IP options */
i6addr_t fi_src; /* source address from packet */
i6addr_t fi_dst; /* destination address from packet */
- u_short fi_secmsk; /* bitmask composed from IP security options */
- u_short fi_auth; /* authentication code from IP sec. options */
+ ipso_t fi_ipso; /* IP security options */
u_32_t fi_flx; /* packet flags */
u_32_t fi_tcpmsk; /* TCP options set/reset */
- u_32_t fi_res1; /* RESERVED */
+ u_32_t fi_ports[2]; /* TCP ports */
+ u_char fi_tcpf; /* TCP flags */
+ u_char fi_sensitivity;
+ u_char fi_xxx[2]; /* pad */
} fr_ip_t;
/*
@@ -263,16 +332,23 @@ typedef struct fr_ip {
#define FI_FRAGBODY 0x2000
#define FI_BADSRC 0x4000
#define FI_LOWTTL 0x8000
-#define FI_CMP 0xcf03 /* Not FI_FRAG,FI_NATED,FI_FRAGTAIL,broadcast */
+#define FI_CMP 0x5cfe3 /* Not FI_FRAG,FI_NATED,FI_FRAGTAIL */
#define FI_ICMPCMP 0x0003 /* Flags we can check for ICMP error packets */
-#define FI_WITH 0xeffe /* Not FI_TCPUDP */
+#define FI_WITH 0x5effe /* Not FI_TCPUDP */
#define FI_V6EXTHDR 0x10000
#define FI_COALESCE 0x20000
#define FI_NEWNAT 0x40000
+#define FI_ICMPQUERY 0x80000
+#define FI_ENCAP 0x100000 /* encap/decap with NAT */
+#define FI_AH 0x200000 /* AH header present */
+#define FI_DOCKSUM 0x10000000 /* Proxy wants L4 recalculation */
#define FI_NOCKSUM 0x20000000 /* don't do a L4 checksum validation */
-#define FI_DONTCACHE 0x40000000 /* don't cache the result */
+#define FI_NOWILD 0x40000000 /* Do not do wildcard searches */
#define FI_IGNORE 0x80000000
+#define fi_secmsk fi_ipso.ipso_ripso[0]
+#define fi_auth fi_ipso.ipso_ripso[1]
+#define fi_doi fi_ipso.ipso_doi
#define fi_saddr fi_src.in4.s_addr
#define fi_daddr fi_dst.in4.s_addr
#define fi_srcnum fi_src.iplookupnum
@@ -303,37 +379,87 @@ typedef struct fr_ip {
#define SI_NEWFR 0x00001000
#define SI_CLONE 0x00002000
#define SI_CLONED 0x00004000
-
+#define SI_NEWCLONE 0x00008000
+
+typedef struct {
+ u_short fda_ports[2];
+ u_char fda_tcpf; /* TCP header flags (SYN, ACK, etc) */
+} frdat_t;
+
+typedef enum fr_breasons_e {
+ FRB_BLOCKED = 0,
+ FRB_LOGFAIL = 1,
+ FRB_PPSRATE = 2,
+ FRB_JUMBO = 3,
+ FRB_MAKEFRIP = 4,
+ FRB_STATEADD = 5,
+ FRB_UPDATEIPID = 6,
+ FRB_LOGFAIL2 = 7,
+ FRB_DECAPFRIP = 8,
+ FRB_AUTHNEW = 9,
+ FRB_AUTHCAPTURE = 10,
+ FRB_COALESCE = 11,
+ FRB_PULLUP = 12,
+ FRB_AUTHFEEDBACK = 13,
+ FRB_BADFRAG = 14,
+ FRB_NATV4 = 15,
+ FRB_NATV6 = 16,
+} fr_breason_t;
+
+#define FRB_MAX_VALUE 16
+
+typedef enum ipf_cksum_e {
+ FI_CK_BAD = -1,
+ FI_CK_NEEDED = 0,
+ FI_CK_SUMOK = 1,
+ FI_CK_L4PART = 2,
+ FI_CK_L4FULL = 4
+} ipf_cksum_t;
typedef struct fr_info {
+ void *fin_main_soft;
void *fin_ifp; /* interface packet is `on' */
- fr_ip_t fin_fi; /* IP Packet summary */
- union {
- u_short fid_16[2]; /* TCP/UDP ports, ICMP code/type */
- u_32_t fid_32;
- } fin_dat;
+ struct frentry *fin_fr; /* last matching rule */
int fin_out; /* in or out ? 1 == out, 0 == in */
- int 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) */
- u_char fin_icode; /* ICMP error to return */
+ fr_ip_t fin_fi; /* IP Packet summary */
+ frdat_t fin_dat; /* TCP/UDP ports, ICMP code/type */
+ int fin_dlen; /* length of data portion of packet */
+ int fin_plen;
u_32_t fin_rule; /* rule # last matched */
+ u_short fin_hlen; /* length of IP header in bytes */
char fin_group[FR_GROUPLEN]; /* group number, -1 for none */
- struct frentry *fin_fr; /* last matching rule */
void *fin_dp; /* start of data past IP header */
- int fin_dlen; /* length of data portion of packet */
- int fin_plen;
+ /*
+ * Fields after fin_dp aren't used for compression of log records.
+ * fin_fi contains the IP version (fin_family)
+ * fin_rule isn't included because adding a new rule can change it but
+ * not change fin_fr. fin_rule is the rule number reported.
+ * It isn't necessary to include fin_crc because that is checked
+ * for explicitly, before calling bcmp.
+ */
+ u_32_t fin_crc; /* Simple calculation for logging */
+ int fin_family; /* AF_INET, etc. */
+ int fin_icode; /* ICMP error to return */
+ int fin_mtu; /* MTU input for ICMP need-frag */
+ int fin_rev; /* state only: 1 = reverse */
int fin_ipoff; /* # bytes from buffer start to hdr */
- u_short fin_id; /* IP packet id field */
+ u_32_t fin_id; /* IP packet id field */
+ u_short fin_l4hlen; /* length of L4 header, if known */
u_short fin_off;
int fin_depth; /* Group nesting depth */
int fin_error; /* Error code to return */
- int fin_cksum; /* -1 bad, 1 good, 0 not done */
- void *fin_nat;
- void *fin_state;
+ ipf_cksum_t fin_cksum; /* -1 = bad, 1 = good, 0 = not done */
+ fr_breason_t fin_reason; /* why auto blocked */
+ u_int fin_pktnum;
void *fin_nattag;
- void *fin_exthdr;
- ip_t *fin_ip;
+ struct frdest *fin_dif;
+ struct frdest *fin_tif;
+ union {
+ ip_t *fip_ip;
+#ifdef USE_INET6
+ ip6_t *fip_ip6;
+#endif
+ } fin_ipu;
mb_t **fin_mp; /* pointer to pointer to mbuf */
mb_t *fin_m; /* pointer to mbuf */
#ifdef MENTAT
@@ -344,35 +470,42 @@ typedef struct fr_info {
#ifdef __sgi
void *fin_hbuf;
#endif
+ void *fin_fraghdr; /* pointer to start of ipv6 frag hdr */
} fr_info_t;
+#define fin_ip fin_ipu.fip_ip
+#define fin_ip6 fin_ipu.fip_ip6
#define fin_v fin_fi.fi_v
#define fin_p fin_fi.fi_p
#define fin_flx fin_fi.fi_flx
#define fin_optmsk fin_fi.fi_optmsk
#define fin_secmsk fin_fi.fi_secmsk
+#define fin_doi fin_fi.fi_doi
#define fin_auth fin_fi.fi_auth
#define fin_src fin_fi.fi_src.in4
-#define fin_src6 fin_fi.fi_src.in6
#define fin_saddr fin_fi.fi_saddr
#define fin_dst fin_fi.fi_dst.in4
-#define fin_dst6 fin_fi.fi_dst.in6
#define fin_daddr fin_fi.fi_daddr
-#define fin_data fin_dat.fid_16
-#define fin_sport fin_dat.fid_16[0]
-#define fin_dport fin_dat.fid_16[1]
-#define fin_ports fin_dat.fid_32
+#define fin_data fin_fi.fi_ports
+#define fin_sport fin_fi.fi_ports[0]
+#define fin_dport fin_fi.fi_ports[1]
+#define fin_tcpf fin_fi.fi_tcpf
+#define fin_src6 fin_fi.fi_src
+#define fin_dst6 fin_fi.fi_dst
+#define fin_srcip6 fin_fi.fi_src.in6
+#define fin_dstip6 fin_fi.fi_dst.in6
#define IPF_IN 0
#define IPF_OUT 1
typedef struct frentry *(*ipfunc_t) __P((fr_info_t *, u_32_t *));
-typedef int (*ipfuncinit_t) __P((struct frentry *));
+typedef int (*ipfuncinit_t) __P((struct ipf_main_softc_s *, struct frentry *));
typedef struct ipfunc_resolve {
char ipfu_name[32];
ipfunc_t ipfu_addr;
ipfuncinit_t ipfu_init;
+ ipfuncinit_t ipfu_fini;
} ipfunc_resolve_t;
/*
@@ -401,39 +534,78 @@ typedef struct {
#define ipt_tag ipt_un.iptu_tag
#define ipt_num ipt_un.iptu_num
+/*
+ * Structure to define address for pool lookups.
+ */
+typedef struct {
+ u_char adf_len;
+ sa_family_t adf_family;
+ u_char adf_xxx[2];
+ i6addr_t adf_addr;
+} addrfamily_t;
+
+
+RBI_LINK(ipf_rb, host_node_s);
+
+typedef struct host_node_s {
+ RBI_FIELD(ipf_rb) hn_entry;
+ addrfamily_t hn_addr;
+ int hn_active;
+} host_node_t;
+
+typedef RBI_HEAD(ipf_rb, host_node_s) ipf_rb_head_t;
+
+typedef struct host_track_s {
+ ipf_rb_head_t ht_root;
+ int ht_max_nodes;
+ int ht_max_per_node;
+ int ht_netmask;
+ int ht_cur_nodes;
+} host_track_t;
+
+typedef enum fr_dtypes_e {
+ FRD_NORMAL = 0,
+ FRD_DSTLIST
+} fr_dtypes_t;
/*
* This structure is used to hold information about the next hop for where
* to forward a packet.
*/
typedef struct frdest {
- void *fd_ifp;
- i6addr_t fd_ip6;
- char fd_ifname[LIFNAMSIZ];
+ void *fd_ptr;
+ addrfamily_t fd_addr;
+ fr_dtypes_t fd_type;
+ int fd_name;
+ int fd_local;
} frdest_t;
+#define fd_ip6 fd_addr.adf_addr
#define fd_ip fd_ip6.in4
+typedef enum fr_ctypes_e {
+ FR_NONE = 0,
+ FR_EQUAL,
+ FR_NEQUAL,
+ FR_LESST,
+ FR_GREATERT,
+ FR_LESSTE,
+ FR_GREATERTE,
+ FR_OUTRANGE,
+ FR_INRANGE,
+ FR_INCRANGE
+} fr_ctypes_t;
+
/*
* This structure holds information about a port comparison.
*/
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 >< */
+ fr_ctypes_t frp_cmp; /* data for port comparisons */
+ u_32_t frp_port; /* top port for <> and >< */
+ u_32_t frp_top; /* top port for <> and >< */
} frpcmp_t;
-#define FR_NONE 0
-#define FR_EQUAL 1
-#define FR_NEQUAL 2
-#define FR_LESST 3
-#define FR_GREATERT 4
-#define FR_LESSTE 5
-#define FR_GREATERTE 6
-#define FR_OUTRANGE 7
-#define FR_INRANGE 8
-#define FR_INCRANGE 9
/*
* Structure containing all the relevant TCP things that can be checked in
@@ -455,23 +627,37 @@ typedef struct frtuc {
#define FR_TCPFMAX 0x3f
+typedef enum fr_atypes_e {
+ FRI_NONE = -1, /* For LHS of NAT */
+ FRI_NORMAL = 0, /* Normal address */
+ FRI_DYNAMIC, /* dynamic address */
+ FRI_LOOKUP, /* address is a pool # */
+ FRI_RANGE, /* address/mask is a range */
+ FRI_NETWORK, /* network address from if */
+ FRI_BROADCAST, /* broadcast address from if */
+ FRI_PEERADDR, /* Peer address for P-to-P */
+ FRI_NETMASKED, /* network address with netmask from if */
+ FRI_SPLIT, /* For NAT compatibility */
+ FRI_INTERFACE /* address is based on interface name */
+} fr_atypes_t;
+
/*
* This structure makes up what is considered to be the IPFilter specific
* matching components of a filter rule, as opposed to the data structures
* used to define the result which are in frentry_t and not here.
*/
typedef struct fripf {
- fr_ip_t fri_ip;
- fr_ip_t fri_mip; /* mask structure */
+ fr_ip_t fri_ip;
+ fr_ip_t fri_mip; /* mask structure */
- u_short fri_icmpm; /* data for ICMP packets (mask) */
- u_short fri_icmp;
+ u_short fri_icmpm; /* data for ICMP packets (mask) */
+ u_short fri_icmp;
- frtuc_t fri_tuc;
- int fri_satype; /* addres type */
- int fri_datype; /* addres type */
- int fri_sifpidx; /* doing dynamic addressing */
- int fri_difpidx; /* index into fr_ifps[] to use when */
+ frtuc_t fri_tuc;
+ fr_atypes_t fri_satype; /* addres type */
+ fr_atypes_t fri_datype; /* addres type */
+ int fri_sifpidx; /* doing dynamic addressing */
+ int fri_difpidx; /* index into fr_ifps[] to use when */
} fripf_t;
#define fri_dlookup fri_mip.fi_dst
@@ -483,28 +669,42 @@ typedef struct fripf {
#define fri_dstptr fri_mip.fi_dstptr
#define fri_srcptr fri_mip.fi_srcptr
-#define FRI_NORMAL 0 /* Normal address */
-#define FRI_DYNAMIC 1 /* dynamic address */
-#define FRI_LOOKUP 2 /* address is a pool # */
-#define FRI_RANGE 3 /* address/mask is a range */
-#define FRI_NETWORK 4 /* network address from if */
-#define FRI_BROADCAST 5 /* broadcast address from if */
-#define FRI_PEERADDR 6 /* Peer address for P-to-P */
-#define FRI_NETMASKED 7 /* network address with netmask from if */
+typedef enum fr_rtypes_e {
+ FR_T_NONE = 0,
+ FR_T_IPF, /* IPF structures */
+ FR_T_BPFOPC, /* BPF opcode */
+ FR_T_CALLFUNC, /* callout to function in fr_func only */
+ FR_T_COMPIPF, /* compiled C code */
+ FR_T_IPFEXPR, /* IPF expression */
+ FR_T_BUILTIN = 0x40000000, /* rule is in kernel space */
+ FR_T_IPF_BUILTIN,
+ FR_T_BPFOPC_BUILTIN,
+ FR_T_CALLFUNC_BUILTIN,
+ FR_T_COMPIPF_BUILTIN,
+ FR_T_IPFEXPR_BUILTIN
+} fr_rtypes_t;
typedef struct frentry * (* frentfunc_t) __P((fr_info_t *));
typedef struct frentry {
ipfmutex_t fr_lock;
struct frentry *fr_next;
- struct frentry **fr_grp;
+ struct frentry **fr_pnext;
+ struct frgroup *fr_grp;
+ struct frgroup *fr_grphead;
+ struct frgroup *fr_icmpgrp;
struct ipscan *fr_isc;
+ struct frentry *fr_dnext; /* 2 fr_die linked list pointers */
+ struct frentry **fr_pdnext;
void *fr_ifas[4];
void *fr_ptr; /* for use with fr_arg */
- char *fr_comment; /* text comment for rule */
- int fr_ref; /* reference count - for grouping */
+ int fr_comment; /* text comment for rule */
+ int fr_size; /* size of this structure */
+ int fr_ref; /* reference count */
int fr_statecnt; /* state count - for limit rules */
+ u_32_t fr_die; /* only used on loading the rule */
+ u_int fr_cksum; /* checksum on filter rules for performance */
/*
* The line number from a file is here because we need to be able to
* match the rule generated with ``grep rule ipf.conf | ipf -rf -''
@@ -521,13 +721,18 @@ typedef struct frentry {
/*
* For PPS rate limiting
+ * fr_lpu is used to always have the same size for this field,
+ * allocating 64bits for seconds and 32bits for milliseconds.
*/
- struct timeval fr_lastpkt;
+ union {
+ struct timeval frp_lastpkt;
+ char frp_bytes[12];
+ } fr_lpu;
int fr_curpps;
union {
void *fru_data;
- caddr_t fru_caddr;
+ char *fru_caddr;
fripf_t *fru_ipf;
frentfunc_t fru_func;
} fr_dun;
@@ -538,29 +743,38 @@ typedef struct frentry {
ipfunc_t fr_func; /* call this function */
int fr_dsize;
int fr_pps;
- int fr_statemax; /* max reference count */
- u_32_t fr_type;
+ fr_rtypes_t fr_type;
u_32_t fr_flags; /* per-rule flags && options (see below) */
u_32_t fr_logtag; /* user defined log tag # */
u_32_t fr_collect; /* collection number */
- u_int fr_arg; /* misc. numeric arg for rule */
+ u_int fr_arg; /* misc. numeric arg for rule */
u_int fr_loglevel; /* syslog log facility + priority */
- u_int fr_age[2]; /* non-TCP timeouts */
- u_char fr_v;
+ u_char fr_family;
u_char fr_icode; /* return ICMP code */
- char fr_group[FR_GROUPLEN]; /* group to which this rule belongs */
- char fr_grhead[FR_GROUPLEN]; /* group # which this rule starts */
+ int fr_group; /* group to which this rule belongs */
+ int fr_grhead; /* group # which this rule starts */
+ int fr_ifnames[4];
+ int fr_isctag;
+ int fr_rpc; /* XID Filtering */
ipftag_t fr_nattag;
- char fr_ifnames[4][LIFNAMSIZ];
- char fr_isctag[16];
frdest_t fr_tifs[2]; /* "to"/"reply-to" interface */
frdest_t fr_dif; /* duplicate packet interface */
/*
- * This must be last and will change after loaded into the kernel.
+ * These are all options related to stateful filtering
*/
- u_int fr_cksum; /* checksum on filter rules for performance */
+ host_track_t fr_srctrack;
+ int fr_nostatelog;
+ int fr_statemax; /* max reference count */
+ int fr_icmphead; /* ICMP group for state options */
+ u_int fr_age[2]; /* non-TCP state timeouts */
+ /*
+ * How big is the name buffer at the end?
+ */
+ int fr_namelen;
+ char fr_names[1];
} frentry_t;
+#define fr_lastpkt fr_lpu.frp_lastpkt
#define fr_caddr fr_dun.fru_caddr
#define fr_data fr_dun.fru_data
#define fr_dfunc fr_dun.fru_func
@@ -589,12 +803,16 @@ typedef struct frentry {
#define fr_stop fr_tuc.ftu_stop
#define fr_dtop fr_tuc.ftu_dtop
#define fr_dst fr_ip.fi_dst.in4
+#define fr_dst6 fr_ip.fi_dst
#define fr_daddr fr_ip.fi_dst.in4.s_addr
#define fr_src fr_ip.fi_src.in4
+#define fr_src6 fr_ip.fi_src
#define fr_saddr fr_ip.fi_src.in4.s_addr
#define fr_dmsk fr_mip.fi_dst.in4
+#define fr_dmsk6 fr_mip.fi_dst
#define fr_dmask fr_mip.fi_dst.in4.s_addr
#define fr_smsk fr_mip.fi_src.in4
+#define fr_smsk6 fr_mip.fi_src
#define fr_smask fr_mip.fi_src.in4.s_addr
#define fr_dstnum fr_ip.fi_dstnum
#define fr_srcnum fr_ip.fi_srcnum
@@ -616,10 +834,10 @@ typedef struct frentry {
#define fr_secmask fr_mip.fi_secmsk
#define fr_authbits fr_ip.fi_auth
#define fr_authmask fr_mip.fi_auth
+#define fr_doi fr_ip.fi_doi
+#define fr_doimask fr_mip.fi_doi
#define fr_flx fr_ip.fi_flx
#define fr_mflx fr_mip.fi_flx
-#define fr_ifname fr_ifnames[0]
-#define fr_oifname fr_ifnames[2]
#define fr_ifa fr_ifas[0]
#define fr_oifa fr_ifas[2]
#define fr_tif fr_tifs[0]
@@ -627,33 +845,22 @@ typedef struct frentry {
#define FR_NOLOGTAG 0
-#ifndef offsetof
-#define offsetof(t,m) (int)((&((t *)0L)->m))
-#endif
#define FR_CMPSIZ (sizeof(struct frentry) - \
offsetof(struct frentry, fr_func))
+#define FR_NAME(_f, _n) (_f)->fr_names + (_f)->_n
-/*
- * fr_type
- */
-#define FR_T_NONE 0
-#define FR_T_IPF 1 /* IPF structures */
-#define FR_T_BPFOPC 2 /* BPF opcode */
-#define FR_T_CALLFUNC 3 /* callout to function in fr_func only */
-#define FR_T_COMPIPF 4 /* compiled C code */
-#define FR_T_BUILTIN 0x80000000 /* rule is in kernel space */
/*
* fr_flags
*/
-#define FR_CALL 0x00000 /* call rule */
#define FR_BLOCK 0x00001 /* do not allow packet to pass */
#define FR_PASS 0x00002 /* allow packet to pass */
#define FR_AUTH 0x00003 /* use authentication */
#define FR_PREAUTH 0x00004 /* require preauthentication */
#define FR_ACCOUNT 0x00005 /* Accounting rule */
#define FR_SKIP 0x00006 /* skip rule */
-#define FR_DIVERT 0x00007 /* divert rule */
+#define FR_DECAPSULATE 0x00008 /* decapsulate rule */
+#define FR_CALL 0x00009 /* call rule */
#define FR_CMDMASK 0x0000f
#define FR_LOG 0x00010 /* Log */
#define FR_LOGB 0x00011 /* Log-fail */
@@ -674,19 +881,19 @@ typedef struct frentry {
#define FR_LOGBODY 0x10000 /* Log the body */
#define FR_LOGFIRST 0x20000 /* Log the first byte if state held */
#define FR_LOGORBLOCK 0x40000 /* block the packet if it can't be logged */
-#define FR_DUP 0x80000 /* duplicate packet */
+#define FR_STLOOSE 0x80000 /* loose state checking */
#define FR_FRSTRICT 0x100000 /* strict frag. cache */
#define FR_STSTRICT 0x200000 /* strict keep state */
#define FR_NEWISN 0x400000 /* new ISN for outgoing TCP */
#define FR_NOICMPERR 0x800000 /* do not match ICMP errors in state */
#define FR_STATESYNC 0x1000000 /* synchronize state to slave */
+#define FR_COPIED 0x2000000 /* copied from user space */
+#define FR_INACTIVE 0x4000000 /* only used when flush'ing rules */
#define FR_NOMATCH 0x8000000 /* no match occured */
/* 0x10000000 FF_LOGPASS */
/* 0x20000000 FF_LOGBLOCK */
/* 0x40000000 FF_LOGNOMATCH */
/* 0x80000000 FF_BLOCKNONIP */
-#define FR_COPIED 0x40000000 /* copied from user space */
-#define FR_INACTIVE 0x80000000 /* only used when flush'ing rules */
#define FR_RETMASK (FR_RETICMP|FR_RETRST|FR_FAKEICMP)
#define FR_ISBLOCK(x) (((x) & FR_CMDMASK) == FR_BLOCK)
@@ -695,6 +902,7 @@ typedef struct frentry {
#define FR_ISPREAUTH(x) (((x) & FR_CMDMASK) == FR_PREAUTH)
#define FR_ISACCOUNT(x) (((x) & FR_CMDMASK) == FR_ACCOUNT)
#define FR_ISSKIP(x) (((x) & FR_CMDMASK) == FR_SKIP)
+#define FR_ISDECAPS(x) (((x) & FR_CMDMASK) == FR_DECAPSULATE)
#define FR_ISNOMATCH(x) ((x) & FR_NOMATCH)
#define FR_INOUT (FR_INQUE|FR_OUTQUE)
@@ -712,8 +920,8 @@ typedef struct frentry {
* Structure that passes information on what/how to flush to the kernel.
*/
typedef struct ipfflush {
- int ipflu_how;
- int ipflu_arg;
+ int ipflu_how;
+ int ipflu_arg;
} ipfflush_t;
@@ -721,12 +929,12 @@ typedef struct ipfflush {
*
*/
typedef struct ipfgetctl {
- u_int ipfg_min; /* min value */
- u_int ipfg_current; /* current value */
- u_int ipfg_max; /* max value */
- u_int ipfg_default; /* default value */
- u_int ipfg_steps; /* value increments */
- char ipfg_name[40]; /* tag name for this control */
+ u_int ipfg_min; /* min value */
+ u_int ipfg_current; /* current value */
+ u_int ipfg_max; /* max value */
+ u_int ipfg_default; /* default value */
+ u_int ipfg_steps; /* value increments */
+ char ipfg_name[40]; /* tag name for this control */
} ipfgetctl_t;
typedef struct ipfsetctl {
@@ -741,7 +949,43 @@ typedef struct ipfsetctl {
* in this single structure so that they can all easily be collected and
* copied back as required.
*/
-typedef struct filterstats {
+typedef struct ipf_statistics {
+ u_long fr_icmp_coalesce;
+ u_long fr_tcp_frag;
+ u_long fr_tcp_pullup;
+ u_long fr_tcp_short;
+ u_long fr_tcp_small;
+ u_long fr_tcp_bad_flags;
+ u_long fr_udp_pullup;
+ u_long fr_ip_freed;
+ u_long fr_v6_ah_bad;
+ u_long fr_v6_bad;
+ u_long fr_v6_badfrag;
+ u_long fr_v6_dst_bad;
+ u_long fr_v6_esp_pullup;
+ u_long fr_v6_ext_short;
+ u_long fr_v6_ext_pullup;
+ u_long fr_v6_ext_hlen;
+ u_long fr_v6_frag_bad;
+ u_long fr_v6_frag_pullup;
+ u_long fr_v6_frag_size;
+ u_long fr_v6_gre_pullup;
+ u_long fr_v6_icmp6_pullup;
+ u_long fr_v6_rh_bad;
+ u_long fr_v6_badttl; /* TTL in packet doesn't reach minimum */
+ u_long fr_v4_ah_bad;
+ u_long fr_v4_ah_pullup;
+ u_long fr_v4_esp_pullup;
+ u_long fr_v4_cipso_bad;
+ u_long fr_v4_cipso_tlen;
+ u_long fr_v4_gre_frag;
+ u_long fr_v4_gre_pullup;
+ u_long fr_v4_icmp_frag;
+ u_long fr_v4_icmp_pullup;
+ u_long fr_v4_badttl; /* TTL in packet doesn't reach minimum */
+ u_long fr_v4_badsrc; /* source received doesn't match route */
+ u_long fr_l4_badcksum; /* layer 4 header checksum failure */
+ u_long fr_badcoalesces;
u_long fr_pass; /* packets allowed */
u_long fr_block; /* packets denied */
u_long fr_nom; /* packets which don't match any rule */
@@ -749,8 +993,6 @@ typedef struct filterstats {
u_long fr_ppkl; /* packets allowed and logged */
u_long fr_bpkl; /* packets denied and logged */
u_long fr_npkl; /* packets unmatched and logged */
- u_long fr_pkl; /* packets logged */
- u_long fr_skip; /* packets to be logged but buffer full */
u_long fr_ret; /* packets for which a return is sent */
u_long fr_acct; /* packets for which counting was performed */
u_long fr_bnfr; /* bad attempts to allocate fragment state */
@@ -759,15 +1001,15 @@ typedef struct filterstats {
u_long fr_bads; /* bad attempts to allocate packet state */
u_long fr_ads; /* new packet state kept */
u_long fr_chit; /* cached hit */
+ u_long fr_cmiss; /* cached miss */
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 */
u_long fr_bad; /* bad IP packets to the filter */
u_long fr_ipv6; /* IPv6 packets in/out */
u_long fr_ppshit; /* dropped because of pps ceiling */
u_long fr_ipud; /* IP id update failures */
-} filterstats_t;
+ u_long fr_blocked[FRB_MAX_VALUE + 1];
+} ipf_statistics_t;
/*
* Log structure. Each packet header logged is prepended by one of these.
@@ -777,6 +1019,7 @@ typedef struct filterstats {
typedef struct iplog {
u_32_t ipl_magic;
u_int ipl_count;
+ u_32_t ipl_seqnum;
struct timeval ipl_time;
size_t ipl_dsize;
struct iplog *ipl_next;
@@ -796,18 +1039,19 @@ typedef struct ipflog {
#else
u_int fl_unit;
#endif
- u_32_t fl_rule;
- u_32_t fl_flags;
- u_32_t fl_lflags;
- u_32_t fl_logtag;
+ u_32_t fl_rule;
+ u_32_t fl_flags;
+ u_32_t fl_lflags;
+ u_32_t fl_logtag;
ipftag_t fl_nattag;
- u_short fl_plen; /* extra data after hlen */
- u_short fl_loglevel; /* syslog log level */
- char fl_group[FR_GROUPLEN];
- u_char fl_hlen; /* length of IP headers saved */
- u_char fl_dir;
- u_char fl_xxx[2]; /* pad */
- char fl_ifname[LIFNAMSIZ];
+ u_short fl_plen; /* extra data after hlen */
+ u_short fl_loglevel; /* syslog log level */
+ char fl_group[FR_GROUPLEN];
+ u_char fl_hlen; /* length of IP headers saved */
+ u_char fl_dir;
+ u_char fl_breason; /* from fin_reason */
+ u_char fl_family; /* address family of packet logged */
+ char fl_ifname[LIFNAMSIZ];
} ipflog_t;
#ifndef IPF_LOGGING
@@ -817,12 +1061,12 @@ typedef struct ipflog {
# define IPF_DEFAULT_PASS FR_PASS
#endif
-#define DEFAULT_IPFLOGSIZE 8192
+#define DEFAULT_IPFLOGSIZE 32768
#ifndef IPFILTER_LOGSIZE
# define IPFILTER_LOGSIZE DEFAULT_IPFLOGSIZE
#else
-# if IPFILTER_LOGSIZE < DEFAULT_IPFLOGSIZE
-# error IPFILTER_LOGSIZE too small. Must be >= DEFAULT_IPFLOGSIZE
+# if IPFILTER_LOGSIZE < 8192
+# error IPFILTER_LOGSIZE too small. Must be >= 8192
# endif
#endif
@@ -867,34 +1111,30 @@ typedef struct ipflog {
* For SIOCGETFS
*/
typedef struct friostat {
- struct filterstats f_st[2];
- struct frentry *f_ipf[2][2];
- struct frentry *f_acct[2][2];
- struct frentry *f_ipf6[2][2];
- struct frentry *f_acct6[2][2];
- struct frentry *f_auth;
- struct frgroup *f_groups[IPL_LOGSIZE][2];
- u_long f_froute[2];
- u_long f_ticks;
- int f_locks[IPL_LOGMAX];
- size_t f_kmutex_sz;
- size_t f_krwlock_sz;
- int f_defpass; /* default pass - from fr_pass */
- int f_active; /* 1 or 0 - active rule set */
- int f_running; /* 1 if running, else 0 */
- int f_logging; /* 1 if enabled, else 0 */
- int f_features;
- char f_version[32]; /* version string */
+ ipf_statistics_t f_st[2];
+ frentry_t *f_ipf[2][2];
+ frentry_t *f_acct[2][2];
+ frentry_t *f_auth;
+ struct frgroup *f_groups[IPL_LOGSIZE][2];
+ u_long f_froute[2];
+ u_long f_log_ok;
+ u_long f_log_fail;
+ u_long f_rb_no_mem;
+ u_long f_rb_node_max;
+ u_32_t f_ticks;
+ int f_locks[IPL_LOGSIZE];
+ int f_defpass; /* default pass - from fr_pass */
+ int f_active; /* 1 or 0 - active rule set */
+ int f_running; /* 1 if running, else 0 */
+ int f_logging; /* 1 if enabled, else 0 */
+ int f_features;
+ char f_version[32]; /* version string */
} friostat_t;
#define f_fin f_ipf[0]
-#define f_fin6 f_ipf6[0]
#define f_fout f_ipf[1]
-#define f_fout6 f_ipf6[1]
#define f_acctin f_acct[0]
-#define f_acctin6 f_acct6[0]
#define f_acctout f_acct[1]
-#define f_acctout6 f_acct6[1]
#define IPF_FEAT_LKM 0x001
#define IPF_FEAT_LOG 0x002
@@ -916,12 +1156,13 @@ typedef struct optlist {
* Group list structure.
*/
typedef struct frgroup {
- struct frgroup *fg_next;
- struct frentry *fg_head;
- struct frentry *fg_start;
- u_32_t fg_flags;
- int fg_ref;
- char fg_name[FR_GROUPLEN];
+ struct frgroup *fg_next;
+ struct frentry *fg_head;
+ struct frentry *fg_start;
+ struct frgroup **fg_set;
+ u_32_t fg_flags;
+ int fg_ref;
+ char fg_name[FR_GROUPLEN];
} frgroup_t;
#define FG_NAME(g) (*(g)->fg_name == '\0' ? "" : (g)->fg_name)
@@ -931,24 +1172,24 @@ typedef struct frgroup {
* Used by state and NAT tables
*/
typedef struct icmpinfo {
- u_short ici_id;
- u_short ici_seq;
- u_char ici_type;
+ u_short ici_id;
+ u_short ici_seq;
+ u_char ici_type;
} icmpinfo_t;
typedef struct udpinfo {
- u_short us_sport;
- u_short us_dport;
+ u_short us_sport;
+ u_short us_dport;
} udpinfo_t;
typedef struct tcpdata {
- u_32_t td_end;
- u_32_t td_maxend;
- u_32_t td_maxwin;
- u_32_t td_winscale;
- u_32_t td_maxseg;
- int td_winflags;
+ u_32_t td_end;
+ u_32_t td_maxend;
+ u_32_t td_maxwin;
+ u_32_t td_winscale;
+ u_32_t td_maxseg;
+ int td_winflags;
} tcpdata_t;
#define TCP_WSCALE_MAX 14
@@ -959,9 +1200,9 @@ typedef struct tcpdata {
typedef struct tcpinfo {
- u_short ts_sport;
- u_short ts_dport;
- tcpdata_t ts_data[2];
+ u_32_t ts_sport;
+ u_32_t ts_dport;
+ tcpdata_t ts_data[2];
} tcpinfo_t;
@@ -969,16 +1210,28 @@ typedef struct tcpinfo {
* Structures to define a GRE header as seen in a packet.
*/
struct grebits {
- u_32_t grb_C:1;
- u_32_t grb_R:1;
- u_32_t grb_K:1;
- u_32_t grb_S:1;
- u_32_t grb_s:1;
- u_32_t grb_recur:1;
- u_32_t grb_A:1;
- u_32_t grb_flags:3;
- u_32_t grb_ver:3;
- u_short grb_ptype;
+#if defined(sparc)
+ u_32_t grb_ver:3;
+ u_32_t grb_flags:3;
+ u_32_t grb_A:1;
+ u_32_t grb_recur:1;
+ u_32_t grb_s:1;
+ u_32_t grb_S:1;
+ u_32_t grb_K:1;
+ u_32_t grb_R:1;
+ u_32_t grb_C:1;
+#else
+ u_32_t grb_C:1;
+ u_32_t grb_R:1;
+ u_32_t grb_K:1;
+ u_32_t grb_S:1;
+ u_32_t grb_s:1;
+ u_32_t grb_recur:1;
+ u_32_t grb_A:1;
+ u_32_t grb_flags:3;
+ u_32_t grb_ver:3;
+#endif
+ u_short grb_ptype;
};
typedef struct grehdr {
@@ -986,8 +1239,8 @@ typedef struct grehdr {
struct grebits gru_bits;
u_short gru_flags;
} gr_un;
- u_short gr_len;
- u_short gr_call;
+ u_short gr_len;
+ u_short gr_call;
} grehdr_t;
#define gr_flags gr_un.gru_flags
@@ -1006,9 +1259,9 @@ typedef struct grehdr {
* GRE information tracked by "keep state"
*/
typedef struct greinfo {
- u_short gs_call[2];
- u_short gs_flags;
- u_short gs_ptype;
+ u_short gs_call[2];
+ u_short gs_flags;
+ u_short gs_ptype;
} greinfo_t;
#define GRE_REV(x) ((ntohs(x) >> 13) & 7)
@@ -1018,11 +1271,11 @@ typedef struct greinfo {
* Format of an Authentication header
*/
typedef struct authhdr {
- u_char ah_next;
- u_char ah_plen;
- u_short ah_reserved;
- u_32_t ah_spi;
- u_32_t ah_seq;
+ u_char ah_next;
+ u_char ah_plen;
+ u_short ah_reserved;
+ u_32_t ah_spi;
+ u_32_t ah_seq;
/* Following the sequence number field is 0 or more bytes of */
/* authentication data, as specified by ah_plen - RFC 2402. */
} authhdr_t;
@@ -1035,14 +1288,15 @@ typedef struct ipftqent {
struct ipftqent **tqe_pnext;
struct ipftqent *tqe_next;
struct ipftq *tqe_ifq;
- void *tqe_parent; /* pointer back to NAT/state struct */
- u_long tqe_die; /* when this entriy is to die */
- u_long tqe_touched;
- int tqe_flags;
- int tqe_state[2]; /* current state of this entry */
+ void *tqe_parent; /* pointer back to NAT/state struct */
+ u_32_t tqe_die; /* when this entriy is to die */
+ u_32_t tqe_touched;
+ int tqe_flags;
+ int tqe_state[2]; /* current state of this entry */
} ipftqent_t;
#define TQE_RULEBASED 0x00000001
+#define TQE_DELETE 0x00000002
/*
@@ -1050,45 +1304,46 @@ typedef struct ipftqent {
*/
typedef struct ipftq {
ipfmutex_t ifq_lock;
- u_int ifq_ttl;
+ u_int ifq_ttl;
ipftqent_t *ifq_head;
ipftqent_t **ifq_tail;
- struct ipftq *ifq_next;
- struct ipftq **ifq_pnext;
- int ifq_ref;
- u_int ifq_flags;
+ struct ipftq *ifq_next;
+ struct ipftq **ifq_pnext;
+ int ifq_ref;
+ u_int ifq_flags;
} ipftq_t;
#define IFQF_USER 0x01 /* User defined aging */
#define IFQF_DELETE 0x02 /* Marked for deletion */
#define IFQF_PROXY 0x04 /* Timeout queue in use by a proxy */
+#define IPFTQ_INIT(x,y,z) do { \
+ (x)->ifq_ttl = (y); \
+ (x)->ifq_head = NULL; \
+ (x)->ifq_ref = 1; \
+ (x)->ifq_tail = &(x)->ifq_head; \
+ MUTEX_INIT(&(x)->ifq_lock, (z)); \
+ } while (0)
+
#define IPF_HZ_MULT 1
#define IPF_HZ_DIVIDE 2 /* How many times a second ipfilter */
/* checks its timeout queues. */
#define IPF_TTLVAL(x) (((x) / IPF_HZ_MULT) * IPF_HZ_DIVIDE)
-typedef int (*ipftq_delete_fn_t)(void *);
-
-/*
- * Structure to define address for pool lookups.
- */
-typedef struct {
- u_char adf_len;
- i6addr_t adf_addr;
-} addrfamily_t;
+typedef int (*ipftq_delete_fn_t)(struct ipf_main_softc_s *, void *);
/*
* Object structure description. For passing through in ioctls.
*/
typedef struct ipfobj {
- u_32_t ipfo_rev; /* IPFilter version number */
- u_32_t ipfo_size; /* size of object at ipfo_ptr */
- void *ipfo_ptr; /* pointer to object */
- int ipfo_type; /* type of object being pointed to */
- int ipfo_offset; /* bytes from ipfo_ptr where to start */
- u_char ipfo_xxxpad[32]; /* reserved for future use */
+ u_32_t ipfo_rev; /* IPFilter version number */
+ u_32_t ipfo_size; /* size of object at ipfo_ptr */
+ void *ipfo_ptr; /* pointer to object */
+ int ipfo_type; /* type of object being pointed to */
+ int ipfo_offset; /* bytes from ipfo_ptr where to start */
+ int ipfo_retval; /* return value */
+ u_char ipfo_xxxpad[28]; /* reserved for future use */
} ipfobj_t;
#define IPFOBJ_FRENTRY 0 /* struct frentry */
@@ -1110,18 +1365,32 @@ typedef struct ipfobj {
#define IPFOBJ_GENITER 16 /* struct ipfgeniter */
#define IPFOBJ_GTABLE 17 /* struct ipftable */
#define IPFOBJ_LOOKUPITER 18 /* struct ipflookupiter */
-#define IPFOBJ_STATETQTAB 19 /* struct ipftq [NSTATES] */
-#define IPFOBJ_COUNT 20 /* How many #defines are above this? */
+#define IPFOBJ_STATETQTAB 19 /* struct ipftq * NSTATES */
+#define IPFOBJ_IPFEXPR 20
+#define IPFOBJ_PROXYCTL 21 /* strct ap_ctl */
+#define IPFOBJ_FRIPF 22 /* structfripf */
+#define IPFOBJ_COUNT 23 /* How many #defines are above this? */
typedef union ipftunevalptr {
- void *ipftp_void;
- u_long *ipftp_long;
- u_int *ipftp_int;
- u_short *ipftp_short;
- u_char *ipftp_char;
+ void *ipftp_void;
+ u_long *ipftp_long;
+ u_int *ipftp_int;
+ u_short *ipftp_short;
+ u_char *ipftp_char;
+ u_long ipftp_offset;
} ipftunevalptr_t;
+typedef union ipftuneval {
+ u_long ipftu_long;
+ u_int ipftu_int;
+ u_short ipftu_short;
+ u_char ipftu_char;
+} ipftuneval_t;
+
+struct ipftuneable;
+typedef int (* ipftunefunc_t) __P((struct ipf_main_softc_s *, struct ipftuneable *, ipftuneval_t *));
+
typedef struct ipftuneable {
ipftunevalptr_t ipft_una;
const char *ipft_name;
@@ -1130,6 +1399,7 @@ typedef struct ipftuneable {
int ipft_sz;
int ipft_flags;
struct ipftuneable *ipft_next;
+ ipftunefunc_t ipft_func;
} ipftuneable_t;
#define ipft_addr ipft_una.ipftp_void
@@ -1141,13 +1411,6 @@ typedef struct ipftuneable {
#define IPFT_RDONLY 1 /* read-only */
#define IPFT_WRDISABLED 2 /* write when disabled only */
-typedef union ipftuneval {
- u_long ipftu_long;
- u_int ipftu_int;
- u_short ipftu_short;
- u_char ipftu_char;
-} ipftuneval_t;
-
typedef struct ipftune {
void *ipft_cookie;
ipftuneval_t ipft_un;
@@ -1164,6 +1427,53 @@ typedef struct ipftune {
#define ipft_vchar ipft_un.ipftu_char
/*
+ * Hash table header
+ */
+#define IPFHASH(x,y) typedef struct { \
+ ipfrwlock_t ipfh_lock; \
+ struct x *ipfh_head; \
+ } y
+
+/*
+** HPUX Port
+*/
+#ifdef __hpux
+/* HP-UX locking sequence deadlock detection module lock MAJOR ID */
+# define IPF_SMAJ 0 /* temp assignment XXX, not critical */
+#endif
+
+#if !defined(CDEV_MAJOR) && defined (__FreeBSD_version) && \
+ (__FreeBSD_version >= 220000)
+# 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) || \
+ (defined(__FreeBSD__) && (__FreeBSD_version >= 500043))
+# if (defined(NetBSD) && NetBSD >= 199905)
+# define PFIL_HOOKS
+# endif
+# ifdef PFIL_HOOKS
+# define NETBSD_PF
+# endif
+#endif
+
+#ifdef _KERNEL
+# define FR_VERBOSE(verb_pr)
+# define FR_DEBUG(verb_pr)
+#else
+extern void ipfkdebug __P((char *, ...));
+extern void ipfkverbose __P((char *, ...));
+# define FR_VERBOSE(verb_pr) ipfkverbose verb_pr
+# define FR_DEBUG(verb_pr) ipfkdebug verb_pr
+#endif
+
+/*
*
*/
typedef struct ipfruleiter {
@@ -1171,7 +1481,7 @@ typedef struct ipfruleiter {
char iri_group[FR_GROUPLEN];
int iri_active;
int iri_nrules;
- int iri_v;
+ int iri_v; /* No longer used (compatibility) */
frentry_t *iri_rule;
} ipfruleiter_t;
@@ -1210,6 +1520,19 @@ typedef struct ipftable {
#define IPFTABLE_BUCKETS_NATOUT 3
+typedef struct ipf_v4_masktab_s {
+ u_32_t imt4_active[33];
+ int imt4_masks[33];
+ int imt4_max;
+} ipf_v4_masktab_t;
+
+typedef struct ipf_v6_masktab_s {
+ i6addr_t imt6_active[129];
+ int imt6_masks[129];
+ int imt6_max;
+} ipf_v6_masktab_t;
+
+
/*
*
*/
@@ -1222,190 +1545,246 @@ typedef struct ipftoken {
int ipt_type;
int ipt_uid;
int ipt_subtype;
- int ipt_alive;
+ int ipt_ref;
+ int ipt_complete;
} ipftoken_t;
/*
-** HPUX Port
-*/
-#ifdef __hpux
-/* HP-UX locking sequence deadlock detection module lock MAJOR ID */
-# define IPF_SMAJ 0 /* temp assignment XXX, not critical */
-#endif
-
-#if !defined(CDEV_MAJOR) && defined (__FreeBSD_version) && \
- (__FreeBSD_version >= 220000)
-# define CDEV_MAJOR 79
-#endif
+ *
+ */
+typedef struct ipfexp {
+ int ipfe_cmd;
+ int ipfe_not;
+ int ipfe_narg;
+ int ipfe_size;
+ int ipfe_arg0[1];
+} ipfexp_t;
/*
- * 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!
+ * Currently support commands (ipfe_cmd)
+ * 32bits is split up follows:
+ * aabbcccc
+ * aa = 0 = packet matching, 1 = meta data matching
+ * bb = IP protocol number
+ * cccc = command
*/
-#if (defined(NetBSD) && (NetBSD > 199609) && (NetBSD <= 1991011)) || \
- (defined(NetBSD1_2) && NetBSD1_2 > 1) || \
- (defined(__FreeBSD__) && (__FreeBSD_version >= 500043))
-# if defined(NetBSD) && (NetBSD >= 199905)
-# define PFIL_HOOKS
-# endif
-# ifdef PFIL_HOOKS
-# define NETBSD_PF
+#define IPF_EXP_IP_PR 0x00000001
+#define IPF_EXP_IP_ADDR 0x00000002
+#define IPF_EXP_IP_SRCADDR 0x00000003
+#define IPF_EXP_IP_DSTADDR 0x00000004
+#define IPF_EXP_IP6_ADDR 0x00000005
+#define IPF_EXP_IP6_SRCADDR 0x00000006
+#define IPF_EXP_IP6_DSTADDR 0x00000007
+#define IPF_EXP_TCP_FLAGS 0x00060001
+#define IPF_EXP_TCP_PORT 0x00060002
+#define IPF_EXP_TCP_SPORT 0x00060003
+#define IPF_EXP_TCP_DPORT 0x00060004
+#define IPF_EXP_UDP_PORT 0x00110002
+#define IPF_EXP_UDP_SPORT 0x00110003
+#define IPF_EXP_UDP_DPORT 0x00110004
+#define IPF_EXP_IDLE_GT 0x01000001
+#define IPF_EXP_TCP_STATE 0x01060002
+#define IPF_EXP_END 0xffffffff
+
+#define ONE_DAY IPF_TTLVAL(1 * 86400) /* 1 day */
+#define FIVE_DAYS (5 * ONE_DAY)
+
+typedef struct ipf_main_softc_s {
+ struct ipf_main_softc_s *ipf_next;
+ ipfmutex_t ipf_rw;
+ ipfmutex_t ipf_timeoutlock;
+ ipfrwlock_t ipf_mutex;
+ ipfrwlock_t ipf_frag;
+ ipfrwlock_t ipf_global;
+ ipfrwlock_t ipf_tokens;
+ ipfrwlock_t ipf_state;
+ ipfrwlock_t ipf_nat;
+ ipfrwlock_t ipf_natfrag;
+ ipfrwlock_t ipf_poolrw;
+ int ipf_dynamic_softc;
+ int ipf_refcnt;
+ int ipf_running;
+ int ipf_flags;
+ int ipf_active;
+ int ipf_control_forwarding;
+ int ipf_update_ipid;
+ int ipf_chksrc; /* causes a system crash if enabled */
+ int ipf_pass;
+ int ipf_minttl;
+ int ipf_icmpminfragmtu;
+ int ipf_interror; /* Should be in a struct that is per */
+ /* thread or process. Does not belong */
+ /* here but there's a lot more work */
+ /* in doing that properly. For now, */
+ /* it is squatting. */
+ u_int ipf_tcpidletimeout;
+ u_int ipf_tcpclosewait;
+ u_int ipf_tcplastack;
+ u_int ipf_tcptimewait;
+ u_int ipf_tcptimeout;
+ u_int ipf_tcpsynsent;
+ u_int ipf_tcpsynrecv;
+ u_int ipf_tcpclosed;
+ u_int ipf_tcphalfclosed;
+ u_int ipf_udptimeout;
+ u_int ipf_udpacktimeout;
+ u_int ipf_icmptimeout;
+ u_int ipf_icmpacktimeout;
+ u_int ipf_iptimeout;
+ u_long ipf_ticks;
+ u_long ipf_userifqs;
+ u_long ipf_rb_no_mem;
+ u_long ipf_rb_node_max;
+ u_long ipf_frouteok[2];
+ ipftuneable_t *ipf_tuners;
+ void *ipf_frag_soft;
+ void *ipf_nat_soft;
+ void *ipf_state_soft;
+ void *ipf_auth_soft;
+ void *ipf_proxy_soft;
+ void *ipf_sync_soft;
+ void *ipf_lookup_soft;
+ void *ipf_log_soft;
+ struct frgroup *ipf_groups[IPL_LOGSIZE][2];
+ frentry_t *ipf_rules[2][2];
+ frentry_t *ipf_acct[2][2];
+ frentry_t *ipf_rule_explist[2];
+ ipftoken_t *ipf_token_head;
+ ipftoken_t **ipf_token_tail;
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) && \
+ defined(_KERNEL)
+ struct callout_handle ipf_slow_ch;
+#endif
+#if defined(linux) && defined(_KERNEL)
+ struct timer_list ipf_timer;
+#endif
+#if NETBSD_GE_REV(104040000)
+ struct callout ipf_slow_ch;
+#endif
+#if SOLARIS
+# if SOLARIS2 >= 7
+ timeout_id_t ipf_slow_ch;
+# else
+ int ipf_slow_ch;
# endif
#endif
-
-#ifdef _KERNEL
-# define FR_VERBOSE(verb_pr)
-# define FR_DEBUG(verb_pr)
-#else
-extern void debug __P((char *, ...));
-extern void verbose __P((char *, ...));
-# define FR_VERBOSE(verb_pr) verbose verb_pr
-# define FR_DEBUG(verb_pr) debug verb_pr
+#if defined(_KERNEL)
+# if SOLARIS
+ struct pollhead ipf_poll_head[IPL_LOGSIZE];
+ void *ipf_dip;
+# if defined(INSTANCES)
+ int ipf_get_loopback;
+ u_long ipf_idnum;
+ net_handle_t ipf_nd_v4;
+ net_handle_t ipf_nd_v6;
+ hook_t *ipf_hk_v4_in;
+ hook_t *ipf_hk_v4_out;
+ hook_t *ipf_hk_v4_nic;
+ hook_t *ipf_hk_v6_in;
+ hook_t *ipf_hk_v6_out;
+ hook_t *ipf_hk_v6_nic;
+ hook_t *ipf_hk_loop_v4_in;
+ hook_t *ipf_hk_loop_v4_out;
+ hook_t *ipf_hk_loop_v6_in;
+ hook_t *ipf_hk_loop_v6_out;
+# endif
+# else
+# if defined(linux) && defined(_KERNEL)
+ struct poll_table_struct ipf_selwait[IPL_LOGSIZE];
+ wait_queue_head_t iplh_linux[IPL_LOGSIZE];
+# else
+ struct selinfo ipf_selwait[IPL_LOGSIZE];
+# endif
+# endif
#endif
+ void *ipf_slow;
+ ipf_statistics_t ipf_stats[2];
+ u_char ipf_iss_secret[32];
+ u_short ipf_ip_id;
+} ipf_main_softc_t;
+#define IPFERROR(_e) do { softc->ipf_interror = (_e); \
+ DT1(user_error, int, _e); \
+ } while (0)
#ifndef _KERNEL
-extern int fr_check __P((struct ip *, int, void *, int, mb_t **));
-extern int (*fr_checkp) __P((ip_t *, int, void *, int, mb_t **));
-extern int ipf_log __P((void));
+extern int ipf_check __P((void *, struct ip *, int, void *, int, mb_t **));
+extern int (*ipf_checkp) __P((ip_t *, int, void *, int, mb_t **));
extern struct ifnet *get_unit __P((char *, int));
extern char *get_ifname __P((struct ifnet *));
-# if defined(__NetBSD__) || defined(__OpenBSD__) || \
- (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000)
-extern int iplioctl __P((int, ioctlcmd_t, caddr_t, int));
-# else
-extern int iplioctl __P((int, ioctlcmd_t, caddr_t, int));
-# endif
-extern int iplopen __P((dev_t, int));
-extern int iplclose __P((dev_t, int));
+extern int ipfioctl __P((ipf_main_softc_t *, int, ioctlcmd_t,
+ caddr_t, int));
extern void m_freem __P((mb_t *));
+extern size_t msgdsize __P((mb_t *));
extern int bcopywrap __P((void *, void *, size_t));
#else /* #ifndef _KERNEL */
-# ifdef BSD
-# if (defined(__NetBSD__) && (__NetBSD_Version__ < 399000000)) || \
- defined(__osf__) || \
- (defined(__FreeBSD_version) && (__FreeBSD_version < 500043))
-# include <sys/select.h>
-# else
-# include <sys/selinfo.h>
-# endif
-extern struct selinfo ipfselwait[IPL_LOGSIZE];
-# endif
# if defined(__NetBSD__) && defined(PFIL_HOOKS)
extern void ipfilterattach __P((int));
# endif
extern int ipl_enable __P((void));
extern int ipl_disable __P((void));
-extern int ipf_inject __P((fr_info_t *, mb_t *));
# ifdef MENTAT
-extern int fr_check __P((struct ip *, int, void *, int, void *,
- mblk_t **));
+extern int ipf_check __P((void *, struct ip *, int, void *, int, void *,
+ mblk_t **));
# if SOLARIS
+extern void ipf_prependmbt(fr_info_t *, mblk_t *);
# if SOLARIS2 >= 7
-extern int iplioctl __P((dev_t, int, intptr_t, int, cred_t *, int *));
+extern int ipfioctl __P((dev_t, int, intptr_t, int, cred_t *, int *));
# else
-extern int iplioctl __P((dev_t, int, int *, int, cred_t *, int *));
+extern int ipfioctl __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 iplread __P((dev_t, uio_t *, cred_t *));
-extern int iplwrite __P((dev_t, uio_t *, cred_t *));
# endif
# ifdef __hpux
-extern int iplopen __P((dev_t, int, intptr_t, int));
-extern int iplclose __P((dev_t, int, int));
-extern int iplioctl __P((dev_t, int, caddr_t, int));
-extern int iplread __P((dev_t, uio_t *));
-extern int iplwrite __P((dev_t, uio_t *));
-extern int iplselect __P((dev_t, int));
+extern int ipfioctl __P((dev_t, int, caddr_t, int));
+extern int ipf_select __P((dev_t, int));
# endif
-extern int fr_qout __P((queue_t *, mblk_t *));
+extern int ipf_qout __P((queue_t *, mblk_t *));
# else /* MENTAT */
-extern int fr_check __P((struct ip *, int, void *, int, mb_t **));
+extern int ipf_check __P((void *, struct ip *, int, void *, int, mb_t **));
extern int (*fr_checkp) __P((ip_t *, int, void *, int, mb_t **));
extern size_t mbufchainlen __P((mb_t *));
# ifdef __sgi
# include <sys/cred.h>
-extern int iplioctl __P((dev_t, int, caddr_t, int, cred_t *, int *));
-extern int iplopen __P((dev_t *, int, int, cred_t *));
-extern int iplclose __P((dev_t, int, int, cred_t *));
-extern int iplread __P((dev_t, uio_t *, cred_t *));
-extern int iplwrite __P((dev_t, uio_t *, cred_t *));
+extern int ipfioctl __P((dev_t, int, caddr_t, int, cred_t *, int *));
extern int ipfilter_sgi_attach __P((void));
extern void ipfilter_sgi_detach __P((void));
extern void ipfilter_sgi_intfsync __P((void));
# else
# ifdef IPFILTER_LKM
-extern int iplidentify __P((char *));
+extern int ipf_identify __P((char *));
# endif
-# if (defined(_BSDI_VERSION) && _BSDI_VERSION >= 199510) || \
- (__FreeBSD_version >= 220000) || \
- (NetBSD >= 199511) || defined(__OpenBSD__)
-# if defined(__NetBSD__) || \
- (defined(_BSDI_VERSION) && _BSDI_VERSION >= 199701) || \
- defined(__OpenBSD__) || (__FreeBSD_version >= 300000)
+# if BSDOS_GE_REV(199510) || FREEBSD_GE_REV(220000) || \
+ (defined(NetBSD) && (NetBSD >= 199511)) || defined(__OpenBSD__)
+# if defined(__NetBSD__) || BSDOS_GE_REV(199701) || \
+ defined(__OpenBSD__) || FREEBSD_GE_REV(300000)
# if (__FreeBSD_version >= 500024)
# if (__FreeBSD_version >= 502116)
-extern int iplioctl __P((struct cdev*, u_long, caddr_t, int, struct thread *));
+extern int ipfioctl __P((struct cdev*, u_long, caddr_t, int, struct thread *));
# else
-extern int iplioctl __P((dev_t, u_long, caddr_t, int, struct thread *));
+extern int ipfioctl __P((dev_t, u_long, caddr_t, int, struct thread *));
# endif /* __FreeBSD_version >= 502116 */
# else
-# if (__NetBSD_Version__ >= 499001000)
-extern int iplioctl __P((dev_t, u_long, void *, int, struct lwp *));
+# if NETBSD_GE_REV(499001000)
+extern int ipfioctl __P((dev_t, u_long, void *, int, struct lwp *));
# else
-# if (__NetBSD_Version__ >= 399001400)
-extern int iplioctl __P((dev_t, u_long, caddr_t, int, struct lwp *));
+# if NETBSD_GE_REV(399001400)
+extern int ipfioctl __P((dev_t, u_long, caddr_t, int, struct lwp *));
# else
-extern int iplioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
+extern int ipfioctl __P((dev_t, u_long, caddr_t, int, struct proc *));
# endif
# endif
# endif /* __FreeBSD_version >= 500024 */
# else
-extern int iplioctl __P((dev_t, int, caddr_t, int, struct thread *));
+extern int ipfioctl __P((dev_t, int, caddr_t, int, struct proc *));
# endif
-# if (__FreeBSD_version >= 500024)
-# if (__FreeBSD_version >= 502116)
-extern int iplopen __P((struct cdev*, int, int, struct thread *));
-extern int iplclose __P((struct cdev*, int, int, struct thread *));
-# else
-extern int iplopen __P((dev_t, int, int, struct thread *));
-extern int iplclose __P((dev_t, int, int, struct thread *));
-# endif /* __FreeBSD_version >= 502116 */
-# else
-# if (__NetBSD_Version__ >= 399001400)
-extern int iplopen __P((dev_t, int, int, struct lwp *));
-extern int iplclose __P((dev_t, int, int, struct lwp *));
-# else
-extern int iplopen __P((dev_t, int, int, struct proc *));
-extern int iplclose __P((dev_t, int, int, struct proc *));
-# endif /* __NetBSD_Version__ >= 399001400 */
-# endif /* __FreeBSD_version >= 500024 */
# else
# ifdef linux
-extern int iplioctl __P((struct inode *, struct file *, u_int, u_long));
+extern int ipfioctl __P((struct inode *, struct file *, u_int, u_long));
# else
-extern int iplopen __P((dev_t, int));
-extern int iplclose __P((dev_t, int));
-extern int iplioctl __P((dev_t, int, caddr_t, int));
+extern int ipfioctl __P((dev_t, int, caddr_t, int));
# endif
# endif /* (_BSDI_VERSION >= 199510) */
-# if BSD >= 199306
-# if (__FreeBSD_version >= 502116)
-extern int iplread __P((struct cdev*, struct uio *, int));
-extern int iplwrite __P((struct cdev*, struct uio *, int));
-# else
-extern int iplread __P((dev_t, struct uio *, int));
-extern int iplwrite __P((dev_t, struct uio *, int));
-# endif /* __FreeBSD_version >= 502116 */
-# else
-# ifndef linux
-extern int iplread __P((dev_t, struct uio *));
-extern int iplwrite __P((dev_t, struct uio *));
-# endif
-# endif /* BSD >= 199306 */
# endif /* __ sgi */
# endif /* MENTAT */
@@ -1416,153 +1795,206 @@ extern void ipf_event_reg __P((void));
extern void ipf_event_dereg __P((void));
# endif
-#endif /* #ifndef _KERNEL */
+# if defined(INSTANCES)
+extern ipf_main_softc_t *ipf_find_softc __P((u_long));
+extern int ipf_set_loopback __P((ipf_main_softc_t *, ipftuneable_t *,
+ ipftuneval_t *));
+# endif
-extern ipfmutex_t ipl_mutex, ipf_authmx, ipf_rw, ipf_hostmap;
-extern ipfmutex_t ipf_timeoutlock, ipf_stinsert, ipf_natio, ipf_nat_new;
-extern ipfrwlock_t ipf_mutex, ipf_global, ip_poolrw, ipf_ipidfrag;
-extern ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth;
-extern ipfrwlock_t ipf_frcache, ipf_tokens;
+#endif /* #ifndef _KERNEL */
extern char *memstr __P((const char *, char *, size_t, size_t));
extern int count4bits __P((u_32_t));
-extern int frrequest __P((int, ioctlcmd_t, caddr_t, int, int));
+#ifdef USE_INET6
+extern int count6bits __P((u_32_t *));
+#endif
+extern int frrequest __P((ipf_main_softc_t *, int, ioctlcmd_t, caddr_t,
+ int, int));
extern char *getifname __P((struct ifnet *));
-extern int ipfattach __P((void));
-extern int ipfdetach __P((void));
+extern int ipfattach __P((ipf_main_softc_t *));
+extern int ipfdetach __P((ipf_main_softc_t *));
extern u_short ipf_cksum __P((u_short *, int));
-extern int copyinptr __P((void *, void *, size_t));
-extern int copyoutptr __P((void *, void *, size_t));
-extern int fr_fastroute __P((mb_t *, mb_t **, fr_info_t *, frdest_t *));
-extern int fr_inobj __P((void *, void *, int));
-extern int fr_inobjsz __P((void *, void *, int, int));
-extern int fr_ioctlswitch __P((int, void *, ioctlcmd_t, int, int, void *));
-extern int fr_ipf_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *));
-extern int fr_ipftune __P((ioctlcmd_t, void *));
-extern int fr_outobj __P((void *, void *, int));
-extern int fr_outobjsz __P((void *, void *, int, int));
-extern void *fr_pullup __P((mb_t *, fr_info_t *, int));
-extern void fr_resolvedest __P((struct frdest *, int));
-extern int fr_resolvefunc __P((void *));
-extern void *fr_resolvenic __P((char *, int));
-extern int fr_send_icmp_err __P((int, fr_info_t *, int));
-extern int fr_send_reset __P((fr_info_t *));
-#if (__FreeBSD_version < 501000) || !defined(_KERNEL)
-extern int ppsratecheck __P((struct timeval *, int *, int));
+extern int copyinptr __P((ipf_main_softc_t *, void *, void *, size_t));
+extern int copyoutptr __P((ipf_main_softc_t *, void *, void *, size_t));
+extern int ipf_fastroute __P((mb_t *, mb_t **, fr_info_t *, frdest_t *));
+extern int ipf_inject __P((fr_info_t *, mb_t *));
+extern int ipf_inobj __P((ipf_main_softc_t *, void *, ipfobj_t *,
+ void *, int));
+extern int ipf_inobjsz __P((ipf_main_softc_t *, void *, void *,
+ int , int));
+extern int ipf_ioctlswitch __P((ipf_main_softc_t *, int, void *,
+ ioctlcmd_t, int, int, void *));
+extern int ipf_ipf_ioctl __P((ipf_main_softc_t *, caddr_t, ioctlcmd_t,
+ int, int, void *));
+extern int ipf_ipftune __P((ipf_main_softc_t *, ioctlcmd_t, void *));
+extern int ipf_matcharray_load __P((ipf_main_softc_t *, caddr_t,
+ ipfobj_t *, int **));
+extern int ipf_matcharray_verify __P((int *, int));
+extern int ipf_outobj __P((ipf_main_softc_t *, void *, void *, int));
+extern int ipf_outobjk __P((ipf_main_softc_t *, ipfobj_t *, void *));
+extern int ipf_outobjsz __P((ipf_main_softc_t *, void *, void *,
+ int, int));
+extern void *ipf_pullup __P((mb_t *, fr_info_t *, int));
+extern int ipf_resolvedest __P((ipf_main_softc_t *, char *,
+ struct frdest *, int));
+extern int ipf_resolvefunc __P((ipf_main_softc_t *, void *));
+extern void *ipf_resolvenic __P((ipf_main_softc_t *, char *, int));
+extern int ipf_send_icmp_err __P((int, fr_info_t *, int));
+extern int ipf_send_reset __P((fr_info_t *));
+#if (defined(__FreeBSD_version) && (__FreeBSD_version < 501000)) || \
+ !defined(_KERNEL) || defined(linux)
#endif
-extern ipftq_t *fr_addtimeoutqueue __P((ipftq_t **, u_int));
-extern void fr_deletequeueentry __P((ipftqent_t *));
-extern int fr_deletetimeoutqueue __P((ipftq_t *));
-extern void fr_freetimeoutqueue __P((ipftq_t *));
-extern void fr_movequeue __P((ipftqent_t *, ipftq_t *, ipftq_t *));
-extern void fr_queueappend __P((ipftqent_t *, ipftq_t *, void *));
-extern void fr_queueback __P((ipftqent_t *));
-extern void fr_queuefront __P((ipftqent_t *));
-extern void fr_checkv4sum __P((fr_info_t *));
-extern int fr_checkl4sum __P((fr_info_t *));
-extern int fr_ifpfillv4addr __P((int, struct sockaddr_in *,
+extern void ipf_apply_timeout __P((ipftq_t *, u_int));
+extern ipftq_t *ipf_addtimeoutqueue __P((ipf_main_softc_t *, ipftq_t **,
+ u_int));
+extern void ipf_deletequeueentry __P((ipftqent_t *));
+extern int ipf_deletetimeoutqueue __P((ipftq_t *));
+extern void ipf_freetimeoutqueue __P((ipf_main_softc_t *, ipftq_t *));
+extern void ipf_movequeue __P((u_long, ipftqent_t *, ipftq_t *,
+ ipftq_t *));
+extern void ipf_queueappend __P((u_long, ipftqent_t *, ipftq_t *, void *));
+extern void ipf_queueback __P((u_long, ipftqent_t *));
+extern int ipf_queueflush __P((ipf_main_softc_t *, ipftq_delete_fn_t,
+ ipftq_t *, ipftq_t *, u_int *, int, int));
+extern void ipf_queuefront __P((ipftqent_t *));
+extern int ipf_settimeout_tcp __P((ipftuneable_t *, ipftuneval_t *,
+ ipftq_t *));
+extern int ipf_checkv4sum __P((fr_info_t *));
+extern int ipf_checkl4sum __P((fr_info_t *));
+extern int ipf_ifpfillv4addr __P((int, struct sockaddr_in *,
struct sockaddr_in *, struct in_addr *,
struct in_addr *));
-extern int fr_coalesce __P((fr_info_t *));
+extern int ipf_coalesce __P((fr_info_t *));
#ifdef USE_INET6
-extern void fr_checkv6sum __P((fr_info_t *));
-extern int fr_ifpfillv6addr __P((int, struct sockaddr_in6 *,
- struct sockaddr_in6 *, struct in_addr *,
- struct in_addr *));
+extern int ipf_checkv6sum __P((fr_info_t *));
+extern int ipf_ifpfillv6addr __P((int, struct sockaddr_in6 *,
+ struct sockaddr_in6 *, i6addr_t *,
+ i6addr_t *));
#endif
-extern int fr_addipftune __P((ipftuneable_t *));
-extern int fr_delipftune __P((ipftuneable_t *));
-
-extern int frflush __P((minor_t, int, int));
-extern void frsync __P((void *));
-extern frgroup_t *fr_addgroup __P((char *, void *, u_32_t, minor_t, int));
-extern int fr_derefrule __P((frentry_t **));
-extern void fr_delgroup __P((char *, minor_t, int));
-extern frgroup_t *fr_findgroup __P((char *, minor_t, int, frgroup_t ***));
-
-extern int fr_loginit __P((void));
-extern int ipflog_canread __P((int));
-extern int ipflog_clear __P((minor_t));
-extern int ipflog_read __P((minor_t, uio_t *));
-extern int ipflog __P((fr_info_t *, u_int));
-extern int ipllog __P((int, fr_info_t *, void **, size_t *, int *, int));
-extern void fr_logunload __P((void));
-
-extern frentry_t *fr_acctpkt __P((fr_info_t *, u_32_t *));
-extern int fr_copytolog __P((int, char *, int));
-extern u_short fr_cksum __P((mb_t *, ip_t *, int, void *, int));
-extern void fr_deinitialise __P((void));
-extern frentry_t *fr_dolog __P((fr_info_t *, u_32_t *));
-extern frentry_t *fr_dstgrpmap __P((fr_info_t *, u_32_t *));
-extern void fr_fixskip __P((frentry_t **, frentry_t *, int));
-extern void fr_forgetifp __P((void *));
-extern frentry_t *fr_getrulen __P((int, char *, u_32_t));
-extern void fr_getstat __P((struct friostat *));
-extern int fr_ifpaddr __P((int, int, void *,
- struct in_addr *, struct in_addr *));
-extern int fr_initialise __P((void));
-extern int fr_lock __P((caddr_t, int *));
-extern int fr_makefrip __P((int, ip_t *, fr_info_t *));
-extern int fr_matchtag __P((ipftag_t *, ipftag_t *));
-extern int fr_matchicmpqueryreply __P((int, icmpinfo_t *,
- struct icmp *, int));
-extern u_32_t fr_newisn __P((fr_info_t *));
-extern u_short fr_nextipid __P((fr_info_t *));
-extern int ipf_queueflush __P((ipftq_delete_fn_t, ipftq_t *, ipftq_t *));
-extern int fr_rulen __P((int, frentry_t *));
-extern int fr_scanlist __P((fr_info_t *, u_32_t));
-extern frentry_t *fr_srcgrpmap __P((fr_info_t *, u_32_t *));
-extern int fr_tcpudpchk __P((fr_info_t *, frtuc_t *));
-extern int fr_verifysrc __P((fr_info_t *fin));
-extern int fr_zerostats __P((void *));
-extern ipftoken_t *ipf_findtoken __P((int, int, void *));
-extern int ipf_getnextrule __P((ipftoken_t *, void *));
-extern void ipf_expiretokens __P((void));
-extern void ipf_freetoken __P((ipftoken_t *));
-extern int ipf_deltoken __P((int,int, void *));
-extern int ipfsync __P((void));
-extern int ipf_genericiter __P((void *, int, void *));
-#ifndef ipf_random
-extern u_32_t ipf_random __P((void));
+extern int ipf_tune_add __P((ipf_main_softc_t *, ipftuneable_t *));
+extern int ipf_tune_add_array __P((ipf_main_softc_t *, ipftuneable_t *));
+extern int ipf_tune_del __P((ipf_main_softc_t *, ipftuneable_t *));
+extern int ipf_tune_del_array __P((ipf_main_softc_t *, ipftuneable_t *));
+extern int ipf_tune_array_link __P((ipf_main_softc_t *, ipftuneable_t *));
+extern int ipf_tune_array_unlink __P((ipf_main_softc_t *,
+ ipftuneable_t *));
+extern ipftuneable_t *ipf_tune_array_copy __P((void *, size_t,
+ ipftuneable_t *));
+
+extern int ipf_pr_pullup __P((fr_info_t *, int));
+
+extern int ipf_flush __P((ipf_main_softc_t *, minor_t, int));
+extern frgroup_t *ipf_group_add __P((ipf_main_softc_t *, char *, void *,
+ u_32_t, minor_t, int));
+extern void ipf_group_del __P((ipf_main_softc_t *, frgroup_t *,
+ frentry_t *));
+extern int ipf_derefrule __P((ipf_main_softc_t *, frentry_t **));
+extern frgroup_t *ipf_findgroup __P((ipf_main_softc_t *, char *, minor_t,
+ int, frgroup_t ***));
+
+extern int ipf_log_init __P((void));
+extern int ipf_log_bytesused __P((ipf_main_softc_t *, int));
+extern int ipf_log_canread __P((ipf_main_softc_t *, int));
+extern int ipf_log_clear __P((ipf_main_softc_t *, minor_t));
+extern u_long ipf_log_failures __P((ipf_main_softc_t *, int));
+extern int ipf_log_read __P((ipf_main_softc_t *, minor_t, uio_t *));
+extern int ipf_log_items __P((ipf_main_softc_t *, int, fr_info_t *,
+ void **, size_t *, int *, int));
+extern u_long ipf_log_logok __P((ipf_main_softc_t *, int));
+extern void ipf_log_unload __P((ipf_main_softc_t *));
+extern int ipf_log_pkt __P((fr_info_t *, u_int));
+
+extern frentry_t *ipf_acctpkt __P((fr_info_t *, u_32_t *));
+extern u_short fr_cksum __P((fr_info_t *, ip_t *, int, void *));
+extern void ipf_deinitialise __P((ipf_main_softc_t *));
+extern int ipf_deliverlocal __P((ipf_main_softc_t *, int, void *,
+ i6addr_t *));
+extern frentry_t *ipf_dstgrpmap __P((fr_info_t *, u_32_t *));
+extern void ipf_fixskip __P((frentry_t **, frentry_t *, int));
+extern void ipf_forgetifp __P((ipf_main_softc_t *, void *));
+extern frentry_t *ipf_getrulen __P((ipf_main_softc_t *, int, char *,
+ u_32_t));
+extern int ipf_ifpaddr __P((ipf_main_softc_t *, int, int, void *,
+ i6addr_t *, i6addr_t *));
+extern void ipf_inet_mask_add __P((int, ipf_v4_masktab_t *));
+extern void ipf_inet_mask_del __P((int, ipf_v4_masktab_t *));
+#ifdef USE_INET6
+extern void ipf_inet6_mask_add __P((int, i6addr_t *,
+ ipf_v6_masktab_t *));
+extern void ipf_inet6_mask_del __P((int, i6addr_t *,
+ ipf_v6_masktab_t *));
#endif
-#ifdef NEED_LOCAL_RAND
-extern void ipf_rand_push __P((void *, int));
+extern int ipf_initialise __P((void));
+extern int ipf_lock __P((caddr_t, int *));
+extern int ipf_makefrip __P((int, ip_t *, fr_info_t *));
+extern int ipf_matchtag __P((ipftag_t *, ipftag_t *));
+extern int ipf_matchicmpqueryreply __P((int, icmpinfo_t *,
+ struct icmp *, int));
+extern u_32_t ipf_newisn __P((fr_info_t *));
+extern u_short ipf_nextipid __P((fr_info_t *));
+extern u_int ipf_pcksum __P((fr_info_t *, int, u_int));
+extern void ipf_rule_expire __P((ipf_main_softc_t *));
+extern int ipf_scanlist __P((fr_info_t *, u_32_t));
+extern frentry_t *ipf_srcgrpmap __P((fr_info_t *, u_32_t *));
+extern int ipf_tcpudpchk __P((fr_ip_t *, frtuc_t *));
+extern int ipf_verifysrc __P((fr_info_t *fin));
+extern int ipf_zerostats __P((ipf_main_softc_t *, char *));
+extern int ipf_getnextrule __P((ipf_main_softc_t *, ipftoken_t *,
+ void *));
+extern int ipf_sync __P((ipf_main_softc_t *, void *));
+extern int ipf_token_deref __P((ipf_main_softc_t *, ipftoken_t *));
+extern void ipf_token_expire __P((ipf_main_softc_t *));
+extern ipftoken_t *ipf_token_find __P((ipf_main_softc_t *, int, int,
+ void *));
+extern int ipf_token_del __P((ipf_main_softc_t *, int, int,
+ void *));
+extern void ipf_token_mark_complete __P((ipftoken_t *));
+extern int ipf_genericiter __P((ipf_main_softc_t *, void *,
+ int, void *));
+#ifdef IPFILTER_LOOKUP
+extern void *ipf_resolvelookup __P((int, u_int, u_int,
+ lookupfunc_t *));
#endif
+extern u_32_t ipf_random __P((void));
+
+extern int ipf_main_load __P((void));
+extern void *ipf_main_soft_create __P((void *));
+extern void ipf_main_soft_destroy __P((ipf_main_softc_t *));
+extern int ipf_main_soft_init __P((ipf_main_softc_t *));
+extern int ipf_main_soft_fini __P((ipf_main_softc_t *));
+extern int ipf_main_unload __P((void));
+extern int ipf_load_all __P((void));
+extern int ipf_unload_all __P((void));
+extern void ipf_destroy_all __P((ipf_main_softc_t *));
+extern ipf_main_softc_t *ipf_create_all __P((void *));
+extern int ipf_init_all __P((ipf_main_softc_t *));
+extern int ipf_fini_all __P((ipf_main_softc_t *));
+extern void ipf_log_soft_destroy __P((ipf_main_softc_t *, void *));
+extern void *ipf_log_soft_create __P((ipf_main_softc_t *));
+extern int ipf_log_soft_init __P((ipf_main_softc_t *, void *));
+extern int ipf_log_soft_fini __P((ipf_main_softc_t *, void *));
+extern int ipf_log_main_load __P((void));
+extern int ipf_log_main_unload __P((void));
+
-extern int fr_running;
-extern u_long fr_frouteok[2];
-extern int fr_pass;
-extern int fr_flags;
-extern int fr_active;
-extern int fr_chksrc;
-extern int fr_minttl;
-extern int fr_refcnt;
-extern int fr_control_forwarding;
-extern int fr_update_ipid;
-extern int nat_logging;
-extern int ipstate_logging;
-extern int ipl_suppress;
-extern int ipl_logmax;
-extern int ipl_logall;
-extern int ipl_logsize;
-extern u_long fr_ticks;
-extern fr_info_t frcache[2][8];
extern char ipfilter_version[];
-extern iplog_t **iplh[IPL_LOGMAX+1], *iplt[IPL_LOGMAX+1];
-extern int 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];
extern int icmpreplytype6[ICMP6_MAXTYPE + 1];
#endif
+#ifdef IPFILTER_COMPAT
+extern int ipf_in_compat __P((ipf_main_softc_t *, ipfobj_t *, void *,int));
+extern int ipf_out_compat __P((ipf_main_softc_t *, ipfobj_t *, void *));
+#endif
extern int icmpreplytype4[ICMP_MAXTYPE + 1];
-extern struct frgroup *ipfgroups[IPL_LOGSIZE][2];
-extern struct filterstats frstats[];
-extern frentry_t *ipfrule_match __P((fr_info_t *));
-extern u_char ipf_iss_secret[32];
-extern ipftuneable_t ipf_tuneables[];
+
+extern int ipf_ht_node_add __P((ipf_main_softc_t *, host_track_t *,
+ int, i6addr_t *));
+extern int ipf_ht_node_del __P((host_track_t *, int, i6addr_t *));
+extern void ipf_rb_ht_flush __P((host_track_t *));
+extern void ipf_rb_ht_freenode __P((host_node_t *, void *));
+extern void ipf_rb_ht_init __P((host_track_t *));
#endif /* __IP_FIL_H__ */
diff --git a/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c b/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c
index 338b69a..9d26193 100644
--- a/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c
+++ b/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c
@@ -1,13 +1,13 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1993-2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* 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_freebsd.c,v 2.53.2.50 2007/09/20 12:51:50 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id$";
#endif
#if defined(KERNEL) || defined(_KERNEL)
@@ -25,60 +25,26 @@ static const char rcsid[] = "@(#)$Id: ip_fil_freebsd.c,v 2.53.2.50 2007/09/20 12
# include "opt_random_ip_id.h"
#endif
#include <sys/param.h>
-#if defined(__FreeBSD__) && !defined(__FreeBSD_version)
-# if defined(IPFILTER_LKM)
-# ifndef __FreeBSD_cc_version
-# include <osreldate.h>
-# else
-# if __FreeBSD_cc_version < 430000
-# include <osreldate.h>
-# endif
-# endif
-# endif
-#endif
#include <sys/errno.h>
#include <sys/types.h>
#include <sys/file.h>
-#if __FreeBSD_version >= 220000
# include <sys/fcntl.h>
# include <sys/filio.h>
-#else
-# include <sys/ioctl.h>
-#endif
#include <sys/time.h>
#include <sys/systm.h>
-#if (__FreeBSD_version >= 300000)
# include <sys/dirent.h>
-#else
-# include <sys/dir.h>
-#endif
+# include <sys/mbuf.h>
+# include <sys/sockopt.h>
#if !defined(__hpux)
# include <sys/mbuf.h>
#endif
-#include <sys/protosw.h>
#include <sys/socket.h>
-#if __FreeBSD_version >= 500043
# include <sys/selinfo.h>
-#else
-# include <sys/select.h>
-#endif
-#if __FreeBSD_version >= 800044
# include <netinet/tcp_var.h>
-#else
-#define V_path_mtu_discovery path_mtu_discovery
-#define V_ipforwarding ipforwarding
-#endif
#include <net/if.h>
-#if __FreeBSD_version >= 300000
# include <net/if_var.h>
-# if __FreeBSD_version >= 500043
# include <net/netisr.h>
-# endif
-# if !defined(IPFILTER_LKM)
-# include "opt_ipfilter.h"
-# endif
-#endif
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
@@ -92,9 +58,6 @@ static const char rcsid[] = "@(#)$Id: ip_fil_freebsd.c,v 2.53.2.50 2007/09/20 12
#include <netinet/udp.h>
#include <netinet/tcpip.h>
#include <netinet/ip_icmp.h>
-#ifndef _KERNEL
-# include "netinet/ipf.h"
-#endif
#include "netinet/ip_compat.h"
#ifdef USE_INET6
# include <netinet/icmp6.h>
@@ -105,101 +68,94 @@ static const char rcsid[] = "@(#)$Id: ip_fil_freebsd.c,v 2.53.2.50 2007/09/20 12
#include "netinet/ip_state.h"
#include "netinet/ip_proxy.h"
#include "netinet/ip_auth.h"
-#ifdef IPFILTER_SYNC
#include "netinet/ip_sync.h"
-#endif
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_dstlist.h"
#ifdef IPFILTER_SCAN
#include "netinet/ip_scan.h"
#endif
#include "netinet/ip_pool.h"
-#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
# include <sys/malloc.h>
-#endif
#include <sys/kernel.h>
#ifdef CSUM_DATA_VALID
#include <machine/in_cksum.h>
#endif
extern int ip_optcopy __P((struct ip *, struct ip *));
-#if (__FreeBSD_version > 460000) && (__FreeBSD_version < 800055)
-extern int path_mtu_discovery;
-#endif
# ifdef IPFILTER_M_IPFILTER
MALLOC_DEFINE(M_IPFILTER, "ipfilter", "IP Filter packet filter data structures");
# endif
-#if !defined(__osf__)
-extern struct protosw inetsw[];
-#endif
-
-static int (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **));
-static int fr_send_ip __P((fr_info_t *, mb_t *, mb_t **));
-# ifdef USE_MUTEXES
-ipfmutex_t ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert;
-ipfmutex_t ipf_nat_new, ipf_natio, ipf_timeoutlock;
-ipfrwlock_t ipf_mutex, ipf_global, ipf_ipidfrag, ipf_frcache, ipf_tokens;
-ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth;
-# endif
+static u_short ipid = 0;
+static int (*ipf_savep) __P((void *, ip_t *, int, void *, int, struct mbuf **));
+static int ipf_send_ip __P((fr_info_t *, mb_t *));
+static void ipf_timer_func __P((void *arg));
int ipf_locks_done = 0;
-#if (__FreeBSD_version >= 300000)
-struct callout_handle fr_slowtimer_ch;
-#endif
-struct selinfo ipfselwait[IPL_LOGSIZE];
+ipf_main_softc_t ipfmain;
-#if (__FreeBSD_version >= 500011)
# include <sys/conf.h>
# if defined(NETBSD_PF)
# include <net/pfil.h>
-# if (__FreeBSD_version < 501108)
-# include <netinet/ipprotosw.h>
-# endif
+# endif /* NETBSD_PF */
/*
- * We provide the fr_checkp name just to minimize changes later.
+ * We provide the ipf_checkp name just to minimize changes later.
*/
-int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
-# endif /* NETBSD_PF */
-#endif /* __FreeBSD_version >= 500011 */
+int (*ipf_checkp) __P((void *, ip_t *ip, int hlen, void *ifp, int out, mb_t **mp));
-#if (__FreeBSD_version >= 502103)
static eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag;
static void ipf_ifevent(void *arg);
static void ipf_ifevent(arg)
-void *arg;
+ void *arg;
{
- frsync(NULL);
+ ipf_sync(arg, NULL);
}
-#endif
-#if (__FreeBSD_version >= 501108) && defined(_KERNEL)
static int
-fr_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
+ipf_check_wrapper(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
{
struct ip *ip = mtod(*mp, struct ip *);
- return fr_check(ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT), mp);
+ int rv;
+
+ /*
+ * IPFilter expects evreything in network byte order
+ */
+#if (__FreeBSD_version < 1000019)
+ ip->ip_len = htons(ip->ip_len);
+ ip->ip_off = htons(ip->ip_off);
+#endif
+ rv = ipf_check(&ipfmain, ip, ip->ip_hl << 2, ifp, (dir == PFIL_OUT),
+ mp);
+#if (__FreeBSD_version < 1000019)
+ if ((rv == 0) && (*mp != NULL)) {
+ ip = mtod(*mp, struct ip *);
+ ip->ip_len = ntohs(ip->ip_len);
+ ip->ip_off = ntohs(ip->ip_off);
+ }
+#endif
+ return rv;
}
# ifdef USE_INET6
# include <netinet/ip6.h>
static int
-fr_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
+ipf_check_wrapper6(void *arg, struct mbuf **mp, struct ifnet *ifp, int dir)
{
- return (fr_check(mtod(*mp, struct ip *), sizeof(struct ip6_hdr),
- ifp, (dir == PFIL_OUT), mp));
+ return (ipf_check(&ipfmain, mtod(*mp, struct ip *),
+ sizeof(struct ip6_hdr), ifp, (dir == PFIL_OUT), mp));
}
# endif
-#endif /* __FreeBSD_version >= 501108 */
#if defined(IPFILTER_LKM)
-int iplidentify(s)
-char *s;
+int ipf_identify(s)
+ char *s;
{
if (strcmp(s, "ipl") == 0)
return 1;
@@ -208,49 +164,67 @@ char *s;
#endif /* IPFILTER_LKM */
-int ipfattach()
+static void
+ipf_timer_func(arg)
+ void *arg;
+{
+ ipf_main_softc_t *softc = arg;
+ SPL_INT(s);
+
+ SPL_NET(s);
+ READ_ENTER(&softc->ipf_global);
+
+ if (softc->ipf_running > 0)
+ ipf_slowtimer(softc);
+
+ if (softc->ipf_running == -1 || softc->ipf_running == 1) {
+#if FREEBSD_GE_REV(300000)
+ softc->ipf_slow_ch = timeout(ipf_timer_func, softc, hz/2);
+#else
+ timeout(ipf_timer_func, softc, hz/2);
+#endif
+ }
+ RWLOCK_EXIT(&softc->ipf_global);
+ SPL_X(s);
+}
+
+
+int
+ipfattach(softc)
+ ipf_main_softc_t *softc;
{
#ifdef USE_SPL
int s;
#endif
SPL_NET(s);
- if (fr_running > 0) {
+ if (softc->ipf_running > 0) {
SPL_X(s);
return EBUSY;
}
- MUTEX_INIT(&ipf_rw, "ipf rw mutex");
- MUTEX_INIT(&ipf_timeoutlock, "ipf timeout queue mutex");
- RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock");
- RWLOCK_INIT(&ipf_tokens, "ipf token rwlock");
- ipf_locks_done = 1;
-
- if (fr_initialise() < 0) {
+ if (ipf_init_all(softc) < 0) {
SPL_X(s);
return EIO;
}
- if (fr_checkp != fr_check) {
- fr_savep = fr_checkp;
- fr_checkp = fr_check;
+ if (ipf_checkp != ipf_check) {
+ ipf_savep = ipf_checkp;
+ ipf_checkp = ipf_check;
}
- bzero((char *)ipfselwait, sizeof(ipfselwait));
- bzero((char *)frcache, sizeof(frcache));
- fr_running = 1;
+ bzero((char *)ipfmain.ipf_selwait, sizeof(ipfmain.ipf_selwait));
+ softc->ipf_running = 1;
- if (fr_control_forwarding & 1)
+ if (softc->ipf_control_forwarding & 1)
V_ipforwarding = 1;
+ ipid = 0;
+
SPL_X(s);
-#if (__FreeBSD_version >= 300000)
- fr_slowtimer_ch = timeout(fr_slowtimer, NULL,
- (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
-#else
- timeout(fr_slowtimer, NULL, (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
-#endif
+ softc->ipf_slow_ch = timeout(ipf_timer_func, softc,
+ (hz / IPF_HZ_DIVIDE) * IPF_HZ_MULT);
return 0;
}
@@ -259,44 +233,32 @@ int ipfattach()
* Disable the filter by removing the hooks from the IP input/output
* stream.
*/
-int ipfdetach()
+int
+ipfdetach(softc)
+ ipf_main_softc_t *softc;
{
#ifdef USE_SPL
int s;
#endif
- if (fr_control_forwarding & 2)
+
+ if (softc->ipf_control_forwarding & 2)
V_ipforwarding = 0;
SPL_NET(s);
-#if (__FreeBSD_version >= 300000)
- if (fr_slowtimer_ch.callout != NULL)
- untimeout(fr_slowtimer, NULL, fr_slowtimer_ch);
- bzero(&fr_slowtimer_ch, sizeof(fr_slowtimer_ch));
-#else
- untimeout(fr_slowtimer, NULL);
-#endif /* FreeBSD */
+ if (softc->ipf_slow_ch.callout != NULL)
+ untimeout(ipf_timer_func, softc, softc->ipf_slow_ch);
+ bzero(&softc->ipf_slow, sizeof(softc->ipf_slow));
#ifndef NETBSD_PF
- if (fr_checkp != NULL)
- fr_checkp = fr_savep;
- fr_savep = NULL;
+ if (ipf_checkp != NULL)
+ ipf_checkp = ipf_savep;
+ ipf_savep = NULL;
#endif
- fr_deinitialise();
-
- fr_running = -2;
-
- (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
- (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE);
+ ipf_fini_all(softc);
- if (ipf_locks_done == 1) {
- MUTEX_DESTROY(&ipf_timeoutlock);
- MUTEX_DESTROY(&ipf_rw);
- RW_DESTROY(&ipf_ipidfrag);
- RW_DESTROY(&ipf_tokens);
- ipf_locks_done = 0;
- }
+ softc->ipf_running = -2;
SPL_X(s);
@@ -307,62 +269,51 @@ int ipfdetach()
/*
* Filter ioctl interface.
*/
-int iplioctl(dev, cmd, data, mode
-# if defined(_KERNEL) && ((BSD >= 199506) || (__FreeBSD_version >= 220000))
+int
+ipfioctl(dev, cmd, data, mode
, p)
-# if (__FreeBSD_version >= 500024)
-struct thread *p;
-# if (__FreeBSD_version >= 500043)
+ struct thread *p;
# define p_cred td_ucred
# define p_uid td_ucred->cr_ruid
-# else
-# define p_cred t_proc->p_cred
-# define p_uid t_proc->p_cred->p_ruid
-# endif
-# else
-struct proc *p;
-# define p_uid p_cred->p_ruid
-# endif /* __FreeBSD_version >= 500024 */
-# else
-)
-# endif
-#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
-struct cdev *dev;
-#else
-dev_t dev;
-#endif
-ioctlcmd_t cmd;
-caddr_t data;
-int mode;
+ struct cdev *dev;
+ ioctlcmd_t cmd;
+ caddr_t data;
+ int mode;
{
int error = 0, unit = 0;
SPL_INT(s);
-#if (BSD >= 199306) && defined(_KERNEL)
-# if (__FreeBSD_version >= 500034)
- if (securelevel_ge(p->p_cred, 3) && (mode & FWRITE))
-# else
- if ((securelevel >= 3) && (mode & FWRITE))
-# endif
+#if (BSD >= 199306)
+ if (securelevel_ge(p->p_cred, 3) && (mode & FWRITE))
+ {
+ ipfmain.ipf_interror = 130001;
return EPERM;
+ }
#endif
unit = GET_MINOR(dev);
- if ((IPL_LOGMAX < unit) || (unit < 0))
+ if ((IPL_LOGMAX < unit) || (unit < 0)) {
+ ipfmain.ipf_interror = 130002;
return ENXIO;
+ }
- if (fr_running <= 0) {
- if (unit != IPL_LOGIPF)
+ if (ipfmain.ipf_running <= 0) {
+ if (unit != IPL_LOGIPF && cmd != SIOCIPFINTERROR) {
+ ipfmain.ipf_interror = 130003;
return EIO;
+ }
if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET &&
cmd != SIOCIPFSET && cmd != SIOCFRENB &&
- cmd != SIOCGETFS && cmd != SIOCGETFF)
+ cmd != SIOCGETFS && cmd != SIOCGETFF &&
+ cmd != SIOCIPFINTERROR) {
+ ipfmain.ipf_interror = 130004;
return EIO;
+ }
}
SPL_NET(s);
- error = fr_ioctlswitch(unit, data, cmd, mode, p->p_uid, p);
+ error = ipf_ioctlswitch(&ipfmain, unit, data, cmd, mode, p->p_uid, p);
if (error != -1) {
SPL_X(s);
return error;
@@ -374,182 +325,13 @@ int mode;
}
-#if 0
-void fr_forgetifp(ifp)
-void *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
- RWLOCK_EXIT(&ipf_mutex);
- fr_natsync(ifp);
-}
-#endif
-
-
-/*
- * routines below for saving IP headers to buffer
- */
-int iplopen(dev, flags
-#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL)
-, devtype, p)
-int devtype;
-# if (__FreeBSD_version >= 500024)
-struct thread *p;
-# else
-struct proc *p;
-# endif /* __FreeBSD_version >= 500024 */
-#else
-)
-#endif
-#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
-struct cdev *dev;
-#else
-dev_t dev;
-#endif
-int flags;
-{
- u_int min = GET_MINOR(dev);
-
- if (IPL_LOGMAX < min)
- min = ENXIO;
- else
- min = 0;
- return min;
-}
-
-
-int iplclose(dev, flags
-#if ((BSD >= 199506) || (__FreeBSD_version >= 220000)) && defined(_KERNEL)
-, devtype, p)
-int devtype;
-# if (__FreeBSD_version >= 500024)
-struct thread *p;
-# else
-struct proc *p;
-# endif /* __FreeBSD_version >= 500024 */
-#else
-)
-#endif
-#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
-struct cdev *dev;
-#else
-dev_t dev;
-#endif
-int flags;
-{
- u_int min = GET_MINOR(dev);
-
- if (IPL_LOGMAX < min)
- min = ENXIO;
- else
- min = 0;
- return min;
-}
-
-/*
- * iplread/ipllog
- * both of these must operate with at least splnet() lest they be
- * called during packet processing and cause an inconsistancy to appear in
- * the filter lists.
- */
-#if (BSD >= 199306)
-int iplread(dev, uio, ioflag)
-int ioflag;
-#else
-int iplread(dev, uio)
-#endif
-#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
-struct cdev *dev;
-#else
-dev_t dev;
-#endif
-register struct uio *uio;
-{
- u_int xmin = GET_MINOR(dev);
-
- if (fr_running < 1)
- return EIO;
-
- if (xmin < 0)
- return ENXIO;
-
-# ifdef IPFILTER_SYNC
- if (xmin == IPL_LOGSYNC)
- return ipfsync_read(uio);
-# endif
-
-#ifdef IPFILTER_LOG
- return ipflog_read(xmin, uio);
-#else
- return ENXIO;
-#endif
-}
-
-
/*
- * iplwrite
- * both of these must operate with at least splnet() lest they be
- * called during packet processing and cause an inconsistancy to appear in
- * the filter lists.
- */
-#if (BSD >= 199306)
-int iplwrite(dev, uio, ioflag)
-int ioflag;
-#else
-int iplwrite(dev, uio)
-#endif
-#if defined(_KERNEL) && (__FreeBSD_version >= 502116)
-struct cdev *dev;
-#else
-dev_t dev;
-#endif
-register struct uio *uio;
-{
-
- if (fr_running < 1)
- return EIO;
-
-#ifdef IPFILTER_SYNC
- if (GET_MINOR(dev) == IPL_LOGSYNC)
- return ipfsync_write(uio);
-#endif
- return ENXIO;
-}
-
-
-/*
- * fr_send_reset - this could conceivably be a call to tcp_respond(), but that
+ * ipf_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 fr_send_reset(fin)
-fr_info_t *fin;
+int
+ipf_send_reset(fin)
+ fr_info_t *fin;
{
struct tcphdr *tcp, *tcp2;
int tlen = 0, hlen;
@@ -563,7 +345,7 @@ fr_info_t *fin;
if (tcp->th_flags & TH_RST)
return -1; /* feedback loop */
- if (fr_checkl4sum(fin) == -1)
+ if (ipf_checkl4sum(fin) == -1)
return -1;
tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
@@ -628,11 +410,11 @@ fr_info_t *fin;
ip6->ip6_plen = htons(sizeof(struct tcphdr));
ip6->ip6_nxt = IPPROTO_TCP;
ip6->ip6_hlim = 0;
- ip6->ip6_src = fin->fin_dst6;
- ip6->ip6_dst = fin->fin_src6;
+ ip6->ip6_src = fin->fin_dst6.in6;
+ ip6->ip6_dst = fin->fin_src6.in6;
tcp2->th_sum = in6_cksum(m, IPPROTO_TCP,
sizeof(*ip6), sizeof(*tcp2));
- return fr_send_ip(fin, m, &m);
+ return ipf_send_ip(fin, m);
}
#endif
ip->ip_p = IPPROTO_TCP;
@@ -640,14 +422,18 @@ fr_info_t *fin;
ip->ip_src.s_addr = fin->fin_daddr;
ip->ip_dst.s_addr = fin->fin_saddr;
tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2));
- ip->ip_len = hlen + sizeof(*tcp2);
- return fr_send_ip(fin, m, &m);
+ ip->ip_len = htons(hlen + sizeof(*tcp2));
+ return ipf_send_ip(fin, m);
}
-static int fr_send_ip(fin, m, mpp)
-fr_info_t *fin;
-mb_t *m, **mpp;
+/*
+ * ip_len must be in network byte order when called.
+ */
+static int
+ipf_send_ip(fin, m)
+ fr_info_t *fin;
+ mb_t *m;
{
fr_info_t fnew;
ip_t *ip, *oip;
@@ -655,24 +441,27 @@ mb_t *m, **mpp;
ip = mtod(m, ip_t *);
bzero((char *)&fnew, sizeof(fnew));
+ fnew.fin_main_soft = fin->fin_main_soft;
IP_V_A(ip, fin->fin_v);
switch (fin->fin_v)
{
case 4 :
- fnew.fin_v = 4;
oip = fin->fin_ip;
+ hlen = sizeof(*oip);
+ fnew.fin_v = 4;
+ fnew.fin_p = ip->ip_p;
+ fnew.fin_plen = ntohs(ip->ip_len);
IP_HL_A(ip, sizeof(*oip) >> 2);
ip->ip_tos = oip->ip_tos;
ip->ip_id = fin->fin_ip->ip_id;
-#if (__FreeBSD_version > 460000)
- ip->ip_off = V_path_mtu_discovery ? IP_DF : 0;
+#if defined(FreeBSD) && (__FreeBSD_version > 460000)
+ ip->ip_off = htons(path_mtu_discovery ? IP_DF : 0);
#else
ip->ip_off = 0;
#endif
ip->ip_ttl = V_ip_defttl;
ip->ip_sum = 0;
- hlen = sizeof(*oip);
break;
#ifdef USE_INET6
case 6 :
@@ -682,8 +471,10 @@ mb_t *m, **mpp;
ip6->ip6_vfc = 0x60;
ip6->ip6_hlim = IPDEFTTL;
- fnew.fin_v = 6;
hlen = sizeof(*ip6);
+ fnew.fin_p = ip6->ip6_nxt;
+ fnew.fin_v = 6;
+ fnew.fin_plen = ntohs(ip6->ip6_plen) + hlen;
break;
}
#endif
@@ -698,28 +489,29 @@ mb_t *m, **mpp;
fnew.fin_flx = FI_NOCKSUM;
fnew.fin_m = m;
fnew.fin_ip = ip;
- fnew.fin_mp = mpp;
+ fnew.fin_mp = &m;
fnew.fin_hlen = hlen;
fnew.fin_dp = (char *)ip + hlen;
- (void) fr_makefrip(hlen, ip, &fnew);
+ (void) ipf_makefrip(hlen, ip, &fnew);
- return fr_fastroute(m, mpp, &fnew, NULL);
+ return ipf_fastroute(m, &m, &fnew, NULL);
}
-int fr_send_icmp_err(type, fin, dst)
-int type;
-fr_info_t *fin;
-int dst;
+int
+ipf_send_icmp_err(type, fin, dst)
+ int type;
+ fr_info_t *fin;
+ int dst;
{
int err, hlen, xtra, iclen, ohlen, avail, code;
struct in_addr dst4;
struct icmp *icmp;
struct mbuf *m;
+ i6addr_t dst6;
void *ifp;
#ifdef USE_INET6
ip6_t *ip6;
- struct in6_addr dst6;
#endif
ip_t *ip, *ip2;
@@ -728,11 +520,17 @@ int dst;
code = fin->fin_icode;
#ifdef USE_INET6
- if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int)))
+#if 0
+ /* XXX Fix an off by one error: s/>/>=/
+ was:
+ if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int)))
+ Fix obtained from NetBSD ip_fil_netbsd.c r1.4: */
+#endif
+ if ((code < 0) || (code >= sizeof(icmptoicmp6unreach)/sizeof(int)))
return -1;
#endif
- if (fr_checkl4sum(fin) == -1)
+ if (ipf_checkl4sum(fin) == -1)
return -1;
#ifdef MGETHDR
MGETHDR(m, M_DONTWAIT, MT_HEADER);
@@ -746,10 +544,10 @@ int dst;
xtra = 0;
hlen = 0;
ohlen = 0;
+ dst4.s_addr = 0;
ifp = fin->fin_ifp;
if (fin->fin_v == 4) {
- if ((fin->fin_p == IPPROTO_ICMP) &&
- !(fin->fin_flx & FI_SHORT))
+ if ((fin->fin_p == IPPROTO_ICMP) && !(fin->fin_flx & FI_SHORT))
switch (ntohs(fin->fin_data[0]) >> 8)
{
case ICMP_ECHO :
@@ -763,16 +561,18 @@ int dst;
}
if (dst == 0) {
- if (fr_ifpaddr(4, FRI_NORMAL, ifp,
- &dst4, NULL) == -1) {
+ if (ipf_ifpaddr(&ipfmain, 4, FRI_NORMAL, ifp,
+ &dst6, NULL) == -1) {
FREE_MB_T(m);
return -1;
}
+ dst4 = dst6.in4;
} else
dst4.s_addr = fin->fin_daddr;
hlen = sizeof(ip_t);
ohlen = fin->fin_hlen;
+ iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
if (fin->fin_hlen < fin->fin_plen)
xtra = MIN(fin->fin_dlen, 8);
else
@@ -783,12 +583,12 @@ int dst;
else if (fin->fin_v == 6) {
hlen = sizeof(ip6_t);
ohlen = sizeof(ip6_t);
+ iclen = hlen + offsetof(struct icmp, icmp_ip) + ohlen;
type = icmptoicmp6types[type];
if (type == ICMP6_DST_UNREACH)
code = icmptoicmp6unreach[code];
- if (hlen + sizeof(*icmp) + max_linkhdr +
- fin->fin_plen > avail) {
+ if (iclen + max_linkhdr + fin->fin_plen > avail) {
MCLGET(m, M_DONTWAIT);
if ((m->m_flags & M_EXT) == 0) {
FREE_MB_T(m);
@@ -796,11 +596,11 @@ int dst;
}
avail = MCLBYTES;
}
- xtra = MIN(fin->fin_plen,
- avail - hlen - sizeof(*icmp) - max_linkhdr);
+ xtra = MIN(fin->fin_plen, avail - iclen - max_linkhdr);
+ xtra = MIN(xtra, IPV6_MMTU - iclen);
if (dst == 0) {
- if (fr_ifpaddr(6, FRI_NORMAL, ifp,
- (struct in_addr *)&dst6, NULL) == -1) {
+ if (ipf_ifpaddr(&ipfmain, 6, FRI_NORMAL, ifp,
+ &dst6, NULL) == -1) {
FREE_MB_T(m);
return -1;
}
@@ -813,7 +613,6 @@ int dst;
return -1;
}
- iclen = hlen + sizeof(*icmp);
avail -= (max_linkhdr + iclen);
if (avail < 0) {
FREE_MB_T(m);
@@ -834,9 +633,17 @@ int dst;
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);
+ if (type == ICMP_UNREACH && fin->fin_icode == ICMP_UNREACH_NEEDFRAG) {
+ if (fin->fin_mtu != 0) {
+ icmp->icmp_nextmtu = htons(fin->fin_mtu);
+
+ } else if (ifp != NULL) {
+ icmp->icmp_nextmtu = htons(GETIFMTU_4(ifp));
+
+ } else { /* make up a number... */
+ icmp->icmp_nextmtu = htons(fin->fin_plen - 20);
+ }
+ }
#endif
bcopy((char *)fin->fin_ip, (char *)ip2, ohlen);
@@ -848,8 +655,8 @@ int dst;
ip6->ip6_plen = htons(iclen - hlen);
ip6->ip6_nxt = IPPROTO_ICMPV6;
ip6->ip6_hlim = 0;
- ip6->ip6_src = dst6;
- ip6->ip6_dst = fin->fin_src6;
+ ip6->ip6_src = dst6.in6;
+ ip6->ip6_dst = fin->fin_src6.in6;
if (xtra > 0)
bcopy((char *)fin->fin_ip + ohlen,
(char *)&icmp->icmp_ip + ohlen, xtra);
@@ -858,8 +665,6 @@ int dst;
} else
#endif
{
- ip2->ip_len = htons(ip2->ip_len);
- ip2->ip_off = htons(ip2->ip_off);
ip->ip_p = IPPROTO_ICMP;
ip->ip_src.s_addr = dst4.s_addr;
ip->ip_dst.s_addr = fin->fin_saddr;
@@ -869,41 +674,25 @@ int dst;
(char *)&icmp->icmp_ip + ohlen, xtra);
icmp->icmp_cksum = ipf_cksum((u_short *)icmp,
sizeof(*icmp) + 8);
- ip->ip_len = iclen;
+ ip->ip_len = htons(iclen);
ip->ip_p = IPPROTO_ICMP;
}
- err = fr_send_ip(fin, m, &m);
+ err = ipf_send_ip(fin, m);
return err;
}
-#if !defined(IPFILTER_LKM) && (__FreeBSD_version < 300000)
-# if (BSD < 199306)
-int iplinit __P((void));
-
-int
-# else
-void iplinit __P((void));
-
-void
-# endif
-iplinit()
-{
- if (ipfattach() != 0)
- printf("IP Filter failed to attach\n");
- ip_init();
-}
-#endif /* __FreeBSD_version < 300000 */
/*
* m0 - pointer to mbuf where the IP packet starts
* mpp - pointer to the mbuf pointer that is the start of the mbuf chain
*/
-int fr_fastroute(m0, mpp, fin, fdp)
-mb_t *m0, **mpp;
-fr_info_t *fin;
-frdest_t *fdp;
+int
+ipf_fastroute(m0, mpp, fin, fdp)
+ mb_t *m0, **mpp;
+ fr_info_t *fin;
+ frdest_t *fdp;
{
register struct ip *ip, *mhip;
register struct mbuf *m = *mpp;
@@ -913,6 +702,7 @@ frdest_t *fdp;
struct sockaddr_in *dst;
struct route iproute;
u_short ip_off;
+ frdest_t node;
frentry_t *fr;
ro = NULL;
@@ -949,33 +739,36 @@ frdest_t *fdp;
* currently "to <if>" and "to <if>:ip#" are not supported
* for IPv6
*/
-#if (__FreeBSD_version >= 490000)
- return ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
-#else
- return ip6_output(m0, NULL, NULL, 0, NULL, NULL);
-#endif
+ return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
}
#endif
hlen = fin->fin_hlen;
ip = mtod(m0, struct ip *);
+ ifp = NULL;
/*
* Route packet.
*/
ro = &iproute;
- bzero((caddr_t)ro, sizeof (*ro));
+ bzero(ro, sizeof (*ro));
dst = (struct sockaddr_in *)&ro->ro_dst;
dst->sin_family = AF_INET;
dst->sin_addr = ip->ip_dst;
fr = fin->fin_fr;
+ if ((fr != NULL) && !(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) &&
+ (fdp->fd_type == FRD_DSTLIST)) {
+ if (ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL, &node) == 0)
+ fdp = &node;
+ }
+
if (fdp != NULL)
- ifp = fdp->fd_ifp;
+ ifp = fdp->fd_ptr;
else
ifp = fin->fin_ifp;
- if ((ifp == NULL) && (!fr || !(fr->fr_flags & FR_FASTROUTE))) {
+ if ((ifp == NULL) && ((fr == NULL) || !(fr->fr_flags & FR_FASTROUTE))) {
error = -2;
goto bad;
}
@@ -1012,21 +805,19 @@ frdest_t *fdp;
sifp = fin->fin_ifp;
fin->fin_ifp = ifp;
fin->fin_out = 1;
- (void) fr_acctpkt(fin, NULL);
+ (void) ipf_acctpkt(fin, NULL);
fin->fin_fr = NULL;
if (!fr || !(fr->fr_flags & FR_RETMASK)) {
u_32_t pass;
- if (fr_checkstate(fin, &pass) != NULL)
- fr_statederef((ipstate_t **)&fin->fin_state);
+ (void) ipf_state_check(fin, &pass);
}
- switch (fr_checknatout(fin, NULL))
+ switch (ipf_nat_checkout(fin, NULL))
{
case 0 :
break;
case 1 :
- fr_natderef((nat_t **)&fin->fin_nat);
ip->ip_sum = 0;
break;
case -1 :
@@ -1042,14 +833,12 @@ frdest_t *fdp;
/*
* If small enough for interface, can just send directly.
*/
- if (ip->ip_len <= ifp->if_mtu) {
- ip->ip_len = htons(ip->ip_len);
- ip->ip_off = htons(ip->ip_off);
-
+ if (ntohs(ip->ip_len) <= ifp->if_mtu) {
if (!ip->ip_sum)
ip->ip_sum = in_cksum(m, hlen);
error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
- ro);
+ ro
+ );
goto done;
}
/*
@@ -1077,7 +866,7 @@ frdest_t *fdp;
*/
m0 = m;
mhlen = sizeof (struct ip);
- for (off = hlen + len; off < ip->ip_len; off += len) {
+ for (off = hlen + len; off < ntohs(ip->ip_len); off += len) {
#ifdef MGETHDR
MGETHDR(m, M_DONTWAIT, MT_HEADER);
#else
@@ -1097,8 +886,8 @@ frdest_t *fdp;
}
m->m_len = mhlen;
mhip->ip_off = ((off - hlen) >> 3) + ip_off;
- if (off + len >= ip->ip_len)
- len = ip->ip_len - off;
+ if (off + len >= ntohs(ip->ip_len))
+ len = ntohs(ip->ip_len) - off;
else
mhip->ip_off |= IP_MF;
mhip->ip_len = htons((u_short)(len + mhlen));
@@ -1130,21 +919,22 @@ sendorfree:
m->m_act = 0;
if (error == 0)
error = (*ifp->if_output)(ifp, m,
- (struct sockaddr *)dst, ro);
+ (struct sockaddr *)dst,
+ ro
+ );
else
FREE_MB_T(m);
}
- }
+ }
done:
if (!error)
- fr_frouteok[0]++;
+ ipfmain.ipf_frouteok[0]++;
else
- fr_frouteok[1]++;
+ ipfmain.ipf_frouteok[1]++;
if ((ro != NULL) && (ro->ro_rt != NULL)) {
RTFREE(ro->ro_rt);
}
- *mpp = NULL;
return 0;
bad:
if (error == EMSGSIZE) {
@@ -1152,7 +942,7 @@ bad:
code = fin->fin_icode;
fin->fin_icode = ICMP_UNREACH_NEEDFRAG;
fin->fin_ifp = ifp;
- (void) fr_send_icmp_err(ICMP_UNREACH, fin, 1);
+ (void) ipf_send_icmp_err(ICMP_UNREACH, fin, 1);
fin->fin_ifp = sifp;
fin->fin_icode = code;
}
@@ -1161,8 +951,9 @@ bad:
}
-int fr_verifysrc(fin)
-fr_info_t *fin;
+int
+ipf_verifysrc(fin)
+ fr_info_t *fin;
{
struct sockaddr_in *dst;
struct route iproute;
@@ -1182,10 +973,12 @@ fr_info_t *fin;
/*
* return the first IP Address associated with an interface
*/
-int fr_ifpaddr(v, atype, ifptr, inp, inpmask)
-int v, atype;
-void *ifptr;
-struct in_addr *inp, *inpmask;
+int
+ipf_ifpaddr(softc, v, atype, ifptr, inp, inpmask)
+ ipf_main_softc_t *softc;
+ int v, atype;
+ void *ifptr;
+ i6addr_t *inp, *inpmask;
{
#ifdef USE_INET6
struct in6_addr *inp6 = NULL;
@@ -1202,16 +995,12 @@ struct in_addr *inp, *inpmask;
ifp = ifptr;
if (v == 4)
- inp->s_addr = 0;
+ inp->in4.s_addr = 0;
#ifdef USE_INET6
else if (v == 6)
- bzero((char *)inp, sizeof(struct in6_addr));
+ bzero((char *)inp, sizeof(*inp));
#endif
-#if (__FreeBSD_version >= 300000)
ifa = TAILQ_FIRST(&ifp->if_addrhead);
-#else
- ifa = ifp->if_addrlist;
-#endif /* __FreeBSD_version >= 300000 */
sock = ifa->ifa_addr;
while (sock != NULL && ifa != NULL) {
@@ -1226,11 +1015,7 @@ struct in_addr *inp, *inpmask;
break;
}
#endif
-#if (__FreeBSD_version >= 300000)
ifa = TAILQ_NEXT(ifa, ifa_link);
-#else
- ifa = ifa->ifa_next;
-#endif /* __FreeBSD_version >= 300000 */
if (ifa != NULL)
sock = ifa->ifa_addr;
}
@@ -1249,79 +1034,45 @@ struct in_addr *inp, *inpmask;
#ifdef USE_INET6
if (v == 6) {
- return fr_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
- (struct sockaddr_in6 *)mask,
- inp, inpmask);
+ return ipf_ifpfillv6addr(atype, (struct sockaddr_in6 *)sock,
+ (struct sockaddr_in6 *)mask,
+ inp, inpmask);
}
#endif
- return fr_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
- (struct sockaddr_in *)mask, inp, inpmask);
+ return ipf_ifpfillv4addr(atype, (struct sockaddr_in *)sock,
+ (struct sockaddr_in *)mask,
+ &inp->in4, &inpmask->in4);
}
-u_32_t fr_newisn(fin)
-fr_info_t *fin;
+u_32_t
+ipf_newisn(fin)
+ fr_info_t *fin;
{
u_32_t newiss;
-#if (__FreeBSD_version >= 400000)
newiss = arc4random();
-#else
- static iss_seq_off = 0;
- u_char hash[16];
- MD5_CTX ctx;
-
- /*
- * Compute the base value of the ISS. It is a hash
- * of (saddr, sport, daddr, dport, secret).
- */
- MD5Init(&ctx);
-
- MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src,
- sizeof(fin->fin_fi.fi_src));
- MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst,
- sizeof(fin->fin_fi.fi_dst));
- MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat));
-
- MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret));
-
- MD5Final(hash, &ctx);
-
- memcpy(&newiss, hash, sizeof(newiss));
-
- /*
- * Now increment our "timer", and add it in to
- * the computed value.
- *
- * XXX Use `addin'?
- * XXX TCP_ISSINCR too large to use?
- */
- iss_seq_off += 0x00010000;
- newiss += iss_seq_off;
-#endif
return newiss;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_nextipid */
+/* Function: ipf_nextipid */
/* Returns: int - 0 == success, -1 == error (packet should be droppped) */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* Returns the next IPv4 ID to use for this packet. */
/* ------------------------------------------------------------------------ */
-u_short fr_nextipid(fin)
-fr_info_t *fin;
+u_short
+ipf_nextipid(fin)
+ fr_info_t *fin;
{
-#ifndef RANDOM_IP_ID
- static u_short ipid = 0;
u_short id;
- MUTEX_ENTER(&ipf_rw);
+#ifndef RANDOM_IP_ID
+ MUTEX_ENTER(&ipfmain.ipf_rw);
id = ipid++;
- MUTEX_EXIT(&ipf_rw);
+ MUTEX_EXIT(&ipfmain.ipf_rw);
#else
- u_short id;
-
id = ip_randomid();
#endif
@@ -1329,8 +1080,9 @@ fr_info_t *fin;
}
-INLINE void fr_checkv4sum(fin)
-fr_info_t *fin;
+INLINE int
+ipf_checkv4sum(fin)
+ fr_info_t *fin;
{
#ifdef CSUM_DATA_VALID
int manual = 0;
@@ -1339,10 +1091,13 @@ fr_info_t *fin;
mb_t *m;
if ((fin->fin_flx & FI_NOCKSUM) != 0)
- return;
+ return 0;
- if (fin->fin_cksum != 0)
- return;
+ if ((fin->fin_flx & FI_SHORT) != 0)
+ return 1;
+
+ if (fin->fin_cksum != FI_CK_NEEDED)
+ return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
m = fin->fin_m;
if (m == NULL) {
@@ -1351,56 +1106,86 @@ fr_info_t *fin;
}
ip = fin->fin_ip;
+ if ((m->m_pkthdr.csum_flags & (CSUM_IP_CHECKED|CSUM_IP_VALID)) ==
+ CSUM_IP_CHECKED) {
+ fin->fin_cksum = FI_CK_BAD;
+ fin->fin_flx |= FI_BAD;
+ return -1;
+ }
if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR)
sum = m->m_pkthdr.csum_data;
else
sum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
htonl(m->m_pkthdr.csum_data +
- fin->fin_ip->ip_len -
- (fin->fin_ip->ip_hl << 2) +
- fin->fin_p));
+ fin->fin_dlen + fin->fin_p));
sum ^= 0xffff;
if (sum != 0) {
+ fin->fin_cksum = FI_CK_BAD;
fin->fin_flx |= FI_BAD;
- fin->fin_cksum = -1;
} else {
- fin->fin_cksum = 1;
+ fin->fin_cksum = FI_CK_SUMOK;
+ return 0;
}
- } else
- manual = 1;
+ } else {
+ if (m->m_pkthdr.csum_flags == CSUM_DELAY_DATA) {
+ fin->fin_cksum = FI_CK_L4FULL;
+ return 0;
+ } else if (m->m_pkthdr.csum_flags == CSUM_TCP ||
+ m->m_pkthdr.csum_flags == CSUM_UDP) {
+ fin->fin_cksum = FI_CK_L4PART;
+ return 0;
+ } else if (m->m_pkthdr.csum_flags == CSUM_IP) {
+ fin->fin_cksum = FI_CK_L4PART;
+ return 0;
+ } else {
+ manual = 1;
+ }
+ }
skipauto:
-# ifdef IPFILTER_CKSUM
- if (manual != 0)
- if (fr_checkl4sum(fin) == -1)
+ if (manual != 0) {
+ if (ipf_checkl4sum(fin) == -1) {
fin->fin_flx |= FI_BAD;
-# else
- ;
-# endif
+ return -1;
+ }
+ }
#else
-# ifdef IPFILTER_CKSUM
- if (fr_checkl4sum(fin) == -1)
+ if (ipf_checkl4sum(fin) == -1) {
fin->fin_flx |= FI_BAD;
-# endif
+ return -1;
+ }
#endif
+ return 0;
}
#ifdef USE_INET6
-INLINE void fr_checkv6sum(fin)
-fr_info_t *fin;
+INLINE int
+ipf_checkv6sum(fin)
+ fr_info_t *fin;
{
-# ifdef IPFILTER_CKSUM
- if (fr_checkl4sum(fin) == -1)
+ if ((fin->fin_flx & FI_NOCKSUM) != 0)
+ return 0;
+
+ if ((fin->fin_flx & FI_SHORT) != 0)
+ return 1;
+
+ if (fin->fin_cksum != FI_CK_NEEDED)
+ return (fin->fin_cksum > FI_CK_NEEDED) ? 0 : -1;
+
+ if (ipf_checkl4sum(fin) == -1) {
fin->fin_flx |= FI_BAD;
-# endif
+ return -1;
+ }
+ return 0;
}
#endif /* USE_INET6 */
-size_t mbufchainlen(m0)
-struct mbuf *m0;
-{
+size_t
+mbufchainlen(m0)
+ struct mbuf *m0;
+ {
size_t len;
if ((m0->m_flags & M_PKTHDR) != 0) {
@@ -1416,29 +1201,30 @@ struct mbuf *m0;
/* ------------------------------------------------------------------------ */
-/* Function: fr_pullup */
+/* Function: ipf_pullup */
/* Returns: NULL == pullup failed, else pointer to protocol header */
-/* Parameters: m(I) - pointer to buffer where data packet starts */
+/* Parameters: xmin(I)- pointer to buffer where data packet starts */
/* fin(I) - pointer to packet information */
/* len(I) - number of bytes to pullup */
/* */
/* Attempt to move at least len bytes (from the start of the buffer) into a */
/* single buffer for ease of access. Operating system native functions are */
/* used to manage buffers - if necessary. If the entire packet ends up in */
-/* a single buffer, set the FI_COALESCE flag even though fr_coalesce() has */
+/* a single buffer, set the FI_COALESCE flag even though ipf_coalesce() has */
/* not been called. Both fin_ip and fin_dp are updated before exiting _IF_ */
/* and ONLY if the pullup succeeds. */
/* */
-/* We assume that 'min' is a pointer to a buffer that is part of the chain */
+/* We assume that 'xmin' is a pointer to a buffer that is part of the chain */
/* of buffers that starts at *fin->fin_mp. */
/* ------------------------------------------------------------------------ */
-void *fr_pullup(min, fin, len)
-mb_t *min;
-fr_info_t *fin;
-int len;
+void *
+ipf_pullup(xmin, fin, len)
+ mb_t *xmin;
+ fr_info_t *fin;
+ int len;
{
- int out = fin->fin_out, dpoff, ipoff;
- mb_t *m = min;
+ int dpoff, ipoff;
+ mb_t *m = xmin;
char *ip;
if (m == NULL)
@@ -1455,12 +1241,25 @@ int len;
dpoff = 0;
if (M_LEN(m) < len) {
-#ifdef MHLEN
+ mb_t *n = *fin->fin_mp;
/*
* Assume that M_PKTHDR is set and just work with what is left
* rather than check..
* Should not make any real difference, anyway.
*/
+ if (m != n) {
+ /*
+ * Record the mbuf that points to the mbuf that we're
+ * about to go to work on so that we can update the
+ * m_next appropriately later.
+ */
+ for (; n->m_next != m; n = n->m_next)
+ ;
+ } else {
+ n = NULL;
+ }
+
+#ifdef MHLEN
if (len > MHLEN)
#else
if (len > MLEN)
@@ -1472,29 +1271,46 @@ int len;
#else
FREE_MB_T(*fin->fin_mp);
m = NULL;
+ n = NULL;
#endif
} else
{
m = m_pullup(m, len);
}
- *fin->fin_mp = m;
+ if (n != NULL)
+ n->m_next = m;
if (m == NULL) {
+ /*
+ * When n is non-NULL, it indicates that m pointed to
+ * a sub-chain (tail) of the mbuf and that the head
+ * of this chain has not yet been free'd.
+ */
+ if (n != NULL) {
+ FREE_MB_T(*fin->fin_mp);
+ }
+
+ *fin->fin_mp = NULL;
fin->fin_m = NULL;
- ATOMIC_INCL(frstats[out].fr_pull[1]);
return NULL;
}
+ if (n == NULL)
+ *fin->fin_mp = m;
+
while (M_LEN(m) == 0) {
m = m->m_next;
}
fin->fin_m = m;
ip = MTOD(m, char *) + ipoff;
- }
- ATOMIC_INCL(frstats[out].fr_pull[0]);
- fin->fin_ip = (ip_t *)ip;
- if (fin->fin_dp != NULL)
- fin->fin_dp = (char *)fin->fin_ip + dpoff;
+ fin->fin_ip = (ip_t *)ip;
+ if (fin->fin_dp != NULL)
+ fin->fin_dp = (char *)fin->fin_ip + dpoff;
+ if (fin->fin_fraghdr != NULL)
+ fin->fin_fraghdr = (char *)ip +
+ ((char *)fin->fin_fraghdr -
+ (char *)fin->fin_ip);
+ }
if (len == fin->fin_plen)
fin->fin_flx |= FI_COALESCE;
@@ -1502,45 +1318,19 @@ int len;
}
-int ipf_inject(fin, m)
-fr_info_t *fin;
-mb_t *m;
+int
+ipf_inject(fin, m)
+ fr_info_t *fin;
+ mb_t *m;
{
int error = 0;
if (fin->fin_out == 0) {
-#if (__FreeBSD_version >= 501000)
netisr_dispatch(NETISR_IP, m);
-#else
- struct ifqueue *ifq;
-
- ifq = &ipintrq;
-
-# ifdef _IF_QFULL
- if (_IF_QFULL(ifq))
-# else
- if (IF_QFULL(ifq))
-# endif
- {
-# ifdef _IF_DROP
- _IF_DROP(ifq);
-# else
- IF_DROP(ifq);
-# endif
- FREE_MB_T(m);
- error = ENOBUFS;
- } else {
- IF_ENQUEUE(ifq, m);
- }
-#endif
} else {
fin->fin_ip->ip_len = ntohs(fin->fin_ip->ip_len);
fin->fin_ip->ip_off = ntohs(fin->fin_ip->ip_off);
-#if (__FreeBSD_version >= 470102)
error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
-#else
- error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL);
-#endif
}
return error;
@@ -1548,38 +1338,22 @@ mb_t *m;
int ipf_pfil_unhook(void) {
#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
-# if __FreeBSD_version >= 501108
struct pfil_head *ph_inet;
# ifdef USE_INET6
struct pfil_head *ph_inet6;
# endif
-# endif
#endif
#ifdef NETBSD_PF
-# if (__FreeBSD_version >= 500011)
-# if (__FreeBSD_version >= 501108)
ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
if (ph_inet != NULL)
- pfil_remove_hook((void *)fr_check_wrapper, NULL,
+ pfil_remove_hook((void *)ipf_check_wrapper, NULL,
PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
-# else
- pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
- &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
-# endif
-# else
- pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK);
-# endif
# ifdef USE_INET6
-# if (__FreeBSD_version >= 501108)
ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
if (ph_inet6 != NULL)
- pfil_remove_hook((void *)fr_check_wrapper6, NULL,
+ pfil_remove_hook((void *)ipf_check_wrapper6, NULL,
PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
-# else
- pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
- &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
-# endif
# endif
#endif
@@ -1588,17 +1362,13 @@ int ipf_pfil_unhook(void) {
int ipf_pfil_hook(void) {
#if defined(NETBSD_PF) && (__FreeBSD_version >= 500011)
-# if __FreeBSD_version >= 501108
struct pfil_head *ph_inet;
# ifdef USE_INET6
struct pfil_head *ph_inet6;
# endif
-# endif
#endif
# ifdef NETBSD_PF
-# if __FreeBSD_version >= 500011
-# if __FreeBSD_version >= 501108
ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
# ifdef USE_INET6
ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
@@ -1607,28 +1377,17 @@ int ipf_pfil_hook(void) {
# ifdef USE_INET6
&& ph_inet6 == NULL
# endif
- )
+ ) {
return ENODEV;
+ }
if (ph_inet != NULL)
- pfil_add_hook((void *)fr_check_wrapper, NULL,
+ pfil_add_hook((void *)ipf_check_wrapper, NULL,
PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet);
-# else
- pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
- &inetsw[ip_protox[IPPROTO_IP]].pr_pfh);
-# endif
-# else
- pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK);
-# endif
# ifdef USE_INET6
-# if __FreeBSD_version >= 501108
if (ph_inet6 != NULL)
- pfil_add_hook((void *)fr_check_wrapper6, NULL,
+ pfil_add_hook((void *)ipf_check_wrapper6, NULL,
PFIL_IN|PFIL_OUT|PFIL_WAITOK, ph_inet6);
-# else
- pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT|PFIL_WAITOK,
- &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh);
-# endif
# endif
# endif
return (0);
@@ -1637,22 +1396,19 @@ int ipf_pfil_hook(void) {
void
ipf_event_reg(void)
{
-#if (__FreeBSD_version >= 502103)
- ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \
- ipf_ifevent, NULL, \
+ ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \
+ ipf_ifevent, &ipfmain, \
EVENTHANDLER_PRI_ANY);
- ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \
- ipf_ifevent, NULL, \
+ ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \
+ ipf_ifevent, &ipfmain, \
EVENTHANDLER_PRI_ANY);
- ipf_clonetag = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \
- NULL, EVENTHANDLER_PRI_ANY);
-#endif
+ ipf_clonetag = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \
+ &ipfmain, EVENTHANDLER_PRI_ANY);
}
void
ipf_event_dereg(void)
{
-#if (__FreeBSD_version >= 502103)
if (ipf_arrivetag != NULL) {
EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag);
}
@@ -1662,5 +1418,40 @@ ipf_event_dereg(void)
if (ipf_clonetag != NULL) {
EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag);
}
-#endif
+}
+
+
+u_32_t
+ipf_random()
+{
+ return arc4random();
+}
+
+
+u_int
+ipf_pcksum(fin, hlen, sum)
+ fr_info_t *fin;
+ int hlen;
+ u_int sum;
+{
+ struct mbuf *m;
+ u_int sum2;
+ int off;
+
+ m = fin->fin_m;
+ off = (char *)fin->fin_dp - (char *)fin->fin_ip;
+ m->m_data += hlen;
+ m->m_len -= hlen;
+ sum2 = in_cksum(fin->fin_m, fin->fin_plen - off);
+ m->m_len += hlen;
+ m->m_data -= hlen;
+
+ /*
+ * Both sum and sum2 are partial sums, so combine them together.
+ */
+ sum += ~sum2 & 0xffff;
+ while (sum > 0xffff)
+ sum = (sum & 0xffff) + (sum >> 16);
+ sum2 = ~sum & 0xffff;
+ return sum2;
}
diff --git a/sys/contrib/ipfilter/netinet/ip_frag.c b/sys/contrib/ipfilter/netinet/ip_frag.c
index fb21bd1..87e5b7b 100644
--- a/sys/contrib/ipfilter/netinet/ip_frag.c
+++ b/sys/contrib/ipfilter/netinet/ip_frag.c
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1993-2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*/
@@ -30,7 +30,8 @@ struct file;
# include <sys/uio.h>
# undef _KERNEL
#endif
-#if defined(_KERNEL) && (__FreeBSD_version >= 220000)
+#if defined(_KERNEL) && \
+ defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
# include <sys/filio.h>
# include <sys/fcntl.h>
#else
@@ -62,7 +63,6 @@ struct file;
#ifdef sun
# include <net/af.h>
#endif
-#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
@@ -79,25 +79,9 @@ struct file;
#include "netinet/ip_frag.h"
#include "netinet/ip_state.h"
#include "netinet/ip_auth.h"
+#include "netinet/ip_lookup.h"
#include "netinet/ip_proxy.h"
-#if (__FreeBSD_version >= 300000)
-# include <sys/malloc.h>
-# if defined(_KERNEL)
-# ifndef IPFILTER_LKM
-# include <sys/libkern.h>
-# include <sys/systm.h>
-# endif
-extern struct callout_handle fr_slowtimer_ch;
-# endif
-#endif
-#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
-# include <sys/callout.h>
-extern struct callout fr_slowtimer_ch;
-#endif
-#if defined(__OpenBSD__)
-# include <sys/timeout.h>
-extern struct timeout fr_slowtimer_ch;
-#endif
+#include "netinet/ip_sync.h"
/* END OF INCLUDES */
#if !defined(lint)
@@ -107,180 +91,398 @@ static const char rcsid[] = "@(#)$FreeBSD$";
#endif
-ipfr_t *ipfr_list = NULL;
-ipfr_t **ipfr_tail = &ipfr_list;
-
-ipfr_t *ipfr_natlist = NULL;
-ipfr_t **ipfr_nattail = &ipfr_natlist;
+typedef struct ipf_frag_softc_s {
+ ipfrwlock_t ipfr_ipidfrag;
+ ipfrwlock_t ipfr_frag;
+ ipfrwlock_t ipfr_natfrag;
+ int ipfr_size;
+ int ipfr_ttl;
+ int ipfr_lock;
+ int ipfr_inited;
+ ipfr_t *ipfr_list;
+ ipfr_t **ipfr_tail;
+ ipfr_t *ipfr_natlist;
+ ipfr_t **ipfr_nattail;
+ ipfr_t *ipfr_ipidlist;
+ ipfr_t **ipfr_ipidtail;
+ ipfr_t **ipfr_heads;
+ ipfr_t **ipfr_nattab;
+ ipfr_t **ipfr_ipidtab;
+ ipfrstat_t ipfr_stats;
+} ipf_frag_softc_t;
-ipfr_t *ipfr_ipidlist = NULL;
-ipfr_t **ipfr_ipidtail = &ipfr_ipidlist;
-static ipfr_t **ipfr_heads;
-static ipfr_t **ipfr_nattab;
-static ipfr_t **ipfr_ipidtab;
-
-static ipfrstat_t ipfr_stats;
-static int ipfr_inuse = 0;
-int ipfr_size = IPFT_SIZE;
+#ifdef USE_MUTEXES
+static ipfr_t *ipfr_frag_new __P((ipf_main_softc_t *, ipf_frag_softc_t *,
+ fr_info_t *, u_32_t, ipfr_t **,
+ ipfrwlock_t *));
+static ipfr_t *ipf_frag_lookup __P((ipf_main_softc_t *, ipf_frag_softc_t *, fr_info_t *, ipfr_t **, ipfrwlock_t *));
+static void ipf_frag_deref __P((void *, ipfr_t **, ipfrwlock_t *));
+static int ipf_frag_next __P((ipf_main_softc_t *, ipftoken_t *, ipfgeniter_t *,
+ ipfr_t **, ipfrwlock_t *));
+#else
+static ipfr_t *ipfr_frag_new __P((ipf_main_softc_t *, ipf_frag_softc_t *,
+ fr_info_t *, u_32_t, ipfr_t **));
+static ipfr_t *ipf_frag_lookup __P((ipf_main_softc_t *, ipf_frag_softc_t *, fr_info_t *, ipfr_t **));
+static void ipf_frag_deref __P((void *, ipfr_t **));
+static int ipf_frag_next __P((ipf_main_softc_t *, ipftoken_t *, ipfgeniter_t *,
+ ipfr_t **));
+#endif
+static void ipf_frag_delete __P((ipf_main_softc_t *, ipfr_t *, ipfr_t ***));
+static void ipf_frag_free __P((ipf_frag_softc_t *, ipfr_t *));
+
+static frentry_t ipfr_block;
+
+ipftuneable_t ipf_tuneables[] = {
+ { { (void *)offsetof(ipf_frag_softc_t, ipfr_size) },
+ "frag_size", 1, 0x7fffffff,
+ stsizeof(ipf_frag_softc_t, ipfr_size),
+ IPFT_WRDISABLED, NULL, NULL },
+ { { (void *)offsetof(ipf_frag_softc_t, ipfr_ttl) },
+ "frag_ttl", 1, 0x7fffffff,
+ stsizeof(ipf_frag_softc_t, ipfr_ttl),
+ 0, NULL, NULL },
+ { { NULL },
+ NULL, 0, 0,
+ 0,
+ 0, NULL, NULL }
+};
+
+#define FBUMP(x) softf->ipfr_stats.x++
+#define FBUMPD(x) do { softf->ipfr_stats.x++; DT(x); } while (0)
-int fr_ipfrttl = 120; /* 60 seconds */
-int fr_frag_lock = 0;
-int fr_frag_init = 0;
-u_long fr_ticks = 0;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_frag_main_load */
+/* Returns: int - 0 == success, -1 == error */
+/* Parameters: Nil */
+/* */
+/* Initialise the filter rule associted with blocked packets - everyone can */
+/* use it. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_frag_main_load()
+{
+ bzero((char *)&ipfr_block, sizeof(ipfr_block));
+ ipfr_block.fr_flags = FR_BLOCK|FR_QUICK;
+ ipfr_block.fr_ref = 1;
-static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **));
-static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **));
-static void fr_fragdelete __P((ipfr_t *, ipfr_t ***));
-static void fr_fragfree __P((ipfr_t *));
+ return 0;
+}
/* ------------------------------------------------------------------------ */
-/* Function: fr_fraginit */
+/* Function: ipf_frag_main_unload */
/* Returns: int - 0 == success, -1 == error */
/* Parameters: Nil */
/* */
+/* A null-op function that exists as a placeholder so that the flow in */
+/* other functions is obvious. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_frag_main_unload()
+{
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_frag_soft_create */
+/* Returns: void * - NULL = failure, else pointer to local context */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Allocate a new soft context structure to track fragment related info. */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+void *
+ipf_frag_soft_create(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_frag_softc_t *softf;
+
+ KMALLOC(softf, ipf_frag_softc_t *);
+ if (softf == NULL)
+ return NULL;
+
+ bzero((char *)softf, sizeof(*softf));
+
+ RWLOCK_INIT(&softf->ipfr_ipidfrag, "frag ipid lock");
+ RWLOCK_INIT(&softf->ipfr_frag, "ipf fragment rwlock");
+ RWLOCK_INIT(&softf->ipfr_natfrag, "ipf NAT fragment rwlock");
+
+ softf->ipfr_size = IPFT_SIZE;
+ softf->ipfr_ttl = IPF_TTLVAL(60);
+ softf->ipfr_lock = 1;
+ softf->ipfr_tail = &softf->ipfr_list;
+ softf->ipfr_nattail = &softf->ipfr_natlist;
+ softf->ipfr_ipidtail = &softf->ipfr_ipidlist;
+
+ return softf;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_frag_soft_destroy */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
/* Initialise the hash tables for the fragment cache lookups. */
/* ------------------------------------------------------------------------ */
-int fr_fraginit()
+void
+ipf_frag_soft_destroy(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
{
- KMALLOCS(ipfr_heads, ipfr_t **, ipfr_size * sizeof(ipfr_t *));
- if (ipfr_heads == NULL)
- return -1;
- bzero((char *)ipfr_heads, ipfr_size * sizeof(ipfr_t *));
+ ipf_frag_softc_t *softf = arg;
+
+ RW_DESTROY(&softf->ipfr_ipidfrag);
+ RW_DESTROY(&softf->ipfr_frag);
+ RW_DESTROY(&softf->ipfr_natfrag);
+
+ KFREE(softf);
+}
- KMALLOCS(ipfr_nattab, ipfr_t **, ipfr_size * sizeof(ipfr_t *));
- if (ipfr_nattab == NULL)
- return -1;
- bzero((char *)ipfr_nattab, ipfr_size * sizeof(ipfr_t *));
- KMALLOCS(ipfr_ipidtab, ipfr_t **, ipfr_size * sizeof(ipfr_t *));
- if (ipfr_ipidtab == NULL)
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_frag_soft_init */
+/* Returns: int - 0 == success, -1 == error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* Initialise the hash tables for the fragment cache lookups. */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+int
+ipf_frag_soft_init(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_frag_softc_t *softf = arg;
+
+ KMALLOCS(softf->ipfr_heads, ipfr_t **,
+ softf->ipfr_size * sizeof(ipfr_t *));
+ if (softf->ipfr_heads == NULL)
return -1;
- bzero((char *)ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *));
- RWLOCK_INIT(&ipf_frag, "ipf fragment rwlock");
- fr_frag_init = 1;
+ bzero((char *)softf->ipfr_heads, softf->ipfr_size * sizeof(ipfr_t *));
+
+ KMALLOCS(softf->ipfr_nattab, ipfr_t **,
+ softf->ipfr_size * sizeof(ipfr_t *));
+ if (softf->ipfr_nattab == NULL)
+ return -2;
+
+ bzero((char *)softf->ipfr_nattab, softf->ipfr_size * sizeof(ipfr_t *));
+
+ KMALLOCS(softf->ipfr_ipidtab, ipfr_t **,
+ softf->ipfr_size * sizeof(ipfr_t *));
+ if (softf->ipfr_ipidtab == NULL)
+ return -3;
+
+ bzero((char *)softf->ipfr_ipidtab,
+ softf->ipfr_size * sizeof(ipfr_t *));
+
+ softf->ipfr_lock = 0;
+ softf->ipfr_inited = 1;
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_fragunload */
-/* Returns: Nil */
-/* Parameters: Nil */
+/* Function: ipf_frag_soft_fini */
+/* Returns: int - 0 == success, -1 == error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
/* */
/* Free all memory allocated whilst running and from initialisation. */
/* ------------------------------------------------------------------------ */
-void fr_fragunload()
+int
+ipf_frag_soft_fini(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
{
- if (fr_frag_init == 1) {
- fr_fragclear();
+ ipf_frag_softc_t *softf = arg;
+
+ softf->ipfr_lock = 1;
- RW_DESTROY(&ipf_frag);
- fr_frag_init = 0;
+ if (softf->ipfr_inited == 1) {
+ ipf_frag_clear(softc);
+
+ softf->ipfr_inited = 0;
}
- if (ipfr_heads != NULL)
- KFREES(ipfr_heads, ipfr_size * sizeof(ipfr_t *));
- ipfr_heads = NULL;
+ if (softf->ipfr_heads != NULL)
+ KFREES(softf->ipfr_heads,
+ softf->ipfr_size * sizeof(ipfr_t *));
+ softf->ipfr_heads = NULL;
+
+ if (softf->ipfr_nattab != NULL)
+ KFREES(softf->ipfr_nattab,
+ softf->ipfr_size * sizeof(ipfr_t *));
+ softf->ipfr_nattab = NULL;
- if (ipfr_nattab != NULL)
- KFREES(ipfr_nattab, ipfr_size * sizeof(ipfr_t *));
- ipfr_nattab = NULL;
+ if (softf->ipfr_ipidtab != NULL)
+ KFREES(softf->ipfr_ipidtab,
+ softf->ipfr_size * sizeof(ipfr_t *));
+ softf->ipfr_ipidtab = NULL;
- if (ipfr_ipidtab != NULL)
- KFREES(ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *));
- ipfr_ipidtab = NULL;
+ return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_fragstats */
+/* Function: ipf_frag_set_lock */
+/* Returns: Nil */
+/* Parameters: arg(I) - pointer to local context to use */
+/* tmp(I) - new value for lock */
+/* */
+/* Stub function that allows for external manipulation of ipfr_lock */
+/* ------------------------------------------------------------------------ */
+void
+ipf_frag_setlock(arg, tmp)
+ void *arg;
+ int tmp;
+{
+ ipf_frag_softc_t *softf = arg;
+
+ softf->ipfr_lock = tmp;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_frag_stats */
/* Returns: ipfrstat_t* - pointer to struct with current frag stats */
-/* Parameters: Nil */
+/* Parameters: arg(I) - pointer to local context to use */
/* */
/* Updates ipfr_stats with current information and returns a pointer to it */
/* ------------------------------------------------------------------------ */
-ipfrstat_t *fr_fragstats()
+ipfrstat_t *
+ipf_frag_stats(arg)
+ void *arg;
{
- ipfr_stats.ifs_table = ipfr_heads;
- ipfr_stats.ifs_nattab = ipfr_nattab;
- ipfr_stats.ifs_inuse = ipfr_inuse;
- return &ipfr_stats;
+ ipf_frag_softc_t *softf = arg;
+
+ softf->ipfr_stats.ifs_table = softf->ipfr_heads;
+ softf->ipfr_stats.ifs_nattab = softf->ipfr_nattab;
+ return &softf->ipfr_stats;
}
/* ------------------------------------------------------------------------ */
-/* Function: ipfr_newfrag */
+/* Function: ipfr_frag_new */
/* Returns: ipfr_t * - pointer to fragment cache state info or NULL */
/* Parameters: fin(I) - pointer to packet information */
/* table(I) - pointer to frag table to add to */
+/* lock(I) - pointer to lock to get a write hold of */
/* */
/* Add a new entry to the fragment cache, registering it as having come */
/* through this box, with the result of the filter operation. */
+/* */
+/* If this function succeeds, it returns with a write lock held on "lock". */
+/* If it fails, no lock is held on return. */
/* ------------------------------------------------------------------------ */
-static ipfr_t *ipfr_newfrag(fin, pass, table)
-fr_info_t *fin;
-u_32_t pass;
-ipfr_t *table[];
+static ipfr_t *
+ipfr_frag_new(softc, softf, fin, pass, table
+#ifdef USE_MUTEXES
+, lock
+#endif
+)
+ ipf_main_softc_t *softc;
+ ipf_frag_softc_t *softf;
+ fr_info_t *fin;
+ u_32_t pass;
+ ipfr_t *table[];
+#ifdef USE_MUTEXES
+ ipfrwlock_t *lock;
+#endif
{
- ipfr_t *fra, frag;
+ ipfr_t *fra, frag, *fran;
u_int idx, off;
frentry_t *fr;
- ip_t *ip;
- if (ipfr_inuse >= IPFT_SIZE)
+ if (softf->ipfr_stats.ifs_inuse >= softf->ipfr_size) {
+ FBUMPD(ifs_maximum);
return NULL;
+ }
- if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
+ if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) {
+ FBUMPD(ifs_newbad);
return NULL;
+ }
- ip = fin->fin_ip;
-
- if (pass & FR_FRSTRICT)
- if (fin->fin_off != 0)
+ if (pass & FR_FRSTRICT) {
+ if (fin->fin_off != 0) {
+ FBUMPD(ifs_newrestrictnot0);
return NULL;
+ }
+ }
- frag.ipfr_p = ip->ip_p;
- idx = ip->ip_p;
- frag.ipfr_id = ip->ip_id;
- idx += ip->ip_id;
- frag.ipfr_tos = ip->ip_tos;
- frag.ipfr_src.s_addr = ip->ip_src.s_addr;
- idx += ip->ip_src.s_addr;
- frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;
- idx += ip->ip_dst.s_addr;
+ frag.ipfr_v = fin->fin_v;
+ idx = fin->fin_v;
+ frag.ipfr_p = fin->fin_p;
+ idx += fin->fin_p;
+ frag.ipfr_id = fin->fin_id;
+ idx += fin->fin_id;
+ frag.ipfr_source = fin->fin_fi.fi_src;
+ idx += frag.ipfr_src.s_addr;
+ frag.ipfr_dest = fin->fin_fi.fi_dst;
+ idx += frag.ipfr_dst.s_addr;
frag.ipfr_ifp = fin->fin_ifp;
idx *= 127;
- idx %= IPFT_SIZE;
+ idx %= softf->ipfr_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...
- */
- for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext)
- if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp,
- IPFR_CMPSZ)) {
- ipfr_stats.ifs_exists++;
- return NULL;
+ off = fin->fin_off >> 3;
+ if (off == 0) {
+ char *ptr;
+ int end;
+
+#ifdef USE_INET6
+ if (fin->fin_v == 6) {
+
+ ptr = (char *)fin->fin_fraghdr +
+ sizeof(struct ip6_frag);
+ } else
+#endif
+ {
+ ptr = fin->fin_dp;
}
+ end = fin->fin_plen - (ptr - (char *)fin->fin_ip);
+ frag.ipfr_firstend = end >> 3;
+ } else {
+ frag.ipfr_firstend = 0;
+ }
/*
* allocate some memory, if possible, if not, just record that we
* failed to do so.
*/
- KMALLOC(fra, ipfr_t *);
- if (fra == NULL) {
- ipfr_stats.ifs_nomem++;
+ KMALLOC(fran, ipfr_t *);
+ if (fran == NULL) {
+ FBUMPD(ifs_nomem);
return NULL;
}
+ WRITE_ENTER(lock);
+
+ /*
+ * first, make sure it isn't already there...
+ */
+ for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext)
+ if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp,
+ IPFR_CMPSZ)) {
+ RWLOCK_EXIT(lock);
+ FBUMPD(ifs_exists);
+ KFREE(fra);
+ return NULL;
+ }
+
+ fra = fran;
+ fran = NULL;
fr = fin->fin_fr;
fra->ipfr_rule = fr;
if (fr != NULL) {
@@ -300,56 +502,63 @@ ipfr_t *table[];
fra->ipfr_data = NULL;
table[idx] = fra;
bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ);
- fra->ipfr_ttl = fr_ticks + fr_ipfrttl;
+ fra->ipfr_v = fin->fin_v;
+ fra->ipfr_ttl = softc->ipf_ticks + softf->ipfr_ttl;
+ fra->ipfr_firstend = frag.ipfr_firstend;
/*
* Compute the offset of the expected start of the next packet.
*/
- off = ip->ip_off & IP_OFFMASK;
if (off == 0)
fra->ipfr_seen0 = 1;
fra->ipfr_off = off + (fin->fin_dlen >> 3);
fra->ipfr_pass = pass;
fra->ipfr_ref = 1;
- ipfr_stats.ifs_new++;
- ipfr_inuse++;
+ fra->ipfr_pkts = 1;
+ fra->ipfr_bytes = fin->fin_plen;
+ FBUMP(ifs_inuse);
+ FBUMP(ifs_new);
return fra;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_newfrag */
+/* Function: ipf_frag_new */
/* Returns: int - 0 == success, -1 == error */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* Add a new entry to the fragment cache table based on the current packet */
/* ------------------------------------------------------------------------ */
-int fr_newfrag(fin, pass)
-u_32_t pass;
-fr_info_t *fin;
+int
+ipf_frag_new(softc, fin, pass)
+ ipf_main_softc_t *softc;
+ u_32_t pass;
+ fr_info_t *fin;
{
+ ipf_frag_softc_t *softf = softc->ipf_frag_soft;
ipfr_t *fra;
- if ((fin->fin_v != 4) || (fr_frag_lock != 0))
+ if (softf->ipfr_lock != 0)
return -1;
- WRITE_ENTER(&ipf_frag);
- fra = ipfr_newfrag(fin, pass, ipfr_heads);
+#ifdef USE_MUTEXES
+ fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_heads, &softc->ipf_frag);
+#else
+ fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_heads);
+#endif
if (fra != NULL) {
- *ipfr_tail = fra;
- fra->ipfr_prev = ipfr_tail;
- ipfr_tail = &fra->ipfr_next;
- if (ipfr_list == NULL)
- ipfr_list = fra;
+ *softf->ipfr_tail = fra;
+ fra->ipfr_prev = softf->ipfr_tail;
+ softf->ipfr_tail = &fra->ipfr_next;
fra->ipfr_next = NULL;
+ RWLOCK_EXIT(&softc->ipf_frag);
}
- RWLOCK_EXIT(&ipf_frag);
return fra ? 0 : -1;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_nat_newfrag */
+/* Function: ipf_frag_natnew */
/* Returns: int - 0 == success, -1 == error */
/* Parameters: fin(I) - pointer to packet information */
/* nat(I) - pointer to NAT structure */
@@ -357,33 +566,41 @@ fr_info_t *fin;
/* Create a new NAT fragment cache entry based on the current packet and */
/* the NAT structure for this "session". */
/* ------------------------------------------------------------------------ */
-int fr_nat_newfrag(fin, pass, nat)
-fr_info_t *fin;
-u_32_t pass;
-nat_t *nat;
+int
+ipf_frag_natnew(softc, fin, pass, nat)
+ ipf_main_softc_t *softc;
+ fr_info_t *fin;
+ u_32_t pass;
+ nat_t *nat;
{
+ ipf_frag_softc_t *softf = softc->ipf_frag_soft;
ipfr_t *fra;
- if ((fin->fin_v != 4) || (fr_frag_lock != 0))
+ if (softf->ipfr_lock != 0)
return 0;
- WRITE_ENTER(&ipf_natfrag);
- fra = ipfr_newfrag(fin, pass, ipfr_nattab);
+#ifdef USE_MUTEXES
+ fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_nattab,
+ &softf->ipfr_natfrag);
+#else
+ fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_nattab);
+#endif
if (fra != NULL) {
fra->ipfr_data = nat;
nat->nat_data = fra;
- *ipfr_nattail = fra;
- fra->ipfr_prev = ipfr_nattail;
- ipfr_nattail = &fra->ipfr_next;
+ *softf->ipfr_nattail = fra;
+ fra->ipfr_prev = softf->ipfr_nattail;
+ softf->ipfr_nattail = &fra->ipfr_next;
fra->ipfr_next = NULL;
+ RWLOCK_EXIT(&softf->ipfr_natfrag);
+ return 0;
}
- RWLOCK_EXIT(&ipf_natfrag);
- return fra ? 0 : -1;
+ return -1;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_ipid_newfrag */
+/* Function: ipf_frag_ipidnew */
/* Returns: int - 0 == success, -1 == error */
/* Parameters: fin(I) - pointer to packet information */
/* ipid(I) - new IP ID for this fragmented packet */
@@ -391,31 +608,37 @@ nat_t *nat;
/* Create a new fragment cache entry for this packet and store, as a data */
/* pointer, the new IP ID value. */
/* ------------------------------------------------------------------------ */
-int fr_ipid_newfrag(fin, ipid)
-fr_info_t *fin;
-u_32_t ipid;
+int
+ipf_frag_ipidnew(fin, ipid)
+ fr_info_t *fin;
+ u_32_t ipid;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_frag_softc_t *softf = softc->ipf_frag_soft;
ipfr_t *fra;
- if ((fin->fin_v != 4) || (fr_frag_lock))
+ if (softf->ipfr_lock)
return 0;
- WRITE_ENTER(&ipf_ipidfrag);
- fra = ipfr_newfrag(fin, 0, ipfr_ipidtab);
+#ifdef USE_MUTEXES
+ fra = ipfr_frag_new(softc, softf, fin, 0, softf->ipfr_ipidtab, &softf->ipfr_ipidfrag);
+#else
+ fra = ipfr_frag_new(softc, softf, fin, 0, softf->ipfr_ipidtab);
+#endif
if (fra != NULL) {
- fra->ipfr_data = (void *)(uintptr_t)ipid;
- *ipfr_ipidtail = fra;
- fra->ipfr_prev = ipfr_ipidtail;
- ipfr_ipidtail = &fra->ipfr_next;
+ fra->ipfr_data = (void *)(intptr_t)ipid;
+ *softf->ipfr_ipidtail = fra;
+ fra->ipfr_prev = softf->ipfr_ipidtail;
+ softf->ipfr_ipidtail = &fra->ipfr_next;
fra->ipfr_next = NULL;
+ RWLOCK_EXIT(&softf->ipfr_ipidfrag);
}
- RWLOCK_EXIT(&ipf_ipidfrag);
return fra ? 0 : -1;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_fraglookup */
+/* Function: ipf_frag_lookup */
/* Returns: ipfr_t * - pointer to ipfr_t structure if there's a */
/* matching entry in the frag table, else NULL */
/* Parameters: fin(I) - pointer to packet information */
@@ -423,17 +646,44 @@ u_32_t ipid;
/* */
/* Check the fragment cache to see if there is already a record of this */
/* packet with its filter result known. */
+/* */
+/* If this function succeeds, it returns with a write lock held on "lock". */
+/* If it fails, no lock is held on return. */
/* ------------------------------------------------------------------------ */
-static ipfr_t *fr_fraglookup(fin, table)
-fr_info_t *fin;
-ipfr_t *table[];
+static ipfr_t *
+ipf_frag_lookup(softc, softf, fin, table
+#ifdef USE_MUTEXES
+, lock
+#endif
+)
+ ipf_main_softc_t *softc;
+ ipf_frag_softc_t *softf;
+ fr_info_t *fin;
+ ipfr_t *table[];
+#ifdef USE_MUTEXES
+ ipfrwlock_t *lock;
+#endif
{
ipfr_t *f, frag;
u_int idx;
- ip_t *ip;
- if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG)
+ /*
+ * We don't want to let short packets match because they could be
+ * compromising the security of other rules that want to match on
+ * layer 4 fields (and can't because they have been fragmented off.)
+ * Why do this check here? The counter acts as an indicator of this
+ * kind of attack, whereas if it was elsewhere, it wouldn't know if
+ * other matching packets had been seen.
+ */
+ if (fin->fin_flx & FI_SHORT) {
+ FBUMPD(ifs_short);
+ return NULL;
+ }
+
+ if ((fin->fin_flx & FI_BAD) != 0) {
+ FBUMPD(ifs_bad);
return NULL;
+ }
/*
* For fragments, we record protocol, packet id, TOS and both IP#'s
@@ -441,59 +691,58 @@ ipfr_t *table[];
*
* build up a hash value to index the table with.
*/
- ip = fin->fin_ip;
- frag.ipfr_p = ip->ip_p;
- idx = ip->ip_p;
- frag.ipfr_id = ip->ip_id;
- idx += ip->ip_id;
- frag.ipfr_tos = ip->ip_tos;
- frag.ipfr_src.s_addr = ip->ip_src.s_addr;
- idx += ip->ip_src.s_addr;
- frag.ipfr_dst.s_addr = ip->ip_dst.s_addr;
- idx += ip->ip_dst.s_addr;
+ frag.ipfr_v = fin->fin_v;
+ idx = fin->fin_v;
+ frag.ipfr_p = fin->fin_p;
+ idx += fin->fin_p;
+ frag.ipfr_id = fin->fin_id;
+ idx += fin->fin_id;
+ frag.ipfr_source = fin->fin_fi.fi_src;
+ idx += frag.ipfr_src.s_addr;
+ frag.ipfr_dest = fin->fin_fi.fi_dst;
+ idx += frag.ipfr_dst.s_addr;
frag.ipfr_ifp = fin->fin_ifp;
idx *= 127;
- idx %= IPFT_SIZE;
+ idx %= softf->ipfr_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;
+ READ_ENTER(lock);
+
/*
* check the table, careful to only compare the right amount of data
*/
- for (f = table[idx]; f; f = f->ipfr_hnext)
+ for (f = table[idx]; f; f = f->ipfr_hnext) {
if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp,
IPFR_CMPSZ)) {
u_short off;
/*
- * We don't want to let short packets match because
- * they could be compromising the security of other
- * rules that want to match on layer 4 fields (and
- * can't because they have been fragmented off.)
- * Why do this check here? The counter acts as an
- * indicator of this kind of attack, whereas if it was
- * elsewhere, it wouldn't know if other matching
- * packets had been seen.
- */
- if (fin->fin_flx & FI_SHORT) {
- ATOMIC_INCL(ipfr_stats.ifs_short);
- continue;
- }
-
- /*
* 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# (or shouldn't).
*/
- off = ip->ip_off & IP_OFFMASK;
+ off = fin->fin_off >> 3;
if (f->ipfr_seen0) {
if (off == 0) {
- ATOMIC_INCL(ipfr_stats.ifs_retrans0);
+ FBUMPD(ifs_retrans0);
continue;
}
+
+ /*
+ * Case 3. See comment for frpr_fragment6.
+ */
+ if ((f->ipfr_firstend != 0) &&
+ (off < f->ipfr_firstend)) {
+ FBUMP(ifs_overlap);
+ DT2(ifs_overlap, u_short, off,
+ ipfr_t *, f);
+ fin->fin_flx |= FI_BAD;
+ break;
+ }
} else if (off == 0)
f->ipfr_seen0 = 1;
@@ -522,82 +771,124 @@ ipfr_t *table[];
* last (in order), shrink expiration time.
*/
if (off == f->ipfr_off) {
- if (!(ip->ip_off & IP_MF))
- f->ipfr_ttl = fr_ticks + 1;
f->ipfr_off = (fin->fin_dlen >> 3) + off;
- } else if (f->ipfr_pass & FR_FRSTRICT)
- continue;
- ATOMIC_INCL(ipfr_stats.ifs_hits);
+
+ /*
+ * Well, we could shrink the expiration time
+ * but only if every fragment has been seen
+ * in order upto this, the last. ipfr_badorder
+ * is used here to count those out of order
+ * and if it equals 0 when we get to the last
+ * fragment then we can assume all of the
+ * fragments have been seen and in order.
+ */
+#if 0
+ /*
+ * Doing this properly requires moving it to
+ * the head of the list which is infesible.
+ */
+ if ((more == 0) && (f->ipfr_badorder == 0))
+ f->ipfr_ttl = softc->ipf_ticks + 1;
+#endif
+ } else {
+ f->ipfr_badorder++;
+ FBUMPD(ifs_unordered);
+ if (f->ipfr_pass & FR_FRSTRICT) {
+ FBUMPD(ifs_strict);
+ continue;
+ }
+ }
+ f->ipfr_pkts++;
+ f->ipfr_bytes += fin->fin_plen;
+ FBUMP(ifs_hits);
return f;
}
+ }
+
+ RWLOCK_EXIT(lock);
+ FBUMP(ifs_miss);
return NULL;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_nat_knownfrag */
+/* Function: ipf_frag_natknown */
/* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */
/* match found, else NULL */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* Functional interface for NAT lookups of the NAT fragment cache */
/* ------------------------------------------------------------------------ */
-nat_t *fr_nat_knownfrag(fin)
-fr_info_t *fin;
+nat_t *
+ipf_frag_natknown(fin)
+ fr_info_t *fin;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_frag_softc_t *softf = softc->ipf_frag_soft;
nat_t *nat;
ipfr_t *ipf;
- if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_natlist)
+ if ((softf->ipfr_lock) || !softf->ipfr_natlist)
return NULL;
- READ_ENTER(&ipf_natfrag);
- ipf = fr_fraglookup(fin, ipfr_nattab);
+#ifdef USE_MUTEXES
+ ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab,
+ &softf->ipfr_natfrag);
+#else
+ ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab);
+#endif
if (ipf != NULL) {
nat = ipf->ipfr_data;
/*
* This is the last fragment for this packet.
*/
- if ((ipf->ipfr_ttl == fr_ticks + 1) && (nat != NULL)) {
+ if ((ipf->ipfr_ttl == softc->ipf_ticks + 1) && (nat != NULL)) {
nat->nat_data = NULL;
ipf->ipfr_data = NULL;
}
+ RWLOCK_EXIT(&softf->ipfr_natfrag);
} else
nat = NULL;
- RWLOCK_EXIT(&ipf_natfrag);
return nat;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_ipid_knownfrag */
+/* Function: ipf_frag_ipidknown */
/* Returns: u_32_t - IPv4 ID for this packet if match found, else */
/* return 0xfffffff to indicate no match. */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* Functional interface for IP ID lookups of the IP ID fragment cache */
/* ------------------------------------------------------------------------ */
-u_32_t fr_ipid_knownfrag(fin)
-fr_info_t *fin;
+u_32_t
+ipf_frag_ipidknown(fin)
+ fr_info_t *fin;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_frag_softc_t *softf = softc->ipf_frag_soft;
ipfr_t *ipf;
u_32_t id;
- if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_ipidlist)
+ if (softf->ipfr_lock || !softf->ipfr_ipidlist)
return 0xffffffff;
- READ_ENTER(&ipf_ipidfrag);
- ipf = fr_fraglookup(fin, ipfr_ipidtab);
- if (ipf != NULL)
- id = (u_32_t)(uintptr_t)ipf->ipfr_data;
- else
+#ifdef USE_MUTEXES
+ ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab,
+ &softf->ipfr_ipidfrag);
+#else
+ ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab);
+#endif
+ if (ipf != NULL) {
+ id = (u_32_t)(intptr_t)ipf->ipfr_data;
+ RWLOCK_EXIT(&softf->ipfr_ipidfrag);
+ } else
id = 0xffffffff;
- RWLOCK_EXIT(&ipf_ipidfrag);
return id;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_knownfrag */
+/* Function: ipf_frag_known */
/* Returns: frentry_t* - pointer to filter rule if a match is found in */
/* the frag cache table, else NULL. */
/* Parameters: fin(I) - pointer to packet information */
@@ -607,78 +898,82 @@ fr_info_t *fin;
/* match is found, return the rule pointer and flags from the rule, except */
/* that if FR_LOGFIRST is set, reset FR_LOG. */
/* ------------------------------------------------------------------------ */
-frentry_t *fr_knownfrag(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+frentry_t *
+ipf_frag_known(fin, passp)
+ fr_info_t *fin;
+ u_32_t *passp;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_frag_softc_t *softf = softc->ipf_frag_soft;
frentry_t *fr = NULL;
ipfr_t *fra;
u_32_t pass;
- if ((fin->fin_v != 4) || (fr_frag_lock) || (ipfr_list == NULL))
+ if ((softf->ipfr_lock) || (softf->ipfr_list == NULL))
return NULL;
- READ_ENTER(&ipf_frag);
- fra = fr_fraglookup(fin, ipfr_heads);
+#ifdef USE_MUTEXES
+ fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads,
+ &softc->ipf_frag);
+#else
+ fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads);
+#endif
if (fra != NULL) {
- fr = fra->ipfr_rule;
+ if (fin->fin_flx & FI_BAD) {
+ fr = &ipfr_block;
+ fin->fin_reason = FRB_BADFRAG;
+ } else {
+ fr = fra->ipfr_rule;
+ }
fin->fin_fr = fr;
if (fr != NULL) {
pass = fr->fr_flags;
+ if ((pass & FR_KEEPSTATE) != 0) {
+ fin->fin_flx |= FI_STATE;
+ /*
+ * Reset the keep state flag here so that we
+ * don't try and add a new state entry because
+ * of a match here. That leads to blocking of
+ * the packet later because the add fails.
+ */
+ pass &= ~FR_KEEPSTATE;
+ }
if ((pass & FR_LOGFIRST) != 0)
pass &= ~(FR_LOGFIRST|FR_LOG);
*passp = pass;
}
+ RWLOCK_EXIT(&softc->ipf_frag);
}
- RWLOCK_EXIT(&ipf_frag);
return fr;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_forget */
-/* Returns: Nil */
-/* Parameters: ptr(I) - pointer to data structure */
-/* */
-/* Search through all of the fragment cache entries and wherever a pointer */
-/* is found to match ptr, reset it to NULL. */
-/* ------------------------------------------------------------------------ */
-void fr_forget(ptr)
-void *ptr;
-{
- ipfr_t *fr;
-
- WRITE_ENTER(&ipf_frag);
- for (fr = ipfr_list; fr; fr = fr->ipfr_next)
- if (fr->ipfr_data == ptr)
- fr->ipfr_data = NULL;
- RWLOCK_EXIT(&ipf_frag);
-}
-
-
-/* ------------------------------------------------------------------------ */
-/* Function: fr_forgetnat */
+/* Function: ipf_frag_natforget */
/* Returns: Nil */
/* Parameters: ptr(I) - pointer to data structure */
/* */
/* Search through all of the fragment cache entries for NAT and wherever a */
/* pointer is found to match ptr, reset it to NULL. */
/* ------------------------------------------------------------------------ */
-void fr_forgetnat(ptr)
-void *ptr;
+void
+ipf_frag_natforget(softc, ptr)
+ ipf_main_softc_t *softc;
+ void *ptr;
{
+ ipf_frag_softc_t *softf = softc->ipf_frag_soft;
ipfr_t *fr;
- WRITE_ENTER(&ipf_natfrag);
- for (fr = ipfr_natlist; fr; fr = fr->ipfr_next)
+ WRITE_ENTER(&softf->ipfr_natfrag);
+ for (fr = softf->ipfr_natlist; fr; fr = fr->ipfr_next)
if (fr->ipfr_data == ptr)
fr->ipfr_data = NULL;
- RWLOCK_EXIT(&ipf_natfrag);
+ RWLOCK_EXIT(&softf->ipfr_natfrag);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_fragdelete */
+/* Function: ipf_frag_delete */
/* Returns: Nil */
/* Parameters: fra(I) - pointer to fragment structure to delete */
/* tail(IO) - pointer to the pointer to the tail of the frag */
@@ -688,9 +983,12 @@ void *ptr;
/* the filter rule it is associated with it if it is no longer used as a */
/* result of decreasing the reference count. */
/* ------------------------------------------------------------------------ */
-static void fr_fragdelete(fra, tail)
-ipfr_t *fra, ***tail;
+static void
+ipf_frag_delete(softc, fra, tail)
+ ipf_main_softc_t *softc;
+ ipfr_t *fra, ***tail;
{
+ ipf_frag_softc_t *softf = softc->ipf_frag_soft;
if (fra->ipfr_next)
fra->ipfr_next->ipfr_prev = fra->ipfr_prev;
@@ -703,107 +1001,112 @@ ipfr_t *fra, ***tail;
*fra->ipfr_hprev = fra->ipfr_hnext;
if (fra->ipfr_rule != NULL) {
- (void) fr_derefrule(&fra->ipfr_rule);
+ (void) ipf_derefrule(softc, &fra->ipfr_rule);
}
if (fra->ipfr_ref <= 0)
- fr_fragfree(fra);
+ ipf_frag_free(softf, fra);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_fragfree */
+/* Function: ipf_frag_free */
/* Returns: Nil */
-/* Parameters: fra - pointer to frag structure to free */
/* */
-/* Take care of the details associated with deleting an entry from the frag */
-/* cache. Currently this just means bumping stats correctly after freeing */
/* ------------------------------------------------------------------------ */
-static void fr_fragfree(fra)
-ipfr_t *fra;
+static void
+ipf_frag_free(softf, fra)
+ ipf_frag_softc_t *softf;
+ ipfr_t *fra;
{
KFREE(fra);
- ipfr_stats.ifs_expire++;
- ipfr_inuse--;
+ FBUMP(ifs_expire);
+ softf->ipfr_stats.ifs_inuse--;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_fragclear */
+/* Function: ipf_frag_clear */
/* Returns: Nil */
/* Parameters: Nil */
/* */
/* Free memory in use by fragment state information kept. Do the normal */
/* fragment state stuff first and then the NAT-fragment table. */
/* ------------------------------------------------------------------------ */
-void fr_fragclear()
+void
+ipf_frag_clear(softc)
+ ipf_main_softc_t *softc;
{
+ ipf_frag_softc_t *softf = softc->ipf_frag_soft;
ipfr_t *fra;
nat_t *nat;
- WRITE_ENTER(&ipf_frag);
- while ((fra = ipfr_list) != NULL) {
+ WRITE_ENTER(&softc->ipf_frag);
+ while ((fra = softf->ipfr_list) != NULL) {
fra->ipfr_ref--;
- fr_fragdelete(fra, &ipfr_tail);
+ ipf_frag_delete(softc, fra, &softf->ipfr_tail);
}
- ipfr_tail = &ipfr_list;
- RWLOCK_EXIT(&ipf_frag);
+ softf->ipfr_tail = &softf->ipfr_list;
+ RWLOCK_EXIT(&softc->ipf_frag);
- WRITE_ENTER(&ipf_nat);
- WRITE_ENTER(&ipf_natfrag);
- while ((fra = ipfr_natlist) != NULL) {
+ WRITE_ENTER(&softc->ipf_nat);
+ WRITE_ENTER(&softf->ipfr_natfrag);
+ while ((fra = softf->ipfr_natlist) != NULL) {
nat = fra->ipfr_data;
if (nat != NULL) {
if (nat->nat_data == fra)
nat->nat_data = NULL;
}
fra->ipfr_ref--;
- fr_fragdelete(fra, &ipfr_nattail);
+ ipf_frag_delete(softc, fra, &softf->ipfr_nattail);
}
- ipfr_nattail = &ipfr_natlist;
- RWLOCK_EXIT(&ipf_natfrag);
- RWLOCK_EXIT(&ipf_nat);
+ softf->ipfr_nattail = &softf->ipfr_natlist;
+ RWLOCK_EXIT(&softf->ipfr_natfrag);
+ RWLOCK_EXIT(&softc->ipf_nat);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_fragexpire */
+/* Function: ipf_frag_expire */
/* Returns: Nil */
/* Parameters: Nil */
/* */
/* Expire entries in the fragment cache table that have been there too long */
/* ------------------------------------------------------------------------ */
-void fr_fragexpire()
+void
+ipf_frag_expire(softc)
+ ipf_main_softc_t *softc;
{
+ ipf_frag_softc_t *softf = softc->ipf_frag_soft;
ipfr_t **fp, *fra;
nat_t *nat;
SPL_INT(s);
- if (fr_frag_lock)
+ if (softf->ipfr_lock)
return;
SPL_NET(s);
- WRITE_ENTER(&ipf_frag);
+ WRITE_ENTER(&softc->ipf_frag);
/*
* Go through the entire table, looking for entries to expire,
- * which is indicated by the ttl being less than or equal to fr_ticks.
+ * which is indicated by the ttl being less than or equal to ipf_ticks.
*/
- for (fp = &ipfr_list; ((fra = *fp) != NULL); ) {
- if (fra->ipfr_ttl > fr_ticks)
+ for (fp = &softf->ipfr_list; ((fra = *fp) != NULL); ) {
+ if (fra->ipfr_ttl > softc->ipf_ticks)
break;
fra->ipfr_ref--;
- fr_fragdelete(fra, &ipfr_tail);
+ ipf_frag_delete(softc, fra, &softf->ipfr_tail);
}
- RWLOCK_EXIT(&ipf_frag);
+ RWLOCK_EXIT(&softc->ipf_frag);
- WRITE_ENTER(&ipf_ipidfrag);
- for (fp = &ipfr_ipidlist; ((fra = *fp) != NULL); ) {
- if (fra->ipfr_ttl > fr_ticks)
+ WRITE_ENTER(&softf->ipfr_ipidfrag);
+ for (fp = &softf->ipfr_ipidlist; ((fra = *fp) != NULL); ) {
+ if (fra->ipfr_ttl > softc->ipf_ticks)
break;
fra->ipfr_ref--;
- fr_fragdelete(fra, &ipfr_ipidtail);
+ ipf_frag_delete(softc, fra, &softf->ipfr_ipidtail);
}
- RWLOCK_EXIT(&ipf_ipidfrag);
+ RWLOCK_EXIT(&softf->ipfr_ipidfrag);
/*
* Same again for the NAT table, except that if the structure also
@@ -815,11 +1118,11 @@ void fr_fragexpire()
* operations - no need to do that if there are no entries in this
* list, right?
*/
- if (ipfr_natlist != NULL) {
- WRITE_ENTER(&ipf_nat);
- WRITE_ENTER(&ipf_natfrag);
- for (fp = &ipfr_natlist; ((fra = *fp) != NULL); ) {
- if (fra->ipfr_ttl > fr_ticks)
+ if (softf->ipfr_natlist != NULL) {
+ WRITE_ENTER(&softc->ipf_nat);
+ WRITE_ENTER(&softf->ipfr_natfrag);
+ for (fp = &softf->ipfr_natlist; ((fra = *fp) != NULL); ) {
+ if (fra->ipfr_ttl > softc->ipf_ticks)
break;
nat = fra->ipfr_data;
if (nat != NULL) {
@@ -827,76 +1130,60 @@ void fr_fragexpire()
nat->nat_data = NULL;
}
fra->ipfr_ref--;
- fr_fragdelete(fra, &ipfr_nattail);
+ ipf_frag_delete(softc, fra, &softf->ipfr_nattail);
}
- RWLOCK_EXIT(&ipf_natfrag);
- RWLOCK_EXIT(&ipf_nat);
+ RWLOCK_EXIT(&softf->ipfr_natfrag);
+ RWLOCK_EXIT(&softc->ipf_nat);
}
SPL_X(s);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_slowtimer */
-/* Returns: Nil */
-/* Parameters: Nil */
-/* */
-/* Slowly expire held state for fragments. Timeouts are set * in */
-/* expectation of this being called twice per second. */
-/* ------------------------------------------------------------------------ */
-#if !defined(_KERNEL) || (!SOLARIS && !defined(__hpux) && !defined(__sgi) && \
- !defined(__osf__) && !defined(linux))
-# if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi))
-void fr_slowtimer __P((void *ptr))
-# else
-int fr_slowtimer()
-# endif
+/* Function: ipf_frag_pkt_next */
+/* ------------------------------------------------------------------------ */
+int
+ipf_frag_pkt_next(softc, token, itp)
+ ipf_main_softc_t *softc;
+ ipftoken_t *token;
+ ipfgeniter_t *itp;
{
- READ_ENTER(&ipf_global);
-
- ipf_expiretokens();
- fr_fragexpire();
- fr_timeoutstate();
- fr_natexpire();
- fr_authexpire();
- fr_ticks++;
- if (fr_running <= 0)
- goto done;
-# ifdef _KERNEL
-# if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000)
- callout_reset(&fr_slowtimer_ch, hz / 2, fr_slowtimer, NULL);
-# else
-# if defined(__OpenBSD__)
- timeout_add(&fr_slowtimer_ch, hz/2);
-# else
-# if (__FreeBSD_version >= 300000)
- fr_slowtimer_ch = timeout(fr_slowtimer, NULL, hz/2);
-# else
-# ifdef linux
- ;
-# else
- timeout(fr_slowtimer, NULL, hz/2);
-# endif
-# endif /* FreeBSD */
-# endif /* OpenBSD */
-# endif /* NetBSD */
-# endif
-done:
- RWLOCK_EXIT(&ipf_global);
-# if (BSD < 199103) || !defined(_KERNEL)
- return 0;
-# endif
+ ipf_frag_softc_t *softf = softc->ipf_frag_soft;
+
+#ifdef USE_MUTEXES
+ return ipf_frag_next(softc, token, itp, &softf->ipfr_list,
+ &softf->ipfr_frag);
+#else
+ return ipf_frag_next(softc, token, itp, &softf->ipfr_list);
+#endif
}
-#endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */
/* ------------------------------------------------------------------------ */
-/* Function: fr_nextfrag */
+/* Function: ipf_frag_nat_next */
+/* ------------------------------------------------------------------------ */
+int
+ipf_frag_nat_next(softc, token, itp)
+ ipf_main_softc_t *softc;
+ ipftoken_t *token;
+ ipfgeniter_t *itp;
+{
+ ipf_frag_softc_t *softf = softc->ipf_frag_soft;;
+
+#ifdef USE_MUTEXES
+ return ipf_frag_next(softc, token, itp, &softf->ipfr_natlist,
+ &softf->ipfr_natfrag);
+#else
+ return ipf_frag_next(softc, token, itp, &softf->ipfr_natlist);
+#endif
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_frag_next */
/* Returns: int - 0 == success, else error */
/* Parameters: token(I) - pointer to token information for this caller */
/* itp(I) - pointer to generic iterator from caller */
/* top(I) - top of the fragment list */
-/* tail(I) - tail of the fragment list */
/* lock(I) - fragment cache lock */
/* */
/* This function is used to interate through the list of entries in the */
@@ -904,30 +1191,39 @@ done:
/* being returned so that the caller can come back and resume from it later.*/
/* */
/* This function is used for both the NAT fragment cache as well as the ipf */
-/* fragment cache - hence the reason for passing in top, tail and lock. */
+/* fragment cache - hence the reason for passing in top and lock. */
/* ------------------------------------------------------------------------ */
-int fr_nextfrag(token, itp, top, tail
+static int
+ipf_frag_next(softc, token, itp, top
#ifdef USE_MUTEXES
, lock
#endif
)
-ipftoken_t *token;
-ipfgeniter_t *itp;
-ipfr_t **top, ***tail;
+ ipf_main_softc_t *softc;
+ ipftoken_t *token;
+ ipfgeniter_t *itp;
+ ipfr_t **top;
#ifdef USE_MUTEXES
-ipfrwlock_t *lock;
+ ipfrwlock_t *lock;
#endif
{
ipfr_t *frag, *next, zero;
int error = 0;
- frag = token->ipt_data;
- if (frag == (ipfr_t *)-1) {
- ipf_freetoken(token);
- return ESRCH;
+ if (itp->igi_data == NULL) {
+ IPFERROR(20001);
+ return EFAULT;
+ }
+
+ if (itp->igi_nitems != 1) {
+ IPFERROR(20003);
+ return EFAULT;
}
+ frag = token->ipt_data;
+
READ_ENTER(lock);
+
if (frag == NULL)
next = *top;
else
@@ -941,26 +1237,72 @@ ipfrwlock_t *lock;
next = &zero;
token->ipt_data = NULL;
}
+ if (next->ipfr_next == NULL)
+ ipf_token_mark_complete(token);
+
RWLOCK_EXIT(lock);
- if (frag != NULL) {
+ error = COPYOUT(next, itp->igi_data, sizeof(*next));
+ if (error != 0)
+ IPFERROR(20002);
+
+ if (frag != NULL) {
#ifdef USE_MUTEXES
- fr_fragderef(&frag, lock);
+ ipf_frag_deref(softc, &frag, lock);
#else
- fr_fragderef(&frag);
+ ipf_frag_deref(softc, &frag);
#endif
- }
+ }
+ return error;
+}
- error = COPYOUT(next, itp->igi_data, sizeof(*next));
- if (error != 0)
- error = EFAULT;
- return error;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_frag_pkt_deref */
+/* Returns: Nil */
+/* */
+/* ------------------------------------------------------------------------ */
+void
+ipf_frag_pkt_deref(softc, data)
+ ipf_main_softc_t *softc;
+ void *data;
+{
+ ipfr_t **frp = data;
+
+#ifdef USE_MUTEXES
+ ipf_frag_softc_t *softf = softc->ipf_frag_soft;
+
+ ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_frag);
+#else
+ ipf_frag_deref(softc->ipf_frag_soft, frp);
+#endif
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_frag_nat_deref */
+/* Returns: Nil */
+/* */
+/* ------------------------------------------------------------------------ */
+void
+ipf_frag_nat_deref(softc, data)
+ ipf_main_softc_t *softc;
+ void *data;
+{
+ ipfr_t **frp = data;
+
+#ifdef USE_MUTEXES
+ ipf_frag_softc_t *softf = softc->ipf_frag_soft;
+
+ ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_natfrag);
+#else
+ ipf_frag_deref(softc->ipf_frag_soft, frp);
+#endif
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_fragderef */
+/* Function: ipf_frag_deref */
/* Returns: Nil */
/* Parameters: frp(IO) - pointer to fragment structure to deference */
/* lock(I) - lock associated with the fragment */
@@ -970,16 +1312,19 @@ ipfrwlock_t *lock;
/* not freed, to enforce the notion that the caller is no longer entitled */
/* to use the pointer it is dropping the reference to. */
/* ------------------------------------------------------------------------ */
-void fr_fragderef(frp
+static void
+ipf_frag_deref(arg, frp
#ifdef USE_MUTEXES
, lock
#endif
)
-ipfr_t **frp;
+ void *arg;
+ ipfr_t **frp;
#ifdef USE_MUTEXES
-ipfrwlock_t *lock;
+ ipfrwlock_t *lock;
#endif
{
+ ipf_frag_softc_t *softf = arg;
ipfr_t *fra;
fra = *frp;
@@ -988,6 +1333,6 @@ ipfrwlock_t *lock;
WRITE_ENTER(lock);
fra->ipfr_ref--;
if (fra->ipfr_ref <= 0)
- fr_fragfree(fra);
+ ipf_frag_free(softf, fra);
RWLOCK_EXIT(lock);
}
diff --git a/sys/contrib/ipfilter/netinet/ip_frag.h b/sys/contrib/ipfilter/netinet/ip_frag.h
index 227dbcd..6b0c1be 100644
--- a/sys/contrib/ipfilter/netinet/ip_frag.h
+++ b/sys/contrib/ipfilter/netinet/ip_frag.h
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1993-2001 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
@@ -21,26 +21,33 @@ typedef struct ipfr {
void *ipfr_data;
frentry_t *ipfr_rule;
u_long ipfr_ttl;
+ u_int ipfr_pkts;
+ u_int ipfr_bytes;
+ u_int ipfr_badorder;
int ipfr_ref;
u_short ipfr_off;
- u_short ipfr_seen0;
+ u_short ipfr_firstend;
+ u_char ipfr_p;
+ u_char ipfr_seen0;
/*
* All of the fields, from ipfr_ifp to ipfr_pass, are compared
* using bcmp to see if an identical entry is present. It is
* therefore important for this set to remain together.
*/
void *ipfr_ifp;
- struct in_addr ipfr_src;
- struct in_addr ipfr_dst;
+ i6addr_t ipfr_source;
+ i6addr_t ipfr_dest;
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_32_t ipfr_id;
u_32_t ipfr_pass;
+ int ipfr_v;
} ipfr_t;
+#define ipfr_src ipfr_source.in4
+#define ipfr_dst ipfr_dest.in4
+
typedef struct ipfrstat {
u_long ifs_exists; /* add & already exists */
@@ -51,6 +58,14 @@ typedef struct ipfrstat {
u_long ifs_inuse;
u_long ifs_retrans0;
u_long ifs_short;
+ u_long ifs_bad;
+ u_long ifs_overlap;
+ u_long ifs_unordered;
+ u_long ifs_strict;
+ u_long ifs_miss;
+ u_long ifs_maximum;
+ u_long ifs_newbad;
+ u_long ifs_newrestrictnot0;
struct ipfr **ifs_table;
struct ipfr **ifs_nattab;
} ipfrstat_t;
@@ -58,51 +73,32 @@ typedef struct ipfrstat {
#define IPFR_CMPSZ (offsetof(ipfr_t, ipfr_pass) - \
offsetof(ipfr_t, ipfr_ifp))
-extern ipfr_t *ipfr_list, **ipfr_tail;
-extern ipfr_t *ipfr_natlist, **ipfr_nattail;
-extern int ipfr_size;
-extern int fr_ipfrttl;
-extern int fr_frag_lock;
-extern int fr_fraginit __P((void));
-extern void fr_fragunload __P((void));
-extern ipfrstat_t *fr_fragstats __P((void));
-
-extern int fr_newfrag __P((fr_info_t *, u_32_t));
-extern frentry_t *fr_knownfrag __P((fr_info_t *, u_32_t *));
-
-extern int fr_nat_newfrag __P((fr_info_t *, u_32_t, struct nat *));
-extern nat_t *fr_nat_knownfrag __P((fr_info_t *));
-
-extern int fr_ipid_newfrag __P((fr_info_t *, u_32_t));
-extern u_32_t fr_ipid_knownfrag __P((fr_info_t *));
-#ifdef USE_MUTEXES
-extern void fr_fragderef __P((ipfr_t **, ipfrwlock_t *));
-extern int fr_nextfrag __P((ipftoken_t *, ipfgeniter_t *, ipfr_t **, \
- ipfr_t ***, ipfrwlock_t *));
-#else
-extern void fr_fragderef __P((ipfr_t **));
-extern int fr_nextfrag __P((ipftoken_t *, ipfgeniter_t *, ipfr_t **, \
- ipfr_t ***));
-#endif
-
-extern void fr_forget __P((void *));
-extern void fr_forgetnat __P((void *));
-extern void fr_fragclear __P((void));
-extern void fr_fragexpire __P((void));
-
-#if defined(_KERNEL) && ((BSD >= 199306) || SOLARIS || defined(__sgi) \
- || defined(__osf__) || (defined(__sgi) && (IRIX >= 60500)))
-# if defined(SOLARIS2) && (SOLARIS2 < 7)
-extern void fr_slowtimer __P((void));
-# else
-extern void fr_slowtimer __P((void *));
-# endif
-#else
-# if defined(linux) && defined(_KERNEL)
-extern void fr_slowtimer __P((long));
-# else
-extern int fr_slowtimer __P((void));
-# endif
-#endif
+extern void *ipf_frag_soft_create __P((ipf_main_softc_t *));
+extern int ipf_frag_soft_init __P((ipf_main_softc_t *, void *));
+extern int ipf_frag_soft_fini __P((ipf_main_softc_t *, void *));
+extern void ipf_frag_soft_destroy __P((ipf_main_softc_t *, void *));
+extern int ipf_frag_main_load __P((void));
+extern int ipf_frag_main_unload __P((void));
+extern int ipf_frag_load __P((void));
+extern void ipf_frag_clear __P((ipf_main_softc_t *));
+extern void ipf_frag_expire __P((ipf_main_softc_t *));
+extern void ipf_frag_forget __P((void *));
+extern int ipf_frag_init __P((void));
+extern u_32_t ipf_frag_ipidknown __P((fr_info_t *));
+extern int ipf_frag_ipidnew __P((fr_info_t *, u_32_t));
+extern frentry_t *ipf_frag_known __P((fr_info_t *, u_32_t *));
+extern void ipf_frag_natforget __P((ipf_main_softc_t *, void *));
+extern int ipf_frag_natnew __P((ipf_main_softc_t *, fr_info_t *, u_32_t, struct nat *));
+extern nat_t *ipf_frag_natknown __P((fr_info_t *));
+extern int ipf_frag_new __P((ipf_main_softc_t *, fr_info_t *, u_32_t));
+extern ipfrstat_t *ipf_frag_stats __P((void *));
+extern void ipf_frag_setlock __P((void *, int));
+extern void ipf_frag_pkt_deref __P((ipf_main_softc_t *, void *));
+extern int ipf_frag_pkt_next __P((ipf_main_softc_t *, ipftoken_t *,
+ ipfgeniter_t *));
+extern void ipf_frag_nat_deref __P((ipf_main_softc_t *, void *));
+extern int ipf_frag_nat_next __P((ipf_main_softc_t *, ipftoken_t *,
+ ipfgeniter_t *));
+extern void ipf_slowtimer __P((ipf_main_softc_t *));
#endif /* __IP_FRAG_H__ */
diff --git a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c
index f56a690..ff83976 100644
--- a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c
+++ b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1997-2003 by Darren Reed
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
@@ -15,6 +15,7 @@
#define IPF_FTP_PROXY
#define IPF_MINPORTLEN 18
+#define IPF_MINEPRTLEN 20
#define IPF_MAXPORTLEN 30
#define IPF_MIN227LEN 39
#define IPF_MAX227LEN 51
@@ -38,93 +39,197 @@
#define FTPXY_PASS_2 14
#define FTPXY_PAOK_2 15
+#define FTPXY_JUNK_OK 0
+#define FTPXY_JUNK_BAD 1 /* Ignore all commands for this connection */
+#define FTPXY_JUNK_EOL 2 /* consume the rest of this line only */
+#define FTPXY_JUNK_CONT 3 /* Saerching for next numeric */
+
/*
* Values for FTP commands. Numerics cover 0-999
*/
#define FTPXY_C_PASV 1000
+#define FTPXY_C_PORT 1001
+#define FTPXY_C_EPSV 1002
+#define FTPXY_C_EPRT 1003
+
+
+typedef struct ipf_ftp_softc_s {
+ int ipf_p_ftp_pasvonly;
+ /* Do not require logins before transfers */
+ int ipf_p_ftp_insecure;
+ int ipf_p_ftp_pasvrdr;
+ /* PASV must be last command prior to 227 */
+ int ipf_p_ftp_forcepasv;
+ int ipf_p_ftp_debug;
+ int ipf_p_ftp_single_xfer;
+ void *ipf_p_ftp_tune;
+} ipf_ftp_softc_t;
+
+
+void ipf_p_ftp_main_load __P((void));
+void ipf_p_ftp_main_unload __P((void));
+void *ipf_p_ftp_soft_create __P((ipf_main_softc_t *));
+void ipf_p_ftp_soft_destroy __P((ipf_main_softc_t *, void *));
+
+int ipf_p_ftp_client __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+ ftpinfo_t *, int));
+int ipf_p_ftp_complete __P((char *, size_t));
+int ipf_p_ftp_in __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_ftp_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_ftp_del __P((ipf_main_softc_t *, ap_session_t *));
+int ipf_p_ftp_out __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_ftp_pasv __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+ ftpinfo_t *, int));
+int ipf_p_ftp_epsv __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+ ftpinfo_t *, int));
+int ipf_p_ftp_port __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+ ftpinfo_t *, int));
+int ipf_p_ftp_process __P((ipf_ftp_softc_t *, fr_info_t *, nat_t *,
+ ftpinfo_t *, int));
+int ipf_p_ftp_server __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+ ftpinfo_t *, int));
+int ipf_p_ftp_valid __P((ipf_ftp_softc_t *, ftpinfo_t *, int, char *, size_t));
+int ipf_p_ftp_server_valid __P((ipf_ftp_softc_t *, ftpside_t *, char *,
+ size_t));
+int ipf_p_ftp_client_valid __P((ipf_ftp_softc_t *, ftpside_t *, char *,
+ size_t));
+u_short ipf_p_ftp_atoi __P((char **));
+int ipf_p_ftp_pasvreply __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+ ftpinfo_t *, u_int, char *, char *));
+int ipf_p_ftp_eprt __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+ ftpinfo_t *, int));
+int ipf_p_ftp_eprt4 __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+ ftpinfo_t *, int));
+int ipf_p_ftp_eprt6 __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+ ftpinfo_t *, int));
+int ipf_p_ftp_addport __P((ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *,
+ ftpinfo_t *, int, int, int));
+void ipf_p_ftp_setpending __P((ipf_main_softc_t *, ftpinfo_t *));
-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 *, ap_session_t *, nat_t *));
-int ippr_ftp_init __P((void));
-void ippr_ftp_fini __P((void));
-int ippr_ftp_new __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_ftp_out __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int));
-int ippr_ftp_epsv __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 *, 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((ftpinfo_t *, int, char *, size_t));
-int ippr_ftp_server_valid __P((ftpside_t *, char *, size_t));
-int ippr_ftp_client_valid __P((ftpside_t *, char *, size_t));
-u_short ippr_ftp_atoi __P((char **));
-int ippr_ftp_pasvreply __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *,
- u_int, char *, char *, u_int));
-
-
-int ftp_proxy_init = 0;
-int ippr_ftp_pasvonly = 0;
-int ippr_ftp_insecure = 0; /* Do not require logins before transfers */
-int ippr_ftp_pasvrdr = 0;
-int ippr_ftp_forcepasv = 0; /* PASV must be last command prior to 227 */
-#if defined(_KERNEL)
-int ippr_ftp_debug = 0;
-#else
-int ippr_ftp_debug = 2;
-#endif
/*
- * 1 - security
- * 2 - errors
- * 3 - error debugging
- * 4 - parsing errors
- * 5 - parsing info
- * 6 - parsing debug
+ * Debug levels
*/
-
+#define DEBUG_SECURITY 0x01
+#define DEBUG_ERROR 0x02
+#define DEBUG_INFO 0x04
+#define DEBUG_PARSE_ERR 0x08
+#define DEBUG_PARSE_INFO 0x10
+#define DEBUG_PARSE 0x20
+
+static int ipf_p_ftp_proxy_init = 0;
static frentry_t ftppxyfr;
-static ipftuneable_t ftptune = {
- { &ippr_ftp_debug },
- "ippr_ftp_debug",
- 0,
- 10,
- sizeof(ippr_ftp_debug),
- 0,
- NULL
+static ipftuneable_t ipf_ftp_tuneables[] = {
+ { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_debug) },
+ "ftp_debug", 0, 0x7f,
+ stsizeof(ipf_ftp_softc_t, ipf_p_ftp_debug),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_pasvonly) },
+ "ftp_pasvonly", 0, 1,
+ stsizeof(ipf_ftp_softc_t, ipf_p_ftp_pasvonly),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_insecure) },
+ "ftp_insecure", 0, 1,
+ stsizeof(ipf_ftp_softc_t, ipf_p_ftp_insecure),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_pasvrdr) },
+ "ftp_pasvrdr", 0, 1,
+ stsizeof(ipf_ftp_softc_t, ipf_p_ftp_pasvrdr),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_forcepasv) },
+ "ftp_forcepasv", 0, 1,
+ stsizeof(ipf_ftp_softc_t, ipf_p_ftp_forcepasv),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_single_xfer) },
+ "ftp_single_xfer", 0, 1,
+ stsizeof(ipf_ftp_softc_t, ipf_p_ftp_single_xfer),
+ 0, NULL, NULL },
+ { { NULL }, NULL, 0, 0, 0, 0, NULL, NULL }
};
-/*
- * Initialize local structures.
- */
-int ippr_ftp_init()
+void
+ipf_p_ftp_main_load()
{
bzero((char *)&ftppxyfr, sizeof(ftppxyfr));
ftppxyfr.fr_ref = 1;
ftppxyfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
- MUTEX_INIT(&ftppxyfr.fr_lock, "FTP Proxy Mutex");
- ftp_proxy_init = 1;
- (void) fr_addipftune(&ftptune);
- return 0;
+ MUTEX_INIT(&ftppxyfr.fr_lock, "FTP Proxy Mutex");
+ ipf_p_ftp_proxy_init = 1;
}
-void ippr_ftp_fini()
+void
+ipf_p_ftp_main_unload()
{
- (void) fr_delipftune(&ftptune);
- if (ftp_proxy_init == 1) {
+ if (ipf_p_ftp_proxy_init == 1) {
MUTEX_DESTROY(&ftppxyfr.fr_lock);
- ftp_proxy_init = 0;
+ ipf_p_ftp_proxy_init = 0;
}
}
-int ippr_ftp_new(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+/*
+ * Initialize local structures.
+ */
+void *
+ipf_p_ftp_soft_create(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_ftp_softc_t *softf;
+
+ KMALLOC(softf, ipf_ftp_softc_t *);
+ if (softf == NULL)
+ return NULL;
+
+ bzero((char *)softf, sizeof(*softf));
+#if defined(_KERNEL)
+ softf->ipf_p_ftp_debug = 0;
+#else
+ softf->ipf_p_ftp_debug = DEBUG_PARSE_ERR;
+#endif
+ softf->ipf_p_ftp_forcepasv = 1;
+
+ softf->ipf_p_ftp_tune = ipf_tune_array_copy(softf,
+ sizeof(ipf_ftp_tuneables),
+ ipf_ftp_tuneables);
+ if (softf->ipf_p_ftp_tune == NULL) {
+ ipf_p_ftp_soft_destroy(softc, softf);
+ return NULL;
+ }
+ if (ipf_tune_array_link(softc, softf->ipf_p_ftp_tune) == -1) {
+ ipf_p_ftp_soft_destroy(softc, softf);
+ return NULL;
+ }
+
+ return softf;
+}
+
+
+void
+ipf_p_ftp_soft_destroy(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_ftp_softc_t *softf = arg;
+
+ if (softf->ipf_p_ftp_tune != NULL) {
+ ipf_tune_array_unlink(softc, softf->ipf_p_ftp_tune);
+ KFREES(softf->ipf_p_ftp_tune, sizeof(ipf_ftp_tuneables));
+ softf->ipf_p_ftp_tune = NULL;
+ }
+
+ KFREE(softf);
+}
+
+
+int
+ipf_p_ftp_new(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
{
ftpinfo_t *ftp;
ftpside_t *f;
@@ -133,11 +238,12 @@ nat_t *nat;
if (ftp == NULL)
return -1;
- fin = fin; /* LINT */
nat = nat; /* LINT */
aps->aps_data = ftp;
aps->aps_psiz = sizeof(ftpinfo_t);
+ aps->aps_sport = htons(fin->fin_sport);
+ aps->aps_dport = htons(fin->fin_dport);
bzero((char *)ftp, sizeof(*ftp));
f = &ftp->ftp_side[0];
@@ -152,25 +258,53 @@ nat_t *nat;
}
-int ippr_ftp_port(fin, ip, nat, f, dlen)
-fr_info_t *fin;
-ip_t *ip;
-nat_t *nat;
-ftpside_t *f;
-int dlen;
+void
+ipf_p_ftp_setpending(ipf_main_softc_t *softc, ftpinfo_t *ftp)
+{
+ if (ftp->ftp_pendnat != NULL)
+ ipf_nat_setpending(softc, ftp->ftp_pendnat);
+
+ if (ftp->ftp_pendstate != NULL) {
+ READ_ENTER(&softc->ipf_state);
+ ipf_state_setpending(softc, ftp->ftp_pendstate);
+ RWLOCK_EXIT(&softc->ipf_state);
+ }
+}
+
+
+void
+ipf_p_ftp_del(softc, aps)
+ ipf_main_softc_t *softc;
+ ap_session_t *aps;
+{
+ ftpinfo_t *ftp;
+
+ ftp = aps->aps_data;
+ if (ftp != NULL)
+ ipf_p_ftp_setpending(softc, ftp);
+}
+
+
+int
+ipf_p_ftp_port(softf, fin, ip, nat, ftp, dlen)
+ ipf_ftp_softc_t *softf;
+ fr_info_t *fin;
+ ip_t *ip;
+ nat_t *nat;
+ ftpinfo_t *ftp;
+ int dlen;
{
- tcphdr_t *tcp, tcph, *tcp2 = &tcph;
char newbuf[IPF_FTPBUFSZ], *s;
- struct in_addr swip, swip2;
u_int a1, a2, a3, a4;
- int inc, off, flags;
u_short a5, a6, sp;
size_t nlen, olen;
- fr_info_t fi;
- nat_t *nat2;
+ tcphdr_t *tcp;
+ int inc, off;
+ ftpside_t *f;
mb_t *m;
m = fin->fin_m;
+ f = &ftp->ftp_side[0];
tcp = (tcphdr_t *)fin->fin_dp;
off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
@@ -178,8 +312,10 @@ int dlen;
* Check for client sending out PORT message.
*/
if (dlen < IPF_MINPORTLEN) {
- if (ippr_ftp_debug > 1)
- printf("ippr_ftp_port:dlen(%d) < IPF_MINPORTLEN\n",
+ DT3(ftp_PORT_error_dlen, nat_t *, nat, ftpside_t *, f,
+ u_int, dlen);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
+ printf("ipf_p_ftp_port:dlen(%d) < IPF_MINPORTLEN\n",
dlen);
return 0;
}
@@ -190,16 +326,18 @@ int dlen;
/*
* Pick out the address components, two at a time.
*/
- a1 = ippr_ftp_atoi(&s);
+ a1 = ipf_p_ftp_atoi(&s);
if (s == NULL) {
- if (ippr_ftp_debug > 1)
- printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 1);
+ DT2(ftp_PORT_error_atoi_1, nat_t *, nat, ftpside_t *, f);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+ printf("ipf_p_ftp_port:ipf_p_ftp_atoi(%d) failed\n", 1);
return 0;
}
- a2 = ippr_ftp_atoi(&s);
+ a2 = ipf_p_ftp_atoi(&s);
if (s == NULL) {
- if (ippr_ftp_debug > 1)
- printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 2);
+ DT2(ftp_PORT_error_atoi_2, nat_t *, nat, ftpside_t *, f);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+ printf("ipf_p_ftp_port:ipf_p_ftp_atoi(%d) failed\n", 2);
return 0;
}
@@ -210,18 +348,21 @@ int dlen;
a1 <<= 16;
a1 |= a2;
if (((nat->nat_dir == NAT_OUTBOUND) &&
- (a1 != ntohl(nat->nat_inip.s_addr))) ||
+ (a1 != ntohl(nat->nat_osrcaddr))) ||
((nat->nat_dir == NAT_INBOUND) &&
- (a1 != ntohl(nat->nat_oip.s_addr)))) {
- if (ippr_ftp_debug > 0)
- printf("ippr_ftp_port:%s != nat->nat_inip\n", "a1");
+ (a1 != ntohl(nat->nat_nsrcaddr)))) {
+ DT3(ftp_PORT_error_address, nat_t *, nat, ftpside_t *, f,
+ u_int, a1);
+ if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+ printf("ipf_p_ftp_port:%s != nat->nat_inip\n", "a1");
return APR_ERR(1);
}
- a5 = ippr_ftp_atoi(&s);
+ a5 = ipf_p_ftp_atoi(&s);
if (s == NULL) {
- if (ippr_ftp_debug > 1)
- printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 3);
+ DT2(ftp_PORT_error_atoi_3, nat_t *, nat, ftpside_t *, f);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+ printf("ipf_p_ftp_port:ipf_p_ftp_atoi(%d) failed\n", 3);
return 0;
}
if (*s == ')')
@@ -232,34 +373,31 @@ int dlen;
*/
if (*s == '\n')
s--;
- if ((*s == '\r') && (*(s + 1) == '\n')) {
- s += 2;
- a6 = a5 & 0xff;
- } else {
- if (ippr_ftp_debug > 1)
- printf("ippr_ftp_port:missing %s\n", "cr-lf");
+ if ((*s != '\r') || (*(s + 1) != '\n')) {
+ DT2(ftp_PORT_error_no_crlf, nat_t *, nat, ftpside_t *, f);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+ printf("ipf_p_ftp_port:missing %s\n", "cr-lf");
return 0;
}
+ s += 2;
+ a6 = a5 & 0xff;
+ /*
+ * Calculate the source port. Verification of > 1024 is in
+ * ipf_p_ftp_addport.
+ */
a5 >>= 8;
a5 &= 0xff;
sp = a5 << 8 | a6;
- /*
- * Don't allow the PORT command to specify a port < 1024 due to
- * security crap.
- */
- if (sp < 1024) {
- if (ippr_ftp_debug > 0)
- printf("ippr_ftp_port:sp(%d) < 1024\n", sp);
- return 0;
- }
+
/*
* Calculate new address parts for PORT command
*/
if (nat->nat_dir == NAT_INBOUND)
- a1 = ntohl(nat->nat_oip.s_addr);
+ a1 = ntohl(nat->nat_ndstaddr);
else
a1 = ntohl(ip->ip_src.s_addr);
+ a1 = ntohl(ip->ip_src.s_addr);
a2 = (a1 >> 16) & 0xff;
a3 = (a1 >> 8) & 0xff;
a4 = a1 & 0xff;
@@ -276,117 +414,213 @@ int dlen;
nlen = strlen(newbuf);
inc = nlen - olen;
- if ((inc + ip->ip_len) > 65535) {
- if (ippr_ftp_debug > 0)
- printf("ippr_ftp_port:inc(%d) + ip->ip_len > 65535\n",
+ if ((inc + fin->fin_plen) > 65535) {
+ DT3(ftp_PORT_error_inc, nat_t *, nat, ftpside_t *, f,
+ int, inc);
+ if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+ printf("ipf_p_ftp_port:inc(%d) + ip->ip_len > 65535\n",
inc);
return 0;
}
#if !defined(_KERNEL)
- bcopy(newbuf, MTOD(m, char *) + off, nlen);
+ M_ADJ(m, inc);
#else
-# if defined(MENTAT)
- if (inc < 0)
- (void)adjmsg(m, inc);
-# else /* defined(MENTAT) */
/*
* m_adj takes care of pkthdr.len, if required and treats inc<0 to
* mean remove -len bytes from the end of the packet.
* The mbuf chain will be extended if necessary by m_copyback().
*/
if (inc < 0)
- m_adj(m, inc);
-# endif /* defined(MENTAT) */
+ M_ADJ(m, inc);
#endif /* !defined(_KERNEL) */
COPYBACK(m, off, nlen, newbuf);
+ fin->fin_flx |= FI_DOCKSUM;
if (inc != 0) {
- ip->ip_len += inc;
- fin->fin_dlen += inc;
fin->fin_plen += inc;
+ ip->ip_len = htons(fin->fin_plen);
+ fin->fin_dlen += inc;
+ }
+
+ f->ftps_cmd = FTPXY_C_PORT;
+ return ipf_p_ftp_addport(softf, fin, ip, nat, ftp, dlen, sp, inc);
+}
+
+
+int
+ipf_p_ftp_addport(softf, fin, ip, nat, ftp, dlen, nport, inc)
+ ipf_ftp_softc_t *softf;
+ fr_info_t *fin;
+ ip_t *ip;
+ nat_t *nat;
+ ftpinfo_t *ftp;
+ int dlen, nport, inc;
+{
+ tcphdr_t tcph, *tcp2 = &tcph;
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
+ int direction;
+ fr_info_t fi;
+ ipnat_t *ipn;
+ nat_t *nat2;
+ u_short sp;
+ int flags;
+
+ softc = fin->fin_main_soft;
+ softn = softc->ipf_nat_soft;
+
+ if ((ftp->ftp_pendnat != NULL) || (ftp->ftp_pendstate != NULL)) {
+ if (softf->ipf_p_ftp_single_xfer != 0) {
+ DT2(ftp_PORT_error_add_active, nat_t *, nat,
+ ftpinfo_t *, ftp);
+ if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+ printf("ipf_p_ftp_addport:xfer active %p/%p\n",
+ ftp->ftp_pendnat, ftp->ftp_pendstate);
+ return 0;
+ }
+ ipf_p_ftp_setpending(softc, ftp);
}
/*
+ * Add skeleton NAT entry for connection which will come back the
+ * other way.
+ */
+ sp = nport;
+ /*
+ * Don't allow the PORT command to specify a port < 1024 due to
+ * security risks.
+ */
+ if (sp < 1024) {
+ DT3(ftp_PORT_error_port, nat_t *, nat, ftpinfo_t *, ftp,
+ u_int, sp);
+ if (softf->ipf_p_ftp_debug & DEBUG_SECURITY)
+ printf("ipf_p_ftp_addport:sp(%d) < 1024\n", sp);
+ 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.
*/
bcopy((char *)fin, (char *)&fi, sizeof(fi));
- fi.fin_state = NULL;
- fi.fin_nat = NULL;
fi.fin_flx |= FI_IGNORE;
fi.fin_data[0] = sp;
fi.fin_data[1] = fin->fin_data[1] - 1;
+ fi.fin_src6 = nat->nat_ndst6;
+ fi.fin_dst6 = nat->nat_nsrc6;
+
+ if (nat->nat_v[0] == 6) {
+#ifndef USE_INET6
+ return APR_INC(inc);
+#endif
+ }
+
/*
* Add skeleton NAT entry for connection which will come back the
* other way.
*/
- if (nat->nat_dir == NAT_OUTBOUND)
- nat2 = nat_outlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p,
- nat->nat_inip, nat->nat_oip);
- else
- nat2 = nat_inlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p,
- nat->nat_inip, nat->nat_oip);
- if (nat2 == NULL) {
- int slen;
-
- slen = ip->ip_len;
- ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
- bzero((char *)tcp2, sizeof(*tcp2));
- tcp2->th_win = htons(8192);
- tcp2->th_sport = htons(sp);
- TCP_OFF_A(tcp2, 5);
- tcp2->th_flags = TH_SYN;
- tcp2->th_dport = 0; /* XXX - don't specify remote port */
- fi.fin_data[1] = 0;
- fi.fin_dlen = sizeof(*tcp2);
- fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
- fi.fin_dp = (char *)tcp2;
- fi.fin_fr = &ftppxyfr;
- fi.fin_out = nat->nat_dir;
- fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
- swip = ip->ip_src;
- swip2 = ip->ip_dst;
+#ifdef USE_INET6
+ if (nat->nat_v[0] == 6) {
if (nat->nat_dir == NAT_OUTBOUND) {
- fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
- ip->ip_src = nat->nat_inip;
- } else if (nat->nat_dir == NAT_INBOUND) {
- fi.fin_fi.fi_saddr = nat->nat_oip.s_addr;
- ip->ip_src = nat->nat_oip;
+ nat2 = ipf_nat6_outlookup(&fi, IPN_TCP|NAT_SEARCH,
+ nat->nat_pr[1],
+ &nat->nat_osrc6.in6,
+ &nat->nat_odst6.in6);
+ } else {
+ nat2 = ipf_nat6_inlookup(&fi, IPN_TCP|NAT_SEARCH,
+ nat->nat_pr[0],
+ &nat->nat_odst6.in6,
+ &nat->nat_osrc6.in6);
}
-
- flags = NAT_SLAVE|IPN_TCP|SI_W_DPORT;
- if (nat->nat_dir == NAT_INBOUND)
- flags |= NAT_NOTRULEPORT;
- nat2 = nat_new(&fi, nat->nat_ptr, NULL, flags, nat->nat_dir);
-
- if (nat2 != NULL) {
- (void) nat_proto(&fi, nat2, IPN_TCP);
- nat_update(&fi, nat2, nat->nat_ptr);
- fi.fin_ifp = NULL;
- if (nat->nat_dir == NAT_INBOUND) {
- fi.fin_fi.fi_daddr = nat->nat_inip.s_addr;
- ip->ip_dst = nat->nat_inip;
- }
- (void) fr_addstate(&fi, NULL, SI_W_DPORT);
- if (fi.fin_state != NULL)
- fr_statederef((ipstate_t **)&fi.fin_state);
+ } else
+#endif
+ {
+ if (nat->nat_dir == NAT_OUTBOUND) {
+ nat2 = ipf_nat_outlookup(&fi, IPN_TCP|NAT_SEARCH,
+ nat->nat_pr[1],
+ nat->nat_osrcip,
+ nat->nat_odstip);
+ } else {
+ nat2 = ipf_nat_inlookup(&fi, IPN_TCP|NAT_SEARCH,
+ nat->nat_pr[0],
+ nat->nat_odstip,
+ nat->nat_osrcip);
}
- ip->ip_len = slen;
- ip->ip_src = swip;
- ip->ip_dst = swip2;
}
+ if (nat2 != NULL)
+ return APR_INC(inc);
+
+ ipn = ipf_proxy_rule_rev(nat);
+ if (ipn == NULL)
+ return APR_ERR(1);
+ ipn->in_use = 0;
+
+ fi.fin_fr = &ftppxyfr;
+ fi.fin_dp = (char *)tcp2;
+ fi.fin_dlen = sizeof(*tcp2);
+ fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
+ fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
+ fi.fin_data[1] = sp;
+ fi.fin_data[0] = 0;
+
+ bzero((char *)tcp2, sizeof(*tcp2));
+ tcp2->th_sport = 0;
+ tcp2->th_dport = htons(sp);
+
+ tcp2->th_win = htons(8192);
+ TCP_OFF_A(tcp2, 5);
+ tcp2->th_flags = TH_SYN;
+
+ if (nat->nat_dir == NAT_INBOUND) {
+ fi.fin_out = 1;
+ direction = NAT_OUTBOUND;
+ } else {
+ fi.fin_out = 0;
+ direction = NAT_INBOUND;
+ }
+ flags = SI_W_SPORT|NAT_SLAVE|IPN_TCP;
+
+ MUTEX_ENTER(&softn->ipf_nat_new);
+ if (nat->nat_v[0] == 6) {
+#ifdef USE_INET6
+ nat2 = ipf_nat6_add(&fi, ipn, &ftp->ftp_pendnat, flags,
+ direction);
+#endif
+ } else {
+ nat2 = ipf_nat_add(&fi, ipn, &ftp->ftp_pendnat, flags,
+ direction);
+ }
+ MUTEX_EXIT(&softn->ipf_nat_new);
+
+ if (nat2 == NULL) {
+ KFREES(ipn, ipn->in_size);
+ return APR_ERR(1);
+ }
+
+ (void) ipf_nat_proto(&fi, nat2, IPN_TCP);
+ MUTEX_ENTER(&nat2->nat_lock);
+ ipf_nat_update(&fi, nat2);
+ MUTEX_EXIT(&nat2->nat_lock);
+ fi.fin_ifp = NULL;
+ if (nat2->nat_dir == NAT_INBOUND)
+ fi.fin_dst6 = nat->nat_osrc6;
+ if (ipf_state_add(softc, &fi, (ipstate_t **)&ftp->ftp_pendstate,
+ SI_W_SPORT) != 0)
+ ipf_nat_setpending(softc, nat2);
+
return APR_INC(inc);
}
-int ippr_ftp_client(fin, ip, nat, ftp, dlen)
-fr_info_t *fin;
-nat_t *nat;
-ftpinfo_t *ftp;
-ip_t *ip;
-int dlen;
+int
+ipf_p_ftp_client(softf, fin, ip, nat, ftp, dlen)
+ ipf_ftp_softc_t *softf;
+ fr_info_t *fin;
+ nat_t *nat;
+ ftpinfo_t *ftp;
+ ip_t *ip;
+ int dlen;
{
char *rptr, *wptr, cmd[6], c;
ftpside_t *f;
@@ -408,6 +642,7 @@ int dlen;
cmd[i] = '\0';
ftp->ftp_incok = 0;
+ DT2(ftp_client_command, char [], cmd, int, ftp->ftp_passok);
if (!strncmp(cmd, "USER ", 5) || !strncmp(cmd, "XAUT ", 5)) {
if (ftp->ftp_passok == FTPXY_ADOK_1 ||
ftp->ftp_passok == FTPXY_AUOK_1) {
@@ -437,14 +672,24 @@ int dlen;
!strncmp(cmd, "ACCT ", 5)) {
ftp->ftp_passok = FTPXY_ACCT_1;
ftp->ftp_incok = 1;
- } else if ((ftp->ftp_passok == FTPXY_GO) && !ippr_ftp_pasvonly &&
+ } else if ((ftp->ftp_passok == FTPXY_GO) &&
+ !softf->ipf_p_ftp_pasvonly &&
!strncmp(cmd, "PORT ", 5)) {
- inc = ippr_ftp_port(fin, ip, nat, f, dlen);
- } else if (ippr_ftp_insecure && !ippr_ftp_pasvonly &&
+ inc = ipf_p_ftp_port(softf, fin, ip, nat, ftp, dlen);
+ } else if ((ftp->ftp_passok == FTPXY_GO) &&
+ !softf->ipf_p_ftp_pasvonly &&
+ !strncmp(cmd, "EPRT ", 5)) {
+ inc = ipf_p_ftp_eprt(softf, fin, ip, nat, ftp, dlen);
+ } else if (softf->ipf_p_ftp_insecure &&
+ !softf->ipf_p_ftp_pasvonly &&
!strncmp(cmd, "PORT ", 5)) {
- inc = ippr_ftp_port(fin, ip, nat, f, dlen);
+ inc = ipf_p_ftp_port(softf, fin, ip, nat, ftp, dlen);
}
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
+ printf("ipf_p_ftp_client: cmd[%s] passok %d incok %d inc %d\n",
+ cmd, ftp->ftp_passok, ftp->ftp_incok, inc);
+ DT2(ftp_client_passok, char *, cmd, int, ftp->ftp_passok);
while ((*rptr++ != '\n') && (rptr < wptr))
;
f->ftps_rptr = rptr;
@@ -452,12 +697,14 @@ int dlen;
}
-int ippr_ftp_pasv(fin, ip, nat, ftp, dlen)
-fr_info_t *fin;
-ip_t *ip;
-nat_t *nat;
-ftpinfo_t *ftp;
-int dlen;
+int
+ipf_p_ftp_pasv(softf, fin, ip, nat, ftp, dlen)
+ ipf_ftp_softc_t *softf;
+ fr_info_t *fin;
+ ip_t *ip;
+ nat_t *nat;
+ ftpinfo_t *ftp;
+ int dlen;
{
u_int a1, a2, a3, a4, data_ip;
char newbuf[IPF_FTPBUFSZ];
@@ -466,11 +713,12 @@ int dlen;
ftpside_t *f;
char *s;
- if (ippr_ftp_forcepasv != 0 &&
- ftp->ftp_side[0].ftps_cmds != FTPXY_C_PASV) {
- if (ippr_ftp_debug > 0)
- printf("ippr_ftp_pasv:ftps_cmds(%d) != FTPXY_C_PASV\n",
- ftp->ftp_side[0].ftps_cmds);
+ if ((softf->ipf_p_ftp_forcepasv != 0) &&
+ (ftp->ftp_side[0].ftps_cmd != FTPXY_C_PASV)) {
+ DT2(ftp_PASV_error_state, nat_t *, nat, ftpinfo_t *, ftp);
+ if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+ printf("ipf_p_ftp_pasv:ftps_cmd(%d) != FTPXY_C_PASV\n",
+ ftp->ftp_side[0].ftps_cmd);
return 0;
}
@@ -481,14 +729,17 @@ int dlen;
* Check for PASV reply message.
*/
if (dlen < IPF_MIN227LEN) {
- if (ippr_ftp_debug > 1)
- printf("ippr_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n",
+ DT3(ftp_PASV_error_short, nat_t *, nat, ftpinfo_t *, ftp,
+ int, dlen);
+ if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+ printf("ipf_p_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n",
dlen);
return 0;
} else if (strncmp(f->ftps_rptr,
"227 Entering Passive Mod", PASV_REPLEN)) {
- if (ippr_ftp_debug > 0)
- printf("ippr_ftp_pasv:%d reply wrong\n", 227);
+ DT2(ftp_PASV_error_string, nat_t *, nat, ftpinfo_t *, ftp);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+ printf("ipf_p_ftp_pasv:%d reply wrong\n", 227);
return 0;
}
@@ -509,16 +760,18 @@ int dlen;
/*
* Pick out the address components, two at a time.
*/
- a1 = ippr_ftp_atoi(&s);
+ a1 = ipf_p_ftp_atoi(&s);
if (s == NULL) {
- if (ippr_ftp_debug > 1)
- printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 1);
+ DT2(ftp_PASV_error_atoi_1, nat_t *, nat, ftpside_t *, f);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+ printf("ipf_p_ftp_pasv:ipf_p_ftp_atoi(%d) failed\n", 1);
return 0;
}
- a2 = ippr_ftp_atoi(&s);
+ a2 = ipf_p_ftp_atoi(&s);
if (s == NULL) {
- if (ippr_ftp_debug > 1)
- printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 2);
+ DT2(ftp_PASV_error_atoi_2, nat_t *, nat, ftpside_t *, f);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+ printf("ipf_p_ftp_pasv:ipf_p_ftp_atoi(%d) failed\n", 2);
return 0;
}
@@ -530,18 +783,21 @@ int dlen;
a1 |= a2;
if (((nat->nat_dir == NAT_INBOUND) &&
- (a1 != ntohl(nat->nat_inip.s_addr))) ||
+ (a1 != ntohl(nat->nat_ndstaddr))) ||
((nat->nat_dir == NAT_OUTBOUND) &&
- (a1 != ntohl(nat->nat_oip.s_addr)))) {
- if (ippr_ftp_debug > 0)
- printf("ippr_ftp_pasv:%s != nat->nat_oip\n", "a1");
+ (a1 != ntohl(nat->nat_odstaddr)))) {
+ DT3(ftp_PASV_error_address, nat_t *, nat, ftpside_t *, f,
+ u_int, a1);
+ if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+ printf("ipf_p_ftp_pasv:%s != nat->nat_oip\n", "a1");
return 0;
}
- a5 = ippr_ftp_atoi(&s);
+ a5 = ipf_p_ftp_atoi(&s);
if (s == NULL) {
- if (ippr_ftp_debug > 1)
- printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 3);
+ DT2(ftp_PASV_error_atoi_3, nat_t *, nat, ftpside_t *, f);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+ printf("ipf_p_ftp_pasv:ipf_p_ftp_atoi(%d) failed\n", 3);
return 0;
}
@@ -554,13 +810,13 @@ int dlen;
/*
* check for CR-LF at the end.
*/
- if ((*s == '\r') && (*(s + 1) == '\n')) {
- s += 2;
- } else {
- if (ippr_ftp_debug > 1)
- printf("ippr_ftp_pasv:missing %s", "cr-lf\n");
+ if ((*s != '\r') || (*(s + 1) != '\n')) {
+ DT(pasv_missing_crlf);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+ printf("ipf_p_ftp_pasv:missing %s", "cr-lf\n");
return 0;
}
+ s += 2;
a6 = a5 & 0xff;
a5 >>= 8;
@@ -568,7 +824,7 @@ int dlen;
* Calculate new address parts for 227 reply
*/
if (nat->nat_dir == NAT_INBOUND) {
- data_ip = nat->nat_outip.s_addr;
+ data_ip = nat->nat_odstaddr;
a1 = ntohl(data_ip);
} else
data_ip = htonl(a1);
@@ -587,156 +843,165 @@ int dlen;
"227 Entering Passive Mode", brackets[0], a1, a2, a3, a4,
a5, a6, brackets[1]);
#endif
- return ippr_ftp_pasvreply(fin, ip, nat, f, (a5 << 8 | a6),
- newbuf, s, data_ip);
+ return ipf_p_ftp_pasvreply(softf, fin, ip, nat, ftp, (a5 << 8 | a6),
+ newbuf, s);
}
-int ippr_ftp_pasvreply(fin, ip, nat, f, port, newmsg, s, data_ip)
-fr_info_t *fin;
-ip_t *ip;
-nat_t *nat;
-ftpside_t *f;
-u_int port;
-char *newmsg;
-char *s;
-u_int data_ip;
+int
+ipf_p_ftp_pasvreply(softf, fin, ip, nat, ftp, port, newmsg, s)
+ ipf_ftp_softc_t *softf;
+ fr_info_t *fin;
+ ip_t *ip;
+ nat_t *nat;
+ ftpinfo_t *ftp;
+ u_int port;
+ char *newmsg;
+ char *s;
{
- int inc, off, nflags, sflags;
+ int inc, off, nflags;
tcphdr_t *tcp, tcph, *tcp2;
- struct in_addr swip, swip2;
- struct in_addr data_addr;
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
size_t nlen, olen;
+#ifdef USE_INET6
+ ip6_t *ip6;
+#endif
+ ipnat_t *ipn;
fr_info_t fi;
+ ftpside_t *f;
nat_t *nat2;
mb_t *m;
+ softc = fin->fin_main_soft;
+ softn = softc->ipf_nat_soft;
+
+ if ((ftp->ftp_pendnat != NULL) || (ftp->ftp_pendstate != NULL))
+ ipf_p_ftp_setpending(softc, ftp);
+
m = fin->fin_m;
tcp = (tcphdr_t *)fin->fin_dp;
off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
- data_addr.s_addr = data_ip;
tcp2 = &tcph;
inc = 0;
-
+ f = &ftp->ftp_side[1];
olen = s - f->ftps_rptr;
nlen = strlen(newmsg);
inc = nlen - olen;
- if ((inc + ip->ip_len) > 65535) {
- if (ippr_ftp_debug > 0)
- printf("ippr_ftp_pasv:inc(%d) + ip->ip_len > 65535\n",
+ if ((inc + fin->fin_plen) > 65535) {
+ DT3(ftp_PASV_error_inc, nat_t *, nat, ftpside_t *, f,
+ int, inc);
+ if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+ printf("ipf_p_ftp_pasv:inc(%d) + ip->ip_len > 65535\n",
inc);
return 0;
}
-#if !defined(_KERNEL)
- bcopy(newmsg, MTOD(m, char *) + off, nlen);
-#else
-# if defined(MENTAT)
- if (inc < 0)
- (void)adjmsg(m, inc);
-# else /* defined(MENTAT) */
- /*
- * m_adj takes care of pkthdr.len, if required and treats inc<0 to
- * mean remove -len bytes from the end of the packet.
- * The mbuf chain will be extended if necessary by m_copyback().
- */
- if (inc < 0)
- m_adj(m, inc);
-# endif /* defined(MENTAT) */
-#endif /* !defined(_KERNEL) */
- COPYBACK(m, off, nlen, newmsg);
-
- if (inc != 0) {
- ip->ip_len += inc;
- fin->fin_dlen += inc;
- fin->fin_plen += inc;
- }
+ ipn = ipf_proxy_rule_fwd(nat);
+ if (ipn == NULL)
+ return APR_ERR(1);
+ ipn->in_use = 0;
/*
* Add skeleton NAT entry for connection which will come back the
* other way.
*/
+ bzero((char *)tcp2, sizeof(*tcp2));
bcopy((char *)fin, (char *)&fi, sizeof(fi));
- fi.fin_state = NULL;
- fi.fin_nat = NULL;
fi.fin_flx |= FI_IGNORE;
fi.fin_data[0] = 0;
fi.fin_data[1] = port;
nflags = IPN_TCP|SI_W_SPORT;
- if (ippr_ftp_pasvrdr && f->ftps_ifp)
- nflags |= SI_W_DPORT;
- if (nat->nat_dir == NAT_OUTBOUND)
- nat2 = nat_outlookup(&fi, nflags|NAT_SEARCH,
- nat->nat_p, nat->nat_inip, nat->nat_oip);
+
+ fi.fin_fr = &ftppxyfr;
+ fi.fin_dp = (char *)tcp2;
+ fi.fin_out = 1 - fin->fin_out;
+ fi.fin_dlen = sizeof(*tcp2);
+ fi.fin_src6 = nat->nat_osrc6;
+ fi.fin_dst6 = nat->nat_odst6;
+ fi.fin_plen = fi.fin_hlen + sizeof(*tcp);
+ fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
+
+ TCP_OFF_A(tcp2, 5);
+ tcp2->th_flags = TH_SYN;
+ tcp2->th_win = htons(8192);
+ tcp2->th_dport = htons(port);
+
+ MUTEX_ENTER(&softn->ipf_nat_new);
+#ifdef USE_INET6
+ if (nat->nat_v[0] == 6)
+ nat2 = ipf_nat6_add(&fi, ipn, &ftp->ftp_pendnat,
+ nflags, nat->nat_dir);
else
- nat2 = nat_inlookup(&fi, nflags|NAT_SEARCH,
- nat->nat_p, nat->nat_inip, nat->nat_oip);
+#endif
+ nat2 = ipf_nat_add(&fi, ipn, &ftp->ftp_pendnat,
+ nflags, nat->nat_dir);
+ MUTEX_EXIT(&softn->ipf_nat_new);
+
if (nat2 == NULL) {
- int slen;
-
- slen = ip->ip_len;
- ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
- bzero((char *)tcp2, sizeof(*tcp2));
- tcp2->th_win = htons(8192);
- tcp2->th_sport = 0; /* XXX - fake it for nat_new */
- TCP_OFF_A(tcp2, 5);
- tcp2->th_flags = TH_SYN;
- fi.fin_data[1] = port;
- fi.fin_dlen = sizeof(*tcp2);
- tcp2->th_dport = htons(port);
- fi.fin_data[0] = 0;
- fi.fin_dp = (char *)tcp2;
- fi.fin_plen = fi.fin_hlen + sizeof(*tcp);
- fi.fin_fr = &ftppxyfr;
- fi.fin_out = nat->nat_dir;
- fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
- swip = ip->ip_src;
- swip2 = ip->ip_dst;
- if (nat->nat_dir == NAT_OUTBOUND) {
- fi.fin_fi.fi_daddr = data_addr.s_addr;
- fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
- ip->ip_dst = data_addr;
- ip->ip_src = nat->nat_inip;
- } else if (nat->nat_dir == NAT_INBOUND) {
- fi.fin_fi.fi_saddr = nat->nat_oip.s_addr;
- fi.fin_fi.fi_daddr = nat->nat_outip.s_addr;
- ip->ip_src = nat->nat_oip;
- ip->ip_dst = nat->nat_outip;
- }
+ KFREES(ipn, ipn->in_size);
+ return APR_ERR(1);
+ }
- sflags = nflags;
- nflags |= NAT_SLAVE;
- if (nat->nat_dir == NAT_INBOUND)
- nflags |= NAT_NOTRULEPORT;
- nat2 = nat_new(&fi, nat->nat_ptr, NULL, nflags, nat->nat_dir);
- if (nat2 != NULL) {
- (void) nat_proto(&fi, nat2, IPN_TCP);
- nat_update(&fi, nat2, nat->nat_ptr);
- fi.fin_ifp = NULL;
- if (nat->nat_dir == NAT_INBOUND) {
- fi.fin_fi.fi_daddr = nat->nat_inip.s_addr;
- ip->ip_dst = nat->nat_inip;
- }
- (void) fr_addstate(&fi, NULL, sflags);
- if (fi.fin_state != NULL)
- fr_statederef((ipstate_t **)&fi.fin_state);
+ (void) ipf_nat_proto(&fi, nat2, IPN_TCP);
+ MUTEX_ENTER(&nat2->nat_lock);
+ ipf_nat_update(&fi, nat2);
+ MUTEX_EXIT(&nat2->nat_lock);
+ fi.fin_ifp = NULL;
+ if (nat->nat_dir == NAT_INBOUND) {
+ if (nat->nat_v[0] == 6) {
+#ifdef USE_INET6
+ fi.fin_dst6 = nat->nat_ndst6;
+#endif
+ } else {
+ fi.fin_daddr = nat->nat_ndstaddr;
}
+ }
+ if (ipf_state_add(softc, &fi, (ipstate_t **)&ftp->ftp_pendstate,
+ SI_W_SPORT) != 0)
+ ipf_nat_setpending(softc, nat2);
+
+#if !defined(_KERNEL)
+ M_ADJ(m, inc);
+#else
+ /*
+ * m_adj takes care of pkthdr.len, if required and treats inc<0 to
+ * mean remove -len bytes from the end of the packet.
+ * The mbuf chain will be extended if necessary by m_copyback().
+ */
+ if (inc < 0)
+ M_ADJ(m, inc);
+#endif /* !defined(_KERNEL) */
+ COPYBACK(m, off, nlen, newmsg);
+ fin->fin_flx |= FI_DOCKSUM;
- ip->ip_len = slen;
- ip->ip_src = swip;
- ip->ip_dst = swip2;
+ if (inc != 0) {
+ fin->fin_plen += inc;
+ fin->fin_dlen += inc;
+ if (nat->nat_v[0] == 6) {
+#ifdef USE_INET6
+ ip6 = (ip6_t *)fin->fin_ip;
+ u_short len = ntohs(ip6->ip6_plen) + inc;
+ ip6->ip6_plen = htons(len);
+#endif
+ } else {
+ ip->ip_len = htons(fin->fin_plen);
+ }
}
- return inc;
+
+ return APR_INC(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;
+int
+ipf_p_ftp_server(softf, fin, ip, nat, ftp, dlen)
+ ipf_ftp_softc_t *softf;
+ fr_info_t *fin;
+ ip_t *ip;
+ nat_t *nat;
+ ftpinfo_t *ftp;
+ int dlen;
{
char *rptr, *wptr;
ftpside_t *f;
@@ -747,19 +1012,29 @@ int dlen;
rptr = f->ftps_rptr;
wptr = f->ftps_wptr;
+ DT2(ftp_server_response, char *, rptr, int, ftp->ftp_passok);
if (*rptr == ' ')
goto server_cmd_ok;
if (!ISDIGIT(*rptr) || !ISDIGIT(*(rptr + 1)) || !ISDIGIT(*(rptr + 2)))
return 0;
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
+ printf("ipf_p_ftp_server_1: cmd[%4.4s] passok %d\n",
+ rptr, ftp->ftp_passok);
if (ftp->ftp_passok == FTPXY_GO) {
if (!strncmp(rptr, "227 ", 4))
- inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen);
+ inc = ipf_p_ftp_pasv(softf, fin, ip, nat, ftp, dlen);
else if (!strncmp(rptr, "229 ", 4))
- inc = ippr_ftp_epsv(fin, ip, nat, f, dlen);
- } else if (ippr_ftp_insecure && !strncmp(rptr, "227 ", 4)) {
- inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen);
- } else if (ippr_ftp_insecure && !strncmp(rptr, "229 ", 4)) {
- inc = ippr_ftp_epsv(fin, ip, nat, f, dlen);
+ inc = ipf_p_ftp_epsv(softf, fin, ip, nat, ftp, dlen);
+ else if (strncmp(rptr, "200", 3)) {
+ /*
+ * 200 is returned for a successful command.
+ */
+ ;
+ }
+ } else if (softf->ipf_p_ftp_insecure && !strncmp(rptr, "227 ", 4)) {
+ inc = ipf_p_ftp_pasv(softf, fin, ip, nat, ftp, dlen);
+ } else if (softf->ipf_p_ftp_insecure && !strncmp(rptr, "229 ", 4)) {
+ inc = ipf_p_ftp_epsv(softf, fin, ip, nat, ftp, dlen);
} else if (*rptr == '5' || *rptr == '4')
ftp->ftp_passok = FTPXY_INIT;
else if (ftp->ftp_incok) {
@@ -784,8 +1059,13 @@ int dlen;
}
}
}
-server_cmd_ok:
ftp->ftp_incok = 0;
+server_cmd_ok:
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
+ printf("ipf_p_ftp_server_2: cmd[%4.4s] passok %d\n",
+ rptr, ftp->ftp_passok);
+ DT3(ftp_server_passok, char *,rptr, int, ftp->ftp_incok,
+ int, ftp->ftp_passok);
while ((*rptr++ != '\n') && (rptr < wptr))
;
@@ -795,13 +1075,20 @@ server_cmd_ok:
/*
+ * 0 FTPXY_JUNK_OK
+ * 1 FTPXY_JUNK_BAD
+ * 2 FTPXY_JUNK_EOL
+ * 3 FTPXY_JUNK_CONT
+ *
* Look to see if the buffer starts with something which we recognise as
* being the correct syntax for the FTP protocol.
*/
-int ippr_ftp_client_valid(ftps, buf, len)
-ftpside_t *ftps;
-char *buf;
-size_t len;
+int
+ipf_p_ftp_client_valid(softf, ftps, buf, len)
+ ipf_ftp_softc_t *softf;
+ ftpside_t *ftps;
+ char *buf;
+ size_t len;
{
register char *s, c, pc;
register size_t i = len;
@@ -809,12 +1096,13 @@ size_t len;
s = buf;
- if (ftps->ftps_junk == 1)
- return 1;
+ if (ftps->ftps_junk == FTPXY_JUNK_BAD)
+ return FTPXY_JUNK_BAD;
if (i < 5) {
- if (ippr_ftp_debug > 3)
- printf("ippr_ftp_client_valid:i(%d) < 5\n", (int)i);
+ DT1(client_valid, int, i);
+ if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+ printf("ipf_p_ftp_client_valid:i(%d) < 5\n", (int)i);
return 2;
}
@@ -847,12 +1135,13 @@ size_t len;
goto bad_client_command;
} else {
bad_client_command:
- if (ippr_ftp_debug > 3)
+ DT4(client_junk, int, len, int, i, int, c, char *, buf);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*.*s]\n",
- "ippr_ftp_client_valid",
+ "ipf_p_ftp_client_valid",
ftps->ftps_junk, (int)len, (int)i, c,
(int)len, (int)len, buf);
- return 1;
+ return FTPXY_JUNK_BAD;
}
for (; i; i--) {
@@ -860,25 +1149,30 @@ bad_client_command:
c = *s++;
if ((pc == '\r') && (c == '\n')) {
cmd[4] = '\0';
- if (!strcmp(cmd, "PASV"))
- ftps->ftps_cmds = FTPXY_C_PASV;
- else
- ftps->ftps_cmds = 0;
+ if (!strcmp(cmd, "PASV")) {
+ ftps->ftps_cmd = FTPXY_C_PASV;
+ } else if (!strcmp(cmd, "EPSV")) {
+ ftps->ftps_cmd = FTPXY_C_EPSV;
+ } else {
+ ftps->ftps_cmd = 0;
+ }
return 0;
}
}
#if !defined(_KERNEL)
- printf("ippr_ftp_client_valid:junk after cmd[%*.*s]\n",
+ printf("ipf_p_ftp_client_valid:junk after cmd[%*.*s]\n",
(int)len, (int)len, buf);
#endif
- return 2;
+ return FTPXY_JUNK_EOL;
}
-int ippr_ftp_server_valid(ftps, buf, len)
-ftpside_t *ftps;
-char *buf;
-size_t len;
+int
+ipf_p_ftp_server_valid(softf, ftps, buf, len)
+ ipf_ftp_softc_t *softf;
+ ftpside_t *ftps;
+ char *buf;
+ size_t len;
{
register char *s, c, pc;
register size_t i = len;
@@ -887,19 +1181,22 @@ size_t len;
s = buf;
cmd = 0;
- if (ftps->ftps_junk == 1)
- return 1;
+ if (ftps->ftps_junk == FTPXY_JUNK_BAD)
+ return FTPXY_JUNK_BAD;
if (i < 5) {
- if (ippr_ftp_debug > 3)
- printf("ippr_ftp_servert_valid:i(%d) < 5\n", (int)i);
+ DT1(server_valid, int, i);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+ printf("ipf_p_ftp_servert_valid:i(%d) < 5\n", (int)i);
return 2;
}
c = *s++;
i--;
- if (c == ' ')
+ if (c == ' ') {
+ cmd = -1;
goto search_eol;
+ }
if (ISDIGIT(c)) {
cmd = (c - '0') * 100;
@@ -915,40 +1212,54 @@ size_t len;
i--;
if ((c != '-') && (c != ' '))
goto bad_server_command;
+ if (c == '-')
+ return FTPXY_JUNK_CONT;
} else
goto bad_server_command;
} else
goto bad_server_command;
} else {
bad_server_command:
- if (ippr_ftp_debug > 3)
+ DT4(server_junk, int len, buf, int, i, int, c, char *, buf);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_INFO)
printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*.*s]\n",
- "ippr_ftp_server_valid",
+ "ipf_p_ftp_server_valid",
ftps->ftps_junk, (int)len, (int)i,
c, (int)len, (int)len, buf);
- return 1;
+ if (ftps->ftps_junk == FTPXY_JUNK_CONT)
+ return FTPXY_JUNK_CONT;
+ return FTPXY_JUNK_BAD;
}
search_eol:
for (; i; i--) {
pc = c;
c = *s++;
if ((pc == '\r') && (c == '\n')) {
- ftps->ftps_cmds = cmd;
- return 0;
+ if (cmd == -1) {
+ if (ftps->ftps_junk == FTPXY_JUNK_CONT)
+ return FTPXY_JUNK_CONT;
+ } else {
+ ftps->ftps_cmd = cmd;
+ }
+ return FTPXY_JUNK_OK;
}
}
- if (ippr_ftp_debug > 3)
- printf("ippr_ftp_server_valid:junk after cmd[%*.*s]\n",
+
+ DT2(junk_eol, int, len, char *, buf);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_INFO)
+ printf("ipf_p_ftp_server_valid:junk after cmd[%*.*s]\n",
(int)len, (int)len, buf);
- return 2;
+ return FTPXY_JUNK_EOL;
}
-int ippr_ftp_valid(ftp, side, buf, len)
-ftpinfo_t *ftp;
-int side;
-char *buf;
-size_t len;
+int
+ipf_p_ftp_valid(softf, ftp, side, buf, len)
+ ipf_ftp_softc_t *softf;
+ ftpinfo_t *ftp;
+ int side;
+ char *buf;
+ size_t len;
{
ftpside_t *ftps;
int ret;
@@ -956,9 +1267,9 @@ size_t len;
ftps = &ftp->ftp_side[side];
if (side == 0)
- ret = ippr_ftp_client_valid(ftps, buf, len);
+ ret = ipf_p_ftp_client_valid(softf, ftps, buf, len);
else
- ret = ippr_ftp_server_valid(ftps, buf, len);
+ ret = ipf_p_ftp_server_valid(softf, ftps, buf, len);
return ret;
}
@@ -971,13 +1282,15 @@ size_t len;
* rv == 0 for inbound processing,
* rv == 1 for outbound processing.
*/
-int ippr_ftp_process(fin, nat, ftp, rv)
-fr_info_t *fin;
-nat_t *nat;
-ftpinfo_t *ftp;
-int rv;
+int
+ipf_p_ftp_process(softf, fin, nat, ftp, rv)
+ ipf_ftp_softc_t *softf;
+ fr_info_t *fin;
+ nat_t *nat;
+ ftpinfo_t *ftp;
+ int rv;
{
- int mlen, len, off, inc, i, sel, sel2, ok, ackoff, seqoff;
+ int mlen, len, off, inc, i, sel, sel2, ok, ackoff, seqoff, retry;
char *rptr, *wptr, *s;
u_32_t thseq, thack;
ap_session_t *aps;
@@ -995,14 +1308,17 @@ int rv;
t = &ftp->ftp_side[1 - rv];
thseq = ntohl(tcp->th_seq);
thack = ntohl(tcp->th_ack);
-
#ifdef __sgi
mlen = fin->fin_plen - off;
#else
mlen = MSGDSIZE(m) - off;
#endif
- if (ippr_ftp_debug > 4)
- printf("ippr_ftp_process: mlen %d\n", mlen);
+
+ DT3(process_debug, tcphdr_t *, tcp, int, off, int, mlen);
+ if (softf->ipf_p_ftp_debug & DEBUG_INFO)
+ printf("ipf_p_ftp_process: %d:%d,%d, mlen %d flags %x\n",
+ fin->fin_out, fin->fin_sport, fin->fin_dport,
+ mlen, tcp->th_flags);
if ((mlen == 0) && ((tcp->th_flags & TH_OPENING) == TH_OPENING)) {
f->ftps_seq[0] = thseq + 1;
@@ -1016,7 +1332,7 @@ int rv;
sel = aps->aps_sel[1 - rv];
sel2 = aps->aps_sel[rv];
- if (rv == 0) {
+ if (rv == 1) {
seqoff = aps->aps_seqoff[sel];
if (aps->aps_seqmin[sel] > seqoff + thseq)
seqoff = aps->aps_seqoff[!sel];
@@ -1025,14 +1341,14 @@ int rv;
ackoff = aps->aps_ackoff[!sel2];
} else {
seqoff = aps->aps_ackoff[sel];
- if (ippr_ftp_debug > 2)
+ if (softf->ipf_p_ftp_debug & DEBUG_INFO)
printf("seqoff %d thseq %x ackmin %x\n", seqoff, thseq,
aps->aps_ackmin[sel]);
if (aps->aps_ackmin[sel] > seqoff + thseq)
seqoff = aps->aps_ackoff[!sel];
ackoff = aps->aps_seqoff[sel2];
- if (ippr_ftp_debug > 2)
+ if (softf->ipf_p_ftp_debug & DEBUG_INFO)
printf("ackoff %d thack %x seqmin %x\n", ackoff, thack,
aps->aps_seqmin[sel2]);
if (ackoff > 0) {
@@ -1043,7 +1359,7 @@ int rv;
ackoff = aps->aps_seqoff[!sel2];
}
}
- if (ippr_ftp_debug > 2) {
+ if (softf->ipf_p_ftp_debug & DEBUG_INFO) {
printf("%s: %x seq %x/%d ack %x/%d len %d/%d off %d\n",
rv ? "IN" : "OUT", tcp->th_flags, thseq, seqoff,
thack, ackoff, mlen, fin->fin_plen, off);
@@ -1060,7 +1376,7 @@ 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 (ippr_ftp_debug > 2) {
+ if (softf->ipf_p_ftp_debug & DEBUG_INFO) {
printf("rv %d t:seq[0] %x seq[1] %x %d/%d\n",
rv, t->ftps_seq[0], t->ftps_seq[1], seqoff, ackoff);
}
@@ -1078,37 +1394,44 @@ int rv;
ok = 1;
}
} else {
- if (t->ftps_seq[0] + ackoff == thack)
+ if (t->ftps_seq[0] + ackoff == thack) {
+ t->ftps_seq[0] = thack;
ok = 1;
- else if (t->ftps_seq[0] == thack + ackoff)
+ } else if (t->ftps_seq[0] == thack + ackoff) {
+ t->ftps_seq[0] = thack + ackoff;
ok = 1;
- else if (t->ftps_seq[1] + ackoff == thack) {
- t->ftps_seq[0] = thack - ackoff;
+ } else if (t->ftps_seq[1] + ackoff == thack) {
+ t->ftps_seq[0] = thack;
ok = 1;
} else if (t->ftps_seq[1] == thack + ackoff) {
- t->ftps_seq[0] = thack - ackoff;
+ t->ftps_seq[0] = thack + ackoff;
ok = 1;
}
}
}
- if (ippr_ftp_debug > 2) {
+ if (softf->ipf_p_ftp_debug & DEBUG_INFO) {
if (!ok)
printf("%s ok\n", "not");
}
if (!mlen) {
- if (t->ftps_seq[0] + ackoff != thack) {
- if (ippr_ftp_debug > 1) {
- printf("%s:seq[0](%x) + (%x) != (%x)\n",
- "ippr_ftp_process", t->ftps_seq[0],
+ if (t->ftps_seq[0] + ackoff != thack &&
+ t->ftps_seq[1] + ackoff != thack) {
+ DT3(thack, ftpside_t *t, t, int, ackoff, u_32_t, thack);
+ if (softf->ipf_p_ftp_debug & DEBUG_ERROR) {
+ printf("%s:seq[0](%u) + (%d) != (%u)\n",
+ "ipf_p_ftp_process", t->ftps_seq[0],
+ ackoff, thack);
+ printf("%s:seq[0](%u) + (%d) != (%u)\n",
+ "ipf_p_ftp_process", t->ftps_seq[1],
ackoff, thack);
}
return APR_ERR(1);
}
- if (ippr_ftp_debug > 2) {
- printf("ippr_ftp_process:f:seq[0] %x seq[1] %x\n",
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE) {
+ printf("ipf_p_ftp_process:f:seq[0] %x seq[1] %x\n",
f->ftps_seq[0], f->ftps_seq[1]);
}
@@ -1117,9 +1440,10 @@ int rv;
f->ftps_seq[0] = f->ftps_seq[1] - seqoff;
f->ftps_seq[1] = thseq + 1 - seqoff;
} else {
- if (ippr_ftp_debug > 1) {
- printf("FIN: thseq %x seqoff %d ftps_seq %x %x\n",
- thseq, seqoff, f->ftps_seq[0], f->ftps_seq[1]);
+ DT2(thseq, ftpside_t *t, t, u_32_t, thseq);
+ if (softf->ipf_p_ftp_debug & DEBUG_ERROR) {
+ printf("FIN: thseq %x seqoff %d ftps_seq %x\n",
+ thseq, seqoff, f->ftps_seq[0]);
}
return APR_ERR(1);
}
@@ -1140,8 +1464,9 @@ int rv;
}
if (ok == 0) {
+ DT3(ok_0, ftpside_t *, f, u_32_t, thseq, int, mlen);
inc = thseq - f->ftps_seq[0];
- if (ippr_ftp_debug > 1) {
+ if (softf->ipf_p_ftp_debug & DEBUG_ERROR) {
printf("inc %d sel %d rv %d\n", inc, sel, rv);
printf("th_seq %x ftps_seq %x/%x\n",
thseq, f->ftps_seq[0], f->ftps_seq[1]);
@@ -1163,68 +1488,69 @@ int rv;
while (mlen > 0) {
len = MIN(mlen, sizeof(f->ftps_buf) - (wptr - rptr));
+ if (len == 0)
+ break;
COPYDATA(m, off, len, wptr);
mlen -= len;
off += len;
wptr += len;
- if (ippr_ftp_debug > 3)
+whilemore:
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
printf("%s:len %d/%d off %d wptr %lx junk %d [%*.*s]\n",
- "ippr_ftp_process",
+ "ipf_p_ftp_process",
len, mlen, off, (u_long)wptr, f->ftps_junk,
len, len, rptr);
f->ftps_wptr = wptr;
- if (f->ftps_junk != 0) {
+ if (f->ftps_junk != FTPXY_JUNK_OK) {
i = f->ftps_junk;
- f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr,
+ f->ftps_junk = ipf_p_ftp_valid(softf, ftp, rv, rptr,
wptr - rptr);
+ DT2(junk_transit, int, i, int, f->ftps_junk);
- if (ippr_ftp_debug > 5)
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE)
printf("%s:junk %d -> %d\n",
- "ippr_ftp_process", i, f->ftps_junk);
+ "ipf_p_ftp_process", i, f->ftps_junk);
- if (f->ftps_junk != 0) {
+ if (f->ftps_junk == FTPXY_JUNK_BAD) {
+ DT(buffer_full);
if (wptr - rptr == sizeof(f->ftps_buf)) {
- if (ippr_ftp_debug > 4)
+ if (softf->ipf_p_ftp_debug &
+ DEBUG_PARSE_INFO)
printf("%s:full buffer\n",
- "ippr_ftp_process");
+ "ipf_p_ftp_process");
f->ftps_rptr = f->ftps_buf;
f->ftps_wptr = f->ftps_buf;
rptr = f->ftps_rptr;
wptr = f->ftps_wptr;
- /*
- * Because we throw away data here that
- * we would otherwise parse, set the
- * junk flag to indicate just ignore
- * any data upto the next CRLF.
- */
- f->ftps_junk = 1;
continue;
}
}
}
- while ((f->ftps_junk == 0) && (wptr > rptr)) {
+ while ((f->ftps_junk == FTPXY_JUNK_OK) && (wptr > rptr)) {
len = wptr - rptr;
- f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, len);
+ f->ftps_junk = ipf_p_ftp_valid(softf, ftp, rv,
+ rptr, len);
- if (ippr_ftp_debug > 3) {
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE) {
printf("%s=%d len %d rv %d ptr %lx/%lx ",
- "ippr_ftp_valid",
+ "ipf_p_ftp_valid",
f->ftps_junk, len, rv, (u_long)rptr,
(u_long)wptr);
printf("buf [%*.*s]\n", len, len, rptr);
}
- if (f->ftps_junk == 0) {
+ if (f->ftps_junk == FTPXY_JUNK_OK) {
+ f->ftps_cmds++;
f->ftps_rptr = rptr;
if (rv)
- inc += ippr_ftp_server(fin, ip, nat,
- ftp, len);
+ inc += ipf_p_ftp_server(softf, fin, ip,
+ nat, ftp, len);
else
- inc += ippr_ftp_client(fin, ip, nat,
- ftp, len);
+ inc += ipf_p_ftp_client(softf, fin, ip,
+ nat, ftp, len);
rptr = f->ftps_rptr;
wptr = f->ftps_wptr;
}
@@ -1234,21 +1560,25 @@ int rv;
* Off to a bad start so lets just forget about using the
* ftp proxy for this connection.
*/
- if ((f->ftps_cmds == 0) && (f->ftps_junk == 1)) {
+ if ((f->ftps_cmds == 0) && (f->ftps_junk == FTPXY_JUNK_BAD)) {
/* f->ftps_seq[1] += inc; */
- if (ippr_ftp_debug > 1)
+ DT(ftp_junk_cmd);
+ if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
printf("%s:cmds == 0 junk == 1\n",
- "ippr_ftp_process");
+ "ipf_p_ftp_process");
return APR_ERR(2);
}
- if ((f->ftps_junk != 0) && (rptr < wptr)) {
+ retry = 0;
+ if ((f->ftps_junk != FTPXY_JUNK_OK) && (rptr < wptr)) {
for (s = rptr; s < wptr; s++) {
if ((*s == '\r') && (s + 1 < wptr) &&
(*(s + 1) == '\n')) {
rptr = s + 2;
- f->ftps_junk = 0;
+ retry = 1;
+ if (f->ftps_junk != FTPXY_JUNK_CONT)
+ f->ftps_junk = FTPXY_JUNK_OK;
break;
}
}
@@ -1264,19 +1594,21 @@ int rv;
* current state.
*/
if (rptr > f->ftps_buf) {
- bcopy(rptr, f->ftps_buf, len);
+ bcopy(rptr, f->ftps_buf, wptr - rptr);
wptr -= rptr - f->ftps_buf;
rptr = f->ftps_buf;
}
}
f->ftps_rptr = rptr;
f->ftps_wptr = wptr;
+ if (retry)
+ goto whilemore;
}
/* f->ftps_seq[1] += inc; */
if (tcp->th_flags & TH_FIN)
f->ftps_seq[1]++;
- if (ippr_ftp_debug > 3) {
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_INFO) {
#ifdef __sgi
mlen = fin->fin_plen;
#else
@@ -1293,11 +1625,14 @@ int rv;
}
-int ippr_ftp_out(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_ftp_out(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
{
+ ipf_ftp_softc_t *softf = arg;
ftpinfo_t *ftp;
int rev;
@@ -1309,15 +1644,18 @@ nat_t *nat;
if (ftp->ftp_side[1 - rev].ftps_ifp == NULL)
ftp->ftp_side[1 - rev].ftps_ifp = fin->fin_ifp;
- return ippr_ftp_process(fin, nat, ftp, rev);
+ return ipf_p_ftp_process(softf, fin, nat, ftp, rev);
}
-int ippr_ftp_in(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_ftp_in(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
{
+ ipf_ftp_softc_t *softf = arg;
ftpinfo_t *ftp;
int rev;
@@ -1329,18 +1667,19 @@ nat_t *nat;
if (ftp->ftp_side[rev].ftps_ifp == NULL)
ftp->ftp_side[rev].ftps_ifp = fin->fin_ifp;
- return ippr_ftp_process(fin, nat, ftp, 1 - rev);
+ return ipf_p_ftp_process(softf, fin, nat, ftp, 1 - rev);
}
/*
- * ippr_ftp_atoi - implement a version of atoi which processes numbers in
+ * ipf_p_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;
+u_short
+ipf_p_ftp_atoi(ptr)
+ char **ptr;
{
register char *s = *ptr, c;
register u_char i = 0, j = 0;
@@ -1364,26 +1703,237 @@ char **ptr;
}
-int ippr_ftp_epsv(fin, ip, nat, f, dlen)
-fr_info_t *fin;
-ip_t *ip;
-nat_t *nat;
-ftpside_t *f;
-int dlen;
+int
+ipf_p_ftp_eprt(softf, fin, ip, nat, ftp, dlen)
+ ipf_ftp_softc_t *softf;
+ fr_info_t *fin;
+ ip_t *ip;
+ nat_t *nat;
+ ftpinfo_t *ftp;
+ int dlen;
+{
+ ftpside_t *f;
+
+ /*
+ * Check for client sending out EPRT message.
+ */
+ if (dlen < IPF_MINEPRTLEN) {
+ DT1(epert_dlen, int, dlen);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+ printf("ipf_p_ftp_eprt:dlen(%d) < IPF_MINEPRTLEN\n",
+ dlen);
+ return 0;
+ }
+
+ /*
+ * Parse the EPRT command. Format is:
+ * "EPRT |1|1.2.3.4|2000|" for IPv4 and
+ * "EPRT |2|ef00::1:2|2000|" for IPv6
+ */
+ f = &ftp->ftp_side[0];
+ if (f->ftps_rptr[5] != '|')
+ return 0;
+ if (f->ftps_rptr[5] == f->ftps_rptr[7]) {
+ if (f->ftps_rptr[6] == '1' && nat->nat_v[0] == 4)
+ return ipf_p_ftp_eprt4(softf, fin, ip, nat, ftp, dlen);
+#ifdef USE_INET6
+ if (f->ftps_rptr[6] == '2' && nat->nat_v[0] == 6)
+ return ipf_p_ftp_eprt6(softf, fin, ip, nat, ftp, dlen);
+#endif
+ }
+ return 0;
+}
+
+
+int
+ipf_p_ftp_eprt4(softf, fin, ip, nat, ftp, dlen)
+ ipf_ftp_softc_t *softf;
+ fr_info_t *fin;
+ ip_t *ip;
+ nat_t *nat;
+ ftpinfo_t *ftp;
+ int dlen;
+{
+ int a1, a2, a3, a4, port, olen, nlen, inc, off;
+ char newbuf[IPF_FTPBUFSZ];
+ char *s, c, delim;
+ u_32_t addr, i;
+ tcphdr_t *tcp;
+ ftpside_t *f;
+ mb_t *m;
+
+ m = fin->fin_m;
+ tcp = (tcphdr_t *)fin->fin_dp;
+ off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
+ f = &ftp->ftp_side[0];
+ delim = f->ftps_rptr[5];
+ s = f->ftps_rptr + 8;
+
+ /*
+ * get the IP address.
+ */
+ i = 0;
+ while (((c = *s++) != '\0') && ISDIGIT(c)) {
+ i *= 10;
+ i += c - '0';
+ }
+ if (i > 255)
+ return 0;
+ if (c != '.')
+ return 0;
+ addr = (i << 24);
+
+ i = 0;
+ while (((c = *s++) != '\0') && ISDIGIT(c)) {
+ i *= 10;
+ i += c - '0';
+ }
+ if (i > 255)
+ return 0;
+ if (c != '.')
+ return 0;
+ addr |= (addr << 16);
+
+ i = 0;
+ while (((c = *s++) != '\0') && ISDIGIT(c)) {
+ i *= 10;
+ i += c - '0';
+ }
+ if (i > 255)
+ return 0;
+ if (c != '.')
+ return 0;
+ addr |= (addr << 8);
+
+ i = 0;
+ while (((c = *s++) != '\0') && ISDIGIT(c)) {
+ i *= 10;
+ i += c - '0';
+ }
+ if (i > 255)
+ return 0;
+ if (c != delim)
+ return 0;
+ addr |= addr;
+
+ /*
+ * Get the port number
+ */
+ i = 0;
+ while (((c = *s++) != '\0') && ISDIGIT(c)) {
+ i *= 10;
+ i += c - '0';
+ }
+ if (i > 65535)
+ return 0;
+ if (c != delim)
+ return 0;
+ port = i;
+
+ /*
+ * Check for CR-LF at the end of the command string.
+ */
+ if ((*s != '\r') || (*(s + 1) != '\n')) {
+ DT(eprt4_no_crlf);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+ printf("ipf_p_ftp_eprt4:missing %s\n", "cr-lf");
+ return 0;
+ }
+ s += 2;
+
+ /*
+ * Calculate new address parts for PORT command
+ */
+ if (nat->nat_dir == NAT_INBOUND)
+ a1 = ntohl(nat->nat_odstaddr);
+ else
+ 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 snprintf! */
+ /*
+ * While we could force the use of | as a delimiter here, it makes
+ * sense to preserve whatever character is being used by the systems
+ * involved in the communication.
+ */
+#if defined(SNPRINTF) && defined(_KERNEL)
+ SNPRINTF(newbuf, sizeof(newbuf), "%s %c1%c%u.%u.%u.%u%c%u%c\r\n",
+ "EPRT", delim, delim, a1, a2, a3, a4, delim, port, delim);
+#else
+ (void) sprintf(newbuf, "%s %c1%c%u.%u.%u.%u%c%u%c\r\n",
+ "EPRT", delim, delim, a1, a2, a3, a4, delim, port,
+ delim);
+#endif
+
+ nlen = strlen(newbuf);
+ inc = nlen - olen;
+ if ((inc + fin->fin_plen) > 65535) {
+ DT2(eprt4_len, int, inc, int, fin->fin_plen);
+ if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+ printf("ipf_p_ftp_eprt4:inc(%d) + ip->ip_len > 65535\n",
+ inc);
+ return 0;
+ }
+
+ off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
+#if !defined(_KERNEL)
+ M_ADJ(m, inc);
+#else
+ if (inc < 0)
+ M_ADJ(m, inc);
+#endif
+ /* the mbuf chain will be extended if necessary by m_copyback() */
+ COPYBACK(m, off, nlen, newbuf);
+ fin->fin_flx |= FI_DOCKSUM;
+
+ if (inc != 0) {
+ fin->fin_plen += inc;
+ ip->ip_len = htons(fin->fin_plen);
+ fin->fin_dlen += inc;
+ }
+
+ f->ftps_cmd = FTPXY_C_EPRT;
+ return ipf_p_ftp_addport(softf, fin, ip, nat, ftp, dlen, port, inc);
+}
+
+
+int
+ipf_p_ftp_epsv(softf, fin, ip, nat, ftp, dlen)
+ ipf_ftp_softc_t *softf;
+ fr_info_t *fin;
+ ip_t *ip;
+ nat_t *nat;
+ ftpinfo_t *ftp;
+ int dlen;
{
char newbuf[IPF_FTPBUFSZ];
- char *s;
u_short ap = 0;
+ ftpside_t *f;
+ char *s;
+
+ if ((softf->ipf_p_ftp_forcepasv != 0) &&
+ (ftp->ftp_side[0].ftps_cmd != FTPXY_C_EPSV)) {
+ DT1(epsv_cmd, int, ftp->ftp_side[0].ftps_cmd);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+ printf("ipf_p_ftp_epsv:ftps_cmd(%d) != FTPXY_C_EPSV\n",
+ ftp->ftp_side[0].ftps_cmd);
+ return 0;
+ }
+ f = &ftp->ftp_side[1];
#define EPSV_REPLEN 33
/*
* Check for EPSV reply message.
*/
- if (dlen < IPF_MIN229LEN)
+ if (dlen < IPF_MIN229LEN) {
return (0);
- else if (strncmp(f->ftps_rptr,
- "229 Entering Extended Passive Mode", EPSV_REPLEN))
+ } else if (strncmp(f->ftps_rptr,
+ "229 Entering Extended Passive Mode", EPSV_REPLEN)) {
return (0);
+}
/*
* Skip the EPSV command + space
@@ -1401,8 +1951,9 @@ int dlen;
ap += *s++ - '0';
}
- if (!*s)
+ if (!s) {
return 0;
+}
if (*s == '|')
s++;
@@ -1413,10 +1964,10 @@ int dlen;
/*
* check for CR-LF at the end.
*/
- if ((*s == '\r') && (*(s + 1) == '\n')) {
- s += 2;
- } else
+ if ((*s != '\r') || (*(s + 1) != '\n')) {
return 0;
+ }
+ s += 2;
#if defined(SNPRINTF) && defined(_KERNEL)
SNPRINTF(newbuf, sizeof(newbuf), "%s (|||%u|)\r\n",
@@ -1426,6 +1977,218 @@ int dlen;
"229 Entering Extended Passive Mode", ap);
#endif
- return ippr_ftp_pasvreply(fin, ip, nat, f, (u_int)ap, newbuf, s,
- ip->ip_src.s_addr);
+ return ipf_p_ftp_pasvreply(softf, fin, ip, nat, ftp, (u_int)ap,
+ newbuf, s);
+}
+
+#ifdef USE_INET6
+int
+ipf_p_ftp_eprt6(softf, fin, ip, nat, ftp, dlen)
+ ipf_ftp_softc_t *softf;
+ fr_info_t *fin;
+ ip_t *ip;
+ nat_t *nat;
+ ftpinfo_t *ftp;
+ int dlen;
+{
+ int port, olen, nlen, inc, off, left, i;
+ char newbuf[IPF_FTPBUFSZ];
+ char *s, c;
+ i6addr_t addr, *a6;
+ tcphdr_t *tcp;
+ ip6_t *ip6;
+ char delim;
+ u_short whole;
+ u_short part;
+ ftpside_t *f;
+ u_short *t;
+ int fwd;
+ mb_t *m;
+ u_32_t a;
+
+ m = fin->fin_m;
+ ip6 = (ip6_t *)ip;
+ f = &ftp->ftp_side[0];
+ s = f->ftps_rptr + 8;
+ f = &ftp->ftp_side[0];
+ delim = f->ftps_rptr[5];
+ tcp = (tcphdr_t *)fin->fin_dp;
+ off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
+
+ addr.i6[0] = 0;
+ addr.i6[1] = 0;
+ addr.i6[2] = 0;
+ addr.i6[3] = 0;
+ /*
+ * Parse an IPv6 address.
+ * Go forward until either :: or | is found. If :: is found,
+ * reverse direction. Direction change is performed to ease
+ * parsing an unknown number of 0s in the middle.
+ */
+ whole = 0;
+ t = (u_short *)&addr;
+ fwd = 1;
+ for (part = 0; (c = *s) != '\0'; ) {
+ if (c == delim) {
+ *t = htons((u_short)whole);
+ break;
+ }
+ if (c == ':') {
+ *t = part;
+ if (fwd) {
+ *t = htons((u_short)whole);
+ t++;
+ } else {
+ *t = htons((u_short)(whole >> 16));
+ t--;
+ }
+ whole = 0;
+ if (fwd == 1 && s[1] == ':') {
+ while (*s && *s != '|')
+ s++;
+ if ((c = *s) != delim)
+ break;
+ t = (u_short *)&addr.i6[3];
+ t++;
+ fwd = 0;
+ } else if (fwd == 0 && s[-1] == ':') {
+ break;
+ }
+ } else {
+ if (c >= '0' && c <= '9') {
+ c -= '0';
+ } else if (c >= 'a' && c <= 'f') {
+ c -= 'a' + 10;
+ } else if (c >= 'A' && c <= 'F') {
+ c -= 'A' + 10;
+ }
+ if (fwd) {
+ whole <<= 8;
+ whole |= c;
+ } else {
+ whole >>= 8;
+ whole |= ((u_32_t)c) << 24;
+ }
+ }
+ if (fwd)
+ s++;
+ else
+ s--;
+ }
+ if (c != ':' && c != delim)
+ return 0;
+
+ while (*s != '|')
+ s++;
+ s++;
+
+ /*
+ * Get the port number
+ */
+ i = 0;
+ while (((c = *s++) != '\0') && ISDIGIT(c)) {
+ i *= 10;
+ i += c - '0';
+ }
+ if (i > 65535)
+ return 0;
+ if (c != delim)
+ return 0;
+ port = (u_short)(i & 0xffff);
+
+ /*
+ * Check for CR-LF at the end of the command string.
+ */
+ if ((*s != '\r') || (*(s + 1) != '\n')) {
+ DT(eprt6_no_crlf);
+ if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR)
+ printf("ipf_p_ftp_eprt6:missing %s\n", "cr-lf");
+ return 0;
+ }
+ s += 2;
+
+ /*
+ * Calculate new address parts for PORT command
+ */
+ a6 = (i6addr_t *)&ip6->ip6_src;
+ olen = s - f->ftps_rptr;
+ /* DO NOT change this to snprintf! */
+ /*
+ * While we could force the use of | as a delimiter here, it makes
+ * sense to preserve whatever character is being used by the systems
+ * involved in the communication.
+ */
+ s = newbuf;
+ left = sizeof(newbuf);
+#if defined(SNPRINTF) && defined(_KERNEL)
+ SNPRINTF(newbuf, left, "EPRT %c2%c", delim, delim);
+ left -= strlen(s) + 1;
+ s += strlen(s);
+ a = ntohl(a6->i6[0]);
+ SNPRINTF(s, left, "%x:%x:", a >> 16, a & 0xffff);
+ left -= strlen(s);
+ s += strlen(s);
+ a = ntohl(a6->i6[1]);
+ SNPRINTF(s, left, "%x:%x:", a >> 16, a & 0xffff);
+ left -= strlen(s);
+ s += strlen(s);
+ a = ntohl(a6->i6[2]);
+ SNPRINTF(s, left, "%x:%x:", a >> 16, a & 0xffff);
+ left -= strlen(s);
+ s += strlen(s);
+ a = ntohl(a6->i6[3]);
+ SNPRINTF(s, left, "%x:%x", a >> 16, a & 0xffff);
+ left -= strlen(s);
+ s += strlen(s);
+ sprintf(s, "|%d|\r\n", port);
+#else
+ (void) sprintf(s, "EPRT %c2%c", delim, delim);
+ s += strlen(s);
+ a = ntohl(a6->i6[0]);
+ sprintf(s, "%x:%x:", a >> 16, a & 0xffff);
+ s += strlen(s);
+ a = ntohl(a6->i6[1]);
+ sprintf(s, "%x:%x:", a >> 16, a & 0xffff);
+ left -= strlen(s);
+ s += strlen(s);
+ a = ntohl(a6->i6[2]);
+ sprintf(s, "%x:%x:", a >> 16, a & 0xffff);
+ left -= strlen(s);
+ s += strlen(s);
+ a = ntohl(a6->i6[3]);
+ sprintf(s, "%x:%x", a >> 16, a & 0xffff);
+ left -= strlen(s);
+ s += strlen(s);
+ sprintf(s, "|%d|\r\n", port);
+#endif
+ nlen = strlen(newbuf);
+ inc = nlen - olen;
+ if ((inc + fin->fin_plen) > 65535) {
+ DT2(eprt6_len, int, inc, int, fin->fin_plen);
+ if (softf->ipf_p_ftp_debug & DEBUG_ERROR)
+ printf("ipf_p_ftp_eprt6:inc(%d) + ip->ip_len > 65535\n",
+ inc);
+ return 0;
+ }
+
+ off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
+#if !defined(_KERNEL)
+ M_ADJ(m, inc);
+#else
+ if (inc < 0)
+ M_ADJ(m, inc);
+#endif
+ /* the mbuf chain will be extended if necessary by m_copyback() */
+ COPYBACK(m, off, nlen, newbuf);
+ fin->fin_flx |= FI_DOCKSUM;
+
+ if (inc != 0) {
+ fin->fin_plen += inc;
+ ip6->ip6_plen = htons(fin->fin_plen - fin->fin_hlen);
+ fin->fin_dlen += inc;
+ }
+
+ f->ftps_cmd = FTPXY_C_EPRT;
+ return ipf_p_ftp_addport(softf, fin, ip, nat, ftp, dlen, port, inc);
}
+#endif
diff --git a/sys/contrib/ipfilter/netinet/ip_htable.c b/sys/contrib/ipfilter/netinet/ip_htable.c
index fc521d8..62707f4 100644
--- a/sys/contrib/ipfilter/netinet/ip_htable.c
+++ b/sys/contrib/ipfilter/netinet/ip_htable.c
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1993-2001, 2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*/
@@ -41,7 +41,7 @@ struct file;
#if defined(_KERNEL)
# include <sys/systm.h>
#else
-# include <stdio.h>
+# include "ipf.h"
#endif
#include <netinet/in.h>
#include <net/if.h>
@@ -53,82 +53,277 @@ struct file;
/* END OF INCLUDES */
#if !defined(lint)
-static const char rcsid[] = "@(#)$Id: ip_htable.c,v 2.34.2.11 2007/09/20 12:51:51 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id$";
#endif
-#ifdef IPFILTER_LOOKUP
-static iphtent_t *fr_iphmfind __P((iphtable_t *, struct in_addr *));
-static u_long ipht_nomem[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-static u_long ipf_nhtables[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-static u_long ipf_nhtnodes[IPL_LOGSIZE] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+# ifdef USE_INET6
+static iphtent_t *ipf_iphmfind6 __P((iphtable_t *, i6addr_t *));
+# endif
+static iphtent_t *ipf_iphmfind __P((iphtable_t *, struct in_addr *));
+static int ipf_iphmfindip __P((ipf_main_softc_t *, void *, int, void *, u_int));
+static int ipf_htable_clear __P((ipf_main_softc_t *, void *, iphtable_t *));
+static int ipf_htable_create __P((ipf_main_softc_t *, void *, iplookupop_t *));
+static int ipf_htable_deref __P((ipf_main_softc_t *, void *, void *));
+static int ipf_htable_destroy __P((ipf_main_softc_t *, void *, int, char *));
+static void *ipf_htable_exists __P((void *, int, char *));
+static size_t ipf_htable_flush __P((ipf_main_softc_t *, void *,
+ iplookupflush_t *));
+static void ipf_htable_free __P((void *, iphtable_t *));
+static int ipf_htable_iter_deref __P((ipf_main_softc_t *, void *, int,
+ int, void *));
+static int ipf_htable_iter_next __P((ipf_main_softc_t *, void *, ipftoken_t *,
+ ipflookupiter_t *));
+static int ipf_htable_node_add __P((ipf_main_softc_t *, void *,
+ iplookupop_t *, int));
+static int ipf_htable_node_del __P((ipf_main_softc_t *, void *,
+ iplookupop_t *, int));
+static int ipf_htable_remove __P((ipf_main_softc_t *, void *, iphtable_t *));
+static void *ipf_htable_soft_create __P((ipf_main_softc_t *));
+static void ipf_htable_soft_destroy __P((ipf_main_softc_t *, void *));
+static int ipf_htable_soft_init __P((ipf_main_softc_t *, void *));
+static void ipf_htable_soft_fini __P((ipf_main_softc_t *, void *));
+static int ipf_htable_stats_get __P((ipf_main_softc_t *, void *,
+ iplookupop_t *));
+static int ipf_htable_table_add __P((ipf_main_softc_t *, void *,
+ iplookupop_t *));
+static int ipf_htable_table_del __P((ipf_main_softc_t *, void *,
+ iplookupop_t *));
+static int ipf_htent_deref __P((void *, iphtent_t *));
+static iphtent_t *ipf_htent_find __P((iphtable_t *, iphtent_t *));
+static int ipf_htent_insert __P((ipf_main_softc_t *, void *, iphtable_t *,
+ iphtent_t *));
+static int ipf_htent_remove __P((ipf_main_softc_t *, void *, iphtable_t *,
+ iphtent_t *));
+static void *ipf_htable_select_add_ref __P((void *, int, char *));
+static void ipf_htable_expire __P((ipf_main_softc_t *, void *));
+
+
+typedef struct ipf_htable_softc_s {
+ u_long ipht_nomem[LOOKUP_POOL_SZ];
+ u_long ipf_nhtables[LOOKUP_POOL_SZ];
+ u_long ipf_nhtnodes[LOOKUP_POOL_SZ];
+ iphtable_t *ipf_htables[LOOKUP_POOL_SZ];
+ iphtent_t *ipf_node_explist;
+} ipf_htable_softc_t;
+
+ipf_lookup_t ipf_htable_backend = {
+ IPLT_HASH,
+ ipf_htable_soft_create,
+ ipf_htable_soft_destroy,
+ ipf_htable_soft_init,
+ ipf_htable_soft_fini,
+ ipf_iphmfindip,
+ ipf_htable_flush,
+ ipf_htable_iter_deref,
+ ipf_htable_iter_next,
+ ipf_htable_node_add,
+ ipf_htable_node_del,
+ ipf_htable_stats_get,
+ ipf_htable_table_add,
+ ipf_htable_table_del,
+ ipf_htable_deref,
+ ipf_htable_exists,
+ ipf_htable_select_add_ref,
+ NULL,
+ ipf_htable_expire,
+ NULL
+};
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_soft_create */
+/* Returns: void * - NULL = failure, else pointer to local context */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Initialise the routing table data structures where required. */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_htable_soft_create(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_htable_softc_t *softh;
+
+ KMALLOC(softh, ipf_htable_softc_t *);
+ if (softh == NULL) {
+ IPFERROR(30026);
+ return NULL;
+ }
+
+ bzero((char *)softh, sizeof(*softh));
+
+ return softh;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_soft_destroy */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* Clean up the pool by free'ing the radix tree associated with it and free */
+/* up the pool context too. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_htable_soft_destroy(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_htable_softc_t *softh = arg;
+
+ KFREE(softh);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_soft_init */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* Initialise the hash table ready for use. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_soft_init(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_htable_softc_t *softh = arg;
-iphtable_t *ipf_htables[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL };
+ bzero((char *)softh, sizeof(*softh));
+ return 0;
+}
-void fr_htable_unload()
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_soft_fini */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* Locks: WRITE(ipf_global) */
+/* */
+/* Clean up all the pool data structures allocated and call the cleanup */
+/* function for the radix tree that supports the pools. ipf_pool_destroy is */
+/* used to delete the pools one by one to ensure they're properly freed up. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_htable_soft_fini(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
{
iplookupflush_t fop;
+ fop.iplf_type = IPLT_HASH;
fop.iplf_unit = IPL_LOGALL;
- (void)fr_flushhtable(&fop);
+ fop.iplf_arg = 0;
+ fop.iplf_count = 0;
+ *fop.iplf_name = '\0';
+ ipf_htable_flush(softc, arg, &fop);
}
-int fr_gethtablestat(op)
-iplookupop_t *op;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_stats_get */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* */
+/* Copy the relevant statistics out of internal structures and into the */
+/* structure used to export statistics. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_stats_get(softc, arg, op)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
{
+ ipf_htable_softc_t *softh = arg;
iphtstat_t stats;
+ int err;
- if (op->iplo_size != sizeof(stats))
+ if (op->iplo_size != sizeof(stats)) {
+ IPFERROR(30001);
return EINVAL;
+ }
- stats.iphs_tables = ipf_htables[op->iplo_unit];
- stats.iphs_numtables = ipf_nhtables[op->iplo_unit];
- stats.iphs_numnodes = ipf_nhtnodes[op->iplo_unit];
- stats.iphs_nomem = ipht_nomem[op->iplo_unit];
+ stats.iphs_tables = softh->ipf_htables[op->iplo_unit + 1];
+ stats.iphs_numtables = softh->ipf_nhtables[op->iplo_unit + 1];
+ stats.iphs_numnodes = softh->ipf_nhtnodes[op->iplo_unit + 1];
+ stats.iphs_nomem = softh->ipht_nomem[op->iplo_unit + 1];
- return COPYOUT(&stats, op->iplo_struct, sizeof(stats));
+ err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
+ if (err != 0) {
+ IPFERROR(30013);
+ return EFAULT;
+ }
+ return 0;
}
-/*
- * Create a new hash table using the template passed.
- */
-int fr_newhtable(op)
-iplookupop_t *op;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_create */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* */
+/* Create a new hash table using the template passed. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_create(softc, arg, op)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
{
- iphtable_t *iph, *oiph;
+ ipf_htable_softc_t *softh = arg;
+ iphtable_t htab, *iph, *oiph;
char name[FR_GROUPLEN];
int err, i, unit;
+ if (op->iplo_size != sizeof(htab)) {
+ IPFERROR(30024);
+ return EINVAL;
+ }
+ err = COPYIN(op->iplo_struct, &htab, sizeof(htab));
+ if (err != 0) {
+ IPFERROR(30003);
+ return EFAULT;
+ }
+
unit = op->iplo_unit;
+ if (htab.iph_unit != unit) {
+ IPFERROR(30005);
+ return EINVAL;
+ }
+ if (htab.iph_size < 1) {
+ IPFERROR(30025);
+ return EINVAL;
+ }
+
+
if ((op->iplo_arg & IPHASH_ANON) == 0) {
- iph = fr_existshtable(unit, op->iplo_name);
+ iph = ipf_htable_exists(softh, unit, op->iplo_name);
if (iph != NULL) {
- if ((iph->iph_flags & IPHASH_DELETE) == 0)
+ if ((iph->iph_flags & IPHASH_DELETE) == 0) {
+ IPFERROR(30004);
return EEXIST;
+ }
iph->iph_flags &= ~IPHASH_DELETE;
+ iph->iph_ref++;
return 0;
}
}
KMALLOC(iph, iphtable_t *);
if (iph == NULL) {
- ipht_nomem[op->iplo_unit]++;
+ softh->ipht_nomem[op->iplo_unit + 1]++;
+ IPFERROR(30002);
return ENOMEM;
}
- err = COPYIN(op->iplo_struct, iph, sizeof(*iph));
- if (err != 0) {
- KFREE(iph);
- return EFAULT;
- }
-
- if (iph->iph_unit != unit) {
- KFREE(iph);
- return EINVAL;
- }
+ *iph = htab;
if ((op->iplo_arg & IPHASH_ANON) != 0) {
i = IPHASH_ANON;
@@ -139,7 +334,7 @@ iplookupop_t *op;
#else
(void)sprintf(name, "%u", i);
#endif
- for (oiph = ipf_htables[unit]; oiph != NULL;
+ for (oiph = softh->ipf_htables[unit + 1]; oiph != NULL;
oiph = oiph->iph_next)
if (strncmp(oiph->iph_name, name,
sizeof(oiph->iph_name)) == 0)
@@ -149,113 +344,316 @@ iplookupop_t *op;
(void)strncpy(iph->iph_name, name, sizeof(iph->iph_name));
(void)strncpy(op->iplo_name, name, sizeof(op->iplo_name));
iph->iph_type |= IPHASH_ANON;
+ } else {
+ (void)strncpy(iph->iph_name, op->iplo_name,
+ sizeof(iph->iph_name));
+ iph->iph_name[sizeof(iph->iph_name) - 1] = '\0';
}
KMALLOCS(iph->iph_table, iphtent_t **,
iph->iph_size * sizeof(*iph->iph_table));
if (iph->iph_table == NULL) {
KFREE(iph);
- ipht_nomem[unit]++;
+ softh->ipht_nomem[unit + 1]++;
+ IPFERROR(30006);
return ENOMEM;
}
bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
- iph->iph_masks = 0;
- iph->iph_list = NULL;
+ iph->iph_maskset[0] = 0;
+ iph->iph_maskset[1] = 0;
+ iph->iph_maskset[2] = 0;
+ iph->iph_maskset[3] = 0;
iph->iph_ref = 1;
- iph->iph_next = ipf_htables[unit];
- iph->iph_pnext = &ipf_htables[unit];
- if (ipf_htables[unit] != NULL)
- ipf_htables[unit]->iph_pnext = &iph->iph_next;
- ipf_htables[unit] = iph;
- ipf_nhtables[unit]++;
+ iph->iph_list = NULL;
+ iph->iph_tail = &iph->iph_list;
+ iph->iph_next = softh->ipf_htables[unit + 1];
+ iph->iph_pnext = &softh->ipf_htables[unit + 1];
+ if (softh->ipf_htables[unit + 1] != NULL)
+ softh->ipf_htables[unit + 1]->iph_pnext = &iph->iph_next;
+ softh->ipf_htables[unit + 1] = iph;
+
+ softh->ipf_nhtables[unit + 1]++;
return 0;
}
-/*
- */
-int fr_removehtable(unit, name)
-int unit;
-char *name;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_table_del */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_table_del(softc, arg, op)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
+{
+ return ipf_htable_destroy(softc, arg, op->iplo_unit, op->iplo_name);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_destroy */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* */
+/* Find the hash table that belongs to the relevant part of ipfilter with a */
+/* matching name and attempt to destroy it. If it is in use, empty it out */
+/* and mark it for deletion so that when all the references disappear, it */
+/* can be removed. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_destroy(softc, arg, unit, name)
+ ipf_main_softc_t *softc;
+ void *arg;
+ int unit;
+ char *name;
{
iphtable_t *iph;
- iph = fr_findhtable(unit, name);
- if (iph == NULL)
+ iph = ipf_htable_find(arg, unit, name);
+ if (iph == NULL) {
+ IPFERROR(30007);
return ESRCH;
+ }
if (iph->iph_unit != unit) {
+ IPFERROR(30008);
return EINVAL;
}
if (iph->iph_ref != 0) {
- (void) fr_clearhtable(iph);
+ ipf_htable_clear(softc, arg, iph);
iph->iph_flags |= IPHASH_DELETE;
return 0;
}
- fr_delhtable(iph);
+ ipf_htable_remove(softc, arg, iph);
return 0;
}
-int fr_clearhtable(iph)
-iphtable_t *iph;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_clear */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* iph(I) - pointer to hash table to destroy */
+/* */
+/* Clean out the hash table by walking the list of entries and removing */
+/* each one, one by one. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_clear(softc, arg, iph)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iphtable_t *iph;
{
iphtent_t *ipe;
while ((ipe = iph->iph_list) != NULL)
- if (fr_delhtent(iph, ipe) != 0)
+ if (ipf_htent_remove(softc, arg, iph, ipe) != 0)
return 1;
return 0;
}
-int fr_delhtable(iph)
-iphtable_t *iph;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_free */
+/* Returns: Nil */
+/* Parameters: arg(I) - pointer to local context to use */
+/* iph(I) - pointer to hash table to destroy */
+/* */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_htable_free(arg, iph)
+ void *arg;
+ iphtable_t *iph;
+{
+ ipf_htable_softc_t *softh = arg;
+
+ if (iph->iph_next != NULL)
+ iph->iph_next->iph_pnext = iph->iph_pnext;
+ if (iph->iph_pnext != NULL)
+ *iph->iph_pnext = iph->iph_next;
+ iph->iph_pnext = NULL;
+ iph->iph_next = NULL;
+
+ softh->ipf_nhtables[iph->iph_unit + 1]--;
+
+ KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
+ KFREE(iph);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_remove */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* iph(I) - pointer to hash table to destroy */
+/* */
+/* It is necessary to unlink here as well as free (called by deref) so that */
+/* the while loop in ipf_htable_flush() functions properly. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_remove(softc, arg, iph)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iphtable_t *iph;
{
- if (fr_clearhtable(iph) != 0)
+ if (ipf_htable_clear(softc, arg, iph) != 0)
return 1;
if (iph->iph_pnext != NULL)
*iph->iph_pnext = iph->iph_next;
if (iph->iph_next != NULL)
iph->iph_next->iph_pnext = iph->iph_pnext;
+ iph->iph_pnext = NULL;
+ iph->iph_next = NULL;
+
+ return ipf_htable_deref(softc, arg, iph);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_node_del */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* uid(I) - real uid of process doing operation */
+/* */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_node_del(softc, arg, op, uid)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
+ int uid;
+{
+ iphtable_t *iph;
+ iphtent_t hte, *ent;
+ int err;
+
+ if (op->iplo_size != sizeof(hte)) {
+ IPFERROR(30014);
+ return EINVAL;
+ }
+
+ err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
+ if (err != 0) {
+ IPFERROR(30015);
+ return EFAULT;
+ }
+
+ iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
+ if (iph == NULL) {
+ IPFERROR(30016);
+ return ESRCH;
+ }
+
+ ent = ipf_htent_find(iph, &hte);
+ if (ent == NULL) {
+ IPFERROR(30022);
+ return ESRCH;
+ }
+
+ if ((uid != 0) && (ent->ipe_uid != uid)) {
+ IPFERROR(30023);
+ return EACCES;
+ }
- ipf_nhtables[iph->iph_unit]--;
+ err = ipf_htent_remove(softc, arg, iph, ent);
- return fr_derefhtable(iph);
+ return err;
}
-/*
- * Delete an entry from a hash table.
- */
-int fr_delhtent(iph, ipe)
-iphtable_t *iph;
-iphtent_t *ipe;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_node_del */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_table_add(softc, arg, op)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
{
+ int err;
+
+ if (ipf_htable_find(arg, op->iplo_unit, op->iplo_name) != NULL) {
+ IPFERROR(30017);
+ err = EEXIST;
+ } else {
+ err = ipf_htable_create(softc, arg, op);
+ }
+
+ return err;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htent_remove */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* iph(I) - pointer to hash table */
+/* ipe(I) - pointer to hash table entry to remove */
+/* */
+/* Delete an entry from a hash table. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htent_remove(softc, arg, iph, ipe)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iphtable_t *iph;
+ iphtent_t *ipe;
+{
+
+ if (iph->iph_tail == &ipe->ipe_next)
+ iph->iph_tail = ipe->ipe_pnext;
- if (ipe->ipe_phnext != NULL)
- *ipe->ipe_phnext = ipe->ipe_hnext;
if (ipe->ipe_hnext != NULL)
ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext;
+ if (ipe->ipe_phnext != NULL)
+ *ipe->ipe_phnext = ipe->ipe_hnext;
+ ipe->ipe_phnext = NULL;
+ ipe->ipe_hnext = NULL;
+
+ if (ipe->ipe_dnext != NULL)
+ ipe->ipe_dnext->ipe_pdnext = ipe->ipe_pdnext;
+ if (ipe->ipe_pdnext != NULL)
+ *ipe->ipe_pdnext = ipe->ipe_dnext;
+ ipe->ipe_pdnext = NULL;
+ ipe->ipe_dnext = NULL;
- if (ipe->ipe_pnext != NULL)
- *ipe->ipe_pnext = ipe->ipe_next;
if (ipe->ipe_next != NULL)
ipe->ipe_next->ipe_pnext = ipe->ipe_pnext;
+ if (ipe->ipe_pnext != NULL)
+ *ipe->ipe_pnext = ipe->ipe_next;
+ ipe->ipe_pnext = NULL;
+ ipe->ipe_next = NULL;
switch (iph->iph_type & ~IPHASH_ANON)
{
case IPHASH_GROUPMAP :
if (ipe->ipe_group != NULL)
- fr_delgroup(ipe->ipe_group, IPL_LOGIPF, fr_active);
+ ipf_group_del(softc, ipe->ipe_ptr, NULL);
break;
default :
@@ -264,35 +662,54 @@ iphtent_t *ipe;
break;
}
- return fr_derefhtent(ipe);
+ return ipf_htent_deref(arg, ipe);
}
-int fr_derefhtable(iph)
-iphtable_t *iph;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_deref */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* object(I) - pointer to hash table */
+/* */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_deref(softc, arg, object)
+ ipf_main_softc_t *softc;
+ void *arg, *object;
{
+ ipf_htable_softc_t *softh = arg;
+ iphtable_t *iph = object;
int refs;
iph->iph_ref--;
refs = iph->iph_ref;
if (iph->iph_ref == 0) {
- KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table));
- KFREE(iph);
+ ipf_htable_free(softh, iph);
}
return refs;
}
-int fr_derefhtent(ipe)
-iphtent_t *ipe;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htent_deref */
+/* Parameters: arg(I) - pointer to local context to use */
+/* ipe(I) - */
+/* */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htent_deref(arg, ipe)
+ void *arg;
+ iphtent_t *ipe;
{
+ ipf_htable_softc_t *softh = arg;
ipe->ipe_ref--;
if (ipe->ipe_ref == 0) {
- ipf_nhtnodes[ipe->ipe_unit]--;
-
+ softh->ipf_nhtnodes[ipe->ipe_unit + 1]--;
KFREE(ipe);
return 0;
@@ -302,26 +719,87 @@ iphtent_t *ipe;
}
-iphtable_t *fr_existshtable(unit, name)
-int unit;
-char *name;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_exists */
+/* Parameters: arg(I) - pointer to local context to use */
+/* */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_htable_exists(arg, unit, name)
+ void *arg;
+ int unit;
+ char *name;
{
+ ipf_htable_softc_t *softh = arg;
iphtable_t *iph;
- for (iph = ipf_htables[unit]; iph != NULL; iph = iph->iph_next)
- if (strncmp(iph->iph_name, name, sizeof(iph->iph_name)) == 0)
- break;
+ if (unit == IPL_LOGALL) {
+ int i;
+
+ for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
+ for (iph = softh->ipf_htables[i]; iph != NULL;
+ iph = iph->iph_next) {
+ if (strncmp(iph->iph_name, name,
+ sizeof(iph->iph_name)) == 0)
+ break;
+ }
+ if (iph != NULL)
+ break;
+ }
+ } else {
+ for (iph = softh->ipf_htables[unit + 1]; iph != NULL;
+ iph = iph->iph_next) {
+ if (strncmp(iph->iph_name, name,
+ sizeof(iph->iph_name)) == 0)
+ break;
+ }
+ }
+ return iph;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_select_add_ref */
+/* Returns: void * - NULL = failure, else pointer to the hash table */
+/* Parameters: arg(I) - pointer to local context to use */
+/* unit(I) - ipfilter device to which we are working on */
+/* name(I) - name of the hash table */
+/* */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_htable_select_add_ref(arg, unit, name)
+ void *arg;
+ int unit;
+ char *name;
+{
+ iphtable_t *iph;
+
+ iph = ipf_htable_exists(arg, unit, name);
+ if (iph != NULL) {
+ ATOMIC_INC32(iph->iph_ref);
+ }
return iph;
}
-iphtable_t *fr_findhtable(unit, name)
-int unit;
-char *name;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_find */
+/* Returns: void * - NULL = failure, else pointer to the hash table */
+/* Parameters: arg(I) - pointer to local context to use */
+/* unit(I) - ipfilter device to which we are working on */
+/* name(I) - name of the hash table */
+/* */
+/* This function is exposed becaues it is used in the group-map feature. */
+/* ------------------------------------------------------------------------ */
+iphtable_t *
+ipf_htable_find(arg, unit, name)
+ void *arg;
+ int unit;
+ char *name;
{
iphtable_t *iph;
- iph = fr_existshtable(unit, name);
+ iph = ipf_htable_exists(arg, unit, name);
if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0)
return iph;
@@ -329,19 +807,31 @@ char *name;
}
-size_t fr_flushhtable(op)
-iplookupflush_t *op;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_flush */
+/* Returns: size_t - number of entries flushed */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* */
+/* ------------------------------------------------------------------------ */
+static size_t
+ipf_htable_flush(softc, arg, op)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupflush_t *op;
{
+ ipf_htable_softc_t *softh = arg;
iphtable_t *iph;
size_t freed;
int i;
freed = 0;
- for (i = 0; i <= IPL_LOGMAX; i++) {
+ for (i = -1; i <= IPL_LOGMAX; i++) {
if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) {
- while ((iph = ipf_htables[i]) != NULL) {
- if (fr_delhtable(iph) == 0) {
+ while ((iph = softh->ipf_htables[i + 1]) != NULL) {
+ if (ipf_htable_remove(softc, arg, iph) == 0) {
freed++;
} else {
iph->iph_flags |= IPHASH_DELETE;
@@ -354,13 +844,73 @@ iplookupflush_t *op;
}
-/*
- * Add an entry to a hash table.
- */
-int fr_addhtent(iph, ipeo)
-iphtable_t *iph;
-iphtent_t *ipeo;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_node_add */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* uid(I) - real uid of process doing operation */
+/* */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_node_add(softc, arg, op, uid)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
+ int uid;
+{
+ iphtable_t *iph;
+ iphtent_t hte;
+ int err;
+
+ if (op->iplo_size != sizeof(hte)) {
+ IPFERROR(30018);
+ return EINVAL;
+ }
+
+ err = COPYIN(op->iplo_struct, &hte, sizeof(hte));
+ if (err != 0) {
+ IPFERROR(30019);
+ return EFAULT;
+ }
+ hte.ipe_uid = uid;
+
+ iph = ipf_htable_find(arg, op->iplo_unit, op->iplo_name);
+ if (iph == NULL) {
+ IPFERROR(30020);
+ return ESRCH;
+ }
+
+ if (ipf_htent_find(iph, &hte) != NULL) {
+ IPFERROR(30021);
+ return EEXIST;
+ }
+
+ err = ipf_htent_insert(softc, arg, iph, &hte);
+
+ return err;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htent_insert */
+/* Returns: int - 0 = success, -1 = error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operation data */
+/* ipeo(I) - */
+/* */
+/* Add an entry to a hash table. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htent_insert(softc, arg, iph, ipeo)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iphtable_t *iph;
+ iphtent_t *ipeo;
{
+ ipf_htable_softc_t *softh = arg;
iphtent_t *ipe;
u_int hv;
int bits;
@@ -370,13 +920,35 @@ iphtent_t *ipeo;
return -1;
bcopy((char *)ipeo, (char *)ipe, sizeof(*ipe));
- ipe->ipe_addr.in4_addr &= ipe->ipe_mask.in4_addr;
- ipe->ipe_addr.in4_addr = ntohl(ipe->ipe_addr.in4_addr);
- bits = count4bits(ipe->ipe_mask.in4_addr);
- ipe->ipe_mask.in4_addr = ntohl(ipe->ipe_mask.in4_addr);
+ ipe->ipe_addr.i6[0] &= ipe->ipe_mask.i6[0];
+ if (ipe->ipe_family == AF_INET) {
+ bits = count4bits(ipe->ipe_mask.in4_addr);
+ ipe->ipe_addr.i6[1] = 0;
+ ipe->ipe_addr.i6[2] = 0;
+ ipe->ipe_addr.i6[3] = 0;
+ ipe->ipe_mask.i6[1] = 0;
+ ipe->ipe_mask.i6[2] = 0;
+ ipe->ipe_mask.i6[3] = 0;
+ hv = IPE_V4_HASH_FN(ipe->ipe_addr.in4_addr,
+ ipe->ipe_mask.in4_addr, iph->iph_size);
+ } else
+#ifdef USE_INET6
+ if (ipe->ipe_family == AF_INET6) {
+ ipe->ipe_addr.i6[1] &= ipe->ipe_mask.i6[1];
+ ipe->ipe_addr.i6[2] &= ipe->ipe_mask.i6[2];
+ ipe->ipe_addr.i6[3] &= ipe->ipe_mask.i6[3];
+
+ bits = count6bits(ipe->ipe_mask.i6);
+ hv = IPE_V6_HASH_FN(ipe->ipe_addr.i6,
+ ipe->ipe_mask.i6, iph->iph_size);
+ } else
+#endif
+ {
+ KFREE(ipe);
+ return -1;
+ }
- hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr,
- iph->iph_size);
+ ipe->ipe_owner = iph;
ipe->ipe_ref = 1;
ipe->ipe_hnext = iph->iph_table[hv];
ipe->ipe_phnext = iph->iph_table + hv;
@@ -385,21 +957,63 @@ iphtent_t *ipeo;
iph->iph_table[hv]->ipe_phnext = &ipe->ipe_hnext;
iph->iph_table[hv] = ipe;
- ipe->ipe_next = iph->iph_list;
- ipe->ipe_pnext = &iph->iph_list;
- if (ipe->ipe_next != NULL)
- ipe->ipe_next->ipe_pnext = &ipe->ipe_next;
- iph->iph_list = ipe;
+ ipe->ipe_pnext = iph->iph_tail;
+ *iph->iph_tail = ipe;
+ iph->iph_tail = &ipe->ipe_next;
+ ipe->ipe_next = NULL;
+
+ if (ipe->ipe_die != 0) {
+ /*
+ * If the new node has a given expiration time, insert it
+ * into the list of expiring nodes with the ones to be
+ * removed first added to the front of the list. The
+ * insertion is O(n) but it is kept sorted for quick scans
+ * at expiration interval checks.
+ */
+ iphtent_t *n;
+
+ ipe->ipe_die = softc->ipf_ticks + IPF_TTLVAL(ipe->ipe_die);
+ for (n = softh->ipf_node_explist; n != NULL; n = n->ipe_dnext) {
+ if (ipe->ipe_die < n->ipe_die)
+ break;
+ if (n->ipe_dnext == NULL) {
+ /*
+ * We've got to the last node and everything
+ * wanted to be expired before this new node,
+ * so we have to tack it on the end...
+ */
+ n->ipe_dnext = ipe;
+ ipe->ipe_pdnext = &n->ipe_dnext;
+ n = NULL;
+ break;
+ }
+ }
- if ((bits >= 0) && (bits != 32))
- iph->iph_masks |= 1 << bits;
+ if (softh->ipf_node_explist == NULL) {
+ softh->ipf_node_explist = ipe;
+ ipe->ipe_pdnext = &softh->ipf_node_explist;
+ } else if (n != NULL) {
+ ipe->ipe_dnext = n;
+ ipe->ipe_pdnext = n->ipe_pdnext;
+ n->ipe_pdnext = &ipe->ipe_dnext;
+ }
+ }
+
+ if (ipe->ipe_family == AF_INET) {
+ ipf_inet_mask_add(bits, &iph->iph_v4_masks);
+ }
+#ifdef USE_INET6
+ else if (ipe->ipe_family == AF_INET6) {
+ ipf_inet6_mask_add(bits, &ipe->ipe_mask, &iph->iph_v6_masks);
+ }
+#endif
switch (iph->iph_type & ~IPHASH_ANON)
{
case IPHASH_GROUPMAP :
- ipe->ipe_ptr = fr_addgroup(ipe->ipe_group, NULL,
+ ipe->ipe_ptr = ipf_group_add(softc, ipe->ipe_group, NULL,
iph->iph_flags, IPL_LOGIPF,
- fr_active);
+ softc->ipf_active);
break;
default :
@@ -409,116 +1023,218 @@ iphtent_t *ipeo;
}
ipe->ipe_unit = iph->iph_unit;
- ipf_nhtnodes[ipe->ipe_unit]++;
+ softh->ipf_nhtnodes[ipe->ipe_unit + 1]++;
return 0;
}
-void *fr_iphmfindgroup(tptr, aptr)
-void *tptr, *aptr;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htent_find */
+/* Returns: int - 0 = success, else error */
+/* Parameters: iph(I) - pointer to table to search */
+/* ipeo(I) - pointer to entry to find */
+/* */
+/* While it isn't absolutely necessary to for the address and mask to be */
+/* passed in through an iphtent_t structure, one is always present when it */
+/* is time to call this function, so it is just more convenient. */
+/* ------------------------------------------------------------------------ */
+static iphtent_t *
+ipf_htent_find(iph, ipeo)
+ iphtable_t *iph;
+ iphtent_t *ipeo;
+{
+ iphtent_t ipe, *ent;
+ u_int hv;
+ int bits;
+
+ bcopy((char *)ipeo, (char *)&ipe, sizeof(ipe));
+ ipe.ipe_addr.i6[0] &= ipe.ipe_mask.i6[0];
+ ipe.ipe_addr.i6[1] &= ipe.ipe_mask.i6[1];
+ ipe.ipe_addr.i6[2] &= ipe.ipe_mask.i6[2];
+ ipe.ipe_addr.i6[3] &= ipe.ipe_mask.i6[3];
+ if (ipe.ipe_family == AF_INET) {
+ bits = count4bits(ipe.ipe_mask.in4_addr);
+ ipe.ipe_addr.i6[1] = 0;
+ ipe.ipe_addr.i6[2] = 0;
+ ipe.ipe_addr.i6[3] = 0;
+ ipe.ipe_mask.i6[1] = 0;
+ ipe.ipe_mask.i6[2] = 0;
+ ipe.ipe_mask.i6[3] = 0;
+ hv = IPE_V4_HASH_FN(ipe.ipe_addr.in4_addr,
+ ipe.ipe_mask.in4_addr, iph->iph_size);
+ } else
+#ifdef USE_INET6
+ if (ipe.ipe_family == AF_INET6) {
+ bits = count6bits(ipe.ipe_mask.i6);
+ hv = IPE_V6_HASH_FN(ipe.ipe_addr.i6,
+ ipe.ipe_mask.i6, iph->iph_size);
+ } else
+#endif
+ return NULL;
+
+ for (ent = iph->iph_table[hv]; ent != NULL; ent = ent->ipe_hnext) {
+ if (ent->ipe_family != ipe.ipe_family)
+ continue;
+ if (IP6_NEQ(&ipe.ipe_addr, &ent->ipe_addr))
+ continue;
+ if (IP6_NEQ(&ipe.ipe_mask, &ent->ipe_mask))
+ continue;
+ break;
+ }
+
+ return ent;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_iphmfindgroup */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* tptr(I) - */
+/* aptr(I) - */
+/* */
+/* Search a hash table for a matching entry and return the pointer stored */
+/* in it for use as the next group of rules to search. */
+/* */
+/* This function is exposed becaues it is used in the group-map feature. */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_iphmfindgroup(softc, tptr, aptr)
+ ipf_main_softc_t *softc;
+ void *tptr, *aptr;
{
struct in_addr *addr;
iphtable_t *iph;
iphtent_t *ipe;
void *rval;
- READ_ENTER(&ip_poolrw);
+ READ_ENTER(&softc->ipf_poolrw);
iph = tptr;
addr = aptr;
- ipe = fr_iphmfind(iph, addr);
+ ipe = ipf_iphmfind(iph, addr);
if (ipe != NULL)
rval = ipe->ipe_ptr;
else
rval = NULL;
- RWLOCK_EXIT(&ip_poolrw);
+ RWLOCK_EXIT(&softc->ipf_poolrw);
return rval;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_iphmfindip */
+/* Function: ipf_iphmfindip */
/* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
-/* Parameters: tptr(I) - pointer to the pool to search */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* tptr(I) - pointer to the pool to search */
/* ipversion(I) - IP protocol version (4 or 6) */
/* aptr(I) - pointer to address information */
+/* bytes(I) - packet length */
/* */
/* Search the hash table for a given address and return a search result. */
/* ------------------------------------------------------------------------ */
-int fr_iphmfindip(tptr, ipversion, aptr)
-void *tptr, *aptr;
-int ipversion;
+static int
+ipf_iphmfindip(softc, tptr, ipversion, aptr, bytes)
+ ipf_main_softc_t *softc;
+ void *tptr, *aptr;
+ int ipversion;
+ u_int bytes;
{
struct in_addr *addr;
iphtable_t *iph;
iphtent_t *ipe;
int rval;
- if (ipversion != 4)
- return -1;
-
if (tptr == NULL || aptr == NULL)
return -1;
iph = tptr;
addr = aptr;
- READ_ENTER(&ip_poolrw);
- ipe = fr_iphmfind(iph, addr);
- if (ipe != NULL)
+ READ_ENTER(&softc->ipf_poolrw);
+ if (ipversion == 4) {
+ ipe = ipf_iphmfind(iph, addr);
+#ifdef USE_INET6
+ } else if (ipversion == 6) {
+ ipe = ipf_iphmfind6(iph, (i6addr_t *)addr);
+#endif
+ } else {
+ ipe = NULL;
+ }
+
+ if (ipe != NULL) {
rval = 0;
- else
+ ipe->ipe_hits++;
+ ipe->ipe_bytes += bytes;
+ } else {
rval = 1;
- RWLOCK_EXIT(&ip_poolrw);
+ }
+ RWLOCK_EXIT(&softc->ipf_poolrw);
return rval;
}
-/* Locks: ip_poolrw */
-static iphtent_t *fr_iphmfind(iph, addr)
-iphtable_t *iph;
-struct in_addr *addr;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_iphmfindip */
+/* Parameters: iph(I) - pointer to hash table */
+/* addr(I) - pointer to IPv4 address */
+/* Locks: ipf_poolrw */
+/* */
+/* ------------------------------------------------------------------------ */
+static iphtent_t *
+ipf_iphmfind(iph, addr)
+ iphtable_t *iph;
+ struct in_addr *addr;
{
- u_32_t hmsk, msk, ips;
+ u_32_t msk, ips;
iphtent_t *ipe;
u_int hv;
+ int i;
- hmsk = iph->iph_masks;
- msk = 0xffffffff;
+ i = 0;
maskloop:
- ips = ntohl(addr->s_addr) & msk;
- hv = IPE_HASH_FN(ips, msk, iph->iph_size);
+ msk = iph->iph_v4_masks.imt4_active[i];
+ ips = addr->s_addr & msk;
+ hv = IPE_V4_HASH_FN(ips, msk, iph->iph_size);
for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_hnext) {
- if (ipe->ipe_mask.in4_addr != msk ||
- ipe->ipe_addr.in4_addr != ips) {
+ if ((ipe->ipe_family != AF_INET) ||
+ (ipe->ipe_mask.in4_addr != msk) ||
+ (ipe->ipe_addr.in4_addr != ips)) {
continue;
}
break;
}
- if ((ipe == NULL) && (hmsk != 0)) {
- while (hmsk != 0) {
- msk <<= 1;
- if (hmsk & 0x80000000)
- break;
- hmsk <<= 1;
- }
- if (hmsk != 0) {
- hmsk <<= 1;
+ if (ipe == NULL) {
+ i++;
+ if (i < iph->iph_v4_masks.imt4_max)
goto maskloop;
- }
}
return ipe;
}
-int fr_htable_getnext(token, ilp)
-ipftoken_t *token;
-ipflookupiter_t *ilp;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_iter_next */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* token(I) - */
+/* ilp(I) - */
+/* */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_iter_next(softc, arg, token, ilp)
+ ipf_main_softc_t *softc;
+ void *arg;
+ ipftoken_t *token;
+ ipflookupiter_t *ilp;
{
+ ipf_htable_softc_t *softh = arg;
iphtent_t *node, zn, *nextnode;
iphtable_t *iph, zp, *nextiph;
+ void *hnext;
int err;
err = 0;
@@ -527,14 +1243,14 @@ ipflookupiter_t *ilp;
nextiph = NULL;
nextnode = NULL;
- READ_ENTER(&ip_poolrw);
+ READ_ENTER(&softc->ipf_poolrw);
switch (ilp->ili_otype)
{
case IPFLOOKUPITER_LIST :
iph = token->ipt_data;
if (iph == NULL) {
- nextiph = ipf_htables[(int)ilp->ili_unit];
+ nextiph = softh->ipf_htables[(int)ilp->ili_unit + 1];
} else {
nextiph = iph->iph_next;
}
@@ -547,15 +1263,18 @@ ipflookupiter_t *ilp;
nextiph = &zp;
token->ipt_data = NULL;
}
+ hnext = nextiph->iph_next;
break;
case IPFLOOKUPITER_NODE :
node = token->ipt_data;
if (node == NULL) {
- iph = fr_findhtable(ilp->ili_unit, ilp->ili_name);
- if (iph == NULL)
+ iph = ipf_htable_find(arg, ilp->ili_unit,
+ ilp->ili_name);
+ if (iph == NULL) {
+ IPFERROR(30009);
err = ESRCH;
- else {
+ } else {
nextnode = iph->iph_list;
}
} else {
@@ -570,73 +1289,179 @@ ipflookupiter_t *ilp;
nextnode = &zn;
token->ipt_data = NULL;
}
+ hnext = nextnode->ipe_next;
break;
+
default :
+ IPFERROR(30010);
err = EINVAL;
+ hnext = NULL;
break;
}
- RWLOCK_EXIT(&ip_poolrw);
+ RWLOCK_EXIT(&softc->ipf_poolrw);
if (err != 0)
return err;
switch (ilp->ili_otype)
{
case IPFLOOKUPITER_LIST :
- if (iph != NULL) {
- WRITE_ENTER(&ip_poolrw);
- fr_derefhtable(iph);
- RWLOCK_EXIT(&ip_poolrw);
- }
err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph));
- if (err != 0)
+ if (err != 0) {
+ IPFERROR(30011);
err = EFAULT;
+ }
+ if (iph != NULL) {
+ WRITE_ENTER(&softc->ipf_poolrw);
+ ipf_htable_deref(softc, softh, iph);
+ RWLOCK_EXIT(&softc->ipf_poolrw);
+ }
break;
case IPFLOOKUPITER_NODE :
- if (node != NULL) {
- WRITE_ENTER(&ip_poolrw);
- fr_derefhtent(node);
- RWLOCK_EXIT(&ip_poolrw);
- }
err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
- if (err != 0)
+ if (err != 0) {
+ IPFERROR(30012);
err = EFAULT;
+ }
+ if (node != NULL) {
+ WRITE_ENTER(&softc->ipf_poolrw);
+ ipf_htent_deref(softc, node);
+ RWLOCK_EXIT(&softc->ipf_poolrw);
+ }
break;
}
+ if (hnext == NULL)
+ ipf_token_mark_complete(token);
+
return err;
}
-void fr_htable_iterderef(otype, unit, data)
-u_int otype;
-int unit;
-void *data;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_htable_iter_deref */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* otype(I) - which data structure type is being walked */
+/* unit(I) - ipfilter device to which we are working on */
+/* data(I) - pointer to old data structure */
+/* */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_htable_iter_deref(softc, arg, otype, unit, data)
+ ipf_main_softc_t *softc;
+ void *arg;
+ int otype;
+ int unit;
+ void *data;
{
if (data == NULL)
- return;
+ return EFAULT;
- if (unit < 0 || unit > IPL_LOGMAX)
- return;
+ if (unit < -1 || unit > IPL_LOGMAX)
+ return EINVAL;
switch (otype)
{
case IPFLOOKUPITER_LIST :
- WRITE_ENTER(&ip_poolrw);
- fr_derefhtable((iphtable_t *)data);
- RWLOCK_EXIT(&ip_poolrw);
+ ipf_htable_deref(softc, arg, (iphtable_t *)data);
break;
case IPFLOOKUPITER_NODE :
- WRITE_ENTER(&ip_poolrw);
- fr_derefhtent((iphtent_t *)data);
- RWLOCK_EXIT(&ip_poolrw);
+ ipf_htent_deref(arg, (iphtent_t *)data);
break;
default :
break;
}
+
+ return 0;
+}
+
+
+#ifdef USE_INET6
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_iphmfind6 */
+/* Parameters: iph(I) - pointer to hash table */
+/* addr(I) - pointer to IPv6 address */
+/* Locks: ipf_poolrw */
+/* */
+/* ------------------------------------------------------------------------ */
+static iphtent_t *
+ipf_iphmfind6(iph, addr)
+ iphtable_t *iph;
+ i6addr_t *addr;
+{
+ i6addr_t *msk, ips;
+ iphtent_t *ipe;
+ u_int hv;
+ int i;
+
+ i = 0;
+maskloop:
+ msk = iph->iph_v6_masks.imt6_active + i;
+ ips.i6[0] = addr->i6[0] & msk->i6[0];
+ ips.i6[1] = addr->i6[1] & msk->i6[1];
+ ips.i6[2] = addr->i6[2] & msk->i6[2];
+ ips.i6[3] = addr->i6[3] & msk->i6[3];
+ hv = IPE_V6_HASH_FN(ips.i6, msk->i6, iph->iph_size);
+ for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) {
+ if ((ipe->ipe_family != AF_INET6) ||
+ IP6_NEQ(&ipe->ipe_mask, msk) ||
+ IP6_NEQ(&ipe->ipe_addr, &ips)) {
+ continue;
+ }
+ break;
+ }
+
+ if (ipe == NULL) {
+ i++;
+ if (i < iph->iph_v6_masks.imt6_max)
+ goto maskloop;
+ }
+ return ipe;
}
+#endif
+
+
+static void
+ipf_htable_expire(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_htable_softc_t *softh = arg;
+ iphtent_t *n;
+
+ while ((n = softh->ipf_node_explist) != NULL) {
+ if (n->ipe_die > softc->ipf_ticks)
+ break;
+
+ ipf_htent_remove(softc, softh, n->ipe_owner, n);
+ }
+}
+
-#endif /* IPFILTER_LOOKUP */
+#ifndef _KERNEL
+
+/* ------------------------------------------------------------------------ */
+/* */
+/* ------------------------------------------------------------------------ */
+void
+ipf_htable_dump(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_htable_softc_t *softh = arg;
+ iphtable_t *iph;
+ int i;
+
+ printf("List of configured hash tables\n");
+ for (i = 0; i < IPL_LOGSIZE; i++)
+ for (iph = softh->ipf_htables[i]; iph != NULL;
+ iph = iph->iph_next)
+ printhash(iph, bcopywrap, NULL, opts, NULL);
+
+}
+#endif
diff --git a/sys/contrib/ipfilter/netinet/ip_htable.h b/sys/contrib/ipfilter/netinet/ip_htable.h
index 2c08812..8038bbc 100644
--- a/sys/contrib/ipfilter/netinet/ip_htable.h
+++ b/sys/contrib/ipfilter/netinet/ip_htable.h
@@ -6,36 +6,52 @@
typedef struct iphtent_s {
struct iphtent_s *ipe_next, **ipe_pnext;
struct iphtent_s *ipe_hnext, **ipe_phnext;
+ struct iphtent_s *ipe_dnext, **ipe_pdnext;
+ struct iphtable_s *ipe_owner;
void *ipe_ptr;
i6addr_t ipe_addr;
i6addr_t ipe_mask;
+ U_QUAD_T ipe_hits;
+ U_QUAD_T ipe_bytes;
+ u_long ipe_die;
+ int ipe_uid;
int ipe_ref;
int ipe_unit;
+ char ipe_family;
+ char ipe_xxx[3];
union {
char ipeu_char[16];
u_long ipeu_long;
u_int ipeu_int;
- }ipe_un;
+ } ipe_un;
} iphtent_t;
#define ipe_value ipe_un.ipeu_int
#define ipe_group ipe_un.ipeu_char
-#define IPE_HASH_FN(a, m, s) (((a) * (m)) % (s))
-
+#define IPE_V4_HASH_FN(a, m, s) ((((m) ^ (a)) - 1 - ((a) >> 8)) % (s))
+#define IPE_V6_HASH_FN(a, m, s) (((((m)[0] ^ (a)[0]) - ((a)[0] >> 8)) + \
+ (((m)[1] & (a)[1]) - ((a)[1] >> 8)) + \
+ (((m)[2] & (a)[2]) - ((a)[2] >> 8)) + \
+ (((m)[3] & (a)[3]) - ((a)[3] >> 8))) % (s))
typedef struct iphtable_s {
ipfrwlock_t iph_rwlock;
struct iphtable_s *iph_next, **iph_pnext;
struct iphtent_s **iph_table;
struct iphtent_s *iph_list;
+ struct iphtent_s **iph_tail;
+#ifdef USE_INET6
+ ipf_v6_masktab_t iph_v6_masks;
+#endif
+ ipf_v4_masktab_t iph_v4_masks;
size_t iph_size; /* size of hash table */
u_long iph_seed; /* hashing seed */
u_32_t iph_flags;
u_int iph_unit; /* IPL_LOG* */
u_int iph_ref;
u_int iph_type; /* lookup or group map - IPHASH_* */
- u_int iph_masks; /* IPv4 netmasks in use */
+ u_int iph_maskset[4]; /* netmasks in use */
char iph_name[FR_GROUPLEN]; /* hash table number */
} iphtable_t;
@@ -55,24 +71,11 @@ typedef struct iphtstat_s {
} iphtstat_t;
-extern iphtable_t *ipf_htables[IPL_LOGSIZE];
-
-extern iphtable_t *fr_existshtable __P((int, char *));
-extern int fr_clearhtable __P((iphtable_t *));
-extern void fr_htable_unload __P((void));
-extern int fr_newhtable __P((iplookupop_t *));
-extern iphtable_t *fr_findhtable __P((int, char *));
-extern int fr_removehtable __P((int, char *));
-extern size_t fr_flushhtable __P((iplookupflush_t *));
-extern int fr_addhtent __P((iphtable_t *, iphtent_t *));
-extern int fr_delhtent __P((iphtable_t *, iphtent_t *));
-extern int fr_derefhtable __P((iphtable_t *));
-extern int fr_derefhtent __P((iphtent_t *));
-extern int fr_delhtable __P((iphtable_t *));
-extern void *fr_iphmfindgroup __P((void *, void *));
-extern int fr_iphmfindip __P((void *, int, void *));
-extern int fr_gethtablestat __P((iplookupop_t *));
-extern int fr_htable_getnext __P((ipftoken_t *, ipflookupiter_t *));
-extern void fr_htable_iterderef __P((u_int, int, void *));
+extern void *ipf_iphmfindgroup __P((ipf_main_softc_t *, void *, void *));
+extern iphtable_t *ipf_htable_find __P((void *, int, char *));
+extern ipf_lookup_t ipf_htable_backend;
+#ifndef _KERNEL
+extern void ipf_htable_dump __P((ipf_main_softc_t *, void *));
+#endif
#endif /* __IP_HTABLE_H__ */
diff --git a/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c b/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c
index e88a6b9..980476a 100644
--- a/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c
+++ b/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c
@@ -1,152 +1,228 @@
/*
- * Copyright (C) 2001-2003 by Darren Reed
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
* Simple ISAKMP transparent proxy for in-kernel use. For use with the NAT
* code.
*
- * $Id: ip_ipsec_pxy.c,v 2.20.2.8 2006/07/14 06:12:14 darrenr Exp $
+ * $Id$
*
*/
#define IPF_IPSEC_PROXY
-int ippr_ipsec_init __P((void));
-void ippr_ipsec_fini __P((void));
-int ippr_ipsec_new __P((fr_info_t *, ap_session_t *, nat_t *));
-void ippr_ipsec_del __P((ap_session_t *));
-int ippr_ipsec_inout __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_ipsec_match __P((fr_info_t *, ap_session_t *, nat_t *));
-
-static frentry_t ipsecfr;
-static ipftq_t *ipsecnattqe;
-static ipftq_t *ipsecstatetqe;
-static char ipsec_buffer[1500];
+/*
+ * IPSec proxy
+ */
+typedef struct ipf_ipsec_softc_s {
+ frentry_t ipsec_fr;
+ int ipsec_proxy_init;
+ int ipsec_proxy_ttl;
+ ipftq_t *ipsec_nat_tqe;
+ ipftq_t *ipsec_state_tqe;
+ char ipsec_buffer[1500];
+} ipf_ipsec_softc_t;
+
+
+void *ipf_p_ipsec_soft_create __P((ipf_main_softc_t *));
+void ipf_p_ipsec_soft_destroy __P((ipf_main_softc_t *, void *));
+int ipf_p_ipsec_soft_init __P((ipf_main_softc_t *, void *));
+void ipf_p_ipsec_soft_fini __P((ipf_main_softc_t *, void *));
+int ipf_p_ipsec_init __P((void));
+void ipf_p_ipsec_fini __P((void));
+int ipf_p_ipsec_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_ipsec_del __P((ipf_main_softc_t *, ap_session_t *));
+int ipf_p_ipsec_inout __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_ipsec_match __P((fr_info_t *, ap_session_t *, nat_t *));
-int ipsec_proxy_init = 0;
-int ipsec_proxy_ttl = 60;
/*
* IPSec application proxy initialization.
*/
-int ippr_ipsec_init()
+void *
+ipf_p_ipsec_soft_create(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_ipsec_softc_t *softi;
+
+ KMALLOC(softi, ipf_ipsec_softc_t *);
+ if (softi == NULL)
+ return NULL;
+
+ bzero((char *)softi, sizeof(*softi));
+ softi->ipsec_fr.fr_ref = 1;
+ softi->ipsec_fr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
+ MUTEX_INIT(&softi->ipsec_fr.fr_lock, "IPsec proxy rule lock");
+ softi->ipsec_proxy_init = 1;
+ softi->ipsec_proxy_ttl = 60;
+
+ return softi;
+}
+
+
+int
+ipf_p_ipsec_soft_init(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
{
- bzero((char *)&ipsecfr, sizeof(ipsecfr));
- ipsecfr.fr_ref = 1;
- ipsecfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
- MUTEX_INIT(&ipsecfr.fr_lock, "IPsec proxy rule lock");
- ipsec_proxy_init = 1;
-
- ipsecnattqe = fr_addtimeoutqueue(&nat_utqe, ipsec_proxy_ttl);
- if (ipsecnattqe == NULL)
+ ipf_ipsec_softc_t *softi = arg;
+
+ softi->ipsec_nat_tqe = ipf_state_add_tq(softc, softi->ipsec_proxy_ttl);
+ if (softi->ipsec_nat_tqe == NULL)
return -1;
- ipsecstatetqe = fr_addtimeoutqueue(&ips_utqe, ipsec_proxy_ttl);
- if (ipsecstatetqe == NULL) {
- if (fr_deletetimeoutqueue(ipsecnattqe) == 0)
- fr_freetimeoutqueue(ipsecnattqe);
- ipsecnattqe = NULL;
+ softi->ipsec_state_tqe = ipf_nat_add_tq(softc, softi->ipsec_proxy_ttl);
+ if (softi->ipsec_state_tqe == NULL) {
+ if (ipf_deletetimeoutqueue(softi->ipsec_nat_tqe) == 0)
+ ipf_freetimeoutqueue(softc, softi->ipsec_nat_tqe);
+ softi->ipsec_nat_tqe = NULL;
return -1;
}
- ipsecnattqe->ifq_flags |= IFQF_PROXY;
- ipsecstatetqe->ifq_flags |= IFQF_PROXY;
-
- ipsecfr.fr_age[0] = ipsec_proxy_ttl;
- ipsecfr.fr_age[1] = ipsec_proxy_ttl;
+ softi->ipsec_nat_tqe->ifq_flags |= IFQF_PROXY;
+ softi->ipsec_state_tqe->ifq_flags |= IFQF_PROXY;
+ softi->ipsec_fr.fr_age[0] = softi->ipsec_proxy_ttl;
+ softi->ipsec_fr.fr_age[1] = softi->ipsec_proxy_ttl;
return 0;
}
-void ippr_ipsec_fini()
+void
+ipf_p_ipsec_soft_fini(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
{
- if (ipsecnattqe != NULL) {
- if (fr_deletetimeoutqueue(ipsecnattqe) == 0)
- fr_freetimeoutqueue(ipsecnattqe);
+ ipf_ipsec_softc_t *softi = arg;
+
+ if (arg == NULL)
+ return;
+
+ if (softi->ipsec_nat_tqe != NULL) {
+ if (ipf_deletetimeoutqueue(softi->ipsec_nat_tqe) == 0)
+ ipf_freetimeoutqueue(softc, softi->ipsec_nat_tqe);
}
- ipsecnattqe = NULL;
- if (ipsecstatetqe != NULL) {
- if (fr_deletetimeoutqueue(ipsecstatetqe) == 0)
- fr_freetimeoutqueue(ipsecstatetqe);
+ softi->ipsec_nat_tqe = NULL;
+ if (softi->ipsec_state_tqe != NULL) {
+ if (ipf_deletetimeoutqueue(softi->ipsec_state_tqe) == 0)
+ ipf_freetimeoutqueue(softc, softi->ipsec_state_tqe);
}
- ipsecstatetqe = NULL;
+ softi->ipsec_state_tqe = NULL;
+}
+
- if (ipsec_proxy_init == 1) {
- MUTEX_DESTROY(&ipsecfr.fr_lock);
- ipsec_proxy_init = 0;
+void
+ipf_p_ipsec_soft_destroy(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_ipsec_softc_t *softi = arg;
+
+ if (softi->ipsec_proxy_init == 1) {
+ MUTEX_DESTROY(&softi->ipsec_fr.fr_lock);
+ softi->ipsec_proxy_init = 0;
}
+
+ KFREE(softi);
}
/*
* Setup for a new IPSEC proxy.
*/
-int ippr_ipsec_new(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_ipsec_new(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
{
+ ipf_ipsec_softc_t *softi = arg;
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+#ifdef USE_MUTEXES
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+#endif
+ int p, off, dlen, ttl;
ipsec_pxy_t *ipsec;
+ ipnat_t *ipn, *np;
fr_info_t fi;
- ipnat_t *ipn;
char *ptr;
- int p, off, dlen, ttl;
- mb_t *m;
+ int size;
ip_t *ip;
+ mb_t *m;
+
+ if (fin->fin_v != 4)
+ return -1;
off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff;
- bzero(ipsec_buffer, sizeof(ipsec_buffer));
+ bzero(softi->ipsec_buffer, sizeof(softi->ipsec_buffer));
ip = fin->fin_ip;
m = fin->fin_m;
dlen = M_LEN(m) - off;
if (dlen < 16)
return -1;
- COPYDATA(m, off, MIN(sizeof(ipsec_buffer), dlen), ipsec_buffer);
+ COPYDATA(m, off, MIN(sizeof(softi->ipsec_buffer), dlen),
+ softi->ipsec_buffer);
- if (nat_outlookup(fin, 0, IPPROTO_ESP, nat->nat_inip,
+ if (ipf_nat_outlookup(fin, 0, IPPROTO_ESP, nat->nat_nsrcip,
ip->ip_dst) != NULL)
return -1;
- aps->aps_psiz = sizeof(*ipsec);
- KMALLOCS(aps->aps_data, ipsec_pxy_t *, sizeof(*ipsec));
- if (aps->aps_data == NULL)
+ np = nat->nat_ptr;
+ size = np->in_size;
+ KMALLOC(ipsec, ipsec_pxy_t *);
+ if (ipsec == NULL)
return -1;
- ipsec = aps->aps_data;
+ KMALLOCS(ipn, ipnat_t *, size);
+ if (ipn == NULL) {
+ KFREE(ipsec);
+ return -1;
+ }
+
+ aps->aps_data = ipsec;
+ aps->aps_psiz = sizeof(*ipsec);
bzero((char *)ipsec, sizeof(*ipsec));
+ bzero((char *)ipn, size);
+ ipsec->ipsc_rule = ipn;
/*
* 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;
- ttl = IPF_TTLVAL(ipsecnattqe->ifq_ttl);
- ipn->in_tqehead[0] = fr_addtimeoutqueue(&nat_utqe, ttl);
- ipn->in_tqehead[1] = fr_addtimeoutqueue(&nat_utqe, ttl);
+ ipn->in_size = size;
+ ttl = IPF_TTLVAL(softi->ipsec_nat_tqe->ifq_ttl);
+ ipn->in_tqehead[0] = ipf_nat_add_tq(softc, ttl);
+ ipn->in_tqehead[1] = ipf_nat_add_tq(softc, ttl);
ipn->in_ifps[0] = 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_snip = ntohl(nat->nat_nsrcaddr);
ipn->in_ippip = 1;
- ipn->in_inip = nat->nat_inip.s_addr;
- ipn->in_inmsk = 0xffffffff;
- ipn->in_outip = fin->fin_saddr;
- ipn->in_outmsk = nat->nat_outip.s_addr;
- ipn->in_srcip = fin->fin_saddr;
- ipn->in_srcmsk = 0xffffffff;
+ ipn->in_osrcip = nat->nat_osrcip;
+ ipn->in_osrcmsk = 0xffffffff;
+ ipn->in_nsrcip = nat->nat_nsrcip;
+ ipn->in_nsrcmsk = 0xffffffff;
+ ipn->in_odstip = nat->nat_odstip;
+ ipn->in_odstmsk = 0xffffffff;
+ ipn->in_ndstip = nat->nat_ndstip;
+ ipn->in_ndstmsk = 0xffffffff;
ipn->in_redir = NAT_MAP;
- bcopy(nat->nat_ptr->in_ifnames[0], ipn->in_ifnames[0],
- sizeof(ipn->in_ifnames[0]));
- ipn->in_p = IPPROTO_ESP;
+ ipn->in_pr[0] = IPPROTO_ESP;
+ ipn->in_pr[1] = IPPROTO_ESP;
+ ipn->in_flags = (np->in_flags | IPN_PROXYRULE);
+ MUTEX_INIT(&ipn->in_lock, "IPSec proxy NAT rule");
+
+ ipn->in_namelen = np->in_namelen;
+ bcopy(np->in_names, ipn->in_ifnames, ipn->in_namelen);
+ ipn->in_ifnames[0] = np->in_ifnames[0];
+ ipn->in_ifnames[1] = np->in_ifnames[1];
bcopy((char *)fin, (char *)&fi, sizeof(fi));
- fi.fin_state = NULL;
- fi.fin_nat = NULL;
fi.fin_fi.fi_p = IPPROTO_ESP;
- fi.fin_fr = &ipsecfr;
+ fi.fin_fr = &softi->ipsec_fr;
fi.fin_data[0] = 0;
fi.fin_data[1] = 0;
p = ip->ip_p;
@@ -154,7 +230,7 @@ nat_t *nat;
fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG);
fi.fin_flx |= FI_IGNORE;
- ptr = ipsec_buffer;
+ ptr = softi->ipsec_buffer;
bcopy(ptr, (char *)ipsec->ipsc_icookie, sizeof(ipsec_cookie_t));
ptr += sizeof(ipsec_cookie_t);
bcopy(ptr, (char *)ipsec->ipsc_rcookie, sizeof(ipsec_cookie_t));
@@ -166,18 +242,19 @@ nat_t *nat;
if ((ipsec->ipsc_rcookie[0]|ipsec->ipsc_rcookie[1]) != 0)
ipsec->ipsc_rckset = 1;
- ipsec->ipsc_nat = nat_new(&fi, ipn, &ipsec->ipsc_nat,
- NAT_SLAVE|SI_WILDP, NAT_OUTBOUND);
+ MUTEX_ENTER(&softn->ipf_nat_new);
+ ipsec->ipsc_nat = ipf_nat_add(&fi, ipn, &ipsec->ipsc_nat,
+ NAT_SLAVE|SI_WILDP, NAT_OUTBOUND);
+ MUTEX_EXIT(&softn->ipf_nat_new);
if (ipsec->ipsc_nat != NULL) {
- (void) nat_proto(&fi, ipsec->ipsc_nat, 0);
- nat_update(&fi, ipsec->ipsc_nat, ipn);
+ (void) ipf_nat_proto(&fi, ipsec->ipsc_nat, 0);
+ MUTEX_ENTER(&ipsec->ipsc_nat->nat_lock);
+ ipf_nat_update(&fi, ipsec->ipsc_nat);
+ MUTEX_EXIT(&ipsec->ipsc_nat->nat_lock);
fi.fin_data[0] = 0;
fi.fin_data[1] = 0;
- ipsec->ipsc_state = fr_addstate(&fi, &ipsec->ipsc_state,
- SI_WILDP);
- if (fi.fin_state != NULL)
- fr_statederef((ipstate_t **)&fi.fin_state);
+ (void) ipf_state_add(softc, &fi, &ipsec->ipsc_state, SI_WILDP);
}
ip->ip_p = p & 0xff;
return 0;
@@ -188,11 +265,15 @@ nat_t *nat;
* For outgoing IKE packets. refresh timeouts for NAT & state entries, if
* we can. If they have disappeared, recreate them.
*/
-int ippr_ipsec_inout(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_ipsec_inout(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
{
+ ipf_ipsec_softc_t *softi = arg;
+ ipf_main_softc_t *softc = fin->fin_main_soft;
ipsec_pxy_t *ipsec;
fr_info_t fi;
ip_t *ip;
@@ -212,10 +293,8 @@ nat_t *nat;
if ((ipsec->ipsc_nat == NULL) || (ipsec->ipsc_state == NULL)) {
bcopy((char *)fin, (char *)&fi, sizeof(fi));
- fi.fin_state = NULL;
- fi.fin_nat = NULL;
fi.fin_fi.fi_p = IPPROTO_ESP;
- fi.fin_fr = &ipsecfr;
+ fi.fin_fr = &softi->ipsec_fr;
fi.fin_data[0] = 0;
fi.fin_data[1] = 0;
ip->ip_p = IPPROTO_ESP;
@@ -227,36 +306,42 @@ nat_t *nat;
* Update NAT timeout/create NAT if missing.
*/
if (ipsec->ipsc_nat != NULL)
- fr_queueback(&ipsec->ipsc_nat->nat_tqe);
+ ipf_queueback(softc->ipf_ticks,
+ &ipsec->ipsc_nat->nat_tqe);
else {
- ipsec->ipsc_nat = nat_new(&fi, &ipsec->ipsc_rule,
- &ipsec->ipsc_nat,
- NAT_SLAVE|SI_WILDP,
- nat->nat_dir);
+#ifdef USE_MUTEXES
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+#endif
+
+ MUTEX_ENTER(&softn->ipf_nat_new);
+ ipsec->ipsc_nat = ipf_nat_add(&fi, ipsec->ipsc_rule,
+ &ipsec->ipsc_nat,
+ NAT_SLAVE|SI_WILDP,
+ nat->nat_dir);
+ MUTEX_EXIT(&softn->ipf_nat_new);
if (ipsec->ipsc_nat != NULL) {
- (void) nat_proto(&fi, ipsec->ipsc_nat, 0);
- nat_update(&fi, ipsec->ipsc_nat,
- &ipsec->ipsc_rule);
+ (void) ipf_nat_proto(&fi, ipsec->ipsc_nat, 0);
+ MUTEX_ENTER(&ipsec->ipsc_nat->nat_lock);
+ ipf_nat_update(&fi, ipsec->ipsc_nat);
+ MUTEX_EXIT(&ipsec->ipsc_nat->nat_lock);
}
}
/*
* Update state timeout/create state if missing.
*/
- READ_ENTER(&ipf_state);
+ READ_ENTER(&softc->ipf_state);
if (ipsec->ipsc_state != NULL) {
- fr_queueback(&ipsec->ipsc_state->is_sti);
+ ipf_queueback(softc->ipf_ticks,
+ &ipsec->ipsc_state->is_sti);
ipsec->ipsc_state->is_die = nat->nat_age;
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
} else {
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
fi.fin_data[0] = 0;
fi.fin_data[1] = 0;
- ipsec->ipsc_state = fr_addstate(&fi,
- &ipsec->ipsc_state,
- SI_WILDP);
- if (fi.fin_state != NULL)
- fr_statederef((ipstate_t **)&fi.fin_state);
+ (void) ipf_state_add(softc, &fi, &ipsec->ipsc_state,
+ SI_WILDP);
}
ip->ip_p = p;
}
@@ -270,10 +355,11 @@ nat_t *nat;
* 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;
+int
+ipf_p_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];
@@ -314,8 +400,10 @@ nat_t *nat;
/*
* clean up after ourselves.
*/
-void ippr_ipsec_del(aps)
-ap_session_t *aps;
+void
+ipf_p_ipsec_del(softc, aps)
+ ipf_main_softc_t *softc;
+ ap_session_t *aps;
{
ipsec_pxy_t *ipsec;
@@ -327,15 +415,17 @@ ap_session_t *aps;
* *_del() is on a callback from aps_free(), from nat_delete()
*/
- READ_ENTER(&ipf_state);
+ READ_ENTER(&softc->ipf_state);
if (ipsec->ipsc_state != NULL) {
- ipsec->ipsc_state->is_die = fr_ticks + 1;
+ ipsec->ipsc_state->is_die = softc->ipf_ticks + 1;
ipsec->ipsc_state->is_me = NULL;
- fr_queuefront(&ipsec->ipsc_state->is_sti);
+ ipf_queuefront(&ipsec->ipsc_state->is_sti);
}
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
ipsec->ipsc_state = NULL;
ipsec->ipsc_nat = NULL;
+ ipsec->ipsc_rule->in_flags |= IPN_DELETE;
+ ipf_nat_rule_deref(softc, &ipsec->ipsc_rule);
}
}
diff --git a/sys/contrib/ipfilter/netinet/ip_irc_pxy.c b/sys/contrib/ipfilter/netinet/ip_irc_pxy.c
index 5bb252a..b9954b4 100644
--- a/sys/contrib/ipfilter/netinet/ip_irc_pxy.c
+++ b/sys/contrib/ipfilter/netinet/ip_irc_pxy.c
@@ -1,9 +1,9 @@
/*
- * Copyright (C) 2000-2003 Darren Reed
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
- * $Id: ip_irc_pxy.c,v 2.39.2.6 2006/07/14 06:12:14 darrenr Exp $
+ * $Id$
*/
#define IPF_IRC_PROXY
@@ -11,12 +11,12 @@
#define IPF_IRCBUFSZ 96 /* This *MUST* be >= 64! */
-int ippr_irc_init __P((void));
-void ippr_irc_fini __P((void));
-int ippr_irc_new __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_irc_out __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_irc_send __P((fr_info_t *, nat_t *));
-int ippr_irc_complete __P((ircinfo_t *, char *, size_t));
+void ipf_p_irc_main_load __P((void));
+void ipf_p_irc_main_unload __P((void));
+int ipf_p_irc_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_irc_out __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_irc_send __P((fr_info_t *, nat_t *));
+int ipf_p_irc_complete __P((ircinfo_t *, char *, size_t));
u_short ipf_irc_atoi __P((char **));
static frentry_t ircnatfr;
@@ -27,19 +27,19 @@ int irc_proxy_init = 0;
/*
* Initialize local structures.
*/
-int ippr_irc_init()
+void
+ipf_p_irc_main_load()
{
bzero((char *)&ircnatfr, sizeof(ircnatfr));
ircnatfr.fr_ref = 1;
ircnatfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
MUTEX_INIT(&ircnatfr.fr_lock, "IRC proxy rule lock");
irc_proxy_init = 1;
-
- return 0;
}
-void ippr_irc_fini()
+void
+ipf_p_irc_main_unload()
{
if (irc_proxy_init == 1) {
MUTEX_DESTROY(&ircnatfr.fr_lock);
@@ -48,7 +48,7 @@ void ippr_irc_fini()
}
-const char *ippr_irc_dcctypes[] = {
+const char *ipf_p_irc_dcctypes[] = {
"CHAT ", /* CHAT chat ipnumber portnumber */
"SEND ", /* SEND filename ipnumber portnumber */
"MOVE ",
@@ -64,10 +64,11 @@ const char *ippr_irc_dcctypes[] = {
*/
-int ippr_irc_complete(ircp, buf, len)
-ircinfo_t *ircp;
-char *buf;
-size_t len;
+int
+ipf_p_irc_complete(ircp, buf, len)
+ ircinfo_t *ircp;
+ char *buf;
+ size_t len;
{
register char *s, c;
register size_t i;
@@ -145,12 +146,12 @@ size_t len;
/*
* Check for a recognised DCC command
*/
- for (j = 0, k = 0; ippr_irc_dcctypes[j]; j++) {
- k = MIN(strlen(ippr_irc_dcctypes[j]), i);
- if (!strncmp(ippr_irc_dcctypes[j], s, k))
+ for (j = 0, k = 0; ipf_p_irc_dcctypes[j]; j++) {
+ k = MIN(strlen(ipf_p_irc_dcctypes[j]), i);
+ if (!strncmp(ipf_p_irc_dcctypes[j], s, k))
break;
}
- if (!ippr_irc_dcctypes[j])
+ if (!ipf_p_irc_dcctypes[j])
return 0;
ircp->irc_type = s;
@@ -222,18 +223,22 @@ size_t len;
}
-int ippr_irc_new(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_irc_new(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
{
ircinfo_t *irc;
+ if (fin->fin_v != 4)
+ return -1;
+
KMALLOC(irc, ircinfo_t *);
if (irc == NULL)
return -1;
- fin = fin; /* LINT */
nat = nat; /* LINT */
aps->aps_data = irc;
@@ -244,13 +249,15 @@ nat_t *nat;
}
-int ippr_irc_send(fin, nat)
-fr_info_t *fin;
-nat_t *nat;
+int
+ipf_p_irc_send(fin, nat)
+ fr_info_t *fin;
+ nat_t *nat;
{
char ctcpbuf[IPF_IRCBUFSZ], newbuf[IPF_IRCBUFSZ];
tcphdr_t *tcp, tcph, *tcp2 = &tcph;
int off, inc = 0, i, dlen;
+ ipf_main_softc_t *softc;
size_t nlen = 0, olen;
struct in_addr swip;
u_short a5, sp;
@@ -263,6 +270,7 @@ nat_t *nat;
#ifdef MENTAT
mb_t *m1;
#endif
+ softc = fin->fin_main_soft;
m = fin->fin_m;
ip = fin->fin_ip;
@@ -285,14 +293,14 @@ nat_t *nat;
*newbuf = '\0';
irc = nat->nat_aps->aps_data;
- if (ippr_irc_complete(irc, ctcpbuf, dlen) == 0)
+ if (ipf_p_irc_complete(irc, ctcpbuf, dlen) == 0)
return 0;
/*
- * check that IP address in the PORT/PASV reply is the same as the
- * sender of the command - prevents using PORT for port scanning.
+ * check that IP address in the DCC reply is the same as the
+ * sender of the command - prevents use for port scanning.
*/
- if (irc->irc_ipnum != ntohl(nat->nat_inip.s_addr))
+ if (irc->irc_ipnum != ntohl(nat->nat_osrcaddr))
return 0;
a5 = irc->irc_port;
@@ -315,7 +323,7 @@ nat_t *nat;
nlen = strlen(newbuf);
inc = nlen - olen;
- if ((inc + ip->ip_len) > 65535)
+ if ((inc + fin->fin_plen) > 65535)
return 0;
#ifdef MENTAT
@@ -326,14 +334,14 @@ nat_t *nat;
/* alloc enough to keep same trailer space for lower driver */
nm = allocb(nlen, BPRI_MED);
- PANIC((!nm),("ippr_irc_out: allocb failed"));
+ PANIC((!nm),("ipf_p_irc_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_irc_out: cannot handle fragmented data block"));
+ ("ipf_p_irc_out: cannot handle fragmented data block"));
linkb(m1, nm);
} else {
@@ -350,13 +358,14 @@ nat_t *nat;
/* the mbuf chain will be extended if necessary by m_copyback() */
#endif
COPYBACK(m, off, nlen, newbuf);
+ fin->fin_flx |= FI_DOCKSUM;
if (inc != 0) {
#if defined(MENTAT) || defined(__sgi)
register u_32_t sum1, sum2;
- sum1 = ip->ip_len;
- sum2 = ip->ip_len + inc;
+ sum1 = fin->fin_plen;
+ sum2 = fin->fin_plen + inc;
/* Because ~1 == -2, We really need ~1 == -1 */
if (sum1 > sum2)
@@ -364,9 +373,11 @@ nat_t *nat;
sum2 -= sum1;
sum2 = (sum2 & 0xffff) + (sum2 >> 16);
- fix_outcksum(fin, &ip->ip_sum, sum2);
+ ipf_fix_outcksum(0, &ip->ip_sum, sum2, 0);
#endif
- ip->ip_len += inc;
+ fin->fin_plen += inc;
+ ip->ip_len = htons(fin->fin_plen);
+ fin->fin_dlen += inc;
}
/*
@@ -389,16 +400,18 @@ nat_t *nat;
bcopy((caddr_t)fin, (caddr_t)&fi, sizeof(fi));
fi.fin_data[0] = sp;
fi.fin_data[1] = fin->fin_data[1];
- nat2 = nat_outlookup(fin, IPN_TCP, nat->nat_p, nat->nat_inip,
+ nat2 = ipf_nat_outlookup(fin, IPN_TCP, nat->nat_pr[1], nat->nat_nsrcip,
ip->ip_dst);
if (nat2 == NULL) {
+#ifdef USE_MUTEXES
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+#endif
+
bcopy((caddr_t)fin, (caddr_t)&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_state = NULL;
- fi.fin_nat = NULL;
fi.fin_data[0] = ntohs(sp);
fi.fin_data[1] = 0;
fi.fin_dp = (char *)tcp2;
@@ -406,16 +419,18 @@ nat_t *nat;
fi.fin_dlen = sizeof(*tcp2);
fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
swip = ip->ip_src;
- ip->ip_src = nat->nat_inip;
- nat2 = nat_new(&fi, nat->nat_ptr, NULL,
+ ip->ip_src = nat->nat_nsrcip;
+ MUTEX_ENTER(&softn->ipf_nat_new);
+ nat2 = ipf_nat_add(&fi, nat->nat_ptr, NULL,
NAT_SLAVE|IPN_TCP|SI_W_DPORT, NAT_OUTBOUND);
+ MUTEX_EXIT(&softn->ipf_nat_new);
if (nat2 != NULL) {
- (void) nat_proto(&fi, nat2, 0);
- nat_update(&fi, nat2, nat2->nat_ptr);
+ (void) ipf_nat_proto(&fi, nat2, 0);
+ MUTEX_ENTER(&nat2->nat_lock);
+ ipf_nat_update(&fi, nat2);
+ MUTEX_EXIT(&nat2->nat_lock);
- (void) fr_addstate(&fi, NULL, SI_W_DPORT);
- if (fi.fin_state != NULL)
- fr_statederef((ipstate_t **)&fi.fin_state);
+ (void) ipf_state_add(softc, &fi, NULL, SI_W_DPORT);
}
ip->ip_src = swip;
}
@@ -423,11 +438,13 @@ nat_t *nat;
}
-int ippr_irc_out(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_irc_out(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
{
aps = aps; /* LINT */
- return ippr_irc_send(fin, nat);
+ return ipf_p_irc_send(fin, nat);
}
diff --git a/sys/contrib/ipfilter/netinet/ip_log.c b/sys/contrib/ipfilter/netinet/ip_log.c
index 863cc9c..d41384d 100644
--- a/sys/contrib/ipfilter/netinet/ip_log.c
+++ b/sys/contrib/ipfilter/netinet/ip_log.c
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1997-2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
@@ -15,22 +15,8 @@
# define KERNEL 1
# define _KERNEL 1
#endif
-#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
- defined(_KERNEL)
-# if (__NetBSD_Version__ < 399001400)
-# include "opt_ipfilter_log.h"
-# else
-# include "opt_ipfilter.h"
-# endif
-#endif
-#if defined(__FreeBSD__) && !defined(IPFILTER_LKM)
-# if defined(_KERNEL)
-# if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
-# include "opt_ipfilter.h"
-# endif
-# else
-# include <osreldate.h>
-# endif
+#if defined(__FreeBSD__) && !defined(_KERNEL)
+# include <osreldate.h>
#endif
#ifndef SOLARIS
# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
@@ -104,7 +90,6 @@ struct file;
#if __FreeBSD_version >= 300000
# include <net/if_var.h>
#endif
-#include <net/route.h>
#include <netinet/in.h>
#ifdef __sgi
# include <sys/ddi.h>
@@ -148,100 +133,240 @@ struct file;
# include <machine/sys/user.h>
# include <sys/kthread_iface.h>
# define READ_COLLISION 0x001
-
-iplog_select_t iplog_ss[IPL_LOGMAX+1];
-
extern int selwait;
# endif /* IPL_SELECT */
+typedef struct ipf_log_softc_s {
+ ipfmutex_t ipl_mutex[IPL_LOGSIZE];
+# if SOLARIS && defined(_KERNEL)
+ kcondvar_t ipl_wait[IPL_LOGSIZE];
+# endif
# if defined(linux) && defined(_KERNEL)
-wait_queue_head_t iplh_linux[IPL_LOGSIZE];
+ wait_queue_head_t iplh_linux[IPL_LOGSIZE];
# endif
-# if SOLARIS && defined(_KERNEL)
-extern kcondvar_t iplwait;
-extern struct pollhead iplpollhead[IPL_LOGSIZE];
+# if defined(__hpux) && defined(_KERNEL)
+ iplog_select_t ipl_ss[IPL_LOGSIZE];
# endif
+ iplog_t **iplh[IPL_LOGSIZE];
+ iplog_t *iplt[IPL_LOGSIZE];
+ iplog_t *ipll[IPL_LOGSIZE];
+ u_long ipl_logfail[IPL_LOGSIZE];
+ u_long ipl_logok[IPL_LOGSIZE];
+ fr_info_t ipl_crc[IPL_LOGSIZE];
+ u_32_t ipl_counter[IPL_LOGSIZE];
+ int ipl_suppress;
+ int ipl_logall;
+ int ipl_log_init;
+ int ipl_logsize;
+ int ipl_used[IPL_LOGSIZE];
+ int ipl_magic[IPL_LOGSIZE];
+ ipftuneable_t *ipf_log_tune;
+ int ipl_readers[IPL_LOGSIZE];
+} ipf_log_softc_t;
+
+static int magic[IPL_LOGSIZE] = { IPL_MAGIC, IPL_MAGIC_NAT, IPL_MAGIC_STATE,
+ IPL_MAGIC, IPL_MAGIC, IPL_MAGIC,
+ IPL_MAGIC, IPL_MAGIC };
+
+static ipftuneable_t ipf_log_tuneables[] = {
+ /* log */
+ { { (void *)offsetof(ipf_log_softc_t, ipl_suppress) },
+ "log_suppress", 0, 1,
+ stsizeof(ipf_log_softc_t, ipl_suppress),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_log_softc_t, ipl_logall) },
+ "log_all", 0, 1,
+ stsizeof(ipf_log_softc_t, ipl_logall),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_log_softc_t, ipl_logsize) },
+ "log_size", 0, 0x80000,
+ stsizeof(ipf_log_softc_t, ipl_logsize),
+ 0, NULL, NULL },
+ { { NULL }, NULL, 0, 0,
+ 0,
+ 0, NULL, NULL }
+};
+
+
+int
+ipf_log_main_load()
+{
+ return 0;
+}
+
+
+int
+ipf_log_main_unload()
+{
+ return 0;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_log_soft_create */
+/* Returns: void * - NULL = failure, else pointer to log context data */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Initialise log buffers & pointers. Also iniialised the CRC to a local */
+/* secret for use in calculating the "last log checksum". */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_log_soft_create(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_log_softc_t *softl;
-iplog_t **iplh[IPL_LOGSIZE], *iplt[IPL_LOGSIZE], *ipll[IPL_LOGSIZE];
-int iplused[IPL_LOGSIZE];
-static fr_info_t iplcrc[IPL_LOGSIZE];
-int ipl_suppress = 1;
-int ipl_logmax = IPL_LOGMAX;
-int ipl_logall = 0;
-int ipl_log_init = 0;
-int ipl_logsize = IPFILTER_LOGSIZE;
-int ipl_magic[IPL_LOGSIZE] = { IPL_MAGIC, IPL_MAGIC_NAT, IPL_MAGIC_STATE,
- IPL_MAGIC, IPL_MAGIC, IPL_MAGIC,
- IPL_MAGIC, IPL_MAGIC };
+ KMALLOC(softl, ipf_log_softc_t *);
+ if (softl == NULL)
+ return NULL;
+ bzero((char *)softl, sizeof(*softl));
+ bcopy((char *)magic, (char *)softl->ipl_magic, sizeof(magic));
+
+ softl->ipf_log_tune = ipf_tune_array_copy(softl,
+ sizeof(ipf_log_tuneables),
+ ipf_log_tuneables);
+ if (softl->ipf_log_tune == NULL) {
+ ipf_log_soft_destroy(softc, softl);
+ return NULL;
+ }
+ if (ipf_tune_array_link(softc, softl->ipf_log_tune) == -1) {
+ ipf_log_soft_destroy(softc, softl);
+ return NULL;
+ }
+
+ softl->ipl_suppress = 1;
+ softl->ipl_logall = 0;
+ softl->ipl_log_init = 0;
+ softl->ipl_logsize = IPFILTER_LOGSIZE;
+
+ return softl;
+}
/* ------------------------------------------------------------------------ */
-/* Function: fr_loginit */
+/* Function: ipf_log_soft_init */
/* Returns: int - 0 == success (always returned) */
-/* Parameters: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
/* */
/* Initialise log buffers & pointers. Also iniialised the CRC to a local */
/* secret for use in calculating the "last log checksum". */
/* ------------------------------------------------------------------------ */
-int fr_loginit()
+int
+ipf_log_soft_init(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
{
- int i;
+ ipf_log_softc_t *softl = arg;
+ 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]));
+ softl->iplt[i] = NULL;
+ softl->ipll[i] = NULL;
+ softl->iplh[i] = &softl->iplt[i];
+ bzero((char *)&softl->ipl_crc[i], sizeof(softl->ipl_crc[i]));
# ifdef IPL_SELECT
- iplog_ss[i].read_waiter = 0;
- iplog_ss[i].state = 0;
+ softl->iplog_ss[i].read_waiter = 0;
+ softl->iplog_ss[i].state = 0;
# endif
# if defined(linux) && defined(_KERNEL)
- init_waitqueue_head(iplh_linux + i);
+ init_waitqueue_head(softl->iplh_linux + i);
# endif
- }
-
# if SOLARIS && defined(_KERNEL)
- cv_init(&iplwait, "ipl condvar", CV_DRIVER, NULL);
+ cv_init(&softl->ipl_wait[i], NULL, CV_DRIVER, NULL);
# endif
- MUTEX_INIT(&ipl_mutex, "ipf log mutex");
+ MUTEX_INIT(&softl->ipl_mutex[i], "ipf log mutex");
+ }
+
- ipl_log_init = 1;
+ softl->ipl_log_init = 1;
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_logunload */
-/* Returns: Nil */
-/* Parameters: Nil */
+/* Function: ipf_log_soft_fini */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to log context structure */
/* */
/* Clean up any log data that has accumulated without being read. */
/* ------------------------------------------------------------------------ */
-void fr_logunload()
+int
+ipf_log_soft_fini(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
{
+ ipf_log_softc_t *softl = arg;
int i;
- if (ipl_log_init == 0)
- return;
+ if (softl->ipl_log_init == 0)
+ return 0;
+
+ softl->ipl_log_init = 0;
- for (i = IPL_LOGMAX; i >= 0; i--)
- (void) ipflog_clear(i);
+ for (i = IPL_LOGMAX; i >= 0; i--) {
+ (void) ipf_log_clear(softc, i);
+
+ /*
+ * This is a busy-wait loop so as to avoid yet another lock
+ * to wait on.
+ */
+ MUTEX_ENTER(&softl->ipl_mutex[i]);
+ while (softl->ipl_readers[i] > 0) {
+# if SOLARIS && defined(_KERNEL)
+ cv_broadcast(&softl->ipl_wait[i]);
+ MUTEX_EXIT(&softl->ipl_mutex[i]);
+ delay(100);
+ pollwakeup(&softc->ipf_poll_head[i], POLLRDNORM);
+# else
+ MUTEX_EXIT(&softl->ipl_mutex[i]);
+ WAKEUP(softl->iplh, i);
+ POLLWAKEUP(i);
+# endif
+ MUTEX_ENTER(&softl->ipl_mutex[i]);
+ }
+ MUTEX_EXIT(&softl->ipl_mutex[i]);
+ }
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_log_soft_destroy */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to log context structure */
+/* */
+/* When this function is called, it is expected that there are no longer */
+/* any threads active in the reading code path or the logging code path. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_log_soft_destroy(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_log_softc_t *softl = arg;
+ int i;
+ for (i = IPL_LOGMAX; i >= 0; i--) {
# if SOLARIS && defined(_KERNEL)
- cv_destroy(&iplwait);
+ cv_destroy(&softl->ipl_wait[i]);
# endif
- MUTEX_DESTROY(&ipl_mutex);
+ MUTEX_DESTROY(&softl->ipl_mutex[i]);
+ }
+
+ if (softl->ipf_log_tune != NULL) {
+ ipf_tune_array_unlink(softc, softl->ipf_log_tune);
+ KFREES(softl->ipf_log_tune, sizeof(ipf_log_tuneables));
+ softl->ipf_log_tune = NULL;
+ }
- ipl_log_init = 0;
+ KFREE(softl);
}
/* ------------------------------------------------------------------------ */
-/* Function: ipflog */
-/* Returns: int - 0 == success, -1 == failure */
+/* Function: ipf_log_pkt */
+/* Returns: int - 0 == success, -1 == failure */
/* Parameters: fin(I) - pointer to packet information */
/* flags(I) - flags from filter rules */
/* */
@@ -251,10 +376,13 @@ void fr_logunload()
/* how much data to copy into the log, including part of the data body if */
/* requested. */
/* ------------------------------------------------------------------------ */
-int ipflog(fin, flags)
-fr_info_t *fin;
-u_int flags;
+int
+ipf_log_pkt(fin, flags)
+ fr_info_t *fin;
+ u_int flags;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_log_softc_t *softl = softc->ipf_log_soft;
register size_t hlen;
int types[2], mlen;
size_t sizes[2];
@@ -262,8 +390,7 @@ u_int flags;
ipflog_t ipfl;
u_char p;
mb_t *m;
-# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) && \
- !defined(_INET_IP_STACK_H)
+# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) && !defined(FW_HOOKS)
qif_t *ifp;
# else
struct ifnet *ifp;
@@ -275,10 +402,8 @@ u_int flags;
ipfl.fl_nattag.ipt_num[0] = 0;
ifp = fin->fin_ifp;
- if (fin->fin_exthdr != NULL)
- hlen = (char *)fin->fin_dp - (char *)fin->fin_ip;
- else
- hlen = fin->fin_hlen;
+ hlen = (char *)fin->fin_dp - (char *)fin->fin_ip;
+
/*
* calculate header size.
*/
@@ -292,7 +417,7 @@ u_int flags;
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
@@ -339,15 +464,14 @@ u_int flags;
* Get the interface number and name to which this packet is
* currently associated.
*/
-# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) && \
- !defined(_INET_IP_STACK_H)
+# if (SOLARIS || defined(__hpux)) && defined(_KERNEL)
+# if !defined(FW_HOOKS)
ipfl.fl_unit = (u_int)ifp->qf_ppa;
+# endif
COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname);
# else
-# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \
- (defined(OpenBSD) && (OpenBSD >= 199603)) || defined(linux) || \
- (defined(__FreeBSD__) && (__FreeBSD_version >= 501113)) || \
- (SOLARIS && defined(_INET_IP_STACK_H))
+# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \
+ OPENBSD_GE_REV(199603) || defined(linux) || FREEBSD_GE_REV(501113)
COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname);
# else
ipfl.fl_unit = (u_int)ifp->if_unit;
@@ -357,13 +481,13 @@ u_int flags;
if ((ipfl.fl_ifname[2] = ifp->if_name[2]))
ipfl.fl_ifname[3] = ifp->if_name[3];
# else
- COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname);
+ (void) strncpy(ipfl.fl_ifname, IFNAME(ifp), sizeof(ipfl.fl_ifname));
ipfl.fl_ifname[sizeof(ipfl.fl_ifname) - 1] = '\0';
# endif
# endif
# endif /* __hpux || SOLARIS */
mlen = fin->fin_plen - hlen;
- if (!ipl_logall) {
+ if (!softl->ipl_logall) {
mlen = (flags & FR_LOGBODY) ? MIN(mlen, 128) : 0;
} else if ((flags & FR_LOGBODY) == 0) {
mlen = 0;
@@ -385,8 +509,10 @@ u_int flags;
bcopy(fin->fin_nattag, (void *)&ipfl.fl_nattag,
sizeof(ipfl.fl_nattag));
ipfl.fl_flags = flags;
+ ipfl.fl_breason = (fin->fin_reason & 0xff);
ipfl.fl_dir = fin->fin_out;
ipfl.fl_lflags = fin->fin_flx;
+ ipfl.fl_family = fin->fin_family;
ptrs[0] = (void *)&ipfl;
sizes[0] = sizeof(ipfl);
types[0] = 0;
@@ -408,14 +534,15 @@ u_int flags;
sizes[1] = hlen + mlen;
types[1] = 1;
# endif /* MENTAT */
- return ipllog(IPL_LOGIPF, fin, ptrs, sizes, types, 2);
+ return ipf_log_items(softc, IPL_LOGIPF, fin, ptrs, sizes, types, 2);
}
/* ------------------------------------------------------------------------ */
-/* Function: ipllog */
-/* Returns: int - 0 == success, -1 == failure */
-/* Parameters: dev(I) - device that owns this log record */
+/* Function: ipf_log_items */
+/* Returns: int - 0 == success, -1 == failure */
+/* Parameters: softc(I) - pointer to main soft context */
+/* unit(I) - device we are reading from */
/* fin(I) - pointer to packet information */
/* items(I) - array of pointers to log data */
/* itemsz(I) - array of size of valid memory pointed to */
@@ -426,72 +553,51 @@ u_int flags;
/* miscellaneous packet information, as well as packet data, for reading */
/* from the log device. */
/* ------------------------------------------------------------------------ */
-int ipllog(dev, fin, items, itemsz, types, cnt)
-int dev;
-fr_info_t *fin;
-void **items;
-size_t *itemsz;
-int *types, cnt;
+int
+ipf_log_items(softc, unit, fin, items, itemsz, types, cnt)
+ ipf_main_softc_t *softc;
+ int unit;
+ fr_info_t *fin;
+ void **items;
+ size_t *itemsz;
+ int *types, cnt;
{
- u_char *buf, *ptr;
+ ipf_log_softc_t *softl = softc->ipf_log_soft;
+ caddr_t buf, ptr;
iplog_t *ipl;
size_t len;
int i;
SPL_INT(s);
/*
- * 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 (ipl_suppress) {
- MUTEX_ENTER(&ipl_mutex);
- if ((fin != NULL) && (fin->fin_off == 0)) {
- if ((ipll[dev] != NULL) &&
- bcmp((char *)fin, (char *)&iplcrc[dev],
- FI_LCSIZE) == 0) {
- ipll[dev]->ipl_count++;
- MUTEX_EXIT(&ipl_mutex);
- return 0;
- }
- bcopy((char *)fin, (char *)&iplcrc[dev], FI_LCSIZE);
- } else
- bzero((char *)&iplcrc[dev], FI_CSIZE);
- MUTEX_EXIT(&ipl_mutex);
- }
-
- /*
* Get the total amount of data to be logged.
*/
for (i = 0, len = sizeof(iplog_t); i < cnt; i++)
len += itemsz[i];
+ SPL_NET(s);
+ MUTEX_ENTER(&softl->ipl_mutex[unit]);
+ softl->ipl_counter[unit]++;
/*
* check that we have space to record this information and can
* allocate that much.
*/
- KMALLOCS(buf, u_char *, len);
- if (buf == NULL)
- return -1;
- SPL_NET(s);
- MUTEX_ENTER(&ipl_mutex);
- if ((iplused[dev] + len) > ipl_logsize) {
- MUTEX_EXIT(&ipl_mutex);
- SPL_X(s);
- KFREES(buf, len);
+ if ((softl->ipl_used[unit] + len) > softl->ipl_logsize) {
+ softl->ipl_logfail[unit]++;
+ MUTEX_EXIT(&softl->ipl_mutex[unit]);
return -1;
}
- iplused[dev] += len;
- MUTEX_EXIT(&ipl_mutex);
- SPL_X(s);
- /*
- * advance the log pointer to the next empty record and deduct the
- * amount of space we're going to use.
- */
+ KMALLOCS(buf, caddr_t, len);
+ if (buf == NULL) {
+ softl->ipl_logfail[unit]++;
+ MUTEX_EXIT(&softl->ipl_mutex[unit]);
+ return -1;
+ }
ipl = (iplog_t *)buf;
- ipl->ipl_magic = ipl_magic[dev];
+ ipl->ipl_magic = softl->ipl_magic[unit];
ipl->ipl_count = 1;
+ ipl->ipl_seqnum = softl->ipl_counter[unit];
ipl->ipl_next = NULL;
ipl->ipl_dsize = len;
#ifdef _KERNEL
@@ -509,42 +615,71 @@ int *types, cnt;
if (types[i] == 0) {
bcopy(items[i], ptr, itemsz[i]);
} else if (types[i] == 1) {
- COPYDATA(items[i], 0, itemsz[i], (char *)ptr);
+ COPYDATA(items[i], 0, itemsz[i], ptr);
}
ptr += itemsz[i];
}
- SPL_NET(s);
- MUTEX_ENTER(&ipl_mutex);
- ipll[dev] = ipl;
- *iplh[dev] = ipl;
- iplh[dev] = &ipl->ipl_next;
+ /*
+ * 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 (softl->ipl_suppress) {
+ if ((fin != NULL) && (fin->fin_off == 0)) {
+ if ((softl->ipll[unit] != NULL) &&
+ (fin->fin_crc == softl->ipl_crc[unit].fin_crc) &&
+ bcmp((char *)fin, (char *)&softl->ipl_crc[unit],
+ FI_LCSIZE) == 0) {
+ softl->ipll[unit]->ipl_count++;
+ MUTEX_EXIT(&softl->ipl_mutex[unit]);
+ SPL_X(s);
+ KFREES(buf, len);
+ return 0;
+ }
+ bcopy((char *)fin, (char *)&softl->ipl_crc[unit],
+ FI_LCSIZE);
+ softl->ipl_crc[unit].fin_crc = fin->fin_crc;
+ } else
+ bzero((char *)&softl->ipl_crc[unit], FI_CSIZE);
+ }
+
+ /*
+ * advance the log pointer to the next empty record and deduct the
+ * amount of space we're going to use.
+ */
+ softl->ipl_logok[unit]++;
+ softl->ipll[unit] = ipl;
+ *softl->iplh[unit] = ipl;
+ softl->iplh[unit] = &ipl->ipl_next;
+ softl->ipl_used[unit] += len;
/*
* Now that the log record has been completed and added to the queue,
* wake up any listeners who may want to read it.
*/
# if SOLARIS && defined(_KERNEL)
- cv_signal(&iplwait);
- MUTEX_EXIT(&ipl_mutex);
- pollwakeup(&iplpollhead[dev], POLLRDNORM);
+ cv_signal(&softl->ipl_wait[unit]);
+ MUTEX_EXIT(&softl->ipl_mutex[unit]);
+ pollwakeup(&softc->ipf_poll_head[unit], POLLRDNORM);
# else
- MUTEX_EXIT(&ipl_mutex);
- WAKEUP(iplh, dev);
- POLLWAKEUP(dev);
+ MUTEX_EXIT(&softl->ipl_mutex[unit]);
+ WAKEUP(softl->iplh, unit);
+ POLLWAKEUP(unit);
# endif
SPL_X(s);
# ifdef IPL_SELECT
- iplog_input_ready(dev);
+ iplog_input_ready(unit);
# endif
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: ipflog_read */
-/* Returns: int - 0 == success, else error value. */
-/* Parameters: unit(I) - device we are reading from */
-/* uio(O) - pointer to information about where to store data */
+/* Function: ipf_log_read */
+/* Returns: int - 0 == success, else error value. */
+/* Parameters: softc(I) - pointer to main soft context */
+/* unit(I) - device we are reading from */
+/* uio(O) - pointer to information about where to store data */
/* */
/* Called to handle a read on an IPFilter device. Returns only complete */
/* log messages - will not partially copy a log record out to userland. */
@@ -552,38 +687,58 @@ int *types, cnt;
/* NOTE: This function will block and wait for a signal to return data if */
/* there is none present. Asynchronous I/O is not implemented. */
/* ------------------------------------------------------------------------ */
-int ipflog_read(unit, uio)
-minor_t unit;
-struct uio *uio;
+int
+ipf_log_read(softc, unit, uio)
+ ipf_main_softc_t *softc;
+ minor_t unit;
+ struct uio *uio;
{
+ ipf_log_softc_t *softl = softc->ipf_log_soft;
size_t dlen, copied;
int error = 0;
iplog_t *ipl;
SPL_INT(s);
+ if (softl->ipl_log_init == 0) {
+ IPFERROR(40007);
+ return 0;
+ }
+
/*
* Sanity checks. Make sure the minor # is valid and we're copying
* a valid chunk of data.
*/
- if (IPL_LOGMAX < unit)
+ if (IPL_LOGMAX < unit) {
+ IPFERROR(40001);
return ENXIO;
+ }
if (uio->uio_resid == 0)
return 0;
- if ((uio->uio_resid < sizeof(iplog_t)) ||
- (uio->uio_resid > ipl_logsize))
+
+ if (uio->uio_resid < sizeof(iplog_t)) {
+ IPFERROR(40002);
+ return EINVAL;
+ }
+ if (uio->uio_resid > softl->ipl_logsize) {
+ IPFERROR(40005);
return EINVAL;
+ }
/*
* Lock the log so we can snapshot the variables. Wait for a signal
* if the log is empty.
*/
SPL_NET(s);
- MUTEX_ENTER(&ipl_mutex);
+ MUTEX_ENTER(&softl->ipl_mutex[unit]);
+ softl->ipl_readers[unit]++;
- while (iplt[unit] == NULL) {
+ while (softl->ipl_log_init == 1 && softl->iplt[unit] == NULL) {
# if SOLARIS && defined(_KERNEL)
- if (!cv_wait_sig(&iplwait, &ipl_mutex.ipf_lk)) {
- MUTEX_EXIT(&ipl_mutex);
+ if (!cv_wait_sig(&softl->ipl_wait[unit],
+ &softl->ipl_mutex[unit].ipf_lk)) {
+ softl->ipl_readers[unit]--;
+ MUTEX_EXIT(&softl->ipl_mutex[unit]);
+ IPFERROR(40003);
return EINTR;
}
# else
@@ -593,114 +748,206 @@ struct uio *uio;
# ifdef IPL_SELECT
if (uio->uio_fpflags & (FNBLOCK|FNDELAY)) {
/* this is no blocking system call */
- MUTEX_EXIT(&ipl_mutex);
+ softl->ipl_readers[unit]--;
+ MUTEX_EXIT(&softl->ipl_mutex[unit]);
return 0;
}
# endif
- MUTEX_EXIT(&ipl_mutex);
- l = get_sleep_lock(&iplh[unit]);
- error = sleep(&iplh[unit], PZERO+1);
+ MUTEX_EXIT(&softl->ipl_mutex[unit]);
+ l = get_sleep_lock(&softl->iplh[unit]);
+ error = sleep(&softl->iplh[unit], PZERO+1);
spinunlock(l);
# else
# if defined(__osf__) && defined(_KERNEL)
- error = mpsleep(&iplh[unit], PSUSP|PCATCH, "iplread", 0,
- &ipl_mutex, MS_LOCK_SIMPLE);
+ error = mpsleep(&softl->iplh[unit], PSUSP|PCATCH, "ipfread", 0,
+ &softl->ipl_mutex, MS_LOCK_SIMPLE);
# else
- MUTEX_EXIT(&ipl_mutex);
+ MUTEX_EXIT(&softl->ipl_mutex[unit]);
SPL_X(s);
- error = SLEEP(unit + iplh, "ipl sleep");
+ error = SLEEP(unit + softl->iplh, "ipl sleep");
# endif /* __osf__ */
# endif /* __hpux */
- if (error)
- return error;
SPL_NET(s);
- MUTEX_ENTER(&ipl_mutex);
+ MUTEX_ENTER(&softl->ipl_mutex[unit]);
+ if (error) {
+ softl->ipl_readers[unit]--;
+ MUTEX_EXIT(&softl->ipl_mutex[unit]);
+ IPFERROR(40004);
+ return error;
+ }
# endif /* SOLARIS */
}
+ if (softl->ipl_log_init != 1) {
+ softl->ipl_readers[unit]--;
+ MUTEX_EXIT(&softl->ipl_mutex[unit]);
+ IPFERROR(40008);
+ return EIO;
+ }
-# if (BSD >= 199101) || defined(__FreeBSD__) || defined(__osf__)
+# if (defined(BSD) && (BSD >= 199101)) || defined(__FreeBSD__) || \
+ defined(__osf__)
uio->uio_rw = UIO_READ;
# endif
- for (copied = 0; (ipl = iplt[unit]) != NULL; copied += dlen) {
+ for (copied = 0; (ipl = softl->iplt[unit]) != NULL; copied += dlen) {
dlen = ipl->ipl_dsize;
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);
+ softl->iplt[unit] = ipl->ipl_next;
+ softl->ipl_used[unit] -= dlen;
+ MUTEX_EXIT(&softl->ipl_mutex[unit]);
SPL_X(s);
error = UIOMOVE(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;
+ MUTEX_ENTER(&softl->ipl_mutex[unit]);
+ IPFERROR(40006);
+ ipl->ipl_next = softl->iplt[unit];
+ softl->iplt[unit] = ipl;
+ softl->ipl_used[unit] += dlen;
break;
}
- MUTEX_ENTER(&ipl_mutex);
- KFREES(ipl, dlen);
+ MUTEX_ENTER(&softl->ipl_mutex[unit]);
+ KFREES((caddr_t)ipl, dlen);
SPL_NET(s);
}
- if (!iplt[unit]) {
- iplused[unit] = 0;
- iplh[unit] = &iplt[unit];
- ipll[unit] = NULL;
+ if (!softl->iplt[unit]) {
+ softl->ipl_used[unit] = 0;
+ softl->iplh[unit] = &softl->iplt[unit];
+ softl->ipll[unit] = NULL;
}
- MUTEX_EXIT(&ipl_mutex);
+ softl->ipl_readers[unit]--;
+ MUTEX_EXIT(&softl->ipl_mutex[unit]);
SPL_X(s);
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: ipflog_clear */
-/* Returns: int - number of log bytes cleared. */
-/* Parameters: unit(I) - device we are reading from */
+/* Function: ipf_log_clear */
+/* Returns: int - number of log bytes cleared. */
+/* Parameters: softc(I) - pointer to main soft context */
+/* unit(I) - device we are reading from */
/* */
/* Deletes all queued up log records for a given output device. */
/* ------------------------------------------------------------------------ */
-int ipflog_clear(unit)
-minor_t unit;
+int
+ipf_log_clear(softc, unit)
+ ipf_main_softc_t *softc;
+ minor_t unit;
{
+ ipf_log_softc_t *softl = softc->ipf_log_soft;
iplog_t *ipl;
int used;
SPL_INT(s);
SPL_NET(s);
- MUTEX_ENTER(&ipl_mutex);
- while ((ipl = iplt[unit]) != NULL) {
- iplt[unit] = ipl->ipl_next;
- KFREES(ipl, ipl->ipl_dsize);
+ MUTEX_ENTER(&softl->ipl_mutex[unit]);
+ while ((ipl = softl->iplt[unit]) != NULL) {
+ softl->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;
- bzero((char *)&iplcrc[unit], FI_CSIZE);
- MUTEX_EXIT(&ipl_mutex);
+ softl->iplh[unit] = &softl->iplt[unit];
+ softl->ipll[unit] = NULL;
+ used = softl->ipl_used[unit];
+ softl->ipl_used[unit] = 0;
+ bzero((char *)&softl->ipl_crc[unit], FI_CSIZE);
+ MUTEX_EXIT(&softl->ipl_mutex[unit]);
SPL_X(s);
return used;
}
/* ------------------------------------------------------------------------ */
-/* Function: ipflog_canread */
-/* Returns: int - 0 == no data to read, 1 = data present */
-/* Parameters: unit(I) - device we are reading from */
+/* Function: ipf_log_canread */
+/* Returns: int - 0 == no data to read, 1 = data present */
+/* Parameters: softc(I) - pointer to main soft context */
+/* unit(I) - device we are reading from */
/* */
/* Returns an indication of whether or not there is data present in the */
/* current buffer for the selected ipf device. */
/* ------------------------------------------------------------------------ */
-int ipflog_canread(unit)
-int unit;
+int
+ipf_log_canread(softc, unit)
+ ipf_main_softc_t *softc;
+ int unit;
{
- return iplt[unit] != NULL;
+ ipf_log_softc_t *softl = softc->ipf_log_soft;
+
+ return softl->iplt[unit] != NULL;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_log_canread */
+/* Returns: int - 0 == no data to read, 1 = data present */
+/* Parameters: softc(I) - pointer to main soft context */
+/* unit(I) - device we are reading from */
+/* */
+/* Returns how many bytes are currently held in log buffers for the */
+/* selected ipf device. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_log_bytesused(softc, unit)
+ ipf_main_softc_t *softc;
+ int unit;
+{
+ ipf_log_softc_t *softl = softc->ipf_log_soft;
+
+ if (softl == NULL)
+ return 0;
+
+ return softl->ipl_used[unit];
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_log_failures */
+/* Returns: U_QUAD_T - number of log failures */
+/* Parameters: softc(I) - pointer to main soft context */
+/* unit(I) - device we are reading from */
+/* */
+/* Returns how many times we've tried to log a packet but failed to do so */
+/* for the selected ipf device. */
+/* ------------------------------------------------------------------------ */
+u_long
+ipf_log_failures(softc, unit)
+ ipf_main_softc_t *softc;
+ int unit;
+{
+ ipf_log_softc_t *softl = softc->ipf_log_soft;
+
+ if (softl == NULL)
+ return 0;
+
+ return softl->ipl_logfail[unit];
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_log_logok */
+/* Returns: U_QUAD_T - number of packets logged */
+/* Parameters: softc(I) - pointer to main soft context */
+/* unit(I) - device we are reading from */
+/* */
+/* Returns how many times we've successfully logged a packet for the */
+/* selected ipf device. */
+/* ------------------------------------------------------------------------ */
+u_long
+ipf_log_logok(softc, unit)
+ ipf_main_softc_t *softc;
+ int unit;
+{
+ ipf_log_softc_t *softl = softc->ipf_log_soft;
+
+ if (softl == NULL)
+ return 0;
+
+ return softl->ipl_logok[unit];
}
#endif /* IPFILTER_LOG */
diff --git a/sys/contrib/ipfilter/netinet/ip_lookup.c b/sys/contrib/ipfilter/netinet/ip_lookup.c
index e33a6fe..45999e0 100644
--- a/sys/contrib/ipfilter/netinet/ip_lookup.c
+++ b/sys/contrib/ipfilter/netinet/ip_lookup.c
@@ -1,5 +1,6 @@
+/* $FreeBSD$ */
/*
- * Copyright (C) 2002-2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*/
@@ -24,7 +25,9 @@
# include <sys/ioctl.h>
#endif
#if !defined(_KERNEL)
+# include <stdio.h>
# include <string.h>
+# include <stdlib.h>
# define _KERNEL
# ifdef __OpenBSD__
struct file;
@@ -33,106 +36,223 @@ struct file;
# undef _KERNEL
#endif
#include <sys/socket.h>
-#if (defined(__osf__) || defined(AIX) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL)
-# include "radix_ipf_local.h"
-# define _RADIX_H_
-#endif
#include <net/if.h>
#if defined(__FreeBSD__)
-# include <sys/cdefs.h>
-# include <sys/proc.h>
+# include <sys/cdefs.h>
+# include <sys/proc.h>
#endif
#if defined(_KERNEL)
# include <sys/systm.h>
# if !defined(__SVR4) && !defined(__svr4__)
# include <sys/mbuf.h>
# endif
+#else
+# include "ipf.h"
#endif
#include <netinet/in.h>
#include "netinet/ip_compat.h"
#include "netinet/ip_fil.h"
+#include "netinet/ip_lookup.h"
#include "netinet/ip_pool.h"
#include "netinet/ip_htable.h"
-#include "netinet/ip_lookup.h"
+#include "netinet/ip_dstlist.h"
/* END OF INCLUDES */
#if !defined(lint)
-static const char rcsid[] = "@(#)$Id: ip_lookup.c,v 2.35.2.19 2007/10/11 09:05:51 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id$";
#endif
-#ifdef IPFILTER_LOOKUP
-int ip_lookup_inited = 0;
+/*
+ * In this file, ip_pool.c, ip_htable.c and ip_dstlist.c, you will find the
+ * range for unit is [-1,IPL_LOGMAX]. The -1 is considered to be a valid number
+ * and represents a "wildcard" or "all" units (IPL_LOGALL). The reason for not
+ * starting the numbering at 0 is because the numbers [0,IPL_LOGMAX] correspond
+ * to the minor device number for their respective device. Thus where there is
+ * array indexing on the unit, +1 is used to map [-1.IPL_LOGMAX] to
+ * [0.POOL_LOOKUP_MAX].
+ */
+static int ipf_lookup_addnode __P((ipf_main_softc_t *, caddr_t, int));
+static int ipf_lookup_delnode __P((ipf_main_softc_t *, caddr_t, int));
+static int ipf_lookup_addtable __P((ipf_main_softc_t *, caddr_t));
+static int ipf_lookup_deltable __P((ipf_main_softc_t *, caddr_t));
+static int ipf_lookup_stats __P((ipf_main_softc_t *, caddr_t));
+static int ipf_lookup_flush __P((ipf_main_softc_t *, caddr_t));
+static int ipf_lookup_iterate __P((ipf_main_softc_t *, void *, int, void *));
+static int ipf_lookup_deltok __P((ipf_main_softc_t *, void *, int, void *));
+
+#define MAX_BACKENDS 3
+static ipf_lookup_t *backends[MAX_BACKENDS] = {
+ &ipf_pool_backend,
+ &ipf_htable_backend,
+ &ipf_dstlist_backend
+};
+
-static int iplookup_addnode __P((caddr_t));
-static int iplookup_delnode __P((caddr_t data));
-static int iplookup_addtable __P((caddr_t));
-static int iplookup_deltable __P((caddr_t));
-static int iplookup_stats __P((caddr_t));
-static int iplookup_flush __P((caddr_t));
-static int iplookup_iterate __P((void *, int, void *));
-static int iplookup_deltok __P((void *, int, void *));
+typedef struct ipf_lookup_softc_s {
+ void *ipf_back[MAX_BACKENDS];
+} ipf_lookup_softc_t;
/* ------------------------------------------------------------------------ */
-/* Function: iplookup_init */
-/* Returns: int - 0 = success, else error */
-/* Parameters: Nil */
+/* Function: ipf_lookup_init */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
/* */
/* Initialise all of the subcomponents of the lookup infrstructure. */
/* ------------------------------------------------------------------------ */
-int ip_lookup_init()
+void *
+ipf_lookup_soft_create(softc)
+ ipf_main_softc_t *softc;
{
+ ipf_lookup_softc_t *softl;
+ ipf_lookup_t **l;
+ int i;
+
+ KMALLOC(softl, ipf_lookup_softc_t *);
+ if (softl == NULL)
+ return NULL;
+
+ bzero((char *)softl, sizeof(*softl));
+
+ for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
+ softl->ipf_back[i] = (*(*l)->ipfl_create)(softc);
+ if (softl->ipf_back[i] == NULL) {
+ ipf_lookup_soft_destroy(softc, softl);
+ return NULL;
+ }
+ }
+
+ return softl;
+}
+
- if (ip_pool_init() == -1)
- return -1;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_lookup_soft_init */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* Initialise all of the subcomponents of the lookup infrstructure. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_lookup_soft_init(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
+ int err = 0;
+ int i;
- RWLOCK_INIT(&ip_poolrw, "ip pool rwlock");
+ for (i = 0; i < MAX_BACKENDS; i++) {
+ err = (*backends[i]->ipfl_init)(softc, softl->ipf_back[i]);
+ if (err != 0)
+ break;
+ }
- ip_lookup_inited = 1;
+ return err;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_lookup_soft_fini */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* Call the fini function in each backend to cleanup all allocated data. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_lookup_soft_fini(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
+ int i;
+
+ for (i = 0; i < MAX_BACKENDS; i++) {
+ if (softl->ipf_back[i] != NULL)
+ (*backends[i]->ipfl_fini)(softc,
+ softl->ipf_back[i]);
+ }
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: iplookup_unload */
+/* Function: ipf_lookup_expire */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Step through each of the backends and call their expire functions, */
+/* allowing them to delete any lifetime limited data. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_lookup_expire(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
+ int i;
+
+ WRITE_ENTER(&softc->ipf_poolrw);
+ for (i = 0; i < MAX_BACKENDS; i++)
+ (*backends[i]->ipfl_expire)(softc, softl->ipf_back[i]);
+ RWLOCK_EXIT(&softc->ipf_poolrw);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_lookup_softc_destroy */
/* Returns: int - 0 = success, else error */
-/* Parameters: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
/* */
/* Free up all pool related memory that has been allocated whilst IPFilter */
/* has been running. Also, do any other deinitialisation required such */
-/* ip_lookup_init() can be called again, safely. */
+/* ipf_lookup_init() can be called again, safely. */
/* ------------------------------------------------------------------------ */
-void ip_lookup_unload()
+void
+ipf_lookup_soft_destroy(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
{
- ip_pool_fini();
- fr_htable_unload();
+ ipf_lookup_softc_t *softl = (ipf_lookup_softc_t *)arg;
+ int i;
- if (ip_lookup_inited == 1) {
- RW_DESTROY(&ip_poolrw);
- ip_lookup_inited = 0;
+ for (i = 0; i < MAX_BACKENDS; i++) {
+ if (softl->ipf_back[i] != NULL)
+ (*backends[i]->ipfl_destroy)(softc,
+ softl->ipf_back[i]);
}
+
+ KFREE(softl);
}
/* ------------------------------------------------------------------------ */
-/* Function: iplookup_ioctl */
+/* Function: ipf_lookup_ioctl */
/* Returns: int - 0 = success, else error */
-/* Parameters: data(IO) - pointer to ioctl data to be copied to/from user */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* data(IO) - pointer to ioctl data to be copied to/from user */
/* space. */
/* cmd(I) - ioctl command number */
/* mode(I) - file mode bits used with open */
+/* uid(I) - uid of process doing ioctl */
+/* ctx(I) - pointer that represents context for uid */
/* */
/* Handle ioctl commands sent to the ioctl device. For the most part, this */
/* involves just calling another function to handle the specifics of each */
/* command. */
/* ------------------------------------------------------------------------ */
-int ip_lookup_ioctl(data, cmd, mode, uid, ctx)
-caddr_t data;
-ioctlcmd_t cmd;
-int mode, uid;
-void *ctx;
+int
+ipf_lookup_ioctl(softc, data, cmd, mode, uid, ctx)
+ ipf_main_softc_t *softc;
+ caddr_t data;
+ ioctlcmd_t cmd;
+ int mode, uid;
+ void *ctx;
{
int err;
SPL_INT(s);
@@ -145,52 +265,53 @@ void *ctx;
{
case SIOCLOOKUPADDNODE :
case SIOCLOOKUPADDNODEW :
- WRITE_ENTER(&ip_poolrw);
- err = iplookup_addnode(data);
- RWLOCK_EXIT(&ip_poolrw);
+ WRITE_ENTER(&softc->ipf_poolrw);
+ err = ipf_lookup_addnode(softc, data, uid);
+ RWLOCK_EXIT(&softc->ipf_poolrw);
break;
case SIOCLOOKUPDELNODE :
case SIOCLOOKUPDELNODEW :
- WRITE_ENTER(&ip_poolrw);
- err = iplookup_delnode(data);
- RWLOCK_EXIT(&ip_poolrw);
+ WRITE_ENTER(&softc->ipf_poolrw);
+ err = ipf_lookup_delnode(softc, data, uid);
+ RWLOCK_EXIT(&softc->ipf_poolrw);
break;
case SIOCLOOKUPADDTABLE :
- WRITE_ENTER(&ip_poolrw);
- err = iplookup_addtable(data);
- RWLOCK_EXIT(&ip_poolrw);
+ WRITE_ENTER(&softc->ipf_poolrw);
+ err = ipf_lookup_addtable(softc, data);
+ RWLOCK_EXIT(&softc->ipf_poolrw);
break;
case SIOCLOOKUPDELTABLE :
- WRITE_ENTER(&ip_poolrw);
- err = iplookup_deltable(data);
- RWLOCK_EXIT(&ip_poolrw);
+ WRITE_ENTER(&softc->ipf_poolrw);
+ err = ipf_lookup_deltable(softc, data);
+ RWLOCK_EXIT(&softc->ipf_poolrw);
break;
case SIOCLOOKUPSTAT :
case SIOCLOOKUPSTATW :
- WRITE_ENTER(&ip_poolrw);
- err = iplookup_stats(data);
- RWLOCK_EXIT(&ip_poolrw);
+ WRITE_ENTER(&softc->ipf_poolrw);
+ err = ipf_lookup_stats(softc, data);
+ RWLOCK_EXIT(&softc->ipf_poolrw);
break;
case SIOCLOOKUPFLUSH :
- WRITE_ENTER(&ip_poolrw);
- err = iplookup_flush(data);
- RWLOCK_EXIT(&ip_poolrw);
+ WRITE_ENTER(&softc->ipf_poolrw);
+ err = ipf_lookup_flush(softc, data);
+ RWLOCK_EXIT(&softc->ipf_poolrw);
break;
case SIOCLOOKUPITER :
- err = iplookup_iterate(data, uid, ctx);
+ err = ipf_lookup_iterate(softc, data, uid, ctx);
break;
case SIOCIPFDELTOK :
- err = iplookup_deltok(data, uid, ctx);
+ err = ipf_lookup_deltok(softc, data, uid, ctx);
break;
default :
+ IPFERROR(50001);
err = EINVAL;
break;
}
@@ -200,192 +321,155 @@ void *ctx;
/* ------------------------------------------------------------------------ */
-/* Function: iplookup_addnode */
+/* Function: ipf_lookup_addnode */
/* Returns: int - 0 = success, else error */
-/* Parameters: data(I) - pointer to data from ioctl call */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* data(I) - pointer to data from ioctl call */
/* */
/* Add a new data node to a lookup structure. First, check to see if the */
/* parent structure refered to by name exists and if it does, then go on to */
/* add a node to it. */
/* ------------------------------------------------------------------------ */
-static int iplookup_addnode(data)
-caddr_t data;
+static int
+ipf_lookup_addnode(softc, data, uid)
+ ipf_main_softc_t *softc;
+ caddr_t data;
+ int uid;
{
- ip_pool_node_t node, *m;
+ ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
iplookupop_t op;
- iphtable_t *iph;
- iphtent_t hte;
- ip_pool_t *p;
+ ipf_lookup_t **l;
int err;
+ int i;
err = BCOPYIN(data, &op, sizeof(op));
- if (err != 0)
+ if (err != 0) {
+ IPFERROR(50002);
return EFAULT;
+ }
- if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
+ if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
+ (op.iplo_unit != IPLT_ALL)) {
+ IPFERROR(50003);
return EINVAL;
+ }
op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
- switch (op.iplo_type)
- {
- case IPLT_POOL :
- if (op.iplo_size != sizeof(node))
- return EINVAL;
-
- err = COPYIN(op.iplo_struct, &node, sizeof(node));
- if (err != 0)
- return EFAULT;
-
- p = ip_pool_find(op.iplo_unit, op.iplo_name);
- if (p == NULL)
- return ESRCH;
-
- /*
- * add an entry to a pool - return an error if it already
- * exists remove an entry from a pool - if it exists
- * - in both cases, the pool *must* exist!
- */
- m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
- if (m)
- return EEXIST;
- err = ip_pool_insert(p, &node.ipn_addr.adf_addr,
- &node.ipn_mask.adf_addr, node.ipn_info);
- break;
-
- case IPLT_HASH :
- if (op.iplo_size != sizeof(hte))
- return EINVAL;
-
- err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
- if (err != 0)
- return EFAULT;
-
- iph = fr_findhtable(op.iplo_unit, op.iplo_name);
- if (iph == NULL)
- return ESRCH;
- err = fr_addhtent(iph, &hte);
- break;
+ for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
+ if (op.iplo_type == (*l)->ipfl_type) {
+ err = (*(*l)->ipfl_node_add)(softc,
+ softl->ipf_back[i],
+ &op, uid);
+ break;
+ }
+ }
- default :
+ if (i == MAX_BACKENDS) {
+ IPFERROR(50012);
err = EINVAL;
- break;
}
+
return err;
}
/* ------------------------------------------------------------------------ */
-/* Function: iplookup_delnode */
+/* Function: ipf_lookup_delnode */
/* Returns: int - 0 = success, else error */
-/* Parameters: data(I) - pointer to data from ioctl call */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* data(I) - pointer to data from ioctl call */
/* */
/* Delete a node from a lookup table by first looking for the table it is */
/* in and then deleting the entry that gets found. */
/* ------------------------------------------------------------------------ */
-static int iplookup_delnode(data)
-caddr_t data;
+static int
+ipf_lookup_delnode(softc, data, uid)
+ ipf_main_softc_t *softc;
+ caddr_t data;
+ int uid;
{
- ip_pool_node_t node, *m;
+ ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
iplookupop_t op;
- iphtable_t *iph;
- iphtent_t hte;
- ip_pool_t *p;
+ ipf_lookup_t **l;
int err;
+ int i;
err = BCOPYIN(data, &op, sizeof(op));
- if (err != 0)
+ if (err != 0) {
+ IPFERROR(50042);
return EFAULT;
+ }
- if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
+ if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
+ (op.iplo_unit != IPLT_ALL)) {
+ IPFERROR(50013);
return EINVAL;
+ }
op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
- switch (op.iplo_type)
- {
- case IPLT_POOL :
- if (op.iplo_size != sizeof(node))
- return EINVAL;
-
- err = COPYIN(op.iplo_struct, &node, sizeof(node));
- if (err != 0)
- return EFAULT;
-
- p = ip_pool_find(op.iplo_unit, op.iplo_name);
- if (!p)
- return ESRCH;
-
- m = ip_pool_findeq(p, &node.ipn_addr, &node.ipn_mask);
- if (m == NULL)
- return ENOENT;
- err = ip_pool_remove(p, m);
- break;
-
- case IPLT_HASH :
- if (op.iplo_size != sizeof(hte))
- return EINVAL;
-
- err = COPYIN(op.iplo_struct, &hte, sizeof(hte));
- if (err != 0)
- return EFAULT;
-
- iph = fr_findhtable(op.iplo_unit, op.iplo_name);
- if (iph == NULL)
- return ESRCH;
- err = fr_delhtent(iph, &hte);
- break;
+ for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
+ if (op.iplo_type == (*l)->ipfl_type) {
+ err = (*(*l)->ipfl_node_del)(softc, softl->ipf_back[i],
+ &op, uid);
+ break;
+ }
+ }
- default :
+ if (i == MAX_BACKENDS) {
+ IPFERROR(50021);
err = EINVAL;
- break;
}
return err;
}
/* ------------------------------------------------------------------------ */
-/* Function: iplookup_addtable */
+/* Function: ipf_lookup_addtable */
/* Returns: int - 0 = success, else error */
-/* Parameters: data(I) - pointer to data from ioctl call */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* data(I) - pointer to data from ioctl call */
/* */
/* Create a new lookup table, if one doesn't already exist using the name */
/* for this one. */
/* ------------------------------------------------------------------------ */
-static int iplookup_addtable(data)
-caddr_t data;
+static int
+ipf_lookup_addtable(softc, data)
+ ipf_main_softc_t *softc;
+ caddr_t data;
{
+ ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
iplookupop_t op;
- int err;
+ ipf_lookup_t **l;
+ int err, i;
err = BCOPYIN(data, &op, sizeof(op));
- if (err != 0)
+ if (err != 0) {
+ IPFERROR(50022);
return EFAULT;
+ }
- if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
+ if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
+ (op.iplo_unit != IPLT_ALL)) {
+ IPFERROR(50023);
return EINVAL;
+ }
op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
- switch (op.iplo_type)
- {
- case IPLT_POOL :
- if (ip_pool_find(op.iplo_unit, op.iplo_name) != NULL)
- err = EEXIST;
- else
- err = ip_pool_create(&op);
- break;
-
- case IPLT_HASH :
- if (fr_findhtable(op.iplo_unit, op.iplo_name) != NULL)
- err = EEXIST;
- else
- err = fr_newhtable(&op);
- break;
+ for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
+ if (op.iplo_type == (*l)->ipfl_type) {
+ err = (*(*l)->ipfl_table_add)(softc,
+ softl->ipf_back[i],
+ &op);
+ break;
+ }
+ }
- default :
+ if (i == MAX_BACKENDS) {
+ IPFERROR(50026);
err = EINVAL;
- break;
}
/*
@@ -394,8 +478,10 @@ caddr_t data;
*/
if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) {
err = BCOPYOUT(&op, data, sizeof(op));
- if (err != 0)
+ if (err != 0) {
+ IPFERROR(50027);
err = EFAULT;
+ }
}
return err;
@@ -403,260 +489,317 @@ caddr_t data;
/* ------------------------------------------------------------------------ */
-/* Function: iplookup_deltable */
+/* Function: ipf_lookup_deltable */
/* Returns: int - 0 = success, else error */
-/* Parameters: data(I) - pointer to data from ioctl call */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* data(I) - pointer to data from ioctl call */
/* */
/* Decodes ioctl request to remove a particular hash table or pool and */
/* calls the relevant function to do the cleanup. */
/* ------------------------------------------------------------------------ */
-static int iplookup_deltable(data)
-caddr_t data;
+static int
+ipf_lookup_deltable(softc, data)
+ ipf_main_softc_t *softc;
+ caddr_t data;
{
+ ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
iplookupop_t op;
- int err;
+ ipf_lookup_t **l;
+ int err, i;
err = BCOPYIN(data, &op, sizeof(op));
- if (err != 0)
+ if (err != 0) {
+ IPFERROR(50028);
return EFAULT;
+ }
- if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
+ if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
+ (op.iplo_unit != IPLT_ALL)) {
+ IPFERROR(50029);
return EINVAL;
+ }
op.iplo_name[sizeof(op.iplo_name) - 1] = '\0';
- /*
- * create a new pool - fail if one already exists with
- * the same #
- */
- switch (op.iplo_type)
- {
- case IPLT_POOL :
- err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
- break;
-
- case IPLT_HASH :
- err = fr_removehtable(op.iplo_unit, op.iplo_name);
- break;
+ for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
+ if (op.iplo_type == (*l)->ipfl_type) {
+ err = (*(*l)->ipfl_table_del)(softc,
+ softl->ipf_back[i],
+ &op);
+ break;
+ }
+ }
- default :
+ if (i == MAX_BACKENDS) {
+ IPFERROR(50030);
err = EINVAL;
- break;
}
return err;
}
/* ------------------------------------------------------------------------ */
-/* Function: iplookup_stats */
+/* Function: ipf_lookup_stats */
/* Returns: int - 0 = success, else error */
-/* Parameters: data(I) - pointer to data from ioctl call */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* data(I) - pointer to data from ioctl call */
/* */
/* Copy statistical information from inside the kernel back to user space. */
/* ------------------------------------------------------------------------ */
-static int iplookup_stats(data)
-caddr_t data;
+static int
+ipf_lookup_stats(softc, data)
+ ipf_main_softc_t *softc;
+ caddr_t data;
{
+ ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
iplookupop_t op;
+ ipf_lookup_t **l;
int err;
+ int i;
err = BCOPYIN(data, &op, sizeof(op));
- if (err != 0)
+ if (err != 0) {
+ IPFERROR(50031);
return EFAULT;
+ }
- if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX)
+ if ((op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) &&
+ (op.iplo_unit != IPLT_ALL)) {
+ IPFERROR(50032);
return EINVAL;
+ }
- switch (op.iplo_type)
- {
- case IPLT_POOL :
- err = ip_pool_statistics(&op);
- break;
-
- case IPLT_HASH :
- err = fr_gethtablestat(&op);
- break;
+ for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
+ if (op.iplo_type == (*l)->ipfl_type) {
+ err = (*(*l)->ipfl_stats_get)(softc,
+ softl->ipf_back[i],
+ &op);
+ break;
+ }
+ }
- default :
+ if (i == MAX_BACKENDS) {
+ IPFERROR(50033);
err = EINVAL;
- break;
}
+
return err;
}
/* ------------------------------------------------------------------------ */
-/* Function: iplookup_flush */
+/* Function: ipf_lookup_flush */
/* Returns: int - 0 = success, else error */
-/* Parameters: data(I) - pointer to data from ioctl call */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* data(I) - pointer to data from ioctl call */
/* */
/* A flush is called when we want to flush all the nodes from a particular */
/* entry in the hash table/pool or want to remove all groups from those. */
/* ------------------------------------------------------------------------ */
-static int iplookup_flush(data)
-caddr_t data;
+static int
+ipf_lookup_flush(softc, data)
+ ipf_main_softc_t *softc;
+ caddr_t data;
{
- int err, unit, num, type;
+ ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
+ int err, unit, num, type, i;
iplookupflush_t flush;
+ ipf_lookup_t **l;
err = BCOPYIN(data, &flush, sizeof(flush));
- if (err != 0)
+ if (err != 0) {
+ IPFERROR(50034);
return EFAULT;
+ }
unit = flush.iplf_unit;
- if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL))
+ if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL)) {
+ IPFERROR(50035);
return EINVAL;
+ }
flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0';
type = flush.iplf_type;
+ IPFERROR(50036);
err = EINVAL;
num = 0;
- if (type == IPLT_POOL || type == IPLT_ALL) {
- err = 0;
- num = ip_pool_flush(&flush);
- }
-
- if (type == IPLT_HASH || type == IPLT_ALL) {
- err = 0;
- num += fr_flushhtable(&flush);
+ for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
+ if (type == (*l)->ipfl_type || type == IPLT_ALL) {
+ err = 0;
+ num += (*(*l)->ipfl_flush)(softc,
+ softl->ipf_back[i],
+ &flush);
+ }
}
if (err == 0) {
flush.iplf_count = num;
err = BCOPYOUT(&flush, data, sizeof(flush));
- if (err != 0)
+ if (err != 0) {
+ IPFERROR(50037);
err = EFAULT;
+ }
}
return err;
}
/* ------------------------------------------------------------------------ */
-/* Function: ip_lookup_delref */
+/* Function: ipf_lookup_delref */
/* Returns: void */
-/* Parameters: type(I) - table type to operate on */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* type(I) - table type to operate on */
/* ptr(I) - pointer to object to remove reference for */
/* */
/* This function organises calling the correct deref function for a given */
/* type of object being passed into it. */
/* ------------------------------------------------------------------------ */
-void ip_lookup_deref(type, ptr)
-int type;
-void *ptr;
+void
+ipf_lookup_deref(softc, type, ptr)
+ ipf_main_softc_t *softc;
+ int type;
+ void *ptr;
{
+ ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
+ int i;
+
if (ptr == NULL)
return;
- WRITE_ENTER(&ip_poolrw);
- switch (type)
- {
- case IPLT_POOL :
- ip_pool_deref(ptr);
- break;
-
- case IPLT_HASH :
- fr_derefhtable(ptr);
- break;
+ for (i = 0; i < MAX_BACKENDS; i++) {
+ if (type == backends[i]->ipfl_type) {
+ WRITE_ENTER(&softc->ipf_poolrw);
+ (*backends[i]->ipfl_table_deref)(softc,
+ softl->ipf_back[i],
+ ptr);
+ RWLOCK_EXIT(&softc->ipf_poolrw);
+ break;
+ }
}
- RWLOCK_EXIT(&ip_poolrw);
}
/* ------------------------------------------------------------------------ */
-/* Function: iplookup_iterate */
+/* Function: ipf_lookup_iterate */
/* Returns: int - 0 = success, else error */
-/* Parameters: data(I) - pointer to data from ioctl call */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* data(I) - pointer to data from ioctl call */
/* uid(I) - uid of caller */
/* ctx(I) - pointer to give the uid context */
/* */
/* Decodes ioctl request to step through either hash tables or pools. */
/* ------------------------------------------------------------------------ */
-static int iplookup_iterate(data, uid, ctx)
-void *data;
-int uid;
-void *ctx;
+static int
+ipf_lookup_iterate(softc, data, uid, ctx)
+ ipf_main_softc_t *softc;
+ void *data;
+ int uid;
+ void *ctx;
{
+ ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
ipflookupiter_t iter;
ipftoken_t *token;
- int err;
+ int err, i;
SPL_INT(s);
- err = fr_inobj(data, &iter, IPFOBJ_LOOKUPITER);
+ err = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_LOOKUPITER);
if (err != 0)
return err;
- if (iter.ili_unit > IPL_LOGMAX)
+ if (iter.ili_unit < IPL_LOGALL && iter.ili_unit > IPL_LOGMAX) {
+ IPFERROR(50038);
return EINVAL;
+ }
- if (iter.ili_ival != IPFGENITER_LOOKUP)
+ if (iter.ili_ival != IPFGENITER_LOOKUP) {
+ IPFERROR(50039);
return EINVAL;
+ }
SPL_SCHED(s);
- token = ipf_findtoken(iter.ili_key, uid, ctx);
+ token = ipf_token_find(softc, iter.ili_key, uid, ctx);
if (token == NULL) {
- RWLOCK_EXIT(&ipf_tokens);
SPL_X(s);
+ IPFERROR(50040);
return ESRCH;
}
- switch (iter.ili_type)
- {
- case IPLT_POOL :
- err = ip_pool_getnext(token, &iter);
- break;
- case IPLT_HASH :
- err = fr_htable_getnext(token, &iter);
- break;
- default :
- err = EINVAL;
- break;
+ for (i = 0; i < MAX_BACKENDS; i++) {
+ if (iter.ili_type == backends[i]->ipfl_type) {
+ err = (*backends[i]->ipfl_iter_next)(softc,
+ softl->ipf_back[i],
+ token, &iter);
+ break;
+ }
}
- RWLOCK_EXIT(&ipf_tokens);
SPL_X(s);
+ if (i == MAX_BACKENDS) {
+ IPFERROR(50041);
+ err = EINVAL;
+ }
+
+ WRITE_ENTER(&softc->ipf_tokens);
+ ipf_token_deref(softc, token);
+ RWLOCK_EXIT(&softc->ipf_tokens);
+
return err;
}
/* ------------------------------------------------------------------------ */
-/* Function: iplookup_iterderef */
-/* Returns: int - 0 = success, else error */
-/* Parameters: data(I) - pointer to data from ioctl call */
+/* Function: ipf_lookup_iterderef */
+/* Returns: void */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* type(I) - backend type to iterate through */
+/* data(I) - pointer to data from ioctl call */
/* */
/* Decodes ioctl request to remove a particular hash table or pool and */
/* calls the relevant function to do the cleanup. */
+/* Because each of the backend types has a different data structure, */
+/* iteration is limited to one type at a time (i.e. it is not permitted to */
+/* go on from pool types to hash types as part of the "get next".) */
/* ------------------------------------------------------------------------ */
-void ip_lookup_iterderef(type, data)
-u_32_t type;
-void *data;
+void
+ipf_lookup_iterderef(softc, type, data)
+ ipf_main_softc_t *softc;
+ u_32_t type;
+ void *data;
{
- iplookupiterkey_t key;
+ ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
+ struct iplookupiterkey *lkey;
+ iplookupiterkey_t key;
+ int i;
key.ilik_key = type;
+ lkey = &key.ilik_unstr;
- if (key.ilik_unstr.ilik_ival != IPFGENITER_LOOKUP)
+ if (lkey->ilik_ival != IPFGENITER_LOOKUP)
return;
- switch (key.ilik_unstr.ilik_type)
- {
- case IPLT_HASH :
- fr_htable_iterderef((u_int)key.ilik_unstr.ilik_otype,
- (int)key.ilik_unstr.ilik_unit, data);
- break;
- case IPLT_POOL :
- ip_pool_iterderef((u_int)key.ilik_unstr.ilik_otype,
- (int)key.ilik_unstr.ilik_unit, data);
- break;
+ WRITE_ENTER(&softc->ipf_poolrw);
+
+ for (i = 0; i < MAX_BACKENDS; i++) {
+ if (lkey->ilik_type == backends[i]->ipfl_type) {
+ (*backends[i]->ipfl_iter_deref)(softc,
+ softl->ipf_back[i],
+ lkey->ilik_otype,
+ lkey->ilik_unit,
+ data);
+ break;
+ }
}
+ RWLOCK_EXIT(&softc->ipf_poolrw);
}
/* ------------------------------------------------------------------------ */
-/* Function: iplookup_deltok */
+/* Function: ipf_lookup_deltok */
/* Returns: int - 0 = success, else error */
-/* Parameters: data(I) - pointer to data from ioctl call */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* data(I) - pointer to data from ioctl call */
/* uid(I) - uid of caller */
/* ctx(I) - pointer to give the uid context */
/* */
@@ -664,32 +807,198 @@ void *data;
/* "key" is a combination of the table type, iterator type and the unit for */
/* which the token was being used. */
/* ------------------------------------------------------------------------ */
-static int iplookup_deltok(data, uid, ctx)
-void *data;
-int uid;
-void *ctx;
+int
+ipf_lookup_deltok(softc, data, uid, ctx)
+ ipf_main_softc_t *softc;
+ void *data;
+ int uid;
+ void *ctx;
{
int error, key;
SPL_INT(s);
SPL_SCHED(s);
- error = BCOPYIN(data, &key, sizeof(key));
+ error = BCOPYIN(data, &key, sizeof(key));
if (error == 0)
- error = ipf_deltoken(key, uid, ctx);
+ error = ipf_token_del(softc, key, uid, ctx);
SPL_X(s);
return error;
}
-#else /* IPFILTER_LOOKUP */
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_lookup_res_num */
+/* Returns: void * - NULL = failure, else success. */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* unit(I) - device for which this is for */
+/* type(I) - type of lookup these parameters are for. */
+/* number(I) - table number to use when searching */
+/* funcptr(IO) - pointer to pointer for storing IP address */
+/* searching function. */
+/* */
+/* Search for the "table" number passed in amongst those configured for */
+/* that particular type. If the type is recognised then the function to */
+/* call to do the IP address search will be change, regardless of whether */
+/* or not the "table" number exists. */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_lookup_res_num(softc, unit, type, number, funcptr)
+ ipf_main_softc_t *softc;
+ int unit;
+ u_int type;
+ u_int number;
+ lookupfunc_t *funcptr;
+{
+ char name[FR_GROUPLEN];
+
+#if defined(SNPRINTF) && defined(_KERNEL)
+ SNPRINTF(name, sizeof(name), "%u", number);
+#else
+ (void) sprintf(name, "%u", number);
+#endif
+
+ return ipf_lookup_res_name(softc, unit, type, name, funcptr);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_lookup_res_name */
+/* Returns: void * - NULL = failure, else success. */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* unit(I) - device for which this is for */
+/* type(I) - type of lookup these parameters are for. */
+/* name(I) - table name to use when searching */
+/* funcptr(IO) - pointer to pointer for storing IP address */
+/* searching function. */
+/* */
+/* Search for the "table" number passed in amongst those configured for */
+/* that particular type. If the type is recognised then the function to */
+/* call to do the IP address search will be changed, regardless of whether */
+/* or not the "table" number exists. */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_lookup_res_name(softc, unit, type, name, funcptr)
+ ipf_main_softc_t *softc;
+ int unit;
+ u_int type;
+ char *name;
+ lookupfunc_t *funcptr;
+{
+ ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
+ ipf_lookup_t **l;
+ void *ptr = NULL;
+ int i;
+
+ READ_ENTER(&softc->ipf_poolrw);
+
+ for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++) {
+ if (type == (*l)->ipfl_type) {
+ ptr = (*(*l)->ipfl_select_add_ref)(softl->ipf_back[i],
+ unit, name);
+ if (ptr != NULL && funcptr != NULL) {
+ *funcptr = (*l)->ipfl_addr_find;
+ }
+ break;
+ }
+ }
+
+ if (i == MAX_BACKENDS) {
+ ptr = NULL;
+ if (funcptr != NULL)
+ *funcptr = NULL;
+ }
+
+ RWLOCK_EXIT(&softc->ipf_poolrw);
+
+ return ptr;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_lookup_find_htable */
+/* Returns: void * - NULL = failure, else success. */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* unit(I) - device for which this is for */
+/* name(I) - table name to use when searching */
+/* */
+/* To support the group-map feature, where a hash table maps address */
+/* networks to rule group numbers, we need to expose a function that uses */
+/* only the hash table backend. */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_lookup_find_htable(softc, unit, name)
+ ipf_main_softc_t *softc;
+ int unit;
+ char *name;
+{
+ ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
+ ipf_lookup_t **l;
+ void *tab = NULL;
+ int i;
+
+ READ_ENTER(&softc->ipf_poolrw);
+
+ for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
+ if (IPLT_HASH == (*l)->ipfl_type) {
+ tab = ipf_htable_find(softl->ipf_back[i], unit, name);
+ break;
+ }
+
+ RWLOCK_EXIT(&softc->ipf_poolrw);
+
+ return tab;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_lookup_sync */
+/* Returns: void */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* This function is the interface that the machine dependent sync functions */
+/* call when a network interface name change occurs. It then calls the sync */
+/* functions of the lookup implementations - if they have one. */
+/* ------------------------------------------------------------------------ */
/*ARGSUSED*/
-int ip_lookup_ioctl(data, cmd, mode, uid, ctx)
-caddr_t data;
-ioctlcmd_t cmd;
-int mode, uid;
-void *ctx;
+void
+ipf_lookup_sync(softc, ifp)
+ ipf_main_softc_t *softc;
+ void *ifp;
{
- return EIO;
+ ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
+ ipf_lookup_t **l;
+ int i;
+
+ READ_ENTER(&softc->ipf_poolrw);
+
+ for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
+ if ((*l)->ipfl_sync != NULL)
+ (*(*l)->ipfl_sync)(softc, softl->ipf_back[i]);
+
+ RWLOCK_EXIT(&softc->ipf_poolrw);
}
-#endif /* IPFILTER_LOOKUP */
+
+
+#ifndef _KERNEL
+void
+ipf_lookup_dump(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_lookup_softc_t *softl = softc->ipf_lookup_soft;
+ ipf_lookup_t **l;
+ int i;
+
+ for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
+ if (IPLT_POOL == (*l)->ipfl_type) {
+ ipf_pool_dump(softc, softl->ipf_back[i]);
+ break;
+ }
+
+ for (i = 0, l = backends; i < MAX_BACKENDS; i++, l++)
+ if (IPLT_HASH == (*l)->ipfl_type) {
+ ipf_htable_dump(softc, softl->ipf_back[i]);
+ break;
+ }
+}
+#endif
diff --git a/sys/contrib/ipfilter/netinet/ip_lookup.h b/sys/contrib/ipfilter/netinet/ip_lookup.h
index 3886df1..181e1bc 100644
--- a/sys/contrib/ipfilter/netinet/ip_lookup.h
+++ b/sys/contrib/ipfilter/netinet/ip_lookup.h
@@ -1,4 +1,10 @@
-
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
#ifndef __IP_LOOKUP_H__
#define __IP_LOOKUP_H__
@@ -24,6 +30,9 @@
# define SIOCLOOKUPDELNODEW _IOW(r, 68, struct iplookupop)
#endif
+#define LOOKUP_POOL_MAX (IPL_LOGSIZE)
+#define LOOKUP_POOL_SZ (IPL_LOGSIZE + 1)
+
typedef struct iplookupop {
int iplo_type; /* IPLT_* */
int iplo_unit; /* IPL_LOG* */
@@ -40,7 +49,7 @@ typedef struct iplookupflush {
int iplf_type; /* IPLT_* */
int iplf_unit; /* IPL_LOG* */
u_int iplf_arg;
- size_t iplf_count;
+ u_int iplf_count;
char iplf_name[FR_GROUPLEN];
} iplookupflush_t;
@@ -55,16 +64,18 @@ typedef struct iplookuplink {
#define IPLT_NONE 0
#define IPLT_POOL 1
#define IPLT_HASH 2
+#define IPLT_DSTLIST 3
+
#define IPLT_ANON 0x80000000
typedef union {
struct iplookupiterkey {
- char ilik_ival;
+ u_char ilik_ival;
u_char ilik_type; /* IPLT_* */
u_char ilik_otype;
- u_char ilik_unit; /* IPL_LOG* */
+ signed char ilik_unit; /* IPL_LOG* */
} ilik_unstr;
u_32_t ilik_key;
} iplookupiterkey_t;
@@ -86,10 +97,56 @@ typedef struct ipflookupiter {
#define IPFLOOKUPITER_NODE 1
-extern int ip_lookup_init __P((void));
-extern int ip_lookup_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *));
-extern void ip_lookup_unload __P((void));
-extern void ip_lookup_deref __P((int, void *));
-extern void ip_lookup_iterderef __P((u_32_t, void *));
-
+typedef struct ipf_lookup {
+ int ipfl_type;
+ void *(*ipfl_create) __P((ipf_main_softc_t *));
+ void (*ipfl_destroy) __P((ipf_main_softc_t *, void *));
+ int (*ipfl_init) __P((ipf_main_softc_t *, void *));
+ void (*ipfl_fini) __P((ipf_main_softc_t *, void *));
+ int (*ipfl_addr_find) __P((ipf_main_softc_t *, void *,
+ int, void *, u_int));
+ size_t (*ipfl_flush) __P((ipf_main_softc_t *, void *,
+ iplookupflush_t *));
+ int (*ipfl_iter_deref) __P((ipf_main_softc_t *, void *,
+ int, int, void *));
+ int (*ipfl_iter_next) __P((ipf_main_softc_t *, void *,
+ ipftoken_t *, ipflookupiter_t *));
+ int (*ipfl_node_add) __P((ipf_main_softc_t *, void *,
+ iplookupop_t *, int));
+ int (*ipfl_node_del) __P((ipf_main_softc_t *, void *,
+ iplookupop_t *, int));
+ int (*ipfl_stats_get) __P((ipf_main_softc_t *, void *,
+ iplookupop_t *));
+ int (*ipfl_table_add) __P((ipf_main_softc_t *, void *,
+ iplookupop_t *));
+ int (*ipfl_table_del) __P((ipf_main_softc_t *, void *,
+ iplookupop_t *));
+ int (*ipfl_table_deref) __P((ipf_main_softc_t *, void *, void *));
+ void *(*ipfl_table_find) __P((void *, int, char *));
+ void *(*ipfl_select_add_ref) __P((void *, int, char *));
+ int (*ipfl_select_node) __P((fr_info_t *, void *, u_32_t *,
+ frdest_t *));
+ void (*ipfl_expire) __P((ipf_main_softc_t *, void *));
+ void (*ipfl_sync) __P((ipf_main_softc_t *, void *));
+} ipf_lookup_t;
+
+extern int ipf_lookup_init __P((void));
+extern int ipf_lookup_ioctl __P((ipf_main_softc_t *, caddr_t, ioctlcmd_t, int, int, void *));
+extern void ipf_lookup_main_unload __P((void));
+extern void ipf_lookup_deref __P((ipf_main_softc_t *, int, void *));
+extern void ipf_lookup_iterderef __P((ipf_main_softc_t *, u_32_t, void *));
+extern void *ipf_lookup_res_name __P((ipf_main_softc_t *, int, u_int, char *,
+ lookupfunc_t *));
+extern void *ipf_lookup_res_num __P((ipf_main_softc_t *, int, u_int, u_int,
+ lookupfunc_t *));
+extern void ipf_lookup_soft_destroy __P((ipf_main_softc_t *, void *));
+extern void *ipf_lookup_soft_create __P((ipf_main_softc_t *));
+extern int ipf_lookup_soft_init __P((ipf_main_softc_t *, void *));
+extern int ipf_lookup_soft_fini __P((ipf_main_softc_t *, void *));
+extern void *ipf_lookup_find_htable __P((ipf_main_softc_t *, int, char *));
+extern void ipf_lookup_expire __P((ipf_main_softc_t *));
+extern void ipf_lookup_sync __P((ipf_main_softc_t *, void *));
+#ifndef _KERNEL
+extern void ipf_lookup_dump __P((ipf_main_softc_t *, void *));
+#endif
#endif /* __IP_LOOKUP_H__ */
diff --git a/sys/contrib/ipfilter/netinet/ip_nat.c b/sys/contrib/ipfilter/netinet/ip_nat.c
index f790c7d..d664708 100644
--- a/sys/contrib/ipfilter/netinet/ip_nat.c
+++ b/sys/contrib/ipfilter/netinet/ip_nat.c
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1995-2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*/
@@ -16,30 +16,23 @@
#include <sys/param.h>
#include <sys/time.h>
#include <sys/file.h>
-#if defined(_KERNEL) && defined(__NetBSD_Version__) && \
- (__NetBSD_Version__ >= 399002000)
+#if defined(_KERNEL) && \
+ (defined(__NetBSD_Version) && (__NetBSD_Version >= 399002000))
# include <sys/kauth.h>
#endif
-#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
- defined(_KERNEL)
-#if defined(__NetBSD_Version__) && (__NetBSD_Version__ < 399001400)
-# include "opt_ipfilter_log.h"
-# else
-# include "opt_ipfilter.h"
-# endif
-#endif
#if !defined(_KERNEL)
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
-# define _KERNEL
-# ifdef __OpenBSD__
+# define KERNEL
+# ifdef _OpenBSD__
struct file;
# endif
# include <sys/uio.h>
-# undef _KERNEL
+# undef KERNEL
#endif
-#if defined(_KERNEL) && (__FreeBSD_version >= 220000)
+#if defined(_KERNEL) && \
+ defined(__FreeBSD_version) && (__FreeBSD_version >= 220000)
# include <sys/filio.h>
# include <sys/fcntl.h>
#else
@@ -61,7 +54,7 @@ struct file;
#if defined(__SVR4) || defined(__svr4__)
# include <sys/filio.h>
# include <sys/byteorder.h>
-# ifdef _KERNEL
+# ifdef KERNEL
# include <sys/dditypes.h>
# endif
# include <sys/stream.h>
@@ -73,14 +66,10 @@ struct file;
#include <net/if.h>
#if __FreeBSD_version >= 300000
# include <net/if_var.h>
-# if defined(_KERNEL) && !defined(IPFILTER_LKM)
-# include "opt_ipfilter.h"
-# endif
#endif
#ifdef sun
# include <net/af.h>
#endif
-#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
@@ -99,17 +88,23 @@ extern struct ifnet vpnif;
#include <netinet/ip_icmp.h>
#include "netinet/ip_compat.h"
#include <netinet/tcpip.h>
+#include "netinet/ipl.h"
#include "netinet/ip_fil.h"
#include "netinet/ip_nat.h"
#include "netinet/ip_frag.h"
#include "netinet/ip_state.h"
#include "netinet/ip_proxy.h"
-#ifdef IPFILTER_SYNC
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_dstlist.h"
#include "netinet/ip_sync.h"
-#endif
-#if (__FreeBSD_version >= 300000)
+#if FREEBSD_GE_REV(300000)
# include <sys/malloc.h>
#endif
+#ifdef HAS_SYS_MD5_H
+# include <sys/md5.h>
+#else
+# include "md5.h"
+#endif
/* END OF INCLUDES */
#undef SOCKADDR_IN
@@ -122,195 +117,396 @@ static const char rcsid[] = "@(#)$FreeBSD$";
#endif
+#define NATFSUM(n,v,f) ((v) == 4 ? (n)->f.in4.s_addr : (n)->f.i6[0] + \
+ (n)->f.i6[1] + (n)->f.i6[2] + (n)->f.i6[3])
+#define NBUMP(x) softn->(x)++
+#define NBUMPD(x, y) do { \
+ softn->x.y++; \
+ DT(y); \
+ } while (0)
+#define NBUMPSIDE(y,x) softn->ipf_nat_stats.ns_side[y].x++
+#define NBUMPSIDED(y,x) do { softn->ipf_nat_stats.ns_side[y].x++; \
+ DT(x); } while (0)
+#define NBUMPSIDEX(y,x,z) \
+ do { softn->ipf_nat_stats.ns_side[y].x++; \
+ DT(z); } while (0)
+#define NBUMPSIDEDF(y,x)do { softn->ipf_nat_stats.ns_side[y].x++; \
+ DT1(x, fr_info_t *, fin); } while (0)
+
+frentry_t ipfnatblock;
+
+static ipftuneable_t ipf_nat_tuneables[] = {
+ /* nat */
+ { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_lock) },
+ "nat_lock", 0, 1,
+ stsizeof(ipf_nat_softc_t, ipf_nat_lock),
+ IPFT_RDONLY, NULL, NULL },
+ { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_sz) },
+ "nat_table_size", 1, 0x7fffffff,
+ stsizeof(ipf_nat_softc_t, ipf_nat_table_sz),
+ 0, NULL, ipf_nat_rehash },
+ { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_max) },
+ "nat_table_max", 1, 0x7fffffff,
+ stsizeof(ipf_nat_softc_t, ipf_nat_table_max),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maprules_sz) },
+ "nat_rules_size", 1, 0x7fffffff,
+ stsizeof(ipf_nat_softc_t, ipf_nat_maprules_sz),
+ 0, NULL, ipf_nat_rehash_rules },
+ { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_rdrrules_sz) },
+ "rdr_rules_size", 1, 0x7fffffff,
+ stsizeof(ipf_nat_softc_t, ipf_nat_rdrrules_sz),
+ 0, NULL, ipf_nat_rehash_rules },
+ { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_hostmap_sz) },
+ "hostmap_size", 1, 0x7fffffff,
+ stsizeof(ipf_nat_softc_t, ipf_nat_hostmap_sz),
+ 0, NULL, ipf_nat_hostmap_rehash },
+ { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maxbucket) },
+ "nat_maxbucket",1, 0x7fffffff,
+ stsizeof(ipf_nat_softc_t, ipf_nat_maxbucket),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_logging) },
+ "nat_logging", 0, 1,
+ stsizeof(ipf_nat_softc_t, ipf_nat_logging),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_doflush) },
+ "nat_doflush", 0, 1,
+ stsizeof(ipf_nat_softc_t, ipf_nat_doflush),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_low) },
+ "nat_table_wm_low", 1, 99,
+ stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_low),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_high) },
+ "nat_table_wm_high", 2, 100,
+ stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_high),
+ 0, NULL, NULL },
+ { { 0 },
+ NULL, 0, 0,
+ 0,
+ 0, NULL, NULL }
+};
+
/* ======================================================================== */
/* How the NAT is organised and works. */
/* */
/* Inside (interface y) NAT Outside (interface x) */
/* -------------------- -+- ------------------------------------- */
-/* Packet going | out, processsed by fr_checknatout() for x */
+/* Packet going | out, processsed by ipf_nat_checkout() for x */
/* ------------> | ------------> */
/* src=10.1.1.1 | src=192.1.1.1 */
/* | */
-/* | in, processed by fr_checknatin() for x */
+/* | in, processed by ipf_nat_checkin() for x */
/* <------------ | <------------ */
/* dst=10.1.1.1 | dst=192.1.1.1 */
/* -------------------- -+- ------------------------------------- */
-/* fr_checknatout() - changes ip_src and if required, sport */
+/* ipf_nat_checkout() - changes ip_src and if required, sport */
/* - creates a new mapping, if required. */
-/* fr_checknatin() - changes ip_dst and if required, dport */
+/* ipf_nat_checkin() - changes ip_dst and if required, dport */
/* */
/* In the NAT table, internal source is recorded as "in" and externally */
/* seen as "out". */
/* ======================================================================== */
-nat_t **nat_table[2] = { NULL, NULL },
- *nat_instances = NULL;
-ipnat_t *nat_list = NULL;
-u_int ipf_nattable_max = NAT_TABLE_MAX;
-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_int fr_nat_maxbucket = 0,
- fr_nat_maxbucket_reset = 1;
-u_32_t nat_masks = 0;
-u_32_t rdr_masks = 0;
-u_long nat_last_force_flush = 0;
-ipnat_t **nat_rules = NULL;
-ipnat_t **rdr_rules = NULL;
-hostmap_t **ipf_hm_maptable = NULL;
-hostmap_t *ipf_hm_maplist = NULL;
-ipftq_t nat_tqb[IPF_TCP_NSTATES];
-ipftq_t nat_udptq;
-ipftq_t nat_icmptq;
-ipftq_t nat_iptq;
-ipftq_t *nat_utqe = NULL;
-int fr_nat_doflush = 0;
+#if SOLARIS && !defined(INSTANCES)
+extern int pfil_delayed_copy;
+#endif
+
+static int ipf_nat_flush_entry __P((ipf_main_softc_t *, void *));
+static int ipf_nat_getent __P((ipf_main_softc_t *, caddr_t, int));
+static int ipf_nat_getsz __P((ipf_main_softc_t *, caddr_t, int));
+static int ipf_nat_putent __P((ipf_main_softc_t *, caddr_t, int));
+static void ipf_nat_addmap __P((ipf_nat_softc_t *, ipnat_t *));
+static void ipf_nat_addrdr __P((ipf_nat_softc_t *, ipnat_t *));
+static int ipf_nat_builddivertmp __P((ipf_nat_softc_t *, ipnat_t *));
+static int ipf_nat_clearlist __P((ipf_main_softc_t *, ipf_nat_softc_t *));
+static int ipf_nat_cmp_rules __P((ipnat_t *, ipnat_t *));
+static int ipf_nat_decap __P((fr_info_t *, nat_t *));
+static void ipf_nat_delrule __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+ ipnat_t *, int));
+static int ipf_nat_extraflush __P((ipf_main_softc_t *, ipf_nat_softc_t *, int));
+static int ipf_nat_finalise __P((fr_info_t *, nat_t *));
+static int ipf_nat_flushtable __P((ipf_main_softc_t *, ipf_nat_softc_t *));
+static int ipf_nat_getnext __P((ipf_main_softc_t *, ipftoken_t *,
+ ipfgeniter_t *, ipfobj_t *));
+static int ipf_nat_gettable __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+ char *));
+static hostmap_t *ipf_nat_hostmap __P((ipf_nat_softc_t *, ipnat_t *,
+ struct in_addr, struct in_addr,
+ struct in_addr, u_32_t));
+static int ipf_nat_icmpquerytype __P((int));
+static int ipf_nat_iterator __P((ipf_main_softc_t *, ipftoken_t *,
+ ipfgeniter_t *, ipfobj_t *));
+static int ipf_nat_match __P((fr_info_t *, ipnat_t *));
+static int ipf_nat_matcharray __P((nat_t *, int *, u_long));
+static int ipf_nat_matchflush __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+ caddr_t));
+static void ipf_nat_mssclamp __P((tcphdr_t *, u_32_t, fr_info_t *,
+ u_short *));
+static int ipf_nat_newmap __P((fr_info_t *, nat_t *, natinfo_t *));
+static int ipf_nat_newdivert __P((fr_info_t *, nat_t *, natinfo_t *));
+static int ipf_nat_newrdr __P((fr_info_t *, nat_t *, natinfo_t *));
+static int ipf_nat_newrewrite __P((fr_info_t *, nat_t *, natinfo_t *));
+static int ipf_nat_nextaddr __P((fr_info_t *, nat_addr_t *, u_32_t *,
+ u_32_t *));
+static int ipf_nat_nextaddrinit __P((ipf_main_softc_t *, char *,
+ nat_addr_t *, int, void *));
+static int ipf_nat_resolverule __P((ipf_main_softc_t *, ipnat_t *));
+static int ipf_nat_ruleaddrinit __P((ipf_main_softc_t *,
+ ipf_nat_softc_t *, ipnat_t *));
+static void ipf_nat_rule_fini __P((ipf_main_softc_t *, ipnat_t *));
+static int ipf_nat_rule_init __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+ ipnat_t *));
+static int ipf_nat_siocaddnat __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+ ipnat_t *, int));
+static void ipf_nat_siocdelnat __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+ ipnat_t *, int));
+static void ipf_nat_tabmove __P((ipf_nat_softc_t *, nat_t *));
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_main_load */
+/* Returns: int - 0 == success, -1 == failure */
+/* Parameters: Nil */
+/* */
+/* The only global NAT structure that needs to be initialised is the filter */
+/* rule that is used with blocking packets. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat_main_load()
+{
+ bzero((char *)&ipfnatblock, sizeof(ipfnatblock));
+ ipfnatblock.fr_flags = FR_BLOCK|FR_QUICK;
+ ipfnatblock.fr_ref = 1;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_main_unload */
+/* Returns: int - 0 == success, -1 == failure */
+/* Parameters: Nil */
+/* */
+/* A null-op function that exists as a placeholder so that the flow in */
+/* other functions is obvious. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat_main_unload()
+{
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_soft_create */
+/* Returns: void * - NULL = failure, else pointer to NAT context */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Allocate the initial soft context structure for NAT and populate it with */
+/* some default values. Creating the tables is left until we call _init so */
+/* that sizes can be changed before we get under way. */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_nat_soft_create(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_nat_softc_t *softn;
+
+ KMALLOC(softn, ipf_nat_softc_t *);
+ if (softn == NULL)
+ return NULL;
+
+ bzero((char *)softn, sizeof(*softn));
+
+ softn->ipf_nat_tune = ipf_tune_array_copy(softn,
+ sizeof(ipf_nat_tuneables),
+ ipf_nat_tuneables);
+ if (softn->ipf_nat_tune == NULL) {
+ ipf_nat_soft_destroy(softc, softn);
+ return NULL;
+ }
+ if (ipf_tune_array_link(softc, softn->ipf_nat_tune) == -1) {
+ ipf_nat_soft_destroy(softc, softn);
+ return NULL;
+ }
+
+ softn->ipf_nat_list_tail = &softn->ipf_nat_list;
+
+ softn->ipf_nat_table_max = NAT_TABLE_MAX;
+ softn->ipf_nat_table_sz = NAT_TABLE_SZ;
+ softn->ipf_nat_maprules_sz = NAT_SIZE;
+ softn->ipf_nat_rdrrules_sz = RDR_SIZE;
+ softn->ipf_nat_hostmap_sz = HOSTMAP_SIZE;
+ softn->ipf_nat_doflush = 0;
#ifdef IPFILTER_LOG
-int nat_logging = 1;
+ softn->ipf_nat_logging = 1;
#else
-int nat_logging = 0;
+ softn->ipf_nat_logging = 0;
#endif
-u_long fr_defnatage = DEF_NAT_AGE,
- fr_defnatipage = 120, /* 60 seconds */
- fr_defnaticmpage = 6; /* 3 seconds */
-natstat_t nat_stats;
-int fr_nat_lock = 0;
-int fr_nat_init = 0;
-#if SOLARIS && !defined(_INET_IP_STACK_H)
-extern int pfil_delayed_copy;
-#endif
+ softn->ipf_nat_defage = DEF_NAT_AGE;
+ softn->ipf_nat_defipage = IPF_TTLVAL(60);
+ softn->ipf_nat_deficmpage = IPF_TTLVAL(3);
+ softn->ipf_nat_table_wm_high = 99;
+ softn->ipf_nat_table_wm_low = 90;
-static int nat_flush_entry __P((void *));
-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_delrdr __P((struct ipnat *));
-static void nat_delnat __P((struct ipnat *));
-static int fr_natgetent __P((caddr_t, int));
-static int fr_natgetsz __P((caddr_t, int));
-static int fr_natputent __P((caddr_t, int));
-static int nat_extraflush __P((int));
-static int nat_gettable __P((char *));
-static void nat_tabmove __P((nat_t *));
-static int nat_match __P((fr_info_t *, ipnat_t *));
-static INLINE int nat_newmap __P((fr_info_t *, nat_t *, natinfo_t *));
-static INLINE int nat_newrdr __P((fr_info_t *, nat_t *, natinfo_t *));
-static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr,
- struct in_addr, struct in_addr, u_32_t));
-static int nat_icmpquerytype4 __P((int));
-static int nat_siocaddnat __P((ipnat_t *, ipnat_t **, int));
-static void nat_siocdelnat __P((ipnat_t *, ipnat_t **, int));
-static int nat_finalise __P((fr_info_t *, nat_t *, natinfo_t *,
- tcphdr_t *, nat_t **, int));
-static int nat_resolverule __P((ipnat_t *));
-static nat_t *fr_natclone __P((fr_info_t *, nat_t *));
-static void nat_mssclamp __P((tcphdr_t *, u_32_t, fr_info_t *, u_short *));
-static int nat_wildok __P((nat_t *, int, int, int, int));
-static int nat_getnext __P((ipftoken_t *, ipfgeniter_t *));
-static int nat_iterator __P((ipftoken_t *, ipfgeniter_t *));
-
-
-/* ------------------------------------------------------------------------ */
-/* Function: fr_natinit */
+ return softn;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_soft_destroy */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* ------------------------------------------------------------------------ */
+void
+ipf_nat_soft_destroy(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_nat_softc_t *softn = arg;
+
+ if (softn->ipf_nat_tune != NULL) {
+ ipf_tune_array_unlink(softc, softn->ipf_nat_tune);
+ KFREES(softn->ipf_nat_tune, sizeof(ipf_nat_tuneables));
+ softn->ipf_nat_tune = NULL;
+ }
+
+ KFREE(softn);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_init */
/* Returns: int - 0 == success, -1 == failure */
-/* Parameters: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
/* */
/* Initialise all of the NAT locks, tables and other structures. */
/* ------------------------------------------------------------------------ */
-int fr_natinit()
+int
+ipf_nat_soft_init(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
{
+ ipf_nat_softc_t *softn = arg;
+ ipftq_t *tq;
int i;
- 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
+ KMALLOCS(softn->ipf_nat_table[0], nat_t **, \
+ sizeof(nat_t *) * softn->ipf_nat_table_sz);
+
+ if (softn->ipf_nat_table[0] != NULL) {
+ bzero((char *)softn->ipf_nat_table[0],
+ softn->ipf_nat_table_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
+ KMALLOCS(softn->ipf_nat_table[1], nat_t **, \
+ sizeof(nat_t *) * softn->ipf_nat_table_sz);
+
+ if (softn->ipf_nat_table[1] != NULL) {
+ bzero((char *)softn->ipf_nat_table[1],
+ softn->ipf_nat_table_sz * sizeof(nat_t *));
+ } else {
return -2;
+ }
- 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
+ KMALLOCS(softn->ipf_nat_map_rules, ipnat_t **, \
+ sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz);
+
+ if (softn->ipf_nat_map_rules != NULL) {
+ bzero((char *)softn->ipf_nat_map_rules,
+ softn->ipf_nat_maprules_sz * sizeof(ipnat_t *));
+ } else {
return -3;
+ }
- 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
+ KMALLOCS(softn->ipf_nat_rdr_rules, ipnat_t **, \
+ sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz);
+
+ if (softn->ipf_nat_rdr_rules != NULL) {
+ bzero((char *)softn->ipf_nat_rdr_rules,
+ softn->ipf_nat_rdrrules_sz * sizeof(ipnat_t *));
+ } else {
return -4;
+ }
- KMALLOCS(ipf_hm_maptable, hostmap_t **, \
- sizeof(hostmap_t *) * ipf_hostmap_sz);
- if (ipf_hm_maptable != NULL)
- bzero((char *)ipf_hm_maptable,
- sizeof(hostmap_t *) * ipf_hostmap_sz);
- else
+ KMALLOCS(softn->ipf_hm_maptable, hostmap_t **, \
+ sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz);
+
+ if (softn->ipf_hm_maptable != NULL) {
+ bzero((char *)softn->ipf_hm_maptable,
+ sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz);
+ } else {
return -5;
- ipf_hm_maplist = NULL;
+ }
+ softn->ipf_hm_maplist = NULL;
- KMALLOCS(nat_stats.ns_bucketlen[0], u_long *,
- ipf_nattable_sz * sizeof(u_long));
- if (nat_stats.ns_bucketlen[0] == NULL)
+ KMALLOCS(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, u_int *,
+ softn->ipf_nat_table_sz * sizeof(u_int));
+
+ if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen == NULL) {
return -6;
- bzero((char *)nat_stats.ns_bucketlen[0],
- ipf_nattable_sz * sizeof(u_long));
+ }
+ bzero((char *)softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
+ softn->ipf_nat_table_sz * sizeof(u_int));
- KMALLOCS(nat_stats.ns_bucketlen[1], u_long *,
- ipf_nattable_sz * sizeof(u_long));
- if (nat_stats.ns_bucketlen[1] == NULL)
+ KMALLOCS(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, u_int *,
+ softn->ipf_nat_table_sz * sizeof(u_int));
+
+ if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen == NULL) {
return -7;
+ }
- bzero((char *)nat_stats.ns_bucketlen[1],
- ipf_nattable_sz * sizeof(u_long));
+ bzero((char *)softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
+ softn->ipf_nat_table_sz * sizeof(u_int));
- if (fr_nat_maxbucket == 0) {
- for (i = ipf_nattable_sz; i > 0; i >>= 1)
- fr_nat_maxbucket++;
- fr_nat_maxbucket *= 2;
+ if (softn->ipf_nat_maxbucket == 0) {
+ for (i = softn->ipf_nat_table_sz; i > 0; i >>= 1)
+ softn->ipf_nat_maxbucket++;
+ softn->ipf_nat_maxbucket *= 2;
}
- fr_sttab_init(nat_tqb);
+ ipf_sttab_init(softc, softn->ipf_nat_tcptq);
/*
* Increase this because we may have "keep state" following this too
* and packet storms can occur if this is removed too quickly.
*/
- nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = fr_tcplastack;
- nat_tqb[IPF_TCP_NSTATES - 1].ifq_next = &nat_udptq;
- nat_udptq.ifq_ttl = fr_defnatage;
- nat_udptq.ifq_ref = 1;
- nat_udptq.ifq_head = NULL;
- nat_udptq.ifq_tail = &nat_udptq.ifq_head;
- MUTEX_INIT(&nat_udptq.ifq_lock, "nat ipftq udp tab");
- nat_udptq.ifq_next = &nat_icmptq;
- nat_icmptq.ifq_ttl = fr_defnaticmpage;
- nat_icmptq.ifq_ref = 1;
- nat_icmptq.ifq_head = NULL;
- nat_icmptq.ifq_tail = &nat_icmptq.ifq_head;
- MUTEX_INIT(&nat_icmptq.ifq_lock, "nat icmp ipftq tab");
- nat_icmptq.ifq_next = &nat_iptq;
- nat_iptq.ifq_ttl = fr_defnatipage;
- nat_iptq.ifq_ref = 1;
- nat_iptq.ifq_head = NULL;
- nat_iptq.ifq_tail = &nat_iptq.ifq_head;
- MUTEX_INIT(&nat_iptq.ifq_lock, "nat ip ipftq tab");
- nat_iptq.ifq_next = NULL;
-
- for (i = 0; i < IPF_TCP_NSTATES; i++) {
- if (nat_tqb[i].ifq_ttl < fr_defnaticmpage)
- nat_tqb[i].ifq_ttl = fr_defnaticmpage;
+ softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack;
+ softn->ipf_nat_tcptq[IPF_TCP_NSTATES - 1].ifq_next =
+ &softn->ipf_nat_udptq;
+
+ IPFTQ_INIT(&softn->ipf_nat_udptq, softn->ipf_nat_defage,
+ "nat ipftq udp tab");
+ softn->ipf_nat_udptq.ifq_next = &softn->ipf_nat_udpacktq;
+
+ IPFTQ_INIT(&softn->ipf_nat_udpacktq, softn->ipf_nat_defage,
+ "nat ipftq udpack tab");
+ softn->ipf_nat_udpacktq.ifq_next = &softn->ipf_nat_icmptq;
+
+ IPFTQ_INIT(&softn->ipf_nat_icmptq, softn->ipf_nat_deficmpage,
+ "nat icmp ipftq tab");
+ softn->ipf_nat_icmptq.ifq_next = &softn->ipf_nat_icmpacktq;
+
+ IPFTQ_INIT(&softn->ipf_nat_icmpacktq, softn->ipf_nat_defage,
+ "nat icmpack ipftq tab");
+ softn->ipf_nat_icmpacktq.ifq_next = &softn->ipf_nat_iptq;
+
+ IPFTQ_INIT(&softn->ipf_nat_iptq, softn->ipf_nat_defipage,
+ "nat ip ipftq tab");
+ softn->ipf_nat_iptq.ifq_next = &softn->ipf_nat_pending;
+
+ IPFTQ_INIT(&softn->ipf_nat_pending, 1, "nat pending ipftq tab");
+ softn->ipf_nat_pending.ifq_next = NULL;
+
+ for (i = 0, tq = softn->ipf_nat_tcptq; i < IPF_TCP_NSTATES; i++, tq++) {
+ if (tq->ifq_ttl < softn->ipf_nat_deficmpage)
+ tq->ifq_ttl = softn->ipf_nat_deficmpage;
#ifdef LARGE_NAT
- else if (nat_tqb[i].ifq_ttl > fr_defnatage)
- nat_tqb[i].ifq_ttl = fr_defnatage;
+ else if (tq->ifq_ttl > softn->ipf_nat_defage)
+ tq->ifq_ttl = softn->ipf_nat_defage;
#endif
}
@@ -319,21 +515,124 @@ int fr_natinit()
* this too and packet storms can occur if this is removed
* too quickly.
*/
- nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = nat_tqb[IPF_TCPS_LAST_ACK].ifq_ttl;
+ softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack;
- RWLOCK_INIT(&ipf_nat, "ipf IP NAT rwlock");
- RWLOCK_INIT(&ipf_natfrag, "ipf IP NAT-Frag rwlock");
- MUTEX_INIT(&ipf_nat_new, "ipf nat new mutex");
- MUTEX_INIT(&ipf_natio, "ipf nat io mutex");
+ MUTEX_INIT(&softn->ipf_nat_new, "ipf nat new mutex");
+ MUTEX_INIT(&softn->ipf_nat_io, "ipf nat io mutex");
- fr_nat_init = 1;
+ softn->ipf_nat_inited = 1;
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_addrdr */
+/* Function: ipf_nat_soft_fini */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Free all memory used by NAT structures allocated at runtime. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat_soft_fini(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_nat_softc_t *softn = arg;
+ ipftq_t *ifq, *ifqnext;
+
+ (void) ipf_nat_clearlist(softc, softn);
+ (void) ipf_nat_flushtable(softc, softn);
+
+ /*
+ * Proxy timeout queues are not cleaned here because although they
+ * exist on the NAT list, ipf_proxy_unload is called after unload
+ * and the proxies actually are responsible for them being created.
+ * Should the proxy timeouts have their own list? There's no real
+ * justification as this is the only complication.
+ */
+ for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) {
+ ifqnext = ifq->ifq_next;
+ if (ipf_deletetimeoutqueue(ifq) == 0)
+ ipf_freetimeoutqueue(softc, ifq);
+ }
+
+ if (softn->ipf_nat_table[0] != NULL) {
+ KFREES(softn->ipf_nat_table[0],
+ sizeof(nat_t *) * softn->ipf_nat_table_sz);
+ softn->ipf_nat_table[0] = NULL;
+ }
+ if (softn->ipf_nat_table[1] != NULL) {
+ KFREES(softn->ipf_nat_table[1],
+ sizeof(nat_t *) * softn->ipf_nat_table_sz);
+ softn->ipf_nat_table[1] = NULL;
+ }
+ if (softn->ipf_nat_map_rules != NULL) {
+ KFREES(softn->ipf_nat_map_rules,
+ sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz);
+ softn->ipf_nat_map_rules = NULL;
+ }
+ if (softn->ipf_nat_rdr_rules != NULL) {
+ KFREES(softn->ipf_nat_rdr_rules,
+ sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz);
+ softn->ipf_nat_rdr_rules = NULL;
+ }
+ if (softn->ipf_hm_maptable != NULL) {
+ KFREES(softn->ipf_hm_maptable,
+ sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz);
+ softn->ipf_hm_maptable = NULL;
+ }
+ if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) {
+ KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
+ sizeof(u_int) * softn->ipf_nat_table_sz);
+ softn->ipf_nat_stats.ns_side[0].ns_bucketlen = NULL;
+ }
+ if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) {
+ KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
+ sizeof(u_int) * softn->ipf_nat_table_sz);
+ softn->ipf_nat_stats.ns_side[1].ns_bucketlen = NULL;
+ }
+
+ if (softn->ipf_nat_inited == 1) {
+ softn->ipf_nat_inited = 0;
+ ipf_sttab_destroy(softn->ipf_nat_tcptq);
+
+ MUTEX_DESTROY(&softn->ipf_nat_new);
+ MUTEX_DESTROY(&softn->ipf_nat_io);
+
+ MUTEX_DESTROY(&softn->ipf_nat_udptq.ifq_lock);
+ MUTEX_DESTROY(&softn->ipf_nat_udpacktq.ifq_lock);
+ MUTEX_DESTROY(&softn->ipf_nat_icmptq.ifq_lock);
+ MUTEX_DESTROY(&softn->ipf_nat_icmpacktq.ifq_lock);
+ MUTEX_DESTROY(&softn->ipf_nat_iptq.ifq_lock);
+ MUTEX_DESTROY(&softn->ipf_nat_pending.ifq_lock);
+ }
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_setlock */
+/* Returns: Nil */
+/* Parameters: arg(I) - pointer to soft state information */
+/* tmp(I) - new lock value */
+/* */
+/* Set the "lock status" of NAT to the value in tmp. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_nat_setlock(arg, tmp)
+ void *arg;
+ int tmp;
+{
+ ipf_nat_softc_t *softn = arg;
+
+ softn->ipf_nat_lock = tmp;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_addrdr */
/* Returns: Nil */
/* Parameters: n(I) - pointer to NAT rule to add */
/* */
@@ -341,31 +640,41 @@ int fr_natinit()
/* loaded NAT rules. Updates the bitmask indicating which netmasks are in */
/* use by redirect rules. */
/* ------------------------------------------------------------------------ */
-static void nat_addrdr(n)
-ipnat_t *n;
+static void
+ipf_nat_addrdr(softn, n)
+ ipf_nat_softc_t *softn;
+ ipnat_t *n;
{
ipnat_t **np;
u_32_t j;
u_int hv;
+ u_int rhv;
int k;
- k = count4bits(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;
+ if (n->in_odstatype == FRI_NORMAL) {
+ k = count4bits(n->in_odstmsk);
+ ipf_inet_mask_add(k, &softn->ipf_nat_rdr_mask);
+ j = (n->in_odstaddr & n->in_odstmsk);
+ rhv = NAT_HASH_FN(j, 0, 0xffffffff);
+ } else {
+ ipf_inet_mask_add(0, &softn->ipf_nat_rdr_mask);
+ j = 0;
+ rhv = 0;
+ }
+ hv = rhv % softn->ipf_nat_rdrrules_sz;
+ np = softn->ipf_nat_rdr_rules + hv;
while (*np != NULL)
np = &(*np)->in_rnext;
n->in_rnext = NULL;
n->in_prnext = np;
- n->in_hv = hv;
+ n->in_hv[0] = hv;
+ n->in_use++;
*np = n;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_addnat */
+/* Function: ipf_nat_addmap */
/* Returns: Nil */
/* Parameters: n(I) - pointer to NAT rule to add */
/* */
@@ -373,63 +682,91 @@ ipnat_t *n;
/* NAT rules. Updates the bitmask indicating which netmasks are in use by */
/* redirect rules. */
/* ------------------------------------------------------------------------ */
-static void nat_addnat(n)
-ipnat_t *n;
+static void
+ipf_nat_addmap(softn, n)
+ ipf_nat_softc_t *softn;
+ ipnat_t *n;
{
ipnat_t **np;
u_32_t j;
u_int hv;
+ u_int rhv;
int k;
- k = count4bits(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;
+ if (n->in_osrcatype == FRI_NORMAL) {
+ k = count4bits(n->in_osrcmsk);
+ ipf_inet_mask_add(k, &softn->ipf_nat_map_mask);
+ j = (n->in_osrcaddr & n->in_osrcmsk);
+ rhv = NAT_HASH_FN(j, 0, 0xffffffff);
+ } else {
+ ipf_inet_mask_add(0, &softn->ipf_nat_map_mask);
+ j = 0;
+ rhv = 0;
+ }
+ hv = rhv % softn->ipf_nat_maprules_sz;
+ np = softn->ipf_nat_map_rules + hv;
while (*np != NULL)
np = &(*np)->in_mnext;
n->in_mnext = NULL;
n->in_pmnext = np;
- n->in_hv = hv;
+ n->in_hv[1] = rhv;
+ n->in_use++;
*np = n;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_delrdr */
+/* Function: ipf_nat_delrdr */
/* Returns: Nil */
/* Parameters: n(I) - pointer to NAT rule to delete */
/* */
/* Removes a redirect rule from the hash table of redirect rules. */
/* ------------------------------------------------------------------------ */
-static void nat_delrdr(n)
-ipnat_t *n;
+void
+ipf_nat_delrdr(softn, n)
+ ipf_nat_softc_t *softn;
+ ipnat_t *n;
{
+ if (n->in_odstatype == FRI_NORMAL) {
+ int k = count4bits(n->in_odstmsk);
+ ipf_inet_mask_del(k, &softn->ipf_nat_rdr_mask);
+ } else {
+ ipf_inet_mask_del(0, &softn->ipf_nat_rdr_mask);
+ }
if (n->in_rnext)
n->in_rnext->in_prnext = n->in_prnext;
*n->in_prnext = n->in_rnext;
+ n->in_use--;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_delnat */
+/* Function: ipf_nat_delmap */
/* Returns: Nil */
/* Parameters: n(I) - pointer to NAT rule to delete */
/* */
/* Removes a NAT map rule from the hash table of NAT map rules. */
/* ------------------------------------------------------------------------ */
-static void nat_delnat(n)
-ipnat_t *n;
+void
+ipf_nat_delmap(softn, n)
+ ipf_nat_softc_t *softn;
+ ipnat_t *n;
{
+ if (n->in_osrcatype == FRI_NORMAL) {
+ int k = count4bits(n->in_osrcmsk);
+ ipf_inet_mask_del(k, &softn->ipf_nat_map_mask);
+ } else {
+ ipf_inet_mask_del(0, &softn->ipf_nat_map_mask);
+ }
if (n->in_mnext != NULL)
n->in_mnext->in_pmnext = n->in_pmnext;
*n->in_pmnext = n->in_mnext;
+ n->in_use--;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_hostmap */
+/* Function: ipf_nat_hostmap */
/* Returns: struct hostmap* - NULL if no hostmap could be created, */
/* else a pointer to the hostmapping to use */
/* Parameters: np(I) - pointer to NAT rule */
@@ -442,57 +779,70 @@ ipnat_t *n;
/* that is not doing port based translation. If is not yet allocated, then */
/* create a new entry if a non-NULL NAT rule pointer has been supplied. */
/* ------------------------------------------------------------------------ */
-static struct hostmap *nat_hostmap(np, src, dst, map, port)
-ipnat_t *np;
-struct in_addr src;
-struct in_addr dst;
-struct in_addr map;
-u_32_t port;
+static struct hostmap *
+ipf_nat_hostmap(softn, np, src, dst, map, port)
+ ipf_nat_softc_t *softn;
+ ipnat_t *np;
+ struct in_addr src;
+ struct in_addr dst;
+ struct in_addr map;
+ u_32_t port;
{
hostmap_t *hm;
- u_int hv;
+ u_int hv, rhv;
hv = (src.s_addr ^ dst.s_addr);
hv += src.s_addr;
hv += dst.s_addr;
- hv %= HOSTMAP_SIZE;
- for (hm = ipf_hm_maptable[hv]; hm; hm = hm->hm_next)
- if ((hm->hm_srcip.s_addr == src.s_addr) &&
- (hm->hm_dstip.s_addr == dst.s_addr) &&
+ rhv = hv;
+ hv %= softn->ipf_nat_hostmap_sz;
+ for (hm = softn->ipf_hm_maptable[hv]; hm; hm = hm->hm_hnext)
+ if ((hm->hm_osrcip.s_addr == src.s_addr) &&
+ (hm->hm_odstip.s_addr == dst.s_addr) &&
((np == NULL) || (np == hm->hm_ipnat)) &&
((port == 0) || (port == hm->hm_port))) {
+ softn->ipf_nat_stats.ns_hm_addref++;
hm->hm_ref++;
return hm;
}
- if (np == NULL)
+ if (np == NULL) {
+ softn->ipf_nat_stats.ns_hm_nullnp++;
return NULL;
+ }
KMALLOC(hm, hostmap_t *);
if (hm) {
- hm->hm_next = ipf_hm_maplist;
- hm->hm_pnext = &ipf_hm_maplist;
- if (ipf_hm_maplist != NULL)
- ipf_hm_maplist->hm_pnext = &hm->hm_next;
- ipf_hm_maplist = hm;
- hm->hm_hnext = ipf_hm_maptable[hv];
- hm->hm_phnext = ipf_hm_maptable + hv;
- if (ipf_hm_maptable[hv] != NULL)
- ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
- ipf_hm_maptable[hv] = hm;
+ hm->hm_next = softn->ipf_hm_maplist;
+ hm->hm_pnext = &softn->ipf_hm_maplist;
+ if (softn->ipf_hm_maplist != NULL)
+ softn->ipf_hm_maplist->hm_pnext = &hm->hm_next;
+ softn->ipf_hm_maplist = hm;
+ hm->hm_hnext = softn->ipf_hm_maptable[hv];
+ hm->hm_phnext = softn->ipf_hm_maptable + hv;
+ if (softn->ipf_hm_maptable[hv] != NULL)
+ softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
+ softn->ipf_hm_maptable[hv] = hm;
hm->hm_ipnat = np;
- hm->hm_srcip = src;
- hm->hm_dstip = dst;
- hm->hm_mapip = map;
+ np->in_use++;
+ hm->hm_osrcip = src;
+ hm->hm_odstip = dst;
+ hm->hm_nsrcip = map;
+ hm->hm_ndstip.s_addr = 0;
hm->hm_ref = 1;
hm->hm_port = port;
+ hm->hm_hv = rhv;
+ hm->hm_v = 4;
+ softn->ipf_nat_stats.ns_hm_new++;
+ } else {
+ softn->ipf_nat_stats.ns_hm_newfail++;
}
return hm;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_hostmapdel */
+/* Function: ipf_nat_hostmapdel */
/* Returns: Nil */
/* Parameters: hmp(I) - pointer to hostmap structure pointer */
/* Write Locks: ipf_nat */
@@ -500,8 +850,10 @@ u_32_t port;
/* Decrement the references to this hostmap structure by one. If this */
/* reaches zero then remove it and free it. */
/* ------------------------------------------------------------------------ */
-void fr_hostmapdel(hmp)
-struct hostmap **hmp;
+void
+ipf_nat_hostmapdel(softc, hmp)
+ ipf_main_softc_t *softc;
+ struct hostmap **hmp;
{
struct hostmap *hm;
@@ -510,6 +862,7 @@ struct hostmap **hmp;
hm->hm_ref--;
if (hm->hm_ref == 0) {
+ ipf_nat_rule_deref(softc, &hm->hm_ipnat);
if (hm->hm_hnext)
hm->hm_hnext->hm_phnext = hm->hm_phnext;
*hm->hm_phnext = hm->hm_hnext;
@@ -522,7 +875,7 @@ struct hostmap **hmp;
/* ------------------------------------------------------------------------ */
-/* Function: fix_outcksum */
+/* Function: ipf_fix_outcksum */
/* Returns: Nil */
/* Parameters: fin(I) - pointer to packet information */
/* sp(I) - location of 16bit checksum to update */
@@ -530,10 +883,11 @@ struct hostmap **hmp;
/* */
/* Adjusts the 16bit checksum by "n" for packets going out. */
/* ------------------------------------------------------------------------ */
-void fix_outcksum(fin, sp, n)
-fr_info_t *fin;
-u_short *sp;
-u_32_t n;
+void
+ipf_fix_outcksum(cksum, sp, n, partial)
+ int cksum;
+ u_short *sp;
+ u_32_t n, partial;
{
u_short sumshort;
u_32_t sum1;
@@ -541,11 +895,14 @@ u_32_t n;
if (n == 0)
return;
- if (n & NAT_HW_CKSUM) {
- n &= 0xffff;
- n += fin->fin_dlen;
- n = (n & 0xffff) + (n >> 16);
- *sp = n & 0xffff;
+ if (cksum == 4) {
+ *sp = 0;
+ return;
+ }
+ if (cksum == 2) {
+ sum1 = partial;
+ sum1 = (sum1 & 0xffff) + (sum1 >> 16);
+ *sp = htons(sum1);
return;
}
sum1 = (~ntohs(*sp)) & 0xffff;
@@ -559,7 +916,7 @@ u_32_t n;
/* ------------------------------------------------------------------------ */
-/* Function: fix_incksum */
+/* Function: ipf_fix_incksum */
/* Returns: Nil */
/* Parameters: fin(I) - pointer to packet information */
/* sp(I) - location of 16bit checksum to update */
@@ -567,10 +924,11 @@ u_32_t n;
/* */
/* Adjusts the 16bit checksum by "n" for packets going in. */
/* ------------------------------------------------------------------------ */
-void fix_incksum(fin, sp, n)
-fr_info_t *fin;
-u_short *sp;
-u_32_t n;
+void
+ipf_fix_incksum(cksum, sp, n, partial)
+ int cksum;
+ u_short *sp;
+ u_32_t n, partial;
{
u_short sumshort;
u_32_t sum1;
@@ -578,13 +936,17 @@ u_32_t n;
if (n == 0)
return;
- if (n & NAT_HW_CKSUM) {
- n &= 0xffff;
- n += fin->fin_dlen;
- n = (n & 0xffff) + (n >> 16);
- *sp = n & 0xffff;
+ if (cksum == 4) {
+ *sp = 0;
+ return;
+ }
+ if (cksum == 2) {
+ sum1 = partial;
+ sum1 = (sum1 & 0xffff) + (sum1 >> 16);
+ *sp = htons(sum1);
return;
}
+
sum1 = (~ntohs(*sp)) & 0xffff;
sum1 += ~(n) & 0xffff;
sum1 = (sum1 >> 16) + (sum1 & 0xffff);
@@ -596,7 +958,7 @@ u_32_t n;
/* ------------------------------------------------------------------------ */
-/* Function: fix_datacksum */
+/* Function: ipf_fix_datacksum */
/* Returns: Nil */
/* Parameters: sp(I) - location of 16bit checksum to update */
/* n((I) - amount to adjust checksum by */
@@ -613,9 +975,10 @@ u_32_t n;
/* 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;
+void
+ipf_fix_datacksum(sp, n)
+ u_short *sp;
+ u_32_t n;
{
u_short sumshort;
u_32_t sum1;
@@ -634,42 +997,48 @@ u_32_t n;
/* ------------------------------------------------------------------------ */
-/* Function: fr_nat_ioctl */
+/* Function: ipf_nat_ioctl */
/* Returns: int - 0 == success, != 0 == failure */
-/* Parameters: data(I) - pointer to ioctl data */
-/* cmd(I) - ioctl command integer */
-/* mode(I) - file mode bits used with open */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* data(I) - pointer to ioctl data */
+/* cmd(I) - ioctl command integer */
+/* mode(I) - file mode bits used with open */
+/* uid(I) - uid of calling process */
+/* ctx(I) - pointer used as key for finding context */
/* */
/* Processes an ioctl call made to operate on the IP Filter NAT device. */
/* ------------------------------------------------------------------------ */
-int fr_nat_ioctl(data, cmd, mode, uid, ctx)
-ioctlcmd_t cmd;
-caddr_t data;
-int mode, uid;
-void *ctx;
+int
+ipf_nat_ioctl(softc, data, cmd, mode, uid, ctx)
+ ipf_main_softc_t *softc;
+ ioctlcmd_t cmd;
+ caddr_t data;
+ int mode, uid;
+ void *ctx;
{
- ipnat_t *nat, *nt, *n = NULL, **np = NULL;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
int error = 0, ret, arg, getlock;
+ ipnat_t *nat, *nt, *n;
ipnat_t natd;
SPL_INT(s);
-#if (BSD >= 199306) && defined(_KERNEL)
-# if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 399002000)
+#if BSD_GE_YEAR(199306) && defined(_KERNEL)
+# if NETBSD_GE_REV(399002000)
if ((mode & FWRITE) &&
kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_FIREWALL,
KAUTH_REQ_NETWORK_FIREWALL_FW,
- NULL, NULL, NULL)) {
- return EPERM;
- }
+ NULL, NULL, NULL))
# else
# if defined(__FreeBSD_version) && (__FreeBSD_version >= 500034)
- if (securelevel_ge(curthread->td_ucred, 3) && (mode & FWRITE)) {
+ if (securelevel_ge(curthread->td_ucred, 3) && (mode & FWRITE))
# else
- if ((securelevel >= 3) && (mode & FWRITE)) {
+ if ((securelevel >= 3) && (mode & FWRITE))
# endif
+# endif
+ {
+ IPFERROR(60001);
return EPERM;
}
-# endif
#endif
#if defined(__osf__) && defined(_KERNEL)
@@ -678,48 +1047,69 @@ void *ctx;
getlock = (mode & NAT_LOCKHELD) ? 0 : 1;
#endif
- nat = NULL; /* XXX gcc -Wuninitialized */
- if (cmd == (ioctlcmd_t)SIOCADNAT) {
- KMALLOC(nt, ipnat_t *);
- } else {
- nt = NULL;
- }
+ n = NULL;
+ nt = NULL;
+ nat = NULL;
- if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) {
+ if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT) ||
+ (cmd == (ioctlcmd_t)SIOCPURGENAT)) {
if (mode & NAT_SYSSPACE) {
bcopy(data, (char *)&natd, sizeof(natd));
+ nat = &natd;
error = 0;
} else {
- error = fr_inobj(data, &natd, IPFOBJ_IPNAT);
- }
- }
+ bzero(&natd, sizeof(natd));
+ error = ipf_inobj(softc, data, NULL, &natd,
+ IPFOBJ_IPNAT);
+ if (error != 0)
+ goto done;
- if (error != 0)
- goto done;
+ if (natd.in_size < sizeof(ipnat_t)) {
+ error = EINVAL;
+ goto done;
+ }
+ KMALLOCS(nt, ipnat_t *, natd.in_size);
+ if (nt == NULL) {
+ IPFERROR(60070);
+ error = ENOMEM;
+ goto done;
+ }
+ bzero(nt, natd.in_size);
+ error = ipf_inobjsz(softc, data, nt, IPFOBJ_IPNAT,
+ natd.in_size);
+ if (error)
+ goto done;
+ nat = nt;
+ }
- /*
- * For add/delete, look to see if the NAT entry is already present
- */
- if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) {
- nat = &natd;
- if (nat->in_v == 0) /* For backward compat. */
- nat->in_v = 4;
+ /*
+ * For add/delete, look to see if the NAT entry is
+ * already present
+ */
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;
- }
- MUTEX_ENTER(&ipf_natio);
- for (np = &nat_list; ((n = *np) != NULL); np = &n->in_next)
- if (bcmp((char *)&nat->in_flags, (char *)&n->in_flags,
- IPN_CMPSIZ) == 0) {
- if (nat->in_redir == NAT_REDIRECT &&
- nat->in_pnext != n->in_pnext)
- continue;
- break;
+ if (nat->in_osrcatype == FRI_NORMAL ||
+ nat->in_osrcatype == FRI_NONE)
+ nat->in_osrcaddr &= nat->in_osrcmsk;
+ if (nat->in_odstatype == FRI_NORMAL ||
+ nat->in_odstatype == FRI_NONE)
+ nat->in_odstaddr &= nat->in_odstmsk;
+ if ((nat->in_flags & (IPN_SPLIT|IPN_SIPRANGE)) == 0) {
+ if (nat->in_nsrcatype == FRI_NORMAL)
+ nat->in_nsrcaddr &= nat->in_nsrcmsk;
+ if (nat->in_ndstatype == FRI_NORMAL)
+ nat->in_ndstaddr &= nat->in_ndstmsk;
}
+ }
+
+ error = ipf_nat_rule_init(softc, softn, nat);
+ if (error != 0)
+ goto done;
+
+ MUTEX_ENTER(&softn->ipf_nat_io);
+ for (n = softn->ipf_nat_list; n != NULL; n = n->in_next)
+ if (ipf_nat_cmp_rules(nat, n) == 0)
+ break;
}
switch (cmd)
@@ -729,115 +1119,169 @@ void *ctx;
{
int tmp;
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(60002);
error = EPERM;
- else {
- tmp = ipflog_clear(IPL_LOGNAT);
- error = BCOPYOUT((char *)&tmp, (char *)data,
- sizeof(tmp));
- if (error != 0)
+ } else {
+ tmp = ipf_log_clear(softc, IPL_LOGNAT);
+ error = BCOPYOUT(&tmp, data, sizeof(tmp));
+ if (error != 0) {
+ IPFERROR(60057);
error = EFAULT;
+ }
}
break;
}
case SIOCSETLG :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(60003);
error = EPERM;
- else {
- error = BCOPYIN((char *)data, (char *)&nat_logging,
- sizeof(nat_logging));
+ } else {
+ error = BCOPYIN(data, &softn->ipf_nat_logging,
+ sizeof(softn->ipf_nat_logging));
if (error != 0)
error = EFAULT;
}
break;
case SIOCGETLG :
- error = BCOPYOUT((char *)&nat_logging, (char *)data,
- sizeof(nat_logging));
- if (error != 0)
+ error = BCOPYOUT(&softn->ipf_nat_logging, data,
+ sizeof(softn->ipf_nat_logging));
+ if (error != 0) {
+ IPFERROR(60004);
error = EFAULT;
+ }
break;
case FIONREAD :
- arg = iplused[IPL_LOGNAT];
+ arg = ipf_log_bytesused(softc, IPL_LOGNAT);
error = BCOPYOUT(&arg, data, sizeof(arg));
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(60005);
error = EFAULT;
+ }
break;
#endif
case SIOCADNAT :
if (!(mode & FWRITE)) {
+ IPFERROR(60006);
error = EPERM;
} else if (n != NULL) {
+ natd.in_flineno = n->in_flineno;
+ (void) ipf_outobj(softc, data, &natd, IPFOBJ_IPNAT);
+ IPFERROR(60007);
error = EEXIST;
} else if (nt == NULL) {
+ IPFERROR(60008);
error = ENOMEM;
}
if (error != 0) {
- MUTEX_EXIT(&ipf_natio);
+ MUTEX_EXIT(&softn->ipf_nat_io);
break;
}
- bcopy((char *)nat, (char *)nt, sizeof(*n));
- error = nat_siocaddnat(nt, np, getlock);
- MUTEX_EXIT(&ipf_natio);
- if (error == 0)
+ if (nat != nt)
+ bcopy((char *)nat, (char *)nt, sizeof(*n));
+ error = ipf_nat_siocaddnat(softc, softn, nt, getlock);
+ MUTEX_EXIT(&softn->ipf_nat_io);
+ if (error == 0) {
+ nat = NULL;
nt = NULL;
+ }
break;
case SIOCRMNAT :
+ case SIOCPURGENAT :
if (!(mode & FWRITE)) {
+ IPFERROR(60009);
error = EPERM;
n = NULL;
} else if (n == NULL) {
+ IPFERROR(60010);
error = ESRCH;
}
if (error != 0) {
- MUTEX_EXIT(&ipf_natio);
+ MUTEX_EXIT(&softn->ipf_nat_io);
break;
}
- nat_siocdelnat(n, np, getlock);
+ if (cmd == (ioctlcmd_t)SIOCPURGENAT) {
+ error = ipf_outobjsz(softc, data, n, IPFOBJ_IPNAT,
+ n->in_size);
+ if (error) {
+ MUTEX_EXIT(&softn->ipf_nat_io);
+ goto done;
+ }
+ n->in_flags |= IPN_PURGE;
+ }
+ ipf_nat_siocdelnat(softc, softn, n, getlock);
- MUTEX_EXIT(&ipf_natio);
+ MUTEX_EXIT(&softn->ipf_nat_io);
n = NULL;
break;
case SIOCGNATS :
- 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 = ipf_hm_maptable;
- nat_stats.ns_maplist = ipf_hm_maplist;
- nat_stats.ns_nattab_sz = ipf_nattable_sz;
- nat_stats.ns_nattab_max = ipf_nattable_max;
- 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;
- nat_stats.ns_ticks = fr_ticks;
- error = fr_outobj(data, &nat_stats, IPFOBJ_NATSTAT);
+ {
+ natstat_t *nsp = &softn->ipf_nat_stats;
+
+ nsp->ns_side[0].ns_table = softn->ipf_nat_table[0];
+ nsp->ns_side[1].ns_table = softn->ipf_nat_table[1];
+ nsp->ns_list = softn->ipf_nat_list;
+ nsp->ns_maptable = softn->ipf_hm_maptable;
+ nsp->ns_maplist = softn->ipf_hm_maplist;
+ nsp->ns_nattab_sz = softn->ipf_nat_table_sz;
+ nsp->ns_nattab_max = softn->ipf_nat_table_max;
+ nsp->ns_rultab_sz = softn->ipf_nat_maprules_sz;
+ nsp->ns_rdrtab_sz = softn->ipf_nat_rdrrules_sz;
+ nsp->ns_hostmap_sz = softn->ipf_nat_hostmap_sz;
+ nsp->ns_instances = softn->ipf_nat_instances;
+ nsp->ns_ticks = softc->ipf_ticks;
+#ifdef IPFILTER_LOGGING
+ nsp->ns_log_ok = ipf_log_logok(softc, IPF_LOGNAT);
+ nsp->ns_log_fail = ipf_log_failures(softc, IPF_LOGNAT);
+#else
+ nsp->ns_log_ok = 0;
+ nsp->ns_log_fail = 0;
+#endif
+ error = ipf_outobj(softc, data, nsp, IPFOBJ_NATSTAT);
break;
+ }
case SIOCGNATL :
{
natlookup_t nl;
- error = fr_inobj(data, &nl, IPFOBJ_NATLOOKUP);
+ error = ipf_inobj(softc, data, NULL, &nl, IPFOBJ_NATLOOKUP);
if (error == 0) {
void *ptr;
if (getlock) {
- READ_ENTER(&ipf_nat);
+ READ_ENTER(&softc->ipf_nat);
}
- ptr = nat_lookupredir(&nl);
+
+ switch (nl.nl_v)
+ {
+ case 4 :
+ ptr = ipf_nat_lookupredir(&nl);
+ break;
+#ifdef USE_INET6
+ case 6 :
+ ptr = ipf_nat6_lookupredir(&nl);
+ break;
+#endif
+ default:
+ ptr = NULL;
+ break;
+ }
+
if (getlock) {
- RWLOCK_EXIT(&ipf_nat);
+ RWLOCK_EXIT(&softc->ipf_nat);
}
if (ptr != NULL) {
- error = fr_outobj(data, &nl, IPFOBJ_NATLOOKUP);
+ error = ipf_outobj(softc, data, &nl,
+ IPFOBJ_NATLOOKUP);
} else {
+ IPFERROR(60011);
error = ESRCH;
}
}
@@ -846,246 +1290,257 @@ void *ctx;
case SIOCIPFFL : /* old SIOCFLNAT & SIOCCNATL */
if (!(mode & FWRITE)) {
+ IPFERROR(60012);
error = EPERM;
break;
}
if (getlock) {
- WRITE_ENTER(&ipf_nat);
+ WRITE_ENTER(&softc->ipf_nat);
}
error = BCOPYIN(data, &arg, sizeof(arg));
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(60013);
error = EFAULT;
- else {
+ } else {
if (arg == 0)
- ret = nat_flushtable();
+ ret = ipf_nat_flushtable(softc, softn);
else if (arg == 1)
- ret = nat_clearlist();
+ ret = ipf_nat_clearlist(softc, softn);
else
- ret = nat_extraflush(arg);
+ ret = ipf_nat_extraflush(softc, softn, arg);
+ ipf_proxy_flush(softc->ipf_proxy_soft, arg);
}
if (getlock) {
- RWLOCK_EXIT(&ipf_nat);
+ RWLOCK_EXIT(&softc->ipf_nat);
}
if (error == 0) {
error = BCOPYOUT(&ret, data, sizeof(ret));
}
break;
+ case SIOCMATCHFLUSH :
+ if (!(mode & FWRITE)) {
+ IPFERROR(60014);
+ error = EPERM;
+ break;
+ }
+ if (getlock) {
+ WRITE_ENTER(&softc->ipf_nat);
+ }
+
+ error = ipf_nat_matchflush(softc, softn, data);
+
+ if (getlock) {
+ RWLOCK_EXIT(&softc->ipf_nat);
+ }
+ break;
+
case SIOCPROXY :
- error = appr_ioctl(data, cmd, mode, ctx);
+ error = ipf_proxy_ioctl(softc, data, cmd, mode, ctx);
break;
case SIOCSTLCK :
if (!(mode & FWRITE)) {
+ IPFERROR(60015);
error = EPERM;
} else {
- error = fr_lock(data, &fr_nat_lock);
+ error = ipf_lock(data, &softn->ipf_nat_lock);
}
break;
case SIOCSTPUT :
if ((mode & FWRITE) != 0) {
- error = fr_natputent(data, getlock);
+ error = ipf_nat_putent(softc, data, getlock);
} else {
+ IPFERROR(60016);
error = EACCES;
}
break;
case SIOCSTGSZ :
- if (fr_nat_lock) {
- error = fr_natgetsz(data, getlock);
- } else
+ if (softn->ipf_nat_lock) {
+ error = ipf_nat_getsz(softc, data, getlock);
+ } else {
+ IPFERROR(60017);
error = EACCES;
+ }
break;
case SIOCSTGET :
- if (fr_nat_lock) {
- error = fr_natgetent(data, getlock);
- } else
+ if (softn->ipf_nat_lock) {
+ error = ipf_nat_getent(softc, data, getlock);
+ } else {
+ IPFERROR(60018);
error = EACCES;
+ }
break;
case SIOCGENITER :
{
ipfgeniter_t iter;
ipftoken_t *token;
+ ipfobj_t obj;
+
+ error = ipf_inobj(softc, data, &obj, &iter, IPFOBJ_GENITER);
+ if (error != 0)
+ break;
SPL_SCHED(s);
- error = fr_inobj(data, &iter, IPFOBJ_GENITER);
- if (error == 0) {
- token = ipf_findtoken(iter.igi_type, uid, ctx);
- if (token != NULL) {
- error = nat_iterator(token, &iter);
- }
- RWLOCK_EXIT(&ipf_tokens);
+ token = ipf_token_find(softc, iter.igi_type, uid, ctx);
+ if (token != NULL) {
+ error = ipf_nat_iterator(softc, token, &iter, &obj);
+ WRITE_ENTER(&softc->ipf_tokens);
+ ipf_token_deref(softc, token);
+ RWLOCK_EXIT(&softc->ipf_tokens);
}
SPL_X(s);
break;
}
case SIOCIPFDELTOK :
- error = BCOPYIN((caddr_t)data, (caddr_t)&arg, sizeof(arg));
+ error = BCOPYIN(data, &arg, sizeof(arg));
if (error == 0) {
SPL_SCHED(s);
- error = ipf_deltoken(arg, uid, ctx);
+ error = ipf_token_del(softc, arg, uid, ctx);
SPL_X(s);
} else {
+ IPFERROR(60019);
error = EFAULT;
}
break;
case SIOCGTQTAB :
- error = fr_outobj(data, nat_tqb, IPFOBJ_STATETQTAB);
+ error = ipf_outobj(softc, data, softn->ipf_nat_tcptq,
+ IPFOBJ_STATETQTAB);
break;
case SIOCGTABL :
- error = nat_gettable(data);
+ error = ipf_nat_gettable(softc, softn, data);
break;
default :
+ IPFERROR(60020);
error = EINVAL;
break;
}
done:
+ if (nat != NULL)
+ ipf_nat_rule_fini(softc, nat);
if (nt != NULL)
- KFREE(nt);
+ KFREES(nt, nt->in_size);
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_siocaddnat */
+/* Function: ipf_nat_siocaddnat */
/* Returns: int - 0 == success, != 0 == failure */
-/* Parameters: n(I) - pointer to new NAT rule */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softn(I) - pointer to NAT context structure */
+/* n(I) - pointer to new NAT rule */
/* np(I) - pointer to where to insert new NAT rule */
-/* getlock(I) - flag indicating if lock on ipf_nat is held */
-/* Mutex Locks: ipf_natio */
+/* getlock(I) - flag indicating if lock on is held */
+/* Mutex Locks: ipf_nat_io */
/* */
/* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */
/* from information passed to the kernel, then add it to the appropriate */
/* NAT rule table(s). */
/* ------------------------------------------------------------------------ */
-static int nat_siocaddnat(n, np, getlock)
-ipnat_t *n, **np;
-int getlock;
+static int
+ipf_nat_siocaddnat(softc, softn, n, getlock)
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
+ ipnat_t *n;
+ int getlock;
{
- int error = 0, i, j;
+ int error = 0;
- if (nat_resolverule(n) != 0)
+ if (ipf_nat_resolverule(softc, n) != 0) {
+ IPFERROR(60022);
return ENOENT;
+ }
- if ((n->in_age[0] == 0) && (n->in_age[1] != 0))
+ if ((n->in_age[0] == 0) && (n->in_age[1] != 0)) {
+ IPFERROR(60023);
return EINVAL;
+ }
- n->in_use = 0;
- 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 if (n->in_outmsk != 0)
- n->in_space = ~ntohl(n->in_outmsk);
- else
- n->in_space = 1;
-
- /*
- * 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) {
- n->in_pnext = ntohs(n->in_pmin);
+ if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) {
/*
- * Multiply by the number of ports made available.
+ * Prerecord whether or not the destination of the divert
+ * is local or not to the interface the packet is going
+ * to be sent out.
*/
- if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) {
- n->in_space *= (ntohs(n->in_pmax) -
- 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 to allow for
- * at least one IP:IP mapping per protocol.
- */
- if ((n->in_flags & IPN_TCPUDPICMP) == 0) {
- j = n->in_space * 256;
- if (j >= n->in_space)
- n->in_space = j;
- else
- n->in_space = 0xffffffff;
- }
+ n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1],
+ n->in_ifps[1], &n->in_ndstip6);
}
- /* Otherwise, these fields are preset */
-
if (getlock) {
- WRITE_ENTER(&ipf_nat);
+ WRITE_ENTER(&softc->ipf_nat);
}
n->in_next = NULL;
- *np = n;
-
- if (n->in_age[0] != 0)
- n->in_tqehead[0] = fr_addtimeoutqueue(&nat_utqe, n->in_age[0]);
-
- if (n->in_age[1] != 0)
- n->in_tqehead[1] = fr_addtimeoutqueue(&nat_utqe, n->in_age[1]);
+ n->in_pnext = softn->ipf_nat_list_tail;
+ *n->in_pnext = n;
+ softn->ipf_nat_list_tail = &n->in_next;
+ n->in_use++;
if (n->in_redir & NAT_REDIRECT) {
n->in_flags &= ~IPN_NOTDST;
- nat_addrdr(n);
+ switch (n->in_v[0])
+ {
+ case 4 :
+ ipf_nat_addrdr(softn, n);
+ break;
+#ifdef USE_INET6
+ case 6 :
+ ipf_nat6_addrdr(softn, n);
+ break;
+#endif
+ default :
+ break;
+ }
+ ATOMIC_INC32(softn->ipf_nat_stats.ns_rules_rdr);
}
+
if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) {
n->in_flags &= ~IPN_NOTSRC;
- nat_addnat(n);
+ switch (n->in_v[0])
+ {
+ case 4 :
+ ipf_nat_addmap(softn, n);
+ break;
+#ifdef USE_INET6
+ case 6 :
+ ipf_nat6_addmap(softn, n);
+ break;
+#endif
+ default :
+ break;
+ }
+ ATOMIC_INC32(softn->ipf_nat_stats.ns_rules_map);
}
+
+ if (n->in_age[0] != 0)
+ n->in_tqehead[0] = ipf_addtimeoutqueue(softc,
+ &softn->ipf_nat_utqe,
+ n->in_age[0]);
+
+ if (n->in_age[1] != 0)
+ n->in_tqehead[1] = ipf_addtimeoutqueue(softc,
+ &softn->ipf_nat_utqe,
+ n->in_age[1]);
+
MUTEX_INIT(&n->in_lock, "ipnat rule lock");
n = NULL;
- nat_stats.ns_rules++;
-#if SOLARIS && !defined(_INET_IP_STACK_H)
+ ATOMIC_INC32(softn->ipf_nat_stats.ns_rules);
+#if SOLARIS && !defined(INSTANCES)
pfil_delayed_copy = 0;
#endif
if (getlock) {
- RWLOCK_EXIT(&ipf_nat); /* WRITE */
+ RWLOCK_EXIT(&softc->ipf_nat); /* WRITE */
}
return error;
@@ -1093,30 +1548,113 @@ int getlock;
/* ------------------------------------------------------------------------ */
-/* Function: nat_resolvrule */
+/* Function: ipf_nat_ruleaddrinit */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softn(I) - pointer to NAT context structure */
+/* n(I) - pointer to NAT rule */
+/* */
+/* Initialise all of the NAT address structures in a NAT rule. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_ruleaddrinit(softc, softn, n)
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
+ ipnat_t *n;
+{
+ int idx, error;
+
+ if ((n->in_ndst.na_atype == FRI_LOOKUP) &&
+ (n->in_ndst.na_type != IPLT_DSTLIST)) {
+ IPFERROR(60071);
+ return EINVAL;
+ }
+ if ((n->in_nsrc.na_atype == FRI_LOOKUP) &&
+ (n->in_nsrc.na_type != IPLT_DSTLIST)) {
+ IPFERROR(60069);
+ return EINVAL;
+ }
+
+ if (n->in_redir == NAT_BIMAP) {
+ n->in_ndstaddr = n->in_osrcaddr;
+ n->in_ndstmsk = n->in_osrcmsk;
+ n->in_odstaddr = n->in_nsrcaddr;
+ n->in_odstmsk = n->in_nsrcmsk;
+
+ }
+
+ if (n->in_redir & NAT_REDIRECT)
+ idx = 1;
+ else
+ idx = 0;
+ /*
+ * Initialise all of the address fields.
+ */
+ error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc, 1,
+ n->in_ifps[idx]);
+ if (error != 0)
+ return error;
+
+ error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst, 1,
+ n->in_ifps[idx]);
+ if (error != 0)
+ return error;
+
+ error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc, 1,
+ n->in_ifps[idx]);
+ if (error != 0)
+ return error;
+
+ error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst, 1,
+ n->in_ifps[idx]);
+ if (error != 0)
+ return error;
+
+ if (n->in_redir & NAT_DIVERTUDP)
+ ipf_nat_builddivertmp(softn, n);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_resolvrule */
/* Returns: Nil */
-/* Parameters: n(I) - pointer to NAT rule */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* n(I) - pointer to NAT rule */
/* */
/* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */
/* from information passed to the kernel, then add it to the appropriate */
/* NAT rule table(s). */
/* ------------------------------------------------------------------------ */
-static int nat_resolverule(n)
-ipnat_t *n;
+static int
+ipf_nat_resolverule(softc, n)
+ ipf_main_softc_t *softc;
+ ipnat_t *n;
{
- n->in_ifnames[0][LIFNAMSIZ - 1] = '\0';
- n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], 4);
+ char *base;
+
+ base = n->in_names;
- n->in_ifnames[1][LIFNAMSIZ - 1] = '\0';
- if (n->in_ifnames[1][0] == '\0') {
- (void) strncpy(n->in_ifnames[1], n->in_ifnames[0], LIFNAMSIZ);
+ n->in_ifps[0] = ipf_resolvenic(softc, base + n->in_ifnames[0],
+ n->in_v[0]);
+
+ if (n->in_ifnames[1] == -1) {
+ n->in_ifnames[1] = n->in_ifnames[0];
n->in_ifps[1] = n->in_ifps[0];
} else {
- n->in_ifps[1] = fr_resolvenic(n->in_ifnames[1], 4);
+ n->in_ifps[1] = ipf_resolvenic(softc, base + n->in_ifnames[1],
+ n->in_v[1]);
}
- if (n->in_plabel[0] != '\0') {
- n->in_apr = appr_lookup(n->in_p, n->in_plabel);
+ if (n->in_plabel != -1) {
+ if (n->in_redir & NAT_REDIRECT)
+ n->in_apr = ipf_proxy_lookup(softc->ipf_proxy_soft,
+ n->in_pr[0],
+ base + n->in_plabel);
+ else
+ n->in_apr = ipf_proxy_lookup(softc->ipf_proxy_soft,
+ n->in_pr[1],
+ base + n->in_plabel);
if (n->in_apr == NULL)
return -1;
}
@@ -1125,106 +1663,93 @@ ipnat_t *n;
/* ------------------------------------------------------------------------ */
-/* Function: nat_siocdelnat */
+/* Function: ipf_nat_siocdelnat */
/* Returns: int - 0 == success, != 0 == failure */
-/* Parameters: n(I) - pointer to new NAT rule */
-/* np(I) - pointer to where to insert new NAT rule */
-/* getlock(I) - flag indicating if lock on ipf_nat is held */
-/* Mutex Locks: ipf_natio */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softn(I) - pointer to NAT context structure */
+/* n(I) - pointer to new NAT rule */
+/* getlock(I) - flag indicating if lock on is held */
+/* Mutex Locks: ipf_nat_io */
/* */
/* Handle SIOCADNAT. Resolve and calculate details inside the NAT rule */
/* from information passed to the kernel, then add it to the appropriate */
/* NAT rule table(s). */
/* ------------------------------------------------------------------------ */
-static void nat_siocdelnat(n, np, getlock)
-ipnat_t *n, **np;
-int getlock;
+static void
+ipf_nat_siocdelnat(softc, softn, n, getlock)
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
+ ipnat_t *n;
+ int getlock;
{
- if (getlock) {
- WRITE_ENTER(&ipf_nat);
- }
- 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;
- }
-
- if (n->in_tqehead[0] != NULL) {
- if (fr_deletetimeoutqueue(n->in_tqehead[0]) == 0) {
- fr_freetimeoutqueue(n->in_tqehead[1]);
- }
- }
+#ifdef IPF_NAT6
+ int i;
+#endif
- if (n->in_tqehead[1] != NULL) {
- if (fr_deletetimeoutqueue(n->in_tqehead[1]) == 0) {
- fr_freetimeoutqueue(n->in_tqehead[1]);
- }
+ if (getlock) {
+ WRITE_ENTER(&softc->ipf_nat);
}
- *np = n->in_next;
+ ipf_nat_delrule(softc, softn, n, 1);
- if (n->in_use == 0) {
- if (n->in_apr)
- appr_free(n->in_apr);
- MUTEX_DESTROY(&n->in_lock);
- KFREE(n);
- nat_stats.ns_rules--;
-#if SOLARIS && !defined(_INET_IP_STACK_H)
- if (nat_stats.ns_rules == 0)
- pfil_delayed_copy = 1;
-#endif
- } else {
- n->in_flags |= IPN_DELETE;
- n->in_next = NULL;
- }
if (getlock) {
- RWLOCK_EXIT(&ipf_nat); /* READ/WRITE */
+ RWLOCK_EXIT(&softc->ipf_nat); /* READ/WRITE */
}
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_natgetsz */
+/* Function: ipf_nat_getsz */
/* Returns: int - 0 == success, != 0 is the error value. */
-/* Parameters: data(I) - pointer to natget structure with kernel pointer */
-/* get the size of. */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* data(I) - pointer to natget structure with kernel */
+/* pointer get the size of. */
+/* getlock(I) - flag indicating whether or not the caller */
+/* holds a lock on ipf_nat */
/* */
/* Handle SIOCSTGSZ. */
/* Return the size of the nat list entry to be copied back to user space. */
/* The size of the entry is stored in the ng_sz field and the enture natget */
/* structure is copied back to the user. */
/* ------------------------------------------------------------------------ */
-static int fr_natgetsz(data, getlock)
-caddr_t data;
-int getlock;
+static int
+ipf_nat_getsz(softc, data, getlock)
+ ipf_main_softc_t *softc;
+ caddr_t data;
+ int getlock;
{
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
ap_session_t *aps;
nat_t *nat, *n;
natget_t ng;
+ int error;
- if (BCOPYIN(data, &ng, sizeof(ng)) != 0)
+ error = BCOPYIN(data, &ng, sizeof(ng));
+ if (error != 0) {
+ IPFERROR(60024);
return EFAULT;
+ }
if (getlock) {
- READ_ENTER(&ipf_nat);
+ READ_ENTER(&softc->ipf_nat);
}
nat = ng.ng_ptr;
if (!nat) {
- nat = nat_instances;
+ nat = softn->ipf_nat_instances;
ng.ng_sz = 0;
/*
* Empty list so the size returned is 0. Simple.
*/
if (nat == NULL) {
if (getlock) {
- RWLOCK_EXIT(&ipf_nat);
+ RWLOCK_EXIT(&softc->ipf_nat);
}
- if (BCOPYOUT(&ng, data, sizeof(ng)) != 0)
+ error = BCOPYOUT(&ng, data, sizeof(ng));
+ if (error != 0) {
+ IPFERROR(60025);
return EFAULT;
+ }
return 0;
}
} else {
@@ -1233,13 +1758,14 @@ int getlock;
* current list of entries. Security precaution to prevent
* copying of random kernel data.
*/
- for (n = nat_instances; n; n = n->nat_next)
+ for (n = softn->ipf_nat_instances; n; n = n->nat_next)
if (n == nat)
break;
if (n == NULL) {
if (getlock) {
- RWLOCK_EXIT(&ipf_nat);
+ RWLOCK_EXIT(&softc->ipf_nat);
}
+ IPFERROR(60026);
return ESRCH;
}
}
@@ -1255,56 +1781,71 @@ int getlock;
ng.ng_sz += aps->aps_psiz;
}
if (getlock) {
- RWLOCK_EXIT(&ipf_nat);
+ RWLOCK_EXIT(&softc->ipf_nat);
}
- if (BCOPYOUT(&ng, data, sizeof(ng)) != 0)
+ error = BCOPYOUT(&ng, data, sizeof(ng));
+ if (error != 0) {
+ IPFERROR(60027);
return EFAULT;
+ }
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_natgetent */
+/* Function: ipf_nat_getent */
/* Returns: int - 0 == success, != 0 is the error value. */
-/* Parameters: data(I) - pointer to natget structure with kernel pointer */
-/* to NAT structure to copy out. */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* data(I) - pointer to natget structure with kernel pointer*/
+/* to NAT structure to copy out. */
+/* getlock(I) - flag indicating whether or not the caller */
+/* holds a lock on ipf_nat */
/* */
/* Handle SIOCSTGET. */
/* Copies out NAT entry to user space. Any additional data held for a */
/* proxy is also copied, as to is the NAT rule which was responsible for it */
/* ------------------------------------------------------------------------ */
-static int fr_natgetent(data, getlock)
-caddr_t data;
-int getlock;
+static int
+ipf_nat_getent(softc, data, getlock)
+ ipf_main_softc_t *softc;
+ caddr_t data;
+ int getlock;
{
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
int error, outsize;
ap_session_t *aps;
nat_save_t *ipn, ipns;
nat_t *n, *nat;
- error = fr_inobj(data, &ipns, IPFOBJ_NATSAVE);
+ error = ipf_inobj(softc, data, NULL, &ipns, IPFOBJ_NATSAVE);
if (error != 0)
return error;
- if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920))
+ if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920)) {
+ IPFERROR(60028);
return EINVAL;
+ }
KMALLOCS(ipn, nat_save_t *, ipns.ipn_dsize);
- if (ipn == NULL)
+ if (ipn == NULL) {
+ IPFERROR(60029);
return ENOMEM;
+ }
if (getlock) {
- READ_ENTER(&ipf_nat);
+ READ_ENTER(&softc->ipf_nat);
}
ipn->ipn_dsize = ipns.ipn_dsize;
nat = ipns.ipn_next;
if (nat == NULL) {
- nat = nat_instances;
+ nat = softn->ipf_nat_instances;
if (nat == NULL) {
- if (nat_instances == NULL)
+ if (softn->ipf_nat_instances == NULL) {
+ IPFERROR(60030);
error = ENOENT;
+ }
goto finished;
}
} else {
@@ -1313,10 +1854,11 @@ int getlock;
* current list of entries. Security precaution to prevent
* copying of random kernel data.
*/
- for (n = nat_instances; n; n = n->nat_next)
+ for (n = softn->ipf_nat_instances; n; n = n->nat_next)
if (n == nat)
break;
if (n == NULL) {
+ IPFERROR(60031);
error = ESRCH;
goto finished;
}
@@ -1333,7 +1875,7 @@ int getlock;
*/
if (nat->nat_ptr != NULL)
bcopy((char *)nat->nat_ptr, (char *)&ipn->ipn_ipnat,
- sizeof(ipn->ipn_ipnat));
+ ipn->ipn_ipnat.in_size);
/*
* If we also know the NAT entry has an associated filter rule,
@@ -1354,6 +1896,7 @@ int getlock;
char *s;
if (outsize < sizeof(*aps)) {
+ IPFERROR(60032);
error = ENOBUFS;
goto finished;
}
@@ -1364,20 +1907,23 @@ int getlock;
outsize -= sizeof(*aps);
if ((aps->aps_data != NULL) && (outsize >= aps->aps_psiz))
bcopy(aps->aps_data, s, aps->aps_psiz);
- else
+ else {
+ IPFERROR(60033);
error = ENOBUFS;
+ }
}
if (error == 0) {
if (getlock) {
- RWLOCK_EXIT(&ipf_nat);
+ READ_ENTER(&softc->ipf_nat);
getlock = 0;
}
- error = fr_outobjsz(data, ipn, IPFOBJ_NATSAVE, ipns.ipn_dsize);
+ error = ipf_outobjsz(softc, data, ipn, IPFOBJ_NATSAVE,
+ ipns.ipn_dsize);
}
finished:
if (getlock) {
- RWLOCK_EXIT(&ipf_nat);
+ READ_ENTER(&softc->ipf_nat);
}
if (ipn != NULL) {
KFREES(ipn, ipns.ipn_dsize);
@@ -1387,21 +1933,25 @@ finished:
/* ------------------------------------------------------------------------ */
-/* Function: fr_natputent */
+/* Function: ipf_nat_putent */
/* Returns: int - 0 == success, != 0 is the error value. */
-/* Parameters: data(I) - pointer to natget structure with NAT */
-/* structure information to load into the kernel */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* data(I) - pointer to natget structure with NAT */
+/* structure information to load into the kernel */
/* getlock(I) - flag indicating whether or not a write lock */
-/* on ipf_nat is already held. */
+/* on is already held. */
/* */
/* Handle SIOCSTPUT. */
/* Loads a NAT table entry from user space, including a NAT rule, proxy and */
/* firewall rule data structures, if pointers to them indicate so. */
/* ------------------------------------------------------------------------ */
-static int fr_natputent(data, getlock)
-caddr_t data;
-int getlock;
+static int
+ipf_nat_putent(softc, data, getlock)
+ ipf_main_softc_t *softc;
+ caddr_t data;
+ int getlock;
{
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
nat_save_t ipn, *ipnn;
ap_session_t *aps;
nat_t *n, *nat;
@@ -1410,13 +1960,14 @@ int getlock;
ipnat_t *in;
int error;
- error = fr_inobj(data, &ipn, IPFOBJ_NATSAVE);
+ error = ipf_inobj(softc, data, NULL, &ipn, IPFOBJ_NATSAVE);
if (error != 0)
return error;
/*
* Initialise early because of code at junkput label.
*/
+ n = NULL;
in = NULL;
aps = NULL;
nat = NULL;
@@ -1429,17 +1980,21 @@ int getlock;
*/
if (ipn.ipn_dsize > sizeof(ipn)) {
if (ipn.ipn_dsize > 81920) {
+ IPFERROR(60034);
error = ENOMEM;
goto junkput;
}
KMALLOCS(ipnn, nat_save_t *, ipn.ipn_dsize);
- if (ipnn == NULL)
+ if (ipnn == NULL) {
+ IPFERROR(60035);
return ENOMEM;
+ }
- error = fr_inobjsz(data, ipnn, IPFOBJ_NATSAVE, ipn.ipn_dsize);
+ bzero(ipnn, ipn.ipn_dsize);
+ error = ipf_inobjsz(softc, data, ipnn, IPFOBJ_NATSAVE,
+ ipn.ipn_dsize);
if (error != 0) {
- error = EFAULT;
goto junkput;
}
} else
@@ -1447,13 +2002,29 @@ int getlock;
KMALLOC(nat, nat_t *);
if (nat == NULL) {
+ IPFERROR(60037);
error = ENOMEM;
goto junkput;
}
bcopy((char *)&ipnn->ipn_nat, (char *)nat, sizeof(*nat));
+
+ switch (nat->nat_v[0])
+ {
+ case 4:
+#ifdef USE_INET6
+ case 6 :
+#endif
+ break;
+ default :
+ IPFERROR(60061);
+ error = EPROTONOSUPPORT;
+ goto junkput;
+ /*NOTREACHED*/
+ }
+
/*
- * Initialize all these so that nat_delete() doesn't cause a crash.
+ * Initialize all these so that ipf_nat_delete() doesn't cause a crash.
*/
bzero((char *)nat, offsetof(struct nat, nat_tqe));
nat->nat_tqe.tqe_pnext = NULL;
@@ -1466,20 +2037,22 @@ int getlock;
*/
in = ipnn->ipn_nat.nat_ptr;
if (in != NULL) {
- KMALLOC(in, ipnat_t *);
+ KMALLOCS(in, ipnat_t *, ipnn->ipn_ipnat.in_size);
nat->nat_ptr = in;
if (in == NULL) {
+ IPFERROR(60038);
error = ENOMEM;
goto junkput;
}
- bzero((char *)in, offsetof(struct ipnat, in_next6));
- bcopy((char *)&ipnn->ipn_ipnat, (char *)in, sizeof(*in));
+ bcopy((char *)&ipnn->ipn_ipnat, (char *)in,
+ ipnn->ipn_ipnat.in_size);
in->in_use = 1;
in->in_flags |= IPN_DELETE;
- ATOMIC_INC(nat_stats.ns_rules);
+ ATOMIC_INC32(softn->ipf_nat_stats.ns_rules);
- if (nat_resolverule(in) != 0) {
+ if (ipf_nat_resolverule(softc, in) != 0) {
+ IPFERROR(60039);
error = ESRCH;
goto junkput;
}
@@ -1491,43 +2064,76 @@ int getlock;
* For NAT_OUTBOUND, we're lookup for a duplicate MAP entry. To do
* this, we check to see if the inbound combination of addresses and
* ports is already known. Similar logic is applied for NAT_INBOUND.
- *
+ *
*/
bzero((char *)&fin, sizeof(fin));
- fin.fin_p = nat->nat_p;
- if (nat->nat_dir == NAT_OUTBOUND) {
- fin.fin_ifp = nat->nat_ifps[0];
- fin.fin_data[0] = ntohs(nat->nat_oport);
- fin.fin_data[1] = ntohs(nat->nat_outport);
+ fin.fin_v = nat->nat_v[0];
+ fin.fin_p = nat->nat_pr[0];
+ fin.fin_rev = nat->nat_rev;
+ fin.fin_ifp = nat->nat_ifps[0];
+ fin.fin_data[0] = ntohs(nat->nat_ndport);
+ fin.fin_data[1] = ntohs(nat->nat_nsport);
+
+ switch (nat->nat_dir)
+ {
+ case NAT_OUTBOUND :
+ case NAT_DIVERTOUT :
if (getlock) {
- READ_ENTER(&ipf_nat);
+ READ_ENTER(&softc->ipf_nat);
+ }
+
+ fin.fin_v = nat->nat_v[1];
+ if (nat->nat_v[1] == 4) {
+ n = ipf_nat_inlookup(&fin, nat->nat_flags, fin.fin_p,
+ nat->nat_ndstip, nat->nat_nsrcip);
+#ifdef USE_INET6
+ } else if (nat->nat_v[1] == 6) {
+ n = ipf_nat6_inlookup(&fin, nat->nat_flags, fin.fin_p,
+ &nat->nat_ndst6.in6,
+ &nat->nat_nsrc6.in6);
+#endif
}
- n = nat_inlookup(&fin, nat->nat_flags, fin.fin_p,
- nat->nat_oip, nat->nat_inip);
+
if (getlock) {
- RWLOCK_EXIT(&ipf_nat);
+ RWLOCK_EXIT(&softc->ipf_nat);
}
if (n != NULL) {
+ IPFERROR(60040);
error = EEXIST;
goto junkput;
}
- } else if (nat->nat_dir == NAT_INBOUND) {
- fin.fin_ifp = nat->nat_ifps[0];
- fin.fin_data[0] = ntohs(nat->nat_outport);
- fin.fin_data[1] = ntohs(nat->nat_oport);
+ break;
+
+ case NAT_INBOUND :
+ case NAT_DIVERTIN :
if (getlock) {
- READ_ENTER(&ipf_nat);
+ READ_ENTER(&softc->ipf_nat);
+ }
+
+ if (fin.fin_v == 4) {
+ n = ipf_nat_outlookup(&fin, nat->nat_flags, fin.fin_p,
+ nat->nat_ndstip,
+ nat->nat_nsrcip);
+#ifdef USE_INET6
+ } else if (fin.fin_v == 6) {
+ n = ipf_nat6_outlookup(&fin, nat->nat_flags, fin.fin_p,
+ &nat->nat_ndst6.in6,
+ &nat->nat_nsrc6.in6);
+#endif
}
- n = nat_outlookup(&fin, nat->nat_flags, fin.fin_p,
- nat->nat_outip, nat->nat_oip);
+
if (getlock) {
- RWLOCK_EXIT(&ipf_nat);
+ RWLOCK_EXIT(&softc->ipf_nat);
}
if (n != NULL) {
+ IPFERROR(60041);
error = EEXIST;
goto junkput;
}
- } else {
+ break;
+
+ default :
+ IPFERROR(60042);
error = EINVAL;
goto junkput;
}
@@ -1541,6 +2147,7 @@ int getlock;
KMALLOC(aps, ap_session_t *);
nat->nat_aps = aps;
if (aps == NULL) {
+ IPFERROR(60043);
error = ENOMEM;
goto junkput;
}
@@ -1551,11 +2158,13 @@ int getlock;
aps->aps_apr = NULL;
if (aps->aps_psiz != 0) {
if (aps->aps_psiz > 81920) {
+ IPFERROR(60044);
error = ENOMEM;
goto junkput;
}
KMALLOCS(aps->aps_data, void *, aps->aps_psiz);
if (aps->aps_data == NULL) {
+ IPFERROR(60045);
error = ENOMEM;
goto junkput;
}
@@ -1577,12 +2186,13 @@ int getlock;
KMALLOC(fr, frentry_t *);
nat->nat_fr = fr;
if (fr == NULL) {
+ IPFERROR(60046);
error = ENOMEM;
goto junkput;
}
ipnn->ipn_nat.nat_fr = fr;
fr->fr_ref = 1;
- (void) fr_outobj(data, ipnn, IPFOBJ_NATSAVE);
+ (void) ipf_outobj(softc, data, ipnn, IPFOBJ_NATSAVE);
bcopy((char *)&ipnn->ipn_fr, (char *)fr, sizeof(*fr));
fr->fr_ref = 1;
@@ -1594,9 +2204,9 @@ int getlock;
MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock");
} else {
if (getlock) {
- READ_ENTER(&ipf_nat);
+ READ_ENTER(&softc->ipf_nat);
}
- for (n = nat_instances; n; n = n->nat_next)
+ for (n = softn->ipf_nat_instances; n; n = n->nat_next)
if (n->nat_fr == fr)
break;
@@ -1606,10 +2216,11 @@ int getlock;
MUTEX_EXIT(&fr->fr_lock);
}
if (getlock) {
- RWLOCK_EXIT(&ipf_nat);
+ RWLOCK_EXIT(&softc->ipf_nat);
}
- if (!n) {
+ if (n == NULL) {
+ IPFERROR(60047);
error = ESRCH;
goto junkput;
}
@@ -1622,25 +2233,30 @@ int getlock;
}
if (getlock) {
- WRITE_ENTER(&ipf_nat);
- }
- error = nat_insert(nat, nat->nat_rev);
- if ((error == 0) && (aps != NULL)) {
- aps->aps_next = ap_sess_list;
- ap_sess_list = aps;
+ WRITE_ENTER(&softc->ipf_nat);
}
+
+ if (fin.fin_v == 4)
+ error = ipf_nat_finalise(&fin, nat);
+#ifdef USE_INET6
+ else
+ error = ipf_nat6_finalise(&fin, nat);
+#endif
+
if (getlock) {
- RWLOCK_EXIT(&ipf_nat);
+ RWLOCK_EXIT(&softc->ipf_nat);
}
if (error == 0)
return 0;
+ IPFERROR(60048);
error = ENOMEM;
junkput:
- if (fr != NULL)
- (void) fr_derefrule(&fr);
+ if (fr != NULL) {
+ (void) ipf_derefrule(softc, &fr);
+ }
if ((ipnn != NULL) && (ipnn != &ipn)) {
KFREES(ipnn, ipn.ipn_dsize);
@@ -1654,8 +2270,8 @@ junkput:
}
if (in != NULL) {
if (in->in_apr)
- appr_free(in->in_apr);
- KFREE(in);
+ ipf_proxy_deref(in->in_apr);
+ KFREES(in, in->in_size);
}
KFREE(nat);
}
@@ -1664,27 +2280,29 @@ junkput:
/* ------------------------------------------------------------------------ */
-/* Function: nat_delete */
+/* Function: ipf_nat_delete */
/* Returns: Nil */
-/* Parameters: natd(I) - pointer to NAT structure to delete */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* nat(I) - pointer to NAT structure to delete */
/* logtype(I) - type of LOG record to create before deleting */
/* Write Lock: ipf_nat */
/* */
/* Delete a nat entry from the various lists and table. If NAT logging is */
/* enabled then generate a NAT log record for this event. */
/* ------------------------------------------------------------------------ */
-void nat_delete(nat, logtype)
-struct nat *nat;
-int logtype;
+void
+ipf_nat_delete(softc, nat, logtype)
+ ipf_main_softc_t *softc;
+ struct nat *nat;
+ int logtype;
{
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ int madeorphan = 0, bkt, removed = 0;
+ nat_stat_side_t *nss;
struct ipnat *ipn;
- int removed = 0;
- if (logtype != 0 && nat_logging != 0)
- nat_log(nat, logtype);
-#if defined(NEED_LOCAL_RAND) && defined(_KERNEL)
- ipf_rand_push(nat, sizeof(*nat));
-#endif
+ if (logtype != 0 && softn->ipf_nat_logging != 0)
+ ipf_nat_log(softc, softn, nat, logtype);
/*
* Take it as a general indication that all the pointers are set if
@@ -1693,8 +2311,19 @@ int logtype;
if (nat->nat_pnext != NULL) {
removed = 1;
- nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--;
- nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--;
+ bkt = nat->nat_hv[0] % softn->ipf_nat_table_sz;
+ nss = &softn->ipf_nat_stats.ns_side[0];
+ nss->ns_bucketlen[bkt]--;
+ if (nss->ns_bucketlen[bkt] == 0) {
+ nss->ns_inuse--;
+ }
+
+ bkt = nat->nat_hv[1] % softn->ipf_nat_table_sz;
+ nss = &softn->ipf_nat_stats.ns_side[1];
+ nss->ns_bucketlen[bkt]--;
+ if (nss->ns_bucketlen[bkt] == 0) {
+ nss->ns_inuse--;
+ }
*nat->nat_pnext = nat->nat_next;
if (nat->nat_next != NULL) {
@@ -1717,20 +2346,34 @@ int logtype;
}
nat->nat_phnext[1] = NULL;
- if ((nat->nat_flags & SI_WILDP) != 0)
- nat_stats.ns_wilds--;
+ if ((nat->nat_flags & SI_WILDP) != 0) {
+ ATOMIC_DEC32(softn->ipf_nat_stats.ns_wilds);
+ }
+ madeorphan = 1;
}
if (nat->nat_me != NULL) {
*nat->nat_me = NULL;
nat->nat_me = NULL;
+ nat->nat_ref--;
+ ASSERT(nat->nat_ref >= 0);
+ }
+
+ if (nat->nat_tqe.tqe_ifq != NULL) {
+ /*
+ * No call to ipf_freetimeoutqueue() is made here, they are
+ * garbage collected in ipf_nat_expire().
+ */
+ (void) ipf_deletequeueentry(&nat->nat_tqe);
}
- if (nat->nat_tqe.tqe_ifq != NULL)
- fr_deletequeueentry(&nat->nat_tqe);
+ if (nat->nat_sync) {
+ ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync);
+ nat->nat_sync = NULL;
+ }
if (logtype == NL_EXPIRE)
- nat_stats.ns_expire++;
+ softn->ipf_nat_stats.ns_expire++;
MUTEX_ENTER(&nat->nat_lock);
/*
@@ -1743,35 +2386,36 @@ int logtype;
nat->nat_ref -= 2;
MUTEX_EXIT(&nat->nat_lock);
if (removed)
- nat_stats.ns_orphans++;
+ softn->ipf_nat_stats.ns_orphans++;
return;
}
} else if (nat->nat_ref > 1) {
nat->nat_ref--;
MUTEX_EXIT(&nat->nat_lock);
- if (removed)
- nat_stats.ns_orphans++;
+ if (madeorphan == 1)
+ softn->ipf_nat_stats.ns_orphans++;
return;
}
+ ASSERT(nat->nat_ref >= 0);
MUTEX_EXIT(&nat->nat_lock);
- /*
- * At this point, nat_ref is 1, doing "--" would make it 0..
- */
nat->nat_ref = 0;
- if (!removed)
- nat_stats.ns_orphans--;
-#ifdef IPFILTER_SYNC
- if (nat->nat_sync)
- ipfsync_del(nat->nat_sync);
-#endif
+ if (madeorphan == 0)
+ softn->ipf_nat_stats.ns_orphans--;
- if (nat->nat_fr != NULL)
- (void) fr_derefrule(&nat->nat_fr);
+ /*
+ * At this point, nat_ref can be either 0 or -1
+ */
+ softn->ipf_nat_stats.ns_proto[nat->nat_pr[0]]--;
+
+ if (nat->nat_fr != NULL) {
+ (void) ipf_derefrule(softc, &nat->nat_fr);
+ }
- if (nat->nat_hm != NULL)
- fr_hostmapdel(&nat->nat_hm);
+ if (nat->nat_hm != NULL) {
+ ipf_nat_hostmapdel(softc, &nat->nat_hm);
+ }
/*
* If there is an active reference from the nat entry to its parent
@@ -1779,38 +2423,51 @@ int logtype;
* longer being used.
*/
ipn = nat->nat_ptr;
+ nat->nat_ptr = NULL;
+
if (ipn != NULL) {
- fr_ipnatderef(&ipn);
+ ipn->in_space++;
+ ipf_nat_rule_deref(softc, &ipn);
+ }
+
+ if (nat->nat_aps != NULL) {
+ ipf_proxy_free(softc, nat->nat_aps);
+ nat->nat_aps = NULL;
}
MUTEX_DESTROY(&nat->nat_lock);
- aps_free(nat->nat_aps);
- nat_stats.ns_inuse--;
+ softn->ipf_nat_stats.ns_active--;
/*
* If there's a fragment table entry too for this nat entry, then
* dereference that as well. This is after nat_lock is released
* because of Tru64.
*/
- fr_forgetnat((void *)nat);
+ ipf_frag_natforget(softc, (void *)nat);
KFREE(nat);
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_flushtable */
+/* Function: ipf_nat_flushtable */
/* Returns: int - number of NAT rules deleted */
-/* Parameters: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softn(I) - pointer to NAT context structure */
+/* Write Lock: ipf_nat */
/* */
/* Deletes all currently active NAT sessions. In deleting each NAT entry a */
-/* log record should be emitted in nat_delete() if NAT logging is enabled. */
+/* log record should be emitted in ipf_nat_delete() if NAT logging is */
+/* enabled. */
/* ------------------------------------------------------------------------ */
/*
* nat_flushtable - clear the NAT table of all mapping entries.
*/
-static int nat_flushtable()
+static int
+ipf_nat_flushtable(softc, softn)
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
{
nat_t *nat;
int j = 0;
@@ -1819,67 +2476,141 @@ static int nat_flushtable()
* ALL NAT mappings deleted, so lets just make the deletions
* quicker.
*/
- 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);
-
- while ((nat = nat_instances) != NULL) {
- nat_delete(nat, NL_FLUSH);
+ if (softn->ipf_nat_table[0] != NULL)
+ bzero((char *)softn->ipf_nat_table[0],
+ sizeof(softn->ipf_nat_table[0]) *
+ softn->ipf_nat_table_sz);
+ if (softn->ipf_nat_table[1] != NULL)
+ bzero((char *)softn->ipf_nat_table[1],
+ sizeof(softn->ipf_nat_table[1]) *
+ softn->ipf_nat_table_sz);
+
+ while ((nat = softn->ipf_nat_instances) != NULL) {
+ ipf_nat_delete(softc, nat, NL_FLUSH);
j++;
}
- nat_stats.ns_inuse = 0;
return j;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_clearlist */
+/* Function: ipf_nat_clearlist */
/* Returns: int - number of NAT/RDR rules deleted */
-/* Parameters: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softn(I) - pointer to NAT context structure */
/* */
/* Delete all rules in the current list of rules. There is nothing elegant */
/* about this cleanup: simply free all entries on the list of rules and */
/* clear out the tables used for hashed NAT rule lookups. */
/* ------------------------------------------------------------------------ */
-static int nat_clearlist()
+static int
+ipf_nat_clearlist(softc, softn)
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
{
- ipnat_t *n, **np = &nat_list;
+ ipnat_t *n;
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) != NULL) {
- *np = n->in_next;
- if (n->in_use == 0) {
- if (n->in_apr != NULL)
- appr_free(n->in_apr);
- MUTEX_DESTROY(&n->in_lock);
- KFREE(n);
- nat_stats.ns_rules--;
- } else {
- n->in_flags |= IPN_DELETE;
- n->in_next = NULL;
- }
+ if (softn->ipf_nat_map_rules != NULL) {
+ bzero((char *)softn->ipf_nat_map_rules,
+ sizeof(*softn->ipf_nat_map_rules) *
+ softn->ipf_nat_maprules_sz);
+ }
+ if (softn->ipf_nat_rdr_rules != NULL) {
+ bzero((char *)softn->ipf_nat_rdr_rules,
+ sizeof(*softn->ipf_nat_rdr_rules) *
+ softn->ipf_nat_rdrrules_sz);
+ }
+
+ while ((n = softn->ipf_nat_list) != NULL) {
+ ipf_nat_delrule(softc, softn, n, 0);
i++;
}
-#if SOLARIS && !defined(_INET_IP_STACK_H)
+#if SOLARIS && !defined(INSTANCES)
pfil_delayed_copy = 1;
#endif
- nat_masks = 0;
- rdr_masks = 0;
return i;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_newmap */
+/* Function: ipf_nat_delrule */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softn(I) - pointer to NAT context structure */
+/* np(I) - pointer to NAT rule to delete */
+/* purge(I) - 1 == allow purge, 0 == prevent purge */
+/* Locks: WRITE(ipf_nat) */
+/* */
+/* Preventing "purge" from occuring is allowed because when all of the NAT */
+/* rules are being removed, allowing the "purge" to walk through the list */
+/* of NAT sessions, possibly multiple times, would be a large performance */
+/* hit, on the order of O(N^2). */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_nat_delrule(softc, softn, np, purge)
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
+ ipnat_t *np;
+ int purge;
+{
+
+ if (np->in_pnext != NULL) {
+ *np->in_pnext = np->in_next;
+ if (np->in_next != NULL)
+ np->in_next->in_pnext = np->in_pnext;
+ if (softn->ipf_nat_list_tail == &np->in_next)
+ softn->ipf_nat_list_tail = np->in_pnext;
+ }
+
+ if ((purge == 1) && ((np->in_flags & IPN_PURGE) != 0)) {
+ nat_t *next;
+ nat_t *nat;
+
+ for (next = softn->ipf_nat_instances; (nat = next) != NULL;) {
+ next = nat->nat_next;
+ if (nat->nat_ptr == np)
+ ipf_nat_delete(softc, nat, NL_PURGE);
+ }
+ }
+
+ if ((np->in_flags & IPN_DELETE) == 0) {
+ if (np->in_redir & NAT_REDIRECT) {
+ switch (np->in_v[0])
+ {
+ case 4 :
+ ipf_nat_delrdr(softn, np);
+ break;
+#ifdef USE_INET6
+ case 6 :
+ ipf_nat6_delrdr(softn, np);
+ break;
+#endif
+ }
+ }
+ if (np->in_redir & (NAT_MAPBLK|NAT_MAP)) {
+ switch (np->in_v[0])
+ {
+ case 4 :
+ ipf_nat_delmap(softn, np);
+ break;
+#ifdef USE_INET6
+ case 6 :
+ ipf_nat6_delmap(softn, np);
+ break;
+#endif
+ }
+ }
+ }
+
+ np->in_flags |= IPN_DELETE;
+ ipf_nat_rule_deref(softc, &np);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_newmap */
/* Returns: int - -1 == error, 0 == success */
/* Parameters: fin(I) - pointer to packet information */
/* nat(I) - pointer to NAT entry */
@@ -1891,11 +2622,14 @@ static int nat_clearlist()
/* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
/* to the new IP address for the translation. */
/* ------------------------------------------------------------------------ */
-static INLINE int nat_newmap(fin, nat, ni)
-fr_info_t *fin;
-nat_t *nat;
-natinfo_t *ni;
+static int
+ipf_nat_newmap(fin, nat, ni)
+ fr_info_t *fin;
+ nat_t *nat;
+ natinfo_t *ni;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
u_short st_port, dport, sport, port, sp, dp;
struct in_addr in, inb;
hostmap_t *hm;
@@ -1912,11 +2646,17 @@ natinfo_t *ni;
l = 0;
hm = NULL;
np = ni->nai_np;
- st_ip = np->in_nip;
- st_port = np->in_pnext;
- flags = ni->nai_flags;
- sport = ni->nai_sport;
- dport = ni->nai_dport;
+ st_ip = np->in_snip;
+ st_port = np->in_spnext;
+ flags = nat->nat_flags;
+
+ if (flags & IPN_ICMPQUERY) {
+ sport = fin->fin_data[1];
+ dport = 0;
+ } else {
+ sport = htons(fin->fin_data[0]);
+ dport = htons(fin->fin_data[1]);
+ }
/*
* Do a loop until we either run out of entries to try or we find
@@ -1925,50 +2665,54 @@ natinfo_t *ni;
*/
do {
port = 0;
- in.s_addr = htonl(np->in_nip);
+ in.s_addr = htonl(np->in_snip);
if (l == 0) {
/*
* Check to see if there is an existing NAT
* setup for this IP address pair.
*/
- hm = nat_hostmap(np, fin->fin_src, fin->fin_dst,
- in, 0);
+ hm = ipf_nat_hostmap(softn, np, fin->fin_src,
+ fin->fin_dst, in, 0);
if (hm != NULL)
- in.s_addr = hm->hm_mapip.s_addr;
+ in.s_addr = hm->hm_nsrcip.s_addr;
} else if ((l == 1) && (hm != NULL)) {
- fr_hostmapdel(&hm);
+ ipf_nat_hostmapdel(softc, &hm);
}
in.s_addr = ntohl(in.s_addr);
nat->nat_hm = hm;
- if ((np->in_outmsk == 0xffffffff) && (np->in_pnext == 0)) {
- if (l > 0)
+ if ((np->in_nsrcmsk == 0xffffffff) && (np->in_spnext == 0)) {
+ if (l > 0) {
+ NBUMPSIDEX(1, ns_exhausted, ns_exhausted_1);
return -1;
+ }
}
if (np->in_redir == NAT_BIMAP &&
- np->in_inmsk == np->in_outmsk) {
+ np->in_osrcmsk == np->in_nsrcmsk) {
/*
* map the address block in a 1:1 fashion
*/
- in.s_addr = np->in_outip;
- in.s_addr |= fin->fin_saddr & ~np->in_inmsk;
+ in.s_addr = np->in_nsrcaddr;
+ in.s_addr |= fin->fin_saddr & ~np->in_osrcmsk;
in.s_addr = ntohl(in.s_addr);
} else if (np->in_redir & NAT_MAPBLK) {
if ((l >= np->in_ppip) || ((l > 0) &&
- !(flags & IPN_TCPUDP)))
+ !(flags & IPN_TCPUDP))) {
+ NBUMPSIDEX(1, ns_exhausted, ns_exhausted_2);
return -1;
+ }
/*
* map-block - Calculate destination address.
*/
in.s_addr = ntohl(fin->fin_saddr);
- in.s_addr &= ntohl(~np->in_inmsk);
+ in.s_addr &= ntohl(~np->in_osrcmsk);
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);
+ in.s_addr &= ntohl(~np->in_nsrcmsk);
+ in.s_addr += ntohl(np->in_nsrcaddr);
/*
* Calculate destination port.
*/
@@ -1982,28 +2726,34 @@ natinfo_t *ni;
port = htons(port);
}
- } else if ((np->in_outip == 0) &&
- (np->in_outmsk == 0xffffffff)) {
+ } else if ((np->in_nsrcaddr == 0) &&
+ (np->in_nsrcmsk == 0xffffffff)) {
+ i6addr_t in6;
+
/*
* 0/32 - use the interface's IP address.
*/
if ((l > 0) ||
- fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp,
- &in, NULL) == -1)
+ ipf_ifpaddr(softc, 4, FRI_NORMAL, fin->fin_ifp,
+ &in6, NULL) == -1) {
+ NBUMPSIDEX(1, ns_new_ifpaddr, ns_new_ifpaddr_1);
return -1;
- in.s_addr = ntohl(in.s_addr);
+ }
+ in.s_addr = ntohl(in6.in4.s_addr);
- } else if ((np->in_outip == 0) && (np->in_outmsk == 0)) {
+ } else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) {
/*
* 0/0 - use the original source address/port.
*/
- if (l > 0)
+ if (l > 0) {
+ NBUMPSIDEX(1, ns_exhausted, ns_exhausted_3);
return -1;
+ }
in.s_addr = ntohl(fin->fin_saddr);
- } else if ((np->in_outmsk != 0xffffffff) &&
- (np->in_pnext == 0) && ((l > 0) || (hm == NULL)))
- np->in_nip++;
+ } else if ((np->in_nsrcmsk != 0xffffffff) &&
+ (np->in_spnext == 0) && ((l > 0) || (hm == NULL)))
+ np->in_snip++;
natl = NULL;
@@ -2014,11 +2764,9 @@ natinfo_t *ni;
* "ports auto" (without map-block)
*/
if ((l > 0) && (l % np->in_ppip == 0)) {
- if (l > np->in_space) {
- return -1;
- } else if ((l > np->in_ppip) &&
- np->in_outmsk != 0xffffffff)
- np->in_nip++;
+ if ((l > np->in_ppip) &&
+ np->in_nsrcmsk != 0xffffffff)
+ np->in_snip++;
}
if (np->in_ppip != 0) {
port = ntohs(sport);
@@ -2032,35 +2780,35 @@ natinfo_t *ni;
}
} else if (((np->in_redir & NAT_MAPBLK) == 0) &&
- (flags & IPN_TCPUDPICMP) && (np->in_pnext != 0)) {
+ (flags & IPN_TCPUDPICMP) && (np->in_spnext != 0)) {
/*
* Standard port translation. Select next port.
*/
if (np->in_flags & IPN_SEQUENTIAL) {
- port = np->in_pnext;
+ port = np->in_spnext;
} else {
- port = ipf_random() % (ntohs(np->in_pmax) -
- ntohs(np->in_pmin));
- port += ntohs(np->in_pmin);
+ port = ipf_random() % (np->in_spmax -
+ np->in_spmin + 1);
+ port += np->in_spmin;
}
port = htons(port);
- np->in_pnext++;
+ np->in_spnext++;
- if (np->in_pnext > ntohs(np->in_pmax)) {
- np->in_pnext = ntohs(np->in_pmin);
- if (np->in_outmsk != 0xffffffff)
- np->in_nip++;
+ if (np->in_spnext > np->in_spmax) {
+ np->in_spnext = np->in_spmin;
+ if (np->in_nsrcmsk != 0xffffffff)
+ np->in_snip++;
}
}
- if (np->in_flags & IPN_IPRANGE) {
- if (np->in_nip > ntohl(np->in_outmsk))
- np->in_nip = ntohl(np->in_outip);
+ if (np->in_flags & IPN_SIPRANGE) {
+ if (np->in_snip > ntohl(np->in_nsrcmsk))
+ np->in_snip = ntohl(np->in_nsrcaddr);
} 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 ((np->in_nsrcmsk != 0xffffffff) &&
+ ((np->in_snip + 1) & ntohl(np->in_nsrcmsk)) >
+ ntohl(np->in_nsrcaddr))
+ np->in_snip = ntohl(np->in_nsrcaddr) + 1;
}
if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY)))
@@ -2080,9 +2828,9 @@ natinfo_t *ni;
sp = fin->fin_data[0];
dp = fin->fin_data[1];
fin->fin_data[0] = fin->fin_data[1];
- fin->fin_data[1] = htons(port);
- natl = nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
- (u_int)fin->fin_p, fin->fin_dst, inb);
+ fin->fin_data[1] = ntohs(port);
+ natl = ipf_nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
+ (u_int)fin->fin_p, fin->fin_dst, inb);
fin->fin_data[0] = sp;
fin->fin_data[1] = dp;
@@ -2091,64 +2839,41 @@ natinfo_t *ni;
* start ?
*/
if ((natl != NULL) &&
- (np->in_pnext != 0) && (st_port == np->in_pnext) &&
- (np->in_nip != 0) && (st_ip == np->in_nip))
+ (np->in_spnext != 0) && (st_port == np->in_spnext) &&
+ (np->in_snip != 0) && (st_ip == np->in_snip)) {
+ NBUMPSIDED(1, ns_wrap);
return -1;
+ }
l++;
} while (natl != NULL);
- if (np->in_space > 0)
- np->in_space--;
-
/* Setup the NAT table */
- nat->nat_inip = fin->fin_src;
- nat->nat_outip.s_addr = htonl(in.s_addr);
- nat->nat_oip = fin->fin_dst;
+ nat->nat_osrcip = fin->fin_src;
+ nat->nat_nsrcaddr = htonl(in.s_addr);
+ nat->nat_odstip = fin->fin_dst;
+ nat->nat_ndstip = fin->fin_dst;
if (nat->nat_hm == NULL)
- nat->nat_hm = nat_hostmap(np, fin->fin_src, fin->fin_dst,
- nat->nat_outip, 0);
-
- /*
- * The ICMP checksum does not have a pseudo header containing
- * the IP addresses
- */
- ni->nai_sum1 = LONG_SUM(ntohl(fin->fin_saddr));
- ni->nai_sum2 = LONG_SUM(in.s_addr);
- if ((flags & IPN_TCPUDP)) {
- ni->nai_sum1 += ntohs(sport);
- ni->nai_sum2 += ntohs(port);
- }
+ nat->nat_hm = ipf_nat_hostmap(softn, np, fin->fin_src,
+ fin->fin_dst, nat->nat_nsrcip,
+ 0);
if (flags & IPN_TCPUDP) {
- nat->nat_inport = sport;
- nat->nat_outport = port; /* sport */
- nat->nat_oport = dport;
+ nat->nat_osport = sport;
+ nat->nat_nsport = port; /* sport */
+ nat->nat_odport = dport;
+ nat->nat_ndport = dport;
((tcphdr_t *)fin->fin_dp)->th_sport = port;
} else if (flags & IPN_ICMPQUERY) {
+ nat->nat_oicmpid = fin->fin_data[1];
((icmphdr_t *)fin->fin_dp)->icmp_id = port;
- nat->nat_inport = port;
- nat->nat_outport = port;
- } else if (fin->fin_p == IPPROTO_GRE) {
-#if 0
- nat->nat_gre.gs_flags = ((grehdr_t *)fin->fin_dp)->gr_flags;
- if (GRE_REV(nat->nat_gre.gs_flags) == 1) {
- nat->nat_oport = 0;/*fin->fin_data[1];*/
- nat->nat_inport = 0;/*fin->fin_data[0];*/
- nat->nat_outport = 0;/*fin->fin_data[0];*/
- nat->nat_call[0] = fin->fin_data[0];
- nat->nat_call[1] = fin->fin_data[0];
- }
-#endif
+ nat->nat_nicmpid = port;
}
- ni->nai_ip.s_addr = in.s_addr;
- ni->nai_port = port;
- ni->nai_nport = dport;
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_newrdr */
+/* Function: ipf_nat_newrdr */
/* Returns: int - -1 == error, 0 == success (no move), 1 == success and */
/* allow rule to be moved if IPN_ROUNDR is set. */
/* Parameters: fin(I) - pointer to packet information */
@@ -2159,11 +2884,14 @@ natinfo_t *ni;
/* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
/* to the new IP address for the translation. */
/* ------------------------------------------------------------------------ */
-static INLINE int nat_newrdr(fin, nat, ni)
-fr_info_t *fin;
-nat_t *nat;
-natinfo_t *ni;
+static int
+ipf_nat_newrdr(fin, nat, ni)
+ fr_info_t *fin;
+ nat_t *nat;
+ natinfo_t *ni;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
u_short nport, dport, sport;
struct in_addr in, inb;
u_short sp, dp;
@@ -2177,9 +2905,18 @@ natinfo_t *ni;
hm = NULL;
in.s_addr = 0;
np = ni->nai_np;
- flags = ni->nai_flags;
- sport = ni->nai_sport;
- dport = ni->nai_dport;
+ flags = nat->nat_flags;
+
+ if (flags & IPN_ICMPQUERY) {
+ dport = fin->fin_data[1];
+ sport = 0;
+ } else {
+ sport = htons(fin->fin_data[0]);
+ dport = htons(fin->fin_data[1]);
+ }
+
+ /* TRACE sport, dport */
+
/*
* If the matching rule has IPN_STICKY set, then we want to have the
@@ -2190,13 +2927,14 @@ natinfo_t *ni;
*/
if (((np->in_flags & (IPN_ROUNDR|IPN_SPLIT)) != 0) &&
((np->in_flags & IPN_STICKY) != 0)) {
- hm = nat_hostmap(NULL, fin->fin_src, fin->fin_dst, in,
- (u_32_t)dport);
+ hm = ipf_nat_hostmap(softn, NULL, fin->fin_src, fin->fin_dst,
+ in, (u_32_t)dport);
if (hm != NULL) {
- in.s_addr = ntohl(hm->hm_mapip.s_addr);
+ in.s_addr = ntohl(hm->hm_ndstip.s_addr);
np = hm->hm_ipnat;
ni->nai_np = np;
move = 0;
+ ipf_nat_hostmapdel(softc, &hm);
}
}
@@ -2207,53 +2945,60 @@ natinfo_t *ni;
* internal port.
*/
if (np->in_flags & IPN_SPLIT) {
- in.s_addr = np->in_nip;
+ in.s_addr = np->in_dnip;
if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) {
- hm = nat_hostmap(NULL, fin->fin_src, fin->fin_dst,
- in, (u_32_t)dport);
+ hm = ipf_nat_hostmap(softn, NULL, fin->fin_src,
+ fin->fin_dst, in, (u_32_t)dport);
if (hm != NULL) {
- in.s_addr = hm->hm_mapip.s_addr;
+ in.s_addr = hm->hm_ndstip.s_addr;
move = 0;
}
}
if (hm == NULL || hm->hm_ref == 1) {
- if (np->in_inip == htonl(in.s_addr)) {
- np->in_nip = ntohl(np->in_inmsk);
+ if (np->in_ndstaddr == htonl(in.s_addr)) {
+ np->in_dnip = ntohl(np->in_ndstmsk);
move = 0;
} else {
- np->in_nip = ntohl(np->in_inip);
+ np->in_dnip = ntohl(np->in_ndstaddr);
}
}
+ if (hm != NULL)
+ ipf_nat_hostmapdel(softc, &hm);
+
+ } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) {
+ i6addr_t in6;
- } else if ((np->in_inip == 0) && (np->in_inmsk == 0xffffffff)) {
/*
* 0/32 - use the interface's IP address.
*/
- if (fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp, &in, NULL) == -1)
+ if (ipf_ifpaddr(softc, 4, FRI_NORMAL, fin->fin_ifp,
+ &in6, NULL) == -1) {
+ NBUMPSIDEX(0, ns_new_ifpaddr, ns_new_ifpaddr_2);
return -1;
- in.s_addr = ntohl(in.s_addr);
+ }
+ in.s_addr = ntohl(in6.in4.s_addr);
- } else if ((np->in_inip == 0) && (np->in_inmsk== 0)) {
+ } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk== 0)) {
/*
* 0/0 - use the original destination address/port.
*/
in.s_addr = ntohl(fin->fin_daddr);
} else if (np->in_redir == NAT_BIMAP &&
- np->in_inmsk == np->in_outmsk) {
+ np->in_ndstmsk == np->in_odstmsk) {
/*
* map the address block in a 1:1 fashion
*/
- in.s_addr = np->in_inip;
- in.s_addr |= fin->fin_daddr & ~np->in_inmsk;
+ in.s_addr = np->in_ndstaddr;
+ in.s_addr |= fin->fin_daddr & ~np->in_ndstmsk;
in.s_addr = ntohl(in.s_addr);
} else {
- in.s_addr = ntohl(np->in_inip);
+ in.s_addr = ntohl(np->in_ndstaddr);
}
- if ((np->in_pnext == 0) || ((flags & NAT_NOTRULEPORT) != 0))
+ if ((np->in_dpnext == 0) || ((flags & NAT_NOTRULEPORT) != 0))
nport = dport;
else {
/*
@@ -2261,12 +3006,15 @@ natinfo_t *ni;
* pmin == pmax, the gain is not significant.
*/
if (((np->in_flags & IPN_FIXEDDPORT) == 0) &&
- (np->in_pmin != np->in_pmax)) {
- nport = ntohs(dport) - ntohs(np->in_pmin) +
- ntohs(np->in_pnext);
+ (np->in_odport != np->in_dtop)) {
+ nport = ntohs(dport) - np->in_odport + np->in_dpmax;
nport = htons(nport);
- } else
- nport = np->in_pnext;
+ } else {
+ nport = htons(np->in_dpnext);
+ np->in_dpnext++;
+ if (np->in_dpnext > np->in_dpmax)
+ np->in_dpnext = np->in_dpmin;
+ }
}
/*
@@ -2275,8 +3023,10 @@ natinfo_t *ni;
* setup any translation for this either.
*/
if (in.s_addr == 0) {
- if (nport == dport)
+ if (nport == dport) {
+ NBUMPSIDED(0, ns_xlate_null);
return -1;
+ }
in.s_addr = ntohl(fin->fin_daddr);
}
@@ -2290,54 +3040,41 @@ natinfo_t *ni;
dp = fin->fin_data[1];
fin->fin_data[1] = fin->fin_data[0];
fin->fin_data[0] = ntohs(nport);
- natl = nat_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
+ natl = ipf_nat_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
(u_int)fin->fin_p, inb, fin->fin_src);
fin->fin_data[0] = sp;
fin->fin_data[1] = dp;
- if (natl != NULL)
+ if (natl != NULL) {
+ DT2(ns_new_xlate_exists, fr_info_t *, fin, nat_t *, natl);
+ NBUMPSIDE(0, ns_xlate_exists);
return -1;
+ }
- nat->nat_inip.s_addr = htonl(in.s_addr);
- nat->nat_outip = fin->fin_dst;
- nat->nat_oip = fin->fin_src;
+ nat->nat_ndstaddr = htonl(in.s_addr);
+ nat->nat_odstip = fin->fin_dst;
+ nat->nat_nsrcip = fin->fin_src;
+ nat->nat_osrcip = fin->fin_src;
if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0))
- nat->nat_hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, in,
- (u_32_t)dport);
-
- ni->nai_sum1 = LONG_SUM(ntohl(fin->fin_daddr)) + ntohs(dport);
- ni->nai_sum2 = LONG_SUM(in.s_addr) + ntohs(nport);
-
- ni->nai_ip.s_addr = in.s_addr;
- ni->nai_nport = nport;
- ni->nai_port = sport;
+ nat->nat_hm = ipf_nat_hostmap(softn, np, fin->fin_src,
+ fin->fin_dst, in, (u_32_t)dport);
if (flags & IPN_TCPUDP) {
- nat->nat_inport = nport;
- nat->nat_outport = dport;
- nat->nat_oport = sport;
+ nat->nat_odport = dport;
+ nat->nat_ndport = nport;
+ nat->nat_osport = sport;
+ nat->nat_nsport = sport;
((tcphdr_t *)fin->fin_dp)->th_dport = nport;
} else if (flags & IPN_ICMPQUERY) {
+ nat->nat_oicmpid = fin->fin_data[1];
((icmphdr_t *)fin->fin_dp)->icmp_id = nport;
- nat->nat_inport = nport;
- nat->nat_outport = nport;
- } else if (fin->fin_p == IPPROTO_GRE) {
-#if 0
- nat->nat_gre.gs_flags = ((grehdr_t *)fin->fin_dp)->gr_flags;
- if (GRE_REV(nat->nat_gre.gs_flags) == 1) {
- nat->nat_call[0] = fin->fin_data[0];
- nat->nat_call[1] = fin->fin_data[1];
- nat->nat_oport = 0; /*fin->fin_data[0];*/
- nat->nat_inport = 0; /*fin->fin_data[1];*/
- nat->nat_outport = 0; /*fin->fin_data[1];*/
- }
-#endif
+ nat->nat_nicmpid = nport;
}
return move;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_new */
+/* Function: ipf_nat_add */
/* Returns: nat_t* - NULL == failure to create new NAT structure, */
/* else pointer to new NAT structure */
/* Parameters: fin(I) - pointer to packet information */
@@ -2358,29 +3095,32 @@ natinfo_t *ni;
/* NOTE: natsave should NOT be used top point back to an ipstate_t struct */
/* as it can result in memory being corrupted. */
/* ------------------------------------------------------------------------ */
-nat_t *nat_new(fin, np, natsave, flags, direction)
-fr_info_t *fin;
-ipnat_t *np;
-nat_t **natsave;
-u_int flags;
-int direction;
+nat_t *
+ipf_nat_add(fin, np, natsave, flags, direction)
+ fr_info_t *fin;
+ ipnat_t *np;
+ nat_t **natsave;
+ u_int flags;
+ int direction;
{
- u_short port = 0, sport = 0, dport = 0, nport = 0;
- tcphdr_t *tcp = NULL;
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
hostmap_t *hm = NULL;
- struct in_addr in;
nat_t *nat, *natl;
+ natstat_t *nsp;
u_int nflags;
natinfo_t ni;
- u_32_t sumd;
int move;
-#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC)
- qpktinfo_t *qpi = fin->fin_qpi;
-#endif
- if (nat_stats.ns_inuse >= ipf_nattable_max) {
- nat_stats.ns_memfail++;
- fr_nat_doflush = 1;
+ nsp = &softn->ipf_nat_stats;
+
+ if ((nsp->ns_active * 100 / softn->ipf_nat_table_max) >
+ softn->ipf_nat_table_wm_high) {
+ softn->ipf_nat_doflush = 1;
+ }
+
+ if (nsp->ns_active >= softn->ipf_nat_table_max) {
+ NBUMPSIDED(fin->fin_out, ns_table_max);
return NULL;
}
@@ -2389,34 +3129,29 @@ int direction;
nflags &= NAT_FROMRULE;
ni.nai_np = np;
- ni.nai_nflags = nflags;
- ni.nai_flags = flags;
ni.nai_dport = 0;
ni.nai_sport = 0;
/* Give me a new nat */
KMALLOC(nat, nat_t *);
if (nat == NULL) {
- nat_stats.ns_memfail++;
+ NBUMPSIDED(fin->fin_out, ns_memfail);
/*
* Try to automatically tune the max # of entries in the
* table allowed to be less than what will cause kmem_alloc()
* to fail and try to eliminate panics due to out of memory
* conditions arising.
*/
- if (ipf_nattable_max > ipf_nattable_sz) {
- ipf_nattable_max = nat_stats.ns_inuse - 100;
- printf("ipf_nattable_max reduced to %d\n",
- ipf_nattable_max);
+ if ((softn->ipf_nat_table_max > softn->ipf_nat_table_sz) &&
+ (nsp->ns_active > 100)) {
+ softn->ipf_nat_table_max = nsp->ns_active - 100;
+ printf("table_max reduced to %d\n",
+ softn->ipf_nat_table_max);
}
return NULL;
}
- if (flags & IPN_TCPUDP) {
- tcp = fin->fin_dp;
- ni.nai_sport = htons(fin->fin_sport);
- ni.nai_dport = htons(fin->fin_dport);
- } else if (flags & IPN_ICMPQUERY) {
+ if (flags & IPN_ICMPQUERY) {
/*
* In the ICMP query NAT code, we translate the ICMP id fields
* to make them unique. This is indepedent of the ICMP type
@@ -2430,28 +3165,34 @@ int direction;
* the concept of source port. We overlay sport, so we can
* maximally reuse the existing code.
*/
- ni.nai_sport = ((icmphdr_t *)fin->fin_dp)->icmp_id;
- ni.nai_dport = ni.nai_sport;
+ ni.nai_sport = fin->fin_data[1];
+ ni.nai_dport = 0;
}
bzero((char *)nat, sizeof(*nat));
nat->nat_flags = flags;
nat->nat_redir = np->in_redir;
-
- if ((flags & NAT_SLAVE) == 0) {
- MUTEX_ENTER(&ipf_nat_new);
- }
+ nat->nat_dir = direction;
+ nat->nat_pr[0] = fin->fin_p;
+ nat->nat_pr[1] = fin->fin_p;
/*
- * Search the current table for a match.
+ * Search the current table for a match and create a new mapping
+ * if there is none found.
*/
- if (direction == NAT_OUTBOUND) {
+ if (np->in_redir & NAT_DIVERTUDP) {
+ move = ipf_nat_newdivert(fin, nat, &ni);
+
+ } else if (np->in_redir & NAT_REWRITE) {
+ move = ipf_nat_newrewrite(fin, nat, &ni);
+
+ } else if (direction == NAT_OUTBOUND) {
/*
* We can now arrange to call this for the same connection
* because ipf_nat_new doesn't protect the code path into
* this function.
*/
- natl = nat_outlookup(fin, nflags, (u_int)fin->fin_p,
+ natl = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p,
fin->fin_src, fin->fin_dst);
if (natl != NULL) {
KFREE(nat);
@@ -2459,166 +3200,184 @@ int direction;
goto done;
}
- move = nat_newmap(fin, nat, &ni);
- if (move == -1)
- goto badnat;
-
- np = ni.nai_np;
- in = ni.nai_ip;
+ move = ipf_nat_newmap(fin, nat, &ni);
} else {
/*
- * NAT_INBOUND is used only for redirects rules
+ * NAT_INBOUND is used for redirects rules
*/
- natl = nat_inlookup(fin, nflags, (u_int)fin->fin_p,
- fin->fin_src, fin->fin_dst);
+ natl = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p,
+ fin->fin_src, fin->fin_dst);
if (natl != NULL) {
KFREE(nat);
nat = natl;
goto done;
}
- move = nat_newrdr(fin, nat, &ni);
- if (move == -1)
- goto badnat;
-
- np = ni.nai_np;
- in = ni.nai_ip;
+ move = ipf_nat_newrdr(fin, nat, &ni);
}
- port = ni.nai_port;
- nport = ni.nai_nport;
+ if (move == -1)
+ goto badnat;
- if ((move == 1) && (np->in_flags & IPN_ROUNDR)) {
- if (np->in_redir == NAT_REDIRECT) {
- nat_delrdr(np);
- nat_addrdr(np);
- } else if (np->in_redir == NAT_MAP) {
- nat_delnat(np);
- nat_addnat(np);
+ np = ni.nai_np;
+
+ nat->nat_mssclamp = np->in_mssclamp;
+ nat->nat_me = natsave;
+ nat->nat_fr = fin->fin_fr;
+ nat->nat_rev = fin->fin_rev;
+ nat->nat_ptr = np;
+ nat->nat_dlocal = np->in_dlocal;
+
+ if ((np->in_apr != NULL) && ((nat->nat_flags & NAT_SLAVE) == 0)) {
+ if (ipf_proxy_new(fin, nat) == -1) {
+ NBUMPSIDED(fin->fin_out, ns_appr_fail);
+ goto badnat;
}
}
- if (flags & IPN_TCPUDP) {
- sport = ni.nai_sport;
- dport = ni.nai_dport;
- } else if (flags & IPN_ICMPQUERY) {
- sport = ni.nai_sport;
- dport = 0;
+ nat->nat_ifps[0] = np->in_ifps[0];
+ if (np->in_ifps[0] != NULL) {
+ COPYIFNAME(np->in_v[0], np->in_ifps[0], nat->nat_ifnames[0]);
}
- CALC_SUMD(ni.nai_sum1, ni.nai_sum2, sumd);
- nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
-#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC)
- if ((flags & IPN_TCP) && dohwcksum &&
- (((ill_t *)qpi->qpi_ill)->ill_ick.ick_magic == ICK_M_CTL_MAGIC)) {
- if (direction == NAT_OUTBOUND)
- ni.nai_sum1 = LONG_SUM(in.s_addr);
- else
- ni.nai_sum1 = LONG_SUM(ntohl(fin->fin_saddr));
- ni.nai_sum1 += LONG_SUM(ntohl(fin->fin_daddr));
- ni.nai_sum1 += 30;
- ni.nai_sum1 = (ni.nai_sum1 & 0xffff) + (ni.nai_sum1 >> 16);
- nat->nat_sumd[1] = NAT_HW_CKSUM|(ni.nai_sum1 & 0xffff);
- } else
-#endif
- nat->nat_sumd[1] = nat->nat_sumd[0];
+ nat->nat_ifps[1] = np->in_ifps[1];
+ if (np->in_ifps[1] != NULL) {
+ COPYIFNAME(np->in_v[1], np->in_ifps[1], nat->nat_ifnames[1]);
+ }
- if ((flags & IPN_TCPUDPICMP) && ((sport != port) || (dport != nport))) {
- if (direction == NAT_OUTBOUND)
- ni.nai_sum1 = LONG_SUM(ntohl(fin->fin_saddr));
- else
- ni.nai_sum1 = LONG_SUM(ntohl(fin->fin_daddr));
+ if (ipf_nat_finalise(fin, nat) == -1) {
+ goto badnat;
+ }
- ni.nai_sum2 = LONG_SUM(in.s_addr);
+ np->in_use++;
- CALC_SUMD(ni.nai_sum1, ni.nai_sum2, sumd);
- nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
- } else {
- nat->nat_ipsumd = nat->nat_sumd[0];
- if (!(flags & IPN_TCPUDPICMP)) {
- nat->nat_sumd[0] = 0;
- nat->nat_sumd[1] = 0;
+ if ((move == 1) && (np->in_flags & IPN_ROUNDR)) {
+ if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_REDIRECT) {
+ ipf_nat_delrdr(softn, np);
+ ipf_nat_addrdr(softn, np);
+ } else if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_MAP) {
+ ipf_nat_delmap(softn, np);
+ ipf_nat_addmap(softn, np);
}
}
- if (nat_finalise(fin, nat, &ni, tcp, natsave, direction) == -1) {
- fr_nat_doflush = 1;
- goto badnat;
- }
if (flags & SI_WILDP)
- nat_stats.ns_wilds++;
- fin->fin_flx |= FI_NEWNAT;
+ nsp->ns_wilds++;
+ nsp->ns_proto[nat->nat_pr[0]]++;
+
goto done;
badnat:
- nat_stats.ns_badnat++;
+ DT2(ns_badnatnew, fr_info_t *, fin, nat_t *, nat);
+ NBUMPSIDE(fin->fin_out, ns_badnatnew);
if ((hm = nat->nat_hm) != NULL)
- fr_hostmapdel(&hm);
+ ipf_nat_hostmapdel(softc, &hm);
KFREE(nat);
nat = NULL;
done:
- if ((flags & NAT_SLAVE) == 0) {
- MUTEX_EXIT(&ipf_nat_new);
- }
+ if (nat != NULL && np != NULL)
+ np->in_hits++;
+ if (natsave != NULL)
+ *natsave = nat;
return nat;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_finalise */
+/* Function: ipf_nat_finalise */
/* Returns: int - 0 == sucess, -1 == failure */
/* Parameters: fin(I) - pointer to packet information */
/* nat(I) - pointer to NAT entry */
-/* ni(I) - pointer to structure with misc. information needed */
-/* to create new NAT entry. */
/* Write Lock: ipf_nat */
/* */
/* This is the tail end of constructing a new NAT entry and is the same */
/* for both IPv4 and IPv6. */
/* ------------------------------------------------------------------------ */
/*ARGSUSED*/
-static int nat_finalise(fin, nat, ni, tcp, natsave, direction)
-fr_info_t *fin;
-nat_t *nat;
-natinfo_t *ni;
-tcphdr_t *tcp;
-nat_t **natsave;
-int direction;
+static int
+ipf_nat_finalise(fin, nat)
+ fr_info_t *fin;
+ nat_t *nat;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ u_32_t sum1, sum2, sumd;
frentry_t *fr;
- ipnat_t *np;
+ u_32_t flags;
+#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC)
+ qpktinfo_t *qpi = fin->fin_qpi;
+#endif
- np = ni->nai_np;
+ flags = nat->nat_flags;
- if (np->in_ifps[0] != NULL) {
- COPYIFNAME(4, np->in_ifps[0], nat->nat_ifnames[0]);
+ switch (nat->nat_pr[0])
+ {
+ case IPPROTO_ICMP :
+ sum1 = LONG_SUM(ntohs(nat->nat_oicmpid));
+ sum2 = LONG_SUM(ntohs(nat->nat_nicmpid));
+ CALC_SUMD(sum1, sum2, sumd);
+ nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
+
+ break;
+
+ default :
+ sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr) + \
+ ntohs(nat->nat_osport));
+ sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr) + \
+ ntohs(nat->nat_nsport));
+ CALC_SUMD(sum1, sum2, sumd);
+ nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
+
+ sum1 = LONG_SUM(ntohl(nat->nat_odstaddr) + \
+ ntohs(nat->nat_odport));
+ sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr) + \
+ ntohs(nat->nat_ndport));
+ CALC_SUMD(sum1, sum2, sumd);
+ nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16);
+ break;
}
- if (np->in_ifps[1] != NULL) {
- COPYIFNAME(4, np->in_ifps[1], nat->nat_ifnames[1]);
+
+ /*
+ * Compute the partial checksum, just in case.
+ * This is only ever placed into outbound packets so care needs
+ * to be taken over which pair of addresses are used.
+ */
+ if (nat->nat_dir == NAT_OUTBOUND) {
+ sum1 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
+ sum1 += LONG_SUM(ntohl(nat->nat_ndstaddr));
+ } else {
+ sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr));
+ sum1 += LONG_SUM(ntohl(nat->nat_odstaddr));
}
-#ifdef IPFILTER_SYNC
- if ((nat->nat_flags & SI_CLONE) == 0)
- nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat);
-#endif
+ sum1 += nat->nat_pr[1];
+ nat->nat_sumd[1] = (sum1 & 0xffff) + (sum1 >> 16);
- nat->nat_me = natsave;
- nat->nat_dir = direction;
- nat->nat_ifps[0] = np->in_ifps[0];
- nat->nat_ifps[1] = np->in_ifps[1];
- nat->nat_ptr = np;
- nat->nat_p = fin->fin_p;
- nat->nat_mssclamp = np->in_mssclamp;
- if (nat->nat_p == IPPROTO_TCP)
- nat->nat_seqnext[0] = ntohl(tcp->th_seq);
+ sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr));
+ sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
+ CALC_SUMD(sum1, sum2, sumd);
+ nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
- if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0))
- if (appr_new(fin, nat) == -1)
- return -1;
+ sum1 = LONG_SUM(ntohl(nat->nat_odstaddr));
+ sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr));
+ CALC_SUMD(sum1, sum2, sumd);
+ nat->nat_ipsumd += (sumd & 0xffff) + (sumd >> 16);
- if (nat_insert(nat, fin->fin_rev) == 0) {
- if (nat_logging)
- nat_log(nat, (u_int)np->in_redir);
- np->in_use++;
- fr = fin->fin_fr;
- nat->nat_fr = fr;
+ nat->nat_v[0] = 4;
+ nat->nat_v[1] = 4;
+
+ if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
+ nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
+ }
+
+ if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
+ nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
+ }
+
+ if ((nat->nat_flags & SI_CLONE) == 0)
+ nat->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, nat);
+
+ if (ipf_nat_insert(softc, softn, nat) == 0) {
+ if (softn->ipf_nat_logging)
+ ipf_nat_log(softc, softn, nat, NL_NEW);
+ fr = nat->nat_fr;
if (fr != NULL) {
MUTEX_ENTER(&fr->fr_lock);
fr->fr_ref++;
@@ -2627,112 +3386,224 @@ int direction;
return 0;
}
+ NBUMPSIDED(fin->fin_out, ns_unfinalised);
/*
* nat_insert failed, so cleanup time...
*/
+ if (nat->nat_sync != NULL)
+ ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync);
return -1;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_insert */
-/* Returns: int - 0 == sucess, -1 == failure */
-/* Parameters: nat(I) - pointer to NAT structure */
-/* rev(I) - flag indicating forward/reverse direction of packet */
-/* Write Lock: ipf_nat */
+/* Function: ipf_nat_insert */
+/* Returns: int - 0 == sucess, -1 == failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softn(I) - pointer to NAT context structure */
+/* nat(I) - pointer to NAT structure */
+/* Write Lock: ipf_nat */
/* */
/* Insert a NAT entry into the hash tables for searching and add it to the */
/* list of active NAT entries. Adjust global counters when complete. */
/* ------------------------------------------------------------------------ */
-int nat_insert(nat, rev)
-nat_t *nat;
-int rev;
+int
+ipf_nat_insert(softc, softn, nat)
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
+ nat_t *nat;
{
- u_int hv1, hv2;
- nat_t **natp;
+ u_int hv0, hv1;
+ u_int sp, dp;
+ ipnat_t *in;
/*
* Try and return an error as early as possible, so calculate the hash
* entry numbers first and then proceed.
*/
if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) {
- 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);
+ if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+ sp = nat->nat_osport;
+ dp = nat->nat_odport;
+ } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
+ sp = 0;
+ dp = nat->nat_oicmpid;
+ } else {
+ sp = 0;
+ dp = 0;
+ }
+ hv0 = NAT_HASH_FN(nat->nat_osrcaddr, sp, 0xffffffff);
+ hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0 + dp, 0xffffffff);
+ /*
+ * TRACE nat_osrcaddr, nat_osport, nat_odstaddr,
+ * nat_odport, hv0
+ */
+
+ if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+ sp = nat->nat_nsport;
+ dp = nat->nat_ndport;
+ } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
+ sp = 0;
+ dp = nat->nat_nicmpid;
+ } else {
+ sp = 0;
+ dp = 0;
+ }
+ hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, sp, 0xffffffff);
+ hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1 + dp, 0xffffffff);
+ /*
+ * TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr,
+ * nat_ndport, hv1
+ */
} 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);
- }
+ hv0 = NAT_HASH_FN(nat->nat_osrcaddr, 0, 0xffffffff);
+ hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0, 0xffffffff);
+ /* TRACE nat_osrcaddr, nat_odstaddr, hv0 */
- if (nat_stats.ns_bucketlen[0][hv1] >= fr_nat_maxbucket ||
- nat_stats.ns_bucketlen[1][hv2] >= fr_nat_maxbucket) {
- return -1;
+ hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, 0, 0xffffffff);
+ hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1, 0xffffffff);
+ /* TRACE nat_nsrcaddr, nat_ndstaddr, hv1 */
}
- nat->nat_hv[0] = hv1;
- nat->nat_hv[1] = hv2;
+ nat->nat_hv[0] = hv0;
+ nat->nat_hv[1] = hv1;
MUTEX_INIT(&nat->nat_lock, "nat entry lock");
- nat->nat_rev = rev;
- nat->nat_ref = 1;
- nat->nat_bytes[0] = 0;
- nat->nat_pkts[0] = 0;
- nat->nat_bytes[1] = 0;
- nat->nat_pkts[1] = 0;
+ in = nat->nat_ptr;
+ nat->nat_ref = nat->nat_me ? 2 : 1;
nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0';
- nat->nat_ifps[0] = fr_resolvenic(nat->nat_ifnames[0], 4);
+ nat->nat_ifps[0] = ipf_resolvenic(softc, nat->nat_ifnames[0], 4);
if (nat->nat_ifnames[1][0] != '\0') {
nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
- nat->nat_ifps[1] = fr_resolvenic(nat->nat_ifnames[1], 4);
- } else {
- (void) strncpy(nat->nat_ifnames[1], nat->nat_ifnames[0],
- LIFNAMSIZ);
- nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
- nat->nat_ifps[1] = nat->nat_ifps[0];
+ nat->nat_ifps[1] = ipf_resolvenic(softc,
+ nat->nat_ifnames[1], 4);
+ } else if (in->in_ifnames[1] != -1) {
+ char *name;
+
+ name = in->in_names + in->in_ifnames[1];
+ if (name[1] != '\0' && name[0] != '-' && name[0] != '*') {
+ (void) strncpy(nat->nat_ifnames[1],
+ nat->nat_ifnames[0], LIFNAMSIZ);
+ nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
+ nat->nat_ifps[1] = nat->nat_ifps[0];
+ }
+ }
+ if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
+ nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
+ }
+ if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
+ nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
}
- nat->nat_next = nat_instances;
- nat->nat_pnext = &nat_instances;
- if (nat_instances)
- nat_instances->nat_pnext = &nat->nat_next;
- nat_instances = nat;
+ return ipf_nat_hashtab_add(softc, softn, nat);
+}
- natp = &nat_table[0][hv1];
- if (*natp)
- (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_hashtab_add */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softn(I) - pointer to NAT context structure */
+/* nat(I) - pointer to NAT structure */
+/* */
+/* Handle the insertion of a NAT entry into the table/list. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat_hashtab_add(softc, softn, nat)
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
+ nat_t *nat;
+{
+ nat_t **natp;
+ u_int hv0;
+ u_int hv1;
+
+ hv0 = nat->nat_hv[0] % softn->ipf_nat_table_sz;
+ hv1 = nat->nat_hv[1] % softn->ipf_nat_table_sz;
+
+ if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) {
+ u_int swap;
+
+ swap = hv0;
+ hv0 = hv1;
+ hv1 = swap;
+ }
+
+ if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0] >=
+ softn->ipf_nat_maxbucket) {
+ DT1(ns_bucket_max_0, int,
+ softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0]);
+ NBUMPSIDE(0, ns_bucket_max);
+ return -1;
+ }
+
+ if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1] >=
+ softn->ipf_nat_maxbucket) {
+ DT1(ns_bucket_max_1, int,
+ softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1]);
+ NBUMPSIDE(1, ns_bucket_max);
+ return -1;
+ }
+
+ /*
+ * The ordering of operations in the list and hash table insertion
+ * is very important. The last operation for each task should be
+ * to update the top of the list, after all the "nexts" have been
+ * done so that walking the list while it is being done does not
+ * find strange pointers.
+ *
+ * Global list of NAT instances
+ */
+ nat->nat_next = softn->ipf_nat_instances;
+ nat->nat_pnext = &softn->ipf_nat_instances;
+ if (softn->ipf_nat_instances)
+ softn->ipf_nat_instances->nat_pnext = &nat->nat_next;
+ softn->ipf_nat_instances = nat;
+
+ /*
+ * Inbound hash table.
+ */
+ natp = &softn->ipf_nat_table[0][hv0];
nat->nat_phnext[0] = natp;
nat->nat_hnext[0] = *natp;
+ if (*natp) {
+ (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
+ } else {
+ NBUMPSIDE(0, ns_inuse);
+ }
*natp = nat;
- nat_stats.ns_bucketlen[0][hv1]++;
+ NBUMPSIDE(0, ns_bucketlen[hv0]);
- natp = &nat_table[1][hv2];
- if (*natp)
- (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
+ /*
+ * Outbound hash table.
+ */
+ natp = &softn->ipf_nat_table[1][hv1];
nat->nat_phnext[1] = natp;
nat->nat_hnext[1] = *natp;
+ if (*natp)
+ (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
+ else {
+ NBUMPSIDE(1, ns_inuse);
+ }
*natp = nat;
- nat_stats.ns_bucketlen[1][hv2]++;
+ NBUMPSIDE(1, ns_bucketlen[hv1]);
- fr_setnatqueue(nat, rev);
+ ipf_nat_setqueue(softc, softn, nat);
- nat_stats.ns_added++;
- nat_stats.ns_inuse++;
+ if (nat->nat_dir & NAT_OUTBOUND) {
+ NBUMPSIDE(1, ns_added);
+ } else {
+ NBUMPSIDE(0, ns_added);
+ }
+ softn->ipf_nat_stats.ns_active++;
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_icmperrorlookup */
+/* Function: ipf_nat_icmperrorlookup */
/* Returns: nat_t* - point to matching NAT structure */
/* Parameters: fin(I) - pointer to packet information */
/* dir(I) - direction of packet (in/out) */
@@ -2741,12 +3612,16 @@ int rev;
/* ICMP query nat entry. It is assumed that the packet is already of the */
/* the required length. */
/* ------------------------------------------------------------------------ */
-nat_t *nat_icmperrorlookup(fin, dir)
-fr_info_t *fin;
-int dir;
+nat_t *
+ipf_nat_icmperrorlookup(fin, dir)
+ fr_info_t *fin;
+ int dir;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
int flags = 0, type, minlen;
icmphdr_t *icmp, *orgicmp;
+ nat_stat_side_t *nside;
tcphdr_t *tcp = NULL;
u_short data[2];
nat_t *nat;
@@ -2755,13 +3630,16 @@ int dir;
icmp = fin->fin_dp;
type = icmp->icmp_type;
+ nside = &softn->ipf_nat_stats.ns_side[fin->fin_out];
/*
* Does it at least have the return (basic) IP header ?
* Only a basic IP header (no options) should be with an ICMP error
* header. Also, if it's not an error type, then return.
*/
- if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR))
+ if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR)) {
+ ATOMIC_INCL(nside->ns_icmp_basic);
return NULL;
+ }
/*
* Check packet size
@@ -2769,35 +3647,45 @@ int dir;
oip = (ip_t *)((char *)fin->fin_dp + 8);
minlen = IP_HL(oip) << 2;
if ((minlen < sizeof(ip_t)) ||
- (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen))
+ (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)) {
+ ATOMIC_INCL(nside->ns_icmp_size);
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
+ * do the pullup early in ipf_check() and thus can't gaurantee it is
* all here now.
*/
-#ifdef _KERNEL
+#ifdef ipf_nat_KERNEL
{
mb_t *m;
m = fin->fin_m;
# if defined(MENTAT)
- if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr)
+ if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
+ (char *)m->b_wptr) {
+ ATOMIC_INCL(nside->ns_icmp_mbuf);
return NULL;
+ }
# else
if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
- (char *)fin->fin_ip + M_LEN(m))
+ (char *)fin->fin_ip + M_LEN(m)) {
+ ATOMIC_INCL(nside->ns_icmp_mbuf);
return NULL;
+ }
# endif
}
#endif
- if (fin->fin_daddr != oip->ip_src.s_addr)
+ if (fin->fin_daddr != oip->ip_src.s_addr) {
+ ATOMIC_INCL(nside->ns_icmp_address);
return NULL;
+ }
p = oip->ip_p;
if (p == IPPROTO_TCP)
@@ -2808,7 +3696,7 @@ int dir;
orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2));
/* see if this is related to an ICMP query */
- if (nat_icmpquerytype4(orgicmp->icmp_type)) {
+ if (ipf_nat_icmpquerytype(orgicmp->icmp_type)) {
data[0] = fin->fin_data[0];
data[1] = fin->fin_data[1];
fin->fin_data[0] = 0;
@@ -2821,21 +3709,26 @@ int dir;
* message flows in the opposite direction.
*/
if (dir == NAT_INBOUND)
- nat = nat_inlookup(fin, flags, p, oip->ip_dst,
- oip->ip_src);
+ nat = ipf_nat_inlookup(fin, flags, p,
+ oip->ip_dst,
+ oip->ip_src);
else
- nat = nat_outlookup(fin, flags, p, oip->ip_dst,
- oip->ip_src);
+ nat = ipf_nat_outlookup(fin, flags, p,
+ oip->ip_dst,
+ oip->ip_src);
fin->fin_data[0] = data[0];
fin->fin_data[1] = data[1];
return nat;
}
}
-
+
if (flags & IPN_TCPUDP) {
minlen += 8; /* + 64bits of data to get ports */
- if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)
+ /* TRACE (fin,minlen) */
+ if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) {
+ ATOMIC_INCL(nside->ns_icmp_short);
return NULL;
+ }
data[0] = fin->fin_data[0];
data[1] = fin->fin_data[1];
@@ -2844,10 +3737,10 @@ int dir;
fin->fin_data[1] = ntohs(tcp->th_sport);
if (dir == NAT_INBOUND) {
- nat = nat_inlookup(fin, flags, p, oip->ip_dst,
- oip->ip_src);
+ nat = ipf_nat_inlookup(fin, flags, p, oip->ip_dst,
+ oip->ip_src);
} else {
- nat = nat_outlookup(fin, flags, p, oip->ip_dst,
+ nat = ipf_nat_outlookup(fin, flags, p, oip->ip_dst,
oip->ip_src);
}
fin->fin_data[0] = data[0];
@@ -2855,14 +3748,16 @@ int dir;
return nat;
}
if (dir == NAT_INBOUND)
- return nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
+ nat = ipf_nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
else
- return nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
+ nat = ipf_nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
+
+ return nat;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_icmperror */
+/* Function: ipf_nat_icmperror */
/* Returns: nat_t* - point to matching NAT structure */
/* Parameters: fin(I) - pointer to packet information */
/* nflags(I) - NAT flags for this packet */
@@ -2874,13 +3769,16 @@ int dir;
/* This should *ONLY* be used for incoming ICMP error packets to make sure */
/* a NAT'd ICMP packet gets correctly recognised. */
/* ------------------------------------------------------------------------ */
-nat_t *nat_icmperror(fin, nflags, dir)
-fr_info_t *fin;
-u_int *nflags;
-int dir;
+nat_t *
+ipf_nat_icmperror(fin, nflags, dir)
+ fr_info_t *fin;
+ u_int *nflags;
+ int dir;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
u_32_t sum1, sum2, sumd, sumd2;
- struct in_addr a1, a2;
+ struct in_addr a1, a2, a3, a4;
int flags, dlen, odst;
icmphdr_t *icmp;
u_short *csump;
@@ -2889,13 +3787,18 @@ int dir;
ip_t *oip;
void *dp;
- if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY)))
+ if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
+ NBUMPSIDED(fin->fin_out, ns_icmp_short);
return NULL;
+ }
+
/*
- * nat_icmperrorlookup() will return NULL for `defective' packets.
+ * ipf_nat_icmperrorlookup() will return NULL for `defective' packets.
*/
- if ((fin->fin_v != 4) || !(nat = nat_icmperrorlookup(fin, dir)))
+ if ((fin->fin_v != 4) || !(nat = ipf_nat_icmperrorlookup(fin, dir))) {
+ NBUMPSIDED(fin->fin_out, ns_icmp_notfound);
return NULL;
+ }
tcp = NULL;
csump = NULL;
@@ -2923,7 +3826,7 @@ int dir;
/*
* 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 as it will be modified again in fr_checknatout
+ * IP address change as it will be modified again in ipf_nat_checkout
* 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
@@ -2949,42 +3852,73 @@ int dir;
* ------------
* MAP rule, SRC=a,DST=b -> SRC=c,DST=b
* - response to outgoing packet (a,b)=>(c,b) (OIP_SRC=c,OIP_DST=b)
- * - OIP_SRC(c)=nat_outip, OIP_DST(b)=nat_oip
+ * - OIP_SRC(c)=nat_newsrcip, OIP_DST(b)=nat_newdstip
+ *=> OIP_SRC(c)=nat_oldsrcip, OIP_DST(b)=nat_olddstip
*
* RDR rule, SRC=a,DST=b -> SRC=a,DST=c
* - response to outgoing packet (c,a)=>(b,a) (OIP_SRC=b,OIP_DST=a)
- * - OIP_SRC(b)=nat_outip, OIP_DST(a)=nat_oip
+ * - OIP_SRC(b)=nat_olddstip, OIP_DST(a)=nat_oldsrcip
+ *=> OIP_SRC(b)=nat_newdstip, OIP_DST(a)=nat_newsrcip
+ *
+ * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
+ * - response to outgoing packet (a,b)=>(c,d) (OIP_SRC=c,OIP_DST=d)
+ * - OIP_SRC(c)=nat_newsrcip, OIP_DST(d)=nat_newdstip
+ *=> OIP_SRC(c)=nat_oldsrcip, OIP_DST(d)=nat_olddstip
+ *
+ * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
+ * - response to outgoing packet (d,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
+ * - OIP_SRC(b)=nat_olddstip, OIP_DST(a)=nat_oldsrcip
+ *=> OIP_SRC(b)=nat_newdstip, OIP_DST(a)=nat_newsrcip
*
* Outbound ICMP
* -------------
* MAP rule, SRC=a,DST=b -> SRC=c,DST=b
* - response to incoming packet (b,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
- * - OIP_SRC(a)=nat_oip, OIP_DST(c)=nat_inip
+ * - OIP_SRC(b)=nat_olddstip, OIP_DST(a)=nat_oldsrcip
+ *=> OIP_SRC(b)=nat_newdstip, OIP_DST(a)=nat_newsrcip
*
* RDR rule, SRC=a,DST=b -> SRC=a,DST=c
* - response to incoming packet (a,b)=>(a,c) (OIP_SRC=a,OIP_DST=c)
- * - OIP_SRC(a)=nat_oip, OIP_DST(c)=nat_inip
+ * - OIP_SRC(a)=nat_newsrcip, OIP_DST(c)=nat_newdstip
+ *=> OIP_SRC(a)=nat_oldsrcip, OIP_DST(c)=nat_olddstip
+ *
+ * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
+ * - response to incoming packet (d,c)=>(b,a) (OIP_SRC=c,OIP_DST=d)
+ * - OIP_SRC(c)=nat_olddstip, OIP_DST(d)=nat_oldsrcip
+ *=> OIP_SRC(b)=nat_newdstip, OIP_DST(a)=nat_newsrcip
*
+ * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
+ * - response to incoming packet (a,b)=>(c,d) (OIP_SRC=b,OIP_DST=a)
+ * - OIP_SRC(b)=nat_newsrcip, OIP_DST(a)=nat_newdstip
+ *=> OIP_SRC(a)=nat_oldsrcip, OIP_DST(c)=nat_olddstip
*/
- odst = (oip->ip_dst.s_addr == nat->nat_oip.s_addr) ? 1 : 0;
- if (odst == 1) {
- a1.s_addr = ntohl(nat->nat_inip.s_addr);
- a2.s_addr = ntohl(oip->ip_src.s_addr);
+
+ if (((fin->fin_out == 0) && ((nat->nat_redir & NAT_MAP) != 0)) ||
+ ((fin->fin_out == 1) && ((nat->nat_redir & NAT_REDIRECT) != 0))) {
+ a1.s_addr = ntohl(nat->nat_osrcaddr);
+ a4.s_addr = ntohl(oip->ip_src.s_addr);
+ a3.s_addr = ntohl(nat->nat_odstaddr);
+ a2.s_addr = ntohl(oip->ip_dst.s_addr);
oip->ip_src.s_addr = htonl(a1.s_addr);
+ oip->ip_dst.s_addr = htonl(a3.s_addr);
+ odst = 1;
} else {
- a1.s_addr = ntohl(nat->nat_outip.s_addr);
+ a1.s_addr = ntohl(nat->nat_ndstaddr);
a2.s_addr = ntohl(oip->ip_dst.s_addr);
- oip->ip_dst.s_addr = htonl(a1.s_addr);
- }
-
- sumd = a2.s_addr - a1.s_addr;
- if (sumd != 0) {
- if (a1.s_addr > a2.s_addr)
- sumd--;
- sumd = ~sumd;
-
- fix_datacksum(&oip->ip_sum, sumd);
+ a3.s_addr = ntohl(nat->nat_nsrcaddr);
+ a4.s_addr = ntohl(oip->ip_src.s_addr);
+ oip->ip_dst.s_addr = htonl(a3.s_addr);
+ oip->ip_src.s_addr = htonl(a1.s_addr);
+ odst = 0;
}
+ sum1 = 0;
+ sum2 = 0;
+ sumd = 0;
+ CALC_SUMD(a2.s_addr, a3.s_addr, sum1);
+ CALC_SUMD(a4.s_addr, a1.s_addr, sum2);
+ sumd = sum2 + sum1;
+ if (sumd != 0)
+ ipf_fix_datacksum(&oip->ip_sum, sumd);
sumd2 = sumd;
sum1 = 0;
@@ -2995,6 +3929,8 @@ int dir;
* IP address change.
*/
if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) {
+ u_32_t sum3, sum4, sumt;
+
/*
* Step 2 :
* For offending TCP/UDP IP packets, translate the ports as
@@ -3003,24 +3939,33 @@ int dir;
*
* Since the port fields are part of the TCP/UDP checksum
* of the offending IP packet, you need to adjust that checksum
- * as well... except that the change in the port numbers should
+ * as well... except that the change in the port numbers should
* be offset by the checksum change. However, the TCP/UDP
* checksum will also need to change if there has been an
* IP address change.
*/
if (odst == 1) {
- sum1 = ntohs(nat->nat_inport);
- sum2 = ntohs(tcp->th_sport);
+ sum1 = ntohs(nat->nat_osport);
+ sum4 = ntohs(tcp->th_sport);
+ sum3 = ntohs(nat->nat_odport);
+ sum2 = ntohs(tcp->th_dport);
tcp->th_sport = htons(sum1);
+ tcp->th_dport = htons(sum3);
} else {
- sum1 = ntohs(nat->nat_outport);
+ sum1 = ntohs(nat->nat_ndport);
sum2 = ntohs(tcp->th_dport);
+ sum3 = ntohs(nat->nat_nsport);
+ sum4 = ntohs(tcp->th_sport);
- tcp->th_dport = htons(sum1);
+ tcp->th_dport = htons(sum3);
+ tcp->th_sport = htons(sum1);
}
+ CALC_SUMD(sum4, sum1, sumt);
+ sumd += sumt;
+ CALC_SUMD(sum2, sum3, sumt);
+ sumd += sumt;
- sumd += sum1 - sum2;
if (sumd != 0 || sumd2 != 0) {
/*
* At this point, sumd is the delta to apply to the
@@ -3038,39 +3983,26 @@ int dir;
*/
if (oip->ip_p == IPPROTO_UDP) {
if ((dlen >= 8) && (*csump != 0)) {
- fix_datacksum(csump, sumd);
+ ipf_fix_datacksum(csump, sumd);
} else {
- sumd2 = sum1 - sum2;
- if (sum2 > sum1)
- sumd2--;
+ CALC_SUMD(sum1, sum4, sumd2);
+ CALC_SUMD(sum3, sum2, sumt);
+ sumd2 += sumt;
}
} else if (oip->ip_p == IPPROTO_TCP) {
if (dlen >= 18) {
- fix_datacksum(csump, sumd);
+ ipf_fix_datacksum(csump, sumd);
} else {
- sumd2 = sum2 - sum1;
- if (sum1 > sum2)
- sumd2--;
+ CALC_SUMD(sum1, sum4, sumd2);
+ CALC_SUMD(sum3, sum2, sumt);
+ sumd2 += sumt;
}
}
-
if (sumd2 != 0) {
- ipnat_t *np;
-
- np = nat->nat_ptr;
sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
-
- if ((odst == 0) && (dir == NAT_OUTBOUND) &&
- (fin->fin_rev == 0) && (np != NULL) &&
- (np->in_redir & NAT_REDIRECT)) {
- fix_outcksum(fin, &icmp->icmp_cksum,
- sumd2);
- } else {
- fix_incksum(fin, &icmp->icmp_cksum,
- sumd2);
- }
+ ipf_fix_incksum(0, &icmp->icmp_cksum, sumd2, 0);
}
}
} else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) {
@@ -3078,12 +4010,13 @@ int dir;
/*
* XXX - what if this is bogus hl and we go off the end ?
- * In this case, nat_icmperrorlookup() will have returned NULL.
+ * In this case, ipf_nat_icmperrorlookup() will have
+ * returned NULL.
*/
orgicmp = (icmphdr_t *)dp;
if (odst == 1) {
- if (orgicmp->icmp_id != nat->nat_inport) {
+ if (orgicmp->icmp_id != nat->nat_osport) {
/*
* Fix ICMP checksum (of the offening ICMP
@@ -3098,10 +4031,10 @@ int dir;
* overall icmp->icmp_cksum
*/
sum1 = ntohs(orgicmp->icmp_id);
- sum2 = ntohs(nat->nat_inport);
+ sum2 = ntohs(nat->nat_oicmpid);
CALC_SUMD(sum1, sum2, sumd);
- orgicmp->icmp_id = nat->nat_inport;
- fix_datacksum(&orgicmp->icmp_cksum, sumd);
+ orgicmp->icmp_id = nat->nat_oicmpid;
+ ipf_fix_datacksum(&orgicmp->icmp_cksum, sumd);
}
} /* nat_dir == NAT_INBOUND is impossible for icmp queries */
}
@@ -3110,12 +4043,19 @@ int dir;
/*
+ * MAP-IN MAP-OUT RDR-IN RDR-OUT
+ * osrc X == src == src X
+ * odst X == dst == dst X
+ * nsrc == dst X X == dst
+ * ndst == src X X == src
+ * MAP = NAT_OUTBOUND, RDR = NAT_INBOUND
+ */
+/*
* NB: these lookups don't lock access to the list, it assumed that it has
* already been done!
*/
-
/* ------------------------------------------------------------------------ */
-/* Function: nat_inlookup */
+/* Function: ipf_nat_inlookup */
/* Returns: nat_t* - NULL == no match, */
/* else pointer to matching NAT entry */
/* Parameters: fin(I) - pointer to packet information */
@@ -3130,17 +4070,20 @@ int dir;
/* */
/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */
/* */
-/* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */
+/* NOTE: IT IS ASSUMED THAT IS ONLY HELD WITH A READ LOCK WHEN */
/* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */
/* */
/* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */
/* the packet is of said protocol */
/* ------------------------------------------------------------------------ */
-nat_t *nat_inlookup(fin, flags, p, src, mapdst)
-fr_info_t *fin;
-u_int flags, p;
-struct in_addr src , mapdst;
+nat_t *
+ipf_nat_inlookup(fin, flags, p, src, mapdst)
+ fr_info_t *fin;
+ u_int flags, p;
+ struct in_addr src , mapdst;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
u_short sport, dport;
grehdr_t *gre;
ipnat_t *ipn;
@@ -3149,11 +4092,9 @@ struct in_addr src , mapdst;
int nflags;
u_32_t dst;
void *ifp;
- u_int hv;
+ u_int hv, rhv;
ifp = fin->fin_ifp;
- sport = 0;
- dport = 0;
gre = NULL;
dst = mapdst.s_addr;
sflags = flags & NAT_TCPUDPICMP;
@@ -3166,12 +4107,17 @@ struct in_addr src , mapdst;
dport = htons(fin->fin_data[1]);
break;
case IPPROTO_ICMP :
- if (flags & IPN_ICMPERR)
+ if (flags & IPN_ICMPERR) {
sport = fin->fin_data[1];
- else
+ dport = 0;
+ } else {
dport = fin->fin_data[1];
+ sport = 0;
+ }
break;
default :
+ sport = 0;
+ dport = 0;
break;
}
@@ -3179,57 +4125,81 @@ struct in_addr src , mapdst;
if ((flags & SI_WILDP) != 0)
goto find_in_wild_ports;
- hv = NAT_HASH_FN(dst, dport, 0xffffffff);
- hv = NAT_HASH_FN(src.s_addr, hv + sport, ipf_nattable_sz);
- nat = nat_table[1][hv];
+ rhv = NAT_HASH_FN(dst, dport, 0xffffffff);
+ rhv = NAT_HASH_FN(src.s_addr, rhv + sport, 0xffffffff);
+ hv = rhv % softn->ipf_nat_table_sz;
+ nat = softn->ipf_nat_table[1][hv];
+ /* TRACE dst, dport, src, sport, hv, nat */
+
for (; nat; nat = nat->nat_hnext[1]) {
if (nat->nat_ifps[0] != NULL) {
if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
continue;
- } else if (ifp != NULL)
- nat->nat_ifps[0] = ifp;
+ }
- nflags = nat->nat_flags;
+ if (nat->nat_pr[0] != p)
+ continue;
- if (nat->nat_oip.s_addr == src.s_addr &&
- nat->nat_outip.s_addr == dst &&
- (((p == 0) &&
- (sflags == (nat->nat_flags & IPN_TCPUDPICMP)))
- || (p == nat->nat_p))) {
- switch (p)
- {
-#if 0
- case IPPROTO_GRE :
- if (nat->nat_call[1] != fin->fin_data[0])
+ switch (nat->nat_dir)
+ {
+ case NAT_INBOUND :
+ case NAT_DIVERTIN :
+ if (nat->nat_v[0] != 4)
+ continue;
+ if (nat->nat_osrcaddr != src.s_addr ||
+ nat->nat_odstaddr != dst)
+ continue;
+ if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+ if (nat->nat_osport != sport)
+ continue;
+ if (nat->nat_odport != dport)
+ continue;
+
+ } else if (p == IPPROTO_ICMP) {
+ if (nat->nat_osport != dport) {
continue;
- break;
-#endif
- case IPPROTO_ICMP :
- if ((flags & IPN_ICMPERR) != 0) {
- if (nat->nat_outport != sport)
- continue;
- } else {
- if (nat->nat_outport != dport)
- continue;
}
- break;
- case IPPROTO_TCP :
- case IPPROTO_UDP :
- if (nat->nat_oport != sport)
+ }
+ break;
+ case NAT_DIVERTOUT :
+ if (nat->nat_dlocal)
+ continue;
+ case NAT_OUTBOUND :
+ if (nat->nat_v[1] != 4)
+ continue;
+ if (nat->nat_dlocal)
+ continue;
+ if (nat->nat_dlocal)
+ continue;
+ if (nat->nat_ndstaddr != src.s_addr ||
+ nat->nat_nsrcaddr != dst)
+ continue;
+ if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+ if (nat->nat_ndport != sport)
continue;
- if (nat->nat_outport != dport)
+ if (nat->nat_nsport != dport)
continue;
- break;
- default :
- break;
+
+ } else if (p == IPPROTO_ICMP) {
+ if (nat->nat_osport != dport) {
+ continue;
+ }
}
+ break;
+ }
+
+ if ((nat->nat_flags & IPN_TCPUDP) != 0) {
ipn = nat->nat_ptr;
if ((ipn != NULL) && (nat->nat_aps != NULL))
- if (appr_match(fin, nat) != 0)
+ if (ipf_proxy_match(fin, nat) != 0)
continue;
- return nat;
}
+ if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
+ nat->nat_ifps[0] = ifp;
+ nat->nat_mtu[0] = GETIFMTU_4(ifp);
+ }
+ return nat;
}
/*
@@ -3240,126 +4210,191 @@ struct in_addr src , mapdst;
* for "dummy" (FI_IGNORE) lookups.
*/
find_in_wild_ports:
- if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH))
+ if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
+ NBUMPSIDEX(0, ns_lookup_miss, ns_lookup_miss_0);
return NULL;
- if (nat_stats.ns_wilds == 0)
+ }
+ if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
+ NBUMPSIDEX(0, ns_lookup_nowild, ns_lookup_nowild_0);
return NULL;
+ }
- RWLOCK_EXIT(&ipf_nat);
+ RWLOCK_EXIT(&softc->ipf_nat);
hv = NAT_HASH_FN(dst, 0, 0xffffffff);
- hv = NAT_HASH_FN(src.s_addr, hv, ipf_nattable_sz);
+ hv = NAT_HASH_FN(src.s_addr, hv, softn->ipf_nat_table_sz);
+ WRITE_ENTER(&softc->ipf_nat);
- WRITE_ENTER(&ipf_nat);
-
- nat = nat_table[1][hv];
+ nat = softn->ipf_nat_table[1][hv];
+ /* TRACE dst, src, hv, nat */
for (; nat; nat = nat->nat_hnext[1]) {
if (nat->nat_ifps[0] != NULL) {
if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
continue;
- } else if (ifp != NULL)
- nat->nat_ifps[0] = ifp;
+ }
- if (nat->nat_p != fin->fin_p)
- continue;
- if (nat->nat_oip.s_addr != src.s_addr ||
- nat->nat_outip.s_addr != dst)
+ if (nat->nat_pr[0] != fin->fin_p)
continue;
+ switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))
+ {
+ case NAT_INBOUND :
+ if (nat->nat_v[0] != 4)
+ continue;
+ if (nat->nat_osrcaddr != src.s_addr ||
+ nat->nat_odstaddr != dst)
+ continue;
+ break;
+ case NAT_OUTBOUND :
+ if (nat->nat_v[1] != 4)
+ continue;
+ if (nat->nat_ndstaddr != src.s_addr ||
+ nat->nat_nsrcaddr != dst)
+ continue;
+ break;
+ }
+
nflags = nat->nat_flags;
if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
continue;
- if (nat_wildok(nat, (int)sport, (int)dport, nflags,
- NAT_INBOUND) == 1) {
+ if (ipf_nat_wildok(nat, (int)sport, (int)dport, nflags,
+ NAT_INBOUND) == 1) {
if ((fin->fin_flx & FI_IGNORE) != 0)
break;
if ((nflags & SI_CLONE) != 0) {
- nat = fr_natclone(fin, nat);
+ nat = ipf_nat_clone(fin, nat);
if (nat == NULL)
break;
} else {
- MUTEX_ENTER(&ipf_nat_new);
- nat_stats.ns_wilds--;
- MUTEX_EXIT(&ipf_nat_new);
+ MUTEX_ENTER(&softn->ipf_nat_new);
+ softn->ipf_nat_stats.ns_wilds--;
+ MUTEX_EXIT(&softn->ipf_nat_new);
+ }
+
+ if (nat->nat_dir == NAT_INBOUND) {
+ if (nat->nat_osport == 0) {
+ nat->nat_osport = sport;
+ nat->nat_nsport = sport;
+ }
+ if (nat->nat_odport == 0) {
+ nat->nat_odport = dport;
+ nat->nat_ndport = dport;
+ }
+ } else if (nat->nat_dir == NAT_OUTBOUND) {
+ if (nat->nat_osport == 0) {
+ nat->nat_osport = dport;
+ nat->nat_nsport = dport;
+ }
+ if (nat->nat_odport == 0) {
+ nat->nat_odport = sport;
+ nat->nat_ndport = sport;
+ }
+ }
+ if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
+ nat->nat_ifps[0] = ifp;
+ nat->nat_mtu[0] = GETIFMTU_4(ifp);
}
- nat->nat_oport = sport;
- nat->nat_outport = dport;
nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
- nat_tabmove(nat);
+ ipf_nat_tabmove(softn, nat);
break;
}
}
- MUTEX_DOWNGRADE(&ipf_nat);
+ MUTEX_DOWNGRADE(&softc->ipf_nat);
+ if (nat == NULL) {
+ NBUMPSIDE(0, ns_lookup_miss);
+ }
return nat;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_tabmove */
+/* Function: ipf_nat_tabmove */
/* Returns: Nil */
-/* Parameters: nat(I) - pointer to NAT structure */
+/* Parameters: softn(I) - pointer to NAT context structure */
+/* nat(I) - pointer to NAT structure */
/* Write Lock: ipf_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)
-nat_t *nat;
+static void
+ipf_nat_tabmove(softn, nat)
+ ipf_nat_softc_t *softn;
+ nat_t *nat;
{
+ u_int hv0, hv1, rhv0, rhv1;
+ natstat_t *nsp;
nat_t **natp;
- u_int hv;
if (nat->nat_flags & SI_CLONE)
return;
+ nsp = &softn->ipf_nat_stats;
/*
* 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];
- nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--;
+ nsp->ns_side[0].ns_bucketlen[nat->nat_hv[0] %
+ softn->ipf_nat_table_sz]--;
if (nat->nat_hnext[1])
nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
*nat->nat_phnext[1] = nat->nat_hnext[1];
- nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--;
+ nsp->ns_side[1].ns_bucketlen[nat->nat_hv[1] %
+ softn->ipf_nat_table_sz]--;
/*
* Add into the NAT table in the new position
*/
- hv = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport, 0xffffffff);
- hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport,
- ipf_nattable_sz);
- nat->nat_hv[0] = hv;
- natp = &nat_table[0][hv];
+ rhv0 = NAT_HASH_FN(nat->nat_osrcaddr, nat->nat_osport, 0xffffffff);
+ rhv0 = NAT_HASH_FN(nat->nat_odstaddr, rhv0 + nat->nat_odport,
+ 0xffffffff);
+ rhv1 = NAT_HASH_FN(nat->nat_nsrcaddr, nat->nat_nsport, 0xffffffff);
+ rhv1 = NAT_HASH_FN(nat->nat_ndstaddr, rhv1 + nat->nat_ndport,
+ 0xffffffff);
+
+ hv0 = rhv0 % softn->ipf_nat_table_sz;
+ hv1 = rhv1 % softn->ipf_nat_table_sz;
+
+ if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) {
+ u_int swap;
+
+ swap = hv0;
+ hv0 = hv1;
+ hv1 = swap;
+ }
+
+ /* TRACE nat_osrcaddr, nat_osport, nat_odstaddr, nat_odport, hv0 */
+ /* TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr, nat_ndport, hv1 */
+
+ nat->nat_hv[0] = rhv0;
+ natp = &softn->ipf_nat_table[0][hv0];
if (*natp)
(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
nat->nat_phnext[0] = natp;
nat->nat_hnext[0] = *natp;
*natp = nat;
- nat_stats.ns_bucketlen[0][hv]++;
+ nsp->ns_side[0].ns_bucketlen[hv0]++;
- hv = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport, 0xffffffff);
- hv = NAT_HASH_FN(nat->nat_oip.s_addr, hv + nat->nat_oport,
- ipf_nattable_sz);
- nat->nat_hv[1] = hv;
- natp = &nat_table[1][hv];
+ nat->nat_hv[1] = rhv1;
+ natp = &softn->ipf_nat_table[1][hv1];
if (*natp)
(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
nat->nat_phnext[1] = natp;
nat->nat_hnext[1] = *natp;
*natp = nat;
- nat_stats.ns_bucketlen[1][hv]++;
+ nsp->ns_side[1].ns_bucketlen[hv1]++;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_outlookup */
+/* Function: ipf_nat_outlookup */
/* Returns: nat_t* - NULL == no match, */
/* else pointer to matching NAT entry */
/* Parameters: fin(I) - pointer to packet information */
@@ -3367,7 +4402,7 @@ nat_t *nat;
/* p(I) - protocol for this packet */
/* src(I) - source IP address */
/* dst(I) - destination IP address */
-/* rw(I) - 1 == write lock on ipf_nat held, 0 == read lock. */
+/* rw(I) - 1 == write lock on held, 0 == read lock. */
/* */
/* Lookup a nat entry based on the source 'real' ip address/port and */
/* destination address/port. We use this lookup when sending a packet out, */
@@ -3375,28 +4410,28 @@ nat_t *nat;
/* */
/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */
/* */
-/* NOTE: IT IS ASSUMED THAT ipf_nat IS ONLY HELD WITH A READ LOCK WHEN */
+/* NOTE: IT IS ASSUMED THAT IS ONLY HELD WITH A READ LOCK WHEN */
/* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */
/* */
/* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */
/* the packet is of said protocol */
/* ------------------------------------------------------------------------ */
-nat_t *nat_outlookup(fin, flags, p, src, dst)
-fr_info_t *fin;
-u_int flags, p;
-struct in_addr src , dst;
+nat_t *
+ipf_nat_outlookup(fin, flags, p, src, dst)
+ fr_info_t *fin;
+ u_int flags, p;
+ struct in_addr src , dst;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
u_short sport, dport;
u_int sflags;
ipnat_t *ipn;
- u_32_t srcip;
nat_t *nat;
- int nflags;
void *ifp;
u_int hv;
ifp = fin->fin_ifp;
- srcip = src.s_addr;
sflags = flags & IPN_TCPUDPICMP;
sport = 0;
dport = 0;
@@ -3421,47 +4456,75 @@ struct in_addr src , dst;
if ((flags & SI_WILDP) != 0)
goto find_out_wild_ports;
- hv = NAT_HASH_FN(srcip, sport, 0xffffffff);
- hv = NAT_HASH_FN(dst.s_addr, hv + dport, ipf_nattable_sz);
- nat = nat_table[0][hv];
+ hv = NAT_HASH_FN(src.s_addr, sport, 0xffffffff);
+ hv = NAT_HASH_FN(dst.s_addr, hv + dport, softn->ipf_nat_table_sz);
+ nat = softn->ipf_nat_table[0][hv];
+
+ /* TRACE src, sport, dst, dport, hv, nat */
+
for (; nat; nat = nat->nat_hnext[0]) {
if (nat->nat_ifps[1] != NULL) {
if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
continue;
- } else if (ifp != NULL)
- nat->nat_ifps[1] = ifp;
+ }
- nflags = nat->nat_flags;
+ if (nat->nat_pr[1] != p)
+ continue;
- if (nat->nat_inip.s_addr == srcip &&
- nat->nat_oip.s_addr == dst.s_addr &&
- (((p == 0) && (sflags == (nflags & NAT_TCPUDPICMP)))
- || (p == nat->nat_p))) {
- switch (p)
- {
-#if 0
- case IPPROTO_GRE :
- if (nat->nat_call[1] != fin->fin_data[0])
+ switch (nat->nat_dir)
+ {
+ case NAT_INBOUND :
+ case NAT_DIVERTIN :
+ if (nat->nat_v[1] != 4)
+ continue;
+ if (nat->nat_ndstaddr != src.s_addr ||
+ nat->nat_nsrcaddr != dst.s_addr)
+ continue;
+
+ if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+ if (nat->nat_ndport != sport)
continue;
- break;
-#endif
- case IPPROTO_TCP :
- case IPPROTO_UDP :
- if (nat->nat_oport != dport)
+ if (nat->nat_nsport != dport)
continue;
- if (nat->nat_inport != sport)
+
+ } else if (p == IPPROTO_ICMP) {
+ if (nat->nat_osport != dport) {
continue;
- break;
- default :
- break;
+ }
}
+ break;
+ case NAT_OUTBOUND :
+ case NAT_DIVERTOUT :
+ if (nat->nat_v[0] != 4)
+ continue;
+ if (nat->nat_osrcaddr != src.s_addr ||
+ nat->nat_odstaddr != dst.s_addr)
+ continue;
- ipn = nat->nat_ptr;
- if ((ipn != NULL) && (nat->nat_aps != NULL))
- if (appr_match(fin, nat) != 0)
+ if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+ if (nat->nat_odport != dport)
continue;
- return nat;
+ if (nat->nat_osport != sport)
+ continue;
+
+ } else if (p == IPPROTO_ICMP) {
+ if (nat->nat_osport != dport) {
+ continue;
+ }
+ }
+ break;
+ }
+
+ ipn = nat->nat_ptr;
+ if ((ipn != NULL) && (nat->nat_aps != NULL))
+ if (ipf_proxy_match(fin, nat) != 0)
+ continue;
+
+ if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
+ nat->nat_ifps[1] = ifp;
+ nat->nat_mtu[1] = GETIFMTU_4(ifp);
}
+ return nat;
}
/*
@@ -3472,67 +4535,107 @@ struct in_addr src , dst;
* for "dummy" (FI_IGNORE) lookups.
*/
find_out_wild_ports:
- if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH))
+ if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
+ NBUMPSIDEX(1, ns_lookup_miss, ns_lookup_miss_1);
return NULL;
- if (nat_stats.ns_wilds == 0)
+ }
+ if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
+ NBUMPSIDEX(1, ns_lookup_nowild, ns_lookup_nowild_1);
return NULL;
+ }
- RWLOCK_EXIT(&ipf_nat);
+ RWLOCK_EXIT(&softc->ipf_nat);
- hv = NAT_HASH_FN(srcip, 0, 0xffffffff);
- hv = NAT_HASH_FN(dst.s_addr, hv, ipf_nattable_sz);
+ hv = NAT_HASH_FN(src.s_addr, 0, 0xffffffff);
+ hv = NAT_HASH_FN(dst.s_addr, hv, softn->ipf_nat_table_sz);
- WRITE_ENTER(&ipf_nat);
+ WRITE_ENTER(&softc->ipf_nat);
- nat = nat_table[0][hv];
+ nat = softn->ipf_nat_table[0][hv];
for (; nat; nat = nat->nat_hnext[0]) {
if (nat->nat_ifps[1] != NULL) {
if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
continue;
- } else if (ifp != NULL)
- nat->nat_ifps[1] = ifp;
+ }
- if (nat->nat_p != fin->fin_p)
- continue;
- if ((nat->nat_inip.s_addr != srcip) ||
- (nat->nat_oip.s_addr != dst.s_addr))
+ if (nat->nat_pr[1] != fin->fin_p)
continue;
- nflags = nat->nat_flags;
- if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
+ switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))
+ {
+ case NAT_INBOUND :
+ if (nat->nat_v[1] != 4)
+ continue;
+ if (nat->nat_ndstaddr != src.s_addr ||
+ nat->nat_nsrcaddr != dst.s_addr)
+ continue;
+ break;
+ case NAT_OUTBOUND :
+ if (nat->nat_v[0] != 4)
+ continue;
+ if (nat->nat_osrcaddr != src.s_addr ||
+ nat->nat_odstaddr != dst.s_addr)
+ continue;
+ break;
+ }
+
+ if (!(nat->nat_flags & (NAT_TCPUDP|SI_WILDP)))
continue;
- if (nat_wildok(nat, (int)sport, (int)dport, nflags,
- NAT_OUTBOUND) == 1) {
+ if (ipf_nat_wildok(nat, (int)sport, (int)dport, nat->nat_flags,
+ NAT_OUTBOUND) == 1) {
if ((fin->fin_flx & FI_IGNORE) != 0)
break;
- if ((nflags & SI_CLONE) != 0) {
- nat = fr_natclone(fin, nat);
+ if ((nat->nat_flags & SI_CLONE) != 0) {
+ nat = ipf_nat_clone(fin, nat);
if (nat == NULL)
break;
} else {
- MUTEX_ENTER(&ipf_nat_new);
- nat_stats.ns_wilds--;
- MUTEX_EXIT(&ipf_nat_new);
+ MUTEX_ENTER(&softn->ipf_nat_new);
+ softn->ipf_nat_stats.ns_wilds--;
+ MUTEX_EXIT(&softn->ipf_nat_new);
+ }
+
+ if (nat->nat_dir == NAT_OUTBOUND) {
+ if (nat->nat_osport == 0) {
+ nat->nat_osport = sport;
+ nat->nat_nsport = sport;
+ }
+ if (nat->nat_odport == 0) {
+ nat->nat_odport = dport;
+ nat->nat_ndport = dport;
+ }
+ } else if (nat->nat_dir == NAT_INBOUND) {
+ if (nat->nat_osport == 0) {
+ nat->nat_osport = dport;
+ nat->nat_nsport = dport;
+ }
+ if (nat->nat_odport == 0) {
+ nat->nat_odport = sport;
+ nat->nat_ndport = sport;
+ }
+ }
+ if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
+ nat->nat_ifps[1] = ifp;
+ nat->nat_mtu[1] = GETIFMTU_4(ifp);
}
- nat->nat_inport = sport;
- nat->nat_oport = dport;
- if (nat->nat_outport == 0)
- nat->nat_outport = sport;
nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
- nat_tabmove(nat);
+ ipf_nat_tabmove(softn, nat);
break;
}
}
- MUTEX_DOWNGRADE(&ipf_nat);
+ MUTEX_DOWNGRADE(&softc->ipf_nat);
+ if (nat == NULL) {
+ NBUMPSIDE(1, ns_lookup_miss);
+ }
return nat;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_lookupredir */
+/* Function: ipf_nat_lookupredir */
/* Returns: nat_t* - NULL == no match, */
/* else pointer to matching NAT entry */
/* Parameters: np(I) - pointer to description of packet to find NAT table */
@@ -3550,8 +4653,9 @@ find_out_wild_ports:
/* nl_in* = source information (untranslated) */
/* nl_out* = destination information (translated) */
/* ------------------------------------------------------------------------ */
-nat_t *nat_lookupredir(np)
-natlookup_t *np;
+nat_t *
+ipf_nat_lookupredir(np)
+ natlookup_t *np;
{
fr_info_t fi;
nat_t *nat;
@@ -3577,34 +4681,34 @@ natlookup_t *np;
* - default: we have the `in' and `out' address, look for `real'.
*/
if (np->nl_flags & IPN_IN) {
- if ((nat = nat_inlookup(&fi, np->nl_flags, fi.fin_p,
- np->nl_realip, np->nl_outip))) {
- np->nl_inip = nat->nat_inip;
- np->nl_inport = nat->nat_inport;
+ if ((nat = ipf_nat_inlookup(&fi, np->nl_flags, fi.fin_p,
+ np->nl_realip, np->nl_outip))) {
+ np->nl_inip = nat->nat_odstip;
+ np->nl_inport = nat->nat_odport;
}
} else {
/*
* 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(&fi, np->nl_flags, fi.fin_p,
+ if ((nat = ipf_nat_outlookup(&fi, np->nl_flags, fi.fin_p,
np->nl_inip, np->nl_outip))) {
if ((np->nl_flags & IPN_FINDFORWARD) != 0) {
fr_info_t fin;
bzero((char *)&fin, sizeof(fin));
- fin.fin_p = nat->nat_p;
- fin.fin_data[0] = ntohs(nat->nat_outport);
- fin.fin_data[1] = ntohs(nat->nat_oport);
- if (nat_inlookup(&fin, np->nl_flags, fin.fin_p,
- nat->nat_outip,
- nat->nat_oip) != NULL) {
+ fin.fin_p = nat->nat_pr[0];
+ fin.fin_data[0] = ntohs(nat->nat_ndport);
+ fin.fin_data[1] = ntohs(nat->nat_nsport);
+ if (ipf_nat_inlookup(&fin, np->nl_flags,
+ fin.fin_p, nat->nat_ndstip,
+ nat->nat_nsrcip) != NULL) {
np->nl_flags &= ~IPN_FINDFORWARD;
}
}
- np->nl_realip = nat->nat_outip;
- np->nl_realport = nat->nat_outport;
+ np->nl_realip = nat->nat_ndstip;
+ np->nl_realport = nat->nat_ndport;
}
}
@@ -3613,46 +4717,54 @@ natlookup_t *np;
/* ------------------------------------------------------------------------ */
-/* Function: nat_match */
+/* Function: ipf_nat_match */
/* Returns: int - 0 == no match, 1 == match */
/* Parameters: fin(I) - pointer to packet information */
/* np(I) - pointer to NAT rule */
/* */
/* Pull the matching of a packet against a NAT rule out of that complex */
-/* loop inside fr_checknatin() and lay it out properly in its own function. */
+/* loop inside ipf_nat_checkin() and lay it out properly in its own function. */
/* ------------------------------------------------------------------------ */
-static int nat_match(fin, np)
-fr_info_t *fin;
-ipnat_t *np;
+static int
+ipf_nat_match(fin, np)
+ fr_info_t *fin;
+ ipnat_t *np;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
frtuc_t *ft;
+ int match;
- if (fin->fin_v != 4)
- return 0;
-
- if (np->in_p && fin->fin_p != np->in_p)
+ match = 0;
+ switch (np->in_osrcatype)
+ {
+ case FRI_NORMAL :
+ match = ((fin->fin_saddr & np->in_osrcmsk) != np->in_osrcaddr);
+ break;
+ case FRI_LOOKUP :
+ match = (*np->in_osrcfunc)(softc, np->in_osrcptr,
+ 4, &fin->fin_saddr, fin->fin_plen);
+ break;
+ }
+ match ^= ((np->in_flags & IPN_NOTSRC) != 0);
+ if (match)
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)
- ^ ((np->in_flags & IPN_NOTSRC) != 0))
- return 0;
- 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))
- 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;
+ match = 0;
+ switch (np->in_odstatype)
+ {
+ case FRI_NORMAL :
+ match = ((fin->fin_daddr & np->in_odstmsk) != np->in_odstaddr);
+ break;
+ case FRI_LOOKUP :
+ match = (*np->in_odstfunc)(softc, np->in_odstptr,
+ 4, &fin->fin_daddr, fin->fin_plen);
+ break;
}
+ match ^= ((np->in_flags & IPN_NOTDST) != 0);
+ if (match)
+ return 0;
+
ft = &np->in_tuc;
if (!(fin->fin_flx & FI_TCPUDP) ||
(fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
@@ -3661,28 +4773,33 @@ ipnat_t *np;
return 1;
}
- return fr_tcpudpchk(fin, ft);
+ return ipf_tcpudpchk(&fin->fin_fi, ft);
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_update */
+/* Function: ipf_nat_update */
/* Returns: Nil */
-/* Parameters: nat(I) - pointer to NAT structure */
-/* np(I) - pointer to NAT rule */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to NAT structure */
/* */
/* Updates the lifetime of a NAT table entry for non-TCP packets. Must be */
-/* called with fin_rev updated - i.e. after calling nat_proto(). */
+/* called with fin_rev updated - i.e. after calling ipf_nat_proto(). */
+/* */
+/* This *MUST* be called after ipf_nat_proto() as it expects fin_rev to */
+/* already be set. */
/* ------------------------------------------------------------------------ */
-void nat_update(fin, nat, np)
-fr_info_t *fin;
-nat_t *nat;
-ipnat_t *np;
+void
+ipf_nat_update(fin, nat)
+ fr_info_t *fin;
+ nat_t *nat;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
ipftq_t *ifq, *ifq2;
ipftqent_t *tqe;
+ ipnat_t *np = nat->nat_ptr;
- MUTEX_ENTER(&nat->nat_lock);
tqe = &nat->nat_tqe;
ifq = tqe->tqe_ifq;
@@ -3691,51 +4808,36 @@ ipnat_t *np;
* TCP, however, if it is TCP and there is no rule timeout set,
* then do not update the timeout here.
*/
- if (np != NULL)
+ if (np != NULL) {
+ np->in_bytes[fin->fin_rev] += fin->fin_plen;
ifq2 = np->in_tqehead[fin->fin_rev];
- else
+ } else {
ifq2 = NULL;
+ }
- if (nat->nat_p == IPPROTO_TCP && ifq2 == NULL) {
- u_32_t end, ack;
- u_char tcpflags;
- tcphdr_t *tcp;
- int dsize;
-
- tcp = fin->fin_dp;
- tcpflags = tcp->th_flags;
- dsize = fin->fin_dlen - (TCP_OFF(tcp) << 2) +
- ((tcpflags & TH_SYN) ? 1 : 0) +
- ((tcpflags & TH_FIN) ? 1 : 0);
-
- ack = ntohl(tcp->th_ack);
- end = ntohl(tcp->th_seq) + dsize;
-
- if (SEQ_GT(ack, nat->nat_seqnext[1 - fin->fin_rev]))
- nat->nat_seqnext[1 - fin->fin_rev] = ack;
-
- if (nat->nat_seqnext[fin->fin_rev] == 0)
- nat->nat_seqnext[fin->fin_rev] = end;
-
- (void) fr_tcp_age(&nat->nat_tqe, fin, nat_tqb, 0);
+ if (nat->nat_pr[0] == IPPROTO_TCP && ifq2 == NULL) {
+ (void) ipf_tcp_age(&nat->nat_tqe, fin, softn->ipf_nat_tcptq,
+ 0, 2);
} else {
if (ifq2 == NULL) {
- if (nat->nat_p == IPPROTO_UDP)
- ifq2 = &nat_udptq;
- else if (nat->nat_p == IPPROTO_ICMP)
- ifq2 = &nat_icmptq;
+ if (nat->nat_pr[0] == IPPROTO_UDP)
+ ifq2 = fin->fin_rev ? &softn->ipf_nat_udpacktq :
+ &softn->ipf_nat_udptq;
+ else if (nat->nat_pr[0] == IPPROTO_ICMP ||
+ nat->nat_pr[0] == IPPROTO_ICMPV6)
+ ifq2 = fin->fin_rev ? &softn->ipf_nat_icmpacktq:
+ &softn->ipf_nat_icmptq;
else
- ifq2 = &nat_iptq;
+ ifq2 = &softn->ipf_nat_iptq;
}
- fr_movequeue(tqe, ifq, ifq2);
+ ipf_movequeue(softc->ipf_ticks, tqe, ifq, ifq2);
}
- MUTEX_EXIT(&nat->nat_lock);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_checknatout */
+/* Function: ipf_nat_checkout */
/* Returns: int - -1 == packet failed NAT checks so block it, */
/* 0 == no packet translation occurred, */
/* 1 == packet was successfully translated. */
@@ -3749,29 +4851,46 @@ ipnat_t *np;
/* NAT entry if a we matched a NAT rule. Lastly, actually change the */
/* packet header(s) as required. */
/* ------------------------------------------------------------------------ */
-int fr_checknatout(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+int
+ipf_nat_checkout(fin, passp)
+ fr_info_t *fin;
+ u_32_t *passp;
{
+ ipnat_t *np = NULL, *npnext;
struct ifnet *ifp, *sifp;
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
icmphdr_t *icmp = NULL;
tcphdr_t *tcp = NULL;
int rval, natfailed;
- ipnat_t *np = NULL;
u_int nflags = 0;
u_32_t ipa, iph;
int natadd = 1;
frentry_t *fr;
nat_t *nat;
- if (nat_stats.ns_rules == 0 || fr_nat_lock != 0)
+ if (fin->fin_v == 6) {
+#ifdef USE_INET6
+ return ipf_nat6_checkout(fin, passp);
+#else
+ return 0;
+#endif
+ }
+
+ softc = fin->fin_main_soft;
+ softn = softc->ipf_nat_soft;
+
+ if (softn->ipf_nat_lock != 0)
+ return 0;
+ if (softn->ipf_nat_stats.ns_rules == 0 &&
+ softn->ipf_nat_instances == NULL)
return 0;
natfailed = 0;
fr = fin->fin_fr;
sifp = fin->fin_ifp;
if (fr != NULL) {
- ifp = fr->fr_tifs[fin->fin_rev].fd_ifp;
+ ifp = fr->fr_tifs[fin->fin_rev].fd_ptr;
if ((ifp != NULL) && (ifp != (void *)-1))
fin->fin_ifp = ifp;
}
@@ -3793,117 +4912,152 @@ u_32_t *passp;
* This is an incoming packet, so the destination is
* the icmp_id and the source port equals 0
*/
- if (nat_icmpquerytype4(icmp->icmp_type))
+ if ((fin->fin_flx & FI_ICMPQUERY) != 0)
nflags = IPN_ICMPQUERY;
break;
default :
break;
}
-
+
if ((nflags & IPN_TCPUDP))
tcp = fin->fin_dp;
}
ipa = fin->fin_saddr;
- READ_ENTER(&ipf_nat);
+ READ_ENTER(&softc->ipf_nat);
- if (((fin->fin_flx & FI_ICMPERR) != 0) &&
- (nat = nat_icmperror(fin, &nflags, NAT_OUTBOUND)))
+ if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) &&
+ (nat = ipf_nat_icmperror(fin, &nflags, NAT_OUTBOUND)))
/*EMPTY*/;
- else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin)))
+ else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
natadd = 0;
- else if ((nat = nat_outlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p,
- fin->fin_src, fin->fin_dst))) {
+ else if ((nat = ipf_nat_outlookup(fin, nflags|NAT_SEARCH,
+ (u_int)fin->fin_p, fin->fin_src,
+ fin->fin_dst))) {
nflags = nat->nat_flags;
- } else {
- u_32_t hv, msk, nmsk;
+ } else if (fin->fin_off == 0) {
+ u_32_t hv, msk, nmsk = 0;
/*
* If there is no current entry in the nat table for this IP#,
* create one for it (if there is a matching rule).
*/
- RWLOCK_EXIT(&ipf_nat);
- msk = 0xffffffff;
- nmsk = nat_masks;
- WRITE_ENTER(&ipf_nat);
maskloop:
- iph = ipa & htonl(msk);
- hv = NAT_HASH_FN(iph, 0, ipf_natrules_sz);
- for (np = nat_rules[hv]; np; np = np->in_mnext)
- {
+ msk = softn->ipf_nat_map_active_masks[nmsk];
+ iph = ipa & msk;
+ hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_maprules_sz);
+retry_roundrobin:
+ for (np = softn->ipf_nat_map_rules[hv]; np; np = npnext) {
+ npnext = np->in_mnext;
if ((np->in_ifps[1] && (np->in_ifps[1] != ifp)))
continue;
- if (np->in_v != fin->fin_v)
+ if (np->in_v[0] != 4)
continue;
- if (np->in_p && (np->in_p != fin->fin_p))
+ if (np->in_pr[1] && (np->in_pr[1] != fin->fin_p))
continue;
- if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
+ if ((np->in_flags & IPN_RF) &&
+ !(np->in_flags & nflags))
continue;
if (np->in_flags & IPN_FILTER) {
- if (!nat_match(fin, np))
+ switch (ipf_nat_match(fin, np))
+ {
+ case 0 :
continue;
- } else if ((ipa & np->in_inmsk) != np->in_inip)
+ case -1 :
+ rval = -1;
+ goto outmatchfail;
+ case 1 :
+ default :
+ break;
+ }
+ } else if ((ipa & np->in_osrcmsk) != np->in_osrcaddr)
continue;
if ((fr != NULL) &&
- !fr_matchtag(&np->in_tag, &fr->fr_nattag))
+ !ipf_matchtag(&np->in_tag, &fr->fr_nattag))
continue;
- if (*np->in_plabel != '\0') {
+ if (np->in_plabel != -1) {
if (((np->in_flags & IPN_FILTER) == 0) &&
- (np->in_dport != tcp->th_dport))
+ (np->in_odport != fin->fin_data[1]))
continue;
- if (appr_ok(fin, tcp, np) == 0)
+ if (ipf_proxy_ok(fin, tcp, np) == 0)
continue;
}
- if ((nat = nat_new(fin, np, NULL, nflags,
- NAT_OUTBOUND))) {
+ if (np->in_flags & IPN_NO) {
np->in_hits++;
break;
- } else
- natfailed = -1;
- }
- if ((np == NULL) && (nmsk != 0)) {
- while (nmsk) {
- msk <<= 1;
- if (nmsk & 0x80000000)
- break;
- nmsk <<= 1;
}
- if (nmsk != 0) {
- nmsk <<= 1;
- goto maskloop;
+ MUTEX_ENTER(&softn->ipf_nat_new);
+ /*
+ * If we've matched a round-robin rule but it has
+ * moved in the list since we got it, start over as
+ * this is now no longer correct.
+ */
+ if (npnext != np->in_mnext) {
+ if ((np->in_flags & IPN_ROUNDR) != 0) {
+ MUTEX_EXIT(&softn->ipf_nat_new);
+ goto retry_roundrobin;
+ }
+ npnext = np->in_mnext;
}
+
+ nat = ipf_nat_add(fin, np, NULL, nflags, NAT_OUTBOUND);
+ MUTEX_EXIT(&softn->ipf_nat_new);
+ if (nat != NULL) {
+ natfailed = 0;
+ break;
+ }
+ natfailed = -1;
+ }
+ if ((np == NULL) && (nmsk < softn->ipf_nat_map_max)) {
+ nmsk++;
+ goto maskloop;
}
- MUTEX_DOWNGRADE(&ipf_nat);
}
if (nat != NULL) {
- rval = fr_natout(fin, nat, natadd, nflags);
+ rval = ipf_nat_out(fin, nat, natadd, nflags);
if (rval == 1) {
MUTEX_ENTER(&nat->nat_lock);
- nat->nat_ref++;
+ ipf_nat_update(fin, nat);
+ nat->nat_bytes[1] += fin->fin_plen;
+ nat->nat_pkts[1]++;
+ fin->fin_pktnum = nat->nat_pkts[1];
MUTEX_EXIT(&nat->nat_lock);
- nat->nat_touched = fr_ticks;
- fin->fin_nat = nat;
}
} else
rval = natfailed;
- RWLOCK_EXIT(&ipf_nat);
+outmatchfail:
+ RWLOCK_EXIT(&softc->ipf_nat);
- if (rval == -1) {
- if (passp != NULL)
+ switch (rval)
+ {
+ case -1 :
+ if (passp != NULL) {
+ DT1(frb_natv4out, fr_info_t *, fin);
+ NBUMPSIDED(1, ns_drop);
*passp = FR_BLOCK;
+ fin->fin_reason = FRB_NATV4;
+ }
fin->fin_flx |= FI_BADNAT;
+ NBUMPSIDED(1, ns_badnat);
+ break;
+ case 0 :
+ NBUMPSIDE(1, ns_ignored);
+ break;
+ case 1 :
+ NBUMPSIDE(1, ns_translated);
+ break;
}
fin->fin_ifp = sifp;
return rval;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_natout */
+/* Function: ipf_nat_out */
/* Returns: int - -1 == packet failed NAT checks so block it, */
/* 1 == packet was successfully translated. */
/* Parameters: fin(I) - pointer to packet information */
@@ -3913,30 +5067,27 @@ maskloop:
/* */
/* Translate a packet coming "out" on an interface. */
/* ------------------------------------------------------------------------ */
-int fr_natout(fin, nat, natadd, nflags)
-fr_info_t *fin;
-nat_t *nat;
-int natadd;
-u_32_t nflags;
+int
+ipf_nat_out(fin, nat, natadd, nflags)
+ fr_info_t *fin;
+ nat_t *nat;
+ int natadd;
+ u_32_t nflags;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
icmphdr_t *icmp;
- u_short *csump;
tcphdr_t *tcp;
ipnat_t *np;
+ int skip;
int i;
tcp = NULL;
icmp = NULL;
- csump = NULL;
np = nat->nat_ptr;
if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL))
- (void) fr_nat_newfrag(fin, 0, nat);
-
- MUTEX_ENTER(&nat->nat_lock);
- nat->nat_bytes[1] += fin->fin_plen;
- nat->nat_pkts[1]++;
- MUTEX_EXIT(&nat->nat_lock);
+ (void) ipf_frag_natnew(softc, fin, 0, nat);
/*
* Fix up checksums, not by recalculating them, but
@@ -3946,90 +5097,240 @@ u_32_t nflags;
* IPFilter is called before the checksum needs calculating so there
* is no call to modify whatever is in the header now.
*/
- if (fin->fin_v == 4) {
- if (nflags == IPN_ICMPERR) {
- u_32_t s1, s2, sumd;
+ if (nflags == IPN_ICMPERR) {
+ u_32_t s1, s2, sumd, msumd;
- s1 = LONG_SUM(ntohl(fin->fin_saddr));
- s2 = LONG_SUM(ntohl(nat->nat_outip.s_addr));
- CALC_SUMD(s1, s2, sumd);
- fix_outcksum(fin, &fin->fin_ip->ip_sum, sumd);
+ s1 = LONG_SUM(ntohl(fin->fin_saddr));
+ if (nat->nat_dir == NAT_OUTBOUND) {
+ s2 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
+ } else {
+ s2 = LONG_SUM(ntohl(nat->nat_odstaddr));
}
+ CALC_SUMD(s1, s2, sumd);
+ msumd = sumd;
+
+ s1 = LONG_SUM(ntohl(fin->fin_daddr));
+ if (nat->nat_dir == NAT_OUTBOUND) {
+ s2 = LONG_SUM(ntohl(nat->nat_ndstaddr));
+ } else {
+ s2 = LONG_SUM(ntohl(nat->nat_osrcaddr));
+ }
+ CALC_SUMD(s1, s2, sumd);
+ msumd += sumd;
+
+ ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, msumd, 0);
+ }
#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
defined(linux) || defined(BRIDGE_IPF)
- else {
- /*
- * Strictly speaking, this isn't necessary on BSD
- * kernels because they do checksum calculation after
- * this code has run BUT if ipfilter is being used
- * to do NAT as a bridge, that code doesn't exist.
- */
- if (nat->nat_dir == NAT_OUTBOUND)
- fix_outcksum(fin, &fin->fin_ip->ip_sum,
- nat->nat_ipsumd);
- else
- fix_incksum(fin, &fin->fin_ip->ip_sum,
- nat->nat_ipsumd);
+ else {
+ /*
+ * Strictly speaking, this isn't necessary on BSD
+ * kernels because they do checksum calculation after
+ * this code has run BUT if ipfilter is being used
+ * to do NAT as a bridge, that code doesn't exist.
+ */
+ switch (nat->nat_dir)
+ {
+ case NAT_OUTBOUND :
+ ipf_fix_outcksum(fin->fin_cksum & FI_CK_L4PART,
+ &fin->fin_ip->ip_sum,
+ nat->nat_ipsumd, 0);
+ break;
+
+ case NAT_INBOUND :
+ ipf_fix_incksum(fin->fin_cksum & FI_CK_L4PART,
+ &fin->fin_ip->ip_sum,
+ nat->nat_ipsumd, 0);
+ break;
+
+ default :
+ break;
}
+ }
#endif
+
+ /*
+ * Address assignment is after the checksum modification because
+ * we are using the address in the packet for determining the
+ * correct checksum offset (the ICMP error could be coming from
+ * anyone...)
+ */
+ switch (nat->nat_dir)
+ {
+ case NAT_OUTBOUND :
+ fin->fin_ip->ip_src = nat->nat_nsrcip;
+ fin->fin_saddr = nat->nat_nsrcaddr;
+ fin->fin_ip->ip_dst = nat->nat_ndstip;
+ fin->fin_daddr = nat->nat_ndstaddr;
+ break;
+
+ case NAT_INBOUND :
+ fin->fin_ip->ip_src = nat->nat_odstip;
+ fin->fin_saddr = nat->nat_ndstaddr;
+ fin->fin_ip->ip_dst = nat->nat_osrcip;
+ fin->fin_daddr = nat->nat_nsrcaddr;
+ break;
+
+ case NAT_DIVERTIN :
+ {
+ mb_t *m;
+
+ skip = ipf_nat_decap(fin, nat);
+ if (skip <= 0) {
+ NBUMPSIDED(1, ns_decap_fail);
+ return -1;
+ }
+
+ m = fin->fin_m;
+
+#if defined(MENTAT) && defined(_KERNEL)
+ m->b_rptr += skip;
+#else
+ m->m_data += skip;
+ m->m_len -= skip;
+
+# ifdef M_PKTHDR
+ if (m->m_flags & M_PKTHDR)
+ m->m_pkthdr.len -= skip;
+# endif
+#endif
+
+ MUTEX_ENTER(&nat->nat_lock);
+ ipf_nat_update(fin, nat);
+ MUTEX_EXIT(&nat->nat_lock);
+ fin->fin_flx |= FI_NATED;
+ if (np != NULL && np->in_tag.ipt_num[0] != 0)
+ fin->fin_nattag = &np->in_tag;
+ return 1;
+ /* NOTREACHED */
+ }
+
+ case NAT_DIVERTOUT :
+ {
+ u_32_t s1, s2, sumd;
+ udphdr_t *uh;
+ ip_t *ip;
+ mb_t *m;
+
+ m = M_DUP(np->in_divmp);
+ if (m == NULL) {
+ NBUMPSIDED(1, ns_divert_dup);
+ return -1;
+ }
+
+ ip = MTOD(m, ip_t *);
+ ip->ip_id = htons(ipf_nextipid(fin));
+ s2 = ntohs(ip->ip_id);
+
+ s1 = ip->ip_len;
+ ip->ip_len = ntohs(ip->ip_len);
+ ip->ip_len += fin->fin_plen;
+ ip->ip_len = htons(ip->ip_len);
+ s2 += ntohs(ip->ip_len);
+ CALC_SUMD(s1, s2, sumd);
+
+ uh = (udphdr_t *)(ip + 1);
+ uh->uh_ulen += fin->fin_plen;
+ uh->uh_ulen = htons(uh->uh_ulen);
+#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
+ defined(linux) || defined(BRIDGE_IPF)
+ ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0);
+#endif
+
+ PREP_MB_T(fin, m);
+
+ fin->fin_src = ip->ip_src;
+ fin->fin_dst = ip->ip_dst;
+ fin->fin_ip = ip;
+ fin->fin_plen += sizeof(ip_t) + 8; /* UDP + IPv4 hdr */
+ fin->fin_dlen += sizeof(ip_t) + 8; /* UDP + IPv4 hdr */
+
+ nflags &= ~IPN_TCPUDPICMP;
+
+ break;
+ }
+
+ default :
+ break;
}
if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
- if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) {
+ u_short *csump;
+
+ if ((nat->nat_nsport != 0) && (nflags & IPN_TCPUDP)) {
tcp = fin->fin_dp;
- tcp->th_sport = nat->nat_outport;
- fin->fin_data[0] = ntohs(nat->nat_outport);
+ switch (nat->nat_dir)
+ {
+ case NAT_OUTBOUND :
+ tcp->th_sport = nat->nat_nsport;
+ fin->fin_data[0] = ntohs(nat->nat_nsport);
+ tcp->th_dport = nat->nat_ndport;
+ fin->fin_data[1] = ntohs(nat->nat_ndport);
+ break;
+
+ case NAT_INBOUND :
+ tcp->th_sport = nat->nat_odport;
+ fin->fin_data[0] = ntohs(nat->nat_odport);
+ tcp->th_dport = nat->nat_osport;
+ fin->fin_data[1] = ntohs(nat->nat_osport);
+ break;
+ }
}
- if ((nat->nat_outport != 0) && (nflags & IPN_ICMPQUERY)) {
+ if ((nat->nat_nsport != 0) && (nflags & IPN_ICMPQUERY)) {
icmp = fin->fin_dp;
- icmp->icmp_id = nat->nat_outport;
+ icmp->icmp_id = nat->nat_nicmpid;
}
- csump = nat_proto(fin, nat, nflags);
- }
-
- fin->fin_ip->ip_src = nat->nat_outip;
-
- nat_update(fin, nat, np);
+ csump = ipf_nat_proto(fin, nat, nflags);
- /*
- * The above comments do not hold for layer 4 (or higher) checksums...
- */
- if (csump != NULL) {
- if (nat->nat_dir == NAT_OUTBOUND)
- fix_outcksum(fin, csump, nat->nat_sumd[1]);
- else
- fix_incksum(fin, csump, nat->nat_sumd[1]);
+ /*
+ * The above comments do not hold for layer 4 (or higher)
+ * checksums...
+ */
+ if (csump != NULL) {
+ if (nat->nat_dir == NAT_OUTBOUND)
+ ipf_fix_outcksum(fin->fin_cksum, csump,
+ nat->nat_sumd[0],
+ nat->nat_sumd[1] +
+ fin->fin_dlen);
+ else
+ ipf_fix_incksum(fin->fin_cksum, csump,
+ nat->nat_sumd[0],
+ nat->nat_sumd[1] +
+ fin->fin_dlen);
+ }
}
-#ifdef IPFILTER_SYNC
- ipfsync_update(SMC_NAT, fin, nat->nat_sync);
-#endif
+
+ ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
/* ------------------------------------------------------------- */
- /* A few quick notes: */
- /* Following are test conditions prior to calling the */
- /* appr_check routine. */
- /* */
- /* A NULL tcp indicates a non TCP/UDP packet. When dealing */
- /* with a redirect rule, we attempt to match the packet's */
- /* source port against in_dport, otherwise we'd compare the */
- /* packet's destination. */
+ /* A few quick notes: */
+ /* Following are test conditions prior to calling the */
+ /* ipf_proxy_check routine. */
+ /* */
+ /* A NULL tcp indicates a non TCP/UDP packet. When dealing */
+ /* with a redirect rule, we attempt to match the packet's */
+ /* source port against in_dport, otherwise we'd compare the */
+ /* packet's destination. */
/* ------------------------------------------------------------- */
if ((np != NULL) && (np->in_apr != NULL)) {
- i = appr_check(fin, nat);
- if (i == 0)
+ i = ipf_proxy_check(fin, nat);
+ if (i == 0) {
i = 1;
- } else
+ } else if (i == -1) {
+ NBUMPSIDED(1, ns_ipf_proxy_fail);
+ }
+ } else {
i = 1;
- ATOMIC_INCL(nat_stats.ns_mapped[1]);
+ }
fin->fin_flx |= FI_NATED;
return i;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_checknatin */
+/* Function: ipf_nat_checkin */
/* Returns: int - -1 == packet failed NAT checks so block it, */
/* 0 == no packet translation occurred, */
/* 1 == packet was successfully translated. */
@@ -4043,22 +5344,31 @@ u_32_t nflags;
/* NAT entry if a we matched a NAT rule. Lastly, actually change the */
/* packet header(s) as required. */
/* ------------------------------------------------------------------------ */
-int fr_checknatin(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+int
+ipf_nat_checkin(fin, passp)
+ fr_info_t *fin;
+ u_32_t *passp;
{
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
u_int nflags, natadd;
+ ipnat_t *np, *npnext;
int rval, natfailed;
struct ifnet *ifp;
struct in_addr in;
icmphdr_t *icmp;
tcphdr_t *tcp;
u_short dport;
- ipnat_t *np;
nat_t *nat;
u_32_t iph;
- if (nat_stats.ns_rules == 0 || fr_nat_lock != 0)
+ softc = fin->fin_main_soft;
+ softn = softc->ipf_nat_soft;
+
+ if (softn->ipf_nat_lock != 0)
+ return 0;
+ if (softn->ipf_nat_stats.ns_rules == 0 &&
+ softn->ipf_nat_instances == NULL)
return 0;
tcp = NULL;
@@ -4085,182 +5395,213 @@ u_32_t *passp;
* This is an incoming packet, so the destination is
* the icmp_id and the source port equals 0
*/
- if (nat_icmpquerytype4(icmp->icmp_type)) {
+ if ((fin->fin_flx & FI_ICMPQUERY) != 0) {
nflags = IPN_ICMPQUERY;
- dport = icmp->icmp_id;
+ dport = icmp->icmp_id;
} break;
default :
break;
}
-
+
if ((nflags & IPN_TCPUDP)) {
tcp = fin->fin_dp;
- dport = tcp->th_dport;
+ dport = fin->fin_data[1];
}
}
in = fin->fin_dst;
- READ_ENTER(&ipf_nat);
+ READ_ENTER(&softc->ipf_nat);
- if (((fin->fin_flx & FI_ICMPERR) != 0) &&
- (nat = nat_icmperror(fin, &nflags, NAT_INBOUND)))
+ if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) &&
+ (nat = ipf_nat_icmperror(fin, &nflags, NAT_INBOUND)))
/*EMPTY*/;
- else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin)))
+ else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
natadd = 0;
- else if ((nat = nat_inlookup(fin, nflags|NAT_SEARCH, (u_int)fin->fin_p,
- fin->fin_src, in))) {
+ else if ((nat = ipf_nat_inlookup(fin, nflags|NAT_SEARCH,
+ (u_int)fin->fin_p,
+ fin->fin_src, in))) {
nflags = nat->nat_flags;
- } else {
- u_32_t hv, msk, rmsk;
+ } else if (fin->fin_off == 0) {
+ u_32_t hv, msk, rmsk = 0;
- RWLOCK_EXIT(&ipf_nat);
- rmsk = rdr_masks;
- msk = 0xffffffff;
- 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).
*/
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) {
+ msk = softn->ipf_nat_rdr_active_masks[rmsk];
+ iph = in.s_addr & msk;
+ hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_rdrrules_sz);
+retry_roundrobin:
+ /* TRACE (iph,msk,rmsk,hv,softn->ipf_nat_rdrrules_sz) */
+ for (np = softn->ipf_nat_rdr_rules[hv]; np; np = npnext) {
+ npnext = np->in_rnext;
if (np->in_ifps[0] && (np->in_ifps[0] != ifp))
continue;
- if (np->in_v != fin->fin_v)
+ if (np->in_v[0] != 4)
continue;
- if (np->in_p && (np->in_p != fin->fin_p))
+ if (np->in_pr[0] && (np->in_pr[0] != fin->fin_p))
continue;
if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
continue;
if (np->in_flags & IPN_FILTER) {
- if (!nat_match(fin, np))
+ switch (ipf_nat_match(fin, np))
+ {
+ case 0 :
continue;
+ case -1 :
+ rval = -1;
+ goto inmatchfail;
+ case 1 :
+ default :
+ break;
+ }
} else {
- if ((in.s_addr & np->in_outmsk) != np->in_outip)
+ if ((in.s_addr & np->in_odstmsk) !=
+ np->in_odstaddr)
continue;
- if (np->in_pmin &&
- ((ntohs(np->in_pmax) < ntohs(dport)) ||
- (ntohs(dport) < ntohs(np->in_pmin))))
+ if (np->in_odport &&
+ ((np->in_dtop < dport) ||
+ (dport < np->in_odport)))
continue;
}
- if (*np->in_plabel != '\0') {
- if (!appr_ok(fin, tcp, np)) {
+ if (np->in_plabel != -1) {
+ if (!ipf_proxy_ok(fin, tcp, np)) {
continue;
}
}
- nat = nat_new(fin, np, NULL, nflags, NAT_INBOUND);
- if (nat != NULL) {
+ if (np->in_flags & IPN_NO) {
np->in_hits++;
break;
- } else
- natfailed = -1;
- }
+ }
- if ((np == NULL) && (rmsk != 0)) {
- while (rmsk) {
- msk <<= 1;
- if (rmsk & 0x80000000)
- break;
- rmsk <<= 1;
+ MUTEX_ENTER(&softn->ipf_nat_new);
+ /*
+ * If we've matched a round-robin rule but it has
+ * moved in the list since we got it, start over as
+ * this is now no longer correct.
+ */
+ if (npnext != np->in_rnext) {
+ if ((np->in_flags & IPN_ROUNDR) != 0) {
+ MUTEX_EXIT(&softn->ipf_nat_new);
+ goto retry_roundrobin;
+ }
+ npnext = np->in_rnext;
}
- if (rmsk != 0) {
- rmsk <<= 1;
- goto maskloop;
+
+ nat = ipf_nat_add(fin, np, NULL, nflags, NAT_INBOUND);
+ MUTEX_EXIT(&softn->ipf_nat_new);
+ if (nat != NULL) {
+ natfailed = 0;
+ break;
}
+ natfailed = -1;
+ }
+ if ((np == NULL) && (rmsk < softn->ipf_nat_rdr_max)) {
+ rmsk++;
+ goto maskloop;
}
- MUTEX_DOWNGRADE(&ipf_nat);
}
+
if (nat != NULL) {
- rval = fr_natin(fin, nat, natadd, nflags);
+ rval = ipf_nat_in(fin, nat, natadd, nflags);
if (rval == 1) {
MUTEX_ENTER(&nat->nat_lock);
- nat->nat_ref++;
+ ipf_nat_update(fin, nat);
+ nat->nat_bytes[0] += fin->fin_plen;
+ nat->nat_pkts[0]++;
+ fin->fin_pktnum = nat->nat_pkts[0];
MUTEX_EXIT(&nat->nat_lock);
- nat->nat_touched = fr_ticks;
- fin->fin_nat = nat;
}
} else
rval = natfailed;
- RWLOCK_EXIT(&ipf_nat);
+inmatchfail:
+ RWLOCK_EXIT(&softc->ipf_nat);
- if (rval == -1) {
- if (passp != NULL)
+ switch (rval)
+ {
+ case -1 :
+ if (passp != NULL) {
+ DT1(frb_natv4in, fr_info_t *, fin);
+ NBUMPSIDED(0, ns_drop);
*passp = FR_BLOCK;
+ fin->fin_reason = FRB_NATV4;
+ }
fin->fin_flx |= FI_BADNAT;
+ NBUMPSIDED(0, ns_badnat);
+ break;
+ case 0 :
+ NBUMPSIDE(0, ns_ignored);
+ break;
+ case 1 :
+ NBUMPSIDE(0, ns_translated);
+ break;
}
return rval;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_natin */
+/* Function: ipf_nat_in */
/* Returns: int - -1 == packet failed NAT checks so block it, */
/* 1 == packet was successfully translated. */
/* Parameters: fin(I) - pointer to packet information */
/* nat(I) - pointer to NAT structure */
/* natadd(I) - flag indicating if it is safe to add frag cache */
/* nflags(I) - NAT flags set for this packet */
-/* Locks Held: ipf_nat (READ) */
+/* Locks Held: ipf_nat(READ) */
/* */
/* Translate a packet coming "in" on an interface. */
/* ------------------------------------------------------------------------ */
-int fr_natin(fin, nat, natadd, nflags)
-fr_info_t *fin;
-nat_t *nat;
-int natadd;
-u_32_t nflags;
+int
+ipf_nat_in(fin, nat, natadd, nflags)
+ fr_info_t *fin;
+ nat_t *nat;
+ int natadd;
+ u_32_t nflags;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ u_32_t sumd, ipsumd, sum1, sum2;
icmphdr_t *icmp;
- u_short *csump;
tcphdr_t *tcp;
ipnat_t *np;
+ int skip;
int i;
tcp = NULL;
- csump = NULL;
np = nat->nat_ptr;
fin->fin_fr = nat->nat_fr;
if (np != NULL) {
if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
- (void) fr_nat_newfrag(fin, 0, nat);
+ (void) ipf_frag_natnew(softc, fin, 0, nat);
/* ------------------------------------------------------------- */
- /* A few quick notes: */
- /* Following are test conditions prior to calling the */
- /* appr_check routine. */
- /* */
- /* A NULL tcp indicates a non TCP/UDP packet. When dealing */
- /* with a map rule, we attempt to match the packet's */
- /* source port against in_dport, otherwise we'd compare the */
- /* packet's destination. */
+ /* A few quick notes: */
+ /* Following are test conditions prior to calling the */
+ /* ipf_proxy_check routine. */
+ /* */
+ /* A NULL tcp indicates a non TCP/UDP packet. When dealing */
+ /* with a map rule, we attempt to match the packet's */
+ /* source port against in_dport, otherwise we'd compare the */
+ /* packet's destination. */
/* ------------------------------------------------------------- */
if (np->in_apr != NULL) {
- i = appr_check(fin, nat);
+ i = ipf_proxy_check(fin, nat);
if (i == -1) {
+ NBUMPSIDED(0, ns_ipf_proxy_fail);
return -1;
}
}
}
-#ifdef IPFILTER_SYNC
- ipfsync_update(SMC_NAT, fin, nat->nat_sync);
-#endif
-
- MUTEX_ENTER(&nat->nat_lock);
- nat->nat_bytes[0] += fin->fin_plen;
- nat->nat_pkts[0]++;
- MUTEX_EXIT(&nat->nat_lock);
-
- fin->fin_ip->ip_dst = nat->nat_inip;
- fin->fin_fi.fi_daddr = nat->nat_inip.s_addr;
- if (nflags & IPN_TCPUDP)
- tcp = fin->fin_dp;
+ ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
+ ipsumd = nat->nat_ipsumd;
/*
* Fix up checksums, not by recalculating them, but
* simply computing adjustments.
@@ -4271,42 +5612,166 @@ u_32_t nflags;
* fast forwarding (so that it doesn't need to be recomputed) but with
* header checksum offloading, perhaps it is a moot point.
*/
+
+ switch (nat->nat_dir)
+ {
+ case NAT_INBOUND :
+ if ((fin->fin_flx & FI_ICMPERR) == 0) {
+ fin->fin_ip->ip_src = nat->nat_nsrcip;
+ fin->fin_saddr = nat->nat_nsrcaddr;
+ } else {
+ sum1 = nat->nat_osrcaddr;
+ sum2 = nat->nat_nsrcaddr;
+ CALC_SUMD(sum1, sum2, sumd);
+ ipsumd -= sumd;
+ }
+ fin->fin_ip->ip_dst = nat->nat_ndstip;
+ fin->fin_daddr = nat->nat_ndstaddr;
#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
defined(__osf__) || defined(linux)
- if (nat->nat_dir == NAT_OUTBOUND)
- fix_incksum(fin, &fin->fin_ip->ip_sum, nat->nat_ipsumd);
- else
- fix_outcksum(fin, &fin->fin_ip->ip_sum, nat->nat_ipsumd);
+ ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, ipsumd, 0);
#endif
+ break;
- if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
- if ((nat->nat_inport != 0) && (nflags & IPN_TCPUDP)) {
- tcp->th_dport = nat->nat_inport;
- fin->fin_data[1] = ntohs(nat->nat_inport);
+ case NAT_OUTBOUND :
+ if ((fin->fin_flx & FI_ICMPERR) == 0) {
+ fin->fin_ip->ip_src = nat->nat_odstip;
+ fin->fin_saddr = nat->nat_odstaddr;
+ } else {
+ sum1 = nat->nat_odstaddr;
+ sum2 = nat->nat_ndstaddr;
+ CALC_SUMD(sum1, sum2, sumd);
+ ipsumd -= sumd;
}
+ fin->fin_ip->ip_dst = nat->nat_osrcip;
+ fin->fin_daddr = nat->nat_osrcaddr;
+#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
+ defined(__osf__) || defined(linux)
+ ipf_fix_incksum(0, &fin->fin_ip->ip_sum, ipsumd, 0);
+#endif
+ break;
+ case NAT_DIVERTIN :
+ {
+ udphdr_t *uh;
+ ip_t *ip;
+ mb_t *m;
- if ((nat->nat_inport != 0) && (nflags & IPN_ICMPQUERY)) {
- icmp = fin->fin_dp;
+ m = M_DUP(np->in_divmp);
+ if (m == NULL) {
+ NBUMPSIDED(0, ns_divert_dup);
+ return -1;
+ }
+
+ ip = MTOD(m, ip_t *);
+ ip->ip_id = htons(ipf_nextipid(fin));
+ sum1 = ntohs(ip->ip_len);
+ ip->ip_len = ntohs(ip->ip_len);
+ ip->ip_len += fin->fin_plen;
+ ip->ip_len = htons(ip->ip_len);
- icmp->icmp_id = nat->nat_inport;
+ uh = (udphdr_t *)(ip + 1);
+ uh->uh_ulen += fin->fin_plen;
+ uh->uh_ulen = htons(uh->uh_ulen);
+
+ sum2 = ntohs(ip->ip_id) + ntohs(ip->ip_len);
+ sum2 += ntohs(ip->ip_off) & IP_DF;
+ CALC_SUMD(sum1, sum2, sumd);
+
+#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
+ defined(__osf__) || defined(linux)
+ ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0);
+#endif
+ PREP_MB_T(fin, m);
+
+ fin->fin_ip = ip;
+ fin->fin_plen += sizeof(ip_t) + 8; /* UDP + new IPv4 hdr */
+ fin->fin_dlen += sizeof(ip_t) + 8; /* UDP + old IPv4 hdr */
+
+ nflags &= ~IPN_TCPUDPICMP;
+
+ break;
+ }
+
+ case NAT_DIVERTOUT :
+ {
+ mb_t *m;
+
+ skip = ipf_nat_decap(fin, nat);
+ if (skip <= 0) {
+ NBUMPSIDED(0, ns_decap_fail);
+ return -1;
}
- csump = nat_proto(fin, nat, nflags);
+ m = fin->fin_m;
+
+#if defined(MENTAT) && defined(_KERNEL)
+ m->b_rptr += skip;
+#else
+ m->m_data += skip;
+ m->m_len -= skip;
+
+# ifdef M_PKTHDR
+ if (m->m_flags & M_PKTHDR)
+ m->m_pkthdr.len -= skip;
+# endif
+#endif
+
+ ipf_nat_update(fin, nat);
+ nflags &= ~IPN_TCPUDPICMP;
+ fin->fin_flx |= FI_NATED;
+ if (np != NULL && np->in_tag.ipt_num[0] != 0)
+ fin->fin_nattag = &np->in_tag;
+ return 1;
+ /* NOTREACHED */
+ }
}
+ if (nflags & IPN_TCPUDP)
+ tcp = fin->fin_dp;
- nat_update(fin, nat, np);
+ if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
+ u_short *csump;
- /*
- * The above comments do not hold for layer 4 (or higher) checksums...
- */
- if (csump != NULL) {
- if (nat->nat_dir == NAT_OUTBOUND)
- fix_incksum(fin, csump, nat->nat_sumd[0]);
- else
- fix_outcksum(fin, csump, nat->nat_sumd[0]);
+ if ((nat->nat_odport != 0) && (nflags & IPN_TCPUDP)) {
+ switch (nat->nat_dir)
+ {
+ case NAT_INBOUND :
+ tcp->th_sport = nat->nat_nsport;
+ fin->fin_data[0] = ntohs(nat->nat_nsport);
+ tcp->th_dport = nat->nat_ndport;
+ fin->fin_data[1] = ntohs(nat->nat_ndport);
+ break;
+
+ case NAT_OUTBOUND :
+ tcp->th_sport = nat->nat_odport;
+ fin->fin_data[0] = ntohs(nat->nat_odport);
+ tcp->th_dport = nat->nat_osport;
+ fin->fin_data[1] = ntohs(nat->nat_osport);
+ break;
+ }
+ }
+
+
+ if ((nat->nat_odport != 0) && (nflags & IPN_ICMPQUERY)) {
+ icmp = fin->fin_dp;
+
+ icmp->icmp_id = nat->nat_nicmpid;
+ }
+
+ csump = ipf_nat_proto(fin, nat, nflags);
+
+ /*
+ * The above comments do not hold for layer 4 (or higher)
+ * checksums...
+ */
+ if (csump != NULL) {
+ if (nat->nat_dir == NAT_OUTBOUND)
+ ipf_fix_incksum(0, csump, nat->nat_sumd[0], 0);
+ else
+ ipf_fix_outcksum(0, csump, nat->nat_sumd[0], 0);
+ }
}
- ATOMIC_INCL(nat_stats.ns_mapped[0]);
+
fin->fin_flx |= FI_NATED;
if (np != NULL && np->in_tag.ipt_num[0] != 0)
fin->fin_nattag = &np->in_tag;
@@ -4315,7 +5780,7 @@ u_32_t nflags;
/* ------------------------------------------------------------------------ */
-/* Function: nat_proto */
+/* Function: ipf_nat_proto */
/* Returns: u_short* - pointer to transport header checksum to update, */
/* NULL if the transport protocol is not recognised */
/* as needing a checksum update. */
@@ -4328,10 +5793,11 @@ u_32_t nflags;
/* that is not strictly 'address' translation, such as clamping the MSS in */
/* TCP down to a specific value, then do it from here. */
/* ------------------------------------------------------------------------ */
-u_short *nat_proto(fin, nat, nflags)
-fr_info_t *fin;
-nat_t *nat;
-u_int nflags;
+u_short *
+ipf_nat_proto(fin, nat, nflags)
+ fr_info_t *fin;
+ nat_t *nat;
+ u_int nflags;
{
icmphdr_t *icmp;
u_short *csump;
@@ -4340,9 +5806,9 @@ u_int nflags;
csump = NULL;
if (fin->fin_out == 0) {
- fin->fin_rev = (nat->nat_dir == NAT_OUTBOUND);
+ fin->fin_rev = (nat->nat_dir & NAT_OUTBOUND);
} else {
- fin->fin_rev = (nat->nat_dir == NAT_INBOUND);
+ fin->fin_rev = ((nat->nat_dir & NAT_OUTBOUND) == 0);
}
switch (fin->fin_p)
@@ -4350,22 +5816,25 @@ u_int nflags;
case IPPROTO_TCP :
tcp = fin->fin_dp;
- csump = &tcp->th_sum;
+ if ((nflags & IPN_TCP) != 0)
+ csump = &tcp->th_sum;
/*
* Do a MSS CLAMPING on a SYN packet,
* only deal IPv4 for now.
*/
if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0)
- nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump);
+ ipf_nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump);
break;
case IPPROTO_UDP :
udp = fin->fin_dp;
- if (udp->uh_sum)
- csump = &udp->uh_sum;
+ if ((nflags & IPN_UDP) != 0) {
+ if (udp->uh_sum != 0)
+ csump = &udp->uh_sum;
+ }
break;
case IPPROTO_ICMP :
@@ -4376,165 +5845,108 @@ u_int nflags;
csump = &icmp->icmp_cksum;
}
break;
- }
- return csump;
-}
-
-/* ------------------------------------------------------------------------ */
-/* Function: fr_natunload */
-/* Returns: Nil */
-/* Parameters: Nil */
-/* */
-/* Free all memory used by NAT structures allocated at runtime. */
-/* ------------------------------------------------------------------------ */
-void fr_natunload()
-{
- ipftq_t *ifq, *ifqnext;
-
- (void) nat_clearlist();
- (void) nat_flushtable();
-
- /*
- * Proxy timeout queues are not cleaned here because although they
- * exist on the NAT list, appr_unload is called after fr_natunload
- * and the proxies actually are responsible for them being created.
- * Should the proxy timeouts have their own list? There's no real
- * justification as this is the only complication.
- */
- for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) {
- ifqnext = ifq->ifq_next;
- if (((ifq->ifq_flags & IFQF_PROXY) == 0) &&
- (fr_deletetimeoutqueue(ifq) == 0))
- fr_freetimeoutqueue(ifq);
- }
-
- 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 (ipf_hm_maptable != NULL) {
- KFREES(ipf_hm_maptable, sizeof(hostmap_t *) * ipf_hostmap_sz);
- ipf_hm_maptable = NULL;
- }
- if (nat_stats.ns_bucketlen[0] != NULL) {
- KFREES(nat_stats.ns_bucketlen[0],
- sizeof(u_long *) * ipf_nattable_sz);
- nat_stats.ns_bucketlen[0] = NULL;
- }
- if (nat_stats.ns_bucketlen[1] != NULL) {
- KFREES(nat_stats.ns_bucketlen[1],
- sizeof(u_long *) * ipf_nattable_sz);
- nat_stats.ns_bucketlen[1] = NULL;
- }
-
- if (fr_nat_maxbucket_reset == 1)
- fr_nat_maxbucket = 0;
-
- if (fr_nat_init == 1) {
- fr_nat_init = 0;
- fr_sttab_destroy(nat_tqb);
-
- RW_DESTROY(&ipf_natfrag);
- RW_DESTROY(&ipf_nat);
+#ifdef USE_INET6
+ case IPPROTO_ICMPV6 :
+ {
+ struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)fin->fin_dp;
- MUTEX_DESTROY(&ipf_nat_new);
- MUTEX_DESTROY(&ipf_natio);
+ icmp6 = fin->fin_dp;
- MUTEX_DESTROY(&nat_udptq.ifq_lock);
- MUTEX_DESTROY(&nat_icmptq.ifq_lock);
- MUTEX_DESTROY(&nat_iptq.ifq_lock);
+ if ((nflags & IPN_ICMPQUERY) != 0) {
+ if (icmp6->icmp6_cksum != 0)
+ csump = &icmp6->icmp6_cksum;
+ }
+ break;
+ }
+#endif
}
+ return csump;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_natexpire */
+/* Function: ipf_nat_expire */
/* Returns: Nil */
-/* Parameters: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
/* */
/* Check all of the timeout queues for entries at the top which need to be */
/* expired. */
/* ------------------------------------------------------------------------ */
-void fr_natexpire()
+void
+ipf_nat_expire(softc)
+ ipf_main_softc_t *softc;
{
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
ipftq_t *ifq, *ifqnext;
ipftqent_t *tqe, *tqn;
int i;
SPL_INT(s);
SPL_NET(s);
- WRITE_ENTER(&ipf_nat);
- for (ifq = nat_tqb, i = 0; ifq != NULL; ifq = ifq->ifq_next) {
+ WRITE_ENTER(&softc->ipf_nat);
+ for (ifq = softn->ipf_nat_tcptq, i = 0; ifq != NULL;
+ ifq = ifq->ifq_next) {
for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) {
- if (tqe->tqe_die > fr_ticks)
+ if (tqe->tqe_die > softc->ipf_ticks)
break;
tqn = tqe->tqe_next;
- nat_delete(tqe->tqe_parent, NL_EXPIRE);
+ ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE);
}
}
- for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) {
- ifqnext = ifq->ifq_next;
-
+ for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifq->ifq_next) {
for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) {
- if (tqe->tqe_die > fr_ticks)
+ if (tqe->tqe_die > softc->ipf_ticks)
break;
tqn = tqe->tqe_next;
- nat_delete(tqe->tqe_parent, NL_EXPIRE);
+ ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE);
}
}
- for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) {
+ for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) {
ifqnext = ifq->ifq_next;
if (((ifq->ifq_flags & IFQF_DELETE) != 0) &&
(ifq->ifq_ref == 0)) {
- fr_freetimeoutqueue(ifq);
+ ipf_freetimeoutqueue(softc, ifq);
}
}
- if (fr_nat_doflush != 0) {
- nat_extraflush(2);
- fr_nat_doflush = 0;
+ if (softn->ipf_nat_doflush != 0) {
+ ipf_nat_extraflush(softc, softn, 2);
+ softn->ipf_nat_doflush = 0;
}
- RWLOCK_EXIT(&ipf_nat);
+ RWLOCK_EXIT(&softc->ipf_nat);
SPL_X(s);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_natsync */
+/* Function: ipf_nat_sync */
/* Returns: Nil */
-/* Parameters: ifp(I) - pointer to network interface */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* ifp(I) - pointer to network interface */
/* */
/* Walk through all of the currently active NAT sessions, looking for those */
/* which need to have their translated address updated. */
/* ------------------------------------------------------------------------ */
-void fr_natsync(ifp)
-void *ifp;
+void
+ipf_nat_sync(softc, ifp)
+ ipf_main_softc_t *softc;
+ void *ifp;
{
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
u_32_t sum1, sum2, sumd;
- struct in_addr in;
+ i6addr_t in;
ipnat_t *n;
nat_t *nat;
void *ifp2;
+ int idx;
SPL_INT(s);
- if (fr_running <= 0)
+ if (softc->ipf_running <= 0)
return;
/*
@@ -4544,28 +5956,63 @@ void *ifp;
* where the rule specifies the address is taken from the interface.
*/
SPL_NET(s);
- WRITE_ENTER(&ipf_nat);
+ WRITE_ENTER(&softc->ipf_nat);
- if (fr_running <= 0) {
- RWLOCK_EXIT(&ipf_nat);
+ if (softc->ipf_running <= 0) {
+ RWLOCK_EXIT(&softc->ipf_nat);
return;
}
- for (nat = nat_instances; nat; nat = nat->nat_next) {
+ for (nat = softn->ipf_nat_instances; nat; nat = nat->nat_next) {
if ((nat->nat_flags & IPN_TCP) != 0)
continue;
+
n = nat->nat_ptr;
- if ((n == NULL) ||
- (n->in_outip != 0) || (n->in_outmsk != 0xffffffff))
- continue;
+ if (n != NULL) {
+ if (n->in_v[1] == 4) {
+ if (n->in_redir & NAT_MAP) {
+ if ((n->in_nsrcaddr != 0) ||
+ (n->in_nsrcmsk != 0xffffffff))
+ continue;
+ } else if (n->in_redir & NAT_REDIRECT) {
+ if ((n->in_ndstaddr != 0) ||
+ (n->in_ndstmsk != 0xffffffff))
+ continue;
+ }
+ }
+#ifdef USE_INET6
+ if (n->in_v[1] == 4) {
+ if (n->in_redir & NAT_MAP) {
+ if (!IP6_ISZERO(&n->in_nsrcaddr) ||
+ !IP6_ISONES(&n->in_nsrcmsk))
+ continue;
+ } else if (n->in_redir & NAT_REDIRECT) {
+ if (!IP6_ISZERO(&n->in_ndstaddr) ||
+ !IP6_ISONES(&n->in_ndstmsk))
+ continue;
+ }
+ }
+#endif
+ }
+
if (((ifp == NULL) || (ifp == nat->nat_ifps[0]) ||
(ifp == nat->nat_ifps[1]))) {
- nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0], 4);
+ nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0],
+ nat->nat_v[0]);
+ if ((nat->nat_ifps[0] != NULL) &&
+ (nat->nat_ifps[0] != (void *)-1)) {
+ nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
+ }
if (nat->nat_ifnames[1][0] != '\0') {
nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1],
- 4);
- } else
+ nat->nat_v[1]);
+ } else {
nat->nat_ifps[1] = nat->nat_ifps[0];
+ }
+ if ((nat->nat_ifps[1] != NULL) &&
+ (nat->nat_ifps[1] != (void *)-1)) {
+ nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
+ }
ifp2 = nat->nat_ifps[0];
if (ifp2 == NULL)
continue;
@@ -4574,10 +6021,13 @@ void *ifp;
* Change the map-to address to be the same as the
* new one.
*/
- sum1 = nat->nat_outip.s_addr;
- if (fr_ifpaddr(4, FRI_NORMAL, ifp2, &in, NULL) != -1)
- nat->nat_outip = in;
- sum2 = nat->nat_outip.s_addr;
+ sum1 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6);
+ if (ipf_ifpaddr(softc, nat->nat_v[0], FRI_NORMAL, ifp2,
+ &in, NULL) != -1) {
+ if (nat->nat_v[0] == 4)
+ nat->nat_nsrcip = in.in4;
+ }
+ sum2 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6);
if (sum1 == sum2)
continue;
@@ -4595,27 +6045,53 @@ void *ifp;
}
}
- for (n = nat_list; (n != NULL); n = n->in_next) {
+ for (n = softn->ipf_nat_list; (n != NULL); n = n->in_next) {
+ char *base = n->in_names;
+
if ((ifp == NULL) || (n->in_ifps[0] == ifp))
- n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], 4);
+ n->in_ifps[0] = ipf_resolvenic(softc,
+ base + n->in_ifnames[0],
+ n->in_v[0]);
if ((ifp == NULL) || (n->in_ifps[1] == ifp))
- n->in_ifps[1] = fr_resolvenic(n->in_ifnames[1], 4);
+ n->in_ifps[1] = ipf_resolvenic(softc,
+ base + n->in_ifnames[1],
+ n->in_v[1]);
+
+ if (n->in_redir & NAT_REDIRECT)
+ idx = 1;
+ else
+ idx = 0;
+
+ if (((ifp == NULL) || (n->in_ifps[idx] == ifp)) &&
+ (n->in_ifps[idx] != NULL &&
+ n->in_ifps[idx] != (void *)-1)) {
+
+ ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc,
+ 0, n->in_ifps[idx]);
+ ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst,
+ 0, n->in_ifps[idx]);
+ ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc,
+ 0, n->in_ifps[idx]);
+ ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst,
+ 0, n->in_ifps[idx]);
+ }
}
- RWLOCK_EXIT(&ipf_nat);
+ RWLOCK_EXIT(&softc->ipf_nat);
SPL_X(s);
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_icmpquerytype4 */
+/* Function: ipf_nat_icmpquerytype */
/* Returns: int - 1 == success, 0 == failure */
/* Parameters: icmptype(I) - ICMP type number */
/* */
/* Tests to see if the ICMP type number passed is a query/response type or */
/* not. */
/* ------------------------------------------------------------------------ */
-static int nat_icmpquerytype4(icmptype)
-int icmptype;
+static int
+ipf_nat_icmpquerytype(icmptype)
+ int icmptype;
{
/*
@@ -4627,10 +6103,8 @@ int icmptype;
* altough it seems silly to call a reply a query, this is exactly
* as it is defined in the IPv4 specification
*/
-
switch (icmptype)
{
-
case ICMP_ECHOREPLY:
case ICMP_ECHO:
/* route aedvertisement/solliciation is currently unsupported: */
@@ -4651,14 +6125,19 @@ int icmptype;
/* ------------------------------------------------------------------------ */
/* Function: nat_log */
/* Returns: Nil */
-/* Parameters: nat(I) - pointer to NAT structure */
-/* type(I) - type of log entry to create */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softn(I) - pointer to NAT context structure */
+/* nat(I) - pointer to NAT structure */
+/* action(I) - action related to NAT structure being performed */
/* */
/* Creates a NAT log entry. */
/* ------------------------------------------------------------------------ */
-void nat_log(nat, type)
-struct nat *nat;
-u_int type;
+void
+ipf_nat_log(softc, softn, nat, action)
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
+ struct nat *nat;
+ u_int action;
{
#ifdef IPFILTER_LOG
# ifndef LARGE_NAT
@@ -4670,22 +6149,40 @@ u_int type;
size_t sizes[1];
int types[1];
- natl.nl_inip = nat->nat_inip;
- natl.nl_outip = nat->nat_outip;
- natl.nl_origip = nat->nat_oip;
+ bcopy((char *)&nat->nat_osrc6, (char *)&natl.nl_osrcip,
+ sizeof(natl.nl_osrcip));
+ bcopy((char *)&nat->nat_nsrc6, (char *)&natl.nl_nsrcip,
+ sizeof(natl.nl_nsrcip));
+ bcopy((char *)&nat->nat_odst6, (char *)&natl.nl_odstip,
+ sizeof(natl.nl_odstip));
+ bcopy((char *)&nat->nat_ndst6, (char *)&natl.nl_ndstip,
+ sizeof(natl.nl_ndstip));
+
natl.nl_bytes[0] = nat->nat_bytes[0];
natl.nl_bytes[1] = nat->nat_bytes[1];
natl.nl_pkts[0] = nat->nat_pkts[0];
natl.nl_pkts[1] = nat->nat_pkts[1];
- 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_odstport = nat->nat_odport;
+ natl.nl_osrcport = nat->nat_osport;
+ natl.nl_nsrcport = nat->nat_nsport;
+ natl.nl_ndstport = nat->nat_ndport;
+ natl.nl_p[0] = nat->nat_pr[0];
+ natl.nl_p[1] = nat->nat_pr[1];
+ natl.nl_v[0] = nat->nat_v[0];
+ natl.nl_v[1] = nat->nat_v[1];
+ natl.nl_type = nat->nat_redir;
+ natl.nl_action = action;
natl.nl_rule = -1;
+
+ bcopy(nat->nat_ifnames[0], natl.nl_ifnames[0],
+ sizeof(nat->nat_ifnames[0]));
+ bcopy(nat->nat_ifnames[1], natl.nl_ifnames[1],
+ sizeof(nat->nat_ifnames[1]));
+
# ifndef LARGE_NAT
if (nat->nat_ptr != NULL) {
- for (rulen = 0, np = nat_list; np; np = np->in_next, rulen++)
+ for (rulen = 0, np = softn->ipf_nat_list; np != NULL;
+ np = np->in_next, rulen++)
if (np == nat->nat_ptr) {
natl.nl_rule = rulen;
break;
@@ -4696,63 +6193,108 @@ u_int type;
sizes[0] = sizeof(natl);
types[0] = 0;
- (void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1);
+ (void) ipf_log_items(softc, IPL_LOGNAT, NULL, items, sizes, types, 1);
#endif
}
#if defined(__OpenBSD__)
/* ------------------------------------------------------------------------ */
-/* Function: nat_ifdetach */
+/* Function: ipf_nat_ifdetach */
/* Returns: Nil */
/* Parameters: ifp(I) - pointer to network interface */
/* */
/* Compatibility interface for OpenBSD to trigger the correct updating of */
/* interface references within IPFilter. */
/* ------------------------------------------------------------------------ */
-void nat_ifdetach(ifp)
-void *ifp;
+void
+ipf_nat_ifdetach(ifp)
+ void *ifp;
{
- frsync(ifp);
+ ipf_main_softc_t *softc;
+
+ softc = ipf_get_softc(0);
+
+ ipf_sync(ifp);
return;
}
#endif
/* ------------------------------------------------------------------------ */
-/* Function: fr_ipnatderef */
+/* Function: ipf_nat_rule_deref */
/* Returns: Nil */
-/* Parameters: isp(I) - pointer to pointer to NAT rule */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* inp(I) - pointer to pointer to NAT rule */
/* Write Locks: ipf_nat */
/* */
+/* Dropping the refernce count for a rule means that whatever held the */
+/* pointer to this rule (*inp) is no longer interested in it and when the */
+/* reference count drops to zero, any resources allocated for the rule can */
+/* be released and the rule itself free'd. */
/* ------------------------------------------------------------------------ */
-void fr_ipnatderef(inp)
-ipnat_t **inp;
+void
+ipf_nat_rule_deref(softc, inp)
+ ipf_main_softc_t *softc;
+ ipnat_t **inp;
{
- ipnat_t *in;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ ipnat_t *n;
- in = *inp;
+ n = *inp;
*inp = NULL;
- in->in_space++;
- in->in_use--;
- if (in->in_use == 0 && (in->in_flags & IPN_DELETE)) {
- if (in->in_apr)
- appr_free(in->in_apr);
- MUTEX_DESTROY(&in->in_lock);
- KFREE(in);
- nat_stats.ns_rules--;
-#if SOLARIS && !defined(_INET_IP_STACK_H)
- if (nat_stats.ns_rules == 0)
- pfil_delayed_copy = 1;
-#endif
+ n->in_use--;
+ if (n->in_use > 0)
+ return;
+
+ if (n->in_apr != NULL)
+ ipf_proxy_deref(n->in_apr);
+
+ ipf_nat_rule_fini(softc, n);
+
+ if (n->in_redir & NAT_REDIRECT) {
+ if ((n->in_flags & IPN_PROXYRULE) == 0) {
+ ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_rdr);
+ }
}
+ if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) {
+ if ((n->in_flags & IPN_PROXYRULE) == 0) {
+ ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_map);
+ }
+ }
+
+ if (n->in_tqehead[0] != NULL) {
+ if (ipf_deletetimeoutqueue(n->in_tqehead[0]) == 0) {
+ ipf_freetimeoutqueue(softc, n->in_tqehead[1]);
+ }
+ }
+
+ if (n->in_tqehead[1] != NULL) {
+ if (ipf_deletetimeoutqueue(n->in_tqehead[1]) == 0) {
+ ipf_freetimeoutqueue(softc, n->in_tqehead[1]);
+ }
+ }
+
+ if ((n->in_flags & IPN_PROXYRULE) == 0) {
+ ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules);
+ }
+
+ MUTEX_DESTROY(&n->in_lock);
+
+ KFREES(n, n->in_size);
+
+#if SOLARIS && !defined(INSTANCES)
+ if (softn->ipf_nat_stats.ns_rules == 0)
+ pfil_delayed_copy = 1;
+#endif
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_natderef */
+/* Function: ipf_nat_deref */
/* Returns: Nil */
-/* Parameters: isp(I) - pointer to pointer to NAT table entry */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* natp(I) - pointer to pointer to NAT table entry */
/* */
/* Decrement the reference counter for this NAT table entry and free it if */
/* there are no more things using it. */
@@ -4765,8 +6307,10 @@ ipnat_t **inp;
/* Holding the lock on nat_lock is required to serialise nat_delete() being */
/* called from a NAT flush ioctl with a deref happening because of a packet.*/
/* ------------------------------------------------------------------------ */
-void fr_natderef(natp)
-nat_t **natp;
+void
+ipf_nat_deref(softc, natp)
+ ipf_main_softc_t *softc;
+ nat_t **natp;
{
nat_t *nat;
@@ -4776,19 +6320,20 @@ nat_t **natp;
MUTEX_ENTER(&nat->nat_lock);
if (nat->nat_ref > 1) {
nat->nat_ref--;
+ ASSERT(nat->nat_ref >= 0);
MUTEX_EXIT(&nat->nat_lock);
return;
}
MUTEX_EXIT(&nat->nat_lock);
- WRITE_ENTER(&ipf_nat);
- nat_delete(nat, NL_EXPIRE);
- RWLOCK_EXIT(&ipf_nat);
+ WRITE_ENTER(&softc->ipf_nat);
+ ipf_nat_delete(softc, nat, NL_EXPIRE);
+ RWLOCK_EXIT(&softc->ipf_nat);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_natclone */
+/* Function: ipf_nat_clone */
/* Returns: ipstate_t* - NULL == cloning failed, */
/* else pointer to new state structure */
/* Parameters: fin(I) - pointer to packet information */
@@ -4797,24 +6342,30 @@ nat_t **natp;
/* */
/* Create a "duplcate" state table entry from the master. */
/* ------------------------------------------------------------------------ */
-static nat_t *fr_natclone(fin, nat)
-fr_info_t *fin;
-nat_t *nat;
+nat_t *
+ipf_nat_clone(fin, nat)
+ fr_info_t *fin;
+ nat_t *nat;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
frentry_t *fr;
nat_t *clone;
ipnat_t *np;
KMALLOC(clone, nat_t *);
- if (clone == NULL)
+ if (clone == NULL) {
+ NBUMPSIDED(fin->fin_out, ns_clone_nomem);
return NULL;
+ }
bcopy((char *)nat, (char *)clone, sizeof(*clone));
MUTEX_NUKE(&clone->nat_lock);
+ clone->nat_rev = fin->fin_rev;
clone->nat_aps = NULL;
/*
- * Initialize all these so that nat_delete() doesn't cause a crash.
+ * Initialize all these so that ipf_nat_delete() doesn't cause a crash.
*/
clone->nat_tqe.tqe_pnext = NULL;
clone->nat_tqe.tqe_next = NULL;
@@ -4827,14 +6378,16 @@ nat_t *nat;
if (clone->nat_hm)
clone->nat_hm->hm_ref++;
- if (nat_insert(clone, fin->fin_rev) == -1) {
+ if (ipf_nat_insert(softc, softn, clone) == -1) {
KFREE(clone);
+ NBUMPSIDED(fin->fin_out, ns_insert_fail);
return NULL;
}
+
np = clone->nat_ptr;
if (np != NULL) {
- if (nat_logging)
- nat_log(clone, (u_int)np->in_redir);
+ if (softn->ipf_nat_logging)
+ ipf_nat_log(softc, softn, clone, NL_CLONE);
np->in_use++;
}
fr = clone->nat_fr;
@@ -4844,26 +6397,25 @@ nat_t *nat;
MUTEX_EXIT(&fr->fr_lock);
}
+
/*
* Because the clone is created outside the normal loop of things and
* TCP has special needs in terms of state, initialise the timeout
* state of the new NAT from here.
*/
- if (clone->nat_p == IPPROTO_TCP) {
- (void) fr_tcp_age(&clone->nat_tqe, fin, nat_tqb,
- clone->nat_flags);
+ if (clone->nat_pr[0] == IPPROTO_TCP) {
+ (void) ipf_tcp_age(&clone->nat_tqe, fin, softn->ipf_nat_tcptq,
+ clone->nat_flags, 2);
}
-#ifdef IPFILTER_SYNC
- clone->nat_sync = ipfsync_new(SMC_NAT, fin, clone);
-#endif
- if (nat_logging)
- nat_log(clone, NL_CLONE);
+ clone->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, clone);
+ if (softn->ipf_nat_logging)
+ ipf_nat_log(softc, softn, clone, NL_CLONE);
return clone;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_wildok */
+/* Function: ipf_nat_wildok */
/* Returns: int - 1 == packet's ports match wildcards */
/* 0 == packet's ports don't match wildcards */
/* Parameters: nat(I) - NAT entry */
@@ -4875,12 +6427,10 @@ nat_t *nat;
/* Use NAT entry and packet direction to determine which combination of */
/* wildcard flags should be used. */
/* ------------------------------------------------------------------------ */
-static int nat_wildok(nat, sport, dport, flags, dir)
-nat_t *nat;
-int sport;
-int dport;
-int flags;
-int dir;
+int
+ipf_nat_wildok(nat, sport, dport, flags, dir)
+ nat_t *nat;
+ int sport, dport, flags, dir;
{
/*
* When called by dir is set to
@@ -4891,34 +6441,33 @@ int dir;
* "intended" direction of that NAT entry in nat->nat_dir to decide
* which combination of wildcard flags to allow.
*/
-
- switch ((dir << 1) | nat->nat_dir)
+ switch ((dir << 1) | (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND)))
{
case 3: /* outbound packet / outbound entry */
- if (((nat->nat_inport == sport) ||
+ if (((nat->nat_osport == sport) ||
(flags & SI_W_SPORT)) &&
- ((nat->nat_oport == dport) ||
+ ((nat->nat_odport == dport) ||
(flags & SI_W_DPORT)))
return 1;
break;
case 2: /* outbound packet / inbound entry */
- if (((nat->nat_outport == sport) ||
- (flags & SI_W_DPORT)) &&
- ((nat->nat_oport == dport) ||
- (flags & SI_W_SPORT)))
+ if (((nat->nat_osport == dport) ||
+ (flags & SI_W_SPORT)) &&
+ ((nat->nat_odport == sport) ||
+ (flags & SI_W_DPORT)))
return 1;
break;
case 1: /* inbound packet / outbound entry */
- if (((nat->nat_oport == sport) ||
- (flags & SI_W_DPORT)) &&
- ((nat->nat_outport == dport) ||
- (flags & SI_W_SPORT)))
+ if (((nat->nat_osport == dport) ||
+ (flags & SI_W_SPORT)) &&
+ ((nat->nat_odport == sport) ||
+ (flags & SI_W_DPORT)))
return 1;
break;
case 0: /* inbound packet / inbound entry */
- if (((nat->nat_oport == sport) ||
+ if (((nat->nat_osport == sport) ||
(flags & SI_W_SPORT)) &&
- ((nat->nat_outport == dport) ||
+ ((nat->nat_odport == dport) ||
(flags & SI_W_DPORT)))
return 1;
break;
@@ -4942,11 +6491,12 @@ int dir;
/* then the TCP header checksum will be updated to reflect the change in */
/* the MSS. */
/* ------------------------------------------------------------------------ */
-static void nat_mssclamp(tcp, maxmss, fin, csump)
-tcphdr_t *tcp;
-u_32_t maxmss;
-fr_info_t *fin;
-u_short *csump;
+static void
+ipf_nat_mssclamp(tcp, maxmss, fin, csump)
+ tcphdr_t *tcp;
+ u_32_t maxmss;
+ fr_info_t *fin;
+ u_short *csump;
{
u_char *cp, *ep, opt;
int hlen, advance;
@@ -4981,7 +6531,7 @@ u_short *csump;
cp[2] = maxmss / 256;
cp[3] = maxmss & 0xff;
CALC_SUMD(mss, maxmss, sumd);
- fix_outcksum(fin, csump, sumd);
+ ipf_fix_outcksum(0, csump, sumd, 0);
}
break;
default:
@@ -4996,20 +6546,24 @@ u_short *csump;
/* ------------------------------------------------------------------------ */
-/* Function: fr_setnatqueue */
+/* Function: ipf_nat_setqueue */
/* Returns: Nil */
-/* Parameters: nat(I)- pointer to NAT structure */
-/* rev(I) - forward(0) or reverse(1) direction */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softn(I) - pointer to NAT context structure */
+/* nat(I)- pointer to NAT structure */
/* Locks: ipf_nat (read or write) */
/* */
/* Put the NAT entry on its default queue entry, using rev as a helped in */
/* determining which queue it should be placed on. */
/* ------------------------------------------------------------------------ */
-void fr_setnatqueue(nat, rev)
-nat_t *nat;
-int rev;
+void
+ipf_nat_setqueue(softc, softn, nat)
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
+ nat_t *nat;
{
ipftq_t *oifq, *nifq;
+ int rev = nat->nat_rev;
if (nat->nat_ptr != NULL)
nifq = nat->nat_ptr->in_tqehead[rev];
@@ -5017,19 +6571,20 @@ int rev;
nifq = NULL;
if (nifq == NULL) {
- switch (nat->nat_p)
+ switch (nat->nat_pr[0])
{
case IPPROTO_UDP :
- nifq = &nat_udptq;
+ nifq = &softn->ipf_nat_udptq;
break;
case IPPROTO_ICMP :
- nifq = &nat_icmptq;
+ nifq = &softn->ipf_nat_icmptq;
break;
case IPPROTO_TCP :
- nifq = nat_tqb + nat->nat_tqe.tqe_state[rev];
+ nifq = softn->ipf_nat_tcptq +
+ nat->nat_tqe.tqe_state[rev];
break;
default :
- nifq = &nat_iptq;
+ nifq = &softn->ipf_nat_iptq;
break;
}
}
@@ -5040,9 +6595,9 @@ int rev;
* another, else put it on the end of the newly determined queue.
*/
if (oifq != NULL)
- fr_movequeue(&nat->nat_tqe, oifq, nifq);
+ ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq, nifq);
else
- fr_queueappend(&nat->nat_tqe, nifq, nat);
+ ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe, nifq, nat);
return;
}
@@ -5050,245 +6605,142 @@ int rev;
/* ------------------------------------------------------------------------ */
/* Function: nat_getnext */
/* Returns: int - 0 == ok, else error */
-/* Parameters: t(I) - pointer to ipftoken structure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* t(I) - pointer to ipftoken structure */
/* itp(I) - pointer to ipfgeniter_t structure */
/* */
/* Fetch the next nat/ipnat structure pointer from the linked list and */
/* copy it out to the storage space pointed to by itp_data. The next item */
/* in the list to look at is put back in the ipftoken struture. */
-/* If we call ipf_freetoken, the accompanying pointer is set to NULL because*/
-/* ipf_freetoken will call a deref function for us and we dont want to call */
-/* that twice (second time would be in the second switch statement below. */
/* ------------------------------------------------------------------------ */
-static int nat_getnext(t, itp)
-ipftoken_t *t;
-ipfgeniter_t *itp;
+static int
+ipf_nat_getnext(softc, t, itp, objp)
+ ipf_main_softc_t *softc;
+ ipftoken_t *t;
+ ipfgeniter_t *itp;
+ ipfobj_t *objp;
{
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
hostmap_t *hm, *nexthm = NULL, zerohm;
ipnat_t *ipn, *nextipnat = NULL, zeroipn;
nat_t *nat, *nextnat = NULL, zeronat;
- int error = 0, count;
- char *dst;
+ int error = 0;
+ void *nnext;
- count = itp->igi_nitems;
- if (count < 1)
+ if (itp->igi_nitems != 1) {
+ IPFERROR(60075);
return ENOSPC;
+ }
- READ_ENTER(&ipf_nat);
+ READ_ENTER(&softc->ipf_nat);
switch (itp->igi_type)
{
case IPFGENITER_HOSTMAP :
hm = t->ipt_data;
if (hm == NULL) {
- nexthm = ipf_hm_maplist;
+ nexthm = softn->ipf_hm_maplist;
} else {
nexthm = hm->hm_next;
}
+ if (nexthm != NULL) {
+ ATOMIC_INC32(nexthm->hm_ref);
+ t->ipt_data = nexthm;
+ } else {
+ bzero(&zerohm, sizeof(zerohm));
+ nexthm = &zerohm;
+ t->ipt_data = NULL;
+ }
+ nnext = nexthm->hm_next;
break;
case IPFGENITER_IPNAT :
ipn = t->ipt_data;
if (ipn == NULL) {
- nextipnat = nat_list;
+ nextipnat = softn->ipf_nat_list;
} else {
nextipnat = ipn->in_next;
}
+ if (nextipnat != NULL) {
+ ATOMIC_INC32(nextipnat->in_use);
+ t->ipt_data = nextipnat;
+ } else {
+ bzero(&zeroipn, sizeof(zeroipn));
+ nextipnat = &zeroipn;
+ t->ipt_data = NULL;
+ }
+ nnext = nextipnat->in_next;
break;
case IPFGENITER_NAT :
nat = t->ipt_data;
if (nat == NULL) {
- nextnat = nat_instances;
+ nextnat = softn->ipf_nat_instances;
} else {
nextnat = nat->nat_next;
}
+ if (nextnat != NULL) {
+ MUTEX_ENTER(&nextnat->nat_lock);
+ nextnat->nat_ref++;
+ MUTEX_EXIT(&nextnat->nat_lock);
+ t->ipt_data = nextnat;
+ } else {
+ bzero(&zeronat, sizeof(zeronat));
+ nextnat = &zeronat;
+ t->ipt_data = NULL;
+ }
+ nnext = nextnat->nat_next;
break;
+
default :
- RWLOCK_EXIT(&ipf_nat);
+ RWLOCK_EXIT(&softc->ipf_nat);
+ IPFERROR(60055);
return EINVAL;
}
- dst = itp->igi_data;
- for (;;) {
- switch (itp->igi_type)
- {
- case IPFGENITER_HOSTMAP :
- if (nexthm != NULL) {
- if (count == 1) {
- ATOMIC_INC32(nexthm->hm_ref);
- t->ipt_data = nexthm;
- }
- } else {
- bzero(&zerohm, sizeof(zerohm));
- nexthm = &zerohm;
- count = 1;
- t->ipt_data = NULL;
- }
- break;
-
- case IPFGENITER_IPNAT :
- if (nextipnat != NULL) {
- if (count == 1) {
- MUTEX_ENTER(&nextipnat->in_lock);
- nextipnat->in_use++;
- MUTEX_EXIT(&nextipnat->in_lock);
- t->ipt_data = nextipnat;
- }
- } else {
- bzero(&zeroipn, sizeof(zeroipn));
- nextipnat = &zeroipn;
- count = 1;
- t->ipt_data = NULL;
- }
- break;
-
- case IPFGENITER_NAT :
- if (nextnat != NULL) {
- if (count == 1) {
- MUTEX_ENTER(&nextnat->nat_lock);
- nextnat->nat_ref++;
- MUTEX_EXIT(&nextnat->nat_lock);
- t->ipt_data = nextnat;
- }
- } else {
- bzero(&zeronat, sizeof(zeronat));
- nextnat = &zeronat;
- count = 1;
- t->ipt_data = NULL;
- }
- break;
- default :
- break;
- }
- RWLOCK_EXIT(&ipf_nat);
-
- /*
- * Copying out to user space needs to be done without the lock.
- */
- switch (itp->igi_type)
- {
- case IPFGENITER_HOSTMAP :
- error = COPYOUT(nexthm, dst, sizeof(*nexthm));
- if (error != 0)
- error = EFAULT;
- else
- dst += sizeof(*nexthm);
- break;
-
- case IPFGENITER_IPNAT :
- error = COPYOUT(nextipnat, dst, sizeof(*nextipnat));
- if (error != 0)
- error = EFAULT;
- else
- dst += sizeof(*nextipnat);
- break;
-
- case IPFGENITER_NAT :
- error = COPYOUT(nextnat, dst, sizeof(*nextnat));
- if (error != 0)
- error = EFAULT;
- else
- dst += sizeof(*nextnat);
- break;
- }
-
- if ((count == 1) || (error != 0))
- break;
-
- count--;
-
- READ_ENTER(&ipf_nat);
-
- /*
- * We need to have the lock again here to make sure that
- * using _next is consistent.
- */
- switch (itp->igi_type)
- {
- case IPFGENITER_HOSTMAP :
- nexthm = nexthm->hm_next;
- break;
- case IPFGENITER_IPNAT :
- nextipnat = nextipnat->in_next;
- break;
- case IPFGENITER_NAT :
- nextnat = nextnat->nat_next;
- break;
- }
- }
+ RWLOCK_EXIT(&softc->ipf_nat);
+ objp->ipfo_ptr = itp->igi_data;
switch (itp->igi_type)
{
case IPFGENITER_HOSTMAP :
+ error = COPYOUT(nexthm, objp->ipfo_ptr, sizeof(*nexthm));
+ if (error != 0) {
+ IPFERROR(60049);
+ error = EFAULT;
+ }
if (hm != NULL) {
- WRITE_ENTER(&ipf_nat);
- fr_hostmapdel(&hm);
- RWLOCK_EXIT(&ipf_nat);
+ WRITE_ENTER(&softc->ipf_nat);
+ ipf_nat_hostmapdel(softc, &hm);
+ RWLOCK_EXIT(&softc->ipf_nat);
}
break;
+
case IPFGENITER_IPNAT :
+ objp->ipfo_size = nextipnat->in_size;
+ objp->ipfo_type = IPFOBJ_IPNAT;
+ error = ipf_outobjk(softc, objp, nextipnat);
if (ipn != NULL) {
- fr_ipnatderef(&ipn);
- }
- break;
- case IPFGENITER_NAT :
- if (nat != NULL) {
- fr_natderef(&nat);
+ WRITE_ENTER(&softc->ipf_nat);
+ ipf_nat_rule_deref(softc, &ipn);
+ RWLOCK_EXIT(&softc->ipf_nat);
}
break;
- default :
- break;
- }
-
- return error;
-}
-
-
-/* ------------------------------------------------------------------------ */
-/* Function: nat_iterator */
-/* Returns: int - 0 == ok, else error */
-/* Parameters: token(I) - pointer to ipftoken structure */
-/* itp(I) - pointer to ipfgeniter_t structure */
-/* */
-/* This function acts as a handler for the SIOCGENITER ioctls that use a */
-/* generic structure to iterate through a list. There are three different */
-/* linked lists of NAT related information to go through: NAT rules, active */
-/* NAT mappings and the NAT fragment cache. */
-/* ------------------------------------------------------------------------ */
-static int nat_iterator(token, itp)
-ipftoken_t *token;
-ipfgeniter_t *itp;
-{
- int error;
- if (itp->igi_data == NULL)
- return EFAULT;
-
- token->ipt_subtype = itp->igi_type;
-
- switch (itp->igi_type)
- {
- case IPFGENITER_HOSTMAP :
- case IPFGENITER_IPNAT :
case IPFGENITER_NAT :
- error = nat_getnext(token, itp);
- break;
+ objp->ipfo_size = sizeof(nat_t);
+ objp->ipfo_type = IPFOBJ_NAT;
+ error = ipf_outobjk(softc, objp, nextnat);
+ if (nat != NULL)
+ ipf_nat_deref(softc, &nat);
- case IPFGENITER_NATFRAG :
-#ifdef USE_MUTEXES
- error = fr_nextfrag(token, itp, &ipfr_natlist,
- &ipfr_nattail, &ipf_natfrag);
-#else
- error = fr_nextfrag(token, itp, &ipfr_natlist, &ipfr_nattail);
-#endif
- break;
- default :
- error = EINVAL;
break;
}
+ if (nnext == NULL)
+ ipf_token_mark_complete(t);
+
return error;
}
@@ -5296,7 +6748,9 @@ ipfgeniter_t *itp;
/* ------------------------------------------------------------------------ */
/* Function: nat_extraflush */
/* Returns: int - 0 == success, -1 == failure */
-/* Parameters: which(I) - how to flush the active NAT table */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softn(I) - pointer to NAT context structure */
+/* which(I) - how to flush the active NAT table */
/* Write Locks: ipf_nat */
/* */
/* Flush nat tables. Three actions currently defined: */
@@ -5310,45 +6764,51 @@ ipfgeniter_t *itp;
/* If that too fails, then work backwards in 30 second intervals */
/* for the last 30 minutes to at worst 30 seconds idle. */
/* ------------------------------------------------------------------------ */
-static int nat_extraflush(which)
-int which;
+static int
+ipf_nat_extraflush(softc, softn, which)
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
+ int which;
{
- ipftq_t *ifq, *ifqnext;
nat_t *nat, **natp;
ipftqent_t *tqn;
+ ipftq_t *ifq;
int removed;
SPL_INT(s);
removed = 0;
SPL_NET(s);
-
switch (which)
{
case 0 :
+ softn->ipf_nat_stats.ns_flush_all++;
/*
* Style 0 flush removes everything...
*/
- for (natp = &nat_instances; ((nat = *natp) != NULL); ) {
- nat_delete(nat, NL_FLUSH);
+ for (natp = &softn->ipf_nat_instances;
+ ((nat = *natp) != NULL); ) {
+ ipf_nat_delete(softc, nat, NL_FLUSH);
removed++;
}
break;
case 1 :
+ softn->ipf_nat_stats.ns_flush_closing++;
/*
* Since we're only interested in things that are closing,
* we can start with the appropriate timeout queue.
*/
- for (ifq = nat_tqb + IPF_TCPS_CLOSE_WAIT; ifq != NULL;
- ifq = ifq->ifq_next) {
+ for (ifq = softn->ipf_nat_tcptq + IPF_TCPS_CLOSE_WAIT;
+ ifq != NULL; ifq = ifq->ifq_next) {
for (tqn = ifq->ifq_head; tqn != NULL; ) {
nat = tqn->tqe_parent;
tqn = tqn->tqe_next;
- if (nat->nat_p != IPPROTO_TCP)
+ if (nat->nat_pr[0] != IPPROTO_TCP ||
+ nat->nat_pr[1] != IPPROTO_TCP)
break;
- nat_delete(nat, NL_EXPIRE);
+ ipf_nat_delete(softc, nat, NL_EXPIRE);
removed++;
}
}
@@ -5356,19 +6816,20 @@ int which;
/*
* Also need to look through the user defined queues.
*/
- for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) {
- ifqnext = ifq->ifq_next;
+ for (ifq = softn->ipf_nat_utqe; ifq != NULL;
+ ifq = ifq->ifq_next) {
for (tqn = ifq->ifq_head; tqn != NULL; ) {
nat = tqn->tqe_parent;
tqn = tqn->tqe_next;
- if (nat->nat_p != IPPROTO_TCP)
+ if (nat->nat_pr[0] != IPPROTO_TCP ||
+ nat->nat_pr[1] != IPPROTO_TCP)
continue;
if ((nat->nat_tcpstate[0] >
IPF_TCPS_ESTABLISHED) &&
(nat->nat_tcpstate[1] >
IPF_TCPS_ESTABLISHED)) {
- nat_delete(nat, NL_EXPIRE);
+ ipf_nat_delete(softc, nat, NL_EXPIRE);
removed++;
}
}
@@ -5386,28 +6847,31 @@ int which;
case IPF_TCPS_FIN_WAIT_2 :
case IPF_TCPS_TIME_WAIT :
case IPF_TCPS_CLOSED :
- tqn = nat_tqb[which].ifq_head;
+ softn->ipf_nat_stats.ns_flush_state++;
+ tqn = softn->ipf_nat_tcptq[which].ifq_head;
while (tqn != NULL) {
nat = tqn->tqe_parent;
tqn = tqn->tqe_next;
- nat_delete(nat, NL_FLUSH);
+ ipf_nat_delete(softc, nat, NL_FLUSH);
removed++;
}
break;
-
+
default :
if (which < 30)
break;
-
+
+ softn->ipf_nat_stats.ns_flush_timeout++;
/*
* Take a large arbitrary number to mean the number of seconds
* for which which consider to be the maximum value we'll allow
* the expiration to be.
*/
which = IPF_TTLVAL(which);
- for (natp = &nat_instances; ((nat = *natp) != NULL); ) {
- if (fr_ticks - nat->nat_touched > which) {
- nat_delete(nat, NL_FLUSH);
+ for (natp = &softn->ipf_nat_instances;
+ ((nat = *natp) != NULL); ) {
+ if (softc->ipf_ticks - nat->nat_touched > which) {
+ ipf_nat_delete(softc, nat, NL_FLUSH);
removed++;
} else
natp = &nat->nat_next;
@@ -5420,12 +6884,25 @@ int which;
return removed;
}
+ softn->ipf_nat_stats.ns_flush_queue++;
+
/*
- * Asked to remove inactive entries because the table is full.
+ * Asked to remove inactive entries because the table is full, try
+ * again, 3 times, if first attempt failed with a different criteria
+ * each time. The order tried in must be in decreasing age.
+ * Another alternative is to implement random drop and drop N entries
+ * at random until N have been freed up.
*/
- if (fr_ticks - nat_last_force_flush > IPF_TTLVAL(5)) {
- nat_last_force_flush = fr_ticks;
- removed = ipf_queueflush(nat_flush_entry, nat_tqb, nat_utqe);
+ if (softc->ipf_ticks - softn->ipf_nat_last_force_flush >
+ IPF_TTLVAL(5)) {
+ softn->ipf_nat_last_force_flush = softc->ipf_ticks;
+
+ removed = ipf_queueflush(softc, ipf_nat_flush_entry,
+ softn->ipf_nat_tcptq,
+ softn->ipf_nat_utqe,
+ &softn->ipf_nat_stats.ns_active,
+ softn->ipf_nat_table_sz,
+ softn->ipf_nat_table_wm_low);
}
SPL_X(s);
@@ -5434,9 +6911,10 @@ int which;
/* ------------------------------------------------------------------------ */
-/* Function: nat_flush_entry */
+/* Function: ipf_nat_flush_entry */
/* Returns: 0 - always succeeds */
-/* Parameters: entry(I) - pointer to NAT entry */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* entry(I) - pointer to NAT entry */
/* Write Locks: ipf_nat */
/* */
/* This function is a stepping stone between ipf_queueflush() and */
@@ -5444,50 +6922,1673 @@ int which;
/* ipf_queueflush() function. Since the nat_delete() function returns void */
/* we translate that to mean it always succeeds in deleting something. */
/* ------------------------------------------------------------------------ */
-static int nat_flush_entry(entry)
-void *entry;
+static int
+ipf_nat_flush_entry(softc, entry)
+ ipf_main_softc_t *softc;
+ void *entry;
+{
+ ipf_nat_delete(softc, entry, NL_FLUSH);
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_iterator */
+/* Returns: int - 0 == ok, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* token(I) - pointer to ipftoken structure */
+/* itp(I) - pointer to ipfgeniter_t structure */
+/* obj(I) - pointer to data description structure */
+/* */
+/* This function acts as a handler for the SIOCGENITER ioctls that use a */
+/* generic structure to iterate through a list. There are three different */
+/* linked lists of NAT related information to go through: NAT rules, active */
+/* NAT mappings and the NAT fragment cache. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_iterator(softc, token, itp, obj)
+ ipf_main_softc_t *softc;
+ ipftoken_t *token;
+ ipfgeniter_t *itp;
+ ipfobj_t *obj;
+{
+ int error;
+
+ if (itp->igi_data == NULL) {
+ IPFERROR(60052);
+ return EFAULT;
+ }
+
+ switch (itp->igi_type)
+ {
+ case IPFGENITER_HOSTMAP :
+ case IPFGENITER_IPNAT :
+ case IPFGENITER_NAT :
+ error = ipf_nat_getnext(softc, token, itp, obj);
+ break;
+
+ case IPFGENITER_NATFRAG :
+ error = ipf_frag_nat_next(softc, token, itp);
+ break;
+ default :
+ IPFERROR(60053);
+ error = EINVAL;
+ break;
+ }
+
+ return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_setpending */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* nat(I) - pointer to NAT structure */
+/* Locks: ipf_nat (read or write) */
+/* */
+/* Put the NAT entry on to the pending queue - this queue has a very short */
+/* lifetime where items are put that can't be deleted straight away because */
+/* of locking issues but we want to delete them ASAP, anyway. In calling */
+/* this function, it is assumed that the owner (if there is one, as shown */
+/* by nat_me) is no longer interested in it. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_nat_setpending(softc, nat)
+ ipf_main_softc_t *softc;
+ nat_t *nat;
{
- nat_delete(entry, NL_FLUSH);
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ ipftq_t *oifq;
+
+ oifq = nat->nat_tqe.tqe_ifq;
+ if (oifq != NULL)
+ ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq,
+ &softn->ipf_nat_pending);
+ else
+ ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe,
+ &softn->ipf_nat_pending, nat);
+
+ if (nat->nat_me != NULL) {
+ *nat->nat_me = NULL;
+ nat->nat_me = NULL;
+ nat->nat_ref--;
+ ASSERT(nat->nat_ref >= 0);
+ }
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat_newrewrite */
+/* Returns: int - -1 == error, 0 == success (no move), 1 == success and */
+/* allow rule to be moved if IPN_ROUNDR is set. */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to NAT entry */
+/* ni(I) - pointer to structure with misc. information needed */
+/* to create new NAT entry. */
+/* Write Lock: ipf_nat */
+/* */
+/* This function is responsible for setting up an active NAT session where */
+/* we are changing both the source and destination parameters at the same */
+/* time. The loop in here works differently to elsewhere - each iteration */
+/* is responsible for changing a single parameter that can be incremented. */
+/* So one pass may increase the source IP#, next source port, next dest. IP#*/
+/* and the last destination port for a total of 4 iterations to try each. */
+/* This is done to try and exhaustively use the translation space available.*/
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_newrewrite(fin, nat, nai)
+ fr_info_t *fin;
+ nat_t *nat;
+ natinfo_t *nai;
+{
+ int src_search = 1;
+ int dst_search = 1;
+ fr_info_t frnat;
+ u_32_t flags;
+ u_short swap;
+ ipnat_t *np;
+ nat_t *natl;
+ int l = 0;
+ int changed;
+
+ natl = NULL;
+ changed = -1;
+ np = nai->nai_np;
+ flags = nat->nat_flags;
+ bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
+
+ nat->nat_hm = NULL;
+
+ do {
+ changed = -1;
+ /* TRACE (l, src_search, dst_search, np) */
+
+ if ((src_search == 0) && (np->in_spnext == 0) &&
+ (dst_search == 0) && (np->in_dpnext == 0)) {
+ if (l > 0)
+ return -1;
+ }
+
+ /*
+ * Find a new source address
+ */
+ if (ipf_nat_nextaddr(fin, &np->in_nsrc, &frnat.fin_saddr,
+ &frnat.fin_saddr) == -1) {
+ return -1;
+ }
+
+ if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0xffffffff)) {
+ src_search = 0;
+ if (np->in_stepnext == 0)
+ np->in_stepnext = 1;
+
+ } else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) {
+ src_search = 0;
+ if (np->in_stepnext == 0)
+ np->in_stepnext = 1;
+
+ } else if (np->in_nsrcmsk == 0xffffffff) {
+ src_search = 0;
+ if (np->in_stepnext == 0)
+ np->in_stepnext = 1;
+
+ } else if (np->in_nsrcmsk != 0xffffffff) {
+ if (np->in_stepnext == 0 && changed == -1) {
+ np->in_snip++;
+ np->in_stepnext++;
+ changed = 0;
+ }
+ }
+
+ if ((flags & IPN_TCPUDPICMP) != 0) {
+ if (np->in_spnext != 0)
+ frnat.fin_data[0] = np->in_spnext;
+
+ /*
+ * Standard port translation. Select next port.
+ */
+ if ((flags & IPN_FIXEDSPORT) != 0) {
+ np->in_stepnext = 2;
+ } else if ((np->in_stepnext == 1) &&
+ (changed == -1) && (natl != NULL)) {
+ np->in_spnext++;
+ np->in_stepnext++;
+ changed = 1;
+ if (np->in_spnext > np->in_spmax)
+ np->in_spnext = np->in_spmin;
+ }
+ } else {
+ np->in_stepnext = 2;
+ }
+ np->in_stepnext &= 0x3;
+
+ /*
+ * Find a new destination address
+ */
+ /* TRACE (fin, np, l, frnat) */
+
+ if (ipf_nat_nextaddr(fin, &np->in_ndst, &frnat.fin_daddr,
+ &frnat.fin_daddr) == -1)
+ return -1;
+ if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) {
+ dst_search = 0;
+ if (np->in_stepnext == 2)
+ np->in_stepnext = 3;
+
+ } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0)) {
+ dst_search = 0;
+ if (np->in_stepnext == 2)
+ np->in_stepnext = 3;
+
+ } else if (np->in_ndstmsk == 0xffffffff) {
+ dst_search = 0;
+ if (np->in_stepnext == 2)
+ np->in_stepnext = 3;
+
+ } else if (np->in_ndstmsk != 0xffffffff) {
+ if ((np->in_stepnext == 2) && (changed == -1) &&
+ (natl != NULL)) {
+ changed = 2;
+ np->in_stepnext++;
+ np->in_dnip++;
+ }
+ }
+
+ if ((flags & IPN_TCPUDPICMP) != 0) {
+ if (np->in_dpnext != 0)
+ frnat.fin_data[1] = np->in_dpnext;
+
+ /*
+ * Standard port translation. Select next port.
+ */
+ if ((flags & IPN_FIXEDDPORT) != 0) {
+ np->in_stepnext = 0;
+ } else if (np->in_stepnext == 3 && changed == -1) {
+ np->in_dpnext++;
+ np->in_stepnext++;
+ changed = 3;
+ if (np->in_dpnext > np->in_dpmax)
+ np->in_dpnext = np->in_dpmin;
+ }
+ } else {
+ if (np->in_stepnext == 3)
+ np->in_stepnext = 0;
+ }
+
+ /* TRACE (frnat) */
+
+ /*
+ * 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.
+ *
+ * fin_data[] is swapped around because we are doing a
+ * lookup of the packet is if it were moving in the opposite
+ * direction of the one we are working with now.
+ */
+ if (flags & IPN_TCPUDP) {
+ swap = frnat.fin_data[0];
+ frnat.fin_data[0] = frnat.fin_data[1];
+ frnat.fin_data[1] = swap;
+ }
+ if (fin->fin_out == 1) {
+ natl = ipf_nat_inlookup(&frnat,
+ flags & ~(SI_WILDP|NAT_SEARCH),
+ (u_int)frnat.fin_p,
+ frnat.fin_dst, frnat.fin_src);
+
+ } else {
+ natl = ipf_nat_outlookup(&frnat,
+ flags & ~(SI_WILDP|NAT_SEARCH),
+ (u_int)frnat.fin_p,
+ frnat.fin_dst, frnat.fin_src);
+ }
+ if (flags & IPN_TCPUDP) {
+ swap = frnat.fin_data[0];
+ frnat.fin_data[0] = frnat.fin_data[1];
+ frnat.fin_data[1] = swap;
+ }
+
+ /* TRACE natl, in_stepnext, l */
+
+ if ((natl != NULL) && (l > 8)) /* XXX 8 is arbitrary */
+ return -1;
+
+ np->in_stepnext &= 0x3;
+
+ l++;
+ changed = -1;
+ } while (natl != NULL);
+
+ nat->nat_osrcip = fin->fin_src;
+ nat->nat_odstip = fin->fin_dst;
+ nat->nat_nsrcip = frnat.fin_src;
+ nat->nat_ndstip = frnat.fin_dst;
+
+ if ((flags & IPN_TCPUDP) != 0) {
+ nat->nat_osport = htons(fin->fin_data[0]);
+ nat->nat_odport = htons(fin->fin_data[1]);
+ nat->nat_nsport = htons(frnat.fin_data[0]);
+ nat->nat_ndport = htons(frnat.fin_data[1]);
+ } else if ((flags & IPN_ICMPQUERY) != 0) {
+ nat->nat_oicmpid = fin->fin_data[1];
+ nat->nat_nicmpid = frnat.fin_data[1];
+ }
+
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: nat_gettable */
+/* Function: nat_newdivert */
+/* Returns: int - -1 == error, 0 == success */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to NAT entry */
+/* ni(I) - pointer to structure with misc. information needed */
+/* to create new NAT entry. */
+/* Write Lock: ipf_nat */
+/* */
+/* Create a new NAT divert session as defined by the NAT rule. This is */
+/* somewhat different to other NAT session creation routines because we */
+/* do not iterate through either port numbers or IP addresses, searching */
+/* for a unique mapping, however, a complimentary duplicate check is made. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_newdivert(fin, nat, nai)
+ fr_info_t *fin;
+ nat_t *nat;
+ natinfo_t *nai;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ fr_info_t frnat;
+ ipnat_t *np;
+ nat_t *natl;
+ int p;
+
+ np = nai->nai_np;
+ bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
+
+ nat->nat_pr[0] = 0;
+ nat->nat_osrcaddr = fin->fin_saddr;
+ nat->nat_odstaddr = fin->fin_daddr;
+ frnat.fin_saddr = htonl(np->in_snip);
+ frnat.fin_daddr = htonl(np->in_dnip);
+ if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+ nat->nat_osport = htons(fin->fin_data[0]);
+ nat->nat_odport = htons(fin->fin_data[1]);
+ } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
+ nat->nat_oicmpid = fin->fin_data[1];
+ }
+
+ if (np->in_redir & NAT_DIVERTUDP) {
+ frnat.fin_data[0] = np->in_spnext;
+ frnat.fin_data[1] = np->in_dpnext;
+ frnat.fin_flx |= FI_TCPUDP;
+ p = IPPROTO_UDP;
+ } else {
+ frnat.fin_flx &= ~FI_TCPUDP;
+ p = IPPROTO_IPIP;
+ }
+
+ if (fin->fin_out == 1) {
+ natl = ipf_nat_inlookup(&frnat, 0, p,
+ frnat.fin_dst, frnat.fin_src);
+
+ } else {
+ natl = ipf_nat_outlookup(&frnat, 0, p,
+ frnat.fin_dst, frnat.fin_src);
+ }
+
+ if (natl != NULL) {
+ NBUMPSIDED(fin->fin_out, ns_divert_exist);
+ return -1;
+ }
+
+ nat->nat_nsrcaddr = frnat.fin_saddr;
+ nat->nat_ndstaddr = frnat.fin_daddr;
+ if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+ nat->nat_nsport = htons(frnat.fin_data[0]);
+ nat->nat_ndport = htons(frnat.fin_data[1]);
+ } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
+ nat->nat_nicmpid = frnat.fin_data[1];
+ }
+
+ nat->nat_pr[fin->fin_out] = fin->fin_p;
+ nat->nat_pr[1 - fin->fin_out] = p;
+
+ if (np->in_redir & NAT_REDIRECT)
+ nat->nat_dir = NAT_DIVERTIN;
+ else
+ nat->nat_dir = NAT_DIVERTOUT;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat_builddivertmp */
+/* Returns: int - -1 == error, 0 == success */
+/* Parameters: softn(I) - pointer to NAT context structure */
+/* np(I) - pointer to a NAT rule */
+/* */
+/* For divert rules, a skeleton packet representing what will be prepended */
+/* to the real packet is created. Even though we don't have the full */
+/* packet here, a checksum is calculated that we update later when we */
+/* fill in the final details. At present a 0 checksum for UDP is being set */
+/* here because it is expected that divert will be used for localhost. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_builddivertmp(softn, np)
+ ipf_nat_softc_t *softn;
+ ipnat_t *np;
+{
+ udphdr_t *uh;
+ size_t len;
+ ip_t *ip;
+
+ if ((np->in_redir & NAT_DIVERTUDP) != 0)
+ len = sizeof(ip_t) + sizeof(udphdr_t);
+ else
+ len = sizeof(ip_t);
+
+ ALLOC_MB_T(np->in_divmp, len);
+ if (np->in_divmp == NULL) {
+ NBUMPD(ipf_nat_stats, ns_divert_build);
+ return -1;
+ }
+
+ /*
+ * First, the header to get the packet diverted to the new destination
+ */
+ ip = MTOD(np->in_divmp, ip_t *);
+ IP_V_A(ip, 4);
+ IP_HL_A(ip, 5);
+ ip->ip_tos = 0;
+ if ((np->in_redir & NAT_DIVERTUDP) != 0)
+ ip->ip_p = IPPROTO_UDP;
+ else
+ ip->ip_p = IPPROTO_IPIP;
+ ip->ip_ttl = 255;
+ ip->ip_off = 0;
+ ip->ip_sum = 0;
+ ip->ip_len = htons(len);
+ ip->ip_id = 0;
+ ip->ip_src.s_addr = htonl(np->in_snip);
+ ip->ip_dst.s_addr = htonl(np->in_dnip);
+ ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip));
+
+ if (np->in_redir & NAT_DIVERTUDP) {
+ uh = (udphdr_t *)(ip + 1);
+ uh->uh_sum = 0;
+ uh->uh_ulen = 8;
+ uh->uh_sport = htons(np->in_spnext);
+ uh->uh_dport = htons(np->in_dpnext);
+ }
+
+ return 0;
+}
+
+
+#define MINDECAP (sizeof(ip_t) + sizeof(udphdr_t) + sizeof(ip_t))
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat_decap */
+/* Returns: int - -1 == error, 0 == success */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to current NAT session */
+/* */
+/* This function is responsible for undoing a packet's encapsulation in the */
+/* reverse of an encap/divert rule. After removing the outer encapsulation */
+/* it is necessary to call ipf_makefrip() again so that the contents of 'fin'*/
+/* match the "new" packet as it may still be used by IPFilter elsewhere. */
+/* We use "dir" here as the basis for some of the expectations about the */
+/* outer header. If we return an error, the goal is to leave the original */
+/* packet information undisturbed - this falls short at the end where we'd */
+/* need to back a backup copy of "fin" - expensive. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_decap(fin, nat)
+ fr_info_t *fin;
+ nat_t *nat;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ char *hdr;
+ int hlen;
+ int skip;
+ mb_t *m;
+
+ if ((fin->fin_flx & FI_ICMPERR) != 0) {
+ /*
+ * ICMP packets don't get decapsulated, instead what we need
+ * to do is change the ICMP reply from including (in the data
+ * portion for errors) the encapsulated packet that we sent
+ * out to something that resembles the original packet prior
+ * to encapsulation. This isn't done here - all we're doing
+ * here is changing the outer address to ensure that it gets
+ * targetted back to the correct system.
+ */
+
+ if (nat->nat_dir & NAT_OUTBOUND) {
+ u_32_t sum1, sum2, sumd;
+
+ sum1 = ntohl(fin->fin_daddr);
+ sum2 = ntohl(nat->nat_osrcaddr);
+ CALC_SUMD(sum1, sum2, sumd);
+ fin->fin_ip->ip_dst = nat->nat_osrcip;
+ fin->fin_daddr = nat->nat_osrcaddr;
+#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \
+ defined(__osf__) || defined(linux)
+ ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, sumd, 0);
+#endif
+ }
+ return 0;
+ }
+
+ m = fin->fin_m;
+ skip = fin->fin_hlen;
+
+ switch (nat->nat_dir)
+ {
+ case NAT_DIVERTIN :
+ case NAT_DIVERTOUT :
+ if (fin->fin_plen < MINDECAP)
+ return -1;
+ skip += sizeof(udphdr_t);
+ break;
+
+ case NAT_ENCAPIN :
+ case NAT_ENCAPOUT :
+ if (fin->fin_plen < (skip + sizeof(ip_t)))
+ return -1;
+ break;
+ default :
+ return -1;
+ /* NOTREACHED */
+ }
+
+ /*
+ * The aim here is to keep the original packet details in "fin" for
+ * as long as possible so that returning with an error is for the
+ * original packet and there is little undoing work to do.
+ */
+ if (M_LEN(m) < skip + sizeof(ip_t)) {
+ if (ipf_pr_pullup(fin, skip + sizeof(ip_t)) == -1)
+ return -1;
+ }
+
+ hdr = MTOD(fin->fin_m, char *);
+ fin->fin_ip = (ip_t *)(hdr + skip);
+ hlen = IP_HL(fin->fin_ip) << 2;
+
+ if (ipf_pr_pullup(fin, skip + hlen) == -1) {
+ NBUMPSIDED(fin->fin_out, ns_decap_pullup);
+ return -1;
+ }
+
+ fin->fin_hlen = hlen;
+ fin->fin_dlen -= skip;
+ fin->fin_plen -= skip;
+ fin->fin_ipoff += skip;
+
+ if (ipf_makefrip(hlen, (ip_t *)hdr, fin) == -1) {
+ NBUMPSIDED(fin->fin_out, ns_decap_bad);
+ return -1;
+ }
+
+ return skip;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat_nextaddr */
+/* Returns: int - -1 == bad input (no new address), */
+/* 0 == success and dst has new address */
+/* Parameters: fin(I) - pointer to packet information */
+/* na(I) - how to generate new address */
+/* old(I) - original address being replaced */
+/* dst(O) - where to put the new address */
+/* Write Lock: ipf_nat */
+/* */
+/* This function uses the contents of the "na" structure, in combination */
+/* with "old" to produce a new address to store in "dst". Not all of the */
+/* possible uses of "na" will result in a new address. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_nextaddr(fin, na, old, dst)
+ fr_info_t *fin;
+ nat_addr_t *na;
+ u_32_t *old, *dst;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ u_32_t amin, amax, new;
+ i6addr_t newip;
+ int error;
+
+ new = 0;
+ amin = na->na_addr[0].in4.s_addr;
+
+ switch (na->na_atype)
+ {
+ case FRI_RANGE :
+ amax = na->na_addr[1].in4.s_addr;
+ break;
+
+ case FRI_NETMASKED :
+ case FRI_DYNAMIC :
+ case FRI_NORMAL :
+ /*
+ * Compute the maximum address by adding the inverse of the
+ * netmask to the minimum address.
+ */
+ amax = ~na->na_addr[1].in4.s_addr;
+ amax |= amin;
+ break;
+
+ case FRI_LOOKUP :
+ break;
+
+ case FRI_BROADCAST :
+ case FRI_PEERADDR :
+ case FRI_NETWORK :
+ default :
+ return -1;
+ }
+
+ error = -1;
+
+ if (na->na_atype == FRI_LOOKUP) {
+ if (na->na_type == IPLT_DSTLIST) {
+ error = ipf_dstlist_select_node(fin, na->na_ptr, dst,
+ NULL);
+ } else {
+ NBUMPSIDE(fin->fin_out, ns_badnextaddr);
+ }
+
+ } else if (na->na_atype == IPLT_NONE) {
+ /*
+ * 0/0 as the new address means leave it alone.
+ */
+ if (na->na_addr[0].in4.s_addr == 0 &&
+ na->na_addr[1].in4.s_addr == 0) {
+ new = *old;
+
+ /*
+ * 0/32 means get the interface's address
+ */
+ } else if (na->na_addr[0].in4.s_addr == 0 &&
+ na->na_addr[1].in4.s_addr == 0xffffffff) {
+ if (ipf_ifpaddr(softc, 4, na->na_atype,
+ fin->fin_ifp, &newip, NULL) == -1) {
+ NBUMPSIDED(fin->fin_out, ns_ifpaddrfail);
+ return -1;
+ }
+ new = newip.in4.s_addr;
+ } else {
+ new = htonl(na->na_nextip);
+ }
+ *dst = new;
+ error = 0;
+
+ } else {
+ NBUMPSIDE(fin->fin_out, ns_badnextaddr);
+ }
+
+ return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat_nextaddrinit */
+/* Returns: int - 0 == success, else error number */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* na(I) - NAT address information for generating new addr*/
+/* initial(I) - flag indicating if it is the first call for */
+/* this "na" structure. */
+/* ifp(I) - network interface to derive address */
+/* information from. */
+/* */
+/* This function is expected to be called in two scenarious: when a new NAT */
+/* rule is loaded into the kernel and when the list of NAT rules is sync'd */
+/* up with the valid network interfaces (possibly due to them changing.) */
+/* To distinguish between these, the "initial" parameter is used. If it is */
+/* 1 then this indicates the rule has just been reloaded and 0 for when we */
+/* are updating information. This difference is important because in */
+/* instances where we are not updating address information associated with */
+/* a network interface, we don't want to disturb what the "next" address to */
+/* come out of ipf_nat_nextaddr() will be. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_nextaddrinit(softc, base, na, initial, ifp)
+ ipf_main_softc_t *softc;
+ char *base;
+ nat_addr_t *na;
+ int initial;
+ void *ifp;
+{
+
+ switch (na->na_atype)
+ {
+ case FRI_LOOKUP :
+ if (na->na_subtype == 0) {
+ na->na_ptr = ipf_lookup_res_num(softc, IPL_LOGNAT,
+ na->na_type,
+ na->na_num,
+ &na->na_func);
+ } else if (na->na_subtype == 1) {
+ na->na_ptr = ipf_lookup_res_name(softc, IPL_LOGNAT,
+ na->na_type,
+ base + na->na_num,
+ &na->na_func);
+ }
+ if (na->na_func == NULL) {
+ IPFERROR(60060);
+ return ESRCH;
+ }
+ if (na->na_ptr == NULL) {
+ IPFERROR(60056);
+ return ESRCH;
+ }
+ break;
+
+ case FRI_DYNAMIC :
+ case FRI_BROADCAST :
+ case FRI_NETWORK :
+ case FRI_NETMASKED :
+ case FRI_PEERADDR :
+ if (ifp != NULL)
+ (void )ipf_ifpaddr(softc, 4, na->na_atype, ifp,
+ &na->na_addr[0], &na->na_addr[1]);
+ break;
+
+ case FRI_SPLIT :
+ case FRI_RANGE :
+ if (initial)
+ na->na_nextip = ntohl(na->na_addr[0].in4.s_addr);
+ break;
+
+ case FRI_NONE :
+ na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr;
+ return 0;
+
+ case FRI_NORMAL :
+ na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr;
+ break;
+
+ default :
+ IPFERROR(60054);
+ return EINVAL;
+ }
+
+ if (initial && (na->na_atype == FRI_NORMAL)) {
+ if (na->na_addr[0].in4.s_addr == 0) {
+ if ((na->na_addr[1].in4.s_addr == 0xffffffff) ||
+ (na->na_addr[1].in4.s_addr == 0)) {
+ return 0;
+ }
+ }
+
+ if (na->na_addr[1].in4.s_addr == 0xffffffff) {
+ na->na_nextip = ntohl(na->na_addr[0].in4.s_addr);
+ } else {
+ na->na_nextip = ntohl(na->na_addr[0].in4.s_addr) + 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_matchflush */
+/* Returns: int - -1 == error, 0 == success */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softn(I) - pointer to NAT context structure */
+/* nat(I) - pointer to current NAT session */
+/* */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_matchflush(softc, softn, data)
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
+ caddr_t data;
+{
+ int *array, flushed, error;
+ nat_t *nat, *natnext;
+ ipfobj_t obj;
+
+ error = ipf_matcharray_load(softc, data, &obj, &array);
+ if (error != 0)
+ return error;
+
+ flushed = 0;
+
+ for (nat = softn->ipf_nat_instances; nat != NULL; nat = natnext) {
+ natnext = nat->nat_next;
+ if (ipf_nat_matcharray(nat, array, softc->ipf_ticks) == 0) {
+ ipf_nat_delete(softc, nat, NL_FLUSH);
+ flushed++;
+ }
+ }
+
+ obj.ipfo_retval = flushed;
+ error = BCOPYOUT(&obj, data, sizeof(obj));
+
+ KFREES(array, array[0] * sizeof(*array));
+
+ return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_matcharray */
+/* Returns: int - -1 == error, 0 == success */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to current NAT session */
+/* */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_matcharray(nat, array, ticks)
+ nat_t *nat;
+ int *array;
+ u_long ticks;
+{
+ int i, n, *x, e, p;
+
+ e = 0;
+ n = array[0];
+ x = array + 1;
+
+ for (; n > 0; x += 3 + x[2]) {
+ if (x[0] == IPF_EXP_END)
+ break;
+ e = 0;
+
+ n -= x[2] + 3;
+ if (n < 0)
+ break;
+
+ p = x[0] >> 16;
+ if (p != 0 && p != nat->nat_pr[1])
+ break;
+
+ switch (x[0])
+ {
+ case IPF_EXP_IP_PR :
+ for (i = 0; !e && i < x[2]; i++) {
+ e |= (nat->nat_pr[1] == x[i + 3]);
+ }
+ break;
+
+ case IPF_EXP_IP_SRCADDR :
+ if (nat->nat_v[0] == 4) {
+ for (i = 0; !e && i < x[2]; i++) {
+ e |= ((nat->nat_osrcaddr & x[i + 4]) ==
+ x[i + 3]);
+ }
+ }
+ if (nat->nat_v[1] == 4) {
+ for (i = 0; !e && i < x[2]; i++) {
+ e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
+ x[i + 3]);
+ }
+ }
+ break;
+
+ case IPF_EXP_IP_DSTADDR :
+ if (nat->nat_v[0] == 4) {
+ for (i = 0; !e && i < x[2]; i++) {
+ e |= ((nat->nat_odstaddr & x[i + 4]) ==
+ x[i + 3]);
+ }
+ }
+ if (nat->nat_v[1] == 4) {
+ for (i = 0; !e && i < x[2]; i++) {
+ e |= ((nat->nat_ndstaddr & x[i + 4]) ==
+ x[i + 3]);
+ }
+ }
+ break;
+
+ case IPF_EXP_IP_ADDR :
+ for (i = 0; !e && i < x[2]; i++) {
+ if (nat->nat_v[0] == 4) {
+ e |= ((nat->nat_osrcaddr & x[i + 4]) ==
+ x[i + 3]);
+ }
+ if (nat->nat_v[1] == 4) {
+ e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
+ x[i + 3]);
+ }
+ if (nat->nat_v[0] == 4) {
+ e |= ((nat->nat_odstaddr & x[i + 4]) ==
+ x[i + 3]);
+ }
+ if (nat->nat_v[1] == 4) {
+ e |= ((nat->nat_ndstaddr & x[i + 4]) ==
+ x[i + 3]);
+ }
+ }
+ break;
+
+#ifdef USE_INET6
+ case IPF_EXP_IP6_SRCADDR :
+ if (nat->nat_v[0] == 6) {
+ for (i = 0; !e && i < x[3]; i++) {
+ e |= IP6_MASKEQ(&nat->nat_osrc6,
+ x + i + 7, x + i + 3);
+ }
+ }
+ if (nat->nat_v[1] == 6) {
+ for (i = 0; !e && i < x[3]; i++) {
+ e |= IP6_MASKEQ(&nat->nat_nsrc6,
+ x + i + 7, x + i + 3);
+ }
+ }
+ break;
+
+ case IPF_EXP_IP6_DSTADDR :
+ if (nat->nat_v[0] == 6) {
+ for (i = 0; !e && i < x[3]; i++) {
+ e |= IP6_MASKEQ(&nat->nat_odst6,
+ x + i + 7,
+ x + i + 3);
+ }
+ }
+ if (nat->nat_v[1] == 6) {
+ for (i = 0; !e && i < x[3]; i++) {
+ e |= IP6_MASKEQ(&nat->nat_ndst6,
+ x + i + 7,
+ x + i + 3);
+ }
+ }
+ break;
+
+ case IPF_EXP_IP6_ADDR :
+ for (i = 0; !e && i < x[3]; i++) {
+ if (nat->nat_v[0] == 6) {
+ e |= IP6_MASKEQ(&nat->nat_osrc6,
+ x + i + 7,
+ x + i + 3);
+ }
+ if (nat->nat_v[0] == 6) {
+ e |= IP6_MASKEQ(&nat->nat_odst6,
+ x + i + 7,
+ x + i + 3);
+ }
+ if (nat->nat_v[1] == 6) {
+ e |= IP6_MASKEQ(&nat->nat_nsrc6,
+ x + i + 7,
+ x + i + 3);
+ }
+ if (nat->nat_v[1] == 6) {
+ e |= IP6_MASKEQ(&nat->nat_ndst6,
+ x + i + 7,
+ x + i + 3);
+ }
+ }
+ break;
+#endif
+
+ case IPF_EXP_UDP_PORT :
+ case IPF_EXP_TCP_PORT :
+ for (i = 0; !e && i < x[2]; i++) {
+ e |= (nat->nat_nsport == x[i + 3]) ||
+ (nat->nat_ndport == x[i + 3]);
+ }
+ break;
+
+ case IPF_EXP_UDP_SPORT :
+ case IPF_EXP_TCP_SPORT :
+ for (i = 0; !e && i < x[2]; i++) {
+ e |= (nat->nat_nsport == x[i + 3]);
+ }
+ break;
+
+ case IPF_EXP_UDP_DPORT :
+ case IPF_EXP_TCP_DPORT :
+ for (i = 0; !e && i < x[2]; i++) {
+ e |= (nat->nat_ndport == x[i + 3]);
+ }
+ break;
+
+ case IPF_EXP_TCP_STATE :
+ for (i = 0; !e && i < x[2]; i++) {
+ e |= (nat->nat_tcpstate[0] == x[i + 3]) ||
+ (nat->nat_tcpstate[1] == x[i + 3]);
+ }
+ break;
+
+ case IPF_EXP_IDLE_GT :
+ e |= (ticks - nat->nat_touched > x[3]);
+ break;
+ }
+ e ^= x[1];
+
+ if (!e)
+ break;
+ }
+
+ return e;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_gettable */
/* Returns: int - 0 = success, else error */
-/* Parameters: data(I) - pointer to ioctl data */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softn(I) - pointer to NAT context structure */
+/* data(I) - pointer to ioctl data */
/* */
/* This function handles ioctl requests for tables of nat information. */
/* At present the only table it deals with is the hash bucket statistics. */
/* ------------------------------------------------------------------------ */
-static int nat_gettable(data)
-char *data;
+static int
+ipf_nat_gettable(softc, softn, data)
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
+ char *data;
{
ipftable_t table;
int error;
- error = fr_inobj(data, &table, IPFOBJ_GTABLE);
+ error = ipf_inobj(softc, data, NULL, &table, IPFOBJ_GTABLE);
if (error != 0)
return error;
switch (table.ita_type)
{
case IPFTABLE_BUCKETS_NATIN :
- error = COPYOUT(nat_stats.ns_bucketlen[0], table.ita_table,
- ipf_nattable_sz * sizeof(u_long));
+ error = COPYOUT(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
+ table.ita_table,
+ softn->ipf_nat_table_sz * sizeof(u_int));
break;
case IPFTABLE_BUCKETS_NATOUT :
- error = COPYOUT(nat_stats.ns_bucketlen[1], table.ita_table,
- ipf_nattable_sz * sizeof(u_long));
+ error = COPYOUT(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
+ table.ita_table,
+ softn->ipf_nat_table_sz * sizeof(u_int));
break;
default :
+ IPFERROR(60058);
return EINVAL;
}
if (error != 0) {
+ IPFERROR(60059);
error = EFAULT;
}
return error;
}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_settimeout */
+/* Returns: int - 0 = success, else failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* t(I) - pointer to tunable */
+/* p(I) - pointer to new tuning data */
+/* */
+/* Apply the timeout change to the NAT timeout queues. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat_settimeout(softc, t, p)
+ struct ipf_main_softc_s *softc;
+ ipftuneable_t *t;
+ ipftuneval_t *p;
+{
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+
+ if (!strncmp(t->ipft_name, "tcp_", 4))
+ return ipf_settimeout_tcp(t, p, softn->ipf_nat_tcptq);
+
+ if (!strcmp(t->ipft_name, "udp_timeout")) {
+ ipf_apply_timeout(&softn->ipf_nat_udptq, p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "udp_ack_timeout")) {
+ ipf_apply_timeout(&softn->ipf_nat_udpacktq, p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "icmp_timeout")) {
+ ipf_apply_timeout(&softn->ipf_nat_icmptq, p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "icmp_ack_timeout")) {
+ ipf_apply_timeout(&softn->ipf_nat_icmpacktq, p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "ip_timeout")) {
+ ipf_apply_timeout(&softn->ipf_nat_iptq, p->ipftu_int);
+ } else {
+ IPFERROR(60062);
+ return ESRCH;
+ }
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_rehash */
+/* Returns: int - 0 = success, else failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* t(I) - pointer to tunable */
+/* p(I) - pointer to new tuning data */
+/* */
+/* To change the size of the basic NAT table, we need to first allocate the */
+/* new tables (lest it fails and we've got nowhere to store all of the NAT */
+/* sessions currently active) and then walk through the entire list and */
+/* insert them into the table. There are two tables here: an inbound one */
+/* and an outbound one. Each NAT entry goes into each table once. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat_rehash(softc, t, p)
+ ipf_main_softc_t *softc;
+ ipftuneable_t *t;
+ ipftuneval_t *p;
+{
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ nat_t **newtab[2], *nat, **natp;
+ u_int *bucketlens[2];
+ u_int maxbucket;
+ u_int newsize;
+ int error;
+ u_int hv;
+ int i;
+
+ newsize = p->ipftu_int;
+ /*
+ * In case there is nothing to do...
+ */
+ if (newsize == softn->ipf_nat_table_sz)
+ return 0;
+
+ newtab[0] = NULL;
+ newtab[1] = NULL;
+ bucketlens[0] = NULL;
+ bucketlens[1] = NULL;
+ /*
+ * 4 tables depend on the NAT table size: the inbound looking table,
+ * the outbound lookup table and the hash chain length for each.
+ */
+ KMALLOCS(newtab[0], nat_t **, newsize * sizeof(nat_t *));
+ if (newtab == NULL) {
+ error = 60063;
+ goto badrehash;
+ }
+
+ KMALLOCS(newtab[1], nat_t **, newsize * sizeof(nat_t *));
+ if (newtab == NULL) {
+ error = 60064;
+ goto badrehash;
+ }
+
+ KMALLOCS(bucketlens[0], u_int *, newsize * sizeof(u_int));
+ if (bucketlens[0] == NULL) {
+ error = 60065;
+ goto badrehash;
+ }
+
+ KMALLOCS(bucketlens[1], u_int *, newsize * sizeof(u_int));
+ if (bucketlens[1] == NULL) {
+ error = 60066;
+ goto badrehash;
+ }
+
+ /*
+ * Recalculate the maximum length based on the new size.
+ */
+ for (maxbucket = 0, i = newsize; i > 0; i >>= 1)
+ maxbucket++;
+ maxbucket *= 2;
+
+ bzero((char *)newtab[0], newsize * sizeof(nat_t *));
+ bzero((char *)newtab[1], newsize * sizeof(nat_t *));
+ bzero((char *)bucketlens[0], newsize * sizeof(u_int));
+ bzero((char *)bucketlens[1], newsize * sizeof(u_int));
+
+ WRITE_ENTER(&softc->ipf_nat);
+
+ if (softn->ipf_nat_table[0] != NULL) {
+ KFREES(softn->ipf_nat_table[0],
+ softn->ipf_nat_table_sz *
+ sizeof(*softn->ipf_nat_table[0]));
+ }
+ softn->ipf_nat_table[0] = newtab[0];
+
+ if (softn->ipf_nat_table[1] != NULL) {
+ KFREES(softn->ipf_nat_table[1],
+ softn->ipf_nat_table_sz *
+ sizeof(*softn->ipf_nat_table[1]));
+ }
+ softn->ipf_nat_table[1] = newtab[1];
+
+ if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) {
+ KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
+ softn->ipf_nat_table_sz * sizeof(u_int));
+ }
+ softn->ipf_nat_stats.ns_side[0].ns_bucketlen = bucketlens[0];
+
+ if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) {
+ KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
+ softn->ipf_nat_table_sz * sizeof(u_int));
+ }
+ softn->ipf_nat_stats.ns_side[1].ns_bucketlen = bucketlens[1];
+
+#ifdef USE_INET6
+ if (softn->ipf_nat_stats.ns_side6[0].ns_bucketlen != NULL) {
+ KFREES(softn->ipf_nat_stats.ns_side6[0].ns_bucketlen,
+ softn->ipf_nat_table_sz * sizeof(u_int));
+ }
+ softn->ipf_nat_stats.ns_side6[0].ns_bucketlen = bucketlens[0];
+
+ if (softn->ipf_nat_stats.ns_side6[1].ns_bucketlen != NULL) {
+ KFREES(softn->ipf_nat_stats.ns_side6[1].ns_bucketlen,
+ softn->ipf_nat_table_sz * sizeof(u_int));
+ }
+ softn->ipf_nat_stats.ns_side6[1].ns_bucketlen = bucketlens[1];
+#endif
+
+ softn->ipf_nat_maxbucket = maxbucket;
+ softn->ipf_nat_table_sz = newsize;
+ /*
+ * Walk through the entire list of NAT table entries and put them
+ * in the new NAT table, somewhere. Because we have a new table,
+ * we need to restart the counter of how many chains are in use.
+ */
+ softn->ipf_nat_stats.ns_side[0].ns_inuse = 0;
+ softn->ipf_nat_stats.ns_side[1].ns_inuse = 0;
+#ifdef USE_INET6
+ softn->ipf_nat_stats.ns_side6[0].ns_inuse = 0;
+ softn->ipf_nat_stats.ns_side6[1].ns_inuse = 0;
+#endif
+
+ for (nat = softn->ipf_nat_instances; nat != NULL; nat = nat->nat_next) {
+ nat->nat_hnext[0] = NULL;
+ nat->nat_phnext[0] = NULL;
+ hv = nat->nat_hv[0] % softn->ipf_nat_table_sz;
+
+ natp = &softn->ipf_nat_table[0][hv];
+ if (*natp) {
+ (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
+ } else {
+ NBUMPSIDE(0, ns_inuse);
+ }
+ nat->nat_phnext[0] = natp;
+ nat->nat_hnext[0] = *natp;
+ *natp = nat;
+ NBUMPSIDE(0, ns_bucketlen[hv]);
+
+ nat->nat_hnext[1] = NULL;
+ nat->nat_phnext[1] = NULL;
+ hv = nat->nat_hv[1] % softn->ipf_nat_table_sz;
+
+ natp = &softn->ipf_nat_table[1][hv];
+ if (*natp) {
+ (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
+ } else {
+ NBUMPSIDE(1, ns_inuse);
+ }
+ nat->nat_phnext[1] = natp;
+ nat->nat_hnext[1] = *natp;
+ *natp = nat;
+ NBUMPSIDE(1, ns_bucketlen[hv]);
+ }
+ RWLOCK_EXIT(&softc->ipf_nat);
+
+ return 0;
+
+badrehash:
+ if (bucketlens[1] != NULL) {
+ KFREES(bucketlens[0], newsize * sizeof(u_int));
+ }
+ if (bucketlens[0] != NULL) {
+ KFREES(bucketlens[0], newsize * sizeof(u_int));
+ }
+ if (newtab[0] != NULL) {
+ KFREES(newtab[0], newsize * sizeof(nat_t *));
+ }
+ if (newtab[1] != NULL) {
+ KFREES(newtab[1], newsize * sizeof(nat_t *));
+ }
+ IPFERROR(error);
+ return ENOMEM;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_rehash_rules */
+/* Returns: int - 0 = success, else failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* t(I) - pointer to tunable */
+/* p(I) - pointer to new tuning data */
+/* */
+/* All of the NAT rules hang off of a hash table that is searched with a */
+/* hash on address after the netmask is applied. There is a different table*/
+/* for both inbound rules (rdr) and outbound (map.) The resizing will only */
+/* affect one of these two tables. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat_rehash_rules(softc, t, p)
+ ipf_main_softc_t *softc;
+ ipftuneable_t *t;
+ ipftuneval_t *p;
+{
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ ipnat_t **newtab, *np, ***old, **npp;
+ u_int newsize;
+ u_int mask;
+ u_int hv;
+
+ newsize = p->ipftu_int;
+ /*
+ * In case there is nothing to do...
+ */
+ if (newsize == *t->ipft_pint)
+ return 0;
+
+ /*
+ * All inbound rules have the NAT_REDIRECT bit set in in_redir and
+ * all outbound rules have either NAT_MAP or MAT_MAPBLK set.
+ * This if statement allows for some more generic code to be below,
+ * rather than two huge gobs of code that almost do the same thing.
+ */
+ if (t->ipft_pint == &softn->ipf_nat_rdrrules_sz) {
+ old = &softn->ipf_nat_rdr_rules;
+ mask = NAT_REDIRECT;
+ } else {
+ old = &softn->ipf_nat_map_rules;
+ mask = NAT_MAP|NAT_MAPBLK;
+ }
+
+ KMALLOCS(newtab, ipnat_t **, newsize * sizeof(ipnat_t *));
+ if (newtab == NULL) {
+ IPFERROR(60067);
+ return ENOMEM;
+ }
+
+ bzero((char *)newtab, newsize * sizeof(ipnat_t *));
+
+ WRITE_ENTER(&softc->ipf_nat);
+
+ if (*old != NULL) {
+ KFREES(*old, *t->ipft_pint * sizeof(ipnat_t **));
+ }
+ *old = newtab;
+ *t->ipft_pint = newsize;
+
+ for (np = softn->ipf_nat_list; np != NULL; np = np->in_next) {
+ if ((np->in_redir & mask) == 0)
+ continue;
+
+ if (np->in_redir & NAT_REDIRECT) {
+ np->in_rnext = NULL;
+ hv = np->in_hv[0] % newsize;
+ for (npp = newtab + hv; *npp != NULL; )
+ npp = &(*npp)->in_rnext;
+ np->in_prnext = npp;
+ *npp = np;
+ }
+ if (np->in_redir & NAT_MAP) {
+ np->in_mnext = NULL;
+ hv = np->in_hv[1] % newsize;
+ for (npp = newtab + hv; *npp != NULL; )
+ npp = &(*npp)->in_mnext;
+ np->in_pmnext = npp;
+ *npp = np;
+ }
+
+ }
+ RWLOCK_EXIT(&softc->ipf_nat);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_hostmap_rehash */
+/* Returns: int - 0 = success, else failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* t(I) - pointer to tunable */
+/* p(I) - pointer to new tuning data */
+/* */
+/* Allocate and populate a new hash table that will contain a reference to */
+/* all of the active IP# translations currently in place. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat_hostmap_rehash(softc, t, p)
+ ipf_main_softc_t *softc;
+ ipftuneable_t *t;
+ ipftuneval_t *p;
+{
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ hostmap_t *hm, **newtab;
+ u_int newsize;
+ u_int hv;
+
+ newsize = p->ipftu_int;
+ /*
+ * In case there is nothing to do...
+ */
+ if (newsize == *t->ipft_pint)
+ return 0;
+
+ KMALLOCS(newtab, hostmap_t **, newsize * sizeof(hostmap_t *));
+ if (newtab == NULL) {
+ IPFERROR(60068);
+ return ENOMEM;
+ }
+
+ bzero((char *)newtab, newsize * sizeof(hostmap_t *));
+
+ WRITE_ENTER(&softc->ipf_nat);
+ if (softn->ipf_hm_maptable != NULL) {
+ KFREES(softn->ipf_hm_maptable,
+ softn->ipf_nat_hostmap_sz * sizeof(hostmap_t *));
+ }
+ softn->ipf_hm_maptable = newtab;
+ softn->ipf_nat_hostmap_sz = newsize;
+
+ for (hm = softn->ipf_hm_maplist; hm != NULL; hm = hm->hm_next) {
+ hv = hm->hm_hv % softn->ipf_nat_hostmap_sz;
+ hm->hm_hnext = softn->ipf_hm_maptable[hv];
+ hm->hm_phnext = softn->ipf_hm_maptable + hv;
+ if (softn->ipf_hm_maptable[hv] != NULL)
+ softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
+ softn->ipf_hm_maptable[hv] = hm;
+ }
+ RWLOCK_EXIT(&softc->ipf_nat);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_add_tq */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* ------------------------------------------------------------------------ */
+ipftq_t *
+ipf_nat_add_tq(softc, ttl)
+ ipf_main_softc_t *softc;
+ int ttl;
+{
+ ipf_nat_softc_t *softs = softc->ipf_nat_soft;
+
+ return ipf_addtimeoutqueue(softc, &softs->ipf_nat_utqe, ttl);
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_uncreate */
+/* Returns: Nil */
+/* Parameters: fin(I) - pointer to packet information */
+/* */
+/* This function is used to remove a NAT entry from the NAT table when we */
+/* decide that the create was actually in error. It is thus assumed that */
+/* fin_flx will have both FI_NATED and FI_NATNEW set. Because we're dealing */
+/* with the translated packet (not the original), we have to reverse the */
+/* lookup. Although doing the lookup is expensive (relatively speaking), it */
+/* is not anticipated that this will be a frequent occurance for normal */
+/* traffic patterns. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_nat_uncreate(fin)
+ fr_info_t *fin;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ int nflags;
+ nat_t *nat;
+
+ switch (fin->fin_p)
+ {
+ case IPPROTO_TCP :
+ nflags = IPN_TCP;
+ break;
+ case IPPROTO_UDP :
+ nflags = IPN_UDP;
+ break;
+ default :
+ nflags = 0;
+ break;
+ }
+
+ WRITE_ENTER(&softc->ipf_nat);
+
+ if (fin->fin_out == 0) {
+ nat = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p,
+ fin->fin_dst, fin->fin_src);
+ } else {
+ nat = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p,
+ fin->fin_src, fin->fin_dst);
+ }
+
+ if (nat != NULL) {
+ NBUMPSIDE(fin->fin_out, ns_uncreate[0]);
+ ipf_nat_delete(softc, nat, NL_DESTROY);
+ } else {
+ NBUMPSIDE(fin->fin_out, ns_uncreate[1]);
+ }
+
+ RWLOCK_EXIT(&softc->ipf_nat);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_cmp_rules */
+/* Returns: int - 0 == success, else rules do not match. */
+/* Parameters: n1(I) - first rule to compare */
+/* n2(I) - first rule to compare */
+/* */
+/* Compare two rules using pointers to each rule. A straight bcmp will not */
+/* work as some fields (such as in_dst, in_pkts) actually do change once */
+/* the rule has been loaded into the kernel. Whilst this function returns */
+/* various non-zero returns, they're strictly to aid in debugging. Use of */
+/* this function should simply care if the result is zero or not. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_cmp_rules(n1, n2)
+ ipnat_t *n1, *n2;
+{
+ if (n1->in_size != n2->in_size)
+ return 1;
+
+ if (bcmp((char *)&n1->in_v, (char *)&n2->in_v,
+ offsetof(ipnat_t, in_ndst) - offsetof(ipnat_t, in_v)) != 0)
+ return 2;
+
+ if (bcmp((char *)&n1->in_tuc, (char *)&n2->in_tuc,
+ n1->in_size - offsetof(ipnat_t, in_tuc)) != 0)
+ return 3;
+ if (n1->in_ndst.na_atype != n2->in_ndst.na_atype)
+ return 5;
+ if (n1->in_ndst.na_function != n2->in_ndst.na_function)
+ return 6;
+ if (bcmp((char *)&n1->in_ndst.na_addr, (char *)&n2->in_ndst.na_addr,
+ sizeof(n1->in_ndst.na_addr)))
+ return 7;
+ if (n1->in_nsrc.na_atype != n2->in_nsrc.na_atype)
+ return 8;
+ if (n1->in_nsrc.na_function != n2->in_nsrc.na_function)
+ return 9;
+ if (bcmp((char *)&n1->in_nsrc.na_addr, (char *)&n2->in_nsrc.na_addr,
+ sizeof(n1->in_nsrc.na_addr)))
+ return 10;
+ if (n1->in_odst.na_atype != n2->in_odst.na_atype)
+ return 11;
+ if (n1->in_odst.na_function != n2->in_odst.na_function)
+ return 12;
+ if (bcmp((char *)&n1->in_odst.na_addr, (char *)&n2->in_odst.na_addr,
+ sizeof(n1->in_odst.na_addr)))
+ return 13;
+ if (n1->in_osrc.na_atype != n2->in_osrc.na_atype)
+ return 14;
+ if (n1->in_osrc.na_function != n2->in_osrc.na_function)
+ return 15;
+ if (bcmp((char *)&n1->in_osrc.na_addr, (char *)&n2->in_osrc.na_addr,
+ sizeof(n1->in_osrc.na_addr)))
+ return 16;
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_rule_init */
+/* Returns: int - 0 == success, else rules do not match. */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softn(I) - pointer to NAT context structure */
+/* n(I) - first rule to compare */
+/* */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat_rule_init(softc, softn, n)
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
+ ipnat_t *n;
+{
+ int error = 0;
+
+ if ((n->in_flags & IPN_SIPRANGE) != 0)
+ n->in_nsrcatype = FRI_RANGE;
+
+ if ((n->in_flags & IPN_DIPRANGE) != 0)
+ n->in_ndstatype = FRI_RANGE;
+
+ if ((n->in_flags & IPN_SPLIT) != 0)
+ n->in_ndstatype = FRI_SPLIT;
+
+ if ((n->in_redir & (NAT_MAP|NAT_REWRITE|NAT_DIVERTUDP)) != 0)
+ n->in_spnext = n->in_spmin;
+
+ if ((n->in_redir & (NAT_REWRITE|NAT_DIVERTUDP)) != 0) {
+ n->in_dpnext = n->in_dpmin;
+ } else if (n->in_redir == NAT_REDIRECT) {
+ n->in_dpnext = n->in_dpmin;
+ }
+
+ n->in_stepnext = 0;
+
+ switch (n->in_v[0])
+ {
+ case 4 :
+ error = ipf_nat_ruleaddrinit(softc, softn, n);
+ if (error != 0)
+ return error;
+ break;
+#ifdef USE_INET6
+ case 6 :
+ error = ipf_nat6_ruleaddrinit(softc, softn, n);
+ if (error != 0)
+ return error;
+ break;
+#endif
+ default :
+ break;
+ }
+
+ if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) {
+ /*
+ * Prerecord whether or not the destination of the divert
+ * is local or not to the interface the packet is going
+ * to be sent out.
+ */
+ n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1],
+ n->in_ifps[1], &n->in_ndstip6);
+ }
+
+ return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat_rule_fini */
+/* Returns: int - 0 == success, else rules do not match. */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* n(I) - rule to work on */
+/* */
+/* This function is used to release any objects that were referenced during */
+/* the rule initialisation. This is useful both when free'ing the rule and */
+/* when handling ioctls that need to initialise these fields but not */
+/* actually use them after the ioctl processing has finished. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_nat_rule_fini(softc, n)
+ ipf_main_softc_t *softc;
+ ipnat_t *n;
+{
+ if (n->in_odst.na_atype == FRI_LOOKUP && n->in_odst.na_ptr != NULL)
+ ipf_lookup_deref(softc, n->in_odst.na_type, n->in_odst.na_ptr);
+
+ if (n->in_osrc.na_atype == FRI_LOOKUP && n->in_osrc.na_ptr != NULL)
+ ipf_lookup_deref(softc, n->in_osrc.na_type, n->in_osrc.na_ptr);
+
+ if (n->in_ndst.na_atype == FRI_LOOKUP && n->in_ndst.na_ptr != NULL)
+ ipf_lookup_deref(softc, n->in_ndst.na_type, n->in_ndst.na_ptr);
+
+ if (n->in_nsrc.na_atype == FRI_LOOKUP && n->in_nsrc.na_ptr != NULL)
+ ipf_lookup_deref(softc, n->in_nsrc.na_type, n->in_nsrc.na_ptr);
+
+ if (n->in_divmp != NULL)
+ FREE_MB_T(n->in_divmp);
+}
diff --git a/sys/contrib/ipfilter/netinet/ip_nat.h b/sys/contrib/ipfilter/netinet/ip_nat.h
index c8581ef..a57bf0c 100644
--- a/sys/contrib/ipfilter/netinet/ip_nat.h
+++ b/sys/contrib/ipfilter/netinet/ip_nat.h
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1995-2001, 2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
@@ -22,11 +22,13 @@
#define SIOCRMNAT _IOW('r', 61, struct ipfobj)
#define SIOCGNATS _IOWR('r', 62, struct ipfobj)
#define SIOCGNATL _IOWR('r', 63, struct ipfobj)
+#define SIOCPURGENAT _IOWR('r', 100, struct ipfobj)
#else
#define SIOCADNAT _IOW(r, 60, struct ipfobj)
#define SIOCRMNAT _IOW(r, 61, struct ipfobj)
#define SIOCGNATS _IOWR(r, 62, struct ipfobj)
#define SIOCGNATL _IOWR(r, 63, struct ipfobj)
+#define SIOCPURGENAT _IOWR(r, 100, struct ipfobj)
#endif
#undef LARGE_NAT /* define this if you're setting up a system to NAT
@@ -78,13 +80,18 @@
#ifndef APR_LABELLEN
#define APR_LABELLEN 16
#endif
-#define NAT_HW_CKSUM 0x80000000
+#define NAT_HW_CKSUM 0x80000000
+#define NAT_HW_CKSUM_PART 0x40000000
#define DEF_NAT_AGE 1200 /* 10 minutes (600 seconds) */
struct ipstate;
struct ap_session;
+/*
+ * This structure is used in the active NAT table and represents an
+ * active NAT session.
+ */
typedef struct nat {
ipfmutex_t nat_lock;
struct nat *nat_next;
@@ -101,13 +108,15 @@ typedef struct nat {
void *nat_ifps[2];
void *nat_sync;
ipftqent_t nat_tqe;
+ int nat_mtu[2];
u_32_t nat_flags;
u_32_t nat_sumd[2]; /* ip checksum delta for data segment*/
u_32_t nat_ipsumd; /* ip checksum delta for ip header */
u_32_t nat_mssclamp; /* if != zero clamp MSS to this */
- i6addr_t nat_inip6;
- i6addr_t nat_outip6;
- i6addr_t nat_oip6; /* other ip */
+ i6addr_t nat_odst6;
+ i6addr_t nat_osrc6;
+ i6addr_t nat_ndst6;
+ i6addr_t nat_nsrc6;
U_QUAD_T nat_pkts[2];
U_QUAD_T nat_bytes[2];
union {
@@ -115,28 +124,37 @@ typedef struct nat {
tcpinfo_t nat_unt;
icmpinfo_t nat_uni;
greinfo_t nat_ugre;
- } nat_un;
- u_short nat_oport; /* other port */
- u_short nat_use;
- u_char nat_p; /* protocol for NAT */
+ } nat_unold, nat_unnew;
+ int nat_use;
+ int nat_pr[2]; /* protocol for NAT */
int nat_dir;
int nat_ref; /* reference count */
- int nat_hv[2];
+ u_int nat_hv[2];
char nat_ifnames[2][LIFNAMSIZ];
int nat_rev; /* 0 = forward, 1 = reverse */
- int nat_redir; /* copy of in_redir */
- u_32_t nat_seqnext[2];
+ int nat_dlocal;
+ int nat_v[2]; /* 0 = old, 1 = new */
+ u_int nat_redir; /* copy of in_redir */
} nat_t;
-#define nat_inip nat_inip6.in4
-#define nat_outip nat_outip6.in4
-#define nat_oip nat_oip6.in4
+#define nat_osrcip nat_osrc6.in4
+#define nat_odstip nat_odst6.in4
+#define nat_nsrcip nat_nsrc6.in4
+#define nat_ndstip nat_ndst6.in4
+#define nat_osrcaddr nat_osrc6.in4.s_addr
+#define nat_odstaddr nat_odst6.in4.s_addr
+#define nat_nsrcaddr nat_nsrc6.in4.s_addr
+#define nat_ndstaddr nat_ndst6.in4.s_addr
#define nat_age nat_tqe.tqe_die
-#define nat_inport nat_un.nat_unt.ts_sport
-#define nat_outport nat_un.nat_unt.ts_dport
-#define nat_type nat_un.nat_uni.ici_type
-#define nat_seq nat_un.nat_uni.ici_seq
-#define nat_id nat_un.nat_uni.ici_id
+#define nat_osport nat_unold.nat_unt.ts_sport
+#define nat_odport nat_unold.nat_unt.ts_dport
+#define nat_nsport nat_unnew.nat_unt.ts_sport
+#define nat_ndport nat_unnew.nat_unt.ts_dport
+#define nat_oicmpid nat_unold.nat_uni.ici_id
+#define nat_nicmpid nat_unnew.nat_uni.ici_id
+#define nat_type nat_unold.nat_uni.ici_type
+#define nat_oseq nat_unold.nat_uni.ici_seq
+#define nat_nseq nat_unnew.nat_uni.ici_seq
#define nat_tcpstate nat_tqe.tqe_state
#define nat_die nat_tqe.tqe_die
#define nat_touched nat_tqe.tqe_touched
@@ -146,6 +164,10 @@ typedef struct nat {
*/
#define NAT_INBOUND 0
#define NAT_OUTBOUND 1
+#define NAT_ENCAPIN 2
+#define NAT_ENCAPOUT 3
+#define NAT_DIVERTIN 4
+#define NAT_DIVERTOUT 5
/*
* Definitions for nat_flags
@@ -174,9 +196,29 @@ typedef struct nat {
#define NAT_DEBUG 0x800000
+typedef struct nat_addr_s {
+ i6addr_t na_addr[2];
+ i6addr_t na_nextaddr;
+ int na_atype;
+ int na_function;
+} nat_addr_t;
+
+#define na_nextip na_nextaddr.in4.s_addr
+#define na_nextip6 na_nextaddr.in6
+#define na_num na_addr[0].iplookupnum
+#define na_type na_addr[0].iplookuptype
+#define na_subtype na_addr[0].iplookupsubtype
+#define na_ptr na_addr[1].iplookupptr
+#define na_func na_addr[1].iplookupfunc
+
+
+/*
+ * This structure represents an actual NAT rule, loaded by ipnat.
+ */
typedef struct ipnat {
ipfmutex_t in_lock;
struct ipnat *in_next; /* NAT rule list next */
+ struct ipnat **in_pnext; /* prior rdr next ptr */
struct ipnat *in_rnext; /* rdr rule hash next */
struct ipnat **in_prnext; /* prior rdr next ptr */
struct ipnat *in_mnext; /* map rule hash next */
@@ -185,49 +227,114 @@ typedef struct ipnat {
void *in_ifps[2];
void *in_apr;
char *in_comment;
- i6addr_t in_next6;
+ mb_t *in_divmp;
+ void *in_pconf;
+ U_QUAD_T in_pkts[2];
+ U_QUAD_T in_bytes[2];
u_long in_space;
u_long in_hits;
- u_int in_use;
- u_int in_hv;
+ int in_size;
+ int in_use;
+ u_int in_hv[2];
int in_flineno; /* conf. file line number */
- u_short in_pnext;
- u_char in_v;
- u_char in_xxx;
+ int in_stepnext;
+ int in_dlocal;
+ u_short in_dpnext;
+ u_short in_spnext;
/* From here to the end is covered by IPN_CMPSIZ */
+ u_char in_v[2]; /* 0 = old, 1 = new */
u_32_t in_flags;
u_32_t in_mssclamp; /* if != 0 clamp MSS to this */
u_int in_age[2];
int in_redir; /* see below for values */
- int in_p; /* protocol. */
- i6addr_t in_in[2];
- i6addr_t in_out[2];
- i6addr_t in_src[2];
+ int in_pr[2]; /* protocol. */
+ nat_addr_t in_ndst;
+ nat_addr_t in_nsrc;
+ nat_addr_t in_osrc;
+ nat_addr_t in_odst;
frtuc_t in_tuc;
- u_short in_port[2];
u_short in_ppip; /* ports per IP. */
u_short in_ippip; /* IP #'s per IP# */
- char in_ifnames[2][LIFNAMSIZ];
- char in_plabel[APR_LABELLEN]; /* proxy label. */
+ u_short in_ndports[2];
+ u_short in_nsports[2];
+ int in_ifnames[2];
+ int in_plabel; /* proxy label. */
+ int in_pconfig; /* proxy label. */
ipftag_t in_tag;
+ int in_namelen;
+ char in_names[1];
} ipnat_t;
-#define in_pmin in_port[0] /* Also holds static redir port */
-#define in_pmax in_port[1]
-#define in_nextip in_next6.in4
-#define in_nip in_next6.in4.s_addr
-#define in_inip in_in[0].in4.s_addr
-#define in_inmsk in_in[1].in4.s_addr
-#define in_outip in_out[0].in4.s_addr
-#define in_outmsk in_out[1].in4.s_addr
-#define in_srcip in_src[0].in4.s_addr
-#define in_srcmsk in_src[1].in4.s_addr
+/*
+ * MAP-IN MAP-OUT RDR-IN RDR-OUT
+ * osrc X == src == src X
+ * odst X == dst == dst X
+ * nsrc == dst X X == dst
+ * ndst == src X X == src
+ */
+#define in_dpmin in_ndports[0] /* Also holds static redir port */
+#define in_dpmax in_ndports[1]
+#define in_spmin in_nsports[0] /* Also holds static redir port */
+#define in_spmax in_nsports[1]
+#define in_ndport in_ndports[0]
+#define in_nsport in_nsports[0]
+#define in_dipnext in_ndst.na_nextaddr.in4
+#define in_dipnext6 in_ndst.na_nextaddr
+#define in_dnip in_ndst.na_nextaddr.in4.s_addr
+#define in_dnip6 in_ndst.na_nextaddr
+#define in_sipnext in_nsrc.na_nextaddr.in4
+#define in_snip in_nsrc.na_nextaddr.in4.s_addr
+#define in_snip6 in_nsrc.na_nextaddr
+#define in_odstip in_odst.na_addr[0].in4
+#define in_odstip6 in_odst.na_addr[0]
+#define in_odstaddr in_odst.na_addr[0].in4.s_addr
+#define in_odstmsk in_odst.na_addr[1].in4.s_addr
+#define in_odstmsk6 in_odst.na_addr[1]
+#define in_odstatype in_odst.na_atype
+#define in_osrcip in_osrc.na_addr[0].in4
+#define in_osrcip6 in_osrc.na_addr[0]
+#define in_osrcaddr in_osrc.na_addr[0].in4.s_addr
+#define in_osrcmsk in_osrc.na_addr[1].in4.s_addr
+#define in_osrcmsk6 in_osrc.na_addr[1]
+#define in_osrcatype in_osrc.na_atype
+#define in_ndstip in_ndst.na_addr[0].in4
+#define in_ndstip6 in_ndst.na_addr[0]
+#define in_ndstaddr in_ndst.na_addr[0].in4.s_addr
+#define in_ndstmsk in_ndst.na_addr[1].in4.s_addr
+#define in_ndstmsk6 in_ndst.na_addr[1]
+#define in_ndstatype in_ndst.na_atype
+#define in_ndstafunc in_ndst.na_function
+#define in_nsrcip in_nsrc.na_addr[0].in4
+#define in_nsrcip6 in_nsrc.na_addr[0]
+#define in_nsrcaddr in_nsrc.na_addr[0].in4.s_addr
+#define in_nsrcmsk in_nsrc.na_addr[1].in4.s_addr
+#define in_nsrcmsk6 in_nsrc.na_addr[1]
+#define in_nsrcatype in_nsrc.na_atype
+#define in_nsrcafunc in_nsrc.na_function
#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 in_osport in_tuc.ftu_sport
+#define in_odport in_tuc.ftu_dport
+#define in_ndstnum in_ndst.na_addr[0].iplookupnum
+#define in_ndsttype in_ndst.na_addr[0].iplookuptype
+#define in_ndstptr in_ndst.na_addr[1].iplookupptr
+#define in_ndstfunc in_ndst.na_addr[1].iplookupfunc
+#define in_nsrcnum in_nsrc.na_addr[0].iplookupnum
+#define in_nsrctype in_nsrc.na_addr[0].iplookuptype
+#define in_nsrcptr in_nsrc.na_addr[1].iplookupptr
+#define in_nsrcfunc in_nsrc.na_addr[1].iplookupfunc
+#define in_odstnum in_odst.na_addr[0].iplookupnum
+#define in_odsttype in_odst.na_addr[0].iplookuptype
+#define in_odstptr in_odst.na_addr[1].iplookupptr
+#define in_odstfunc in_odst.na_addr[1].iplookupfunc
+#define in_osrcnum in_osrc.na_addr[0].iplookupnum
+#define in_osrctype in_osrc.na_addr[0].iplookuptype
+#define in_osrcptr in_osrc.na_addr[1].iplookupptr
+#define in_osrcfunc in_osrc.na_addr[1].iplookupfunc
+#define in_icmpidmin in_nsports[0]
+#define in_icmpidmax in_nsports[1]
/*
* Bit definitions for in_flags
@@ -242,25 +349,30 @@ typedef struct ipnat {
#define IPN_TCPUDPICMPQ (IPN_TCP|IPN_UDP|IPN_ICMPQUERY)
#define IPN_RF (IPN_TCPUDP|IPN_DELETE|IPN_ICMPERR)
#define IPN_AUTOPORTMAP 0x00010
-#define IPN_IPRANGE 0x00020
-#define IPN_FILTER 0x00040
-#define IPN_SPLIT 0x00080
-#define IPN_ROUNDR 0x00100
-#define IPN_NOTSRC 0x04000
-#define IPN_NOTDST 0x08000
-#define IPN_DYNSRCIP 0x10000 /* dynamic src IP# */
-#define IPN_DYNDSTIP 0x20000 /* dynamic dst IP# */
-#define IPN_DELETE 0x40000
-#define IPN_STICKY 0x80000
-#define IPN_FRAG 0x100000
-#define IPN_FIXEDDPORT 0x200000
-#define IPN_FINDFORWARD 0x400000
-#define IPN_IN 0x800000
-#define IPN_SEQUENTIAL 0x1000000
-#define IPN_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_IPRANGE|IPN_SPLIT|\
- IPN_ROUNDR|IPN_FILTER|IPN_NOTSRC|IPN_NOTDST|\
+#define IPN_FILTER 0x00020
+#define IPN_SPLIT 0x00040
+#define IPN_ROUNDR 0x00080
+#define IPN_SIPRANGE 0x00100
+#define IPN_DIPRANGE 0x00200
+#define IPN_NOTSRC 0x00400
+#define IPN_NOTDST 0x00800
+#define IPN_NO 0x01000
+#define IPN_DYNSRCIP 0x02000 /* dynamic src IP# */
+#define IPN_DYNDSTIP 0x04000 /* dynamic dst IP# */
+#define IPN_DELETE 0x08000
+#define IPN_STICKY 0x10000
+#define IPN_FRAG 0x20000
+#define IPN_FIXEDSPORT 0x40000
+#define IPN_FIXEDDPORT 0x80000
+#define IPN_FINDFORWARD 0x100000
+#define IPN_IN 0x200000
+#define IPN_SEQUENTIAL 0x400000
+#define IPN_PURGE 0x800000
+#define IPN_PROXYRULE 0x1000000
+#define IPN_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_SIPRANGE|IPN_SPLIT|\
+ IPN_ROUNDR|IPN_FILTER|IPN_NOTSRC|IPN_NOTDST|IPN_NO|\
IPN_FRAG|IPN_STICKY|IPN_FIXEDDPORT|IPN_ICMPQUERY|\
- IPN_SEQUENTIAL)
+ IPN_DIPRANGE|IPN_SEQUENTIAL|IPN_PURGE)
/*
* Values for in_redir
@@ -269,22 +381,33 @@ typedef struct ipnat {
#define NAT_REDIRECT 0x02
#define NAT_BIMAP (NAT_MAP|NAT_REDIRECT)
#define NAT_MAPBLK 0x04
+#define NAT_REWRITE 0x08
+#define NAT_ENCAP 0x10
+#define NAT_DIVERTUDP 0x20
#define MAPBLK_MINPORT 1024 /* don't use reserved ports for src port */
#define USABLE_PORTS (65536 - MAPBLK_MINPORT)
-#define IPN_CMPSIZ (sizeof(ipnat_t) - offsetof(ipnat_t, in_flags))
+#define IPN_CMPSIZ (sizeof(ipnat_t) - offsetof(ipnat_t, in_v))
typedef struct natlookup {
- struct in_addr nl_inip;
- struct in_addr nl_outip;
- struct in_addr nl_realip;
- int nl_flags;
- u_short nl_inport;
- u_short nl_outport;
- u_short nl_realport;
+ i6addr_t nl_inipaddr;
+ i6addr_t nl_outipaddr;
+ i6addr_t nl_realipaddr;
+ int nl_v;
+ int nl_flags;
+ u_short nl_inport;
+ u_short nl_outport;
+ u_short nl_realport;
} natlookup_t;
+#define nl_inip nl_inipaddr.in4
+#define nl_outip nl_outipaddr.in4
+#define nl_realip nl_realipaddr.in4
+#define nl_inip6 nl_inipaddr.in6
+#define nl_outip6 nl_outipaddr.in6
+#define nl_realip6 nl_realipaddr.in6
+
typedef struct nat_save {
void *ipn_next;
@@ -315,13 +438,25 @@ typedef struct hostmap {
struct hostmap *hm_next;
struct hostmap **hm_pnext;
struct ipnat *hm_ipnat;
- struct in_addr hm_srcip;
- struct in_addr hm_dstip;
- struct in_addr hm_mapip;
+ i6addr_t hm_osrcip6;
+ i6addr_t hm_odstip6;
+ i6addr_t hm_nsrcip6;
+ i6addr_t hm_ndstip6;
u_32_t hm_port;
int hm_ref;
+ int hm_hv;
+ int hm_v;
} hostmap_t;
+#define hm_osrcip hm_osrcip6.in4
+#define hm_odstip hm_odstip6.in4
+#define hm_nsrcip hm_nsrcip6.in4
+#define hm_ndstip hm_ndstip6.in4
+#define hm_osrc6 hm_osrcip6.in6
+#define hm_odst6 hm_odstip6.in6
+#define hm_nsrc6 hm_nsrcip6.in6
+#define hm_ndst6 hm_ndstip6.in6
+
/*
* Structure used to pass information in to nat_newmap and nat_newrdr.
@@ -330,9 +465,7 @@ typedef struct natinfo {
ipnat_t *nai_np;
u_32_t nai_sum1;
u_32_t nai_sum2;
- u_32_t nai_nflags;
- u_32_t nai_flags;
- struct in_addr nai_ip;
+ struct in_addr nai_ip; /* In host byte order */
u_short nai_port;
u_short nai_nport;
u_short nai_sport;
@@ -340,62 +473,134 @@ typedef struct natinfo {
} natinfo_t;
-typedef struct natstat {
- u_long ns_mapped[2];
- u_long ns_rules;
+typedef struct nat_stat_side {
+ u_int *ns_bucketlen;
+ nat_t **ns_table;
u_long ns_added;
- u_long ns_expire;
+ u_long ns_appr_fail;
+ u_long ns_badnat;
+ u_long ns_badnatnew;
+ u_long ns_badnextaddr;
+ u_long ns_bucket_max;
+ u_long ns_clone_nomem;
+ u_long ns_decap_bad;
+ u_long ns_decap_fail;
+ u_long ns_decap_pullup;
+ u_long ns_divert_dup;
+ u_long ns_divert_exist;
+ u_long ns_drop;
+ u_long ns_encap_dup;
+ u_long ns_encap_pullup;
+ u_long ns_exhausted;
+ u_long ns_icmp_address;
+ u_long ns_icmp_basic;
+ u_long ns_icmp_mbuf;
+ u_long ns_icmp_notfound;
+ u_long ns_icmp_rebuild;
+ u_long ns_icmp_short;
+ u_long ns_icmp_size;
+ u_long ns_ifpaddrfail;
+ u_long ns_ignored;
+ u_long ns_insert_fail;
u_long ns_inuse;
- u_long ns_logged;
- u_long ns_logfail;
+ u_long ns_log;
+ u_long ns_lookup_miss;
+ u_long ns_lookup_nowild;
+ u_long ns_new_ifpaddr;
u_long ns_memfail;
- u_long ns_badnat;
- u_long ns_addtrpnt;
- nat_t **ns_table[2];
- hostmap_t **ns_maptable;
- ipnat_t *ns_list;
- void *ns_apslist;
- u_int ns_wilds;
- u_int ns_nattab_sz;
- u_int ns_nattab_max;
- u_int ns_rultab_sz;
- u_int ns_rdrtab_sz;
- u_int ns_trpntab_sz;
- u_int ns_hostmap_sz;
- nat_t *ns_instances;
- hostmap_t *ns_maplist;
- u_long *ns_bucketlen[2];
- u_long ns_ticks;
- u_int ns_orphans;
+ u_long ns_table_max;
+ u_long ns_translated;
+ u_long ns_unfinalised;
+ u_long ns_wrap;
+ u_long ns_xlate_null;
+ u_long ns_xlate_exists;
+ u_long ns_ipf_proxy_fail;
+ u_long ns_uncreate[2];
+} nat_stat_side_t;
+
+
+typedef struct natstat {
+ nat_t *ns_instances;
+ ipnat_t *ns_list;
+ hostmap_t *ns_maplist;
+ hostmap_t **ns_maptable;
+ u_int ns_active;
+ u_long ns_addtrpnt;
+ u_long ns_divert_build;
+ u_long ns_expire;
+ u_long ns_flush_all;
+ u_long ns_flush_closing;
+ u_long ns_flush_queue;
+ u_long ns_flush_state;
+ u_long ns_flush_timeout;
+ u_long ns_hm_new;
+ u_long ns_hm_newfail;
+ u_long ns_hm_addref;
+ u_long ns_hm_nullnp;
+ u_long ns_log_ok;
+ u_long ns_log_fail;
+ u_int ns_hostmap_sz;
+ u_int ns_nattab_sz;
+ u_int ns_nattab_max;
+ u_int ns_orphans;
+ u_int ns_rules;
+ u_int ns_rules_map;
+ u_int ns_rules_rdr;
+ u_int ns_rultab_sz;
+ u_int ns_rdrtab_sz;
+ u_32_t ns_ticks;
+ u_int ns_trpntab_sz;
+ u_int ns_wilds;
+ u_long ns_proto[256];
+ nat_stat_side_t ns_side[2];
+#ifdef USE_INET6
+ nat_stat_side_t ns_side6[2];
+#endif
} natstat_t;
typedef struct natlog {
- struct in_addr nl_origip;
- struct in_addr nl_outip;
- struct in_addr nl_inip;
- u_short nl_origport;
- u_short nl_outport;
- u_short nl_inport;
- u_short nl_type;
- int nl_rule;
+ i6addr_t nl_osrcip;
+ i6addr_t nl_odstip;
+ i6addr_t nl_nsrcip;
+ i6addr_t nl_ndstip;
+ u_short nl_osrcport;
+ u_short nl_odstport;
+ u_short nl_nsrcport;
+ u_short nl_ndstport;
+ int nl_action;
+ int nl_type;
+ int nl_rule;
U_QUAD_T nl_pkts[2];
U_QUAD_T nl_bytes[2];
- u_char nl_p;
+ u_char nl_p[2];
+ u_char nl_v[2];
+ u_char nl_ifnames[2][LIFNAMSIZ];
} natlog_t;
-#define NL_NEWMAP NAT_MAP
-#define NL_NEWRDR NAT_REDIRECT
-#define NL_NEWBIMAP NAT_BIMAP
-#define NL_NEWBLOCK NAT_MAPBLK
-#define NL_DESTROY 0xfffc
-#define NL_CLONE 0xfffd
+#define NL_NEW 0
+#define NL_CLONE 1
+#define NL_PURGE 0xfffc
+#define NL_DESTROY 0xfffd
#define NL_FLUSH 0xfffe
#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 NAT_HASH_FN(_k,_l,_m) (((_k) + ((_k) >> 12) + _l) % (_m))
+#define NAT_HASH_FN6(_k,_l,_m) ((((u_32_t *)(_k))[3] \
+ + (((u_32_t *)(_k))[3] >> 12) \
+ + (((u_32_t *)(_k))[2]) \
+ + (((u_32_t *)(_k))[2] >> 12) \
+ + (((u_32_t *)(_k))[1]) \
+ + (((u_32_t *)(_k))[1] >> 12) \
+ + (((u_32_t *)(_k))[0]) \
+ + (((u_32_t *)(_k))[0] >> 12) \
+ + _l) % (_m))
+
+#define LONG_SUM(_i) (((_i) & 0xffff) + ((_i) >> 16))
+#define LONG_SUM6(_i) (LONG_SUM(ntohl(((u_32_t *)(_i))[0])) + \
+ LONG_SUM(ntohl(((u_32_t *)(_i))[1])) + \
+ LONG_SUM(ntohl(((u_32_t *)(_i))[2])) + \
+ LONG_SUM(ntohl(((u_32_t *)(_i))[3])))
#define CALC_SUMD(s1, s2, sd) { \
(s1) = ((s1) & 0xffff) + ((s1) >> 16); \
@@ -411,64 +616,159 @@ typedef struct natlog {
#define NAT_SYSSPACE 0x80000000
#define NAT_LOCKHELD 0x40000000
-
-extern u_int ipf_nattable_sz;
-extern u_int ipf_nattable_max;
-extern u_int ipf_natrules_sz;
-extern u_int ipf_rdrrules_sz;
-extern u_int ipf_hostmap_sz;
-extern u_int fr_nat_maxbucket;
-extern u_int fr_nat_maxbucket_reset;
-extern int fr_nat_lock;
-extern int fr_nat_doflush;
-extern void fr_natsync __P((void *));
-extern u_long fr_defnatage;
-extern u_long fr_defnaticmpage;
-extern u_long fr_defnatipage;
- /* nat_table[0] -> hashed list sorted by inside (ip, port) */
- /* nat_table[1] -> hashed list sorted by outside (ip, port) */
-extern nat_t **nat_table[2];
-extern nat_t *nat_instances;
-extern ipnat_t *nat_list;
-extern ipnat_t **nat_rules;
-extern ipnat_t **rdr_rules;
-extern ipftq_t *nat_utqe;
-extern natstat_t nat_stats;
-
+/*
+ * This is present in ip_nat.h because it needs to be shared between
+ * ip_nat.c and ip_nat6.c
+ */
+typedef struct ipf_nat_softc_s {
+ ipfmutex_t ipf_nat_new;
+ ipfmutex_t ipf_nat_io;
+ int ipf_nat_doflush;
+ int ipf_nat_logging;
+ int ipf_nat_lock;
+ int ipf_nat_inited;
+ int ipf_nat_table_wm_high;
+ int ipf_nat_table_wm_low;
+ u_int ipf_nat_table_max;
+ u_int ipf_nat_table_sz;
+ u_int ipf_nat_maprules_sz;
+ u_int ipf_nat_rdrrules_sz;
+ u_int ipf_nat_hostmap_sz;
+ u_int ipf_nat_maxbucket;
+ u_int ipf_nat_last_force_flush;
+ u_int ipf_nat_defage;
+ u_int ipf_nat_defipage;
+ u_int ipf_nat_deficmpage;
+ ipf_v4_masktab_t ipf_nat_map_mask;
+ ipf_v6_masktab_t ipf_nat6_map_mask;
+ ipf_v4_masktab_t ipf_nat_rdr_mask;
+ ipf_v6_masktab_t ipf_nat6_rdr_mask;
+ nat_t **ipf_nat_table[2];
+ nat_t *ipf_nat_instances;
+ ipnat_t *ipf_nat_list;
+ ipnat_t **ipf_nat_list_tail;
+ ipnat_t **ipf_nat_map_rules;
+ ipnat_t **ipf_nat_rdr_rules;
+ ipftq_t *ipf_nat_utqe;
+ hostmap_t **ipf_hm_maptable ;
+ hostmap_t *ipf_hm_maplist ;
+ ipftuneable_t *ipf_nat_tune;
+ ipftq_t ipf_nat_udptq;
+ ipftq_t ipf_nat_udpacktq;
+ ipftq_t ipf_nat_icmptq;
+ ipftq_t ipf_nat_icmpacktq;
+ ipftq_t ipf_nat_iptq;
+ ipftq_t ipf_nat_pending;
+ ipftq_t ipf_nat_tcptq[IPF_TCP_NSTATES];
+ natstat_t ipf_nat_stats;
+} ipf_nat_softc_t ;
+
+#define ipf_nat_map_max ipf_nat_map_mask.imt4_max
+#define ipf_nat_rdr_max ipf_nat_rdr_mask.imt4_max
+#define ipf_nat6_map_max ipf_nat6_map_mask.imt6_max
+#define ipf_nat6_rdr_max ipf_nat6_rdr_mask.imt6_max
+#define ipf_nat_map_active_masks ipf_nat_map_mask.imt4_active
+#define ipf_nat_rdr_active_masks ipf_nat_rdr_mask.imt4_active
+#define ipf_nat6_map_active_masks ipf_nat6_map_mask.imt6_active
+#define ipf_nat6_rdr_active_masks ipf_nat6_rdr_mask.imt6_active
+
+extern frentry_t ipfnatblock;
+
+extern void ipf_fix_datacksum __P((u_short *, u_32_t));
+extern void ipf_fix_incksum __P((int, u_short *, u_32_t, u_32_t));
+extern void ipf_fix_outcksum __P((int, u_short *, u_32_t, u_32_t));
+
+extern int ipf_nat_checkin __P((fr_info_t *, u_32_t *));
+extern int ipf_nat_checkout __P((fr_info_t *, u_32_t *));
+extern void ipf_nat_delete __P((ipf_main_softc_t *, struct nat *, int));
+extern void ipf_nat_deref __P((ipf_main_softc_t *, nat_t **));
+extern void ipf_nat_expire __P((ipf_main_softc_t *));
+extern int ipf_nat_hashtab_add __P((ipf_main_softc_t *,
+ ipf_nat_softc_t *, nat_t *));
+extern void ipf_nat_hostmapdel __P((ipf_main_softc_t *, hostmap_t **));
+extern int ipf_nat_hostmap_rehash __P((ipf_main_softc_t *,
+ ipftuneable_t *, ipftuneval_t *));
+extern nat_t *ipf_nat_icmperrorlookup __P((fr_info_t *, int));
+extern nat_t *ipf_nat_icmperror __P((fr_info_t *, u_int *, int));
#if defined(__OpenBSD__)
-extern void nat_ifdetach __P((void *));
+extern void ipf_nat_ifdetach __P((void *));
#endif
-extern int fr_nat_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *));
-extern int fr_natinit __P((void));
-extern nat_t *nat_new __P((fr_info_t *, ipnat_t *, nat_t **, u_int, int));
-extern nat_t *nat_outlookup __P((fr_info_t *, u_int, u_int, struct in_addr,
- struct in_addr));
-extern void fix_datacksum __P((u_short *, u_32_t));
-extern nat_t *nat_inlookup __P((fr_info_t *, u_int, u_int, struct in_addr,
- struct in_addr));
-extern nat_t *nat_tnlookup __P((fr_info_t *, int));
-extern nat_t *nat_maplookup __P((void *, u_int, struct in_addr,
+extern int ipf_nat_init __P((void));
+extern nat_t *ipf_nat_inlookup __P((fr_info_t *, u_int, u_int,
+ struct in_addr, struct in_addr));
+extern int ipf_nat_in __P((fr_info_t *, nat_t *, int, u_32_t));
+extern int ipf_nat_insert __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+ nat_t *));
+extern int ipf_nat_ioctl __P((ipf_main_softc_t *, caddr_t, ioctlcmd_t,
+ int, int, void *));
+extern void ipf_nat_log __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+ struct nat *, u_int));
+extern nat_t *ipf_nat_lookupredir __P((natlookup_t *));
+extern nat_t *ipf_nat_maplookup __P((void *, u_int, struct in_addr,
struct in_addr));
-extern nat_t *nat_lookupredir __P((natlookup_t *));
-extern nat_t *nat_icmperrorlookup __P((fr_info_t *, int));
-extern nat_t *nat_icmperror __P((fr_info_t *, u_int *, int));
-extern void nat_delete __P((struct nat *, int));
-extern int nat_insert __P((nat_t *, int));
-
-extern int fr_checknatout __P((fr_info_t *, u_32_t *));
-extern int fr_natout __P((fr_info_t *, nat_t *, int, u_32_t));
-extern int fr_checknatin __P((fr_info_t *, u_32_t *));
-extern int fr_natin __P((fr_info_t *, nat_t *, int, u_32_t));
-extern void fr_natunload __P((void));
-extern void fr_natexpire __P((void));
-extern void nat_log __P((struct nat *, u_int));
-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 fr_ipnatderef __P((ipnat_t **));
-extern void fr_natderef __P((nat_t **));
-extern u_short *nat_proto __P((fr_info_t *, nat_t *, u_int));
-extern void nat_update __P((fr_info_t *, nat_t *, ipnat_t *));
-extern void fr_setnatqueue __P((nat_t *, int));
-extern void fr_hostmapdel __P((hostmap_t **));
+extern nat_t *ipf_nat_add __P((fr_info_t *, ipnat_t *, nat_t **,
+ u_int, int));
+extern int ipf_nat_out __P((fr_info_t *, nat_t *, int, u_32_t));
+extern nat_t *ipf_nat_outlookup __P((fr_info_t *, u_int, u_int,
+ struct in_addr, struct in_addr));
+extern u_short *ipf_nat_proto __P((fr_info_t *, nat_t *, u_int));
+extern void ipf_nat_rule_deref __P((ipf_main_softc_t *, ipnat_t **));
+extern void ipf_nat_setqueue __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+ nat_t *));
+extern void ipf_nat_setpending __P((ipf_main_softc_t *, nat_t *));
+extern nat_t *ipf_nat_tnlookup __P((fr_info_t *, int));
+extern void ipf_nat_update __P((fr_info_t *, nat_t *));
+extern int ipf_nat_rehash __P((ipf_main_softc_t *, ipftuneable_t *,
+ ipftuneval_t *));
+extern int ipf_nat_rehash_rules __P((ipf_main_softc_t *, ipftuneable_t *,
+ ipftuneval_t *));
+extern int ipf_nat_settimeout __P((struct ipf_main_softc_s *,
+ ipftuneable_t *, ipftuneval_t *));
+extern void ipf_nat_sync __P((ipf_main_softc_t *, void *));
+
+extern nat_t *ipf_nat_clone __P((fr_info_t *, nat_t *));
+extern void ipf_nat_delmap __P((ipf_nat_softc_t *, ipnat_t *));
+extern void ipf_nat_delrdr __P((ipf_nat_softc_t *, ipnat_t *));
+extern int ipf_nat_wildok __P((nat_t *, int, int, int, int));
+extern void ipf_nat_setlock __P((void *, int));
+extern void ipf_nat_load __P((void));
+extern void *ipf_nat_soft_create __P((ipf_main_softc_t *));
+extern int ipf_nat_soft_init __P((ipf_main_softc_t *, void *));
+extern void ipf_nat_soft_destroy __P((ipf_main_softc_t *, void *));
+extern int ipf_nat_soft_fini __P((ipf_main_softc_t *, void *));
+extern int ipf_nat_main_load __P((void));
+extern int ipf_nat_main_unload __P((void));
+extern ipftq_t *ipf_nat_add_tq __P((ipf_main_softc_t *, int));
+extern void ipf_nat_uncreate __P((fr_info_t *));
+
+#ifdef USE_INET6
+extern nat_t *ipf_nat6_add __P((fr_info_t *, ipnat_t *, nat_t **,
+ u_int, int));
+extern void ipf_nat6_addrdr __P((ipf_nat_softc_t *, ipnat_t *));
+extern void ipf_nat6_addmap __P((ipf_nat_softc_t *, ipnat_t *));
+extern void ipf_nat6_addencap __P((ipf_nat_softc_t *, ipnat_t *));
+extern int ipf_nat6_checkout __P((fr_info_t *, u_32_t *));
+extern int ipf_nat6_checkin __P((fr_info_t *, u_32_t *));
+extern void ipf_nat6_delmap __P((ipf_nat_softc_t *, ipnat_t *));
+extern void ipf_nat6_delrdr __P((ipf_nat_softc_t *, ipnat_t *));
+extern int ipf_nat6_finalise __P((fr_info_t *, nat_t *));
+extern nat_t *ipf_nat6_icmperror __P((fr_info_t *, u_int *, int));
+extern nat_t *ipf_nat6_icmperrorlookup __P((fr_info_t *, int));
+extern nat_t *ipf_nat6_inlookup __P((fr_info_t *, u_int, u_int,
+ struct in6_addr *, struct in6_addr *));
+extern u_32_t ipf_nat6_ip6subtract __P((i6addr_t *, i6addr_t *));
+extern frentry_t *ipf_nat6_ipfin __P((fr_info_t *, u_32_t *));
+extern frentry_t *ipf_nat6_ipfout __P((fr_info_t *, u_32_t *));
+extern nat_t *ipf_nat6_lookupredir __P((natlookup_t *));
+extern int ipf_nat6_newmap __P((fr_info_t *, nat_t *, natinfo_t *));
+extern int ipf_nat6_newrdr __P((fr_info_t *, nat_t *, natinfo_t *));
+extern nat_t *ipf_nat6_outlookup __P((fr_info_t *, u_int, u_int,
+ struct in6_addr *, struct in6_addr *));
+extern int ipf_nat6_newrewrite __P((fr_info_t *, nat_t *, natinfo_t *));
+extern int ipf_nat6_newdivert __P((fr_info_t *, nat_t *, natinfo_t *));
+extern int ipf_nat6_ruleaddrinit __P((ipf_main_softc_t *, ipf_nat_softc_t *, ipnat_t *));
+
+#endif
+
#endif /* __IP_NAT_H__ */
diff --git a/sys/contrib/ipfilter/netinet/ip_nat6.c b/sys/contrib/ipfilter/netinet/ip_nat6.c
new file mode 100644
index 0000000..72931c9
--- /dev/null
+++ b/sys/contrib/ipfilter/netinet/ip_nat6.c
@@ -0,0 +1,4098 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#if defined(KERNEL) || defined(_KERNEL)
+# undef KERNEL
+# undef _KERNEL
+# define KERNEL 1
+# define _KERNEL 1
+#endif
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/file.h>
+#if defined(_KERNEL) && defined(__NetBSD_Version__) && \
+ (__NetBSD_Version__ >= 399002000)
+# include <sys/kauth.h>
+#endif
+#if !defined(_KERNEL)
+# include <stdio.h>
+# include <string.h>
+# include <stdlib.h>
+# define _KERNEL
+# ifdef ipf_nat6__OpenBSD__
+struct file;
+# endif
+# include <sys/uio.h>
+# undef _KERNEL
+#endif
+#if defined(_KERNEL) && (__FreeBSD_version >= 220000)
+# include <sys/filio.h>
+# include <sys/fcntl.h>
+#else
+# include <sys/ioctl.h>
+#endif
+#if !defined(AIX)
+# include <sys/fcntl.h>
+#endif
+#if !defined(linux)
+# include <sys/protosw.h>
+#endif
+#include <sys/socket.h>
+#if defined(_KERNEL)
+# include <sys/systm.h>
+# if !defined(__SVR4) && !defined(__svr4__)
+# include <sys/mbuf.h>
+# endif
+#endif
+#if defined(__SVR4) || defined(__svr4__)
+# include <sys/filio.h>
+# include <sys/byteorder.h>
+# ifdef _KERNEL
+# include <sys/dditypes.h>
+# endif
+# include <sys/stream.h>
+# include <sys/kmem.h>
+#endif
+#if __FreeBSD_version >= 300000
+# include <sys/queue.h>
+#endif
+#include <net/if.h>
+#if __FreeBSD_version >= 300000
+# include <net/if_var.h>
+#endif
+#ifdef sun
+# include <net/af.h>
+#endif
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#ifdef RFC1825
+# include <vpn/md5.h>
+# include <vpn/ipsec.h>
+extern struct ifnet vpnif;
+#endif
+
+#if !defined(linux)
+# include <netinet/ip_var.h>
+#endif
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+#include <netinet/ip_icmp.h>
+#include "netinet/ip_compat.h"
+#include <netinet/tcpip.h>
+#include "netinet/ip_fil.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_frag.h"
+#include "netinet/ip_state.h"
+#include "netinet/ip_proxy.h"
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_dstlist.h"
+#include "netinet/ip_sync.h"
+#if (__FreeBSD_version >= 300000)
+# include <sys/malloc.h>
+#endif
+#ifdef HAS_SYS_MD5_H
+# include <sys/md5.h>
+#else
+# include "md5.h"
+#endif
+/* END OF INCLUDES */
+
+#undef SOCKADDR_IN
+#define SOCKADDR_IN struct sockaddr_in
+
+#if !defined(lint)
+static const char rcsid[] = "@(#)$Id: ip_nat6.c,v 1.22.2.20 2012/07/22 08:04:23 darren_r Exp $";
+#endif
+
+#ifdef USE_INET6
+static struct hostmap *ipf_nat6_hostmap __P((ipf_nat_softc_t *, ipnat_t *,
+ i6addr_t *, i6addr_t *,
+ i6addr_t *, u_32_t));
+static int ipf_nat6_match __P((fr_info_t *, ipnat_t *));
+static void ipf_nat6_tabmove __P((ipf_nat_softc_t *, nat_t *));
+static int ipf_nat6_decap __P((fr_info_t *, nat_t *));
+static int ipf_nat6_nextaddr __P((fr_info_t *, nat_addr_t *, i6addr_t *,
+ i6addr_t *));
+static int ipf_nat6_icmpquerytype __P((int));
+static int ipf_nat6_out __P((fr_info_t *, nat_t *, int, u_32_t));
+static int ipf_nat6_in __P((fr_info_t *, nat_t *, int, u_32_t));
+static int ipf_nat6_builddivertmp __P((ipf_nat_softc_t *, ipnat_t *));
+static int ipf_nat6_nextaddrinit __P((ipf_main_softc_t *, char *,
+ nat_addr_t *, int, void *));
+static int ipf_nat6_insert __P((ipf_main_softc_t *, ipf_nat_softc_t *,
+ nat_t *));
+
+
+#define NINCLSIDE6(y,x) ATOMIC_INCL(softn->ipf_nat_stats.ns_side6[y].x)
+#define NBUMPSIDE(y,x) softn->ipf_nat_stats.ns_side[y].x++
+#define NBUMPSIDE6(y,x) softn->ipf_nat_stats.ns_side6[y].x++
+#define NBUMPSIDE6D(y,x) \
+ do { \
+ softn->ipf_nat_stats.ns_side6[y].x++; \
+ DT(x); \
+ } while (0)
+#define NBUMPSIDE6DX(y,x,z) \
+ do { \
+ softn->ipf_nat_stats.ns_side6[y].x++; \
+ DT(z); \
+ } while (0)
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_ruleaddrinit */
+/* Returns: int - 0 == success, else failure */
+/* Parameters: in(I) - NAT rule that requires address fields to be init'd */
+/* */
+/* For each of the source/destination address fields in a NAT rule, call */
+/* ipf_nat6_nextaddrinit() to prepare the structure for active duty. Other */
+/* IPv6 specific actions can also be taken care of here. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat6_ruleaddrinit(softc, softn, n)
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
+ ipnat_t *n;
+{
+ int idx, error;
+
+ if (n->in_redir == NAT_BIMAP) {
+ n->in_ndstip6 = n->in_osrcip6;
+ n->in_ndstmsk6 = n->in_osrcmsk6;
+ n->in_odstip6 = n->in_nsrcip6;
+ n->in_odstmsk6 = n->in_nsrcmsk6;
+
+ }
+
+ if (n->in_redir & NAT_REDIRECT)
+ idx = 1;
+ else
+ idx = 0;
+ /*
+ * Initialise all of the address fields.
+ */
+ error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_osrc, 1,
+ n->in_ifps[idx]);
+ if (error != 0)
+ return error;
+
+ error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_odst, 1,
+ n->in_ifps[idx]);
+ if (error != 0)
+ return error;
+
+ error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_nsrc, 1,
+ n->in_ifps[idx]);
+ if (error != 0)
+ return error;
+
+ error = ipf_nat6_nextaddrinit(softc, n->in_names, &n->in_ndst, 1,
+ n->in_ifps[idx]);
+ if (error != 0)
+ return error;
+
+ if (n->in_redir & NAT_DIVERTUDP)
+ ipf_nat6_builddivertmp(softn, n);
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_addrdr */
+/* Returns: Nil */
+/* Parameters: n(I) - pointer to NAT rule to add */
+/* */
+/* Adds a redirect rule to the hash table of redirect rules and the list of */
+/* loaded NAT rules. Updates the bitmask indicating which netmasks are in */
+/* use by redirect rules. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_nat6_addrdr(softn, n)
+ ipf_nat_softc_t *softn;
+ ipnat_t *n;
+{
+ i6addr_t *mask;
+ ipnat_t **np;
+ i6addr_t j;
+ u_int hv;
+ int k;
+
+ if ((n->in_redir & NAT_BIMAP) == NAT_BIMAP) {
+ k = count6bits(n->in_nsrcmsk6.i6);
+ mask = &n->in_nsrcmsk6;
+ IP6_AND(&n->in_odstip6, &n->in_odstmsk6, &j);
+ hv = NAT_HASH_FN6(&j, 0, softn->ipf_nat_rdrrules_sz);
+
+ } else if (n->in_odstatype == FRI_NORMAL) {
+ k = count6bits(n->in_odstmsk6.i6);
+ mask = &n->in_odstmsk6;
+ IP6_AND(&n->in_odstip6, &n->in_odstmsk6, &j);
+ hv = NAT_HASH_FN6(&j, 0, softn->ipf_nat_rdrrules_sz);
+ } else {
+ k = 0;
+ hv = 0;
+ mask = NULL;
+ }
+ ipf_inet6_mask_add(k, mask, &softn->ipf_nat6_rdr_mask);
+
+ np = softn->ipf_nat_rdr_rules + hv;
+ while (*np != NULL)
+ np = &(*np)->in_rnext;
+ n->in_rnext = NULL;
+ n->in_prnext = np;
+ n->in_hv[0] = hv;
+ n->in_use++;
+ *np = n;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_addmap */
+/* Returns: Nil */
+/* Parameters: n(I) - pointer to NAT rule to add */
+/* */
+/* Adds a NAT map rule to the hash table of rules and the list of loaded */
+/* NAT rules. Updates the bitmask indicating which netmasks are in use by */
+/* redirect rules. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_nat6_addmap(softn, n)
+ ipf_nat_softc_t *softn;
+ ipnat_t *n;
+{
+ i6addr_t *mask;
+ ipnat_t **np;
+ i6addr_t j;
+ u_int hv;
+ int k;
+
+ if (n->in_osrcatype == FRI_NORMAL) {
+ k = count6bits(n->in_osrcmsk6.i6);
+ mask = &n->in_osrcmsk6;
+ IP6_AND(&n->in_osrcip6, &n->in_osrcmsk6, &j);
+ hv = NAT_HASH_FN6(&j, 0, softn->ipf_nat_maprules_sz);
+ } else {
+ k = 0;
+ hv = 0;
+ mask = NULL;
+ }
+ ipf_inet6_mask_add(k, mask, &softn->ipf_nat6_map_mask);
+
+ np = softn->ipf_nat_map_rules + hv;
+ while (*np != NULL)
+ np = &(*np)->in_mnext;
+ n->in_mnext = NULL;
+ n->in_pmnext = np;
+ n->in_hv[1] = hv;
+ n->in_use++;
+ *np = n;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_del_rdr */
+/* Returns: Nil */
+/* Parameters: n(I) - pointer to NAT rule to delete */
+/* */
+/* Removes a NAT rdr rule from the hash table of NAT rdr rules. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_nat6_delrdr(softn, n)
+ ipf_nat_softc_t *softn;
+ ipnat_t *n;
+{
+ i6addr_t *mask;
+ int k;
+
+ if ((n->in_redir & NAT_BIMAP) == NAT_BIMAP) {
+ k = count6bits(n->in_nsrcmsk6.i6);
+ mask = &n->in_nsrcmsk6;
+ } else if (n->in_odstatype == FRI_NORMAL) {
+ k = count6bits(n->in_odstmsk6.i6);
+ mask = &n->in_odstmsk6;
+ } else {
+ k = 0;
+ mask = NULL;
+ }
+ ipf_inet6_mask_del(k, mask, &softn->ipf_nat6_rdr_mask);
+
+ if (n->in_rnext != NULL)
+ n->in_rnext->in_prnext = n->in_prnext;
+ *n->in_prnext = n->in_rnext;
+ n->in_use--;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_delmap */
+/* Returns: Nil */
+/* Parameters: n(I) - pointer to NAT rule to delete */
+/* */
+/* Removes a NAT map rule from the hash table of NAT map rules. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_nat6_delmap(softn, n)
+ ipf_nat_softc_t *softn;
+ ipnat_t *n;
+{
+ i6addr_t *mask;
+ int k;
+
+ if (n->in_osrcatype == FRI_NORMAL) {
+ k = count6bits(n->in_osrcmsk6.i6);
+ mask = &n->in_osrcmsk6;
+ } else {
+ k = 0;
+ mask = NULL;
+ }
+ ipf_inet6_mask_del(k, mask, &softn->ipf_nat6_map_mask);
+
+ if (n->in_mnext != NULL)
+ n->in_mnext->in_pmnext = n->in_pmnext;
+ *n->in_pmnext = n->in_mnext;
+ n->in_use--;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_hostmap */
+/* Returns: struct hostmap* - NULL if no hostmap could be created, */
+/* else a pointer to the hostmapping to use */
+/* Parameters: np(I) - pointer to NAT rule */
+/* real(I) - real IP address */
+/* map(I) - mapped IP address */
+/* port(I) - destination port number */
+/* Write Locks: ipf_nat */
+/* */
+/* Check if an ip address has already been allocated for a given mapping */
+/* that is not doing port based translation. If is not yet allocated, then */
+/* create a new entry if a non-NULL NAT rule pointer has been supplied. */
+/* ------------------------------------------------------------------------ */
+static struct hostmap *
+ipf_nat6_hostmap(softn, np, src, dst, map, port)
+ ipf_nat_softc_t *softn;
+ ipnat_t *np;
+ i6addr_t *src, *dst, *map;
+ u_32_t port;
+{
+ hostmap_t *hm;
+ u_int hv;
+
+ hv = (src->i6[3] ^ dst->i6[3]);
+ hv += (src->i6[2] ^ dst->i6[2]);
+ hv += (src->i6[1] ^ dst->i6[1]);
+ hv += (src->i6[0] ^ dst->i6[0]);
+ hv += src->i6[3];
+ hv += src->i6[2];
+ hv += src->i6[1];
+ hv += src->i6[0];
+ hv += dst->i6[3];
+ hv += dst->i6[2];
+ hv += dst->i6[1];
+ hv += dst->i6[0];
+ hv %= HOSTMAP_SIZE;
+ for (hm = softn->ipf_hm_maptable[hv]; hm; hm = hm->hm_next)
+ if (IP6_EQ(&hm->hm_osrc6, src) &&
+ IP6_EQ(&hm->hm_odst6, dst) &&
+ ((np == NULL) || (np == hm->hm_ipnat)) &&
+ ((port == 0) || (port == hm->hm_port))) {
+ softn->ipf_nat_stats.ns_hm_addref++;
+ hm->hm_ref++;
+ return hm;
+ }
+
+ if (np == NULL) {
+ softn->ipf_nat_stats.ns_hm_nullnp++;
+ return NULL;
+ }
+
+ KMALLOC(hm, hostmap_t *);
+ if (hm) {
+ hm->hm_next = softn->ipf_hm_maplist;
+ hm->hm_pnext = &softn->ipf_hm_maplist;
+ if (softn->ipf_hm_maplist != NULL)
+ softn->ipf_hm_maplist->hm_pnext = &hm->hm_next;
+ softn->ipf_hm_maplist = hm;
+ hm->hm_hnext = softn->ipf_hm_maptable[hv];
+ hm->hm_phnext = softn->ipf_hm_maptable + hv;
+ if (softn->ipf_hm_maptable[hv] != NULL)
+ softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
+ softn->ipf_hm_maptable[hv] = hm;
+ hm->hm_ipnat = np;
+ np->in_use++;
+ hm->hm_osrcip6 = *src;
+ hm->hm_odstip6 = *dst;
+ hm->hm_nsrcip6 = *map;
+ hm->hm_ndstip6.i6[0] = 0;
+ hm->hm_ndstip6.i6[1] = 0;
+ hm->hm_ndstip6.i6[2] = 0;
+ hm->hm_ndstip6.i6[3] = 0;
+ hm->hm_ref = 1;
+ hm->hm_port = port;
+ hm->hm_hv = hv;
+ hm->hm_v = 6;
+ softn->ipf_nat_stats.ns_hm_new++;
+ } else {
+ softn->ipf_nat_stats.ns_hm_newfail++;
+ }
+ return hm;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_newmap */
+/* Returns: int - -1 == error, 0 == success */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to NAT entry */
+/* ni(I) - pointer to structure with misc. information needed */
+/* to create new NAT entry. */
+/* */
+/* Given an empty NAT structure, populate it with new information about a */
+/* new NAT session, as defined by the matching NAT rule. */
+/* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
+/* to the new IP address for the translation. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat6_newmap(fin, nat, ni)
+ fr_info_t *fin;
+ nat_t *nat;
+ natinfo_t *ni;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ u_short st_port, dport, sport, port, sp, dp;
+ i6addr_t in, st_ip;
+ hostmap_t *hm;
+ u_32_t flags;
+ ipnat_t *np;
+ nat_t *natl;
+ int l;
+
+ /*
+ * If it's an outbound packet which doesn't match any existing
+ * record, then create a new port
+ */
+ l = 0;
+ hm = NULL;
+ np = ni->nai_np;
+ st_ip = np->in_snip6;
+ st_port = np->in_spnext;
+ flags = nat->nat_flags;
+
+ if (flags & IPN_ICMPQUERY) {
+ sport = fin->fin_data[1];
+ dport = 0;
+ } else {
+ sport = htons(fin->fin_data[0]);
+ dport = htons(fin->fin_data[1]);
+ }
+
+ /*
+ * Do a loop until we either run out of entries to try or we find
+ * a NAT mapping that isn't currently being used. This is done
+ * because the change to the source is not (usually) being fixed.
+ */
+ do {
+ port = 0;
+ in = np->in_nsrc.na_nextaddr;
+ if (l == 0) {
+ /*
+ * Check to see if there is an existing NAT
+ * setup for this IP address pair.
+ */
+ hm = ipf_nat6_hostmap(softn, np, &fin->fin_src6,
+ &fin->fin_dst6, &in, 0);
+ if (hm != NULL)
+ in = hm->hm_nsrcip6;
+ } else if ((l == 1) && (hm != NULL)) {
+ ipf_nat_hostmapdel(softc, &hm);
+ }
+
+ nat->nat_hm = hm;
+
+ if (IP6_ISONES(&np->in_nsrcmsk6) && (np->in_spnext == 0)) {
+ if (l > 0) {
+ NBUMPSIDE6DX(1, ns_exhausted, ns_exhausted_1);
+ return -1;
+ }
+ }
+
+ if ((np->in_redir == NAT_BIMAP) &&
+ IP6_EQ(&np->in_osrcmsk6, &np->in_nsrcmsk6)) {
+ i6addr_t temp;
+ /*
+ * map the address block in a 1:1 fashion
+ */
+ temp.i6[0] = fin->fin_src6.i6[0] &
+ ~np->in_osrcmsk6.i6[0];
+ temp.i6[1] = fin->fin_src6.i6[1] &
+ ~np->in_osrcmsk6.i6[1];
+ temp.i6[2] = fin->fin_src6.i6[2] &
+ ~np->in_osrcmsk6.i6[0];
+ temp.i6[3] = fin->fin_src6.i6[3] &
+ ~np->in_osrcmsk6.i6[3];
+ in = np->in_nsrcip6;
+ IP6_MERGE(&in, &temp, &np->in_osrc);
+
+#ifdef NEED_128BIT_MATH
+ } else if (np->in_redir & NAT_MAPBLK) {
+ if ((l >= np->in_ppip) || ((l > 0) &&
+ !(flags & IPN_TCPUDP))) {
+ NBUMPSIDE6DX(1, ns_exhausted, ns_exhausted_2);
+ return -1;
+ }
+ /*
+ * map-block - Calculate destination address.
+ */
+ IP6_MASK(&in, &fin->fin_src6, &np->in_osrcmsk6);
+ in = ntohl(in);
+ inb = in;
+ in.s_addr /= np->in_ippip;
+ in.s_addr &= ntohl(~np->in_nsrcmsk6);
+ in.s_addr += ntohl(np->in_nsrcaddr6);
+ /*
+ * 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);
+ }
+#endif
+
+ } else if (IP6_ISZERO(&np->in_nsrcaddr) &&
+ IP6_ISONES(&np->in_nsrcmsk)) {
+ /*
+ * 0/32 - use the interface's IP address.
+ */
+ if ((l > 0) ||
+ ipf_ifpaddr(softc, 6, FRI_NORMAL, fin->fin_ifp,
+ &in, NULL) == -1) {
+ NBUMPSIDE6DX(1, ns_new_ifpaddr,
+ ns_new_ifpaddr_1);
+ return -1;
+ }
+
+ } else if (IP6_ISZERO(&np->in_nsrcip6) &&
+ IP6_ISZERO(&np->in_nsrcmsk6)) {
+ /*
+ * 0/0 - use the original source address/port.
+ */
+ if (l > 0) {
+ NBUMPSIDE6DX(1, ns_exhausted, ns_exhausted_3);
+ return -1;
+ }
+ in = fin->fin_src6;
+
+ } else if (!IP6_ISONES(&np->in_nsrcmsk6) &&
+ (np->in_spnext == 0) && ((l > 0) || (hm == NULL))) {
+ IP6_INC(&np->in_snip6);
+ }
+
+ natl = NULL;
+
+ if ((flags & IPN_TCPUDP) &&
+ ((np->in_redir & NAT_MAPBLK) == 0) &&
+ (np->in_flags & IPN_AUTOPORTMAP)) {
+#ifdef NEED_128BIT_MATH
+ /*
+ * "ports auto" (without map-block)
+ */
+ if ((l > 0) && (l % np->in_ppip == 0)) {
+ if ((l > np->in_ppip) &&
+ !IP6_ISONES(&np->in_nsrcmsk)) {
+ IP6_INC(&np->in_snip6)
+ }
+ }
+ if (np->in_ppip != 0) {
+ port = ntohs(sport);
+ port += (l % np->in_ppip);
+ port %= np->in_ppip;
+ port += np->in_ppip *
+ (ntohl(fin->fin_src6) %
+ np->in_ippip);
+ port += MAPBLK_MINPORT;
+ port = htons(port);
+ }
+#endif
+
+ } else if (((np->in_redir & NAT_MAPBLK) == 0) &&
+ (flags & IPN_TCPUDPICMP) && (np->in_spnext != 0)) {
+ /*
+ * Standard port translation. Select next port.
+ */
+ if (np->in_flags & IPN_SEQUENTIAL) {
+ port = np->in_spnext;
+ } else {
+ port = ipf_random() % (np->in_spmax -
+ np->in_spmin + 1);
+ port += np->in_spmin;
+ }
+ port = htons(port);
+ np->in_spnext++;
+
+ if (np->in_spnext > np->in_spmax) {
+ np->in_spnext = np->in_spmin;
+ if (!IP6_ISONES(&np->in_nsrcmsk6)) {
+ IP6_INC(&np->in_snip6);
+ }
+ }
+ }
+
+ if (np->in_flags & IPN_SIPRANGE) {
+ if (IP6_GT(&np->in_snip, &np->in_nsrcmsk))
+ np->in_snip6 = np->in_nsrcip6;
+ } else {
+ i6addr_t a1, a2;
+
+ a1 = np->in_snip6;
+ IP6_INC(&a1);
+ IP6_AND(&a1, &np->in_nsrcmsk6, &a2);
+
+ if (!IP6_ISONES(&np->in_nsrcmsk6) &&
+ IP6_GT(&a2, &np->in_nsrcip6)) {
+ IP6_ADD(&np->in_nsrcip6, 1, &np->in_snip6);
+ }
+ }
+
+ if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY)))
+ port = sport;
+
+ /*
+ * 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.
+ */
+ sp = fin->fin_data[0];
+ dp = fin->fin_data[1];
+ fin->fin_data[0] = fin->fin_data[1];
+ fin->fin_data[1] = ntohs(port);
+ natl = ipf_nat6_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
+ (u_int)fin->fin_p, &fin->fin_dst6.in6,
+ &in.in6);
+ fin->fin_data[0] = sp;
+ fin->fin_data[1] = dp;
+
+ /*
+ * Has the search wrapped around and come back to the
+ * start ?
+ */
+ if ((natl != NULL) &&
+ (np->in_spnext != 0) && (st_port == np->in_spnext) &&
+ (!IP6_ISZERO(&np->in_snip6) &&
+ IP6_EQ(&st_ip, &np->in_snip6))) {
+ NBUMPSIDE6D(1, ns_wrap);
+ return -1;
+ }
+ l++;
+ } while (natl != NULL);
+
+ /* Setup the NAT table */
+ nat->nat_osrc6 = fin->fin_src6;
+ nat->nat_nsrc6 = in;
+ nat->nat_odst6 = fin->fin_dst6;
+ nat->nat_ndst6 = fin->fin_dst6;
+ if (nat->nat_hm == NULL)
+ nat->nat_hm = ipf_nat6_hostmap(softn, np, &fin->fin_src6,
+ &fin->fin_dst6,
+ &nat->nat_nsrc6, 0);
+
+ if (flags & IPN_TCPUDP) {
+ nat->nat_osport = sport;
+ nat->nat_nsport = port; /* sport */
+ nat->nat_odport = dport;
+ nat->nat_ndport = dport;
+ ((tcphdr_t *)fin->fin_dp)->th_sport = port;
+ } else if (flags & IPN_ICMPQUERY) {
+ nat->nat_oicmpid = fin->fin_data[1];
+ ((struct icmp6_hdr *)fin->fin_dp)->icmp6_id = port;
+ nat->nat_nicmpid = port;
+ }
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_newrdr */
+/* Returns: int - -1 == error, 0 == success (no move), 1 == success and */
+/* allow rule to be moved if IPN_ROUNDR is set. */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to NAT entry */
+/* ni(I) - pointer to structure with misc. information needed */
+/* to create new NAT entry. */
+/* */
+/* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
+/* to the new IP address for the translation. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat6_newrdr(fin, nat, ni)
+ fr_info_t *fin;
+ nat_t *nat;
+ natinfo_t *ni;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ u_short nport, dport, sport;
+ u_short sp, dp;
+ hostmap_t *hm;
+ u_32_t flags;
+ i6addr_t in;
+ ipnat_t *np;
+ nat_t *natl;
+ int move;
+
+ move = 1;
+ hm = NULL;
+ in.i6[0] = 0;
+ in.i6[1] = 0;
+ in.i6[2] = 0;
+ in.i6[3] = 0;
+ np = ni->nai_np;
+ flags = nat->nat_flags;
+
+ if (flags & IPN_ICMPQUERY) {
+ dport = fin->fin_data[1];
+ sport = 0;
+ } else {
+ sport = htons(fin->fin_data[0]);
+ dport = htons(fin->fin_data[1]);
+ }
+
+ /* TRACE sport, dport */
+
+
+ /*
+ * If the matching rule has IPN_STICKY set, then we want to have the
+ * same rule kick in as before. Why would this happen? If you have
+ * a collection of rdr rules with "round-robin sticky", the current
+ * packet might match a different one to the previous connection but
+ * we want the same destination to be used.
+ */
+ if (((np->in_flags & (IPN_ROUNDR|IPN_SPLIT)) != 0) &&
+ ((np->in_flags & IPN_STICKY) != 0)) {
+ hm = ipf_nat6_hostmap(softn, NULL, &fin->fin_src6,
+ &fin->fin_dst6, &in, (u_32_t)dport);
+ if (hm != NULL) {
+ in = hm->hm_ndstip6;
+ np = hm->hm_ipnat;
+ ni->nai_np = np;
+ move = 0;
+ }
+ }
+
+ /*
+ * 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.
+ */
+ if (np->in_flags & IPN_SPLIT) {
+ in = np->in_dnip6;
+
+ if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) {
+ hm = ipf_nat6_hostmap(softn, NULL, &fin->fin_src6,
+ &fin->fin_dst6, &in,
+ (u_32_t)dport);
+ if (hm != NULL) {
+ in = hm->hm_ndstip6;
+ move = 0;
+ }
+ }
+
+ if (hm == NULL || hm->hm_ref == 1) {
+ if (IP6_EQ(&np->in_ndstip6, &in)) {
+ np->in_dnip6 = np->in_ndstmsk6;
+ move = 0;
+ } else {
+ np->in_dnip6 = np->in_ndstip6;
+ }
+ }
+
+ } else if (IP6_ISZERO(&np->in_ndstaddr) &&
+ IP6_ISONES(&np->in_ndstmsk)) {
+ /*
+ * 0/32 - use the interface's IP address.
+ */
+ if (ipf_ifpaddr(softc, 6, FRI_NORMAL, fin->fin_ifp,
+ &in, NULL) == -1) {
+ NBUMPSIDE6DX(0, ns_new_ifpaddr, ns_new_ifpaddr_2);
+ return -1;
+ }
+
+ } else if (IP6_ISZERO(&np->in_ndstip6) &&
+ IP6_ISZERO(&np->in_ndstmsk6)) {
+ /*
+ * 0/0 - use the original destination address/port.
+ */
+ in = fin->fin_dst6;
+
+ } else if (np->in_redir == NAT_BIMAP &&
+ IP6_EQ(&np->in_ndstmsk6, &np->in_odstmsk6)) {
+ i6addr_t temp;
+ /*
+ * map the address block in a 1:1 fashion
+ */
+ temp.i6[0] = fin->fin_dst6.i6[0] & ~np->in_osrcmsk6.i6[0];
+ temp.i6[1] = fin->fin_dst6.i6[1] & ~np->in_osrcmsk6.i6[1];
+ temp.i6[2] = fin->fin_dst6.i6[2] & ~np->in_osrcmsk6.i6[0];
+ temp.i6[3] = fin->fin_dst6.i6[3] & ~np->in_osrcmsk6.i6[3];
+ in = np->in_ndstip6;
+ IP6_MERGE(&in, &temp, &np->in_ndstmsk6);
+ } else {
+ in = np->in_ndstip6;
+ }
+
+ if ((np->in_dpnext == 0) || ((flags & NAT_NOTRULEPORT) != 0))
+ nport = dport;
+ else {
+ /*
+ * Whilst not optimized for the case where
+ * pmin == pmax, the gain is not significant.
+ */
+ if (((np->in_flags & IPN_FIXEDDPORT) == 0) &&
+ (np->in_odport != np->in_dtop)) {
+ nport = ntohs(dport) - np->in_odport + np->in_dpmax;
+ nport = htons(nport);
+ } else {
+ nport = htons(np->in_dpnext);
+ np->in_dpnext++;
+ if (np->in_dpnext > np->in_dpmax)
+ np->in_dpnext = np->in_dpmin;
+ }
+ }
+
+ /*
+ * 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 (IP6_ISZERO(&in)) {
+ if (nport == dport) {
+ NBUMPSIDE6D(0, ns_xlate_null);
+ return -1;
+ }
+ in = fin->fin_dst6;
+ }
+
+ /*
+ * Check to see if this redirect mapping already exists and if
+ * it does, return "failure" (allowing it to be created will just
+ * cause one or both of these "connections" to stop working.)
+ */
+ sp = fin->fin_data[0];
+ dp = fin->fin_data[1];
+ fin->fin_data[1] = fin->fin_data[0];
+ fin->fin_data[0] = ntohs(nport);
+ natl = ipf_nat6_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
+ (u_int)fin->fin_p, &in.in6,
+ &fin->fin_src6.in6);
+ fin->fin_data[0] = sp;
+ fin->fin_data[1] = dp;
+ if (natl != NULL) {
+ NBUMPSIDE6D(0, ns_xlate_exists);
+ return -1;
+ }
+
+ nat->nat_ndst6 = in;
+ nat->nat_odst6 = fin->fin_dst6;
+ nat->nat_nsrc6 = fin->fin_src6;
+ nat->nat_osrc6 = fin->fin_src6;
+ if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0))
+ nat->nat_hm = ipf_nat6_hostmap(softn, np, &fin->fin_src6,
+ &fin->fin_dst6, &in,
+ (u_32_t)dport);
+
+ if (flags & IPN_TCPUDP) {
+ nat->nat_odport = dport;
+ nat->nat_ndport = nport;
+ nat->nat_osport = sport;
+ nat->nat_nsport = sport;
+ ((tcphdr_t *)fin->fin_dp)->th_dport = nport;
+ } else if (flags & IPN_ICMPQUERY) {
+ nat->nat_oicmpid = fin->fin_data[1];
+ ((struct icmp6_hdr *)fin->fin_dp)->icmp6_id = nport;
+ nat->nat_nicmpid = nport;
+ }
+
+ return move;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_add */
+/* Returns: nat6_t* - NULL == failure to create new NAT structure, */
+/* else pointer to new NAT structure */
+/* Parameters: fin(I) - pointer to packet information */
+/* np(I) - pointer to NAT rule */
+/* natsave(I) - pointer to where to store NAT struct pointer */
+/* flags(I) - flags describing the current packet */
+/* direction(I) - direction of packet (in/out) */
+/* Write Lock: ipf_nat */
+/* */
+/* Attempts to create a new NAT entry. Does not actually change the packet */
+/* in any way. */
+/* */
+/* This fucntion is in three main parts: (1) deal with creating a new NAT */
+/* structure for a "MAP" rule (outgoing NAT translation); (2) deal with */
+/* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */
+/* and (3) building that structure and putting it into the NAT table(s). */
+/* */
+/* NOTE: natsave should NOT be used top point back to an ipstate_t struct */
+/* as it can result in memory being corrupted. */
+/* ------------------------------------------------------------------------ */
+nat_t *
+ipf_nat6_add(fin, np, natsave, flags, direction)
+ fr_info_t *fin;
+ ipnat_t *np;
+ nat_t **natsave;
+ u_int flags;
+ int direction;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ hostmap_t *hm = NULL;
+ nat_t *nat, *natl;
+ natstat_t *nsp;
+ u_int nflags;
+ natinfo_t ni;
+ int move;
+#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_M_CTL_MAGIC)
+ qpktinfo_t *qpi = fin->fin_qpi;
+#endif
+
+ nsp = &softn->ipf_nat_stats;
+
+ if ((nsp->ns_active * 100 / softn->ipf_nat_table_max) >
+ softn->ipf_nat_table_wm_high) {
+ softn->ipf_nat_doflush = 1;
+ }
+
+ if (nsp->ns_active >= softn->ipf_nat_table_max) {
+ NBUMPSIDE6(fin->fin_out, ns_table_max);
+ return NULL;
+ }
+
+ move = 1;
+ nflags = np->in_flags & flags;
+ nflags &= NAT_FROMRULE;
+
+ ni.nai_np = np;
+ ni.nai_dport = 0;
+ ni.nai_sport = 0;
+
+ /* Give me a new nat */
+ KMALLOC(nat, nat_t *);
+ if (nat == NULL) {
+ NBUMPSIDE6(fin->fin_out, ns_memfail);
+ /*
+ * Try to automatically tune the max # of entries in the
+ * table allowed to be less than what will cause kmem_alloc()
+ * to fail and try to eliminate panics due to out of memory
+ * conditions arising.
+ */
+ if ((softn->ipf_nat_table_max > softn->ipf_nat_table_sz) &&
+ (nsp->ns_active > 100)) {
+ softn->ipf_nat_table_max = nsp->ns_active - 100;
+ printf("table_max reduced to %d\n",
+ softn->ipf_nat_table_max);
+ }
+ return NULL;
+ }
+
+ if (flags & IPN_ICMPQUERY) {
+ /*
+ * In the ICMP query NAT code, we translate the ICMP id fields
+ * to make them unique. This is indepedent of the ICMP type
+ * (e.g. in the unlikely event that a host sends an echo and
+ * an tstamp request with the same id, both packets will have
+ * their ip address/id field changed in the same way).
+ */
+ /* The icmp6_id field is used by the sender to identify the
+ * process making the icmp request. (the receiver justs
+ * copies it back in its response). So, it closely matches
+ * the concept of source port. We overlay sport, so we can
+ * maximally reuse the existing code.
+ */
+ ni.nai_sport = fin->fin_data[1];
+ ni.nai_dport = 0;
+ }
+
+ bzero((char *)nat, sizeof(*nat));
+ nat->nat_flags = flags;
+ nat->nat_redir = np->in_redir;
+ nat->nat_dir = direction;
+ nat->nat_pr[0] = fin->fin_p;
+ nat->nat_pr[1] = fin->fin_p;
+
+ /*
+ * Search the current table for a match and create a new mapping
+ * if there is none found.
+ */
+ if (np->in_redir & NAT_DIVERTUDP) {
+ move = ipf_nat6_newdivert(fin, nat, &ni);
+
+ } else if (np->in_redir & NAT_REWRITE) {
+ move = ipf_nat6_newrewrite(fin, nat, &ni);
+
+ } else if (direction == NAT_OUTBOUND) {
+ /*
+ * We can now arrange to call this for the same connection
+ * because ipf_nat6_new doesn't protect the code path into
+ * this function.
+ */
+ natl = ipf_nat6_outlookup(fin, nflags, (u_int)fin->fin_p,
+ &fin->fin_src6.in6,
+ &fin->fin_dst6.in6);
+ if (natl != NULL) {
+ KFREE(nat);
+ nat = natl;
+ goto done;
+ }
+
+ move = ipf_nat6_newmap(fin, nat, &ni);
+ } else {
+ /*
+ * NAT_INBOUND is used for redirects rules
+ */
+ natl = ipf_nat6_inlookup(fin, nflags, (u_int)fin->fin_p,
+ &fin->fin_src6.in6,
+ &fin->fin_dst6.in6);
+ if (natl != NULL) {
+ KFREE(nat);
+ nat = natl;
+ goto done;
+ }
+
+ move = ipf_nat6_newrdr(fin, nat, &ni);
+ }
+ if (move == -1)
+ goto badnat;
+
+ np = ni.nai_np;
+
+ nat->nat_mssclamp = np->in_mssclamp;
+ nat->nat_me = natsave;
+ nat->nat_fr = fin->fin_fr;
+ nat->nat_rev = fin->fin_rev;
+ nat->nat_ptr = np;
+ nat->nat_dlocal = np->in_dlocal;
+
+ if ((np->in_apr != NULL) && ((nat->nat_flags & NAT_SLAVE) == 0)) {
+ if (ipf_proxy_new(fin, nat) == -1) {
+ NBUMPSIDE6D(fin->fin_out, ns_appr_fail);
+ goto badnat;
+ }
+ }
+
+ nat->nat_ifps[0] = np->in_ifps[0];
+ if (np->in_ifps[0] != NULL) {
+ COPYIFNAME(np->in_v[0], np->in_ifps[0], nat->nat_ifnames[0]);
+ }
+
+ nat->nat_ifps[1] = np->in_ifps[1];
+ if (np->in_ifps[1] != NULL) {
+ COPYIFNAME(np->in_v[1], np->in_ifps[1], nat->nat_ifnames[1]);
+ }
+
+ if (ipf_nat6_finalise(fin, nat) == -1) {
+ goto badnat;
+ }
+
+ np->in_use++;
+
+ if ((move == 1) && (np->in_flags & IPN_ROUNDR)) {
+ if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_REDIRECT) {
+ ipf_nat6_delrdr(softn, np);
+ ipf_nat6_addrdr(softn, np);
+ } else if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_MAP) {
+ ipf_nat6_delmap(softn, np);
+ ipf_nat6_addmap(softn, np);
+ }
+ }
+
+ if (flags & SI_WILDP)
+ nsp->ns_wilds++;
+ softn->ipf_nat_stats.ns_proto[nat->nat_pr[0]]++;
+
+ goto done;
+badnat:
+ NBUMPSIDE6(fin->fin_out, ns_badnatnew);
+ if ((hm = nat->nat_hm) != NULL)
+ ipf_nat_hostmapdel(softc, &hm);
+ KFREE(nat);
+ nat = NULL;
+done:
+ if (nat != NULL && np != NULL)
+ np->in_hits++;
+ if (natsave != NULL)
+ *natsave = nat;
+ return nat;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_finalise */
+/* Returns: int - 0 == sucess, -1 == failure */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to NAT entry */
+/* Write Lock: ipf_nat */
+/* */
+/* This is the tail end of constructing a new NAT entry and is the same */
+/* for both IPv4 and IPv6. */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+int
+ipf_nat6_finalise(fin, nat)
+ fr_info_t *fin;
+ nat_t *nat;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ u_32_t sum1, sum2, sumd;
+ frentry_t *fr;
+ u_32_t flags;
+
+ flags = nat->nat_flags;
+
+ switch (fin->fin_p)
+ {
+ case IPPROTO_ICMPV6 :
+ sum1 = LONG_SUM6(&nat->nat_osrc6);
+ sum1 += ntohs(nat->nat_oicmpid);
+ sum2 = LONG_SUM6(&nat->nat_nsrc6);
+ sum2 += ntohs(nat->nat_nicmpid);
+ CALC_SUMD(sum1, sum2, sumd);
+ nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
+
+ sum1 = LONG_SUM6(&nat->nat_odst6);
+ sum2 = LONG_SUM6(&nat->nat_ndst6);
+ CALC_SUMD(sum1, sum2, sumd);
+ nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16);
+ break;
+
+ case IPPROTO_TCP :
+ case IPPROTO_UDP :
+ sum1 = LONG_SUM6(&nat->nat_osrc6);
+ sum1 += ntohs(nat->nat_osport);
+ sum2 = LONG_SUM6(&nat->nat_nsrc6);
+ sum2 += ntohs(nat->nat_nsport);
+ CALC_SUMD(sum1, sum2, sumd);
+ nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
+
+ sum1 = LONG_SUM6(&nat->nat_odst6);
+ sum1 += ntohs(nat->nat_odport);
+ sum2 = LONG_SUM6(&nat->nat_ndst6);
+ sum2 += ntohs(nat->nat_ndport);
+ CALC_SUMD(sum1, sum2, sumd);
+ nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16);
+ break;
+
+ default :
+ sum1 = LONG_SUM6(&nat->nat_osrc6);
+ sum2 = LONG_SUM6(&nat->nat_nsrc6);
+ CALC_SUMD(sum1, sum2, sumd);
+ nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
+
+ sum1 = LONG_SUM6(&nat->nat_odst6);
+ sum2 = LONG_SUM6(&nat->nat_ndst6);
+ CALC_SUMD(sum1, sum2, sumd);
+ nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16);
+ break;
+ }
+
+ /*
+ * Compute the partial checksum, just in case.
+ * This is only ever placed into outbound packets so care needs
+ * to be taken over which pair of addresses are used.
+ */
+ if (nat->nat_dir == NAT_OUTBOUND) {
+ sum1 = LONG_SUM6(&nat->nat_nsrc6);
+ sum1 += LONG_SUM6(&nat->nat_ndst6);
+ } else {
+ sum1 = LONG_SUM6(&nat->nat_osrc6);
+ sum1 += LONG_SUM6(&nat->nat_odst6);
+ }
+ sum1 += nat->nat_pr[1];
+ nat->nat_sumd[1] = (sum1 & 0xffff) + (sum1 >> 16);
+
+ if ((nat->nat_flags & SI_CLONE) == 0)
+ nat->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, nat);
+
+ if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
+ nat->nat_mtu[0] = GETIFMTU_6(nat->nat_ifps[0]);
+ }
+
+ if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
+ nat->nat_mtu[1] = GETIFMTU_6(nat->nat_ifps[1]);
+ }
+
+ nat->nat_v[0] = 6;
+ nat->nat_v[1] = 6;
+
+ if (ipf_nat6_insert(softc, softn, nat) == 0) {
+ if (softn->ipf_nat_logging)
+ ipf_nat_log(softc, softn, nat, NL_NEW);
+ fr = nat->nat_fr;
+ if (fr != NULL) {
+ MUTEX_ENTER(&fr->fr_lock);
+ fr->fr_ref++;
+ MUTEX_EXIT(&fr->fr_lock);
+ }
+ return 0;
+ }
+
+ NBUMPSIDE6D(fin->fin_out, ns_unfinalised);
+ /*
+ * nat6_insert failed, so cleanup time...
+ */
+ if (nat->nat_sync != NULL)
+ ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync);
+ return -1;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_insert */
+/* Returns: int - 0 == sucess, -1 == failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softn(I) - pointer to NAT context structure */
+/* nat(I) - pointer to NAT structure */
+/* Write Lock: ipf_nat */
+/* */
+/* Insert a NAT entry into the hash tables for searching and add it to the */
+/* list of active NAT entries. Adjust global counters when complete. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_insert(softc, softn, nat)
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
+ nat_t *nat;
+{
+ u_int hv1, hv2;
+ u_32_t sp, dp;
+ ipnat_t *in;
+
+ /*
+ * Try and return an error as early as possible, so calculate the hash
+ * entry numbers first and then proceed.
+ */
+ if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) {
+ if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+ sp = nat->nat_osport;
+ dp = nat->nat_odport;
+ } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
+ sp = 0;
+ dp = nat->nat_oicmpid;
+ } else {
+ sp = 0;
+ dp = 0;
+ }
+ hv1 = NAT_HASH_FN6(&nat->nat_osrc6, sp, 0xffffffff);
+ hv1 = NAT_HASH_FN6(&nat->nat_odst6, hv1 + dp,
+ softn->ipf_nat_table_sz);
+
+ /*
+ * TRACE nat6_osrc6, nat6_osport, nat6_odst6,
+ * nat6_odport, hv1
+ */
+
+ if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+ sp = nat->nat_nsport;
+ dp = nat->nat_ndport;
+ } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
+ sp = 0;
+ dp = nat->nat_nicmpid;
+ } else {
+ sp = 0;
+ dp = 0;
+ }
+ hv2 = NAT_HASH_FN6(&nat->nat_nsrc6, sp, 0xffffffff);
+ hv2 = NAT_HASH_FN6(&nat->nat_ndst6, hv2 + dp,
+ softn->ipf_nat_table_sz);
+ /*
+ * TRACE nat6_nsrcaddr, nat6_nsport, nat6_ndstaddr,
+ * nat6_ndport, hv1
+ */
+ } else {
+ hv1 = NAT_HASH_FN6(&nat->nat_osrc6, 0, 0xffffffff);
+ hv1 = NAT_HASH_FN6(&nat->nat_odst6, hv1,
+ softn->ipf_nat_table_sz);
+ /* TRACE nat6_osrcip6, nat6_odstip6, hv1 */
+
+ hv2 = NAT_HASH_FN6(&nat->nat_nsrc6, 0, 0xffffffff);
+ hv2 = NAT_HASH_FN6(&nat->nat_ndst6, hv2,
+ softn->ipf_nat_table_sz);
+ /* TRACE nat6_nsrcip6, nat6_ndstip6, hv2 */
+ }
+
+ nat->nat_hv[0] = hv1;
+ nat->nat_hv[1] = hv2;
+
+ MUTEX_INIT(&nat->nat_lock, "nat entry lock");
+
+ in = nat->nat_ptr;
+ nat->nat_ref = nat->nat_me ? 2 : 1;
+
+ nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0';
+ nat->nat_ifps[0] = ipf_resolvenic(softc, nat->nat_ifnames[0],
+ nat->nat_v[0]);
+
+ if (nat->nat_ifnames[1][0] != '\0') {
+ nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
+ nat->nat_ifps[1] = ipf_resolvenic(softc, nat->nat_ifnames[1],
+ nat->nat_v[1]);
+ } else if (in->in_ifnames[1] != -1) {
+ char *name;
+
+ name = in->in_names + in->in_ifnames[1];
+ if (name[1] != '\0' && name[0] != '-' && name[0] != '*') {
+ (void) strncpy(nat->nat_ifnames[1],
+ nat->nat_ifnames[0], LIFNAMSIZ);
+ nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
+ nat->nat_ifps[1] = nat->nat_ifps[0];
+ }
+ }
+ if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
+ nat->nat_mtu[0] = GETIFMTU_6(nat->nat_ifps[0]);
+ }
+ if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
+ nat->nat_mtu[1] = GETIFMTU_6(nat->nat_ifps[1]);
+ }
+
+ return ipf_nat_hashtab_add(softc, softn, nat);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_icmperrorlookup */
+/* Returns: nat6_t* - point to matching NAT structure */
+/* Parameters: fin(I) - pointer to packet information */
+/* dir(I) - direction of packet (in/out) */
+/* */
+/* Check if the ICMP error message is related to an existing TCP, UDP or */
+/* ICMP query nat entry. It is assumed that the packet is already of the */
+/* the required length. */
+/* ------------------------------------------------------------------------ */
+nat_t *
+ipf_nat6_icmperrorlookup(fin, dir)
+ fr_info_t *fin;
+ int dir;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ struct icmp6_hdr *icmp6, *orgicmp;
+ int flags = 0, type, minlen;
+ nat_stat_side_t *nside;
+ tcphdr_t *tcp = NULL;
+ u_short data[2];
+ ip6_t *oip6;
+ nat_t *nat;
+ u_int p;
+
+ minlen = 40;
+ icmp6 = fin->fin_dp;
+ type = icmp6->icmp6_type;
+ nside = &softn->ipf_nat_stats.ns_side6[fin->fin_out];
+ /*
+ * Does it at least have the return (basic) IP header ?
+ * Only a basic IP header (no options) should be with an ICMP error
+ * header. Also, if it's not an error type, then return.
+ */
+ if (!(fin->fin_flx & FI_ICMPERR)) {
+ ATOMIC_INCL(nside->ns_icmp_basic);
+ return NULL;
+ }
+
+ /*
+ * Check packet size
+ */
+ if (fin->fin_plen < ICMP6ERR_IPICMPHLEN) {
+ ATOMIC_INCL(nside->ns_icmp_size);
+ return NULL;
+ }
+ oip6 = (ip6_t *)((char *)fin->fin_dp + 8);
+
+ /*
+ * 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 ipf_check() and thus can't gaurantee it is
+ * all here now.
+ */
+#ifdef _KERNEL
+ {
+ mb_t *m;
+
+ m = fin->fin_m;
+# if defined(MENTAT)
+ if ((char *)oip6 + fin->fin_dlen - ICMPERR_ICMPHLEN >
+ (char *)m->b_wptr) {
+ ATOMIC_INCL(nside->ns_icmp_mbuf);
+ return NULL;
+ }
+# else
+ if ((char *)oip6 + fin->fin_dlen - ICMPERR_ICMPHLEN >
+ (char *)fin->fin_ip + M_LEN(m)) {
+ ATOMIC_INCL(nside->ns_icmp_mbuf);
+ return NULL;
+ }
+# endif
+ }
+#endif
+
+ if (IP6_NEQ(&fin->fin_dst6, &oip6->ip6_src)) {
+ ATOMIC_INCL(nside->ns_icmp_address);
+ return NULL;
+ }
+
+ p = oip6->ip6_nxt;
+ if (p == IPPROTO_TCP)
+ flags = IPN_TCP;
+ else if (p == IPPROTO_UDP)
+ flags = IPN_UDP;
+ else if (p == IPPROTO_ICMPV6) {
+ orgicmp = (struct icmp6_hdr *)(oip6 + 1);
+
+ /* see if this is related to an ICMP query */
+ if (ipf_nat6_icmpquerytype(orgicmp->icmp6_type)) {
+ data[0] = fin->fin_data[0];
+ data[1] = fin->fin_data[1];
+ fin->fin_data[0] = 0;
+ fin->fin_data[1] = orgicmp->icmp6_id;
+
+ flags = IPN_ICMPERR|IPN_ICMPQUERY;
+ /*
+ * NOTE : dir refers to the direction of the original
+ * ip packet. By definition the icmp error
+ * message flows in the opposite direction.
+ */
+ if (dir == NAT_INBOUND)
+ nat = ipf_nat6_inlookup(fin, flags, p,
+ &oip6->ip6_dst,
+ &oip6->ip6_src);
+ else
+ nat = ipf_nat6_outlookup(fin, flags, p,
+ &oip6->ip6_dst,
+ &oip6->ip6_src);
+ fin->fin_data[0] = data[0];
+ fin->fin_data[1] = data[1];
+ return nat;
+ }
+ }
+
+ if (flags & IPN_TCPUDP) {
+ minlen += 8; /* + 64bits of data to get ports */
+ /* TRACE (fin,minlen) */
+ if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) {
+ ATOMIC_INCL(nside->ns_icmp_short);
+ return NULL;
+ }
+
+ data[0] = fin->fin_data[0];
+ data[1] = fin->fin_data[1];
+ tcp = (tcphdr_t *)(oip6 + 1);
+ fin->fin_data[0] = ntohs(tcp->th_dport);
+ fin->fin_data[1] = ntohs(tcp->th_sport);
+
+ if (dir == NAT_INBOUND) {
+ nat = ipf_nat6_inlookup(fin, flags, p, &oip6->ip6_dst,
+ &oip6->ip6_src);
+ } else {
+ nat = ipf_nat6_outlookup(fin, flags, p, &oip6->ip6_dst,
+ &oip6->ip6_src);
+ }
+ fin->fin_data[0] = data[0];
+ fin->fin_data[1] = data[1];
+ return nat;
+ }
+ if (dir == NAT_INBOUND)
+ nat = ipf_nat6_inlookup(fin, 0, p, &oip6->ip6_dst,
+ &oip6->ip6_src);
+ else
+ nat = ipf_nat6_outlookup(fin, 0, p, &oip6->ip6_dst,
+ &oip6->ip6_src);
+
+ return nat;
+}
+
+
+/* result = ip1 - ip2 */
+u_32_t
+ipf_nat6_ip6subtract(ip1, ip2)
+ i6addr_t *ip1, *ip2;
+{
+ i6addr_t l1, l2, d;
+ u_short *s1, *s2, *ds;
+ u_32_t r;
+ int i, neg;
+
+ neg = 0;
+ l1 = *ip1;
+ l2 = *ip2;
+ s1 = (u_short *)&l1;
+ s2 = (u_short *)&l2;
+ ds = (u_short *)&d;
+
+ for (i = 7; i > 0; i--) {
+ if (s1[i] > s2[i]) {
+ ds[i] = s2[i] + 0x10000 - s1[i];
+ s2[i - 1] += 0x10000;
+ } else {
+ ds[i] = s2[i] - s1[i];
+ }
+ }
+ if (s2[0] > s1[0]) {
+ ds[0] = s2[0] + 0x10000 - s1[0];
+ neg = 1;
+ } else {
+ ds[0] = s2[0] - s1[0];
+ }
+
+ for (i = 0, r = 0; i < 8; i++) {
+ r += ds[i];
+ }
+
+ return r;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_icmperror */
+/* Returns: nat6_t* - point to matching NAT structure */
+/* Parameters: fin(I) - pointer to packet information */
+/* nflags(I) - NAT flags for this packet */
+/* dir(I) - direction of packet (in/out) */
+/* */
+/* Fix up an ICMP packet which is an error message for an existing NAT */
+/* session. This will correct both packet header data and checksums. */
+/* */
+/* This should *ONLY* be used for incoming ICMP error packets to make sure */
+/* a NAT'd ICMP packet gets correctly recognised. */
+/* ------------------------------------------------------------------------ */
+nat_t *
+ipf_nat6_icmperror(fin, nflags, dir)
+ fr_info_t *fin;
+ u_int *nflags;
+ int dir;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ u_32_t sum1, sum2, sumd, sumd2;
+ i6addr_t a1, a2, a3, a4;
+ struct icmp6_hdr *icmp6;
+ int flags, dlen, odst;
+ u_short *csump;
+ tcphdr_t *tcp;
+ ip6_t *oip6;
+ nat_t *nat;
+ void *dp;
+
+ if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
+ NBUMPSIDE6D(fin->fin_out, ns_icmp_short);
+ return NULL;
+ }
+
+ /*
+ * ipf_nat6_icmperrorlookup() will return NULL for `defective' packets.
+ */
+ if ((fin->fin_v != 6) || !(nat = ipf_nat6_icmperrorlookup(fin, dir))) {
+ NBUMPSIDE6D(fin->fin_out, ns_icmp_notfound);
+ return NULL;
+ }
+
+ tcp = NULL;
+ csump = NULL;
+ flags = 0;
+ sumd2 = 0;
+ *nflags = IPN_ICMPERR;
+ icmp6 = fin->fin_dp;
+ oip6 = (ip6_t *)((u_char *)icmp6 + sizeof(*icmp6));
+ dp = (u_char *)oip6 + sizeof(*oip6);
+ if (oip6->ip6_nxt == IPPROTO_TCP) {
+ tcp = (tcphdr_t *)dp;
+ csump = (u_short *)&tcp->th_sum;
+ flags = IPN_TCP;
+ } else if (oip6->ip6_nxt == IPPROTO_UDP) {
+ udphdr_t *udp;
+
+ udp = (udphdr_t *)dp;
+ tcp = (tcphdr_t *)dp;
+ csump = (u_short *)&udp->uh_sum;
+ flags = IPN_UDP;
+ } else if (oip6->ip6_nxt == IPPROTO_ICMPV6)
+ flags = IPN_ICMPQUERY;
+ dlen = fin->fin_plen - ((char *)dp - (char *)fin->fin_ip);
+
+ /*
+ * 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 as it will be modified again in ipf_nat6_checkout
+ * 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.
+ *
+ * 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 oip6->ip6_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.
+ *
+ * Inbound ICMP
+ * ------------
+ * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
+ * - response to outgoing packet (a,b)=>(c,b) (OIP_SRC=c,OIP_DST=b)
+ * - OIP_SRC(c)=nat6_newsrcip, OIP_DST(b)=nat6_newdstip
+ *=> OIP_SRC(c)=nat6_oldsrcip, OIP_DST(b)=nat6_olddstip
+ *
+ * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
+ * - response to outgoing packet (c,a)=>(b,a) (OIP_SRC=b,OIP_DST=a)
+ * - OIP_SRC(b)=nat6_olddstip, OIP_DST(a)=nat6_oldsrcip
+ *=> OIP_SRC(b)=nat6_newdstip, OIP_DST(a)=nat6_newsrcip
+ *
+ * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
+ * - response to outgoing packet (a,b)=>(c,d) (OIP_SRC=c,OIP_DST=d)
+ * - OIP_SRC(c)=nat6_newsrcip, OIP_DST(d)=nat6_newdstip
+ *=> OIP_SRC(c)=nat6_oldsrcip, OIP_DST(d)=nat6_olddstip
+ *
+ * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
+ * - response to outgoing packet (d,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
+ * - OIP_SRC(b)=nat6_olddstip, OIP_DST(a)=nat6_oldsrcip
+ *=> OIP_SRC(b)=nat6_newdstip, OIP_DST(a)=nat6_newsrcip
+ *
+ * Outbound ICMP
+ * -------------
+ * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
+ * - response to incoming packet (b,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
+ * - OIP_SRC(b)=nat6_olddstip, OIP_DST(a)=nat6_oldsrcip
+ *=> OIP_SRC(b)=nat6_newdstip, OIP_DST(a)=nat6_newsrcip
+ *
+ * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
+ * - response to incoming packet (a,b)=>(a,c) (OIP_SRC=a,OIP_DST=c)
+ * - OIP_SRC(a)=nat6_newsrcip, OIP_DST(c)=nat6_newdstip
+ *=> OIP_SRC(a)=nat6_oldsrcip, OIP_DST(c)=nat6_olddstip
+ *
+ * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
+ * - response to incoming packet (d,c)=>(b,a) (OIP_SRC=c,OIP_DST=d)
+ * - OIP_SRC(c)=nat6_olddstip, OIP_DST(d)=nat6_oldsrcip
+ *=> OIP_SRC(b)=nat6_newdstip, OIP_DST(a)=nat6_newsrcip
+ *
+ * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
+ * - response to incoming packet (a,b)=>(c,d) (OIP_SRC=b,OIP_DST=a)
+ * - OIP_SRC(b)=nat6_newsrcip, OIP_DST(a)=nat6_newdstip
+ *=> OIP_SRC(a)=nat6_oldsrcip, OIP_DST(c)=nat6_olddstip
+ */
+
+ if (((fin->fin_out == 0) && ((nat->nat_redir & NAT_MAP) != 0)) ||
+ ((fin->fin_out == 1) && ((nat->nat_redir & NAT_REDIRECT) != 0))) {
+ a1 = nat->nat_osrc6;
+ a4.in6 = oip6->ip6_src;
+ a3 = nat->nat_odst6;
+ a2.in6 = oip6->ip6_dst;
+ oip6->ip6_src = a1.in6;
+ oip6->ip6_dst = a3.in6;
+ odst = 1;
+ } else {
+ a1 = nat->nat_ndst6;
+ a2.in6 = oip6->ip6_dst;
+ a3 = nat->nat_nsrc6;
+ a4.in6 = oip6->ip6_src;
+ oip6->ip6_dst = a3.in6;
+ oip6->ip6_src = a1.in6;
+ odst = 0;
+ }
+
+ sumd = 0;
+ if (IP6_NEQ(&a3, &a2) || IP6_NEQ(&a1, &a4)) {
+ if (IP6_GT(&a3, &a2)) {
+ sumd = ipf_nat6_ip6subtract(&a2, &a3);
+ sumd--;
+ } else {
+ sumd = ipf_nat6_ip6subtract(&a2, &a3);
+ }
+ if (IP6_GT(&a1, &a4)) {
+ sumd += ipf_nat6_ip6subtract(&a4, &a1);
+ sumd--;
+ } else {
+ sumd += ipf_nat6_ip6subtract(&a4, &a1);
+ }
+ sumd = ~sumd;
+ }
+
+ sumd2 = sumd;
+ sum1 = 0;
+ sum2 = 0;
+
+ /*
+ * Fix UDP pseudo header checksum to compensate for the
+ * IP address change.
+ */
+ if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) {
+ u_32_t sum3, sum4;
+ /*
+ * Step 2 :
+ * For offending TCP/UDP IP packets, translate the ports as
+ * well, based on the NAT specification. Of course such
+ * a change may be reflected in the ICMP checksum as well.
+ *
+ * Since the port fields are part of the TCP/UDP checksum
+ * of the offending IP packet, you need to adjust that checksum
+ * as well... except that the change in the port numbers should
+ * be offset by the checksum change. However, the TCP/UDP
+ * checksum will also need to change if there has been an
+ * IP address change.
+ */
+ if (odst == 1) {
+ sum1 = ntohs(nat->nat_osport);
+ sum4 = ntohs(tcp->th_sport);
+ sum3 = ntohs(nat->nat_odport);
+ sum2 = ntohs(tcp->th_dport);
+
+ tcp->th_sport = htons(sum1);
+ tcp->th_dport = htons(sum3);
+ } else {
+ sum1 = ntohs(nat->nat_ndport);
+ sum2 = ntohs(tcp->th_dport);
+ sum3 = ntohs(nat->nat_nsport);
+ sum4 = ntohs(tcp->th_sport);
+
+ tcp->th_dport = htons(sum3);
+ tcp->th_sport = htons(sum1);
+ }
+ sumd += sum1 - sum4;
+ sumd += sum3 - sum2;
+
+ if (sumd != 0 || sumd2 != 0) {
+ /*
+ * At this point, sumd is the delta to apply to the
+ * TCP/UDP header, given the changes in both the IP
+ * address and the ports and sumd2 is the delta to
+ * apply to the ICMP header, given the IP address
+ * change delta that may need to be applied to the
+ * TCP/UDP checksum instead.
+ *
+ * If we will both the IP and TCP/UDP checksums
+ * then the ICMP checksum changes by the address
+ * delta applied to the TCP/UDP checksum. If we
+ * do not change the TCP/UDP checksum them we
+ * apply the delta in ports to the ICMP checksum.
+ */
+ if (oip6->ip6_nxt == IPPROTO_UDP) {
+ if ((dlen >= 8) && (*csump != 0)) {
+ ipf_fix_datacksum(csump, sumd);
+ } else {
+ sumd2 = sum4 - sum1;
+ if (sum1 > sum4)
+ sumd2--;
+ sumd2 += sum2 - sum3;
+ if (sum3 > sum2)
+ sumd2--;
+ }
+ } else if (oip6->ip6_nxt == IPPROTO_TCP) {
+ if (dlen >= 18) {
+ ipf_fix_datacksum(csump, sumd);
+ } else {
+ sumd2 = sum4 - sum1;
+ if (sum1 > sum4)
+ sumd2--;
+ sumd2 += sum2 - sum3;
+ if (sum3 > sum2)
+ sumd2--;
+ }
+ }
+ if (sumd2 != 0) {
+ sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
+ sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
+ sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
+ ipf_fix_incksum(0, &icmp6->icmp6_cksum,
+ sumd2, 0);
+ }
+ }
+ } else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) {
+ struct icmp6_hdr *orgicmp;
+
+ /*
+ * XXX - what if this is bogus hl and we go off the end ?
+ * In this case, ipf_nat6_icmperrorlookup() will have
+ * returned NULL.
+ */
+ orgicmp = (struct icmp6_hdr *)dp;
+
+ if (odst == 1) {
+ if (orgicmp->icmp6_id != nat->nat_osport) {
+
+ /*
+ * Fix ICMP checksum (of the offening ICMP
+ * query packet) to compensate the change
+ * in the ICMP id of the offending ICMP
+ * packet.
+ *
+ * Since you modify orgicmp->icmp6_id with
+ * a delta (say x) and you compensate that
+ * in origicmp->icmp6_cksum with a delta
+ * minus x, you don't have to adjust the
+ * overall icmp->icmp6_cksum
+ */
+ sum1 = ntohs(orgicmp->icmp6_id);
+ sum2 = ntohs(nat->nat_osport);
+ CALC_SUMD(sum1, sum2, sumd);
+ orgicmp->icmp6_id = nat->nat_oicmpid;
+ ipf_fix_datacksum(&orgicmp->icmp6_cksum, sumd);
+ }
+ } /* nat6_dir == NAT_INBOUND is impossible for icmp queries */
+ }
+ return nat;
+}
+
+
+/*
+ * MAP-IN MAP-OUT RDR-IN RDR-OUT
+ * osrc X == src == src X
+ * odst X == dst == dst X
+ * nsrc == dst X X == dst
+ * ndst == src X X == src
+ * MAP = NAT_OUTBOUND, RDR = NAT_INBOUND
+ */
+/*
+ * NB: these lookups don't lock access to the list, it assumed that it has
+ * already been done!
+ */
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_inlookup */
+/* Returns: nat6_t* - NULL == no match, */
+/* else pointer to matching NAT entry */
+/* Parameters: fin(I) - pointer to packet information */
+/* flags(I) - NAT flags for this packet */
+/* p(I) - protocol for this packet */
+/* src(I) - source IP address */
+/* mapdst(I) - destination IP address */
+/* */
+/* Lookup a nat entry based on the mapped destination ip address/port and */
+/* real source address/port. We use this lookup when receiving a packet, */
+/* we're looking for a table entry, based on the destination address. */
+/* */
+/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */
+/* */
+/* NOTE: IT IS ASSUMED THAT IS ONLY HELD WITH A READ LOCK WHEN */
+/* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */
+/* */
+/* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */
+/* the packet is of said protocol */
+/* ------------------------------------------------------------------------ */
+nat_t *
+ipf_nat6_inlookup(fin, flags, p, src, mapdst)
+ fr_info_t *fin;
+ u_int flags, p;
+ struct in6_addr *src , *mapdst;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ u_short sport, dport;
+ grehdr_t *gre;
+ ipnat_t *ipn;
+ u_int sflags;
+ nat_t *nat;
+ int nflags;
+ i6addr_t dst;
+ void *ifp;
+ u_int hv;
+
+ ifp = fin->fin_ifp;
+ sport = 0;
+ dport = 0;
+ gre = NULL;
+ dst.in6 = *mapdst;
+ sflags = flags & NAT_TCPUDPICMP;
+
+ switch (p)
+ {
+ case IPPROTO_TCP :
+ case IPPROTO_UDP :
+ sport = htons(fin->fin_data[0]);
+ dport = htons(fin->fin_data[1]);
+ break;
+ case IPPROTO_ICMPV6 :
+ if (flags & IPN_ICMPERR)
+ sport = fin->fin_data[1];
+ else
+ dport = fin->fin_data[1];
+ break;
+ default :
+ break;
+ }
+
+
+ if ((flags & SI_WILDP) != 0)
+ goto find_in_wild_ports;
+
+ hv = NAT_HASH_FN6(&dst, dport, 0xffffffff);
+ hv = NAT_HASH_FN6(src, hv + sport, softn->ipf_nat_table_sz);
+ nat = softn->ipf_nat_table[1][hv];
+ /* TRACE dst, dport, src, sport, hv, nat */
+
+ for (; nat; nat = nat->nat_hnext[1]) {
+ if (nat->nat_ifps[0] != NULL) {
+ if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
+ continue;
+ }
+
+ if (nat->nat_pr[0] != p)
+ continue;
+
+ switch (nat->nat_dir)
+ {
+ case NAT_INBOUND :
+ if (nat->nat_v[0] != 6)
+ continue;
+ if (IP6_NEQ(&nat->nat_osrc6, src) ||
+ IP6_NEQ(&nat->nat_odst6, &dst))
+ continue;
+ if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+ if (nat->nat_osport != sport)
+ continue;
+ if (nat->nat_odport != dport)
+ continue;
+
+ } else if (p == IPPROTO_ICMPV6) {
+ if (nat->nat_osport != dport) {
+ continue;
+ }
+ }
+ break;
+ case NAT_OUTBOUND :
+ if (nat->nat_v[1] != 6)
+ continue;
+ if (IP6_NEQ(&nat->nat_ndst6, src) ||
+ IP6_NEQ(&nat->nat_nsrc6, &dst))
+ continue;
+ if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+ if (nat->nat_ndport != sport)
+ continue;
+ if (nat->nat_nsport != dport)
+ continue;
+
+ } else if (p == IPPROTO_ICMPV6) {
+ if (nat->nat_osport != dport) {
+ continue;
+ }
+ }
+ break;
+ }
+
+
+ if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+ ipn = nat->nat_ptr;
+#ifdef IPF_V6_PROXIES
+ if ((ipn != NULL) && (nat->nat_aps != NULL))
+ if (appr_match(fin, nat) != 0)
+ continue;
+#endif
+ }
+ if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
+ nat->nat_ifps[0] = ifp;
+ nat->nat_mtu[0] = GETIFMTU_6(ifp);
+ }
+ return nat;
+ }
+
+ /*
+ * So if we didn't find it but there are wildcard members in the hash
+ * table, go back and look for them. We do this search and update here
+ * because it is modifying the NAT table and we want to do this only
+ * for the first packet that matches. The exception, of course, is
+ * for "dummy" (FI_IGNORE) lookups.
+ */
+find_in_wild_ports:
+ if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
+ NBUMPSIDE6DX(0, ns_lookup_miss, ns_lookup_miss_1);
+ return NULL;
+ }
+ if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
+ NBUMPSIDE6D(0, ns_lookup_nowild);
+ return NULL;
+ }
+
+ RWLOCK_EXIT(&softc->ipf_nat);
+
+ hv = NAT_HASH_FN6(&dst, 0, 0xffffffff);
+ hv = NAT_HASH_FN6(src, hv, softn->ipf_nat_table_sz);
+ WRITE_ENTER(&softc->ipf_nat);
+
+ nat = softn->ipf_nat_table[1][hv];
+ /* TRACE dst, src, hv, nat */
+ for (; nat; nat = nat->nat_hnext[1]) {
+ if (nat->nat_ifps[0] != NULL) {
+ if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
+ continue;
+ }
+
+ if (nat->nat_pr[0] != fin->fin_p)
+ continue;
+
+ switch (nat->nat_dir)
+ {
+ case NAT_INBOUND :
+ if (nat->nat_v[0] != 6)
+ continue;
+ if (IP6_NEQ(&nat->nat_osrc6, src) ||
+ IP6_NEQ(&nat->nat_odst6, &dst))
+ continue;
+ break;
+ case NAT_OUTBOUND :
+ if (nat->nat_v[1] != 6)
+ continue;
+ if (IP6_NEQ(&nat->nat_ndst6, src) ||
+ IP6_NEQ(&nat->nat_nsrc6, &dst))
+ continue;
+ break;
+ }
+
+ nflags = nat->nat_flags;
+ if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
+ continue;
+
+ if (ipf_nat_wildok(nat, (int)sport, (int)dport, nflags,
+ NAT_INBOUND) == 1) {
+ if ((fin->fin_flx & FI_IGNORE) != 0)
+ break;
+ if ((nflags & SI_CLONE) != 0) {
+ nat = ipf_nat_clone(fin, nat);
+ if (nat == NULL)
+ break;
+ } else {
+ MUTEX_ENTER(&softn->ipf_nat_new);
+ softn->ipf_nat_stats.ns_wilds--;
+ MUTEX_EXIT(&softn->ipf_nat_new);
+ }
+
+ if (nat->nat_dir == NAT_INBOUND) {
+ if (nat->nat_osport == 0) {
+ nat->nat_osport = sport;
+ nat->nat_nsport = sport;
+ }
+ if (nat->nat_odport == 0) {
+ nat->nat_odport = dport;
+ nat->nat_ndport = dport;
+ }
+ } else {
+ if (nat->nat_osport == 0) {
+ nat->nat_osport = dport;
+ nat->nat_nsport = dport;
+ }
+ if (nat->nat_odport == 0) {
+ nat->nat_odport = sport;
+ nat->nat_ndport = sport;
+ }
+ }
+ if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
+ nat->nat_ifps[0] = ifp;
+ nat->nat_mtu[0] = GETIFMTU_6(ifp);
+ }
+ nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
+ ipf_nat6_tabmove(softn, nat);
+ break;
+ }
+ }
+
+ MUTEX_DOWNGRADE(&softc->ipf_nat);
+
+ if (nat == NULL) {
+ NBUMPSIDE6DX(0, ns_lookup_miss, ns_lookup_miss_2);
+ }
+ return nat;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_tabmove */
+/* Returns: Nil */
+/* Parameters: nat(I) - pointer to NAT structure */
+/* Write Lock: ipf_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
+ipf_nat6_tabmove(softn, nat)
+ ipf_nat_softc_t *softn;
+ nat_t *nat;
+{
+ nat_t **natp;
+ u_int hv0, hv1;
+
+ if (nat->nat_flags & SI_CLONE)
+ return;
+
+ /*
+ * 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];
+ softn->ipf_nat_stats.ns_side[0].ns_bucketlen[nat->nat_hv[0]]--;
+
+ if (nat->nat_hnext[1])
+ nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
+ *nat->nat_phnext[1] = nat->nat_hnext[1];
+ softn->ipf_nat_stats.ns_side[1].ns_bucketlen[nat->nat_hv[1]]--;
+
+ /*
+ * Add into the NAT table in the new position
+ */
+ hv0 = NAT_HASH_FN6(&nat->nat_osrc6, nat->nat_osport, 0xffffffff);
+ hv0 = NAT_HASH_FN6(&nat->nat_odst6, hv0 + nat->nat_odport,
+ softn->ipf_nat_table_sz);
+ hv1 = NAT_HASH_FN6(&nat->nat_nsrc6, nat->nat_nsport, 0xffffffff);
+ hv1 = NAT_HASH_FN6(&nat->nat_ndst6, hv1 + nat->nat_ndport,
+ softn->ipf_nat_table_sz);
+
+ if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) {
+ u_int swap;
+
+ swap = hv0;
+ hv0 = hv1;
+ hv1 = swap;
+ }
+
+ /* TRACE nat_osrc6, nat_osport, nat_odst6, nat_odport, hv0 */
+ /* TRACE nat_nsrc6, nat_nsport, nat_ndst6, nat_ndport, hv1 */
+
+ nat->nat_hv[0] = hv0;
+ natp = &softn->ipf_nat_table[0][hv0];
+ if (*natp)
+ (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
+ nat->nat_phnext[0] = natp;
+ nat->nat_hnext[0] = *natp;
+ *natp = nat;
+ softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0]++;
+
+ nat->nat_hv[1] = hv1;
+ natp = &softn->ipf_nat_table[1][hv1];
+ if (*natp)
+ (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
+ nat->nat_phnext[1] = natp;
+ nat->nat_hnext[1] = *natp;
+ *natp = nat;
+ softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1]++;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_outlookup */
+/* Returns: nat6_t* - NULL == no match, */
+/* else pointer to matching NAT entry */
+/* Parameters: fin(I) - pointer to packet information */
+/* flags(I) - NAT flags for this packet */
+/* p(I) - protocol for this packet */
+/* src(I) - source IP address */
+/* dst(I) - destination IP address */
+/* rw(I) - 1 == write lock on held, 0 == read lock. */
+/* */
+/* Lookup a nat entry based on the source 'real' ip address/port and */
+/* destination address/port. We use this lookup when sending a packet out, */
+/* we're looking for a table entry, based on the source address. */
+/* */
+/* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY. */
+/* */
+/* NOTE: IT IS ASSUMED THAT IS ONLY HELD WITH A READ LOCK WHEN */
+/* THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags. */
+/* */
+/* flags -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if */
+/* the packet is of said protocol */
+/* ------------------------------------------------------------------------ */
+nat_t *
+ipf_nat6_outlookup(fin, flags, p, src, dst)
+ fr_info_t *fin;
+ u_int flags, p;
+ struct in6_addr *src , *dst;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ u_short sport, dport;
+ u_int sflags;
+ ipnat_t *ipn;
+ nat_t *nat;
+ void *ifp;
+ u_int hv;
+
+ ifp = fin->fin_ifp;
+ sflags = flags & IPN_TCPUDPICMP;
+ sport = 0;
+ dport = 0;
+
+ switch (p)
+ {
+ case IPPROTO_TCP :
+ case IPPROTO_UDP :
+ sport = htons(fin->fin_data[0]);
+ dport = htons(fin->fin_data[1]);
+ break;
+ case IPPROTO_ICMPV6 :
+ if (flags & IPN_ICMPERR)
+ sport = fin->fin_data[1];
+ else
+ dport = fin->fin_data[1];
+ break;
+ default :
+ break;
+ }
+
+ if ((flags & SI_WILDP) != 0)
+ goto find_out_wild_ports;
+
+ hv = NAT_HASH_FN6(src, sport, 0xffffffff);
+ hv = NAT_HASH_FN6(dst, hv + dport, softn->ipf_nat_table_sz);
+ nat = softn->ipf_nat_table[0][hv];
+
+ /* TRACE src, sport, dst, dport, hv, nat */
+
+ for (; nat; nat = nat->nat_hnext[0]) {
+ if (nat->nat_ifps[1] != NULL) {
+ if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
+ continue;
+ }
+
+ if (nat->nat_pr[1] != p)
+ continue;
+
+ switch (nat->nat_dir)
+ {
+ case NAT_INBOUND :
+ if (nat->nat_v[1] != 6)
+ continue;
+ if (IP6_NEQ(&nat->nat_ndst6, src) ||
+ IP6_NEQ(&nat->nat_nsrc6, dst))
+ continue;
+
+ if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+ if (nat->nat_ndport != sport)
+ continue;
+ if (nat->nat_nsport != dport)
+ continue;
+
+ } else if (p == IPPROTO_ICMPV6) {
+ if (nat->nat_osport != dport) {
+ continue;
+ }
+ }
+ break;
+ case NAT_OUTBOUND :
+ if (nat->nat_v[0] != 6)
+ continue;
+ if (IP6_NEQ(&nat->nat_osrc6, src) ||
+ IP6_NEQ(&nat->nat_odst6, dst))
+ continue;
+
+ if ((nat->nat_flags & IPN_TCPUDP) != 0) {
+ if (nat->nat_odport != dport)
+ continue;
+ if (nat->nat_osport != sport)
+ continue;
+
+ } else if (p == IPPROTO_ICMPV6) {
+ if (nat->nat_osport != dport) {
+ continue;
+ }
+ }
+ break;
+ }
+
+ ipn = nat->nat_ptr;
+#ifdef IPF_V6_PROXIES
+ if ((ipn != NULL) && (nat->nat_aps != NULL))
+ if (appr_match(fin, nat) != 0)
+ continue;
+#endif
+
+ if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
+ nat->nat_ifps[1] = ifp;
+ nat->nat_mtu[1] = GETIFMTU_6(ifp);
+ }
+ return nat;
+ }
+
+ /*
+ * So if we didn't find it but there are wildcard members in the hash
+ * table, go back and look for them. We do this search and update here
+ * because it is modifying the NAT table and we want to do this only
+ * for the first packet that matches. The exception, of course, is
+ * for "dummy" (FI_IGNORE) lookups.
+ */
+find_out_wild_ports:
+ if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
+ NBUMPSIDE6DX(1, ns_lookup_miss, ns_lookup_miss_3);
+ return NULL;
+ }
+ if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
+ NBUMPSIDE6D(1, ns_lookup_nowild);
+ return NULL;
+ }
+
+ RWLOCK_EXIT(&softc->ipf_nat);
+
+ hv = NAT_HASH_FN6(src, 0, 0xffffffff);
+ hv = NAT_HASH_FN6(dst, hv, softn->ipf_nat_table_sz);
+
+ WRITE_ENTER(&softc->ipf_nat);
+
+ nat = softn->ipf_nat_table[0][hv];
+ for (; nat; nat = nat->nat_hnext[0]) {
+ if (nat->nat_ifps[1] != NULL) {
+ if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
+ continue;
+ }
+
+ if (nat->nat_pr[1] != fin->fin_p)
+ continue;
+
+ switch (nat->nat_dir)
+ {
+ case NAT_INBOUND :
+ if (nat->nat_v[1] != 6)
+ continue;
+ if (IP6_NEQ(&nat->nat_ndst6, src) ||
+ IP6_NEQ(&nat->nat_nsrc6, dst))
+ continue;
+ break;
+ case NAT_OUTBOUND :
+ if (nat->nat_v[0] != 6)
+ continue;
+ if (IP6_NEQ(&nat->nat_osrc6, src) ||
+ IP6_NEQ(&nat->nat_odst6, dst))
+ continue;
+ break;
+ }
+
+ if (!(nat->nat_flags & (NAT_TCPUDP|SI_WILDP)))
+ continue;
+
+ if (ipf_nat_wildok(nat, (int)sport, (int)dport, nat->nat_flags,
+ NAT_OUTBOUND) == 1) {
+ if ((fin->fin_flx & FI_IGNORE) != 0)
+ break;
+ if ((nat->nat_flags & SI_CLONE) != 0) {
+ nat = ipf_nat_clone(fin, nat);
+ if (nat == NULL)
+ break;
+ } else {
+ MUTEX_ENTER(&softn->ipf_nat_new);
+ softn->ipf_nat_stats.ns_wilds--;
+ MUTEX_EXIT(&softn->ipf_nat_new);
+ }
+
+ if (nat->nat_dir == NAT_OUTBOUND) {
+ if (nat->nat_osport == 0) {
+ nat->nat_osport = sport;
+ nat->nat_nsport = sport;
+ }
+ if (nat->nat_odport == 0) {
+ nat->nat_odport = dport;
+ nat->nat_ndport = dport;
+ }
+ } else {
+ if (nat->nat_osport == 0) {
+ nat->nat_osport = dport;
+ nat->nat_nsport = dport;
+ }
+ if (nat->nat_odport == 0) {
+ nat->nat_odport = sport;
+ nat->nat_ndport = sport;
+ }
+ }
+ if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
+ nat->nat_ifps[1] = ifp;
+ nat->nat_mtu[1] = GETIFMTU_6(ifp);
+ }
+ nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
+ ipf_nat6_tabmove(softn, nat);
+ break;
+ }
+ }
+
+ MUTEX_DOWNGRADE(&softc->ipf_nat);
+
+ if (nat == NULL) {
+ NBUMPSIDE6DX(1, ns_lookup_miss, ns_lookup_miss_4);
+ }
+ return nat;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_lookupredir */
+/* Returns: nat6_t* - NULL == no match, */
+/* else pointer to matching NAT entry */
+/* Parameters: np(I) - pointer to description of packet to find NAT table */
+/* entry for. */
+/* */
+/* Lookup the NAT tables to search for a matching redirect */
+/* The contents of natlookup_t should imitate those found in a packet that */
+/* would be translated - ie a packet coming in for RDR or going out for MAP.*/
+/* We can do the lookup in one of two ways, imitating an inbound or */
+/* outbound packet. By default we assume outbound, unless IPN_IN is set. */
+/* For IN, the fields are set as follows: */
+/* nl_real* = source information */
+/* nl_out* = destination information (translated) */
+/* For an out packet, the fields are set like this: */
+/* nl_in* = source information (untranslated) */
+/* nl_out* = destination information (translated) */
+/* ------------------------------------------------------------------------ */
+nat_t *
+ipf_nat6_lookupredir(np)
+ natlookup_t *np;
+{
+ fr_info_t fi;
+ nat_t *nat;
+
+ bzero((char *)&fi, sizeof(fi));
+ if (np->nl_flags & IPN_IN) {
+ fi.fin_data[0] = ntohs(np->nl_realport);
+ fi.fin_data[1] = ntohs(np->nl_outport);
+ } else {
+ fi.fin_data[0] = ntohs(np->nl_inport);
+ fi.fin_data[1] = ntohs(np->nl_outport);
+ }
+ if (np->nl_flags & IPN_TCP)
+ fi.fin_p = IPPROTO_TCP;
+ else if (np->nl_flags & IPN_UDP)
+ fi.fin_p = IPPROTO_UDP;
+ else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY))
+ fi.fin_p = IPPROTO_ICMPV6;
+
+ /*
+ * We can do two sorts of lookups:
+ * - IPN_IN: we have the `real' and `out' address, look for `in'.
+ * - default: we have the `in' and `out' address, look for `real'.
+ */
+ if (np->nl_flags & IPN_IN) {
+ if ((nat = ipf_nat6_inlookup(&fi, np->nl_flags, fi.fin_p,
+ &np->nl_realip6,
+ &np->nl_outip6))) {
+ np->nl_inip6 = nat->nat_odst6.in6;
+ np->nl_inport = nat->nat_odport;
+ }
+ } else {
+ /*
+ * If nl_inip is non null, this is a lookup based on the real
+ * ip address. Else, we use the fake.
+ */
+ if ((nat = ipf_nat6_outlookup(&fi, np->nl_flags, fi.fin_p,
+ &np->nl_inip6, &np->nl_outip6))) {
+
+ if ((np->nl_flags & IPN_FINDFORWARD) != 0) {
+ fr_info_t fin;
+ bzero((char *)&fin, sizeof(fin));
+ fin.fin_p = nat->nat_pr[0];
+ fin.fin_data[0] = ntohs(nat->nat_ndport);
+ fin.fin_data[1] = ntohs(nat->nat_nsport);
+ if (ipf_nat6_inlookup(&fin, np->nl_flags,
+ fin.fin_p,
+ &nat->nat_ndst6.in6,
+ &nat->nat_nsrc6.in6) !=
+ NULL) {
+ np->nl_flags &= ~IPN_FINDFORWARD;
+ }
+ }
+
+ np->nl_realip6 = nat->nat_ndst6.in6;
+ np->nl_realport = nat->nat_ndport;
+ }
+ }
+
+ return nat;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_match */
+/* Returns: int - 0 == no match, 1 == match */
+/* Parameters: fin(I) - pointer to packet information */
+/* np(I) - pointer to NAT rule */
+/* */
+/* Pull the matching of a packet against a NAT rule out of that complex */
+/* loop inside ipf_nat6_checkin() and lay it out properly in its own */
+/* function. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_match(fin, np)
+ fr_info_t *fin;
+ ipnat_t *np;
+{
+ frtuc_t *ft;
+ int match;
+
+ match = 0;
+ switch (np->in_osrcatype)
+ {
+ case FRI_NORMAL :
+ match = IP6_MASKNEQ(&fin->fin_src6, &np->in_osrcmsk6,
+ &np->in_osrcip6);
+ break;
+ case FRI_LOOKUP :
+ match = (*np->in_osrcfunc)(fin->fin_main_soft, np->in_osrcptr,
+ 6, &fin->fin_src6, fin->fin_plen);
+ break;
+ }
+ match ^= ((np->in_flags & IPN_NOTSRC) != 0);
+ if (match)
+ return 0;
+
+ match = 0;
+ switch (np->in_odstatype)
+ {
+ case FRI_NORMAL :
+ match = IP6_MASKNEQ(&fin->fin_dst6, &np->in_odstmsk6,
+ &np->in_odstip6);
+ break;
+ case FRI_LOOKUP :
+ match = (*np->in_odstfunc)(fin->fin_main_soft, np->in_odstptr,
+ 6, &fin->fin_dst6, fin->fin_plen);
+ break;
+ }
+
+ match ^= ((np->in_flags & IPN_NOTDST) != 0);
+ if (match)
+ return 0;
+
+ ft = &np->in_tuc;
+ if (!(fin->fin_flx & FI_TCPUDP) ||
+ (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
+ if (ft->ftu_scmp || ft->ftu_dcmp)
+ return 0;
+ return 1;
+ }
+
+ return ipf_tcpudpchk(&fin->fin_fi, ft);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_checkout */
+/* Returns: int - -1 == packet failed NAT checks so block it, */
+/* 0 == no packet translation occurred, */
+/* 1 == packet was successfully translated. */
+/* Parameters: fin(I) - pointer to packet information */
+/* passp(I) - pointer to filtering result flags */
+/* */
+/* Check to see if an outcoming packet should be changed. ICMP packets are */
+/* first checked to see if they match an existing entry (if an error), */
+/* otherwise a search of the current NAT table is made. If neither results */
+/* in a match then a search for a matching NAT rule is made. Create a new */
+/* NAT entry if a we matched a NAT rule. Lastly, actually change the */
+/* packet header(s) as required. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat6_checkout(fin, passp)
+ fr_info_t *fin;
+ u_32_t *passp;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ struct icmp6_hdr *icmp6 = NULL;
+ struct ifnet *ifp, *sifp;
+ tcphdr_t *tcp = NULL;
+ int rval, natfailed;
+ ipnat_t *np = NULL;
+ u_int nflags = 0;
+ i6addr_t ipa, iph;
+ int natadd = 1;
+ frentry_t *fr;
+ nat_t *nat;
+
+ if (softn->ipf_nat_stats.ns_rules == 0 || softn->ipf_nat_lock != 0)
+ return 0;
+
+ icmp6 = NULL;
+ natfailed = 0;
+ fr = fin->fin_fr;
+ sifp = fin->fin_ifp;
+ if (fr != NULL) {
+ ifp = fr->fr_tifs[fin->fin_rev].fd_ptr;
+ if ((ifp != NULL) && (ifp != (void *)-1))
+ fin->fin_ifp = ifp;
+ }
+ ifp = fin->fin_ifp;
+
+ if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
+ switch (fin->fin_p)
+ {
+ case IPPROTO_TCP :
+ nflags = IPN_TCP;
+ break;
+ case IPPROTO_UDP :
+ nflags = IPN_UDP;
+ break;
+ case IPPROTO_ICMPV6 :
+ icmp6 = fin->fin_dp;
+
+ /*
+ * Apart from ECHO request and reply, all other
+ * informational messages should not be translated
+ * so as to keep IPv6 working.
+ */
+ if (icmp6->icmp6_type > ICMP6_ECHO_REPLY)
+ return 0;
+
+ /*
+ * This is an incoming packet, so the destination is
+ * the icmp6_id and the source port equals 0
+ */
+ if ((fin->fin_flx & FI_ICMPQUERY) != 0)
+ nflags = IPN_ICMPQUERY;
+ break;
+ default :
+ break;
+ }
+
+ if ((nflags & IPN_TCPUDP))
+ tcp = fin->fin_dp;
+ }
+
+ ipa = fin->fin_src6;
+
+ READ_ENTER(&softc->ipf_nat);
+
+ if ((fin->fin_p == IPPROTO_ICMPV6) && !(nflags & IPN_ICMPQUERY) &&
+ (nat = ipf_nat6_icmperror(fin, &nflags, NAT_OUTBOUND)))
+ /*EMPTY*/;
+ else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
+ natadd = 0;
+ else if ((nat = ipf_nat6_outlookup(fin, nflags|NAT_SEARCH,
+ (u_int)fin->fin_p,
+ &fin->fin_src6.in6,
+ &fin->fin_dst6.in6))) {
+ nflags = nat->nat_flags;
+ } else if (fin->fin_off == 0) {
+ u_32_t hv, nmsk = 0;
+ i6addr_t *msk;
+
+ /*
+ * If there is no current entry in the nat table for this IP#,
+ * create one for it (if there is a matching rule).
+ */
+maskloop:
+ msk = &softn->ipf_nat6_map_active_masks[nmsk];
+ IP6_AND(&ipa, msk, &iph);
+ hv = NAT_HASH_FN6(&iph, 0, softn->ipf_nat_maprules_sz);
+ for (np = softn->ipf_nat_map_rules[hv]; np; np = np->in_mnext) {
+ if ((np->in_ifps[1] && (np->in_ifps[1] != ifp)))
+ continue;
+ if (np->in_v[0] != 6)
+ continue;
+ if (np->in_pr[1] && (np->in_pr[1] != fin->fin_p))
+ continue;
+ if ((np->in_flags & IPN_RF) &&
+ !(np->in_flags & nflags))
+ continue;
+ if (np->in_flags & IPN_FILTER) {
+ switch (ipf_nat6_match(fin, np))
+ {
+ case 0 :
+ continue;
+ case -1 :
+ rval = -1;
+ goto outmatchfail;
+ case 1 :
+ default :
+ break;
+ }
+ } else if (!IP6_MASKEQ(&ipa, &np->in_osrcmsk,
+ &np->in_osrcip6))
+ continue;
+
+ if ((fr != NULL) &&
+ !ipf_matchtag(&np->in_tag, &fr->fr_nattag))
+ continue;
+
+#ifdef IPF_V6_PROXIES
+ if (np->in_plabel != -1) {
+ if (((np->in_flags & IPN_FILTER) == 0) &&
+ (np->in_odport != fin->fin_data[1]))
+ continue;
+ if (appr_ok(fin, tcp, np) == 0)
+ continue;
+ }
+#endif
+
+ if (np->in_flags & IPN_NO) {
+ np->in_hits++;
+ break;
+ }
+
+ MUTEX_ENTER(&softn->ipf_nat_new);
+ nat = ipf_nat6_add(fin, np, NULL, nflags, NAT_OUTBOUND);
+ MUTEX_EXIT(&softn->ipf_nat_new);
+ if (nat != NULL) {
+ np->in_hits++;
+ break;
+ }
+ natfailed = -1;
+ }
+ if ((np == NULL) && (nmsk < softn->ipf_nat6_map_max)) {
+ nmsk++;
+ goto maskloop;
+ }
+ }
+
+ if (nat != NULL) {
+ rval = ipf_nat6_out(fin, nat, natadd, nflags);
+ if (rval == 1) {
+ MUTEX_ENTER(&nat->nat_lock);
+ ipf_nat_update(fin, nat);
+ nat->nat_bytes[1] += fin->fin_plen;
+ nat->nat_pkts[1]++;
+ MUTEX_EXIT(&nat->nat_lock);
+ }
+ } else
+ rval = natfailed;
+outmatchfail:
+ RWLOCK_EXIT(&softc->ipf_nat);
+
+ switch (rval)
+ {
+ case -1 :
+ if (passp != NULL) {
+ NBUMPSIDE6D(1, ns_drop);
+ *passp = FR_BLOCK;
+ fin->fin_reason = FRB_NATV6;
+ }
+ fin->fin_flx |= FI_BADNAT;
+ NBUMPSIDE6D(1, ns_badnat);
+ break;
+ case 0 :
+ NBUMPSIDE6D(1, ns_ignored);
+ break;
+ case 1 :
+ NBUMPSIDE6D(1, ns_translated);
+ break;
+ }
+ fin->fin_ifp = sifp;
+ return rval;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_out */
+/* Returns: int - -1 == packet failed NAT checks so block it, */
+/* 1 == packet was successfully translated. */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to NAT structure */
+/* natadd(I) - flag indicating if it is safe to add frag cache */
+/* nflags(I) - NAT flags set for this packet */
+/* */
+/* Translate a packet coming "out" on an interface. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_out(fin, nat, natadd, nflags)
+ fr_info_t *fin;
+ nat_t *nat;
+ int natadd;
+ u_32_t nflags;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ struct icmp6_hdr *icmp6;
+ tcphdr_t *tcp;
+ ipnat_t *np;
+ int skip;
+ int i;
+
+ tcp = NULL;
+ icmp6 = NULL;
+ np = nat->nat_ptr;
+
+ if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL))
+ (void) ipf_frag_natnew(softc, fin, 0, nat);
+
+ /*
+ * Address assignment is after the checksum modification because
+ * we are using the address in the packet for determining the
+ * correct checksum offset (the ICMP error could be coming from
+ * anyone...)
+ */
+ switch (nat->nat_dir)
+ {
+ case NAT_OUTBOUND :
+ fin->fin_ip6->ip6_src = nat->nat_nsrc6.in6;
+ fin->fin_src6 = nat->nat_nsrc6;
+ fin->fin_ip6->ip6_dst = nat->nat_ndst6.in6;
+ fin->fin_dst6 = nat->nat_ndst6;
+ break;
+
+ case NAT_INBOUND :
+ fin->fin_ip6->ip6_src = nat->nat_odst6.in6;
+ fin->fin_src6 = nat->nat_ndst6;
+ fin->fin_ip6->ip6_dst = nat->nat_osrc6.in6;
+ fin->fin_dst6 = nat->nat_nsrc6;
+ break;
+
+ case NAT_DIVERTIN :
+ {
+ mb_t *m;
+
+ skip = ipf_nat6_decap(fin, nat);
+ if (skip <= 0) {
+ NBUMPSIDE6D(1, ns_decap_fail);
+ return -1;
+ }
+
+ m = fin->fin_m;
+
+#if defined(MENTAT) && defined(_KERNEL)
+ m->b_rptr += skip;
+#else
+ m->m_data += skip;
+ m->m_len -= skip;
+
+# ifdef M_PKTHDR
+ if (m->m_flags & M_PKTHDR)
+ m->m_pkthdr.len -= skip;
+# endif
+#endif
+
+ MUTEX_ENTER(&nat->nat_lock);
+ ipf_nat_update(fin, nat);
+ MUTEX_EXIT(&nat->nat_lock);
+ fin->fin_flx |= FI_NATED;
+ if (np != NULL && np->in_tag.ipt_num[0] != 0)
+ fin->fin_nattag = &np->in_tag;
+ return 1;
+ /* NOTREACHED */
+ }
+
+ case NAT_DIVERTOUT :
+ {
+ udphdr_t *uh;
+ ip6_t *ip6;
+ mb_t *m;
+
+ m = M_DUP(np->in_divmp);
+ if (m == NULL) {
+ NBUMPSIDE6D(1, ns_divert_dup);
+ return -1;
+ }
+
+ ip6 = MTOD(m, ip6_t *);
+
+ ip6->ip6_plen = htons(fin->fin_plen + 8);
+
+ uh = (udphdr_t *)(ip6 + 1);
+ uh->uh_ulen = htons(fin->fin_plen);
+
+ PREP_MB_T(fin, m);
+
+ fin->fin_ip6 = ip6;
+ fin->fin_plen += sizeof(ip6_t) + 8; /* UDP + new IPv4 hdr */
+ fin->fin_dlen += sizeof(ip6_t) + 8; /* UDP + old IPv4 hdr */
+
+ nflags &= ~IPN_TCPUDPICMP;
+
+ break;
+ }
+
+ default :
+ break;
+ }
+
+ if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
+ u_short *csump;
+
+ if ((nat->nat_nsport != 0) && (nflags & IPN_TCPUDP)) {
+ tcp = fin->fin_dp;
+
+ switch (nat->nat_dir)
+ {
+ case NAT_OUTBOUND :
+ tcp->th_sport = nat->nat_nsport;
+ fin->fin_data[0] = ntohs(nat->nat_nsport);
+ tcp->th_dport = nat->nat_ndport;
+ fin->fin_data[1] = ntohs(nat->nat_ndport);
+ break;
+
+ case NAT_INBOUND :
+ tcp->th_sport = nat->nat_odport;
+ fin->fin_data[0] = ntohs(nat->nat_odport);
+ tcp->th_dport = nat->nat_osport;
+ fin->fin_data[1] = ntohs(nat->nat_osport);
+ break;
+ }
+ }
+
+ if ((nat->nat_nsport != 0) && (nflags & IPN_ICMPQUERY)) {
+ icmp6 = fin->fin_dp;
+ icmp6->icmp6_id = nat->nat_nicmpid;
+ }
+
+ csump = ipf_nat_proto(fin, nat, nflags);
+
+ /*
+ * The above comments do not hold for layer 4 (or higher)
+ * checksums...
+ */
+ if (csump != NULL) {
+ if (nat->nat_dir == NAT_OUTBOUND)
+ ipf_fix_outcksum(fin->fin_cksum, csump,
+ nat->nat_sumd[0],
+ nat->nat_sumd[1] +
+ fin->fin_dlen);
+ else
+ ipf_fix_incksum(fin->fin_cksum, csump,
+ nat->nat_sumd[0],
+ nat->nat_sumd[1] +
+ fin->fin_dlen);
+ }
+ }
+
+ ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
+ /* ------------------------------------------------------------- */
+ /* A few quick notes: */
+ /* Following are test conditions prior to calling the */
+ /* ipf_proxy_check routine. */
+ /* */
+ /* A NULL tcp indicates a non TCP/UDP packet. When dealing */
+ /* with a redirect rule, we attempt to match the packet's */
+ /* source port against in_dport, otherwise we'd compare the */
+ /* packet's destination. */
+ /* ------------------------------------------------------------- */
+ if ((np != NULL) && (np->in_apr != NULL)) {
+ i = ipf_proxy_check(fin, nat);
+ if (i == 0) {
+ i = 1;
+ } else if (i == -1) {
+ NBUMPSIDE6D(1, ns_ipf_proxy_fail);
+ }
+ } else {
+ i = 1;
+ }
+ fin->fin_flx |= FI_NATED;
+ return i;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_checkin */
+/* Returns: int - -1 == packet failed NAT checks so block it, */
+/* 0 == no packet translation occurred, */
+/* 1 == packet was successfully translated. */
+/* Parameters: fin(I) - pointer to packet information */
+/* passp(I) - pointer to filtering result flags */
+/* */
+/* Check to see if an incoming packet should be changed. ICMP packets are */
+/* first checked to see if they match an existing entry (if an error), */
+/* otherwise a search of the current NAT table is made. If neither results */
+/* in a match then a search for a matching NAT rule is made. Create a new */
+/* NAT entry if a we matched a NAT rule. Lastly, actually change the */
+/* packet header(s) as required. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat6_checkin(fin, passp)
+ fr_info_t *fin;
+ u_32_t *passp;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ struct icmp6_hdr *icmp6;
+ u_int nflags, natadd;
+ int rval, natfailed;
+ struct ifnet *ifp;
+ i6addr_t ipa, iph;
+ tcphdr_t *tcp;
+ u_short dport;
+ ipnat_t *np;
+ nat_t *nat;
+
+ if (softn->ipf_nat_stats.ns_rules == 0 || softn->ipf_nat_lock != 0)
+ return 0;
+
+ tcp = NULL;
+ icmp6 = NULL;
+ dport = 0;
+ natadd = 1;
+ nflags = 0;
+ natfailed = 0;
+ ifp = fin->fin_ifp;
+
+ if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
+ switch (fin->fin_p)
+ {
+ case IPPROTO_TCP :
+ nflags = IPN_TCP;
+ break;
+ case IPPROTO_UDP :
+ nflags = IPN_UDP;
+ break;
+ case IPPROTO_ICMPV6 :
+ icmp6 = fin->fin_dp;
+
+ /*
+ * Apart from ECHO request and reply, all other
+ * informational messages should not be translated
+ * so as to keep IPv6 working.
+ */
+ if (icmp6->icmp6_type > ICMP6_ECHO_REPLY)
+ return 0;
+
+ /*
+ * This is an incoming packet, so the destination is
+ * the icmp6_id and the source port equals 0
+ */
+ if ((fin->fin_flx & FI_ICMPQUERY) != 0) {
+ nflags = IPN_ICMPQUERY;
+ dport = icmp6->icmp6_id;
+ } break;
+ default :
+ break;
+ }
+
+ if ((nflags & IPN_TCPUDP)) {
+ tcp = fin->fin_dp;
+ dport = fin->fin_data[1];
+ }
+ }
+
+ ipa = fin->fin_dst6;
+
+ READ_ENTER(&softc->ipf_nat);
+
+ if ((fin->fin_p == IPPROTO_ICMPV6) && !(nflags & IPN_ICMPQUERY) &&
+ (nat = ipf_nat6_icmperror(fin, &nflags, NAT_INBOUND)))
+ /*EMPTY*/;
+ else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
+ natadd = 0;
+ else if ((nat = ipf_nat6_inlookup(fin, nflags|NAT_SEARCH,
+ (u_int)fin->fin_p,
+ &fin->fin_src6.in6, &ipa.in6))) {
+ nflags = nat->nat_flags;
+ } else if (fin->fin_off == 0) {
+ u_32_t hv, rmsk = 0;
+ i6addr_t *msk;
+
+ /*
+ * If there is no current entry in the nat table for this IP#,
+ * create one for it (if there is a matching rule).
+ */
+maskloop:
+ msk = &softn->ipf_nat6_rdr_active_masks[rmsk];
+ IP6_AND(&ipa, msk, &iph);
+ hv = NAT_HASH_FN6(&iph, 0, softn->ipf_nat_rdrrules_sz);
+ for (np = softn->ipf_nat_rdr_rules[hv]; np; np = np->in_rnext) {
+ if (np->in_ifps[0] && (np->in_ifps[0] != ifp))
+ continue;
+ if (np->in_v[0] != 6)
+ continue;
+ if (np->in_pr[0] && (np->in_pr[0] != fin->fin_p))
+ continue;
+ if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
+ continue;
+ if (np->in_flags & IPN_FILTER) {
+ switch (ipf_nat6_match(fin, np))
+ {
+ case 0 :
+ continue;
+ case -1 :
+ rval = -1;
+ goto inmatchfail;
+ case 1 :
+ default :
+ break;
+ }
+ } else {
+ if (!IP6_MASKEQ(&ipa, &np->in_odstmsk6,
+ &np->in_odstip6)) {
+ continue;
+ }
+ if (np->in_odport &&
+ ((np->in_dtop < dport) ||
+ (dport < np->in_odport)))
+ continue;
+ }
+
+#ifdef IPF_V6_PROXIES
+ if (np->in_plabel != -1) {
+ if (!appr_ok(fin, tcp, np)) {
+ continue;
+ }
+ }
+#endif
+
+ if (np->in_flags & IPN_NO) {
+ np->in_hits++;
+ break;
+ }
+
+ MUTEX_ENTER(&softn->ipf_nat_new);
+ nat = ipf_nat6_add(fin, np, NULL, nflags, NAT_INBOUND);
+ MUTEX_EXIT(&softn->ipf_nat_new);
+ if (nat != NULL) {
+ np->in_hits++;
+ break;
+ }
+ natfailed = -1;
+ }
+
+ if ((np == NULL) && (rmsk < softn->ipf_nat6_rdr_max)) {
+ rmsk++;
+ goto maskloop;
+ }
+ }
+ if (nat != NULL) {
+ rval = ipf_nat6_in(fin, nat, natadd, nflags);
+ if (rval == 1) {
+ MUTEX_ENTER(&nat->nat_lock);
+ ipf_nat_update(fin, nat);
+ nat->nat_bytes[0] += fin->fin_plen;
+ nat->nat_pkts[0]++;
+ MUTEX_EXIT(&nat->nat_lock);
+ }
+ } else
+ rval = natfailed;
+inmatchfail:
+ RWLOCK_EXIT(&softc->ipf_nat);
+
+ switch (rval)
+ {
+ case -1 :
+ if (passp != NULL) {
+ NBUMPSIDE6D(0, ns_drop);
+ *passp = FR_BLOCK;
+ fin->fin_reason = FRB_NATV6;
+ }
+ fin->fin_flx |= FI_BADNAT;
+ NBUMPSIDE6D(0, ns_badnat);
+ break;
+ case 0 :
+ NBUMPSIDE6D(0, ns_ignored);
+ break;
+ case 1 :
+ NBUMPSIDE6D(0, ns_translated);
+ break;
+ }
+ return rval;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_in */
+/* Returns: int - -1 == packet failed NAT checks so block it, */
+/* 1 == packet was successfully translated. */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to NAT structure */
+/* natadd(I) - flag indicating if it is safe to add frag cache */
+/* nflags(I) - NAT flags set for this packet */
+/* Locks Held: (READ) */
+/* */
+/* Translate a packet coming "in" on an interface. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_in(fin, nat, natadd, nflags)
+ fr_info_t *fin;
+ nat_t *nat;
+ int natadd;
+ u_32_t nflags;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ struct icmp6_hdr *icmp6;
+ u_short *csump;
+ tcphdr_t *tcp;
+ ipnat_t *np;
+ int skip;
+ int i;
+
+ tcp = NULL;
+ csump = NULL;
+ np = nat->nat_ptr;
+ fin->fin_fr = nat->nat_fr;
+
+ if (np != NULL) {
+ if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
+ (void) ipf_frag_natnew(softc, fin, 0, nat);
+
+ /* ------------------------------------------------------------- */
+ /* A few quick notes: */
+ /* Following are test conditions prior to calling the */
+ /* ipf_proxy_check routine. */
+ /* */
+ /* A NULL tcp indicates a non TCP/UDP packet. When dealing */
+ /* with a map rule, we attempt to match the packet's */
+ /* source port against in_dport, otherwise we'd compare the */
+ /* packet's destination. */
+ /* ------------------------------------------------------------- */
+ if (np->in_apr != NULL) {
+ i = ipf_proxy_check(fin, nat);
+ if (i == -1) {
+ NBUMPSIDE6D(0, ns_ipf_proxy_fail);
+ return -1;
+ }
+ }
+ }
+
+ ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
+
+ /*
+ * Fix up checksums, not by recalculating them, but
+ * simply computing adjustments.
+ * Why only do this for some platforms on inbound packets ?
+ * Because for those that it is done, IP processing is yet to happen
+ * and so the IPv4 header checksum has not yet been evaluated.
+ * Perhaps it should always be done for the benefit of things like
+ * fast forwarding (so that it doesn't need to be recomputed) but with
+ * header checksum offloading, perhaps it is a moot point.
+ */
+
+ switch (nat->nat_dir)
+ {
+ case NAT_INBOUND :
+ if ((fin->fin_flx & FI_ICMPERR) == 0) {
+ fin->fin_ip6->ip6_src = nat->nat_nsrc6.in6;
+ fin->fin_src6 = nat->nat_nsrc6;
+ }
+ fin->fin_ip6->ip6_dst = nat->nat_ndst6.in6;
+ fin->fin_dst6 = nat->nat_ndst6;
+ break;
+
+ case NAT_OUTBOUND :
+ if ((fin->fin_flx & FI_ICMPERR) == 0) {
+ fin->fin_ip6->ip6_src = nat->nat_odst6.in6;
+ fin->fin_src6 = nat->nat_odst6;
+ }
+ fin->fin_ip6->ip6_dst = nat->nat_osrc6.in6;
+ fin->fin_dst6 = nat->nat_osrc6;
+ break;
+
+ case NAT_DIVERTIN :
+ {
+ udphdr_t *uh;
+ ip6_t *ip6;
+ mb_t *m;
+
+ m = M_DUP(np->in_divmp);
+ if (m == NULL) {
+ NBUMPSIDE6D(0, ns_divert_dup);
+ return -1;
+ }
+
+ ip6 = MTOD(m, ip6_t *);
+ ip6->ip6_plen = htons(fin->fin_plen + sizeof(udphdr_t));
+
+ uh = (udphdr_t *)(ip6 + 1);
+ uh->uh_ulen = ntohs(fin->fin_plen);
+
+ PREP_MB_T(fin, m);
+
+ fin->fin_ip6 = ip6;
+ fin->fin_plen += sizeof(ip6_t) + 8; /* UDP + new IPv6 hdr */
+ fin->fin_dlen += sizeof(ip6_t) + 8; /* UDP + old IPv6 hdr */
+
+ nflags &= ~IPN_TCPUDPICMP;
+
+ break;
+ }
+
+ case NAT_DIVERTOUT :
+ {
+ mb_t *m;
+
+ skip = ipf_nat6_decap(fin, nat);
+ if (skip <= 0) {
+ NBUMPSIDE6D(0, ns_decap_fail);
+ return -1;
+ }
+
+ m = fin->fin_m;
+
+#if defined(MENTAT) && defined(_KERNEL)
+ m->b_rptr += skip;
+#else
+ m->m_data += skip;
+ m->m_len -= skip;
+
+# ifdef M_PKTHDR
+ if (m->m_flags & M_PKTHDR)
+ m->m_pkthdr.len -= skip;
+# endif
+#endif
+
+ ipf_nat_update(fin, nat);
+ fin->fin_flx |= FI_NATED;
+ if (np != NULL && np->in_tag.ipt_num[0] != 0)
+ fin->fin_nattag = &np->in_tag;
+ return 1;
+ /* NOTREACHED */
+ }
+ }
+ if (nflags & IPN_TCPUDP)
+ tcp = fin->fin_dp;
+
+ if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
+ if ((nat->nat_odport != 0) && (nflags & IPN_TCPUDP)) {
+ switch (nat->nat_dir)
+ {
+ case NAT_INBOUND :
+ tcp->th_sport = nat->nat_nsport;
+ fin->fin_data[0] = ntohs(nat->nat_nsport);
+ tcp->th_dport = nat->nat_ndport;
+ fin->fin_data[1] = ntohs(nat->nat_ndport);
+ break;
+
+ case NAT_OUTBOUND :
+ tcp->th_sport = nat->nat_odport;
+ fin->fin_data[0] = ntohs(nat->nat_odport);
+ tcp->th_dport = nat->nat_osport;
+ fin->fin_data[1] = ntohs(nat->nat_osport);
+ break;
+ }
+ }
+
+
+ if ((nat->nat_odport != 0) && (nflags & IPN_ICMPQUERY)) {
+ icmp6 = fin->fin_dp;
+
+ icmp6->icmp6_id = nat->nat_nicmpid;
+ }
+
+ csump = ipf_nat_proto(fin, nat, nflags);
+ }
+
+ /*
+ * The above comments do not hold for layer 4 (or higher) checksums...
+ */
+ if (csump != NULL) {
+ if (nat->nat_dir == NAT_OUTBOUND)
+ ipf_fix_incksum(0, csump, nat->nat_sumd[0], 0);
+ else
+ ipf_fix_outcksum(0, csump, nat->nat_sumd[0], 0);
+ }
+ fin->fin_flx |= FI_NATED;
+ if (np != NULL && np->in_tag.ipt_num[0] != 0)
+ fin->fin_nattag = &np->in_tag;
+ return 1;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_newrewrite */
+/* Returns: int - -1 == error, 0 == success (no move), 1 == success and */
+/* allow rule to be moved if IPN_ROUNDR is set. */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to NAT entry */
+/* ni(I) - pointer to structure with misc. information needed */
+/* to create new NAT entry. */
+/* Write Lock: ipf_nat */
+/* */
+/* This function is responsible for setting up an active NAT session where */
+/* we are changing both the source and destination parameters at the same */
+/* time. The loop in here works differently to elsewhere - each iteration */
+/* is responsible for changing a single parameter that can be incremented. */
+/* So one pass may increase the source IP#, next source port, next dest. IP#*/
+/* and the last destination port for a total of 4 iterations to try each. */
+/* This is done to try and exhaustively use the translation space available.*/
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat6_newrewrite(fin, nat, nai)
+ fr_info_t *fin;
+ nat_t *nat;
+ natinfo_t *nai;
+{
+ int src_search = 1;
+ int dst_search = 1;
+ fr_info_t frnat;
+ u_32_t flags;
+ u_short swap;
+ ipnat_t *np;
+ nat_t *natl;
+ int l = 0;
+ int changed;
+
+ natl = NULL;
+ changed = -1;
+ np = nai->nai_np;
+ flags = nat->nat_flags;
+ bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
+
+ nat->nat_hm = NULL;
+
+ do {
+ changed = -1;
+ /* TRACE (l, src_search, dst_search, np) */
+
+ if ((src_search == 0) && (np->in_spnext == 0) &&
+ (dst_search == 0) && (np->in_dpnext == 0)) {
+ if (l > 0)
+ return -1;
+ }
+
+ /*
+ * Find a new source address
+ */
+ if (ipf_nat6_nextaddr(fin, &np->in_nsrc, &frnat.fin_src6,
+ &frnat.fin_src6) == -1) {
+ return -1;
+ }
+
+ if (IP6_ISZERO(&np->in_nsrcip6) &&
+ IP6_ISONES(&np->in_nsrcmsk6)) {
+ src_search = 0;
+ if (np->in_stepnext == 0)
+ np->in_stepnext = 1;
+
+ } else if (IP6_ISZERO(&np->in_nsrcip6) &&
+ IP6_ISZERO(&np->in_nsrcmsk6)) {
+ src_search = 0;
+ if (np->in_stepnext == 0)
+ np->in_stepnext = 1;
+
+ } else if (IP6_ISONES(&np->in_nsrcmsk)) {
+ src_search = 0;
+ if (np->in_stepnext == 0)
+ np->in_stepnext = 1;
+
+ } else if (!IP6_ISONES(&np->in_nsrcmsk6)) {
+ if (np->in_stepnext == 0 && changed == -1) {
+ IP6_INC(&np->in_snip);
+ np->in_stepnext++;
+ changed = 0;
+ }
+ }
+
+ if ((flags & IPN_TCPUDPICMP) != 0) {
+ if (np->in_spnext != 0)
+ frnat.fin_data[0] = np->in_spnext;
+
+ /*
+ * Standard port translation. Select next port.
+ */
+ if ((flags & IPN_FIXEDSPORT) != 0) {
+ np->in_stepnext = 2;
+ } else if ((np->in_stepnext == 1) &&
+ (changed == -1) && (natl != NULL)) {
+ np->in_spnext++;
+ np->in_stepnext++;
+ changed = 1;
+ if (np->in_spnext > np->in_spmax)
+ np->in_spnext = np->in_spmin;
+ }
+ } else {
+ np->in_stepnext = 2;
+ }
+ np->in_stepnext &= 0x3;
+
+ /*
+ * Find a new destination address
+ */
+ /* TRACE (fin, np, l, frnat) */
+
+ if (ipf_nat6_nextaddr(fin, &np->in_ndst, &frnat.fin_dst6,
+ &frnat.fin_dst6) == -1)
+ return -1;
+
+ if (IP6_ISZERO(&np->in_ndstip6) &&
+ IP6_ISONES(&np->in_ndstmsk6)) {
+ dst_search = 0;
+ if (np->in_stepnext == 2)
+ np->in_stepnext = 3;
+
+ } else if (IP6_ISZERO(&np->in_ndstip6) &&
+ IP6_ISZERO(&np->in_ndstmsk6)) {
+ dst_search = 0;
+ if (np->in_stepnext == 2)
+ np->in_stepnext = 3;
+
+ } else if (IP6_ISONES(&np->in_ndstmsk6)) {
+ dst_search = 0;
+ if (np->in_stepnext == 2)
+ np->in_stepnext = 3;
+
+ } else if (!IP6_ISONES(&np->in_ndstmsk6)) {
+ if ((np->in_stepnext == 2) && (changed == -1) &&
+ (natl != NULL)) {
+ changed = 2;
+ np->in_stepnext++;
+ IP6_INC(&np->in_dnip6);
+ }
+ }
+
+ if ((flags & IPN_TCPUDPICMP) != 0) {
+ if (np->in_dpnext != 0)
+ frnat.fin_data[1] = np->in_dpnext;
+
+ /*
+ * Standard port translation. Select next port.
+ */
+ if ((flags & IPN_FIXEDDPORT) != 0) {
+ np->in_stepnext = 0;
+ } else if (np->in_stepnext == 3 && changed == -1) {
+ np->in_dpnext++;
+ np->in_stepnext++;
+ changed = 3;
+ if (np->in_dpnext > np->in_dpmax)
+ np->in_dpnext = np->in_dpmin;
+ }
+ } else {
+ if (np->in_stepnext == 3)
+ np->in_stepnext = 0;
+ }
+
+ /* TRACE (frnat) */
+
+ /*
+ * 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.
+ *
+ * fin_data[] is swapped around because we are doing a
+ * lookup of the packet is if it were moving in the opposite
+ * direction of the one we are working with now.
+ */
+ if (flags & IPN_TCPUDP) {
+ swap = frnat.fin_data[0];
+ frnat.fin_data[0] = frnat.fin_data[1];
+ frnat.fin_data[1] = swap;
+ }
+ if (fin->fin_out == 1) {
+ natl = ipf_nat6_inlookup(&frnat,
+ flags & ~(SI_WILDP|NAT_SEARCH),
+ (u_int)frnat.fin_p,
+ &frnat.fin_dst6.in6,
+ &frnat.fin_src6.in6);
+
+ } else {
+ natl = ipf_nat6_outlookup(&frnat,
+ flags & ~(SI_WILDP|NAT_SEARCH),
+ (u_int)frnat.fin_p,
+ &frnat.fin_dst6.in6,
+ &frnat.fin_src6.in6);
+ }
+ if (flags & IPN_TCPUDP) {
+ swap = frnat.fin_data[0];
+ frnat.fin_data[0] = frnat.fin_data[1];
+ frnat.fin_data[1] = swap;
+ }
+
+ /* TRACE natl, in_stepnext, l */
+
+ if ((natl != NULL) && (l > 8)) /* XXX 8 is arbitrary */
+ return -1;
+
+ np->in_stepnext &= 0x3;
+
+ l++;
+ changed = -1;
+ } while (natl != NULL);
+ nat->nat_osrc6 = fin->fin_src6;
+ nat->nat_odst6 = fin->fin_dst6;
+ nat->nat_nsrc6 = frnat.fin_src6;
+ nat->nat_ndst6 = frnat.fin_dst6;
+
+ if ((flags & IPN_TCPUDP) != 0) {
+ nat->nat_osport = htons(fin->fin_data[0]);
+ nat->nat_odport = htons(fin->fin_data[1]);
+ nat->nat_nsport = htons(frnat.fin_data[0]);
+ nat->nat_ndport = htons(frnat.fin_data[1]);
+ } else if ((flags & IPN_ICMPQUERY) != 0) {
+ nat->nat_oicmpid = fin->fin_data[1];
+ nat->nat_nicmpid = frnat.fin_data[1];
+ }
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_newdivert */
+/* Returns: int - -1 == error, 0 == success */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to NAT entry */
+/* ni(I) - pointer to structure with misc. information needed */
+/* to create new NAT entry. */
+/* Write Lock: ipf_nat */
+/* */
+/* Create a new NAT divert session as defined by the NAT rule. This is */
+/* somewhat different to other NAT session creation routines because we */
+/* do not iterate through either port numbers or IP addresses, searching */
+/* for a unique mapping, however, a complimentary duplicate check is made. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_nat6_newdivert(fin, nat, nai)
+ fr_info_t *fin;
+ nat_t *nat;
+ natinfo_t *nai;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ fr_info_t frnat;
+ ipnat_t *np;
+ nat_t *natl;
+ int p;
+
+ np = nai->nai_np;
+ bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
+
+ nat->nat_pr[0] = 0;
+ nat->nat_osrc6 = fin->fin_src6;
+ nat->nat_odst6 = fin->fin_dst6;
+ nat->nat_osport = htons(fin->fin_data[0]);
+ nat->nat_odport = htons(fin->fin_data[1]);
+ frnat.fin_src6 = np->in_snip6;
+ frnat.fin_dst6 = np->in_dnip6;
+
+ if (np->in_redir & NAT_DIVERTUDP) {
+ frnat.fin_data[0] = np->in_spnext;
+ frnat.fin_data[1] = np->in_dpnext;
+ frnat.fin_flx |= FI_TCPUDP;
+ p = IPPROTO_UDP;
+ } else {
+ frnat.fin_flx &= ~FI_TCPUDP;
+ p = IPPROTO_IPIP;
+ }
+
+ if (fin->fin_out == 1) {
+ natl = ipf_nat6_inlookup(&frnat, 0, p, &frnat.fin_dst6.in6,
+ &frnat.fin_src6.in6);
+
+ } else {
+ natl = ipf_nat6_outlookup(&frnat, 0, p, &frnat.fin_dst6.in6,
+ &frnat.fin_src6.in6);
+ }
+
+ if (natl != NULL) {
+ NBUMPSIDE6D(fin->fin_out, ns_divert_exist);
+ return -1;
+ }
+
+ nat->nat_nsrc6 = frnat.fin_src6;
+ nat->nat_ndst6 = frnat.fin_dst6;
+ if (np->in_redir & NAT_DIVERTUDP) {
+ nat->nat_nsport = htons(frnat.fin_data[0]);
+ nat->nat_ndport = htons(frnat.fin_data[1]);
+ }
+ nat->nat_pr[fin->fin_out] = fin->fin_p;
+ nat->nat_pr[1 - fin->fin_out] = p;
+
+ if (np->in_redir & NAT_REDIRECT)
+ nat->nat_dir = NAT_DIVERTIN;
+ else
+ nat->nat_dir = NAT_DIVERTOUT;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_builddivertmp */
+/* Returns: int - -1 == error, 0 == success */
+/* Parameters: np(I) - pointer to a NAT rule */
+/* */
+/* For divert rules, a skeleton packet representing what will be prepended */
+/* to the real packet is created. Even though we don't have the full */
+/* packet here, a checksum is calculated that we update later when we */
+/* fill in the final details. At present a 0 checksum for UDP is being set */
+/* here because it is expected that divert will be used for localhost. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_builddivertmp(softn, np)
+ ipf_nat_softc_t *softn;
+ ipnat_t *np;
+{
+ udphdr_t *uh;
+ size_t len;
+ ip6_t *ip6;
+
+ if ((np->in_redir & NAT_DIVERTUDP) != 0)
+ len = sizeof(ip6_t) + sizeof(udphdr_t);
+ else
+ len = sizeof(ip6_t);
+
+ ALLOC_MB_T(np->in_divmp, len);
+ if (np->in_divmp == NULL) {
+ ATOMIC_INCL(softn->ipf_nat_stats.ns_divert_build);
+ return -1;
+ }
+
+ /*
+ * First, the header to get the packet diverted to the new destination
+ */
+ ip6 = MTOD(np->in_divmp, ip6_t *);
+ ip6->ip6_vfc = 0x60;
+ if ((np->in_redir & NAT_DIVERTUDP) != 0)
+ ip6->ip6_nxt = IPPROTO_UDP;
+ else
+ ip6->ip6_nxt = IPPROTO_IPIP;
+ ip6->ip6_hlim = 255;
+ ip6->ip6_plen = 0;
+ ip6->ip6_src = np->in_snip6.in6;
+ ip6->ip6_dst = np->in_dnip6.in6;
+
+ if (np->in_redir & NAT_DIVERTUDP) {
+ uh = (udphdr_t *)((u_char *)ip6 + sizeof(*ip6));
+ uh->uh_sum = 0;
+ uh->uh_ulen = 8;
+ uh->uh_sport = htons(np->in_spnext);
+ uh->uh_dport = htons(np->in_dpnext);
+ }
+
+ return 0;
+}
+
+
+#define MINDECAP (sizeof(ip6_t) + sizeof(udphdr_t) + sizeof(ip6_t))
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_decap */
+/* Returns: int - -1 == error, 0 == success */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to current NAT session */
+/* */
+/* This function is responsible for undoing a packet's encapsulation in the */
+/* reverse of an encap/divert rule. After removing the outer encapsulation */
+/* it is necessary to call ipf_makefrip() again so that the contents of 'fin'*/
+/* match the "new" packet as it may still be used by IPFilter elsewhere. */
+/* We use "dir" here as the basis for some of the expectations about the */
+/* outer header. If we return an error, the goal is to leave the original */
+/* packet information undisturbed - this falls short at the end where we'd */
+/* need to back a backup copy of "fin" - expensive. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_decap(fin, nat)
+ fr_info_t *fin;
+ nat_t *nat;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ char *hdr;
+ int skip;
+ mb_t *m;
+
+ if ((fin->fin_flx & FI_ICMPERR) != 0) {
+ return 0;
+ }
+
+ m = fin->fin_m;
+ skip = fin->fin_hlen;
+
+ switch (nat->nat_dir)
+ {
+ case NAT_DIVERTIN :
+ case NAT_DIVERTOUT :
+ if (fin->fin_plen < MINDECAP)
+ return -1;
+ skip += sizeof(udphdr_t);
+ break;
+
+ case NAT_ENCAPIN :
+ case NAT_ENCAPOUT :
+ if (fin->fin_plen < (skip + sizeof(ip6_t)))
+ return -1;
+ break;
+ default :
+ return -1;
+ /* NOTREACHED */
+ }
+
+ /*
+ * The aim here is to keep the original packet details in "fin" for
+ * as long as possible so that returning with an error is for the
+ * original packet and there is little undoing work to do.
+ */
+ if (M_LEN(m) < skip + sizeof(ip6_t)) {
+ if (ipf_pr_pullup(fin, skip + sizeof(ip6_t)) == -1)
+ return -1;
+ }
+
+ hdr = MTOD(fin->fin_m, char *);
+ fin->fin_ip6 = (ip6_t *)(hdr + skip);
+
+ if (ipf_pr_pullup(fin, skip + sizeof(ip6_t)) == -1) {
+ NBUMPSIDE6D(fin->fin_out, ns_decap_pullup);
+ return -1;
+ }
+
+ fin->fin_hlen = sizeof(ip6_t);
+ fin->fin_dlen -= skip;
+ fin->fin_plen -= skip;
+ fin->fin_ipoff += skip;
+
+ if (ipf_makefrip(sizeof(ip6_t), (ip_t *)hdr, fin) == -1) {
+ NBUMPSIDE6D(fin->fin_out, ns_decap_bad);
+ return -1;
+ }
+
+ return skip;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: nat6_nextaddr */
+/* Returns: int - -1 == bad input (no new address), */
+/* 0 == success and dst has new address */
+/* Parameters: fin(I) - pointer to packet information */
+/* na(I) - how to generate new address */
+/* old(I) - original address being replaced */
+/* dst(O) - where to put the new address */
+/* Write Lock: ipf_nat */
+/* */
+/* This function uses the contents of the "na" structure, in combination */
+/* with "old" to produce a new address to store in "dst". Not all of the */
+/* possible uses of "na" will result in a new address. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_nextaddr(fin, na, old, dst)
+ fr_info_t *fin;
+ nat_addr_t *na;
+ i6addr_t *old, *dst;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+ i6addr_t newip, new;
+ u_32_t amin, amax;
+ int error;
+
+ new.i6[0] = 0;
+ new.i6[1] = 0;
+ new.i6[2] = 0;
+ new.i6[3] = 0;
+ amin = na->na_addr[0].in4.s_addr;
+
+ switch (na->na_atype)
+ {
+ case FRI_RANGE :
+ amax = na->na_addr[1].in4.s_addr;
+ break;
+
+ case FRI_NETMASKED :
+ case FRI_DYNAMIC :
+ case FRI_NORMAL :
+ /*
+ * Compute the maximum address by adding the inverse of the
+ * netmask to the minimum address.
+ */
+ amax = ~na->na_addr[1].in4.s_addr;
+ amax |= amin;
+ break;
+
+ case FRI_LOOKUP :
+ break;
+
+ case FRI_BROADCAST :
+ case FRI_PEERADDR :
+ case FRI_NETWORK :
+ default :
+ return -1;
+ }
+
+ error = -1;
+ switch (na->na_function)
+ {
+ case IPLT_DSTLIST :
+ error = ipf_dstlist_select_node(fin, na->na_ptr, dst->i6,
+ NULL);
+ break;
+
+ case IPLT_NONE :
+ /*
+ * 0/0 as the new address means leave it alone.
+ */
+ if (na->na_addr[0].in4.s_addr == 0 &&
+ na->na_addr[1].in4.s_addr == 0) {
+ new = *old;
+
+ /*
+ * 0/32 means get the interface's address
+ */
+ } else if (IP6_ISZERO(&na->na_addr[0].in6) &&
+ IP6_ISONES(&na->na_addr[1].in6)) {
+ if (ipf_ifpaddr(softc, 6, na->na_atype,
+ fin->fin_ifp, &newip, NULL) == -1) {
+ NBUMPSIDE6(fin->fin_out, ns_ifpaddrfail);
+ return -1;
+ }
+ new = newip;
+ } else {
+ new.in6 = na->na_nextip6;
+ }
+ *dst = new;
+ error = 0;
+ break;
+
+ default :
+ NBUMPSIDE6(fin->fin_out, ns_badnextaddr);
+ break;
+ }
+
+ return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_nextaddrinit */
+/* Returns: int - 0 == success, else error number */
+/* Parameters: na(I) - NAT address information for generating new addr*/
+/* base(I) - start of where to find strings */
+/* initial(I) - flag indicating if it is the first call for */
+/* this "na" structure. */
+/* ifp(I) - network interface to derive address */
+/* information from. */
+/* */
+/* This function is expected to be called in two scenarious: when a new NAT */
+/* rule is loaded into the kernel and when the list of NAT rules is sync'd */
+/* up with the valid network interfaces (possibly due to them changing.) */
+/* To distinguish between these, the "initial" parameter is used. If it is */
+/* 1 then this indicates the rule has just been reloaded and 0 for when we */
+/* are updating information. This difference is important because in */
+/* instances where we are not updating address information associated with */
+/* a network interface, we don't want to disturb what the "next" address to */
+/* come out of ipf_nat6_nextaddr() will be. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_nextaddrinit(softc, base, na, initial, ifp)
+ ipf_main_softc_t *softc;
+ char *base;
+ nat_addr_t *na;
+ int initial;
+ void *ifp;
+{
+ switch (na->na_atype)
+ {
+ case FRI_LOOKUP :
+ if (na->na_subtype == 0) {
+ na->na_ptr = ipf_lookup_res_num(softc, IPL_LOGNAT,
+ na->na_type,
+ na->na_num,
+ &na->na_func);
+ } else if (na->na_subtype == 1) {
+ na->na_ptr = ipf_lookup_res_name(softc, IPL_LOGNAT,
+ na->na_type,
+ base + na->na_num,
+ &na->na_func);
+ }
+ if (na->na_func == NULL) {
+ IPFERROR(60072);
+ return ESRCH;
+ }
+ if (na->na_ptr == NULL) {
+ IPFERROR(60073);
+ return ESRCH;
+ }
+ break;
+ case FRI_DYNAMIC :
+ case FRI_BROADCAST :
+ case FRI_NETWORK :
+ case FRI_NETMASKED :
+ case FRI_PEERADDR :
+ if (ifp != NULL)
+ (void )ipf_ifpaddr(softc, 6, na->na_atype, ifp,
+ &na->na_addr[0],
+ &na->na_addr[1]);
+ break;
+
+ case FRI_SPLIT :
+ case FRI_RANGE :
+ if (initial)
+ na->na_nextip6 = na->na_addr[0].in6;
+ break;
+
+ case FRI_NONE :
+ IP6_ANDASSIGN(&na->na_addr[0].in6, &na->na_addr[1].in6);
+ return 0;
+
+ case FRI_NORMAL :
+ IP6_ANDASSIGN(&na->na_addr[0].in6, &na->na_addr[1].in6);
+ break;
+
+ default :
+ IPFERROR(60074);
+ return EINVAL;
+ }
+
+ if (initial && (na->na_atype == FRI_NORMAL)) {
+ if (IP6_ISZERO(&na->na_addr[0].in6)) {
+ if (IP6_ISONES(&na->na_addr[1].in6) ||
+ IP6_ISZERO(&na->na_addr[1].in6)) {
+ return 0;
+ }
+ }
+
+ na->na_nextip6 = na->na_addr[0].in6;
+ if (!IP6_ISONES(&na->na_addr[1].in6)) {
+ IP6_INC(&na->na_nextip6);
+ }
+ }
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_nat6_icmpquerytype */
+/* Returns: int - 1 == success, 0 == failure */
+/* Parameters: icmptype(I) - ICMP type number */
+/* */
+/* Tests to see if the ICMP type number passed is a query/response type or */
+/* not. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_nat6_icmpquerytype(icmptype)
+ int icmptype;
+{
+
+ /*
+ * For the ICMP query NAT code, it is essential that both the query
+ * and the reply match on the NAT rule. Because the NAT structure
+ * does not keep track of the icmptype, and a single NAT structure
+ * is used for all icmp types with the same src, dest and id, we
+ * simply define the replies as queries as well. The funny thing is,
+ * altough it seems silly to call a reply a query, this is exactly
+ * as it is defined in the IPv4 specification
+ */
+
+ switch (icmptype)
+ {
+
+ case ICMP6_ECHO_REPLY:
+ case ICMP6_ECHO_REQUEST:
+ /* route aedvertisement/solliciation is currently unsupported: */
+ /* it would require rewriting the ICMP data section */
+ case ICMP6_MEMBERSHIP_QUERY:
+ case ICMP6_MEMBERSHIP_REPORT:
+ case ICMP6_MEMBERSHIP_REDUCTION:
+ case ICMP6_WRUREQUEST:
+ case ICMP6_WRUREPLY:
+ case MLD6_MTRACE_RESP:
+ case MLD6_MTRACE:
+ return 1;
+ default:
+ return 0;
+ }
+}
+#endif /* USE_INET6 */
diff --git a/sys/contrib/ipfilter/netinet/ip_netbios_pxy.c b/sys/contrib/ipfilter/netinet/ip_netbios_pxy.c
index 1a0b2a2..4e8bdc6 100644
--- a/sys/contrib/ipfilter/netinet/ip_netbios_pxy.c
+++ b/sys/contrib/ipfilter/netinet/ip_netbios_pxy.c
@@ -1,7 +1,7 @@
/*
* Simple netbios-dgm transparent proxy for in-kernel use.
* For use with the NAT code.
- * $Id: ip_netbios_pxy.c,v 2.8.2.1 2005/08/20 13:48:23 darrenr Exp $
+ * $Id$
*/
/*-
@@ -29,14 +29,14 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: ip_netbios_pxy.c,v 2.8.2.1 2005/08/20 13:48:23 darrenr Exp $
+ * $Id$
*/
#define IPF_NETBIOS_PROXY
-int ippr_netbios_init __P((void));
-void ippr_netbios_fini __P((void));
-int ippr_netbios_out __P((fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_netbios_main_load __P((void));
+void ipf_p_netbios_main_unload __P((void));
+int ipf_p_netbios_out __P((void *, fr_info_t *, ap_session_t *, nat_t *));
static frentry_t netbiosfr;
@@ -45,19 +45,19 @@ int netbios_proxy_init = 0;
/*
* Initialize local structures.
*/
-int ippr_netbios_init()
+void
+ipf_p_netbios_main_load()
{
bzero((char *)&netbiosfr, sizeof(netbiosfr));
netbiosfr.fr_ref = 1;
netbiosfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
MUTEX_INIT(&netbiosfr.fr_lock, "NETBIOS proxy rule lock");
netbios_proxy_init = 1;
-
- return 0;
}
-void ippr_netbios_fini()
+void
+ipf_p_netbios_main_unload()
{
if (netbios_proxy_init == 1) {
MUTEX_DESTROY(&netbiosfr.fr_lock);
@@ -66,10 +66,12 @@ void ippr_netbios_fini()
}
-int ippr_netbios_out(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_netbios_out(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
{
char dgmbuf[6];
int off, dlen;
diff --git a/sys/contrib/ipfilter/netinet/ip_pool.c b/sys/contrib/ipfilter/netinet/ip_pool.c
index eab3310..2a43cdb 100644
--- a/sys/contrib/ipfilter/netinet/ip_pool.c
+++ b/sys/contrib/ipfilter/netinet/ip_pool.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1993-2001, 2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*/
@@ -33,15 +33,10 @@ struct file;
# endif
#endif
#include <sys/time.h>
-#if !defined(linux)
-# include <sys/protosw.h>
-#endif
-#include <sys/socket.h>
-#if defined(_KERNEL) && (!defined(__SVR4) && !defined(__svr4__))
+#if defined(_KERNEL) && !defined(SOLARIS2)
# include <sys/mbuf.h>
#endif
#if defined(__SVR4) || defined(__svr4__)
-# include <sys/filio.h>
# include <sys/byteorder.h>
# ifdef _KERNEL
# include <sys/dditypes.h>
@@ -53,69 +48,91 @@ struct file;
# include <sys/malloc.h>
#endif
-#if defined(SOLARIS2) && !defined(_KERNEL)
-# include "radix_ipf.h"
-#endif
-#if defined(_KERNEL) && (defined(__osf__) || defined(AIX) || \
- defined(__hpux) || defined(__sgi))
-# include "radix_ipf_local.h"
-# define _RADIX_H_
-#endif
+#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
+#if !defined(_KERNEL)
+# include "ipf.h"
+#endif
#include "netinet/ip_compat.h"
#include "netinet/ip_fil.h"
#include "netinet/ip_pool.h"
-
-#if defined(IPFILTER_LOOKUP) && defined(_KERNEL) && \
- ((BSD >= 198911) && !defined(__osf__) && \
- !defined(__hpux) && !defined(__sgi))
-static int rn_freenode __P((struct radix_node *, void *));
-#endif
+#include "netinet/radix_ipf.h"
/* END OF INCLUDES */
#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_pool.c,v 2.55.2.24 2007/10/10 09:45:37 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id$";
#endif
-#ifdef IPFILTER_LOOKUP
-
-# if !defined(RADIX_NODE_HEAD_LOCK) || !defined(RADIX_NODE_HEAD_UNLOCK) || \
- !defined(_KERNEL)
-# undef RADIX_NODE_HEAD_LOCK
-# undef RADIX_NODE_HEAD_UNLOCK
-# define RADIX_NODE_HEAD_LOCK(x) ;
-# define RADIX_NODE_HEAD_UNLOCK(x) ;
-# endif
-
-static void ip_pool_clearnodes __P((ip_pool_t *));
-static void *ip_pool_exists __P((int, char *));
-
-ip_pool_stat_t ipoolstat;
-ipfrwlock_t ip_poolrw;
-
-/*
- * Binary tree routines from Sedgewick and enhanced to do ranges of addresses.
- * NOTE: Insertion *MUST* be from greatest range to least for it to work!
- * These should be replaced, eventually, by something else - most notably a
- * interval searching method. The important feature is to be able to find
- * the best match.
- *
- * So why not use a radix tree for this? As the first line implies, it
- * has been written to work with a _range_ of addresses. A range is not
- * necessarily a match with any given netmask so what we end up dealing
- * with is an interval tree. Implementations of these are hard to find
- * and the one herein is far from bug free.
- *
- * Sigh, in the end I became convinced that the bugs the code contained did
- * not make it worthwhile not using radix trees. For now the radix tree from
- * 4.4 BSD is used, but this is not viewed as a long term solution.
- */
-ip_pool_t *ip_pool_list[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL };
+typedef struct ipf_pool_softc_s {
+ void *ipf_radix;
+ ip_pool_t *ipf_pool_list[LOOKUP_POOL_SZ];
+ ipf_pool_stat_t ipf_pool_stats;
+ ip_pool_node_t *ipf_node_explist;
+} ipf_pool_softc_t;
+
+
+static void ipf_pool_clearnodes __P((ipf_main_softc_t *, ipf_pool_softc_t *,
+ ip_pool_t *));
+static int ipf_pool_create __P((ipf_main_softc_t *, ipf_pool_softc_t *, iplookupop_t *));
+static int ipf_pool_deref __P((ipf_main_softc_t *, void *, void *));
+static int ipf_pool_destroy __P((ipf_main_softc_t *, ipf_pool_softc_t *, int, char *));
+static void *ipf_pool_exists __P((ipf_pool_softc_t *, int, char *));
+static void *ipf_pool_find __P((void *, int, char *));
+static ip_pool_node_t *ipf_pool_findeq __P((ipf_pool_softc_t *, ip_pool_t *,
+ addrfamily_t *, addrfamily_t *));
+static void ipf_pool_free __P((ipf_main_softc_t *, ipf_pool_softc_t *,
+ ip_pool_t *));
+static int ipf_pool_insert_node __P((ipf_main_softc_t *, ipf_pool_softc_t *,
+ ip_pool_t *, struct ip_pool_node *));
+static int ipf_pool_iter_deref __P((ipf_main_softc_t *, void *, int, int, void *));
+static int ipf_pool_iter_next __P((ipf_main_softc_t *, void *, ipftoken_t *,
+ ipflookupiter_t *));
+static size_t ipf_pool_flush __P((ipf_main_softc_t *, void *, iplookupflush_t *));
+static int ipf_pool_node_add __P((ipf_main_softc_t *, void *, iplookupop_t *,
+ int));
+static int ipf_pool_node_del __P((ipf_main_softc_t *, void *, iplookupop_t *,
+ int));
+static void ipf_pool_node_deref __P((ipf_pool_softc_t *, ip_pool_node_t *));
+static int ipf_pool_remove_node __P((ipf_main_softc_t *, ipf_pool_softc_t *,
+ ip_pool_t *, ip_pool_node_t *));
+static int ipf_pool_search __P((ipf_main_softc_t *, void *, int,
+ void *, u_int));
+static void *ipf_pool_soft_create __P((ipf_main_softc_t *));
+static void ipf_pool_soft_destroy __P((ipf_main_softc_t *, void *));
+static void ipf_pool_soft_fini __P((ipf_main_softc_t *, void *));
+static int ipf_pool_soft_init __P((ipf_main_softc_t *, void *));
+static int ipf_pool_stats_get __P((ipf_main_softc_t *, void *, iplookupop_t *));
+static int ipf_pool_table_add __P((ipf_main_softc_t *, void *, iplookupop_t *));
+static int ipf_pool_table_del __P((ipf_main_softc_t *, void *, iplookupop_t *));
+static void *ipf_pool_select_add_ref __P((void *, int, char *));
+static void ipf_pool_expire __P((ipf_main_softc_t *, void *));
+
+ipf_lookup_t ipf_pool_backend = {
+ IPLT_POOL,
+ ipf_pool_soft_create,
+ ipf_pool_soft_destroy,
+ ipf_pool_soft_init,
+ ipf_pool_soft_fini,
+ ipf_pool_search,
+ ipf_pool_flush,
+ ipf_pool_iter_deref,
+ ipf_pool_iter_next,
+ ipf_pool_node_add,
+ ipf_pool_node_del,
+ ipf_pool_stats_get,
+ ipf_pool_table_add,
+ ipf_pool_table_del,
+ ipf_pool_deref,
+ ipf_pool_find,
+ ipf_pool_select_add_ref,
+ NULL,
+ ipf_pool_expire,
+ NULL
+};
#ifdef TEST_POOL
@@ -126,96 +143,98 @@ main(argc, argv)
int argc;
char *argv[];
{
+ ip_pool_node_t node;
addrfamily_t a, b;
iplookupop_t op;
ip_pool_t *ipo;
i6addr_t ip;
- RWLOCK_INIT(&ip_poolrw, "poolrw");
- ip_pool_init();
+ RWLOCK_INIT(softc->ipf_poolrw, "poolrw");
+ ipf_pool_init();
- bzero((char *)&a, sizeof(a));
- bzero((char *)&b, sizeof(b));
bzero((char *)&ip, sizeof(ip));
bzero((char *)&op, sizeof(op));
+ bzero((char *)&node, sizeof(node));
strcpy(op.iplo_name, "0");
- if (ip_pool_create(&op) == 0)
- ipo = ip_pool_exists(0, "0");
-
- a.adf_addr.in4.s_addr = 0x0a010203;
- b.adf_addr.in4.s_addr = 0xffffffff;
- ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
- ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
-
- a.adf_addr.in4.s_addr = 0x0a000000;
- b.adf_addr.in4.s_addr = 0xff000000;
- ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
- ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
-
- a.adf_addr.in4.s_addr = 0x0a010100;
- b.adf_addr.in4.s_addr = 0xffffff00;
- ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
- ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
-
- a.adf_addr.in4.s_addr = 0x0a010200;
- b.adf_addr.in4.s_addr = 0xffffff00;
- ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
- ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 0);
-
- a.adf_addr.in4.s_addr = 0x0a010000;
- b.adf_addr.in4.s_addr = 0xffff0000;
- ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
- ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
-
- a.adf_addr.in4.s_addr = 0x0a01020f;
- b.adf_addr.in4.s_addr = 0xffffffff;
- ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
- ip_pool_insert(ipo, &a.adf_addr, &b.adf_addr, 1);
+ if (ipf_pool_create(&op) == 0)
+ ipo = ipf_pool_exists(0, "0");
+
+ node.ipn_addr.adf_family = AF_INET;
+
+ node.ipn_addr.adf_addr.in4.s_addr = 0x0a010203;
+ node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
+ node.ipn_info = 1;
+ ipf_pool_insert_node(ipo, &node);
+
+ node.ipn_addr.adf_addr.in4.s_addr = 0x0a000000;
+ node.ipn_mask.adf_addr.in4.s_addr = 0xff000000;
+ node.ipn_info = 0;
+ ipf_pool_insert_node(ipo, &node);
+
+ node.ipn_addr.adf_addr.in4.s_addr = 0x0a010100;
+ node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
+ node.ipn_info = 1;
+ ipf_pool_insert_node(ipo, &node);
+
+ node.ipn_addr.adf_addr.in4.s_addr = 0x0a010200;
+ node.ipn_mask.adf_addr.in4.s_addr = 0xffffff00;
+ node.ipn_info = 0;
+ ipf_pool_insert_node(ipo, &node);
+
+ node.ipn_addr.adf_addr.in4.s_addr = 0x0a010000;
+ node.ipn_mask.adf_addr.in4.s_addr = 0xffff0000;
+ node.ipn_info = 1;
+ ipf_pool_insert_node(ipo, &node);
+
+ node.ipn_addr.adf_addr.in4.s_addr = 0x0a01020f;
+ node.ipn_mask.adf_addr.in4.s_addr = 0xffffffff;
+ node.ipn_info = 1;
+ ipf_pool_insert_node(ipo, &node);
#ifdef DEBUG_POOL
-treeprint(ipo);
+ treeprint(ipo);
#endif
ip.in4.s_addr = 0x0a00aabb;
printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
- ip_pool_search(ipo, 4, &ip));
+ ipf_pool_search(ipo, 4, &ip, 1));
ip.in4.s_addr = 0x0a000001;
printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
- ip_pool_search(ipo, 4, &ip));
+ ipf_pool_search(ipo, 4, &ip, 1));
ip.in4.s_addr = 0x0a000101;
printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
- ip_pool_search(ipo, 4, &ip));
+ ipf_pool_search(ipo, 4, &ip, 1));
ip.in4.s_addr = 0x0a010001;
printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
- ip_pool_search(ipo, 4, &ip));
+ ipf_pool_search(ipo, 4, &ip, 1));
ip.in4.s_addr = 0x0a010101;
printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
- ip_pool_search(ipo, 4, &ip));
+ ipf_pool_search(ipo, 4, &ip, 1));
ip.in4.s_addr = 0x0a010201;
printf("search(%#x) = %d (0)\n", ip.in4.s_addr,
- ip_pool_search(ipo, 4, &ip));
+ ipf_pool_search(ipo, 4, &ip, 1));
ip.in4.s_addr = 0x0a010203;
printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
- ip_pool_search(ipo, 4, &ip));
+ ipf_pool_search(ipo, 4, &ip, 1));
ip.in4.s_addr = 0x0a01020f;
printf("search(%#x) = %d (1)\n", ip.in4.s_addr,
- ip_pool_search(ipo, 4, &ip));
+ ipf_pool_search(ipo, 4, &ip, 1));
ip.in4.s_addr = 0x0b00aabb;
printf("search(%#x) = %d (-1)\n", ip.in4.s_addr,
- ip_pool_search(ipo, 4, &ip));
+ ipf_pool_search(ipo, 4, &ip, 1));
#ifdef DEBUG_POOL
-treeprint(ipo);
+ treeprint(ipo);
#endif
- ip_pool_fini();
+ ipf_pool_fini();
return 0;
}
@@ -223,7 +242,7 @@ treeprint(ipo);
void
treeprint(ipo)
-ip_pool_t *ipo;
+ ip_pool_t *ipo;
{
ip_pool_node_t *c;
@@ -237,123 +256,445 @@ ip_pool_t *ipo;
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_init */
+/* Function: ipf_pool_soft_create */
+/* Returns: void * - NULL = failure, else pointer to local context */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Initialise the routing table data structures where required. */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_pool_soft_create(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_pool_softc_t *softp;
+
+ KMALLOC(softp, ipf_pool_softc_t *);
+ if (softp == NULL) {
+ IPFERROR(70032);
+ return NULL;
+ }
+
+ bzero((char *)softp, sizeof(*softp));
+
+ softp->ipf_radix = ipf_rx_create();
+ if (softp->ipf_radix == NULL) {
+ IPFERROR(70033);
+ KFREE(softp);
+ return NULL;
+ }
+
+ return softp;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_pool_soft_init */
/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
/* */
/* Initialise the routing table data structures where required. */
/* ------------------------------------------------------------------------ */
-int ip_pool_init()
+static int
+ipf_pool_soft_init(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
{
+ ipf_pool_softc_t *softp = arg;
- bzero((char *)&ipoolstat, sizeof(ipoolstat));
+ ipf_rx_init(softp->ipf_radix);
-#if (!defined(_KERNEL) || (BSD < 199306))
- rn_init();
-#endif
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_fini */
-/* Returns: int - 0 = success, else error */
+/* Function: ipf_pool_soft_fini */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
/* Locks: WRITE(ipf_global) */
/* */
/* Clean up all the pool data structures allocated and call the cleanup */
-/* function for the radix tree that supports the pools. ip_pool_destroy() is*/
+/* function for the radix tree that supports the pools. ipf_pool_destroy is */
/* used to delete the pools one by one to ensure they're properly freed up. */
/* ------------------------------------------------------------------------ */
-void ip_pool_fini()
+static void
+ipf_pool_soft_fini(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
{
+ ipf_pool_softc_t *softp = arg;
ip_pool_t *p, *q;
int i;
- for (i = 0; i <= IPL_LOGMAX; i++) {
- for (q = ip_pool_list[i]; (p = q) != NULL; ) {
+ softc = arg;
+
+ for (i = -1; i <= IPL_LOGMAX; i++) {
+ for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
q = p->ipo_next;
- (void) ip_pool_destroy(i, p->ipo_name);
+ (void) ipf_pool_destroy(softc, arg, i, p->ipo_name);
}
}
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_pool_soft_destroy */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* Clean up the pool by free'ing the radix tree associated with it and free */
+/* up the pool context too. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_pool_soft_destroy(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_pool_softc_t *softp = arg;
+
+ ipf_rx_destroy(softp->ipf_radix);
+
+ KFREE(softp);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_pool_node_add */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operatin data */
+/* */
+/* When adding a new node, a check is made to ensure that the address/mask */
+/* pair supplied has been appropriately prepared by applying the mask to */
+/* the address prior to calling for the pair to be added. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_pool_node_add(softc, arg, op, uid)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
+ int uid;
+{
+ ip_pool_node_t node, *m;
+ ip_pool_t *p;
+ int err;
-#if (!defined(_KERNEL) || (BSD < 199306))
- rn_fini();
+ if (op->iplo_size != sizeof(node)) {
+ IPFERROR(70014);
+ return EINVAL;
+ }
+
+ err = COPYIN(op->iplo_struct, &node, sizeof(node));
+ if (err != 0) {
+ IPFERROR(70015);
+ return EFAULT;
+ }
+
+ p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
+ if (p == NULL) {
+ IPFERROR(70017);
+ return ESRCH;
+ }
+
+ if (node.ipn_addr.adf_family == AF_INET) {
+ if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
+ sizeof(struct in_addr)) {
+ IPFERROR(70028);
+ return EINVAL;
+ }
+ }
+#ifdef USE_INET6
+ else if (node.ipn_addr.adf_family == AF_INET6) {
+ if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
+ sizeof(struct in6_addr)) {
+ IPFERROR(70034);
+ return EINVAL;
+ }
+ }
+#endif
+ if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
+ IPFERROR(70029);
+ return EINVAL;
+ }
+
+ /*
+ * Check that the address/mask pair works.
+ */
+ if (node.ipn_addr.adf_family == AF_INET) {
+ if ((node.ipn_addr.adf_addr.in4.s_addr &
+ node.ipn_mask.adf_addr.in4.s_addr) !=
+ node.ipn_addr.adf_addr.in4.s_addr) {
+ IPFERROR(70035);
+ return EINVAL;
+ }
+ }
+#ifdef USE_INET6
+ else if (node.ipn_addr.adf_family == AF_INET6) {
+ if (IP6_MASKNEQ(&node.ipn_addr.adf_addr.in6,
+ &node.ipn_mask.adf_addr.in6,
+ &node.ipn_addr.adf_addr.in6)) {
+ IPFERROR(70036);
+ return EINVAL;
+ }
+ }
#endif
+
+ /*
+ * add an entry to a pool - return an error if it already
+ * exists remove an entry from a pool - if it exists
+ * - in both cases, the pool *must* exist!
+ */
+ m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
+ if (m != NULL) {
+ IPFERROR(70018);
+ return EEXIST;
+ }
+ err = ipf_pool_insert_node(softc, arg, p, &node);
+
+ return err;
}
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_statistics */
-/* Returns: int - 0 = success, else error */
-/* Parameters: op(I) - pointer to lookup operation arguments */
+/* Function: ipf_pool_node_del */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operatin data */
+/* */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_pool_node_del(softc, arg, op, uid)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
+ int uid;
+{
+ ip_pool_node_t node, *m;
+ ip_pool_t *p;
+ int err;
+
+
+ if (op->iplo_size != sizeof(node)) {
+ IPFERROR(70019);
+ return EINVAL;
+ }
+ node.ipn_uid = uid;
+
+ err = COPYIN(op->iplo_struct, &node, sizeof(node));
+ if (err != 0) {
+ IPFERROR(70020);
+ return EFAULT;
+ }
+
+ if (node.ipn_addr.adf_family == AF_INET) {
+ if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
+ sizeof(struct in_addr)) {
+ IPFERROR(70030);
+ return EINVAL;
+ }
+ }
+#ifdef USE_INET6
+ else if (node.ipn_addr.adf_family == AF_INET6) {
+ if (node.ipn_addr.adf_len != offsetof(addrfamily_t, adf_addr) +
+ sizeof(struct in6_addr)) {
+ IPFERROR(70037);
+ return EINVAL;
+ }
+ }
+#endif
+ if (node.ipn_mask.adf_len != node.ipn_addr.adf_len) {
+ IPFERROR(70031);
+ return EINVAL;
+ }
+
+ p = ipf_pool_find(arg, op->iplo_unit, op->iplo_name);
+ if (p == NULL) {
+ IPFERROR(70021);
+ return ESRCH;
+ }
+
+ m = ipf_pool_findeq(arg, p, &node.ipn_addr, &node.ipn_mask);
+ if (m == NULL) {
+ IPFERROR(70022);
+ return ENOENT;
+ }
+
+ if ((uid != 0) && (uid != m->ipn_uid)) {
+ IPFERROR(70024);
+ return EACCES;
+ }
+
+ err = ipf_pool_remove_node(softc, arg, p, m);
+
+ return err;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_pool_table_add */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operatin data */
+/* */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_pool_table_add(softc, arg, op)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
+{
+ int err;
+
+ if (((op->iplo_arg & LOOKUP_ANON) == 0) &&
+ (ipf_pool_find(arg, op->iplo_unit, op->iplo_name) != NULL)) {
+ IPFERROR(70023);
+ err = EEXIST;
+ } else {
+ err = ipf_pool_create(softc, arg, op);
+ }
+
+ return err;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_pool_table_del */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operatin data */
+/* */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_pool_table_del(softc, arg, op)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
+{
+ return ipf_pool_destroy(softc, arg, op->iplo_unit, op->iplo_name);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_pool_statistics */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* op(I) - pointer to lookup operatin data */
/* */
/* Copy the current statistics out into user space, collecting pool list */
/* pointers as appropriate for later use. */
/* ------------------------------------------------------------------------ */
-int ip_pool_statistics(op)
-iplookupop_t *op;
+static int
+ipf_pool_stats_get(softc, arg, op)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupop_t *op;
{
- ip_pool_stat_t stats;
+ ipf_pool_softc_t *softp = arg;
+ ipf_pool_stat_t stats;
int unit, i, err = 0;
- if (op->iplo_size != sizeof(ipoolstat))
+ if (op->iplo_size != sizeof(ipf_pool_stat_t)) {
+ IPFERROR(70001);
return EINVAL;
+ }
- bcopy((char *)&ipoolstat, (char *)&stats, sizeof(stats));
+ bcopy((char *)&softp->ipf_pool_stats, (char *)&stats, sizeof(stats));
unit = op->iplo_unit;
if (unit == IPL_LOGALL) {
- for (i = 0; i < IPL_LOGSIZE; i++)
- stats.ipls_list[i] = ip_pool_list[i];
- } else if (unit >= 0 && unit < IPL_LOGSIZE) {
+ for (i = 0; i <= LOOKUP_POOL_MAX; i++)
+ stats.ipls_list[i] = softp->ipf_pool_list[i];
+ } else if (unit >= 0 && unit <= IPL_LOGMAX) {
+ unit++; /* -1 => 0 */
if (op->iplo_name[0] != '\0')
- stats.ipls_list[unit] = ip_pool_exists(unit,
- op->iplo_name);
+ stats.ipls_list[unit] = ipf_pool_exists(softp, unit - 1,
+ op->iplo_name);
else
- stats.ipls_list[unit] = ip_pool_list[unit];
- } else
+ stats.ipls_list[unit] = softp->ipf_pool_list[unit];
+ } else {
+ IPFERROR(70025);
err = EINVAL;
- if (err == 0)
+ }
+ if (err == 0) {
err = COPYOUT(&stats, op->iplo_struct, sizeof(stats));
- return err;
+ if (err != 0) {
+ IPFERROR(70026);
+ return EFAULT;
+ }
+ }
+ return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_exists */
-/* Returns: int - 0 = success, else error */
-/* Parameters: ipo(I) - pointer to the pool getting the new node. */
+/* Function: ipf_pool_exists */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softp(I) - pointer to soft context pool information */
+/* unit(I) - ipfilter device to which we are working on */
+/* name(I) - name of the pool */
/* */
/* Find a matching pool inside the collection of pools for a particular */
/* device, indicated by the unit number. */
/* ------------------------------------------------------------------------ */
-static void *ip_pool_exists(unit, name)
-int unit;
-char *name;
+static void *
+ipf_pool_exists(softp, unit, name)
+ ipf_pool_softc_t *softp;
+ int unit;
+ char *name;
{
ip_pool_t *p;
+ int i;
- for (p = ip_pool_list[unit]; p != NULL; p = p->ipo_next)
- if (strncmp(p->ipo_name, name, sizeof(p->ipo_name)) == 0)
- break;
+ if (unit == IPL_LOGALL) {
+ for (i = 0; i <= LOOKUP_POOL_MAX; i++) {
+ for (p = softp->ipf_pool_list[i]; p != NULL;
+ p = p->ipo_next) {
+ if (strncmp(p->ipo_name, name,
+ sizeof(p->ipo_name)) == 0)
+ break;
+ }
+ if (p != NULL)
+ break;
+ }
+ } else {
+ for (p = softp->ipf_pool_list[unit + 1]; p != NULL;
+ p = p->ipo_next)
+ if (strncmp(p->ipo_name, name,
+ sizeof(p->ipo_name)) == 0)
+ break;
+ }
return p;
}
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_find */
-/* Returns: int - 0 = success, else error */
-/* Parameters: ipo(I) - pointer to the pool getting the new node. */
+/* Function: ipf_pool_find */
+/* Returns: int - 0 = success, else error */
+/* Parameters: arg(I) - pointer to local context to use */
+/* unit(I) - ipfilter device to which we are working on */
+/* name(I) - name of the pool */
/* */
/* Find a matching pool inside the collection of pools for a particular */
/* device, indicated by the unit number. If it is marked for deletion then */
/* pretend it does not exist. */
/* ------------------------------------------------------------------------ */
-void *ip_pool_find(unit, name)
-int unit;
-char *name;
+static void *
+ipf_pool_find(arg, unit, name)
+ void *arg;
+ int unit;
+ char *name;
{
+ ipf_pool_softc_t *softp = arg;
ip_pool_t *p;
- p = ip_pool_exists(unit, name);
+ p = ipf_pool_exists(softp, unit, name);
if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE))
return NULL;
@@ -362,45 +703,75 @@ char *name;
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_findeq */
+/* Function: ipf_pool_select_add_ref */
+/* Returns: int - 0 = success, else error */
+/* Parameters: arg(I) - pointer to local context to use */
+/* unit(I) - ipfilter device to which we are working on */
+/* name(I) - name of the pool */
+/* */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_pool_select_add_ref(arg, unit, name)
+ void *arg;
+ int unit;
+ char *name;
+{
+ ip_pool_t *p;
+
+ p = ipf_pool_find(arg, -1, name);
+ if (p == NULL)
+ p = ipf_pool_find(arg, unit, name);
+ if (p != NULL) {
+ ATOMIC_INC32(p->ipo_ref);
+ }
+ return p;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_pool_findeq */
/* Returns: int - 0 = success, else error */
-/* Parameters: ipo(I) - pointer to the pool getting the new node. */
-/* addr(I) - pointer to address information to delete */
-/* mask(I) - */
+/* Parameters: softp(I) - pointer to soft context pool information */
+/* ipo(I) - pointer to the pool getting the new node. */
+/* addr(I) - pointer to address information to match on */
+/* mask(I) - pointer to the address mask to match */
/* */
/* Searches for an exact match of an entry in the pool. */
/* ------------------------------------------------------------------------ */
-ip_pool_node_t *ip_pool_findeq(ipo, addr, mask)
-ip_pool_t *ipo;
-addrfamily_t *addr, *mask;
+extern void printhostmask __P((int, u_32_t *, u_32_t *));
+static ip_pool_node_t *
+ipf_pool_findeq(softp, ipo, addr, mask)
+ ipf_pool_softc_t *softp;
+ ip_pool_t *ipo;
+ addrfamily_t *addr, *mask;
{
- struct radix_node *n;
- SPL_INT(s);
-
- SPL_NET(s);
- RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
- n = ipo->ipo_head->rnh_lookup(addr, mask, ipo->ipo_head);
- RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
- SPL_X(s);
+ ipf_rdx_node_t *n;
+
+ n = ipo->ipo_head->lookup(ipo->ipo_head, addr, mask);
return (ip_pool_node_t *)n;
}
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_search */
+/* Function: ipf_pool_search */
/* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */
-/* Parameters: tptr(I) - pointer to the pool to search */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* tptr(I) - pointer to the pool to search */
/* version(I) - IP protocol version (4 or 6) */
/* dptr(I) - pointer to address information */
+/* bytes(I) - length of packet */
/* */
/* Search the pool for a given address and return a search result. */
/* ------------------------------------------------------------------------ */
-int ip_pool_search(tptr, ipversion, dptr)
-void *tptr;
-int ipversion;
-void *dptr;
+static int
+ipf_pool_search(softc, tptr, ipversion, dptr, bytes)
+ ipf_main_softc_t *softc;
+ void *tptr;
+ int ipversion;
+ void *dptr;
+ u_int bytes;
{
- struct radix_node *rn;
+ ipf_rdx_node_t *rn;
ip_pool_node_t *m;
i6addr_t *addr;
addrfamily_t v;
@@ -415,102 +786,154 @@ void *dptr;
m = NULL;
addr = (i6addr_t *)dptr;
bzero(&v, sizeof(v));
- v.adf_len = offsetof(addrfamily_t, adf_addr);
if (ipversion == 4) {
- v.adf_len += sizeof(addr->in4);
+ v.adf_family = AF_INET;
+ v.adf_len = offsetof(addrfamily_t, adf_addr) +
+ sizeof(struct in_addr);
v.adf_addr.in4 = addr->in4;
#ifdef USE_INET6
} else if (ipversion == 6) {
- v.adf_len += sizeof(addr->in6);
+ v.adf_family = AF_INET6;
+ v.adf_len = offsetof(addrfamily_t, adf_addr) +
+ sizeof(struct in6_addr);
v.adf_addr.in6 = addr->in6;
#endif
} else
return -1;
- READ_ENTER(&ip_poolrw);
+ READ_ENTER(&softc->ipf_poolrw);
- RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
- rn = ipo->ipo_head->rnh_matchaddr(&v, ipo->ipo_head);
- RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
+ rn = ipo->ipo_head->matchaddr(ipo->ipo_head, &v);
- if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) {
+ if ((rn != NULL) && (rn->root == 0)) {
m = (ip_pool_node_t *)rn;
ipo->ipo_hits++;
+ m->ipn_bytes += bytes;
m->ipn_hits++;
rv = m->ipn_info;
}
- RWLOCK_EXIT(&ip_poolrw);
+ RWLOCK_EXIT(&softc->ipf_poolrw);
return rv;
}
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_insert */
-/* Returns: int - 0 = success, else error */
-/* Parameters: ipo(I) - pointer to the pool getting the new node. */
-/* addr(I) - address being added as a node */
-/* mask(I) - netmask to with the node being added */
-/* info(I) - extra information to store in this node. */
-/* Locks: WRITE(ip_poolrw) */
+/* Function: ipf_pool_insert_node */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softp(I) - pointer to soft context pool information */
+/* ipo(I) - pointer to the pool getting the new node. */
+/* node(I) - structure with address/mask to add */
+/* Locks: WRITE(ipf_poolrw) */
/* */
/* Add another node to the pool given by ipo. The three parameters passed */
/* in (addr, mask, info) shold all be stored in the node. */
/* ------------------------------------------------------------------------ */
-int ip_pool_insert(ipo, addr, mask, info)
-ip_pool_t *ipo;
-i6addr_t *addr, *mask;
-int info;
+static int
+ipf_pool_insert_node(softc, softp, ipo, node)
+ ipf_main_softc_t *softc;
+ ipf_pool_softc_t *softp;
+ ip_pool_t *ipo;
+ struct ip_pool_node *node;
{
- struct radix_node *rn;
+ ipf_rdx_node_t *rn;
ip_pool_node_t *x;
+ if ((node->ipn_addr.adf_len > sizeof(*rn)) ||
+ (node->ipn_addr.adf_len < 4)) {
+ IPFERROR(70003);
+ return EINVAL;
+ }
+
+ if ((node->ipn_mask.adf_len > sizeof(*rn)) ||
+ (node->ipn_mask.adf_len < 4)) {
+ IPFERROR(70004);
+ return EINVAL;
+ }
+
KMALLOC(x, ip_pool_node_t *);
if (x == NULL) {
+ IPFERROR(70002);
return ENOMEM;
}
- bzero(x, sizeof(*x));
-
- x->ipn_info = info;
- (void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name));
+ *x = *node;
+ bzero((char *)x->ipn_nodes, sizeof(x->ipn_nodes));
+ x->ipn_owner = ipo;
+ x->ipn_hits = 0;
+ x->ipn_next = NULL;
+ x->ipn_pnext = NULL;
+ x->ipn_dnext = NULL;
+ x->ipn_pdnext = NULL;
+
+ if (x->ipn_die != 0) {
+ /*
+ * If the new node has a given expiration time, insert it
+ * into the list of expiring nodes with the ones to be
+ * removed first added to the front of the list. The
+ * insertion is O(n) but it is kept sorted for quick scans
+ * at expiration interval checks.
+ */
+ ip_pool_node_t *n;
+
+ x->ipn_die = softc->ipf_ticks + IPF_TTLVAL(x->ipn_die);
+ for (n = softp->ipf_node_explist; n != NULL; n = n->ipn_dnext) {
+ if (x->ipn_die < n->ipn_die)
+ break;
+ if (n->ipn_dnext == NULL) {
+ /*
+ * We've got to the last node and everything
+ * wanted to be expired before this new node,
+ * so we have to tack it on the end...
+ */
+ n->ipn_dnext = x;
+ x->ipn_pdnext = &n->ipn_dnext;
+ n = NULL;
+ break;
+ }
+ }
- bcopy(addr, &x->ipn_addr.adf_addr, sizeof(*addr));
- x->ipn_addr.adf_len = sizeof(x->ipn_addr);
- bcopy(mask, &x->ipn_mask.adf_addr, sizeof(*mask));
- x->ipn_mask.adf_len = sizeof(x->ipn_mask);
+ if (softp->ipf_node_explist == NULL) {
+ softp->ipf_node_explist = x;
+ x->ipn_pdnext = &softp->ipf_node_explist;
+ } else if (n != NULL) {
+ x->ipn_dnext = n;
+ x->ipn_pdnext = n->ipn_pdnext;
+ n->ipn_pdnext = &x->ipn_dnext;
+ }
+ }
- RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
- rn = ipo->ipo_head->rnh_addaddr(&x->ipn_addr, &x->ipn_mask,
- ipo->ipo_head, x->ipn_nodes);
- RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
+ rn = ipo->ipo_head->addaddr(ipo->ipo_head, &x->ipn_addr, &x->ipn_mask,
+ x->ipn_nodes);
#ifdef DEBUG_POOL
printf("Added %p at %p\n", x, rn);
#endif
if (rn == NULL) {
KFREE(x);
+ IPFERROR(70005);
return ENOMEM;
}
x->ipn_ref = 1;
- x->ipn_next = ipo->ipo_list;
- x->ipn_pnext = &ipo->ipo_list;
- if (ipo->ipo_list != NULL)
- ipo->ipo_list->ipn_pnext = &x->ipn_next;
- ipo->ipo_list = x;
+ x->ipn_pnext = ipo->ipo_tail;
+ *ipo->ipo_tail = x;
+ ipo->ipo_tail = &x->ipn_next;
- ipoolstat.ipls_nodes++;
+ softp->ipf_pool_stats.ipls_nodes++;
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_create */
-/* Returns: int - 0 = success, else error */
-/* Parameters: op(I) - pointer to iplookup struct with call details */
-/* Locks: WRITE(ip_poolrw) */
+/* Function: ipf_pool_create */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softp(I) - pointer to soft context pool information */
+/* op(I) - pointer to iplookup struct with call details */
+/* Locks: WRITE(ipf_poolrw) */
/* */
/* Creates a new group according to the paramters passed in via the */
/* iplookupop structure. Does not check to see if the group already exists */
@@ -522,8 +945,11 @@ int info;
/* as this likely means we've tried to free a pool that is in use (flush) */
/* and now want to repopulate it with "new" data. */
/* ------------------------------------------------------------------------ */
-int ip_pool_create(op)
-iplookupop_t *op;
+static int
+ipf_pool_create(softc, softp, op)
+ ipf_main_softc_t *softc;
+ ipf_pool_softc_t *softp;
+ iplookupop_t *op;
{
char name[FR_GROUPLEN];
int poolnum, unit;
@@ -532,23 +958,27 @@ iplookupop_t *op;
unit = op->iplo_unit;
if ((op->iplo_arg & LOOKUP_ANON) == 0) {
- h = ip_pool_exists(unit, op->iplo_name);
+ h = ipf_pool_exists(softp, unit, op->iplo_name);
if (h != NULL) {
- if ((h->ipo_flags & IPOOL_DELETE) == 0)
+ if ((h->ipo_flags & IPOOL_DELETE) == 0) {
+ IPFERROR(70006);
return EEXIST;
+ }
h->ipo_flags &= ~IPOOL_DELETE;
return 0;
}
}
KMALLOC(h, ip_pool_t *);
- if (h == NULL)
+ if (h == NULL) {
+ IPFERROR(70007);
return ENOMEM;
+ }
bzero(h, sizeof(*h));
- if (rn_inithead((void **)&h->ipo_head,
- offsetof(addrfamily_t, adf_addr) << 3) == 0) {
+ if (ipf_rx_inithead(softp->ipf_radix, &h->ipo_head) != 0) {
KFREE(h);
+ IPFERROR(70008);
return ENOMEM;
}
@@ -564,7 +994,7 @@ iplookupop_t *op;
(void)sprintf(name, "%x", poolnum);
#endif
- for (p = ip_pool_list[unit]; p != NULL; ) {
+ for (p = softp->ipf_pool_list[unit + 1]; p != NULL; ) {
if (strncmp(name, p->ipo_name,
sizeof(p->ipo_name)) == 0) {
poolnum++;
@@ -573,7 +1003,7 @@ iplookupop_t *op;
#else
(void)sprintf(name, "%x", poolnum);
#endif
- p = ip_pool_list[unit];
+ p = softp->ipf_pool_list[unit + 1];
} else
p = p->ipo_next;
}
@@ -584,121 +1014,144 @@ iplookupop_t *op;
(void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name));
}
+ h->ipo_radix = softp->ipf_radix;
h->ipo_ref = 1;
h->ipo_list = NULL;
+ h->ipo_tail = &h->ipo_list;
h->ipo_unit = unit;
- h->ipo_next = ip_pool_list[unit];
- if (ip_pool_list[unit] != NULL)
- ip_pool_list[unit]->ipo_pnext = &h->ipo_next;
- h->ipo_pnext = &ip_pool_list[unit];
- ip_pool_list[unit] = h;
+ h->ipo_next = softp->ipf_pool_list[unit + 1];
+ if (softp->ipf_pool_list[unit + 1] != NULL)
+ softp->ipf_pool_list[unit + 1]->ipo_pnext = &h->ipo_next;
+ h->ipo_pnext = &softp->ipf_pool_list[unit + 1];
+ softp->ipf_pool_list[unit + 1] = h;
- ipoolstat.ipls_pools++;
+ softp->ipf_pool_stats.ipls_pools++;
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_remove */
-/* Returns: int - 0 = success, else error */
-/* Parameters: ipo(I) - pointer to the pool to remove the node from. */
-/* ipe(I) - address being deleted as a node */
-/* Locks: WRITE(ip_poolrw) */
+/* Function: ipf_pool_remove_node */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* ipo(I) - pointer to the pool to remove the node from. */
+/* ipe(I) - address being deleted as a node */
+/* Locks: WRITE(ipf_poolrw) */
/* */
/* Remove a node from the pool given by ipo. */
/* ------------------------------------------------------------------------ */
-int ip_pool_remove(ipo, ipe)
-ip_pool_t *ipo;
-ip_pool_node_t *ipe;
+static int
+ipf_pool_remove_node(softc, softp, ipo, ipe)
+ ipf_main_softc_t *softc;
+ ipf_pool_softc_t *softp;
+ ip_pool_t *ipo;
+ ip_pool_node_t *ipe;
{
+ void *ptr;
+
+ if (ipo->ipo_tail == &ipe->ipn_next)
+ ipo->ipo_tail = ipe->ipn_pnext;
if (ipe->ipn_pnext != NULL)
*ipe->ipn_pnext = ipe->ipn_next;
if (ipe->ipn_next != NULL)
ipe->ipn_next->ipn_pnext = ipe->ipn_pnext;
- RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
- ipo->ipo_head->rnh_deladdr(&ipe->ipn_addr, &ipe->ipn_mask,
- ipo->ipo_head);
- RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
+ if (ipe->ipn_pdnext != NULL)
+ *ipe->ipn_pdnext = ipe->ipn_dnext;
+ if (ipe->ipn_dnext != NULL)
+ ipe->ipn_dnext->ipn_pdnext = ipe->ipn_pdnext;
- ip_pool_node_deref(ipe);
+ ptr = ipo->ipo_head->deladdr(ipo->ipo_head, &ipe->ipn_addr,
+ &ipe->ipn_mask);
- return 0;
+ if (ptr != NULL) {
+ ipf_pool_node_deref(softp, ipe);
+ return 0;
+ }
+ IPFERROR(70027);
+ return ESRCH;
}
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_destroy */
+/* Function: ipf_pool_destroy */
/* Returns: int - 0 = success, else error */
-/* Parameters: op(I) - information about the pool to remove */
-/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softp(I) - pointer to soft context pool information */
+/* unit(I) - ipfilter device to which we are working on */
+/* name(I) - name of the pool */
+/* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */
/* */
/* Search for a pool using paramters passed in and if it's not otherwise */
/* busy, free it. If it is busy, clear all of its nodes, mark it for being */
/* deleted and return an error saying it is busy. */
/* */
-/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
+/* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
/* may not be initialised, we can't use an ASSERT to enforce the locking */
-/* assertion that one of the two (ip_poolrw,ipf_global) is held. */
+/* assertion that one of the two (ipf_poolrw,ipf_global) is held. */
/* ------------------------------------------------------------------------ */
-int ip_pool_destroy(unit, name)
-int unit;
-char *name;
+static int
+ipf_pool_destroy(softc, softp, unit, name)
+ ipf_main_softc_t *softc;
+ ipf_pool_softc_t *softp;
+ int unit;
+ char *name;
{
ip_pool_t *ipo;
- ipo = ip_pool_exists(unit, name);
- if (ipo == NULL)
+ ipo = ipf_pool_exists(softp, unit, name);
+ if (ipo == NULL) {
+ IPFERROR(70009);
return ESRCH;
+ }
if (ipo->ipo_ref != 1) {
- ip_pool_clearnodes(ipo);
+ ipf_pool_clearnodes(softc, softp, ipo);
ipo->ipo_flags |= IPOOL_DELETE;
return 0;
}
- ip_pool_free(ipo);
+ ipf_pool_free(softc, softp, ipo);
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_flush */
+/* Function: ipf_pool_flush */
/* Returns: int - number of pools deleted */
-/* Parameters: fp(I) - which pool(s) to flush */
-/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* fp(I) - which pool(s) to flush */
+/* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */
/* */
/* Free all pools associated with the device that matches the unit number */
/* passed in with operation. */
/* */
-/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
+/* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
/* may not be initialised, we can't use an ASSERT to enforce the locking */
-/* assertion that one of the two (ip_poolrw,ipf_global) is held. */
+/* assertion that one of the two (ipf_poolrw,ipf_global) is held. */
/* ------------------------------------------------------------------------ */
-int ip_pool_flush(fp)
-iplookupflush_t *fp;
+static size_t
+ipf_pool_flush(softc, arg, fp)
+ ipf_main_softc_t *softc;
+ void *arg;
+ iplookupflush_t *fp;
{
+ ipf_pool_softc_t *softp = arg;
int i, num = 0, unit, err;
ip_pool_t *p, *q;
- iplookupop_t op;
unit = fp->iplf_unit;
-
- for (i = 0; i <= IPL_LOGMAX; i++) {
+ for (i = -1; i <= IPL_LOGMAX; i++) {
if (unit != IPLT_ALL && i != unit)
continue;
- for (q = ip_pool_list[i]; (p = q) != NULL; ) {
- op.iplo_unit = i;
- (void)strncpy(op.iplo_name, p->ipo_name,
- sizeof(op.iplo_name));
+ for (q = softp->ipf_pool_list[i + 1]; (p = q) != NULL; ) {
q = p->ipo_next;
- err = ip_pool_destroy(op.iplo_unit, op.iplo_name);
+ err = ipf_pool_destroy(softc, softp, i, p->ipo_name);
if (err == 0)
num++;
- else
- break;
}
}
return num;
@@ -706,125 +1159,140 @@ iplookupflush_t *fp;
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_free */
+/* Function: ipf_pool_free */
/* Returns: void */
-/* Parameters: ipo(I) - pointer to pool structure */
-/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softp(I) - pointer to soft context pool information */
+/* ipo(I) - pointer to pool structure */
+/* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */
/* */
/* Deletes the pool strucutre passed in from the list of pools and deletes */
/* all of the address information stored in it, including any tree data */
/* structures also allocated. */
/* */
-/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */
+/* NOTE: Because this function is called out of ipfdetach() where ipf_poolrw*/
/* may not be initialised, we can't use an ASSERT to enforce the locking */
-/* assertion that one of the two (ip_poolrw,ipf_global) is held. */
+/* assertion that one of the two (ipf_poolrw,ipf_global) is held. */
/* ------------------------------------------------------------------------ */
-void ip_pool_free(ipo)
-ip_pool_t *ipo;
+static void
+ipf_pool_free(softc, softp, ipo)
+ ipf_main_softc_t *softc;
+ ipf_pool_softc_t *softp;
+ ip_pool_t *ipo;
{
- ip_pool_clearnodes(ipo);
+ ipf_pool_clearnodes(softc, softp, ipo);
if (ipo->ipo_next != NULL)
ipo->ipo_next->ipo_pnext = ipo->ipo_pnext;
*ipo->ipo_pnext = ipo->ipo_next;
- rn_freehead(ipo->ipo_head);
+ ipf_rx_freehead(ipo->ipo_head);
KFREE(ipo);
- ipoolstat.ipls_pools--;
+ softp->ipf_pool_stats.ipls_pools--;
}
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_clearnodes */
+/* Function: ipf_pool_clearnodes */
/* Returns: void */
-/* Parameters: ipo(I) - pointer to pool structure */
-/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softp(I) - pointer to soft context pool information */
+/* ipo(I) - pointer to pool structure */
+/* Locks: WRITE(ipf_poolrw) or WRITE(ipf_global) */
/* */
/* Deletes all nodes stored in a pool structure. */
/* ------------------------------------------------------------------------ */
-static void ip_pool_clearnodes(ipo)
-ip_pool_t *ipo;
+static void
+ipf_pool_clearnodes(softc, softp, ipo)
+ ipf_main_softc_t *softc;
+ ipf_pool_softc_t *softp;
+ ip_pool_t *ipo;
{
- ip_pool_node_t *n;
-
- RADIX_NODE_HEAD_LOCK(ipo->ipo_head);
- while ((n = ipo->ipo_list) != NULL) {
- ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask,
- ipo->ipo_head);
-
- *n->ipn_pnext = n->ipn_next;
- if (n->ipn_next)
- n->ipn_next->ipn_pnext = n->ipn_pnext;
-
- KFREE(n);
+ ip_pool_node_t *n, **next;
- ipoolstat.ipls_nodes--;
- }
- RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head);
+ for (next = &ipo->ipo_list; (n = *next) != NULL; )
+ ipf_pool_remove_node(softc, softp, ipo, n);
ipo->ipo_list = NULL;
}
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_deref */
+/* Function: ipf_pool_deref */
/* Returns: void */
-/* Parameters: ipo(I) - pointer to pool structure */
-/* Locks: WRITE(ip_poolrw) */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* pool(I) - pointer to pool structure */
+/* Locks: WRITE(ipf_poolrw) */
/* */
/* Drop the number of known references to this pool structure by one and if */
/* we arrive at zero known references, free it. */
/* ------------------------------------------------------------------------ */
-void ip_pool_deref(ipo)
-ip_pool_t *ipo;
+static int
+ipf_pool_deref(softc, arg, pool)
+ ipf_main_softc_t *softc;
+ void *arg, *pool;
{
+ ip_pool_t *ipo = pool;
ipo->ipo_ref--;
if (ipo->ipo_ref == 0)
- ip_pool_free(ipo);
+ ipf_pool_free(softc, arg, ipo);
else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE))
- ip_pool_destroy(ipo->ipo_unit, ipo->ipo_name);
+ ipf_pool_destroy(softc, arg, ipo->ipo_unit, ipo->ipo_name);
+
+ return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_node_deref */
+/* Function: ipf_pool_node_deref */
/* Returns: void */
-/* Parameters: ipn(I) - pointer to pool structure */
-/* Locks: WRITE(ip_poolrw) */
+/* Parameters: softp(I) - pointer to soft context pool information */
+/* ipn(I) - pointer to pool structure */
+/* Locks: WRITE(ipf_poolrw) */
/* */
/* Drop a reference to the pool node passed in and if we're the last, free */
/* it all up and adjust the stats accordingly. */
/* ------------------------------------------------------------------------ */
-void ip_pool_node_deref(ipn)
-ip_pool_node_t *ipn;
+static void
+ipf_pool_node_deref(softp, ipn)
+ ipf_pool_softc_t *softp;
+ ip_pool_node_t *ipn;
{
ipn->ipn_ref--;
if (ipn->ipn_ref == 0) {
KFREE(ipn);
- ipoolstat.ipls_nodes--;
+ softp->ipf_pool_stats.ipls_nodes--;
}
}
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_getnext */
+/* Function: ipf_pool_iter_next */
/* Returns: void */
-/* Parameters: token(I) - pointer to pool structure */
-/* Parameters: ilp(IO) - pointer to pool iterating structure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* token(I) - pointer to pool structure */
+/* ilp(IO) - pointer to pool iterating structure */
/* */
/* ------------------------------------------------------------------------ */
-int ip_pool_getnext(token, ilp)
-ipftoken_t *token;
-ipflookupiter_t *ilp;
+static int
+ipf_pool_iter_next(softc, arg, token, ilp)
+ ipf_main_softc_t *softc;
+ void *arg;
+ ipftoken_t *token;
+ ipflookupiter_t *ilp;
{
+ ipf_pool_softc_t *softp = arg;
ip_pool_node_t *node, zn, *nextnode;
ip_pool_t *ipo, zp, *nextipo;
+ void *pnext;
int err;
err = 0;
@@ -833,35 +1301,38 @@ ipflookupiter_t *ilp;
ipo = NULL;
nextipo = NULL;
- READ_ENTER(&ip_poolrw);
+ READ_ENTER(&softc->ipf_poolrw);
switch (ilp->ili_otype)
{
case IPFLOOKUPITER_LIST :
ipo = token->ipt_data;
if (ipo == NULL) {
- nextipo = ip_pool_list[(int)ilp->ili_unit];
+ nextipo = softp->ipf_pool_list[(int)ilp->ili_unit + 1];
} else {
nextipo = ipo->ipo_next;
}
if (nextipo != NULL) {
- ATOMIC_INC(nextipo->ipo_ref);
+ ATOMIC_INC32(nextipo->ipo_ref);
token->ipt_data = nextipo;
} else {
bzero((char *)&zp, sizeof(zp));
nextipo = &zp;
token->ipt_data = NULL;
}
+ pnext = nextipo->ipo_next;
break;
case IPFLOOKUPITER_NODE :
node = token->ipt_data;
if (node == NULL) {
- ipo = ip_pool_exists(ilp->ili_unit, ilp->ili_name);
- if (ipo == NULL)
+ ipo = ipf_pool_exists(arg, ilp->ili_unit,
+ ilp->ili_name);
+ if (ipo == NULL) {
+ IPFERROR(70010);
err = ESRCH;
- else {
+ } else {
nextnode = ipo->ipo_list;
ipo = NULL;
}
@@ -870,123 +1341,149 @@ ipflookupiter_t *ilp;
}
if (nextnode != NULL) {
- ATOMIC_INC(nextnode->ipn_ref);
+ ATOMIC_INC32(nextnode->ipn_ref);
token->ipt_data = nextnode;
} else {
bzero((char *)&zn, sizeof(zn));
nextnode = &zn;
token->ipt_data = NULL;
}
+ pnext = nextnode->ipn_next;
break;
+
default :
+ IPFERROR(70011);
+ pnext = NULL;
err = EINVAL;
break;
}
- RWLOCK_EXIT(&ip_poolrw);
-
+ RWLOCK_EXIT(&softc->ipf_poolrw);
if (err != 0)
return err;
switch (ilp->ili_otype)
{
case IPFLOOKUPITER_LIST :
- if (ipo != NULL) {
- WRITE_ENTER(&ip_poolrw);
- ip_pool_deref(ipo);
- RWLOCK_EXIT(&ip_poolrw);
- }
err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo));
- if (err != 0)
+ if (err != 0) {
+ IPFERROR(70012);
err = EFAULT;
+ }
+ if (ipo != NULL) {
+ WRITE_ENTER(&softc->ipf_poolrw);
+ ipf_pool_deref(softc, softp, ipo);
+ RWLOCK_EXIT(&softc->ipf_poolrw);
+ }
break;
case IPFLOOKUPITER_NODE :
- if (node != NULL) {
- WRITE_ENTER(&ip_poolrw);
- ip_pool_node_deref(node);
- RWLOCK_EXIT(&ip_poolrw);
- }
err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode));
- if (err != 0)
+ if (err != 0) {
+ IPFERROR(70013);
err = EFAULT;
+ }
+ if (node != NULL) {
+ WRITE_ENTER(&softc->ipf_poolrw);
+ ipf_pool_node_deref(softp, node);
+ RWLOCK_EXIT(&softc->ipf_poolrw);
+ }
break;
}
+ if (pnext == NULL)
+ ipf_token_mark_complete(token);
return err;
}
/* ------------------------------------------------------------------------ */
-/* Function: ip_pool_iterderef */
+/* Function: ipf_pool_iterderef */
/* Returns: void */
-/* Parameters: ipn(I) - pointer to pool structure */
-/* Locks: WRITE(ip_poolrw) */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* unit(I) - ipfilter device to which we are working on */
+/* Locks: WRITE(ipf_poolrw) */
/* */
/* ------------------------------------------------------------------------ */
-void ip_pool_iterderef(otype, unit, data)
-u_int otype;
-int unit;
-void *data;
+static int
+ipf_pool_iter_deref(softc, arg, otype, unit, data)
+ ipf_main_softc_t *softc;
+ void *arg;
+ int otype;
+ int unit;
+ void *data;
{
+ ipf_pool_softc_t *softp = arg;
if (data == NULL)
- return;
+ return EINVAL;
if (unit < 0 || unit > IPL_LOGMAX)
- return;
+ return EINVAL;
switch (otype)
{
case IPFLOOKUPITER_LIST :
- WRITE_ENTER(&ip_poolrw);
- ip_pool_deref((ip_pool_t *)data);
- RWLOCK_EXIT(&ip_poolrw);
+ ipf_pool_deref(softc, softp, (ip_pool_t *)data);
break;
case IPFLOOKUPITER_NODE :
- WRITE_ENTER(&ip_poolrw);
- ip_pool_node_deref((ip_pool_node_t *)data);
- RWLOCK_EXIT(&ip_poolrw);
+ ipf_pool_node_deref(softp, (ip_pool_node_t *)data);
break;
default :
break;
}
+
+ return 0;
}
-# if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \
- !defined(__hpux) && !defined(__sgi))
-static int
-rn_freenode(struct radix_node *n, void *p)
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_pool_expire */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* At present this function exists just to support temporary addition of */
+/* nodes to the address pool. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_pool_expire(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
{
- struct radix_node_head *rnh = p;
- struct radix_node *d;
+ ipf_pool_softc_t *softp = arg;
+ ip_pool_node_t *n;
- d = rnh->rnh_deladdr(n->rn_key, NULL, rnh);
- if (d != NULL) {
- FreeS(d, max_keylen + 2 * sizeof (*d));
+ while ((n = softp->ipf_node_explist) != NULL) {
+ /*
+ * Because the list is kept sorted on insertion, the fist
+ * one that dies in the future means no more work to do.
+ */
+ if (n->ipn_die > softc->ipf_ticks)
+ break;
+ ipf_pool_remove_node(softc, softp, n->ipn_owner, n);
}
- return 0;
}
-void
-rn_freehead(rnh)
- struct radix_node_head *rnh;
-{
- RADIX_NODE_HEAD_LOCK(rnh);
- (*rnh->rnh_walktree)(rnh, rn_freenode, rnh);
- rnh->rnh_addaddr = NULL;
- rnh->rnh_deladdr = NULL;
- rnh->rnh_matchaddr = NULL;
- rnh->rnh_lookup = NULL;
- rnh->rnh_walktree = NULL;
- RADIX_NODE_HEAD_UNLOCK(rnh);
+#ifndef _KERNEL
+void
+ipf_pool_dump(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_pool_softc_t *softp = arg;
+ ip_pool_t *ipl;
+ int i;
- Free(rnh);
+ printf("List of configured pools\n");
+ for (i = 0; i <= LOOKUP_POOL_MAX; i++)
+ for (ipl = softp->ipf_pool_list[i]; ipl != NULL;
+ ipl = ipl->ipo_next)
+ printpool(ipl, bcopywrap, NULL, opts, NULL);
}
-# endif
-#endif /* IPFILTER_LOOKUP */
+#endif
diff --git a/sys/contrib/ipfilter/netinet/ip_pool.h b/sys/contrib/ipfilter/netinet/ip_pool.h
index 9968ef0..8524e60 100644
--- a/sys/contrib/ipfilter/netinet/ip_pool.h
+++ b/sys/contrib/ipfilter/netinet/ip_pool.h
@@ -1,90 +1,67 @@
/*
- * Copyright (C) 1993-2001, 2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
- * $Id: ip_pool.h,v 2.26.2.6 2007/10/10 09:51:43 darrenr Exp $
+ * $Id$
*/
#ifndef __IP_POOL_H__
#define __IP_POOL_H__
-#if defined(_KERNEL) && !defined(__osf__) && !defined(__hpux) && \
- !defined(linux) && !defined(sun) && !defined(AIX)
-# include <net/radix.h>
-extern void rn_freehead __P((struct radix_node_head *));
-# define FreeS(p, z) KFREES(p, z)
-extern int max_keylen;
-#else
-# if defined(__osf__) || defined(__hpux) || defined(sun)
-# include "radix_ipf_local.h"
-# define radix_mask ipf_radix_mask
-# define radix_node ipf_radix_node
-# define radix_node_head ipf_radix_node_head
-# else
-# include "radix_ipf.h"
-# endif
-#endif
#include "netinet/ip_lookup.h"
+#include "radix_ipf.h"
#define IP_POOL_NOMATCH 0
#define IP_POOL_POSITIVE 1
typedef struct ip_pool_node {
- struct radix_node ipn_nodes[2];
+ ipf_rdx_node_t ipn_nodes[2];
addrfamily_t ipn_addr;
addrfamily_t ipn_mask;
+ int ipn_uid;
int ipn_info;
int ipn_ref;
-char ipn_name[FR_GROUPLEN];
-u_long ipn_hits;
+ char ipn_name[FR_GROUPLEN];
+ U_QUAD_T ipn_hits;
+ U_QUAD_T ipn_bytes;
+ u_long ipn_die;
struct ip_pool_node *ipn_next, **ipn_pnext;
+ struct ip_pool_node *ipn_dnext, **ipn_pdnext;
+ struct ip_pool_s *ipn_owner;
} ip_pool_node_t;
typedef struct ip_pool_s {
struct ip_pool_s *ipo_next;
struct ip_pool_s **ipo_pnext;
- struct radix_node_head *ipo_head;
- ip_pool_node_t *ipo_list;
- u_long ipo_hits;
- int ipo_unit;
- int ipo_flags;
- int ipo_ref;
- char ipo_name[FR_GROUPLEN];
+ ipf_rdx_head_t *ipo_head;
+ ip_pool_node_t *ipo_list;
+ ip_pool_node_t **ipo_tail;
+ ip_pool_node_t *ipo_nextaddr;
+ void *ipo_radix;
+ u_long ipo_hits;
+ int ipo_unit;
+ int ipo_flags;
+ int ipo_ref;
+ char ipo_name[FR_GROUPLEN];
} ip_pool_t;
#define IPOOL_DELETE 0x01
#define IPOOL_ANON 0x02
-typedef struct ip_pool_stat {
- u_long ipls_pools;
- u_long ipls_tables;
- u_long ipls_nodes;
- ip_pool_t *ipls_list[IPL_LOGSIZE];
-} ip_pool_stat_t;
-
+typedef struct ipf_pool_stat {
+ u_long ipls_pools;
+ u_long ipls_tables;
+ u_long ipls_nodes;
+ ip_pool_t *ipls_list[LOOKUP_POOL_SZ];
+} ipf_pool_stat_t;
-extern ip_pool_stat_t ipoolstat;
-extern ip_pool_t *ip_pool_list[IPL_LOGSIZE];
+extern ipf_lookup_t ipf_pool_backend;
-extern int ip_pool_search __P((void *, int, void *));
-extern int ip_pool_init __P((void));
-extern void ip_pool_fini __P((void));
-extern int ip_pool_create __P((iplookupop_t *));
-extern int ip_pool_insert __P((ip_pool_t *, i6addr_t *, i6addr_t *, int));
-extern int ip_pool_remove __P((ip_pool_t *, ip_pool_node_t *));
-extern int ip_pool_destroy __P((int, char *));
-extern void ip_pool_free __P((ip_pool_t *));
-extern void ip_pool_deref __P((ip_pool_t *));
-extern void ip_pool_node_deref __P((ip_pool_node_t *));
-extern void *ip_pool_find __P((int, char *));
-extern ip_pool_node_t *ip_pool_findeq __P((ip_pool_t *,
- addrfamily_t *, addrfamily_t *));
-extern int ip_pool_flush __P((iplookupflush_t *));
-extern int ip_pool_statistics __P((iplookupop_t *));
-extern int ip_pool_getnext __P((ipftoken_t *, ipflookupiter_t *));
-extern void ip_pool_iterderef __P((u_int, int, void *));
+#ifndef _KERNEL
+extern void ipf_pool_dump __P((ipf_main_softc_t *, void *));
+#endif
#endif /* __IP_POOL_H__ */
diff --git a/sys/contrib/ipfilter/netinet/ip_pptp_pxy.c b/sys/contrib/ipfilter/netinet/ip_pptp_pxy.c
index 3924d4b..959b107 100644
--- a/sys/contrib/ipfilter/netinet/ip_pptp_pxy.c
+++ b/sys/contrib/ipfilter/netinet/ip_pptp_pxy.c
@@ -1,18 +1,42 @@
/*
- * Copyright (C) 2002-2003 by Darren Reed
+ * Copyright (C) 2012 by Darren Reed.
*
* Simple PPTP transparent proxy for in-kernel use. For use with the NAT
* code.
*
- * $Id: ip_pptp_pxy.c,v 2.10.2.15 2006/10/31 12:11:23 darrenr Exp $
+ * $Id$
*
*/
#define IPF_PPTP_PROXY
+
+
+/*
+ * PPTP proxy
+ */
+typedef struct pptp_side {
+ u_32_t pptps_nexthdr;
+ u_32_t pptps_next;
+ int pptps_state;
+ int pptps_gothdr;
+ int pptps_len;
+ int pptps_bytes;
+ char *pptps_wptr;
+ char pptps_buffer[512];
+} pptp_side_t;
+
+typedef struct pptp_pxy {
+ nat_t *pptp_nat;
+ struct ipstate *pptp_state;
+ u_short pptp_call[2];
+ pptp_side_t pptp_side[2];
+ ipnat_t *pptp_rule;
+} pptp_pxy_t;
+
typedef struct pptp_hdr {
- u_short pptph_len;
- u_short pptph_type;
- u_32_t pptph_cookie;
+ u_short pptph_len;
+ u_short pptph_type;
+ u_32_t pptph_cookie;
} pptp_hdr_t;
#define PPTP_MSGTYPE_CTL 1
@@ -33,41 +57,41 @@ typedef struct pptp_hdr {
#define PPTP_MTCTL_LINKINFO 15
-int ippr_pptp_init __P((void));
-void ippr_pptp_fini __P((void));
-int ippr_pptp_new __P((fr_info_t *, ap_session_t *, nat_t *));
-void ippr_pptp_del __P((ap_session_t *));
-int ippr_pptp_inout __P((fr_info_t *, ap_session_t *, nat_t *));
-void ippr_pptp_donatstate __P((fr_info_t *, nat_t *, pptp_pxy_t *));
-int ippr_pptp_message __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *));
-int ippr_pptp_nextmessage __P((fr_info_t *, nat_t *, pptp_pxy_t *, int));
-int ippr_pptp_mctl __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *));
+void ipf_p_pptp_main_load __P((void));
+void ipf_p_pptp_main_unload __P((void));
+int ipf_p_pptp_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_pptp_del __P((ipf_main_softc_t *, ap_session_t *));
+int ipf_p_pptp_inout __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_pptp_donatstate __P((fr_info_t *, nat_t *, pptp_pxy_t *));
+int ipf_p_pptp_message __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *));
+int ipf_p_pptp_nextmessage __P((fr_info_t *, nat_t *, pptp_pxy_t *, int));
+int ipf_p_pptp_mctl __P((fr_info_t *, nat_t *, pptp_pxy_t *, pptp_side_t *));
static frentry_t pptpfr;
-int pptp_proxy_init = 0;
-int ippr_pptp_debug = 0;
-int ippr_pptp_gretimeout = IPF_TTLVAL(120); /* 2 minutes */
+static int pptp_proxy_init = 0;
+static int ipf_p_pptp_debug = 0;
+static int ipf_p_pptp_gretimeout = IPF_TTLVAL(120); /* 2 minutes */
/*
* PPTP application proxy initialization.
*/
-int ippr_pptp_init()
+void
+ipf_p_pptp_main_load()
{
bzero((char *)&pptpfr, sizeof(pptpfr));
pptpfr.fr_ref = 1;
- pptpfr.fr_age[0] = ippr_pptp_gretimeout;
- pptpfr.fr_age[1] = ippr_pptp_gretimeout;
+ pptpfr.fr_age[0] = ipf_p_pptp_gretimeout;
+ pptpfr.fr_age[1] = ipf_p_pptp_gretimeout;
pptpfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
MUTEX_INIT(&pptpfr.fr_lock, "PPTP proxy rule lock");
pptp_proxy_init = 1;
-
- return 0;
}
-void ippr_pptp_fini()
+void
+ipf_p_pptp_main_unload()
{
if (pptp_proxy_init == 1) {
MUTEX_DESTROY(&pptpfr.fr_lock);
@@ -82,64 +106,83 @@ void ippr_pptp_fini()
* NOTE: The printf's are broken up with %s in them to prevent them being
* optimised into puts statements on FreeBSD (this doesn't exist in the kernel)
*/
-int ippr_pptp_new(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_pptp_new(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
{
pptp_pxy_t *pptp;
ipnat_t *ipn;
+ ipnat_t *np;
+ int size;
ip_t *ip;
+ if (fin->fin_v != 4)
+ return -1;
+
ip = fin->fin_ip;
+ np = nat->nat_ptr;
+ size = np->in_size;
- if (nat_outlookup(fin, 0, IPPROTO_GRE, nat->nat_inip,
+ if (ipf_nat_outlookup(fin, 0, IPPROTO_GRE, nat->nat_osrcip,
ip->ip_dst) != NULL) {
- if (ippr_pptp_debug > 0)
- printf("ippr_pptp_new: GRE session %s\n",
- "already exists");
+ if (ipf_p_pptp_debug > 0)
+ printf("ipf_p_pptp_new: GRE session already exists\n");
return -1;
}
- aps->aps_psiz = sizeof(*pptp);
- KMALLOCS(aps->aps_data, pptp_pxy_t *, sizeof(*pptp));
- if (aps->aps_data == NULL) {
- if (ippr_pptp_debug > 0)
- printf("ippr_pptp_new: malloc for aps_data %s\n",
- "failed");
+ KMALLOC(pptp, pptp_pxy_t *);
+ if (pptp == NULL) {
+ if (ipf_p_pptp_debug > 0)
+ printf("ipf_p_pptp_new: malloc for aps_data failed\n");
+ return -1;
+ }
+ KMALLOCS(ipn, ipnat_t *, size);
+ if (ipn == NULL) {
+ KFREE(pptp);
return -1;
}
+ aps->aps_data = pptp;
+ aps->aps_psiz = sizeof(*pptp);
+ bzero((char *)pptp, sizeof(*pptp));
+ bzero((char *)ipn, size);
+ pptp->pptp_rule = ipn;
+
/*
* Create NAT rule against which the tunnel/transport mapping is
* created. This is required because the current NAT rule does not
* describe GRE but TCP instead.
*/
- pptp = aps->aps_data;
- bzero((char *)pptp, sizeof(*pptp));
- ipn = &pptp->pptp_rule;
+ ipn->in_size = size;
ipn->in_ifps[0] = fin->fin_ifp;
ipn->in_apr = NULL;
ipn->in_use = 1;
ipn->in_hits = 1;
ipn->in_ippip = 1;
- if (nat->nat_dir == NAT_OUTBOUND) {
- ipn->in_nip = ntohl(nat->nat_outip.s_addr);
- ipn->in_outip = fin->fin_saddr;
- ipn->in_redir = NAT_MAP;
- } else if (nat->nat_dir == NAT_INBOUND) {
- ipn->in_nip = 0;
- ipn->in_outip = nat->nat_outip.s_addr;
- ipn->in_redir = NAT_REDIRECT;
- }
- ipn->in_inip = nat->nat_inip.s_addr;
- ipn->in_inmsk = 0xffffffff;
- ipn->in_outmsk = 0xffffffff;
- ipn->in_srcip = fin->fin_saddr;
- ipn->in_srcmsk = 0xffffffff;
- bcopy(nat->nat_ptr->in_ifnames[0], ipn->in_ifnames[0],
- sizeof(ipn->in_ifnames[0]));
- ipn->in_p = IPPROTO_GRE;
+ ipn->in_snip = ntohl(nat->nat_nsrcaddr);
+ ipn->in_nsrcaddr = fin->fin_saddr;
+ ipn->in_dnip = ntohl(nat->nat_ndstaddr);
+ ipn->in_ndstaddr = nat->nat_ndstaddr;
+ ipn->in_redir = np->in_redir;
+ ipn->in_osrcaddr = nat->nat_osrcaddr;
+ ipn->in_odstaddr = nat->nat_odstaddr;
+ ipn->in_osrcmsk = 0xffffffff;
+ ipn->in_nsrcmsk = 0xffffffff;
+ ipn->in_odstmsk = 0xffffffff;
+ ipn->in_ndstmsk = 0xffffffff;
+ ipn->in_flags = (np->in_flags | IPN_PROXYRULE);
+ MUTEX_INIT(&ipn->in_lock, "pptp proxy NAT rule");
+
+ ipn->in_namelen = np->in_namelen;
+ bcopy(np->in_names, ipn->in_ifnames, ipn->in_namelen);
+ ipn->in_ifnames[0] = np->in_ifnames[0];
+ ipn->in_ifnames[1] = np->in_ifnames[1];
+
+ ipn->in_pr[0] = IPPROTO_GRE;
+ ipn->in_pr[1] = IPPROTO_GRE;
pptp->pptp_side[0].pptps_wptr = pptp->pptp_side[0].pptps_buffer;
pptp->pptp_side[1].pptps_wptr = pptp->pptp_side[1].pptps_buffer;
@@ -147,11 +190,13 @@ nat_t *nat;
}
-void ippr_pptp_donatstate(fin, nat, pptp)
-fr_info_t *fin;
-nat_t *nat;
-pptp_pxy_t *pptp;
+void
+ipf_p_pptp_donatstate(fin, nat, pptp)
+ fr_info_t *fin;
+ nat_t *nat;
+ pptp_pxy_t *pptp;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
fr_info_t fi;
grehdr_t gre;
nat_t *nat2;
@@ -165,8 +210,6 @@ pptp_pxy_t *pptp;
if ((nat2 == NULL) || (pptp->pptp_state == NULL)) {
bcopy((char *)fin, (char *)&fi, sizeof(fi));
bzero((char *)&gre, sizeof(gre));
- fi.fin_state = NULL;
- fi.fin_nat = NULL;
fi.fin_fi.fi_p = IPPROTO_GRE;
fi.fin_fr = &pptpfr;
if ((nat->nat_dir == NAT_OUTBOUND && fin->fin_out) ||
@@ -183,47 +226,47 @@ pptp_pxy_t *pptp;
fi.fin_flx |= FI_IGNORE;
fi.fin_dp = &gre;
gre.gr_flags = htons(1 << 13);
- if (fin->fin_out && nat->nat_dir == NAT_INBOUND) {
- fi.fin_fi.fi_saddr = fin->fin_fi.fi_daddr;
- fi.fin_fi.fi_daddr = nat->nat_outip.s_addr;
- } else if (!fin->fin_out && nat->nat_dir == NAT_OUTBOUND) {
- fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
- fi.fin_fi.fi_daddr = fin->fin_fi.fi_saddr;
- }
+
+ fi.fin_fi.fi_saddr = nat->nat_osrcaddr;
+ fi.fin_fi.fi_daddr = nat->nat_odstaddr;
}
/*
* Update NAT timeout/create NAT if missing.
*/
if (nat2 != NULL)
- fr_queueback(&nat2->nat_tqe);
+ ipf_queueback(softc->ipf_ticks, &nat2->nat_tqe);
else {
- nat2 = nat_new(&fi, &pptp->pptp_rule, &pptp->pptp_nat,
- NAT_SLAVE, nat->nat_dir);
- pptp->pptp_nat = nat2;
+#ifdef USE_MUTEXES
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+#endif
+
+ MUTEX_ENTER(&softn->ipf_nat_new);
+ nat2 = ipf_nat_add(&fi, pptp->pptp_rule, &pptp->pptp_nat,
+ NAT_SLAVE, nat->nat_dir);
+ MUTEX_EXIT(&softn->ipf_nat_new);
if (nat2 != NULL) {
- (void) nat_proto(&fi, nat2, 0);
- nat_update(&fi, nat2, nat2->nat_ptr);
+ (void) ipf_nat_proto(&fi, nat2, 0);
+ MUTEX_ENTER(&nat2->nat_lock);
+ ipf_nat_update(&fi, nat2);
+ MUTEX_EXIT(&nat2->nat_lock);
}
}
- READ_ENTER(&ipf_state);
+ READ_ENTER(&softc->ipf_state);
if (pptp->pptp_state != NULL) {
- fr_queueback(&pptp->pptp_state->is_sti);
- RWLOCK_EXIT(&ipf_state);
+ ipf_queueback(softc->ipf_ticks, &pptp->pptp_state->is_sti);
+ RWLOCK_EXIT(&softc->ipf_state);
} else {
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
if (nat2 != NULL) {
if (nat->nat_dir == NAT_INBOUND)
- fi.fin_fi.fi_daddr = nat2->nat_inip.s_addr;
+ fi.fin_fi.fi_daddr = nat2->nat_ndstaddr;
else
- fi.fin_fi.fi_saddr = nat2->nat_inip.s_addr;
+ fi.fin_fi.fi_saddr = nat2->nat_osrcaddr;
}
fi.fin_ifp = NULL;
- pptp->pptp_state = fr_addstate(&fi, &pptp->pptp_state,
- 0);
- if (fi.fin_state != NULL)
- fr_statederef((ipstate_t **)&fi.fin_state);
+ (void) ipf_state_add(softc, &fi, &pptp->pptp_state, 0);
}
ip->ip_p = p;
return;
@@ -235,13 +278,14 @@ pptp_pxy_t *pptp;
* build it up completely (fits in our buffer) then pass it off to the message
* parsing function.
*/
-int ippr_pptp_nextmessage(fin, nat, pptp, rev)
-fr_info_t *fin;
-nat_t *nat;
-pptp_pxy_t *pptp;
-int rev;
+int
+ipf_p_pptp_nextmessage(fin, nat, pptp, rev)
+ fr_info_t *fin;
+ nat_t *nat;
+ pptp_pxy_t *pptp;
+ int rev;
{
- static const char *funcname = "ippr_pptp_nextmessage";
+ static const char *funcname = "ipf_p_pptp_nextmessage";
pptp_side_t *pptps;
u_32_t start, end;
pptp_hdr_t *hdr;
@@ -271,7 +315,7 @@ int rev;
return 0;
if (pptps->pptps_next != start) {
- if (ippr_pptp_debug > 5)
+ if (ipf_p_pptp_debug > 5)
printf("%s: next (%x) != start (%x)\n", funcname,
pptps->pptps_next, start);
return -1;
@@ -296,7 +340,7 @@ int rev;
if (pptps->pptps_bytes == 8) {
pptps->pptps_next += 8;
if (ntohl(hdr->pptph_cookie) != 0x1a2b3c4d) {
- if (ippr_pptp_debug > 1)
+ if (ipf_p_pptp_debug > 1)
printf("%s: bad cookie (%x)\n",
funcname,
hdr->pptph_cookie);
@@ -320,7 +364,7 @@ int rev;
* bad data packet, anyway.
*/
if (len > sizeof(pptps->pptps_buffer)) {
- if (ippr_pptp_debug > 3)
+ if (ipf_p_pptp_debug > 3)
printf("%s: message too big (%d)\n",
funcname, len);
pptps->pptps_next = pptps->pptps_nexthdr;
@@ -341,7 +385,7 @@ int rev;
if (pptps->pptps_len > pptps->pptps_bytes)
break;
- ippr_pptp_message(fin, nat, pptp, pptps);
+ ipf_p_pptp_message(fin, nat, pptp, pptps);
pptps->pptps_wptr = pptps->pptps_buffer;
pptps->pptps_gothdr = 0;
pptps->pptps_bytes = 0;
@@ -359,18 +403,19 @@ int rev;
/*
* handle a complete PPTP message
*/
-int ippr_pptp_message(fin, nat, pptp, pptps)
-fr_info_t *fin;
-nat_t *nat;
-pptp_pxy_t *pptp;
-pptp_side_t *pptps;
+int
+ipf_p_pptp_message(fin, nat, pptp, pptps)
+ fr_info_t *fin;
+ nat_t *nat;
+ pptp_pxy_t *pptp;
+ pptp_side_t *pptps;
{
pptp_hdr_t *hdr = (pptp_hdr_t *)pptps->pptps_buffer;
switch (ntohs(hdr->pptph_type))
{
case PPTP_MSGTYPE_CTL :
- ippr_pptp_mctl(fin, nat, pptp, pptps);
+ ipf_p_pptp_mctl(fin, nat, pptp, pptps);
break;
default :
@@ -383,11 +428,12 @@ pptp_side_t *pptps;
/*
* handle a complete PPTP control message
*/
-int ippr_pptp_mctl(fin, nat, pptp, pptps)
-fr_info_t *fin;
-nat_t *nat;
-pptp_pxy_t *pptp;
-pptp_side_t *pptps;
+int
+ipf_p_pptp_mctl(fin, nat, pptp, pptps)
+ fr_info_t *fin;
+ nat_t *nat;
+ pptp_pxy_t *pptp;
+ pptp_side_t *pptps;
{
u_short *buffer = (u_short *)(pptps->pptps_buffer);
pptp_side_t *pptpo;
@@ -432,7 +478,7 @@ pptp_side_t *pptps;
pptps->pptps_state = PPTP_MTCTL_OUTREP;
pptp->pptp_call[0] = buffer[7];
pptp->pptp_call[1] = buffer[6];
- ippr_pptp_donatstate(fin, nat, pptp);
+ ipf_p_pptp_donatstate(fin, nat, pptp);
}
break;
case PPTP_MTCTL_INREQ :
@@ -443,7 +489,7 @@ pptp_side_t *pptps;
pptps->pptps_state = PPTP_MTCTL_INREP;
pptp->pptp_call[0] = buffer[7];
pptp->pptp_call[1] = buffer[6];
- ippr_pptp_donatstate(fin, nat, pptp);
+ ipf_p_pptp_donatstate(fin, nat, pptp);
}
break;
case PPTP_MTCTL_INCONNECT :
@@ -471,10 +517,12 @@ pptp_side_t *pptps;
* For outgoing PPTP packets. refresh timeouts for NAT & state entries, if
* we can. If they have disappeared, recreate them.
*/
-int ippr_pptp_inout(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_pptp_inout(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
{
pptp_pxy_t *pptp;
tcphdr_t *tcp;
@@ -495,7 +543,7 @@ nat_t *nat;
pptp->pptp_side[rev].pptps_next = ntohl(tcp->th_seq) + 1;
pptp->pptp_side[rev].pptps_nexthdr = ntohl(tcp->th_seq) + 1;
}
- return ippr_pptp_nextmessage(fin, nat, (pptp_pxy_t *)aps->aps_data,
+ return ipf_p_pptp_nextmessage(fin, nat, (pptp_pxy_t *)aps->aps_data,
rev);
}
@@ -503,8 +551,10 @@ nat_t *nat;
/*
* clean up after ourselves.
*/
-void ippr_pptp_del(aps)
-ap_session_t *aps;
+void
+ipf_p_pptp_del(softc, aps)
+ ipf_main_softc_t *softc;
+ ap_session_t *aps;
{
pptp_pxy_t *pptp;
@@ -516,15 +566,15 @@ ap_session_t *aps;
* *_del() is on a callback from aps_free(), from nat_delete()
*/
- READ_ENTER(&ipf_state);
+ READ_ENTER(&softc->ipf_state);
if (pptp->pptp_state != NULL) {
- pptp->pptp_state->is_die = fr_ticks + 1;
- pptp->pptp_state->is_me = NULL;
- fr_queuefront(&pptp->pptp_state->is_sti);
+ ipf_state_setpending(softc, pptp->pptp_state);
}
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
- pptp->pptp_state = NULL;
- pptp->pptp_nat = NULL;
+ if (pptp->pptp_nat != NULL)
+ ipf_nat_setpending(softc, pptp->pptp_nat);
+ pptp->pptp_rule->in_flags |= IPN_DELETE;
+ ipf_nat_rule_deref(softc, &pptp->pptp_rule);
}
}
diff --git a/sys/contrib/ipfilter/netinet/ip_proxy.c b/sys/contrib/ipfilter/netinet/ip_proxy.c
index e492a33..39addb0 100644
--- a/sys/contrib/ipfilter/netinet/ip_proxy.c
+++ b/sys/contrib/ipfilter/netinet/ip_proxy.c
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1997-2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*/
@@ -49,9 +49,6 @@ struct file;
#if defined(_KERNEL) && (__FreeBSD_version >= 220000)
# include <sys/filio.h>
# include <sys/fcntl.h>
-# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM)
-# include "opt_ipfilter.h"
-# endif
#else
# include <sys/ioctl.h>
#endif
@@ -70,7 +67,6 @@ struct file;
#ifdef sun
# include <net/af.h>
#endif
-#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
@@ -90,9 +86,12 @@ struct file;
# include <sys/malloc.h>
#endif
+/* END OF INCLUDES */
+
#include "netinet/ip_ftp_pxy.c"
+#include "netinet/ip_tftp_pxy.c"
#include "netinet/ip_rcmd_pxy.c"
-# include "netinet/ip_pptp_pxy.c"
+#include "netinet/ip_pptp_pxy.c"
#if defined(_KERNEL)
# include "netinet/ip_irc_pxy.c"
# include "netinet/ip_raudio_pxy.c"
@@ -101,93 +100,474 @@ struct file;
#include "netinet/ip_ipsec_pxy.c"
#include "netinet/ip_rpcb_pxy.c"
-/* END OF INCLUDES */
-
#if !defined(lint)
-static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.62.2.21 2007/06/02 21:22:28 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id$";
#endif
-static int appr_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int ));
-
#define AP_SESS_SIZE 53
-#if defined(_KERNEL)
-int ipf_proxy_debug = 0;
-#else
-int ipf_proxy_debug = 2;
-#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[] = {
+static int ipf_proxy_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int ));
+static aproxy_t *ipf_proxy_create_clone __P((ipf_main_softc_t *, aproxy_t *));
+
+typedef struct ipf_proxy_softc_s {
+ int ips_proxy_debug;
+ int ips_proxy_session_size;
+ ap_session_t **ips_sess_tab;
+ ap_session_t *ips_sess_list;
+ aproxy_t *ips_proxies;
+ int ips_init_run;
+ ipftuneable_t *ipf_proxy_tune;
+} ipf_proxy_softc_t;
+
+static ipftuneable_t ipf_proxy_tuneables[] = {
+ { { (void *)offsetof(ipf_proxy_softc_t, ips_proxy_debug) },
+ "proxy_debug", 0, 0x1f,
+ stsizeof(ipf_proxy_softc_t, ips_proxy_debug),
+ 0, NULL, NULL },
+ { { NULL }, NULL, 0, 0,
+ 0,
+ 0, NULL, NULL}
+};
+
+static aproxy_t *ap_proxylist = NULL;
+static aproxy_t ips_proxies[] = {
#ifdef IPF_FTP_PROXY
- { NULL, "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, ippr_ftp_fini,
- ippr_ftp_new, NULL, ippr_ftp_in, ippr_ftp_out, NULL, NULL },
+ { NULL, NULL, "ftp", (char)IPPROTO_TCP, 0, 0, 0,
+ ipf_p_ftp_main_load, ipf_p_ftp_main_unload,
+ ipf_p_ftp_soft_create, ipf_p_ftp_soft_destroy,
+ NULL, NULL,
+ ipf_p_ftp_new, ipf_p_ftp_del, ipf_p_ftp_in, ipf_p_ftp_out, NULL,
+ NULL, NULL, NULL, NULL },
+#endif
+#ifdef IPF_TFTP_PROXY
+ { NULL, NULL, "tftp", (char)IPPROTO_UDP, 0, 0, 0,
+ ipf_p_tftp_main_load, ipf_p_tftp_main_unload,
+ ipf_p_tftp_soft_create, ipf_p_tftp_soft_destroy,
+ NULL, NULL,
+ ipf_p_tftp_new, ipf_p_tftp_del,
+ ipf_p_tftp_in, ipf_p_tftp_out, NULL,
+ NULL, NULL, NULL, NULL },
#endif
#ifdef IPF_IRC_PROXY
- { NULL, "irc", (char)IPPROTO_TCP, 0, 0, ippr_irc_init, ippr_irc_fini,
- ippr_irc_new, NULL, NULL, ippr_irc_out, NULL, NULL },
+ { NULL, NULL, "irc", (char)IPPROTO_TCP, 0, 0, 0,
+ ipf_p_irc_main_load, ipf_p_irc_main_unload,
+ NULL, NULL,
+ NULL, NULL,
+ ipf_p_irc_new, NULL, NULL, ipf_p_irc_out, NULL,
+ NULL, NULL, NULL, NULL },
#endif
#ifdef IPF_RCMD_PROXY
- { NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, ippr_rcmd_init, ippr_rcmd_fini,
- ippr_rcmd_new, NULL, ippr_rcmd_in, ippr_rcmd_out, NULL, NULL },
+ { NULL, NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, 0,
+ ipf_p_rcmd_main_load, ipf_p_rcmd_main_unload,
+ NULL, NULL,
+ NULL, NULL,
+ ipf_p_rcmd_new, ipf_p_rcmd_del,
+ ipf_p_rcmd_in, ipf_p_rcmd_out, NULL,
+ NULL, NULL, NULL, NULL },
#endif
#ifdef IPF_RAUDIO_PROXY
- { NULL, "raudio", (char)IPPROTO_TCP, 0, 0, ippr_raudio_init, ippr_raudio_fini,
- ippr_raudio_new, NULL, ippr_raudio_in, ippr_raudio_out, NULL, NULL },
+ { NULL, NULL, "raudio", (char)IPPROTO_TCP, 0, 0, 0,
+ ipf_p_raudio_main_load, ipf_p_raudio_main_unload,
+ NULL, NULL,
+ NULL, NULL,
+ ipf_p_raudio_new, NULL, ipf_p_raudio_in, ipf_p_raudio_out, NULL,
+ NULL, NULL, NULL, NULL },
#endif
#ifdef IPF_MSNRPC_PROXY
- { NULL, "msnrpc", (char)IPPROTO_TCP, 0, 0, ippr_msnrpc_init, ippr_msnrpc_fini,
- ippr_msnrpc_new, NULL, ippr_msnrpc_in, ippr_msnrpc_out, NULL, NULL },
+ { NULL, NULL, "msnrpc", (char)IPPROTO_TCP, 0, 0, 0,
+ ipf_p_msnrpc_init, ipf_p_msnrpc_fini,
+ NULL, NULL,
+ NULL, NULL,
+ ipf_p_msnrpc_new, NULL, ipf_p_msnrpc_in, ipf_p_msnrpc_out, NULL,
+ NULL, NULL, NULL, NULL },
#endif
#ifdef IPF_NETBIOS_PROXY
- { NULL, "netbios", (char)IPPROTO_UDP, 0, 0, ippr_netbios_init, ippr_netbios_fini,
- NULL, NULL, NULL, ippr_netbios_out, NULL, NULL },
+ { NULL, NULL, "netbios", (char)IPPROTO_UDP, 0, 0, 0,
+ ipf_p_netbios_main_load, ipf_p_netbios_main_unload,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL, NULL, ipf_p_netbios_out, NULL,
+ NULL, NULL, NULL, NULL },
#endif
#ifdef IPF_IPSEC_PROXY
- { NULL, "ipsec", (char)IPPROTO_UDP, 0, 0,
- ippr_ipsec_init, ippr_ipsec_fini, ippr_ipsec_new, ippr_ipsec_del,
- ippr_ipsec_inout, ippr_ipsec_inout, ippr_ipsec_match, NULL },
+ { NULL, NULL, "ipsec", (char)IPPROTO_UDP, 0, 0, 0,
+ NULL, NULL,
+ ipf_p_ipsec_soft_create, ipf_p_ipsec_soft_destroy,
+ ipf_p_ipsec_soft_init, ipf_p_ipsec_soft_fini,
+ ipf_p_ipsec_new, ipf_p_ipsec_del,
+ ipf_p_ipsec_inout, ipf_p_ipsec_inout, ipf_p_ipsec_match,
+ NULL, NULL, NULL, NULL },
#endif
-#ifdef IPF_PPTP_PROXY
- { NULL, "pptp", (char)IPPROTO_TCP, 0, 0,
- ippr_pptp_init, ippr_pptp_fini, ippr_pptp_new, ippr_pptp_del,
- ippr_pptp_inout, ippr_pptp_inout, NULL, NULL },
+#ifdef IPF_DNS_PROXY
+ { NULL, NULL, "dns", (char)IPPROTO_UDP, 0, 0, 0,
+ NULL, NULL,
+ ipf_p_dns_soft_create, ipf_p_dns_soft_destroy,
+ NULL, NULL,
+ ipf_p_dns_new, ipf_p_ipsec_del,
+ ipf_p_dns_inout, ipf_p_dns_inout, ipf_p_dns_match,
+ ipf_p_dns_ctl, NULL, NULL, NULL },
#endif
-#ifdef IPF_H323_PROXY
- { NULL, "h323", (char)IPPROTO_TCP, 0, 0, ippr_h323_init, ippr_h323_fini,
- ippr_h323_new, ippr_h323_del, ippr_h323_in, NULL, NULL, NULL },
- { NULL, "h245", (char)IPPROTO_TCP, 0, 0, NULL, NULL,
- ippr_h245_new, NULL, NULL, ippr_h245_out, NULL, NULL },
+#ifdef IPF_PPTP_PROXY
+ { NULL, NULL, "pptp", (char)IPPROTO_TCP, 0, 0, 0,
+ ipf_p_pptp_main_load, ipf_p_pptp_main_unload,
+ NULL, NULL,
+ NULL, NULL,
+ ipf_p_pptp_new, ipf_p_pptp_del,
+ ipf_p_pptp_inout, ipf_p_pptp_inout, NULL,
+ NULL, NULL, NULL, NULL },
#endif
#ifdef IPF_RPCB_PROXY
-# if 0
- { NULL, "rpcbt", (char)IPPROTO_TCP, 0, 0,
- ippr_rpcb_init, ippr_rpcb_fini, ippr_rpcb_new, ippr_rpcb_del,
- ippr_rpcb_in, ippr_rpcb_out, NULL, NULL },
+# ifndef _KERNEL
+ { NULL, NULL, "rpcbt", (char)IPPROTO_TCP, 0, 0, 0,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ ipf_p_rpcb_new, ipf_p_rpcb_del,
+ ipf_p_rpcb_in, ipf_p_rpcb_out, NULL,
+ NULL, NULL, NULL, NULL },
# endif
- { NULL, "rpcbu", (char)IPPROTO_UDP, 0, 0,
- ippr_rpcb_init, ippr_rpcb_fini, ippr_rpcb_new, ippr_rpcb_del,
- ippr_rpcb_in, ippr_rpcb_out, NULL, NULL },
+ { NULL, NULL, "rpcbu", (char)IPPROTO_UDP, 0, 0, 0,
+ ipf_p_rpcb_main_load, ipf_p_rpcb_main_unload,
+ NULL, NULL,
+ NULL, NULL,
+ ipf_p_rpcb_new, ipf_p_rpcb_del,
+ ipf_p_rpcb_in, ipf_p_rpcb_out, NULL,
+ NULL, NULL, NULL, NULL },
#endif
- { NULL, "", '\0', 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
+ { NULL, NULL, "", '\0', 0, 0, 0,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL }
};
-/*
- * Dynamically add a new kernel proxy. Ensure that it is unique in the
- * collection compiled in and dynamically added.
- */
-int appr_add(ap)
-aproxy_t *ap;
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_main_load */
+/* Returns: int - 0 == success, else failure. */
+/* Parameters: Nil */
+/* */
+/* Initialise hook for kernel application proxies. */
+/* Call the initialise routine for all the compiled in kernel proxies. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_main_load()
+{
+ aproxy_t *ap;
+
+ for (ap = ips_proxies; ap->apr_p; ap++) {
+ if (ap->apr_load != NULL)
+ (*ap->apr_load)();
+ }
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_main_unload */
+/* Returns: int - 0 == success, else failure. */
+/* Parameters: Nil */
+/* */
+/* Unload hook for kernel application proxies. */
+/* Call the finialise routine for all the compiled in kernel proxies. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_main_unload()
+{
+ aproxy_t *ap;
+
+ for (ap = ips_proxies; ap->apr_p; ap++)
+ if (ap->apr_unload != NULL)
+ (*ap->apr_unload)();
+ for (ap = ap_proxylist; ap; ap = ap->apr_next)
+ if (ap->apr_unload != NULL)
+ (*ap->apr_unload)();
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_soft_create */
+/* Returns: void * - */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Build the structure to hold all of the run time data to support proxies. */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_proxy_soft_create(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_proxy_softc_t *softp;
+ aproxy_t *last;
+ aproxy_t *apn;
+ aproxy_t *ap;
+
+ KMALLOC(softp, ipf_proxy_softc_t *);
+ if (softp == NULL)
+ return softp;
+
+ bzero((char *)softp, sizeof(*softp));
+
+#if defined(_KERNEL)
+ softp->ips_proxy_debug = 0;
+#else
+ softp->ips_proxy_debug = 2;
+#endif
+ softp->ips_proxy_session_size = AP_SESS_SIZE;
+
+ softp->ipf_proxy_tune = ipf_tune_array_copy(softp,
+ sizeof(ipf_proxy_tuneables),
+ ipf_proxy_tuneables);
+ if (softp->ipf_proxy_tune == NULL) {
+ ipf_proxy_soft_destroy(softc, softp);
+ return NULL;
+ }
+ if (ipf_tune_array_link(softc, softp->ipf_proxy_tune) == -1) {
+ ipf_proxy_soft_destroy(softc, softp);
+ return NULL;
+ }
+
+ last = NULL;
+ for (ap = ips_proxies; ap->apr_p; ap++) {
+ apn = ipf_proxy_create_clone(softc, ap);
+ if (apn == NULL)
+ goto failed;
+ if (last != NULL)
+ last->apr_next = apn;
+ else
+ softp->ips_proxies = apn;
+ last = apn;
+ }
+ for (ap = ips_proxies; ap != NULL; ap = ap->apr_next) {
+ apn = ipf_proxy_create_clone(softc, ap);
+ if (apn == NULL)
+ goto failed;
+ if (last != NULL)
+ last->apr_next = apn;
+ else
+ softp->ips_proxies = apn;
+ last = apn;
+ }
+
+ return softp;
+failed:
+ ipf_proxy_soft_destroy(softc, softp);
+ return NULL;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_soft_create */
+/* Returns: void * - */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* orig(I) - pointer to proxy definition to copy */
+/* */
+/* This function clones a proxy definition given by orig and returns a */
+/* a pointer to that copy. */
+/* ------------------------------------------------------------------------ */
+static aproxy_t *
+ipf_proxy_create_clone(softc, orig)
+ ipf_main_softc_t *softc;
+ aproxy_t *orig;
+{
+ aproxy_t *apn;
+
+ KMALLOC(apn, aproxy_t *);
+ if (apn == NULL)
+ return NULL;
+
+ bcopy((char *)orig, (char *)apn, sizeof(*apn));
+ apn->apr_next = NULL;
+ apn->apr_soft = NULL;
+
+ if (apn->apr_create != NULL) {
+ apn->apr_soft = (*apn->apr_create)(softc);
+ if (apn->apr_soft == NULL) {
+ KFREE(apn);
+ return NULL;
+ }
+ }
+
+ apn->apr_parent = orig;
+ orig->apr_clones++;
+
+ return apn;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_soft_create */
+/* Returns: int - 0 == success, else failure. */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to proxy contect data */
+/* */
+/* Initialise the proxy context and walk through each of the proxies and */
+/* call its initialisation function. This allows for proxies to do any */
+/* local setup prior to actual use. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_soft_init(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_proxy_softc_t *softp;
+ aproxy_t *ap;
+ u_int size;
+ int err;
+
+ softp = arg;
+ size = softp->ips_proxy_session_size * sizeof(ap_session_t *);
+
+ KMALLOCS(softp->ips_sess_tab, ap_session_t **, size);
+
+ if (softp->ips_sess_tab == NULL)
+ return -1;
+
+ bzero(softp->ips_sess_tab, size);
+
+ for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next) {
+ if (ap->apr_init != NULL) {
+ err = (*ap->apr_init)(softc, ap->apr_soft);
+ if (err != 0)
+ return -2;
+ }
+ }
+ softp->ips_init_run = 1;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_soft_create */
+/* Returns: int - 0 == success, else failure. */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to proxy contect data */
+/* */
+/* This function should always succeed. It is responsible for ensuring that */
+/* the proxy context can be safely called when ipf_proxy_soft_destroy is */
+/* called and suring all of the proxies have similarly been instructed. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_soft_fini(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_proxy_softc_t *softp = arg;
+ aproxy_t *ap;
+
+ for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next) {
+ if (ap->apr_fini != NULL) {
+ (*ap->apr_fini)(softc, ap->apr_soft);
+ }
+ }
+
+ if (softp->ips_sess_tab != NULL) {
+ KFREES(softp->ips_sess_tab,
+ softp->ips_proxy_session_size * sizeof(ap_session_t *));
+ softp->ips_sess_tab = NULL;
+ }
+ softp->ips_init_run = 0;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_soft_destroy */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to proxy contect data */
+/* */
+/* Free up all of the local data structures allocated during creation. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_proxy_soft_destroy(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
{
+ ipf_proxy_softc_t *softp = arg;
+ aproxy_t *ap;
+
+ while ((ap = softp->ips_proxies) != NULL) {
+ softp->ips_proxies = ap->apr_next;
+ if (ap->apr_destroy != NULL)
+ (*ap->apr_destroy)(softc, ap->apr_soft);
+ ap->apr_parent->apr_clones--;
+ KFREE(ap);
+ }
+
+ if (softp->ipf_proxy_tune != NULL) {
+ ipf_tune_array_unlink(softc, softp->ipf_proxy_tune);
+ KFREES(softp->ipf_proxy_tune, sizeof(ipf_proxy_tuneables));
+ softp->ipf_proxy_tune = NULL;
+ }
+
+ KFREE(softp);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_flush */
+/* Returns: Nil */
+/* Parameters: arg(I) - pointer to proxy contect data */
+/* how(I) - indicates the type of flush operation */
+/* */
+/* Walk through all of the proxies and pass on the flush command as either */
+/* a flush or a clear. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_proxy_flush(arg, how)
+ void *arg;
+ int how;
+{
+ ipf_proxy_softc_t *softp = arg;
+ aproxy_t *ap;
+
+ switch (how)
+ {
+ case 0 :
+ for (ap = softp->ips_proxies; ap; ap = ap->apr_next)
+ if (ap->apr_flush != NULL)
+ (*ap->apr_flush)(ap, how);
+ break;
+ case 1 :
+ for (ap = softp->ips_proxies; ap; ap = ap->apr_next)
+ if (ap->apr_clear != NULL)
+ (*ap->apr_clear)(ap);
+ break;
+ default :
+ break;
+ }
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_add */
+/* Returns: int - 0 == success, else failure. */
+/* Parameters: ap(I) - pointer to proxy structure */
+/* */
+/* Dynamically add a new kernel proxy. Ensure that it is unique in the */
+/* collection compiled in and dynamically added. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_add(arg, ap)
+ void *arg;
+ aproxy_t *ap;
+{
+ ipf_proxy_softc_t *softp = arg;
+
aproxy_t *a;
- for (a = ap_proxies; a->apr_p; a++)
+ for (a = ips_proxies; a->apr_p; a++)
if ((a->apr_p == ap->apr_p) &&
!strncmp(a->apr_label, ap->apr_label,
sizeof(ap->apr_label))) {
- if (ipf_proxy_debug > 1)
- printf("appr_add: %s/%d already present (B)\n",
+ if (softp->ips_proxy_debug & 0x01)
+ printf("ipf_proxy_add: %s/%d present (B)\n",
a->apr_label, a->apr_p);
return -1;
}
@@ -196,89 +576,113 @@ aproxy_t *ap;
if ((a->apr_p == ap->apr_p) &&
!strncmp(a->apr_label, ap->apr_label,
sizeof(ap->apr_label))) {
- if (ipf_proxy_debug > 1)
- printf("appr_add: %s/%d already present (D)\n",
+ if (softp->ips_proxy_debug & 0x01)
+ printf("ipf_proxy_add: %s/%d present (D)\n",
a->apr_label, a->apr_p);
return -1;
}
ap->apr_next = ap_proxylist;
ap_proxylist = ap;
- if (ap->apr_init != NULL)
- return (*ap->apr_init)();
+ if (ap->apr_load != NULL)
+ (*ap->apr_load)();
return 0;
}
-/*
- * Check to see if the proxy this control request has come through for
- * exists, and if it does and it has a control function then invoke that
- * control function.
- */
-int appr_ctl(ctl)
-ap_ctl_t *ctl;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_ctl */
+/* Returns: int - 0 == success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to proxy context */
+/* ctl(I) - pointer to proxy control structure */
+/* */
+/* Check to see if the proxy this control request has come through for */
+/* exists, and if it does and it has a control function then invoke that */
+/* control function. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_ctl(softc, arg, ctl)
+ ipf_main_softc_t *softc;
+ void *arg;
+ ap_ctl_t *ctl;
{
+ ipf_proxy_softc_t *softp = arg;
aproxy_t *a;
int error;
- a = appr_lookup(ctl->apc_p, ctl->apc_label);
+ a = ipf_proxy_lookup(arg, ctl->apc_p, ctl->apc_label);
if (a == NULL) {
- if (ipf_proxy_debug > 1)
- printf("appr_ctl: can't find %s/%d\n",
+ if (softp->ips_proxy_debug & 0x01)
+ printf("ipf_proxy_ctl: can't find %s/%d\n",
ctl->apc_label, ctl->apc_p);
+ IPFERROR(80001);
error = ESRCH;
} else if (a->apr_ctl == NULL) {
- if (ipf_proxy_debug > 1)
- printf("appr_ctl: no ctl function for %s/%d\n",
+ if (softp->ips_proxy_debug & 0x01)
+ printf("ipf_proxy_ctl: no ctl function for %s/%d\n",
ctl->apc_label, ctl->apc_p);
+ IPFERROR(80002);
error = ENXIO;
} else {
- error = (*a->apr_ctl)(a, ctl);
- if ((error != 0) && (ipf_proxy_debug > 1))
- printf("appr_ctl: %s/%d ctl error %d\n",
+ error = (*a->apr_ctl)(softc, a->apr_soft, ctl);
+ if ((error != 0) && (softp->ips_proxy_debug & 0x02))
+ printf("ipf_proxy_ctl: %s/%d ctl error %d\n",
a->apr_label, a->apr_p, error);
}
return error;
}
-/*
- * Delete a proxy that has been added dynamically from those available.
- * If it is in use, return 1 (do not destroy NOW), not in use 0 or -1
- * if it cannot be matched.
- */
-int appr_del(ap)
-aproxy_t *ap;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_del */
+/* Returns: int - 0 == success, else failure. */
+/* Parameters: ap(I) - pointer to proxy structure */
+/* */
+/* Delete a proxy that has been added dynamically from those available. */
+/* If it is in use, return 1 (do not destroy NOW), not in use 0 or -1 */
+/* if it cannot be matched. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_del(ap)
+ aproxy_t *ap;
{
aproxy_t *a, **app;
- for (app = &ap_proxylist; ((a = *app) != NULL); app = &a->apr_next)
+ for (app = &ap_proxylist; ((a = *app) != NULL); app = &a->apr_next) {
if (a == ap) {
a->apr_flags |= APR_DELETE;
- *app = a->apr_next;
- if (ap->apr_ref != 0) {
- if (ipf_proxy_debug > 2)
- printf("appr_del: orphaning %s/%d\n",
- ap->apr_label, ap->apr_p);
- return 1;
+ if (ap->apr_ref == 0 && ap->apr_clones == 0) {
+ *app = a->apr_next;
+ return 0;
}
- return 0;
+ return 1;
}
- if (ipf_proxy_debug > 1)
- printf("appr_del: proxy %lx not found\n", (u_long)ap);
+ }
+
return -1;
}
-/*
- * Return 1 if the packet is a good match against a proxy, else 0.
- */
-int appr_ok(fin, tcp, nat)
-fr_info_t *fin;
-tcphdr_t *tcp;
-ipnat_t *nat;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_ok */
+/* Returns: int - 1 == good match else not. */
+/* Parameters: fin(I) - pointer to packet information */
+/* tcp(I) - pointer to TCP/UDP header */
+/* nat(I) - pointer to current NAT session */
+/* */
+/* This function extends the NAT matching to ensure that a packet that has */
+/* arrived matches the proxy information attached to the NAT rule. Notably, */
+/* if the proxy is scheduled to be deleted then packets will not match the */
+/* rule even if the rule is still active. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_ok(fin, tcp, np)
+ fr_info_t *fin;
+ tcphdr_t *tcp;
+ ipnat_t *np;
{
- aproxy_t *apr = nat->in_apr;
- u_short dport = nat->in_dport;
+ aproxy_t *apr = np->in_apr;
+ u_short dport = np->in_odport;
if ((apr == NULL) || (apr->apr_flags & APR_DELETE) ||
(fin->fin_p != apr->apr_p))
@@ -289,14 +693,26 @@ ipnat_t *nat;
}
-int appr_ioctl(data, cmd, mode, ctx)
-caddr_t data;
-ioctlcmd_t cmd;
-int mode;
-void *ctx;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_ioctl */
+/* Returns: int - 0 == success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* data(I) - pointer to ioctl data */
+/* cmd(I) - ioctl command */
+/* mode(I) - mode bits for device */
+/* ctx(I) - pointer to context information */
+/* */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_ioctl(softc, data, cmd, mode, ctx)
+ ipf_main_softc_t *softc;
+ caddr_t data;
+ ioctlcmd_t cmd;
+ int mode;
+ void *ctx;
{
ap_ctl_t ctl;
- u_char *ptr;
+ caddr_t ptr;
int error;
mode = mode; /* LINT */
@@ -304,17 +720,19 @@ void *ctx;
switch (cmd)
{
case SIOCPROXY :
- error = BCOPYIN(data, &ctl, sizeof(ctl));
- if (error != 0)
- return EFAULT;
+ error = ipf_inobj(softc, data, NULL, &ctl, IPFOBJ_PROXYCTL);
+ if (error != 0) {
+ return error;
+ }
ptr = NULL;
if (ctl.apc_dsize > 0) {
- KMALLOCS(ptr, u_char *, ctl.apc_dsize);
- if (ptr == NULL)
+ KMALLOCS(ptr, caddr_t, ctl.apc_dsize);
+ if (ptr == NULL) {
+ IPFERROR(80003);
error = ENOMEM;
- else {
- error = copyinptr(ctl.apc_data, ptr,
+ } else {
+ error = copyinptr(softc, ctl.apc_data, ptr,
ctl.apc_dsize);
if (error == 0)
ctl.apc_data = ptr;
@@ -325,49 +743,61 @@ void *ctx;
}
if (error == 0)
- error = appr_ctl(&ctl);
+ error = ipf_proxy_ctl(softc, softc->ipf_proxy_soft,
+ &ctl);
- if (ptr != NULL) {
+ if ((error != 0) && (ptr != NULL)) {
KFREES(ptr, ctl.apc_dsize);
}
break;
default :
+ IPFERROR(80004);
error = EINVAL;
}
return error;
}
-/*
- * If a proxy has a match function, call that to do extended packet
- * matching.
- */
-int appr_match(fin, nat)
-fr_info_t *fin;
-nat_t *nat;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_match */
+/* Returns: int - 0 == success, else error */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to current NAT session */
+/* */
+/* If a proxy has a match function, call that to do extended packet */
+/* matching. Whilst other parts of the NAT code are rather lenient when it */
+/* comes to the quality of the packet that it will transform, the proxy */
+/* matching is not because they need to work with data, not just headers. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_match(fin, nat)
+ fr_info_t *fin;
+ nat_t *nat;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
aproxy_t *apr;
ipnat_t *ipn;
int result;
ipn = nat->nat_ptr;
- if (ipf_proxy_debug > 8)
- printf("appr_match(%lx,%lx) aps %lx ptr %lx\n",
+ if (softp->ips_proxy_debug & 0x04)
+ printf("ipf_proxy_match(%lx,%lx) aps %lx ptr %lx\n",
(u_long)fin, (u_long)nat, (u_long)nat->nat_aps,
(u_long)ipn);
if ((fin->fin_flx & (FI_SHORT|FI_BAD)) != 0) {
- if (ipf_proxy_debug > 0)
- printf("appr_match: flx 0x%x (BAD|SHORT)\n",
+ if (softp->ips_proxy_debug & 0x08)
+ printf("ipf_proxy_match: flx 0x%x (BAD|SHORT)\n",
fin->fin_flx);
return -1;
}
apr = ipn->in_apr;
if ((apr == NULL) || (apr->apr_flags & APR_DELETE)) {
- if (ipf_proxy_debug > 0)
- printf("appr_match:apr %lx apr_flags 0x%x\n",
+ if (softp->ips_proxy_debug & 0x08)
+ printf("ipf_proxy_match:apr %lx apr_flags 0x%x\n",
(u_long)apr, apr ? apr->apr_flags : 0);
return -1;
}
@@ -375,8 +805,8 @@ nat_t *nat;
if (apr->apr_match != NULL) {
result = (*apr->apr_match)(fin, nat->nat_aps, nat);
if (result != 0) {
- if (ipf_proxy_debug > 4)
- printf("appr_match: result %d\n", result);
+ if (softp->ips_proxy_debug & 0x08)
+ printf("ipf_proxy_match: result %d\n", result);
return -1;
}
}
@@ -384,24 +814,32 @@ nat_t *nat;
}
-/*
- * Allocate a new application proxy structure and fill it in with the
- * relevant details. call the init function once complete, prior to
- * returning.
- */
-int appr_new(fin, nat)
-fr_info_t *fin;
-nat_t *nat;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_new */
+/* Returns: int - 0 == success, else error */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to current NAT session */
+/* */
+/* Allocate a new application proxy structure and fill it in with the */
+/* relevant details. call the init function once complete, prior to */
+/* returning. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_new(fin, nat)
+ fr_info_t *fin;
+ nat_t *nat;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
register ap_session_t *aps;
aproxy_t *apr;
- if (ipf_proxy_debug > 8)
- printf("appr_new(%lx,%lx) \n", (u_long)fin, (u_long)nat);
+ if (softp->ips_proxy_debug & 0x04)
+ printf("ipf_proxy_new(%lx,%lx) \n", (u_long)fin, (u_long)nat);
if ((nat->nat_ptr == NULL) || (nat->nat_aps != NULL)) {
- if (ipf_proxy_debug > 0)
- printf("appr_new: nat_ptr %lx nat_aps %lx\n",
+ if (softp->ips_proxy_debug & 0x08)
+ printf("ipf_proxy_new: nat_ptr %lx nat_aps %lx\n",
(u_long)nat->nat_ptr, (u_long)nat->nat_aps);
return -1;
}
@@ -410,65 +848,71 @@ nat_t *nat;
if ((apr->apr_flags & APR_DELETE) ||
(fin->fin_p != apr->apr_p)) {
- if (ipf_proxy_debug > 2)
- printf("appr_new: apr_flags 0x%x p %d/%d\n",
+ if (softp->ips_proxy_debug & 0x08)
+ printf("ipf_proxy_new: apr_flags 0x%x p %d/%d\n",
apr->apr_flags, fin->fin_p, apr->apr_p);
return -1;
}
KMALLOC(aps, ap_session_t *);
if (!aps) {
- if (ipf_proxy_debug > 0)
- printf("appr_new: malloc failed (%lu)\n",
+ if (softp->ips_proxy_debug & 0x08)
+ printf("ipf_proxy_new: malloc failed (%lu)\n",
(u_long)sizeof(ap_session_t));
return -1;
}
bzero((char *)aps, sizeof(*aps));
- aps->aps_p = fin->fin_p;
aps->aps_data = NULL;
aps->aps_apr = apr;
aps->aps_psiz = 0;
if (apr->apr_new != NULL)
- if ((*apr->apr_new)(fin, aps, nat) == -1) {
+ if ((*apr->apr_new)(apr->apr_soft, fin, aps, nat) == -1) {
if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) {
KFREES(aps->aps_data, aps->aps_psiz);
}
KFREE(aps);
- if (ipf_proxy_debug > 2)
- printf("appr_new: new(%lx) failed\n",
+ if (softp->ips_proxy_debug & 0x08)
+ printf("ipf_proxy_new: new(%lx) failed\n",
(u_long)apr->apr_new);
return -1;
}
aps->aps_nat = nat;
- aps->aps_next = ap_sess_list;
- ap_sess_list = aps;
+ aps->aps_next = softp->ips_sess_list;
+ softp->ips_sess_list = aps;
nat->nat_aps = aps;
return 0;
}
-/*
- * Check to see if a packet should be passed through an active proxy routine
- * if one has been setup for it. We don't need to check the checksum here if
- * IPFILTER_CKSUM is defined because if it is, a failed check causes FI_BAD
- * to be set.
- */
-int appr_check(fin, nat)
-fr_info_t *fin;
-nat_t *nat;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_check */
+/* Returns: int - -1 == error, 0 == success */
+/* Parameters: fin(I) - pointer to packet information */
+/* nat(I) - pointer to current NAT session */
+/* */
+/* Check to see if a packet should be passed through an active proxy */
+/* routine if one has been setup for it. We don't need to check the */
+/* checksum here if IPFILTER_CKSUM is defined because if it is, a failed */
+/* check causes FI_BAD to be set. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_proxy_check(fin, nat)
+ fr_info_t *fin;
+ nat_t *nat;
{
-#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
-# if defined(ICK_VALID)
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
+#if SOLARIS && defined(_KERNEL) && defined(ICK_VALID)
mb_t *m;
-# endif
- int dosum = 1;
#endif
tcphdr_t *tcp = NULL;
udphdr_t *udp = NULL;
ap_session_t *aps;
aproxy_t *apr;
+ short adjlen;
+ int dosum;
ip_t *ip;
short rv;
int err;
@@ -477,55 +921,54 @@ nat_t *nat;
#endif
if (fin->fin_flx & FI_BAD) {
- if (ipf_proxy_debug > 0)
- printf("appr_check: flx 0x%x (BAD)\n", fin->fin_flx);
+ if (softp->ips_proxy_debug & 0x08)
+ printf("ipf_proxy_check: flx 0x%x (BAD)\n",
+ fin->fin_flx);
return -1;
}
#ifndef IPFILTER_CKSUM
- if ((fin->fin_out == 0) && (fr_checkl4sum(fin) == -1)) {
- if (ipf_proxy_debug > 0)
- printf("appr_check: l4 checksum failure %d\n",
+ if ((fin->fin_out == 0) && (ipf_checkl4sum(fin) == -1)) {
+ if (softp->ips_proxy_debug & 0x08)
+ printf("ipf_proxy_check: l4 checksum failure %d\n",
fin->fin_p);
if (fin->fin_p == IPPROTO_TCP)
- frstats[fin->fin_out].fr_tcpbad++;
+ softc->ipf_stats[fin->fin_out].fr_tcpbad++;
return -1;
}
#endif
aps = nat->nat_aps;
- if ((aps != NULL) && (aps->aps_p == fin->fin_p)) {
+ if (aps != NULL) {
/*
* If there is data in this packet to be proxied then try and
* get it all into the one buffer, else drop it.
*/
#if defined(MENTAT) || defined(HAVE_M_PULLDOWN)
if ((fin->fin_dlen > 0) && !(fin->fin_flx & FI_COALESCE))
- if (fr_coalesce(fin) == -1) {
- if (ipf_proxy_debug > 0)
- printf("appr_check: fr_coalesce failed %x\n", fin->fin_flx);
+ if (ipf_coalesce(fin) == -1) {
+ if (softp->ips_proxy_debug & 0x08)
+ printf("ipf_proxy_check: %s %x\n",
+ "coalesce failed", fin->fin_flx);
return -1;
}
#endif
ip = fin->fin_ip;
+ if (fin->fin_cksum > FI_CK_SUMOK)
+ dosum = 0;
+ else
+ dosum = 1;
switch (fin->fin_p)
{
case IPPROTO_TCP :
tcp = (tcphdr_t *)fin->fin_dp;
-
-#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID)
+#if SOLARIS && defined(_KERNEL) && defined(ICK_VALID)
m = fin->fin_qfm;
if (dohwcksum && (m->b_ick_flag == ICK_VALID))
dosum = 0;
#endif
- /*
- * Don't bother the proxy with these...or in fact,
- * should we free up proxy stuff when seen?
- */
- if ((fin->fin_tcpf & TH_RST) != 0)
- break;
- /*FALLTHROUGH*/
+ break;
case IPPROTO_UDP :
udp = (udphdr_t *)fin->fin_dp;
break;
@@ -537,22 +980,24 @@ nat_t *nat;
err = 0;
if (fin->fin_out != 0) {
if (apr->apr_outpkt != NULL)
- err = (*apr->apr_outpkt)(fin, aps, nat);
+ err = (*apr->apr_outpkt)(apr->apr_soft, fin,
+ aps, nat);
} else {
if (apr->apr_inpkt != NULL)
- err = (*apr->apr_inpkt)(fin, aps, nat);
+ err = (*apr->apr_inpkt)(apr->apr_soft, fin,
+ aps, nat);
}
rv = APR_EXIT(err);
- if (((ipf_proxy_debug > 0) && (rv != 0)) ||
- (ipf_proxy_debug > 8))
- printf("appr_check: out %d err %x rv %d\n",
+ if (((softp->ips_proxy_debug & 0x08) && (rv != 0)) ||
+ (softp->ips_proxy_debug & 0x04))
+ printf("ipf_proxy_check: out %d err %x rv %d\n",
fin->fin_out, err, rv);
if (rv == 1)
return -1;
if (rv == 2) {
- appr_free(apr);
+ ipf_proxy_deref(apr);
nat->nat_aps = NULL;
return -1;
}
@@ -562,16 +1007,17 @@ nat_t *nat;
* so we need to recalculate the header checksums for the
* packet.
*/
+ adjlen = APR_INC(err);
#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi)
- if (err != 0) {
- short adjlen = err & 0xffff;
-
- s1 = LONG_SUM(fin->fin_plen - adjlen);
- s2 = LONG_SUM(fin->fin_plen);
- CALC_SUMD(s1, s2, sd);
- fix_outcksum(fin, &ip->ip_sum, sd);
- }
+ s1 = LONG_SUM(fin->fin_plen - adjlen);
+ s2 = LONG_SUM(fin->fin_plen);
+ CALC_SUMD(s1, s2, sd);
+ if ((err != 0) && (fin->fin_cksum < FI_CK_L4PART) &&
+ fin->fin_v == 4)
+ ipf_fix_outcksum(0, &ip->ip_sum, sd, 0);
#endif
+ if (fin->fin_flx & FI_DOCKSUM)
+ dosum = 1;
/*
* For TCP packets, we may need to adjust the sequence and
@@ -583,28 +1029,24 @@ nat_t *nat;
* changed or not.
*/
if (tcp != NULL) {
- err = appr_fixseqack(fin, ip, aps, APR_INC(err));
-#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
- if (dosum)
- tcp->th_sum = fr_cksum(fin->fin_qfm, ip,
- IPPROTO_TCP, tcp,
- fin->fin_plen);
-#else
- tcp->th_sum = fr_cksum(fin->fin_m, ip,
- IPPROTO_TCP, tcp,
- fin->fin_plen);
-#endif
+ err = ipf_proxy_fixseqack(fin, ip, aps, adjlen);
+ if (fin->fin_cksum == FI_CK_L4PART) {
+ u_short sum = ntohs(tcp->th_sum);
+ sum += adjlen;
+ tcp->th_sum = htons(sum);
+ } else if (fin->fin_cksum < FI_CK_L4PART) {
+ tcp->th_sum = fr_cksum(fin, ip,
+ IPPROTO_TCP, tcp);
+ }
} else if ((udp != NULL) && (udp->uh_sum != 0)) {
-#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
- if (dosum)
- udp->uh_sum = fr_cksum(fin->fin_qfm, ip,
- IPPROTO_UDP, udp,
- fin->fin_plen);
-#else
- udp->uh_sum = fr_cksum(fin->fin_m, ip,
- IPPROTO_UDP, udp,
- fin->fin_plen);
-#endif
+ if (fin->fin_cksum == FI_CK_L4PART) {
+ u_short sum = ntohs(udp->uh_sum);
+ sum += adjlen;
+ udp->uh_sum = htons(sum);
+ } else if (dosum) {
+ udp->uh_sum = fr_cksum(fin, ip,
+ IPPROTO_UDP, udp);
+ }
}
aps->aps_bytes += fin->fin_plen;
aps->aps_pkts++;
@@ -614,54 +1056,78 @@ nat_t *nat;
}
-/*
- * Search for an proxy by the protocol it is being used with and its name.
- */
-aproxy_t *appr_lookup(pr, name)
-u_int pr;
-char *name;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_lookup */
+/* Returns: int - -1 == error, 0 == success */
+/* Parameters: arg(I) - pointer to proxy context information */
+/* pr(I) - protocol number for proxy */
+/* name(I) - proxy name */
+/* */
+/* Search for an proxy by the protocol it is being used with and its name. */
+/* ------------------------------------------------------------------------ */
+aproxy_t *
+ipf_proxy_lookup(arg, pr, name)
+ void *arg;
+ u_int pr;
+ char *name;
{
+ ipf_proxy_softc_t *softp = arg;
aproxy_t *ap;
- if (ipf_proxy_debug > 8)
- printf("appr_lookup(%d,%s)\n", pr, name);
+ if (softp->ips_proxy_debug & 0x04)
+ printf("ipf_proxy_lookup(%d,%s)\n", pr, name);
- for (ap = ap_proxies; ap->apr_p; ap++)
+ for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next)
if ((ap->apr_p == pr) &&
!strncmp(name, ap->apr_label, sizeof(ap->apr_label))) {
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;
- }
- if (ipf_proxy_debug > 2)
- printf("appr_lookup: failed for %d/%s\n", pr, name);
+ if (softp->ips_proxy_debug & 0x08)
+ printf("ipf_proxy_lookup: failed for %d/%s\n", pr, name);
return NULL;
}
-void appr_free(ap)
-aproxy_t *ap;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_deref */
+/* Returns: Nil */
+/* Parameters: ap(I) - pointer to proxy structure */
+/* */
+/* Drop the reference counter associated with the proxy. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_proxy_deref(ap)
+ aproxy_t *ap;
{
ap->apr_ref--;
}
-void aps_free(aps)
-ap_session_t *aps;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_free */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* aps(I) - pointer to current proxy session */
+/* Locks Held: ipf_nat_new, ipf_nat(W) */
+/* */
+/* Free up proxy session information allocated to be used with a NAT */
+/* session. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_proxy_free(softc, aps)
+ ipf_main_softc_t *softc;
+ ap_session_t *aps;
{
+ ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
ap_session_t *a, **ap;
aproxy_t *apr;
if (!aps)
return;
- for (ap = &ap_sess_list; ((a = *ap) != NULL); ap = &a->aps_next)
+ for (ap = &softp->ips_sess_list; ((a = *ap) != NULL); ap = &a->aps_next)
if (a == aps) {
*ap = a->aps_next;
break;
@@ -669,7 +1135,7 @@ ap_session_t *aps;
apr = aps->aps_apr;
if ((apr != NULL) && (apr->apr_del != NULL))
- (*apr->apr_del)(aps);
+ (*apr->apr_del)(softc, aps);
if ((aps->aps_data != NULL) && (aps->aps_psiz != 0))
KFREES(aps->aps_data, aps->aps_psiz);
@@ -677,15 +1143,28 @@ ap_session_t *aps;
}
-/*
- * returns 2 if ack or seq number in TCP header is changed, returns 0 otherwise
- */
-static int appr_fixseqack(fin, ip, aps, inc)
-fr_info_t *fin;
-ip_t *ip;
-ap_session_t *aps;
-int inc;
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_fixseqack */
+/* Returns: int - 2 if TCP ack/seq is changed, else 0 */
+/* Parameters: fin(I) - pointer to packet information */
+/* ip(I) - pointer to IP header */
+/* nat(I) - pointer to current NAT session */
+/* inc(I) - delta to apply to TCP sequence numbering */
+/* */
+/* Adjust the TCP sequence/acknowledge numbers in the TCP header based on */
+/* whether or not the new header is past the point at which an adjustment */
+/* occurred. This might happen because of (say) an FTP string being changed */
+/* and the new string being a different length to the old. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_proxy_fixseqack(fin, ip, aps, inc)
+ fr_info_t *fin;
+ ip_t *ip;
+ ap_session_t *aps;
+ int inc;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
int sel, ch = 0, out, nlen;
u_32_t seq1, seq2;
tcphdr_t *tcp;
@@ -694,10 +1173,10 @@ int inc;
tcp = (tcphdr_t *)fin->fin_dp;
out = fin->fin_out;
/*
- * fin->fin_plen has already been adjusted by 'inc'.
+ * ip_len has already been adjusted by 'inc'.
*/
- nlen = fin->fin_plen;
- nlen -= (IP_HL(ip) << 2) + (TCP_OFF(tcp) << 2);
+ nlen = fin->fin_dlen;
+ nlen -= (TCP_OFF(tcp) << 2);
inc2 = inc;
inc = (int)inc2;
@@ -709,7 +1188,7 @@ int inc;
/* switch to other set ? */
if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) &&
(seq1 > aps->aps_seqmin[!sel])) {
- if (ipf_proxy_debug > 7)
+ if (softp->ips_proxy_debug & 0x10)
printf("proxy out switch set seq %d -> %d %x > %x\n",
sel, !sel, seq1,
aps->aps_seqmin[!sel]);
@@ -729,7 +1208,7 @@ int inc;
if (inc && (seq1 > aps->aps_seqmin[!sel])) {
aps->aps_seqmin[sel] = seq1 + nlen - 1;
aps->aps_seqoff[sel] = aps->aps_seqoff[sel] + inc;
- if (ipf_proxy_debug > 7)
+ if (softp->ips_proxy_debug & 0x10)
printf("proxy seq set %d at %x to %d + %d\n",
sel, aps->aps_seqmin[sel],
aps->aps_seqoff[sel], inc);
@@ -743,7 +1222,7 @@ int inc;
/* switch to other set ? */
if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) &&
(seq1 > aps->aps_ackmin[!sel])) {
- if (ipf_proxy_debug > 7)
+ if (softp->ips_proxy_debug & 0x10)
printf("proxy out switch set ack %d -> %d %x > %x\n",
sel, !sel, seq1,
aps->aps_ackmin[!sel]);
@@ -762,7 +1241,7 @@ int inc;
/* switch to other set ? */
if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) &&
(seq1 > aps->aps_ackmin[!sel])) {
- if (ipf_proxy_debug > 7)
+ if (softp->ips_proxy_debug & 0x10)
printf("proxy in switch set ack %d -> %d %x > %x\n",
sel, !sel, seq1, aps->aps_ackmin[!sel]);
sel = aps->aps_sel[out] = !sel;
@@ -782,7 +1261,7 @@ int inc;
aps->aps_ackmin[!sel] = seq1 + nlen - 1;
aps->aps_ackoff[!sel] = aps->aps_ackoff[sel] + inc;
- if (ipf_proxy_debug > 7)
+ if (softp->ips_proxy_debug & 0x10)
printf("proxy ack set %d at %x to %d + %d\n",
!sel, aps->aps_seqmin[!sel],
aps->aps_seqoff[sel], inc);
@@ -796,14 +1275,14 @@ int inc;
/* switch to other set ? */
if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) &&
(seq1 > aps->aps_seqmin[!sel])) {
- if (ipf_proxy_debug > 7)
+ if (softp->ips_proxy_debug & 0x10)
printf("proxy in switch set seq %d -> %d %x > %x\n",
sel, !sel, seq1, aps->aps_seqmin[!sel]);
sel = aps->aps_sel[1 - out] = !sel;
}
if (aps->aps_seqoff[sel] != 0) {
- if (ipf_proxy_debug > 7)
+ if (softp->ips_proxy_debug & 0x10)
printf("sel %d seqoff %d seq1 %x seqmin %x\n",
sel, aps->aps_seqoff[sel], seq1,
aps->aps_seqmin[sel]);
@@ -815,45 +1294,175 @@ int inc;
}
}
- if (ipf_proxy_debug > 8)
- printf("appr_fixseqack: seq %x ack %x\n",
+ if (softp->ips_proxy_debug & 0x10)
+ printf("ipf_proxy_fixseqack: seq %u ack %u\n",
(u_32_t)ntohl(tcp->th_seq), (u_32_t)ntohl(tcp->th_ack));
return ch ? 2 : 0;
}
-/*
- * Initialise hook for kernel application proxies.
- * Call the initialise routine for all the compiled in kernel proxies.
- */
-int appr_init()
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_rule_rev */
+/* Returns: ipnat_t * - NULL = failure, else pointer to new rule */
+/* Parameters: nat(I) - pointer to NAT session to create rule from */
+/* */
+/* This function creates a NAT rule that is based upon the reverse packet */
+/* flow associated with this NAT session. Thus if this NAT session was */
+/* created with a map rule then this function will create a rdr rule. */
+/* Only address fields and network interfaces are assigned in this function */
+/* and the address fields are formed such that an exact is required. If the */
+/* original rule had a netmask, that is not replicated here not is it */
+/* desired. The ultimate goal here is to create a NAT rule to support a NAT */
+/* session being created that does not have a user configured rule. The */
+/* classic example is supporting the FTP proxy, where a data channel needs */
+/* to be setup, based on the addresses used for the control connection. In */
+/* that case, this function is used to handle creating NAT rules to support */
+/* data connections with the PORT and EPRT commands. */
+/* ------------------------------------------------------------------------ */
+ipnat_t *
+ipf_proxy_rule_rev(nat)
+ nat_t *nat;
{
- aproxy_t *ap;
- int err = 0;
-
- for (ap = ap_proxies; ap->apr_p; ap++) {
- if (ap->apr_init != NULL) {
- err = (*ap->apr_init)();
- if (err != 0)
- break;
+ ipnat_t *old;
+ ipnat_t *ipn;
+ int size;
+
+ old = nat->nat_ptr;
+ size = old->in_size;
+
+ KMALLOCS(ipn, ipnat_t *, size);
+ if (ipn == NULL)
+ return NULL;
+
+ bzero((char *)ipn, size);
+
+ ipn->in_use = 1;
+ ipn->in_hits = 1;
+ ipn->in_ippip = 1;
+ ipn->in_apr = NULL;
+ ipn->in_size = size;
+ ipn->in_pr[0] = old->in_pr[1];
+ ipn->in_pr[1] = old->in_pr[0];
+ ipn->in_v[0] = old->in_v[1];
+ ipn->in_v[1] = old->in_v[0];
+ ipn->in_ifps[0] = old->in_ifps[1];
+ ipn->in_ifps[1] = old->in_ifps[0];
+ ipn->in_flags = (old->in_flags | IPN_PROXYRULE);
+
+ ipn->in_nsrcip6 = nat->nat_odst6;
+ ipn->in_osrcip6 = nat->nat_ndst6;
+
+ if ((old->in_redir & NAT_REDIRECT) != 0) {
+ ipn->in_redir = NAT_MAP;
+ if (ipn->in_v[0] == 4) {
+ ipn->in_snip = ntohl(nat->nat_odstaddr);
+ ipn->in_dnip = ntohl(nat->nat_nsrcaddr);
+ } else {
+#ifdef USE_INET6
+ ipn->in_snip6 = nat->nat_odst6;
+ ipn->in_dnip6 = nat->nat_nsrc6;
+#endif
}
+ ipn->in_ndstip6 = nat->nat_nsrc6;
+ ipn->in_odstip6 = nat->nat_osrc6;
+ } else {
+ ipn->in_redir = NAT_REDIRECT;
+ if (ipn->in_v[0] == 4) {
+ ipn->in_snip = ntohl(nat->nat_odstaddr);
+ ipn->in_dnip = ntohl(nat->nat_osrcaddr);
+ } else {
+#ifdef USE_INET6
+ ipn->in_snip6 = nat->nat_odst6;
+ ipn->in_dnip6 = nat->nat_osrc6;
+#endif
+ }
+ ipn->in_ndstip6 = nat->nat_osrc6;
+ ipn->in_odstip6 = nat->nat_nsrc6;
}
- return err;
+
+ IP6_SETONES(&ipn->in_osrcmsk6);
+ IP6_SETONES(&ipn->in_nsrcmsk6);
+ IP6_SETONES(&ipn->in_odstmsk6);
+ IP6_SETONES(&ipn->in_ndstmsk6);
+
+ ipn->in_namelen = old->in_namelen;
+ ipn->in_ifnames[0] = old->in_ifnames[1];
+ ipn->in_ifnames[1] = old->in_ifnames[0];
+ bcopy(old->in_names, ipn->in_names, ipn->in_namelen);
+ MUTEX_INIT(&ipn->in_lock, "ipnat rev rule lock");
+
+ return ipn;
}
-/*
- * Unload hook for kernel application proxies.
- * Call the finialise routine for all the compiled in kernel proxies.
- */
-void appr_unload()
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_proxy_rule_fwd */
+/* Returns: ipnat_t * - NULL = failure, else pointer to new rule */
+/* Parameters: nat(I) - pointer to NAT session to create rule from */
+/* */
+/* The purpose and rationale of this function is much the same as the above */
+/* function, ipf_proxy_rule_rev, except that a rule is created that matches */
+/* the same direction as that of the existing NAT session. Thus if this NAT */
+/* session was created with a map rule then this function will also create */
+/* a data structure to represent a map rule. Whereas ipf_proxy_rule_rev is */
+/* used to support PORT/EPRT, this function supports PASV/EPSV. */
+/* ------------------------------------------------------------------------ */
+ipnat_t *
+ipf_proxy_rule_fwd(nat)
+ nat_t *nat;
{
- aproxy_t *ap;
+ ipnat_t *old;
+ ipnat_t *ipn;
+ int size;
+
+ old = nat->nat_ptr;
+ size = old->in_size;
+
+ KMALLOCS(ipn, ipnat_t *, size);
+ if (ipn == NULL)
+ return NULL;
+
+ bzero((char *)ipn, size);
+
+ ipn->in_use = 1;
+ ipn->in_hits = 1;
+ ipn->in_ippip = 1;
+ ipn->in_apr = NULL;
+ ipn->in_size = size;
+ ipn->in_pr[0] = old->in_pr[0];
+ ipn->in_pr[1] = old->in_pr[1];
+ ipn->in_v[0] = old->in_v[0];
+ ipn->in_v[1] = old->in_v[1];
+ ipn->in_ifps[0] = nat->nat_ifps[0];
+ ipn->in_ifps[1] = nat->nat_ifps[1];
+ ipn->in_flags = (old->in_flags | IPN_PROXYRULE);
+
+ ipn->in_nsrcip6 = nat->nat_nsrc6;
+ ipn->in_osrcip6 = nat->nat_osrc6;
+ ipn->in_ndstip6 = nat->nat_ndst6;
+ ipn->in_odstip6 = nat->nat_odst6;
+ ipn->in_redir = old->in_redir;
+
+ if (ipn->in_v[0] == 4) {
+ ipn->in_snip = ntohl(nat->nat_nsrcaddr);
+ ipn->in_dnip = ntohl(nat->nat_ndstaddr);
+ } else {
+#ifdef USE_INET6
+ ipn->in_snip6 = nat->nat_nsrc6;
+ ipn->in_dnip6 = nat->nat_ndst6;
+#endif
+ }
- for (ap = ap_proxies; ap->apr_p; ap++)
- if (ap->apr_fini != NULL)
- (*ap->apr_fini)();
- for (ap = ap_proxylist; ap; ap = ap->apr_next)
- if (ap->apr_fini != NULL)
- (*ap->apr_fini)();
+ IP6_SETONES(&ipn->in_osrcmsk6);
+ IP6_SETONES(&ipn->in_nsrcmsk6);
+ IP6_SETONES(&ipn->in_odstmsk6);
+ IP6_SETONES(&ipn->in_ndstmsk6);
+
+ ipn->in_namelen = old->in_namelen;
+ ipn->in_ifnames[0] = old->in_ifnames[0];
+ ipn->in_ifnames[1] = old->in_ifnames[1];
+ bcopy(old->in_names, ipn->in_names, ipn->in_namelen);
+ MUTEX_INIT(&ipn->in_lock, "ipnat fwd rule lock");
+
+ return ipn;
}
diff --git a/sys/contrib/ipfilter/netinet/ip_proxy.h b/sys/contrib/ipfilter/netinet/ip_proxy.h
index 1bcfc60..1a1fdfa 100644
--- a/sys/contrib/ipfilter/netinet/ip_proxy.h
+++ b/sys/contrib/ipfilter/netinet/ip_proxy.h
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1997-2001 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
@@ -53,14 +53,11 @@ typedef struct ap_session {
struct ap_tcp apu_tcp;
struct ap_udp apu_udp;
} aps_un;
- u_int aps_flags;
U_QUAD_T aps_bytes; /* bytes sent */
U_QUAD_T aps_pkts; /* packets sent */
void *aps_nat; /* pointer back to nat struct */
void *aps_data; /* private data */
- int aps_p; /* protocol */
int aps_psiz; /* size of private data */
- struct ap_session *aps_hnext;
struct ap_session *aps_next;
} ap_session_t;
@@ -76,6 +73,7 @@ typedef struct ap_session {
typedef struct ap_control {
char apc_label[APR_LABELLEN];
+ char apc_config[APR_LABELLEN];
u_char apc_p;
/*
* The following fields are upto the proxy's apr_ctl routine to deal
@@ -93,21 +91,36 @@ typedef struct ap_control {
size_t apc_dsize;
} ap_ctl_t;
+#define APC_CMD_ADD 0
+#define APC_CMD_DEL 1
+
typedef struct aproxy {
struct aproxy *apr_next;
+ struct aproxy *apr_parent;
char apr_label[APR_LABELLEN]; /* Proxy label # */
- u_char apr_p; /* protocol */
- int apr_ref; /* +1 per rule referencing it */
+ u_char apr_p; /* protocol */
int apr_flags;
- int (* apr_init) __P((void));
- void (* apr_fini) __P((void));
- int (* apr_new) __P((fr_info_t *, ap_session_t *, struct nat *));
- void (* apr_del) __P((ap_session_t *));
- int (* apr_inpkt) __P((fr_info_t *, ap_session_t *, struct nat *));
- int (* apr_outpkt) __P((fr_info_t *, ap_session_t *, struct nat *));
+ int apr_ref;
+ int apr_clones;
+ void (* apr_load) __P((void));
+ void (* apr_unload) __P((void));
+ void *(* apr_create) __P((ipf_main_softc_t *));
+ void (* apr_destroy) __P((ipf_main_softc_t *, void *));
+ int (* apr_init) __P((ipf_main_softc_t *, void *));
+ void (* apr_fini) __P((ipf_main_softc_t *, void *));
+ int (* apr_new) __P((void *, fr_info_t *, ap_session_t *,
+ struct nat *));
+ void (* apr_del) __P((ipf_main_softc_t *, ap_session_t *));
+ int (* apr_inpkt) __P((void *, fr_info_t *, ap_session_t *,
+ struct nat *));
+ int (* apr_outpkt) __P((void *, fr_info_t *, ap_session_t *,
+ struct nat *));
int (* apr_match) __P((fr_info_t *, ap_session_t *, struct nat *));
- int (* apr_ctl) __P((struct aproxy *, struct ap_control *));
+ int (* apr_ctl) __P((ipf_main_softc_t *, void *, ap_ctl_t *));
+ int (* apr_clear) __P((struct aproxy *));
+ int (* apr_flush) __P((struct aproxy *, int));
+ void *apr_soft;
} aproxy_t;
#define APR_DELETE 1
@@ -116,42 +129,37 @@ typedef struct aproxy {
#define APR_EXIT(x) (((x) >> 16) & 0xffff)
#define APR_INC(x) ((x) & 0xffff)
+
+#ifdef _KERNEL
/*
* Generic #define's to cover missing things in the kernel
*/
-#ifndef isdigit
-#define isdigit(x) ((x) >= '0' && (x) <= '9')
-#endif
-#ifndef isupper
-#define isupper(x) (((unsigned)(x) >= 'A') && ((unsigned)(x) <= 'Z'))
-#endif
-#ifndef islower
-#define islower(x) (((unsigned)(x) >= 'a') && ((unsigned)(x) <= 'z'))
-#endif
-#ifndef isalpha
-#define isalpha(x) (isupper(x) || islower(x))
-#endif
-#ifndef toupper
-#define toupper(x) (isupper(x) ? (x) : (x) - 'a' + 'A')
-#endif
-#ifndef isspace
-#define isspace(x) (((x) == ' ') || ((x) == '\r') || ((x) == '\n') || \
+# ifndef isdigit
+# define isdigit(x) ((x) >= '0' && (x) <= '9')
+# endif
+# ifndef isupper
+# define isupper(x) (((unsigned)(x) >= 'A') && ((unsigned)(x) <= 'Z'))
+# endif
+# ifndef islower
+# define islower(x) (((unsigned)(x) >= 'a') && ((unsigned)(x) <= 'z'))
+# endif
+# ifndef isalpha
+# define isalpha(x) (isupper(x) || islower(x))
+# endif
+# ifndef toupper
+# define toupper(x) (isupper(x) ? (x) : (x) - 'a' + 'A')
+# endif
+# ifndef isspace
+# define isspace(x) (((x) == ' ') || ((x) == '\r') || ((x) == '\n') || \
((x) == '\t') || ((x) == '\b'))
-#endif
+# endif
+#endif /* _KERNEL */
/*
- * This is the scratch buffer size used to hold strings from the TCP stream
- * that we may want to parse. It's an arbitrary size, really, but it must
- * be at least as large as IPF_FTPBUFSZ.
- */
-#define FTP_BUFSZ 120
-
-/*
- * This buffer, however, doesn't need to be nearly so big. It just needs to
- * be able to squeeze in the largest command it needs to rewrite, Which ones
- * does it rewrite? EPRT, PORT, 227 replies.
+ * For the ftp proxy.
*/
-#define IPF_FTPBUFSZ 80 /* This *MUST* be >= 53! */
+#define FTP_BUFSZ 160
+#define IPF_FTPBUFSZ 160
typedef struct ftpside {
char *ftps_rptr;
@@ -159,19 +167,37 @@ typedef struct ftpside {
void *ftps_ifp;
u_32_t ftps_seq[2];
u_32_t ftps_len;
- int ftps_junk; /* 2 = no cr/lf yet, 1 = cannot parse */
+ int ftps_junk;
int ftps_cmds;
+ int ftps_cmd;
char ftps_buf[FTP_BUFSZ];
} ftpside_t;
typedef struct ftpinfo {
int ftp_passok;
int ftp_incok;
+ void *ftp_pendstate;
+ nat_t *ftp_pendnat;
ftpside_t ftp_side[2];
} ftpinfo_t;
/*
+ * IPsec proxy
+ */
+typedef u_32_t ipsec_cookie_t[2];
+
+typedef struct ipsec_pxy {
+ ipsec_cookie_t ipsc_icookie;
+ ipsec_cookie_t ipsc_rcookie;
+ int ipsc_rckset;
+ nat_t *ipsc_nat;
+ struct ipstate *ipsc_state;
+ ipnat_t *ipsc_rule;
+} ipsec_pxy_t;
+
+
+/*
* For the irc proxy.
*/
typedef struct ircinfo {
@@ -187,6 +213,16 @@ typedef struct ircinfo {
/*
+ * For the DNS "proxy"
+ */
+typedef struct dnsinfo {
+ ipfmutex_t dnsi_lock;
+ u_short dnsi_id;
+ char dnsi_buffer[512];
+} dnsinfo_t;
+
+
+/*
* Real audio proxy structure and #defines
*/
typedef struct raudio_s {
@@ -231,43 +267,6 @@ typedef struct msnrpcinfo {
/*
- * IPSec proxy
- */
-typedef u_32_t ipsec_cookie_t[2];
-
-typedef struct ipsec_pxy {
- ipsec_cookie_t ipsc_icookie;
- ipsec_cookie_t ipsc_rcookie;
- int ipsc_rckset;
- ipnat_t ipsc_rule;
- nat_t *ipsc_nat;
- struct ipstate *ipsc_state;
-} ipsec_pxy_t;
-
-/*
- * PPTP proxy
- */
-typedef struct pptp_side {
- u_32_t pptps_nexthdr;
- u_32_t pptps_next;
- int pptps_state;
- int pptps_gothdr;
- int pptps_len;
- int pptps_bytes;
- char *pptps_wptr;
- char pptps_buffer[512];
-} pptp_side_t;
-
-typedef struct pptp_pxy {
- ipnat_t pptp_rule;
- nat_t *pptp_nat;
- struct ipstate *pptp_state;
- u_short pptp_call[2];
- pptp_side_t pptp_side[2];
-} pptp_pxy_t;
-
-
-/*
* Sun RPCBIND proxy
*/
#define RPCB_MAXMSG 888
@@ -439,24 +438,26 @@ typedef struct rpcb_session {
*/
#define XDRALIGN(x) ((((x) % 4) != 0) ? ((((x) + 3) / 4) * 4) : (x))
-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 ipf_proxy_debug;
-
-extern int appr_add __P((aproxy_t *));
-extern int appr_ctl __P((ap_ctl_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((fr_info_t *, tcphdr_t *, struct ipnat *));
-extern int appr_match __P((fr_info_t *, struct nat *));
-extern void appr_free __P((aproxy_t *));
-extern void aps_free __P((ap_session_t *));
-extern int appr_check __P((fr_info_t *, struct nat *));
-extern aproxy_t *appr_lookup __P((u_int, char *));
-extern int appr_new __P((fr_info_t *, struct nat *));
-extern int appr_ioctl __P((caddr_t, ioctlcmd_t, int, void *));
+extern int ipf_proxy_add __P((void *, aproxy_t *));
+extern int ipf_proxy_check __P((fr_info_t *, struct nat *));
+extern int ipf_proxy_ctl __P((ipf_main_softc_t *, void *, ap_ctl_t *));
+extern int ipf_proxy_del __P((aproxy_t *));
+extern void ipf_proxy_deref __P((aproxy_t *));
+extern void ipf_proxy_flush __P((void *, int));
+extern int ipf_proxy_init __P((void));
+extern int ipf_proxy_ioctl __P((ipf_main_softc_t *, caddr_t, ioctlcmd_t, int, void *));
+extern aproxy_t *ipf_proxy_lookup __P((void *, u_int, char *));
+extern int ipf_proxy_match __P((fr_info_t *, struct nat *));
+extern int ipf_proxy_new __P((fr_info_t *, struct nat *));
+extern int ipf_proxy_ok __P((fr_info_t *, tcphdr_t *, struct ipnat *));
+extern void ipf_proxy_free __P((ipf_main_softc_t *, ap_session_t *));
+extern int ipf_proxy_main_load __P((void));
+extern int ipf_proxy_main_unload __P((void));
+extern ipnat_t *ipf_proxy_rule_fwd __P((nat_t *));
+extern ipnat_t *ipf_proxy_rule_rev __P((nat_t *));
+extern void *ipf_proxy_soft_create __P((ipf_main_softc_t *));
+extern void ipf_proxy_soft_destroy __P((ipf_main_softc_t *, void *));
+extern int ipf_proxy_soft_init __P((ipf_main_softc_t *, void *));
+extern int ipf_proxy_soft_fini __P((ipf_main_softc_t *, void *));
#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 2729dc6..0313637 100644
--- a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c
+++ b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c
@@ -1,8 +1,7 @@
/* $FreeBSD$ */
/*
- * $FreeBSD$
- * Copyright (C) 1998-2003 by Darren Reed
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
@@ -12,11 +11,11 @@
#define IPF_RAUDIO_PROXY
-int ippr_raudio_init __P((void));
-void ippr_raudio_fini __P((void));
-int ippr_raudio_new __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_raudio_in __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_raudio_out __P((fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_raudio_main_load __P((void));
+void ipf_p_raudio_main_unload __P((void));
+int ipf_p_raudio_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_raudio_in __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_raudio_out __P((void *, fr_info_t *, ap_session_t *, nat_t *));
static frentry_t raudiofr;
@@ -26,19 +25,19 @@ int raudio_proxy_init = 0;
/*
* Real Audio application proxy initialization.
*/
-int ippr_raudio_init()
+void
+ipf_p_raudio_main_load()
{
bzero((char *)&raudiofr, sizeof(raudiofr));
raudiofr.fr_ref = 1;
raudiofr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
MUTEX_INIT(&raudiofr.fr_lock, "Real Audio proxy rule lock");
raudio_proxy_init = 1;
-
- return 0;
}
-void ippr_raudio_fini()
+void
+ipf_p_raudio_main_unload()
{
if (raudio_proxy_init == 1) {
MUTEX_DESTROY(&raudiofr.fr_lock);
@@ -50,20 +49,24 @@ void ippr_raudio_fini()
/*
* Setup for a new proxy to handle Real Audio.
*/
-int ippr_raudio_new(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_raudio_new(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
{
raudio_t *rap;
+ nat = nat; /* LINT */
+
+ if (fin->fin_v != 4)
+ return -1;
+
KMALLOCS(aps->aps_data, void *, sizeof(raudio_t));
if (aps->aps_data == NULL)
return -1;
- fin = fin; /* LINT */
- nat = nat; /* LINT */
-
bzero(aps->aps_data, sizeof(raudio_t));
rap = aps->aps_data;
aps->aps_psiz = sizeof(raudio_t);
@@ -73,10 +76,12 @@ nat_t *nat;
-int ippr_raudio_out(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_raudio_out(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
{
raudio_t *rap = aps->aps_data;
unsigned char membuf[512 + 1], *s;
@@ -179,14 +184,18 @@ nat_t *nat;
}
-int ippr_raudio_in(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_raudio_in(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
{
unsigned char membuf[IPF_MAXPORTLEN + 1], *s;
tcphdr_t *tcp, tcph, *tcp2 = &tcph;
raudio_t *rap = aps->aps_data;
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
struct in_addr swa, swb;
int off, dlen, slen;
int a1, a2, a3, a4;
@@ -198,6 +207,8 @@ nat_t *nat;
ip_t *ip;
mb_t *m;
+ softc = fin->fin_main_soft;
+ softn = softc->ipf_nat_soft;
/*
* 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
@@ -272,14 +283,12 @@ nat_t *nat;
swb = ip->ip_dst;
ip->ip_p = IPPROTO_UDP;
- ip->ip_src = nat->nat_inip;
- ip->ip_dst = nat->nat_oip;
+ ip->ip_src = nat->nat_ndstip;
+ ip->ip_dst = nat->nat_odstip;
bcopy((char *)fin, (char *)&fi, sizeof(fi));
bzero((char *)tcp2, sizeof(*tcp2));
TCP_OFF_A(tcp2, 5);
- fi.fin_state = NULL;
- fi.fin_nat = NULL;
fi.fin_flx |= FI_IGNORE;
fi.fin_dp = (char *)tcp2;
fi.fin_fr = &raudiofr;
@@ -287,7 +296,7 @@ nat_t *nat;
fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
tcp2->th_win = htons(8192);
slen = ip->ip_len;
- ip->ip_len = fin->fin_hlen + sizeof(*tcp);
+ ip->ip_len = htons(fin->fin_hlen + sizeof(*tcp));
if (((rap->rap_mode & RAP_M_UDP_ROBUST) == RAP_M_UDP_ROBUST) &&
(rap->rap_srport != 0)) {
@@ -298,16 +307,19 @@ nat_t *nat;
fi.fin_data[0] = dp;
fi.fin_data[1] = sp;
fi.fin_out = 0;
- nat2 = nat_new(&fi, nat->nat_ptr, NULL,
+ MUTEX_ENTER(&softn->ipf_nat_new);
+ nat2 = ipf_nat_add(&fi, nat->nat_ptr, NULL,
NAT_SLAVE|IPN_UDP | (sp ? 0 : SI_W_SPORT),
NAT_OUTBOUND);
+ MUTEX_EXIT(&softn->ipf_nat_new);
if (nat2 != NULL) {
- (void) nat_proto(&fi, nat2, IPN_UDP);
- nat_update(&fi, nat2, nat2->nat_ptr);
+ (void) ipf_nat_proto(&fi, nat2, IPN_UDP);
+ MUTEX_ENTER(&nat2->nat_lock);
+ ipf_nat_update(&fi, nat2);
+ MUTEX_EXIT(&nat2->nat_lock);
- (void) fr_addstate(&fi, NULL, (sp ? 0 : SI_W_SPORT));
- if (fi.fin_state != NULL)
- fr_statederef((ipstate_t **)&fi.fin_state);
+ (void) ipf_state_add(softc, &fi, NULL,
+ (sp ? 0 : SI_W_SPORT));
}
}
@@ -318,16 +330,18 @@ nat_t *nat;
fi.fin_data[0] = sp;
fi.fin_data[1] = 0;
fi.fin_out = 1;
- nat2 = nat_new(&fi, nat->nat_ptr, NULL,
+ MUTEX_ENTER(&softn->ipf_nat_new);
+ nat2 = ipf_nat_add(&fi, nat->nat_ptr, NULL,
NAT_SLAVE|IPN_UDP|SI_W_DPORT,
NAT_OUTBOUND);
+ MUTEX_EXIT(&softn->ipf_nat_new);
if (nat2 != NULL) {
- (void) nat_proto(&fi, nat2, IPN_UDP);
- nat_update(&fi, nat2, nat2->nat_ptr);
+ (void) ipf_nat_proto(&fi, nat2, IPN_UDP);
+ MUTEX_ENTER(&nat2->nat_lock);
+ ipf_nat_update(&fi, nat2);
+ MUTEX_EXIT(&nat2->nat_lock);
- (void) fr_addstate(&fi, NULL, SI_W_DPORT);
- if (fi.fin_state != NULL)
- fr_statederef((ipstate_t **)&fi.fin_state);
+ (void) ipf_state_add(softc, &fi, NULL, SI_W_DPORT);
}
}
diff --git a/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c b/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c
index dc92bf5..4b453c0 100644
--- a/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c
+++ b/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c
@@ -1,11 +1,11 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1998-2003 by Darren Reed
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
- * $Id: ip_rcmd_pxy.c,v 1.41.2.7 2006/07/14 06:12:18 darrenr Exp $
+ * $Id$
*
* Simple RCMD transparent proxy for in-kernel use. For use with the NAT
* code.
@@ -14,36 +14,45 @@
#define IPF_RCMD_PROXY
-
-int ippr_rcmd_init __P((void));
-void ippr_rcmd_fini __P((void));
-int ippr_rcmd_new __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_rcmd_out __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_rcmd_in __P((fr_info_t *, ap_session_t *, nat_t *));
+typedef struct rcmdinfo {
+ u_32_t rcmd_port; /* Port number seen */
+ u_32_t rcmd_portseq; /* Sequence number where port is first seen */
+ ipnat_t *rcmd_rule; /* Template rule for back connection */
+} rcmdinfo_t;
+
+void ipf_p_rcmd_main_load __P((void));
+void ipf_p_rcmd_main_unload __P((void));
+
+int ipf_p_rcmd_init __P((void));
+void ipf_p_rcmd_fini __P((void));
+void ipf_p_rcmd_del __P((ipf_main_softc_t *, ap_session_t *));
+int ipf_p_rcmd_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_rcmd_out __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_rcmd_in __P((void *, fr_info_t *, ap_session_t *, nat_t *));
u_short ipf_rcmd_atoi __P((char *));
-int ippr_rcmd_portmsg __P((fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_rcmd_portmsg __P((fr_info_t *, ap_session_t *, nat_t *));
static frentry_t rcmdfr;
-int rcmd_proxy_init = 0;
+static int rcmd_proxy_init = 0;
/*
* RCMD application proxy initialization.
*/
-int ippr_rcmd_init()
+void
+ipf_p_rcmd_main_load()
{
bzero((char *)&rcmdfr, sizeof(rcmdfr));
rcmdfr.fr_ref = 1;
rcmdfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
MUTEX_INIT(&rcmdfr.fr_lock, "RCMD proxy rule lock");
rcmd_proxy_init = 1;
-
- return 0;
}
-void ippr_rcmd_fini()
+void
+ipf_p_rcmd_main_unload()
{
if (rcmd_proxy_init == 1) {
MUTEX_DESTROY(&rcmdfr.fr_lock);
@@ -55,36 +64,70 @@ void ippr_rcmd_fini()
/*
* Setup for a new RCMD proxy.
*/
-int ippr_rcmd_new(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_rcmd_new(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
{
tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
+ rcmdinfo_t *rc;
+ ipnat_t *ipn;
+ ipnat_t *np;
+ int size;
fin = fin; /* LINT */
- nat = nat; /* LINT */
- aps->aps_psiz = sizeof(u_32_t);
- KMALLOCS(aps->aps_data, u_32_t *, sizeof(u_32_t));
- if (aps->aps_data == NULL) {
+ np = nat->nat_ptr;
+ size = np->in_size;
+ KMALLOC(rc, rcmdinfo_t *);
+ if (rc == NULL) {
#ifdef IP_RCMD_PROXY_DEBUG
- printf("ippr_rcmd_new:KMALLOCS(%d) failed\n", sizeof(u_32_t));
+ printf("ipf_p_rcmd_new:KMALLOCS(%d) failed\n", sizeof(*rc));
#endif
return -1;
}
- *(u_32_t *)aps->aps_data = 0;
aps->aps_sport = tcp->th_sport;
aps->aps_dport = tcp->th_dport;
+
+ ipn = ipf_proxy_rule_rev(nat);
+ if (ipn == NULL) {
+ KFREE(rc);
+ return -1;
+ }
+
+ aps->aps_data = rc;
+ aps->aps_psiz = sizeof(*rc);
+ bzero((char *)rc, sizeof(*rc));
+
+ rc->rcmd_rule = ipn;
+
return 0;
}
+void
+ipf_p_rcmd_del(softc, aps)
+ ipf_main_softc_t *softc;
+ ap_session_t *aps;
+{
+ rcmdinfo_t *rci;
+
+ rci = aps->aps_data;
+ if (rci != NULL) {
+ rci->rcmd_rule->in_flags |= IPN_DELETE;
+ ipf_nat_rule_deref(softc, &rci->rcmd_rule);
+ }
+}
+
+
/*
* ipf_rcmd_atoi - implement a simple version of atoi
*/
-u_short ipf_rcmd_atoi(ptr)
-char *ptr;
+u_short
+ipf_rcmd_atoi(ptr)
+ char *ptr;
{
register char *s = ptr, c;
register u_short i = 0;
@@ -97,44 +140,50 @@ char *ptr;
}
-int ippr_rcmd_portmsg(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_rcmd_portmsg(fin, aps, nat)
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
{
tcphdr_t *tcp, tcph, *tcp2 = &tcph;
- struct in_addr swip, swip2;
- int off, dlen, nflags;
+ int off, dlen, nflags, direction;
+ ipf_main_softc_t *softc;
+ ipf_nat_softc_t *softn;
char portbuf[8], *s;
+ rcmdinfo_t *rc;
fr_info_t fi;
u_short sp;
nat_t *nat2;
+#ifdef USE_INET6
+ ip6_t *ip6;
+#endif
+ int tcpsz;
+ int slen;
ip_t *ip;
mb_t *m;
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;
-
m = fin->fin_m;
ip = fin->fin_ip;
- off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
-
-#ifdef __sgi
- dlen = fin->fin_plen - off;
-#else
- dlen = MSGDSIZE(m) - off;
+ tcpsz = TCP_OFF(tcp) << 2;
+#ifdef USE_INET6
+ ip6 = (ip6_t *)fin->fin_ip;
#endif
+ softc = fin->fin_main_soft;
+ softn = softc->ipf_nat_soft;
+ off = (char *)tcp - (char *)ip + tcpsz + fin->fin_ipoff;
+
+ dlen = fin->fin_dlen - tcpsz;
if (dlen <= 0)
return 0;
+ rc = (rcmdinfo_t *)aps->aps_data;
+ if ((rc->rcmd_portseq != 0) &&
+ (tcp->th_seq != rc->rcmd_portseq))
+ return 0;
+
bzero(portbuf, sizeof(portbuf));
COPYDATA(m, off, MIN(sizeof(portbuf), dlen), portbuf);
@@ -143,97 +192,161 @@ nat_t *nat;
sp = ipf_rcmd_atoi(s);
if (sp == 0) {
#ifdef IP_RCMD_PROXY_DEBUG
- printf("ippr_rcmd_portmsg:sp == 0 dlen %d [%s]\n",
+ printf("ipf_p_rcmd_portmsg:sp == 0 dlen %d [%s]\n",
dlen, portbuf);
#endif
return 0;
}
+ if (rc->rcmd_port != 0 && sp != rc->rcmd_port) {
+#ifdef IP_RCMD_PROXY_DEBUG
+ printf("ipf_p_rcmd_portmsg:sp(%d) != rcmd_port(%d)\n",
+ sp, rc->rcmd_port);
+#endif
+ return 0;
+ }
+
+ rc->rcmd_port = sp;
+ rc->rcmd_portseq = tcp->th_seq;
+
/*
- * Add skeleton NAT entry for connection which will come back the
- * other way.
+ * Initialise the packet info structure so we can search the NAT
+ * table to see if there already is soemthing present that matches
+ * up with what we want to add.
*/
bcopy((char *)fin, (char *)&fi, sizeof(fi));
- fi.fin_state = NULL;
- fi.fin_nat = NULL;
fi.fin_flx |= FI_IGNORE;
- fi.fin_data[0] = sp;
- fi.fin_data[1] = 0;
- if (nat->nat_dir == NAT_OUTBOUND)
- nat2 = nat_outlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p,
- nat->nat_inip, nat->nat_oip);
- else
- nat2 = nat_inlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p,
- nat->nat_inip, nat->nat_oip);
- if (nat2 == NULL) {
- int slen;
-
- slen = ip->ip_len;
- ip->ip_len = fin->fin_hlen + sizeof(*tcp);
- bzero((char *)tcp2, sizeof(*tcp2));
- tcp2->th_win = htons(8192);
- tcp2->th_sport = htons(sp);
- tcp2->th_dport = 0; /* XXX - don't specify remote port */
- TCP_OFF_A(tcp2, 5);
- tcp2->th_flags = TH_SYN;
- fi.fin_dp = (char *)tcp2;
- fi.fin_fr = &rcmdfr;
- fi.fin_dlen = sizeof(*tcp2);
- fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
- fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
- nflags = NAT_SLAVE|IPN_TCP|SI_W_DPORT;
-
- swip = ip->ip_src;
- swip2 = ip->ip_dst;
+ fi.fin_data[0] = 0;
+ fi.fin_data[1] = sp;
+ fi.fin_src6 = nat->nat_ndst6;
+ fi.fin_dst6 = nat->nat_nsrc6;
+ if (nat->nat_v[0] == 6) {
+#ifdef USE_INET6
if (nat->nat_dir == NAT_OUTBOUND) {
- fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
- ip->ip_src = nat->nat_inip;
+ nat2 = ipf_nat6_outlookup(&fi, NAT_SEARCH|IPN_TCP,
+ nat->nat_pr[1],
+ &nat->nat_osrc6.in6,
+ &nat->nat_odst6.in6);
} else {
- fi.fin_fi.fi_saddr = nat->nat_oip.s_addr;
- ip->ip_src = nat->nat_oip;
- nflags |= NAT_NOTRULEPORT;
+ nat2 = ipf_nat6_inlookup(&fi, NAT_SEARCH|IPN_TCP,
+ nat->nat_pr[0],
+ &nat->nat_osrc6.in6,
+ &nat->nat_odst6.in6);
}
-
- nat2 = nat_new(&fi, nat->nat_ptr, NULL, nflags, nat->nat_dir);
-
- if (nat2 != NULL) {
- (void) nat_proto(&fi, nat2, IPN_TCP);
- nat_update(&fi, nat2, nat2->nat_ptr);
- fi.fin_ifp = NULL;
- if (nat->nat_dir == NAT_INBOUND) {
- fi.fin_fi.fi_daddr = nat->nat_inip.s_addr;
- ip->ip_dst = nat->nat_inip;
- }
- (void) fr_addstate(&fi, NULL, SI_W_DPORT);
- if (fi.fin_state != NULL)
- fr_statederef((ipstate_t **)&fi.fin_state);
+#else
+ nat2 = (void *)-1;
+#endif
+ } else {
+ if (nat->nat_dir == NAT_OUTBOUND) {
+ nat2 = ipf_nat_outlookup(&fi, NAT_SEARCH|IPN_TCP,
+ nat->nat_pr[1],
+ nat->nat_osrcip,
+ nat->nat_odstip);
+ } else {
+ nat2 = ipf_nat_inlookup(&fi, NAT_SEARCH|IPN_TCP,
+ nat->nat_pr[0],
+ nat->nat_osrcip,
+ nat->nat_odstip);
}
+ }
+ if (nat2 != NULL)
+ return APR_ERR(1);
+
+ /*
+ * Add skeleton NAT entry for connection which will come
+ * back the other way.
+ */
+
+ if (nat->nat_v[0] == 6) {
+#ifdef USE_INET6
+ slen = ip6->ip6_plen;
+ ip6->ip6_plen = htons(sizeof(*tcp));
+#endif
+ } else {
+ slen = ip->ip_len;
+ ip->ip_len = htons(fin->fin_hlen + sizeof(*tcp));
+ }
+
+ /*
+ * Fill out the fake TCP header with a few fields that ipfilter
+ * considers to be important.
+ */
+ bzero((char *)tcp2, sizeof(*tcp2));
+ tcp2->th_win = htons(8192);
+ TCP_OFF_A(tcp2, 5);
+ tcp2->th_flags = TH_SYN;
+
+ fi.fin_dp = (char *)tcp2;
+ fi.fin_fr = &rcmdfr;
+ fi.fin_dlen = sizeof(*tcp2);
+ fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
+ fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
+
+ if (nat->nat_dir == NAT_OUTBOUND) {
+ fi.fin_out = 0;
+ direction = NAT_INBOUND;
+ } else {
+ fi.fin_out = 1;
+ direction = NAT_OUTBOUND;
+ }
+ nflags = SI_W_SPORT|NAT_SLAVE|IPN_TCP;
+
+ MUTEX_ENTER(&softn->ipf_nat_new);
+ if (fin->fin_v == 4)
+ nat2 = ipf_nat_add(&fi, rc->rcmd_rule, NULL, nflags,
+ direction);
+#ifdef USE_INET6
+ else
+ nat2 = ipf_nat6_add(&fi, rc->rcmd_rule, NULL, nflags,
+ direction);
+#endif
+ MUTEX_EXIT(&softn->ipf_nat_new);
+
+ if (nat2 != NULL) {
+ (void) ipf_nat_proto(&fi, nat2, IPN_TCP);
+ MUTEX_ENTER(&nat2->nat_lock);
+ ipf_nat_update(&fi, nat2);
+ MUTEX_EXIT(&nat2->nat_lock);
+ fi.fin_ifp = NULL;
+ if (nat2->nat_dir == NAT_INBOUND)
+ fi.fin_dst6 = nat->nat_osrc6;
+ (void) ipf_state_add(softc, &fi, NULL, SI_W_SPORT);
+ }
+ if (nat->nat_v[0] == 6) {
+#ifdef USE_INET6
+ ip6->ip6_plen = slen;
+#endif
+ } else {
ip->ip_len = slen;
- ip->ip_src = swip;
- ip->ip_dst = swip2;
}
+ if (nat2 == NULL)
+ return APR_ERR(1);
return 0;
}
-int ippr_rcmd_out(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_rcmd_out(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
{
if (nat->nat_dir == NAT_OUTBOUND)
- return ippr_rcmd_portmsg(fin, aps, nat);
+ return ipf_p_rcmd_portmsg(fin, aps, nat);
return 0;
}
-int ippr_rcmd_in(fin, aps, nat)
-fr_info_t *fin;
-ap_session_t *aps;
-nat_t *nat;
+int
+ipf_p_rcmd_in(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
{
if (nat->nat_dir == NAT_INBOUND)
- return ippr_rcmd_portmsg(fin, aps, nat);
+ return ipf_p_rcmd_portmsg(fin, aps, nat);
return 0;
}
diff --git a/sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c b/sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c
index da76fde..9493d2b 100644
--- a/sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c
+++ b/sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002-2003 by Ryan Beasley <ryanb@goddamnbastard.org>
+ * Copyright (C) 2002-2012 by Ryan Beasley <ryanb@goddamnbastard.org>
*
* See the IPFILTER.LICENCE file for details on licencing.
*/
@@ -37,44 +37,43 @@
* o The enclosed hack of STREAMS support is pretty sick and most likely
* broken.
*
- * $Id: ip_rpcb_pxy.c,v 2.25.2.7 2007/06/04 09:16:31 darrenr Exp $
+ * $Id$
*/
-
#define IPF_RPCB_PROXY
/*
* Function prototypes
*/
-int ippr_rpcb_init __P((void));
-void ippr_rpcb_fini __P((void));
-int ippr_rpcb_new __P((fr_info_t *, ap_session_t *, nat_t *));
-void ippr_rpcb_del __P((ap_session_t *));
-int ippr_rpcb_in __P((fr_info_t *, ap_session_t *, nat_t *));
-int ippr_rpcb_out __P((fr_info_t *, ap_session_t *, nat_t *));
-
-static void ippr_rpcb_flush __P((rpcb_session_t *));
-static int ippr_rpcb_decodereq __P((fr_info_t *, nat_t *,
+void ipf_p_rpcb_main_load __P((void));
+void ipf_p_rpcb_main_unload __P((void));
+int ipf_p_rpcb_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_rpcb_del __P((ipf_main_softc_t *, ap_session_t *));
+int ipf_p_rpcb_in __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_rpcb_out __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+
+static void ipf_p_rpcb_flush __P((rpcb_session_t *));
+static int ipf_p_rpcb_decodereq __P((fr_info_t *, nat_t *,
rpcb_session_t *, rpc_msg_t *));
-static int ippr_rpcb_skipauth __P((rpc_msg_t *, xdr_auth_t *, u_32_t **));
-static int ippr_rpcb_insert __P((rpcb_session_t *, rpcb_xact_t *));
-static int ippr_rpcb_xdrrpcb __P((rpc_msg_t *, u_32_t *, rpcb_args_t *));
-static int ippr_rpcb_getuaddr __P((rpc_msg_t *, xdr_uaddr_t *,
+static int ipf_p_rpcb_skipauth __P((rpc_msg_t *, xdr_auth_t *, u_32_t **));
+static int ipf_p_rpcb_insert __P((rpcb_session_t *, rpcb_xact_t *));
+static int ipf_p_rpcb_xdrrpcb __P((rpc_msg_t *, u_32_t *, rpcb_args_t *));
+static int ipf_p_rpcb_getuaddr __P((rpc_msg_t *, xdr_uaddr_t *,
u_32_t **));
-static u_int ippr_rpcb_atoi __P((char *));
-static int ippr_rpcb_modreq __P((fr_info_t *, nat_t *, rpc_msg_t *,
+static u_int ipf_p_rpcb_atoi __P((char *));
+static int ipf_p_rpcb_modreq __P((fr_info_t *, nat_t *, rpc_msg_t *,
mb_t *, u_int));
-static int ippr_rpcb_decoderep __P((fr_info_t *, nat_t *,
+static int ipf_p_rpcb_decoderep __P((fr_info_t *, nat_t *,
rpcb_session_t *, rpc_msg_t *, rpcb_xact_t **));
-static rpcb_xact_t * ippr_rpcb_lookup __P((rpcb_session_t *, u_32_t));
-static void ippr_rpcb_deref __P((rpcb_session_t *, rpcb_xact_t *));
-static int ippr_rpcb_getproto __P((rpc_msg_t *, xdr_proto_t *,
+static rpcb_xact_t * ipf_p_rpcb_lookup __P((rpcb_session_t *, u_32_t));
+static void ipf_p_rpcb_deref __P((rpcb_session_t *, rpcb_xact_t *));
+static int ipf_p_rpcb_getproto __P((rpc_msg_t *, xdr_proto_t *,
u_32_t **));
-static int ippr_rpcb_getnat __P((fr_info_t *, nat_t *, u_int, u_int));
-static int ippr_rpcb_modv3 __P((fr_info_t *, nat_t *, rpc_msg_t *,
+static int ipf_p_rpcb_getnat __P((fr_info_t *, nat_t *, u_int, u_int));
+static int ipf_p_rpcb_modv3 __P((fr_info_t *, nat_t *, rpc_msg_t *,
mb_t *, u_int));
-static int ippr_rpcb_modv4 __P((fr_info_t *, nat_t *, rpc_msg_t *,
+static int ipf_p_rpcb_modv4 __P((fr_info_t *, nat_t *, rpc_msg_t *,
mb_t *, u_int));
-static void ippr_rpcb_fixlen __P((fr_info_t *, int));
+static void ipf_p_rpcb_fixlen __P((fr_info_t *, int));
/*
* Global variables
@@ -84,7 +83,7 @@ static frentry_t rpcbfr; /* Skeleton rule for reference by entities
static int rpcbcnt; /* Upper bound of allocated RPCB sessions. */
/* XXX rpcbcnt still requires locking. */
-int rpcb_proxy_init = 0;
+static int rpcb_proxy_init = 0;
/*
@@ -98,15 +97,15 @@ int rpcb_proxy_init = 0;
* Public subroutines
*/
-/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_init */
-/* Returns: int - 0 == success */
-/* Parameters: (void) */
-/* */
-/* Initialize the filter rule entry and session limiter. */
-/* -------------------------------------------------------------------- */
-int
-ippr_rpcb_init()
+/* -------------------------------------------------------------------- */
+/* Function: ipf_p_rpcb_main_load */
+/* Returns: void */
+/* Parameters: (void) */
+/* */
+/* Initialize the filter rule entry and session limiter. */
+/* -------------------------------------------------------------------- */
+void
+ipf_p_rpcb_main_load()
{
rpcbcnt = 0;
@@ -115,19 +114,17 @@ ippr_rpcb_init()
rpcbfr.fr_flags = FR_PASS|FR_QUICK|FR_KEEPSTATE;
MUTEX_INIT(&rpcbfr.fr_lock, "ipf Sun RPCB proxy rule lock");
rpcb_proxy_init = 1;
-
- return(0);
}
-/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_fini */
-/* Returns: void */
-/* Parameters: (void) */
-/* */
-/* Destroy rpcbfr's mutex to avoid a lock leak. */
-/* -------------------------------------------------------------------- */
+/* -------------------------------------------------------------------- */
+/* Function: ipf_p_rpcb_main_unload */
+/* Returns: void */
+/* Parameters: (void) */
+/* */
+/* Destroy rpcbfr's mutex to avoid a lock leak. */
+/* -------------------------------------------------------------------- */
void
-ippr_rpcb_fini()
+ipf_p_rpcb_main_unload()
{
if (rpcb_proxy_init == 1) {
MUTEX_DESTROY(&rpcbfr.fr_lock);
@@ -136,7 +133,7 @@ ippr_rpcb_fini()
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_new */
+/* Function: ipf_p_rpcb_new */
/* Returns: int - -1 == failure, 0 == success */
/* Parameters: fin(I) - pointer to packet information */
/* aps(I) - pointer to proxy session structure */
@@ -145,16 +142,19 @@ ippr_rpcb_fini()
/* Allocate resources for per-session proxy structures. */
/* -------------------------------------------------------------------- */
int
-ippr_rpcb_new(fin, aps, nat)
+ipf_p_rpcb_new(arg, fin, aps, nat)
+ void *arg;
fr_info_t *fin;
ap_session_t *aps;
nat_t *nat;
{
rpcb_session_t *rs;
- fin = fin; /* LINT */
nat = nat; /* LINT */
+ if (fin->fin_v != 4)
+ return -1;
+
KMALLOC(rs, rpcb_session_t *);
if (rs == NULL)
return(-1);
@@ -168,27 +168,28 @@ ippr_rpcb_new(fin, aps, nat)
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_del */
+/* Function: ipf_p_rpcb_del */
/* Returns: void */
/* Parameters: aps(I) - pointer to proxy session structure */
/* */
/* Free up a session's list of RPCB requests. */
/* -------------------------------------------------------------------- */
void
-ippr_rpcb_del(aps)
+ipf_p_rpcb_del(softc, aps)
+ ipf_main_softc_t *softc;
ap_session_t *aps;
{
rpcb_session_t *rs;
rs = (rpcb_session_t *)aps->aps_data;
MUTEX_ENTER(&rs->rs_rxlock);
- ippr_rpcb_flush(rs);
+ ipf_p_rpcb_flush(rs);
MUTEX_EXIT(&rs->rs_rxlock);
MUTEX_DESTROY(&rs->rs_rxlock);
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_in */
+/* Function: ipf_p_rpcb_in */
/* Returns: int - APR_ERR(1) == drop the packet, */
/* APR_ERR(2) == kill the proxy session, */
/* else change in packet length (in bytes) */
@@ -201,7 +202,8 @@ ippr_rpcb_del(aps)
/* for decoding. Also pass packet off for a rewrite if necessary. */
/* -------------------------------------------------------------------- */
int
-ippr_rpcb_in(fin, aps, nat)
+ipf_p_rpcb_in(arg, fin, aps, nat)
+ void *arg;
fr_info_t *fin;
ap_session_t *aps;
nat_t *nat;
@@ -235,7 +237,7 @@ ippr_rpcb_in(fin, aps, nat)
rm->rm_buflen = dlen;
/* Send off to decode request. */
- rv = ippr_rpcb_decodereq(fin, nat, rs, rm);
+ rv = ipf_p_rpcb_decodereq(fin, nat, rs, rm);
switch(rv)
{
@@ -246,18 +248,18 @@ ippr_rpcb_in(fin, aps, nat)
case 0:
break;
case 1:
- rv = ippr_rpcb_modreq(fin, nat, rm, m, off);
+ rv = ipf_p_rpcb_modreq(fin, nat, rm, m, off);
break;
default:
/*CONSTANTCONDITION*/
- IPF_PANIC(1, ("illegal rv %d (ippr_rpcb_req)", rv));
+ IPF_PANIC(1, ("illegal rv %d (ipf_p_rpcb_req)", rv));
}
return(rv);
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_out */
+/* Function: ipf_p_rpcb_out */
/* Returns: int - APR_ERR(1) == drop the packet, */
/* APR_ERR(2) == kill the proxy session, */
/* else change in packet length (in bytes) */
@@ -272,7 +274,8 @@ ippr_rpcb_in(fin, aps, nat)
/* allow direct communication between RPC client and server. */
/* -------------------------------------------------------------------- */
int
-ippr_rpcb_out(fin, aps, nat)
+ipf_p_rpcb_out(arg, fin, aps, nat)
+ void *arg;
fr_info_t *fin;
ap_session_t *aps;
nat_t *nat;
@@ -311,14 +314,14 @@ ippr_rpcb_out(fin, aps, nat)
rx = NULL; /* XXX gcc */
/* Send off to decode reply. */
- rv = ippr_rpcb_decoderep(fin, nat, rs, rm, &rx);
+ rv = ipf_p_rpcb_decoderep(fin, nat, rs, rm, &rx);
switch(rv)
{
case -1: /* Bad packet */
if (rx != NULL) {
MUTEX_ENTER(&rs->rs_rxlock);
- ippr_rpcb_deref(rs, rx);
+ ipf_p_rpcb_deref(rs, rx);
MUTEX_EXIT(&rs->rs_rxlock);
}
return(APR_ERR(1));
@@ -334,16 +337,16 @@ ippr_rpcb_out(fin, aps, nat)
* same. (i.e., this box is either a router or rpcbind
* only listens on loopback.)
*/
- if (nat->nat_inip.s_addr != nat->nat_outip.s_addr) {
+ if (nat->nat_odstaddr != nat->nat_ndstaddr) {
if (rx->rx_type == RPCB_RES_STRING)
- diff = ippr_rpcb_modv3(fin, nat, rm, m, off);
+ diff = ipf_p_rpcb_modv3(fin, nat, rm, m, off);
else if (rx->rx_type == RPCB_RES_LIST)
- diff = ippr_rpcb_modv4(fin, nat, rm, m, off);
+ diff = ipf_p_rpcb_modv4(fin, nat, rm, m, off);
}
break;
default:
/*CONSTANTCONDITION*/
- IPF_PANIC(1, ("illegal rv %d (ippr_rpcb_decoderep)", rv));
+ IPF_PANIC(1, ("illegal rv %d (ipf_p_rpcb_decoderep)", rv));
}
if (rx != NULL) {
@@ -354,8 +357,8 @@ ippr_rpcb_out(fin, aps, nat)
* finished with rx, and the other signals that we've
* processed its reply.
*/
- ippr_rpcb_deref(rs, rx);
- ippr_rpcb_deref(rs, rx);
+ ipf_p_rpcb_deref(rs, rx);
+ ipf_p_rpcb_deref(rs, rx);
MUTEX_EXIT(&rs->rs_rxlock);
}
@@ -367,14 +370,14 @@ ippr_rpcb_out(fin, aps, nat)
*/
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_flush */
+/* Function: ipf_p_rpcb_flush */
/* Returns: void */
/* Parameters: rs(I) - pointer to RPCB session structure */
/* */
/* Simply flushes the list of outstanding transactions, if any. */
/* -------------------------------------------------------------------- */
static void
-ippr_rpcb_flush(rs)
+ipf_p_rpcb_flush(rs)
rpcb_session_t *rs;
{
rpcb_xact_t *r1, *r2;
@@ -391,7 +394,7 @@ ippr_rpcb_flush(rs)
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_decodereq */
+/* Function: ipf_p_rpcb_decodereq */
/* Returns: int - -1 == bad request or critical failure, */
/* 0 == request successfully decoded, */
/* 1 == request successfully decoded; requires */
@@ -408,7 +411,7 @@ ippr_rpcb_flush(rs)
/* is enough room in rs_buf for the basic RPC message "preamble". */
/* -------------------------------------------------------------------- */
static int
-ippr_rpcb_decodereq(fin, nat, rs, rm)
+ipf_p_rpcb_decodereq(fin, nat, rs, rm)
fr_info_t *fin;
nat_t *nat;
rpcb_session_t *rs;
@@ -440,9 +443,9 @@ ippr_rpcb_decodereq(fin, nat, rs, rm)
rc->rc_proc = p++;
/* Bypass RPC authentication stuff. */
- if (ippr_rpcb_skipauth(rm, &rc->rc_authcred, &p) != 0)
+ if (ipf_p_rpcb_skipauth(rm, &rc->rc_authcred, &p) != 0)
return(-1);
- if (ippr_rpcb_skipauth(rm, &rc->rc_authverf, &p) != 0)
+ if (ipf_p_rpcb_skipauth(rm, &rc->rc_authverf, &p) != 0)
return(-1);
/* Compare RPCB version and procedure numbers. */
@@ -488,17 +491,17 @@ ippr_rpcb_decodereq(fin, nat, rs, rm)
ra = &rc->rc_rpcbargs;
/* Decode the 'struct rpcb' request. */
- if (ippr_rpcb_xdrrpcb(rm, p, ra) != 0)
+ if (ipf_p_rpcb_xdrrpcb(rm, p, ra) != 0)
return(-1);
/* Are the target address & port valid? */
- if ((ra->ra_maddr.xu_ip != nat->nat_outip.s_addr) ||
- (ra->ra_maddr.xu_port != nat->nat_outport))
+ if ((ra->ra_maddr.xu_ip != nat->nat_ndstaddr) ||
+ (ra->ra_maddr.xu_port != nat->nat_ndport))
return(-1);
/* Do we need to rewrite this packet? */
- if ((nat->nat_outip.s_addr != nat->nat_inip.s_addr) ||
- (nat->nat_outport != nat->nat_inport))
+ if ((nat->nat_ndstaddr != nat->nat_odstaddr) ||
+ (nat->nat_ndport != nat->nat_odport))
mod = 1;
break;
default:
@@ -506,7 +509,7 @@ ippr_rpcb_decodereq(fin, nat, rs, rm)
}
MUTEX_ENTER(&rs->rs_rxlock);
- if (ippr_rpcb_insert(rs, &rx) != 0) {
+ if (ipf_p_rpcb_insert(rs, &rx) != 0) {
MUTEX_EXIT(&rs->rs_rxlock);
return(-1);
}
@@ -516,7 +519,7 @@ ippr_rpcb_decodereq(fin, nat, rs, rm)
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_skipauth */
+/* Function: ipf_p_rpcb_skipauth */
/* Returns: int -- -1 == illegal auth parameters (lengths) */
/* 0 == valid parameters, pointer advanced */
/* Parameters: rm(I) - pointer to RPC message structure */
@@ -527,7 +530,7 @@ ippr_rpcb_decodereq(fin, nat, rs, rm)
/* it. */
/* -------------------------------------------------------------------- */
static int
-ippr_rpcb_skipauth(rm, auth, buf)
+ipf_p_rpcb_skipauth(rm, auth, buf)
rpc_msg_t *rm;
xdr_auth_t *auth;
u_32_t **buf;
@@ -559,20 +562,20 @@ ippr_rpcb_skipauth(rm, auth, buf)
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_insert */
+/* Function: ipf_p_rpcb_insert */
/* Returns: int -- -1 == list insertion failed, */
/* 0 == item successfully added */
/* Parameters: rs(I) - pointer to RPCB session structure */
/* rx(I) - pointer to RPCB transaction structure */
/* -------------------------------------------------------------------- */
static int
-ippr_rpcb_insert(rs, rx)
+ipf_p_rpcb_insert(rs, rx)
rpcb_session_t *rs;
rpcb_xact_t *rx;
{
rpcb_xact_t *rxp;
- rxp = ippr_rpcb_lookup(rs, rx->rx_xid);
+ rxp = ipf_p_rpcb_lookup(rs, rx->rx_xid);
if (rxp != NULL) {
++rxp->rx_ref;
return(0);
@@ -602,7 +605,7 @@ ippr_rpcb_insert(rs, rx)
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_xdrrpcb */
+/* Function: ipf_p_rpcb_xdrrpcb */
/* Returns: int -- -1 == failure to properly decode the request */
/* 0 == rpcb successfully decoded */
/* Parameters: rs(I) - pointer to RPCB session structure */
@@ -613,7 +616,7 @@ ippr_rpcb_insert(rs, rx)
/* within only the context of TCP/UDP over IP networks. */
/* -------------------------------------------------------------------- */
static int
-ippr_rpcb_xdrrpcb(rm, p, ra)
+ipf_p_rpcb_xdrrpcb(rm, p, ra)
rpc_msg_t *rm;
u_32_t *p;
rpcb_args_t *ra;
@@ -625,11 +628,11 @@ ippr_rpcb_xdrrpcb(rm, p, ra)
p += 2;
/* Decode r_netid. Must be "tcp" or "udp". */
- if (ippr_rpcb_getproto(rm, &ra->ra_netid, &p) != 0)
+ if (ipf_p_rpcb_getproto(rm, &ra->ra_netid, &p) != 0)
return(-1);
/* Decode r_maddr. */
- if (ippr_rpcb_getuaddr(rm, &ra->ra_maddr, &p) != 0)
+ if (ipf_p_rpcb_getuaddr(rm, &ra->ra_maddr, &p) != 0)
return(-1);
/* Advance to r_owner and make sure it's empty. */
@@ -640,7 +643,7 @@ ippr_rpcb_xdrrpcb(rm, p, ra)
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_getuaddr */
+/* Function: ipf_p_rpcb_getuaddr */
/* Returns: int -- -1 == illegal string, */
/* 0 == string parsed; contents recorded */
/* Parameters: rm(I) - pointer to RPC message structure */
@@ -650,7 +653,7 @@ ippr_rpcb_xdrrpcb(rm, p, ra)
/* Decode the IP address / port at p and record them in xu. */
/* -------------------------------------------------------------------- */
static int
-ippr_rpcb_getuaddr(rm, xu, p)
+ipf_p_rpcb_getuaddr(rm, xu, p)
rpc_msg_t *rm;
xdr_uaddr_t *xu;
u_32_t **p;
@@ -699,7 +702,7 @@ ippr_rpcb_getuaddr(rm, xu, p)
/* Check for ASCII byte. */
*c = '\0';
- t = ippr_rpcb_atoi(b);
+ t = ipf_p_rpcb_atoi(b);
if (t > 255)
return(-1);
@@ -721,7 +724,7 @@ ippr_rpcb_getuaddr(rm, xu, p)
return(-1);
/* Handle the last byte (port low byte) */
- t = ippr_rpcb_atoi(b);
+ t = ipf_p_rpcb_atoi(b);
if (t > 255)
return(-1);
pp[d - 4] = t & 0xff;
@@ -730,14 +733,14 @@ ippr_rpcb_getuaddr(rm, xu, p)
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_atoi (XXX should be generic for all proxies) */
+/* Function: ipf_p_rpcb_atoi (XXX should be generic for all proxies) */
/* Returns: int -- integer representation of supplied string */
/* Parameters: ptr(I) - input string */
/* */
/* Simple version of atoi(3) ripped from ip_rcmd_pxy.c. */
/* -------------------------------------------------------------------- */
static u_int
-ippr_rpcb_atoi(ptr)
+ipf_p_rpcb_atoi(ptr)
char *ptr;
{
register char *s = ptr, c;
@@ -751,7 +754,7 @@ ippr_rpcb_atoi(ptr)
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_modreq */
+/* Function: ipf_p_rpcb_modreq */
/* Returns: int -- change in datagram length */
/* APR_ERR(2) - critical failure */
/* Parameters: fin(I) - pointer to packet information */
@@ -764,7 +767,7 @@ ippr_rpcb_atoi(ptr)
/* with the latter. (This is exclusive to protocol versions 3 & 4). */
/* -------------------------------------------------------------------- */
static int
-ippr_rpcb_modreq(fin, nat, rm, m, off)
+ipf_p_rpcb_modreq(fin, nat, rm, m, off)
fr_info_t *fin;
nat_t *nat;
rpc_msg_t *rm;
@@ -779,8 +782,8 @@ ippr_rpcb_modreq(fin, nat, rm, m, off)
int diff;
ra = &rm->rm_call.rc_rpcbargs;
- i = (char *)&nat->nat_inip.s_addr;
- p = (char *)&nat->nat_inport;
+ i = (char *)&nat->nat_odstaddr;
+ p = (char *)&nat->nat_odport;
/* Form new string. */
bzero(uaddr, sizeof(uaddr)); /* Just in case we need padding. */
@@ -821,9 +824,9 @@ ippr_rpcb_modreq(fin, nat, rm, m, off)
if (diff != 0) {
udp = fin->fin_dp;
udp->uh_ulen = htons(ntohs(udp->uh_ulen) + diff);
- fin->fin_ip->ip_len += diff;
- fin->fin_dlen += diff;
fin->fin_plen += diff;
+ fin->fin_ip->ip_len = htons(fin->fin_plen);
+ fin->fin_dlen += diff;
/* XXX Storage lengths. */
}
@@ -831,7 +834,7 @@ ippr_rpcb_modreq(fin, nat, rm, m, off)
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_decoderep */
+/* Function: ipf_p_rpcb_decoderep */
/* Returns: int - -1 == bad request or critical failure, */
/* 0 == valid, negative reply */
/* 1 == vaddlid, positive reply; needs no changes */
@@ -851,7 +854,7 @@ ippr_rpcb_modreq(fin, nat, rm, m, off)
/* is enough room in rs_buf for the basic RPC message "preamble". */
/* -------------------------------------------------------------------- */
static int
-ippr_rpcb_decoderep(fin, nat, rs, rm, rxp)
+ipf_p_rpcb_decoderep(fin, nat, rs, rm, rxp)
fr_info_t *fin;
nat_t *nat;
rpcb_session_t *rs;
@@ -875,7 +878,7 @@ ippr_rpcb_decoderep(fin, nat, rs, rm, rxp)
/* Lookup XID */
MUTEX_ENTER(&rs->rs_rxlock);
- if ((rx = ippr_rpcb_lookup(rs, xdr)) == NULL) {
+ if ((rx = ipf_p_rpcb_lookup(rs, xdr)) == NULL) {
MUTEX_EXIT(&rs->rs_rxlock);
return(-1);
}
@@ -900,7 +903,7 @@ ippr_rpcb_decoderep(fin, nat, rs, rm, rxp)
}
/* Bypass RPC authentication stuff. */
- if (ippr_rpcb_skipauth(rm, &rr->rr_authverf, &p) != 0)
+ if (ipf_p_rpcb_skipauth(rm, &rr->rr_authverf, &p) != 0)
return(-1);
/* Test accept status */
@@ -916,20 +919,20 @@ ippr_rpcb_decoderep(fin, nat, rs, rm, rxp)
/* There must be only one 4 byte argument. */
if (!RPCB_BUF_EQ(rm, p, 4))
return(-1);
-
+
rr->rr_v2 = p;
xdr = B(rr->rr_v2);
-
+
/* Reply w/ a 0 port indicates service isn't registered */
if (xdr == 0)
return(0);
-
+
/* Is the value sane? */
if (xdr > 65535)
return(-1);
/* Create NAT & state table entries. */
- if (ippr_rpcb_getnat(fin, nat, rx->rx_proto, (u_int)xdr) != 0)
+ if (ipf_p_rpcb_getnat(fin, nat, rx->rx_proto, (u_int)xdr) != 0)
return(-1);
break;
case RPCB_RES_STRING:
@@ -947,15 +950,15 @@ ippr_rpcb_decoderep(fin, nat, rs, rm, rxp)
return(0);
/* Decode the target IP address / port. */
- if (ippr_rpcb_getuaddr(rm, &rr->rr_v3, &p) != 0)
+ if (ipf_p_rpcb_getuaddr(rm, &rr->rr_v3, &p) != 0)
return(-1);
/* Validate the IP address and port contained. */
- if (nat->nat_inip.s_addr != rr->rr_v3.xu_ip)
+ if (nat->nat_odstaddr != rr->rr_v3.xu_ip)
return(-1);
/* Create NAT & state table entries. */
- if (ippr_rpcb_getnat(fin, nat, rx->rx_proto,
+ if (ipf_p_rpcb_getnat(fin, nat, rx->rx_proto,
(u_int)rr->rr_v3.xu_port) != 0)
return(-1);
break;
@@ -980,9 +983,9 @@ ippr_rpcb_decoderep(fin, nat, rs, rm, rxp)
for(;;) {
re = &rl->rl_entries[rl->rl_cnt];
- if (ippr_rpcb_getuaddr(rm, &re->re_maddr, &p) != 0)
+ if (ipf_p_rpcb_getuaddr(rm, &re->re_maddr, &p) != 0)
return(-1);
- if (ippr_rpcb_getproto(rm, &re->re_netid, &p) != 0)
+ if (ipf_p_rpcb_getproto(rm, &re->re_netid, &p) != 0)
return(-1);
/* re_semantics & re_pfamily length */
if (!RPCB_BUF_GEQ(rm, p, 12))
@@ -992,7 +995,7 @@ ippr_rpcb_decoderep(fin, nat, rs, rm, rxp)
if ((xdr != 4) || strncmp((char *)p, "inet", 4))
return(-1);
p++;
- if (ippr_rpcb_getproto(rm, &re->re_proto, &p) != 0)
+ if (ipf_p_rpcb_getproto(rm, &re->re_proto, &p) != 0)
return(-1);
if (!RPCB_BUF_GEQ(rm, p, 4))
return(-1);
@@ -1011,7 +1014,7 @@ ippr_rpcb_decoderep(fin, nat, rs, rm, rxp)
for(rl->rl_cnt = 0; rl->rl_cnt < cnt; rl->rl_cnt++) {
re = &rl->rl_entries[rl->rl_cnt];
- rv = ippr_rpcb_getnat(fin, nat,
+ rv = ipf_p_rpcb_getnat(fin, nat,
re->re_proto.xp_proto,
(u_int)re->re_maddr.xu_port);
if (rv != 0)
@@ -1027,14 +1030,14 @@ ippr_rpcb_decoderep(fin, nat, rs, rm, rxp)
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_lookup */
+/* Function: ipf_p_rpcb_lookup */
/* Returns: rpcb_xact_t * - NULL == no matching record, */
/* else pointer to relevant entry */
/* Parameters: rs(I) - pointer to RPCB session */
/* xid(I) - XID to look for */
/* -------------------------------------------------------------------- */
static rpcb_xact_t *
-ippr_rpcb_lookup(rs, xid)
+ipf_p_rpcb_lookup(rs, xid)
rpcb_session_t *rs;
u_32_t xid;
{
@@ -1051,7 +1054,7 @@ ippr_rpcb_lookup(rs, xid)
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_deref */
+/* Function: ipf_p_rpcb_deref */
/* Returns: (void) */
/* Parameters: rs(I) - pointer to RPCB session */
/* rx(I) - pointer to RPC transaction struct to remove */
@@ -1062,7 +1065,7 @@ ippr_rpcb_lookup(rs, xid)
/* Free the RPCB transaction record rx from the chain of entries. */
/* -------------------------------------------------------------------- */
static void
-ippr_rpcb_deref(rs, rx)
+ipf_p_rpcb_deref(rs, rx)
rpcb_session_t *rs;
rpcb_xact_t *rx;
{
@@ -1085,7 +1088,7 @@ ippr_rpcb_deref(rs, rx)
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_getproto */
+/* Function: ipf_p_rpcb_getproto */
/* Returns: int - -1 == illegal protocol/netid, */
/* 0 == legal protocol/netid */
/* Parameters: rm(I) - pointer to RPC message structure */
@@ -1095,7 +1098,7 @@ ippr_rpcb_deref(rs, rx)
/* Decode netid/proto stored at p and record its numeric value. */
/* -------------------------------------------------------------------- */
static int
-ippr_rpcb_getproto(rm, xp, p)
+ipf_p_rpcb_getproto(rm, xp, p)
rpc_msg_t *rm;
xdr_proto_t *xp;
u_32_t **p;
@@ -1122,7 +1125,7 @@ ippr_rpcb_getproto(rm, xp, p)
else {
return(-1);
}
-
+
/* Advance past the string. */
(*p)++;
@@ -1130,7 +1133,7 @@ ippr_rpcb_getproto(rm, xp, p)
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_getnat */
+/* Function: ipf_p_rpcb_getnat */
/* Returns: int -- -1 == failed to create table entries, */
/* 0 == success */
/* Parameters: fin(I) - pointer to packet information */
@@ -1142,12 +1145,13 @@ ippr_rpcb_getproto(rm, xp, p)
/* attempt between RPC client and server. */
/* -------------------------------------------------------------------- */
static int
-ippr_rpcb_getnat(fin, nat, proto, port)
+ipf_p_rpcb_getnat(fin, nat, proto, port)
fr_info_t *fin;
nat_t *nat;
u_int proto;
u_int port;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
ipnat_t *ipn, ipnat;
tcphdr_t tcp;
ipstate_t *is;
@@ -1159,15 +1163,13 @@ ippr_rpcb_getnat(fin, nat, proto, port)
/* Generate dummy fr_info */
bcopy((char *)fin, (char *)&fi, sizeof(fi));
- fi.fin_state = NULL;
- fi.fin_nat = NULL;
fi.fin_out = 0;
- fi.fin_src = fin->fin_dst;
- fi.fin_dst = nat->nat_outip;
fi.fin_p = proto;
fi.fin_sport = 0;
fi.fin_dport = port & 0xffff;
fi.fin_flx |= FI_IGNORE;
+ fi.fin_saddr = nat->nat_osrcaddr;
+ fi.fin_daddr = nat->nat_odstaddr;
bzero((char *)&tcp, sizeof(tcp));
tcp.th_dport = htons(port);
@@ -1195,18 +1197,18 @@ ippr_rpcb_getnat(fin, nat, proto, port)
* If successful, fr_stlookup returns with ipf_state locked. We have
* no use for this lock, so simply unlock it if necessary.
*/
- is = fr_stlookup(&fi, &tcp, NULL);
+ is = ipf_state_lookup(&fi, &tcp, NULL);
if (is != NULL) {
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
}
- RWLOCK_EXIT(&ipf_nat);
+ RWLOCK_EXIT(&softc->ipf_nat);
- WRITE_ENTER(&ipf_nat);
- natl = nat_inlookup(&fi, nflags, proto, fi.fin_src, fi.fin_dst);
+ WRITE_ENTER(&softc->ipf_nat);
+ natl = ipf_nat_inlookup(&fi, nflags, proto, fi.fin_src, fi.fin_dst);
if ((natl != NULL) && (is != NULL)) {
- MUTEX_DOWNGRADE(&ipf_nat);
+ MUTEX_DOWNGRADE(&softc->ipf_nat);
return(0);
}
@@ -1220,6 +1222,10 @@ ippr_rpcb_getnat(fin, nat, proto, port)
nflags &= ~NAT_SEARCH;
if (natl == NULL) {
+#ifdef USE_MUTEXES
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+#endif
+
/* XXX Since we're just copying the original ipn contents
* back, would we be better off just sending a pointer to
* the 'temp' copy off to nat_new instead?
@@ -1228,46 +1234,51 @@ ippr_rpcb_getnat(fin, nat, proto, port)
bcopy((char *)ipn, (char *)&ipnat, sizeof(ipnat));
ipn->in_flags = nflags & IPN_TCPUDP;
ipn->in_apr = NULL;
- ipn->in_p = proto;
- ipn->in_pmin = htons(fi.fin_dport);
- ipn->in_pmax = htons(fi.fin_dport);
- ipn->in_pnext = htons(fi.fin_dport);
+ ipn->in_pr[0] = proto;
+ ipn->in_pr[1] = proto;
+ ipn->in_dpmin = fi.fin_dport;
+ ipn->in_dpmax = fi.fin_dport;
+ ipn->in_dpnext = fi.fin_dport;
ipn->in_space = 1;
ipn->in_ippip = 1;
if (ipn->in_flags & IPN_FILTER) {
ipn->in_scmp = 0;
ipn->in_dcmp = 0;
}
- *ipn->in_plabel = '\0';
+ ipn->in_plabel = -1;
/* Create NAT entry. return NULL if this fails. */
- natl = nat_new(&fi, ipn, NULL, nflags|SI_CLONE|NAT_SLAVE,
+ MUTEX_ENTER(&softn->ipf_nat_new);
+ natl = ipf_nat_add(&fi, ipn, NULL, nflags|SI_CLONE|NAT_SLAVE,
NAT_INBOUND);
+ MUTEX_EXIT(&softn->ipf_nat_new);
bcopy((char *)&ipnat, (char *)ipn, sizeof(ipnat));
if (natl == NULL) {
- MUTEX_DOWNGRADE(&ipf_nat);
+ MUTEX_DOWNGRADE(&softc->ipf_nat);
return(-1);
}
+ natl->nat_ptr = ipn;
+ fi.fin_saddr = natl->nat_nsrcaddr;
+ fi.fin_daddr = natl->nat_ndstaddr;
ipn->in_use++;
- (void) nat_proto(&fi, natl, nflags);
- nat_update(&fi, natl, natl->nat_ptr);
+ (void) ipf_nat_proto(&fi, natl, nflags);
+ MUTEX_ENTER(&natl->nat_lock);
+ ipf_nat_update(&fi, natl);
+ MUTEX_EXIT(&natl->nat_lock);
}
- MUTEX_DOWNGRADE(&ipf_nat);
+ MUTEX_DOWNGRADE(&softc->ipf_nat);
if (is == NULL) {
/* Create state entry. Return NULL if this fails. */
- fi.fin_dst = nat->nat_inip;
- fi.fin_nat = (void *)natl;
fi.fin_flx |= FI_NATED;
fi.fin_flx &= ~FI_STATE;
nflags &= NAT_TCPUDP;
nflags |= SI_W_SPORT|SI_CLONE;
- is = fr_addstate(&fi, NULL, nflags);
- if (is == NULL) {
+ if (ipf_state_add(softc, &fi, NULL, nflags) != 0) {
/*
* XXX nat_delete is private to ip_nat.c. Should
* check w/ Darren about this one.
@@ -1276,15 +1287,13 @@ ippr_rpcb_getnat(fin, nat, proto, port)
*/
return(-1);
}
- if (fi.fin_state != NULL)
- fr_statederef((ipstate_t **)&fi.fin_state);
}
return(0);
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_modv3 */
+/* Function: ipf_p_rpcb_modv3 */
/* Returns: int -- change in packet length */
/* Parameters: fin(I) - pointer to packet information */
/* nat(I) - pointer to NAT session */
@@ -1296,7 +1305,7 @@ ippr_rpcb_getnat(fin, nat, proto, port)
/* lengths as necessary. */
/* -------------------------------------------------------------------- */
static int
-ippr_rpcb_modv3(fin, nat, rm, m, off)
+ipf_p_rpcb_modv3(fin, nat, rm, m, off)
fr_info_t *fin;
nat_t *nat;
rpc_msg_t *rm;
@@ -1310,7 +1319,7 @@ ippr_rpcb_modv3(fin, nat, rm, m, off)
int diff;
rr = &rm->rm_resp;
- i = (char *)&nat->nat_outip.s_addr;
+ i = (char *)&nat->nat_ndstaddr;
p = (char *)&rr->rr_v3.xu_port;
/* Form new string. */
@@ -1336,7 +1345,7 @@ ippr_rpcb_modv3(fin, nat, rm, m, off)
/* Write new string. */
COPYBACK(m, off, xlen, uaddr);
-
+
/* Determine difference in data lengths. */
diff = xlen - XDRALIGN(B(rr->rr_v3.xu_xslen));
@@ -1345,13 +1354,13 @@ ippr_rpcb_modv3(fin, nat, rm, m, off)
* adjustments.
*/
if (diff != 0)
- ippr_rpcb_fixlen(fin, diff);
+ ipf_p_rpcb_fixlen(fin, diff);
return(diff);
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_modv4 */
+/* Function: ipf_p_rpcb_modv4 */
/* Returns: int -- change in packet length */
/* Parameters: fin(I) - pointer to packet information */
/* nat(I) - pointer to NAT session */
@@ -1362,7 +1371,7 @@ ippr_rpcb_modv3(fin, nat, rm, m, off)
/* Write new rpcb_entry list, adjusting lengths as necessary. */
/* -------------------------------------------------------------------- */
static int
-ippr_rpcb_modv4(fin, nat, rm, m, off)
+ipf_p_rpcb_modv4(fin, nat, rm, m, off)
fr_info_t *fin;
nat_t *nat;
rpc_msg_t *rm;
@@ -1381,7 +1390,7 @@ ippr_rpcb_modv4(fin, nat, rm, m, off)
rr = &rm->rm_resp;
rl = &rr->rr_v4;
- i = (char *)&nat->nat_outip.s_addr;
+ i = (char *)&nat->nat_ndstaddr;
/* Determine mbuf offset to write to. */
re = &rl->rl_entries[0];
@@ -1432,14 +1441,14 @@ ippr_rpcb_modv4(fin, nat, rm, m, off)
* adjustments.
*/
if (diff != 0)
- ippr_rpcb_fixlen(fin, diff);
+ ipf_p_rpcb_fixlen(fin, diff);
return(diff);
}
/* -------------------------------------------------------------------- */
-/* Function: ippr_rpcb_fixlen */
+/* Function: ipf_p_rpcb_fixlen */
/* Returns: (void) */
/* Parameters: fin(I) - pointer to packet information */
/* len(I) - change in packet length */
@@ -1448,7 +1457,7 @@ ippr_rpcb_modv4(fin, nat, rm, m, off)
/* header fields. */
/* -------------------------------------------------------------------- */
static void
-ippr_rpcb_fixlen(fin, len)
+ipf_p_rpcb_fixlen(fin, len)
fr_info_t *fin;
int len;
{
@@ -1456,9 +1465,9 @@ ippr_rpcb_fixlen(fin, len)
udp = fin->fin_dp;
udp->uh_ulen = htons(ntohs(udp->uh_ulen) + len);
- fin->fin_ip->ip_len += len;
- fin->fin_dlen += len;
fin->fin_plen += len;
+ fin->fin_ip->ip_len = htons(fin->fin_plen);
+ fin->fin_dlen += len;
}
#undef B
diff --git a/sys/contrib/ipfilter/netinet/ip_rules.c b/sys/contrib/ipfilter/netinet/ip_rules.c
index f080ec5b..434b9de 100644
--- a/sys/contrib/ipfilter/netinet/ip_rules.c
+++ b/sys/contrib/ipfilter/netinet/ip_rules.c
@@ -1,18 +1,29 @@
/* $FreeBSD$ */
/*
-* Copyright (C) 1993-2000 by Darren Reed.
+* Copyright (C) 2012 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.
*/
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
-#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi)
-# include <sys/systm.h>
+#if defined(__FreeBSD_version) && (__FreeBSD_version >= 40000)
+# if defined(_KERNEL)
+# include <sys/libkern.h>
+# else
+# include <sys/unistd.h>
+# endif
+#endif
+#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 399000000)
+#else
+# if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi)
+# include <sys/systm.h>
+# endif
#endif
#include <sys/errno.h>
#include <sys/param.h>
@@ -40,18 +51,32 @@
#ifdef IPFILTER_COMPILED
+extern ipf_main_softc_t ipfmain;
+
+
static u_long in_rule__0[] = {
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80000000, 0x8002, 0, 0, 0, 0xffff, 0, 0, 0x4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+0, 0, 0, 0, 0, 0, 0, 0x8070d88, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0x1b0, 0x1, 0, 0, 0, 0x2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40000000, 0x8002, 0, 0, 0, 0xffff, 0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0
};
static u_long out_rule__0[] = {
-0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80000000, 0x4002, 0, 0, 0, 0xffff, 0, 0, 0x4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+0, 0, 0, 0, 0, 0, 0, 0x8070d88, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0x1b0, 0x1, 0, 0, 0, 0x3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x40000000, 0x4002, 0, 0, 0, 0xffff, 0, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xffffffff, 0, 0, 0, 0
};
frentry_t *ipf_rules_in_[1] = {
(frentry_t *)&in_rule__0
};
+/* XXX This file (ip_rules.c) is not part of the ipfilter tarball, it is
+ XXX generated by the ipfilter build process. Unfortunately the build
+ XXX process did not generate the following lines so they are added
+ XXX by hand here. This is a bit of a hack but it works for now. Future
+ XXX imports/merges of ipfilter may generate this so the following will
+ XXX need to be removed following some future merge.
+ XXX */
+frentry_t *ipf_rules_out_[1] = {
+ (frentry_t *)&out_rule__0
+};
+
frentry_t *ipfrule_match_in_(fin, passp)
fr_info_t *fin;
u_32_t *passp;
@@ -62,10 +87,6 @@ u_32_t *passp;
return fr;
}
-frentry_t *ipf_rules_out_[1] = {
- (frentry_t *)&out_rule__0
-};
-
frentry_t *ipfrule_match_out_(fin, passp)
fr_info_t *fin;
u_32_t *passp;
@@ -87,9 +108,14 @@ int ipfrule_add_out_()
fp = ipf_rules_out_[i];
fp->fr_next = NULL;
for (j = i + 1; j < max; j++)
- if (strncmp(fp->fr_group,
+ if (strncmp(fp->fr_names + fp->fr_group,
+ ipf_rules_out_[j]->fr_names +
ipf_rules_out_[j]->fr_group,
FR_GROUPLEN) == 0) {
+ if (ipf_rules_out_[j] != NULL)
+ ipf_rules_out_[j]->fr_pnext =
+ &fp->fr_next;
+ fp->fr_pnext = &ipf_rules_out_[j];
fp->fr_next = ipf_rules_out_[j];
break;
}
@@ -97,13 +123,14 @@ int ipfrule_add_out_()
fp = &ipfrule_out_;
bzero((char *)fp, sizeof(*fp));
- fp->fr_type = FR_T_CALLFUNC|FR_T_BUILTIN;
+ fp->fr_type = FR_T_CALLFUNC_BUILTIN;
fp->fr_flags = FR_OUTQUE|FR_NOMATCH;
fp->fr_data = (void *)ipf_rules_out_[0];
fp->fr_dsize = sizeof(ipf_rules_out_[0]);
- fp->fr_v = 4;
+ fp->fr_family = AF_INET;
fp->fr_func = (ipfunc_t)ipfrule_match_out_;
- err = frrequest(IPL_LOGIPF, SIOCADDFR, (caddr_t)fp, fr_active, 0);
+ err = frrequest(&ipfmain, IPL_LOGIPF, SIOCADDFR, (caddr_t)fp,
+ ipfmain.ipf_active, 0);
return err;
}
@@ -129,8 +156,9 @@ int ipfrule_remove_out_()
}
}
if (err == 0)
- err = frrequest(IPL_LOGIPF, SIOCDELFR,
- (caddr_t)&ipfrule_out_, fr_active, 0);
+ err = frrequest(&ipfmain, IPL_LOGIPF, SIOCDELFR,
+ (caddr_t)&ipfrule_out_,
+ ipfmain.ipf_active, 0);
if (err)
return err;
@@ -149,9 +177,14 @@ int ipfrule_add_in_()
fp = ipf_rules_in_[i];
fp->fr_next = NULL;
for (j = i + 1; j < max; j++)
- if (strncmp(fp->fr_group,
+ if (strncmp(fp->fr_names + fp->fr_group,
+ ipf_rules_in_[j]->fr_names +
ipf_rules_in_[j]->fr_group,
FR_GROUPLEN) == 0) {
+ if (ipf_rules_in_[j] != NULL)
+ ipf_rules_in_[j]->fr_pnext =
+ &fp->fr_next;
+ fp->fr_pnext = &ipf_rules_in_[j];
fp->fr_next = ipf_rules_in_[j];
break;
}
@@ -159,13 +192,14 @@ int ipfrule_add_in_()
fp = &ipfrule_in_;
bzero((char *)fp, sizeof(*fp));
- fp->fr_type = FR_T_CALLFUNC|FR_T_BUILTIN;
+ fp->fr_type = FR_T_CALLFUNC_BUILTIN;
fp->fr_flags = FR_INQUE|FR_NOMATCH;
fp->fr_data = (void *)ipf_rules_in_[0];
fp->fr_dsize = sizeof(ipf_rules_in_[0]);
- fp->fr_v = 4;
+ fp->fr_family = AF_INET;
fp->fr_func = (ipfunc_t)ipfrule_match_in_;
- err = frrequest(IPL_LOGIPF, SIOCADDFR, (caddr_t)fp, fr_active, 0);
+ err = frrequest(&ipfmain, IPL_LOGIPF, SIOCADDFR, (caddr_t)fp,
+ ipfmain.ipf_active, 0);
return err;
}
@@ -191,8 +225,9 @@ int ipfrule_remove_in_()
}
}
if (err == 0)
- err = frrequest(IPL_LOGIPF, SIOCDELFR,
- (caddr_t)&ipfrule_in_, fr_active, 0);
+ err = frrequest(&ipfmain, IPL_LOGIPF, SIOCDELFR,
+ (caddr_t)&ipfrule_in_,
+ ipfmain.ipf_active, 0);
if (err)
return err;
diff --git a/sys/contrib/ipfilter/netinet/ip_scan.c b/sys/contrib/ipfilter/netinet/ip_scan.c
index 54acb2a..5b7c77e 100644
--- a/sys/contrib/ipfilter/netinet/ip_scan.c
+++ b/sys/contrib/ipfilter/netinet/ip_scan.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1995-2001 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*/
@@ -58,17 +58,17 @@ struct file;
#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_scan.c,v 2.40.2.10 2007/06/02 21:22:28 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id$";
#endif
#ifdef IPFILTER_SCAN /* endif at bottom of file */
-ipscan_t *ipsc_list = NULL,
- *ipsc_tail = NULL;
-ipscanstat_t ipsc_stat;
+ipscan_t *ipf_scan_list = NULL,
+ *ipf_scan_tail = NULL;
+ipscanstat_t ipf_scan_stat;
# ifdef USE_MUTEXES
-ipfrwlock_t ipsc_rwlock;
+ipfrwlock_t ipf_scan_rwlock;
# endif
# ifndef isalpha
@@ -77,42 +77,47 @@ ipfrwlock_t ipsc_rwlock;
# endif
-int ipsc_add __P((caddr_t));
-int ipsc_delete __P((caddr_t));
-struct ipscan *ipsc_lookup __P((char *));
-int ipsc_matchstr __P((sinfo_t *, char *, int));
-int ipsc_matchisc __P((ipscan_t *, ipstate_t *, int, int, int *));
-int ipsc_match __P((ipstate_t *));
+int ipf_scan_add __P((caddr_t));
+int ipf_scan_remove __P((caddr_t));
+struct ipscan *ipf_scan_lookup __P((char *));
+int ipf_scan_matchstr __P((sinfo_t *, char *, int));
+int ipf_scan_matchisc __P((ipscan_t *, ipstate_t *, int, int, int *));
+int ipf_scan_match __P((ipstate_t *));
-static int ipsc_inited = 0;
+static int ipf_scan_inited = 0;
-int ipsc_init()
+int
+ipf_scan_init()
{
- RWLOCK_INIT(&ipsc_rwlock, "ip scan rwlock");
- ipsc_inited = 1;
+ RWLOCK_INIT(&ipf_scan_rwlock, "ip scan rwlock");
+ ipf_scan_inited = 1;
return 0;
}
-void fr_scanunload()
+void
+ipf_scan_unload(ipf_main_softc_t *arg)
{
- if (ipsc_inited == 1) {
- RW_DESTROY(&ipsc_rwlock);
- ipsc_inited = 0;
+ if (ipf_scan_inited == 1) {
+ RW_DESTROY(&ipf_scan_rwlock);
+ ipf_scan_inited = 0;
}
}
-int ipsc_add(data)
-caddr_t data;
+int
+ipf_scan_add(data)
+ caddr_t data;
{
ipscan_t *i, *isc;
int err;
KMALLOC(isc, ipscan_t *);
- if (!isc)
+ if (!isc) {
+ ipf_interror = 90001;
return ENOMEM;
+ }
err = copyinptr(data, isc, sizeof(*isc));
if (err) {
@@ -120,23 +125,24 @@ caddr_t data;
return err;
}
- WRITE_ENTER(&ipsc_rwlock);
+ WRITE_ENTER(&ipf_scan_rwlock);
- i = ipsc_lookup(isc->ipsc_tag);
- if (i) {
- RWLOCK_EXIT(&ipsc_rwlock);
+ i = ipf_scan_lookup(isc->ipsc_tag);
+ if (i != NULL) {
+ RWLOCK_EXIT(&ipf_scan_rwlock);
KFREE(isc);
+ ipf_interror = 90002;
return EEXIST;
}
- if (ipsc_tail) {
- ipsc_tail->ipsc_next = isc;
- isc->ipsc_pnext = &ipsc_tail->ipsc_next;
- ipsc_tail = isc;
+ if (ipf_scan_tail) {
+ ipf_scan_tail->ipsc_next = isc;
+ isc->ipsc_pnext = &ipf_scan_tail->ipsc_next;
+ ipf_scan_tail = isc;
} else {
- ipsc_list = isc;
- ipsc_tail = isc;
- isc->ipsc_pnext = &ipsc_list;
+ ipf_scan_list = isc;
+ ipf_scan_tail = isc;
+ isc->ipsc_pnext = &ipf_scan_list;
}
isc->ipsc_next = NULL;
@@ -145,14 +151,15 @@ caddr_t data;
isc->ipsc_sref = 0;
isc->ipsc_active = 0;
- ipsc_stat.iscs_entries++;
- RWLOCK_EXIT(&ipsc_rwlock);
+ ipf_scan_stat.iscs_entries++;
+ RWLOCK_EXIT(&ipf_scan_rwlock);
return 0;
}
-int ipsc_delete(data)
-caddr_t data;
+int
+ipf_scan_remove(data)
+ caddr_t data;
{
ipscan_t isc, *i;
int err;
@@ -161,14 +168,15 @@ caddr_t data;
if (err)
return err;
- WRITE_ENTER(&ipsc_rwlock);
+ WRITE_ENTER(&ipf_scan_rwlock);
- i = ipsc_lookup(isc.ipsc_tag);
+ i = ipf_scan_lookup(isc.ipsc_tag);
if (i == NULL)
err = ENOENT;
else {
if (i->ipsc_fref) {
- RWLOCK_EXIT(&ipsc_rwlock);
+ RWLOCK_EXIT(&ipf_scan_rwlock);
+ ipf_interror = 90003;
return EBUSY;
}
@@ -176,61 +184,66 @@ caddr_t data;
if (i->ipsc_next)
i->ipsc_next->ipsc_pnext = i->ipsc_pnext;
else {
- if (i->ipsc_pnext == &ipsc_list)
- ipsc_tail = NULL;
+ if (i->ipsc_pnext == &ipf_scan_list)
+ ipf_scan_tail = NULL;
else
- ipsc_tail = *(*i->ipsc_pnext)->ipsc_pnext;
+ ipf_scan_tail = *(*i->ipsc_pnext)->ipsc_pnext;
}
- ipsc_stat.iscs_entries--;
+ ipf_scan_stat.iscs_entries--;
KFREE(i);
}
- RWLOCK_EXIT(&ipsc_rwlock);
+ RWLOCK_EXIT(&ipf_scan_rwlock);
return err;
}
-struct ipscan *ipsc_lookup(tag)
-char *tag;
+struct ipscan *
+ipf_scan_lookup(tag)
+ char *tag;
{
ipscan_t *i;
- for (i = ipsc_list; i; i = i->ipsc_next)
+ for (i = ipf_scan_list; i; i = i->ipsc_next)
if (!strcmp(i->ipsc_tag, tag))
return i;
return NULL;
}
-int ipsc_attachfr(fr)
-struct frentry *fr;
+int
+ipf_scan_attachfr(fr)
+ struct frentry *fr;
{
ipscan_t *i;
- if (fr->fr_isctag[0]) {
- READ_ENTER(&ipsc_rwlock);
- i = ipsc_lookup(fr->fr_isctag);
+ if (fr->fr_isctag != -1) {
+ READ_ENTER(&ipf_scan_rwlock);
+ i = ipf_scan_lookup(fr->fr_isctag + fr->fr_names);
if (i != NULL) {
ATOMIC_INC32(i->ipsc_fref);
}
- RWLOCK_EXIT(&ipsc_rwlock);
- if (i == NULL)
+ RWLOCK_EXIT(&ipf_scan_rwlock);
+ if (i == NULL) {
+ ipf_interror = 90004;
return ENOENT;
+ }
fr->fr_isc = i;
}
return 0;
}
-int ipsc_attachis(is)
-struct ipstate *is;
+int
+ipf_scan_attachis(is)
+ struct ipstate *is;
{
frentry_t *fr;
ipscan_t *i;
- READ_ENTER(&ipsc_rwlock);
+ READ_ENTER(&ipf_scan_rwlock);
fr = is->is_rule;
- if (fr) {
+ if (fr != NULL) {
i = fr->fr_isc;
if ((i != NULL) && (i != (ipscan_t *)-1)) {
is->is_isc = i;
@@ -245,13 +258,14 @@ struct ipstate *is;
is->is_flags |= IS_SC_MATCHS;
}
}
- RWLOCK_EXIT(&ipsc_rwlock);
+ RWLOCK_EXIT(&ipf_scan_rwlock);
return 0;
}
-int ipsc_detachfr(fr)
-struct frentry *fr;
+int
+ipf_scan_detachfr(fr)
+ struct frentry *fr;
{
ipscan_t *i;
@@ -263,18 +277,19 @@ struct frentry *fr;
}
-int ipsc_detachis(is)
-struct ipstate *is;
+int
+ipf_scan_detachis(is)
+ struct ipstate *is;
{
ipscan_t *i;
- READ_ENTER(&ipsc_rwlock);
+ READ_ENTER(&ipf_scan_rwlock);
if ((i = is->is_isc) && (i != (ipscan_t *)-1)) {
ATOMIC_DEC32(i->ipsc_sref);
is->is_isc = NULL;
is->is_flags &= ~(IS_SC_CLIENT|IS_SC_SERVER);
}
- RWLOCK_EXIT(&ipsc_rwlock);
+ RWLOCK_EXIT(&ipf_scan_rwlock);
return 0;
}
@@ -282,10 +297,11 @@ struct ipstate *is;
/*
* 'string' compare for scanning
*/
-int ipsc_matchstr(sp, str, n)
-sinfo_t *sp;
-char *str;
-int n;
+int
+ipf_scan_matchstr(sp, str, n)
+ sinfo_t *sp;
+ char *str;
+ int n;
{
char *s, *t, *up;
int i = n;
@@ -316,10 +332,11 @@ int n;
* Returns 3 if both server and client match, 2 if just server,
* 1 if just client
*/
-int ipsc_matchisc(isc, is, cl, sl, maxm)
-ipscan_t *isc;
-ipstate_t *is;
-int cl, sl, maxm[2];
+int
+ipf_scan_matchisc(isc, is, cl, sl, maxm)
+ ipscan_t *isc;
+ ipstate_t *is;
+ int cl, sl, maxm[2];
{
int i, j, k, n, ret = 0, flags;
@@ -348,7 +365,8 @@ int cl, sl, maxm[2];
i = 0;
n = MIN(cl, isc->ipsc_clen);
if ((n > 0) && (!maxm || (n >= maxm[1]))) {
- if (!ipsc_matchstr(&isc->ipsc_cl, is->is_sbuf[0], n)) {
+ if (!ipf_scan_matchstr(&isc->ipsc_cl,
+ is->is_sbuf[0], n)) {
i++;
ret |= 1;
if (n > j)
@@ -364,7 +382,8 @@ int cl, sl, maxm[2];
i = 0;
n = MIN(cl, isc->ipsc_slen);
if ((n > 0) && (!maxm || (n >= maxm[1]))) {
- if (!ipsc_matchstr(&isc->ipsc_sl, is->is_sbuf[1], n)) {
+ if (!ipf_scan_matchstr(&isc->ipsc_sl,
+ is->is_sbuf[1], n)) {
i++;
ret |= 2;
if (n > k)
@@ -381,8 +400,9 @@ int cl, sl, maxm[2];
}
-int ipsc_match(is)
-ipstate_t *is;
+int
+ipf_scan_match(is)
+ ipstate_t *is;
{
int i, j, k, n, cl, sl, maxm[2];
ipscan_t *isc, *lm;
@@ -399,7 +419,7 @@ ipstate_t *is;
/*
* Known object to scan for.
*/
- i = ipsc_matchisc(isc, is, cl, sl, NULL);
+ i = ipf_scan_matchisc(isc, is, cl, sl, NULL);
if (i & 1) {
is->is_flags |= IS_SC_MATCHC;
is->is_flags &= ~IS_SC_CLIENT;
@@ -415,8 +435,8 @@ ipstate_t *is;
lm = NULL;
maxm[0] = 0;
maxm[1] = 0;
- for (k = 0, isc = ipsc_list; isc; isc = isc->ipsc_next) {
- i = ipsc_matchisc(isc, is, cl, sl, maxm);
+ for (k = 0, isc = ipf_scan_list; isc; isc = isc->ipsc_next) {
+ i = ipf_scan_matchisc(isc, is, cl, sl, maxm);
if (i) {
/*
* We only want to remember the best match
@@ -475,7 +495,7 @@ ipstate_t *is;
j = ISC_A_NONE;
if ((is->is_flags & IS_SC_MATCHALL) == IS_SC_MATCHALL) {
j = isc->ipsc_action;
- ipsc_stat.iscs_acted++;
+ ipf_scan_stat.iscs_acted++;
} else if ((is->is_isc != NULL) &&
((is->is_flags & IS_SC_MATCHALL) != IS_SC_MATCHALL) &&
!(is->is_flags & (IS_SC_CLIENT|IS_SC_SERVER))) {
@@ -483,7 +503,7 @@ ipstate_t *is;
* Matching failed...
*/
j = isc->ipsc_else;
- ipsc_stat.iscs_else++;
+ ipf_scan_stat.iscs_else++;
}
switch (j)
@@ -508,9 +528,10 @@ ipstate_t *is;
/*
* check if a packet matches what we're scanning for
*/
-int ipsc_packet(fin, is)
-fr_info_t *fin;
-ipstate_t *is;
+int
+ipf_scan_packet(fin, is)
+ fr_info_t *fin;
+ ipstate_t *is;
{
int i, j, rv, dlen, off, thoff;
u_32_t seq, s0;
@@ -552,7 +573,7 @@ ipstate_t *is;
if (j == 0)
return 1;
- (void) ipsc_match(is);
+ (void) ipf_scan_match(is);
#if 0
/*
* There is the potential here for plain text passwords to get
@@ -567,11 +588,12 @@ ipstate_t *is;
}
-int fr_scan_ioctl(data, cmd, mode, uid, ctx)
-caddr_t data;
-ioctlcmd_t cmd;
-int mode, uid;
-void *ctx;
+int
+ipf_scan_ioctl(data, cmd, mode, uid, ctx)
+ caddr_t data;
+ ioctlcmd_t cmd;
+ int mode, uid;
+ void *ctx;
{
ipscanstat_t ipscs;
int err = 0;
@@ -579,17 +601,19 @@ void *ctx;
switch (cmd)
{
case SIOCADSCA :
- err = ipsc_add(data);
+ err = ipf_scan_add(data);
break;
case SIOCRMSCA :
- err = ipsc_delete(data);
+ err = ipf_scan_remove(data);
break;
case SIOCGSCST :
- bcopy((char *)&ipsc_stat, (char *)&ipscs, sizeof(ipscs));
- ipscs.iscs_list = ipsc_list;
+ bcopy((char *)&ipf_scan_stat, (char *)&ipscs, sizeof(ipscs));
+ ipscs.iscs_list = ipf_scan_list;
err = BCOPYOUT(&ipscs, data, sizeof(ipscs));
- if (err != 0)
+ if (err != 0) {
+ ipf_interror = 90005;
err = EFAULT;
+ }
break;
default :
err = EINVAL;
diff --git a/sys/contrib/ipfilter/netinet/ip_scan.h b/sys/contrib/ipfilter/netinet/ip_scan.h
index 4772d28..9903209 100644
--- a/sys/contrib/ipfilter/netinet/ip_scan.h
+++ b/sys/contrib/ipfilter/netinet/ip_scan.h
@@ -1,10 +1,10 @@
/*
- * Copyright (C) 1993-2001 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
* @(#)ip_fil.h 1.35 6/5/96
- * $Id: ip_scan.h,v 2.9.2.2 2006/07/14 06:12:19 darrenr Exp $
+ * $Id$
*/
#ifndef __IP_SCAN_H__
@@ -94,13 +94,13 @@ typedef struct ipscanstat {
} ipscanstat_t;
-extern int fr_scan_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *));
-extern int ipsc_init __P((void));
-extern int ipsc_attachis __P((struct ipstate *));
-extern int ipsc_attachfr __P((struct frentry *));
-extern int ipsc_detachis __P((struct ipstate *));
-extern int ipsc_detachfr __P((struct frentry *));
-extern int ipsc_packet __P((struct fr_info *, struct ipstate *));
-extern void fr_scanunload __P((void));
+extern int ipf_scan_ioctl __P((ipf_main_softc_t *, caddr_t, ioctlcmd_t, int, int, void *));
+extern int ipf_scan_init __P((void));
+extern int ipf_scan_attachis __P((struct ipstate *));
+extern int ipf_scan_attachfr __P((struct frentry *));
+extern int ipf_scan_detachis __P((struct ipstate *));
+extern int ipf_scan_detachfr __P((struct frentry *));
+extern int ipf_scan_packet __P((struct fr_info *, struct ipstate *));
+extern void ipf_scan_unload __P((ipf_main_softc_t *));
#endif /* __IP_SCAN_H__ */
diff --git a/sys/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c
index 6c8b158..9c6a244 100644
--- a/sys/contrib/ipfilter/netinet/ip_state.c
+++ b/sys/contrib/ipfilter/netinet/ip_state.c
@@ -1,9 +1,13 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1995-2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Copyright 2008 Sun Microsystems.
+ *
+ * $Id$
*/
#if defined(KERNEL) || defined(_KERNEL)
# undef KERNEL
@@ -15,14 +19,6 @@
#include <sys/types.h>
#include <sys/param.h>
#include <sys/file.h>
-#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
- defined(_KERNEL)
-# if (__NetBSD_Version__ < 399001400)
-# include "opt_ipfilter_log.h"
-# else
-# include "opt_ipfilter.h"
-# endif
-#endif
#if defined(_KERNEL) && defined(__FreeBSD_version) && \
(__FreeBSD_version >= 400000) && !defined(KLD_MODULE)
#include "opt_inet6.h"
@@ -41,9 +37,6 @@ struct file;
#if defined(_KERNEL) && (__FreeBSD_version >= 220000)
# include <sys/filio.h>
# include <sys/fcntl.h>
-# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM)
-# include "opt_ipfilter.h"
-# endif
#else
# include <sys/ioctl.h>
#endif
@@ -72,36 +65,31 @@ struct file;
#ifdef sun
# include <net/af.h>
#endif
-#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
-#if !defined(linux)
-# include <netinet/ip_var.h>
-#endif
#if !defined(__hpux) && !defined(linux)
# include <netinet/tcp_fsm.h>
#endif
#include <netinet/udp.h>
#include <netinet/ip_icmp.h>
+#if !defined(_KERNEL)
+# include "ipf.h"
+#endif
#include "netinet/ip_compat.h"
-#include <netinet/tcpip.h>
#include "netinet/ip_fil.h"
#include "netinet/ip_nat.h"
#include "netinet/ip_frag.h"
#include "netinet/ip_state.h"
#include "netinet/ip_proxy.h"
-#ifdef IPFILTER_SYNC
+#include "netinet/ip_lookup.h"
+#include "netinet/ip_dstlist.h"
#include "netinet/ip_sync.h"
-#endif
-#ifdef IPFILTER_SCAN
-#include "netinet/ip_scan.h"
-#endif
#ifdef USE_INET6
#include <netinet/icmp6.h>
#endif
-#if (__FreeBSD_version >= 300000)
+#if FREEBSD_GE_REV(300000)
# include <sys/malloc.h>
# if defined(_KERNEL) && !defined(IPFILTER_LKM)
# include <sys/libkern.h>
@@ -113,342 +101,501 @@ struct file;
#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.186.2.80 2007/10/16 09:33:23 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id$";
#endif
-static ipstate_t **ips_table = NULL;
-static u_long *ips_seed = NULL;
-static int ips_num = 0;
-static u_long ips_last_force_flush = 0;
-ips_stat_t ips_stats;
+
+static ipftuneable_t ipf_state_tuneables[] = {
+ { { (void *)offsetof(ipf_state_softc_t, ipf_state_max) },
+ "state_max", 1, 0x7fffffff,
+ stsizeof(ipf_state_softc_t, ipf_state_max),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_state_softc_t, ipf_state_size) },
+ "state_size", 1, 0x7fffffff,
+ stsizeof(ipf_state_softc_t, ipf_state_size),
+ 0, NULL, ipf_state_rehash },
+ { { (void *)offsetof(ipf_state_softc_t, ipf_state_lock) },
+ "state_lock", 0, 1,
+ stsizeof(ipf_state_softc_t, ipf_state_lock),
+ IPFT_RDONLY, NULL, NULL },
+ { { (void *)offsetof(ipf_state_softc_t, ipf_state_maxbucket) },
+ "state_maxbucket", 1, 0x7fffffff,
+ stsizeof(ipf_state_softc_t, ipf_state_maxbucket),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_state_softc_t, ipf_state_logging) },
+ "state_logging",0, 1,
+ stsizeof(ipf_state_softc_t, ipf_state_logging),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_state_softc_t, ipf_state_wm_high) },
+ "state_wm_high",2, 100,
+ stsizeof(ipf_state_softc_t, ipf_state_wm_high),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_state_softc_t, ipf_state_wm_low) },
+ "state_wm_low", 1, 99,
+ stsizeof(ipf_state_softc_t, ipf_state_wm_low),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_state_softc_t, ipf_state_wm_freq) },
+ "state_wm_freq",2, 999999,
+ stsizeof(ipf_state_softc_t, ipf_state_wm_freq),
+ 0, NULL, NULL },
+ { { NULL },
+ NULL, 0, 0,
+ 0,
+ 0, NULL, NULL }
+};
+
+#define SINCL(x) ATOMIC_INCL(softs->x)
+#define SBUMP(x) (softs->x)++
+#define SBUMPD(x, y) do { (softs->x.y)++; DT(y); } while (0)
+#define SBUMPDX(x, y, z)do { (softs->x.y)++; DT(z); } while (0)
#ifdef USE_INET6
-static ipstate_t *fr_checkicmp6matchingstate __P((fr_info_t *));
+static ipstate_t *ipf_checkicmp6matchingstate __P((fr_info_t *));
#endif
-static ipstate_t *fr_matchsrcdst __P((fr_info_t *, ipstate_t *, i6addr_t *,
+static int ipf_allowstateicmp __P((fr_info_t *, ipstate_t *, i6addr_t *));
+static ipstate_t *ipf_matchsrcdst __P((fr_info_t *, ipstate_t *, i6addr_t *,
i6addr_t *, tcphdr_t *, u_32_t));
-static ipstate_t *fr_checkicmpmatchingstate __P((fr_info_t *));
-static int fr_state_flush __P((int, int));
-static int fr_state_flush_entry __P((void *));
-static ips_stat_t *fr_statetstats __P((void));
-static int fr_delstate __P((ipstate_t *, int));
-static int fr_state_remove __P((caddr_t));
-static void fr_ipsmove __P((ipstate_t *, u_int));
-static int fr_tcpstate __P((fr_info_t *, tcphdr_t *, ipstate_t *));
-static int fr_tcpoptions __P((fr_info_t *, tcphdr_t *, tcpdata_t *));
-static ipstate_t *fr_stclone __P((fr_info_t *, tcphdr_t *, ipstate_t *));
-static void fr_fixinisn __P((fr_info_t *, ipstate_t *));
-static void fr_fixoutisn __P((fr_info_t *, ipstate_t *));
-static void fr_checknewisn __P((fr_info_t *, ipstate_t *));
-static int fr_stateiter __P((ipftoken_t *, ipfgeniter_t *));
-static int fr_stgettable __P((char *));
-
-int fr_stputent __P((caddr_t));
-int fr_stgetent __P((caddr_t));
+static ipstate_t *ipf_checkicmpmatchingstate __P((fr_info_t *));
+static int ipf_state_flush_entry __P((ipf_main_softc_t *, void *));
+static ips_stat_t *ipf_state_stats __P((ipf_main_softc_t *));
+static int ipf_state_del __P((ipf_main_softc_t *, ipstate_t *, int));
+static int ipf_state_remove __P((ipf_main_softc_t *, caddr_t));
+static int ipf_state_match __P((ipstate_t *is1, ipstate_t *is2));
+static int ipf_state_matchaddresses __P((ipstate_t *is1, ipstate_t *is2));
+static int ipf_state_matchipv4addrs __P((ipstate_t *is1, ipstate_t *is2));
+static int ipf_state_matchipv6addrs __P((ipstate_t *is1, ipstate_t *is2));
+static int ipf_state_matchisps __P((ipstate_t *is1, ipstate_t *is2));
+static int ipf_state_matchports __P((udpinfo_t *is1, udpinfo_t *is2));
+static int ipf_state_matcharray __P((ipstate_t *, int *, u_long));
+static void ipf_ipsmove __P((ipf_state_softc_t *, ipstate_t *, u_int));
+static int ipf_state_tcp __P((ipf_main_softc_t *, ipf_state_softc_t *,
+ fr_info_t *, tcphdr_t *, ipstate_t *));
+static int ipf_tcpoptions __P((ipf_state_softc_t *, fr_info_t *,
+ tcphdr_t *, tcpdata_t *));
+static ipstate_t *ipf_state_clone __P((fr_info_t *, tcphdr_t *, ipstate_t *));
+static void ipf_fixinisn __P((fr_info_t *, ipstate_t *));
+static void ipf_fixoutisn __P((fr_info_t *, ipstate_t *));
+static void ipf_checknewisn __P((fr_info_t *, ipstate_t *));
+static int ipf_state_iter __P((ipf_main_softc_t *, ipftoken_t *,
+ ipfgeniter_t *, ipfobj_t *));
+static int ipf_state_gettable __P((ipf_main_softc_t *, ipf_state_softc_t *,
+ char *));
+static int ipf_state_tcpinwindow __P((struct fr_info *, struct tcpdata *,
+ struct tcpdata *, tcphdr_t *, int));
+
+static int ipf_state_getent __P((ipf_main_softc_t *, ipf_state_softc_t *,
+ caddr_t));
+static int ipf_state_putent __P((ipf_main_softc_t *, ipf_state_softc_t *,
+ caddr_t));
#define ONE_DAY IPF_TTLVAL(1 * 86400) /* 1 day */
#define FIVE_DAYS (5 * ONE_DAY)
-#define DOUBLE_HASH(x) (((x) + ips_seed[(x) % fr_statesize]) % fr_statesize)
-
-u_long fr_tcpidletimeout = FIVE_DAYS,
- fr_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL),
- fr_tcplastack = IPF_TTLVAL(30),
- fr_tcptimeout = IPF_TTLVAL(2 * TCP_MSL),
- fr_tcptimewait = IPF_TTLVAL(2 * TCP_MSL),
- fr_tcpclosed = IPF_TTLVAL(30),
- fr_tcphalfclosed = IPF_TTLVAL(2 * 3600), /* 2 hours */
- fr_udptimeout = IPF_TTLVAL(120),
- fr_udpacktimeout = IPF_TTLVAL(12),
- fr_icmptimeout = IPF_TTLVAL(60),
- fr_icmpacktimeout = IPF_TTLVAL(6),
- fr_iptimeout = IPF_TTLVAL(60);
-int fr_statemax = IPSTATE_MAX,
- fr_statesize = IPSTATE_SIZE;
-int fr_state_doflush = 0,
- fr_state_lock = 0,
- fr_state_maxbucket = 0,
- fr_state_maxbucket_reset = 1,
- fr_state_init = 0;
-ipftq_t ips_tqtqb[IPF_TCP_NSTATES],
- ips_udptq,
- ips_udpacktq,
- ips_iptq,
- ips_icmptq,
- ips_icmpacktq,
- ips_deletetq,
- *ips_utqe = NULL;
-#ifdef IPFILTER_LOG
-int ipstate_logging = 1;
-#else
-int ipstate_logging = 0;
-#endif
-ipstate_t *ips_list = NULL;
+#define DOUBLE_HASH(x) (((x) + softs->ipf_state_seed[(x) % \
+ softs->ipf_state_size]) % softs->ipf_state_size)
/* ------------------------------------------------------------------------ */
-/* Function: fr_stateinit */
+/* Function: ipf_state_main_load */
/* Returns: int - 0 == success, -1 == failure */
/* Parameters: Nil */
/* */
-/* Initialise all the global variables used within the state code. */
-/* This action also includes initiailising locks. */
+/* A null-op function that exists as a placeholder so that the flow in */
+/* other functions is obvious. */
/* ------------------------------------------------------------------------ */
-int fr_stateinit()
+int
+ipf_state_main_load()
{
-#if defined(NEED_LOCAL_RAND) || !defined(_KERNEL)
- struct timeval tv;
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_state_main_unload */
+/* Returns: int - 0 == success, -1 == failure */
+/* Parameters: Nil */
+/* */
+/* A null-op function that exists as a placeholder so that the flow in */
+/* other functions is obvious. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_state_main_unload()
+{
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_state_soft_create */
+/* Returns: void * - NULL = failure, else pointer to soft context */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Create a new state soft context structure and populate it with the list */
+/* of tunables and other default settings. */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_state_soft_create(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_state_softc_t *softs;
+
+ KMALLOC(softs, ipf_state_softc_t *);
+ if (softs == NULL)
+ return NULL;
+
+ bzero((char *)softs, sizeof(*softs));
+
+ softs->ipf_state_tune = ipf_tune_array_copy(softs,
+ sizeof(ipf_state_tuneables),
+ ipf_state_tuneables);
+ if (softs->ipf_state_tune == NULL) {
+ ipf_state_soft_destroy(softc, softs);
+ return NULL;
+ }
+ if (ipf_tune_array_link(softc, softs->ipf_state_tune) == -1) {
+ ipf_state_soft_destroy(softc, softs);
+ return NULL;
+ }
+
+#ifdef IPFILTER_LOG
+ softs->ipf_state_logging = 1;
+#else
+ softs->ipf_state_logging = 0;
#endif
+ softs->ipf_state_size = IPSTATE_SIZE,
+ softs->ipf_state_maxbucket = 0;
+ softs->ipf_state_wm_freq = IPF_TTLVAL(10);
+ softs->ipf_state_max = IPSTATE_MAX;
+ softs->ipf_state_wm_last = 0;
+ softs->ipf_state_wm_high = 99;
+ softs->ipf_state_wm_low = 90;
+ softs->ipf_state_inited = 0;
+ softs->ipf_state_lock = 0;
+ softs->ipf_state_doflush = 0;
+
+ return softs;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_state_soft_destroy */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* Undo only what we did in soft create: unlink and free the tunables and */
+/* free the soft context structure itself. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_state_soft_destroy(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_state_softc_t *softs = arg;
+
+ if (softs->ipf_state_tune != NULL) {
+ ipf_tune_array_unlink(softc, softs->ipf_state_tune);
+ KFREES(softs->ipf_state_tune, sizeof(ipf_state_tuneables));
+ softs->ipf_state_tune = NULL;
+ }
+
+ KFREE(softs);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_state_soft_init */
+/* Returns: int - 0 == success, -1 == failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
+/* */
+/* Initialise the state soft context structure so it is ready for use. */
+/* This involves: */
+/* - allocating a hash table and zero'ing it out */
+/* - building a secondary table of seeds for double hashing to make it more */
+/* difficult to attempt to attack the hash table itself (for DoS) */
+/* - initialise all of the timeout queues, including a table for TCP, some */
+/* pairs of query/response for UDP and other IP protocols (typically the */
+/* reply queue has a shorter timeout than the query) */
+/* ------------------------------------------------------------------------ */
+int
+ipf_state_soft_init(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_state_softc_t *softs = arg;
int i;
- KMALLOCS(ips_table, ipstate_t **, fr_statesize * sizeof(ipstate_t *));
- if (ips_table == NULL)
+ KMALLOCS(softs->ipf_state_table,
+ ipstate_t **, softs->ipf_state_size * sizeof(ipstate_t *));
+ if (softs->ipf_state_table == NULL)
return -1;
- bzero((char *)ips_table, fr_statesize * sizeof(ipstate_t *));
- KMALLOCS(ips_seed, u_long *, fr_statesize * sizeof(*ips_seed));
- if (ips_seed == NULL)
+ bzero((char *)softs->ipf_state_table,
+ softs->ipf_state_size * sizeof(ipstate_t *));
+
+ KMALLOCS(softs->ipf_state_seed, u_long *,
+ softs->ipf_state_size * sizeof(*softs->ipf_state_seed));
+ if (softs->ipf_state_seed == NULL)
return -2;
-#if defined(NEED_LOCAL_RAND) || !defined(_KERNEL)
- tv.tv_sec = 0;
- GETKTIME(&tv);
-#endif
- for (i = 0; i < fr_statesize; i++) {
+
+ for (i = 0; i < softs->ipf_state_size; i++) {
/*
- * XXX - ips_seed[X] should be a random number of sorts.
+ * XXX - ipf_state_seed[X] should be a random number of sorts.
*/
-#if !defined(NEED_LOCAL_RAND) && defined(_KERNEL)
- ips_seed[i] = arc4random();
+#if FREEBSD_GE_REV(400000)
+ softs->ipf_state_seed[i] = arc4random();
#else
- ips_seed[i] = ((u_long)ips_seed + i) * fr_statesize;
- ips_seed[i] += tv.tv_sec;
- ips_seed[i] *= (u_long)ips_seed;
- ips_seed[i] ^= 0x5a5aa5a5;
- ips_seed[i] *= fr_statemax;
+ softs->ipf_state_seed[i] = ((u_long)softs->ipf_state_seed + i) *
+ softs->ipf_state_size;
+ softs->ipf_state_seed[i] ^= 0xa5a55a5a;
+ softs->ipf_state_seed[i] *= (u_long)softs->ipf_state_seed;
+ softs->ipf_state_seed[i] ^= 0x5a5aa5a5;
+ softs->ipf_state_seed[i] *= softs->ipf_state_max;
#endif
}
-#if defined(NEED_LOCAL_RAND) && defined(_KERNEL)
- ipf_rand_push(ips_seed, fr_statesize * sizeof(*ips_seed));
-#endif
- /* 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;
-#ifdef USE_INET6
- /* fill icmp reply type table */
- for (i = 0; i <= ICMP6_MAXTYPE; i++)
- icmpreplytype6[i] = -1;
- icmpreplytype6[ICMP6_ECHO_REQUEST] = ICMP6_ECHO_REPLY;
- icmpreplytype6[ICMP6_MEMBERSHIP_QUERY] = ICMP6_MEMBERSHIP_REPORT;
- icmpreplytype6[ICMP6_NI_QUERY] = ICMP6_NI_REPLY;
- icmpreplytype6[ND_ROUTER_SOLICIT] = ND_ROUTER_ADVERT;
- icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT;
-#endif
+ KMALLOCS(softs->ipf_state_stats.iss_bucketlen, u_int *,
+ softs->ipf_state_size * sizeof(u_int));
+ if (softs->ipf_state_stats.iss_bucketlen == NULL)
+ return -3;
+
+ bzero((char *)softs->ipf_state_stats.iss_bucketlen,
+ softs->ipf_state_size * sizeof(u_int));
+
+ if (softs->ipf_state_maxbucket == 0) {
+ for (i = softs->ipf_state_size; i > 0; i >>= 1)
+ softs->ipf_state_maxbucket++;
+ softs->ipf_state_maxbucket *= 2;
+ }
+
+ ipf_sttab_init(softc, softs->ipf_state_tcptq);
+ softs->ipf_state_stats.iss_tcptab = softs->ipf_state_tcptq;
+ softs->ipf_state_tcptq[IPF_TCP_NSTATES - 1].ifq_next =
+ &softs->ipf_state_udptq;
+
+ IPFTQ_INIT(&softs->ipf_state_udptq, softc->ipf_udptimeout,
+ "ipftq udp tab");
+ softs->ipf_state_udptq.ifq_next = &softs->ipf_state_udpacktq;
+
+ IPFTQ_INIT(&softs->ipf_state_udpacktq, softc->ipf_udpacktimeout,
+ "ipftq udpack tab");
+ softs->ipf_state_udpacktq.ifq_next = &softs->ipf_state_icmptq;
+
+ IPFTQ_INIT(&softs->ipf_state_icmptq, softc->ipf_icmptimeout,
+ "ipftq icmp tab");
+ softs->ipf_state_icmptq.ifq_next = &softs->ipf_state_icmpacktq;
+
+ IPFTQ_INIT(&softs->ipf_state_icmpacktq, softc->ipf_icmpacktimeout,
+ "ipftq icmpack tab");
+ softs->ipf_state_icmpacktq.ifq_next = &softs->ipf_state_iptq;
+
+ IPFTQ_INIT(&softs->ipf_state_iptq, softc->ipf_iptimeout,
+ "ipftq iptimeout tab");
+ softs->ipf_state_iptq.ifq_next = &softs->ipf_state_pending;
+
+ IPFTQ_INIT(&softs->ipf_state_pending, IPF_HZ_DIVIDE, "ipftq pending");
+ softs->ipf_state_pending.ifq_next = &softs->ipf_state_deletetq;
+
+ IPFTQ_INIT(&softs->ipf_state_deletetq, 1, "ipftq delete");
+ softs->ipf_state_deletetq.ifq_next = NULL;
+
+ MUTEX_INIT(&softs->ipf_stinsert, "ipf state insert mutex");
+
+
+ softs->ipf_state_wm_last = softc->ipf_ticks;
+ softs->ipf_state_inited = 1;
- KMALLOCS(ips_stats.iss_bucketlen, u_long *,
- fr_statesize * sizeof(u_long));
- if (ips_stats.iss_bucketlen == NULL)
- return -1;
- bzero((char *)ips_stats.iss_bucketlen, fr_statesize * sizeof(u_long));
-
- if (fr_state_maxbucket == 0) {
- for (i = fr_statesize; i > 0; i >>= 1)
- fr_state_maxbucket++;
- fr_state_maxbucket *= 2;
- }
-
- ips_stats.iss_tcptab = ips_tqtqb;
- fr_sttab_init(ips_tqtqb);
- ips_tqtqb[IPF_TCP_NSTATES - 1].ifq_next = &ips_udptq;
- ips_udptq.ifq_ttl = (u_long)fr_udptimeout;
- ips_udptq.ifq_ref = 1;
- ips_udptq.ifq_head = NULL;
- ips_udptq.ifq_tail = &ips_udptq.ifq_head;
- MUTEX_INIT(&ips_udptq.ifq_lock, "ipftq udp tab");
- ips_udptq.ifq_next = &ips_udpacktq;
- ips_udpacktq.ifq_ttl = (u_long)fr_udpacktimeout;
- ips_udpacktq.ifq_ref = 1;
- ips_udpacktq.ifq_head = NULL;
- ips_udpacktq.ifq_tail = &ips_udpacktq.ifq_head;
- MUTEX_INIT(&ips_udpacktq.ifq_lock, "ipftq udpack tab");
- ips_udpacktq.ifq_next = &ips_icmptq;
- ips_icmptq.ifq_ttl = (u_long)fr_icmptimeout;
- ips_icmptq.ifq_ref = 1;
- ips_icmptq.ifq_head = NULL;
- ips_icmptq.ifq_tail = &ips_icmptq.ifq_head;
- MUTEX_INIT(&ips_icmptq.ifq_lock, "ipftq icmp tab");
- ips_icmptq.ifq_next = &ips_icmpacktq;
- ips_icmpacktq.ifq_ttl = (u_long)fr_icmpacktimeout;
- ips_icmpacktq.ifq_ref = 1;
- ips_icmpacktq.ifq_head = NULL;
- ips_icmpacktq.ifq_tail = &ips_icmpacktq.ifq_head;
- MUTEX_INIT(&ips_icmpacktq.ifq_lock, "ipftq icmpack tab");
- ips_icmpacktq.ifq_next = &ips_iptq;
- ips_iptq.ifq_ttl = (u_long)fr_iptimeout;
- ips_iptq.ifq_ref = 1;
- ips_iptq.ifq_head = NULL;
- ips_iptq.ifq_tail = &ips_iptq.ifq_head;
- MUTEX_INIT(&ips_iptq.ifq_lock, "ipftq ip tab");
- ips_iptq.ifq_next = &ips_deletetq;
- ips_deletetq.ifq_ttl = (u_long)1;
- ips_deletetq.ifq_ref = 1;
- ips_deletetq.ifq_head = NULL;
- ips_deletetq.ifq_tail = &ips_deletetq.ifq_head;
- MUTEX_INIT(&ips_deletetq.ifq_lock, "state delete queue");
- ips_deletetq.ifq_next = NULL;
-
- RWLOCK_INIT(&ipf_state, "ipf IP state rwlock");
- MUTEX_INIT(&ipf_stinsert, "ipf state insert mutex");
- fr_state_init = 1;
-
- ips_last_force_flush = fr_ticks;
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_stateunload */
-/* Returns: Nil */
-/* Parameters: Nil */
+/* Function: ipf_state_soft_fini */
+/* Returns: int - 0 = success, -1 = failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* arg(I) - pointer to local context to use */
/* */
/* Release and destroy any resources acquired or initialised so that */
/* IPFilter can be unloaded or re-initialised. */
/* ------------------------------------------------------------------------ */
-void fr_stateunload()
+int
+ipf_state_soft_fini(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
{
+ ipf_state_softc_t *softs = arg;
ipftq_t *ifq, *ifqnext;
ipstate_t *is;
- while ((is = ips_list) != NULL)
- fr_delstate(is, ISL_UNLOAD);
+ while ((is = softs->ipf_state_list) != NULL)
+ ipf_state_del(softc, is, ISL_UNLOAD);
/*
* Proxy timeout queues are not cleaned here because although they
- * exist on the state list, appr_unload is called after fr_stateunload
- * and the proxies actually are responsible for them being created.
- * Should the proxy timeouts have their own list? There's no real
- * justification as this is the only complicationA
+ * exist on the state list, appr_unload is called after
+ * ipf_state_unload and the proxies actually are responsible for them
+ * being created. Should the proxy timeouts have their own list?
+ * There's no real justification as this is the only complication.
*/
- for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) {
+ for (ifq = softs->ipf_state_usertq; ifq != NULL; ifq = ifqnext) {
ifqnext = ifq->ifq_next;
- if (((ifq->ifq_flags & IFQF_PROXY) == 0) &&
- (fr_deletetimeoutqueue(ifq) == 0))
- fr_freetimeoutqueue(ifq);
- }
- ips_stats.iss_inuse = 0;
- ips_num = 0;
+ if (ipf_deletetimeoutqueue(ifq) == 0)
+ ipf_freetimeoutqueue(softc, ifq);
+ }
- if (fr_state_init == 1) {
- fr_sttab_destroy(ips_tqtqb);
- MUTEX_DESTROY(&ips_udptq.ifq_lock);
- MUTEX_DESTROY(&ips_icmptq.ifq_lock);
- MUTEX_DESTROY(&ips_udpacktq.ifq_lock);
- MUTEX_DESTROY(&ips_icmpacktq.ifq_lock);
- MUTEX_DESTROY(&ips_iptq.ifq_lock);
- MUTEX_DESTROY(&ips_deletetq.ifq_lock);
+ softs->ipf_state_stats.iss_inuse = 0;
+ softs->ipf_state_stats.iss_active = 0;
+
+ if (softs->ipf_state_inited == 1) {
+ softs->ipf_state_inited = 0;
+ ipf_sttab_destroy(softs->ipf_state_tcptq);
+ MUTEX_DESTROY(&softs->ipf_state_udptq.ifq_lock);
+ MUTEX_DESTROY(&softs->ipf_state_icmptq.ifq_lock);
+ MUTEX_DESTROY(&softs->ipf_state_udpacktq.ifq_lock);
+ MUTEX_DESTROY(&softs->ipf_state_icmpacktq.ifq_lock);
+ MUTEX_DESTROY(&softs->ipf_state_iptq.ifq_lock);
+ MUTEX_DESTROY(&softs->ipf_state_deletetq.ifq_lock);
+ MUTEX_DESTROY(&softs->ipf_state_pending.ifq_lock);
+ MUTEX_DESTROY(&softs->ipf_stinsert);
}
- if (ips_table != NULL) {
- KFREES(ips_table, fr_statesize * sizeof(*ips_table));
- ips_table = NULL;
+ if (softs->ipf_state_table != NULL) {
+ KFREES(softs->ipf_state_table,
+ softs->ipf_state_size * sizeof(*softs->ipf_state_table));
+ softs->ipf_state_table = NULL;
}
- if (ips_seed != NULL) {
- KFREES(ips_seed, fr_statesize * sizeof(*ips_seed));
- ips_seed = NULL;
+ if (softs->ipf_state_seed != NULL) {
+ KFREES(softs->ipf_state_seed,
+ softs->ipf_state_size * sizeof(*softs->ipf_state_seed));
+ softs->ipf_state_seed = NULL;
}
- if (ips_stats.iss_bucketlen != NULL) {
- KFREES(ips_stats.iss_bucketlen, fr_statesize * sizeof(u_long));
- ips_stats.iss_bucketlen = NULL;
+ if (softs->ipf_state_stats.iss_bucketlen != NULL) {
+ KFREES(softs->ipf_state_stats.iss_bucketlen,
+ softs->ipf_state_size * sizeof(u_int));
+ softs->ipf_state_stats.iss_bucketlen = NULL;
}
- if (fr_state_maxbucket_reset == 1)
- fr_state_maxbucket = 0;
+ return 0;
+}
- if (fr_state_init == 1) {
- fr_state_init = 0;
- RW_DESTROY(&ipf_state);
- MUTEX_DESTROY(&ipf_stinsert);
- }
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_state_set_lock */
+/* Returns: Nil */
+/* Parameters: arg(I) - pointer to local context to use */
+/* tmp(I) - new value for lock */
+/* */
+/* Stub function that allows for external manipulation of ipf_state_lock */
+/* ------------------------------------------------------------------------ */
+void
+ipf_state_setlock(arg, tmp)
+ void *arg;
+ int tmp;
+{
+ ipf_state_softc_t *softs = arg;
+
+ softs->ipf_state_lock = tmp;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_statetstats */
+/* Function: ipf_state_stats */
/* Returns: ips_state_t* - pointer to state stats structure */
-/* Parameters: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
/* */
/* Put all the current numbers and pointers into a single struct and return */
/* a pointer to it. */
/* ------------------------------------------------------------------------ */
-static ips_stat_t *fr_statetstats()
+static ips_stat_t *
+ipf_state_stats(softc)
+ ipf_main_softc_t *softc;
{
- ips_stats.iss_active = ips_num;
- ips_stats.iss_statesize = fr_statesize;
- ips_stats.iss_statemax = fr_statemax;
- ips_stats.iss_table = ips_table;
- ips_stats.iss_list = ips_list;
- ips_stats.iss_ticks = fr_ticks;
- return &ips_stats;
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
+ ips_stat_t *issp = &softs->ipf_state_stats;
+
+ issp->iss_state_size = softs->ipf_state_size;
+ issp->iss_state_max = softs->ipf_state_max;
+ issp->iss_table = softs->ipf_state_table;
+ issp->iss_list = softs->ipf_state_list;
+ issp->iss_ticks = softc->ipf_ticks;
+
+#ifdef IPFILTER_LOGGING
+ issp->iss_log_ok = ipf_log_logok(softc, IPF_LOGSTATE);
+ issp->iss_log_fail = ipf_log_failures(softc, IPF_LOGSTATE);
+#else
+ issp->iss_log_ok = 0;
+ issp->iss_log_fail = 0;
+#endif
+ return issp;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_state_remove */
+/* Function: ipf_state_remove */
/* Returns: int - 0 == success, != 0 == failure */
-/* Parameters: data(I) - pointer to state structure to delete from table */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* data(I) - pointer to state structure to delete from table */
/* */
/* Search for a state structure that matches the one passed, according to */
/* the IP addresses and other protocol specific information. */
/* ------------------------------------------------------------------------ */
-static int fr_state_remove(data)
-caddr_t data;
+static int
+ipf_state_remove(softc, data)
+ ipf_main_softc_t *softc;
+ caddr_t data;
{
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
ipstate_t *sp, st;
int error;
sp = &st;
- error = fr_inobj(data, &st, IPFOBJ_IPSTATE);
+ error = ipf_inobj(softc, data, NULL, &st, IPFOBJ_IPSTATE);
if (error)
return EFAULT;
- WRITE_ENTER(&ipf_state);
- for (sp = ips_list; sp; sp = sp->is_next)
+ WRITE_ENTER(&softc->ipf_state);
+ for (sp = softs->ipf_state_list; sp; sp = sp->is_next)
if ((sp->is_p == st.is_p) && (sp->is_v == st.is_v) &&
!bcmp((caddr_t)&sp->is_src, (caddr_t)&st.is_src,
sizeof(st.is_src)) &&
- !bcmp((caddr_t)&sp->is_dst, (caddr_t)&st.is_src,
+ !bcmp((caddr_t)&sp->is_dst, (caddr_t)&st.is_dst,
sizeof(st.is_dst)) &&
!bcmp((caddr_t)&sp->is_ps, (caddr_t)&st.is_ps,
sizeof(st.is_ps))) {
- fr_delstate(sp, ISL_REMOVE);
- RWLOCK_EXIT(&ipf_state);
+ ipf_state_del(softc, sp, ISL_REMOVE);
+ RWLOCK_EXIT(&softc->ipf_state);
return 0;
}
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
+
+ IPFERROR(100001);
return ESRCH;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_state_ioctl */
+/* Function: ipf_state_ioctl */
/* Returns: int - 0 == success, != 0 == failure */
-/* Parameters: data(I) - pointer to ioctl data */
-/* cmd(I) - ioctl command integer */
-/* mode(I) - file mode bits used with open */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* data(I) - pointer to ioctl data */
+/* cmd(I) - ioctl command integer */
+/* mode(I) - file mode bits used with open */
+/* uid(I) - uid of process making the ioctl call */
+/* ctx(I) - pointer specific to context of the call */
/* */
/* Processes an ioctl call made to operate on the IP Filter state device. */
/* ------------------------------------------------------------------------ */
-int fr_state_ioctl(data, cmd, mode, uid, ctx)
-caddr_t data;
-ioctlcmd_t cmd;
-int mode, uid;
-void *ctx;
+int
+ipf_state_ioctl(softc, data, cmd, mode, uid, ctx)
+ ipf_main_softc_t *softc;
+ caddr_t data;
+ ioctlcmd_t cmd;
+ int mode, uid;
+ void *ctx;
{
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
int arg, ret, error = 0;
SPL_INT(s);
@@ -458,55 +605,75 @@ void *ctx;
* Delete an entry from the state table.
*/
case SIOCDELST :
- error = fr_state_remove(data);
+ error = ipf_state_remove(softc, data);
break;
/*
* Flush the state table
*/
case SIOCIPFFL :
- error = BCOPYIN(data, (char *)&arg, sizeof(arg));
+ error = BCOPYIN(data, &arg, sizeof(arg));
if (error != 0) {
+ IPFERROR(100002);
error = EFAULT;
+
} else {
- WRITE_ENTER(&ipf_state);
- ret = fr_state_flush(arg, 4);
- RWLOCK_EXIT(&ipf_state);
- error = BCOPYOUT((char *)&ret, data, sizeof(ret));
- if (error != 0)
+ WRITE_ENTER(&softc->ipf_state);
+ ret = ipf_state_flush(softc, arg, 4);
+ RWLOCK_EXIT(&softc->ipf_state);
+
+ error = BCOPYOUT(&ret, data, sizeof(ret));
+ if (error != 0) {
+ IPFERROR(100003);
error = EFAULT;
+ }
}
break;
#ifdef USE_INET6
case SIOCIPFL6 :
- error = BCOPYIN(data, (char *)&arg, sizeof(arg));
+ error = BCOPYIN(data, &arg, sizeof(arg));
if (error != 0) {
+ IPFERROR(100004);
error = EFAULT;
+
} else {
- WRITE_ENTER(&ipf_state);
- ret = fr_state_flush(arg, 6);
- RWLOCK_EXIT(&ipf_state);
- error = BCOPYOUT((char *)&ret, data, sizeof(ret));
- if (error != 0)
+ WRITE_ENTER(&softc->ipf_state);
+ ret = ipf_state_flush(softc, arg, 6);
+ RWLOCK_EXIT(&softc->ipf_state);
+
+ error = BCOPYOUT(&ret, data, sizeof(ret));
+ if (error != 0) {
+ IPFERROR(100005);
error = EFAULT;
+ }
}
break;
#endif
+
+ case SIOCMATCHFLUSH :
+ WRITE_ENTER(&softc->ipf_state);
+ error = ipf_state_matchflush(softc, data);
+ RWLOCK_EXIT(&softc->ipf_state);
+ break;
+
#ifdef IPFILTER_LOG
/*
* Flush the state log.
*/
case SIOCIPFFB :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(100008);
error = EPERM;
- else {
+ } else {
int tmp;
- tmp = ipflog_clear(IPL_LOGSTATE);
- error = BCOPYOUT((char *)&tmp, data, sizeof(tmp));
- if (error != 0)
+ tmp = ipf_log_clear(softc, IPL_LOGSTATE);
+ error = BCOPYOUT(&tmp, data, sizeof(tmp));
+ if (error != 0) {
+ IPFERROR(100009);
error = EFAULT;
+ }
}
break;
@@ -514,13 +681,16 @@ void *ctx;
* Turn logging of state information on/off.
*/
case SIOCSETLG :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(100010);
error = EPERM;
- else {
- error = BCOPYIN((char *)data, (char *)&ipstate_logging,
- sizeof(ipstate_logging));
- if (error != 0)
+ } else {
+ error = BCOPYIN(data, &softs->ipf_state_logging,
+ sizeof(softs->ipf_state_logging));
+ if (error != 0) {
+ IPFERROR(100011);
error = EFAULT;
+ }
}
break;
@@ -528,20 +698,24 @@ void *ctx;
* Return the current state of logging.
*/
case SIOCGETLG :
- error = BCOPYOUT((char *)&ipstate_logging, (char *)data,
- sizeof(ipstate_logging));
- if (error != 0)
+ error = BCOPYOUT(&softs->ipf_state_logging, data,
+ sizeof(softs->ipf_state_logging));
+ if (error != 0) {
+ IPFERROR(100012);
error = EFAULT;
+ }
break;
/*
* Return the number of bytes currently waiting to be read.
*/
case FIONREAD :
- arg = iplused[IPL_LOGSTATE]; /* returned in an int */
- error = BCOPYOUT((char *)&arg, data, sizeof(arg));
- if (error != 0)
+ arg = ipf_log_bytesused(softc, IPL_LOGSTATE);
+ error = BCOPYOUT(&arg, data, sizeof(arg));
+ if (error != 0) {
+ IPFERROR(100013);
error = EFAULT;
+ }
break;
#endif
@@ -549,7 +723,8 @@ void *ctx;
* Get the current state statistics.
*/
case SIOCGETFS :
- error = fr_outobj(data, fr_statetstats(), IPFOBJ_STATESTAT);
+ error = ipf_outobj(softc, data, ipf_state_stats(softc),
+ IPFOBJ_STATESTAT);
break;
/*
@@ -558,9 +733,10 @@ void *ctx;
*/
case SIOCSTLCK :
if (!(mode & FWRITE)) {
+ IPFERROR(100014);
error = EPERM;
} else {
- error = fr_lock(data, &fr_state_lock);
+ error = ipf_lock(data, &softs->ipf_state_lock);
}
break;
@@ -568,74 +744,86 @@ void *ctx;
* Add an entry to the current state table.
*/
case SIOCSTPUT :
- if (!fr_state_lock || !(mode &FWRITE)) {
+ if (!softs->ipf_state_lock || !(mode &FWRITE)) {
+ IPFERROR(100015);
error = EACCES;
break;
}
- error = fr_stputent(data);
+ error = ipf_state_putent(softc, softs, data);
break;
/*
* Get a state table entry.
*/
case SIOCSTGET :
- if (!fr_state_lock) {
+ if (!softs->ipf_state_lock) {
+ IPFERROR(100016);
error = EACCES;
break;
}
- error = fr_stgetent(data);
+ error = ipf_state_getent(softc, softs, data);
break;
/*
* Return a copy of the hash table bucket lengths
*/
case SIOCSTAT1 :
- error = BCOPYOUT(ips_stats.iss_bucketlen, data,
- fr_statesize * sizeof(u_long));
- if (error != 0)
+ error = BCOPYOUT(softs->ipf_state_stats.iss_bucketlen, data,
+ softs->ipf_state_size * sizeof(u_int));
+ if (error != 0) {
+ IPFERROR(100017);
error = EFAULT;
+ }
break;
case SIOCGENITER :
{
ipftoken_t *token;
ipfgeniter_t iter;
+ ipfobj_t obj;
- error = fr_inobj(data, &iter, IPFOBJ_GENITER);
+ error = ipf_inobj(softc, data, &obj, &iter, IPFOBJ_GENITER);
if (error != 0)
break;
SPL_SCHED(s);
- token = ipf_findtoken(IPFGENITER_STATE, uid, ctx);
- if (token != NULL)
- error = fr_stateiter(token, &iter);
- else
+ token = ipf_token_find(softc, IPFGENITER_STATE, uid, ctx);
+ if (token != NULL) {
+ error = ipf_state_iter(softc, token, &iter, &obj);
+ WRITE_ENTER(&softc->ipf_tokens);
+ ipf_token_deref(softc, token);
+ RWLOCK_EXIT(&softc->ipf_tokens);
+ } else {
+ IPFERROR(100018);
error = ESRCH;
- RWLOCK_EXIT(&ipf_tokens);
+ }
SPL_X(s);
break;
}
case SIOCGTABL :
- error = fr_stgettable(data);
+ error = ipf_state_gettable(softc, softs, data);
break;
case SIOCIPFDELTOK :
- error = BCOPYIN(data, (char *)&arg, sizeof(arg));
+ error = BCOPYIN(data, &arg, sizeof(arg));
if (error != 0) {
+ IPFERROR(100019);
error = EFAULT;
} else {
SPL_SCHED(s);
- error = ipf_deltoken(arg, uid, ctx);
+ error = ipf_token_del(softc, arg, uid, ctx);
SPL_X(s);
}
break;
case SIOCGTQTAB :
- error = fr_outobj(data, ips_tqtqb, IPFOBJ_STATETQTAB);
+ error = ipf_outobj(softc, data, softs->ipf_state_tcptq,
+ IPFOBJ_STATETQTAB);
break;
default :
+ IPFERROR(100020);
error = EINVAL;
break;
}
@@ -644,9 +832,11 @@ void *ctx;
/* ------------------------------------------------------------------------ */
-/* Function: fr_stgetent */
+/* Function: ipf_state_getent */
/* Returns: int - 0 == success, != 0 == failure */
-/* Parameters: data(I) - pointer to state structure to retrieve from table */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softs(I) - pointer to state context structure */
+/* data(I) - pointer to state structure to retrieve from table*/
/* */
/* Copy out state information from the kernel to a user space process. If */
/* there is a filter rule associated with the state entry, copy that out */
@@ -654,25 +844,30 @@ void *ctx;
/* the struct passed in and if not null and not found in the list of current*/
/* state entries, the retrieval fails. */
/* ------------------------------------------------------------------------ */
-int fr_stgetent(data)
-caddr_t data;
+static int
+ipf_state_getent(softc, softs, data)
+ ipf_main_softc_t *softc;
+ ipf_state_softc_t *softs;
+ caddr_t data;
{
ipstate_t *is, *isn;
ipstate_save_t ips;
int error;
- error = fr_inobj(data, &ips, IPFOBJ_STATESAVE);
- if (error != 0)
- return error;
+ error = ipf_inobj(softc, data, NULL, &ips, IPFOBJ_STATESAVE);
+ if (error)
+ return EFAULT;
- READ_ENTER(&ipf_state);
+ READ_ENTER(&softc->ipf_state);
isn = ips.ips_next;
if (isn == NULL) {
- isn = ips_list;
+ isn = softs->ipf_state_list;
if (isn == NULL) {
- RWLOCK_EXIT(&ipf_state);
- if (ips.ips_next == NULL)
+ if (ips.ips_next == NULL) {
+ RWLOCK_EXIT(&softc->ipf_state);
+ IPFERROR(100021);
return ENOENT;
+ }
return 0;
}
} else {
@@ -681,11 +876,12 @@ caddr_t data;
* current list of entries. Security precaution to prevent
* copying of random kernel data.
*/
- for (is = ips_list; is; is = is->is_next)
+ for (is = softs->ipf_state_list; is; is = is->is_next)
if (is == isn)
break;
- if (is == NULL) {
- RWLOCK_EXIT(&ipf_state);
+ if (!is) {
+ RWLOCK_EXIT(&softc->ipf_state);
+ IPFERROR(100022);
return ESRCH;
}
}
@@ -695,24 +891,29 @@ caddr_t data;
if (isn->is_rule != NULL)
bcopy((char *)isn->is_rule, (char *)&ips.ips_fr,
sizeof(ips.ips_fr));
- RWLOCK_EXIT(&ipf_state);
- error = fr_outobj(data, &ips, IPFOBJ_STATESAVE);
+ RWLOCK_EXIT(&softc->ipf_state);
+ error = ipf_outobj(softc, data, &ips, IPFOBJ_STATESAVE);
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_stputent */
+/* Function: ipf_state_putent */
/* Returns: int - 0 == success, != 0 == failure */
-/* Parameters: data(I) - pointer to state information struct */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softs(I) - pointer to state context structure */
+/* data(I) - pointer to state information struct */
/* */
/* This function implements the SIOCSTPUT ioctl: insert a state entry into */
/* the state table. If the state info. includes a pointer to a filter rule */
/* then also add in an orphaned rule (will not show up in any "ipfstat -io" */
/* output. */
/* ------------------------------------------------------------------------ */
-int fr_stputent(data)
-caddr_t data;
+int
+ipf_state_putent(softc, softs, data)
+ ipf_main_softc_t *softc;
+ ipf_state_softc_t *softs;
+ caddr_t data;
{
ipstate_t *is, *isn;
ipstate_save_t ips;
@@ -720,13 +921,15 @@ caddr_t data;
frentry_t *fr;
char *name;
- error = fr_inobj(data, &ips, IPFOBJ_STATESAVE);
- if (error)
- return EFAULT;
+ error = ipf_inobj(softc, data, NULL, &ips, IPFOBJ_STATESAVE);
+ if (error != 0)
+ return error;
KMALLOC(isn, ipstate_t *);
- if (isn == NULL)
+ if (isn == NULL) {
+ IPFERROR(100023);
return ENOMEM;
+ }
bcopy((char *)&ips.ips_is, (char *)isn, sizeof(*isn));
bzero((char *)isn, offsetof(struct ipstate, is_pkts));
@@ -742,17 +945,21 @@ caddr_t data;
fr = ips.ips_rule;
if (fr == NULL) {
- READ_ENTER(&ipf_state);
- fr_stinsert(isn, 0);
+ int inserr;
+
+ READ_ENTER(&softc->ipf_state);
+ inserr = ipf_state_insert(softc, isn, 0);
MUTEX_EXIT(&isn->is_lock);
- RWLOCK_EXIT(&ipf_state);
- return 0;
+ RWLOCK_EXIT(&softc->ipf_state);
+
+ return inserr;
}
if (isn->is_flags & SI_NEWFR) {
KMALLOC(fr, frentry_t *);
if (fr == NULL) {
KFREE(isn);
+ IPFERROR(100024);
return ENOMEM;
}
bcopy((char *)&ips.ips_fr, (char *)fr, sizeof(*fr));
@@ -766,10 +973,19 @@ caddr_t data;
* Look up all the interface names in the rule.
*/
for (i = 0; i < 4; i++) {
- name = fr->fr_ifnames[i];
- fr->fr_ifas[i] = fr_resolvenic(name, fr->fr_v);
+ if (fr->fr_ifnames[i] == -1) {
+ fr->fr_ifas[i] = NULL;
+ continue;
+ }
+ name = fr->fr_names + fr->fr_ifnames[i];
+ fr->fr_ifas[i] = ipf_resolvenic(softc, name,
+ fr->fr_family);
+ }
+
+ for (i = 0; i < 4; i++) {
name = isn->is_ifname[i];
- isn->is_ifp[i] = fr_resolvenic(name, isn->is_v);
+ isn->is_ifp[i] = ipf_resolvenic(softc, name,
+ isn->is_v);
}
fr->fr_ref = 0;
@@ -777,31 +993,35 @@ caddr_t data;
fr->fr_data = NULL;
fr->fr_type = FR_T_NONE;
- fr_resolvedest(&fr->fr_tifs[0], fr->fr_v);
- fr_resolvedest(&fr->fr_tifs[1], fr->fr_v);
- fr_resolvedest(&fr->fr_dif, fr->fr_v);
+ (void) ipf_resolvedest(softc, fr->fr_names, &fr->fr_tifs[0],
+ fr->fr_family);
+ (void) ipf_resolvedest(softc, fr->fr_names, &fr->fr_tifs[1],
+ fr->fr_family);
+ (void) ipf_resolvedest(softc, fr->fr_names, &fr->fr_dif,
+ fr->fr_family);
/*
* send a copy back to userland of what we ended up
* to allow for verification.
*/
- error = fr_outobj(data, &ips, IPFOBJ_STATESAVE);
- if (error) {
+ error = ipf_outobj(softc, data, &ips, IPFOBJ_STATESAVE);
+ if (error != 0) {
KFREE(isn);
MUTEX_DESTROY(&fr->fr_lock);
KFREE(fr);
+ IPFERROR(100025);
return EFAULT;
}
- READ_ENTER(&ipf_state);
- fr_stinsert(isn, 0);
+ READ_ENTER(&softc->ipf_state);
+ error = ipf_state_insert(softc, isn, 0);
MUTEX_EXIT(&isn->is_lock);
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
} else {
- READ_ENTER(&ipf_state);
- for (is = ips_list; is; is = is->is_next)
+ READ_ENTER(&softc->ipf_state);
+ for (is = softs->ipf_state_list; is; is = is->is_next)
if (is->is_rule == fr) {
- fr_stinsert(isn, 0);
+ error = ipf_state_insert(softc, isn, 0);
MUTEX_EXIT(&isn->is_lock);
break;
}
@@ -810,60 +1030,62 @@ caddr_t data;
KFREE(isn);
isn = NULL;
}
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
- return (isn == NULL) ? ESRCH : 0;
+ if (isn == NULL) {
+ IPFERROR(100033);
+ error = ESRCH;
+ }
}
- return 0;
+ return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_stinsert */
-/* Returns: Nil */
-/* Parameters: is(I) - pointer to state structure */
-/* rev(I) - flag indicating forward/reverse direction of packet */
+/* Function: ipf_state_insert */
+/* Returns: int - 0 == success, -1 == failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* Parameters: is(I) - pointer to state structure */
+/* rev(I) - flag indicating direction of packet */
/* */
/* Inserts a state structure into the hash table (for lookups) and the list */
/* of state entries (for enumeration). Resolves all of the interface names */
/* to pointers and adjusts running stats for the hash table as appropriate. */
/* */
+/* This function can fail if the filter rule has had a population policy of */
+/* IP addresses used with stateful filteirng assigned to it. */
+/* */
/* Locking: it is assumed that some kind of lock on ipf_state is held. */
-/* Exits with is_lock initialised and held. */
+/* Exits with is_lock initialised and held - *EVEN IF ERROR*. */
/* ------------------------------------------------------------------------ */
-void fr_stinsert(is, rev)
-ipstate_t *is;
-int rev;
+int
+ipf_state_insert(softc, is, rev)
+ ipf_main_softc_t *softc;
+ ipstate_t *is;
+ int rev;
{
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
frentry_t *fr;
u_int hv;
int i;
- MUTEX_INIT(&is->is_lock, "ipf state entry");
-
- fr = is->is_rule;
- if (fr != NULL) {
- MUTEX_ENTER(&fr->fr_lock);
- fr->fr_ref++;
- fr->fr_statecnt++;
- MUTEX_EXIT(&fr->fr_lock);
- }
-
/*
* Look up all the interface names in the state entry.
*/
for (i = 0; i < 4; i++) {
if (is->is_ifp[i] != NULL)
continue;
- is->is_ifp[i] = fr_resolvenic(is->is_ifname[i], is->is_v);
+ is->is_ifp[i] = ipf_resolvenic(softc, is->is_ifname[i],
+ is->is_v);
}
/*
- * If we could trust is_hv, then the modulous would not be needed, but
- * when running with IPFILTER_SYNC, this stops bad values.
+ * If we could trust is_hv, then the modulous would not be needed,
+ * but when running with IPFILTER_SYNC, this stops bad values.
*/
- hv = is->is_hv % fr_statesize;
+ hv = is->is_hv % softs->ipf_state_size;
+ /* TRACE is, hv */
is->is_hv = hv;
/*
@@ -871,37 +1093,265 @@ int rev;
* possible that once the insert is complete another packet might
* come along, match the entry and want to update it.
*/
+ MUTEX_INIT(&is->is_lock, "ipf state entry");
MUTEX_ENTER(&is->is_lock);
- MUTEX_ENTER(&ipf_stinsert);
+ MUTEX_ENTER(&softs->ipf_stinsert);
+
+ fr = is->is_rule;
+ if (fr != NULL) {
+ if ((fr->fr_srctrack.ht_max_nodes != 0) &&
+ (ipf_ht_node_add(softc, &fr->fr_srctrack,
+ is->is_family, &is->is_src) == -1)) {
+ SBUMPD(ipf_state_stats, iss_max_track);
+ MUTEX_EXIT(&softs->ipf_stinsert);
+ return -1;
+ }
+
+ MUTEX_ENTER(&fr->fr_lock);
+ fr->fr_ref++;
+ MUTEX_EXIT(&fr->fr_lock);
+ fr->fr_statecnt++;
+ }
+
+ if (is->is_flags & (SI_WILDP|SI_WILDA)) {
+ DT(iss_wild_plus_one);
+ SINCL(ipf_state_stats.iss_wild);
+ }
+
+ SBUMP(ipf_state_stats.iss_proto[is->is_p]);
+ SBUMP(ipf_state_stats.iss_active_proto[is->is_p]);
/*
* add into list table.
*/
- if (ips_list != NULL)
- ips_list->is_pnext = &is->is_next;
- is->is_pnext = &ips_list;
- is->is_next = ips_list;
- ips_list = is;
-
- if (ips_table[hv] != NULL)
- ips_table[hv]->is_phnext = &is->is_hnext;
+ if (softs->ipf_state_list != NULL)
+ softs->ipf_state_list->is_pnext = &is->is_next;
+ is->is_pnext = &softs->ipf_state_list;
+ is->is_next = softs->ipf_state_list;
+ softs->ipf_state_list = is;
+
+ if (softs->ipf_state_table[hv] != NULL)
+ softs->ipf_state_table[hv]->is_phnext = &is->is_hnext;
+ else
+ softs->ipf_state_stats.iss_inuse++;
+ is->is_phnext = softs->ipf_state_table + hv;
+ is->is_hnext = softs->ipf_state_table[hv];
+ softs->ipf_state_table[hv] = is;
+ softs->ipf_state_stats.iss_bucketlen[hv]++;
+ softs->ipf_state_stats.iss_active++;
+ MUTEX_EXIT(&softs->ipf_stinsert);
+
+ ipf_state_setqueue(softc, is, rev);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_state_matchipv4addrs */
+/* Returns: int - 2 addresses match (strong match), 1 reverse match, */
+/* 0 no match */
+/* Parameters: is1, is2 pointers to states we are checking */
+/* */
+/* Function matches IPv4 addresses it returns strong match for ICMP proto */
+/* even there is only reverse match */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_state_matchipv4addrs(is1, is2)
+ ipstate_t *is1, *is2;
+{
+ int rv;
+
+ if (is1->is_saddr == is2->is_saddr && is1->is_daddr == is2->is_daddr)
+ rv = 2;
+ else if (is1->is_saddr == is2->is_daddr &&
+ is1->is_daddr == is2->is_saddr) {
+ /* force strong match for ICMP protocol */
+ rv = (is1->is_p == IPPROTO_ICMP) ? 2 : 1;
+ }
else
- ips_stats.iss_inuse++;
- is->is_phnext = ips_table + hv;
- is->is_hnext = ips_table[hv];
- ips_table[hv] = is;
- ips_stats.iss_bucketlen[hv]++;
- ips_num++;
- MUTEX_EXIT(&ipf_stinsert);
-
- fr_setstatequeue(is, rev);
+ rv = 0;
+
+ return (rv);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_addstate */
-/* Returns: ipstate_t* - NULL == failure, else pointer to new state */
-/* Parameters: fin(I) - pointer to packet information */
+/* Function: ipf_state_matchipv6addrs */
+/* Returns: int - 2 addresses match (strong match), 1 reverse match, */
+/* 0 no match */
+/* Parameters: is1, is2 pointers to states we are checking */
+/* */
+/* Function matches IPv6 addresses it returns strong match for ICMP proto */
+/* even there is only reverse match */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_state_matchipv6addrs(is1, is2)
+ ipstate_t *is1, *is2;
+{
+ int rv;
+
+ if (IP6_EQ(&is1->is_src, &is2->is_src) &&
+ IP6_EQ(&is1->is_dst, &is2->is_dst))
+ rv = 2;
+ else if (IP6_EQ(&is1->is_src, &is2->is_dst) &&
+ IP6_EQ(&is1->is_dst, &is2->is_src)) {
+ /* force strong match for ICMPv6 protocol */
+ rv = (is1->is_p == IPPROTO_ICMPV6) ? 2 : 1;
+ }
+ else
+ rv = 0;
+
+ return (rv);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_state_matchaddresses */
+/* Returns: int - 2 addresses match, 1 reverse match, zero no match */
+/* Parameters: is1, is2 pointers to states we are checking */
+/* */
+/* function retruns true if two pairs of addresses belong to single */
+/* connection. suppose there are two endpoints: */
+/* endpoint1 1.1.1.1 */
+/* endpoint2 1.1.1.2 */
+/* */
+/* the state is established by packet flying from .1 to .2 so we see: */
+/* is1->src = 1.1.1.1 */
+/* is1->dst = 1.1.1.2 */
+/* now endpoint 1.1.1.2 sends answer */
+/* retreives is1 record created by first packat and compares it with is2 */
+/* temporal record, is2 is initialized as follows: */
+/* is2->src = 1.1.1.2 */
+/* is2->dst = 1.1.1.1 */
+/* in this case 1 will be returned */
+/* */
+/* the ipf_matchaddresses() assumes those two records to be same. of course */
+/* the ipf_matchaddresses() also assume records are same in case you pass */
+/* identical arguments (i.e. ipf_matchaddress(is1, is1) would return 2 */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_state_matchaddresses(is1, is2)
+ ipstate_t *is1, *is2;
+{
+ int rv;
+
+ if (is1->is_v == 4) {
+ rv = ipf_state_matchipv4addrs(is1, is2);
+ }
+ else {
+ rv = ipf_state_matchipv6addrs(is1, is2);
+ }
+
+ return (rv);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_matchports */
+/* Returns: int - 2 match, 1 rverse match, 0 no match */
+/* Parameters: ppairs1, ppairs - src, dst ports we want to match */
+/* */
+/* performs the same match for isps members as for addresses */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_state_matchports(ppairs1, ppairs2)
+ udpinfo_t *ppairs1, *ppairs2;
+{
+ int rv;
+
+ if (ppairs1->us_sport == ppairs2->us_sport &&
+ ppairs1->us_dport == ppairs2->us_dport)
+ rv = 2;
+ else if (ppairs1->us_sport == ppairs2->us_dport &&
+ ppairs1->us_dport == ppairs2->us_sport)
+ rv = 1;
+ else
+ rv = 0;
+
+ return (rv);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_matchisps */
+/* Returns: int - nonzero if isps members match, 0 nomatch */
+/* Parameters: is1, is2 - states we want to match */
+/* */
+/* performs the same match for isps members as for addresses */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_state_matchisps(is1, is2)
+ ipstate_t *is1, *is2;
+{
+ int rv;
+
+ if (is1->is_p == is2->is_p) {
+ switch (is1->is_p)
+ {
+ case IPPROTO_TCP :
+ case IPPROTO_UDP :
+ case IPPROTO_GRE :
+ /* greinfo_t can be also interprted as port pair */
+ rv = ipf_state_matchports(&is1->is_ps.is_us,
+ &is2->is_ps.is_us);
+ break;
+
+ case IPPROTO_ICMP :
+ case IPPROTO_ICMPV6 :
+ /* force strong match for ICMP datagram. */
+ if (bcmp(&is1->is_ps, &is2->is_ps,
+ sizeof(icmpinfo_t)) == 0) {
+ rv = 2;
+ } else {
+ rv = 0;
+ }
+ break;
+
+ default:
+ rv = 0;
+ }
+ } else {
+ rv = 0;
+ }
+
+ return (rv);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_state_match */
+/* Returns: int - nonzero match, zero no match */
+/* Parameters: is1, is2 - states we want to match */
+/* */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_state_match(is1, is2)
+ ipstate_t *is1, *is2;
+{
+ int rv;
+ int amatch;
+ int pomatch;
+
+ if (bcmp(&is1->is_pass, &is2->is_pass,
+ offsetof(struct ipstate, is_authmsk) -
+ offsetof(struct ipstate, is_pass)) == 0) {
+
+ pomatch = ipf_state_matchisps(is1, is2);
+ amatch = ipf_state_matchaddresses(is1, is2);
+ rv = (amatch != 0) && (amatch == pomatch);
+ } else {
+ rv = 0;
+ }
+
+ return (rv);
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_state_add */
+/* Returns: ipstate_t - 0 = success */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* fin(I) - pointer to packet information */
/* stsave(O) - pointer to place to save pointer to created */
/* state structure. */
/* flags(I) - flags to use when creating the structure */
@@ -916,25 +1366,49 @@ int rev;
/* either outlive this (not expired) or will deref the ip_state_t */
/* when they are deleted. */
/* ------------------------------------------------------------------------ */
-ipstate_t *fr_addstate(fin, stsave, flags)
-fr_info_t *fin;
-ipstate_t **stsave;
-u_int flags;
+int
+ipf_state_add(softc, fin, stsave, flags)
+ ipf_main_softc_t *softc;
+ fr_info_t *fin;
+ ipstate_t **stsave;
+ u_int flags;
{
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
ipstate_t *is, ips;
struct icmp *ic;
u_int pass, hv;
frentry_t *fr;
tcphdr_t *tcp;
- grehdr_t *gre;
+ frdest_t *fdp;
int out;
- if (fr_state_lock ||
- (fin->fin_flx & (FI_SHORT|FI_STATE|FI_FRAGBODY|FI_BAD)))
- return NULL;
+ /*
+ * If a packet that was created locally is trying to go out but we
+ * do not match here here because of this lock, it is likely that
+ * the policy will block it and return network unreachable back up
+ * the stack. To mitigate this error, EAGAIN is returned instead,
+ * telling the IP stack to try sending this packet again later.
+ */
+ if (softs->ipf_state_lock) {
+ SBUMPD(ipf_state_stats, iss_add_locked);
+ fin->fin_error = EAGAIN;
+ return -1;
+ }
- if ((fin->fin_flx & FI_OOW) && !(fin->fin_tcpf & TH_SYN))
- return NULL;
+ if (fin->fin_flx & (FI_SHORT|FI_STATE|FI_FRAGBODY|FI_BAD)) {
+ SBUMPD(ipf_state_stats, iss_add_bad);
+ return -1;
+ }
+
+ if ((fin->fin_flx & FI_OOW) && !(fin->fin_tcpf & TH_SYN)) {
+ SBUMPD(ipf_state_stats, iss_add_oow);
+ return -1;
+ }
+
+ if ((softs->ipf_state_stats.iss_active * 100 / softs->ipf_state_max) >
+ softs->ipf_state_wm_high) {
+ softs->ipf_state_doflush = 1;
+ }
/*
* If a "keep state" rule has reached the maximum number of references
@@ -948,26 +1422,49 @@ u_int flags;
*/
fr = fin->fin_fr;
if (fr != NULL) {
- if ((ips_num >= fr_statemax) && (fr->fr_statemax == 0)) {
- ATOMIC_INCL(ips_stats.iss_max);
- fr_state_doflush = 1;
- return NULL;
+ if ((softs->ipf_state_stats.iss_active >=
+ softs->ipf_state_max) && (fr->fr_statemax == 0)) {
+ SBUMPD(ipf_state_stats, iss_max);
+ return 1;
}
if ((fr->fr_statemax != 0) &&
(fr->fr_statecnt >= fr->fr_statemax)) {
- ATOMIC_INCL(ips_stats.iss_maxref);
- return NULL;
+ SBUMPD(ipf_state_stats, iss_max_ref);
+ return 2;
}
}
- pass = (fr == NULL) ? 0 : fr->fr_flags;
+ is = &ips;
+ if (fr == NULL) {
+ pass = softc->ipf_flags;
+ is->is_tag = FR_NOLOGTAG;
+ } else {
+ pass = fr->fr_flags;
+ }
ic = NULL;
tcp = NULL;
out = fin->fin_out;
- is = &ips;
bzero((char *)is, sizeof(*is));
- is->is_die = 1 + fr_ticks;
+ is->is_die = 1 + softc->ipf_ticks;
+ /*
+ * 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_pass = pass;
+ is->is_v = fin->fin_v;
+ is->is_sec = fin->fin_secmsk;
+ is->is_secmsk = 0xffff;
+ is->is_auth = fin->fin_auth;
+ is->is_authmsk = 0xffff;
+ is->is_family = fin->fin_family;
+ is->is_opt[0] = fin->fin_optmsk;
+ is->is_optmsk[0] = 0xffffffff;
+ if (is->is_v == 6) {
+ is->is_opt[0] &= ~0x8;
+ is->is_optmsk[0] &= ~0x8;
+ }
/*
* Copy and calculate...
@@ -1008,13 +1505,8 @@ u_int flags;
#endif
if ((fin->fin_v == 4) &&
(fin->fin_flx & (FI_MULTICAST|FI_BROADCAST|FI_MBCAST))) {
- if (fin->fin_out == 0) {
- flags |= SI_W_DADDR|SI_CLONE;
- hv -= is->is_daddr;
- } else {
- flags |= SI_W_SADDR|SI_CLONE;
- hv -= is->is_saddr;
- }
+ flags |= SI_W_DADDR;
+ hv -= is->is_daddr;
}
switch (is->is_p)
@@ -1026,9 +1518,8 @@ u_int flags;
switch (ic->icmp_type)
{
case ICMP6_ECHO_REQUEST :
- is->is_icmp.ici_type = ic->icmp_type;
hv += (is->is_icmp.ici_id = ic->icmp_id);
- break;
+ /*FALLTHROUGH*/
case ICMP6_MEMBERSHIP_QUERY :
case ND_ROUTER_SOLICIT :
case ND_NEIGHBOR_SOLICIT :
@@ -1036,9 +1527,9 @@ u_int flags;
is->is_icmp.ici_type = ic->icmp_type;
break;
default :
- return NULL;
+ SBUMPD(ipf_state_stats, iss_icmp6_notquery);
+ return -2;
}
- ATOMIC_INCL(ips_stats.iss_icmp);
break;
#endif
case IPPROTO_ICMP :
@@ -1054,11 +1545,12 @@ u_int flags;
hv += (is->is_icmp.ici_id = ic->icmp_id);
break;
default :
- return NULL;
+ SBUMPD(ipf_state_stats, iss_icmp_notquery);
+ return -3;
}
- ATOMIC_INCL(ips_stats.iss_icmp);
break;
+#if 0
case IPPROTO_GRE :
gre = fin->fin_dp;
@@ -1069,12 +1561,18 @@ u_int flags;
is->is_call[1] = fin->fin_data[1];
}
break;
+#endif
case IPPROTO_TCP :
tcp = fin->fin_dp;
- if (tcp->th_flags & TH_RST)
- return NULL;
+ if (tcp->th_flags & TH_RST) {
+ SBUMPD(ipf_state_stats, iss_tcp_rstadd);
+ return -4;
+ }
+
+ /* TRACE is, flags, hv */
+
/*
* The endian of the ports doesn't matter, but the ack and
* sequence numbers do as we do mathematics on them later.
@@ -1086,6 +1584,8 @@ u_int flags;
hv += is->is_dport;
}
+ /* TRACE is, flags, hv */
+
/*
* If this is a real packet then initialise fields in the
* state information structure from the TCP header information.
@@ -1110,15 +1610,14 @@ u_int flags;
if ((tcp->th_flags & ~(TH_FIN|TH_ACK|TH_ECNALL)) ==
TH_SYN &&
(TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) {
- if (fr_tcpoptions(fin, tcp,
- &is->is_tcp.ts_data[0]) == -1) {
+ if (ipf_tcpoptions(softs, fin, tcp,
+ &is->is_tcp.ts_data[0]) == -1)
fin->fin_flx |= FI_BAD;
- }
}
if ((fin->fin_out != 0) && (pass & FR_NEWISN) != 0) {
- fr_checknewisn(fin, is);
- fr_fixoutisn(fin, is);
+ ipf_checknewisn(fin, is);
+ ipf_fixoutisn(fin, is);
}
if ((tcp->th_flags & TH_OPENING) == TH_SYN)
@@ -1132,11 +1631,10 @@ u_int flags;
}
/*
- * 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 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.
*/
- ATOMIC_INCL(ips_stats.iss_tcp);
break;
case IPPROTO_UDP :
@@ -1148,7 +1646,6 @@ u_int flags;
hv += tcp->th_dport;
hv += tcp->th_sport;
}
- ATOMIC_INCL(ips_stats.iss_udp);
break;
default :
@@ -1156,144 +1653,173 @@ u_int flags;
}
hv = DOUBLE_HASH(hv);
is->is_hv = hv;
- is->is_rule = fr;
- is->is_flags = flags & IS_INHERITED;
/*
* Look for identical state.
*/
- for (is = ips_table[is->is_hv % fr_statesize]; is != NULL;
- is = is->is_hnext) {
- if (bcmp(&ips.is_src, &is->is_src,
- offsetof(struct ipstate, is_ps) -
- offsetof(struct ipstate, is_src)) == 0)
+ for (is = softs->ipf_state_table[hv % softs->ipf_state_size];
+ is != NULL; is = is->is_hnext) {
+ if (ipf_state_match(&ips, is) == 1)
break;
}
- if (is != NULL)
- return NULL;
+ if (is != NULL) {
+ SBUMPD(ipf_state_stats, iss_add_dup);
+ return 3;
+ }
- if (ips_stats.iss_bucketlen[hv] >= fr_state_maxbucket) {
- ATOMIC_INCL(ips_stats.iss_bucketfull);
- return NULL;
+ if (softs->ipf_state_stats.iss_bucketlen[hv] >=
+ softs->ipf_state_maxbucket) {
+ SBUMPD(ipf_state_stats, iss_bucket_full);
+ return 4;
}
KMALLOC(is, ipstate_t *);
if (is == NULL) {
- ATOMIC_INCL(ips_stats.iss_nomem);
- return NULL;
+ SBUMPD(ipf_state_stats, iss_nomem);
+ return 5;
}
bcopy((char *)&ips, (char *)is, sizeof(*is));
+ is->is_flags = flags & IS_INHERITED;
+ is->is_rulen = fin->fin_rule;
+ is->is_rule = fr;
+
/*
- * Do not do the modulous here, it is done in fr_stinsert().
+ * Do not do the modulous here, it is done in ipf_state_insert().
*/
if (fr != NULL) {
- (void) strncpy(is->is_group, fr->fr_group, FR_GROUPLEN);
+ ipftq_t *tq;
+
+ (void) strncpy(is->is_group, FR_NAME(fr, fr_group),
+ FR_GROUPLEN);
if (fr->fr_age[0] != 0) {
- is->is_tqehead[0] = fr_addtimeoutqueue(&ips_utqe,
- fr->fr_age[0]);
+ tq = ipf_addtimeoutqueue(softc,
+ &softs->ipf_state_usertq,
+ fr->fr_age[0]);
+ is->is_tqehead[0] = tq;
is->is_sti.tqe_flags |= TQE_RULEBASED;
}
if (fr->fr_age[1] != 0) {
- is->is_tqehead[1] = fr_addtimeoutqueue(&ips_utqe,
- fr->fr_age[1]);
+ tq = ipf_addtimeoutqueue(softc,
+ &softs->ipf_state_usertq,
+ fr->fr_age[1]);
+ is->is_tqehead[1] = tq;
is->is_sti.tqe_flags |= TQE_RULEBASED;
}
is->is_tag = fr->fr_logtag;
-
- /*
- * The name '-' is special for network interfaces and causes
- * a NULL name to be present, always, allowing packets to
- * match it, regardless of their interface.
- */
- if ((fin->fin_ifp == NULL) ||
- (fr->fr_ifnames[out << 1][0] == '-' &&
- fr->fr_ifnames[out << 1][1] == '\0')) {
- is->is_ifp[out << 1] = fr->fr_ifas[0];
- strncpy(is->is_ifname[out << 1], fr->fr_ifnames[0],
- sizeof(fr->fr_ifnames[0]));
- } else {
- is->is_ifp[out << 1] = fin->fin_ifp;
- COPYIFNAME(is->is_v, fin->fin_ifp,
- is->is_ifname[out << 1]);
- }
-
- is->is_ifp[(out << 1) + 1] = fr->fr_ifas[1];
- strncpy(is->is_ifname[(out << 1) + 1], fr->fr_ifnames[1],
- sizeof(fr->fr_ifnames[1]));
-
- is->is_ifp[(1 - out) << 1] = fr->fr_ifas[2];
- strncpy(is->is_ifname[((1 - out) << 1)], fr->fr_ifnames[2],
- sizeof(fr->fr_ifnames[2]));
-
- is->is_ifp[((1 - out) << 1) + 1] = fr->fr_ifas[3];
- strncpy(is->is_ifname[((1 - out) << 1) + 1], fr->fr_ifnames[3],
- sizeof(fr->fr_ifnames[3]));
- } else {
- pass = fr_flags;
- is->is_tag = FR_NOLOGTAG;
-
- if (fin->fin_ifp != NULL) {
- is->is_ifp[out << 1] = fin->fin_ifp;
- COPYIFNAME(is->is_v, fin->fin_ifp,
- is->is_ifname[out << 1]);
- }
}
/*
- * It may seem strange to set is_ref to 2, but fr_check() will call
- * fr_statederef() after calling fr_addstate() and the idea is to
- * have it exist at the end of fr_check() with is_ref == 1.
+ * It may seem strange to set is_ref to 2, but if stsave is not NULL
+ * then a copy of the pointer is being stored somewhere else and in
+ * the end, it will expect to be able to do osmething with it.
*/
- is->is_ref = 2;
- is->is_pass = pass;
+ is->is_me = stsave;
+ if (stsave != NULL) {
+ *stsave = is;
+ is->is_ref = 2;
+ } else {
+ is->is_ref = 1;
+ }
is->is_pkts[0] = 0, is->is_bytes[0] = 0;
is->is_pkts[1] = 0, is->is_bytes[1] = 0;
is->is_pkts[2] = 0, is->is_bytes[2] = 0;
is->is_pkts[3] = 0, is->is_bytes[3] = 0;
if ((fin->fin_flx & FI_IGNORE) == 0) {
is->is_pkts[out] = 1;
+ fin->fin_pktnum = 1;
is->is_bytes[out] = fin->fin_plen;
is->is_flx[out][0] = fin->fin_flx & FI_CMP;
is->is_flx[out][0] &= ~FI_OOW;
}
+ if (pass & FR_STLOOSE)
+ is->is_flags |= IS_LOOSE;
+
if (pass & FR_STSTRICT)
is->is_flags |= IS_STRICT;
if (pass & FR_STATESYNC)
is->is_flags |= IS_STATESYNC;
- /*
- * 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_v = fin->fin_v;
- is->is_opt[0] = fin->fin_optmsk;
- is->is_optmsk[0] = 0xffffffff;
- is->is_optmsk[1] = 0xffffffff;
- if (is->is_v == 6) {
- is->is_opt[0] &= ~0x8;
- is->is_optmsk[0] &= ~0x8;
- is->is_optmsk[1] &= ~0x8;
- }
- is->is_me = stsave;
- is->is_sec = fin->fin_secmsk;
- is->is_secmsk = 0xffff;
- is->is_auth = fin->fin_auth;
- is->is_authmsk = 0xffff;
- if (flags & (SI_WILDP|SI_WILDA)) {
- ATOMIC_INCL(ips_stats.iss_wild);
+ if (pass & FR_LOGFIRST)
+ is->is_pass &= ~(FR_LOGFIRST|FR_LOG);
+
+ READ_ENTER(&softc->ipf_state);
+
+ if (ipf_state_insert(softc, is, fin->fin_rev) == -1) {
+ RWLOCK_EXIT(&softc->ipf_state);
+ /*
+ * This is a bit more manual than it should be but
+ * ipf_state_del cannot be called.
+ */
+ MUTEX_EXIT(&is->is_lock);
+ MUTEX_DESTROY(&is->is_lock);
+ if (is->is_tqehead[0] != NULL) {
+ if (ipf_deletetimeoutqueue(is->is_tqehead[0]) == 0)
+ ipf_freetimeoutqueue(softc, is->is_tqehead[0]);
+ is->is_tqehead[0] = NULL;
+ }
+ if (is->is_tqehead[1] != NULL) {
+ if (ipf_deletetimeoutqueue(is->is_tqehead[1]) == 0)
+ ipf_freetimeoutqueue(softc, is->is_tqehead[1]);
+ is->is_tqehead[1] = NULL;
+ }
+ KFREE(is);
+ return -1;
}
- is->is_rulen = fin->fin_rule;
+ /*
+ * Filling in the interface name is after the insert so that an
+ * event (such as add/delete) of an interface that is referenced
+ * by this rule will see this state entry.
+ */
+ if (fr != NULL) {
+ /*
+ * The name '-' is special for network interfaces and causes
+ * a NULL name to be present, always, allowing packets to
+ * match it, regardless of their interface.
+ */
+ if ((fin->fin_ifp == NULL) ||
+ (fr->fr_ifnames[out << 1] != -1 &&
+ fr->fr_names[fr->fr_ifnames[out << 1] + 0] == '-' &&
+ fr->fr_names[fr->fr_ifnames[out << 1] + 1] == '\0')) {
+ is->is_ifp[out << 1] = fr->fr_ifas[0];
+ strncpy(is->is_ifname[out << 1],
+ fr->fr_names + fr->fr_ifnames[0],
+ sizeof(fr->fr_ifnames[0]));
+ } else {
+ is->is_ifp[out << 1] = fin->fin_ifp;
+ COPYIFNAME(fin->fin_v, fin->fin_ifp,
+ is->is_ifname[out << 1]);
+ }
- if (pass & FR_LOGFIRST)
- is->is_pass &= ~(FR_LOGFIRST|FR_LOG);
+ is->is_ifp[(out << 1) + 1] = fr->fr_ifas[1];
+ if (fr->fr_ifnames[1] != -1) {
+ strncpy(is->is_ifname[(out << 1) + 1],
+ fr->fr_names + fr->fr_ifnames[1],
+ sizeof(fr->fr_ifnames[1]));
+ }
- READ_ENTER(&ipf_state);
+ is->is_ifp[(1 - out) << 1] = fr->fr_ifas[2];
+ if (fr->fr_ifnames[2] != -1) {
+ strncpy(is->is_ifname[((1 - out) << 1)],
+ fr->fr_names + fr->fr_ifnames[2],
+ sizeof(fr->fr_ifnames[2]));
+ }
- fr_stinsert(is, fin->fin_rev);
+ is->is_ifp[((1 - out) << 1) + 1] = fr->fr_ifas[3];
+ if (fr->fr_ifnames[3] != -1) {
+ strncpy(is->is_ifname[((1 - out) << 1) + 1],
+ fr->fr_names + fr->fr_ifnames[3],
+ sizeof(fr->fr_ifnames[3]));
+ }
+ } else {
+ if (fin->fin_ifp != NULL) {
+ is->is_ifp[out << 1] = fin->fin_ifp;
+ COPYIFNAME(fin->fin_v, fin->fin_ifp,
+ is->is_ifname[out << 1]);
+ }
+ }
if (fin->fin_p == IPPROTO_TCP) {
/*
@@ -1301,56 +1827,79 @@ u_int flags;
* timer on it as we'll never see an error if it fails to
* connect.
*/
- (void) fr_tcp_age(&is->is_sti, fin, ips_tqtqb, is->is_flags);
- MUTEX_EXIT(&is->is_lock);
-#ifdef IPFILTER_SCAN
- if ((is->is_flags & SI_CLONE) == 0)
- (void) ipsc_attachis(is);
-#endif
- } else {
- MUTEX_EXIT(&is->is_lock);
+ (void) ipf_tcp_age(&is->is_sti, fin, softs->ipf_state_tcptq,
+ is->is_flags, 2);
}
-#ifdef IPFILTER_SYNC
+ MUTEX_EXIT(&is->is_lock);
if ((is->is_flags & IS_STATESYNC) && ((is->is_flags & SI_CLONE) == 0))
- is->is_sync = ipfsync_new(SMC_STATE, fin, is);
-#endif
- if (ipstate_logging)
- ipstate_log(is, ISL_NEW);
+ is->is_sync = ipf_sync_new(softc, SMC_STATE, fin, is);
+ if (softs->ipf_state_logging)
+ ipf_state_log(softc, is, ISL_NEW);
+
+ RWLOCK_EXIT(&softc->ipf_state);
- RWLOCK_EXIT(&ipf_state);
- fin->fin_state = is;
- fin->fin_rev = IP6_NEQ(&is->is_dst, &fin->fin_daddr);
fin->fin_flx |= FI_STATE;
if (fin->fin_flx & FI_FRAG)
- (void) fr_newfrag(fin, pass ^ FR_KEEPSTATE);
+ (void) ipf_frag_new(softc, fin, pass);
- return is;
+ fdp = &fr->fr_tifs[0];
+ if (fdp->fd_type == FRD_DSTLIST) {
+ ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL,
+ &is->is_tifs[0]);
+ } else {
+ bcopy(fdp, &is->is_tifs[0], sizeof(*fdp));
+ }
+
+ fdp = &fr->fr_tifs[1];
+ if (fdp->fd_type == FRD_DSTLIST) {
+ ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL,
+ &is->is_tifs[1]);
+ } else {
+ bcopy(fdp, &is->is_tifs[1], sizeof(*fdp));
+ }
+ fin->fin_tif = &is->is_tifs[fin->fin_rev];
+
+ fdp = &fr->fr_dif;
+ if (fdp->fd_type == FRD_DSTLIST) {
+ ipf_dstlist_select_node(fin, fdp->fd_ptr, NULL,
+ &is->is_dif);
+ } else {
+ bcopy(fdp, &is->is_dif, sizeof(*fdp));
+ }
+ fin->fin_dif = &is->is_dif;
+
+ return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_tcpoptions */
+/* Function: ipf_tcpoptions */
/* Returns: int - 1 == packet matches state entry, 0 == it does not, */
/* -1 == packet has bad TCP options data */
-/* Parameters: fin(I) - pointer to packet information */
+/* Parameters: softs(I) - pointer to state context structure */
+/* fin(I) - pointer to packet information */
/* tcp(I) - pointer to TCP packet header */
/* td(I) - pointer to TCP data held as part of the state */
/* */
/* Look after the TCP header for any options and deal with those that are */
/* present. Record details about those that we recogise. */
/* ------------------------------------------------------------------------ */
-static int fr_tcpoptions(fin, tcp, td)
-fr_info_t *fin;
-tcphdr_t *tcp;
-tcpdata_t *td;
+static int
+ipf_tcpoptions(softs, fin, tcp, td)
+ ipf_state_softc_t *softs;
+ fr_info_t *fin;
+ tcphdr_t *tcp;
+ tcpdata_t *td;
{
int off, mlen, ol, i, len, retval;
char buf[64], *s, opt;
mb_t *m = NULL;
len = (TCP_OFF(tcp) << 2);
- if (fin->fin_dlen < len)
+ if (fin->fin_dlen < len) {
+ SBUMPD(ipf_state_stats, iss_tcp_toosmall);
return 0;
+ }
len -= sizeof(*tcp);
off = fin->fin_plen - fin->fin_dlen + sizeof(*tcp) + fin->fin_ipoff;
@@ -1422,14 +1971,19 @@ tcpdata_t *td;
len -= ol;
s += ol;
}
+ if (retval == -1) {
+ SBUMPD(ipf_state_stats, iss_tcp_badopt);
+ }
return retval;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_tcpstate */
+/* Function: ipf_state_tcp */
/* Returns: int - 1 == packet matches state entry, 0 == it does not */
-/* Parameters: fin(I) - pointer to packet information */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* softs(I) - pointer to state context structure */
+/* fin(I) - pointer to packet information */
/* tcp(I) - pointer to TCP packet header */
/* is(I) - pointer to master state structure */
/* */
@@ -1437,16 +1991,19 @@ tcpdata_t *td;
/* Change timeout depending on whether new packet is a SYN-ACK returning */
/* for a SYN or a RST or FIN which indicate time to close up shop. */
/* ------------------------------------------------------------------------ */
-static int fr_tcpstate(fin, tcp, is)
-fr_info_t *fin;
-tcphdr_t *tcp;
-ipstate_t *is;
+static int
+ipf_state_tcp(softc, softs, fin, tcp, is)
+ ipf_main_softc_t *softc;
+ ipf_state_softc_t *softs;
+ fr_info_t *fin;
+ tcphdr_t *tcp;
+ ipstate_t *is;
{
- int source, ret = 0, flags;
tcpdata_t *fdata, *tdata;
+ int source, ret, flags;
source = !fin->fin_rev;
- if (((is->is_flags & IS_TCPFSM) != 0) && (source == 1) &&
+ if (((is->is_flags & IS_TCPFSM) != 0) && (source == 1) &&
(ntohs(is->is_sport) != fin->fin_data[0]))
source = 0;
fdata = &is->is_tcp.ts_data[!source];
@@ -1462,34 +2019,37 @@ ipstate_t *is;
if ((is->is_state[0] > IPF_TCPS_ESTABLISHED) &&
(is->is_state[1] > IPF_TCPS_ESTABLISHED)) {
is->is_state[!source] = IPF_TCPS_CLOSED;
- fr_movequeue(&is->is_sti, is->is_sti.tqe_ifq,
- &ips_deletetq);
+ ipf_movequeue(softc->ipf_ticks, &is->is_sti,
+ is->is_sti.tqe_ifq,
+ &softs->ipf_state_deletetq);
MUTEX_EXIT(&is->is_lock);
+ DT1(iss_tcp_closing, ipstate_t *, is);
+ SBUMP(ipf_state_stats.iss_tcp_closing);
return 0;
}
}
- ret = fr_tcpinwindow(fin, fdata, tdata, tcp, is->is_flags);
+ if (is->is_flags & IS_LOOSE)
+ ret = 1;
+ else
+ ret = ipf_state_tcpinwindow(fin, fdata, tdata, tcp,
+ is->is_flags);
if (ret > 0) {
-#ifdef IPFILTER_SCAN
- if (is->is_flags & (IS_SC_CLIENT|IS_SC_SERVER)) {
- ipsc_packet(fin, is);
- if (FR_ISBLOCK(is->is_pass)) {
- MUTEX_EXIT(&is->is_lock);
- return 1;
- }
- }
-#endif
-
/*
* Nearing end of connection, start timeout.
*/
- ret = fr_tcp_age(&is->is_sti, fin, ips_tqtqb, is->is_flags);
+ ret = ipf_tcp_age(&is->is_sti, fin, softs->ipf_state_tcptq,
+ is->is_flags, ret);
if (ret == 0) {
MUTEX_EXIT(&is->is_lock);
+ DT2(iss_tcp_fsm, fr_info_t *, fin, ipstate_t *, is);
+ SBUMP(ipf_state_stats.iss_tcp_fsm);
return 0;
}
+ if (softs->ipf_state_logging > 4)
+ ipf_state_log(softc, is, ISL_STATECHANGE);
+
/*
* set s0's as appropriate. Use syn-ack packet as it
* contains both pieces of required information.
@@ -1503,25 +2063,29 @@ ipstate_t *is;
is->is_s0[source] = ntohl(tcp->th_ack);
is->is_s0[!source] = ntohl(tcp->th_seq) + 1;
if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) {
- if (fr_tcpoptions(fin, tcp, fdata) == -1)
+ if (ipf_tcpoptions(softs, fin, tcp,
+ fdata) == -1)
fin->fin_flx |= FI_BAD;
}
if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN))
- fr_checknewisn(fin, is);
+ ipf_checknewisn(fin, is);
} else if (flags == TH_SYN) {
is->is_s0[source] = ntohl(tcp->th_seq) + 1;
if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) {
- if (fr_tcpoptions(fin, tcp, fdata) == -1)
+ if (ipf_tcpoptions(softs, fin, tcp,
+ fdata) == -1)
fin->fin_flx |= FI_BAD;
}
if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN))
- fr_checknewisn(fin, is);
+ ipf_checknewisn(fin, is);
}
ret = 1;
} else {
- fin->fin_flx |= FI_OOW;
+ DT2(iss_tcp_oow, fr_info_t *, fin, ipstate_t *, is);
+ SBUMP(ipf_state_stats.iss_tcp_oow);
+ ret = 0;
}
MUTEX_EXIT(&is->is_lock);
return ret;
@@ -1529,7 +2093,7 @@ ipstate_t *is;
/* ------------------------------------------------------------------------ */
-/* Function: fr_checknewisn */
+/* Function: ipf_checknewisn */
/* Returns: Nil */
/* Parameters: fin(I) - pointer to packet information */
/* is(I) - pointer to master state structure */
@@ -1540,9 +2104,10 @@ ipstate_t *is;
/* NOTE: This does not actually change the sequence numbers, only gets new */
/* one ready. */
/* ------------------------------------------------------------------------ */
-static void fr_checknewisn(fin, is)
-fr_info_t *fin;
-ipstate_t *is;
+static void
+ipf_checknewisn(fin, is)
+ fr_info_t *fin;
+ ipstate_t *is;
{
u_32_t sumd, old, new;
tcphdr_t *tcp;
@@ -1554,7 +2119,7 @@ ipstate_t *is;
if (((i == 0) && !(is->is_flags & IS_ISNSYN)) ||
((i == 1) && !(is->is_flags & IS_ISNACK))) {
old = ntohl(tcp->th_seq);
- new = fr_newisn(fin);
+ new = ipf_newisn(fin);
is->is_isninc[i] = new - old;
CALC_SUMD(old, new, sumd);
is->is_sumd[i] = (sumd & 0xffff) + (sumd >> 16);
@@ -1565,9 +2130,8 @@ ipstate_t *is;
/* ------------------------------------------------------------------------ */
-/* Function: fr_tcpinwindow */
-/* Returns: int - 1 == packet inside TCP "window", 0 == not inside, */
-/* 2 == packet seq number matches next expected */
+/* Function: ipf_state_tcpinwindow */
+/* Returns: int - 1 == packet inside TCP "window", 0 == not inside. */
/* Parameters: fin(I) - pointer to packet information */
/* fdata(I) - pointer to tcp state informatio (forward) */
/* tdata(I) - pointer to tcp state informatio (reverse) */
@@ -1577,12 +2141,15 @@ ipstate_t *is;
/* within the TCP data window. In a show of generosity, allow packets that */
/* are within the window space behind the current sequence # as well. */
/* ------------------------------------------------------------------------ */
-int fr_tcpinwindow(fin, fdata, tdata, tcp, flags)
-fr_info_t *fin;
-tcpdata_t *fdata, *tdata;
-tcphdr_t *tcp;
-int flags;
+static int
+ipf_state_tcpinwindow(fin, fdata, tdata, tcp, flags)
+ fr_info_t *fin;
+ tcpdata_t *fdata, *tdata;
+ tcphdr_t *tcp;
+ int flags;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
tcp_seq seq, ack, end;
int ackskew, tcpflags;
u_32_t win, maxwin;
@@ -1651,12 +2218,17 @@ int flags;
/*
* Strict sequencing only allows in-order delivery.
*/
- if (seq != fdata->td_end) {
- if ((flags & IS_STRICT) != 0) {
+ if ((flags & IS_STRICT) != 0) {
+ if (seq != fdata->td_end) {
+ DT2(iss_tcp_struct, tcpdata_t *, fdata, int, seq);
+ SBUMP(ipf_state_stats.iss_tcp_strict);
+ fin->fin_flx |= FI_OOW;
return 0;
}
}
+#define SEQ_GE(a,b) ((int)((a) - (b)) >= 0)
+#define SEQ_GT(a,b) ((int)((a) - (b)) > 0)
inseq = 0;
if ((SEQ_GE(fdata->td_maxend, end)) &&
(SEQ_GE(seq, fdata->td_end - maxwin)) &&
@@ -1672,6 +2244,8 @@ int flags;
} else if ((seq == fdata->td_maxend) && (ackskew == 0) &&
(fdata->td_winflags & TCP_SACK_PERMIT) &&
(tdata->td_winflags & TCP_SACK_PERMIT)) {
+ DT2(iss_sinsack, tcpdata_t *, fdata, int, seq);
+ SBUMP(ipf_state_stats.iss_winsack);
inseq = 1;
/*
* Sometimes a TCP RST will be generated with only the ACK field
@@ -1693,7 +2267,7 @@ int flags;
* accepted, even if it appears out of sequence.
*/
inseq = 1;
- } else
+ } else
#endif
if (!(fdata->td_winflags &
(TCP_WSCALE_SEEN|TCP_WSCALE_FIRST))) {
@@ -1737,12 +2311,14 @@ int flags;
tdata->td_maxend = ack + win;
return 1;
}
+ SBUMP(ipf_state_stats.iss_oow);
+ fin->fin_flx |= FI_OOW;
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_stclone */
+/* Function: ipf_state_clone */
/* Returns: ipstate_t* - NULL == cloning failed, */
/* else pointer to new state structure */
/* Parameters: fin(I) - pointer to packet information */
@@ -1751,27 +2327,40 @@ int flags;
/* */
/* Create a "duplcate" state table entry from the master. */
/* ------------------------------------------------------------------------ */
-static ipstate_t *fr_stclone(fin, tcp, is)
-fr_info_t *fin;
-tcphdr_t *tcp;
-ipstate_t *is;
+static ipstate_t *
+ipf_state_clone(fin, tcp, is)
+ fr_info_t *fin;
+ tcphdr_t *tcp;
+ ipstate_t *is;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
ipstate_t *clone;
u_32_t send;
- if (ips_num == fr_statemax) {
- ATOMIC_INCL(ips_stats.iss_max);
- fr_state_doflush = 1;
+ if (softs->ipf_state_stats.iss_active == softs->ipf_state_max) {
+ SBUMPD(ipf_state_stats, iss_max);
+ softs->ipf_state_doflush = 1;
return NULL;
}
KMALLOC(clone, ipstate_t *);
- if (clone == NULL)
+ if (clone == NULL) {
+ SBUMPD(ipf_state_stats, iss_clone_nomem);
return NULL;
+ }
bcopy((char *)is, (char *)clone, sizeof(*clone));
MUTEX_NUKE(&clone->is_lock);
+ /*
+ * It has not yet been placed on any timeout queue, so make sure
+ * all of that data is zero'd out.
+ */
+ clone->is_sti.tqe_pnext = NULL;
+ clone->is_sti.tqe_next = NULL;
+ clone->is_sti.tqe_ifq = NULL;
+ clone->is_sti.tqe_parent = clone;
- clone->is_die = ONE_DAY + fr_ticks;
+ clone->is_die = ONE_DAY + softc->ipf_ticks;
clone->is_state[0] = 0;
clone->is_state[1] = 0;
send = ntohl(tcp->th_seq) + fin->fin_dlen - (TCP_OFF(tcp) << 2) +
@@ -1798,49 +2387,61 @@ ipstate_t *is;
clone->is_flags &= ~SI_CLONE;
clone->is_flags |= SI_CLONED;
- fr_stinsert(clone, fin->fin_rev);
- clone->is_ref = 2;
+ if (ipf_state_insert(softc, clone, fin->fin_rev) == -1) {
+ KFREE(clone);
+ return NULL;
+ }
+
+ clone->is_ref = 1;
if (clone->is_p == IPPROTO_TCP) {
- (void) fr_tcp_age(&clone->is_sti, fin, ips_tqtqb,
- clone->is_flags);
+ (void) ipf_tcp_age(&clone->is_sti, fin, softs->ipf_state_tcptq,
+ clone->is_flags, 2);
}
MUTEX_EXIT(&clone->is_lock);
-#ifdef IPFILTER_SCAN
- (void) ipsc_attachis(is);
-#endif
-#ifdef IPFILTER_SYNC
if (is->is_flags & IS_STATESYNC)
- clone->is_sync = ipfsync_new(SMC_STATE, fin, clone);
-#endif
+ clone->is_sync = ipf_sync_new(softc, SMC_STATE, fin, clone);
+ DT2(iss_clone, ipstate_t *, is, ipstate_t *, clone);
+ SBUMP(ipf_state_stats.iss_cloned);
return clone;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_matchsrcdst */
+/* Function: ipf_matchsrcdst */
/* Returns: Nil */
-/* Parameters: fin(I) - pointer to packet information */
-/* is(I) - pointer to state structure */
-/* src(I) - pointer to source address */
-/* dst(I) - pointer to destination address */
-/* tcp(I) - pointer to TCP/UDP header */
+/* Parameters: fin(I) - pointer to packet information */
+/* is(I) - pointer to state structure */
+/* src(I) - pointer to source address */
+/* dst(I) - pointer to destination address */
+/* tcp(I) - pointer to TCP/UDP header */
+/* cmask(I) - mask of FI_* bits to check */
/* */
/* Match a state table entry against an IP packet. The logic below is that */
/* ret gets set to one if the match succeeds, else remains 0. If it is */
/* still 0 after the test. no match. */
/* ------------------------------------------------------------------------ */
-static ipstate_t *fr_matchsrcdst(fin, is, src, dst, tcp, cmask)
-fr_info_t *fin;
-ipstate_t *is;
-i6addr_t *src, *dst;
-tcphdr_t *tcp;
-u_32_t cmask;
+static ipstate_t *
+ipf_matchsrcdst(fin, is, src, dst, tcp, cmask)
+ fr_info_t *fin;
+ ipstate_t *is;
+ i6addr_t *src, *dst;
+ tcphdr_t *tcp;
+ u_32_t cmask;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
int ret = 0, rev, out, flags, flx = 0, idx;
u_short sp, dp;
u_32_t cflx;
void *ifp;
+ /*
+ * If a connection is about to be deleted, no packets
+ * are allowed to match it.
+ */
+ if (is->is_sti.tqe_ifq == &softs->ipf_state_deletetq)
+ return NULL;
+
rev = IP6_NEQ(&is->is_dst, dst);
ifp = fin->fin_ifp;
out = fin->fin_out;
@@ -1872,8 +2473,12 @@ u_32_t cmask;
*is->is_ifname[idx] == '*')))
ret = 1;
- if (ret == 0)
+ if (ret == 0) {
+ DT2(iss_lookup_badifp, fr_info_t *, fin, ipstate_t *, is);
+ SBUMP(ipf_state_stats.iss_lookup_badifp);
+ /* TRACE is, out, rev, idx */
return NULL;
+ }
ret = 0;
/*
@@ -1883,7 +2488,8 @@ u_32_t cmask;
if ((IP6_EQ(&is->is_dst, dst) || (flags & SI_W_DADDR)) &&
(IP6_EQ(&is->is_src, src) || (flags & SI_W_SADDR))) {
if (tcp) {
- if ((sp == is->is_sport || flags & SI_W_SPORT)&&
+ if ((sp == is->is_sport || flags & SI_W_SPORT)
+ &&
(dp == is->is_dport || flags & SI_W_DPORT))
ret = 1;
} else {
@@ -1894,7 +2500,8 @@ u_32_t cmask;
if ((IP6_EQ(&is->is_dst, src) || (flags & SI_W_DADDR)) &&
(IP6_EQ(&is->is_src, dst) || (flags & SI_W_SADDR))) {
if (tcp) {
- if ((dp == is->is_sport || flags & SI_W_SPORT)&&
+ if ((dp == is->is_sport || flags & SI_W_SPORT)
+ &&
(sp == is->is_dport || flags & SI_W_DPORT))
ret = 1;
} else {
@@ -1903,8 +2510,12 @@ u_32_t cmask;
}
}
- if (ret == 0)
+ if (ret == 0) {
+ SBUMP(ipf_state_stats.iss_lookup_badport);
+ DT2(iss_lookup_badport, fr_info_t *, fin, ipstate_t *, is);
+ /* TRACE rev, is, sp, dp, src, dst */
return NULL;
+ }
/*
* Whether or not this should be here, is questionable, but the aim
@@ -1925,55 +2536,27 @@ u_32_t cmask;
if ((flags & SI_W_SADDR) != 0) {
if (rev == 0) {
-#ifdef USE_INET6
- if (is->is_v == 6 &&
- IN6_IS_ADDR_MULTICAST(&fi->fi_src.in6))
- /*EMPTY*/;
- else
-#endif
- {
- is->is_src = fi->fi_src;
- is->is_flags &= ~SI_W_SADDR;
- }
+ is->is_src = fi->fi_src;
+ is->is_flags &= ~SI_W_SADDR;
} else {
-#ifdef USE_INET6
- if (is->is_v == 6 &&
- IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6))
- /*EMPTY*/;
- else
-#endif
- {
+ if (!(fin->fin_flx & (FI_MULTICAST|FI_MBCAST))){
is->is_src = fi->fi_dst;
is->is_flags &= ~SI_W_SADDR;
}
}
} else if ((flags & SI_W_DADDR) != 0) {
if (rev == 0) {
-#ifdef USE_INET6
- if (is->is_v == 6 &&
- IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6))
- /*EMPTY*/;
- else
-#endif
- {
+ if (!(fin->fin_flx & (FI_MULTICAST|FI_MBCAST))){
is->is_dst = fi->fi_dst;
is->is_flags &= ~SI_W_DADDR;
}
} else {
-#ifdef USE_INET6
- if (is->is_v == 6 &&
- IN6_IS_ADDR_MULTICAST(&fi->fi_src.in6))
- /*EMPTY*/;
- else
-#endif
- {
- is->is_dst = fi->fi_src;
- is->is_flags &= ~SI_W_DADDR;
- }
+ is->is_dst = fi->fi_src;
+ is->is_flags &= ~SI_W_DADDR;
}
}
if ((is->is_flags & (SI_WILDA|SI_WILDP)) == 0) {
- ATOMIC_DECL(ips_stats.iss_wild);
+ ATOMIC_DECL(softs->ipf_state_stats.iss_wild);
}
}
@@ -1986,29 +2569,31 @@ u_32_t cmask;
if ((cflx && (flx != (cflx & cmask))) ||
((fin->fin_optmsk & is->is_optmsk[rev]) != is->is_opt[rev]) ||
((fin->fin_secmsk & is->is_secmsk) != is->is_sec) ||
- ((fin->fin_auth & is->is_authmsk) != is->is_auth))
+ ((fin->fin_auth & is->is_authmsk) != is->is_auth)) {
+ SBUMPD(ipf_state_stats, iss_miss_mask);
return NULL;
+ }
- /*
- * Only one of the source or destination port can be flagged as a
- * wildcard. When filling it in, fill in a copy of the matched entry
- * if it has the cloning flag set.
- */
if ((fin->fin_flx & FI_IGNORE) != 0) {
fin->fin_rev = rev;
return is;
}
+ /*
+ * Only one of the source or destination port can be flagged as a
+ * wildcard. When filling it in, fill in a copy of the matched entry
+ * if it has the cloning flag set.
+ */
if ((flags & (SI_W_SPORT|SI_W_DPORT))) {
if ((flags & SI_CLONE) != 0) {
ipstate_t *clone;
- clone = fr_stclone(fin, tcp, is);
+ clone = ipf_state_clone(fin, tcp, is);
if (clone == NULL)
return NULL;
is = clone;
} else {
- ATOMIC_DECL(ips_stats.iss_wild);
+ ATOMIC_DECL(softs->ipf_state_stats.iss_wild);
}
if ((flags & SI_W_SPORT) != 0) {
@@ -2031,18 +2616,21 @@ u_32_t cmask;
is->is_maxdend = is->is_dend + 1;
}
is->is_flags &= ~(SI_W_SPORT|SI_W_DPORT);
- if ((flags & SI_CLONED) && ipstate_logging)
- ipstate_log(is, ISL_CLONE);
+ if ((flags & SI_CLONED) && softs->ipf_state_logging)
+ ipf_state_log(softc, is, ISL_CLONE);
}
ret = -1;
if (is->is_flx[out][rev] == 0) {
is->is_flx[out][rev] = flx;
- is->is_opt[rev] = fin->fin_optmsk;
- if (is->is_v == 6) {
- is->is_opt[rev] &= ~0x8;
- is->is_optmsk[rev] &= ~0x8;
+ if (rev == 1 && is->is_optmsk[1] == 0) {
+ is->is_opt[1] = fin->fin_optmsk;
+ is->is_optmsk[1] = 0xffffffff;
+ if (is->is_v == 6) {
+ is->is_opt[1] &= ~0x8;
+ is->is_optmsk[1] &= ~0x8;
+ }
}
}
@@ -2053,7 +2641,7 @@ u_32_t cmask;
if (is->is_ifp[idx] == NULL &&
(*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '*')) {
is->is_ifp[idx] = ifp;
- COPYIFNAME(is->is_v, ifp, is->is_ifname[idx]);
+ COPYIFNAME(fin->fin_v, ifp, is->is_ifname[idx]);
}
fin->fin_rev = rev;
return is;
@@ -2061,7 +2649,7 @@ u_32_t cmask;
/* ------------------------------------------------------------------------ */
-/* Function: fr_checkicmpmatchingstate */
+/* Function: ipf_checkicmpmatchingstate */
/* Returns: Nil */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -2071,13 +2659,13 @@ u_32_t cmask;
/* If we return NULL then no lock on ipf_state is held. */
/* If we return non-null then a read-lock on ipf_state is held. */
/* ------------------------------------------------------------------------ */
-static ipstate_t *fr_checkicmpmatchingstate(fin)
-fr_info_t *fin;
+static ipstate_t *
+ipf_checkicmpmatchingstate(fin)
+ fr_info_t *fin;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
ipstate_t *is, **isp;
- u_short sport, dport;
- u_char pr;
- int backward, i, oi;
i6addr_t dst, src;
struct icmp *ic;
u_short savelen;
@@ -2085,6 +2673,7 @@ fr_info_t *fin;
fr_info_t ofin;
tcphdr_t *tcp;
int type, len;
+ u_char pr;
ip_t *oip;
u_int hv;
@@ -2096,8 +2685,10 @@ fr_info_t *fin;
*/
if ((fin->fin_v != 4) || (fin->fin_hlen != sizeof(ip_t)) ||
(fin->fin_plen < ICMPERR_MINPKTLEN) ||
- !(fin->fin_flx & FI_ICMPERR))
+ !(fin->fin_flx & FI_ICMPERR)) {
+ SBUMPD(ipf_state_stats, iss_icmp_bad);
return NULL;
+ }
ic = fin->fin_dp;
type = ic->icmp_type;
@@ -2106,15 +2697,20 @@ fr_info_t *fin;
* Check if the at least the old IP header (with options) and
* 8 bytes of payload is present.
*/
- if (fin->fin_plen < ICMPERR_MAXPKTLEN + ((IP_HL(oip) - 5) << 2))
+ if (fin->fin_plen < ICMPERR_MAXPKTLEN + ((IP_HL(oip) - 5) << 2)) {
+ SBUMPDX(ipf_state_stats, iss_icmp_short, iss_icmp_short_1);
return NULL;
+ }
/*
* Sanity Checks.
*/
len = fin->fin_dlen - ICMPERR_ICMPHLEN;
- if ((len <= 0) || ((IP_HL(oip) << 2) > len))
+ if ((len <= 0) || ((IP_HL(oip) << 2) > len)) {
+ DT2(iss_icmp_len, fr_info_t *, fin, struct ip*, oip);
+ SBUMPDX(ipf_state_stats, iss_icmp_short, iss_icmp_short_1);
return NULL;
+ }
/*
* Is the buffer big enough for all of it ? It's the size of the IP
@@ -2122,7 +2718,7 @@ fr_info_t *fin;
* 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 guarantee it is
+ * do the pullup early in ipf_check() and thus can't guarantee it is
* all here now.
*/
#ifdef _KERNEL
@@ -2131,14 +2727,19 @@ fr_info_t *fin;
m = fin->fin_m;
# if defined(MENTAT)
- if ((char *)oip + len > (char *)m->b_wptr)
+ if ((char *)oip + len > (char *)m->b_wptr) {
+ SBUMPDX(ipf_state_stats, iss_icmp_short, iss_icmp_short_2);
return NULL;
+ }
# else
- if ((char *)oip + len > (char *)fin->fin_ip + m->m_len)
+ if ((char *)oip + len > (char *)fin->fin_ip + m->m_len) {
+ SBUMPDX(ipf_state_stats, iss_icmp_short, iss_icmp_short_3);
return NULL;
+ }
# endif
}
#endif
+
bcopy((char *)fin, (char *)&ofin, sizeof(*fin));
/*
@@ -2154,37 +2755,42 @@ fr_info_t *fin;
* 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.
+ * a kernel panic. ipf_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, like
- * oip->ip_off - it is still in network byte order so fix it.
+ * oip->ip_len.
*/
savelen = oip->ip_len;
- oip->ip_len = len;
- oip->ip_off = ntohs(oip->ip_off);
+ oip->ip_len = htons(len);
ofin.fin_flx = FI_NOCKSUM;
ofin.fin_v = 4;
ofin.fin_ip = oip;
ofin.fin_m = NULL; /* if dereferenced, panic XXX */
ofin.fin_mp = NULL; /* if dereferenced, panic XXX */
- (void) fr_makefrip(IP_HL(oip) << 2, oip, &ofin);
+ (void) ipf_makefrip(IP_HL(oip) << 2, oip, &ofin);
ofin.fin_ifp = fin->fin_ifp;
ofin.fin_out = !fin->fin_out;
+
+ 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;
+
/*
- * Reset the short and bad flag here because in fr_matchsrcdst()
+ * Reset the short and bad flag here because in ipf_matchsrcdst()
* the flags for the current packet (fin_flx) are compared against
* those for the existing session.
*/
ofin.fin_flx &= ~(FI_BAD|FI_SHORT);
/*
- * Put old values of ip_len and ip_off back as we don't know
- * if we have to forward the packet (or process it again.
+ * Put old values of ip_len back as we don't know
+ * if we have to forward the packet or process it again.
*/
oip->ip_len = savelen;
- oip->ip_off = htons(oip->ip_off);
switch (oip->ip_p)
{
@@ -2196,75 +2802,52 @@ fr_info_t *fin;
* XXX theoretically ICMP_ECHOREP and the other reply's are
* ICMP query's as well, but adding them here seems strange XXX
*/
- if ((ofin.fin_flx & FI_ICMPERR) != 0)
+ if ((ofin.fin_flx & FI_ICMPERR) != 0) {
+ DT1(iss_icmp_icmperr, fr_info_t *, &ofin);
+ SBUMP(ipf_state_stats.iss_icmp_icmperr);
return NULL;
+ }
/*
* perform a lookup of the ICMP packet in the state table
*/
icmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2));
- 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 = DOUBLE_HASH(hv);
- READ_ENTER(&ipf_state);
- for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) {
+ READ_ENTER(&softc->ipf_state);
+ for (isp = &softs->ipf_state_table[hv];
+ ((is = *isp) != NULL); ) {
isp = &is->is_hnext;
if ((is->is_p != pr) || (is->is_v != 4))
continue;
if (is->is_pass & FR_NOICMPERR)
continue;
- is = fr_matchsrcdst(&ofin, is, &src, &dst,
+
+ is = ipf_matchsrcdst(&ofin, is, &src, &dst,
NULL, FI_ICMPCMP);
- if (is != NULL) {
- /*
- * i : the index of this packet (the icmp
- * unreachable)
- * oi : the index of the original packet found
- * in the icmp header (i.e. the packet
- * causing this icmp)
- * backward : original packet was backward
- * compared to the state
- */
- backward = IP6_NEQ(&is->is_src, &src);
- fin->fin_rev = !backward;
- i = (!backward << 1) + fin->fin_out;
- oi = (backward << 1) + ofin.fin_out;
- if (is->is_icmppkts[i] > is->is_pkts[oi])
- continue;
- ips_stats.iss_hits++;
- is->is_icmppkts[i]++;
+ if ((is != NULL) && !ipf_allowstateicmp(fin, is, &src))
return is;
- }
}
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
+ SBUMPDX(ipf_state_stats, iss_icmp_miss, iss_icmp_miss_1);
return NULL;
case IPPROTO_TCP :
case IPPROTO_UDP :
break;
default :
+ SBUMPDX(ipf_state_stats, iss_icmp_miss, iss_icmp_miss_2);
return NULL;
}
tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 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 += tcp->th_dport;;
+ hv += tcp->th_sport;;
hv = DOUBLE_HASH(hv);
- READ_ENTER(&ipf_state);
- for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) {
+ READ_ENTER(&softc->ipf_state);
+ for (isp = &softs->ipf_state_table[hv]; ((is = *isp) != NULL); ) {
isp = &is->is_hnext;
/*
* Only allow this icmp though if the
@@ -2276,40 +2859,93 @@ fr_info_t *fin;
* short flag is set.
*/
if ((is->is_p == pr) && (is->is_v == 4) &&
- (is = fr_matchsrcdst(&ofin, is, &src, &dst,
- tcp, FI_ICMPCMP))) {
- /*
- * i : the index of this packet (the icmp unreachable)
- * oi : the index of the original packet found in the
- * icmp header (i.e. the packet causing this icmp)
- * backward : original packet was backward compared to
- * the state
- */
- backward = IP6_NEQ(&is->is_src, &src);
- fin->fin_rev = !backward;
- i = (!backward << 1) + fin->fin_out;
- oi = (backward << 1) + ofin.fin_out;
-
- if (((is->is_pass & FR_NOICMPERR) != 0) ||
- (is->is_icmppkts[i] > is->is_pkts[oi]))
- break;
- ips_stats.iss_hits++;
- is->is_icmppkts[i]++;
- /*
- * we deliberately do not touch the timeouts
- * for the accompanying state table entry.
- * It remains to be seen if that is correct. XXX
- */
- return is;
+ (is = ipf_matchsrcdst(&ofin, is, &src, &dst,
+ tcp, FI_ICMPCMP))) {
+ if (ipf_allowstateicmp(fin, is, &src) == 0)
+ return is;
}
}
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
+ SBUMPDX(ipf_state_stats, iss_icmp_miss, iss_icmp_miss_3);
return NULL;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_ipsmove */
+/* Function: ipf_allowstateicmp */
+/* Returns: int - 1 = packet denied, 0 = packet allowed */
+/* Parameters: fin(I) - pointer to packet information */
+/* is(I) - pointer to state table entry */
+/* src(I) - source address to check permission for */
+/* */
+/* For an ICMP packet that has so far matched a state table entry, check if */
+/* there are any further refinements that might mean we want to block this */
+/* packet. This code isn't specific to either IPv4 or IPv6. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_allowstateicmp(fin, is, src)
+ fr_info_t *fin;
+ ipstate_t *is;
+ i6addr_t *src;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
+ frentry_t *savefr;
+ frentry_t *fr;
+ u_32_t ipass;
+ int backward;
+ int oi;
+ int i;
+
+ fr = is->is_rule;
+ if (fr != NULL && fr->fr_icmpgrp != NULL) {
+ savefr = fin->fin_fr;
+ fin->fin_fr = fr->fr_icmpgrp->fg_start;
+
+ ipass = ipf_scanlist(fin, softc->ipf_pass);
+ fin->fin_fr = savefr;
+ if (FR_ISBLOCK(ipass)) {
+ SBUMPD(ipf_state_stats, iss_icmp_headblock);
+ return 1;
+ }
+ }
+
+ /*
+ * i : the index of this packet (the icmp unreachable)
+ * oi : the index of the original packet found in the
+ * icmp header (i.e. the packet causing this icmp)
+ * backward : original packet was backward compared to
+ * the state
+ */
+ backward = IP6_NEQ(&is->is_src, src);
+ fin->fin_rev = !backward;
+ i = (!backward << 1) + fin->fin_out;
+ oi = (backward << 1) + !fin->fin_out;
+
+ if (is->is_pass & FR_NOICMPERR) {
+ SBUMPD(ipf_state_stats, iss_icmp_banned);
+ return 1;
+ }
+ if (is->is_icmppkts[i] > is->is_pkts[oi]) {
+ SBUMPD(ipf_state_stats, iss_icmp_toomany);
+ return 1;
+ }
+
+ DT2(iss_icmp_hits, fr_info_t *, fin, ipstate_t *, is);
+ SBUMP(ipf_state_stats.iss_icmp_hits);
+ is->is_icmppkts[i]++;
+
+ /*
+ * we deliberately do not touch the timeouts
+ * for the accompanying state table entry.
+ * It remains to be seen if that is correct. XXX
+ */
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_ipsmove */
/* Returns: Nil */
/* Parameters: is(I) - pointer to state table entry */
/* hv(I) - new hash value for state table entry */
@@ -2317,14 +2953,19 @@ fr_info_t *fin;
/* */
/* Move a state entry from one position in the hash table to another. */
/* ------------------------------------------------------------------------ */
-static void fr_ipsmove(is, hv)
-ipstate_t *is;
-u_int hv;
+static void
+ipf_ipsmove(softs, is, hv)
+ ipf_state_softc_t *softs;
+ ipstate_t *is;
+ u_int hv;
{
ipstate_t **isp;
u_int hvm;
hvm = is->is_hv;
+
+ /* TRACE is, is_hv, hvm */
+
/*
* Remove the hash from the old location...
*/
@@ -2332,21 +2973,24 @@ u_int hv;
if (is->is_hnext)
is->is_hnext->is_phnext = isp;
*isp = is->is_hnext;
- if (ips_table[hvm] == NULL)
- ips_stats.iss_inuse--;
- ips_stats.iss_bucketlen[hvm]--;
+ if (softs->ipf_state_table[hvm] == NULL)
+ softs->ipf_state_stats.iss_inuse--;
+ softs->ipf_state_stats.iss_bucketlen[hvm]--;
/*
* ...and put the hash in the new one.
*/
hvm = DOUBLE_HASH(hv);
is->is_hv = hvm;
- isp = &ips_table[hvm];
+
+ /* TRACE is, hv, is_hv, hvm */
+
+ isp = &softs->ipf_state_table[hvm];
if (*isp)
(*isp)->is_phnext = &is->is_hnext;
else
- ips_stats.iss_inuse++;
- ips_stats.iss_bucketlen[hvm]++;
+ softs->ipf_state_stats.iss_inuse++;
+ softs->ipf_state_stats.iss_bucketlen[hvm]++;
is->is_phnext = isp;
is->is_hnext = *isp;
*isp = is;
@@ -2354,23 +2998,28 @@ u_int hv;
/* ------------------------------------------------------------------------ */
-/* Function: fr_stlookup */
+/* Function: ipf_state_lookup */
/* Returns: ipstate_t* - NULL == no matching state found, */
/* else pointer to state information is returned */
-/* Parameters: fin(I) - pointer to packet information */
-/* tcp(I) - pointer to TCP/UDP header. */
+/* Parameters: fin(I) - pointer to packet information */
+/* tcp(I) - pointer to TCP/UDP header. */
+/* ifqp(O) - pointer for storing tailq timeout */
/* */
/* Search the state table for a matching entry to the packet described by */
-/* the contents of *fin. */
+/* the contents of *fin. For certain protocols, when a match is found the */
+/* timeout queue is also selected and stored in ifpq if it is non-NULL. */
/* */
/* If we return NULL then no lock on ipf_state is held. */
/* If we return non-null then a read-lock on ipf_state is held. */
/* ------------------------------------------------------------------------ */
-ipstate_t *fr_stlookup(fin, tcp, ifqp)
-fr_info_t *fin;
-tcphdr_t *tcp;
-ipftq_t **ifqp;
+ipstate_t *
+ipf_state_lookup(fin, tcp, ifqp)
+ fr_info_t *fin;
+ tcphdr_t *tcp;
+ ipftq_t **ifqp;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
u_int hv, hvm, pr, v, tryagain;
ipstate_t *is, **isp;
u_short dport, sport;
@@ -2415,6 +3064,8 @@ ipftq_t **ifqp;
}
}
+ /* TRACE fin_saddr, fin_daddr, hv */
+
/*
* Search the hash table for matching packet header info.
*/
@@ -2429,28 +3080,22 @@ ipftq_t **ifqp;
hv += ic->icmp_id;
}
}
- READ_ENTER(&ipf_state);
+ READ_ENTER(&softc->ipf_state);
icmp6again:
hvm = DOUBLE_HASH(hv);
- for (isp = &ips_table[hvm]; ((is = *isp) != NULL); ) {
+ for (isp = &softs->ipf_state_table[hvm];
+ ((is = *isp) != NULL); ) {
isp = &is->is_hnext;
- /*
- * If a connection is about to be deleted, no packets
- * are allowed to match it.
- */
- if (is->is_sti.tqe_ifq == &ips_deletetq)
- continue;
-
if ((is->is_p != pr) || (is->is_v != v))
continue;
- is = fr_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP);
+ is = ipf_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP);
if (is != NULL &&
- fr_matchicmpqueryreply(v, &is->is_icmp,
+ ipf_matchicmpqueryreply(v, &is->is_icmp,
ic, fin->fin_rev)) {
if (fin->fin_rev)
- ifq = &ips_icmpacktq;
+ ifq = &softs->ipf_state_icmpacktq;
else
- ifq = &ips_icmptq;
+ ifq = &softs->ipf_state_icmptq;
break;
}
}
@@ -2461,12 +3106,12 @@ icmp6again:
hv += fin->fin_fi.fi_src.i6[1];
hv += fin->fin_fi.fi_src.i6[2];
hv += fin->fin_fi.fi_src.i6[3];
- fr_ipsmove(is, hv);
- MUTEX_DOWNGRADE(&ipf_state);
+ ipf_ipsmove(softs, is, hv);
+ MUTEX_DOWNGRADE(&softc->ipf_state);
}
break;
}
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
/*
* No matching icmp state entry. Perhaps this is a
@@ -2478,18 +3123,19 @@ icmp6again:
* advantage of this requires some significant code changes
* to handle the specific types where that is the case.
*/
- if ((ips_stats.iss_wild != 0) && (v == 6) && (tryagain == 0) &&
- !IN6_IS_ADDR_MULTICAST(&fin->fin_fi.fi_src.in6)) {
+ if ((softs->ipf_state_stats.iss_wild != 0) &&
+ ((fin->fin_flx & FI_NOWILD) == 0) &&
+ (v == 6) && (tryagain == 0)) {
hv -= fin->fin_fi.fi_src.i6[0];
hv -= fin->fin_fi.fi_src.i6[1];
hv -= fin->fin_fi.fi_src.i6[2];
hv -= fin->fin_fi.fi_src.i6[3];
tryagain = 1;
- WRITE_ENTER(&ipf_state);
+ WRITE_ENTER(&softc->ipf_state);
goto icmp6again;
}
- is = fr_checkicmp6matchingstate(fin);
+ is = ipf_checkicmp6matchingstate(fin);
if (is != NULL)
return is;
break;
@@ -2500,25 +3146,26 @@ icmp6again:
hv += ic->icmp_id;
}
hv = DOUBLE_HASH(hv);
- READ_ENTER(&ipf_state);
- for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) {
+ READ_ENTER(&softc->ipf_state);
+ for (isp = &softs->ipf_state_table[hv];
+ ((is = *isp) != NULL); ) {
isp = &is->is_hnext;
if ((is->is_p != pr) || (is->is_v != v))
continue;
- is = fr_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP);
+ is = ipf_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP);
if ((is != NULL) &&
(ic->icmp_id == is->is_icmp.ici_id) &&
- fr_matchicmpqueryreply(v, &is->is_icmp,
+ ipf_matchicmpqueryreply(v, &is->is_icmp,
ic, fin->fin_rev)) {
if (fin->fin_rev)
- ifq = &ips_icmpacktq;
+ ifq = &softs->ipf_state_icmpacktq;
else
- ifq = &ips_icmptq;
+ ifq = &softs->ipf_state_icmptq;
break;
}
}
if (is == NULL) {
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
}
break;
@@ -2531,18 +3178,23 @@ icmp6again:
hv += dport;
oow = 0;
tryagain = 0;
- READ_ENTER(&ipf_state);
+ READ_ENTER(&softc->ipf_state);
retry_tcpudp:
hvm = DOUBLE_HASH(hv);
- for (isp = &ips_table[hvm]; ((is = *isp) != NULL); ) {
+
+ /* TRACE hv, hvm */
+
+ for (isp = &softs->ipf_state_table[hvm];
+ ((is = *isp) != NULL); ) {
isp = &is->is_hnext;
if ((is->is_p != pr) || (is->is_v != v))
continue;
fin->fin_flx &= ~FI_OOW;
- is = fr_matchsrcdst(fin, is, &src, &dst, tcp, FI_CMP);
+ is = ipf_matchsrcdst(fin, is, &src, &dst, tcp, FI_CMP);
if (is != NULL) {
if (pr == IPPROTO_TCP) {
- if (!fr_tcpstate(fin, tcp, is)) {
+ if (!ipf_state_tcp(softc, softs, fin,
+ tcp, is)) {
oow |= fin->fin_flx & FI_OOW;
continue;
}
@@ -2555,14 +3207,15 @@ retry_tcpudp:
!(is->is_flags & (SI_CLONE|SI_WILDP|SI_WILDA))) {
hv += dport;
hv += sport;
- fr_ipsmove(is, hv);
- MUTEX_DOWNGRADE(&ipf_state);
+ ipf_ipsmove(softs, is, hv);
+ MUTEX_DOWNGRADE(&softc->ipf_state);
}
break;
}
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
- if (ips_stats.iss_wild) {
+ if ((softs->ipf_state_stats.iss_wild != 0) &&
+ ((fin->fin_flx & FI_NOWILD) == 0)) {
if (tryagain == 0) {
hv -= dport;
hv -= sport;
@@ -2584,7 +3237,7 @@ retry_tcpudp:
}
tryagain++;
if (tryagain <= 2) {
- WRITE_ENTER(&ipf_state);
+ WRITE_ENTER(&softc->ipf_state);
goto retry_tcpudp;
}
}
@@ -2602,19 +3255,20 @@ retry_tcpudp:
default :
ifqp = NULL;
hvm = DOUBLE_HASH(hv);
- READ_ENTER(&ipf_state);
- for (isp = &ips_table[hvm]; ((is = *isp) != NULL); ) {
+ READ_ENTER(&softc->ipf_state);
+ for (isp = &softs->ipf_state_table[hvm];
+ ((is = *isp) != NULL); ) {
isp = &is->is_hnext;
if ((is->is_p != pr) || (is->is_v != v))
continue;
- is = fr_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP);
+ is = ipf_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP);
if (is != NULL) {
- ifq = &ips_iptq;
+ ifq = &softs->ipf_state_iptq;
break;
}
}
if (is == NULL) {
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
}
break;
}
@@ -2625,90 +3279,45 @@ retry_tcpudp:
ifq = is->is_tqehead[fin->fin_rev];
if (ifq != NULL && ifqp != NULL)
*ifqp = ifq;
+ } else {
+ SBUMP(ipf_state_stats.iss_lookup_miss);
}
return is;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_updatestate */
-/* Returns: Nil */
-/* Parameters: fin(I) - pointer to packet information */
-/* is(I) - pointer to state table entry */
-/* Read Locks: ipf_state */
-/* */
-/* Updates packet and byte counters for a newly received packet. Seeds the */
-/* fragment cache with a new entry as required. */
-/* ------------------------------------------------------------------------ */
-void fr_updatestate(fin, is, ifq)
-fr_info_t *fin;
-ipstate_t *is;
-ipftq_t *ifq;
-{
- ipftqent_t *tqe;
- int i, pass;
-
- i = (fin->fin_rev << 1) + fin->fin_out;
-
- /*
- * For TCP packets, ifq == NULL. For all others, check if this new
- * queue is different to the last one it was on and move it if so.
- */
- tqe = &is->is_sti;
- MUTEX_ENTER(&is->is_lock);
- if ((tqe->tqe_flags & TQE_RULEBASED) != 0)
- ifq = is->is_tqehead[fin->fin_rev];
-
- if (ifq != NULL)
- fr_movequeue(tqe, tqe->tqe_ifq, ifq);
-
- is->is_pkts[i]++;
- is->is_bytes[i] += fin->fin_plen;
- MUTEX_EXIT(&is->is_lock);
-
-#ifdef IPFILTER_SYNC
- if (is->is_flags & IS_STATESYNC)
- ipfsync_update(SMC_STATE, fin, is->is_sync);
-#endif
-
- ATOMIC_INCL(ips_stats.iss_hits);
-
- fin->fin_fr = is->is_rule;
-
- /*
- * If this packet is a fragment and the rule says to track fragments,
- * then create a new fragment cache entry.
- */
- pass = is->is_pass;
- if ((fin->fin_flx & FI_FRAG) && FR_ISPASS(pass))
- (void) fr_newfrag(fin, pass ^ FR_KEEPSTATE);
-}
-
-
-/* ------------------------------------------------------------------------ */
-/* Function: fr_checkstate */
+/* Function: ipf_state_check */
/* Returns: frentry_t* - NULL == search failed, */
/* else pointer to rule for matching state */
-/* Parameters: ifp(I) - pointer to interface */
+/* Parameters: fin(I) - pointer to packet information */
/* passp(I) - pointer to filtering result flags */
/* */
/* Check if a packet is associated with an entry in the state table. */
/* ------------------------------------------------------------------------ */
-frentry_t *fr_checkstate(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+frentry_t *
+ipf_state_check(fin, passp)
+ fr_info_t *fin;
+ u_32_t *passp;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
+ ipftqent_t *tqe;
ipstate_t *is;
frentry_t *fr;
tcphdr_t *tcp;
ipftq_t *ifq;
u_int pass;
+ int inout;
- if (fr_state_lock || (ips_list == NULL) ||
- (fin->fin_flx & (FI_SHORT|FI_STATE|FI_FRAGBODY|FI_BAD)))
+ if (softs->ipf_state_lock || (softs->ipf_state_list == NULL))
return NULL;
- is = NULL;
+ if (fin->fin_flx & (FI_SHORT|FI_FRAGBODY|FI_BAD)) {
+ SBUMPD(ipf_state_stats, iss_check_bad);
+ return NULL;
+ }
+
if ((fin->fin_flx & FI_TCPUDP) ||
(fin->fin_fi.fi_p == IPPROTO_ICMP)
#ifdef USE_INET6
@@ -2719,13 +3328,12 @@ u_32_t *passp;
else
tcp = NULL;
+ ifq = NULL;
/*
* Search the hash table for matching packet header info.
*/
- ifq = NULL;
- is = fin->fin_state;
- if (is == NULL)
- is = fr_stlookup(fin, tcp, &ifq);
+ is = ipf_state_lookup(fin, tcp, &ifq);
+
switch (fin->fin_p)
{
#ifdef USE_INET6
@@ -2733,9 +3341,7 @@ u_32_t *passp;
if (is != NULL)
break;
if (fin->fin_v == 6) {
- is = fr_checkicmp6matchingstate(fin);
- if (is != NULL)
- goto matched;
+ is = ipf_checkicmp6matchingstate(fin);
}
break;
#endif
@@ -2746,56 +3352,92 @@ u_32_t *passp;
* No matching icmp state entry. Perhaps this is a
* response to another state entry.
*/
- is = fr_checkicmpmatchingstate(fin);
- if (is != NULL)
- goto matched;
+ is = ipf_checkicmpmatchingstate(fin);
break;
+
case IPPROTO_TCP :
if (is == NULL)
break;
if (is->is_pass & FR_NEWISN) {
if (fin->fin_out == 0)
- fr_fixinisn(fin, is);
+ ipf_fixinisn(fin, is);
else if (fin->fin_out == 1)
- fr_fixoutisn(fin, is);
+ ipf_fixoutisn(fin, is);
}
break;
default :
if (fin->fin_rev)
- ifq = &ips_udpacktq;
+ ifq = &softs->ipf_state_udpacktq;
else
- ifq = &ips_udptq;
+ ifq = &softs->ipf_state_udptq;
break;
}
if (is == NULL) {
- ATOMIC_INCL(ips_stats.iss_miss);
+ SBUMP(ipf_state_stats.iss_check_miss);
return NULL;
}
-matched:
fr = is->is_rule;
if (fr != NULL) {
if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) {
- if (fin->fin_nattag == NULL)
+ if (fin->fin_nattag == NULL) {
+ RWLOCK_EXIT(&softc->ipf_state);
+ SBUMPD(ipf_state_stats, iss_check_notag);
return NULL;
- if (fr_matchtag(&fr->fr_nattag, fin->fin_nattag) != 0)
+ }
+ if (ipf_matchtag(&fr->fr_nattag, fin->fin_nattag)!=0) {
+ RWLOCK_EXIT(&softc->ipf_state);
+ SBUMPD(ipf_state_stats, iss_check_nattag);
return NULL;
+ }
}
- (void) strncpy(fin->fin_group, fr->fr_group, FR_GROUPLEN);
+ (void) strncpy(fin->fin_group, FR_NAME(fr, fr_group),
+ FR_GROUPLEN);
fin->fin_icode = fr->fr_icode;
}
fin->fin_rule = is->is_rulen;
- pass = is->is_pass;
- fr_updatestate(fin, is, ifq);
+ fin->fin_fr = fr;
+
+ /*
+ * If this packet is a fragment and the rule says to track fragments,
+ * then create a new fragment cache entry.
+ */
+ if ((fin->fin_flx & FI_FRAG) && FR_ISPASS(is->is_pass))
+ (void) ipf_frag_new(softc, fin, is->is_pass);
+
+ /*
+ * For TCP packets, ifq == NULL. For all others, check if this new
+ * queue is different to the last one it was on and move it if so.
+ */
+ tqe = &is->is_sti;
+ if ((tqe->tqe_flags & TQE_RULEBASED) != 0)
+ ifq = is->is_tqehead[fin->fin_rev];
- fin->fin_state = is;
- is->is_touched = fr_ticks;
MUTEX_ENTER(&is->is_lock);
- is->is_ref++;
+
+ if (ifq != NULL)
+ ipf_movequeue(softc->ipf_ticks, tqe, tqe->tqe_ifq, ifq);
+
+ inout = (fin->fin_rev << 1) + fin->fin_out;
+ is->is_pkts[inout]++;
+ is->is_bytes[inout] += fin->fin_plen;
+ fin->fin_pktnum = is->is_pkts[inout] + is->is_icmppkts[inout];
+
MUTEX_EXIT(&is->is_lock);
- RWLOCK_EXIT(&ipf_state);
+
+ pass = is->is_pass;
+
+ if (is->is_flags & IS_STATESYNC)
+ ipf_sync_update(softc, SMC_STATE, fin, is->is_sync);
+
+ RWLOCK_EXIT(&softc->ipf_state);
+
+ SBUMP(ipf_state_stats.iss_hits);
+
+ fin->fin_dif = &is->is_dif;
+ fin->fin_tif = &is->is_tifs[fin->fin_rev];
fin->fin_flx |= FI_STATE;
if ((pass & FR_LOGFIRST) != 0)
pass &= ~(FR_LOGFIRST|FR_LOG);
@@ -2805,17 +3447,18 @@ matched:
/* ------------------------------------------------------------------------ */
-/* Function: fr_fixoutisn */
+/* Function: ipf_fixoutisn */
/* Returns: Nil */
-/* Parameters: fin(I) - pointer to packet information */
+/* Parameters: fin(I) - pointer to packet information */
/* is(I) - pointer to master state structure */
/* */
/* Called only for outbound packets, adjusts the sequence number and the */
/* TCP checksum to match that change. */
/* ------------------------------------------------------------------------ */
-static void fr_fixoutisn(fin, is)
-fr_info_t *fin;
-ipstate_t *is;
+static void
+ipf_fixoutisn(fin, is)
+ fr_info_t *fin;
+ ipstate_t *is;
{
tcphdr_t *tcp;
int rev;
@@ -2824,26 +3467,26 @@ ipstate_t *is;
tcp = fin->fin_dp;
rev = fin->fin_rev;
if ((is->is_flags & IS_ISNSYN) != 0) {
- if (rev == 0) {
+ if ((rev == 0) && (fin->fin_cksum < FI_CK_L4PART)) {
seq = ntohl(tcp->th_seq);
seq += is->is_isninc[0];
tcp->th_seq = htonl(seq);
- fix_outcksum(fin, &tcp->th_sum, is->is_sumd[0]);
+ ipf_fix_outcksum(0, &tcp->th_sum, is->is_sumd[0], 0);
}
}
if ((is->is_flags & IS_ISNACK) != 0) {
- if (rev == 1) {
+ if ((rev == 1) && (fin->fin_cksum < FI_CK_L4PART)) {
seq = ntohl(tcp->th_seq);
seq += is->is_isninc[1];
tcp->th_seq = htonl(seq);
- fix_outcksum(fin, &tcp->th_sum, is->is_sumd[1]);
+ ipf_fix_outcksum(0, &tcp->th_sum, is->is_sumd[1], 0);
}
}
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_fixinisn */
+/* Function: ipf_fixinisn */
/* Returns: Nil */
/* Parameters: fin(I) - pointer to packet information */
/* is(I) - pointer to master state structure */
@@ -2851,9 +3494,10 @@ ipstate_t *is;
/* Called only for inbound packets, adjusts the acknowledge number and the */
/* TCP checksum to match that change. */
/* ------------------------------------------------------------------------ */
-static void fr_fixinisn(fin, is)
-fr_info_t *fin;
-ipstate_t *is;
+static void
+ipf_fixinisn(fin, is)
+ fr_info_t *fin;
+ ipstate_t *is;
{
tcphdr_t *tcp;
int rev;
@@ -2862,28 +3506,29 @@ ipstate_t *is;
tcp = fin->fin_dp;
rev = fin->fin_rev;
if ((is->is_flags & IS_ISNSYN) != 0) {
- if (rev == 1) {
+ if ((rev == 1) && (fin->fin_cksum < FI_CK_L4PART)) {
ack = ntohl(tcp->th_ack);
ack -= is->is_isninc[0];
tcp->th_ack = htonl(ack);
- fix_incksum(fin, &tcp->th_sum, is->is_sumd[0]);
+ ipf_fix_incksum(0, &tcp->th_sum, is->is_sumd[0], 0);
}
}
if ((is->is_flags & IS_ISNACK) != 0) {
- if (rev == 0) {
+ if ((rev == 0) && (fin->fin_cksum < FI_CK_L4PART)) {
ack = ntohl(tcp->th_ack);
ack -= is->is_isninc[1];
tcp->th_ack = htonl(ack);
- fix_incksum(fin, &tcp->th_sum, is->is_sumd[1]);
+ ipf_fix_incksum(0, &tcp->th_sum, is->is_sumd[1], 0);
}
}
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_statesync */
+/* Function: ipf_state_sync */
/* Returns: Nil */
-/* Parameters: ifp(I) - pointer to interface */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* ifp(I) - pointer to interface */
/* */
/* Walk through all state entries and if an interface pointer match is */
/* found then look it up again, based on its name in case the pointer has */
@@ -2892,40 +3537,45 @@ ipstate_t *is;
/* If ifp is passed in as being non-null then we are only doing updates for */
/* existing, matching, uses of it. */
/* ------------------------------------------------------------------------ */
-void fr_statesync(ifp)
-void *ifp;
+void
+ipf_state_sync(softc, ifp)
+ ipf_main_softc_t *softc;
+ void *ifp;
{
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
ipstate_t *is;
int i;
- if (fr_running <= 0)
+ if (softc->ipf_running <= 0)
return;
- WRITE_ENTER(&ipf_state);
+ WRITE_ENTER(&softc->ipf_state);
- if (fr_running <= 0) {
- RWLOCK_EXIT(&ipf_state);
+ if (softc->ipf_running <= 0) {
+ RWLOCK_EXIT(&softc->ipf_state);
return;
}
- for (is = ips_list; is; is = is->is_next) {
+ for (is = softs->ipf_state_list; is; is = is->is_next) {
/*
* Look up all the interface names in the state entry.
*/
for (i = 0; i < 4; i++) {
if (ifp == NULL || ifp == is->is_ifp[i])
- is->is_ifp[i] = fr_resolvenic(is->is_ifname[i],
+ is->is_ifp[i] = ipf_resolvenic(softc,
+ is->is_ifname[i],
is->is_v);
}
}
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_delstate */
-/* Returns: int - 0 = entry deleted, else reference count on struct */
-/* Parameters: is(I) - pointer to state structure to delete */
+/* Function: ipf_state_del */
+/* Returns: int - 0 = deleted, else refernce count on active struct */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* is(I) - pointer to state structure to delete */
/* why(I) - if not 0, log reason why it was deleted */
/* Write Locks: ipf_state */
/* */
@@ -2933,10 +3583,15 @@ void *ifp;
/* and timeout queue lists. Make adjustments to hash table statistics and */
/* global counters as required. */
/* ------------------------------------------------------------------------ */
-static int fr_delstate(is, why)
-ipstate_t *is;
-int why;
+static int
+ipf_state_del(softc, is, why)
+ ipf_main_softc_t *softc;
+ ipstate_t *is;
+ int why;
{
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
+ int orphan = 1;
+ frentry_t *fr;
/*
* Since we want to delete this, remove it from the state table,
@@ -2946,22 +3601,23 @@ int why;
*is->is_phnext = is->is_hnext;
if (is->is_hnext != NULL)
is->is_hnext->is_phnext = is->is_phnext;
- if (ips_table[is->is_hv] == NULL)
- ips_stats.iss_inuse--;
- ips_stats.iss_bucketlen[is->is_hv]--;
+ if (softs->ipf_state_table[is->is_hv] == NULL)
+ softs->ipf_state_stats.iss_inuse--;
+ softs->ipf_state_stats.iss_bucketlen[is->is_hv]--;
is->is_phnext = NULL;
is->is_hnext = NULL;
+ orphan = 0;
}
/*
- * Because ips_stats.iss_wild is a count of entries in the state
+ * Because ipf_state_stats.iss_wild is a count of entries in the state
* table that have wildcard flags set, only decerement it once
* and do it here.
*/
if (is->is_flags & (SI_WILDP|SI_WILDA)) {
if (!(is->is_flags & SI_CLONED)) {
- ATOMIC_DECL(ips_stats.iss_wild);
+ ATOMIC_DECL(softs->ipf_state_stats.iss_wild);
}
is->is_flags &= ~(SI_WILDP|SI_WILDA);
}
@@ -2970,47 +3626,56 @@ int why;
* Next, remove it from the timeout queue it is in.
*/
if (is->is_sti.tqe_ifq != NULL)
- fr_deletequeueentry(&is->is_sti);
-
- if (is->is_me != NULL) {
- *is->is_me = NULL;
- is->is_me = NULL;
- }
+ ipf_deletequeueentry(&is->is_sti);
/*
* If it is still in use by something else, do not go any further,
* but note that at this point it is now an orphan. How can this
- * be? fr_state_flush() calls fr_delete() directly because it wants
+ * be? ipf_state_flush() calls ipf_delete() directly because it wants
* to empty the table out and if something has a hold on a state
* entry (such as ipfstat), it'll do the deref path that'll bring
* us back here to do the real delete & free.
*/
MUTEX_ENTER(&is->is_lock);
+ if (is->is_me != NULL) {
+ *is->is_me = NULL;
+ is->is_me = NULL;
+ is->is_ref--;
+ }
if (is->is_ref > 1) {
+ int refs;
+
is->is_ref--;
+ refs = is->is_ref;
MUTEX_EXIT(&is->is_lock);
- return is->is_ref;
+ if (!orphan)
+ softs->ipf_state_stats.iss_orphan++;
+ return refs;
}
MUTEX_EXIT(&is->is_lock);
+ fr = is->is_rule;
+ is->is_rule = NULL;
+ if (fr != NULL) {
+ if (fr->fr_srctrack.ht_max_nodes != 0) {
+ (void) ipf_ht_node_del(&fr->fr_srctrack,
+ is->is_family, &is->is_src);
+ }
+ }
+
is->is_ref = 0;
if (is->is_tqehead[0] != NULL) {
- if (fr_deletetimeoutqueue(is->is_tqehead[0]) == 0)
- fr_freetimeoutqueue(is->is_tqehead[0]);
+ if (ipf_deletetimeoutqueue(is->is_tqehead[0]) == 0)
+ ipf_freetimeoutqueue(softc, is->is_tqehead[0]);
}
if (is->is_tqehead[1] != NULL) {
- if (fr_deletetimeoutqueue(is->is_tqehead[1]) == 0)
- fr_freetimeoutqueue(is->is_tqehead[1]);
+ if (ipf_deletetimeoutqueue(is->is_tqehead[1]) == 0)
+ ipf_freetimeoutqueue(softc, is->is_tqehead[1]);
}
-#ifdef IPFILTER_SYNC
if (is->is_sync)
- ipfsync_del(is->is_sync);
-#endif
-#ifdef IPFILTER_SCAN
- (void) ipsc_detachis(is);
-#endif
+ ipf_sync_del_state(softc->ipf_sync_soft, is->is_sync);
/*
* Now remove it from the linked list of known states
@@ -3025,94 +3690,100 @@ int why;
is->is_next = NULL;
}
- if (ipstate_logging != 0 && why != 0)
- ipstate_log(is, why);
+ if (softs->ipf_state_logging != 0 && why != 0)
+ ipf_state_log(softc, is, why);
if (is->is_p == IPPROTO_TCP)
- ips_stats.iss_fin++;
+ softs->ipf_state_stats.iss_fin++;
else
- ips_stats.iss_expire++;
+ softs->ipf_state_stats.iss_expire++;
+ if (orphan)
+ softs->ipf_state_stats.iss_orphan--;
- if (is->is_rule != NULL) {
- is->is_rule->fr_statecnt--;
- (void) fr_derefrule(&is->is_rule);
+ if (fr != NULL) {
+ fr->fr_statecnt--;
+ (void) ipf_derefrule(softc, &fr);
}
-#if defined(NEED_LOCAL_RAND) && defined(_KERNEL)
- ipf_rand_push(is, sizeof(*is));
-#endif
+ softs->ipf_state_stats.iss_active_proto[is->is_p]--;
MUTEX_DESTROY(&is->is_lock);
KFREE(is);
- ips_num--;
+ softs->ipf_state_stats.iss_active--;
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_timeoutstate */
+/* Function: ipf_state_expire */
/* Returns: Nil */
-/* Parameters: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
/* */
/* Slowly expire held state for thingslike UDP and ICMP. The algorithm */
/* used here is to keep the queue sorted with the oldest things at the top */
/* and the youngest at the bottom. So if the top one doesn't need to be */
/* expired then neither will any under it. */
/* ------------------------------------------------------------------------ */
-void fr_timeoutstate()
+void
+ipf_state_expire(softc)
+ ipf_main_softc_t *softc;
{
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
ipftq_t *ifq, *ifqnext;
ipftqent_t *tqe, *tqn;
ipstate_t *is;
SPL_INT(s);
SPL_NET(s);
- WRITE_ENTER(&ipf_state);
- for (ifq = ips_tqtqb; ifq != NULL; ifq = ifq->ifq_next)
+ WRITE_ENTER(&softc->ipf_state);
+ for (ifq = softs->ipf_state_tcptq; ifq != NULL; ifq = ifq->ifq_next)
for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
- if (tqe->tqe_die > fr_ticks)
+ if (tqe->tqe_die > softc->ipf_ticks)
break;
tqn = tqe->tqe_next;
is = tqe->tqe_parent;
- fr_delstate(is, ISL_EXPIRE);
+ ipf_state_del(softc, is, ISL_EXPIRE);
}
- for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) {
+ for (ifq = softs->ipf_state_usertq; ifq != NULL; ifq = ifqnext) {
ifqnext = ifq->ifq_next;
for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
- if (tqe->tqe_die > fr_ticks)
+ if (tqe->tqe_die > softc->ipf_ticks)
break;
tqn = tqe->tqe_next;
is = tqe->tqe_parent;
- fr_delstate(is, ISL_EXPIRE);
+ ipf_state_del(softc, is, ISL_EXPIRE);
}
}
- for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) {
+ for (ifq = softs->ipf_state_usertq; ifq != NULL; ifq = ifqnext) {
ifqnext = ifq->ifq_next;
if (((ifq->ifq_flags & IFQF_DELETE) != 0) &&
(ifq->ifq_ref == 0)) {
- fr_freetimeoutqueue(ifq);
+ ipf_freetimeoutqueue(softc, ifq);
}
}
- if (fr_state_doflush) {
- (void) fr_state_flush(2, 0);
- fr_state_doflush = 0;
+ if (softs->ipf_state_doflush) {
+ (void) ipf_state_flush(softc, 2, 0);
+ softs->ipf_state_doflush = 0;
+ softs->ipf_state_wm_last = softc->ipf_ticks;
}
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
SPL_X(s);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_state_flush */
+/* Function: ipf_state_flush */
/* Returns: int - 0 == success, -1 == failure */
-/* Parameters: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* which(I) - which flush action to perform */
+/* proto(I) - which protocol to flush (0 == ALL) */
/* Write Locks: ipf_state */
/* */
/* Flush state tables. Three actions currently defined: */
@@ -3126,12 +3797,15 @@ void fr_timeoutstate()
/* If that too fails, then work backwards in 30 second intervals */
/* for the last 30 minutes to at worst 30 seconds idle. */
/* ------------------------------------------------------------------------ */
-static int fr_state_flush(which, proto)
-int which, proto;
+int
+ipf_state_flush(softc, which, proto)
+ ipf_main_softc_t *softc;
+ int which, proto;
{
- ipftq_t *ifq, *ifqnext;
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
ipftqent_t *tqe, *tqn;
ipstate_t *is, **isp;
+ ipftq_t *ifq;
int removed;
SPL_INT(s);
@@ -3142,15 +3816,16 @@ int which, proto;
switch (which)
{
case 0 :
+ SBUMP(ipf_state_stats.iss_flush_all);
/*
* Style 0 flush removes everything...
*/
- for (isp = &ips_list; ((is = *isp) != NULL); ) {
+ for (isp = &softs->ipf_state_list; ((is = *isp) != NULL); ) {
if ((proto != 0) && (is->is_v != proto)) {
isp = &is->is_next;
continue;
}
- if (fr_delstate(is, ISL_FLUSH) == 0)
+ if (ipf_state_del(softc, is, ISL_FLUSH) == 0)
removed++;
else
isp = &is->is_next;
@@ -3158,19 +3833,20 @@ int which, proto;
break;
case 1 :
+ SBUMP(ipf_state_stats.iss_flush_closing);
/*
* Since we're only interested in things that are closing,
* we can start with the appropriate timeout queue.
*/
- for (ifq = ips_tqtqb + IPF_TCPS_CLOSE_WAIT; ifq != NULL;
- ifq = ifq->ifq_next) {
+ for (ifq = softs->ipf_state_tcptq + IPF_TCPS_CLOSE_WAIT;
+ ifq != NULL; ifq = ifq->ifq_next) {
for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
tqn = tqe->tqe_next;
is = tqe->tqe_parent;
if (is->is_p != IPPROTO_TCP)
break;
- if (fr_delstate(is, ISL_EXPIRE) == 0)
+ if (ipf_state_del(softc, is, ISL_FLUSH) == 0)
removed++;
}
}
@@ -3178,8 +3854,8 @@ int which, proto;
/*
* Also need to look through the user defined queues.
*/
- for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) {
- ifqnext = ifq->ifq_next;
+ for (ifq = softs->ipf_state_usertq; ifq != NULL;
+ ifq = ifq->ifq_next) {
for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
tqn = tqe->tqe_next;
is = tqe->tqe_parent;
@@ -3188,7 +3864,8 @@ int which, proto;
if ((is->is_state[0] > IPF_TCPS_ESTABLISHED) &&
(is->is_state[1] > IPF_TCPS_ESTABLISHED)) {
- if (fr_delstate(is, ISL_EXPIRE) == 0)
+ if (ipf_state_del(softc, is,
+ ISL_FLUSH) == 0)
removed++;
}
}
@@ -3198,7 +3875,7 @@ int which, proto;
case 2 :
break;
- /*
+ /*
* Args 5-11 correspond to flushing those particular states
* for TCP connections.
*/
@@ -3209,12 +3886,13 @@ int which, proto;
case IPF_TCPS_FIN_WAIT_2 :
case IPF_TCPS_TIME_WAIT :
case IPF_TCPS_CLOSED :
- tqn = ips_tqtqb[which].ifq_head;
+ SBUMP(ipf_state_stats.iss_flush_queue);
+ tqn = softs->ipf_state_tcptq[which].ifq_head;
while (tqn != NULL) {
tqe = tqn;
tqn = tqe->tqe_next;
is = tqe->tqe_parent;
- if (fr_delstate(is, ISL_FLUSH) == 0)
+ if (ipf_state_del(softc, is, ISL_FLUSH) == 0)
removed++;
}
break;
@@ -3223,16 +3901,18 @@ int which, proto;
if (which < 30)
break;
- /*
+ SBUMP(ipf_state_stats.iss_flush_state);
+ /*
* Take a large arbitrary number to mean the number of seconds
* for which which consider to be the maximum value we'll allow
* the expiration to be.
*/
which = IPF_TTLVAL(which);
- for (isp = &ips_list; ((is = *isp) != NULL); ) {
+ for (isp = &softs->ipf_state_list; ((is = *isp) != NULL); ) {
if ((proto == 0) || (is->is_v == proto)) {
- if (fr_ticks - is->is_touched > which) {
- if (fr_delstate(is, ISL_FLUSH) == 0) {
+ if (softc->ipf_ticks - is->is_touched > which) {
+ if (ipf_state_del(softc, is,
+ ISL_FLUSH) == 0) {
removed++;
continue;
}
@@ -3248,13 +3928,23 @@ int which, proto;
return removed;
}
+ SBUMP(ipf_state_stats.iss_flush_timeout);
/*
- * Asked to remove inactive entries because the table is full.
+ * Asked to remove inactive entries because the table is full, try
+ * again, 3 times, if first attempt failed with a different criteria
+ * each time. The order tried in must be in decreasing age.
+ * Another alternative is to implement random drop and drop N entries
+ * at random until N have been freed up.
*/
- if (fr_ticks - ips_last_force_flush > IPF_TTLVAL(5)) {
- ips_last_force_flush = fr_ticks;
- removed = ipf_queueflush(fr_state_flush_entry, ips_tqtqb,
- ips_utqe);
+ if (softc->ipf_ticks - softs->ipf_state_wm_last >
+ softs->ipf_state_wm_freq) {
+ removed = ipf_queueflush(softc, ipf_state_flush_entry,
+ softs->ipf_state_tcptq,
+ softs->ipf_state_usertq,
+ &softs->ipf_state_stats.iss_active,
+ softs->ipf_state_size,
+ softs->ipf_state_wm_low);
+ softs->ipf_state_wm_last = softc->ipf_ticks;
}
SPL_X(s);
@@ -3263,29 +3953,33 @@ int which, proto;
/* ------------------------------------------------------------------------ */
-/* Function: fr_state_flush_entry */
+/* Function: ipf_state_flush_entry */
/* Returns: int - 0 = entry deleted, else not deleted */
-/* Parameters: entry(I) - pointer to state structure to delete */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* entry(I) - pointer to state structure to delete */
/* Write Locks: ipf_state */
/* */
/* This function is a stepping stone between ipf_queueflush() and */
-/* fr_delstate(). It is used so we can provide a uniform interface via the */
-/* ipf_queueflush() function. */
+/* ipf_state_del(). It is used so we can provide a uniform interface via */
+/* the ipf_queueflush() function. */
/* ------------------------------------------------------------------------ */
-static int fr_state_flush_entry(entry)
-void *entry;
+static int
+ipf_state_flush_entry(softc, entry)
+ ipf_main_softc_t *softc;
+ void *entry;
{
- return fr_delstate(entry, ISL_FLUSH);
-}
+ return ipf_state_del(softc, entry, ISL_FLUSH);
+}
/* ------------------------------------------------------------------------ */
-/* Function: fr_tcp_age */
+/* Function: ipf_tcp_age */
/* Returns: int - 1 == state transition made, 0 == no change (rejected) */
-/* Parameters: tq(I) - pointer to timeout queue information */
+/* Parameters: tqe(I) - pointer to timeout queue information */
/* fin(I) - pointer to packet information */
/* tqtab(I) - TCP timeout queue table this is in */
/* flags(I) - flags from state/NAT entry */
+/* ok(I) - can we advance state */
/* */
/* Rewritten by Arjan de Vet <Arjan.deVet@adv.iae.nl>, 2000-07-29: */
/* */
@@ -3297,7 +3991,7 @@ void *entry;
/* */
/* - 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. */
+/* to ipf_tcp_age have been changed accordingly. */
/* */
/* Internal Parameters: */
/* */
@@ -3328,12 +4022,14 @@ void *entry;
/* */
/* Locking: it is assumed that the parent of the tqe structure is locked. */
/* ------------------------------------------------------------------------ */
-int fr_tcp_age(tqe, fin, tqtab, flags)
-ipftqent_t *tqe;
-fr_info_t *fin;
-ipftq_t *tqtab;
-int flags;
+int
+ipf_tcp_age(tqe, fin, tqtab, flags, ok)
+ ipftqent_t *tqe;
+ fr_info_t *fin;
+ ipftq_t *tqtab;
+ int flags, ok;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
int dlen, ostate, nstate, rval, dir;
u_char tcpflags;
tcphdr_t *tcp;
@@ -3344,17 +4040,20 @@ int flags;
dir = fin->fin_rev;
tcpflags = tcp->th_flags;
dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2);
+ ostate = tqe->tqe_state[1 - dir];
+ nstate = tqe->tqe_state[dir];
if (tcpflags & TH_RST) {
if (!(tcpflags & TH_PUSH) && !dlen)
nstate = IPF_TCPS_CLOSED;
else
nstate = IPF_TCPS_CLOSE_WAIT;
+
+ if (ostate <= IPF_TCPS_ESTABLISHED) {
+ tqe->tqe_state[1 - dir] = IPF_TCPS_CLOSE_WAIT;
+ }
rval = 1;
} else {
- ostate = tqe->tqe_state[1 - dir];
- nstate = tqe->tqe_state[dir];
-
switch (nstate)
{
case IPF_TCPS_LISTEN: /* 0 */
@@ -3410,7 +4109,7 @@ int flags;
if ((tcpflags & ~(TH_ECN|TH_CWR)) == TH_SYN) {
/*
* A retransmitted SYN packet. We do not reset
- * the timeout here to fr_tcptimeout because a
+ * the timeout here to ipf_tcptimeout because a
* connection connect timeout does not renew
* after every packet that is sent. We need to
* set rval so as to indicate the packet has
@@ -3578,7 +4277,7 @@ int flags;
* the FIN packet here? does the window code
* guarantee that?
*/
- nstate = IPF_TCPS_TIME_WAIT;
+ nstate = IPF_TCPS_LAST_ACK;
} else {
/*
* we closed our side of the connection
@@ -3594,25 +4293,18 @@ int flags;
if ((tcpflags & (TH_FIN|TH_ACK)) == TH_ACK) {
nstate = IPF_TCPS_TIME_WAIT;
}
- rval = 2;
+ rval = 1;
break;
case IPF_TCPS_LAST_ACK: /* 8 */
if (tcpflags & TH_ACK) {
- if ((tcpflags & TH_PUSH) || dlen)
- /*
- * there is still data to be delivered,
- * reset timeout
- */
- rval = 1;
- else
- rval = 2;
+ rval = 1;
}
/*
- * 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
+ * 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;
@@ -3624,8 +4316,10 @@ int flags;
/* we're in 2MSL timeout now */
if (ostate == IPF_TCPS_LAST_ACK) {
nstate = IPF_TCPS_CLOSED;
+ rval = 1;
+ } else {
+ rval = 2;
}
- rval = 1;
break;
case IPF_TCPS_CLOSED: /* 11 */
@@ -3633,18 +4327,7 @@ int flags;
break;
default :
-#if defined(_KERNEL)
-# if SOLARIS
- cmn_err(CE_NOTE,
- "tcp %lx flags %x si %lx nstate %d ostate %d\n",
- (u_long)tcp, tcpflags, (u_long)tqe,
- nstate, ostate);
-# else
- printf("tcp %lx flags %x si %lx nstate %d ostate %d\n",
- (u_long)tcp, tcpflags, (u_long)tqe,
- nstate, ostate);
-# endif
-#else
+#if !defined(_KERNEL)
abort();
#endif
break;
@@ -3658,9 +4341,11 @@ int flags;
if (rval == 2)
rval = 1;
else if (rval == 1) {
- tqe->tqe_state[dir] = nstate;
+ if (ok)
+ tqe->tqe_state[dir] = nstate;
if ((tqe->tqe_flags & TQE_RULEBASED) == 0)
- fr_movequeue(tqe, tqe->tqe_ifq, tqtab + nstate);
+ ipf_movequeue(softc->ipf_ticks, tqe, tqe->tqe_ifq,
+ tqtab + nstate);
}
return rval;
@@ -3668,18 +4353,21 @@ int flags;
/* ------------------------------------------------------------------------ */
-/* Function: ipstate_log */
+/* Function: ipf_state_log */
/* Returns: Nil */
-/* Parameters: is(I) - pointer to state structure */
-/* type(I) - type of log entry to create */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* is(I) - pointer to state structure */
+/* type(I) - type of log entry to create */
/* */
/* Creates a state table log entry using the state structure and type info. */
/* passed in. Log packet/byte counts, source/destination address and other */
/* protocol specific information. */
/* ------------------------------------------------------------------------ */
-void ipstate_log(is, type)
-struct ipstate *is;
-u_int type;
+void
+ipf_state_log(softc, is, type)
+ ipf_main_softc_t *softc;
+ struct ipstate *is;
+ u_int type;
{
#ifdef IPFILTER_LOG
struct ipslog ipsl;
@@ -3729,18 +4417,14 @@ u_int type;
sizes[0] = sizeof(ipsl);
types[0] = 0;
- if (ipllog(IPL_LOGSTATE, NULL, items, sizes, types, 1)) {
- ATOMIC_INCL(ips_stats.iss_logged);
- } else {
- ATOMIC_INCL(ips_stats.iss_logfail);
- }
+ (void) ipf_log_items(softc, IPL_LOGSTATE, NULL, items, sizes, types, 1);
#endif
}
#ifdef USE_INET6
/* ------------------------------------------------------------------------ */
-/* Function: fr_checkicmp6matchingstate */
+/* Function: ipf_checkicmp6matchingstate */
/* Returns: ipstate_t* - NULL == no match found, */
/* else pointer to matching state entry */
/* Parameters: fin(I) - pointer to packet information */
@@ -3749,11 +4433,13 @@ u_int type;
/* If we've got an ICMPv6 error message, using the information stored in */
/* the ICMPv6 packet, look for a matching state table entry. */
/* ------------------------------------------------------------------------ */
-static ipstate_t *fr_checkicmp6matchingstate(fin)
-fr_info_t *fin;
+static ipstate_t *
+ipf_checkicmp6matchingstate(fin)
+ fr_info_t *fin;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
struct icmp6_hdr *ic6, *oic;
- int type, backward, i;
ipstate_t *is, **isp;
u_short sport, dport;
i6addr_t dst, src;
@@ -3762,8 +4448,9 @@ fr_info_t *fin;
fr_info_t ofin;
tcphdr_t *tcp;
ip6_t *oip6;
- u_char pr;
+ u_char pr;
u_int hv;
+ int type;
/*
* Does it at least have the return (basic) IP header ?
@@ -3772,15 +4459,19 @@ fr_info_t *fin;
* an ICMP error header.
*/
if ((fin->fin_v != 6) || (fin->fin_plen < ICMP6ERR_MINPKTLEN) ||
- !(fin->fin_flx & FI_ICMPERR))
+ !(fin->fin_flx & FI_ICMPERR)) {
+ SBUMPD(ipf_state_stats, iss_icmp_bad);
return NULL;
+ }
ic6 = fin->fin_dp;
type = ic6->icmp6_type;
oip6 = (ip6_t *)((char *)ic6 + ICMPERR_ICMPHLEN);
- if (fin->fin_plen < sizeof(*oip6))
+ if (fin->fin_plen < sizeof(*oip6)) {
+ SBUMPD(ipf_state_stats, iss_icmp_short);
return NULL;
+ }
bcopy((char *)fin, (char *)&ofin, sizeof(*fin));
ofin.fin_v = 6;
@@ -3794,21 +4485,31 @@ fr_info_t *fin;
* matchsrcdst. Note that not all fields are necessary
* 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.
+ * a kernel panic. ipf_matchsrcdst does not use this.
*
* watch out here, as ip is in host order and oip6 in network
* order. Any change we make must be undone afterwards.
*/
savelen = oip6->ip6_plen;
- oip6->ip6_plen = fin->fin_dlen - ICMPERR_ICMPHLEN;
+ oip6->ip6_plen = htons(fin->fin_dlen - ICMPERR_ICMPHLEN);
ofin.fin_flx = FI_NOCKSUM;
ofin.fin_ip = (ip_t *)oip6;
- (void) fr_makefrip(sizeof(*oip6), (ip_t *)oip6, &ofin);
+ (void) ipf_makefrip(sizeof(*oip6), (ip_t *)oip6, &ofin);
ofin.fin_flx &= ~(FI_BAD|FI_SHORT);
oip6->ip6_plen = savelen;
+ pr = ofin.fin_p;
+
+ /*
+ * an ICMP error can never generate an ICMP error in response.
+ */
+ if (ofin.fin_flx & FI_ICMPERR) {
+ DT1(iss_icmp6_icmperr, fr_info_t *, &ofin);
+ SBUMP(ipf_state_stats.iss_icmp6_icmperr);
+ return NULL;
+ }
if (oip6->ip6_nxt == IPPROTO_ICMPV6) {
- oic = (struct icmp6_hdr *)(oip6 + 1);
+ oic = ofin.fin_dp;
/*
* an ICMP error can only be generated as a result of an
* ICMP query, not as the response on an ICMP error
@@ -3816,8 +4517,11 @@ fr_info_t *fin;
* 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;
+ if (!(oic->icmp6_type & ICMP6_INFOMSG_MASK)) {
+ DT1(iss_icmp6_notinfo, fr_info_t *, &ofin);
+ SBUMP(ipf_state_stats.iss_icmp6_notinfo);
+ return NULL;
+ }
/*
* perform a lookup of the ICMP packet in the state table
@@ -3831,15 +4535,16 @@ fr_info_t *fin;
hv += oic->icmp6_seq;
hv = DOUBLE_HASH(hv);
- READ_ENTER(&ipf_state);
- for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) {
+ READ_ENTER(&softc->ipf_state);
+ for (isp = &softs->ipf_state_table[hv];
+ ((is = *isp) != NULL); ) {
ic = &is->is_icmp;
isp = &is->is_hnext;
if ((is->is_p == pr) &&
!(is->is_pass & FR_NOICMPERR) &&
(oic->icmp6_id == ic->ici_id) &&
(oic->icmp6_seq == ic->ici_seq) &&
- (is = fr_matchsrcdst(&ofin, is, &src,
+ (is = ipf_matchsrcdst(&ofin, is, &src,
&dst, NULL, FI_ICMPCMP))) {
/*
* in the state table ICMP query's are stored
@@ -3849,16 +4554,13 @@ fr_info_t *fin;
if (((ic->ici_type == ICMP6_ECHO_REPLY) &&
(oic->icmp6_type == ICMP6_ECHO_REQUEST)) ||
(ic->ici_type - 1 == oic->icmp6_type )) {
- ips_stats.iss_hits++;
- backward = IP6_NEQ(&is->is_dst, &src);
- fin->fin_rev = !backward;
- i = (backward << 1) + fin->fin_out;
- is->is_icmppkts[i]++;
- return is;
+ if (!ipf_allowstateicmp(fin, is, &src))
+ return is;
}
}
}
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
+ SBUMPD(ipf_state_stats, iss_icmp6_miss);
return NULL;
}
@@ -3874,18 +4576,33 @@ fr_info_t *fin;
hv += dst.i6[2];
hv += dst.i6[3];
- if ((oip6->ip6_nxt == IPPROTO_TCP) || (oip6->ip6_nxt == IPPROTO_UDP)) {
+ tcp = NULL;
+
+ switch (oip6->ip6_nxt)
+ {
+ case IPPROTO_TCP :
+ case IPPROTO_UDP :
tcp = (tcphdr_t *)(oip6 + 1);
dport = tcp->th_dport;
sport = tcp->th_sport;
hv += dport;
hv += sport;
- } else
- tcp = NULL;
+ break;
+
+ case IPPROTO_ICMPV6 :
+ oic = (struct icmp6_hdr *)(oip6 + 1);
+ hv += oic->icmp6_id;
+ hv += oic->icmp6_seq;
+ break;
+
+ default :
+ break;
+ }
+
hv = DOUBLE_HASH(hv);
- READ_ENTER(&ipf_state);
- for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) {
+ READ_ENTER(&softc->ipf_state);
+ for (isp = &softs->ipf_state_table[hv]; ((is = *isp) != NULL); ) {
isp = &is->is_hnext;
/*
* Only allow this icmp though if the
@@ -3897,73 +4614,63 @@ fr_info_t *fin;
if ((is->is_p != pr) || (is->is_v != 6) ||
(is->is_pass & FR_NOICMPERR))
continue;
- is = fr_matchsrcdst(&ofin, is, &src, &dst, tcp, FI_ICMPCMP);
- if (is != NULL) {
- ips_stats.iss_hits++;
- backward = IP6_NEQ(&is->is_dst, &src);
- fin->fin_rev = !backward;
- i = (backward << 1) + fin->fin_out;
- is->is_icmppkts[i]++;
- /*
- * we deliberately do not touch the timeouts
- * for the accompanying state table entry.
- * It remains to be seen if that is correct. XXX
- */
+ is = ipf_matchsrcdst(&ofin, is, &src, &dst, tcp, FI_ICMPCMP);
+ if ((is != NULL) && (ipf_allowstateicmp(fin, is, &src) == 0))
return is;
- }
}
- RWLOCK_EXIT(&ipf_state);
+ RWLOCK_EXIT(&softc->ipf_state);
+ SBUMPD(ipf_state_stats, iss_icmp_miss);
return NULL;
}
#endif
/* ------------------------------------------------------------------------ */
-/* Function: fr_sttab_init */
+/* Function: ipf_sttab_init */
/* Returns: Nil */
-/* Parameters: tqp(I) - pointer to an array of timeout queues for TCP */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* tqp(I) - pointer to an array of timeout queues for TCP */
/* */
/* Initialise the array of timeout queues for TCP. */
/* ------------------------------------------------------------------------ */
-void fr_sttab_init(tqp)
-ipftq_t *tqp;
+void
+ipf_sttab_init(softc, tqp)
+ ipf_main_softc_t *softc;
+ ipftq_t *tqp;
{
int i;
for (i = IPF_TCP_NSTATES - 1; i >= 0; i--) {
- tqp[i].ifq_ttl = 0;
- tqp[i].ifq_ref = 1;
- tqp[i].ifq_head = NULL;
- tqp[i].ifq_tail = &tqp[i].ifq_head;
+ IPFTQ_INIT(&tqp[i], 0, "ipftq tcp tab");
tqp[i].ifq_next = tqp + i + 1;
- MUTEX_INIT(&tqp[i].ifq_lock, "ipftq tcp tab");
}
tqp[IPF_TCP_NSTATES - 1].ifq_next = NULL;
- tqp[IPF_TCPS_CLOSED].ifq_ttl = fr_tcpclosed;
- tqp[IPF_TCPS_LISTEN].ifq_ttl = fr_tcptimeout;
- tqp[IPF_TCPS_SYN_SENT].ifq_ttl = fr_tcptimeout;
- tqp[IPF_TCPS_SYN_RECEIVED].ifq_ttl = fr_tcptimeout;
- tqp[IPF_TCPS_ESTABLISHED].ifq_ttl = fr_tcpidletimeout;
- tqp[IPF_TCPS_CLOSE_WAIT].ifq_ttl = fr_tcphalfclosed;
- tqp[IPF_TCPS_FIN_WAIT_1].ifq_ttl = fr_tcphalfclosed;
- tqp[IPF_TCPS_CLOSING].ifq_ttl = fr_tcptimeout;
- tqp[IPF_TCPS_LAST_ACK].ifq_ttl = fr_tcplastack;
- tqp[IPF_TCPS_FIN_WAIT_2].ifq_ttl = fr_tcpclosewait;
- tqp[IPF_TCPS_TIME_WAIT].ifq_ttl = fr_tcptimewait;
- tqp[IPF_TCPS_HALF_ESTAB].ifq_ttl = fr_tcptimeout;
+ tqp[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcpclosed;
+ tqp[IPF_TCPS_LISTEN].ifq_ttl = softc->ipf_tcptimeout;
+ tqp[IPF_TCPS_SYN_SENT].ifq_ttl = softc->ipf_tcpsynsent;
+ tqp[IPF_TCPS_SYN_RECEIVED].ifq_ttl = softc->ipf_tcpsynrecv;
+ tqp[IPF_TCPS_ESTABLISHED].ifq_ttl = softc->ipf_tcpidletimeout;
+ tqp[IPF_TCPS_CLOSE_WAIT].ifq_ttl = softc->ipf_tcphalfclosed;
+ tqp[IPF_TCPS_FIN_WAIT_1].ifq_ttl = softc->ipf_tcphalfclosed;
+ tqp[IPF_TCPS_CLOSING].ifq_ttl = softc->ipf_tcptimeout;
+ tqp[IPF_TCPS_LAST_ACK].ifq_ttl = softc->ipf_tcplastack;
+ tqp[IPF_TCPS_FIN_WAIT_2].ifq_ttl = softc->ipf_tcpclosewait;
+ tqp[IPF_TCPS_TIME_WAIT].ifq_ttl = softc->ipf_tcptimewait;
+ tqp[IPF_TCPS_HALF_ESTAB].ifq_ttl = softc->ipf_tcptimeout;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_sttab_destroy */
+/* Function: ipf_sttab_destroy */
/* Returns: Nil */
/* Parameters: tqp(I) - pointer to an array of timeout queues for TCP */
/* */
/* Do whatever is necessary to "destroy" each of the entries in the array */
/* of timeout queues for TCP. */
/* ------------------------------------------------------------------------ */
-void fr_sttab_destroy(tqp)
-ipftq_t *tqp;
+void
+ipf_sttab_destroy(tqp)
+ ipftq_t *tqp;
{
int i;
@@ -3973,9 +4680,10 @@ ipftq_t *tqp;
/* ------------------------------------------------------------------------ */
-/* Function: fr_statederef */
+/* Function: ipf_state_deref */
/* Returns: Nil */
-/* Parameters: isp(I) - pointer to pointer to state table entry */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* isp(I) - pointer to pointer to state table entry */
/* */
/* Decrement the reference counter for this state table entry and free it */
/* if there are no more things using it. */
@@ -4003,10 +4711,12 @@ ipftq_t *tqp;
/* dir == 0 : a packet from source to dest */
/* dir == 1 : a packet from dest to source */
/* ------------------------------------------------------------------------ */
-void fr_statederef(isp)
-ipstate_t **isp;
+void
+ipf_state_deref(softc, isp)
+ ipf_main_softc_t *softc;
+ ipstate_t **isp;
{
- ipstate_t *is;
+ ipstate_t *is = *isp;
is = *isp;
*isp = NULL;
@@ -4017,37 +4727,40 @@ ipstate_t **isp;
MUTEX_EXIT(&is->is_lock);
#ifndef _KERNEL
if ((is->is_sti.tqe_state[0] > IPF_TCPS_ESTABLISHED) ||
- (is->is_sti.tqe_state[1] > IPF_TCPS_ESTABLISHED)) {
- fr_delstate(is, ISL_ORPHAN);
+ (is->is_sti.tqe_state[1] > IPF_TCPS_ESTABLISHED)) {
+ ipf_state_del(softc, is, ISL_EXPIRE);
}
#endif
return;
}
MUTEX_EXIT(&is->is_lock);
- WRITE_ENTER(&ipf_state);
- fr_delstate(is, ISL_EXPIRE);
- RWLOCK_EXIT(&ipf_state);
+ WRITE_ENTER(&softc->ipf_state);
+ ipf_state_del(softc, is, ISL_ORPHAN);
+ RWLOCK_EXIT(&softc->ipf_state);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_setstatequeue */
+/* Function: ipf_state_setqueue */
/* Returns: Nil */
-/* Parameters: is(I) - pointer to state structure */
-/* rev(I) - forward(0) or reverse(1) direction */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* is(I) - pointer to state structure */
+/* rev(I) - forward(0) or reverse(1) direction */
/* Locks: ipf_state (read or write) */
/* */
/* Put the state entry on its default queue entry, using rev as a helped in */
/* determining which queue it should be placed on. */
/* ------------------------------------------------------------------------ */
-void fr_setstatequeue(is, rev)
-ipstate_t *is;
-int rev;
+void
+ipf_state_setqueue(softc, is, rev)
+ ipf_main_softc_t *softc;
+ ipstate_t *is;
+ int rev;
{
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
ipftq_t *oifq, *nifq;
-
if ((is->is_sti.tqe_flags & TQE_RULEBASED) != 0)
nifq = is->is_tqehead[rev];
else
@@ -4059,30 +4772,30 @@ int rev;
#ifdef USE_INET6
case IPPROTO_ICMPV6 :
if (rev == 1)
- nifq = &ips_icmpacktq;
+ nifq = &softs->ipf_state_icmpacktq;
else
- nifq = &ips_icmptq;
+ nifq = &softs->ipf_state_icmptq;
break;
#endif
case IPPROTO_ICMP :
if (rev == 1)
- nifq = &ips_icmpacktq;
+ nifq = &softs->ipf_state_icmpacktq;
else
- nifq = &ips_icmptq;
+ nifq = &softs->ipf_state_icmptq;
break;
case IPPROTO_TCP :
- nifq = ips_tqtqb + is->is_state[rev];
+ nifq = softs->ipf_state_tcptq + is->is_state[rev];
break;
case IPPROTO_UDP :
if (rev == 1)
- nifq = &ips_udpacktq;
+ nifq = &softs->ipf_state_udpacktq;
else
- nifq = &ips_udptq;
+ nifq = &softs->ipf_state_udptq;
break;
default :
- nifq = &ips_iptq;
+ nifq = &softs->ipf_state_iptq;
break;
}
}
@@ -4093,126 +4806,560 @@ int rev;
* another, else put it on the end of the newly determined queue.
*/
if (oifq != NULL)
- fr_movequeue(&is->is_sti, oifq, nifq);
+ ipf_movequeue(softc->ipf_ticks, &is->is_sti, oifq, nifq);
else
- fr_queueappend(&is->is_sti, nifq, is);
+ ipf_queueappend(softc->ipf_ticks, &is->is_sti, nifq, is);
return;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_stateiter */
+/* Function: ipf_state_iter */
/* Returns: int - 0 == success, else error */
-/* Parameters: token(I) - pointer to ipftoken structure */
+/* Parameters: softc(I) - pointer to main soft context */
+/* token(I) - pointer to ipftoken structure */
/* itp(I) - pointer to ipfgeniter structure */
+/* obj(I) - pointer to data description structure */
/* */
/* This function handles the SIOCGENITER ioctl for the state tables and */
-/* walks through the list of entries in the state table list (ips_list.) */
+/* walks through the list of entries in the state table list (softs->ipf_state_list.) */
/* ------------------------------------------------------------------------ */
-static int fr_stateiter(token, itp)
-ipftoken_t *token;
-ipfgeniter_t *itp;
+static int
+ipf_state_iter(softc, token, itp, obj)
+ ipf_main_softc_t *softc;
+ ipftoken_t *token;
+ ipfgeniter_t *itp;
+ ipfobj_t *obj;
{
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
ipstate_t *is, *next, zero;
- int error, count;
- char *dst;
+ int error;
- if (itp->igi_data == NULL)
+ if (itp->igi_data == NULL) {
+ IPFERROR(100026);
return EFAULT;
+ }
- if (itp->igi_nitems < 1)
+ if (itp->igi_nitems < 1) {
+ IPFERROR(100027);
return ENOSPC;
+ }
- if (itp->igi_type != IPFGENITER_STATE)
+ if (itp->igi_type != IPFGENITER_STATE) {
+ IPFERROR(100028);
return EINVAL;
+ }
is = token->ipt_data;
if (is == (void *)-1) {
- ipf_freetoken(token);
+ IPFERROR(100029);
return ESRCH;
}
error = 0;
- dst = itp->igi_data;
+ obj->ipfo_type = IPFOBJ_IPSTATE;
+ obj->ipfo_size = sizeof(ipstate_t);
- READ_ENTER(&ipf_state);
+ READ_ENTER(&softc->ipf_state);
+
+ is = token->ipt_data;
if (is == NULL) {
- next = ips_list;
+ next = softs->ipf_state_list;
} else {
next = is->is_next;
}
- count = itp->igi_nitems;
- for (;;) {
- if (next != NULL) {
- /*
- * If we find a state entry to use, bump its
- * reference count so that it can be used for
- * is_next when we come back.
- */
- if (count == 1) {
- MUTEX_ENTER(&next->is_lock);
- next->is_ref++;
- MUTEX_EXIT(&next->is_lock);
- token->ipt_data = next;
- }
- } else {
- bzero(&zero, sizeof(zero));
- next = &zero;
- count = 1;
- token->ipt_data = NULL;
- }
- RWLOCK_EXIT(&ipf_state);
-
- /*
- * This should arguably be via fr_outobj() so that the state
- * structure can (if required) be massaged going out.
- */
- error = COPYOUT(next, dst, sizeof(*next));
- if (error != 0)
- error = EFAULT;
- if ((count == 1) || (error != 0))
- break;
-
- dst += sizeof(*next);
- count--;
-
- READ_ENTER(&ipf_state);
- next = next->is_next;
+ /*
+ * If we find a state entry to use, bump its reference count so that
+ * it can be used for is_next when we come back.
+ */
+ if (next != NULL) {
+ MUTEX_ENTER(&next->is_lock);
+ next->is_ref++;
+ MUTEX_EXIT(&next->is_lock);
+ token->ipt_data = next;
+ } else {
+ bzero(&zero, sizeof(zero));
+ next = &zero;
+ token->ipt_data = NULL;
}
+ if (next->is_next == NULL)
+ ipf_token_mark_complete(token);
- if (is != NULL) {
- fr_statederef(&is);
- }
+ RWLOCK_EXIT(&softc->ipf_state);
+
+ obj->ipfo_ptr = itp->igi_data;
+ error = ipf_outobjk(softc, obj, next);
+ if (is != NULL)
+ ipf_state_deref(softc, &is);
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_stgettable */
+/* Function: ipf_state_gettable */
/* Returns: int - 0 = success, else error */
-/* Parameters: data(I) - pointer to ioctl data */
+/* Parameters: softc(I) - pointer to main soft context */
+/* softs(I) - pointer to state context structure */
+/* data(I) - pointer to ioctl data */
/* */
/* This function handles ioctl requests for tables of state information. */
/* At present the only table it deals with is the hash bucket statistics. */
/* ------------------------------------------------------------------------ */
-static int fr_stgettable(data)
-char *data;
+static int
+ipf_state_gettable(softc, softs, data)
+ ipf_main_softc_t *softc;
+ ipf_state_softc_t *softs;
+ char *data;
{
ipftable_t table;
int error;
- error = fr_inobj(data, &table, IPFOBJ_GTABLE);
+ error = ipf_inobj(softc, data, NULL, &table, IPFOBJ_GTABLE);
if (error != 0)
return error;
- if (table.ita_type != IPFTABLE_BUCKETS)
+ if (table.ita_type != IPFTABLE_BUCKETS) {
+ IPFERROR(100031);
return EINVAL;
+ }
- error = COPYOUT(ips_stats.iss_bucketlen, table.ita_table,
- fr_statesize * sizeof(u_long));
- if (error != 0)
+ error = COPYOUT(softs->ipf_state_stats.iss_bucketlen, table.ita_table,
+ softs->ipf_state_size * sizeof(u_int));
+ if (error != 0) {
+ IPFERROR(100032);
error = EFAULT;
+ }
return error;
}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_state_setpending */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to main soft context */
+/* is(I) - pointer to state structure */
+/* Locks: ipf_state (read or write) */
+/* */
+/* Put the state entry on to the pending queue - this queue has a very */
+/* short lifetime where items are put that can't be deleted straight away */
+/* because of locking issues but we want to delete them ASAP, anyway. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_state_setpending(softc, is)
+ ipf_main_softc_t *softc;
+ ipstate_t *is;
+{
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
+ ipftq_t *oifq;
+
+ oifq = is->is_sti.tqe_ifq;
+ if (oifq != NULL)
+ ipf_movequeue(softc->ipf_ticks, &is->is_sti, oifq,
+ &softs->ipf_state_pending);
+ else
+ ipf_queueappend(softc->ipf_ticks, &is->is_sti,
+ &softs->ipf_state_pending, is);
+
+ MUTEX_ENTER(&is->is_lock);
+ if (is->is_me != NULL) {
+ *is->is_me = NULL;
+ is->is_me = NULL;
+ is->is_ref--;
+ }
+ MUTEX_EXIT(&is->is_lock);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_state_matchflush */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to main soft context */
+/* data(I) - pointer to state structure */
+/* Locks: ipf_state (read or write) */
+/* */
+/* Flush all entries from the list of state entries that match the */
+/* properties in the array loaded. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_state_matchflush(softc, data)
+ ipf_main_softc_t *softc;
+ caddr_t data;
+{
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
+ int *array, flushed, error;
+ ipstate_t *state, *statenext;
+ ipfobj_t obj;
+
+ error = ipf_matcharray_load(softc, data, &obj, &array);
+ if (error != 0)
+ return error;
+
+ flushed = 0;
+
+ for (state = softs->ipf_state_list; state != NULL; state = statenext) {
+ statenext = state->is_next;
+ if (ipf_state_matcharray(state, array, softc->ipf_ticks) == 0) {
+ ipf_state_del(softc, state, ISL_FLUSH);
+ flushed++;
+ }
+ }
+
+ obj.ipfo_retval = flushed;
+ error = BCOPYOUT(&obj, data, sizeof(obj));
+
+ KFREES(array, array[0] * sizeof(*array));
+
+ return error;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_state_matcharray */
+/* Returns: int - 0 = no match, 1 = match */
+/* Parameters: state(I) - pointer to state structure */
+/* array(I) - pointer to ipf matching expression */
+/* ticks(I) - current value of ipfilter tick timer */
+/* Locks: ipf_state (read or write) */
+/* */
+/* Compare a state entry with the match array passed in and return a value */
+/* to indicate whether or not the matching was successful. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_state_matcharray(state, array, ticks)
+ ipstate_t *state;
+ int *array;
+ u_long ticks;
+{
+ int i, n, *x, rv, p;
+ ipfexp_t *e;
+
+ rv = 0;
+ n = array[0];
+ x = array + 1;
+
+ for (; n > 0; x += 3 + x[3], rv = 0) {
+ e = (ipfexp_t *)x;
+ n -= e->ipfe_size;
+ if (x[0] == IPF_EXP_END)
+ break;
+
+ /*
+ * If we need to match the protocol and that doesn't match,
+ * don't even both with the instruction array.
+ */
+ p = e->ipfe_cmd >> 16;
+ if ((p != 0) && (p != state->is_p))
+ break;
+
+ switch (e->ipfe_cmd)
+ {
+ case IPF_EXP_IP_PR :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (state->is_p == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_IP_SRCADDR :
+ if (state->is_v != 4)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= ((state->is_saddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]);
+ }
+ break;
+
+ case IPF_EXP_IP_DSTADDR :
+ if (state->is_v != 4)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= ((state->is_daddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]);
+ }
+ break;
+
+ case IPF_EXP_IP_ADDR :
+ if (state->is_v != 4)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= ((state->is_saddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]) ||
+ ((state->is_daddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]);
+ }
+ break;
+
+#ifdef USE_INET6
+ case IPF_EXP_IP6_SRCADDR :
+ if (state->is_v != 6)
+ break;
+ for (i = 0; !rv && i < x[3]; i++) {
+ rv |= IP6_MASKEQ(&state->is_src.in6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]);
+ }
+ break;
+
+ case IPF_EXP_IP6_DSTADDR :
+ if (state->is_v != 6)
+ break;
+ for (i = 0; !rv && i < x[3]; i++) {
+ rv |= IP6_MASKEQ(&state->is_dst.in6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]);
+ }
+ break;
+
+ case IPF_EXP_IP6_ADDR :
+ if (state->is_v != 6)
+ break;
+ for (i = 0; !rv && i < x[3]; i++) {
+ rv |= IP6_MASKEQ(&state->is_src.in6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]) ||
+ IP6_MASKEQ(&state->is_dst.in6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]);
+ }
+ break;
+#endif
+
+ case IPF_EXP_UDP_PORT :
+ case IPF_EXP_TCP_PORT :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (state->is_sport == e->ipfe_arg0[i]) ||
+ (state->is_dport == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_UDP_SPORT :
+ case IPF_EXP_TCP_SPORT :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (state->is_sport == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_UDP_DPORT :
+ case IPF_EXP_TCP_DPORT :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (state->is_dport == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_TCP_STATE :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (state->is_state[0] == e->ipfe_arg0[i]) ||
+ (state->is_state[1] == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_IDLE_GT :
+ rv |= (ticks - state->is_touched > e->ipfe_arg0[0]);
+ break;
+ }
+
+ /*
+ * Factor in doing a negative match.
+ */
+ rv ^= e->ipfe_not;
+
+ if (rv == 0)
+ break;
+ }
+
+ return rv;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_state_settimeout */
+/* Returns: int 0 = success, else failure */
+/* Parameters: softc(I) - pointer to main soft context */
+/* t(I) - pointer to tuneable being changed */
+/* p(I) - pointer to the new value */
+/* */
+/* Sets a timeout value for one of the many timeout queues. We find the */
+/* correct queue using a somewhat manual process of comparing the timeout */
+/* names for each specific value available and calling ipf_apply_timeout on */
+/* that queue so that all of the items on it are updated accordingly. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_state_settimeout(softc, t, p)
+ struct ipf_main_softc_s *softc;
+ ipftuneable_t *t;
+ ipftuneval_t *p;
+{
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
+
+ /*
+ * In case there is nothing to do...
+ */
+ if (*t->ipft_pint == p->ipftu_int)
+ return 0;
+
+ if (!strncmp(t->ipft_name, "tcp_", 4))
+ return ipf_settimeout_tcp(t, p, softs->ipf_state_tcptq);
+
+ if (!strcmp(t->ipft_name, "udp_timeout")) {
+ ipf_apply_timeout(&softs->ipf_state_udptq, p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "udp_ack_timeout")) {
+ ipf_apply_timeout(&softs->ipf_state_udpacktq, p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "icmp_timeout")) {
+ ipf_apply_timeout(&softs->ipf_state_icmptq, p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "icmp_ack_timeout")) {
+ ipf_apply_timeout(&softs->ipf_state_icmpacktq, p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "ip_timeout")) {
+ ipf_apply_timeout(&softs->ipf_state_iptq, p->ipftu_int);
+ } else {
+ IPFERROR(100034);
+ return ESRCH;
+ }
+
+ /*
+ * Update the tuneable being set.
+ */
+ *t->ipft_pint = p->ipftu_int;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_state_rehash */
+/* Returns: int 0 = success, else failure */
+/* Parameters: softc(I) - pointer to main soft context */
+/* t(I) - pointer to tuneable being changed */
+/* p(I) - pointer to the new value */
+/* */
+/* To change the size of the state hash table at runtime, a new table has */
+/* to be allocated and then all of the existing entries put in it, bumping */
+/* up the bucketlength for it as we go along. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_state_rehash(softc, t, p)
+ ipf_main_softc_t *softc;
+ ipftuneable_t *t;
+ ipftuneval_t *p;
+{
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
+ ipstate_t **newtab, *is;
+ u_int *bucketlens;
+ u_int maxbucket;
+ u_int newsize;
+ u_int hv;
+ int i;
+
+ newsize = p->ipftu_int;
+ /*
+ * In case there is nothing to do...
+ */
+ if (newsize == softs->ipf_state_size)
+ return 0;
+
+ KMALLOCS(newtab, ipstate_t **, newsize * sizeof(ipstate_t *));
+ if (newtab == NULL) {
+ IPFERROR(100035);
+ return ENOMEM;
+ }
+
+ KMALLOCS(bucketlens, u_int *, newsize * sizeof(u_int));
+ if (bucketlens == NULL) {
+ KFREES(newtab, newsize * sizeof(*softs->ipf_state_table));
+ IPFERROR(100036);
+ return ENOMEM;
+ }
+
+ for (maxbucket = 0, i = newsize; i > 0; i >>= 1)
+ maxbucket++;
+ maxbucket *= 2;
+
+ bzero((char *)newtab, newsize * sizeof(ipstate_t *));
+ bzero((char *)bucketlens, newsize * sizeof(u_int));
+
+ WRITE_ENTER(&softc->ipf_state);
+
+ if (softs->ipf_state_table != NULL) {
+ KFREES(softs->ipf_state_table,
+ softs->ipf_state_size * sizeof(*softs->ipf_state_table));
+ }
+ softs->ipf_state_table = newtab;
+
+ if (softs->ipf_state_stats.iss_bucketlen != NULL) {
+ KFREES(softs->ipf_state_stats.iss_bucketlen,
+ softs->ipf_state_size * sizeof(u_int));
+ }
+ softs->ipf_state_stats.iss_bucketlen = bucketlens;
+ softs->ipf_state_maxbucket = maxbucket;
+ softs->ipf_state_size = newsize;
+
+ /*
+ * Walk through the entire list of state table entries and put them
+ * in the new state table, somewhere. Because we have a new table,
+ * we need to restart the counter of how many chains are in use.
+ */
+ softs->ipf_state_stats.iss_inuse = 0;
+ for (is = softs->ipf_state_list; is != NULL; is = is->is_next) {
+ is->is_hnext = NULL;
+ is->is_phnext = NULL;
+ hv = is->is_hv % softs->ipf_state_size;
+
+ if (softs->ipf_state_table[hv] != NULL)
+ softs->ipf_state_table[hv]->is_phnext = &is->is_hnext;
+ else
+ softs->ipf_state_stats.iss_inuse++;
+ is->is_phnext = softs->ipf_state_table + hv;
+ is->is_hnext = softs->ipf_state_table[hv];
+ softs->ipf_state_table[hv] = is;
+ softs->ipf_state_stats.iss_bucketlen[hv]++;
+ }
+ RWLOCK_EXIT(&softc->ipf_state);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_state_add_tq */
+/* Returns: ipftq_t * - NULL = failure, else pointer to new timeout */
+/* queue */
+/* Parameters: softc(I) - pointer to main soft context */
+/* ttl(I) - pointer to the ttl for the new queue */
+/* */
+/* Request a pointer to a timeout queue that has a ttl as given by the */
+/* value being passed in. The timeout queue is added tot the list of those */
+/* used internally for stateful filtering. */
+/* ------------------------------------------------------------------------ */
+ipftq_t *
+ipf_state_add_tq(softc, ttl)
+ ipf_main_softc_t *softc;
+ int ttl;
+{
+ ipf_state_softc_t *softs = softc->ipf_state_soft;
+
+ return ipf_addtimeoutqueue(softc, &softs->ipf_state_usertq, ttl);
+}
+
+
+#ifndef _KERNEL
+/*
+ * Display the built up state table rules and mapping entries.
+ */
+void
+ipf_state_dump(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_state_softc_t *softs = arg;
+ ipstate_t *ips;
+
+ printf("List of active state sessions:\n");
+ for (ips = softs->ipf_state_list; ips != NULL; )
+ ips = printstate(ips, opts & (OPT_DEBUG|OPT_VERBOSE),
+ softc->ipf_ticks);
+}
+#endif
diff --git a/sys/contrib/ipfilter/netinet/ip_state.h b/sys/contrib/ipfilter/netinet/ip_state.h
index 9c4e814..e765ac7 100644
--- a/sys/contrib/ipfilter/netinet/ip_state.h
+++ b/sys/contrib/ipfilter/netinet/ip_state.h
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1995-2001 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
@@ -27,8 +27,10 @@ struct ipscan;
# define IPSTATE_MAX 4013 /* Maximum number of states held */
#endif
-#define SEQ_GE(a,b) ((int)((a) - (b)) >= 0)
-#define SEQ_GT(a,b) ((int)((a) - (b)) > 0)
+#define PAIRS(s1,d1,s2,d2) ((((s1) == (s2)) && ((d1) == (d2))) ||\
+ (((s1) == (d2)) && ((d1) == (s2))))
+#define IPPAIR(s1,d1,s2,d2) PAIRS((s1).s_addr, (d1).s_addr, \
+ (s2).s_addr, (d2).s_addr)
typedef struct ipstate {
@@ -56,6 +58,7 @@ typedef struct ipstate {
u_int is_pass;
u_char is_p; /* Protocol */
u_char is_v;
+ int is_family;
u_32_t is_hv;
u_32_t is_tag;
u_32_t is_opt[2]; /* packet options set */
@@ -75,6 +78,8 @@ typedef struct ipstate {
u_32_t is_rulen; /* rule number when created */
u_32_t is_s0[2];
u_short is_smsk[2];
+ frdest_t is_dif;
+ frdest_t is_tifs[2];
char is_group[FR_GROUPLEN];
char is_sbuf[2][16];
char is_ifname[4][LIFNAMSIZ];
@@ -87,7 +92,6 @@ typedef struct ipstate {
#define is_daddr is_dst.in4.s_addr
#define is_icmp is_ps.is_ics
#define is_type is_icmp.ici_type
-#define is_code is_icmp.ici_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
@@ -119,6 +123,7 @@ typedef struct ipstate {
#define IS_ISNSYN 0x40000
#define IS_ISNACK 0x80000
#define IS_STATESYNC 0x100000
+#define IS_LOOSE 0x200000
/*
* IS_SC flags are for scan-operations that need to be recognised in state.
*/
@@ -130,7 +135,7 @@ typedef struct ipstate {
#define IS_SC_ALL (IS_SC_MATCHC|IS_SC_MATCHC|IS_SC_CLIENT|IS_SC_SERVER)
/*
- * Flags that can be passed into fr_addstate
+ * Flags that can be passed into ipf_addstate
*/
#define IS_INHERITED 0x0fffff00
@@ -181,6 +186,7 @@ typedef struct ipslog {
#define ISL_NEW 0
#define ISL_CLONE 1
+#define ISL_STATECHANGE 2
#define ISL_EXPIRE 0xffff
#define ISL_FLUSH 0xfffe
#define ISL_REMOVE 0xfffd
@@ -191,71 +197,141 @@ typedef struct ipslog {
typedef struct ips_stat {
+ u_int iss_active;
+ u_int iss_active_proto[256];
+ u_long iss_add_bad;
+ u_long iss_add_dup;
+ u_long iss_add_locked;
+ u_long iss_add_oow;
+ u_long iss_bucket_full;
+ u_long iss_check_bad;
+ u_long iss_check_miss;
+ u_long iss_check_nattag;
+ u_long iss_check_notag;
+ u_long iss_clone_nomem;
+ u_long iss_cloned;
+ u_long iss_expire;
+ u_long iss_fin;
+ u_long iss_flush_all;
+ u_long iss_flush_closing;
+ u_long iss_flush_queue;
+ u_long iss_flush_state;
+ u_long iss_flush_timeout;
u_long iss_hits;
- u_long iss_miss;
+ u_long iss_icmp6_icmperr;
+ u_long iss_icmp6_miss;
+ u_long iss_icmp6_notinfo;
+ u_long iss_icmp6_notquery;
+ u_long iss_icmp_bad;
+ u_long iss_icmp_banned;
+ u_long iss_icmp_headblock;
+ u_long iss_icmp_hits;
+ u_long iss_icmp_icmperr;
+ u_long iss_icmp_miss;
+ u_long iss_icmp_notquery;
+ u_long iss_icmp_short;
+ u_long iss_icmp_toomany;
+ u_int iss_inuse;
+ ipstate_t *iss_list;
+ u_long iss_log_fail;
+ u_long iss_log_ok;
+ u_long iss_lookup_badifp;
+ u_long iss_lookup_badport;
+ u_long iss_lookup_miss;
u_long iss_max;
- u_long iss_maxref;
- u_long iss_tcp;
- u_long iss_udp;
- u_long iss_icmp;
+ u_long iss_max_ref;
+ u_long iss_max_track;
+ u_long iss_miss_mask;
u_long iss_nomem;
- u_long iss_expire;
- u_long iss_fin;
- u_long iss_active;
- u_long iss_logged;
- u_long iss_logfail;
- u_long iss_inuse;
- u_long iss_wild;
- u_long iss_killed;
- u_long iss_ticks;
- u_long iss_bucketfull;
- int iss_statesize;
- int iss_statemax;
+ u_long iss_oow;
+ u_long iss_orphan;
+ u_long iss_proto[256];
+ u_long iss_scan_block;
+ u_long iss_state_max;
+ u_long iss_state_size;
+ u_long iss_states[IPF_TCP_NSTATES];
ipstate_t **iss_table;
- ipstate_t *iss_list;
- u_long *iss_bucketlen;
+ u_long iss_tcp_closing;
+ u_long iss_tcp_oow;
+ u_long iss_tcp_rstadd;
+ u_long iss_tcp_toosmall;
+ u_long iss_tcp_badopt;
+ u_long iss_tcp_fsm;
+ u_long iss_tcp_strict;
ipftq_t *iss_tcptab;
+ u_int iss_ticks;
+ u_long iss_wild;
+ u_long iss_winsack;
+ u_int *iss_bucketlen;
} ips_stat_t;
-extern u_long fr_tcpidletimeout;
-extern u_long fr_tcpclosewait;
-extern u_long fr_tcplastack;
-extern u_long fr_tcptimeout;
-extern u_long fr_tcpclosed;
-extern u_long fr_tcphalfclosed;
-extern u_long fr_udptimeout;
-extern u_long fr_udpacktimeout;
-extern u_long fr_icmptimeout;
-extern u_long fr_icmpacktimeout;
-extern u_long fr_iptimeout;
-extern int fr_statemax;
-extern int fr_statesize;
-extern int fr_state_lock;
-extern int fr_state_maxbucket;
-extern int fr_state_maxbucket_reset;
-extern ipstate_t *ips_list;
-extern ipftq_t *ips_utqe;
-extern ipftq_t ips_tqtqb[IPF_TCP_NSTATES];
+typedef struct ipf_state_softc_s {
+ ipfmutex_t ipf_stinsert;
+ int ipf_state_logging;
+ int ipf_state_lock;
+ int ipf_state_doflush;
+ u_int ipf_state_inited;
+ u_int ipf_state_max;
+ u_int ipf_state_maxbucket;
+ u_int ipf_state_size;
+ u_int ipf_state_wm_freq;
+ u_int ipf_state_wm_high;
+ u_int ipf_state_wm_low;
+ u_int ipf_state_wm_last;
+ u_long *ipf_state_seed;
+ ipstate_t *ipf_state_list;
+ ipstate_t **ipf_state_table;
+ ipftuneable_t *ipf_state_tune;
+ ipftq_t *ipf_state_usertq;
+ ipftq_t ipf_state_pending;
+ ipftq_t ipf_state_deletetq;
+ ipftq_t ipf_state_udptq;
+ ipftq_t ipf_state_udpacktq;
+ ipftq_t ipf_state_iptq;
+ ipftq_t ipf_state_icmptq;
+ ipftq_t ipf_state_icmpacktq;
+ ipftq_t ipf_state_tcptq[IPF_TCP_NSTATES];
+ ips_stat_t ipf_state_stats;
+} ipf_state_softc_t;
+
-extern int fr_stateinit __P((void));
-extern ipstate_t *fr_addstate __P((fr_info_t *, ipstate_t **, u_int));
-extern frentry_t *fr_checkstate __P((struct fr_info *, u_32_t *));
-extern ipstate_t *fr_stlookup __P((fr_info_t *, tcphdr_t *, ipftq_t **));
-extern void fr_statesync __P((void *));
-extern void fr_timeoutstate __P((void));
-extern int fr_tcp_age __P((struct ipftqent *, struct fr_info *,
- struct ipftq *, int));
-extern int fr_tcpinwindow __P((struct fr_info *, struct tcpdata *,
+#ifndef _KERNEL
+extern void ipf_state_dump __P((ipf_main_softc_t *, void *));
+#endif
+extern int ipf_tcp_age __P((struct ipftqent *, struct fr_info *,
+ struct ipftq *, int, int));
+extern int ipf_tcpinwindow __P((struct fr_info *, struct tcpdata *,
struct tcpdata *, tcphdr_t *, int));
-extern void fr_stateunload __P((void));
-extern void ipstate_log __P((struct ipstate *, u_int));
-extern int fr_state_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *));
-extern void fr_stinsert __P((struct ipstate *, int));
-extern void fr_sttab_init __P((struct ipftq *));
-extern void fr_sttab_destroy __P((struct ipftq *));
-extern void fr_updatestate __P((fr_info_t *, ipstate_t *, ipftq_t *));
-extern void fr_statederef __P((ipstate_t **));
-extern void fr_setstatequeue __P((ipstate_t *, int));
+
+extern int ipf_state_add __P((ipf_main_softc_t *, fr_info_t *,
+ ipstate_t **, u_int));
+extern frentry_t *ipf_state_check __P((struct fr_info *, u_32_t *));
+extern void ipf_state_deref __P((ipf_main_softc_t *, ipstate_t **));
+extern void ipf_state_expire __P((ipf_main_softc_t *));
+extern int ipf_state_flush __P((ipf_main_softc_t *, int, int));
+extern ipstate_t *ipf_state_lookup __P((fr_info_t *, tcphdr_t *, ipftq_t **));
+extern int ipf_state_init __P((void));
+extern int ipf_state_insert __P((ipf_main_softc_t *, struct ipstate *, int));
+extern int ipf_state_ioctl __P((ipf_main_softc_t *, caddr_t, ioctlcmd_t, int, int, void *));
+extern void ipf_state_log __P((ipf_main_softc_t *, struct ipstate *, u_int));
+extern int ipf_state_matchflush __P((ipf_main_softc_t *, caddr_t));
+extern int ipf_state_rehash __P((ipf_main_softc_t *, ipftuneable_t *, ipftuneval_t *));
+extern void ipf_state_setqueue __P((ipf_main_softc_t *, ipstate_t *, int));
+extern void ipf_state_setpending __P((ipf_main_softc_t *, ipstate_t *));
+extern int ipf_state_settimeout __P((struct ipf_main_softc_s *, ipftuneable_t *, ipftuneval_t *));
+extern void ipf_state_sync __P((ipf_main_softc_t *, void *));
+extern void ipf_state_update __P((fr_info_t *, ipstate_t *));
+
+extern void ipf_sttab_init __P((ipf_main_softc_t *, struct ipftq *));
+extern void ipf_sttab_destroy __P((struct ipftq *));
+extern void ipf_state_setlock __P((void *, int));
+extern int ipf_state_main_load __P((void));
+extern int ipf_state_main_unload __P((void));
+extern void *ipf_state_soft_create __P((ipf_main_softc_t *));
+extern void ipf_state_soft_destroy __P((ipf_main_softc_t *, void *));
+extern int ipf_state_soft_init __P((ipf_main_softc_t *, void *));
+extern int ipf_state_soft_fini __P((ipf_main_softc_t *, void *));
+extern ipftq_t *ipf_state_add_tq __P((ipf_main_softc_t *, int));
#endif /* __IP_STATE_H__ */
diff --git a/sys/contrib/ipfilter/netinet/ip_sync.c b/sys/contrib/ipfilter/netinet/ip_sync.c
index a72f50f..0c2fe10 100644
--- a/sys/contrib/ipfilter/netinet/ip_sync.c
+++ b/sys/contrib/ipfilter/netinet/ip_sync.c
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1995-1998 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*/
@@ -32,6 +32,10 @@ struct file;
# if !defined(__SVR4) && !defined(__svr4__)
# include <sys/mbuf.h>
# endif
+# include <sys/select.h>
+# if __FreeBSD_version >= 500000
+# include <sys/selinfo.h>
+# endif
#endif
#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000)
# include <sys/proc.h>
@@ -39,9 +43,6 @@ struct file;
#if defined(_KERNEL) && (__FreeBSD_version >= 220000)
# include <sys/filio.h>
# include <sys/fcntl.h>
-# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM)
-# include "opt_ipfilter.h"
-# endif
#else
# include <sys/ioctl.h>
#endif
@@ -64,7 +65,6 @@ struct file;
#ifdef sun
# include <net/af.h>
#endif
-#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
@@ -98,66 +98,219 @@ struct file;
/* END OF INCLUDES */
#if !defined(lint)
-static const char rcsid[] = "@(#)$Id: ip_sync.c,v 2.40.2.9 2007/06/02 21:22:28 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id$";
#endif
#define SYNC_STATETABSZ 256
#define SYNC_NATTABSZ 256
-#ifdef IPFILTER_SYNC
-ipfmutex_t ipf_syncadd, ipsl_mutex;
-ipfrwlock_t ipf_syncstate, ipf_syncnat;
+typedef struct ipf_sync_softc_s {
+ ipfmutex_t ipf_syncadd;
+ ipfmutex_t ipsl_mutex;
+ ipfrwlock_t ipf_syncstate;
+ ipfrwlock_t ipf_syncnat;
#if SOLARIS && defined(_KERNEL)
-kcondvar_t ipslwait;
+ kcondvar_t ipslwait;
#endif
-synclist_t *syncstatetab[SYNC_STATETABSZ];
-synclist_t *syncnattab[SYNC_NATTABSZ];
-synclogent_t synclog[SYNCLOG_SZ];
-syncupdent_t syncupd[SYNCLOG_SZ];
-u_int ipf_syncnum = 1;
-u_int ipf_syncwrap = 0;
-u_int sl_idx = 0, /* next available sync log entry */
- su_idx = 0, /* next available sync update entry */
- sl_tail = 0, /* next sync log entry to read */
- su_tail = 0; /* next sync update entry to read */
-int ipf_sync_debug = 0;
-
+#if defined(linux) && defined(_KERNEL)
+ wait_queue_head_t sl_tail_linux;
+#endif
+ synclist_t **syncstatetab;
+ synclist_t **syncnattab;
+ synclogent_t *synclog;
+ syncupdent_t *syncupd;
+ u_int ipf_sync_num;
+ u_int ipf_sync_wrap;
+ u_int sl_idx; /* next available sync log entry */
+ u_int su_idx; /* next available sync update entry */
+ u_int sl_tail; /* next sync log entry to read */
+ u_int su_tail; /* next sync update entry to read */
+ int ipf_sync_log_sz;
+ int ipf_sync_nat_tab_sz;
+ int ipf_sync_state_tab_sz;
+ int ipf_sync_debug;
+ int ipf_sync_events;
+ u_32_t ipf_sync_lastwakeup;
+ int ipf_sync_wake_interval;
+ int ipf_sync_event_high_wm;
+ int ipf_sync_queue_high_wm;
+ int ipf_sync_inited;
+} ipf_sync_softc_t;
+
+static int ipf_sync_flush_table __P((ipf_sync_softc_t *, int, synclist_t **));
+static void ipf_sync_wakeup __P((ipf_main_softc_t *));
+static void ipf_sync_del __P((ipf_sync_softc_t *, synclist_t *));
+static void ipf_sync_poll_wakeup __P((ipf_main_softc_t *));
+static int ipf_sync_nat __P((ipf_main_softc_t *, synchdr_t *, void *));
+static int ipf_sync_state __P((ipf_main_softc_t *, synchdr_t *, void *));
# if !defined(sparc) && !defined(__hppa)
-void ipfsync_tcporder __P((int, struct tcpdata *));
-void ipfsync_natorder __P((int, struct nat *));
-void ipfsync_storder __P((int, struct ipstate *));
+void ipf_sync_tcporder __P((int, struct tcpdata *));
+void ipf_sync_natorder __P((int, struct nat *));
+void ipf_sync_storder __P((int, struct ipstate *));
# endif
+void *
+ipf_sync_soft_create(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_sync_softc_t *softs;
+
+ KMALLOC(softs, ipf_sync_softc_t *);
+ if (softs == NULL) {
+ IPFERROR(110024);
+ return NULL;
+ }
+
+ bzero((char *)softs, sizeof(*softs));
+
+ softs->ipf_sync_log_sz = SYNCLOG_SZ;
+ softs->ipf_sync_nat_tab_sz = SYNC_STATETABSZ;
+ softs->ipf_sync_state_tab_sz = SYNC_STATETABSZ;
+ softs->ipf_sync_event_high_wm = SYNCLOG_SZ * 100 / 90; /* 90% */
+ softs->ipf_sync_queue_high_wm = SYNCLOG_SZ * 100 / 90; /* 90% */
+
+ return softs;
+}
+
+
/* ------------------------------------------------------------------------ */
-/* Function: ipfsync_init */
+/* Function: ipf_sync_init */
/* Returns: int - 0 == success, -1 == failure */
/* Parameters: Nil */
/* */
/* Initialise all of the locks required for the sync code and initialise */
/* any data structures, as required. */
/* ------------------------------------------------------------------------ */
-int ipfsync_init()
+int
+ipf_sync_soft_init(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
{
- RWLOCK_INIT(&ipf_syncstate, "add things to state sync table");
- RWLOCK_INIT(&ipf_syncnat, "add things to nat sync table");
- MUTEX_INIT(&ipf_syncadd, "add things to sync table");
- MUTEX_INIT(&ipsl_mutex, "add things to sync table");
+ ipf_sync_softc_t *softs = arg;
+
+ KMALLOCS(softs->synclog, synclogent_t *,
+ softs->ipf_sync_log_sz * sizeof(*softs->synclog));
+ if (softs->synclog == NULL)
+ return -1;
+ bzero((char *)softs->synclog,
+ softs->ipf_sync_log_sz * sizeof(*softs->synclog));
+
+ KMALLOCS(softs->syncupd, syncupdent_t *,
+ softs->ipf_sync_log_sz * sizeof(*softs->syncupd));
+ if (softs->syncupd == NULL)
+ return -2;
+ bzero((char *)softs->syncupd,
+ softs->ipf_sync_log_sz * sizeof(*softs->syncupd));
+
+ KMALLOCS(softs->syncstatetab, synclist_t **,
+ softs->ipf_sync_state_tab_sz * sizeof(*softs->syncstatetab));
+ if (softs->syncstatetab == NULL)
+ return -3;
+ bzero((char *)softs->syncstatetab,
+ softs->ipf_sync_state_tab_sz * sizeof(*softs->syncstatetab));
+
+ KMALLOCS(softs->syncnattab, synclist_t **,
+ softs->ipf_sync_nat_tab_sz * sizeof(*softs->syncnattab));
+ if (softs->syncnattab == NULL)
+ return -3;
+ bzero((char *)softs->syncnattab,
+ softs->ipf_sync_nat_tab_sz * sizeof(*softs->syncnattab));
+
+ softs->ipf_sync_num = 1;
+ softs->ipf_sync_wrap = 0;
+ softs->sl_idx = 0;
+ softs->su_idx = 0;
+ softs->sl_tail = 0;
+ softs->su_tail = 0;
+ softs->ipf_sync_events = 0;
+ softs->ipf_sync_lastwakeup = 0;
+
+
# if SOLARIS && defined(_KERNEL)
- cv_init(&ipslwait, "ipsl condvar", CV_DRIVER, NULL);
+ cv_init(&softs->ipslwait, "ipsl condvar", CV_DRIVER, NULL);
# endif
+ RWLOCK_INIT(&softs->ipf_syncstate, "add things to state sync table");
+ RWLOCK_INIT(&softs->ipf_syncnat, "add things to nat sync table");
+ MUTEX_INIT(&softs->ipf_syncadd, "add things to sync table");
+ MUTEX_INIT(&softs->ipsl_mutex, "read ring lock");
- bzero((char *)syncnattab, sizeof(syncnattab));
- bzero((char *)syncstatetab, sizeof(syncstatetab));
+ softs->ipf_sync_inited = 1;
return 0;
}
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_sync_unload */
+/* Returns: int - 0 == success, -1 == failure */
+/* Parameters: Nil */
+/* */
+/* Destroy the locks created when initialising and free any memory in use */
+/* with the synchronisation tables. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_sync_soft_fini(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_sync_softc_t *softs = arg;
+
+ if (softs->syncnattab != NULL) {
+ ipf_sync_flush_table(softs, softs->ipf_sync_nat_tab_sz,
+ softs->syncnattab);
+ KFREES(softs->syncnattab,
+ softs->ipf_sync_nat_tab_sz * sizeof(*softs->syncnattab));
+ softs->syncnattab = NULL;
+ }
+
+ if (softs->syncstatetab != NULL) {
+ ipf_sync_flush_table(softs, softs->ipf_sync_state_tab_sz,
+ softs->syncstatetab);
+ KFREES(softs->syncstatetab,
+ softs->ipf_sync_state_tab_sz *
+ sizeof(*softs->syncstatetab));
+ softs->syncstatetab = NULL;
+ }
+
+ if (softs->syncupd != NULL) {
+ KFREES(softs->syncupd,
+ softs->ipf_sync_log_sz * sizeof(*softs->syncupd));
+ softs->syncupd = NULL;
+ }
+
+ if (softs->synclog != NULL) {
+ KFREES(softs->synclog,
+ softs->ipf_sync_log_sz * sizeof(*softs->synclog));
+ softs->synclog = NULL;
+ }
+
+ if (softs->ipf_sync_inited == 1) {
+ MUTEX_DESTROY(&softs->ipsl_mutex);
+ MUTEX_DESTROY(&softs->ipf_syncadd);
+ RW_DESTROY(&softs->ipf_syncnat);
+ RW_DESTROY(&softs->ipf_syncstate);
+ softs->ipf_sync_inited = 0;
+ }
+
+ return 0;
+}
+
+void
+ipf_sync_soft_destroy(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_sync_softc_t *softs = arg;
+
+ KFREE(softs);
+}
+
+
# if !defined(sparc) && !defined(__hppa)
/* ------------------------------------------------------------------------ */
-/* Function: ipfsync_tcporder */
+/* Function: ipf_sync_tcporder */
/* Returns: Nil */
/* Parameters: way(I) - direction of byte order conversion. */
/* td(IO) - pointer to data to be converted. */
@@ -165,9 +318,10 @@ int ipfsync_init()
/* Do byte swapping on values in the TCP state information structure that */
/* need to be used at both ends by the host in their native byte order. */
/* ------------------------------------------------------------------------ */
-void ipfsync_tcporder(way, td)
-int way;
-tcpdata_t *td;
+void
+ipf_sync_tcporder(way, td)
+ int way;
+ tcpdata_t *td;
{
if (way) {
td->td_maxwin = htons(td->td_maxwin);
@@ -182,7 +336,7 @@ tcpdata_t *td;
/* ------------------------------------------------------------------------ */
-/* Function: ipfsync_natorder */
+/* Function: ipf_sync_natorder */
/* Returns: Nil */
/* Parameters: way(I) - direction of byte order conversion. */
/* nat(IO) - pointer to data to be converted. */
@@ -190,9 +344,10 @@ tcpdata_t *td;
/* Do byte swapping on values in the NAT data structure that need to be */
/* used at both ends by the host in their native byte order. */
/* ------------------------------------------------------------------------ */
-void ipfsync_natorder(way, n)
-int way;
-nat_t *n;
+void
+ipf_sync_natorder(way, n)
+ int way;
+ nat_t *n;
{
if (way) {
n->nat_age = htonl(n->nat_age);
@@ -211,7 +366,7 @@ nat_t *n;
/* ------------------------------------------------------------------------ */
-/* Function: ipfsync_storder */
+/* Function: ipf_sync_storder */
/* Returns: Nil */
/* Parameters: way(I) - direction of byte order conversion. */
/* ips(IO) - pointer to data to be converted. */
@@ -219,12 +374,13 @@ nat_t *n;
/* Do byte swapping on values in the IP state data structure that need to */
/* be used at both ends by the host in their native byte order. */
/* ------------------------------------------------------------------------ */
-void ipfsync_storder(way, ips)
-int way;
-ipstate_t *ips;
+void
+ipf_sync_storder(way, ips)
+ int way;
+ ipstate_t *ips;
{
- ipfsync_tcporder(way, &ips->is_tcp.ts_data[0]);
- ipfsync_tcporder(way, &ips->is_tcp.ts_data[1]);
+ ipf_sync_tcporder(way, &ips->is_tcp.ts_data[0]);
+ ipf_sync_tcporder(way, &ips->is_tcp.ts_data[1]);
if (way) {
ips->is_hv = htonl(ips->is_hv);
@@ -263,36 +419,37 @@ ipstate_t *ips;
}
}
# else /* !defined(sparc) && !defined(__hppa) */
-# define ipfsync_tcporder(x,y)
-# define ipfsync_natorder(x,y)
-# define ipfsync_storder(x,y)
+# define ipf_sync_tcporder(x,y)
+# define ipf_sync_natorder(x,y)
+# define ipf_sync_storder(x,y)
# endif /* !defined(sparc) && !defined(__hppa) */
-/* enable this for debugging */
-# ifdef _KERNEL
/* ------------------------------------------------------------------------ */
-/* Function: ipfsync_write */
+/* Function: ipf_sync_write */
/* Returns: int - 0 == success, else error value. */
/* Parameters: uio(I) - pointer to information about data to write */
/* */
/* Moves data from user space into the kernel and uses it for updating data */
/* structures in the state/NAT tables. */
/* ------------------------------------------------------------------------ */
-int ipfsync_write(uio)
-struct uio *uio;
+int
+ipf_sync_write(softc, uio)
+ ipf_main_softc_t *softc;
+ struct uio *uio;
{
+ ipf_sync_softc_t *softs = softc->ipf_sync_soft;
synchdr_t sh;
- /*
+ /*
* THIS MUST BE SUFFICIENT LARGE TO STORE
- * ANY POSSIBLE DATA TYPE
+ * ANY POSSIBLE DATA TYPE
*/
- char data[2048];
+ char data[2048];
int err = 0;
-# if (BSD >= 199306) || defined(__FreeBSD__) || defined(__osf__)
+# if BSD_GE_YEAR(199306) || defined(__FreeBSD__) || defined(__osf__)
uio->uio_rw = UIO_WRITE;
# endif
@@ -304,7 +461,7 @@ struct uio *uio;
err = UIOMOVE(&sh, sizeof(sh), UIO_WRITE, uio);
if (err) {
- if (ipf_sync_debug > 2)
+ if (softs->ipf_sync_debug > 2)
printf("uiomove(header) failed: %d\n",
err);
return err;
@@ -315,59 +472,65 @@ struct uio *uio;
sh.sm_len = ntohl(sh.sm_len);
sh.sm_num = ntohl(sh.sm_num);
- if (ipf_sync_debug > 8)
+ if (softs->ipf_sync_debug > 8)
printf("[%d] Read v:%d p:%d cmd:%d table:%d rev:%d len:%d magic:%x\n",
sh.sm_num, sh.sm_v, sh.sm_p, sh.sm_cmd,
sh.sm_table, sh.sm_rev, sh.sm_len,
sh.sm_magic);
if (sh.sm_magic != SYNHDRMAGIC) {
- if (ipf_sync_debug > 2)
- printf("uiomove(header) invalud %s\n",
+ if (softs->ipf_sync_debug > 2)
+ printf("uiomove(header) invalid %s\n",
"magic");
+ IPFERROR(110001);
return EINVAL;
}
if (sh.sm_v != 4 && sh.sm_v != 6) {
- if (ipf_sync_debug > 2)
+ if (softs->ipf_sync_debug > 2)
printf("uiomove(header) invalid %s\n",
"protocol");
+ IPFERROR(110002);
return EINVAL;
}
if (sh.sm_cmd > SMC_MAXCMD) {
- if (ipf_sync_debug > 2)
+ if (softs->ipf_sync_debug > 2)
printf("uiomove(header) invalid %s\n",
"command");
+ IPFERROR(110003);
return EINVAL;
}
if (sh.sm_table > SMC_MAXTBL) {
- if (ipf_sync_debug > 2)
+ if (softs->ipf_sync_debug > 2)
printf("uiomove(header) invalid %s\n",
"table");
+ IPFERROR(110004);
return EINVAL;
}
} else {
/* unsufficient data, wait until next call */
- if (ipf_sync_debug > 2)
+ if (softs->ipf_sync_debug > 2)
printf("uiomove(header) insufficient data");
+ IPFERROR(110005);
return EAGAIN;
}
/*
- * We have a header, so try to read the amount of data
+ * We have a header, so try to read the amount of data
* needed for the request
*/
/* not supported */
if (sh.sm_len == 0) {
- if (ipf_sync_debug > 2)
+ if (softs->ipf_sync_debug > 2)
printf("uiomove(data zero length %s\n",
"not supported");
+ IPFERROR(110006);
return EINVAL;
}
@@ -376,33 +539,34 @@ struct uio *uio;
err = UIOMOVE(data, sh.sm_len, UIO_WRITE, uio);
if (err) {
- if (ipf_sync_debug > 2)
+ if (softs->ipf_sync_debug > 2)
printf("uiomove(data) failed: %d\n",
err);
return err;
}
- if (ipf_sync_debug > 7)
+ if (softs->ipf_sync_debug > 7)
printf("uiomove(data) %d bytes read\n",
sh.sm_len);
if (sh.sm_table == SMC_STATE)
- err = ipfsync_state(&sh, data);
+ err = ipf_sync_state(softc, &sh, data);
else if (sh.sm_table == SMC_NAT)
- err = ipfsync_nat(&sh, data);
- if (ipf_sync_debug > 7)
+ err = ipf_sync_nat(softc, &sh, data);
+ if (softs->ipf_sync_debug > 7)
printf("[%d] Finished with error %d\n",
sh.sm_num, err);
} else {
/* insufficient data, wait until next call */
- if (ipf_sync_debug > 2)
+ if (softs->ipf_sync_debug > 2)
printf("uiomove(data) %s %d bytes, got %d\n",
"insufficient data, need",
- sh.sm_len, uio->uio_resid);
+ sh.sm_len, (int)uio->uio_resid);
+ IPFERROR(110007);
return EAGAIN;
}
- }
+ }
/* no more data */
return 0;
@@ -410,7 +574,7 @@ struct uio *uio;
/* ------------------------------------------------------------------------ */
-/* Function: ipfsync_read */
+/* Function: ipf_sync_read */
/* Returns: int - 0 == success, else error value. */
/* Parameters: uio(O) - pointer to information about where to store data */
/* */
@@ -418,89 +582,105 @@ struct uio *uio;
/* for pending state/NAT updates. If no data is available, the caller is */
/* put to sleep, pending a wakeup from the "lower half" of this code. */
/* ------------------------------------------------------------------------ */
-int ipfsync_read(uio)
-struct uio *uio;
+int
+ipf_sync_read(softc, uio)
+ ipf_main_softc_t *softc;
+ struct uio *uio;
{
+ ipf_sync_softc_t *softs = softc->ipf_sync_soft;
syncupdent_t *su;
synclogent_t *sl;
int err = 0;
- if ((uio->uio_resid & 3) || (uio->uio_resid < 8))
+ if ((uio->uio_resid & 3) || (uio->uio_resid < 8)) {
+ IPFERROR(110008);
return EINVAL;
+ }
-# if (BSD >= 199306) || defined(__FreeBSD__) || defined(__osf__)
+# if BSD_GE_YEAR(199306) || defined(__FreeBSD__) || defined(__osf__)
uio->uio_rw = UIO_READ;
# endif
- MUTEX_ENTER(&ipsl_mutex);
- while ((sl_tail == sl_idx) && (su_tail == su_idx)) {
-# if SOLARIS && defined(_KERNEL)
- if (!cv_wait_sig(&ipslwait, &ipsl_mutex)) {
- MUTEX_EXIT(&ipsl_mutex);
+ MUTEX_ENTER(&softs->ipsl_mutex);
+ while ((softs->sl_tail == softs->sl_idx) &&
+ (softs->su_tail == softs->su_idx)) {
+# if defined(_KERNEL)
+# if SOLARIS
+ if (!cv_wait_sig(&softs->ipslwait, &softs->ipsl_mutex.ipf_lk)) {
+ MUTEX_EXIT(&softs->ipsl_mutex);
+ IPFERROR(110009);
return EINTR;
}
-# else
-# ifdef __hpux
+# else
+# ifdef __hpux
{
lock_t *l;
- l = get_sleep_lock(&sl_tail);
- err = sleep(&sl_tail, PZERO+1);
+ l = get_sleep_lock(&softs->sl_tail);
+ err = sleep(&softs->sl_tail, PZERO+1);
if (err) {
- MUTEX_EXIT(&ipsl_mutex);
+ MUTEX_EXIT(&softs->ipsl_mutex);
+ IPFERROR(110010);
return EINTR;
}
spinunlock(l);
}
-# else /* __hpux */
-# ifdef __osf__
- err = mpsleep(&sl_tail, PSUSP|PCATCH, "ipl sleep", 0,
- &ipsl_mutex, MS_LOCK_SIMPLE);
- if (err)
+# else /* __hpux */
+# ifdef __osf__
+ err = mpsleep(&softs->sl_tail, PSUSP|PCATCH, "ipl sleep", 0,
+ &softs->ipsl_mutex, MS_LOCK_SIMPLE);
+ if (err) {
+ IPFERROR(110011);
return EINTR;
-# else
- MUTEX_EXIT(&ipsl_mutex);
- err = SLEEP(&sl_tail, "ipl sleep");
- if (err)
+ }
+# else
+ MUTEX_EXIT(&softs->ipsl_mutex);
+ err = SLEEP(&softs->sl_tail, "ipl sleep");
+ if (err) {
+ IPFERROR(110012);
return EINTR;
- MUTEX_ENTER(&ipsl_mutex);
-# endif /* __osf__ */
-# endif /* __hpux */
-# endif /* SOLARIS */
+ }
+ MUTEX_ENTER(&softs->ipsl_mutex);
+# endif /* __osf__ */
+# endif /* __hpux */
+# endif /* SOLARIS */
+# endif /* _KERNEL */
}
- MUTEX_EXIT(&ipsl_mutex);
- READ_ENTER(&ipf_syncstate);
- while ((sl_tail < sl_idx) && (uio->uio_resid > sizeof(*sl))) {
- sl = synclog + sl_tail++;
+ while ((softs->sl_tail < softs->sl_idx) &&
+ (uio->uio_resid > sizeof(*sl))) {
+ sl = softs->synclog + softs->sl_tail++;
+ MUTEX_EXIT(&softs->ipsl_mutex);
err = UIOMOVE(sl, sizeof(*sl), UIO_READ, uio);
if (err != 0)
- break;
+ goto goterror;
+ MUTEX_ENTER(&softs->ipsl_mutex);
}
- while ((su_tail < su_idx) && (uio->uio_resid > sizeof(*su))) {
- su = syncupd + su_tail;
- su_tail++;
+ while ((softs->su_tail < softs->su_idx) &&
+ (uio->uio_resid > sizeof(*su))) {
+ su = softs->syncupd + softs->su_tail;
+ softs->su_tail++;
+ MUTEX_EXIT(&softs->ipsl_mutex);
err = UIOMOVE(su, sizeof(*su), UIO_READ, uio);
if (err != 0)
- break;
+ goto goterror;
+ MUTEX_ENTER(&softs->ipsl_mutex);
if (su->sup_hdr.sm_sl != NULL)
su->sup_hdr.sm_sl->sl_idx = -1;
}
-
- MUTEX_ENTER(&ipf_syncadd);
- if (su_tail == su_idx)
- su_tail = su_idx = 0;
- if (sl_tail == sl_idx)
- sl_tail = sl_idx = 0;
- MUTEX_EXIT(&ipf_syncadd);
- RWLOCK_EXIT(&ipf_syncstate);
+ if (softs->sl_tail == softs->sl_idx)
+ softs->sl_tail = softs->sl_idx = 0;
+ if (softs->su_tail == softs->su_idx)
+ softs->su_tail = softs->su_idx = 0;
+ MUTEX_EXIT(&softs->ipsl_mutex);
+goterror:
return err;
}
/* ------------------------------------------------------------------------ */
-/* Function: ipfsync_state */
+/* Function: ipf_sync_state */
/* Returns: int - 0 == success, else error value. */
/* Parameters: sp(I) - pointer to sync packet data header */
/* uio(I) - pointer to user data for further information */
@@ -511,10 +691,13 @@ struct uio *uio;
/* create a new state entry or update one. Deletion is left to the state */
/* structures being timed out correctly. */
/* ------------------------------------------------------------------------ */
-int ipfsync_state(sp, data)
-synchdr_t *sp;
-void *data;
+static int
+ipf_sync_state(softc, sp, data)
+ ipf_main_softc_t *softc;
+ synchdr_t *sp;
+ void *data;
{
+ ipf_sync_softc_t *softs = softc->ipf_sync_soft;
synctcp_update_t su;
ipstate_t *is, sn;
synclist_t *sl;
@@ -522,7 +705,7 @@ void *data;
u_int hv;
int err = 0;
- hv = sp->sm_num & (SYNC_STATETABSZ - 1);
+ hv = sp->sm_num & (softs->ipf_sync_state_tab_sz - 1);
switch (sp->sm_cmd)
{
@@ -531,12 +714,14 @@ void *data;
bcopy(data, &sn, sizeof(sn));
KMALLOC(is, ipstate_t *);
if (is == NULL) {
+ IPFERROR(110013);
err = ENOMEM;
break;
}
KMALLOC(sl, synclist_t *);
if (sl == NULL) {
+ IPFERROR(110014);
err = ENOMEM;
KFREE(is);
break;
@@ -545,23 +730,23 @@ void *data;
bzero((char *)is, offsetof(ipstate_t, is_die));
bcopy((char *)&sn.is_die, (char *)&is->is_die,
sizeof(*is) - offsetof(ipstate_t, is_die));
- ipfsync_storder(0, is);
+ ipf_sync_storder(0, is);
/*
* We need to find the same rule on the slave as was used on
* the master to create this state entry.
*/
- READ_ENTER(&ipf_mutex);
- fr = fr_getrulen(IPL_LOGIPF, sn.is_group, sn.is_rulen);
+ READ_ENTER(&softc->ipf_mutex);
+ fr = ipf_getrulen(softc, IPL_LOGIPF, sn.is_group, sn.is_rulen);
if (fr != NULL) {
MUTEX_ENTER(&fr->fr_lock);
fr->fr_ref++;
fr->fr_statecnt++;
MUTEX_EXIT(&fr->fr_lock);
}
- RWLOCK_EXIT(&ipf_mutex);
+ RWLOCK_EXIT(&softc->ipf_mutex);
- if (ipf_sync_debug > 4)
+ if (softs->ipf_sync_debug > 4)
printf("[%d] Filter rules = %p\n", sp->sm_num, fr);
is->is_rule = fr;
@@ -571,16 +756,16 @@ void *data;
sl->sl_ips = is;
bcopy(sp, &sl->sl_hdr, sizeof(struct synchdr));
- WRITE_ENTER(&ipf_syncstate);
- WRITE_ENTER(&ipf_state);
+ WRITE_ENTER(&softs->ipf_syncstate);
+ WRITE_ENTER(&softc->ipf_state);
- sl->sl_pnext = syncstatetab + hv;
- sl->sl_next = syncstatetab[hv];
- if (syncstatetab[hv] != NULL)
- syncstatetab[hv]->sl_pnext = &sl->sl_next;
- syncstatetab[hv] = sl;
- MUTEX_DOWNGRADE(&ipf_syncstate);
- fr_stinsert(is, sp->sm_rev);
+ sl->sl_pnext = softs->syncstatetab + hv;
+ sl->sl_next = softs->syncstatetab[hv];
+ if (softs->syncstatetab[hv] != NULL)
+ softs->syncstatetab[hv]->sl_pnext = &sl->sl_next;
+ softs->syncstatetab[hv] = sl;
+ MUTEX_DOWNGRADE(&softs->ipf_syncstate);
+ ipf_state_insert(softc, is, sp->sm_rev);
/*
* Do not initialise the interface pointers for the state
* entry as the full complement of interface names may not
@@ -594,29 +779,31 @@ void *data;
case SMC_UPDATE :
bcopy(data, &su, sizeof(su));
- if (ipf_sync_debug > 4)
+ if (softs->ipf_sync_debug > 4)
printf("[%d] Update age %lu state %d/%d \n",
sp->sm_num, su.stu_age, su.stu_state[0],
su.stu_state[1]);
- READ_ENTER(&ipf_syncstate);
- for (sl = syncstatetab[hv]; (sl != NULL); sl = sl->sl_next)
+ READ_ENTER(&softs->ipf_syncstate);
+ for (sl = softs->syncstatetab[hv]; (sl != NULL);
+ sl = sl->sl_next)
if (sl->sl_hdr.sm_num == sp->sm_num)
break;
if (sl == NULL) {
- if (ipf_sync_debug > 1)
+ if (softs->ipf_sync_debug > 1)
printf("[%d] State not found - can't update\n",
sp->sm_num);
- RWLOCK_EXIT(&ipf_syncstate);
+ RWLOCK_EXIT(&softs->ipf_syncstate);
+ IPFERROR(110015);
err = ENOENT;
break;
}
- READ_ENTER(&ipf_state);
+ READ_ENTER(&softc->ipf_state);
- if (ipf_sync_debug > 6)
- printf("[%d] Data from state v:%d p:%d cmd:%d table:%d rev:%d\n",
- sp->sm_num, sl->sl_hdr.sm_v, sl->sl_hdr.sm_p,
+ if (softs->ipf_sync_debug > 6)
+ printf("[%d] Data from state v:%d p:%d cmd:%d table:%d rev:%d\n",
+ sp->sm_num, sl->sl_hdr.sm_v, sl->sl_hdr.sm_p,
sl->sl_hdr.sm_cmd, sl->sl_hdr.sm_table,
sl->sl_hdr.sm_rev);
@@ -640,56 +827,97 @@ void *data;
break;
}
- if (ipf_sync_debug > 6)
+ if (softs->ipf_sync_debug > 6)
printf("[%d] Setting timers for state\n", sp->sm_num);
- fr_setstatequeue(is, sp->sm_rev);
+ ipf_state_setqueue(softc, is, sp->sm_rev);
MUTEX_EXIT(&is->is_lock);
break;
default :
+ IPFERROR(110016);
err = EINVAL;
break;
}
if (err == 0) {
- RWLOCK_EXIT(&ipf_state);
- RWLOCK_EXIT(&ipf_syncstate);
+ RWLOCK_EXIT(&softc->ipf_state);
+ RWLOCK_EXIT(&softs->ipf_syncstate);
}
- if (ipf_sync_debug > 6)
+ if (softs->ipf_sync_debug > 6)
printf("[%d] Update completed with error %d\n",
sp->sm_num, err);
return err;
}
-# endif /* _KERNEL */
/* ------------------------------------------------------------------------ */
-/* Function: ipfsync_del */
+/* Function: ipf_sync_del */
/* Returns: Nil */
/* Parameters: sl(I) - pointer to synclist object to delete */
/* */
-/* Deletes an object from the synclist table and free's its memory. */
+/* Deletes an object from the synclist. */
/* ------------------------------------------------------------------------ */
-void ipfsync_del(sl)
-synclist_t *sl;
+static void
+ipf_sync_del(softs, sl)
+ ipf_sync_softc_t *softs;
+ synclist_t *sl;
{
- WRITE_ENTER(&ipf_syncstate);
*sl->sl_pnext = sl->sl_next;
if (sl->sl_next != NULL)
sl->sl_next->sl_pnext = sl->sl_pnext;
if (sl->sl_idx != -1)
- syncupd[sl->sl_idx].sup_hdr.sm_sl = NULL;
- RWLOCK_EXIT(&ipf_syncstate);
+ softs->syncupd[sl->sl_idx].sup_hdr.sm_sl = NULL;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_sync_del_state */
+/* Returns: Nil */
+/* Parameters: sl(I) - pointer to synclist object to delete */
+/* */
+/* Deletes an object from the synclist state table and free's its memory. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_sync_del_state(arg, sl)
+ void *arg;
+ synclist_t *sl;
+{
+ ipf_sync_softc_t *softs = arg;
+
+ WRITE_ENTER(&softs->ipf_syncstate);
+ ipf_sync_del(softs, sl);
+ RWLOCK_EXIT(&softs->ipf_syncstate);
KFREE(sl);
}
/* ------------------------------------------------------------------------ */
-/* Function: ipfsync_nat */
+/* Function: ipf_sync_del_nat */
+/* Returns: Nil */
+/* Parameters: sl(I) - pointer to synclist object to delete */
+/* */
+/* Deletes an object from the synclist nat table and free's its memory. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_sync_del_nat(arg, sl)
+ void *arg;
+ synclist_t *sl;
+{
+ ipf_sync_softc_t *softs = arg;
+
+ WRITE_ENTER(&softs->ipf_syncnat);
+ ipf_sync_del(softs, sl);
+ RWLOCK_EXIT(&softs->ipf_syncnat);
+ KFREE(sl);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_sync_nat */
/* Returns: int - 0 == success, else error value. */
/* Parameters: sp(I) - pointer to sync packet data header */
/* uio(I) - pointer to user data for further information */
@@ -700,29 +928,34 @@ synclist_t *sl;
/* create a new NAT entry or update one. Deletion is left to the NAT */
/* structures being timed out correctly. */
/* ------------------------------------------------------------------------ */
-int ipfsync_nat(sp, data)
-synchdr_t *sp;
-void *data;
+static int
+ipf_sync_nat(softc, sp, data)
+ ipf_main_softc_t *softc;
+ synchdr_t *sp;
+ void *data;
{
+ ipf_sync_softc_t *softs = softc->ipf_sync_soft;
syncupdent_t su;
nat_t *n, *nat;
synclist_t *sl;
u_int hv = 0;
int err;
- READ_ENTER(&ipf_syncstate);
+ READ_ENTER(&softs->ipf_syncnat);
switch (sp->sm_cmd)
{
case SMC_CREATE :
KMALLOC(n, nat_t *);
if (n == NULL) {
+ IPFERROR(110017);
err = ENOMEM;
break;
}
KMALLOC(sl, synclist_t *);
if (sl == NULL) {
+ IPFERROR(110018);
err = ENOMEM;
KFREE(n);
break;
@@ -732,59 +965,63 @@ void *data;
bzero((char *)n, offsetof(nat_t, nat_age));
bcopy((char *)&nat->nat_age, (char *)&n->nat_age,
sizeof(*n) - offsetof(nat_t, nat_age));
- ipfsync_natorder(0, n);
+ ipf_sync_natorder(0, n);
n->nat_sync = sl;
+ n->nat_rev = sl->sl_rev;
sl->sl_idx = -1;
sl->sl_ipn = n;
sl->sl_num = ntohl(sp->sm_num);
- WRITE_ENTER(&ipf_nat);
- sl->sl_pnext = syncstatetab + hv;
- sl->sl_next = syncstatetab[hv];
- if (syncstatetab[hv] != NULL)
- syncstatetab[hv]->sl_pnext = &sl->sl_next;
- syncstatetab[hv] = sl;
- nat_insert(n, sl->sl_rev);
- RWLOCK_EXIT(&ipf_nat);
+ WRITE_ENTER(&softc->ipf_nat);
+ sl->sl_pnext = softs->syncnattab + hv;
+ sl->sl_next = softs->syncnattab[hv];
+ if (softs->syncnattab[hv] != NULL)
+ softs->syncnattab[hv]->sl_pnext = &sl->sl_next;
+ softs->syncnattab[hv] = sl;
+ (void) ipf_nat_insert(softc, softc->ipf_nat_soft, n);
+ RWLOCK_EXIT(&softc->ipf_nat);
break;
case SMC_UPDATE :
bcopy(data, &su, sizeof(su));
- READ_ENTER(&ipf_syncstate);
- for (sl = syncstatetab[hv]; (sl != NULL); sl = sl->sl_next)
+ for (sl = softs->syncnattab[hv]; (sl != NULL);
+ sl = sl->sl_next)
if (sl->sl_hdr.sm_num == sp->sm_num)
break;
if (sl == NULL) {
+ IPFERROR(110019);
err = ENOENT;
break;
}
- READ_ENTER(&ipf_nat);
+ READ_ENTER(&softc->ipf_nat);
nat = sl->sl_ipn;
+ nat->nat_rev = sl->sl_rev;
MUTEX_ENTER(&nat->nat_lock);
- fr_setnatqueue(nat, sl->sl_rev);
+ ipf_nat_setqueue(softc, softc->ipf_nat_soft, nat);
MUTEX_EXIT(&nat->nat_lock);
- RWLOCK_EXIT(&ipf_nat);
+ RWLOCK_EXIT(&softc->ipf_nat);
break;
default :
+ IPFERROR(110020);
err = EINVAL;
break;
}
- RWLOCK_EXIT(&ipf_syncstate);
+ RWLOCK_EXIT(&softs->ipf_syncnat);
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: ipfsync_new */
+/* Function: ipf_sync_new */
/* Returns: synclist_t* - NULL == failure, else pointer to new synclist */
/* data structure. */
/* Parameters: tab(I) - type of synclist_t to create */
@@ -794,43 +1031,36 @@ void *data;
/* Creates a new sync table entry and notifies any sleepers that it's there */
/* waiting to be processed. */
/* ------------------------------------------------------------------------ */
-synclist_t *ipfsync_new(tab, fin, ptr)
-int tab;
-fr_info_t *fin;
-void *ptr;
+synclist_t *
+ipf_sync_new(softc, tab, fin, ptr)
+ ipf_main_softc_t *softc;
+ int tab;
+ fr_info_t *fin;
+ void *ptr;
{
+ ipf_sync_softc_t *softs = softc->ipf_sync_soft;
synclist_t *sl, *ss;
synclogent_t *sle;
u_int hv, sz;
- if (sl_idx == SYNCLOG_SZ)
+ if (softs->sl_idx == softs->ipf_sync_log_sz)
return NULL;
KMALLOC(sl, synclist_t *);
if (sl == NULL)
return NULL;
- MUTEX_ENTER(&ipf_syncadd);
+ MUTEX_ENTER(&softs->ipf_syncadd);
/*
* Get a unique number for this synclist_t. The number is only meant
* to be unique for the lifetime of the structure and may be reused
* later.
*/
- ipf_syncnum++;
- if (ipf_syncnum == 0) {
- ipf_syncnum = 1;
- ipf_syncwrap = 1;
+ softs->ipf_sync_num++;
+ if (softs->ipf_sync_num == 0) {
+ softs->ipf_sync_num = 1;
+ softs->ipf_sync_wrap++;
}
- hv = ipf_syncnum & (SYNC_STATETABSZ - 1);
- while (ipf_syncwrap != 0) {
- for (ss = syncstatetab[hv]; ss; ss = ss->sl_next)
- if (ss->sl_hdr.sm_num == ipf_syncnum)
- break;
- if (ss == NULL)
- break;
- ipf_syncnum++;
- hv = ipf_syncnum & (SYNC_STATETABSZ - 1);
- }
/*
* Use the synch number of the object as the hash key. Should end up
* with relatively even distribution over time.
@@ -839,11 +1069,48 @@ void *ptr;
* nth connection they make, where n is a value in the interval
* [0, SYNC_STATETABSZ-1].
*/
- sl->sl_pnext = syncstatetab + hv;
- sl->sl_next = syncstatetab[hv];
- syncstatetab[hv] = sl;
- sl->sl_num = ipf_syncnum;
- MUTEX_EXIT(&ipf_syncadd);
+ switch (tab)
+ {
+ case SMC_STATE :
+ hv = softs->ipf_sync_num & (softs->ipf_sync_state_tab_sz - 1);
+ while (softs->ipf_sync_wrap != 0) {
+ for (ss = softs->syncstatetab[hv]; ss; ss = ss->sl_next)
+ if (ss->sl_hdr.sm_num == softs->ipf_sync_num)
+ break;
+ if (ss == NULL)
+ break;
+ softs->ipf_sync_num++;
+ hv = softs->ipf_sync_num &
+ (softs->ipf_sync_state_tab_sz - 1);
+ }
+ sl->sl_pnext = softs->syncstatetab + hv;
+ sl->sl_next = softs->syncstatetab[hv];
+ softs->syncstatetab[hv] = sl;
+ break;
+
+ case SMC_NAT :
+ hv = softs->ipf_sync_num & (softs->ipf_sync_nat_tab_sz - 1);
+ while (softs->ipf_sync_wrap != 0) {
+ for (ss = softs->syncnattab[hv]; ss; ss = ss->sl_next)
+ if (ss->sl_hdr.sm_num == softs->ipf_sync_num)
+ break;
+ if (ss == NULL)
+ break;
+ softs->ipf_sync_num++;
+ hv = softs->ipf_sync_num &
+ (softs->ipf_sync_nat_tab_sz - 1);
+ }
+ sl->sl_pnext = softs->syncnattab + hv;
+ sl->sl_next = softs->syncnattab[hv];
+ softs->syncnattab[hv] = sl;
+ break;
+
+ default :
+ break;
+ }
+
+ sl->sl_num = softs->ipf_sync_num;
+ MUTEX_EXIT(&softs->ipf_syncadd);
sl->sl_magic = htonl(SYNHDRMAGIC);
sl->sl_v = fin->fin_v;
@@ -868,8 +1135,8 @@ void *ptr;
* Create the log entry to be read by a user daemon. When it has been
* finished and put on the queue, send a signal to wakeup any waiters.
*/
- MUTEX_ENTER(&ipf_syncadd);
- sle = synclog + sl_idx++;
+ MUTEX_ENTER(&softs->ipf_syncadd);
+ sle = softs->synclog + softs->sl_idx++;
bcopy((char *)&sl->sl_hdr, (char *)&sle->sle_hdr,
sizeof(sle->sle_hdr));
sle->sle_hdr.sm_num = htonl(sle->sle_hdr.sm_num);
@@ -877,31 +1144,20 @@ void *ptr;
if (ptr != NULL) {
bcopy((char *)ptr, (char *)&sle->sle_un, sz);
if (tab == SMC_STATE) {
- ipfsync_storder(1, &sle->sle_un.sleu_ips);
+ ipf_sync_storder(1, &sle->sle_un.sleu_ips);
} else if (tab == SMC_NAT) {
- ipfsync_natorder(1, &sle->sle_un.sleu_ipn);
+ ipf_sync_natorder(1, &sle->sle_un.sleu_ipn);
}
}
- MUTEX_EXIT(&ipf_syncadd);
+ MUTEX_EXIT(&softs->ipf_syncadd);
- MUTEX_ENTER(&ipsl_mutex);
-# if SOLARIS
-# ifdef _KERNEL
- cv_signal(&ipslwait);
-# endif
- MUTEX_EXIT(&ipsl_mutex);
-# else
- MUTEX_EXIT(&ipsl_mutex);
-# ifdef _KERNEL
- wakeup(&sl_tail);
-# endif
-# endif
+ ipf_sync_wakeup(softc);
return sl;
}
/* ------------------------------------------------------------------------ */
-/* Function: ipfsync_update */
+/* Function: ipf_sync_update */
/* Returns: Nil */
/* Parameters: tab(I) - type of synclist_t to create */
/* fin(I) - pointer to packet information */
@@ -910,24 +1166,36 @@ void *ptr;
/* For outbound packets, only, create an sync update record for the user */
/* process to read. */
/* ------------------------------------------------------------------------ */
-void ipfsync_update(tab, fin, sl)
-int tab;
-fr_info_t *fin;
-synclist_t *sl;
+void
+ipf_sync_update(softc, tab, fin, sl)
+ ipf_main_softc_t *softc;
+ int tab;
+ fr_info_t *fin;
+ synclist_t *sl;
{
+ ipf_sync_softc_t *softs = softc->ipf_sync_soft;
synctcp_update_t *st;
syncupdent_t *slu;
ipstate_t *ips;
nat_t *nat;
+ ipfrwlock_t *lock;
if (fin->fin_out == 0 || sl == NULL)
return;
- WRITE_ENTER(&ipf_syncstate);
- MUTEX_ENTER(&ipf_syncadd);
+ if (tab == SMC_STATE) {
+ lock = &softs->ipf_syncstate;
+ } else {
+ lock = &softs->ipf_syncnat;
+ }
+
+ READ_ENTER(lock);
if (sl->sl_idx == -1) {
- slu = syncupd + su_idx;
- sl->sl_idx = su_idx++;
+ MUTEX_ENTER(&softs->ipf_syncadd);
+ slu = softs->syncupd + softs->su_idx;
+ sl->sl_idx = softs->su_idx++;
+ MUTEX_EXIT(&softs->ipf_syncadd);
+
bcopy((char *)&sl->sl_hdr, (char *)&slu->sup_hdr,
sizeof(slu->sup_hdr));
slu->sup_hdr.sm_magic = htonl(SYNHDRMAGIC);
@@ -944,9 +1212,7 @@ synclist_t *sl;
}
# endif
} else
- slu = syncupd + sl->sl_idx;
- MUTEX_EXIT(&ipf_syncadd);
- MUTEX_DOWNGRADE(&ipf_syncstate);
+ slu = softs->syncupd + sl->sl_idx;
/*
* Only TCP has complex timeouts, others just use default timeouts.
@@ -970,25 +1236,61 @@ synclist_t *sl;
st->stu_age = htonl(nat->nat_age);
}
}
- RWLOCK_EXIT(&ipf_syncstate);
+ RWLOCK_EXIT(lock);
- MUTEX_ENTER(&ipsl_mutex);
-# if SOLARIS
-# ifdef _KERNEL
- cv_signal(&ipslwait);
-# endif
- MUTEX_EXIT(&ipsl_mutex);
-# else
- MUTEX_EXIT(&ipsl_mutex);
-# ifdef _KERNEL
- wakeup(&sl_tail);
-# endif
-# endif
+ ipf_sync_wakeup(softc);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_sync_ioctl */
+/* Function: ipf_sync_flush_table */
+/* Returns: int - number of entries freed by flushing table */
+/* Parameters: tabsize(I) - size of the array pointed to by table */
+/* table(I) - pointer to sync table to empty */
+/* */
+/* Walk through a table of sync entries and free each one. It is assumed */
+/* that some lock is held so that nobody else tries to access the table */
+/* during this cleanup. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_sync_flush_table(softs, tabsize, table)
+ ipf_sync_softc_t *softs;
+ int tabsize;
+ synclist_t **table;
+{
+ synclist_t *sl;
+ int i, items;
+
+ items = 0;
+
+ for (i = 0; i < tabsize; i++) {
+ while ((sl = table[i]) != NULL) {
+ switch (sl->sl_table) {
+ case SMC_STATE :
+ if (sl->sl_ips != NULL)
+ sl->sl_ips->is_sync = NULL;
+ break;
+ case SMC_NAT :
+ if (sl->sl_ipn != NULL)
+ sl->sl_ipn->nat_sync = NULL;
+ break;
+ }
+ if (sl->sl_next != NULL)
+ sl->sl_next->sl_pnext = sl->sl_pnext;
+ table[i] = sl->sl_next;
+ if (sl->sl_idx != -1)
+ softs->syncupd[sl->sl_idx].sup_hdr.sm_sl = NULL;
+ KFREE(sl);
+ items++;
+ }
+ }
+
+ return items;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_sync_ioctl */
/* Returns: int - 0 == success, != 0 == failure */
/* Parameters: data(I) - pointer to ioctl data */
/* cmd(I) - ioctl command integer */
@@ -997,24 +1299,199 @@ synclist_t *sl;
/* This function currently does not handle any ioctls and so just returns */
/* EINVAL on all occasions. */
/* ------------------------------------------------------------------------ */
-int fr_sync_ioctl(data, cmd, mode, uid, ctx)
-caddr_t data;
-ioctlcmd_t cmd;
-int mode, uid;
-void *ctx;
+int
+ipf_sync_ioctl(softc, data, cmd, mode, uid, ctx)
+ ipf_main_softc_t *softc;
+ caddr_t data;
+ ioctlcmd_t cmd;
+ int mode, uid;
+ void *ctx;
{
- return EINVAL;
+ ipf_sync_softc_t *softs = softc->ipf_sync_soft;
+ int error, i;
+ SPL_INT(s);
+
+ switch (cmd)
+ {
+ case SIOCIPFFL:
+ error = BCOPYIN(data, &i, sizeof(i));
+ if (error != 0) {
+ IPFERROR(110023);
+ error = EFAULT;
+ break;
+ }
+
+ switch (i)
+ {
+ case SMC_RLOG :
+ SPL_NET(s);
+ MUTEX_ENTER(&softs->ipsl_mutex);
+ i = (softs->sl_tail - softs->sl_idx) +
+ (softs->su_tail - softs->su_idx);
+ softs->sl_idx = 0;
+ softs->su_idx = 0;
+ softs->sl_tail = 0;
+ softs->su_tail = 0;
+ MUTEX_EXIT(&softs->ipsl_mutex);
+ SPL_X(s);
+ break;
+
+ case SMC_NAT :
+ SPL_NET(s);
+ WRITE_ENTER(&softs->ipf_syncnat);
+ i = ipf_sync_flush_table(softs, SYNC_NATTABSZ,
+ softs->syncnattab);
+ RWLOCK_EXIT(&softs->ipf_syncnat);
+ SPL_X(s);
+ break;
+
+ case SMC_STATE :
+ SPL_NET(s);
+ WRITE_ENTER(&softs->ipf_syncstate);
+ i = ipf_sync_flush_table(softs, SYNC_STATETABSZ,
+ softs->syncstatetab);
+ RWLOCK_EXIT(&softs->ipf_syncstate);
+ SPL_X(s);
+ break;
+ }
+
+ error = BCOPYOUT(&i, data, sizeof(i));
+ if (error != 0) {
+ IPFERROR(110022);
+ error = EFAULT;
+ }
+ break;
+
+ default :
+ IPFERROR(110021);
+ error = EINVAL;
+ break;
+ }
+
+ return error;
}
-int ipfsync_canread()
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_sync_canread */
+/* Returns: int - 0 == success, != 0 == failure */
+/* Parameters: Nil */
+/* */
+/* This function provides input to the poll handler about whether or not */
+/* there is data waiting to be read from the /dev/ipsync device. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_sync_canread(arg)
+ void *arg;
{
- return !((sl_tail == sl_idx) && (su_tail == su_idx));
+ ipf_sync_softc_t *softs = arg;
+ return !((softs->sl_tail == softs->sl_idx) &&
+ (softs->su_tail == softs->su_idx));
}
-int ipfsync_canwrite()
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_sync_canwrite */
+/* Returns: int - 1 == can always write */
+/* Parameters: Nil */
+/* */
+/* This function lets the poll handler know that it is always ready willing */
+/* to accept write events. */
+/* XXX Maybe this should return false if the sync table is full? */
+/* ------------------------------------------------------------------------ */
+int
+ipf_sync_canwrite(arg)
+ void *arg;
{
return 1;
}
-#endif /* IPFILTER_SYNC */
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_sync_wakeup */
+/* Parameters: Nil */
+/* Returns: Nil */
+/* */
+/* This function implements the heuristics that decide how often to */
+/* generate a poll wakeup for programs that are waiting for information */
+/* about when they can do a read on /dev/ipsync. */
+/* */
+/* There are three different considerations here: */
+/* - do not keep a program waiting too long: ipf_sync_wake_interval is the */
+/* maximum number of ipf ticks to let pass by; */
+/* - do not let the queue of ouststanding things to generate notifies for */
+/* get too full (ipf_sync_queue_high_wm is the high water mark); */
+/* - do not let too many events get collapsed in before deciding that the */
+/* other host(s) need an update (ipf_sync_event_high_wm is the high water */
+/* mark for this counter.) */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_sync_wakeup(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_sync_softc_t *softs = softc->ipf_sync_soft;
+
+ softs->ipf_sync_events++;
+ if ((softc->ipf_ticks >
+ softs->ipf_sync_lastwakeup + softs->ipf_sync_wake_interval) ||
+ (softs->ipf_sync_events > softs->ipf_sync_event_high_wm) ||
+ ((softs->sl_tail - softs->sl_idx) >
+ softs->ipf_sync_queue_high_wm) ||
+ ((softs->su_tail - softs->su_idx) >
+ softs->ipf_sync_queue_high_wm)) {
+
+ ipf_sync_poll_wakeup(softc);
+ }
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_sync_poll_wakeup */
+/* Parameters: Nil */
+/* Returns: Nil */
+/* */
+/* Deliver a poll wakeup and reset counters for two of the three heuristics */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_sync_poll_wakeup(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_sync_softc_t *softs = softc->ipf_sync_soft;
+
+ softs->ipf_sync_events = 0;
+ softs->ipf_sync_lastwakeup = softc->ipf_ticks;
+
+# ifdef _KERNEL
+# if SOLARIS
+ MUTEX_ENTER(&softs->ipsl_mutex);
+ cv_signal(&softs->ipslwait);
+ MUTEX_EXIT(&softs->ipsl_mutex);
+ pollwakeup(&softc->ipf_poll_head[IPL_LOGSYNC], POLLIN|POLLRDNORM);
+# else
+ WAKEUP(&softs->sl_tail, 0);
+ POLLWAKEUP(IPL_LOGSYNC);
+# endif
+# endif
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_sync_expire */
+/* Parameters: Nil */
+/* Returns: Nil */
+/* */
+/* This is the function called even ipf_tick. It implements one of the */
+/* three heuristics above *IF* there are events waiting. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_sync_expire(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_sync_softc_t *softs = softc->ipf_sync_soft;
+
+ if ((softs->ipf_sync_events > 0) &&
+ (softc->ipf_ticks >
+ softs->ipf_sync_lastwakeup + softs->ipf_sync_wake_interval)) {
+ ipf_sync_poll_wakeup(softc);
+ }
+}
diff --git a/sys/contrib/ipfilter/netinet/ip_sync.h b/sys/contrib/ipfilter/netinet/ip_sync.h
index 8104db3..d9d6d41 100644
--- a/sys/contrib/ipfilter/netinet/ip_sync.h
+++ b/sys/contrib/ipfilter/netinet/ip_sync.h
@@ -1,10 +1,10 @@
/*
- * Copyright (C) 1993-2001 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
* @(#)ip_fil.h 1.35 6/5/96
- * $Id: ip_sync.h,v 2.11.2.4 2006/07/14 06:12:20 darrenr Exp $
+ * $Id$
*/
#ifndef __IP_SYNC_H__
@@ -36,6 +36,7 @@ typedef struct synchdr {
/*
* Tables
*/
+#define SMC_RLOG -2 /* Only used with SIOCIPFFL */
#define SMC_NAT 0
#define SMC_STATE 1
#define SMC_MAXTBL 1
@@ -99,19 +100,22 @@ typedef struct syncupdent { /* 28 or 32 bytes */
struct synctcp_update sup_tcp;
} syncupdent_t;
-extern synclogent_t synclog[SYNCLOG_SZ];
-
-
-extern int fr_sync_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *));
-extern synclist_t *ipfsync_new __P((int, fr_info_t *, void *));
-extern void ipfsync_del __P((synclist_t *));
-extern void ipfsync_update __P((int, fr_info_t *, synclist_t *));
-extern int ipfsync_init __P((void));
-extern int ipfsync_nat __P((synchdr_t *sp, void *data));
-extern int ipfsync_state __P((synchdr_t *sp, void *data));
-extern int ipfsync_read __P((struct uio *uio));
-extern int ipfsync_write __P((struct uio *uio));
-extern int ipfsync_canread __P((void));
-extern int ipfsync_canwrite __P((void));
-
-#endif /* IP_SYNC */
+extern void *ipf_sync_create __P((ipf_main_softc_t *));
+extern int ipf_sync_soft_init __P((ipf_main_softc_t *, void *));
+extern int ipf_sync_soft_fini __P((ipf_main_softc_t *, void *));
+extern int ipf_sync_canread __P((void *));
+extern int ipf_sync_canwrite __P((void *));
+extern void ipf_sync_del_nat __P((void *, synclist_t *));
+extern void ipf_sync_del_state __P((void *, synclist_t *));
+extern int ipf_sync_init __P((void));
+extern int ipf_sync_ioctl __P((ipf_main_softc_t *, caddr_t, ioctlcmd_t, int, int, void *));
+extern synclist_t *ipf_sync_new __P((ipf_main_softc_t *, int, fr_info_t *, void *));
+extern int ipf_sync_read __P((ipf_main_softc_t *, struct uio *uio));
+extern int ipf_sync_write __P((ipf_main_softc_t *, struct uio *uio));
+extern int ipf_sync_main_unload __P((void));
+extern void ipf_sync_update __P((ipf_main_softc_t *, int, fr_info_t *, synclist_t *));
+extern void ipf_sync_expire __P((ipf_main_softc_t *));
+extern void ipf_sync_soft_destroy __P((ipf_main_softc_t *, void *));
+extern void *ipf_sync_soft_create __P((ipf_main_softc_t *));
+
+#endif /* __IP_SYNC_H__ */
diff --git a/sys/contrib/ipfilter/netinet/ip_tftp_pxy.c b/sys/contrib/ipfilter/netinet/ip_tftp_pxy.c
new file mode 100644
index 0000000..409b982
--- /dev/null
+++ b/sys/contrib/ipfilter/netinet/ip_tftp_pxy.c
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id: ip_tftp_pxy.c,v 1.1.2.9 2012/07/22 08:04:23 darren_r Exp $
+ */
+
+#define IPF_TFTP_PROXY
+
+typedef struct ipf_tftp_softc_s {
+ int ipf_p_tftp_readonly;
+ ipftuneable_t *ipf_p_tftp_tune;
+} ipf_tftp_softc_t;
+
+int ipf_p_tftp_backchannel __P((fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_tftp_client __P((ipf_tftp_softc_t *, fr_info_t *, ap_session_t *,
+ nat_t *));
+int ipf_p_tftp_in __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_tftp_main_load __P((void));
+void ipf_p_tftp_main_unload __P((void));
+int ipf_p_tftp_new __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+void ipf_p_tftp_del __P((ipf_main_softc_t *, ap_session_t *));
+int ipf_p_tftp_out __P((void *, fr_info_t *, ap_session_t *, nat_t *));
+int ipf_p_tftp_server __P((ipf_tftp_softc_t *, fr_info_t *, ap_session_t *,
+ nat_t *));
+void *ipf_p_tftp_soft_create __P((ipf_main_softc_t *));
+void ipf_p_tftp_soft_destroy __P((ipf_main_softc_t *, void *));
+
+static frentry_t tftpfr;
+static int tftp_proxy_init = 0;
+
+typedef enum tftp_cmd_e {
+ TFTP_CMD_READ = 1,
+ TFTP_CMD_WRITE = 2,
+ TFTP_CMD_DATA = 3,
+ TFTP_CMD_ACK = 4,
+ TFTP_CMD_ERROR = 5
+} tftp_cmd_t;
+
+typedef struct tftpinfo {
+ tftp_cmd_t ti_lastcmd;
+ int ti_nextblk;
+ int ti_lastblk;
+ int ti_lasterror;
+ char ti_filename[80];
+ ipnat_t *ti_rule;
+} tftpinfo_t;
+
+static ipftuneable_t ipf_tftp_tuneables[] = {
+ { { (void *)offsetof(ipf_tftp_softc_t, ipf_p_tftp_readonly) },
+ "tftp_read_only", 0, 1,
+ stsizeof(ipf_tftp_softc_t, ipf_p_tftp_readonly),
+ 0, NULL, NULL },
+ { { NULL }, NULL, 0, 0, 0, 0, NULL, NULL }
+};
+
+
+/*
+ * TFTP application proxy initialization.
+ */
+void
+ipf_p_tftp_main_load()
+{
+
+ bzero((char *)&tftpfr, sizeof(tftpfr));
+ tftpfr.fr_ref = 1;
+ tftpfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
+ MUTEX_INIT(&tftpfr.fr_lock, "TFTP proxy rule lock");
+ tftp_proxy_init = 1;
+}
+
+
+void
+ipf_p_tftp_main_unload()
+{
+
+ if (tftp_proxy_init == 1) {
+ MUTEX_DESTROY(&tftpfr.fr_lock);
+ tftp_proxy_init = 0;
+ }
+}
+
+
+void *
+ipf_p_tftp_soft_create(softc)
+ ipf_main_softc_t *softc;
+{
+ ipf_tftp_softc_t *softt;
+
+ KMALLOC(softt, ipf_tftp_softc_t *);
+ if (softt == NULL)
+ return NULL;
+
+ bzero((char *)softt, sizeof(*softt));
+
+ softt->ipf_p_tftp_tune = ipf_tune_array_copy(softt,
+ sizeof(ipf_tftp_tuneables),
+ ipf_tftp_tuneables);
+ if (softt->ipf_p_tftp_tune == NULL) {
+ ipf_p_tftp_soft_destroy(softc, softt);
+ return NULL;
+ }
+ if (ipf_tune_array_link(softc, softt->ipf_p_tftp_tune) == -1) {
+ ipf_p_tftp_soft_destroy(softc, softt);
+ return NULL;
+ }
+
+ softt->ipf_p_tftp_readonly = 1;
+
+ return softt;
+}
+
+
+void
+ipf_p_tftp_soft_destroy(softc, arg)
+ ipf_main_softc_t *softc;
+ void *arg;
+{
+ ipf_tftp_softc_t *softt = arg;
+
+ if (softt->ipf_p_tftp_tune != NULL) {
+ ipf_tune_array_unlink(softc, softt->ipf_p_tftp_tune);
+ KFREES(softt->ipf_p_tftp_tune, sizeof(ipf_tftp_tuneables));
+ softt->ipf_p_tftp_tune = NULL;
+ }
+
+ KFREE(softt);
+}
+
+
+int
+ipf_p_tftp_out(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
+{
+ ipf_tftp_softc_t *softt = arg;
+
+ fin->fin_flx |= FI_NOWILD;
+ if (nat->nat_dir == NAT_OUTBOUND)
+ return ipf_p_tftp_client(softt, fin, aps, nat);
+ return ipf_p_tftp_server(softt, fin, aps, nat);
+}
+
+
+int
+ipf_p_tftp_in(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
+{
+ ipf_tftp_softc_t *softt = arg;
+
+ fin->fin_flx |= FI_NOWILD;
+ if (nat->nat_dir == NAT_INBOUND)
+ return ipf_p_tftp_client(softt, fin, aps, nat);
+ return ipf_p_tftp_server(softt, fin, aps, nat);
+}
+
+
+int
+ipf_p_tftp_new(arg, fin, aps, nat)
+ void *arg;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
+{
+ udphdr_t *udp;
+ tftpinfo_t *ti;
+ ipnat_t *ipn;
+ ipnat_t *np;
+ int size;
+
+ fin = fin; /* LINT */
+
+ np = nat->nat_ptr;
+ size = np->in_size;
+
+ KMALLOC(ti, tftpinfo_t *);
+ if (ti == NULL)
+ return -1;
+ KMALLOCS(ipn, ipnat_t *, size);
+ if (ipn == NULL) {
+ KFREE(ti);
+ return -1;
+ }
+
+ aps->aps_data = ti;
+ aps->aps_psiz = sizeof(*ti);
+ bzero((char *)ti, sizeof(*ti));
+ bzero((char *)ipn, size);
+ ti->ti_rule = ipn;
+
+ udp = (udphdr_t *)fin->fin_dp;
+ aps->aps_sport = udp->uh_sport;
+ aps->aps_dport = udp->uh_dport;
+
+ ipn->in_size = size;
+ ipn->in_apr = NULL;
+ ipn->in_use = 1;
+ ipn->in_hits = 1;
+ ipn->in_ippip = 1;
+ ipn->in_pr[0] = IPPROTO_UDP;
+ ipn->in_pr[1] = IPPROTO_UDP;
+ ipn->in_ifps[0] = nat->nat_ifps[0];
+ ipn->in_ifps[1] = nat->nat_ifps[1];
+ ipn->in_v[0] = nat->nat_ptr->in_v[1];
+ ipn->in_v[1] = nat->nat_ptr->in_v[0];
+ ipn->in_flags = IPN_UDP|IPN_FIXEDDPORT|IPN_PROXYRULE;
+
+ ipn->in_nsrcip6 = nat->nat_odst6;
+ ipn->in_osrcip6 = nat->nat_ndst6;
+
+ if ((np->in_redir & NAT_REDIRECT) != 0) {
+ ipn->in_redir = NAT_MAP;
+ if (ipn->in_v[0] == 4) {
+ ipn->in_snip = ntohl(nat->nat_odstaddr);
+ ipn->in_dnip = ntohl(nat->nat_nsrcaddr);
+ } else {
+#ifdef USE_INET6
+ ipn->in_snip6 = nat->nat_odst6;
+ ipn->in_dnip6 = nat->nat_nsrc6;
+#endif
+ }
+ ipn->in_ndstip6 = nat->nat_nsrc6;
+ ipn->in_odstip6 = nat->nat_osrc6;
+ } else {
+ ipn->in_redir = NAT_REDIRECT;
+ if (ipn->in_v[0] == 4) {
+ ipn->in_snip = ntohl(nat->nat_odstaddr);
+ ipn->in_dnip = ntohl(nat->nat_osrcaddr);
+ } else {
+#ifdef USE_INET6
+ ipn->in_snip6 = nat->nat_odst6;
+ ipn->in_dnip6 = nat->nat_osrc6;
+#endif
+ }
+ ipn->in_ndstip6 = nat->nat_osrc6;
+ ipn->in_odstip6 = nat->nat_nsrc6;
+ }
+ ipn->in_odport = htons(fin->fin_sport);
+ ipn->in_ndport = htons(fin->fin_sport);
+
+ IP6_SETONES(&ipn->in_osrcmsk6);
+ IP6_SETONES(&ipn->in_nsrcmsk6);
+ IP6_SETONES(&ipn->in_odstmsk6);
+ IP6_SETONES(&ipn->in_ndstmsk6);
+ MUTEX_INIT(&ipn->in_lock, "tftp proxy NAT rule");
+
+ ipn->in_namelen = np->in_namelen;
+ bcopy(np->in_names, ipn->in_ifnames, ipn->in_namelen);
+ ipn->in_ifnames[0] = np->in_ifnames[0];
+ ipn->in_ifnames[1] = np->in_ifnames[1];
+
+ ti->ti_lastcmd = 0;
+
+ return 0;
+}
+
+
+void
+ipf_p_tftp_del(softc, aps)
+ ipf_main_softc_t *softc;
+ ap_session_t *aps;
+{
+ tftpinfo_t *tftp;
+
+ tftp = aps->aps_data;
+ if (tftp != NULL) {
+ tftp->ti_rule->in_flags |= IPN_DELETE;
+ ipf_nat_rule_deref(softc, &tftp->ti_rule);
+ }
+}
+
+
+/*
+ * Setup for a new TFTP proxy.
+ */
+int
+ipf_p_tftp_backchannel(fin, aps, nat)
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+#ifdef USE_MUTEXES
+ ipf_nat_softc_t *softn = softc->ipf_nat_soft;
+#endif
+#ifdef USE_INET6
+ i6addr_t swip6, sw2ip6;
+ ip6_t *ip6;
+#endif
+ struct in_addr swip, sw2ip;
+ tftpinfo_t *ti;
+ udphdr_t udp;
+ fr_info_t fi;
+ u_short slen;
+ nat_t *nat2;
+ int nflags;
+ ip_t *ip;
+ int dir;
+
+ ti = aps->aps_data;
+ /*
+ * Add skeleton NAT entry for connection which will come back the
+ * other way.
+ */
+ bcopy((char *)fin, (char *)&fi, sizeof(fi));
+ fi.fin_flx |= FI_IGNORE;
+ fi.fin_data[1] = 0;
+
+ bzero((char *)&udp, sizeof(udp));
+ udp.uh_sport = 0; /* XXX - don't specify remote port */
+ udp.uh_dport = ti->ti_rule->in_ndport;
+ udp.uh_ulen = htons(sizeof(udp));
+ udp.uh_sum = 0;
+
+ fi.fin_fr = &tftpfr;
+ fi.fin_dp = (char *)&udp;
+ fi.fin_sport = 0;
+ fi.fin_dport = ntohs(ti->ti_rule->in_ndport);
+ fi.fin_dlen = sizeof(udp);
+ fi.fin_plen = fi.fin_hlen + sizeof(udp);
+ fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
+ nflags = NAT_SLAVE|IPN_UDP|SI_W_SPORT;
+#ifdef USE_INET6
+ ip6 = (ip6_t *)fin->fin_ip;
+#endif
+ ip = fin->fin_ip;
+ sw2ip.s_addr = 0;
+ swip.s_addr = 0;
+
+ fi.fin_src6 = nat->nat_ndst6;
+ fi.fin_dst6 = nat->nat_nsrc6;
+ if (nat->nat_v[0] == 4) {
+ slen = ip->ip_len;
+ ip->ip_len = htons(fin->fin_hlen + sizeof(udp));
+ swip = ip->ip_src;
+ sw2ip = ip->ip_dst;
+ ip->ip_src = nat->nat_ndstip;
+ ip->ip_dst = nat->nat_nsrcip;
+ } else {
+#ifdef USE_INET6
+ slen = ip6->ip6_plen;
+ ip6->ip6_plen = htons(sizeof(udp));
+ swip6.in6 = ip6->ip6_src;
+ sw2ip6.in6 = ip6->ip6_dst;
+ ip6->ip6_src = nat->nat_ndst6.in6;
+ ip6->ip6_dst = nat->nat_nsrc6.in6;
+#endif
+ }
+
+ if (nat->nat_dir == NAT_INBOUND) {
+ dir = NAT_OUTBOUND;
+ fi.fin_out = 1;
+ } else {
+ dir = NAT_INBOUND;
+ fi.fin_out = 0;
+ }
+ nflags |= NAT_NOTRULEPORT;
+
+ MUTEX_ENTER(&softn->ipf_nat_new);
+#ifdef USE_INET6
+ if (nat->nat_v[0] == 6)
+ nat2 = ipf_nat6_add(&fi, ti->ti_rule, NULL, nflags, dir);
+ else
+#endif
+ nat2 = ipf_nat_add(&fi, ti->ti_rule, NULL, nflags, dir);
+ MUTEX_EXIT(&softn->ipf_nat_new);
+ if (nat2 != NULL) {
+ (void) ipf_nat_proto(&fi, nat2, IPN_UDP);
+ ipf_nat_update(&fi, nat2);
+ fi.fin_ifp = NULL;
+ if (ti->ti_rule->in_redir == NAT_MAP) {
+ fi.fin_src6 = nat->nat_ndst6;
+ fi.fin_dst6 = nat->nat_nsrc6;
+ if (nat->nat_v[0] == 4) {
+ ip->ip_src = nat->nat_ndstip;
+ ip->ip_dst = nat->nat_nsrcip;
+ } else {
+#ifdef USE_INET6
+ ip6->ip6_src = nat->nat_ndst6.in6;
+ ip6->ip6_dst = nat->nat_nsrc6.in6;
+#endif
+ }
+ } else {
+ fi.fin_src6 = nat->nat_odst6;
+ fi.fin_dst6 = nat->nat_osrc6;
+ if (fin->fin_v == 4) {
+ ip->ip_src = nat->nat_odstip;
+ ip->ip_dst = nat->nat_osrcip;
+ } else {
+#ifdef USE_INET6
+ ip6->ip6_src = nat->nat_odst6.in6;
+ ip6->ip6_dst = nat->nat_osrc6.in6;
+#endif
+ }
+ }
+ if (ipf_state_add(softc, &fi, NULL, SI_W_SPORT) != 0) {
+ ipf_nat_setpending(softc, nat2);
+ }
+ }
+ if (nat->nat_v[0] == 4) {
+ ip->ip_len = slen;
+ ip->ip_src = swip;
+ ip->ip_dst = sw2ip;
+ } else {
+#ifdef USE_INET6
+ ip6->ip6_plen = slen;
+ ip6->ip6_src = swip6.in6;
+ ip6->ip6_dst = sw2ip6.in6;
+#endif
+ }
+ return 0;
+}
+
+
+int
+ipf_p_tftp_client(softt, fin, aps, nat)
+ ipf_tftp_softc_t *softt;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
+{
+ u_char *msg, *s, *t;
+ tftpinfo_t *ti;
+ u_short opcode;
+ udphdr_t *udp;
+ int len;
+
+ if (fin->fin_dlen < 4)
+ return 0;
+
+ ti = aps->aps_data;
+ msg = fin->fin_dp;
+ msg += sizeof(udphdr_t);
+ opcode = (msg[0] << 8) | msg[1];
+ DT3(tftp_cmd, fr_info_t *, fin, int, opcode, nat_t *, nat);
+
+ switch (opcode)
+ {
+ case TFTP_CMD_WRITE :
+ if (softt->ipf_p_tftp_readonly != 0)
+ break;
+ /* FALLTHROUGH */
+ case TFTP_CMD_READ :
+ len = fin->fin_dlen - sizeof(*udp) - 2;
+ if (len > sizeof(ti->ti_filename) - 1)
+ len = sizeof(ti->ti_filename) - 1;
+ s = msg + 2;
+ for (t = (u_char *)ti->ti_filename; (len > 0); len--, s++) {
+ *t++ = *s;
+ if (*s == '\0')
+ break;
+ }
+ ipf_p_tftp_backchannel(fin, aps, nat);
+ break;
+ default :
+ return -1;
+ }
+
+ ti = aps->aps_data;
+ ti->ti_lastcmd = opcode;
+ return 0;
+}
+
+
+int
+ipf_p_tftp_server(softt, fin, aps, nat)
+ ipf_tftp_softc_t *softt;
+ fr_info_t *fin;
+ ap_session_t *aps;
+ nat_t *nat;
+{
+ tftpinfo_t *ti;
+ u_short opcode;
+ u_short arg;
+ u_char *msg;
+
+ if (fin->fin_dlen < 4)
+ return 0;
+
+ ti = aps->aps_data;
+ msg = fin->fin_dp;
+ msg += sizeof(udphdr_t);
+ arg = (msg[2] << 8) | msg[3];
+ opcode = (msg[0] << 8) | msg[1];
+
+ switch (opcode)
+ {
+ case TFTP_CMD_ACK :
+ ti->ti_lastblk = arg;
+ break;
+
+ case TFTP_CMD_ERROR :
+ ti->ti_lasterror = arg;
+ break;
+
+ default :
+ return -1;
+ }
+
+ ti->ti_lastcmd = opcode;
+ return 0;
+}
diff --git a/sys/contrib/ipfilter/netinet/ipf_rb.h b/sys/contrib/ipfilter/netinet/ipf_rb.h
new file mode 100644
index 0000000..3d7a59d
--- /dev/null
+++ b/sys/contrib/ipfilter/netinet/ipf_rb.h
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ */
+typedef enum rbcolour_e {
+ C_BLACK = 0,
+ C_RED = 1
+} rbcolour_t;
+
+#define RBI_LINK(_n, _t) \
+ struct _n##_rb_link { \
+ struct _t *left; \
+ struct _t *right; \
+ struct _t *parent; \
+ rbcolour_t colour; \
+ }
+
+#define RBI_HEAD(_n, _t) \
+struct _n##_rb_head { \
+ struct _t top; \
+ int count; \
+ int (* compare)(struct _t *, struct _t *); \
+}
+
+#define RBI_CODE(_n, _t, _f, _cmp) \
+ \
+typedef void (*_n##_rb_walker_t)(_t *, void *); \
+ \
+_t * _n##_rb_delete(struct _n##_rb_head *, _t *); \
+void _n##_rb_init(struct _n##_rb_head *); \
+void _n##_rb_insert(struct _n##_rb_head *, _t *); \
+_t * _n##_rb_search(struct _n##_rb_head *, void *); \
+void _n##_rb_walktree(struct _n##_rb_head *, _n##_rb_walker_t, void *);\
+ \
+static void \
+rotate_left(struct _n##_rb_head *head, _t *node) \
+{ \
+ _t *parent, *tmp1, *tmp2; \
+ \
+ parent = node->_f.parent; \
+ tmp1 = node->_f.right; \
+ tmp2 = tmp1->_f.left; \
+ node->_f.right = tmp2; \
+ if (tmp2 != & _n##_rb_zero) \
+ tmp2->_f.parent = node; \
+ if (parent == & _n##_rb_zero) \
+ head->top._f.right = tmp1; \
+ else if (parent->_f.right == node) \
+ parent->_f.right = tmp1; \
+ else \
+ parent->_f.left = tmp1; \
+ tmp1->_f.left = node; \
+ tmp1->_f.parent = parent; \
+ node->_f.parent = tmp1; \
+} \
+ \
+static void \
+rotate_right(struct _n##_rb_head *head, _t *node) \
+{ \
+ _t *parent, *tmp1, *tmp2; \
+ \
+ parent = node->_f.parent; \
+ tmp1 = node->_f.left; \
+ tmp2 = tmp1->_f.right; \
+ node->_f.left = tmp2; \
+ if (tmp2 != &_n##_rb_zero) \
+ tmp2->_f.parent = node; \
+ if (parent == &_n##_rb_zero) \
+ head->top._f.right = tmp1; \
+ else if (parent->_f.right == node) \
+ parent->_f.right = tmp1; \
+ else \
+ parent->_f.left = tmp1; \
+ tmp1->_f.right = node; \
+ tmp1->_f.parent = parent; \
+ node->_f.parent = tmp1; \
+} \
+ \
+void \
+_n##_rb_insert(struct _n##_rb_head *head, _t *node) \
+{ \
+ _t *n, *parent, **p, *tmp1, *gparent; \
+ \
+ parent = &head->top; \
+ node->_f.left = &_n##_rb_zero; \
+ node->_f.right = &_n##_rb_zero; \
+ p = &head->top._f.right; \
+ while ((n = *p) != &_n##_rb_zero) { \
+ if (_cmp(node, n) < 0) \
+ p = &n->_f.left; \
+ else \
+ p = &n->_f.right; \
+ parent = n; \
+ } \
+ *p = node; \
+ node->_f.colour = C_RED; \
+ node->_f.parent = parent; \
+ \
+ while ((node != &_n##_rb_zero) && (parent->_f.colour == C_RED)){\
+ gparent = parent->_f.parent; \
+ if (parent == gparent->_f.left) { \
+ tmp1 = gparent->_f.right; \
+ if (tmp1->_f.colour == C_RED) { \
+ parent->_f.colour = C_BLACK; \
+ tmp1->_f.colour = C_BLACK; \
+ gparent->_f.colour = C_RED; \
+ node = gparent; \
+ } else { \
+ if (node == parent->_f.right) { \
+ node = parent; \
+ rotate_left(head, node); \
+ parent = node->_f.parent; \
+ } \
+ parent->_f.colour = C_BLACK; \
+ gparent->_f.colour = C_RED; \
+ rotate_right(head, gparent); \
+ } \
+ } else { \
+ tmp1 = gparent->_f.left; \
+ if (tmp1->_f.colour == C_RED) { \
+ parent->_f.colour = C_BLACK; \
+ tmp1->_f.colour = C_BLACK; \
+ gparent->_f.colour = C_RED; \
+ node = gparent; \
+ } else { \
+ if (node == parent->_f.left) { \
+ node = parent; \
+ rotate_right(head, node); \
+ parent = node->_f.parent; \
+ } \
+ parent->_f.colour = C_BLACK; \
+ gparent->_f.colour = C_RED; \
+ rotate_left(head, parent->_f.parent); \
+ } \
+ } \
+ parent = node->_f.parent; \
+ } \
+ head->top._f.right->_f.colour = C_BLACK; \
+ head->count++; \
+} \
+ \
+static void \
+deleteblack(struct _n##_rb_head *head, _t *parent, _t *node) \
+{ \
+ _t *tmp; \
+ \
+ while ((node == &_n##_rb_zero || node->_f.colour == C_BLACK) && \
+ node != &head->top) { \
+ if (parent->_f.left == node) { \
+ tmp = parent->_f.right; \
+ if (tmp->_f.colour == C_RED) { \
+ tmp->_f.colour = C_BLACK; \
+ parent->_f.colour = C_RED; \
+ rotate_left(head, parent); \
+ tmp = parent->_f.right; \
+ } \
+ if ((tmp->_f.left == &_n##_rb_zero || \
+ tmp->_f.left->_f.colour == C_BLACK) && \
+ (tmp->_f.right == &_n##_rb_zero || \
+ tmp->_f.right->_f.colour == C_BLACK)) { \
+ tmp->_f.colour = C_RED; \
+ node = parent; \
+ parent = node->_f.parent; \
+ } else { \
+ if (tmp->_f.right == &_n##_rb_zero || \
+ tmp->_f.right->_f.colour == C_BLACK) {\
+ _t *tmp2 = tmp->_f.left; \
+ \
+ if (tmp2 != &_n##_rb_zero) \
+ tmp2->_f.colour = C_BLACK;\
+ tmp->_f.colour = C_RED; \
+ rotate_right(head, tmp); \
+ tmp = parent->_f.right; \
+ } \
+ tmp->_f.colour = parent->_f.colour; \
+ parent->_f.colour = C_BLACK; \
+ if (tmp->_f.right != &_n##_rb_zero) \
+ tmp->_f.right->_f.colour = C_BLACK;\
+ rotate_left(head, parent); \
+ node = head->top._f.right; \
+ } \
+ } else { \
+ tmp = parent->_f.left; \
+ if (tmp->_f.colour == C_RED) { \
+ tmp->_f.colour = C_BLACK; \
+ parent->_f.colour = C_RED; \
+ rotate_right(head, parent); \
+ tmp = parent->_f.left; \
+ } \
+ if ((tmp->_f.left == &_n##_rb_zero || \
+ tmp->_f.left->_f.colour == C_BLACK) && \
+ (tmp->_f.right == &_n##_rb_zero || \
+ tmp->_f.right->_f.colour == C_BLACK)) { \
+ tmp->_f.colour = C_RED; \
+ node = parent; \
+ parent = node->_f.parent; \
+ } else { \
+ if (tmp->_f.left == &_n##_rb_zero || \
+ tmp->_f.left->_f.colour == C_BLACK) {\
+ _t *tmp2 = tmp->_f.right; \
+ \
+ if (tmp2 != &_n##_rb_zero) \
+ tmp2->_f.colour = C_BLACK;\
+ tmp->_f.colour = C_RED; \
+ rotate_left(head, tmp); \
+ tmp = parent->_f.left; \
+ } \
+ tmp->_f.colour = parent->_f.colour; \
+ parent->_f.colour = C_BLACK; \
+ if (tmp->_f.left != &_n##_rb_zero) \
+ tmp->_f.left->_f.colour = C_BLACK;\
+ rotate_right(head, parent); \
+ node = head->top._f.right; \
+ break; \
+ } \
+ } \
+ } \
+ if (node != &_n##_rb_zero) \
+ node->_f.colour = C_BLACK; \
+} \
+ \
+_t * \
+_n##_rb_delete(struct _n##_rb_head *head, _t *node) \
+{ \
+ _t *child, *parent, *old = node, *left; \
+ rbcolour_t color; \
+ \
+ if (node->_f.left == &_n##_rb_zero) { \
+ child = node->_f.right; \
+ } else if (node->_f.right == &_n##_rb_zero) { \
+ child = node->_f.left; \
+ } else { \
+ node = node->_f.right; \
+ while ((left = node->_f.left) != &_n##_rb_zero) \
+ node = left; \
+ child = node->_f.right; \
+ parent = node->_f.parent; \
+ color = node->_f.colour; \
+ if (child != &_n##_rb_zero) \
+ child->_f.parent = parent; \
+ if (parent != &_n##_rb_zero) { \
+ if (parent->_f.left == node) \
+ parent->_f.left = child; \
+ else \
+ parent->_f.right = child; \
+ } else { \
+ head->top._f.right = child; \
+ } \
+ if (node->_f.parent == old) \
+ parent = node; \
+ *node = *old; \
+ if (old->_f.parent != &_n##_rb_zero) { \
+ if (old->_f.parent->_f.left == old) \
+ old->_f.parent->_f.left = node; \
+ else \
+ old->_f.parent->_f.right = node; \
+ } else { \
+ head->top._f.right = child; \
+ } \
+ old->_f.left->_f.parent = node; \
+ if (old->_f.right != &_n##_rb_zero) \
+ old->_f.right->_f.parent = node; \
+ if (parent != &_n##_rb_zero) { \
+ left = parent; \
+ } \
+ goto colour; \
+ } \
+ parent = node->_f.parent; \
+ color= node->_f.colour; \
+ if (child != &_n##_rb_zero) \
+ child->_f.parent = parent; \
+ if (parent != &_n##_rb_zero) { \
+ if (parent->_f.left == node) \
+ parent->_f.left = child; \
+ else \
+ parent->_f.right = child; \
+ } else { \
+ head->top._f.right = child; \
+ } \
+colour: \
+ if (color == C_BLACK) \
+ deleteblack(head, parent, node); \
+ head->count--; \
+ return old; \
+} \
+ \
+void \
+_n##_rb_init(struct _n##_rb_head *head) \
+{ \
+ memset(head, 0, sizeof(*head)); \
+ memset(&_n##_rb_zero, 0, sizeof(_n##_rb_zero)); \
+ head->top._f.left = &_n##_rb_zero; \
+ head->top._f.right = &_n##_rb_zero; \
+ head->top._f.parent = &head->top; \
+ _n##_rb_zero._f.left = &_n##_rb_zero; \
+ _n##_rb_zero._f.right = &_n##_rb_zero; \
+ _n##_rb_zero._f.parent = &_n##_rb_zero; \
+} \
+ \
+void \
+_n##_rb_walktree(struct _n##_rb_head *head, _n##_rb_walker_t func, void *arg)\
+{ \
+ _t *prev; \
+ _t *next; \
+ _t *node = head->top._f.right; \
+ _t *base; \
+ \
+ while (node != &_n##_rb_zero) \
+ node = node->_f.left; \
+ \
+ for (;;) { \
+ base = node; \
+ prev = node; \
+ while ((node->_f.parent->_f.right == node) && \
+ (node != &_n##_rb_zero)) { \
+ prev = node; \
+ node = node->_f.parent; \
+ } \
+ \
+ node = prev; \
+ for (node = node->_f.parent->_f.right; node != &_n##_rb_zero;\
+ node = node->_f.left) \
+ prev = node; \
+ next = prev; \
+ \
+ if (node != &_n##_rb_zero) \
+ func(node, arg); \
+ \
+ node = next; \
+ if (node == &_n##_rb_zero) \
+ break; \
+ } \
+} \
+ \
+_t * \
+_n##_rb_search(struct _n##_rb_head *head, void *key) \
+{ \
+ int match; \
+ _t *node; \
+ node = head->top._f.right; \
+ while (node != &_n##_rb_zero) { \
+ match = _cmp(key, node); \
+ if (match == 0) \
+ break; \
+ if (match< 0) \
+ node = node->_f.left; \
+ else \
+ node = node->_f.right; \
+ } \
+ if (node == &_n##_rb_zero || match != 0) \
+ return (NULL); \
+ return (node); \
+}
+
+#define RBI_DELETE(_n, _h, _v) _n##_rb_delete(_h, _v)
+#define RBI_FIELD(_n) struct _n##_rb_link
+#define RBI_INIT(_n, _h) _n##_rb_init(_h)
+#define RBI_INSERT(_n, _h, _v) _n##_rb_insert(_h, _v)
+#define RBI_ISEMPTY(_h) ((_h)->count == 0)
+#define RBI_SEARCH(_n, _h, _k) _n##_rb_search(_h, _k)
+#define RBI_WALK(_n, _h, _w, _a) _n##_rb_walktree(_h, _w, _a)
+#define RBI_ZERO(_n) _n##_rb_zero
diff --git a/sys/contrib/ipfilter/netinet/ipl.h b/sys/contrib/ipfilter/netinet/ipl.h
index 4f2f122..ca3baf2 100644
--- a/sys/contrib/ipfilter/netinet/ipl.h
+++ b/sys/contrib/ipfilter/netinet/ipl.h
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1993-2001, 2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
*
@@ -13,8 +13,8 @@
#ifndef __IPL_H__
#define __IPL_H__
-#define IPL_VERSION "IP Filter: v4.1.28"
+#define IPL_VERSION "IP Filter: v5.1.2"
-#define IPFILTER_VERSION 4012800
+#define IPFILTER_VERSION 5010200
-#endif
+#endif /* __IPL_H__ */
diff --git a/sys/contrib/ipfilter/netinet/mlfk_ipl.c b/sys/contrib/ipfilter/netinet/mlfk_ipl.c
index 6dcb821..3f4f2e9 100644
--- a/sys/contrib/ipfilter/netinet/mlfk_ipl.c
+++ b/sys/contrib/ipfilter/netinet/mlfk_ipl.c
@@ -1,7 +1,7 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 2000 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* $FreeBSD$
* See the IPFILTER.LICENCE file for details on licencing.
@@ -18,20 +18,22 @@
#include <sys/select.h>
#if __FreeBSD_version >= 500000
# include <sys/selinfo.h>
-#endif
+#endif
#include <net/if.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
-#include <netinet/ipl.h>
-#include <netinet/ip_compat.h>
-#include <netinet/ip_fil.h>
-#include <netinet/ip_state.h>
-#include <netinet/ip_nat.h>
-#include <netinet/ip_auth.h>
-#include <netinet/ip_frag.h>
-#include <netinet/ip_sync.h>
+#include "netinet/ipl.h"
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_state.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_auth.h"
+#include "netinet/ip_frag.h"
+#include "netinet/ip_sync.h"
+
+extern ipf_main_softc_t ipfmain;
#if __FreeBSD_version >= 502116
static struct cdev *ipf_devs[IPL_LOGSIZE];
@@ -39,10 +41,34 @@ static struct cdev *ipf_devs[IPL_LOGSIZE];
static dev_t ipf_devs[IPL_LOGSIZE];
#endif
+#if 0
static int sysctl_ipf_int ( SYSCTL_HANDLER_ARGS );
+#endif
static int ipf_modload(void);
static int ipf_modunload(void);
+#if (__FreeBSD_version >= 500024)
+# if (__FreeBSD_version >= 502116)
+static int ipfopen __P((struct cdev*, int, int, struct thread *));
+static int ipfclose __P((struct cdev*, int, int, struct thread *));
+# else
+static int ipfopen __P((dev_t, int, int, struct thread *));
+static int ipfclose __P((dev_t, int, int, struct thread *));
+# endif /* __FreeBSD_version >= 502116 */
+#else
+static int ipfopen __P((dev_t, int, int, struct proc *));
+static int ipfclose __P((dev_t, int, int, struct proc *));
+#endif
+#if (__FreeBSD_version >= 502116)
+static int ipfread __P((struct cdev*, struct uio *, int));
+static int ipfwrite __P((struct cdev*, struct uio *, int));
+#else
+static int ipfread __P((dev_t, struct uio *, int));
+static int ipfwrite __P((dev_t, struct uio *, int));
+#endif /* __FreeBSD_version >= 502116 */
+
+
+
SYSCTL_DECL(_net_inet);
#define SYSCTL_IPF(parent, nbr, name, access, ptr, val, descr) \
SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|access, \
@@ -50,91 +76,91 @@ SYSCTL_DECL(_net_inet);
#define CTLFLAG_OFF 0x00800000 /* IPFilter must be disabled */
#define CTLFLAG_RWO (CTLFLAG_RW|CTLFLAG_OFF)
SYSCTL_NODE(_net_inet, OID_AUTO, ipf, CTLFLAG_RW, 0, "IPF");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &fr_flags, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_pass, CTLFLAG_RW, &fr_pass, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &fr_active, 0, "");
+#if 0
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_flags, CTLFLAG_RW, &ipf_flags, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_pass, CTLFLAG_RW, &ipf_pass, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_active, CTLFLAG_RD, &ipf_active, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO,
- &fr_tcpidletimeout, 0, "");
+ &ipf_tcpidletimeout, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO,
- &fr_tcphalfclosed, 0, "");
+ &ipf_tcphalfclosed, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO,
- &fr_tcpclosewait, 0, "");
+ &ipf_tcpclosewait, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RWO,
- &fr_tcplastack, 0, "");
+ &ipf_tcplastack, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO,
- &fr_tcptimeout, 0, "");
+ &ipf_tcptimeout, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO,
- &fr_tcpclosed, 0, "");
+ &ipf_tcpclosed, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO,
- &fr_udptimeout, 0, "");
+ &ipf_udptimeout, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udpacktimeout, CTLFLAG_RWO,
- &fr_udpacktimeout, 0, "");
+ &ipf_udpacktimeout, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO,
- &fr_icmptimeout, 0, "");
+ &ipf_icmptimeout, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RWO,
- &fr_defnatage, 0, "");
+ &ipf_nat_defage, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_ipfrttl, CTLFLAG_RW,
- &fr_ipfrttl, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_running, CTLFLAG_RD,
- &fr_running, 0, "");
+ &ipf_ipfrttl, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_running, CTLFLAG_RD,
+ &ipf_running, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statesize, CTLFLAG_RWO,
- &fr_statesize, 0, "");
+ &ipf_state_size, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statemax, CTLFLAG_RWO,
- &fr_statemax, 0, "");
+ &ipf_state_max, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_nattable_sz, CTLFLAG_RWO,
- &ipf_nattable_sz, 0, "");
+ &ipf_nat_table_sz, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_natrules_sz, CTLFLAG_RWO,
- &ipf_natrules_sz, 0, "");
+ &ipf_nat_maprules_sz, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_rdrrules_sz, CTLFLAG_RWO,
- &ipf_rdrrules_sz, 0, "");
+ &ipf_nat_rdrrules_sz, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_hostmap_sz, CTLFLAG_RWO,
- &ipf_hostmap_sz, 0, "");
+ &ipf_nat_hostmap_sz, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RWO,
- &fr_authsize, 0, "");
+ &ipf_auth_size, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD,
- &fr_authused, 0, "");
+ &ipf_auth_used, 0, "");
SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW,
- &fr_defaultauthage, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, "");
-SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &fr_minttl, 0, "");
+ &ipf_auth_defaultage, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &ipf_chksrc, 0, "");
+SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &ipf_minttl, 0, "");
+#endif
#define CDEV_MAJOR 79
#include <sys/poll.h>
#if __FreeBSD_version >= 500043
# include <sys/select.h>
-static int iplpoll(struct cdev *dev, int events, struct thread *td);
+static int ipfpoll(struct cdev *dev, int events, struct thread *td);
-static struct cdevsw ipl_cdevsw = {
-# if __FreeBSD_version >= 502103
+static struct cdevsw ipf_cdevsw = {
+#if __FreeBSD_version >= 502103
.d_version = D_VERSION,
.d_flags = 0, /* D_NEEDGIANT - Should be SMP safe */
-# endif
- .d_open = iplopen,
- .d_close = iplclose,
- .d_read = iplread,
- .d_write = iplwrite,
- .d_ioctl = iplioctl,
- .d_name = "ipl",
-# if __FreeBSD_version >= 500043
- .d_poll = iplpoll,
-# endif
-# if __FreeBSD_version < 600000
+#endif
+ .d_open = ipfopen,
+ .d_close = ipfclose,
+ .d_read = ipfread,
+ .d_write = ipfwrite,
+ .d_ioctl = ipfioctl,
+ .d_poll = ipfpoll,
+ .d_name = "ipf",
+#if __FreeBSD_version < 600000
.d_maj = CDEV_MAJOR,
-# endif
+#endif
};
#else
-static int iplpoll(dev_t dev, int events, struct proc *p);
-
-static struct cdevsw ipl_cdevsw = {
- /* open */ iplopen,
- /* close */ iplclose,
- /* read */ iplread,
- /* write */ iplwrite,
- /* ioctl */ iplioctl,
- /* poll */ iplpoll,
+static int ipfpoll(dev_t dev, int events, struct proc *td);
+
+static struct cdevsw ipf_cdevsw = {
+ /* open */ ipfopen,
+ /* close */ ipfclose,
+ /* read */ ipfread,
+ /* write */ ipfwrite,
+ /* ioctl */ ipfioctl,
+ /* poll */ ipfpoll,
/* mmap */ nommap,
/* strategy */ nostrategy,
- /* name */ "ipl",
+ /* name */ "ipf",
/* maj */ CDEV_MAJOR,
/* dump */ nodump,
/* psize */ nopsize,
@@ -142,7 +168,7 @@ static struct cdevsw ipl_cdevsw = {
# if (__FreeBSD_version < 500043)
/* bmaj */ -1,
# endif
-# if (__FreeBSD_version > 430000)
+# if (__FreeBSD_version >= 430000)
/* kqfilter */ NULL
# endif
};
@@ -180,17 +206,15 @@ ipf_modload()
char *defpass, *c, *str;
int i, j, error;
- RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex");
- RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock");
- RWLOCK_INIT(&ipf_frcache, "ipf cache rwlock");
+ if (ipf_load_all() != 0)
+ return EIO;
- error = ipfattach();
- if (error) {
- RW_DESTROY(&ipf_global);
- RW_DESTROY(&ipf_mutex);
- RW_DESTROY(&ipf_frcache);
+ if (ipf_create_all(&ipfmain) == NULL)
+ return EIO;
+
+ error = ipfattach(&ipfmain);
+ if (error)
return error;
- }
for (i = 0; i < IPL_LOGSIZE; i++)
ipf_devs[i] = NULL;
@@ -204,7 +228,7 @@ ipf_modload()
}
if (!c)
c = str;
- ipf_devs[i] = make_dev(&ipl_cdevsw, i, 0, 0, 0600, "%s", c);
+ ipf_devs[i] = make_dev(&ipf_cdevsw, i, 0, 0, 0600, "%s", c);
}
error = ipf_pfil_hook();
@@ -212,15 +236,15 @@ ipf_modload()
return error;
ipf_event_reg();
- if (FR_ISPASS(fr_pass))
+ if (FR_ISPASS(ipfmain.ipf_pass))
defpass = "pass";
- else if (FR_ISBLOCK(fr_pass))
+ else if (FR_ISBLOCK(ipfmain.ipf_pass))
defpass = "block";
- else
+ else
defpass = "no-match -> block";
printf("%s initialized. Default = %s all, Logging = %s%s\n",
- ipfilter_version, defpass,
+ ipfilter_version, defpass,
#ifdef IPFILTER_LOG
"enabled",
#else
@@ -231,7 +255,7 @@ ipf_modload()
#else
""
#endif
- );
+ );
return 0;
}
@@ -241,25 +265,24 @@ ipf_modunload()
{
int error, i;
- if (fr_refcnt)
+ if (ipfmain.ipf_refcnt)
return EBUSY;
- if (fr_running >= 0) {
- ipf_pfil_unhook();
- ipf_event_dereg();
- WRITE_ENTER(&ipf_global);
- error = ipfdetach();
- RWLOCK_EXIT(&ipf_global);
+ error = ipf_pfil_unhook();
+ if (error != 0)
+ return error;
+
+ if (ipfmain.ipf_running >= 0) {
+ error = ipfdetach(&ipfmain);
if (error != 0)
return error;
+
+ ipf_destroy_all(&ipfmain);
+ ipf_unload_all();
} else
error = 0;
- RW_DESTROY(&ipf_global);
- RW_DESTROY(&ipf_mutex);
- RW_DESTROY(&ipf_frcache);
-
- fr_running = -2;
+ ipfmain.ipf_running = -2;
for (i = 0; ipf_devfiles[i]; i++) {
if (ipf_devs[i] != NULL)
@@ -285,6 +308,7 @@ MODULE_VERSION(ipfilter, 1);
#endif
+#if 0
#ifdef SYSCTL_IPF
int
sysctl_ipf_int ( SYSCTL_HANDLER_ARGS )
@@ -302,7 +326,7 @@ sysctl_ipf_int ( SYSCTL_HANDLER_ARGS )
if (!arg1)
error = EPERM;
else {
- if ((oidp->oid_kind & CTLFLAG_OFF) && (fr_running > 0))
+ if ((oidp->oid_kind & CTLFLAG_OFF) && (ipfmain.ipf_running > 0))
error = EBUSY;
else
error = SYSCTL_IN(req, arg1, sizeof(int));
@@ -310,44 +334,43 @@ sysctl_ipf_int ( SYSCTL_HANDLER_ARGS )
return (error);
}
#endif
+#endif
static int
#if __FreeBSD_version >= 500043
-iplpoll(struct cdev *dev, int events, struct thread *td)
+ipfpoll(struct cdev *dev, int events, struct thread *td)
#else
-iplpoll(dev_t dev, int events, struct proc *td)
+ipfpoll(dev_t dev, int events, struct proc *td)
#endif
{
- u_int xmin = GET_MINOR(dev);
+ int unit = GET_MINOR(dev);
int revents;
- if (xmin < 0 || xmin > IPL_LOGMAX)
+ if (unit < 0 || unit > IPL_LOGMAX)
return 0;
revents = 0;
- switch (xmin)
+ switch (unit)
{
case IPL_LOGIPF :
case IPL_LOGNAT :
case IPL_LOGSTATE :
#ifdef IPFILTER_LOG
- if ((events & (POLLIN | POLLRDNORM)) && ipflog_canread(xmin))
+ if ((events & (POLLIN | POLLRDNORM)) && ipf_log_canread(&ipfmain, unit))
revents |= events & (POLLIN | POLLRDNORM);
-#endif
+#endif
break;
case IPL_LOGAUTH :
- if ((events & (POLLIN | POLLRDNORM)) && fr_auth_waiting())
+ if ((events & (POLLIN | POLLRDNORM)) && ipf_auth_waiting(&ipfmain))
revents |= events & (POLLIN | POLLRDNORM);
- break;
+ break;
case IPL_LOGSYNC :
-#ifdef IPFILTER_SYNC
- if ((events & (POLLIN | POLLRDNORM)) && ipfsync_canread())
+ if ((events & (POLLIN | POLLRDNORM)) && ipf_sync_canread(&ipfmain))
revents |= events & (POLLIN | POLLRDNORM);
- if ((events & (POLLOUT | POLLWRNORM)) && ipfsync_canwrite())
+ if ((events & (POLLOUT | POLLWRNORM)) && ipf_sync_canwrite(&ipfmain))
revents |= events & (POLLOUT | POLLWRNORM);
-#endif
break;
case IPL_LOGSCAN :
case IPL_LOGLOOKUP :
@@ -356,7 +379,152 @@ iplpoll(dev_t dev, int events, struct proc *td)
}
if ((revents == 0) && ((events & (POLLIN|POLLRDNORM)) != 0))
- selrecord(td, &ipfselwait[xmin]);
+ selrecord(td, &ipfmain.ipf_selwait[unit]);
return revents;
}
+
+
+/*
+ * routines below for saving IP headers to buffer
+ */
+static int ipfopen(dev, flags
+#if ((BSD >= 199506) || (__FreeBSD_version >= 220000))
+, devtype, p)
+ int devtype;
+# if (__FreeBSD_version >= 500024)
+ struct thread *p;
+# else
+ struct proc *p;
+# endif /* __FreeBSD_version >= 500024 */
+#else
+)
+#endif
+#if (__FreeBSD_version >= 502116)
+ struct cdev *dev;
+#else
+ dev_t dev;
+#endif
+ int flags;
+{
+ int unit = GET_MINOR(dev);
+ int error;
+
+ if (IPL_LOGMAX < unit)
+ error = ENXIO;
+ else {
+ switch (unit)
+ {
+ case IPL_LOGIPF :
+ case IPL_LOGNAT :
+ case IPL_LOGSTATE :
+ case IPL_LOGAUTH :
+ case IPL_LOGLOOKUP :
+ case IPL_LOGSYNC :
+#ifdef IPFILTER_SCAN
+ case IPL_LOGSCAN :
+#endif
+ error = 0;
+ break;
+ default :
+ error = ENXIO;
+ break;
+ }
+ }
+ return error;
+}
+
+
+static int ipfclose(dev, flags
+#if ((BSD >= 199506) || (__FreeBSD_version >= 220000))
+, devtype, p)
+ int devtype;
+# if (__FreeBSD_version >= 500024)
+ struct thread *p;
+# else
+ struct proc *p;
+# endif /* __FreeBSD_version >= 500024 */
+#else
+)
+#endif
+#if (__FreeBSD_version >= 502116)
+ struct cdev *dev;
+#else
+ dev_t dev;
+#endif
+ int flags;
+{
+ int unit = GET_MINOR(dev);
+
+ if (IPL_LOGMAX < unit)
+ unit = ENXIO;
+ else
+ unit = 0;
+ return unit;
+}
+
+/*
+ * ipfread/ipflog
+ * both of these must operate with at least splnet() lest they be
+ * called during packet processing and cause an inconsistancy to appear in
+ * the filter lists.
+ */
+#if (BSD >= 199306)
+static int ipfread(dev, uio, ioflag)
+ int ioflag;
+#else
+static int ipfread(dev, uio)
+#endif
+#if (__FreeBSD_version >= 502116)
+ struct cdev *dev;
+#else
+ dev_t dev;
+#endif
+ struct uio *uio;
+{
+ int unit = GET_MINOR(dev);
+
+ if (unit < 0)
+ return ENXIO;
+
+ if (ipfmain.ipf_running < 1)
+ return EIO;
+
+ if (unit == IPL_LOGSYNC)
+ return ipf_sync_read(&ipfmain, uio);
+
+#ifdef IPFILTER_LOG
+ return ipf_log_read(&ipfmain, unit, uio);
+#else
+ return ENXIO;
+#endif
+}
+
+
+/*
+ * ipfwrite
+ * both of these must operate with at least splnet() lest they be
+ * called during packet processing and cause an inconsistancy to appear in
+ * the filter lists.
+ */
+#if (BSD >= 199306)
+static int ipfwrite(dev, uio, ioflag)
+ int ioflag;
+#else
+static int ipfwrite(dev, uio)
+#endif
+#if (__FreeBSD_version >= 502116)
+ struct cdev *dev;
+#else
+ dev_t dev;
+#endif
+ struct uio *uio;
+{
+
+ if (ipfmain.ipf_running < 1)
+ return EIO;
+
+ if (GET_MINOR(dev) == IPL_LOGSYNC)
+ return ipf_sync_write(&ipfmain, uio);
+ return ENXIO;
+}
diff --git a/sys/contrib/ipfilter/netinet/radix_ipf.c b/sys/contrib/ipfilter/netinet/radix_ipf.c
new file mode 100644
index 0000000..f145c38
--- /dev/null
+++ b/sys/contrib/ipfilter/netinet/radix_ipf.c
@@ -0,0 +1,1528 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#if !defined(_KERNEL)
+# include <stddef.h>
+# include <stdlib.h>
+# include <strings.h>
+# include <string.h>
+#endif
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#ifdef RDX_DEBUG
+# include <arpa/inet.h>
+# include <stdlib.h>
+# include <stdio.h>
+#endif
+#include "netinet/radix_ipf.h"
+
+#define ADF_OFF offsetof(addrfamily_t, adf_addr)
+#define ADF_OFF_BITS (ADF_OFF << 3)
+
+static ipf_rdx_node_t *ipf_rx_insert __P((ipf_rdx_head_t *,
+ ipf_rdx_node_t nodes[2], int *));
+static void ipf_rx_attach_mask __P((ipf_rdx_node_t *, ipf_rdx_mask_t *));
+static int count_mask_bits __P((addrfamily_t *, u_32_t **));
+static void buildnodes __P((addrfamily_t *, addrfamily_t *,
+ ipf_rdx_node_t n[2]));
+static ipf_rdx_node_t *ipf_rx_find_addr __P((ipf_rdx_node_t *, u_32_t *));
+static ipf_rdx_node_t *ipf_rx_lookup __P((ipf_rdx_head_t *, addrfamily_t *,
+ addrfamily_t *));
+static ipf_rdx_node_t *ipf_rx_match __P((ipf_rdx_head_t *, addrfamily_t *));
+
+/*
+ * Foreword.
+ * ---------
+ * The code in this file has been written to target using the addrfamily_t
+ * data structure to house the address information and no other. Thus there
+ * are certain aspects of thise code (such as offsets to the address itself)
+ * that are hard coded here whilst they might be more variable elsewhere.
+ * Similarly, this code enforces no maximum key length as that's implied by
+ * all keys needing to be stored in addrfamily_t.
+ */
+
+/* ------------------------------------------------------------------------ */
+/* Function: count_mask_bits */
+/* Returns: number of consecutive bits starting at "mask". */
+/* */
+/* Count the number of bits set in the address section of addrfamily_t and */
+/* return both that number and a pointer to the last word with a bit set if */
+/* lastp is not NULL. The bit count is performed using network byte order */
+/* as the guide for which bit is the most significant bit. */
+/* ------------------------------------------------------------------------ */
+static int
+count_mask_bits(mask, lastp)
+ addrfamily_t *mask;
+ u_32_t **lastp;
+{
+ u_32_t *mp = (u_32_t *)&mask->adf_addr;
+ u_32_t m;
+ int count = 0;
+ int mlen;
+
+ mlen = mask->adf_len - offsetof(addrfamily_t, adf_addr);
+ for (; mlen > 0; mlen -= 4, mp++) {
+ if ((m = ntohl(*mp)) == 0)
+ break;
+ if (lastp != NULL)
+ *lastp = mp;
+ for (; m & 0x80000000; m <<= 1)
+ count++;
+ }
+
+ return count;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: buildnodes */
+/* Returns: Nil */
+/* Parameters: addr(I) - network address for this radix node */
+/* mask(I) - netmask associated with the above address */
+/* nodes(O) - pair of ipf_rdx_node_t's to initialise with data */
+/* associated with addr and mask. */
+/* */
+/* Initialise the fields in a pair of radix tree nodes according to the */
+/* data supplied in the paramters "addr" and "mask". It is expected that */
+/* "mask" will contain a consecutive string of bits set. Masks with gaps in */
+/* the middle are not handled by this implementation. */
+/* ------------------------------------------------------------------------ */
+static void
+buildnodes(addr, mask, nodes)
+ addrfamily_t *addr, *mask;
+ ipf_rdx_node_t nodes[2];
+{
+ u_32_t maskbits;
+ u_32_t lastbits;
+ u_32_t lastmask;
+ u_32_t *last;
+ int masklen;
+
+ last = NULL;
+ maskbits = count_mask_bits(mask, &last);
+ if (last == NULL) {
+ masklen = 0;
+ lastmask = 0;
+ } else {
+ masklen = last - (u_32_t *)mask;
+ lastmask = *last;
+ }
+ lastbits = maskbits & 0x1f;
+
+ bzero(&nodes[0], sizeof(ipf_rdx_node_t) * 2);
+ nodes[0].maskbitcount = maskbits;
+ nodes[0].index = -1 - (ADF_OFF_BITS + maskbits);
+ nodes[0].addrkey = (u_32_t *)addr;
+ nodes[0].maskkey = (u_32_t *)mask;
+ nodes[0].addroff = nodes[0].addrkey + masklen;
+ nodes[0].maskoff = nodes[0].maskkey + masklen;
+ nodes[0].parent = &nodes[1];
+ nodes[0].offset = masklen;
+ nodes[0].lastmask = lastmask;
+ nodes[1].offset = masklen;
+ nodes[1].left = &nodes[0];
+ nodes[1].maskbitcount = maskbits;
+#ifdef RDX_DEBUG
+ (void) strcpy(nodes[0].name, "_BUILD.0");
+ (void) strcpy(nodes[1].name, "_BUILD.1");
+#endif
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_find_addr */
+/* Returns: ipf_rdx_node_t * - pointer to a node in the radix tree. */
+/* Parameters: tree(I) - pointer to first right node in tree to search */
+/* addr(I) - pointer to address to match */
+/* */
+/* Walk the radix tree given by "tree", looking for a leaf node that is a */
+/* match for the address given by "addr". */
+/* ------------------------------------------------------------------------ */
+static ipf_rdx_node_t *
+ipf_rx_find_addr(tree, addr)
+ ipf_rdx_node_t *tree;
+ u_32_t *addr;
+{
+ ipf_rdx_node_t *cur;
+
+ for (cur = tree; cur->index >= 0;) {
+ if (cur->bitmask & addr[cur->offset]) {
+ cur = cur->right;
+ } else {
+ cur = cur->left;
+ }
+ }
+
+ return (cur);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_match */
+/* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
+/* added to the tree. */
+/* Paramters: head(I) - pointer to tree head to search */
+/* addr(I) - pointer to address to find */
+/* */
+/* Search the radix tree for the best match to the address pointed to by */
+/* "addr" and return a pointer to that node. This search will not match the */
+/* address information stored in either of the root leaves as neither of */
+/* them are considered to be part of the tree of data being stored. */
+/* ------------------------------------------------------------------------ */
+static ipf_rdx_node_t *
+ipf_rx_match(head, addr)
+ ipf_rdx_head_t *head;
+ addrfamily_t *addr;
+{
+ ipf_rdx_mask_t *masknode;
+ ipf_rdx_node_t *prev;
+ ipf_rdx_node_t *node;
+ ipf_rdx_node_t *cur;
+ u_32_t *data;
+ u_32_t *mask;
+ u_32_t *key;
+ u_32_t *end;
+ int len;
+ int i;
+
+ len = addr->adf_len;
+ end = (u_32_t *)((u_char *)addr + len);
+ node = ipf_rx_find_addr(head->root, (u_32_t *)addr);
+
+ /*
+ * Search the dupkey list for a potential match.
+ */
+ for (cur = node; (cur != NULL) && (cur->root == 0); cur = cur->dupkey) {
+ i = cur[0].addroff - cur[0].addrkey;
+ data = cur[0].addrkey + i;
+ mask = cur[0].maskkey + i;
+ key = (u_32_t *)addr + i;
+ for (; key < end; data++, key++, mask++)
+ if ((*key & *mask) != *data)
+ break;
+ if ((end == key) && (cur->root == 0))
+ return (cur); /* Equal keys */
+ }
+ prev = node->parent;
+ key = (u_32_t *)addr;
+
+ for (node = prev; node->root == 0; node = node->parent) {
+ /*
+ * We know that the node hasn't matched so therefore only
+ * the entries in the mask list are searched, not the top
+ * node nor the dupkey list.
+ */
+ masknode = node->masks;
+ for (; masknode != NULL; masknode = masknode->next) {
+ if (masknode->maskbitcount > node->maskbitcount)
+ continue;
+ cur = masknode->node;
+ for (i = ADF_OFF >> 2; i <= node->offset; i++) {
+ if ((key[i] & masknode->mask[i]) ==
+ cur->addrkey[i])
+ return (cur);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_lookup */
+/* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
+/* added to the tree. */
+/* Paramters: head(I) - pointer to tree head to search */
+/* addr(I) - address part of the key to match */
+/* mask(I) - netmask part of the key to match */
+/* */
+/* ipf_rx_lookup searches for an exact match on (addr,mask). The intention */
+/* is to see if a given key is in the tree, not to see if a route exists. */
+/* ------------------------------------------------------------------------ */
+ipf_rdx_node_t *
+ipf_rx_lookup(head, addr, mask)
+ ipf_rdx_head_t *head;
+ addrfamily_t *addr, *mask;
+{
+ ipf_rdx_node_t *found;
+ ipf_rdx_node_t *node;
+ u_32_t *akey;
+ int count;
+
+ found = ipf_rx_find_addr(head->root, (u_32_t *)addr);
+ if (found->root == 1)
+ return NULL;
+
+ /*
+ * It is possible to find a matching address in the tree but for the
+ * netmask to not match. If the netmask does not match and there is
+ * no list of alternatives present at dupkey, return a failure.
+ */
+ count = count_mask_bits(mask, NULL);
+ if (count != found->maskbitcount && found->dupkey == NULL)
+ return (NULL);
+
+ akey = (u_32_t *)addr;
+ if ((found->addrkey[found->offset] & found->maskkey[found->offset]) !=
+ akey[found->offset])
+ return NULL;
+
+ if (found->dupkey != NULL) {
+ node = found;
+ while (node != NULL && node->maskbitcount != count)
+ node = node->dupkey;
+ if (node == NULL)
+ return (NULL);
+ found = node;
+ }
+ return found;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_attach_mask */
+/* Returns: Nil */
+/* Parameters: node(I) - pointer to a radix tree node */
+/* mask(I) - pointer to mask structure to add */
+/* */
+/* Add the netmask to the given node in an ordering where the most specific */
+/* netmask is at the top of the list. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_rx_attach_mask(node, mask)
+ ipf_rdx_node_t *node;
+ ipf_rdx_mask_t *mask;
+{
+ ipf_rdx_mask_t **pm;
+ ipf_rdx_mask_t *m;
+
+ for (pm = &node->masks; (m = *pm) != NULL; pm = &m->next)
+ if (m->maskbitcount < mask->maskbitcount)
+ break;
+ mask->next = *pm;
+ *pm = mask;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_insert */
+/* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
+/* added to the tree. */
+/* Paramters: head(I) - pointer to tree head to add nodes to */
+/* nodes(I) - pointer to radix nodes to be added */
+/* dup(O) - set to 1 if node is a duplicate, else 0. */
+/* */
+/* Add the new radix tree entry that owns nodes[] to the tree given by head.*/
+/* If there is already a matching key in the table, "dup" will be set to 1 */
+/* and the existing node pointer returned if there is a complete key match. */
+/* A complete key match is a matching of all key data that is presented by */
+/* by the netmask. */
+/* ------------------------------------------------------------------------ */
+static ipf_rdx_node_t *
+ipf_rx_insert(head, nodes, dup)
+ ipf_rdx_head_t *head;
+ ipf_rdx_node_t nodes[2];
+ int *dup;
+{
+ ipf_rdx_mask_t **pmask;
+ ipf_rdx_node_t *node;
+ ipf_rdx_node_t *prev;
+ ipf_rdx_mask_t *mask;
+ ipf_rdx_node_t *cur;
+ u_32_t nodemask;
+ u_32_t *addr;
+ u_32_t *data;
+ int nodebits;
+ u_32_t *key;
+ u_32_t *end;
+ u_32_t bits;
+ int nodekey;
+ int nodeoff;
+ int nlen;
+ int len;
+
+ addr = nodes[0].addrkey;
+
+ node = ipf_rx_find_addr(head->root, addr);
+ len = ((addrfamily_t *)addr)->adf_len;
+ key = (u_32_t *)&((addrfamily_t *)addr)->adf_addr;
+ data= (u_32_t *)&((addrfamily_t *)node->addrkey)->adf_addr;
+ end = (u_32_t *)((u_char *)addr + len);
+ for (nlen = 0; key < end; data++, key++, nlen += 32)
+ if (*key != *data)
+ break;
+ if (end == data) {
+ *dup = 1;
+ return (node); /* Equal keys */
+ }
+ *dup = 0;
+
+ bits = (ntohl(*data) ^ ntohl(*key));
+ for (; bits != 0; nlen++) {
+ if ((bits & 0x80000000) != 0)
+ break;
+ bits <<= 1;
+ }
+ nlen += ADF_OFF_BITS;
+ nodes[1].index = nlen;
+ nodes[1].bitmask = htonl(0x80000000 >> (nlen & 0x1f));
+ nodes[0].offset = nlen / 32;
+ nodes[1].offset = nlen / 32;
+
+ /*
+ * Walk through the tree and look for the correct place to attach
+ * this node. ipf_rx_fin_addr is not used here because the place
+ * to attach this node may be an internal node (same key, different
+ * netmask.) Additionally, the depth of the search is forcibly limited
+ * here to not exceed the netmask, so that a short netmask will be
+ * added higher up the tree even if there are lower branches.
+ */
+ cur = head->root;
+ key = nodes[0].addrkey;
+ do {
+ prev = cur;
+ if (key[cur->offset] & cur->bitmask) {
+ cur = cur->right;
+ } else {
+ cur = cur->left;
+ }
+ } while (nlen > (unsigned)cur->index);
+
+ if ((key[prev->offset] & prev->bitmask) == 0) {
+ prev->left = &nodes[1];
+ } else {
+ prev->right = &nodes[1];
+ }
+ cur->parent = &nodes[1];
+ nodes[1].parent = prev;
+ if ((key[nodes[1].offset] & nodes[1].bitmask) == 0) {
+ nodes[1].right = cur;
+ } else {
+ nodes[1].right = &nodes[0];
+ nodes[1].left = cur;
+ }
+
+ nodeoff = nodes[0].offset;
+ nodekey = nodes[0].addrkey[nodeoff];
+ nodemask = nodes[0].lastmask;
+ nodebits = nodes[0].maskbitcount;
+ prev = NULL;
+ /*
+ * Find the node up the tree with the largest pattern that still
+ * matches the node being inserted to see if this mask can be
+ * moved there.
+ */
+ for (cur = nodes[1].parent; cur->root == 0; cur = cur->parent) {
+ if (cur->maskbitcount <= nodebits)
+ break;
+ if (((cur - 1)->addrkey[nodeoff] & nodemask) != nodekey)
+ break;
+ prev = cur;
+ }
+
+ KMALLOC(mask, ipf_rdx_mask_t *);
+ if (mask == NULL)
+ return NULL;
+ bzero(mask, sizeof(*mask));
+ mask->next = NULL;
+ mask->node = &nodes[0];
+ mask->maskbitcount = nodebits;
+ mask->mask = nodes[0].maskkey;
+ nodes[0].mymask = mask;
+
+ if (prev != NULL) {
+ ipf_rdx_mask_t *m;
+
+ for (pmask = &prev->masks; (m = *pmask) != NULL;
+ pmask = &m->next) {
+ if (m->maskbitcount < nodebits)
+ break;
+ }
+ } else {
+ /*
+ * No higher up nodes qualify, so attach mask locally.
+ */
+ pmask = &nodes[0].masks;
+ }
+ mask->next = *pmask;
+ *pmask = mask;
+
+ /*
+ * Search the mask list on each child to see if there are any masks
+ * there that can be moved up to this newly inserted node.
+ */
+ cur = nodes[1].right;
+ if (cur->root == 0) {
+ for (pmask = &cur->masks; (mask = *pmask) != NULL; ) {
+ if (mask->maskbitcount < nodebits) {
+ *pmask = mask->next;
+ ipf_rx_attach_mask(&nodes[0], mask);
+ } else {
+ pmask = &mask->next;
+ }
+ }
+ }
+ cur = nodes[1].left;
+ if (cur->root == 0 && cur != &nodes[0]) {
+ for (pmask = &cur->masks; (mask = *pmask) != NULL; ) {
+ if (mask->maskbitcount < nodebits) {
+ *pmask = mask->next;
+ ipf_rx_attach_mask(&nodes[0], mask);
+ } else {
+ pmask = &mask->next;
+ }
+ }
+ }
+ return (&nodes[0]);
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_addroute */
+/* Returns: ipf_rdx_node_t * - NULL on error, else pointer to the node */
+/* added to the tree. */
+/* Paramters: head(I) - pointer to tree head to search */
+/* addr(I) - address portion of "route" to add */
+/* mask(I) - netmask portion of "route" to add */
+/* nodes(I) - radix tree data nodes inside allocate structure */
+/* */
+/* Attempt to add a node to the radix tree. The key for the node is the */
+/* (addr,mask). No memory allocation for the radix nodes themselves is */
+/* performed here, the data structure that this radix node is being used to */
+/* find is expected to house the node data itself however the call to */
+/* ipf_rx_insert() will attempt to allocate memory in order for netmask to */
+/* be promoted further up the tree. */
+/* In this case, the ip_pool_node_t structure from ip_pool.h contains both */
+/* the key material (addr,mask) and the radix tree nodes[]. */
+/* */
+/* The mechanics of inserting the node into the tree is handled by the */
+/* function ipf_rx_insert() above. Here, the code deals with the case */
+/* where the data to be inserted is a duplicate. */
+/* ------------------------------------------------------------------------ */
+ipf_rdx_node_t *
+ipf_rx_addroute(head, addr, mask, nodes)
+ ipf_rdx_head_t *head;
+ addrfamily_t *addr, *mask;
+ ipf_rdx_node_t *nodes;
+{
+ ipf_rdx_node_t *node;
+ ipf_rdx_node_t *prev;
+ ipf_rdx_node_t *x;
+ int dup;
+
+ buildnodes(addr, mask, nodes);
+ x = ipf_rx_insert(head, nodes, &dup);
+ if (x == NULL)
+ return NULL;
+
+ if (dup == 1) {
+ node = &nodes[0];
+ prev = NULL;
+ /*
+ * The duplicate list is kept sorted with the longest
+ * mask at the top, meaning that the most specific entry
+ * in the listis found first. This list thus allows for
+ * duplicates such as 128.128.0.0/32 and 128.128.0.0/16.
+ */
+ while ((x != NULL) && (x->maskbitcount > node->maskbitcount)) {
+ prev = x;
+ x = x->dupkey;
+ }
+
+ /*
+ * Is it a complete duplicate? If so, return NULL and
+ * fail the insert. Otherwise, insert it into the list
+ * of netmasks active for this key.
+ */
+ if ((x != NULL) && (x->maskbitcount == node->maskbitcount))
+ return (NULL);
+
+ if (prev != NULL) {
+ nodes[0].dupkey = x;
+ prev->dupkey = &nodes[0];
+ nodes[0].parent = prev;
+ if (x != NULL)
+ x->parent = &nodes[0];
+ } else {
+ nodes[0].dupkey = x->dupkey;
+ prev = x->parent;
+ nodes[0].parent = prev;
+ x->parent = &nodes[0];
+ if (prev->left == x)
+ prev->left = &nodes[0];
+ else
+ prev->right = &nodes[0];
+ }
+ }
+
+ return &nodes[0];
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_delete */
+/* Returns: ipf_rdx_node_t * - NULL on error, else node removed from */
+/* the tree. */
+/* Paramters: head(I) - pointer to tree head to search */
+/* addr(I) - pointer to the address part of the key */
+/* mask(I) - pointer to the netmask part of the key */
+/* */
+/* Search for an entry in the radix tree that is an exact match for (addr, */
+/* mask) and remove it if it exists. In the case where (addr,mask) is a not */
+/* a unique key, the tree structure itself is not changed - only the list */
+/* of duplicate keys. */
+/* ------------------------------------------------------------------------ */
+ipf_rdx_node_t *
+ipf_rx_delete(head, addr, mask)
+ ipf_rdx_head_t *head;
+ addrfamily_t *addr, *mask;
+{
+ ipf_rdx_mask_t **pmask;
+ ipf_rdx_node_t *parent;
+ ipf_rdx_node_t *found;
+ ipf_rdx_node_t *prev;
+ ipf_rdx_node_t *node;
+ ipf_rdx_node_t *cur;
+ ipf_rdx_mask_t *m;
+ int count;
+
+ found = ipf_rx_find_addr(head->root, (u_32_t *)addr);
+ if (found == NULL)
+ return NULL;
+ if (found->root == 1)
+ return NULL;
+ count = count_mask_bits(mask, NULL);
+ parent = found->parent;
+ if (found->dupkey != NULL) {
+ node = found;
+ while (node != NULL && node->maskbitcount != count)
+ node = node->dupkey;
+ if (node == NULL)
+ return (NULL);
+ if (node != found) {
+ /*
+ * Remove from the dupkey list. Here, "parent" is
+ * the previous node on the list (rather than tree)
+ * and "dupkey" is the next node on the list.
+ */
+ parent = node->parent;
+ parent->dupkey = node->dupkey;
+ node->dupkey->parent = parent;
+ } else {
+ /*
+ *
+ * When removing the top node of the dupkey list,
+ * the pointers at the top of the list that point
+ * to other tree nodes need to be preserved and
+ * any children must have their parent updated.
+ */
+ node = node->dupkey;
+ node->parent = found->parent;
+ node->right = found->right;
+ node->left = found->left;
+ found->right->parent = node;
+ found->left->parent = node;
+ if (parent->left == found)
+ parent->left = node;
+ else
+ parent->right= node;
+ }
+ } else {
+ if (count != found->maskbitcount)
+ return (NULL);
+ /*
+ * Remove the node from the tree and reconnect the subtree
+ * below.
+ */
+ /*
+ * If there is a tree to the left, look for something to
+ * attach in place of "found".
+ */
+ prev = found + 1;
+ cur = parent->parent;
+ if (parent != found + 1) {
+ if ((found + 1)->parent->right == found + 1)
+ (found + 1)->parent->right = parent;
+ else
+ (found + 1)->parent->left = parent;
+ if (cur->right == parent) {
+ if (parent->left == found) {
+ cur->right = parent->right;
+ } else if (parent->left != parent - 1) {
+ cur->right = parent->left;
+ } else {
+ cur->right = parent - 1;
+ }
+ cur->right->parent = cur;
+ } else {
+ if (parent->right == found) {
+ cur->left = parent->left;
+ } else if (parent->right != parent - 1) {
+ cur->left = parent->right;
+ } else {
+ cur->left = parent - 1;
+ }
+ cur->left->parent = cur;
+ }
+ parent->left = (found + 1)->left;
+ if ((found + 1)->right != parent)
+ parent->right = (found + 1)->right;
+ parent->left->parent = parent;
+ parent->right->parent = parent;
+ parent->parent = (found + 1)->parent;
+
+ parent->bitmask = prev->bitmask;
+ parent->offset = prev->offset;
+ parent->index = prev->index;
+ } else {
+ /*
+ * We found an edge node.
+ */
+ cur = parent->parent;
+ if (cur->left == parent) {
+ if (parent->left == found) {
+ cur->left = parent->right;
+ parent->right->parent = cur;
+ } else {
+ cur->left = parent->left;
+ parent->left->parent = cur;
+ }
+ } else {
+ if (parent->right != found) {
+ cur->right = parent->right;
+ parent->right->parent = cur;
+ } else {
+ cur->right = parent->left;
+ prev->left->parent = cur;
+ }
+ }
+ }
+ }
+
+ /*
+ * Remove mask associated with this node.
+ */
+ for (cur = parent; cur->root == 0; cur = cur->parent) {
+ ipf_rdx_mask_t **pm;
+
+ if (cur->maskbitcount <= found->maskbitcount)
+ break;
+ if (((cur - 1)->addrkey[found->offset] & found->bitmask) !=
+ found->addrkey[found->offset])
+ break;
+ for (pm = &cur->masks; (m = *pm) != NULL; )
+ if (m->node == cur) {
+ *pm = m->next;
+ break;
+ } else {
+ pm = &m->next;
+ }
+ }
+ KFREE(found->mymask);
+
+ /*
+ * Masks that have been brought up to this node from below need to
+ * be sent back down.
+ */
+ for (pmask = &parent->masks; (m = *pmask) != NULL; ) {
+ *pmask = m->next;
+ cur = m->node;
+ if (cur == found)
+ continue;
+ if (found->addrkey[cur->offset] & cur->lastmask) {
+ ipf_rx_attach_mask(parent->right, m);
+ } else if (parent->left != found) {
+ ipf_rx_attach_mask(parent->left, m);
+ }
+ }
+
+ return (found);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_walktree */
+/* Returns: Nil */
+/* Paramters: head(I) - pointer to tree head to search */
+/* walker(I) - function to call for each node in the tree */
+/* arg(I) - parameter to pass to walker, in addition to the */
+/* node pointer */
+/* */
+/* A standard tree walking function except that it is iterative, rather */
+/* than recursive and tracks the next node in case the "walker" function */
+/* should happen to delete and free the current node. It thus goes without */
+/* saying that the "walker" function is not permitted to cause any change */
+/* in the validity of the data found at either the left or right child. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rx_walktree(head, walker, arg)
+ ipf_rdx_head_t *head;
+ radix_walk_func_t walker;
+ void *arg;
+{
+ ipf_rdx_node_t *next;
+ ipf_rdx_node_t *node = head->root;
+ ipf_rdx_node_t *base;
+
+ while (node->index >= 0)
+ node = node->left;
+
+ for (;;) {
+ base = node;
+ while ((node->parent->right == node) && (node->root == 0))
+ node = node->parent;
+
+ for (node = node->parent->right; node->index >= 0; )
+ node = node->left;
+ next = node;
+
+ for (node = base; node != NULL; node = base) {
+ base = node->dupkey;
+ if (node->root == 0)
+ walker(node, arg);
+ }
+ node = next;
+ if (node->root)
+ return;
+ }
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_inithead */
+/* Returns: int - 0 = success, else failure */
+/* Paramters: softr(I) - pointer to radix context */
+/* headp(O) - location for where to store allocated tree head */
+/* */
+/* This function allocates and initialises a radix tree head structure. */
+/* As a traditional radix tree, node 0 is used as the "0" sentinel and node */
+/* "2" is used as the all ones sentinel, leaving node "1" as the root from */
+/* which the tree is hung with node "0" on its left and node "2" to the */
+/* right. The context, "softr", is used here to provide a common source of */
+/* the zeroes and ones data rather than have one per head. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_rx_inithead(softr, headp)
+ radix_softc_t *softr;
+ ipf_rdx_head_t **headp;
+{
+ ipf_rdx_head_t *ptr;
+ ipf_rdx_node_t *node;
+
+ KMALLOC(ptr, ipf_rdx_head_t *);
+ *headp = ptr;
+ if (ptr == NULL)
+ return -1;
+ bzero(ptr, sizeof(*ptr));
+ node = ptr->nodes;
+ ptr->root = node + 1;
+ node[0].index = ADF_OFF_BITS;
+ node[0].index = -1 - node[0].index;
+ node[1].index = ADF_OFF_BITS;
+ node[2].index = node[0].index;
+ node[0].parent = node + 1;
+ node[1].parent = node + 1;
+ node[2].parent = node + 1;
+ node[1].bitmask = htonl(0x80000000);
+ node[0].root = 1;
+ node[1].root = 1;
+ node[2].root = 1;
+ node[0].offset = ADF_OFF_BITS >> 5;
+ node[1].offset = ADF_OFF_BITS >> 5;
+ node[2].offset = ADF_OFF_BITS >> 5;
+ node[1].left = &node[0];
+ node[1].right = &node[2];
+ node[0].addrkey = (u_32_t *)softr->zeros;
+ node[2].addrkey = (u_32_t *)softr->ones;
+#ifdef RDX_DEBUG
+ (void) strcpy(node[0].name, "0_ROOT");
+ (void) strcpy(node[1].name, "1_ROOT");
+ (void) strcpy(node[2].name, "2_ROOT");
+#endif
+
+ ptr->addaddr = ipf_rx_addroute;
+ ptr->deladdr = ipf_rx_delete;
+ ptr->lookup = ipf_rx_lookup;
+ ptr->matchaddr = ipf_rx_match;
+ ptr->walktree = ipf_rx_walktree;
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_freehead */
+/* Returns: Nil */
+/* Paramters: head(I) - pointer to tree head to free */
+/* */
+/* This function simply free's up the radix tree head. Prior to calling */
+/* this function, it is expected that the tree will have been emptied. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rx_freehead(head)
+ ipf_rdx_head_t *head;
+{
+ KFREE(head);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_create */
+/* Parameters: Nil */
+/* */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_rx_create()
+{
+ radix_softc_t *softr;
+
+ KMALLOC(softr, radix_softc_t *);
+ if (softr == NULL)
+ return NULL;
+ bzero((char *)softr, sizeof(*softr));
+
+ KMALLOCS(softr->zeros, u_char *, 3 * sizeof(addrfamily_t));
+ if (softr->zeros == NULL) {
+ KFREE(softr);
+ return (NULL);
+ }
+ softr->ones = softr->zeros + sizeof(addrfamily_t);
+
+ return softr;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_init */
+/* Returns: int - 0 = success (always) */
+/* */
+/* ------------------------------------------------------------------------ */
+int
+ipf_rx_init(ctx)
+ void *ctx;
+{
+ radix_softc_t *softr = ctx;
+
+ memset(softr->zeros, 0, 3 * sizeof(addrfamily_t));
+ memset(softr->ones, 0xff, sizeof(addrfamily_t));
+
+ return (0);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rx_destroy */
+/* Returns: Nil */
+/* */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rx_destroy(ctx)
+ void *ctx;
+{
+ radix_softc_t *softr = ctx;
+
+ if (softr->zeros != NULL)
+ KFREES(softr->zeros, 3 * sizeof(addrfamily_t));
+ KFREE(softr);
+}
+
+/* ====================================================================== */
+
+#ifdef RDX_DEBUG
+/*
+ * To compile this file as a standalone test unit, use -DRDX_DEBUG=1
+ */
+#define NAME(x) ((x)->index < 0 ? (x)->name : (x)->name)
+#define GNAME(y) ((y) == NULL ? "NULL" : NAME(y))
+
+typedef struct myst {
+ struct ipf_rdx_node nodes[2];
+ addrfamily_t dst;
+ addrfamily_t mask;
+ struct myst *next;
+ int printed;
+} myst_t;
+
+typedef struct tabe_s {
+ char *host;
+ char *mask;
+ char *what;
+} tabe_t;
+
+tabe_t builtin[] = {
+#if 1
+ { "192:168:100::0", "48", "d" },
+ { "192:168:100::2", "128", "d" },
+#else
+ { "127.192.0.0", "255.255.255.0", "d" },
+ { "127.128.0.0", "255.255.255.0", "d" },
+ { "127.96.0.0", "255.255.255.0", "d" },
+ { "127.80.0.0", "255.255.255.0", "d" },
+ { "127.72.0.0", "255.255.255.0", "d" },
+ { "127.64.0.0", "255.255.255.0", "d" },
+ { "127.56.0.0", "255.255.255.0", "d" },
+ { "127.48.0.0", "255.255.255.0", "d" },
+ { "127.40.0.0", "255.255.255.0", "d" },
+ { "127.32.0.0", "255.255.255.0", "d" },
+ { "127.24.0.0", "255.255.255.0", "d" },
+ { "127.16.0.0", "255.255.255.0", "d" },
+ { "127.8.0.0", "255.255.255.0", "d" },
+ { "124.0.0.0", "255.0.0.0", "d" },
+ { "125.0.0.0", "255.0.0.0", "d" },
+ { "126.0.0.0", "255.0.0.0", "d" },
+ { "127.0.0.0", "255.0.0.0", "d" },
+ { "10.0.0.0", "255.0.0.0", "d" },
+ { "128.250.0.0", "255.255.0.0", "d" },
+ { "192.168.0.0", "255.255.0.0", "d" },
+ { "192.168.1.0", "255.255.255.0", "d" },
+#endif
+ { NULL, NULL, NULL }
+};
+
+char *mtable[][1] = {
+#if 1
+ { "192:168:100::2" },
+ { "192:168:101::2" },
+#else
+ { "9.0.0.0" },
+ { "9.0.0.1" },
+ { "11.0.0.0" },
+ { "11.0.0.1" },
+ { "127.0.0.1" },
+ { "127.0.1.0" },
+ { "255.255.255.0" },
+ { "126.0.0.1" },
+ { "128.251.0.0" },
+ { "128.251.0.1" },
+ { "128.251.255.255" },
+ { "129.250.0.0" },
+ { "129.250.0.1" },
+ { "192.168.255.255" },
+#endif
+ { NULL }
+};
+
+
+int forder[22] = {
+ 14, 13, 12, 5, 10, 3, 19, 7, 4, 20, 8,
+ 2, 17, 9, 16, 11, 15, 1, 6, 18, 0, 21
+};
+
+static int nodecount = 0;
+myst_t *myst_top = NULL;
+tabe_t *ttable = NULL;
+
+void add_addr(ipf_rdx_head_t *, int , int);
+void checktree(ipf_rdx_head_t *);
+void delete_addr(ipf_rdx_head_t *rnh, int item);
+void dumptree(ipf_rdx_head_t *rnh);
+void nodeprinter(ipf_rdx_node_t *, void *);
+void printroots(ipf_rdx_head_t *);
+void random_add(ipf_rdx_head_t *);
+void random_delete(ipf_rdx_head_t *);
+void test_addr(ipf_rdx_head_t *rnh, int pref, addrfamily_t *, int);
+
+
+static void
+ipf_rx_freenode(node, arg)
+ ipf_rdx_node_t *node;
+ void *arg;
+{
+ ipf_rdx_head_t *head = arg;
+ ipf_rdx_node_t *rv;
+ myst_t *stp;
+
+ stp = (myst_t *)node;
+ rv = ipf_rx_delete(head, &stp->dst, &stp->mask);
+ if (rv != NULL) {
+ free(rv);
+ }
+}
+
+
+const char *
+addrname(ap)
+ addrfamily_t *ap;
+{
+ static char name[80];
+ const char *txt;
+
+ bzero((char *)name, sizeof(name));
+ txt = inet_ntop(ap->adf_family, &ap->adf_addr, name,
+ sizeof(name));
+ return txt;
+}
+
+
+void
+fill6bits(bits, msk)
+ int bits;
+ u_int *msk;
+{
+ if (bits == 0) {
+ msk[0] = 0;
+ msk[1] = 0;
+ msk[2] = 0;
+ msk[3] = 0;
+ return;
+ }
+
+ msk[0] = 0xffffffff;
+ msk[1] = 0xffffffff;
+ msk[2] = 0xffffffff;
+ msk[3] = 0xffffffff;
+
+ if (bits == 128)
+ return;
+ if (bits > 96) {
+ msk[3] = htonl(msk[3] << (128 - bits));
+ } else if (bits > 64) {
+ msk[3] = 0;
+ msk[2] = htonl(msk[2] << (96 - bits));
+ } else if (bits > 32) {
+ msk[3] = 0;
+ msk[2] = 0;
+ msk[1] = htonl(msk[1] << (64 - bits));
+ } else {
+ msk[3] = 0;
+ msk[2] = 0;
+ msk[1] = 0;
+ msk[0] = htonl(msk[0] << (32 - bits));
+ }
+}
+
+
+void
+setaddr(afp, str)
+ addrfamily_t *afp;
+ char *str;
+{
+
+ bzero((char *)afp, sizeof(*afp));
+
+ if (strchr(str, ':') == NULL) {
+ afp->adf_family = AF_INET;
+ afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
+ } else {
+ afp->adf_family = AF_INET6;
+ afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16;
+ }
+ inet_pton(afp->adf_family, str, &afp->adf_addr);
+}
+
+
+void
+setmask(afp, str)
+ addrfamily_t *afp;
+ char *str;
+{
+ if (strchr(str, '.') != NULL) {
+ afp->adf_addr.in4.s_addr = inet_addr(str);
+ afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
+ } else if (afp->adf_family == AF_INET) {
+ afp->adf_addr.i6[0] = htonl(0xffffffff << (32 - atoi(str)));
+ afp->adf_len = offsetof(addrfamily_t, adf_addr) + 4;
+ } else if (afp->adf_family == AF_INET6) {
+ fill6bits(atoi(str), afp->adf_addr.i6);
+ afp->adf_len = offsetof(addrfamily_t, adf_addr) + 16;
+ }
+}
+
+
+void
+nodeprinter(node, arg)
+ ipf_rdx_node_t *node;
+ void *arg;
+{
+ myst_t *stp = (myst_t *)node;
+
+ printf("Node %-9.9s L %-9.9s R %-9.9s P %9.9s/%-9.9s %s/%d\n",
+ node[0].name,
+ GNAME(node[1].left), GNAME(node[1].right),
+ GNAME(node[0].parent), GNAME(node[1].parent),
+ addrname(&stp->dst), node[0].maskbitcount);
+ if (stp->printed == -1)
+ printf("!!! %d\n", stp->printed);
+ else
+ stp->printed = 1;
+}
+
+
+void
+printnode(stp)
+ myst_t *stp;
+{
+ ipf_rdx_node_t *node = &stp->nodes[0];
+
+ if (stp->nodes[0].index > 0)
+ stp = (myst_t *)&stp->nodes[-1];
+
+ printf("Node %-9.9s ", node[0].name);
+ printf("L %-9.9s ", GNAME(node[1].left));
+ printf("R %-9.9s ", GNAME(node[1].right));
+ printf("P %9.9s", GNAME(node[0].parent));
+ printf("/%-9.9s ", GNAME(node[1].parent));
+ printf("%s P%d\n", addrname(&stp->dst), stp->printed);
+}
+
+
+void
+buildtab(void)
+{
+ char line[80], *s;
+ tabe_t *tab;
+ int lines;
+ FILE *fp;
+
+ lines = 0;
+ fp = fopen("hosts", "r");
+
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ s = strchr(line, '\n');
+ if (s != NULL)
+ *s = '\0';
+ lines++;
+ if (lines == 1)
+ tab = malloc(sizeof(*tab) * 2);
+ else
+ tab = realloc(tab, (lines + 1) * sizeof(*tab));
+ tab[lines - 1].host = strdup(line);
+ s = strchr(tab[lines - 1].host, '/');
+ *s++ = '\0';
+ tab[lines - 1].mask = s;
+ tab[lines - 1].what = "d";
+ }
+ fclose(fp);
+
+ tab[lines].host = NULL;
+ tab[lines].mask = NULL;
+ tab[lines].what = NULL;
+ ttable = tab;
+}
+
+
+void
+printroots(rnh)
+ ipf_rdx_head_t *rnh;
+{
+ printf("Root.0.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
+ GNAME(&rnh->nodes[0]),
+ rnh->nodes[0].index, GNAME(rnh->nodes[0].parent),
+ GNAME(rnh->nodes[0].left), GNAME(rnh->nodes[0].right));
+ printf("Root.1.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
+ GNAME(&rnh->nodes[1]),
+ rnh->nodes[1].index, GNAME(rnh->nodes[1].parent),
+ GNAME(rnh->nodes[1].left), GNAME(rnh->nodes[1].right));
+ printf("Root.2.%s b %3d p %-9.9s l %-9.9s r %-9.9s\n",
+ GNAME(&rnh->nodes[2]),
+ rnh->nodes[2].index, GNAME(rnh->nodes[2].parent),
+ GNAME(rnh->nodes[2].left), GNAME(rnh->nodes[2].right));
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ addrfamily_t af;
+ ipf_rdx_head_t *rnh;
+ radix_softc_t *ctx;
+ int j;
+ int i;
+
+ rnh = NULL;
+
+ buildtab();
+ ctx = ipf_rx_create();
+ ipf_rx_init(ctx);
+ ipf_rx_inithead(ctx, &rnh);
+
+ printf("=== ADD-0 ===\n");
+ for (i = 0; ttable[i].host != NULL; i++) {
+ add_addr(rnh, i, i);
+ checktree(rnh);
+ }
+ printroots(rnh);
+ ipf_rx_walktree(rnh, nodeprinter, NULL);
+ printf("=== DELETE-0 ===\n");
+ for (i = 0; ttable[i].host != NULL; i++) {
+ delete_addr(rnh, i);
+ printroots(rnh);
+ ipf_rx_walktree(rnh, nodeprinter, NULL);
+ }
+ printf("=== ADD-1 ===\n");
+ for (i = 0; ttable[i].host != NULL; i++) {
+ setaddr(&af, ttable[i].host);
+ add_addr(rnh, i, i); /*forder[i]); */
+ checktree(rnh);
+ }
+ dumptree(rnh);
+ ipf_rx_walktree(rnh, nodeprinter, NULL);
+ printf("=== TEST-1 ===\n");
+ for (i = 0; ttable[i].host != NULL; i++) {
+ setaddr(&af, ttable[i].host);
+ test_addr(rnh, i, &af, -1);
+ }
+
+ printf("=== TEST-2 ===\n");
+ for (i = 0; mtable[i][0] != NULL; i++) {
+ setaddr(&af, mtable[i][0]);
+ test_addr(rnh, i, &af, -1);
+ }
+ printf("=== DELETE-1 ===\n");
+ for (i = 0; ttable[i].host != NULL; i++) {
+ if (ttable[i].what[0] != 'd')
+ continue;
+ delete_addr(rnh, i);
+ for (j = 0; ttable[j].host != NULL; j++) {
+ setaddr(&af, ttable[j].host);
+ test_addr(rnh, i, &af, 3);
+ }
+ printroots(rnh);
+ ipf_rx_walktree(rnh, nodeprinter, NULL);
+ }
+
+ dumptree(rnh);
+
+ printf("=== ADD-2 ===\n");
+ random_add(rnh);
+ checktree(rnh);
+ dumptree(rnh);
+ ipf_rx_walktree(rnh, nodeprinter, NULL);
+ printf("=== DELETE-2 ===\n");
+ random_delete(rnh);
+ checktree(rnh);
+ dumptree(rnh);
+
+ ipf_rx_walktree(rnh, ipf_rx_freenode, rnh);
+
+ return 0;
+}
+
+
+void
+dumptree(rnh)
+ ipf_rdx_head_t *rnh;
+{
+ myst_t *stp;
+
+ printf("VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n");
+ printroots(rnh);
+ for (stp = myst_top; stp; stp = stp->next)
+ printnode(stp);
+ printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
+}
+
+
+void
+test_addr(rnh, pref, addr, limit)
+ ipf_rdx_head_t *rnh;
+ int pref;
+ addrfamily_t *addr;
+{
+ static int extras[14] = { 0, -1, 1, 3, 5, 8, 9,
+ 15, 16, 19, 255, 256, 65535, 65536
+ };
+ ipf_rdx_node_t *rn;
+ addrfamily_t af;
+ char name[80];
+ myst_t *stp;
+ int i;
+
+ memset(&af, 0, sizeof(af));
+#if 0
+ if (limit < 0 || limit > 14)
+ limit = 14;
+
+ for (i = 0; i < limit; i++) {
+ if (ttable[i].host == NULL)
+ break;
+ setaddr(&af, ttable[i].host);
+ printf("%d.%d.LOOKUP(%s)", pref, i, addrname(&af));
+ rn = ipf_rx_match(rnh, &af);
+ stp = (myst_t *)rn;
+ printf(" = %s (%s/%d)\n", GNAME(rn),
+ rn ? addrname(&stp->dst) : "NULL",
+ rn ? rn->maskbitcount : 0);
+ }
+#else
+ printf("%d.%d.LOOKUP(%s)", pref, -1, addrname(addr));
+ rn = ipf_rx_match(rnh, addr);
+ stp = (myst_t *)rn;
+ printf(" = %s (%s/%d)\n", GNAME(rn),
+ rn ? addrname(&stp->dst) : "NULL", rn ? rn->maskbitcount : 0);
+#endif
+}
+
+
+void
+delete_addr(rnh, item)
+ ipf_rdx_head_t *rnh;
+ int item;
+{
+ ipf_rdx_node_t *rn;
+ addrfamily_t mask;
+ addrfamily_t af;
+ myst_t **pstp;
+ myst_t *stp;
+
+ memset(&af, 0, sizeof(af));
+ memset(&mask, 0, sizeof(mask));
+ setaddr(&af, ttable[item].host);
+ mask.adf_family = af.adf_family;
+ setmask(&mask, ttable[item].mask);
+
+ printf("DELETE(%s)\n", addrname(&af));
+ rn = ipf_rx_delete(rnh, &af, &mask);
+ if (rn == NULL) {
+ printf("FAIL LOOKUP DELETE\n");
+ checktree(rnh);
+ for (stp = myst_top; stp != NULL; stp = stp->next)
+ if (stp->printed != -1)
+ stp->printed = -2;
+ ipf_rx_walktree(rnh, nodeprinter, NULL);
+ dumptree(rnh);
+ abort();
+ }
+ printf("%d.delete(%s) = %s\n", item, addrname(&af), GNAME(rn));
+
+ for (pstp = &myst_top; (stp = *pstp) != NULL; pstp = &stp->next)
+ if (stp == (myst_t *)rn)
+ break;
+ stp->printed = -1;
+ stp->nodes[0].parent = &stp->nodes[0];
+ stp->nodes[1].parent = &stp->nodes[1];
+ *pstp = stp->next;
+ free(stp);
+ nodecount--;
+ checktree(rnh);
+}
+
+
+void
+add_addr(rnh, n, item)
+ ipf_rdx_head_t *rnh;
+ int n, item;
+{
+ ipf_rdx_node_t *rn;
+ myst_t *stp;
+
+ stp = calloc(1, sizeof(*stp));
+ rn = (ipf_rdx_node_t *)stp;
+ setaddr(&stp->dst, ttable[item].host);
+ stp->mask.adf_family = stp->dst.adf_family;
+ setmask(&stp->mask, ttable[item].mask);
+ stp->next = myst_top;
+ myst_top = stp;
+ (void) sprintf(rn[0].name, "_BORN.0");
+ (void) sprintf(rn[1].name, "_BORN.1");
+ rn = ipf_rx_addroute(rnh, &stp->dst, &stp->mask, stp->nodes);
+ (void) sprintf(rn[0].name, "%d_NODE.0", item);
+ (void) sprintf(rn[1].name, "%d_NODE.1", item);
+ printf("ADD %d/%d %s/%s\n", n, item, rn[0].name, rn[1].name);
+ nodecount++;
+ checktree(rnh);
+}
+
+
+void
+checktree(ipf_rdx_head_t *head)
+{
+ myst_t *s1;
+ ipf_rdx_node_t *rn;
+
+ if (nodecount <= 1)
+ return;
+
+ for (s1 = myst_top; s1 != NULL; s1 = s1->next) {
+ int fault = 0;
+ if (s1->printed == -1)
+ continue;
+ rn = &s1->nodes[1];
+ if (rn->right->parent != rn)
+ fault |= 1;
+ if (rn->left->parent != rn)
+ fault |= 2;
+ if (rn->parent->left != rn && rn->parent->right != rn)
+ fault |= 4;
+ if (fault != 0) {
+ printf("FAULT %#x %s\n", fault, rn->name);
+ dumptree(head);
+ ipf_rx_walktree(head, nodeprinter, NULL);
+ fflush(stdout);
+ fflush(stderr);
+ printf("--\n");
+ abort();
+ }
+ }
+}
+
+
+int *
+randomize(int *pnitems)
+{
+ int *order;
+ int nitems;
+ int choice;
+ int j;
+ int i;
+
+ nitems = sizeof(ttable) / sizeof(ttable[0]);
+ *pnitems = nitems;
+ order = calloc(nitems, sizeof(*order));
+ srandom(getpid() * time(NULL));
+ memset(order, 0xff, nitems * sizeof(*order));
+ order[21] = 21;
+ for (i = 0; i < nitems - 1; i++) {
+ do {
+ choice = rand() % (nitems - 1);
+ for (j = 0; j < nitems; j++)
+ if (order[j] == choice)
+ break;
+ } while (j != nitems);
+ order[i] = choice;
+ }
+
+ return order;
+}
+
+
+void
+random_add(rnh)
+ ipf_rdx_head_t *rnh;
+{
+ int *order;
+ int nitems;
+ int i;
+
+ order = randomize(&nitems);
+
+ for (i = 0; i < nitems - 1; i++) {
+ add_addr(rnh, i, order[i]);
+ checktree(rnh);
+ }
+}
+
+
+void
+random_delete(rnh)
+ ipf_rdx_head_t *rnh;
+{
+ int *order;
+ int nitems;
+ int i;
+
+ order = randomize(&nitems);
+
+ for (i = 0; i < nitems - 1; i++) {
+ delete_addr(rnh, i);
+ checktree(rnh);
+ }
+}
+#endif /* RDX_DEBUG */
diff --git a/sys/contrib/ipfilter/netinet/radix_ipf.h b/sys/contrib/ipfilter/netinet/radix_ipf.h
new file mode 100644
index 0000000..73e66b0
--- /dev/null
+++ b/sys/contrib/ipfilter/netinet/radix_ipf.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ */
+#ifndef __RADIX_IPF_H__
+#define __RADIX_IPF_H__
+
+#ifndef U_32_T
+typedef unsigned int u_32_t;
+# define U_32_T 1
+#endif
+
+typedef struct ipf_rdx_mask {
+ struct ipf_rdx_mask *next;
+ struct ipf_rdx_node *node;
+ u_32_t *mask;
+ int maskbitcount;
+} ipf_rdx_mask_t;
+
+typedef struct ipf_rdx_node {
+ struct ipf_rdx_node *left;
+ struct ipf_rdx_node *right;
+ struct ipf_rdx_node *parent;
+ struct ipf_rdx_node *dupkey;
+ struct ipf_rdx_mask *masks;
+ struct ipf_rdx_mask *mymask;
+ u_32_t *addrkey;
+ u_32_t *maskkey;
+ u_32_t *addroff;
+ u_32_t *maskoff;
+ u_32_t lastmask;
+ u_32_t bitmask;
+ int offset;
+ int index;
+ int maskbitcount;
+ int root;
+#ifdef RDX_DEBUG
+ char name[40];
+#endif
+} ipf_rdx_node_t;
+
+struct ipf_rdx_head;
+
+typedef void (* radix_walk_func_t)(ipf_rdx_node_t *, void *);
+typedef ipf_rdx_node_t *(* idx_hamn_func_t)(struct ipf_rdx_head *,
+ addrfamily_t *, addrfamily_t *,
+ ipf_rdx_node_t *);
+typedef ipf_rdx_node_t *(* idx_ham_func_t)(struct ipf_rdx_head *,
+ addrfamily_t *, addrfamily_t *);
+typedef ipf_rdx_node_t *(* idx_ha_func_t)(struct ipf_rdx_head *,
+ addrfamily_t *);
+typedef void (* idx_walk_func_t)(struct ipf_rdx_head *,
+ radix_walk_func_t, void *);
+
+typedef struct ipf_rdx_head {
+ ipf_rdx_node_t *root;
+ ipf_rdx_node_t nodes[3];
+ ipfmutex_t lock;
+ idx_hamn_func_t addaddr; /* add addr/mask to tree */
+ idx_ham_func_t deladdr; /* delete addr/mask from tree */
+ idx_ham_func_t lookup; /* look for specific addr/mask */
+ idx_ha_func_t matchaddr; /* search tree for address match */
+ idx_walk_func_t walktree; /* walk entire tree */
+} ipf_rdx_head_t;
+
+typedef struct radix_softc {
+ u_char *zeros;
+ u_char *ones;
+} radix_softc_t;
+
+#undef RADIX_NODE_HEAD_LOCK
+#undef RADIX_NODE_HEAD_UNLOCK
+#ifdef _KERNEL
+# define RADIX_NODE_HEAD_LOCK(x) MUTEX_ENTER(&(x)->lock)
+# define RADIX_NODE_HEAD_UNLOCK(x) MUTEX_UNLOCK(&(x)->lock)
+#else
+# define RADIX_NODE_HEAD_LOCK(x)
+# define RADIX_NODE_HEAD_UNLOCK(x)
+#endif
+
+extern void *ipf_rx_create __P((void));
+extern int ipf_rx_init __P((void *));
+extern void ipf_rx_destroy __P((void *));
+extern int ipf_rx_inithead __P((radix_softc_t *, ipf_rdx_head_t **));
+extern void ipf_rx_freehead __P((ipf_rdx_head_t *));
+extern ipf_rdx_node_t *ipf_rx_addroute __P((ipf_rdx_head_t *,
+ addrfamily_t *, addrfamily_t *,
+ ipf_rdx_node_t *));
+extern ipf_rdx_node_t *ipf_rx_delete __P((ipf_rdx_head_t *, addrfamily_t *,
+ addrfamily_t *));
+extern void ipf_rx_walktree __P((ipf_rdx_head_t *, radix_walk_func_t,
+ void *));
+
+#endif /* __RADIX_IPF_H__ */
OpenPOWER on IntegriCloud