diff options
Diffstat (limited to 'sys')
43 files changed, 0 insertions, 40513 deletions
diff --git a/sys/contrib/ipfilter/netinet/IPFILTER.LICENCE b/sys/contrib/ipfilter/netinet/IPFILTER.LICENCE deleted file mode 100644 index 41c151c..0000000 --- a/sys/contrib/ipfilter/netinet/IPFILTER.LICENCE +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 1993-2001 by Darren Reed. - * - * The author accepts no responsibility for the use of this software and - * provides it on an ``as is'' basis without express or implied warranty. - * - * Redistribution and use, with or without modification, in source and binary - * forms, are permitted provided that this notice is preserved in its entirety - * and due credit is given to the original author and the contributors. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied, in part or in whole, and put under another distribution licence - * [including the GNU Public Licence.] - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * I hate legalese, don't you ? - */ diff --git a/sys/contrib/ipfilter/netinet/QNX_OCL.txt b/sys/contrib/ipfilter/netinet/QNX_OCL.txt deleted file mode 100644 index 6aa33ea..0000000 --- a/sys/contrib/ipfilter/netinet/QNX_OCL.txt +++ /dev/null @@ -1,275 +0,0 @@ - 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 deleted file mode 100644 index 3183dd1..0000000 --- a/sys/contrib/ipfilter/netinet/fil.c +++ /dev/null @@ -1,7353 +0,0 @@ -/* - * Copyright (C) 1993-2003 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> -#if defined(__NetBSD__) -# if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL) -# if (__NetBSD_Version__ < 399001400) -# 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) -# if !defined(IPFILTER_LKM) -# include "opt_inet6.h" -# endif -# if (__FreeBSD_version == 400019) -# define CSUM_DELAY_DATA -# endif -# endif -# include <sys/filio.h> -#else -# include <sys/ioctl.h> -#endif -#if (defined(__SVR4) || defined(__svr4__)) && defined(sun) -# include <sys/filio.h> -#endif -#if !defined(_AIX51) -# include <sys/fcntl.h> -#endif -#if defined(_KERNEL) -# include <sys/systm.h> -# include <sys/file.h> -#else -# include <stdio.h> -# include <string.h> -# include <stdlib.h> -# include <stddef.h> -# include <sys/file.h> -# define _KERNEL -# ifdef __OpenBSD__ -struct file; -# endif -# include <sys/uio.h> -# undef _KERNEL -#endif -#if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux) && \ - !defined(linux) -# include <sys/mbuf.h> -#else -# if !defined(linux) -# include <sys/byteorder.h> -# endif -# if (SOLARIS2 < 5) && defined(sun) -# include <sys/dditypes.h> -# endif -#endif -#ifdef __hpux -# define _NET_ROUTE_INCLUDED -#endif -#if !defined(linux) -# include <sys/protosw.h> -#endif -#include <sys/socket.h> -#include <net/if.h> -#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> -#endif -#include <netinet/tcp.h> -#if (!defined(__sgi) && !defined(AIX)) || defined(_KERNEL) -# include <netinet/udp.h> -# include <netinet/ip_icmp.h> -#endif -#ifdef __hpux -# undef _NET_ROUTE_INCLUDED -#endif -#ifdef __osf__ -# undef _RADIX_H_ -#endif -#include "netinet/ip_compat.h" -#ifdef USE_INET6 -# include <netinet/icmp6.h> -# if !SOLARIS && defined(_KERNEL) && !defined(__osf__) && !defined(__hpux) -# 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" -#include "netinet/ip_state.h" -#include "netinet/ip_proxy.h" -#include "netinet/ip_auth.h" -#ifdef IPFILTER_SCAN -# include "netinet/ip_scan.h" -#endif -#ifdef IPFILTER_SYNC -# include "netinet/ip_sync.h" -#endif -#include "netinet/ip_pool.h" -#include "netinet/ip_htable.h" -#ifdef IPFILTER_COMPILED -# include "netinet/ip_rules.h" -#endif -#if defined(IPFILTER_BPF) && defined(_KERNEL) -# include <net/bpf.h> -#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 */ - -#if !defined(lint) -static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: fil.c,v 2.243.2.125 2007/10/10 09:27:20 darrenr Exp $"; -#endif - -#ifndef _KERNEL -# include "ipf.h" -# include "ipt.h" -# include "bpf-ipf.h" -extern int opts; -#endif /* _KERNEL */ - - -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 -#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 *)); -#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 *)); - - -/* - * bit values for identifying presence of individual IP options - * All of these tables should be ordered by increasing key value on the left - * 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] = { - { IPOPT_NOP, 0x000001 }, - { IPOPT_RR, 0x000002 }, - { IPOPT_ZSU, 0x000004 }, - { IPOPT_MTUP, 0x000008 }, - { IPOPT_MTUR, 0x000010 }, - { IPOPT_ENCODE, 0x000020 }, - { IPOPT_TS, 0x000040 }, - { IPOPT_TR, 0x000080 }, - { IPOPT_SECURITY, 0x000100 }, - { IPOPT_LSRR, 0x000200 }, - { IPOPT_E_SEC, 0x000400 }, - { IPOPT_CIPSO, 0x000800 }, - { IPOPT_SATID, 0x001000 }, - { IPOPT_SSRR, 0x002000 }, - { IPOPT_ADDEXT, 0x004000 }, - { IPOPT_VISA, 0x008000 }, - { IPOPT_IMITD, 0x010000 }, - { IPOPT_EIP, 0x020000 }, - { IPOPT_FINN, 0x040000 }, - { 0, 0x000000 } -}; - -#ifdef USE_INET6 -struct optlist ip6exthdr[] = { - { IPPROTO_HOPOPTS, 0x000001 }, - { IPPROTO_IPV6, 0x000002 }, - { IPPROTO_ROUTING, 0x000004 }, - { IPPROTO_FRAGMENT, 0x000008 }, - { IPPROTO_ESP, 0x000010 }, - { IPPROTO_AH, 0x000020 }, - { IPPROTO_NONE, 0x000040 }, - { IPPROTO_DSTOPTS, 0x000080 }, - { IPPROTO_MOBILITY, 0x000100 }, - { 0, 0 } -}; -#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] = { - { IPSO_CLASS_RES4, 0x01 }, - { IPSO_CLASS_TOPS, 0x02 }, - { IPSO_CLASS_SECR, 0x04 }, - { IPSO_CLASS_RES3, 0x08 }, - { IPSO_CLASS_CONF, 0x10 }, - { IPSO_CLASS_UNCL, 0x20 }, - { IPSO_CLASS_RES2, 0x40 }, - { IPSO_CLASS_RES1, 0x80 } -}; - - -/* - * 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 }, -#endif - { "", NULL, NULL } -}; - - -/* - * The next section of code is a a collection of small routines that set - * fields in the fr_info_t structure passed based on properties of the - * 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 - * 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 */ -/* Returns: void */ -/* Parameters: fin(I) - pointer to packet information */ -/* */ -/* 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. */ -/* ------------------------------------------------------------------------ */ -static INLINE void frpr_short6(fin, xmin) -fr_info_t *fin; -int xmin; -{ - - if (fin->fin_dlen < xmin) - fin->fin_flx |= FI_SHORT; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_ipv6hdr */ -/* Returns: int - 0 = IPv6 packet intact, -1 = packet lost */ -/* Parameters: fin(I) - pointer to packet information */ -/* */ -/* IPv6 Only */ -/* Copy values from the IPv6 header into the fr_info_t struct and call the */ -/* per-protocol analyzer if it exists. In validating the packet, a protocol*/ -/* 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; -{ - ip6_t *ip6 = (ip6_t *)fin->fin_ip; - int p, go = 1, i, hdrcount; - fr_ip_t *fi = &fin->fin_fi; - - fin->fin_off = 0; - - fi->fi_tos = 0; - fi->fi_optmsk = 0; - fi->fi_secmsk = 0; - fi->fi_auth = 0; - - p = ip6->ip6_nxt; - fi->fi_ttl = ip6->ip6_hlim; - fi->fi_src.in6 = ip6->ip6_src; - fi->fi_dst.in6 = ip6->ip6_dst; - fin->fin_id = (u_short)(ip6->ip6_flow & 0xffff); - - hdrcount = 0; - while (go && !(fin->fin_flx & (FI_BAD|FI_SHORT))) { - switch (p) - { - case IPPROTO_UDP : - frpr_udp6(fin); - go = 0; - break; - - case IPPROTO_TCP : - frpr_tcp6(fin); - go = 0; - break; - - case IPPROTO_ICMPV6 : - frpr_icmp6(fin); - go = 0; - break; - - case IPPROTO_GRE : - frpr_gre6(fin); - go = 0; - break; - - case IPPROTO_HOPOPTS : - p = frpr_hopopts6(fin); - break; - - case IPPROTO_MOBILITY : - p = frpr_mobility6(fin); - break; - - case IPPROTO_DSTOPTS : - p = frpr_dstopts6(fin); - break; - - case IPPROTO_ROUTING : - p = frpr_routing6(fin); - break; - - case IPPROTO_AH : - p = frpr_ah6(fin); - break; - - case IPPROTO_ESP : - frpr_esp6(fin); - go = 0; - break; - - case IPPROTO_IPV6 : - for (i = 0; ip6exthdr[i].ol_bit != 0; i++) - if (ip6exthdr[i].ol_val == p) { - fin->fin_flx |= ip6exthdr[i].ol_bit; - break; - } - go = 0; - break; - - case IPPROTO_NONE : - go = 0; - break; - - case IPPROTO_FRAGMENT : - p = frpr_fragment6(fin); - if (fin->fin_off != 0) - go = 0; - break; - - default : - go = 0; - break; - } - hdrcount++; - - /* - * It is important to note that at this point, for the - * extension headers (go != 0), the entire header may not have - * been pulled up when the code gets to this point. This is - * only done for "go != 0" because the other header handlers - * will all pullup their complete header. The other indicator - * of an incomplete packet is that this was just an extension - * header. - */ - if ((go != 0) && (p != IPPROTO_NONE) && - (frpr_pullup(fin, 0) == -1)) { - p = IPPROTO_NONE; - go = 0; - } - } - fi->fi_p = p; - - /* - * Some of the above functions, like frpr_esp6(), can call fr_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. - */ - if (fin->fin_m == NULL) - return -1; - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_ipv6exthdr */ -/* Returns: int - value of the next header or IPPROTO_NONE if error */ -/* 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; -{ - struct ip6_ext *hdr; - u_short shift; - int i; - - fin->fin_flx |= FI_V6EXTHDR; - - /* 8 is default length of extension hdr */ - if ((fin->fin_dlen - 8) < 0) { - fin->fin_flx |= FI_SHORT; - return IPPROTO_NONE; - } - - if (frpr_pullup(fin, 8) == -1) - return IPPROTO_NONE; - - hdr = fin->fin_dp; - switch (proto) - { - case IPPROTO_FRAGMENT : - shift = 8; - break; - default : - shift = 8 + (hdr->ip6e_len << 3); - break; - } - - if (shift > fin->fin_dlen) { /* Nasty extension header length? */ - fin->fin_flx |= FI_BAD; - return IPPROTO_NONE; - } - - for (i = 0; ip6exthdr[i].ol_bit != 0; i++) - if (ip6exthdr[i].ol_val == proto) { - /* - * Most IPv6 extension headers are only allowed once. - */ - if ((multiple == 0) && - ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0)) - fin->fin_flx |= FI_BAD; - else - fin->fin_optmsk |= ip6exthdr[i].ol_bit; - break; - } - - fin->fin_exthdr = fin->fin_dp; - fin->fin_dp = (char *)fin->fin_dp + shift; - fin->fin_dlen -= shift; - - return hdr->ip6e_nxt; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_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; -{ - return frpr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_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; -{ - return frpr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_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; -{ - struct ip6_ext *hdr; - - if (frpr_ipv6exthdr(fin, 0, IPPROTO_ROUTING) == IPPROTO_NONE) - 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; - /* - * Compensate for the changes made in frpr_ipv6exthdr() - */ - fin->fin_dlen += 8 + (hdr->ip6e_len << 3); - fin->fin_dp = hdr; - return IPPROTO_NONE; - } - - return hdr->ip6e_nxt; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_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; -{ - 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) - 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; - } - - 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); - - return frag->ip6f_nxt; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_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; -{ - return frpr_ipv6exthdr(fin, 1, IPPROTO_DSTOPTS); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_icmp6 */ -/* Returns: void */ -/* Parameters: fin(I) - pointer to packet information */ -/* */ -/* IPv6 Only */ -/* 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; -{ - int minicmpsz = sizeof(struct icmp6_hdr); - struct icmp6_hdr *icmp6; - - if (frpr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) - return; - - if (fin->fin_dlen > 1) { - ip6_t *ip6; - - icmp6 = fin->fin_dp; - - fin->fin_data[0] = *(u_short *)icmp6; - - switch (icmp6->icmp6_type) - { - case ICMP6_ECHO_REPLY : - case ICMP6_ECHO_REQUEST : - minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t); - break; - case ICMP6_DST_UNREACH : - case ICMP6_PACKET_TOO_BIG : - case ICMP6_TIME_EXCEEDED : - case ICMP6_PARAM_PROB : - fin->fin_flx |= FI_ICMPERR; - minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t); - if (fin->fin_plen < ICMP6ERR_IPICMPHLEN) - break; - - if (M_LEN(fin->fin_m) < fin->fin_plen) { - if (fr_coalesce(fin) != 1) - return; - } - - /* - * If the destination of this packet doesn't match the - * source of the original packet then this packet is - * not correct. - */ - icmp6 = fin->fin_dp; - ip6 = (ip6_t *)((char *)icmp6 + ICMPERR_ICMPHLEN); - 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); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_udp6 */ -/* Returns: void */ -/* Parameters: fin(I) - pointer to packet information */ -/* */ -/* IPv6 Only */ -/* 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; -{ - - frpr_short6(fin, sizeof(struct udphdr)); - - if (frpr_udpcommon(fin) == 0) { - u_char p = fin->fin_p; - - fin->fin_p = IPPROTO_UDP; - fr_checkv6sum(fin); - fin->fin_p = p; - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_tcp6 */ -/* Returns: void */ -/* Parameters: fin(I) - pointer to packet information */ -/* */ -/* IPv6 Only */ -/* 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; -{ - - frpr_short6(fin, sizeof(struct tcphdr)); - - if (frpr_tcpcommon(fin) == 0) { - u_char p = fin->fin_p; - - fin->fin_p = IPPROTO_TCP; - fr_checkv6sum(fin); - fin->fin_p = p; - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_esp6 */ -/* Returns: void */ -/* Parameters: fin(I) - pointer to packet information */ -/* */ -/* IPv6 Only */ -/* Analyse the packet for ESP properties. */ -/* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ -/* even though the newer ESP packets must also have a sequence number that */ -/* 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; -{ - - frpr_short6(fin, sizeof(grehdr_t)); - - (void) frpr_pullup(fin, 8); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_ah6 */ -/* Returns: void */ -/* Parameters: fin(I) - pointer to packet information */ -/* */ -/* IPv6 Only */ -/* 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 int frpr_ah6(fin) -fr_info_t *fin; -{ - authhdr_t *ah; - - frpr_short6(fin, 12); - - if (frpr_pullup(fin, sizeof(*ah)) == -1) - return IPPROTO_NONE; - - ah = (authhdr_t *)fin->fin_dp; - return ah->ah_next; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_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; -{ - grehdr_t *gre; - - frpr_short6(fin, sizeof(grehdr_t)); - - if (frpr_pullup(fin, sizeof(grehdr_t)) == -1) - return; - - gre = fin->fin_dp; - if (GRE_REV(gre->gr_flags) == 1) - fin->fin_data[0] = gre->gr_call; -} -#endif /* USE_INET6 */ - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_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, */ -/* consecutively in the packet buffer. */ -/* */ -/* This function pulls up 'extra' data at the location of fin_dp. fin_dp */ -/* points to the first byte after the complete layer 3 header, which will */ -/* include all of the known extension headers for IPv6 or options for IPv4. */ -/* */ -/* Since fr_pullup() expects the total length of bytes to be pulled up, it */ -/* 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; -{ - 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 defined(_KERNEL) - if (fr_pullup(fin->fin_m, fin, plen) == NULL) - return -1; -#else - /* - * Fake fr_pullup failing - */ - *fin->fin_mp = NULL; - fin->fin_m = NULL; - fin->fin_ip = NULL; - return -1; -#endif - } - } - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_short */ -/* Returns: void */ -/* Parameters: fin(I) - pointer to packet information */ -/* xmin(I) - minimum header size */ -/* */ -/* Check if a packet is "short" as defined by xmin. The rule we are */ -/* applying here is that the packet must not be fragmented within the layer */ -/* 4 header. That is, it must not be a fragment that has its offset set to */ -/* 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; -{ - - if (fin->fin_off == 0) { - if (fin->fin_dlen < xmin) - fin->fin_flx |= FI_SHORT; - } else if (fin->fin_off < xmin) { - fin->fin_flx |= FI_SHORT; - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_icmp */ -/* Returns: void */ -/* Parameters: fin(I) - pointer to packet information */ -/* */ -/* IPv4 Only */ -/* Do a sanity check on the packet for ICMP (v4). In nearly all cases, */ -/* except extrememly bad packets, both type and code will be present. */ -/* The expected minimum size of an ICMP packet is very much dependent on */ -/* the type of it. */ -/* */ -/* XXX - other ICMP sanity checks? */ -/* ------------------------------------------------------------------------ */ -static INLINE void frpr_icmp(fin) -fr_info_t *fin; -{ - int minicmpsz = sizeof(struct icmp); - icmphdr_t *icmp; - ip_t *oip; - - if (fin->fin_off != 0) { - frpr_short(fin, ICMPERR_ICMPHLEN); - return; - } - - if (frpr_pullup(fin, ICMPERR_ICMPHLEN) == -1) - return; - - if (fin->fin_dlen > 1) { - icmp = fin->fin_dp; - - fin->fin_data[0] = *(u_short *)icmp; - - 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 : - minicmpsz = ICMP_MINLEN; - break; - /* - * type(1) + code(1) + cksum(2) + id(2) seq(2) + - * 3 * timestamp(3 * 4) - */ - 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; - /* - * 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 < 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; - } - } - - frpr_short(fin, minicmpsz); - - if ((fin->fin_flx & FI_FRAG) == 0) - fr_checkv4sum(fin); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_tcpcommon */ -/* Returns: int - 0 = header ok, 1 = bad packet, -1 = buffer error */ -/* Parameters: fin(I) - pointer to packet information */ -/* */ -/* TCP header sanity checking. Look for bad combinations of TCP flags, */ -/* and make some checks with how they interact with other fields. */ -/* 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; -{ - int flags, tlen; - tcphdr_t *tcp; - - fin->fin_flx |= FI_TCPUDP; - if (fin->fin_off != 0) - return 0; - - if (frpr_pullup(fin, sizeof(*tcp)) == -1) - return -1; - 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) - return 1; - - /* - * Use of the TCP data offset *must* result in a value that is at - * least the same size as the TCP header. - */ - tlen = TCP_OFF(tcp) << 2; - if (tlen < sizeof(tcphdr_t)) { - fin->fin_flx |= FI_BAD; - return 1; - } - - flags = tcp->th_flags; - fin->fin_tcpf = tcp->th_flags; - - /* - * If the urgent flag is set, then the urgent pointer must - * also be set and vice versa. Good TCP packets do not have - * just one of these set. - */ - if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) { - fin->fin_flx |= FI_BAD; -#if 0 - } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) { - /* - * Ignore this case (#if 0) as it shows up in "real" - * traffic with bogus values in the urgent pointer field. - */ - fin->fin_flx |= FI_BAD; -#endif - } else if (((flags & (TH_SYN|TH_FIN)) != 0) && - ((flags & (TH_RST|TH_ACK)) == TH_RST)) { - /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */ - fin->fin_flx |= FI_BAD; -#if 1 - } else if (((flags & TH_SYN) != 0) && - ((flags & (TH_URG|TH_PUSH)) != 0)) { - /* - * SYN with URG and PUSH set is not for normal TCP but it is - * possible(?) with T/TCP...but who uses T/TCP? - */ - fin->fin_flx |= FI_BAD; -#endif - } else if (!(flags & TH_ACK)) { - /* - * If the ack bit isn't set, then either the SYN or - * RST bit must be set. If the SYN bit is set, then - * we expect the ACK field to be 0. If the ACK is - * not set and if URG, PSH or FIN are set, consdier - * that to indicate a bad TCP packet. - */ - if ((flags == TH_SYN) && (tcp->th_ack != 0)) { - /* - * Cisco PIX sets the ACK field to a random value. - * In light of this, do not set FI_BAD until a patch - * is available from Cisco to ensure that - * interoperability between existing systems is - * achieved. - */ - /*fin->fin_flx |= FI_BAD*/; - } else if (!(flags & (TH_RST|TH_SYN))) { - fin->fin_flx |= FI_BAD; - } else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) { - fin->fin_flx |= FI_BAD; - } - } - - /* - * At this point, it's not exactly clear what is to be gained by - * marking up which TCP options are and are not present. The one we - * are most interested in is the TCP window scale. This is only in - * a SYN packet [RFC1323] so we don't need this here...? - * 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)) - return 0; - - if (frpr_pullup(fin, tlen) == -1) - return -1; - -#if 0 - tcp = fin->fin_dp; - ip = fin->fin_ip; - s = (u_char *)(tcp + 1); - off = IP_HL(ip) << 2; -# ifdef _KERNEL - if (fin->fin_mp != NULL) { - mb_t *m = *fin->fin_mp; - - if (off + tlen > M_LEN(m)) - return; - } -# endif - for (tlen -= (int)sizeof(*tcp); tlen > 0; ) { - opt = *s; - if (opt == '\0') - break; - else if (opt == TCPOPT_NOP) - ol = 1; - else { - if (tlen < 2) - break; - ol = (int)*(s + 1); - if (ol < 2 || ol > tlen) - break; - } - - for (i = 9, mv = 4; mv >= 0; ) { - op = ipopts + i; - if (opt == (u_char)op->ol_val) { - optmsk |= op->ol_bit; - break; - } - } - tlen -= ol; - s += ol; - } -#endif /* 0 */ - - return 0; -} - - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_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; -{ - udphdr_t *udp; - - fin->fin_flx |= FI_TCPUDP; - - if (!fin->fin_off && (fin->fin_dlen > 3)) { - if (frpr_pullup(fin, sizeof(*udp)) == -1) { - fin->fin_flx |= FI_SHORT; - return 1; - } - - udp = fin->fin_dp; - - fin->fin_sport = ntohs(udp->uh_sport); - fin->fin_dport = ntohs(udp->uh_dport); - } - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_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; -{ - - frpr_short(fin, sizeof(tcphdr_t)); - - if (frpr_tcpcommon(fin) == 0) { - if ((fin->fin_flx & FI_FRAG) == 0) - fr_checkv4sum(fin); - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_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; -{ - - frpr_short(fin, sizeof(udphdr_t)); - - if (frpr_udpcommon(fin) == 0) { - if ((fin->fin_flx & FI_FRAG) == 0) - fr_checkv4sum(fin); - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_esp */ -/* Returns: void */ -/* Parameters: fin(I) - pointer to packet information */ -/* */ -/* Analyse the packet for ESP properties. */ -/* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ -/* even though the newer ESP packets must also have a sequence number that */ -/* 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; -{ - - if (fin->fin_off == 0) { - frpr_short(fin, 8); - (void) frpr_pullup(fin, 8); - } - -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_ah */ -/* Returns: void */ -/* 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; -{ - authhdr_t *ah; - int len; - - frpr_short(fin, sizeof(*ah)); - - if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0)) - return; - - if (frpr_pullup(fin, sizeof(*ah)) == -1) - return; - - ah = (authhdr_t *)fin->fin_dp; - - len = (ah->ah_plen + 2) << 2; - frpr_short(fin, len); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_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; -{ - grehdr_t *gre; - - frpr_short(fin, sizeof(*gre)); - - if (fin->fin_off != 0) - return; - - if (frpr_pullup(fin, sizeof(*gre)) == -1) - return; - - if (fin->fin_off == 0) { - gre = fin->fin_dp; - if (GRE_REV(gre->gr_flags) == 1) - fin->fin_data[0] = gre->gr_call; - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frpr_ipv4hdr */ -/* Returns: void */ -/* Parameters: fin(I) - pointer to packet information */ -/* */ -/* IPv4 Only */ -/* 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; -{ - u_short optmsk = 0, secmsk = 0, auth = 0; - int hlen, ol, mv, p, i; - const struct optlist *op; - u_char *s, opt; - u_short off; - fr_ip_t *fi; - ip_t *ip; - - fi = &fin->fin_fi; - hlen = fin->fin_hlen; - - ip = fin->fin_ip; - p = ip->ip_p; - fi->fi_p = p; - fi->fi_tos = ip->ip_tos; - fin->fin_id = ip->ip_id; - off = 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; - fi->fi_src.i6[2] = 0; - fi->fi_src.i6[3] = 0; - fi->fi_dst.i6[1] = 0; - fi->fi_dst.i6[2] = 0; - fi->fi_dst.i6[3] = 0; - - fi->fi_saddr = ip->ip_src.s_addr; - fi->fi_daddr = ip->ip_dst.s_addr; - - /* - * set packet attribute flags based on the offset and - * calculate the byte offset that it represents. - */ - off &= IP_MF|IP_OFFMASK; - if (off != 0) { - int morefrag = off & IP_MF; - - fi->fi_flx |= FI_FRAG; - off &= IP_OFFMASK; - if (off != 0) { - fin->fin_flx |= FI_FRAGBODY; - off <<= 3; - 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 - * length of an IP packet is only 16 bits. - * - * Any fragment that isn't the last fragment - * must have a length greater than 0 and it - * must be an even multiple of 8. - */ - fi->fi_flx |= FI_BAD; - } - } - } - fin->fin_off = off; - - /* - * Call per-protocol setup and checking - */ - switch (p) - { - case IPPROTO_UDP : - frpr_udp(fin); - break; - case IPPROTO_TCP : - frpr_tcp(fin); - break; - case IPPROTO_ICMP : - frpr_icmp(fin); - break; - case IPPROTO_AH : - frpr_ah(fin); - break; - case IPPROTO_ESP : - frpr_esp(fin); - break; - case IPPROTO_GRE : - frpr_gre(fin); - break; - } - - ip = fin->fin_ip; - if (ip == NULL) - return; - - /* - * If it is a standard IP header (no options), set the flag fields - * which relate to options to 0. - */ - if (hlen == sizeof(*ip)) { - fi->fi_optmsk = 0; - fi->fi_secmsk = 0; - fi->fi_auth = 0; - return; - } - - /* - * So the IP header has some IP options attached. Walk the entire - * list of options present with this packet and set flags to indicate - * which ones are here and which ones are not. For the somewhat out - * of date and obscure security classification options, set a flag to - * represent which classification is present. - */ - fi->fi_flx |= FI_OPTIONS; - - for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) { - opt = *s; - if (opt == '\0') - break; - else if (opt == IPOPT_NOP) - ol = 1; - else { - if (hlen < 2) - break; - ol = (int)*(s + 1); - if (ol < 2 || ol > hlen) - break; - } - for (i = 9, mv = 4; mv >= 0; ) { - op = ipopts + i; - if ((opt == (u_char)op->ol_val) && (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--; - } - } - break; - } - if (opt < op->ol_val) - i -= mv; - else - i += mv; - mv--; - } - hlen -= ol; - s += ol; - } - - /* - * - */ - if (auth && !(auth & 0x0100)) - auth &= 0xff00; - fi->fi_optmsk = optmsk; - fi->fi_secmsk = secmsk; - fi->fi_auth = auth; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_makefrip */ -/* Returns: void */ -/* Parameters: hlen(I) - length of IP packet header */ -/* ip(I) - pointer to the IP header */ -/* fin(IO) - pointer to packet information */ -/* */ -/* Compact the IP header into a structure which contains just the info. */ -/* which is useful for comparing IP headers with and store this information */ -/* 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 v; - - fin->fin_nat = NULL; - fin->fin_state = NULL; - fin->fin_depth = 0; - fin->fin_hlen = (u_short)hlen; - fin->fin_ip = ip; - fin->fin_rule = 0xffffffff; - fin->fin_group[0] = -1; - fin->fin_group[1] = '\0'; - fin->fin_dp = (char *)ip + hlen; - - v = fin->fin_v; - if (v == 4) { - fin->fin_plen = ip->ip_len; - fin->fin_dlen = fin->fin_plen - hlen; - - frpr_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; -#endif - } - if (fin->fin_ip == NULL) - return -1; - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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 */ -/* */ -/* 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; -{ - u_short tup, po; - int err = 1; - - tup = *pop; - po = frp->frp_port; - - /* - * Do opposite test to that required and continue if that succeeds. - */ - switch (frp->frp_cmp) - { - case FR_EQUAL : - if (tup != po) /* EQUAL */ - err = 0; - break; - case FR_NEQUAL : - if (tup == po) /* NOTEQUAL */ - err = 0; - break; - case FR_LESST : - if (tup >= po) /* LESSTHAN */ - err = 0; - break; - case FR_GREATERT : - if (tup <= po) /* GREATERTHAN */ - err = 0; - break; - case FR_LESSTE : - if (tup > po) /* LT or EQ */ - err = 0; - break; - case FR_GREATERTE : - if (tup < po) /* GT or EQ */ - err = 0; - break; - case FR_OUTRANGE : - if (tup >= po && tup <= frp->frp_top) /* Out of range */ - err = 0; - break; - case FR_INRANGE : - if (tup <= po || tup >= frp->frp_top) /* In range */ - err = 0; - break; - case FR_INCRANGE : - if (tup < po || tup > frp->frp_top) /* Inclusive range */ - err = 0; - break; - default : - break; - } - return err; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_tcpudpchk */ -/* Returns: int - 1 == protocol matched, 0 == check failed */ -/* Parameters: fin(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 err = 1; - - /* - * Both ports should *always* be in the first fragment. - * So far, I cannot find any cases where they can not be. - * - * compare destination ports - */ - if (ft->ftu_dcmp) - err = fr_portcheck(&ft->ftu_dst, &fin->fin_dport); - - /* - * compare source ports - */ - if (err && ft->ftu_scmp) - err = fr_portcheck(&ft->ftu_src, &fin->fin_sport); - - /* - * If we don't have all the TCP/UDP header, then how can we - * expect to do any sort of match on it ? If we were looking for - * 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) - 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_tcpfm, ft->ftu_tcpf)); - err = 0; - } - } - return err; -} - - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_ipfcheck */ -/* Returns: int - 0 == match, 1 == no match */ -/* Parameters: fin(I) - pointer to packet information */ -/* fr(I) - pointer to filter rule */ -/* portcmp(I) - flag indicating whether to attempt matching on */ -/* TCP/UDP port data. */ -/* */ -/* Check to see if a packet matches an IPFilter rule. Checks of addresses, */ -/* 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; -{ - u_32_t *ld, *lm, *lip; - fripf_t *fri; - fr_ip_t *fi; - int i; - - fi = &fin->fin_fi; - fri = fr->fr_ipf; - lip = (u_32_t *)fi; - lm = (u_32_t *)&fri->fri_mip; - ld = (u_32_t *)&fri->fri_ip; - - /* - * first 32 bits to check coversion: - * IP version, TOS, TTL, protocol - */ - i = ((*lip & *lm) != *ld); - FR_DEBUG(("0. %#08x & %#08x != %#08x\n", - ntohl(*lip), ntohl(*lm), ntohl(*ld))); - if (i) - return 1; - - /* - * Next 32 bits is a constructed bitmask indicating which IP options - * are present (if any) in this packet. - */ - lip++, lm++, ld++; - i |= ((*lip & *lm) != *ld); - FR_DEBUG(("1. %#08x & %#08x != %#08x\n", - ntohl(*lip), ntohl(*lm), ntohl(*ld))); - if (i) - return 1; - - lip++, lm++, ld++; - /* - * Unrolled loops (4 each, for 32 bits) for address checks. - */ - /* - * Check the source address. - */ -#ifdef IPFILTER_LOOKUP - if (fr->fr_satype == FRI_LOOKUP) { - i = (*fr->fr_srcfunc)(fr->fr_srcptr, fi->fi_v, lip); - 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))); - if (fi->fi_v == 6) { - lip++, lm++, ld++; - i |= ((*lip & *lm) != *ld); - FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", - ntohl(*lip), ntohl(*lm), ntohl(*ld))); - lip++, lm++, ld++; - i |= ((*lip & *lm) != *ld); - FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", - ntohl(*lip), ntohl(*lm), ntohl(*ld))); - lip++, lm++, ld++; - i |= ((*lip & *lm) != *ld); - FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", - ntohl(*lip), ntohl(*lm), ntohl(*ld))); - } else { - lip += 3; - lm += 3; - ld += 3; - } -#ifdef IPFILTER_LOOKUP - } -#endif - i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6; - if (i) - 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); - 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))); - if (fi->fi_v == 6) { - lip++, lm++, ld++; - i |= ((*lip & *lm) != *ld); - FR_DEBUG(("3b. %#08x & %#08x != %#08x\n", - ntohl(*lip), ntohl(*lm), ntohl(*ld))); - lip++, lm++, ld++; - i |= ((*lip & *lm) != *ld); - FR_DEBUG(("3c. %#08x & %#08x != %#08x\n", - ntohl(*lip), ntohl(*lm), ntohl(*ld))); - lip++, lm++, ld++; - i |= ((*lip & *lm) != *ld); - FR_DEBUG(("3d. %#08x & %#08x != %#08x\n", - ntohl(*lip), ntohl(*lm), ntohl(*ld))); - } else { - lip += 3; - lm += 3; - ld += 3; - } -#ifdef IPFILTER_LOOKUP - } -#endif - i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7; - if (i) - 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)); - - /* - * 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)); - - if (i == 0) { - /* - * If a fragment, then only the first has what we're - * looking for here... - */ - if (portcmp) { - if (!fr_tcpudpchk(fin, &fr->fr_tuc)) - i = 1; - } else { - if (fr->fr_dcmp || fr->fr_scmp || - fr->fr_tcpf || fr->fr_tcpfm) - i = 1; - if (fr->fr_icmpm || fr->fr_icmp) { - if (((fi->fi_p != IPPROTO_ICMP) && - (fi->fi_p != IPPROTO_ICMPV6)) || - fin->fin_off || (fin->fin_dlen < 2)) - i = 1; - else if ((fin->fin_data[0] & fr->fr_icmpm) != - fr->fr_icmp) { - FR_DEBUG(("i. %#x & %#x != %#x\n", - fin->fin_data[0], - fr->fr_icmpm, fr->fr_icmp)); - i = 1; - } - } - } - } - return i; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_scanlist */ -/* Returns: int - result flags of scanning filter list */ -/* Parameters: fin(I) - pointer to packet information */ -/* pass(I) - default result to return for filtering */ -/* */ -/* Check the input/output list of rules for a match to the current packet. */ -/* If a match is found, the value of fr_flags from the rule becomes the */ -/* return value and fin->fin_fr points to the matched rule. */ -/* */ -/* This function may be called recusively upto 16 times (limit inbuilt.) */ -/* When unwinding, it should finish up with fin_depth as 0. */ -/* */ -/* 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 rulen, portcmp, off, skip; - struct frentry *fr, *fnext; - u_32_t passt, passo; - - /* - * Do not allow nesting deeper than 16 levels. - */ - if (fin->fin_depth >= 16) - return pass; - - fr = fin->fin_fr; - - /* - * If there are no rules in this list, return now. - */ - if (fr == NULL) - return pass; - - skip = 0; - portcmp = 0; - fin->fin_depth++; - fin->fin_fr = NULL; - off = fin->fin_off; - - if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) - portcmp = 1; - - for (rulen = 0; fr; fr = fnext, rulen++) { - fnext = fr->fr_next; - if (skip != 0) { - FR_VERBOSE(("%d (%#x)\n", skip, fr->fr_flags)); - skip--; - continue; - } - - /* - * In all checks below, a null (zero) value in the - * filter struture is taken to mean a wildcard. - * - * check that we are working for the right interface - */ -#ifdef _KERNEL - if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) - continue; -#else - if (opts & (OPT_VERBOSE|OPT_DEBUG)) - printf("\n"); - FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' : - FR_ISPASS(pass) ? 'p' : - FR_ISACCOUNT(pass) ? 'A' : - FR_ISAUTH(pass) ? 'a' : - (pass & FR_NOMATCH) ? 'n' :'b')); - if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) - continue; - FR_VERBOSE((":i")); -#endif - - switch (fr->fr_type) - { - case FR_T_IPF : - case FR_T_IPF|FR_T_BUILTIN : - if (fr_ipfcheck(fin, fr, portcmp)) - continue; - break; -#if defined(IPFILTER_BPF) - case FR_T_BPFOPC : - case FR_T_BPFOPC|FR_T_BUILTIN : - { - u_char *mc; - - if (*fin->fin_mp == NULL) - continue; - if (fin->fin_v != fr->fr_v) - continue; - mc = (u_char *)fin->fin_m; - if (!bpf_filter(fr->fr_data, mc, fin->fin_plen, 0)) - continue; - break; - } -#endif - case FR_T_CALLFUNC|FR_T_BUILTIN : - { - frentry_t *f; - - f = (*fr->fr_func)(fin, &pass); - if (f != NULL) - fr = f; - else - continue; - break; - } - default : - break; - } - - 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) - continue; - } - FR_VERBOSE(("=%s.%d *", 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 - * it, except for increasing the hit counter. - */ - if ((passt & FR_CALLNOW) != 0) { - frentry_t *frs; - - ATOMIC_INC64(fr->fr_hits); - if ((fr->fr_func != NULL) && - (fr->fr_func == (ipfunc_t)-1)) - continue; - - frs = fin->fin_fr; - fin->fin_fr = fr; - fr = (*fr->fr_func)(fin, &passt); - if (fr == NULL) { - fin->fin_fr = frs; - continue; - } - passt = fr->fr_flags; - } - fin->fin_fr = fr; - -#ifdef IPFILTER_LOG - /* - * Just log this packet... - */ - if ((passt & FR_LOGMASK) == FR_LOG) { - if (ipflog(fin, passt) == -1) { - if (passt & FR_LOGORBLOCK) { - passt &= ~FR_CMDMASK; - passt |= FR_BLOCK|FR_QUICK; - } - ATOMIC_INCL(frstats[fin->fin_out].fr_skip); - } - ATOMIC_INCL(frstats[fin->fin_out].fr_pkl); - fin->fin_flx |= FI_DONTCACHE; - } -#endif /* IPFILTER_LOG */ - fr->fr_bytes += (U_QUAD_T)fin->fin_plen; - passo = pass; - if (FR_ISSKIP(passt)) - skip = fr->fr_arg; - else if ((passt & FR_LOGMASK) != FR_LOG) - 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 (fin->fin_fr == NULL) { - fin->fin_rule = rulen; - (void) strncpy(fin->fin_group, fr->fr_group, - FR_GROUPLEN); - fin->fin_fr = fr; - passt = pass; - } - pass = passt; - } - - if (passt & FR_QUICK) { - /* - * Finally, if we've asked to track state for this - * packet, set it up. Add state for "quick" rules - * here so that if the action fails we can consider - * the rule to "not match" and keep on processing - * filter rules. - */ - if ((pass & FR_KEEPSTATE) && - !(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); - } else { - ATOMIC_INCL(frstats[out].fr_bads); - pass = passo; - continue; - } - } - break; - } - } - fin->fin_depth--; - return pass; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_acctpkt */ -/* Returns: frentry_t* - always returns NULL */ -/* Parameters: fin(I) - pointer to packet information */ -/* passp(IO) - pointer to current/new filter decision (unused) */ -/* */ -/* Checks a packet against accounting rules, if there are any for the given */ -/* 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(). */ -/* ------------------------------------------------------------------------ */ -frentry_t *fr_acctpkt(fin, passp) -fr_info_t *fin; -u_32_t *passp; -{ - 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]; - - 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); - if (FR_ISACCOUNT(pass)) { - ATOMIC_INCL(frstats[0].fr_acct); - } - fin->fin_fr = frsave; - bcopy(group, fin->fin_group, FR_GROUPLEN); - fin->fin_rule = rulen; - } - return NULL; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_firewall */ -/* Returns: frentry_t* - returns pointer to matched rule, if no matches */ -/* were found, returns NULL. */ -/* Parameters: fin(I) - pointer to packet information */ -/* passp(IO) - pointer to current/new filter decision (unused) */ -/* */ -/* Applies an appropriate set of firewall rules to the packet, to see if */ -/* there are any matches. The first check is to see if a match can be seen */ -/* in the cache. If not, then search an appropriate list of rules. Once a */ -/* 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; -{ - frentry_t *fr; - fr_info_t *fc; - u_32_t pass; - int out; - - out = fin->fin_out; - 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. - */ - 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); - -#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; - } - - /* - * 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); - pass |= FR_BLOCK; - ATOMIC_INCL(frstats[out].fr_ppshit); - } - - /* - * If we fail to add a packet to the authorization queue, then we - * drop the packet later. However, if it was added then pretend - * we've dropped it already. - */ - if (FR_ISAUTH(pass)) { - if (fr_newauth(fin->fin_m, fin) != 0) { -#ifdef _KERNEL - if ((pass & FR_RETMASK) == 0) - fin->fin_m = *fin->fin_mp = NULL; -#else - ; -#endif - fin->fin_error = 0; - } else - fin->fin_error = ENOSPC; - } - - if ((fr != NULL) && (fr->fr_func != NULL) && - (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW)) - (void) (*fr->fr_func)(fin, &pass); - - /* - * If a rule is a pre-auth rule, check again in the list of rules - * loaded for authenticated use. It does not particulary matter - * if this search fails because a "preauth" result, from a rule, - * 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); - } - - /* - * If the rule has "keep frag" and the packet is actually a fragment, - * then create a fragment state entry. - */ - 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); - } else { - ATOMIC_INCL(frstats[out].fr_nfr); - } - } else { - ATOMIC_INCL(frstats[out].fr_cfr); - } - } - - fr = fin->fin_fr; - - if (passp != NULL) - *passp = pass; - - return fr; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_check */ -/* Returns: int - 0 == packet allowed through, */ -/* User space: */ -/* -1 == packet blocked */ -/* 1 == packet not matched */ -/* -2 == requires authentication */ -/* Kernel: */ -/* > 0 == filter error # for packet */ -/* Parameters: ip(I) - pointer to start of IPv4/6 packet */ -/* hlen(I) - length of header */ -/* ifp(I) - pointer to interface this packet is on */ -/* out(I) - 0 == packet going in, 1 == packet going out */ -/* mp(IO) - pointer to caller's buffer pointer that holds this */ -/* IP packet. */ -/* Solaris & HP-UX ONLY : */ -/* qpi(I) - pointer to STREAMS queue information for this */ -/* interface & direction. */ -/* */ -/* fr_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 */ -/* directed by firewall rules and of course whether or not to allow the */ -/* packet to be further processed by the kernel. */ -/* */ -/* For packets blocked, the contents of "mp" will be NULL'd and the buffer */ -/* 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 -#if defined(_KERNEL) && defined(MENTAT) -, qif, mp) -void *qif; -#else -, mp) -#endif -mb_t **mp; -ip_t *ip; -int hlen; -void *ifp; -int out; -{ - /* - * The above really sucks, but short of writing a diff - */ - fr_info_t frinfo; - fr_info_t *fin = &frinfo; - u_32_t pass = fr_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 - * 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 - * to hold all the required packet headers. - */ -#ifdef _KERNEL -# ifdef MENTAT - qpktinfo_t *qpi = qif; - -# if !defined(_INET_IP_STACK_H) - if ((u_int)ip & 0x3) - return 2; -# endif -# else - SPL_INT(s); -# endif - - READ_ENTER(&ipf_global); - - if (fr_running <= 0) { - RWLOCK_EXIT(&ipf_global); - return 0; - } - - bzero((char *)fin, sizeof(*fin)); - -# ifdef MENTAT - if (qpi->qpi_flags & QF_GROUP) - fin->fin_flx |= FI_MBCAST; - m = qpi->qpi_m; - fin->fin_qfm = m; - fin->fin_qpi = qpi; -# else /* MENTAT */ - - 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 -# ifdef M_CANFASTFWD - /* - * XXX For now, IP Filter and fast-forwarding of cached flows - * XXX are mutually exclusive. Eventually, IP Filter should - * XXX get a "can-fast-forward" filter rule. - */ - m->m_flags &= ~M_CANFASTFWD; -# endif /* M_CANFASTFWD */ -# ifdef CSUM_DELAY_DATA - /* - * disable delayed checksums. - */ - if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { - in_delayed_cksum(m); - m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; - } -# endif /* CSUM_DELAY_DATA */ -# endif /* MENTAT */ -#else - READ_ENTER(&ipf_global); - - bzero((char *)fin, sizeof(*fin)); - m = *mp; -#endif /* _KERNEL */ - - fin->fin_v = v; - fin->fin_m = m; - fin->fin_ip = ip; - fin->fin_mp = mp; - fin->fin_out = out; - fin->fin_ifp = ifp; - fin->fin_error = ENETUNREACH; - fin->fin_hlen = (u_short)hlen; - fin->fin_dp = (char *)ip + hlen; - - fin->fin_ipoff = (char *)ip - MTOD(m, char *); - - SPL_NET(s); - -#ifdef USE_INET6 - if (v == 6) { - ATOMIC_INCL(frstats[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) { - pass = FR_BLOCK|FR_NOMATCH; - goto finished; - } - } else -#endif - { -#if (OpenBSD >= 200311) && defined(_KERNEL) - ip->ip_len = ntohs(ip->ip_len); - ip->ip_off = ntohs(ip->ip_off); -#endif - } - - if (fr_makefrip(hlen, ip, fin) == -1) { - pass = FR_BLOCK|FR_NOMATCH; - goto finished; - } - - /* - * For at least IPv6 packets, if a m_pullup() fails then this pointer - * becomes NULL and so we have no packet to free. - */ - if (*fin->fin_mp == NULL) - goto finished; - - if (!out) { - if (v == 4) { -#ifdef _KERNEL - if (fr_chksrc && !fr_verifysrc(fin)) { - ATOMIC_INCL(frstats[0].fr_badsrc); - fin->fin_flx |= FI_BADSRC; - } -#endif - if (fin->fin_ip->ip_ttl < fr_minttl) { - ATOMIC_INCL(frstats[0].fr_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); - fin->fin_flx |= FI_LOWTTL; - } - } -#endif - } - - if (fin->fin_flx & FI_SHORT) { - ATOMIC_INCL(frstats[out].fr_short); - } - - READ_ENTER(&ipf_mutex); - - /* - * Check auth now. This, combined with the check below to see if apass - * is 0 is to ensure that we don't count the packet twice, which can - * otherwise occur when we reprocess it. As it is, we only count it - * after it has no auth. table matchup. This also stops NAT from - * occuring until after the packet has been auth'd. - */ - fr = fr_checkauth(fin, &pass); - if (!out) { - if (fr_checknatin(fin, &pass) == -1) { - goto filterdone; - } - } - if (!out) - (void) fr_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 (fr == NULL) - fr = fr_checkstate(fin, &pass); - } - - if ((pass & FR_NOMATCH) || (fr == NULL)) - fr = fr_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 - * to return a packet for "keep state" - */ - if ((pass & FR_KEEPSTATE) && !(fin->fin_flx & FI_STATE)) { - if (fr_addstate(fin, NULL, 0) != NULL) { - ATOMIC_INCL(frstats[out].fr_ads); - } else { - ATOMIC_INCL(frstats[out].fr_bads); - if (FR_ISPASS(pass)) { - pass &= ~FR_CMDMASK; - pass |= FR_BLOCK; - } - } - } - - fin->fin_fr = fr; - - /* - * Only count/translate packets which will be passed on, out the - * interface. - */ - if (out && FR_ISPASS(pass)) { - (void) fr_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); - } - } - } - -filterdone: -#ifdef IPFILTER_LOG - if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { - (void) fr_dolog(fin, &pass); - } -#endif - - /* - * The FI_STATE flag is cleared here so that calling fr_checkstate - * 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); - } - } - - /* - * 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. - */ - if (fr != NULL) { - MUTEX_ENTER(&fr->fr_lock); - fr->fr_ref++; - MUTEX_EXIT(&fr->fr_lock); - } - - RWLOCK_EXIT(&ipf_mutex); - - 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. - */ - if (!out) { - if (pass & FR_RETICMP) { - int dst; - - if ((pass & FR_RETMASK) == FR_FAKEICMP) - dst = 1; - else - dst = 0; - (void) fr_send_icmp_err(ICMP_UNREACH, fin, dst); - ATOMIC_INCL(frstats[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); - } - } - - /* - * When using return-* with auth rules, the auth code - * takes over disposing of this packet. - */ - if (FR_ISAUTH(pass) && (fin->fin_m != NULL)) { - fin->fin_m = *fin->fin_mp = NULL; - } - } else { - if (pass & FR_RETRST) - fin->fin_error = ECONNRESET; - } - } - - /* - * 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 *). - */ - if (fr != NULL) { - frdest_t *fdp; - - fdp = &fr->fr_tifs[fin->fin_rev]; - - if (!out && (pass & FR_FASTROUTE)) { - /* - * For fastroute rule, no destioation interface defined - * so pass NULL as the frdest_t parameter - */ - (void) fr_fastroute(fin->fin_m, mp, fin, NULL); - m = *mp = NULL; - } else if ((fdp->fd_ifp != NULL) && - (fdp->fd_ifp != (struct ifnet *)-1)) { - /* this is for to rules: */ - (void) fr_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); - } - -finished: - if (!FR_ISPASS(pass)) { - ATOMIC_INCL(frstats[out].fr_block); - if (*mp != NULL) { - FREE_MB_T(*mp); - m = *mp = NULL; - } - } else { - ATOMIC_INCL(frstats[out].fr_pass); -#if defined(_KERNEL) && defined(__sgi) - if ((fin->fin_hbuf != NULL) && - (mtod(fin->fin_m, struct ip *) != fin->fin_ip)) { - COPYBACK(fin->fin_m, 0, fin->fin_plen, fin->fin_hbuf); - } -#endif - } - - SPL_X(s); - RWLOCK_EXIT(&ipf_global); - -#ifdef _KERNEL -# if OpenBSD >= 200311 - 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; -#else /* _KERNEL */ - FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass)); - if ((pass & FR_NOMATCH) != 0) - return 1; - - if ((pass & FR_RETMASK) != 0) - switch (pass & FR_RETMASK) - { - case FR_RETRST : - return 3; - case FR_RETICMP : - return 4; - case FR_FAKEICMP : - return 5; - } - - switch (pass & FR_CMDMASK) - { - case FR_PASS : - return 0; - case FR_BLOCK : - return -1; - case FR_AUTH : - return -2; - case FR_ACCOUNT : - return -3; - case FR_PREAUTH : - return -4; - } - return 2; -#endif /* _KERNEL */ -} - - -#ifdef IPFILTER_LOG -/* ------------------------------------------------------------------------ */ -/* Function: fr_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) */ -/* */ -/* 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; -{ - u_32_t pass; - int out; - - out = fin->fin_out; - pass = *passp; - - if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { - pass |= FF_LOGNOMATCH; - ATOMIC_INCL(frstats[out].fr_npkl); - goto logit; - } else if (((pass & FR_LOGMASK) == FR_LOGP) || - (FR_ISPASS(pass) && (fr_flags & FF_LOGPASS))) { - if ((pass & FR_LOGMASK) != FR_LOGP) - pass |= FF_LOGPASS; - ATOMIC_INCL(frstats[out].fr_ppkl); - goto logit; - } else if (((pass & FR_LOGMASK) == FR_LOGB) || - (FR_ISBLOCK(pass) && (fr_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); - - /* - * 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)) { - pass &= ~FR_CMDMASK; - pass |= FR_BLOCK; - } - } - *passp = pass; - } - - return fin->fin_fr; -} -#endif /* IPFILTER_LOG */ - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_cksum */ -/* Returns: u_short - IP header checksum */ -/* Parameters: addr(I) - pointer to start of buffer to checksum */ -/* len(I) - length of buffer in bytes */ -/* */ -/* Calculate the two's complement 16 bit checksum of the buffer passed. */ -/* */ -/* N.B.: addr should be 16bit aligned. */ -/* ------------------------------------------------------------------------ */ -u_short ipf_cksum(addr, len) -u_short *addr; -int len; -{ - u_32_t sum = 0; - - for (sum = 0; len > 1; len -= 2) - sum += *addr++; - - /* mop up an odd byte, if necessary */ - if (len == 1) - sum += *(u_char *)addr; - - /* - * add back carry outs from top 16 bits to low 16 bits - */ - sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ - sum += (sum >> 16); /* add carry */ - return (u_short)(~sum); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_cksum */ -/* Returns: u_short - layer 4 checksum */ -/* Parameters: m(I ) - pointer to buffer holding packet */ -/* 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. */ -/* */ -/* NB: This function assumes we've pullup'd enough for all of the IP header */ -/* 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. */ -/* ------------------------------------------------------------------------ */ -u_short fr_cksum(m, ip, l4proto, l4hdr, l3len) -mb_t *m; -ip_t *ip; -int l4proto, l3len; -void *l4hdr; -{ - u_short *sp, slen, sumsave, l4hlen, *csump; - u_int sum, sum2; - int hlen; -#ifdef USE_INET6 - ip6_t *ip6; -#endif - - csump = NULL; - sumsave = 0; - l4hlen = 0; - sp = NULL; - slen = 0; - hlen = 0; - sum = 0; - - /* - * Add up IP Header portion - */ -#ifdef USE_INET6 - if (IP_V(ip) == 4) { -#endif - hlen = IP_HL(ip) << 2; - slen = l3len - hlen; - sum = htons((u_short)l4proto); - sum += htons(slen); - sp = (u_short *)&ip->ip_src; - sum += *sp++; /* ip_src */ - sum += *sp++; - sum += *sp++; /* ip_dst */ - sum += *sp++; -#ifdef USE_INET6 - } else if (IP_V(ip) == 6) { - ip6 = (ip6_t *)ip; - hlen = sizeof(*ip6); - slen = l3len - hlen; - sum = htons((u_short)l4proto); - sum += htons(slen); - sp = (u_short *)&ip6->ip6_src; - sum += *sp++; /* ip6_src */ - sum += *sp++; - sum += *sp++; - sum += *sp++; - sum += *sp++; - sum += *sp++; - sum += *sp++; - sum += *sp++; - sum += *sp++; /* ip6_dst */ - sum += *sp++; - sum += *sp++; - sum += *sp++; - sum += *sp++; - sum += *sp++; - sum += *sp++; - sum += *sp++; - } -#endif - - 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; - break; - default : - break; - } - - if (csump != NULL) { - sumsave = *csump; - *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 */ - 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 */ -/* Returns: frgroup_t * - NULL = group not found, else pointer to group */ -/* Parameters: 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 */ -/* to where to add the next (last) group or where */ -/* to delete group from. */ -/* */ -/* 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 *fg, **fgp; - - /* - * Which list of groups to search in is dependent on which list of - * rules are being operated on. - */ - fgp = &ipfgroups[unit][set]; - - while ((fg = *fgp) != NULL) { - if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0) - break; - else - fgp = &fg->fg_next; - } - if (fgpp != NULL) - *fgpp = fgp; - return fg; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_addgroup */ -/* Returns: frgroup_t * - NULL == did not create group, */ -/* != NULL == pointer to the group */ -/* Parameters: 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 */ -/* set(I) - which set of rules (inactive/inactive) this is */ -/* Write Locks: ipf_mutex */ -/* */ -/* 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 *fg, **fgp; - u_32_t gflags; - - if (group == NULL) - return NULL; - - if (unit == IPL_LOGIPF && *group == '\0') - return NULL; - - fgp = NULL; - gflags = flags & FR_INOUT; - - fg = fr_findgroup(group, unit, set, &fgp); - if (fg != NULL) { - if (fg->fg_flags == 0) - fg->fg_flags = gflags; - else if (gflags != fg->fg_flags) - return NULL; - 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); - fg->fg_flags = gflags; - fg->fg_ref = 1; - *fgp = fg; - } - return fg; -} - - -/* ------------------------------------------------------------------------ */ -/* 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 */ -/* Write Locks: ipf_mutex */ -/* */ -/* Attempt to delete a group head. */ -/* Only do this when its reference count reaches 0. */ -/* ------------------------------------------------------------------------ */ -void fr_delgroup(group, unit, set) -char *group; -minor_t unit; -int set; -{ - frgroup_t *fg, **fgp; - - fg = fr_findgroup(group, unit, set, &fgp); - if (fg == NULL) - return; - - fg->fg_ref--; - if (fg->fg_ref == 0) { - *fgp = fg->fg_next; - KFREE(fg); - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_getrulen */ -/* Returns: frentry_t * - NULL == not found, else pointer to rule n */ -/* 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 */ -/* n(I) - rule number to find */ -/* */ -/* 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 *fr; - frgroup_t *fg; - - fg = fr_findgroup(group, unit, fr_active, NULL); - if (fg == NULL) - return NULL; - for (fr = fg->fg_head; fr && n; fr = fr->fr_next, n--) - ; - if (n != 0) - return NULL; - return fr; -} - - -/* ------------------------------------------------------------------------ */ -/* 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 */ -/* 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 */ -/* nfreedp(O) - pointer to int where flush count is stored */ -/* listp(I) - pointer to list to flush pointer */ -/* Write Locks: ipf_mutex */ -/* */ -/* Recursively flush rules from the list, descending groups as they are */ -/* encountered. if a rule is the head of a group and it has lost all its */ -/* group members, then also delete the group reference. nfreedp is needed */ -/* to store the accumulating count of rules removed, whereas the returned */ -/* value is just the number removed from the current list. The latter is */ -/* needed to correctly adjust reference counts on rules that define groups. */ -/* */ -/* 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; -{ - int freed = 0; - frentry_t *fp; - - while ((fp = *listp) != NULL) { - if ((fp->fr_type & FR_T_BUILTIN) || - !(fp->fr_flags & FR_COPIED)) { - listp = &fp->fr_next; - continue; - } - *listp = fp->fr_next; - if (fp->fr_grp != NULL) { - (void) frflushlist(set, unit, nfreedp, fp->fr_grp); - } - - if (fp->fr_grhead != NULL) { - fr_delgroup(fp->fr_grhead, unit, set); - *fp->fr_grhead = '\0'; - } - - ASSERT(fp->fr_ref > 0); - fp->fr_next = NULL; - if (fr_derefrule(&fp) == 0) - freed++; - } - *nfreedp += freed; - return freed; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: frflush */ -/* Returns: int - >= 0 - number of flushed rules */ -/* Parameters: 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 flushed = 0, set; - - WRITE_ENTER(&ipf_mutex); - bzero((char *)frcache, sizeof(frcache)); - - set = fr_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]); - } - } - 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]); - } - } - RWLOCK_EXIT(&ipf_mutex); - - if (unit == IPL_LOGIPF) { - int tmp; - - tmp = frflush(IPL_LOGCOUNT, proto, flags); - if (tmp >= 0) - flushed += tmp; - } - return flushed; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: memstr */ -/* Returns: char * - NULL if failed, != NULL pointer to matching bytes */ -/* Parameters: src(I) - pointer to byte sequence to match */ -/* dst(I) - pointer to byte sequence to search */ -/* slen(I) - match length */ -/* dlen(I) - length available to search in */ -/* */ -/* 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 *s = NULL; - - while (dlen >= slen) { - if (bcmp(src, dst, slen) == 0) { - s = dst; - break; - } - dst++; - dlen--; - } - return s; -} -/* ------------------------------------------------------------------------ */ -/* Function: fr_fixskip */ -/* Returns: Nil */ -/* Parameters: listp(IO) - pointer to start of list with skip rule */ -/* rp(I) - rule added/removed with skip in it. */ -/* addremove(I) - adjustment (-1/+1) to make to skip count, */ -/* depending on whether a rule was just added */ -/* or removed. */ -/* */ -/* 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; -{ - int rules, rn; - frentry_t *fp; - - rules = 0; - for (fp = *listp; (fp != NULL) && (fp != rp); fp = fp->fr_next) - rules++; - - if (!fp) - return; - - for (rn = 0, fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++) - if (FR_ISSKIP(fp->fr_flags) && (rn + fp->fr_arg >= rules)) - fp->fr_arg += addremove; -} - - -#ifdef _KERNEL -/* ------------------------------------------------------------------------ */ -/* Function: count4bits */ -/* Returns: int - >= 0 - number of consecutive bits in input */ -/* Parameters: ip(I) - 32bit IP address */ -/* */ -/* IPv4 ONLY */ -/* count consecutive 1's in bit mask. If the mask generated by counting */ -/* consecutive 1's is different to that passed, return -1, else return # */ -/* of bits. */ -/* ------------------------------------------------------------------------ */ -int count4bits(ip) -u_32_t ip; -{ - u_32_t ipn; - int cnt = 0, i, j; - - ip = ipn = ntohl(ip); - for (i = 32; i; i--, ipn *= 2) - if (ipn & 0x80000000) - cnt++; - else - break; - ipn = 0; - for (i = 32, j = cnt; i; i--, j--) { - ipn *= 2; - if (j > 0) - ipn++; - } - if (ipn == ip) - return cnt; - return -1; -} - - -# if 0 -/* ------------------------------------------------------------------------ */ -/* Function: count6bits */ -/* Returns: int - >= 0 - number of consecutive bits in input */ -/* Parameters: msk(I) - pointer to start of IPv6 bitmask */ -/* */ -/* IPv6 ONLY */ -/* count consecutive 1's in bit mask. */ -/* ------------------------------------------------------------------------ */ -int count6bits(msk) -u_32_t *msk; -{ - int i = 0, k; - u_32_t j; - - for (k = 3; k >= 0; k--) - if (msk[k] == 0xffffffff) - i += 32; - else { - for (j = msk[k]; j; j <<= 1) - if (j & 0x80000000) - i++; - } - return i; -} -# endif -#endif /* _KERNEL */ - - -/* ------------------------------------------------------------------------ */ -/* Function: frsynclist */ -/* Returns: void */ -/* Parameters: fr(I) - start of filter list to sync interface names for */ -/* ifp(I) - interface pointer for limiting sync lookups */ -/* Write Locks: ipf_mutex */ -/* */ -/* Walk through a list of filter rules and resolve any interface names into */ -/* 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; -{ - frdest_t *fdp; - int v, i; - - for (; fr; fr = fr->fr_next) { - v = fr->fr_v; - - /* - * Lookup all the interface names that are part of the rule. - */ - 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_type == 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); - } - 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); - } - } - - fdp = &fr->fr_tifs[0]; - if ((ifp == NULL) || (fdp->fd_ifp == ifp)) - fr_resolvedest(fdp, v); - - fdp = &fr->fr_tifs[1]; - if ((ifp == NULL) || (fdp->fd_ifp == ifp)) - fr_resolvedest(fdp, v); - - 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); - } -#endif - } -} - - -#ifdef _KERNEL -/* ------------------------------------------------------------------------ */ -/* Function: frsync */ -/* Returns: void */ -/* Parameters: Nil */ -/* */ -/* frsync() 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 i; - -# if !SOLARIS - fr_natsync(ifp); - fr_statesync(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); - - 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); - } - RWLOCK_EXIT(&ipf_mutex); -} - - -/* - * In the functions below, bcopy() is called because the pointer being - * copied _from_ in this instance is a pointer to a char buf (which could - * end up being unaligned) and on the kernel's local stack. - */ -/* ------------------------------------------------------------------------ */ -/* Function: copyinptr */ -/* Returns: int - 0 = success, else failure */ -/* Parameters: src(I) - pointer to the source address */ -/* dst(I) - destination address */ -/* size(I) - number of bytes to copy */ -/* */ -/* Copy a block of data in from user space, given a pointer to the pointer */ -/* 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; -{ - caddr_t ca; - int error; - -# if SOLARIS - error = COPYIN(src, &ca, sizeof(ca)); - if (error != 0) - return error; -# else - bcopy(src, (caddr_t)&ca, sizeof(ca)); -# endif - error = COPYIN(ca, dst, size); - if (error != 0) - error = EFAULT; - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: copyoutptr */ -/* Returns: int - 0 = success, else failure */ -/* Parameters: src(I) - pointer to the source address */ -/* dst(I) - destination address */ -/* size(I) - number of bytes to copy */ -/* */ -/* Copy a block of data out to user space, given a pointer to the pointer */ -/* 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; -{ - caddr_t ca; - int error; - - bcopy(dst, (caddr_t)&ca, sizeof(ca)); - error = COPYOUT(src, ca, size); - if (error != 0) - error = EFAULT; - return error; -} -#endif - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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 */ -/* */ -/* 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 arg, err; - - err = BCOPYIN(data, &arg, sizeof(arg)); - if (err != 0) - return EFAULT; - err = BCOPYOUT(lockp, data, sizeof(*lockp)); - if (err != 0) - return EFAULT; - *lockp = arg; - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_getstat */ -/* Returns: Nil */ -/* Parameters: fiop(I) - pointer to ipfilter stats structure */ -/* */ -/* Stores a copy of current pointers, counters, etc, in the friostat */ -/* structure. */ -/* ------------------------------------------------------------------------ */ -void fr_getstat(fiop) -friostat_t *fiop; -{ - 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]; - - fiop->f_running = fr_running; - for (i = 0; i < IPL_LOGSIZE; i++) { - fiop->f_groups[i][0] = ipfgroups[i][0]; - fiop->f_groups[i][1] = ipfgroups[i][1]; - } -#ifdef IPFILTER_LOG - fiop->f_logging = 1; -#else - fiop->f_logging = 0; -#endif - fiop->f_defpass = fr_pass; - fiop->f_features = fr_features; - (void) strncpy(fiop->f_version, ipfilter_version, - sizeof(fiop->f_version)); -} - - -#ifdef USE_INET6 -int icmptoicmp6types[ICMP_MAXTYPE+1] = { - ICMP6_ECHO_REPLY, /* 0: ICMP_ECHOREPLY */ - -1, /* 1: UNUSED */ - -1, /* 2: UNUSED */ - ICMP6_DST_UNREACH, /* 3: ICMP_UNREACH */ - -1, /* 4: ICMP_SOURCEQUENCH */ - ND_REDIRECT, /* 5: ICMP_REDIRECT */ - -1, /* 6: UNUSED */ - -1, /* 7: UNUSED */ - ICMP6_ECHO_REQUEST, /* 8: ICMP_ECHO */ - -1, /* 9: UNUSED */ - -1, /* 10: UNUSED */ - ICMP6_TIME_EXCEEDED, /* 11: ICMP_TIMXCEED */ - ICMP6_PARAM_PROB, /* 12: ICMP_PARAMPROB */ - -1, /* 13: ICMP_TSTAMP */ - -1, /* 14: ICMP_TSTAMPREPLY */ - -1, /* 15: ICMP_IREQ */ - -1, /* 16: ICMP_IREQREPLY */ - -1, /* 17: ICMP_MASKREQ */ - -1, /* 18: ICMP_MASKREPLY */ -}; - - -int icmptoicmp6unreach[ICMP_MAX_UNREACH] = { - ICMP6_DST_UNREACH_ADDR, /* 0: ICMP_UNREACH_NET */ - ICMP6_DST_UNREACH_ADDR, /* 1: ICMP_UNREACH_HOST */ - -1, /* 2: ICMP_UNREACH_PROTOCOL */ - ICMP6_DST_UNREACH_NOPORT, /* 3: ICMP_UNREACH_PORT */ - -1, /* 4: ICMP_UNREACH_NEEDFRAG */ - ICMP6_DST_UNREACH_NOTNEIGHBOR, /* 5: ICMP_UNREACH_SRCFAIL */ - ICMP6_DST_UNREACH_ADDR, /* 6: ICMP_UNREACH_NET_UNKNOWN */ - ICMP6_DST_UNREACH_ADDR, /* 7: ICMP_UNREACH_HOST_UNKNOWN */ - -1, /* 8: ICMP_UNREACH_ISOLATED */ - ICMP6_DST_UNREACH_ADMIN, /* 9: ICMP_UNREACH_NET_PROHIB */ - ICMP6_DST_UNREACH_ADMIN, /* 10: ICMP_UNREACH_HOST_PROHIB */ - -1, /* 11: ICMP_UNREACH_TOSNET */ - -1, /* 12: ICMP_UNREACH_TOSHOST */ - ICMP6_DST_UNREACH_ADMIN, /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */ -}; -int icmpreplytype6[ICMP6_MAXTYPE + 1]; -#endif - -int icmpreplytype4[ICMP_MAXTYPE + 1]; - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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 */ -/* icmp(I) - ICMP packet header */ -/* rev(I) - direction (0 = forward/1 = reverse) of packet */ -/* */ -/* Check if the ICMP packet defined by the header pointed to by icmp is a */ -/* 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 ictype; - - ictype = ic->ici_type; - - if (v == 4) { - /* - * If we matched its type on the way in, then when going out - * it will still be the same type. - */ - if ((!rev && (icmp->icmp_type == ictype)) || - (rev && (icmpreplytype4[ictype] == icmp->icmp_type))) { - if (icmp->icmp_type != ICMP_ECHOREPLY) - return 1; - if (icmp->icmp_id == ic->ici_id) - return 1; - } - } -#ifdef USE_INET6 - else if (v == 6) { - if ((!rev && (icmp->icmp_type == ictype)) || - (rev && (icmpreplytype6[ictype] == icmp->icmp_type))) { - if (icmp->icmp_type != ICMP6_ECHO_REPLY) - return 1; - if (icmp->icmp_id == ic->ici_id) - return 1; - } - } -#endif - return 0; -} - - -#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 */ -/* Parameters: unit(I) - device for which this is for */ -/* req(I) - ioctl command (SIOC*) */ -/* data(I) - pointr to ioctl data */ -/* set(I) - 1 or 0 (filter set) */ -/* makecopy(I) - flag indicating whether data points to a rule */ -/* in kernel space & hence doesn't need copying. */ -/* */ -/* This function handles all the requests which operate on the list of */ -/* filter rules. This includes adding, deleting, insertion. It is also */ -/* responsible for creating groups when a "head" rule is loaded. Interface */ -/* names are resolved here and other sanity checks are made on the content */ -/* 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; -{ - frentry_t frd, *fp, *f, **fprev, **ftail; - int error = 0, in, v; - void *ptr, *uptr; - u_int *p, *pp; - frgroup_t *fg; - char *group; - - 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) - return EINVAL; - fp->fr_ref = 0; - fp->fr_flags |= FR_COPIED; - } else { - fp = (frentry_t *)data; - if ((fp->fr_type & FR_T_BUILTIN) == 0) - 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; - - v = fp->fr_v; - uptr = fp->fr_data; - - /* - * Only filter rules for IPv4 or IPv6 are accepted. - */ - if (v == 4) - /*EMPTY*/; -#ifdef USE_INET6 - else if (v == 6) - /*EMPTY*/; -#endif - else { - return EINVAL; - } - - /* - * If the rule is being loaded from user space, i.e. we had to copy it - * into kernel space, then do not trust the function pointer in the - * 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; - } - - 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'; - - 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; - } - - in = (fp->fr_flags & FR_INQUE) ? 0 : 1; - - /* - * Work out which rule list this change is being applied to. - */ - 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 (FR_ISACCOUNT(fp->fr_flags)) - fprev = &ipacct6[in][set]; - else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0) - fprev = &ipfilter6[in][set]; - } - if (fprev == NULL) - return ESRCH; - - if (*group != '\0') { - if (!fg && !(fg = fr_findgroup(group, unit, set, NULL))) - return ESRCH; - fprev = &fg->fg_start; - } - - /* - * Copy in extra data for the rule. - */ - 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; - } else { - ptr = uptr; - error = 0; - } - if (error != 0) { - KFREES(ptr, fp->fr_dsize); - return ENOMEM; - } - fp->fr_data = ptr; - } else - fp->fr_data = NULL; - - /* - * Perform per-rule type sanity checks of their members. - */ - switch (fp->fr_type & ~FR_T_BUILTIN) - { -#if defined(IPFILTER_BPF) - case FR_T_BPFOPC : - if (fp->fr_dsize == 0) - return EINVAL; - 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; - } - break; -#endif - case FR_T_IPF : - if (fp->fr_dsize != sizeof(fripf_t)) - return EINVAL; - - /* - * 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; - - switch (fp->fr_satype) - { - case FRI_BROADCAST : - case FRI_DYNAMIC : - 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; - } - 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; - break; -#endif - default : - break; - } - - switch (fp->fr_datype) - { - case FRI_BROADCAST : - case FRI_DYNAMIC : - 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; - } - 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; - break; -#endif - default : - break; - } - break; - case FR_T_NONE : - break; - case FR_T_CALLFUNC : - break; - case FR_T_COMPIPF : - break; - default : - if (makecopy && fp->fr_data != NULL) { - KFREES(fp->fr_data, fp->fr_dsize); - } - return EINVAL; - } - - /* - * Lookup all the interface names that are part of the rule. - */ - frsynclist(fp, NULL); - fp->fr_statecnt = 0; - - /* - * Look for an existing matching filter rule, but don't include the - * next or interface pointer in the comparison (fr_next, fr_ifa). - * This elminates rules which are indentical being loaded. Checksum - * the constant part of the filter rule to make comparisons quicker - * (this meaning no pointers are included). - */ - for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_func, pp = &fp->fr_cksum; - p < pp; p++) - fp->fr_cksum += *p; - pp = (u_int *)(fp->fr_caddr + fp->fr_dsize); - for (p = (u_int *)fp->fr_data; p < pp; p++) - fp->fr_cksum += *p; - - WRITE_ENTER(&ipf_mutex); - - /* - * Now that the filter rule lists are locked, we can walk the - * chain of them without fear. - */ - ftail = fprev; - for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) { - if (fp->fr_collect <= f->fr_collect) { - ftail = fprev; - f = NULL; - break; - } - fprev = ftail; - } - bzero((char *)frcache, sizeof(frcache)); - - for (; (f = *ftail) != NULL; ftail = &f->fr_next) { - if ((fp->fr_cksum != f->fr_cksum) || - (f->fr_dsize != fp->fr_dsize)) - continue; - if (bcmp((char *)&f->fr_func, (char *)&fp->fr_func, FR_CMPSIZ)) - continue; - if ((!ptr && !f->fr_data) || - (ptr && f->fr_data && - !bcmp((char *)ptr, (char *)f->fr_data, f->fr_dsize))) - break; - } - - /* - * If zero'ing statistics, copy current to caller and zero. - */ - if (req == (ioctlcmd_t)SIOCZRLST) { - if (f == NULL) - error = ESRCH; - else { - /* - * Copy and reduce lock because of impending copyout. - * Well we should, but if we do then the atomicity of - * this call and the correctness of fr_hits and - * fr_bytes cannot be guaranteed. As it is, this code - * 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); */ - - /* - * 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); - - if (error == 0) { - if ((f->fr_dsize != 0) && (uptr != NULL)) - error = COPYOUT(f->fr_data, uptr, - f->fr_dsize); - if (error != 0) - error = EFAULT; - if (error == 0) { - f->fr_hits = 0; - f->fr_bytes = 0; - } - } - } - - if ((ptr != NULL) && (makecopy != 0)) { - KFREES(ptr, fp->fr_dsize); - } - RWLOCK_EXIT(&ipf_mutex); - return error; - } - - if (!f) { - /* - * At the end of this, ftail must point to the place where the - * new rule is to be saved/inserted/added. - * For SIOCAD*FR, this should be the last rule in the group of - * rules that have equal fr_collect fields. - * For SIOCIN*FR, ... - */ - if (req == (ioctlcmd_t)SIOCADAFR || - req == (ioctlcmd_t)SIOCADIFR) { - - for (ftail = fprev; (f = *ftail) != NULL; ) { - if (f->fr_collect > fp->fr_collect) - break; - ftail = &f->fr_next; - } - f = NULL; - ptr = NULL; - error = 0; - } else if (req == (ioctlcmd_t)SIOCINAFR || - req == (ioctlcmd_t)SIOCINIFR) { - while ((f = *fprev) != NULL) { - if (f->fr_collect >= fp->fr_collect) - break; - fprev = &f->fr_next; - } - 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; - fp->fr_hits--; - } - } - f = NULL; - ptr = NULL; - error = 0; - } - } - - /* - * Request to remove a rule. - */ - if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR) { - if (!f) - error = ESRCH; - else { - /* - * Do not allow activity from user space to interfere - * with rules not loaded that way. - */ - if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) { - error = EPERM; - goto done; - } - - /* - * Return EBUSY if the rule is being reference by - * something else (eg state information.) - */ - if (f->fr_ref > 1) { - error = EBUSY; - goto done; - } -#ifdef IPFILTER_SCAN - if (f->fr_isctag[0] != '\0' && - (f->fr_isc != (struct ipscan *)-1)) - ipsc_detachfr(f); -#endif - if (unit == IPL_LOGAUTH) { - error = fr_preauthcmd(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); - } - } else { - /* - * Not removing, so we must be adding/inserting a rule. - */ - if (f) - 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; - } - } -done: - RWLOCK_EXIT(&ipf_mutex); - if ((ptr != NULL) && (error != 0) && (makecopy != 0)) { - KFREES(ptr, fp->fr_dsize); - } - return (error); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_funcinit */ -/* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */ -/* Parameters: 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; -{ - ipfunc_resolve_t *ft; - int err; - - err = ESRCH; - - for (ft = fr_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); - break; - } - return err; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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; -{ - ipfunc_resolve_t *ft; - - for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) - if (ft->ipfu_addr == funcptr) - return funcptr; - return NULL; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_resolvefunc */ -/* Returns: int - 0 == success, else error */ -/* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */ -/* */ -/* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */ -/* This will either be the function name (if the pointer is set) or the */ -/* 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; -{ - ipfunc_resolve_t res, *ft; - int err; - - err = BCOPYIN(data, &res, sizeof(res)); - if (err != 0) - return EFAULT; - - if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') { - for (ft = fr_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) - return EFAULT; - return 0; - } - } - if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') { - for (ft = fr_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) - return EFAULT; - return 0; - } - } - 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)) -/* - * From: NetBSD - * ppsratecheck(): packets (or events) per second limitation. - */ -int -ppsratecheck(lasttime, curpps, maxpps) - struct timeval *lasttime; - int *curpps; - int maxpps; /* maximum pps allowed */ -{ - struct timeval tv, delta; - int rv; - - GETKTIME(&tv); - - delta.tv_sec = tv.tv_sec - lasttime->tv_sec; - delta.tv_usec = tv.tv_usec - lasttime->tv_usec; - if (delta.tv_usec < 0) { - delta.tv_sec--; - delta.tv_usec += 1000000; - } - - /* - * check for 0,0 is so that the message will be seen at least once. - * if more than one second have passed since the last update of - * lasttime, reset the counter. - * - * we do increment *curpps even in *curpps < maxpps case, as some may - * try to use *curpps for stat purposes as well. - */ - if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || - delta.tv_sec >= 1) { - *lasttime = tv; - *curpps = 0; - rv = 1; - } else if (maxpps < 0) - rv = 1; - else if (*curpps < maxpps) - rv = 1; - else - rv = 0; - *curpps = *curpps + 1; - - return (rv); -} -#endif - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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; -{ - frentry_t *fr; - - fr = *frp; - *frp = NULL; - - MUTEX_ENTER(&fr->fr_lock); - fr->fr_ref--; - if (fr->fr_ref == 0) { - 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 - - if (fr->fr_dsize) { - KFREES(fr->fr_data, fr->fr_dsize); - } - if ((fr->fr_flags & FR_COPIED) != 0) { - KFREE(fr); - return 0; - } - return 1; - } else { - MUTEX_EXIT(&fr->fr_lock); - } - return -1; -} - - -#ifdef IPFILTER_LOOKUP -/* ------------------------------------------------------------------------ */ -/* Function: fr_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. */ -/* ------------------------------------------------------------------------ */ -static int fr_grpmapinit(fr) -frentry_t *fr; -{ - char name[FR_GROUPLEN]; - iphtable_t *iph; - -#if defined(SNPRINTF) && defined(_KERNEL) - SNPRINTF(name, sizeof(name), "%d", fr->fr_arg); -#else - (void) sprintf(name, "%d", fr->fr_arg); -#endif - iph = fr_findhtable(IPL_LOGIPF, name); - if (iph == NULL) - return ESRCH; - if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) - return ESRCH; - fr->fr_ptr = iph; - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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) */ -/* */ -/* Look for a rule group head in a hash table, using the source address as */ -/* 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; -{ - frgroup_t *fg; - void *rval; - - rval = fr_iphmfindgroup(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); - return fin->fin_fr; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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) */ -/* */ -/* Look for a rule group head in a hash table, using the destination */ -/* 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; -{ - frgroup_t *fg; - void *rval; - - rval = fr_iphmfindgroup(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); - 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. - */ - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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 */ -/* of interface queues. */ -/* seconds(I) - timeout value in seconds for this queue. */ -/* */ -/* This routine first looks for a timeout queue that matches the interval */ -/* being requested. If it finds one, increments the reference counter and */ -/* returns a pointer to it. If none are found, it allocates a new one and */ -/* inserts it at the top of the list. */ -/* */ -/* Locking. */ -/* 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 *ifq; - u_int period; - - period = seconds * IPF_HZ_DIVIDE; - - MUTEX_ENTER(&ipf_timeoutlock); - for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) { - if (ifq->ifq_ttl == period) { - /* - * Reset the delete flag, if set, so the structure - * gets reused rather than freed and reallocated. - */ - MUTEX_ENTER(&ifq->ifq_lock); - ifq->ifq_flags &= ~IFQF_DELETE; - ifq->ifq_ref++; - MUTEX_EXIT(&ifq->ifq_lock); - MUTEX_EXIT(&ipf_timeoutlock); - - return ifq; - } - } - - KMALLOC(ifq, ipftq_t *); - if (ifq != NULL) { - ifq->ifq_ttl = period; - ifq->ifq_head = NULL; - ifq->ifq_tail = &ifq->ifq_head; - ifq->ifq_next = *parent; - ifq->ifq_pnext = parent; - ifq->ifq_ref = 1; - ifq->ifq_flags = IFQF_USER; - *parent = ifq; - fr_userifqs++; - MUTEX_NUKE(&ifq->ifq_lock); - MUTEX_INIT(&ifq->ifq_lock, "ipftq mutex"); - } - MUTEX_EXIT(&ipf_timeoutlock); - return ifq; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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 */ -/* */ -/* This routine must be called when we're discarding a pointer to a timeout */ -/* queue object, taking care of the reference counter. */ -/* */ -/* Now that this just sets a DELETE flag, it requires the expire code to */ -/* check the list of user defined timeout queues and call the free function */ -/* below (currently commented out) to stop memory leaking. It is done this */ -/* 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; -{ - - ifq->ifq_ref--; - if ((ifq->ifq_ref == 0) && ((ifq->ifq_flags & IFQF_USER) != 0)) { - ifq->ifq_flags |= IFQF_DELETE; - } - - return ifq->ifq_ref; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_freetimeoutqueue */ -/* Parameters: ifq(I) - timeout queue which is losing a reference. */ -/* Returns: Nil */ -/* */ -/* Locking: */ -/* It is assumed that the caller of this function has an appropriate lock */ -/* 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 */ -/* tidy up after this is done. */ -/* ------------------------------------------------------------------------ */ -void fr_freetimeoutqueue(ifq) -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", - (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl, - ifq->ifq_ref); - return; - } - - /* - * Remove from its position in the list. - */ - *ifq->ifq_pnext = ifq->ifq_next; - if (ifq->ifq_next != NULL) - ifq->ifq_next->ifq_pnext = ifq->ifq_pnext; - - MUTEX_DESTROY(&ifq->ifq_lock); - ATOMIC_DEC(fr_userifqs); - KFREE(ifq); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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 */ -/* the correct lock(s) may not be held that would make it safe to do so. */ -/* ------------------------------------------------------------------------ */ -void fr_deletequeueentry(tqe) -ipftqent_t *tqe; -{ - ipftq_t *ifq; - - ifq = tqe->tqe_ifq; - - MUTEX_ENTER(&ifq->ifq_lock); - - if (tqe->tqe_pnext != NULL) { - *tqe->tqe_pnext = tqe->tqe_next; - if (tqe->tqe_next != NULL) - tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; - else /* we must be the tail anyway */ - ifq->ifq_tail = tqe->tqe_pnext; - - tqe->tqe_pnext = NULL; - tqe->tqe_ifq = NULL; - } - - (void) fr_deletetimeoutqueue(ifq); - - MUTEX_EXIT(&ifq->ifq_lock); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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; -{ - ipftq_t *ifq; - - ifq = tqe->tqe_ifq; - if (ifq == NULL) - return; - - MUTEX_ENTER(&ifq->ifq_lock); - if (ifq->ifq_head != tqe) { - *tqe->tqe_pnext = tqe->tqe_next; - if (tqe->tqe_next) - tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; - else - ifq->ifq_tail = tqe->tqe_pnext; - - tqe->tqe_next = ifq->ifq_head; - ifq->ifq_head->tqe_pnext = &tqe->tqe_next; - ifq->ifq_head = tqe; - tqe->tqe_pnext = &ifq->ifq_head; - } - MUTEX_EXIT(&ifq->ifq_lock); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_queueback */ -/* Returns: Nil */ -/* Parameters: tqe(I) - pointer to timeout queue entry */ -/* */ -/* Move a queue entry to the back of the queue, if it isn't already there. */ -/* ------------------------------------------------------------------------ */ -void fr_queueback(tqe) -ipftqent_t *tqe; -{ - ipftq_t *ifq; - - ifq = tqe->tqe_ifq; - if (ifq == NULL) - return; - tqe->tqe_die = fr_ticks + ifq->ifq_ttl; - - MUTEX_ENTER(&ifq->ifq_lock); - if (tqe->tqe_next != NULL) { /* at the end already ? */ - /* - * Remove from list - */ - *tqe->tqe_pnext = tqe->tqe_next; - tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; - - /* - * Make it the last entry. - */ - tqe->tqe_next = NULL; - tqe->tqe_pnext = ifq->ifq_tail; - *ifq->ifq_tail = tqe; - ifq->ifq_tail = &tqe->tqe_next; - } - MUTEX_EXIT(&ifq->ifq_lock); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_queueappend */ -/* Returns: Nil */ -/* Parameters: 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. */ -/* ------------------------------------------------------------------------ */ -void fr_queueappend(tqe, ifq, parent) -ipftqent_t *tqe; -ipftq_t *ifq; -void *parent; -{ - - MUTEX_ENTER(&ifq->ifq_lock); - tqe->tqe_parent = parent; - tqe->tqe_pnext = ifq->ifq_tail; - *ifq->ifq_tail = tqe; - ifq->ifq_tail = &tqe->tqe_next; - tqe->tqe_next = NULL; - tqe->tqe_ifq = ifq; - tqe->tqe_die = fr_ticks + ifq->ifq_ttl; - ifq->ifq_ref++; - MUTEX_EXIT(&ifq->ifq_lock); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_movequeue */ -/* Returns: Nil */ -/* Parameters: tq(I) - pointer to timeout queue information */ -/* oifp(I) - old timeout queue entry was on */ -/* nifp(I) - new timeout queue to put entry on */ -/* */ -/* Move a queue entry from one timeout queue to another timeout queue. */ -/* 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; -{ - /* - * Is the operation here going to be a no-op ? - */ - 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; - - (void) fr_deletetimeoutqueue(oifq); - - MUTEX_EXIT(&oifq->ifq_lock); - - MUTEX_ENTER(&nifq->ifq_lock); - - tqe->tqe_ifq = nifq; - nifq->ifq_ref++; - } - - /* - * 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_EXIT(&nifq->ifq_lock); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_updateipid */ -/* Returns: int - 0 == success, -1 == error (packet should be droppped) */ -/* Parameters: fin(I) - pointer to packet information */ -/* */ -/* When we are doing NAT, change the IP of every packet to represent a */ -/* single sequence of packets coming from the host, hiding any host */ -/* specific sequencing that might otherwise be revealed. If the packet is */ -/* a fragment, then store the 'new' IPid in the fragment cache and look up */ -/* 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; -{ - u_short id, ido, sums; - u_32_t sumd, sum; - ip_t *ip; - - if (fin->fin_off != 0) { - sum = fr_ipid_knownfrag(fin); - if (sum == 0xffffffff) - return -1; - sum &= 0xffff; - id = (u_short)sum; - } else { - id = fr_nextipid(fin); - if (fin->fin_off == 0 && (fin->fin_flx & FI_FRAG) != 0) - (void) fr_ipid_newfrag(fin, (u_32_t)id); - } - - ip = fin->fin_ip; - ido = ntohs(ip->ip_id); - if (id == ido) - return 0; - ip->ip_id = htons(id); - CALC_SUMD(ido, id, sumd); /* DESTRUCTIVE MACRO! id,ido change */ - sum = (~ntohs(ip->ip_sum)) & 0xffff; - sum += sumd; - sum = (sum >> 16) + (sum & 0xffff); - sum = (sum >> 16) + (sum & 0xffff); - sums = ~(u_short)sum; - ip->ip_sum = htons(sums); - return 0; -} - - -#ifdef NEED_FRGETIFNAME -/* ------------------------------------------------------------------------ */ -/* Function: fr_getifname */ -/* Returns: char * - pointer to interface name */ -/* Parameters: ifp(I) - pointer to network interface */ -/* buffer(O) - pointer to where to store interface name */ -/* */ -/* Constructs an interface name in the buffer passed. The buffer passed is */ -/* 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; -{ - static char namebuf[LIFNAMSIZ]; -# if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ - defined(__sgi) || defined(linux) || defined(_AIX51) || \ - (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) - int unit, space; - char temp[20]; - char *s; -# endif - - if (buffer == NULL) - buffer = namebuf; - (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ); - buffer[LIFNAMSIZ - 1] = '\0'; -# if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ - defined(__sgi) || defined(_AIX51) || \ - (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) - for (s = buffer; *s; s++) - ; - unit = ifp->if_unit; - space = LIFNAMSIZ - (s - buffer); - if (space > 0) { -# if defined(SNPRINTF) && defined(_KERNEL) - SNPRINTF(temp, sizeof(temp), "%d", unit); -# else - (void) sprintf(temp, "%d", unit); -# endif - (void) strncpy(s, temp, space); - } -# endif - return buffer; -} -#endif - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_ioctlswitch */ -/* Returns: int - -1 continue processing, else ioctl return value */ -/* Parameters: unit(I) - device unit opened */ -/* data(I) - pointer to ioctl data */ -/* cmd(I) - ioctl command */ -/* mode(I) - mode value */ -/* uid(I) - uid making the ioctl call */ -/* ctx(I) - pointer to context data */ -/* */ -/* 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. */ -/* ------------------------------------------------------------------------ */ -int fr_ioctlswitch(unit, data, cmd, mode, uid, ctx) -int unit, mode, uid; -ioctlcmd_t cmd; -void *data, *ctx; -{ - int error = 0; - - switch (unit) - { - case IPL_LOGIPF : - error = fr_ipf_ioctl(data, cmd, mode, uid, ctx); - break; - case IPL_LOGNAT : - if (fr_running > 0) - error = fr_nat_ioctl(data, cmd, mode, uid, ctx); - else - error = EIO; - break; - case IPL_LOGSTATE : - if (fr_running > 0) - error = fr_state_ioctl(data, cmd, mode, uid, ctx); - else - error = EIO; - break; - case IPL_LOGAUTH : - if (fr_running > 0) - error = fr_auth_ioctl(data, cmd, mode, uid, ctx); - else - error = EIO; - break; - case IPL_LOGSYNC : -#ifdef IPFILTER_SYNC - if (fr_running > 0) - error = fr_sync_ioctl(data, cmd, mode, uid, ctx); - else -#endif - error = EIO; - break; - case IPL_LOGSCAN : -#ifdef IPFILTER_SCAN - if (fr_running > 0) - error = fr_scan_ioctl(data, cmd, mode, uid, ctx); - else -#endif - error = EIO; - break; - case IPL_LOGLOOKUP : -#ifdef IPFILTER_LOOKUP - if (fr_running > 0) - error = ip_lookup_ioctl(data, cmd, mode, uid, ctx); - else -#endif - error = EIO; - break; - default : - error = EIO; - break; - } - - return error; -} - - -/* - * This array defines the expected size of objects coming into the kernel - * for the various recognised object types. - */ -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) }, - { 0, sizeof(struct ipftq) * IPF_TCP_NSTATES }, -}; - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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 */ -/* */ -/* 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. */ -/* ------------------------------------------------------------------------ */ -int fr_inobj(data, ptr, type) -void *data; -void *ptr; -int type; -{ - ipfobj_t obj; - int error = 0; - - if ((type < 0) || (type >= IPFOBJ_COUNT)) - return EINVAL; - - error = BCOPYIN(data, &obj, sizeof(obj)); - if (error != 0) - return EFAULT; - - if (obj.ipfo_type != type) - return EINVAL; - -#ifndef IPFILTER_COMPAT - if ((fr_objbytes[type][0] & 1) != 0) { - if (obj.ipfo_size < fr_objbytes[type][1]) - return EINVAL; - } else if (obj.ipfo_size != fr_objbytes[type][1]) { - return EINVAL; - } -#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; -#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 */ -/* 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_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(). */ -/* ------------------------------------------------------------------------ */ -int fr_inobjsz(data, ptr, type, sz) -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])) - return EINVAL; - - error = BCOPYIN(data, &obj, sizeof(obj)); - if (error != 0) - return EFAULT; - - if (obj.ipfo_type != type) - return EINVAL; - -#ifndef IPFILTER_COMPAT - if (obj.ipfo_size != sz) - return EINVAL; -#else - if (obj.ipfo_rev != IPFILTER_VERSION) - /* XXX compatibility hook here */ - ; - if (obj.ipfo_size != sz) - /* XXX compatibility hook here */ - return EINVAL; -#endif - - error = COPYIN(obj.ipfo_ptr, ptr, sz); - if (error != 0) - error = EFAULT; - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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 */ -/* 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(). */ -/* ------------------------------------------------------------------------ */ -int fr_outobjsz(data, ptr, type, sz) -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])) - return EINVAL; - - error = BCOPYIN(data, &obj, sizeof(obj)); - if (error != 0) - return EFAULT; - - if (obj.ipfo_type != type) - return EINVAL; - -#ifndef IPFILTER_COMPAT - if (obj.ipfo_size != sz) - return EINVAL; -#else - if (obj.ipfo_rev != IPFILTER_VERSION) - /* XXX compatibility hook here */ - ; - if (obj.ipfo_size != sz) - /* XXX compatibility hook here */ - return EINVAL; -#endif - - error = COPYOUT(ptr, obj.ipfo_ptr, sz); - if (error != 0) - error = EFAULT; - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_outobj */ -/* 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 */ -/* */ -/* Copy out the contents of what ptr is to where ipfobj 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. */ -/* ------------------------------------------------------------------------ */ -int fr_outobj(data, ptr, type) -void *data; -void *ptr; -int type; -{ - ipfobj_t obj; - int error; - - if ((type < 0) || (type >= IPFOBJ_COUNT)) - return EINVAL; - - error = BCOPYIN(data, &obj, sizeof(obj)); - if (error != 0) - return EFAULT; - - if (obj.ipfo_type != type) - return EINVAL; - -#ifndef IPFILTER_COMPAT - if ((fr_objbytes[type][0] & 1) != 0) { - if (obj.ipfo_size < fr_objbytes[type][1]) - return EINVAL; - } else if (obj.ipfo_size != fr_objbytes[type][1]) - return EINVAL; -#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; -#endif - - error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size); - if (error != 0) - error = EFAULT; - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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. */ -/* ------------------------------------------------------------------------ */ -int fr_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 - * this check fails then considered the packet to be "bad". - */ - if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0) - return 1; - - csump = NULL; - hdrsum = 0; - 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; - dosum = 1; - break; - - case IPPROTO_UDP : - udp = fin->fin_dp; - if (udp->uh_sum != 0) { - csump = &udp->uh_sum; - dosum = 1; - } - break; - - case IPPROTO_ICMP : - csump = &((struct icmp *)fin->fin_dp)->icmp_cksum; - dosum = 1; - break; - - default : - return 1; - /*NOTREACHED*/ - } - - 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) - } -#endif -#if !defined(_KERNEL) - if (sum == hdrsum) { - FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum)); - } else { - FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum)); - } -#endif - if (hdrsum == sum) { - fin->fin_cksum = 1; - return 0; - } - fin->fin_cksum = -1; - return -1; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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 */ -/* mask(I) - pointer to source of netmask information */ -/* inp(I) - pointer to destination address store */ -/* inpmask(I) - pointer to destination netmask store */ -/* */ -/* Given a type of network address update (atype) to perform, copy */ -/* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ -/* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ -/* which case the operation fails. For all values of atype other than */ -/* 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; -{ - if (inpmask != NULL && atype != FRI_NETMASKED) - inpmask->s_addr = 0xffffffff; - - if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { - if (atype == FRI_NETMASKED) { - if (inpmask == NULL) - return -1; - inpmask->s_addr = mask->sin_addr.s_addr; - } - inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr; - } else { - inp->s_addr = sin->sin_addr.s_addr; - } - return 0; -} - - -#ifdef USE_INET6 -/* ------------------------------------------------------------------------ */ -/* Function: fr_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 */ -/* mask(I) - pointer to source of netmask information */ -/* inp(I) - pointer to destination address store */ -/* inpmask(I) - pointer to destination netmask store */ -/* */ -/* Given a type of network address update (atype) to perform, copy */ -/* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ -/* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ -/* which case the operation fails. For all values of atype other than */ -/* 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; -{ - i6addr_t *src, *dst, *and, *dmask; - - 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; - } - - 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]; - } - - 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]; - } 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]; - } - return 0; -} -#endif - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_matchtag */ -/* Returns: 0 == mismatch, 1 == match. */ -/* Parameters: tag1(I) - pointer to first tag to compare */ -/* tag2(I) - pointer to second tag to compare */ -/* */ -/* Returns true (non-zero) or false(0) if the two tag structures can be */ -/* considered to be a match or not match, respectively. The tag is 16 */ -/* bytes long (16 characters) but that is overlayed with 4 32bit ints so */ -/* compare the ints instead, for speed. tag1 is the master of the */ -/* 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; -{ - if (tag1 == tag2) - return 1; - - if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0)) - return 1; - - if ((tag1->ipt_num[0] == tag2->ipt_num[0]) && - (tag1->ipt_num[1] == tag2->ipt_num[1]) && - (tag1->ipt_num[2] == tag2->ipt_num[2]) && - (tag1->ipt_num[3] == tag2->ipt_num[3])) - return 1; - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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; -{ - if ((fin->fin_flx & FI_COALESCE) != 0) - return 1; - - /* - * If the mbuf pointers indicate that there is no mbuf to work with, - * return but do not indicate success or failure. - */ - if (fin->fin_m == NULL || fin->fin_mp == NULL) - return 0; - -#if defined(_KERNEL) - if (fr_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) { - ATOMIC_INCL(fr_badcoalesces[fin->fin_out]); -# ifdef MENTAT - FREE_MB_T(*fin->fin_mp); -# endif - *fin->fin_mp = NULL; - fin->fin_m = NULL; - return -1; - } -#else - fin = fin; /* LINT */ -#endif - return 1; -} - - -/* - * The following table lists all of the tunable variables that can be - * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXt. The format of each row - * in the table below is as follows: - * - * pointer to value, name of value, minimum, maximum, size of the value's - * container, value attribute flags - * - * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED - * means the value can only be written to when IPFilter is loaded but disabled. - * 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 */ -/* 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 */ -/* "next" tuneable, if it is desired. */ -/* */ -/* This function is used to walk through all of the existing tunables with */ -/* successive calls. It searches the known tunables for the one which has */ -/* 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; -{ - ipftuneable_t *ta, **tap; - - for (ta = ipf_tuneables; ta->ipft_name != NULL; ta++) - if (ta == cookie) { - if (next != NULL) { - /* - * If the next entry in the array has a name - * present, then return a pointer to it for - * where to go next, else return a pointer to - * the dynaminc list as a key to search there - * next. This facilitates a weak linking of - * the two "lists" together. - */ - if ((ta + 1)->ipft_name != NULL) - *next = ta + 1; - else - *next = &ipf_tunelist; - } - return ta; - } - - for (tap = &ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next) - if (tap == cookie) { - if (next != NULL) - *next = &ta->ipft_next; - return ta; - } - - if (next != NULL) - *next = NULL; - return NULL; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_findtunebyname */ -/* Returns: NULL = search failed, else pointer to tune struct */ -/* Parameters: name(I) - name of the tuneable entry to find. */ -/* */ -/* Search the static array of tuneables and the list of dynamic tuneables */ -/* 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; -{ - ipftuneable_t *ta; - - for (ta = ipf_tuneables; ta->ipft_name != NULL; ta++) - 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: fr_addipftune */ -/* Returns: int - 0 == success, else failure */ -/* Parameters: newtune - pointer to new tune struct 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". */ -/* ------------------------------------------------------------------------ */ -int fr_addipftune(newtune) -ipftuneable_t *newtune; -{ - ipftuneable_t *ta, **tap; - - ta = fr_findtunebyname(newtune->ipft_name); - if (ta != NULL) - return EEXIST; - - for (tap = &ipf_tunelist; *tap != NULL; tap = &(*tap)->ipft_next) - ; - - newtune->ipft_next = NULL; - *tap = newtune; - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_delipftune */ -/* Returns: int - 0 == success, else failure */ -/* Parameters: oldtune - pointer to tune struct 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; -{ - ipftuneable_t *ta, **tap; - - for (tap = &ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next) - if (ta == oldtune) { - *tap = oldtune->ipft_next; - oldtune->ipft_next = NULL; - return 0; - } - - return ESRCH; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_ipftune */ -/* Returns: int - 0 == success, else failure */ -/* Parameters: cmd(I) - ioctl command number */ -/* data(I) - pointer to ioctl data structure */ -/* */ -/* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET. These */ -/* three ioctls provide the means to access and control global variables */ -/* within IPFilter, allowing (for example) timeouts and table sizes to be */ -/* changed without rebooting, reloading or recompiling. The initialisation */ -/* 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; -{ - ipftuneable_t *ta; - ipftune_t tu; - void *cookie; - int error; - - error = fr_inobj(data, &tu, IPFOBJ_TUNEABLE); - if (error != 0) - return error; - - tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; - cookie = tu.ipft_cookie; - ta = NULL; - - switch (cmd) - { - case SIOCIPFGETNEXT : - /* - * If cookie is non-NULL, assume it to be a pointer to the last - * entry we looked at, so find it (if possible) and return a - * pointer to the next one after it. The last entry in the - * the table is a NULL entry, so when we get to it, set cookie - * to NULL and return that, indicating end of list, erstwhile - * if we come in with cookie set to NULL, we are starting anew - * at the front of the list. - */ - if (cookie != NULL) { - ta = fr_findtunebycookie(cookie, &tu.ipft_cookie); - } else { - ta = ipf_tuneables; - tu.ipft_cookie = ta + 1; - } - if (ta != NULL) { - /* - * 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)) - return EINVAL; - - tu.ipft_vlong = 0; - if (ta->ipft_sz == sizeof(u_long)) - tu.ipft_vlong = *ta->ipft_plong; - else if (ta->ipft_sz == sizeof(u_int)) - tu.ipft_vint = *ta->ipft_pint; - else if (ta->ipft_sz == sizeof(u_short)) - tu.ipft_vshort = *ta->ipft_pshort; - else if (ta->ipft_sz == sizeof(u_char)) - tu.ipft_vchar = *ta->ipft_pchar; - - tu.ipft_sz = ta->ipft_sz; - tu.ipft_min = ta->ipft_min; - tu.ipft_max = ta->ipft_max; - tu.ipft_flags = ta->ipft_flags; - bcopy(ta->ipft_name, tu.ipft_name, - MIN(sizeof(tu.ipft_name), - strlen(ta->ipft_name) + 1)); - } - error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE); - break; - - case SIOCIPFGET : - case SIOCIPFSET : - /* - * Search by name or by cookie value for a particular entry - * in the tuning paramter table. - */ - error = ESRCH; - if (cookie != NULL) { - ta = fr_findtunebycookie(cookie, NULL); - if (ta != NULL) - error = 0; - } else if (tu.ipft_name[0] != '\0') { - ta = fr_findtunebyname(tu.ipft_name); - if (ta != NULL) - error = 0; - } - if (error != 0) - break; - - if (cmd == (ioctlcmd_t)SIOCIPFGET) { - /* - * Fetch the tuning parameters for a particular value - */ - tu.ipft_vlong = 0; - if (ta->ipft_sz == sizeof(u_long)) - tu.ipft_vlong = *ta->ipft_plong; - else if (ta->ipft_sz == sizeof(u_int)) - tu.ipft_vint = *ta->ipft_pint; - else if (ta->ipft_sz == sizeof(u_short)) - tu.ipft_vshort = *ta->ipft_pshort; - else if (ta->ipft_sz == sizeof(u_char)) - tu.ipft_vchar = *ta->ipft_pchar; - tu.ipft_cookie = ta; - tu.ipft_sz = ta->ipft_sz; - 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); - - } else if (cmd == (ioctlcmd_t)SIOCIPFSET) { - /* - * Set an internal parameter. The hard part here is - * getting the new value safely and correctly out of - * the kernel (given we only know its size, not type.) - */ - u_long in; - - if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) && - (fr_running > 0)) { - error = EBUSY; - break; - } - - in = tu.ipft_vlong; - if (in < ta->ipft_min || in > ta->ipft_max) { - error = EINVAL; - break; - } - - 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); - } - break; - - default : - error = EINVAL; - break; - } - - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* 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 */ -/* Returns: int - 0 = success, else failure */ -/* Parameters: data(O) - pointer to pointer for copying data back to */ -/* */ -/* Copies the current statistics out to userspace and then zero's the */ -/* 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; -{ - friostat_t fio; - int error; - - fr_getstat(&fio); - error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT); - if (error) - return EFAULT; - - WRITE_ENTER(&ipf_mutex); - bzero(&frstats, sizeof(frstats)); - RWLOCK_EXIT(&ipf_mutex); - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_resolvedest */ -/* Returns: Nil */ -/* Parameters: 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 */ -/* then store the interface pointer in the frdest struct. If no match is */ -/* 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; -{ - void *ifp; - - ifp = NULL; - v = v; /* LINT */ - - if (*fdp->fd_ifname != '\0') { - ifp = GETIFP(fdp->fd_ifname, v); - if (ifp == NULL) - ifp = (void *)-1; - } - fdp->fd_ifp = ifp; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_resolvenic */ -/* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */ -/* pointer to interface structure for NIC */ -/* Parameters: 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 *nic; - - if (name[0] == '\0') - return NULL; - - if ((name[1] == '\0') && ((name[0] == '-') || (name[0] == '*'))) { - return NULL; - } - - name[LIFNAMSIZ - 1] = '\0'; - - nic = GETIFP(name, v); - if (nic == NULL) - nic = (void *)-1; - return nic; -} - - -ipftoken_t *ipftokenhead = NULL, **ipftokentail = &ipftokenhead; - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_expiretokens */ -/* Returns: None. */ -/* Parameters: None. */ -/* */ -/* 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() -{ - ipftoken_t *it; - - WRITE_ENTER(&ipf_tokens); - while ((it = ipftokenhead) != NULL) { - if (it->ipt_die > fr_ticks) - break; - - ipf_freetoken(it); - } - RWLOCK_EXIT(&ipf_tokens); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_deltoken */ -/* Returns: int - 0 = success, else error */ -/* Parameters: 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. */ -/* ------------------------------------------------------------------------ */ -int ipf_deltoken(type, uid, ptr) -int type, uid; -void *ptr; -{ - ipftoken_t *it; - int error = ESRCH; - - WRITE_ENTER(&ipf_tokens); - for (it = ipftokenhead; it != NULL; it = it->ipt_next) - if (ptr == it->ipt_ctx && type == it->ipt_type && - uid == it->ipt_uid) { - ipf_freetoken(it); - error = 0; - break; - } - RWLOCK_EXIT(&ipf_tokens); - - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_findtoken */ -/* Returns: ipftoken_t * - NULL if no memory, else pointer to token */ -/* Parameters: 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 live token in the list of current tokens that */ -/* 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 *it, *new; - - KMALLOC(new, ipftoken_t *); - - 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) - break; - } - - if (it == NULL) { - it = new; - new = NULL; - if (it == NULL) - 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; - } else { - if (new != NULL) { - KFREE(new); - new = NULL; - } - - ipf_unlinktoken(it); - } - it->ipt_pnext = ipftokentail; - *ipftokentail = it; - ipftokentail = &it->ipt_next; - it->ipt_next = NULL; - - it->ipt_die = fr_ticks + 2; - - MUTEX_DOWNGRADE(&ipf_tokens); - - return it; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_unlinktoken */ -/* Returns: None. */ -/* Parameters: token(I) - pointer to token structure */ -/* */ -/* 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; -{ - - if (ipftokentail == &token->ipt_next) - ipftokentail = token->ipt_pnext; - - *token->ipt_pnext = token->ipt_next; - if (token->ipt_next != NULL) - token->ipt_next->ipt_pnext = token->ipt_pnext; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_freetoken */ -/* Returns: None. */ -/* Parameters: token(I) - pointer to token structure */ -/* */ -/* 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. */ -/* ------------------------------------------------------------------------ */ -void ipf_freetoken(token) -ipftoken_t *token; -{ - void *data, **datap; - - ipf_unlinktoken(token); - - data = token->ipt_data; - datap = &data; - - if ((data != NULL) && (data != (void *)-1)) { - switch (token->ipt_type) - { - case IPFGENITER_IPF : - (void) fr_derefrule((frentry_t **)datap); - break; - case IPFGENITER_IPNAT : - WRITE_ENTER(&ipf_nat); - fr_ipnatderef((ipnat_t **)datap); - RWLOCK_EXIT(&ipf_nat); - break; - case IPFGENITER_NAT : - fr_natderef((nat_t **)datap); - break; - case IPFGENITER_STATE : - fr_statederef((ipstate_t **)datap); - break; - case IPFGENITER_FRAG : -#ifdef USE_MUTEXES - fr_fragderef((ipfr_t **)datap, &ipf_frag); -#else - fr_fragderef((ipfr_t **)datap); -#endif - break; - case IPFGENITER_NATFRAG : -#ifdef USE_MUTEXES - fr_fragderef((ipfr_t **)datap, &ipf_natfrag); -#else - fr_fragderef((ipfr_t **)datap); -#endif - break; - case IPFGENITER_HOSTMAP : - WRITE_ENTER(&ipf_nat); - fr_hostmapdel((hostmap_t **)datap); - RWLOCK_EXIT(&ipf_nat); - break; - default : -#ifdef IPFILTER_LOOKUP - ip_lookup_iterderef(token->ipt_type, data); -#endif - break; - } - } - - KFREE(token); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_getnextrule */ -/* Returns: int - 0 = success, else error */ -/* Parameters: 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 */ -/* the ipfobj_t structure to determine what should be the next rule to */ -/* return. Once the ipfruleiter_t has been brought in, it then tries to */ -/* find the 'next rule'. This may include searching rule group lists or */ -/* just be as simple as looking at the 'next' field in the rule structure. */ -/* 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) -{ - frentry_t *fr, *next, zero; - int error, count, out; - ipfruleiter_t it; - frgroup_t *fg; - char *dst; - - if (t == NULL || ptr == NULL) - return EFAULT; - error = fr_inobj(ptr, &it, IPFOBJ_IPFITER); - if (error != 0) - return error; - if ((it.iri_inout < 0) || (it.iri_inout > 3)) - return EINVAL; - if ((it.iri_active != 0) && (it.iri_active != 1)) - return EINVAL; - if (it.iri_nrules == 0) - return ENOSPC; - if (it.iri_rule == NULL) - return EFAULT; - - out = it.iri_inout & F_OUT; - fr = t->ipt_data; - READ_ENTER(&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]; - } else { - if (it.iri_v == 4) - next = ipfilter[out][it.iri_active]; - else - next = ipfilter6[out][it.iri_active]; - } - } else { - fg = fr_findgroup(it.iri_group, IPL_LOGIPF, - it.iri_active, NULL); - if (fg != NULL) - next = fg->fg_start; - else - next = NULL; - } - } else { - next = fr->fr_next; - } - - 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->fr_data != NULL) { - dst += sizeof(*next); - error = COPYOUT(next->fr_data, dst, next->fr_dsize); - if (error != 0) - error = EFAULT; - else - dst += next->fr_dsize; - } - - if ((count == 1) || (error != 0)) - break; - - count--; - - READ_ENTER(&ipf_mutex); - next = next->fr_next; - } - - if (fr != NULL) { - (void) fr_derefrule(&fr); - } - - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_frruleiter */ -/* Returns: int - 0 = success, else error */ -/* Parameters: 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 */ -/* 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; -{ - ipftoken_t *token; - int error; - - token = ipf_findtoken(IPFGENITER_IPF, uid, ctx); - if (token != NULL) - error = ipf_getnextrule(token, data); - else - error = EFAULT; - RWLOCK_EXIT(&ipf_tokens); - - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_geniter */ -/* Returns: int - 0 = success, else error */ -/* Parameters: token(I) - pointer to ipftoken_t structure */ -/* itp(I) - */ -/* */ -/* ------------------------------------------------------------------------ */ -static int ipf_geniter(token, itp) -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 - break; - default : - error = EINVAL; - break; - } - - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_genericiter */ -/* Returns: int - 0 = success, else error */ -/* Parameters: data(I) - the token type to match */ -/* uid(I) - uid owning the token */ -/* ptr(I) - context pointer for the token */ -/* */ -/* ------------------------------------------------------------------------ */ -int ipf_genericiter(data, uid, ctx) -void *data, *ctx; -int uid; -{ - ipftoken_t *token; - ipfgeniter_t iter; - int error; - - error = fr_inobj(data, &iter, IPFOBJ_GENITER); - if (error != 0) - return error; - - token = ipf_findtoken(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); - - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_ipf_ioctl */ -/* Returns: int - 0 = success, else error */ -/* Parameters: 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 */ -/* ptr(I) - context pointer for the token */ -/* */ -/* 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; -{ - friostat_t fio; - int error, tmp; - SPL_INT(s); - - switch (cmd) - { - case SIOCFRENB : - if (!(mode & FWRITE)) - error = EPERM; - else { - error = BCOPYIN(data, &tmp, sizeof(tmp)); - if (error != 0) { - error = EFAULT; - break; - } - - RWLOCK_EXIT(&ipf_global); - WRITE_ENTER(&ipf_global); - if (tmp) { - if (fr_running > 0) - error = 0; - else - error = ipfattach(); - if (error == 0) - fr_running = 1; - else - (void) ipfdetach(); - } else { - error = ipfdetach(); - if (error == 0) - fr_running = -1; - } - } - break; - - case SIOCIPFSET : - if (!(mode & FWRITE)) { - error = EPERM; - break; - } - /* FALLTHRU */ - case SIOCIPFGETNEXT : - case SIOCIPFGET : - error = fr_ipftune(cmd, (void *)data); - break; - - case SIOCSETFF : - if (!(mode & FWRITE)) - error = EPERM; - else { - error = BCOPYIN(data, &fr_flags, sizeof(fr_flags)); - if (error != 0) - error = EFAULT; - } - break; - - case SIOCGETFF : - error = BCOPYOUT(&fr_flags, data, sizeof(fr_flags)); - if (error != 0) - error = EFAULT; - break; - - case SIOCFUNCL : - error = fr_resolvefunc((void *)data); - break; - - case SIOCINAFR : - case SIOCRMAFR : - case SIOCADAFR : - case SIOCZRLST : - if (!(mode & FWRITE)) - error = EPERM; - else - error = frrequest(IPL_LOGIPF, cmd, data, fr_active, 1); - break; - - case SIOCINIFR : - case SIOCRMIFR : - case SIOCADIFR : - if (!(mode & FWRITE)) - error = EPERM; - else - error = frrequest(IPL_LOGIPF, cmd, data, - 1 - fr_active, 1); - break; - - case SIOCSWAPA : - if (!(mode & FWRITE)) - 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) - error = EFAULT; - else - fr_active = 1 - fr_active; - RWLOCK_EXIT(&ipf_mutex); - } - break; - - case SIOCGETFS : - fr_getstat(&fio); - error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT); - break; - - case SIOCFRZST : - if (!(mode & FWRITE)) - error = EPERM; - else - error = fr_zerostats(data); - break; - - case SIOCIPFFL : - if (!(mode & FWRITE)) - error = EPERM; - else { - error = BCOPYIN(data, &tmp, sizeof(tmp)); - if (!error) { - tmp = frflush(IPL_LOGIPF, 4, tmp); - error = BCOPYOUT(&tmp, data, sizeof(tmp)); - if (error != 0) - error = EFAULT; - } else - error = EFAULT; - } - break; - -#ifdef USE_INET6 - case SIOCIPFL6 : - if (!(mode & FWRITE)) - error = EPERM; - else { - error = BCOPYIN(data, &tmp, sizeof(tmp)); - if (!error) { - tmp = frflush(IPL_LOGIPF, 6, tmp); - error = BCOPYOUT(&tmp, data, sizeof(tmp)); - if (error != 0) - error = EFAULT; - } else - 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; - break; - -#ifdef IPFILTER_LOG - case SIOCIPFFB : - if (!(mode & FWRITE)) - error = EPERM; - else { - tmp = ipflog_clear(IPL_LOGIPF); - error = BCOPYOUT(&tmp, data, sizeof(tmp)); - if (error) - error = EFAULT; - } - break; -#endif /* IPFILTER_LOG */ - - case SIOCFRSYN : - if (!(mode & FWRITE)) - error = EPERM; - else { - RWLOCK_EXIT(&ipf_global); - WRITE_ENTER(&ipf_global); -#ifdef MENTAT - error = ipfsync(); -#else - frsync(NULL); - error = 0; -#endif - - } - break; - - case SIOCGFRST : - error = fr_outobj((void *)data, fr_fragstats(), - IPFOBJ_FRAGSTAT); - break; - -#ifdef IPFILTER_LOG - case FIONREAD : - tmp = (int)iplused[IPL_LOGIPF]; - - error = BCOPYOUT(&tmp, data, sizeof(tmp)); - break; -#endif - - case SIOCIPFITER : - SPL_SCHED(s); - error = ipf_frruleiter(data, uid, ctx); - SPL_X(s); - break; - - case SIOCGENITER : - SPL_SCHED(s); - error = ipf_genericiter(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); - break; - - default : - error = EINVAL; - break; - } - - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipf_queueflush */ -/* Returns: int - number of entries flushed (0 = none) */ -/* Parameters: 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. */ -/* touched */ -/* die fr_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 */ -/* 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. */ -/* - 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 */ -/* */ -/* 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. */ -/* ------------------------------------------------------------------------ */ -int ipf_queueflush(deletefn, ipfqs, userqs) -ipftq_delete_fn_t deletefn; -ipftq_t *ipfqs, *userqs; -{ - u_long interval, istart, iend; - ipftq_t *ifq, *ifqnext; - ipftqent_t *tqe, *tqn; - int 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)) { - istart = IPF_TTLVAL(86400 * 4); - interval = IPF_TTLVAL(43200); - } else if (fr_ticks > IPF_TTLVAL(1800 * 15 / 10)) { - istart = IPF_TTLVAL(43200); - interval = IPF_TTLVAL(1800); - } else if (fr_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) - istart = interval; - else - istart = (fr_ticks / interval) * interval; - } - - iend = fr_ticks - interval; - removed = 0; - - for (;;) { - u_long try; - - try = fr_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) - removed++; - } - } - - for (ifq = userqs; ifq != NULL; ifq = ifqnext) { - ifqnext = 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) - removed++; - } - } - - if (try >= iend) { - if (removed > 0) - break; - if (interval == IPF_TTLVAL(43200)) { - interval = IPF_TTLVAL(1800); - } else if (interval == IPF_TTLVAL(1800)) { - interval = IPF_TTLVAL(30); - } else { - break; - } - if (interval >= fr_ticks) - break; - - iend = fr_ticks - interval; - } - istart -= interval; - } - - return removed; -} diff --git a/sys/contrib/ipfilter/netinet/ip_auth.c b/sys/contrib/ipfilter/netinet/ip_auth.c deleted file mode 100644 index 11bd07b..0000000 --- a/sys/contrib/ipfilter/netinet/ip_auth.c +++ /dev/null @@ -1,1048 +0,0 @@ -/* - * Copyright (C) 1998-2003 by Darren Reed & Guido van Rooij. - * - * 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) -# include <stdio.h> -# include <stdlib.h> -# include <string.h> -# define _KERNEL -# ifdef __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(linux) -# include <sys/protosw.h> -#endif -#include <sys/socket.h> -#if defined(_KERNEL) -# include <sys/systm.h> -# if !defined(__SVR4) && !defined(__svr4__) && !defined(linux) -# 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 (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000) -# include <sys/queue.h> -#endif -#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) -# include <machine/cpu.h> -#endif -#if defined(_KERNEL) && defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) -# include <sys/proc.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> -#if !defined(_KERNEL) && !defined(__osf__) && !defined(__sgi) -# define KERNEL -# define _KERNEL -# define NOT_KERNEL -#endif -#if !defined(linux) -# include <netinet/ip_var.h> -#endif -#ifdef NOT_KERNEL -# undef _KERNEL -# undef KERNEL -#endif -#include <netinet/tcp.h> -#if defined(IRIX) && (IRIX < 60516) /* IRIX < 6 */ -extern struct ifqueue ipintrq; /* ip packet input queue */ -#else -# if !defined(__hpux) && !defined(linux) -# if __FreeBSD_version >= 300000 -# include <net/if_var.h> -# if __FreeBSD_version >= 500042 -# define IF_QFULL _IF_QFULL -# define IF_DROP _IF_DROP -# endif /* __FreeBSD_version >= 500042 */ -# endif -# include <netinet/in_var.h> -# include <netinet/tcp_fsm.h> -# endif -#endif -#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_auth.h" -#if !defined(MENTAT) && !defined(linux) -# include <net/netisr.h> -# ifdef __FreeBSD__ -# include <machine/cpufunc.h> -# endif -#endif -#if (__FreeBSD_version >= 300000) -# include <sys/malloc.h> -# if defined(_KERNEL) && !defined(IPFILTER_LKM) -# include <sys/libkern.h> -# include <sys/systm.h> -# endif -#endif -/* END OF INCLUDES */ - -#if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.24 2007/09/09 11:32:04 darrenr Exp $"; -#endif - - -#if SOLARIS && defined(_KERNEL) -extern kcondvar_t ipfauthwait; -extern struct pollhead iplpollhead[IPL_LOGSIZE]; -#endif /* SOLARIS */ -#if defined(linux) && defined(_KERNEL) -wait_queue_head_t fr_authnext_linux; -#endif - -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 */ -/* Returns: int - 0 == success, else error */ -/* Parameters: None */ -/* */ -/* Allocate memory and initialise data structures used in handling auth */ -/* rules. */ -/* ------------------------------------------------------------------------ */ -int fr_authinit() -{ - KMALLOCS(fr_auth, frauth_t *, fr_authsize * sizeof(*fr_auth)); - if (fr_auth != NULL) - bzero((char *)fr_auth, fr_authsize * sizeof(*fr_auth)); - else - return -1; - - KMALLOCS(fr_authpkts, mb_t **, fr_authsize * sizeof(*fr_authpkts)); - if (fr_authpkts != NULL) - bzero((char *)fr_authpkts, fr_authsize * sizeof(*fr_authpkts)); - else - return -2; - - 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); -#endif - - fr_auth_init = 1; - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_checkauth */ -/* 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 */ -/* */ -/* Check if a packet has authorization. If the packet is found to match an */ -/* authorization result and that would result in a feedback loop (i.e. it */ -/* will end up returning FR_AUTH) then return FR_BLOCK instead. */ -/* ------------------------------------------------------------------------ */ -frentry_t *fr_checkauth(fin, passp) -fr_info_t *fin; -u_32_t *passp; -{ - frentry_t *fr; - frauth_t *fra; - u_32_t pass; - u_short id; - ip_t *ip; - int i; - - if (fr_auth_lock || !fr_authused) - return NULL; - - ip = fin->fin_ip; - id = ip->ip_id; - - READ_ENTER(&ipf_auth); - for (i = fr_authstart; i != fr_authend; ) { - /* - * index becomes -2 only after an SIOCAUTHW. Check this in - * case the same packet gets sent again and it hasn't yet been - * auth'd. - */ - fra = fr_auth + i; - if ((fra->fra_index == -2) && (id == fra->fra_info.fin_id) && - !bcmp((char *)fin, (char *)&fra->fra_info, FI_CSIZE)) { - /* - * Avoid feedback loop. - */ - if (!(pass = fra->fra_pass) || (FR_ISAUTH(pass))) - pass = FR_BLOCK; - /* - * Create a dummy rule for the stateful checking to - * use and return. Zero out any values we don't - * trust from userland! - */ - if ((pass & FR_KEEPSTATE) || ((pass & FR_KEEPFRAG) && - (fin->fin_flx & FI_FRAG))) { - KMALLOC(fr, frentry_t *); - if (fr) { - bcopy((char *)fra->fra_info.fin_fr, - (char *)fr, sizeof(*fr)); - fr->fr_grp = NULL; - fr->fr_ifa = fin->fin_ifp; - fr->fr_func = NULL; - fr->fr_ref = 1; - fr->fr_flags = pass; - fr->fr_ifas[1] = NULL; - fr->fr_ifas[2] = NULL; - fr->fr_ifas[3] = NULL; - } - } else - fr = fra->fra_info.fin_fr; - fin->fin_fr = fr; - RWLOCK_EXIT(&ipf_auth); - - WRITE_ENTER(&ipf_auth); - /* - * fr_authlist 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_authstats.fas_hits++; - fra->fra_index = -1; - fr_authused--; - if (i == fr_authstart) { - while (fra->fra_index == -1) { - i++; - fra++; - if (i == fr_authsize) { - i = 0; - fra = fr_auth; - } - fr_authstart = i; - if (i == fr_authend) - break; - } - if (fr_authstart == fr_authend) { - fr_authnext = 0; - fr_authstart = fr_authend = 0; - } - } - RWLOCK_EXIT(&ipf_auth); - if (passp != NULL) - *passp = pass; - ATOMIC_INC64(fr_authstats.fas_hits); - return fr; - } - i++; - if (i == fr_authsize) - i = 0; - } - fr_authstats.fas_miss++; - RWLOCK_EXIT(&ipf_auth); - ATOMIC_INC64(fr_authstats.fas_miss); - return NULL; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_newauth */ -/* Returns: int - 0 == success, else error */ -/* Parameters: m(I) - pointer to mb_t with packet in it */ -/* fin(I) - pointer to packet information */ -/* */ -/* Check if we have room in the auth array to hold details for another */ -/* packet. If we do, store it and wake up any user programs which are */ -/* waiting to hear about these events. */ -/* ------------------------------------------------------------------------ */ -int fr_newauth(m, fin) -mb_t *m; -fr_info_t *fin; -{ -#if defined(_KERNEL) && defined(MENTAT) - qpktinfo_t *qpi = fin->fin_qpi; -#endif - frauth_t *fra; -#if !defined(sparc) && !defined(m68k) - ip_t *ip; -#endif - int i; - - if (fr_auth_lock) - return 0; - - WRITE_ENTER(&ipf_auth); - if (((fr_authend + 1) % fr_authsize) == fr_authstart) { - fr_authstats.fas_nospace++; - RWLOCK_EXIT(&ipf_auth); - return 0; - } - - fr_authstats.fas_added++; - fr_authused++; - i = fr_authend++; - if (fr_authend == fr_authsize) - fr_authend = 0; - RWLOCK_EXIT(&ipf_auth); - - fra = fr_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; - bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); -#if !defined(sparc) && !defined(m68k) - /* - * No need to copyback here as we want to undo the changes, not keep - * them. - */ - ip = fin->fin_ip; -# if defined(MENTAT) && defined(_KERNEL) - if ((ip == (ip_t *)m->b_rptr) && (fin->fin_v == 4)) -# endif - { - register u_short bo; - - bo = ip->ip_len; - ip->ip_len = htons(bo); - bo = ip->ip_off; - ip->ip_off = htons(bo); - } -#endif -#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); -#else - fr_authpkts[i] = m; - WAKEUP(&fr_authnext,0); -#endif - return 1; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_auth_ioctl */ -/* Returns: int - 0 == success, else error */ -/* Parameters: data(IO) - pointer to ioctl data */ -/* cmd(I) - ioctl command */ -/* mode(I) - mode flags associated with open descriptor */ -/* uid(I) - uid associatd with application making the call */ -/* 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 */ -/* ------------------------------------------------------------------------ */ -int fr_auth_ioctl(data, cmd, mode, uid, ctx) -caddr_t data; -ioctlcmd_t cmd; -int mode, uid; -void *ctx; -{ - int error = 0, i; - SPL_INT(s); - - switch (cmd) - { - case SIOCGENITER : - { - ipftoken_t *token; - ipfgeniter_t iter; - - error = fr_inobj(data, &iter, IPFOBJ_GENITER); - if (error != 0) - break; - - SPL_SCHED(s); - token = ipf_findtoken(IPFGENITER_AUTH, uid, ctx); - if (token != NULL) - error = fr_authgeniter(token, &iter); - else - error = ESRCH; - RWLOCK_EXIT(&ipf_tokens); - SPL_X(s); - - break; - } - - case SIOCADAFR : - case SIOCRMAFR : - if (!(mode & FWRITE)) - error = EPERM; - else - error = frrequest(IPL_LOGAUTH, cmd, data, - fr_active, 1); - break; - - case SIOCSTLCK : - if (!(mode & FWRITE)) { - error = EPERM; - break; - } - error = fr_lock(data, &fr_auth_lock); - break; - - case SIOCATHST: - fr_authstats.fas_faelist = fae_list; - error = fr_outobj(data, &fr_authstats, IPFOBJ_AUTHSTAT); - break; - - case SIOCIPFFL: - SPL_NET(s); - WRITE_ENTER(&ipf_auth); - i = fr_authflush(); - RWLOCK_EXIT(&ipf_auth); - SPL_X(s); - error = BCOPYOUT((char *)&i, data, sizeof(i)); - if (error != 0) - error = EFAULT; - break; - - case SIOCAUTHW: - error = fr_authwait(data); - break; - - case SIOCAUTHR: - error = fr_authreply(data); - break; - - default : - error = EINVAL; - break; - } - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* 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 */ -/* Returns: None */ -/* Parameters: None */ -/* */ -/* Slowly expire held auth records. Timeouts are set in expectation of */ -/* this being called twice per second. */ -/* ------------------------------------------------------------------------ */ -void fr_authexpire() -{ - frauthent_t *fae, **faep; - frentry_t *fr, **frp; - frauth_t *fra; - mb_t *m; - int i; - SPL_INT(s); - - if (fr_auth_lock) - return; - - SPL_NET(s); - WRITE_ENTER(&ipf_auth); - for (i = 0, fra = fr_auth; i < fr_authsize; 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--; - } - } - - /* - * Expire pre-auth rules - */ - for (faep = &fae_list; ((fae = *faep) != NULL); ) { - fae->fae_age--; - if (fae->fae_age == 0) { - fr_authderef(&fae); - fr_authstats.fas_expire++; - } else - faep = &fae->fae_next; - } - if (fae_list != NULL) - ipauth = &fae_list->fae_fr; - else - ipauth = NULL; - - for (frp = &fr_authlist; ((fr = *frp) != NULL); ) { - if (fr->fr_ref == 1) { - *frp = fr->fr_next; - KFREE(fr); - } else - frp = &fr->fr_next; - } - RWLOCK_EXIT(&ipf_auth); - SPL_X(s); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_preauthcmd */ -/* 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; -{ - frauthent_t *fae, **faep; - int error = 0; - SPL_INT(s); - - if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) - return EIO; - - for (faep = &fae_list; ((fae = *faep) != NULL); ) { - if (&fae->fae_fr == fr) - break; - else - faep = &fae->fae_next; - } - - if (cmd == (ioctlcmd_t)SIOCRMAFR) { - if (fr == NULL || frptr == NULL) - error = EINVAL; - else if (fae == NULL) - error = ESRCH; - else { - SPL_NET(s); - WRITE_ENTER(&ipf_auth); - *faep = fae->fae_next; - if (ipauth == &fae->fae_fr) - ipauth = fae_list ? &fae_list->fae_fr : NULL; - RWLOCK_EXIT(&ipf_auth); - SPL_X(s); - - KFREE(fae); - } - } else if (fr != NULL && frptr != NULL) { - KMALLOC(fae, frauthent_t *); - if (fae != NULL) { - bcopy((char *)fr, (char *)&fae->fae_fr, - sizeof(*fr)); - SPL_NET(s); - WRITE_ENTER(&ipf_auth); - fae->fae_age = fr_defaultauthage; - 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); - SPL_X(s); - } else - error = ENOMEM; - } else - error = EINVAL; - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_authflush */ -/* Returns: int - number of auth entries flushed */ -/* Parameters: None */ -/* Locks: WRITE(ipf_auth) */ -/* */ -/* This function flushs the fr_authpkts 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() -{ - register int i, num_flushed; - mb_t *m; - - if (fr_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; - /* perhaps add & use a flush counter inst.*/ - fr_authstats.fas_expire++; - fr_authused--; - num_flushed++; - } - } - - fr_authstart = 0; - fr_authend = 0; - fr_authnext = 0; - - return num_flushed; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_auth_waiting */ -/* Returns: int - 0 = no pakcets wiating, 1 = packets waiting. */ -/* Parameters: None */ -/* */ -/* Simple truth check to see if there are any packets waiting in the auth */ -/* queue. */ -/* ------------------------------------------------------------------------ */ -int fr_auth_waiting() -{ - return (fr_authused != 0); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_authgeniter */ -/* Returns: int - 0 == success, else error */ -/* Parameters: token(I) - pointer to ipftoken structure */ -/* itp(I) - pointer to ipfgeniter structure */ -/* */ -/* ------------------------------------------------------------------------ */ -int fr_authgeniter(token, itp) -ipftoken_t *token; -ipfgeniter_t *itp; -{ - frauthent_t *fae, *next, zero; - int error; - - if (itp->igi_data == NULL) - return EFAULT; - - if (itp->igi_type != IPFGENITER_AUTH) - return EINVAL; - - fae = token->ipt_data; - READ_ENTER(&ipf_auth); - if (fae == NULL) { - next = fae_list; - } else { - next = fae->fae_next; - } - - 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; - } - } else { - bzero(&zero, sizeof(zero)); - next = &zero; - } - 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); - } - - /* - * 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; - - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_authderef */ -/* Returns: None */ -/* Parameters: faep(IO) - pointer to caller's frauthent_t pointer */ -/* Locks: WRITE(ipf_auth) */ -/* */ -/* 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; -{ - frauthent_t *fae; - - fae = *faep; - *faep = NULL; - - fae->fae_ref--; - if (fae->fae_ref == 0) { - KFREE(fae); - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_authwait */ -/* 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. */ -/* ------------------------------------------------------------------------ */ -int fr_authwait(data) -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); - if (error != 0) - return error; - - /* - * XXX Locks are held below over calls to copyout...a better - * solution needs to be found so this isn't necessary. The situation - * 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); - - /* - * 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 (fr_authused > 0) { - while (fr_authpkts[fr_authnext] == NULL) { - fr_authnext++; - if (fr_authnext == fr_authsize) - fr_authnext = 0; - } - - error = fr_outobj(data, &fr_auth[fr_authnext], IPFOBJ_FRAUTH); - if (error != 0) - 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]; - len = MSGDSIZE(m); - if (len > auth.fra_len) - len = auth.fra_len; - auth.fra_len = len; - - for (t = auth.fra_buf; m && (len > 0); ) { - i = MIN(M_LEN(m), len); - error = copyoutptr(MTOD(m, char *), &t, i); - len -= i; - t += i; - if (error != 0) - return error; - m = m->m_next; - } - } - RWLOCK_EXIT(&ipf_auth); - - SPL_NET(s); - WRITE_ENTER(&ipf_auth); - fr_authnext++; - if (fr_authnext == fr_authsize) - fr_authnext = 0; - RWLOCK_EXIT(&ipf_auth); - SPL_X(s); - - return 0; - } - RWLOCK_EXIT(&ipf_auth); - - /* - * We exit ipf_global here because a program that enters in - * here will have a lock on it and goto sleep having this lock. - * If someone were to do an 'ipf -D' the system would then - * deadlock. The catch with releasing it here is that the - * caller of this function expects it to be held when we - * return so we have to reacquire it in here. - */ - RWLOCK_EXIT(&ipf_global); - - MUTEX_ENTER(&ipf_authmx); -#ifdef _KERNEL -# if SOLARIS - error = 0; - if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk)) - error = EINTR; -# else /* SOLARIS */ -# ifdef __hpux - { - lock_t *l; - - l = get_sleep_lock(&fr_authnext); - error = sleep(&fr_authnext, PZERO+1); - spinunlock(l); - } -# else -# ifdef __osf__ - error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0, - &ipf_authmx, MS_LOCK_SIMPLE); -# else - error = SLEEP(&fr_authnext, "fr_authnext"); -# endif /* __osf__ */ -# endif /* __hpux */ -# endif /* SOLARIS */ -#endif - MUTEX_EXIT(&ipf_authmx); - READ_ENTER(&ipf_global); - if (error == 0) - goto fr_authioctlloop; - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_authreply */ -/* Returns: int - 0 == success, else error */ -/* Parameters: data(I) - pointer to data from ioctl call */ -/* */ -/* This function is called by an application when it wants to return a */ -/* decision on a packet using the SIOCAUTHR ioctl. This is after it has */ -/* 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; -{ - frauth_t auth, *au = &auth, *fra; - int error, i; - mb_t *m; - SPL_INT(s); - - error = fr_inobj(data, &auth, IPFOBJ_FRAUTH); - if (error != 0) - return error; - - SPL_NET(s); - WRITE_ENTER(&ipf_auth); - - i = au->fra_index; - fra = fr_auth + i; - error = 0; - - /* - * Check the validity of the information being returned with two simple - * 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); - SPL_X(s); - return ESRCH; - } - - m = fr_authpkts[i]; - fra->fra_index = -2; - fra->fra_pass = au->fra_pass; - fr_authpkts[i] = NULL; - - RWLOCK_EXIT(&ipf_auth); - - /* - * Re-insert the packet back into the packet stream flowing through - * the kernel in a manner that will mean IPFilter sees the packet - * again. This is not the same as is done with fastroute, - * deliberately, as we want to resume the normal packet processing - * path for it. - */ -#ifdef _KERNEL - if ((m != NULL) && (au->fra_info.fin_out != 0)) { - error = ipf_inject(&fra->fra_info, m); - if (error != 0) { - error = ENOBUFS; - fr_authstats.fas_sendfail++; - } else { - fr_authstats.fas_sendok++; - } - } else if (m) { - error = ipf_inject(&fra->fra_info, m); - if (error != 0) { - error = ENOBUFS; - fr_authstats.fas_quefail++; - } else { - fr_authstats.fas_queok++; - } - } else { - error = EINVAL; - } - - /* - * If we experience an error which will result in the packet - * not being processed, make sure we advance to the next one. - */ - if (error == ENOBUFS) { - fr_authused--; - fra->fra_index = -1; - fra->fra_pass = 0; - if (i == fr_authstart) { - while (fra->fra_index == -1) { - i++; - if (i == fr_authsize) - i = 0; - fr_authstart = i; - if (i == fr_authend) - break; - } - if (fr_authstart == fr_authend) { - fr_authnext = 0; - fr_authstart = fr_authend = 0; - } - } - } -#endif /* _KERNEL */ - SPL_X(s); - - return 0; -} diff --git a/sys/contrib/ipfilter/netinet/ip_auth.h b/sys/contrib/ipfilter/netinet/ip_auth.h deleted file mode 100644 index 818497b..0000000 --- a/sys/contrib/ipfilter/netinet/ip_auth.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 1997-2001 by Darren Reed & Guido Van Rooij. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * $Id: ip_auth.h,v 2.16.2.3 2006/07/14 06:12:05 darrenr Exp $ - * - */ -#ifndef __IP_AUTH_H__ -#define __IP_AUTH_H__ - -#define FR_NUMAUTH 32 - -typedef struct frauth { - int fra_age; - int fra_len; - int fra_index; - u_32_t fra_pass; - fr_info_t fra_info; - char *fra_buf; -#ifdef MENTAT - queue_t *fra_q; - mb_t *fra_m; -#endif -} frauth_t; - -typedef struct frauthent { - struct frentry fae_fr; - struct frauthent *fae_next; - struct frauthent **fae_pnext; - u_long fae_age; - int fae_ref; -} frauthent_t; - -typedef struct fr_authstat { - U_QUAD_T fas_hits; - U_QUAD_T fas_miss; - u_long fas_nospace; - u_long fas_added; - u_long fas_sendfail; - u_long fas_sendok; - u_long fas_queok; - u_long fas_quefail; - u_long fas_expire; - frauthent_t *fas_faelist; -} fr_authstat_t; - - -extern frentry_t *ipauth; -extern struct fr_authstat fr_authstats; -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)); - -#endif /* __IP_AUTH_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h deleted file mode 100644 index 901d21b..0000000 --- a/sys/contrib/ipfilter/netinet/ip_compat.h +++ /dev/null @@ -1,2504 +0,0 @@ -/* - * Copyright (C) 1993-2001, 2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * @(#)ip_compat.h 1.8 1/14/96 - * $Id: ip_compat.h,v 2.142.2.57 2007/10/10 09:51:42 darrenr Exp $ - */ - -#ifndef __IP_COMPAT_H__ -#define __IP_COMPAT_H__ - -#ifndef __P -# ifdef __STDC__ -# define __P(x) x -# else -# define __P(x) () -# endif -#endif -#ifndef __STDC__ -# undef const -# define const -#endif - -#if defined(_KERNEL) || defined(KERNEL) || defined(__KERNEL__) -# undef KERNEL -# undef _KERNEL -# undef __KERNEL__ -# define KERNEL -# define _KERNEL -# define __KERNEL__ -#endif - -#ifndef SOLARIS -#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) -#endif -#if SOLARIS2 >= 8 -# ifndef USE_INET6 -# define USE_INET6 -# endif -#endif -#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \ - !defined(_KERNEL) && !defined(USE_INET6) && !defined(NOINET6) -# define USE_INET6 -#endif -#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105000000) && \ - !defined(_KERNEL) && !defined(USE_INET6) -# define USE_INET6 -# define IPFILTER_M_IPFILTER -#endif -#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 -#endif - -#if defined(BSD) && (BSD < 199103) && defined(__osf__) -# undef BSD -# define BSD 199103 -#endif - -#if defined(__SVR4) || defined(__svr4__) || defined(__sgi) -# define index strchr -# if !defined(_KERNEL) -# define bzero(a,b) memset(a,0,b) -# define bcmp memcmp -# define bcopy(a,b,c) memmove(b,a,c) -# endif -#endif - -#ifndef LIFNAMSIZ -# ifdef IF_NAMESIZE -# define LIFNAMSIZ IF_NAMESIZE -# else -# ifdef IFNAMSIZ -# define LIFNAMSIZ IFNAMSIZ -# else -# define LIFNAMSIZ 16 -# endif -# endif -#endif - -#if defined(__sgi) || defined(bsdi) || defined(__hpux) || defined(hpux) -struct ether_addr { - u_char ether_addr_octet[6]; -}; -#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 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 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 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 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 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 (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 SOLARIS2 < 6 -typedef struct uio uio_t; -# endif -typedef int ioctlcmd_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 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 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 - -# 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__ */ - - -/* ----------------------------------------------------------------------- */ -/* F R E E B S D */ -/* ----------------------------------------------------------------------- */ -#ifdef __FreeBSD__ -# 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) -/* - * 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 -# endif /* _KERNEL */ - -# if (__FreeBSD_version >= 500043) -# include <sys/mutex.h> -# if (__FreeBSD_version > 700014) -# 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. - */ -# 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); \ - else \ - sx_sunlock(&(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) -# define MUTEX_INIT(x,y) mtx_init(&(x)->ipf_lk, (y), NULL,\ - MTX_DEF) -# define MUTEX_DESTROY(x) mtx_destroy(&(x)->ipf_lk) -# define MUTEX_NUKE(x) bzero((x), sizeof(*(x))) -# 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_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) ; -extern int in_cksum __P((struct mbuf *, int)); -# 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 IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } -typedef struct mbuf mb_t; -# endif /* _KERNEL */ - -# if __FreeBSD__ < 3 -# include <machine/spl.h> -# else -# if __FreeBSD__ == 3 -# 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 - * filter rules. - */ -#if !defined(IPFILTER_BPF) -# if (defined(NBPF) && (NBPF > 0)) || (defined(DEV_BPF) && (DEV_BPF > 0)) || \ - (defined(NBPFILTER) && (NBPFILTER > 0)) -# define IPFILTER_BPF -# endif -#endif - -/* - * Userland locking primitives - */ -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 { - char *eMrw_owner; - char *eMrw_heldin; - u_int eMrw_magic; - short eMrw_read; - short eMrw_write; - int eMrw_heldat; -#ifdef __hpux - char eMm_fill[24]; -#endif -} eMrwlock_t; - -typedef union { -#ifdef KMUTEX_T - struct { - KMUTEX_T ipf_slk; - char *ipf_lname; - } ipf_lkun_s; -#endif - eMmutex_t ipf_emu; -} ipfmutex_t; - -typedef union { -#ifdef KRWLOCK_T - struct { - KRWLOCK_T ipf_slk; - char *ipf_lname; - int ipf_sr; - int ipf_sw; - u_int ipf_magic; - } ipf_lkun_s; -#endif - eMrwlock_t ipf_emu; -} ipfrwlock_t; - -#define ipf_lk ipf_lkun_s.ipf_slk -#define ipf_lname ipf_lkun_s.ipf_lname -#define ipf_isr ipf_lkun_s.ipf_sr -#define ipf_isw ipf_lkun_s.ipf_sw -#define ipf_magic ipf_lkun_s.ipf_magic - -#if !defined(__GNUC__) || \ - (defined(__FreeBSD_version) && (__FreeBSD_version >= 503000)) -# ifndef INLINE -# define INLINE -# endif -#else -# 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 *)); -#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, - * somewhere in userland. - */ -#ifndef _KERNEL -typedef struct mb_s { - struct mb_s *mb_next; - int mb_len; - 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) -# define GETKTIME(x) gettimeofday((struct timeval *)(x), NULL) -# undef MTOD -# define MTOD(m, t) ((t)(m)->mb_buf) -# define FREE_MB_T(x) -# define SLEEP(x,y) 1; -# define WAKEUP(x,y) ; -# define POLLWAKEUP(y) ; -# define IPF_PANIC(x,y) ; -# define PANIC(x,y) ; -# define SPL_SCHED(x) ; -# define SPL_NET(x) ; -# define SPL_IMP(x) ; -# define SPL_X(x) ; -# define KMALLOC(a,b) (a) = (b)malloc(sizeof(*a)) -# define KMALLOCS(a,b,c) (a) = (b)malloc(c) -# define KFREE(x) free(x) -# define KFREES(x,s) free(x) -# define GETIFP(x, v) get_unit(x,v) -# 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), \ - (b), (l)) -# define COPYBACK(m, o, l, b) bcopy((b), \ - MTOD((mb_t *)m, char *) + (o), \ - (l)) -# define UIOMOVE(a,b,c,d) ipfuiomove((caddr_t)a,b,c,d) -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 - -# define MUTEX_DESTROY(x) eMmutex_destroy(&(x)->ipf_emu) -# 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_NUKE(x) bzero((x), sizeof(*(x))) - -# define MUTEX_DOWNGRADE(x) eMrwlock_downgrade(&(x)->ipf_emu, \ - __FILE__, __LINE__) -# define READ_ENTER(x) eMrwlock_read_enter(&(x)->ipf_emu, \ - __FILE__, __LINE__) -# define RWLOCK_INIT(x, y) eMrwlock_init(&(x)->ipf_emu, y) -# define RWLOCK_EXIT(x) eMrwlock_exit(&(x)->ipf_emu) -# define RW_DESTROY(x) eMrwlock_destroy(&(x)->ipf_emu) -# define WRITE_ENTER(x) eMrwlock_write_enter(&(x)->ipf_emu, \ - __FILE__, \ - __LINE__) - -# define USE_MUTEXES 1 - -extern void eMmutex_destroy __P((eMmutex_t *)); -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 eMrwlock_destroy __P((eMrwlock_t *)); -extern void eMrwlock_exit __P((eMrwlock_t *)); -extern void eMrwlock_init __P((eMrwlock_t *, char *)); -extern void eMrwlock_read_enter __P((eMrwlock_t *, char *, int)); -extern void eMrwlock_write_enter __P((eMrwlock_t *, char *, int)); -extern void eMrwlock_downgrade __P((eMrwlock_t *, char *, int)); - -#endif - -#define MAX_IPV4HDR ((0xf << 2) + sizeof(struct icmp) + sizeof(ip_t) + 8) - -#ifndef IP_OFFMASK -# define IP_OFFMASK 0x1fff -#endif - - -/* - * On BSD's use quad_t as a guarantee for getting at least a 64bit sized - * object. - */ -#if BSD > 199306 -# define USE_QUAD_T -# define U_QUAD_T u_quad_t -# define QUAD_T quad_t -#else /* BSD > 199306 */ -# define U_QUAD_T u_long -# define QUAD_T long -#endif /* BSD > 199306 */ - - -#ifdef USE_INET6 -# if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \ - 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 - -#ifndef MAX -# define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#endif - -#if defined(_KERNEL) -# ifdef MENTAT -# 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)) -# include <uvm/uvm_extern.h> -# else -# include <vm/vm_extern.h> -extern vm_map_t kmem_map; -# endif -# include <sys/proc.h> -# else /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD_version >= 300000) */ -# include <vm/vm_kern.h> -# endif /* !__FreeBSD__ || (__FreeBSD__ && __FreeBSD_version >= 300000) */ - -# ifdef IPFILTER_M_IPFILTER -# include <sys/malloc.h> -MALLOC_DECLARE(M_IPFILTER); -# define _M_IPF M_IPFILTER -# else /* IPFILTER_M_IPFILTER */ -# ifdef M_PFIL -# define _M_IPF M_PFIL -# else -# ifdef M_IPFILTER -# define _M_IPF M_IPFILTER -# else -# define _M_IPF M_TEMP -# endif /* M_IPFILTER */ -# endif /* M_PFIL */ -# endif /* IPFILTER_M_IPFILTER */ -# 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 -# define KFREE(x) FREE((x), _M_IPF) -# define KFREES(x,s) FREE((x), _M_IPF) -# 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) -# define GETIFP(n, v) ifunit(n) -# endif /* (Free)BSD */ - -# if !defined(USE_MUTEXES) && !defined(SPL_NET) -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199407)) || \ - (defined(OpenBSD) && (OpenBSD >= 200006)) -# define SPL_NET(x) x = splsoftnet() -# else -# define SPL_IMP(x) x = splimp() -# define SPL_NET(x) x = splnet() -# endif /* NetBSD && (NetBSD <= 1991011) && (NetBSD >= 199407) */ -# if !defined(SPL_SCHED) -# define SPL_SCHED(x) x = splsched() -# endif -# define SPL_X(x) (void) splx(x) -# endif /* !USE_MUTEXES */ - -# ifndef FREE_MB_T -# define FREE_MB_T(m) m_freem(m) -# endif - -# ifndef MTOD -# define MTOD(m,t) mtod(m,t) -# endif - -# ifndef COPYIN -# 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) -# endif - -# ifndef KMALLOC -# define KMALLOC(a,b) (a) = (b)new_kmem_alloc(sizeof(*(a)), \ - KMEM_NOSLEEP) -# define KMALLOCS(a,b,c) (a) = (b)new_kmem_alloc((c), KMEM_NOSLEEP) -# endif - -# ifndef GET_MINOR -# define GET_MINOR(x) minor(x) -# endif -# define PANIC(x,y) if (x) panic y -#endif /* _KERNEL */ - -#if !defined(IFNAME) && !defined(_KERNEL) -# define IFNAME(x) ((struct ifnet *)x)->if_name -#endif -#ifndef COPYIFNAME -# define NEED_FRGETIFNAME -extern char *fr_getifname __P((struct ifnet *, char *)); -# define COPYIFNAME(v, x, b) \ - fr_getifname((struct ifnet *)x, b) -#endif - -#ifndef ASSERT -# ifdef _KERNEL -# define ASSERT(x) -# else -# define ASSERT(x) do { if (!(x)) abort(); } while (0) -# endif -#endif - -#ifndef BCOPYIN -# define BCOPYIN(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) -# define BCOPYOUT(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) -#endif - -/* - * Because the ctype(3) posix definition, if used "safely" in code everywhere, - * would mean all normal code that walks through strings needed casts. Yuck. - */ -#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)) -#define ISLOWER(x) islower((u_char)(x)) -#define TOUPPER(x) toupper((u_char)(x)) -#define TOLOWER(x) tolower((u_char)(x)) - -/* - * If mutexes aren't being used, turn all the mutex functions into null-ops. - */ -#if !defined(USE_MUTEXES) -# define USE_SPL 1 -# undef RW_DESTROY -# undef MUTEX_INIT -# undef MUTEX_NUKE -# undef MUTEX_DESTROY -# define MUTEX_ENTER(x) ; -# define READ_ENTER(x) ; -# define WRITE_ENTER(x) ; -# define MUTEX_DOWNGRADE(x) ; -# define RWLOCK_INIT(x, y) ; -# define RWLOCK_EXIT(x) ; -# define RW_DESTROY(x) ; -# define MUTEX_EXIT(x) ; -# define MUTEX_INIT(x,y) ; -# define MUTEX_DESTROY(x) ; -# define MUTEX_NUKE(x) ; -#endif /* !USE_MUTEXES */ -#ifndef ATOMIC_INC -# define ATOMIC_INC(x) (x)++ -# define ATOMIC_DEC(x) (x)-- -#endif - -#if defined(USE_SPL) && defined(_KERNEL) -# define SPL_INT(x) int x -#else -# define SPL_INT(x) -#endif - -/* - * If there are no atomic operations for bit sizes defined, define them to all - * use a generic one that works for all sizes. - */ -#ifndef ATOMIC_INCL -# 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 -typedef struct tcphdr tcphdr_t; -typedef struct udphdr udphdr_t; -#endif -typedef struct icmp icmphdr_t; -typedef struct ip ip_t; -typedef struct ether_header ether_header_t; -typedef struct tcpiphdr tcpiphdr_t; - -#ifndef FR_GROUPLEN -# define FR_GROUPLEN 16 -#endif - -#ifndef offsetof -# define offsetof(t,m) (int)((&((t *)0L)->m)) -#endif - -/* - * This set of macros has been brought about because on Tru64 it is not - * possible to easily assign or examine values in a structure that are - * bit fields. - */ -#ifndef IP_V -# define IP_V(x) (x)->ip_v -#endif -#ifndef IP_V_A -# define IP_V_A(x,y) (x)->ip_v = (y) -#endif -#ifndef IP_HL -# define IP_HL(x) (x)->ip_hl -#endif -#ifndef IP_HL_A -# define IP_HL_A(x,y) (x)->ip_hl = ((y) & 0xf) -#endif -#ifndef TCP_X2 -# define TCP_X2(x) (x)->th_x2 -#endif -#ifndef TCP_X2_A -# define TCP_X2_A(x,y) (x)->th_x2 = (y) -#endif -#ifndef TCP_OFF -# define TCP_OFF(x) (x)->th_off -#endif -#ifndef TCP_OFF_A -# define TCP_OFF_A(x,y) (x)->th_off = (y) -#endif -#define IPMINLEN(i, h) ((i)->ip_len >= (IP_HL(i) * 4 + sizeof(struct h))) - - -/* - * XXX - This is one of those *awful* hacks which nobody likes - */ -#ifdef ultrix -#define A_A -#else -#define A_A & -#endif - -#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) -# define m_act m_nextpkt -#endif - -/* - * Security Options for Intenet Protocol (IPSO) as defined in RFC 1108. - * - * Basic Option - * - * 00000001 - (Reserved 4) - * 00111101 - Top Secret - * 01011010 - Secret - * 10010110 - Confidential - * 01100110 - (Reserved 3) - * 11001100 - (Reserved 2) - * 10101011 - Unclassified - * 11110001 - (Reserved 1) - */ -#define IPSO_CLASS_RES4 0x01 -#define IPSO_CLASS_TOPS 0x3d -#define IPSO_CLASS_SECR 0x5a -#define IPSO_CLASS_CONF 0x96 -#define IPSO_CLASS_RES3 0x66 -#define IPSO_CLASS_RES2 0xcc -#define IPSO_CLASS_UNCL 0xab -#define IPSO_CLASS_RES1 0xf1 - -#define IPSO_AUTH_GENSER 0x80 -#define IPSO_AUTH_ESI 0x40 -#define IPSO_AUTH_SCI 0x20 -#define IPSO_AUTH_NSA 0x10 -#define IPSO_AUTH_DOE 0x08 -#define IPSO_AUTH_UN 0x06 -#define IPSO_AUTH_FTE 0x01 - -/* - * IP option #defines - */ -#undef IPOPT_RR -#define IPOPT_RR 7 -#undef IPOPT_ZSU -#define IPOPT_ZSU 10 /* ZSU */ -#undef IPOPT_MTUP -#define IPOPT_MTUP 11 /* MTUP */ -#undef IPOPT_MTUR -#define IPOPT_MTUR 12 /* MTUR */ -#undef IPOPT_ENCODE -#define IPOPT_ENCODE 15 /* ENCODE */ -#undef IPOPT_TS -#define IPOPT_TS 68 -#undef IPOPT_TR -#define IPOPT_TR 82 /* TR */ -#undef IPOPT_SECURITY -#define IPOPT_SECURITY 130 -#undef IPOPT_LSRR -#define IPOPT_LSRR 131 -#undef IPOPT_E_SEC -#define IPOPT_E_SEC 133 /* E-SEC */ -#undef IPOPT_CIPSO -#define IPOPT_CIPSO 134 /* CIPSO */ -#undef IPOPT_SATID -#define IPOPT_SATID 136 -#ifndef IPOPT_SID -# define IPOPT_SID IPOPT_SATID -#endif -#undef IPOPT_SSRR -#define IPOPT_SSRR 137 -#undef IPOPT_ADDEXT -#define IPOPT_ADDEXT 147 /* ADDEXT */ -#undef IPOPT_VISA -#define IPOPT_VISA 142 /* VISA */ -#undef IPOPT_IMITD -#define IPOPT_IMITD 144 /* IMITD */ -#undef IPOPT_EIP -#define IPOPT_EIP 145 /* EIP */ -#undef IPOPT_RTRALRT -#define IPOPT_RTRALRT 148 /* RTRALRT */ -#undef IPOPT_SDB -#define IPOPT_SDB 149 -#undef IPOPT_NSAPA -#define IPOPT_NSAPA 150 -#undef IPOPT_DPS -#define IPOPT_DPS 151 -#undef IPOPT_UMP -#define IPOPT_UMP 152 -#undef IPOPT_FINN -#define IPOPT_FINN 205 /* FINN */ - -#ifndef TCPOPT_EOL -# define TCPOPT_EOL 0 -#endif -#ifndef TCPOPT_NOP -# define TCPOPT_NOP 1 -#endif -#ifndef TCPOPT_MAXSEG -# define TCPOPT_MAXSEG 2 -#endif -#ifndef TCPOLEN_MAXSEG -# define TCPOLEN_MAXSEG 4 -#endif -#ifndef TCPOPT_WINDOW -# define TCPOPT_WINDOW 3 -#endif -#ifndef TCPOLEN_WINDOW -# define TCPOLEN_WINDOW 3 -#endif -#ifndef TCPOPT_SACK_PERMITTED -# define TCPOPT_SACK_PERMITTED 4 -#endif -#ifndef TCPOLEN_SACK_PERMITTED -# define TCPOLEN_SACK_PERMITTED 2 -#endif -#ifndef TCPOPT_SACK -# define TCPOPT_SACK 5 -#endif -#ifndef TCPOPT_TIMESTAMP -# define TCPOPT_TIMESTAMP 8 -#endif - -#ifndef ICMP_MINLEN -# define ICMP_MINLEN 8 -#endif -#ifndef ICMP_ECHOREPLY -# define ICMP_ECHOREPLY 0 -#endif -#ifndef ICMP_UNREACH -# define ICMP_UNREACH 3 -#endif -#ifndef ICMP_UNREACH_NET -# define ICMP_UNREACH_NET 0 -#endif -#ifndef ICMP_UNREACH_HOST -# define ICMP_UNREACH_HOST 1 -#endif -#ifndef ICMP_UNREACH_PROTOCOL -# define ICMP_UNREACH_PROTOCOL 2 -#endif -#ifndef ICMP_UNREACH_PORT -# define ICMP_UNREACH_PORT 3 -#endif -#ifndef ICMP_UNREACH_NEEDFRAG -# define ICMP_UNREACH_NEEDFRAG 4 -#endif -#ifndef ICMP_UNREACH_SRCFAIL -# define ICMP_UNREACH_SRCFAIL 5 -#endif -#ifndef ICMP_UNREACH_NET_UNKNOWN -# define ICMP_UNREACH_NET_UNKNOWN 6 -#endif -#ifndef ICMP_UNREACH_HOST_UNKNOWN -# define ICMP_UNREACH_HOST_UNKNOWN 7 -#endif -#ifndef ICMP_UNREACH_ISOLATED -# define ICMP_UNREACH_ISOLATED 8 -#endif -#ifndef ICMP_UNREACH_NET_PROHIB -# define ICMP_UNREACH_NET_PROHIB 9 -#endif -#ifndef ICMP_UNREACH_HOST_PROHIB -# define ICMP_UNREACH_HOST_PROHIB 10 -#endif -#ifndef ICMP_UNREACH_TOSNET -# define ICMP_UNREACH_TOSNET 11 -#endif -#ifndef ICMP_UNREACH_TOSHOST -# define ICMP_UNREACH_TOSHOST 12 -#endif -#ifndef ICMP_UNREACH_ADMIN_PROHIBIT -# define ICMP_UNREACH_ADMIN_PROHIBIT 13 -#endif -#ifndef ICMP_UNREACH_FILTER -# define ICMP_UNREACH_FILTER 13 -#endif -#ifndef ICMP_UNREACH_HOST_PRECEDENCE -# define ICMP_UNREACH_HOST_PRECEDENCE 14 -#endif -#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF -# define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 -#endif -#ifndef ICMP_SOURCEQUENCH -# define ICMP_SOURCEQUENCH 4 -#endif -#ifndef ICMP_REDIRECT_NET -# define ICMP_REDIRECT_NET 0 -#endif -#ifndef ICMP_REDIRECT_HOST -# define ICMP_REDIRECT_HOST 1 -#endif -#ifndef ICMP_REDIRECT_TOSNET -# define ICMP_REDIRECT_TOSNET 2 -#endif -#ifndef ICMP_REDIRECT_TOSHOST -# define ICMP_REDIRECT_TOSHOST 3 -#endif -#ifndef ICMP_ALTHOSTADDR -# define ICMP_ALTHOSTADDR 6 -#endif -#ifndef ICMP_TIMXCEED -# define ICMP_TIMXCEED 11 -#endif -#ifndef ICMP_TIMXCEED_INTRANS -# define ICMP_TIMXCEED_INTRANS 0 -#endif -#ifndef ICMP_TIMXCEED_REASS -# define ICMP_TIMXCEED_REASS 1 -#endif -#ifndef ICMP_PARAMPROB -# define ICMP_PARAMPROB 12 -#endif -#ifndef ICMP_PARAMPROB_ERRATPTR -# define ICMP_PARAMPROB_ERRATPTR 0 -#endif -#ifndef ICMP_PARAMPROB_OPTABSENT -# define ICMP_PARAMPROB_OPTABSENT 1 -#endif -#ifndef ICMP_PARAMPROB_LENGTH -# define ICMP_PARAMPROB_LENGTH 2 -#endif -#ifndef ICMP_TSTAMP -# define ICMP_TSTAMP 13 -#endif -#ifndef ICMP_TSTAMPREPLY -# define ICMP_TSTAMPREPLY 14 -#endif -#ifndef ICMP_IREQ -# define ICMP_IREQ 15 -#endif -#ifndef ICMP_IREQREPLY -# define ICMP_IREQREPLY 16 -#endif -#ifndef ICMP_MASKREQ -# define ICMP_MASKREQ 17 -#endif -#ifndef ICMP_MASKREPLY -# define ICMP_MASKREPLY 18 -#endif -#ifndef ICMP_TRACEROUTE -# define ICMP_TRACEROUTE 30 -#endif -#ifndef ICMP_DATACONVERR -# define ICMP_DATACONVERR 31 -#endif -#ifndef ICMP_MOBILE_REDIRECT -# define ICMP_MOBILE_REDIRECT 32 -#endif -#ifndef ICMP_IPV6_WHEREAREYOU -# define ICMP_IPV6_WHEREAREYOU 33 -#endif -#ifndef ICMP_IPV6_IAMHERE -# define ICMP_IPV6_IAMHERE 34 -#endif -#ifndef ICMP_MOBILE_REGREQUEST -# define ICMP_MOBILE_REGREQUEST 35 -#endif -#ifndef ICMP_MOBILE_REGREPLY -# define ICMP_MOBILE_REGREPLY 36 -#endif -#ifndef ICMP_SKIP -# define ICMP_SKIP 39 -#endif -#ifndef ICMP_PHOTURIS -# define ICMP_PHOTURIS 40 -#endif -#ifndef ICMP_PHOTURIS_UNKNOWN_INDEX -# define ICMP_PHOTURIS_UNKNOWN_INDEX 1 -#endif -#ifndef ICMP_PHOTURIS_AUTH_FAILED -# define ICMP_PHOTURIS_AUTH_FAILED 2 -#endif -#ifndef ICMP_PHOTURIS_DECRYPT_FAILED -# define ICMP_PHOTURIS_DECRYPT_FAILED 3 -#endif -#ifndef IPVERSION -# define IPVERSION 4 -#endif -#ifndef IPOPT_MINOFF -# define IPOPT_MINOFF 4 -#endif -#ifndef IPOPT_COPIED -# define IPOPT_COPIED(x) ((x)&0x80) -#endif -#ifndef IPOPT_EOL -# define IPOPT_EOL 0 -#endif -#ifndef IPOPT_NOP -# define IPOPT_NOP 1 -#endif -#ifndef IP_MF -# define IP_MF ((u_short)0x2000) -#endif -#ifndef ETHERTYPE_IP -# define ETHERTYPE_IP ((u_short)0x0800) -#endif -#ifndef TH_FIN -# define TH_FIN 0x01 -#endif -#ifndef TH_SYN -# define TH_SYN 0x02 -#endif -#ifndef TH_RST -# define TH_RST 0x04 -#endif -#ifndef TH_PUSH -# define TH_PUSH 0x08 -#endif -#ifndef TH_ACK -# define TH_ACK 0x10 -#endif -#ifndef TH_URG -# define TH_URG 0x20 -#endif -#undef TH_ACKMASK -#define TH_ACKMASK (TH_FIN|TH_SYN|TH_RST|TH_ACK) - -#ifndef IPOPT_EOL -# define IPOPT_EOL 0 -#endif -#ifndef IPOPT_NOP -# define IPOPT_NOP 1 -#endif -#ifndef IPOPT_RR -# define IPOPT_RR 7 -#endif -#ifndef IPOPT_TS -# define IPOPT_TS 68 -#endif -#ifndef IPOPT_SECURITY -# define IPOPT_SECURITY 130 -#endif -#ifndef IPOPT_LSRR -# define IPOPT_LSRR 131 -#endif -#ifndef IPOPT_SATID -# define IPOPT_SATID 136 -#endif -#ifndef IPOPT_SSRR -# define IPOPT_SSRR 137 -#endif -#ifndef IPOPT_SECUR_UNCLASS -# define IPOPT_SECUR_UNCLASS ((u_short)0x0000) -#endif -#ifndef IPOPT_SECUR_CONFID -# define IPOPT_SECUR_CONFID ((u_short)0xf135) -#endif -#ifndef IPOPT_SECUR_EFTO -# define IPOPT_SECUR_EFTO ((u_short)0x789a) -#endif -#ifndef IPOPT_SECUR_MMMM -# define IPOPT_SECUR_MMMM ((u_short)0xbc4d) -#endif -#ifndef IPOPT_SECUR_RESTR -# define IPOPT_SECUR_RESTR ((u_short)0xaf13) -#endif -#ifndef IPOPT_SECUR_SECRET -# define IPOPT_SECUR_SECRET ((u_short)0xd788) -#endif -#ifndef IPOPT_SECUR_TOPSECRET -# define IPOPT_SECUR_TOPSECRET ((u_short)0x6bc5) -#endif -#ifndef IPOPT_OLEN -# define IPOPT_OLEN 1 -#endif -#ifndef IPPROTO_HOPOPTS -# define IPPROTO_HOPOPTS 0 -#endif -#ifndef IPPROTO_ENCAP -# define IPPROTO_ENCAP 4 -#endif -#ifndef IPPROTO_IPV6 -# define IPPROTO_IPV6 41 -#endif -#ifndef IPPROTO_ROUTING -# define IPPROTO_ROUTING 43 -#endif -#ifndef IPPROTO_FRAGMENT -# define IPPROTO_FRAGMENT 44 -#endif -#ifndef IPPROTO_GRE -# define IPPROTO_GRE 47 /* GRE encaps RFC 1701 */ -#endif -#ifndef IPPROTO_ESP -# define IPPROTO_ESP 50 -#endif -#ifndef IPPROTO_AH -# define IPPROTO_AH 51 -#endif -#ifndef IPPROTO_ICMPV6 -# define IPPROTO_ICMPV6 58 -#endif -#ifndef IPPROTO_NONE -# define IPPROTO_NONE 59 -#endif -#ifndef IPPROTO_DSTOPTS -# define IPPROTO_DSTOPTS 60 -#endif -#ifndef IPPROTO_MOBILITY -# define IPPROTO_MOBILITY 135 -#endif - -#ifndef ICMP_ROUTERADVERT -# define ICMP_ROUTERADVERT 9 -#endif -#ifndef ICMP_ROUTERSOLICIT -# define ICMP_ROUTERSOLICIT 10 -#endif -#ifndef ICMP6_DST_UNREACH -# define ICMP6_DST_UNREACH 1 -#endif -#ifndef ICMP6_PACKET_TOO_BIG -# define ICMP6_PACKET_TOO_BIG 2 -#endif -#ifndef ICMP6_TIME_EXCEEDED -# define ICMP6_TIME_EXCEEDED 3 -#endif -#ifndef ICMP6_PARAM_PROB -# define ICMP6_PARAM_PROB 4 -#endif - -#ifndef ICMP6_ECHO_REQUEST -# define ICMP6_ECHO_REQUEST 128 -#endif -#ifndef ICMP6_ECHO_REPLY -# define ICMP6_ECHO_REPLY 129 -#endif -#ifndef ICMP6_MEMBERSHIP_QUERY -# define ICMP6_MEMBERSHIP_QUERY 130 -#endif -#ifndef MLD6_LISTENER_QUERY -# define MLD6_LISTENER_QUERY 130 -#endif -#ifndef ICMP6_MEMBERSHIP_REPORT -# define ICMP6_MEMBERSHIP_REPORT 131 -#endif -#ifndef MLD6_LISTENER_REPORT -# define MLD6_LISTENER_REPORT 131 -#endif -#ifndef ICMP6_MEMBERSHIP_REDUCTION -# define ICMP6_MEMBERSHIP_REDUCTION 132 -#endif -#ifndef MLD6_LISTENER_DONE -# define MLD6_LISTENER_DONE 132 -#endif -#ifndef ND_ROUTER_SOLICIT -# define ND_ROUTER_SOLICIT 133 -#endif -#ifndef ND_ROUTER_ADVERT -# define ND_ROUTER_ADVERT 134 -#endif -#ifndef ND_NEIGHBOR_SOLICIT -# define ND_NEIGHBOR_SOLICIT 135 -#endif -#ifndef ND_NEIGHBOR_ADVERT -# define ND_NEIGHBOR_ADVERT 136 -#endif -#ifndef ND_REDIRECT -# define ND_REDIRECT 137 -#endif -#ifndef ICMP6_ROUTER_RENUMBERING -# define ICMP6_ROUTER_RENUMBERING 138 -#endif -#ifndef ICMP6_WRUREQUEST -# define ICMP6_WRUREQUEST 139 -#endif -#ifndef ICMP6_WRUREPLY -# define ICMP6_WRUREPLY 140 -#endif -#ifndef ICMP6_FQDN_QUERY -# define ICMP6_FQDN_QUERY 139 -#endif -#ifndef ICMP6_FQDN_REPLY -# define ICMP6_FQDN_REPLY 140 -#endif -#ifndef ICMP6_NI_QUERY -# define ICMP6_NI_QUERY 139 -#endif -#ifndef ICMP6_NI_REPLY -# define ICMP6_NI_REPLY 140 -#endif -#ifndef MLD6_MTRACE_RESP -# define MLD6_MTRACE_RESP 200 -#endif -#ifndef MLD6_MTRACE -# define MLD6_MTRACE 201 -#endif -#ifndef ICMP6_HADISCOV_REQUEST -# define ICMP6_HADISCOV_REQUEST 202 -#endif -#ifndef ICMP6_HADISCOV_REPLY -# define ICMP6_HADISCOV_REPLY 203 -#endif -#ifndef ICMP6_MOBILEPREFIX_SOLICIT -# define ICMP6_MOBILEPREFIX_SOLICIT 204 -#endif -#ifndef ICMP6_MOBILEPREFIX_ADVERT -# define ICMP6_MOBILEPREFIX_ADVERT 205 -#endif -#ifndef ICMP6_MAXTYPE -# define ICMP6_MAXTYPE 205 -#endif - -#ifndef ICMP6_DST_UNREACH_NOROUTE -# define ICMP6_DST_UNREACH_NOROUTE 0 -#endif -#ifndef ICMP6_DST_UNREACH_ADMIN -# define ICMP6_DST_UNREACH_ADMIN 1 -#endif -#ifndef ICMP6_DST_UNREACH_NOTNEIGHBOR -# define ICMP6_DST_UNREACH_NOTNEIGHBOR 2 -#endif -#ifndef ICMP6_DST_UNREACH_BEYONDSCOPE -# define ICMP6_DST_UNREACH_BEYONDSCOPE 2 -#endif -#ifndef ICMP6_DST_UNREACH_ADDR -# define ICMP6_DST_UNREACH_ADDR 3 -#endif -#ifndef ICMP6_DST_UNREACH_NOPORT -# define ICMP6_DST_UNREACH_NOPORT 4 -#endif -#ifndef ICMP6_TIME_EXCEED_TRANSIT -# define ICMP6_TIME_EXCEED_TRANSIT 0 -#endif -#ifndef ICMP6_TIME_EXCEED_REASSEMBLY -# define ICMP6_TIME_EXCEED_REASSEMBLY 1 -#endif - -#ifndef ICMP6_NI_SUCCESS -# define ICMP6_NI_SUCCESS 0 -#endif -#ifndef ICMP6_NI_REFUSED -# define ICMP6_NI_REFUSED 1 -#endif -#ifndef ICMP6_NI_UNKNOWN -# define ICMP6_NI_UNKNOWN 2 -#endif - -#ifndef ICMP6_ROUTER_RENUMBERING_COMMAND -# define ICMP6_ROUTER_RENUMBERING_COMMAND 0 -#endif -#ifndef ICMP6_ROUTER_RENUMBERING_RESULT -# define ICMP6_ROUTER_RENUMBERING_RESULT 1 -#endif -#ifndef ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET -# define ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET 255 -#endif - -#ifndef ICMP6_PARAMPROB_HEADER -# define ICMP6_PARAMPROB_HEADER 0 -#endif -#ifndef ICMP6_PARAMPROB_NEXTHEADER -# define ICMP6_PARAMPROB_NEXTHEADER 1 -#endif -#ifndef ICMP6_PARAMPROB_OPTION -# define ICMP6_PARAMPROB_OPTION 2 -#endif - -#ifndef ICMP6_NI_SUBJ_IPV6 -# define ICMP6_NI_SUBJ_IPV6 0 -#endif -#ifndef ICMP6_NI_SUBJ_FQDN -# define ICMP6_NI_SUBJ_FQDN 1 -#endif -#ifndef ICMP6_NI_SUBJ_IPV4 -# define ICMP6_NI_SUBJ_IPV4 2 -#endif - -/* - * ECN is a new addition to TCP - RFC 2481 - */ -#ifndef TH_ECN -# define TH_ECN 0x40 -#endif -#ifndef TH_CWR -# define TH_CWR 0x80 -#endif -#define TH_ECNALL (TH_ECN|TH_CWR) - -/* - * TCP States - */ -#define IPF_TCPS_LISTEN 0 /* listening for connection */ -#define IPF_TCPS_SYN_SENT 1 /* active, have sent syn */ -#define IPF_TCPS_SYN_RECEIVED 2 /* have send and received syn */ -#define IPF_TCPS_HALF_ESTAB 3 /* for connections not fully "up" */ -/* states < IPF_TCPS_ESTABLISHED are those where connections not established */ -#define IPF_TCPS_ESTABLISHED 4 /* established */ -#define IPF_TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ -/* states > IPF_TCPS_CLOSE_WAIT are those where user has closed */ -#define IPF_TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ -#define IPF_TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ -#define IPF_TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ -/* states > IPF_TCPS_CLOSE_WAIT && < IPF_TCPS_FIN_WAIT_2 await ACK of FIN */ -#define IPF_TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ -#define IPF_TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ -#define IPF_TCPS_CLOSED 11 /* closed */ -#define IPF_TCP_NSTATES 12 - -#define TCP_MSL 120 - -#undef ICMP_MAX_UNREACH -#define ICMP_MAX_UNREACH 14 -#undef ICMP_MAXTYPE -#define ICMP_MAXTYPE 18 - -#ifndef IFNAMSIZ -#define IFNAMSIZ 16 -#endif - -#ifndef LOG_FTP -# define LOG_FTP (11<<3) -#endif -#ifndef LOG_AUTHPRIV -# define LOG_AUTHPRIV (10<<3) -#endif -#ifndef LOG_AUDIT -# define LOG_AUDIT (13<<3) -#endif -#ifndef LOG_NTP -# define LOG_NTP (12<<3) -#endif -#ifndef LOG_SECURITY -# define LOG_SECURITY (13<<3) -#endif -#ifndef LOG_LFMT -# define LOG_LFMT (14<<3) -#endif -#ifndef LOG_CONSOLE -# define LOG_CONSOLE (14<<3) -#endif - -/* - * ICMP error replies have an IP header (20 bytes), 8 bytes of ICMP data, - * another IP header and then 64 bits of data, totalling 56. Of course, - * the last 64 bits is dependent on that being available. - */ -#define ICMPERR_ICMPHLEN 8 -#define ICMPERR_IPICMPHLEN (20 + 8) -#define ICMPERR_MINPKTLEN (20 + 8 + 20) -#define ICMPERR_MAXPKTLEN (20 + 8 + 20 + 8) -#define ICMP6ERR_MINPKTLEN (40 + 8) -#define ICMP6ERR_IPICMPHLEN (40 + 8 + 40) - -#ifndef MIN -# define MIN(a,b) (((a)<(b))?(a):(b)) -#endif - -#ifdef IPF_DEBUG -# define DPRINT(x) printf x -#else -# define DPRINT(x) -#endif - -#ifdef RESCUE -# undef IPFILTER_BPF -#endif - -#endif /* __IP_COMPAT_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_fil.c b/sys/contrib/ipfilter/netinet/ip_fil.c deleted file mode 100644 index 00e8565..0000000 --- a/sys/contrib/ipfilter/netinet/ip_fil.c +++ /dev/null @@ -1,2293 +0,0 @@ -/* - * Copyright (C) 1993-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -#ifndef SOLARIS -#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) -#endif - -#if defined(KERNEL) && !defined(_KERNEL) -# define _KERNEL -#endif -#if defined(_KERNEL) && defined(__FreeBSD_version) && \ - (__FreeBSD_version >= 400000) && !defined(KLD_MODULE) -#include "opt_inet6.h" -#endif -#include <sys/param.h> -#if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ - defined(_KERNEL) && !defined(_LKM) -# include "opt_ipfilter_log.h" -#endif -#if defined(__FreeBSD__) && !defined(__FreeBSD_version) -# if !defined(_KERNEL) || defined(IPFILTER_LKM) -# include <osreldate.h> -# endif -#endif -#if defined(__sgi) && (IRIX > 602) -# define _KMEMUSER -# include <sys/ptimers.h> -#endif -#ifndef _KERNEL -# include <stdio.h> -# include <string.h> -# include <stdlib.h> -# include <ctype.h> -# include <fcntl.h> -#endif -#include <sys/errno.h> -#include <sys/types.h> -#include <sys/file.h> -#if __FreeBSD_version >= 220000 && defined(_KERNEL) -# include <sys/fcntl.h> -# include <sys/filio.h> -#else -# include <sys/ioctl.h> -#endif -#include <sys/time.h> -#ifdef _KERNEL -# include <sys/systm.h> -#endif -#if !SOLARIS -# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) -# include <sys/dirent.h> -# else -# include <sys/dir.h> -# endif -# include <sys/mbuf.h> -#else -# include <sys/filio.h> -#endif -#include <sys/protosw.h> -#include <sys/socket.h> - -#include <net/if.h> -#ifdef sun -# include <net/af.h> -#endif -#if __FreeBSD_version >= 300000 -# include <net/if_var.h> -# if defined(_KERNEL) && !defined(IPFILTER_LKM) -# include "opt_ipfilter.h" -# endif -#endif -#ifdef __sgi -#include <sys/debug.h> -# ifdef IFF_DRVRLOCK /* IRIX6 */ -#include <sys/hashing.h> -# endif -#endif -#include <net/route.h> -#include <netinet/in.h> -#if !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /* IRIX < 6 */ -# include <netinet/in_var.h> -#endif -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/ip_var.h> -#include <netinet/tcp.h> -#include <netinet/udp.h> -#include <netinet/tcpip.h> -#include <netinet/ip_icmp.h> -#ifndef _KERNEL -# include <unistd.h> -# include <syslog.h> -#endif -#include "netinet/ip_compat.h" -#ifdef USE_INET6 -# include <netinet/icmp6.h> -# if !SOLARIS -# include <netinet6/ip6protosw.h> -# include <netinet6/nd6.h> -# endif -#endif -#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_auth.h" -#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) -# include <sys/malloc.h> -#endif -#ifndef MIN -# define MIN(a,b) (((a)<(b))?(a):(b)) -#endif -#if !SOLARIS && defined(_KERNEL) && !defined(__sgi) -# include <sys/kernel.h> -extern int ip_optcopy __P((struct ip *, struct ip *)); -#endif -#if defined(OpenBSD) && (OpenBSD >= 200211) && defined(_KERNEL) -extern int ip6_getpmtu(struct route_in6 *, struct route_in6 *, - struct ifnet *, struct in6_addr *, u_long *); -#endif - -#if !defined(lint) -static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.76 2004/05/12 23:21:03 darrenr Exp $"; -#endif - - -extern struct protosw inetsw[]; - -#ifndef _KERNEL -# include "ipt.h" -static struct ifnet **ifneta = NULL; -static int nifs = 0; -#else -# if (BSD < 199306) || defined(__sgi) -extern int tcp_ttl; -# endif -#endif - -#ifdef ICMP_UNREACH_FILTER_PROHIB -int ipl_unreach = ICMP_UNREACH_FILTER_PROHIB; -#else -int ipl_unreach = ICMP_UNREACH_FILTER; -#endif -u_long ipl_frouteok[2] = {0, 0}; - -static int frzerostats __P((caddr_t)); -#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) -static int frrequest __P((int, u_long, caddr_t, int)); -#else -static int frrequest __P((int, int, caddr_t, int)); -#endif -#ifdef _KERNEL -static int (*fr_savep) __P((ip_t *, int, void *, int, struct mbuf **)); -static int send_ip __P((ip_t *, fr_info_t *, struct mbuf **)); -# ifdef USE_INET6 -static int ipfr_fastroute6 __P((struct mbuf *, struct mbuf **, - fr_info_t *, frdest_t *)); -# endif -# ifdef __sgi -extern int tcp_mtudisc; -extern kmutex_t ipf_rw; -extern KRWLOCK_T ipf_mutex; -# endif -#else -void init_ifp __P((void)); -# if defined(__sgi) && (IRIX < 605) -static int no_output __P((struct ifnet *, struct mbuf *, - struct sockaddr *)); -static int write_output __P((struct ifnet *, struct mbuf *, - struct sockaddr *)); -# else -static int no_output __P((struct ifnet *, struct mbuf *, - struct sockaddr *, struct rtentry *)); -static int write_output __P((struct ifnet *, struct mbuf *, - struct sockaddr *, struct rtentry *)); -# endif -#endif -int fr_running = 0; - -#if (__FreeBSD_version >= 300000) && defined(_KERNEL) -struct callout_handle ipfr_slowtimer_ch; -#endif -#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) -# include <sys/callout.h> -struct callout ipfr_slowtimer_ch; -#endif -#if defined(__OpenBSD__) -# include <sys/timeout.h> -struct timeout ipfr_slowtimer_ch; -#endif -#if defined(__sgi) && defined(_KERNEL) -toid_t ipfr_slowtimer_ch; -#endif - -#if defined(__NetBSD__) && (__NetBSD_Version__ >= 106080000) && \ - defined(_KERNEL) -# include <sys/conf.h> -const struct cdevsw ipl_cdevsw = { - iplopen, iplclose, iplread, nowrite, iplioctl, - nostop, notty, nopoll, nommap, -}; -#endif - -#if (_BSDI_VERSION >= 199510) && defined(_KERNEL) -# include <sys/device.h> -# include <sys/conf.h> - -struct cfdriver iplcd = { - NULL, "ipl", NULL, NULL, DV_DULL, 0 -}; - -struct devsw iplsw = { - &iplcd, - iplopen, iplclose, iplread, nowrite, iplioctl, noselect, nommap, - nostrat, nodump, nopsize, 0, - nostop -}; -#endif /* _BSDI_VERSION >= 199510 && _KERNEL */ - -#if defined(__NetBSD__) || defined(__OpenBSD__) || (_BSDI_VERSION >= 199701) -# include <sys/conf.h> -# if defined(NETBSD_PF) -# include <net/pfil.h> -/* - * We provide the fr_checkp name just to minimize changes later. - */ -int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp)); -# endif /* NETBSD_PF */ -#endif /* __NetBSD__ */ - - -#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105110000) && \ - defined(_KERNEL) -# include <net/pfil.h> - -static int fr_check_wrapper(void *, struct mbuf **, struct ifnet *, int ); - -static int fr_check_wrapper(arg, mp, ifp, dir) -void *arg; -struct mbuf **mp; -struct ifnet *ifp; -int dir; -{ - struct ip *ip = mtod(*mp, struct ip *); - int rv, hlen = ip->ip_hl << 2; - -#if defined(M_CSUM_TCPv4) - /* - * If the packet is out-bound, we can't delay checksums - * here. For in-bound, the checksum has already been - * validated. - */ - if (dir == PFIL_OUT) { - if ((*mp)->m_pkthdr.csum_flags & (M_CSUM_TCPv4|M_CSUM_UDPv4)) { - in_delayed_cksum(*mp); - (*mp)->m_pkthdr.csum_flags &= - ~(M_CSUM_TCPv4|M_CSUM_UDPv4); - } - } -#endif /* M_CSUM_TCPv4 */ - - /* - * We get the packet with all fields in network byte - * order. We expect ip_len and ip_off to be in host - * order. We frob them, call the filter, then frob - * them back. - * - * Note, we don't need to update the checksum, because - * it has already been verified. - */ - NTOHS(ip->ip_len); - NTOHS(ip->ip_off); - - rv = fr_check(ip, hlen, ifp, (dir == PFIL_OUT), mp); - - if (rv == 0 && *mp != NULL) { - ip = mtod(*mp, struct ip *); - HTONS(ip->ip_len); - HTONS(ip->ip_off); - } - - return (rv); -} - -# ifdef USE_INET6 -# include <netinet/ip6.h> - -static int fr_check_wrapper6(void *, struct mbuf **, struct ifnet *, int ); - -static int fr_check_wrapper6(arg, mp, ifp, dir) -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)); -} -# endif -#endif /* __NetBSD_Version >= 105110000 && _KERNEL */ -#ifdef _KERNEL -# if defined(IPFILTER_LKM) && !defined(__sgi) -int iplidentify(s) -char *s; -{ - if (strcmp(s, "ipl") == 0) - return 1; - return 0; -} -# endif /* IPFILTER_LKM */ - - -/* - * Try to detect the case when compiling for NetBSD with pseudo-device - */ -# if defined(__NetBSD__) && defined(PFIL_HOOKS) -void -ipfilterattach(count) -int count; -{ - - /* - * Do nothing here, really. The filter will be enabled - * by the SIOCFRENB ioctl. - */ -} -# endif - - -# if defined(__NetBSD__) || defined(__OpenBSD__) -int ipl_enable() -# else -int iplattach() -# endif -{ - char *defpass; - int s; -# if defined(__sgi) || (defined(NETBSD_PF) && (__NetBSD_Version__ >= 104200000)) - int error = 0; -# endif -#if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105110000) - struct pfil_head *ph_inet; -# ifdef USE_INET6 - struct pfil_head *ph_inet6; -# endif -#endif - - SPL_NET(s); - if (fr_running || (fr_checkp == fr_check)) { - printf("IP Filter: already initialized\n"); - SPL_X(s); - return EBUSY; - } - -# ifdef IPFILTER_LOG - ipflog_init(); -# endif - if (nat_init() == -1) { - SPL_X(s); - return EIO; - } - if (fr_stateinit() == -1) { - SPL_X(s); - return EIO; - } - if (appr_init() == -1) { - SPL_X(s); - return EIO; - } - -# ifdef NETBSD_PF -# if (__NetBSD_Version__ >= 104200000) || (__FreeBSD_version >= 500011) -# if __NetBSD_Version__ >= 105110000 - ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); -# ifdef USE_INET6 - ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); -# endif - if (ph_inet == NULL -# ifdef USE_INET6 - && ph_inet6 == NULL -# endif - ) - return ENODEV; - - if (ph_inet != NULL) - error = pfil_add_hook((void *)fr_check_wrapper, NULL, - PFIL_IN|PFIL_OUT, ph_inet); - else - error = 0; -# else - error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, - &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); -# endif - if (error) { -# ifdef USE_INET6 - goto pfil_error; -# else - SPL_X(s); - appr_unload(); - ip_natunload(); - fr_stateunload(); - return error; -# endif - } -# else - pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT); -# endif -# ifdef USE_INET6 -# if __NetBSD_Version__ >= 105110000 - if (ph_inet6 != NULL) - error = pfil_add_hook((void *)fr_check_wrapper6, NULL, - PFIL_IN|PFIL_OUT, ph_inet6); - else - error = 0; - if (error) { - pfil_remove_hook((void *)fr_check_wrapper6, NULL, - PFIL_IN|PFIL_OUT, ph_inet6); -# else - error = pfil_add_hook((void *)fr_check, PFIL_IN|PFIL_OUT, - &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); - if (error) { - pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, - &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); -# endif -pfil_error: - SPL_X(s); - appr_unload(); - ip_natunload(); - fr_stateunload(); - return error; - } -# endif -# endif - -# ifdef __sgi - error = ipfilter_sgi_attach(); - if (error) { - SPL_X(s); - appr_unload(); - ip_natunload(); - fr_stateunload(); - return error; - } -# endif - - bzero((char *)frcache, sizeof(frcache)); - fr_savep = fr_checkp; - fr_checkp = fr_check; - fr_running = 1; - - SPL_X(s); - if (fr_pass & FR_PASS) - defpass = "pass"; - else if (fr_pass & FR_BLOCK) - defpass = "block"; - else - defpass = "no-match -> block"; - - printf("%s initialized. Default = %s all, Logging = %s\n", - ipfilter_version, defpass, -# ifdef IPFILTER_LOG - "enabled"); -# else - "disabled"); -# endif -#ifdef _KERNEL -# if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) - callout_init(&ipfr_slowtimer_ch); - callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL); -# else -# if defined(__OpenBSD__) - timeout_set(&ipfr_slowtimer_ch, ipfr_slowtimer, NULL); - timeout_add(&ipfr_slowtimer_ch, hz/2); -# else -# if (__FreeBSD_version >= 300000) || defined(__sgi) - ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); -# else - timeout(ipfr_slowtimer, NULL, hz/2); -# endif -# endif -# endif -#endif - return 0; -} - - -/* - * Disable the filter by removing the hooks from the IP input/output - * stream. - */ -# if defined(__NetBSD__) -int ipl_disable() -# else -int ipldetach() -# endif -{ - int s, i; -#if defined(NETBSD_PF) && \ - ((__NetBSD_Version__ >= 104200000) || (__FreeBSD_version >= 500011)) - int error = 0; -# if __NetBSD_Version__ >= 105150000 - struct pfil_head *ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); -# ifdef USE_INET6 - struct pfil_head *ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); -# endif -# endif -#endif - -#ifdef _KERNEL -# if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) - callout_stop(&ipfr_slowtimer_ch); -# else -# if (__FreeBSD_version >= 300000) - untimeout(ipfr_slowtimer, NULL, ipfr_slowtimer_ch); -# else -# ifdef __sgi - untimeout(ipfr_slowtimer_ch); -# else -# if defined(__OpenBSD__) - timeout_del(&ipfr_slowtimer_ch); -# else - untimeout(ipfr_slowtimer, NULL); -# endif /* OpenBSD */ -# endif /* __sgi */ -# endif /* FreeBSD */ -# endif /* NetBSD */ -#endif - SPL_NET(s); - if (!fr_running) - { - printf("IP Filter: not initialized\n"); - SPL_X(s); - return 0; - } - - printf("%s unloaded\n", ipfilter_version); - - fr_checkp = fr_savep; - i = frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE); - i += frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE); - fr_running = 0; - -# ifdef NETBSD_PF -# if ((__NetBSD_Version__ >= 104200000) || (__FreeBSD_version >= 500011)) -# if __NetBSD_Version__ >= 105110000 - if (ph_inet != NULL) - error = pfil_remove_hook((void *)fr_check_wrapper, NULL, - PFIL_IN|PFIL_OUT, ph_inet); - else - error = 0; -# else - error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, - &inetsw[ip_protox[IPPROTO_IP]].pr_pfh); -# endif - if (error) { - SPL_X(s); - return error; - } -# else - pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT); -# endif -# ifdef USE_INET6 -# if __NetBSD_Version__ >= 105110000 - if (ph_inet6 != NULL) - error = pfil_remove_hook((void *)fr_check_wrapper6, NULL, - PFIL_IN|PFIL_OUT, ph_inet6); - else - error = 0; -# else - error = pfil_remove_hook((void *)fr_check, PFIL_IN|PFIL_OUT, - &inet6sw[ip6_protox[IPPROTO_IPV6]].pr_pfh); -# endif - if (error) { - SPL_X(s); - return error; - } -# endif -# endif - -# ifdef __sgi - ipfilter_sgi_detach(); -# endif - - appr_unload(); - ipfr_unload(); - ip_natunload(); - fr_stateunload(); - fr_authunload(); - - SPL_X(s); - return 0; -} -#endif /* _KERNEL */ - - -static int frzerostats(data) -caddr_t data; -{ - friostat_t fio; - int error; - - fr_getstat(&fio); - error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio)); - if (error) - return EFAULT; - - bzero((char *)frstats, sizeof(*frstats) * 2); - - return 0; -} - - -/* - * Filter ioctl interface. - */ -#ifdef __sgi -int IPL_EXTERN(ioctl)(dev_t dev, int cmd, caddr_t data, int mode -# ifdef _KERNEL - , cred_t *cp, int *rp -# endif -) -#else -int IPL_EXTERN(ioctl)(dev, cmd, data, mode -# if (defined(_KERNEL) && ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || \ - (NetBSD >= 199511) || (__FreeBSD_version >= 220000) || \ - defined(__OpenBSD__))) -, p) -struct proc *p; -# else -) -# endif -dev_t dev; -# if defined(__NetBSD__) || defined(__OpenBSD__) || \ - (_BSDI_VERSION >= 199701) || (__FreeBSD_version >= 300000) -u_long cmd; -# else -int cmd; -# endif -caddr_t data; -int mode; -#endif /* __sgi */ -{ -#if defined(_KERNEL) && !SOLARIS - int s; -#endif - int error = 0, unit = 0, tmp; - -#if (BSD >= 199306) && defined(_KERNEL) - if ((securelevel >= 3) && (mode & FWRITE)) - return EPERM; -#endif -#ifdef _KERNEL - unit = GET_MINOR(dev); - if ((IPL_LOGMAX < unit) || (unit < 0)) - return ENXIO; -#else - unit = dev; -#endif - - if (fr_running == 0 && (cmd != SIOCFRENB || unit != IPL_LOGIPF)) - return ENODEV; - - SPL_NET(s); - - if (unit == IPL_LOGNAT) { - if (fr_running) - error = nat_ioctl(data, cmd, mode); - else - error = EIO; - SPL_X(s); - return error; - } - if (unit == IPL_LOGSTATE) { - if (fr_running) - error = fr_state_ioctl(data, cmd, mode); - else - error = EIO; - SPL_X(s); - return error; - } - if (unit == IPL_LOGAUTH) { - if (!fr_running) - error = EIO; - else - if ((cmd == SIOCADAFR) || (cmd == SIOCRMAFR)) { - if (!(mode & FWRITE)) { - error = EPERM; - } else { - error = frrequest(unit, cmd, data, - fr_active); - } - } else { - error = fr_auth_ioctl(data, mode, cmd); - } - SPL_X(s); - return error; - } - - switch (cmd) { - case FIONREAD : -#ifdef IPFILTER_LOG - error = IWCOPY((caddr_t)&iplused[IPL_LOGIPF], (caddr_t)data, - sizeof(iplused[IPL_LOGIPF])); -#endif - break; -#if (!defined(IPFILTER_LKM) || defined(__NetBSD__)) && defined(_KERNEL) - case SIOCFRENB : - { - u_int enable; - - if (!(mode & FWRITE)) - error = EPERM; - else { - error = IRCOPY(data, (caddr_t)&enable, sizeof(enable)); - if (error) - break; - if (enable) -# if defined(__NetBSD__) || defined(__OpenBSD__) - error = ipl_enable(); -# else - error = iplattach(); -# endif - else -# if defined(__NetBSD__) - error = ipl_disable(); -# else - error = ipldetach(); -# endif - } - break; - } -#endif - case SIOCSETFF : - if (!(mode & FWRITE)) - error = EPERM; - else - error = IRCOPY(data, (caddr_t)&fr_flags, - sizeof(fr_flags)); - break; - case SIOCGETFF : - error = IWCOPY((caddr_t)&fr_flags, data, sizeof(fr_flags)); - break; - case SIOCINAFR : - case SIOCRMAFR : - case SIOCADAFR : - case SIOCZRLST : - if (!(mode & FWRITE)) - error = EPERM; - else - error = frrequest(unit, cmd, data, fr_active); - break; - case SIOCINIFR : - case SIOCRMIFR : - case SIOCADIFR : - if (!(mode & FWRITE)) - error = EPERM; - else - error = frrequest(unit, cmd, data, 1 - fr_active); - break; - case SIOCSWAPA : - if (!(mode & FWRITE)) - error = EPERM; - else { - bzero((char *)frcache, sizeof(frcache[0]) * 2); - *(u_int *)data = fr_active; - fr_active = 1 - fr_active; - } - break; - case SIOCGETFS : - { - friostat_t fio; - - fr_getstat(&fio); - error = IWCOPYPTR((caddr_t)&fio, data, sizeof(fio)); - if (error) - error = EFAULT; - break; - } - case SIOCFRZST : - if (!(mode & FWRITE)) - error = EPERM; - else - error = frzerostats(data); - break; - case SIOCIPFFL : - if (!(mode & FWRITE)) - error = EPERM; - else { - error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); - if (!error) { - tmp = frflush(unit, 4, tmp); - error = IWCOPY((caddr_t)&tmp, data, - sizeof(tmp)); - } - } - break; -#ifdef USE_INET6 - case SIOCIPFL6 : - if (!(mode & FWRITE)) - error = EPERM; - else { - error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); - if (!error) { - tmp = frflush(unit, 6, tmp); - error = IWCOPY((caddr_t)&tmp, data, - sizeof(tmp)); - } - } - break; -#endif - case SIOCSTLCK : - error = IRCOPY(data, (caddr_t)&tmp, sizeof(tmp)); - if (!error) { - fr_state_lock = tmp; - fr_nat_lock = tmp; - fr_frag_lock = tmp; - fr_auth_lock = tmp; - } else - error = EFAULT; - break; -#ifdef IPFILTER_LOG - case SIOCIPFFB : - if (!(mode & FWRITE)) - error = EPERM; - else - *(int *)data = ipflog_clear(unit); - break; -#endif /* IPFILTER_LOG */ - case SIOCGFRST : - error = IWCOPYPTR((caddr_t)ipfr_fragstats(), data, - sizeof(ipfrstat_t)); - if (error) - error = EFAULT; - break; - case SIOCFRSYN : - if (!(mode & FWRITE)) - error = EPERM; - else { -#if defined(_KERNEL) && defined(__sgi) - ipfsync(); -#endif - frsync(); - } - break; - default : - error = EINVAL; - break; - } - SPL_X(s); - return error; -} - - -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); - ip_natsync(ifp); -} - - -static int frrequest(unit, req, data, set) -int unit; -#if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003) -u_long req; -#else -int req; -#endif -int set; -caddr_t data; -{ - register frentry_t *fp, *f, **fprev; - register frentry_t **ftail; - frgroup_t *fg = NULL; - int error = 0, in, i; - u_int *p, *pp; - frentry_t frd; - frdest_t *fdp; - u_int group; - - fp = &frd; - error = IRCOPYPTR(data, (caddr_t)fp, sizeof(*fp)); - if (error) - return EFAULT; - fp->fr_ref = 0; -#if (BSD >= 199306) && defined(_KERNEL) - if ((securelevel > 0) && (fp->fr_func != NULL)) - return EPERM; -#endif - - /* - * Check that the group number does exist and that if a head group - * has been specified, doesn't exist. - */ - if ((req != SIOCZRLST) && ((req == SIOCINAFR) || (req == SIOCINIFR) || - (req == SIOCADAFR) || (req == SIOCADIFR)) && fp->fr_grhead && - fr_findgroup((u_int)fp->fr_grhead, fp->fr_flags, unit, set, NULL)) - return EEXIST; - if ((req != SIOCZRLST) && fp->fr_group && - !fr_findgroup((u_int)fp->fr_group, fp->fr_flags, unit, set, NULL)) - return ESRCH; - - in = (fp->fr_flags & FR_INQUE) ? 0 : 1; - - if (unit == IPL_LOGAUTH) - ftail = fprev = &ipauth; - else if ((fp->fr_flags & FR_ACCOUNT) && (fp->fr_v == 4)) - ftail = fprev = &ipacct[in][set]; - else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) && (fp->fr_v == 4)) - ftail = fprev = &ipfilter[in][set]; -#ifdef USE_INET6 - else if ((fp->fr_flags & FR_ACCOUNT) && (fp->fr_v == 6)) - ftail = fprev = &ipacct6[in][set]; - else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) && (fp->fr_v == 6)) - ftail = fprev = &ipfilter6[in][set]; -#endif - else - return ESRCH; - - if ((group = fp->fr_group)) { - if (!(fg = fr_findgroup(group, fp->fr_flags, unit, set, NULL))) - return ESRCH; - ftail = fprev = fg->fg_start; - } - - bzero((char *)frcache, sizeof(frcache[0]) * 2); - - for (i = 0; i < 4; i++) { - if ((fp->fr_ifnames[i][1] == '\0') && - ((fp->fr_ifnames[i][0] == '-') || - (fp->fr_ifnames[i][0] == '*'))) { - fp->fr_ifas[i] = NULL; - } else if (*fp->fr_ifnames[i]) { - fp->fr_ifas[i] = GETUNIT(fp->fr_ifnames[i], fp->fr_v); - if (!fp->fr_ifas[i]) - fp->fr_ifas[i] = (void *)-1; - } - } - - fdp = &fp->fr_dif; - fp->fr_flags &= ~FR_DUP; - if (*fdp->fd_ifname) { - fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_v); - if (!fdp->fd_ifp) - fdp->fd_ifp = (struct ifnet *)-1; - else - fp->fr_flags |= FR_DUP; - } - - fdp = &fp->fr_tif; - if (*fdp->fd_ifname) { - fdp->fd_ifp = GETUNIT(fdp->fd_ifname, fp->fr_v); - if (!fdp->fd_ifp) - fdp->fd_ifp = (struct ifnet *)-1; - } - - /* - * Look for a matching filter rule, but don't include the next or - * interface pointer in the comparison (fr_next, fr_ifa). - */ - for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_ip, pp = &fp->fr_cksum; - p < pp; p++) - fp->fr_cksum += *p; - - for (; (f = *ftail); ftail = &f->fr_next) - if ((fp->fr_cksum == f->fr_cksum) && - !bcmp((char *)&f->fr_ip, (char *)&fp->fr_ip, FR_CMPSIZ)) - break; - - /* - * If zero'ing statistics, copy current to caller and zero. - */ - if (req == SIOCZRLST) { - if (!f) - return ESRCH; - error = IWCOPYPTR((caddr_t)f, data, sizeof(*f)); - if (error) - return EFAULT; - f->fr_hits = 0; - f->fr_bytes = 0; - return 0; - } - - if (!f) { - if (req != SIOCINAFR && req != SIOCINIFR) - while ((f = *ftail)) - ftail = &f->fr_next; - else { - ftail = fprev; - if (fp->fr_hits) { - while (--fp->fr_hits && (f = *ftail)) - ftail = &f->fr_next; - } - f = NULL; - } - } - - if (req == SIOCRMAFR || req == SIOCRMIFR) { - if (!f) - error = ESRCH; - else { - /* - * Only return EBUSY if there is a group list, else - * it's probably just state information referencing - * the rule. - */ - if ((f->fr_ref > 1) && f->fr_grp) - return EBUSY; - if (fg && fg->fg_head) - fg->fg_head->fr_ref--; - if (unit == IPL_LOGAUTH) { - return fr_preauthcmd(req, f, ftail); - } - if (f->fr_grhead) - fr_delgroup((u_int)f->fr_grhead, fp->fr_flags, - unit, set); - fixskip(fprev, f, -1); - *ftail = f->fr_next; - f->fr_next = NULL; - f->fr_ref--; - if (f->fr_ref == 0) - KFREE(f); - } - } else { - if (f) - error = EEXIST; - else { - if (unit == IPL_LOGAUTH) { - return fr_preauthcmd(req, fp, ftail); - } - KMALLOC(f, frentry_t *); - if (f != NULL) { - if (fg && fg->fg_head) - fg->fg_head->fr_ref++; - bcopy((char *)fp, (char *)f, sizeof(*f)); - f->fr_ref = 1; - f->fr_hits = 0; - f->fr_next = *ftail; - *ftail = f; - if (req == SIOCINIFR || req == SIOCINAFR) - fixskip(fprev, f, 1); - f->fr_grp = NULL; - if ((group = f->fr_grhead)) - fg = fr_addgroup(group, f, unit, set); - } else - error = ENOMEM; - } - } - return (error); -} - - -#ifdef _KERNEL -/* - * routines below for saving IP headers to buffer - */ -# ifdef __sgi -# ifdef _KERNEL -int IPL_EXTERN(open)(dev_t *pdev, int flags, int devtype, cred_t *cp) -# else -int IPL_EXTERN(open)(dev_t dev, int flags) -# endif -# else -int IPL_EXTERN(open)(dev, flags -# if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ - (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL) -, devtype, p) -int devtype; -struct proc *p; -# else -) -# endif -dev_t dev; -int flags; -# endif /* __sgi */ -{ -# if defined(__sgi) && defined(_KERNEL) - u_int min = geteminor(*pdev); -# else - u_int min = GET_MINOR(dev); -# endif - - if (IPL_LOGMAX < min) - min = ENXIO; - else - min = 0; - return min; -} - - -# ifdef __sgi -int IPL_EXTERN(close)(dev_t dev, int flags, int devtype, cred_t *cp) -#else -int IPL_EXTERN(close)(dev, flags -# if ((_BSDI_VERSION >= 199510) || (BSD >= 199506) || (NetBSD >= 199511) || \ - (__FreeBSD_version >= 220000) || defined(__OpenBSD__)) && defined(_KERNEL) -, devtype, p) -int devtype; -struct proc *p; -# else -) -# endif -dev_t dev; -int flags; -# endif /* __sgi */ -{ - 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. - */ -# ifdef __sgi -int IPL_EXTERN(read)(dev_t dev, uio_t *uio, cred_t *crp) -# else -# if BSD >= 199306 -int IPL_EXTERN(read)(dev, uio, ioflag) -int ioflag; -# else -int IPL_EXTERN(read)(dev, uio) -# endif -dev_t dev; -register struct uio *uio; -# endif /* __sgi */ -{ -# ifdef IPFILTER_LOG - return ipflog_read(GET_MINOR(dev), uio); -# else - return ENXIO; -# endif -} - - -/* - * send_reset - this could conceivably be a call to tcp_respond(), but that - * requires a large amount of setting up and isn't any more efficient. - */ -int send_reset(oip, fin) -struct ip *oip; -fr_info_t *fin; -{ - struct tcphdr *tcp, *tcp2; - int tlen = 0, hlen; - struct mbuf *m; -#ifdef USE_INET6 - ip6_t *ip6, *oip6 = (ip6_t *)oip; -#endif - ip_t *ip; - - tcp = (struct tcphdr *)fin->fin_dp; - if (tcp->th_flags & TH_RST) - return -1; /* feedback loop */ -# if (BSD < 199306) || defined(__sgi) - m = m_get(M_DONTWAIT, MT_HEADER); -# else - m = m_gethdr(M_DONTWAIT, MT_HEADER); -# endif - if (m == NULL) - return ENOBUFS; - if (m == NULL) - return -1; - - tlen = fin->fin_dlen - (tcp->th_off << 2) + - ((tcp->th_flags & TH_SYN) ? 1 : 0) + - ((tcp->th_flags & TH_FIN) ? 1 : 0); - -#ifdef USE_INET6 - hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); -#else - hlen = sizeof(ip_t); -#endif - m->m_len = sizeof(*tcp2) + hlen; -# if BSD >= 199306 - m->m_data += max_linkhdr; - m->m_pkthdr.len = m->m_len; - m->m_pkthdr.rcvif = (struct ifnet *)0; -# endif - ip = mtod(m, struct ip *); -# ifdef USE_INET6 - ip6 = (ip6_t *)ip; -# endif - bzero((char *)ip, sizeof(*tcp2) + hlen); - tcp2 = (struct tcphdr *)((char *)ip + hlen); - - tcp2->th_sport = tcp->th_dport; - tcp2->th_dport = tcp->th_sport; - if (tcp->th_flags & TH_ACK) { - tcp2->th_seq = tcp->th_ack; - tcp2->th_flags = TH_RST; - } else { - tcp2->th_ack = ntohl(tcp->th_seq); - tcp2->th_ack += tlen; - tcp2->th_ack = htonl(tcp2->th_ack); - tcp2->th_flags = TH_RST|TH_ACK; - } - tcp2->th_off = sizeof(*tcp2) >> 2; -# ifdef USE_INET6 - if (fin->fin_v == 6) { - ip6->ip6_plen = htons(sizeof(struct tcphdr)); - ip6->ip6_nxt = IPPROTO_TCP; - ip6->ip6_src = oip6->ip6_dst; - ip6->ip6_dst = oip6->ip6_src; - tcp2->th_sum = in6_cksum(m, IPPROTO_TCP, - sizeof(*ip6), sizeof(*tcp2)); - return send_ip(oip, fin, &m); - } -# endif - ip->ip_p = IPPROTO_TCP; - ip->ip_len = htons(sizeof(struct tcphdr)); - ip->ip_src.s_addr = oip->ip_dst.s_addr; - ip->ip_dst.s_addr = oip->ip_src.s_addr; - tcp2->th_sum = in_cksum(m, hlen + sizeof(*tcp2)); - ip->ip_len = hlen + sizeof(*tcp2); - return send_ip(oip, fin, &m); -} - - -/* - * Send an IP(v4/v6) datagram out into the network - */ -static int send_ip(oip, fin, mp) -ip_t *oip; -fr_info_t *fin; -struct mbuf **mp; -{ - struct mbuf *m = *mp; - int error, hlen; - fr_info_t frn; - ip_t *ip; - - bzero((char *)&frn, sizeof(frn)); - frn.fin_ifp = fin->fin_ifp; - frn.fin_v = fin->fin_v; - frn.fin_out = fin->fin_out; - frn.fin_mp = mp; - - ip = mtod(m, ip_t *); - hlen = sizeof(*ip); - - ip->ip_v = fin->fin_v; - if (ip->ip_v == 4) { - ip->ip_hl = (sizeof(*oip) >> 2); - ip->ip_v = IPVERSION; - ip->ip_tos = oip->ip_tos; - ip->ip_id = oip->ip_id; - -# if defined(__NetBSD__) || \ - (defined(__OpenBSD__) && (OpenBSD >= 200012)) - if (ip_mtudisc != 0) - ip->ip_off = IP_DF; -# else -# if defined(__sgi) - if (ip->ip_p == IPPROTO_TCP && tcp_mtudisc != 0) - ip->ip_off = IP_DF; -# endif -# endif - -# if (BSD < 199306) || defined(__sgi) - ip->ip_ttl = tcp_ttl; -# else - ip->ip_ttl = ip_defttl; -# endif - ip->ip_sum = 0; - frn.fin_dp = (char *)(ip + 1); - } -# ifdef USE_INET6 - else if (ip->ip_v == 6) { - ip6_t *ip6 = (ip6_t *)ip; - - hlen = sizeof(*ip6); - ip6->ip6_hlim = 127; - frn.fin_dp = (char *)(ip6 + 1); - } -# endif -# ifdef IPSEC - m->m_pkthdr.rcvif = NULL; -# endif - - if (fr_makefrip(hlen, ip, &frn) == 0) - error = ipfr_fastroute(m, mp, &frn, NULL); - else - error = EINVAL; - return error; -} - - -int send_icmp_err(oip, type, fin, dst) -ip_t *oip; -int type; -fr_info_t *fin; -int dst; -{ - int err, hlen = 0, xtra = 0, iclen, ohlen = 0, avail, code; - u_short shlen, slen = 0, soff = 0; - struct in_addr dst4; - struct icmp *icmp; - struct mbuf *m; - void *ifp; -#ifdef USE_INET6 - ip6_t *ip6, *oip6 = (ip6_t *)oip; - struct in6_addr dst6; -#endif - ip_t *ip; - - if ((type < 0) || (type > ICMP_MAXTYPE)) - return -1; - - code = fin->fin_icode; -#ifdef USE_INET6 - if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) - return -1; -#endif - - avail = 0; - m = NULL; - ifp = fin->fin_ifp; - if (fin->fin_v == 4) { - if ((oip->ip_p == IPPROTO_ICMP) && - !(fin->fin_fi.fi_fl & FI_SHORT)) - switch (ntohs(fin->fin_data[0]) >> 8) - { - case ICMP_ECHO : - case ICMP_TSTAMP : - case ICMP_IREQ : - case ICMP_MASKREQ : - break; - default : - return 0; - } - -# if (BSD < 199306) || defined(__sgi) - avail = MLEN; - m = m_get(M_DONTWAIT, MT_HEADER); -# else - avail = MHLEN; - m = m_gethdr(M_DONTWAIT, MT_HEADER); -# endif - if (m == NULL) - return ENOBUFS; - - if (dst == 0) { - if (fr_ifpaddr(4, ifp, &dst4) == -1) - return -1; - } else - dst4.s_addr = oip->ip_dst.s_addr; - - hlen = sizeof(ip_t); - ohlen = oip->ip_hl << 2; - xtra = 8; - } - -#ifdef USE_INET6 - else if (fin->fin_v == 6) { - hlen = sizeof(ip6_t); - ohlen = sizeof(ip6_t); - type = icmptoicmp6types[type]; - if (type == ICMP6_DST_UNREACH) - code = icmptoicmp6unreach[code]; - - MGETHDR(m, M_DONTWAIT, MT_HEADER); - if (!m) - return ENOBUFS; - - MCLGET(m, M_DONTWAIT); - if ((m->m_flags & M_EXT) == 0) { - m_freem(m); - return ENOBUFS; - } -# ifdef M_TRAILINGSPACE - m->m_len = 0; - avail = M_TRAILINGSPACE(m); -# else - avail = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN; -# endif - xtra = MIN(ntohs(oip6->ip6_plen) + sizeof(ip6_t), - avail - hlen - sizeof(*icmp) - max_linkhdr); - if (dst == 0) { - if (fr_ifpaddr(6, ifp, (struct in_addr *)&dst6) == -1) - return -1; - } else - dst6 = oip6->ip6_dst; - } -#endif - - iclen = hlen + sizeof(*icmp); -# if BSD >= 199306 - avail -= (max_linkhdr + iclen); - m->m_data += max_linkhdr; - m->m_pkthdr.rcvif = (struct ifnet *)0; - if (xtra > avail) - xtra = avail; - iclen += xtra; - m->m_pkthdr.len = iclen; -#else - avail -= (m->m_off + iclen); - if (xtra > avail) - xtra = avail; - iclen += xtra; -#endif - m->m_len = iclen; - ip = mtod(m, ip_t *); - icmp = (struct icmp *)((char *)ip + hlen); - bzero((char *)ip, iclen); - - icmp->icmp_type = type; - icmp->icmp_code = fin->fin_icode; - icmp->icmp_cksum = 0; -#ifdef icmp_nextmtu - if (type == ICMP_UNREACH && - fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp) - icmp->icmp_nextmtu = htons(((struct ifnet *) ifp)->if_mtu); -#endif - - if (avail) { - slen = oip->ip_len; - oip->ip_len = htons(oip->ip_len); - soff = oip->ip_off; - oip->ip_off = htons(oip->ip_off); - bcopy((char *)oip, (char *)&icmp->icmp_ip, MIN(ohlen, avail)); - oip->ip_len = slen; - oip->ip_off = soff; - avail -= MIN(ohlen, avail); - } - -#ifdef USE_INET6 - ip6 = (ip6_t *)ip; - if (fin->fin_v == 6) { - ip6->ip6_flow = 0; - ip6->ip6_plen = htons(iclen - hlen); - ip6->ip6_nxt = IPPROTO_ICMPV6; - ip6->ip6_hlim = 0; - ip6->ip6_src = dst6; - ip6->ip6_dst = oip6->ip6_src; - if (avail) - bcopy((char *)oip + ohlen, - (char *)&icmp->icmp_ip + ohlen, avail); - icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6, - sizeof(*ip6), iclen - hlen); - } else -#endif - { - - ip->ip_src.s_addr = dst4.s_addr; - ip->ip_dst.s_addr = oip->ip_src.s_addr; - - if (avail > 8) - avail = 8; - if (avail) - bcopy((char *)oip + ohlen, - (char *)&icmp->icmp_ip + ohlen, avail); - icmp->icmp_cksum = ipf_cksum((u_short *)icmp, - sizeof(*icmp) + 8); - ip->ip_len = iclen; - ip->ip_p = IPPROTO_ICMP; - } - - shlen = fin->fin_hlen; - fin->fin_hlen = hlen; - err = send_ip(oip, fin, &m); - fin->fin_hlen = shlen; - - return err; -} - - -# if !defined(IPFILTER_LKM) && !defined(__sgi) && \ - (!defined(__FreeBSD_version) || (__FreeBSD_version < 300000)) -# if (BSD < 199306) -int iplinit __P((void)); - -int -# else -void iplinit __P((void)); - -void -# endif -iplinit() -{ - -# if defined(__NetBSD__) || defined(__OpenBSD__) - if (ipl_enable() != 0) -# else - if (iplattach() != 0) -# endif - { - printf("IP Filter failed to attach\n"); - } - ip_init(); -} -# endif /* ! __NetBSD__ */ - - -/* - * Return the length of the entire mbuf. - */ -size_t mbufchainlen(m0) -register struct mbuf *m0; -{ -#if BSD >= 199306 - return m0->m_pkthdr.len; -#else - register size_t len = 0; - - for (; m0; m0 = m0->m_next) - len += m0->m_len; - return len; -#endif -} - - -int ipfr_fastroute(m0, mpp, fin, fdp) -struct mbuf *m0, **mpp; -fr_info_t *fin; -frdest_t *fdp; -{ - register struct ip *ip, *mhip; - register struct mbuf *m = m0; - register struct route *ro; - int len, off, error = 0, hlen, code, sout; - struct ifnet *ifp, *sifp; - struct sockaddr_in *dst; - struct route iproute; - frentry_t *fr; - - ip = NULL; - ro = NULL; - ifp = NULL; - ro = &iproute; - ro->ro_rt = NULL; - -#ifdef USE_INET6 - if (fin->fin_v == 6) { - error = ipfr_fastroute6(m0, mpp, fin, fdp); - if (error != 0) - goto bad; - goto done; - } -#else - if (fin->fin_v == 6) - goto bad; -#endif - -#ifdef M_WRITABLE - /* - * HOT FIX/KLUDGE: - * - * If the mbuf we're about to send is not writable (because of - * a cluster reference, for example) we'll need to make a copy - * of it since this routine modifies the contents. - * - * If you have non-crappy network hardware that can transmit data - * from the mbuf, rather than making a copy, this is gonna be a - * problem. - */ - if (M_WRITABLE(m) == 0) { - if ((m0 = m_dup(m, M_DONTWAIT)) != NULL) { - m_freem(*mpp); - *mpp = m0; - m = m0; - } else { - error = ENOBUFS; - m_freem(*mpp); - goto done; - } - } -#endif - - hlen = fin->fin_hlen; - ip = mtod(m0, struct ip *); - -#if defined(__NetBSD__) && defined(M_CSUM_IPv4) - /* - * Clear any in-bound checksum flags for this packet. - */ -# if (__NetBSD_Version__ > 105009999) - m0->m_pkthdr.csum_flags = 0; -# else - m0->m_pkthdr.csuminfo = 0; -# endif -#endif /* __NetBSD__ && M_CSUM_IPv4 */ - - /* - * Route packet. - */ -#if (defined(IRIX) && (IRIX >= 605)) - ROUTE_RDLOCK(); -#endif - bzero((caddr_t)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 (fdp != NULL) - ifp = fdp->fd_ifp; - else - ifp = fin->fin_ifp; - - /* - * In case we're here due to "to <if>" being used with "keep state", - * check that we're going in the correct direction. - */ - if ((fr != NULL) && (fin->fin_rev != 0)) { - if ((ifp != NULL) && (fdp == &fr->fr_tif)) { -# if (defined(IRIX) && (IRIX >= 605)) - ROUTE_UNLOCK(); -# endif - return 0; - } - } else if (fdp != NULL) { - if (fdp->fd_ip.s_addr != 0) - dst->sin_addr = fdp->fd_ip; - } - -# if BSD >= 199306 - dst->sin_len = sizeof(*dst); -# endif -# if (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \ - !defined(__OpenBSD__) -# ifdef RTF_CLONING - rtalloc_ign(ro, RTF_CLONING); -# else - rtalloc_ign(ro, RTF_PRCLONING); -# endif -# else - rtalloc(ro); -# endif - - if (!ifp) { - if (!fr || !(fr->fr_flags & FR_FASTROUTE)) { - error = -2; -# if (defined(IRIX) && (IRIX >= 605)) - ROUTE_UNLOCK(); -# endif - goto bad; - } - } - - if ((ifp == NULL) && (ro->ro_rt != NULL)) - ifp = ro->ro_rt->rt_ifp; - - if ((ro->ro_rt == NULL) || (ifp == NULL)) { - if (in_localaddr(ip->ip_dst)) - error = EHOSTUNREACH; - else - error = ENETUNREACH; -# if (defined(IRIX) && (IRIX >= 605)) - ROUTE_UNLOCK(); -# endif - goto bad; - } - - if (ro->ro_rt->rt_flags & RTF_GATEWAY) { -#if (BSD >= 199306) || (defined(IRIX) && (IRIX >= 605)) - dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; -#else - dst = (struct sockaddr_in *)&ro->ro_rt->rt_gateway; -#endif - } - ro->ro_rt->rt_use++; - -#if (defined(IRIX) && (IRIX > 602)) - ROUTE_UNLOCK(); -#endif - - /* - * For input packets which are being "fastrouted", they won't - * go back through output filtering and miss their chance to get - * NAT'd and counted. - */ - if (fin->fin_out == 0) { - sifp = fin->fin_ifp; - sout = fin->fin_out; - fin->fin_ifp = ifp; - fin->fin_out = 1; - if ((fin->fin_fr = ipacct[1][fr_active]) && - (fr_scanlist(FR_NOMATCH, ip, fin, m) & FR_ACCOUNT)) { - ATOMIC_INCL(frstats[1].fr_acct); - } - fin->fin_fr = NULL; - if (!fr || !(fr->fr_flags & FR_RETMASK)) - (void) fr_checkstate(ip, fin); - - switch (ip_natout(ip, fin)) - { - case 0 : - break; - case 1 : - ip->ip_sum = 0; - break; - case -1 : - error = EINVAL; - goto done; - break; - } - - fin->fin_ifp = sifp; - fin->fin_out = sout; - } else - ip->ip_sum = 0; - - /* - * If small enough for interface, can just send directly. - */ - if (ip->ip_len <= ifp->if_mtu) { -# ifndef sparc -# if (!defined(__FreeBSD__) && !(_BSDI_VERSION >= 199510)) && \ - !(__NetBSD_Version__ >= 105110000) - ip->ip_id = htons(ip->ip_id); -# endif - ip->ip_len = htons(ip->ip_len); - ip->ip_off = htons(ip->ip_off); -# endif -# if defined(__NetBSD__) && defined(M_CSUM_IPv4) -# if (__NetBSD_Version__ > 105009999) - if (ifp->if_csum_flags_tx & IFCAP_CSUM_IPv4) - m->m_pkthdr.csum_flags |= M_CSUM_IPv4; - else if (ip->ip_sum == 0) - ip->ip_sum = in_cksum(m, hlen); -# else - if (ifp->if_capabilities & IFCAP_CSUM_IPv4) - m->m_pkthdr.csuminfo |= M_CSUM_IPv4; - else if (ip->ip_sum == 0) - ip->ip_sum = in_cksum(m, hlen); -# endif -# else - if (!ip->ip_sum) - ip->ip_sum = in_cksum(m, hlen); -# endif /* __NetBSD__ && M_CSUM_IPv4 */ -# if (BSD >= 199306) || (defined(IRIX) && (IRIX >= 605)) -# ifdef IRIX - IFNET_UPPERLOCK(ifp); -# endif - error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, - ro->ro_rt); -# ifdef IRIX - IFNET_UPPERUNLOCK(ifp); -# endif -# else - error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst); -# endif - goto done; - } - - /* - * Too large for interface; fragment if possible. - * Must be able to put at least 8 bytes per fragment. - */ - if (ip->ip_off & IP_DF) { - error = EMSGSIZE; - goto bad; - } - len = (ifp->if_mtu - hlen) &~ 7; - if (len < 8) { - error = EMSGSIZE; - goto bad; - } - - { - int mhlen, firstlen = len; - struct mbuf **mnext = &m->m_act; - - /* - * Loop through length of segment after first fragment, - * make new header and copy data of each part and link onto chain. - */ - m0 = m; - mhlen = sizeof (struct ip); - for (off = hlen + len; off < ip->ip_len; off += len) { -# ifdef MGETHDR - MGETHDR(m, M_DONTWAIT, MT_HEADER); -# else - MGET(m, M_DONTWAIT, MT_HEADER); -# endif - if (m == 0) { - error = ENOBUFS; - goto bad; - } -# if BSD >= 199306 - m->m_data += max_linkhdr; -# else - m->m_off = MMAXOFF - hlen; -# endif - mhip = mtod(m, struct ip *); - bcopy((char *)ip, (char *)mhip, sizeof(*ip)); - if (hlen > sizeof (struct ip)) { - mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); - mhip->ip_hl = mhlen >> 2; - } - m->m_len = mhlen; - mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); - if (ip->ip_off & IP_MF) - mhip->ip_off |= IP_MF; - if (off + len >= ip->ip_len) - len = ip->ip_len - off; - else - mhip->ip_off |= IP_MF; - mhip->ip_len = htons((u_short)(len + mhlen)); - m->m_next = m_copy(m0, off, len); - if (m->m_next == 0) { - error = ENOBUFS; /* ??? */ - goto sendorfree; - } -# if BSD >= 199306 - m->m_pkthdr.len = mhlen + len; - m->m_pkthdr.rcvif = NULL; -# endif - mhip->ip_off = htons((u_short)mhip->ip_off); - mhip->ip_sum = 0; - mhip->ip_sum = in_cksum(m, mhlen); - *mnext = m; - mnext = &m->m_act; - } - /* - * Update first fragment by trimming what's been copied out - * and updating header, then send each fragment (in order). - */ - m_adj(m0, hlen + firstlen - ip->ip_len); - ip->ip_len = htons((u_short)(hlen + firstlen)); - ip->ip_off = htons((u_short)(ip->ip_off | IP_MF)); - ip->ip_sum = 0; - ip->ip_sum = in_cksum(m0, hlen); -sendorfree: - for (m = m0; m; m = m0) { - m0 = m->m_act; - m->m_act = 0; - if (error == 0) -# if (BSD >= 199306) || (defined(IRIX) && (IRIX >= 605)) - error = (*ifp->if_output)(ifp, m, - (struct sockaddr *)dst, ro->ro_rt); -# else - error = (*ifp->if_output)(ifp, m, - (struct sockaddr *)dst); -# endif - else - m_freem(m); - } - } -done: - if (!error) - ipl_frouteok[0]++; - else - ipl_frouteok[1]++; - - if (ro->ro_rt != NULL) { - RTFREE(ro->ro_rt); - } - *mpp = NULL; - return error; -bad: - if ((error == EMSGSIZE) && (fin->fin_v == 4)) { - sifp = fin->fin_ifp; - code = fin->fin_icode; - fin->fin_icode = ICMP_UNREACH_NEEDFRAG; - fin->fin_ifp = ifp; - (void) send_icmp_err(ip, ICMP_UNREACH, fin, 1); - fin->fin_ifp = sifp; - fin->fin_icode = code; - } - m_freem(m); - goto done; -} - - -/* - * Return true or false depending on whether the route to the - * given IP address uses the same interface as the one passed. - */ -int fr_verifysrc(ipa, ifp) -struct in_addr ipa; -void *ifp; -{ - struct sockaddr_in *dst; - struct route iproute; - - bzero((char *)&iproute, sizeof(iproute)); - dst = (struct sockaddr_in *)&iproute.ro_dst; -# if (BSD >= 199306) - dst->sin_len = sizeof(*dst); -# endif - dst->sin_family = AF_INET; - dst->sin_addr = ipa; -# if (BSD >= 199306) && !defined(__NetBSD__) && !defined(__bsdi__) && \ - !defined(__OpenBSD__) -# ifdef RTF_CLONING - rtalloc_ign(&iproute, RTF_CLONING); -# else - rtalloc_ign(&iproute, RTF_PRCLONING); -# endif -# else - rtalloc(&iproute); -# endif - if (iproute.ro_rt == NULL) - return 0; - return (ifp == iproute.ro_rt->rt_ifp); -} - - -# ifdef USE_GETIFNAME -char * -get_ifname(ifp) -struct ifnet *ifp; -{ - static char workbuf[64]; - - sprintf(workbuf, "%s%d", ifp->if_name, ifp->if_unit); - return workbuf; -} -# endif - - -# if defined(USE_INET6) -/* - * This is the IPv6 specific fastroute code. It doesn't clean up the mbuf's - * or ensure that it is an IPv6 packet that is being forwarded, those are - * expected to be done by the called (ipfr_fastroute). - */ -static int ipfr_fastroute6(m0, mpp, fin, fdp) -struct mbuf *m0, **mpp; -fr_info_t *fin; -frdest_t *fdp; -{ - struct route_in6 ip6route; - struct sockaddr_in6 *dst6; - struct route_in6 *ro; - struct ifnet *ifp; - frentry_t *fr; -#if defined(OpenBSD) && (OpenBSD >= 200211) - struct route_in6 *ro_pmtu = NULL; - struct in6_addr finaldst; - ip6_t *ip6; -#endif - u_long mtu; - int error; - - ro = &ip6route; - fr = fin->fin_fr; - bzero((caddr_t)ro, sizeof(*ro)); - dst6 = (struct sockaddr_in6 *)&ro->ro_dst; - dst6->sin6_family = AF_INET6; - dst6->sin6_len = sizeof(struct sockaddr_in6); - dst6->sin6_addr = fin->fin_fi.fi_dst.in6; - - if (fdp != NULL) - ifp = fdp->fd_ifp; - else - ifp = fin->fin_ifp; - - if ((fr != NULL) && (fin->fin_rev != 0)) { - if ((ifp != NULL) && (fdp == &fr->fr_tif)) - return 0; - } else if (fdp != NULL) { - if (IP6_NOTZERO(&fdp->fd_ip6)) - dst6->sin6_addr = fdp->fd_ip6.in6; - } - if (ifp == NULL) - return -2; - -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) - /* KAME */ - if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr)) - dst6->sin6_addr.s6_addr16[1] = htons(ifp->if_index); -#endif - rtalloc((struct route *)ro); - - if ((ifp == NULL) && (ro->ro_rt != NULL)) - ifp = ro->ro_rt->rt_ifp; - - if ((ro->ro_rt == NULL) || (ifp == NULL) || - (ifp != ro->ro_rt->rt_ifp)) { - error = EHOSTUNREACH; - } else { - if (ro->ro_rt->rt_flags & RTF_GATEWAY) - dst6 = (struct sockaddr_in6 *)ro->ro_rt->rt_gateway; - ro->ro_rt->rt_use++; - -#if defined(OpenBSD) && (OpenBSD >= 200211) - ip6 = mtod(m0, ip6_t *); - ro_pmtu = ro; - finaldst = ip6->ip6_dst; - error = ip6_getpmtu(ro_pmtu, ro, ifp, &finaldst, &mtu); - if (error == 0) { -#else -# ifdef IN6_LINKMTU - mtu = IN6_LINKMTU(ifp); -# else -# ifdef ND_IFINFO - mtu = ND_IFINFO(ifp)->linkmtu; -# else - mtu = nd_ifinfo[ifp->if_index].linkmtu; -# endif -# endif -#endif - if (m0->m_pkthdr.len <= mtu) - error = nd6_output(ifp, fin->fin_ifp, m0, - dst6, ro->ro_rt); - else - error = EMSGSIZE; -#if defined(OpenBSD) && (OpenBSD >= 200211) - } -#endif - } - - if (ro->ro_rt != NULL) { - RTFREE(ro->ro_rt); - } - return error; -} -# endif -#else /* #ifdef _KERNEL */ - - -# if defined(__sgi) && (IRIX < 605) -static int no_output __P((struct ifnet *ifp, struct mbuf *m, - struct sockaddr *s)) -# else -static int no_output __P((struct ifnet *ifp, struct mbuf *m, - struct sockaddr *s, struct rtentry *rt)) -# endif -{ - return 0; -} - - -# ifdef __STDC__ -# if defined(__sgi) && (IRIX < 605) -static int write_output __P((struct ifnet *ifp, struct mbuf *m, - struct sockaddr *s)) -# else -static int write_output __P((struct ifnet *ifp, struct mbuf *m, - struct sockaddr *s, struct rtentry *rt)) -# endif -{ - ip_t *ip = (ip_t *)m; -# else -static int write_output(ifp, ip) -struct ifnet *ifp; -ip_t *ip; -{ -# endif - char fname[32]; - int fd; - -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) - sprintf(fname, "%s", ifp->if_xname); -# else - sprintf(fname, "%s%d", ifp->if_name, ifp->if_unit); -# endif - fd = open(fname, O_WRONLY|O_APPEND); - if (fd == -1) { - perror("open"); - return -1; - } - write(fd, (char *)ip, ntohs(ip->ip_len)); - close(fd); - return 0; -} - - -char *get_ifname(ifp) -struct ifnet *ifp; -{ -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) - return ifp->if_xname; -# else - static char fullifname[LIFNAMSIZ]; - - sprintf(fullifname, "%s%d", ifp->if_name, ifp->if_unit); - return fullifname; -# endif -} - - -struct ifnet *get_unit(ifname, v) -char *ifname; -int v; -{ - struct ifnet *ifp, **ifa, **old_ifneta; - - for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) - if (!strncmp(ifname, ifp->if_xname, sizeof(ifp->if_xname))) -# else - char fullname[LIFNAMSIZ]; - - sprintf(fullname, "%s%d", ifp->if_name, ifp->if_unit); - if (!strcmp(ifname, fullname)) -# endif - return ifp; - } - - if (!ifneta) { - ifneta = (struct ifnet **)malloc(sizeof(ifp) * 2); - if (!ifneta) - return NULL; - ifneta[1] = NULL; - ifneta[0] = (struct ifnet *)calloc(1, sizeof(*ifp)); - if (!ifneta[0]) { - free(ifneta); - return NULL; - } - nifs = 1; - } else { - old_ifneta = ifneta; - nifs++; - ifneta = (struct ifnet **)realloc(ifneta, - (nifs + 1) * sizeof(*ifa)); - if (!ifneta) { - free(old_ifneta); - nifs = 0; - return NULL; - } - ifneta[nifs] = NULL; - ifneta[nifs - 1] = (struct ifnet *)malloc(sizeof(*ifp)); - if (!ifneta[nifs - 1]) { - nifs--; - return NULL; - } - } - ifp = ifneta[nifs - 1]; - -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) - strncpy(ifp->if_xname, ifname, sizeof(ifp->if_xname)); -# else - ifp->if_name = strdup(ifname); - - ifname = ifp->if_name; - while (*ifname && !isdigit(*ifname)) - ifname++; - if (*ifname && isdigit(*ifname)) { - ifp->if_unit = atoi(ifname); - *ifname = '\0'; - } else - ifp->if_unit = -1; -# endif - ifp->if_output = no_output; - return ifp; -} - - - -void init_ifp() -{ - struct ifnet *ifp, **ifa; - char fname[32]; - int fd; - -# if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199606)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) - for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { - ifp->if_output = write_output; - sprintf(fname, "/tmp/%s", ifp->if_xname); - fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); - if (fd == -1) - perror("open"); - else - close(fd); - } -# else - - for (ifa = ifneta; ifa && (ifp = *ifa); ifa++) { - ifp->if_output = write_output; - sprintf(fname, "/tmp/%s%d", ifp->if_name, ifp->if_unit); - fd = open(fname, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600); - if (fd == -1) - perror("open"); - else - close(fd); - } -# endif -} - - -int send_reset(ip, fin) -ip_t *ip; -fr_info_t *fin; -{ - verbose("- TCP RST sent\n"); - return 0; -} - - -int send_icmp_err(ip, code, fin, dst) -ip_t *ip; -int code; -fr_info_t *fin; -int dst; -{ - verbose("- ICMP UNREACHABLE sent\n"); - return 0; -} - - -void frsync() -{ - return; -} - -void m_copydata(m, off, len, cp) -mb_t *m; -int off, len; -caddr_t cp; -{ - bcopy((char *)m + off, cp, len); -} - - -int ipfuiomove(buf, len, rwflag, uio) -caddr_t buf; -int len, rwflag; -struct uio *uio; -{ - int left, ioc, num, offset; - struct iovec *io; - char *start; - - if (rwflag == UIO_READ) { - left = len; - ioc = 0; - - offset = uio->uio_offset; - - while ((left > 0) && (ioc < uio->uio_iovcnt)) { - io = uio->uio_iov + ioc; - num = io->iov_len; - if (num > left) - num = left; - start = (char *)io->iov_base + offset; - if (start > (char *)io->iov_base + io->iov_len) { - offset -= io->iov_len; - ioc++; - continue; - } - bcopy(buf, start, num); - uio->uio_resid -= num; - uio->uio_offset += num; - left -= num; - if (left > 0) - ioc++; - } - if (left > 0) - return EFAULT; - } - return 0; -} -#endif /* _KERNEL */ diff --git a/sys/contrib/ipfilter/netinet/ip_fil.h b/sys/contrib/ipfilter/netinet/ip_fil.h deleted file mode 100644 index 8236cef..0000000 --- a/sys/contrib/ipfilter/netinet/ip_fil.h +++ /dev/null @@ -1,1559 +0,0 @@ -/* - * Copyright (C) 1993-2001, 2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * @(#)ip_fil.h 1.35 6/5/96 - * $Id: ip_fil.h,v 2.170.2.51 2007/10/10 09:48:03 darrenr Exp $ - */ - -#ifndef __IP_FIL_H__ -#define __IP_FIL_H__ - -#include "netinet/ip_compat.h" - -#ifndef SOLARIS -# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) -#endif - -#ifndef __P -# ifdef __STDC__ -# define __P(x) x -# else -# define __P(x) () -# endif -#endif - -#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51) -# define SIOCADAFR _IOW('r', 60, struct ipfobj) -# define SIOCRMAFR _IOW('r', 61, struct ipfobj) -# define SIOCSETFF _IOW('r', 62, u_int) -# define SIOCGETFF _IOR('r', 63, u_int) -# define SIOCGETFS _IOWR('r', 64, struct ipfobj) -# define SIOCIPFFL _IOWR('r', 65, int) -# define SIOCIPFFB _IOR('r', 66, int) -# define SIOCADIFR _IOW('r', 67, struct ipfobj) -# define SIOCRMIFR _IOW('r', 68, struct ipfobj) -# define SIOCSWAPA _IOR('r', 69, u_int) -# define SIOCINAFR _IOW('r', 70, struct ipfobj) -# define SIOCINIFR _IOW('r', 71, struct ipfobj) -# define SIOCFRENB _IOW('r', 72, u_int) -# define SIOCFRSYN _IOW('r', 73, u_int) -# define SIOCFRZST _IOWR('r', 74, struct ipfobj) -# define SIOCZRLST _IOWR('r', 75, struct ipfobj) -# define SIOCAUTHW _IOWR('r', 76, struct ipfobj) -# define SIOCAUTHR _IOWR('r', 77, struct ipfobj) -# define SIOCSTAT1 _IOWR('r', 78, struct ipfobj) -# define SIOCSTLCK _IOWR('r', 79, u_int) -# define SIOCSTPUT _IOWR('r', 80, struct ipfobj) -# define SIOCSTGET _IOWR('r', 81, struct ipfobj) -# define SIOCSTGSZ _IOWR('r', 82, struct ipfobj) -# define SIOCSTAT2 _IOWR('r', 83, struct ipfobj) -# define SIOCSETLG _IOWR('r', 84, int) -# define SIOCGETLG _IOWR('r', 85, int) -# define SIOCFUNCL _IOWR('r', 86, struct ipfunc_resolve) -# define SIOCIPFGETNEXT _IOWR('r', 87, struct ipfobj) -# define SIOCIPFGET _IOWR('r', 88, struct ipfobj) -# define SIOCIPFSET _IOWR('r', 89, struct ipfobj) -# define SIOCIPFL6 _IOWR('r', 90, int) -# define SIOCIPFITER _IOWR('r', 91, struct ipfobj) -# define SIOCGENITER _IOWR('r', 92, struct ipfobj) -# define SIOCGTABL _IOWR('r', 93, struct ipfobj) -# define SIOCIPFDELTOK _IOWR('r', 94, int) -# define SIOCLOOKUPITER _IOWR('r', 95, struct ipfobj) -# define SIOCGTQTAB _IOWR('r', 96, struct ipfobj) -#else -# define SIOCADAFR _IOW(r, 60, struct ipfobj) -# define SIOCRMAFR _IOW(r, 61, struct ipfobj) -# define SIOCSETFF _IOW(r, 62, u_int) -# define SIOCGETFF _IOR(r, 63, u_int) -# define SIOCGETFS _IOWR(r, 64, struct ipfobj) -# define SIOCIPFFL _IOWR(r, 65, int) -# define SIOCIPFFB _IOR(r, 66, int) -# define SIOCADIFR _IOW(r, 67, struct ipfobj) -# define SIOCRMIFR _IOW(r, 68, struct ipfobj) -# define SIOCSWAPA _IOR(r, 69, u_int) -# define SIOCINAFR _IOW(r, 70, struct ipfobj) -# define SIOCINIFR _IOW(r, 71, struct ipfobj) -# define SIOCFRENB _IOW(r, 72, u_int) -# define SIOCFRSYN _IOW(r, 73, u_int) -# define SIOCFRZST _IOWR(r, 74, struct ipfobj) -# define SIOCZRLST _IOWR(r, 75, struct ipfobj) -# define SIOCAUTHW _IOWR(r, 76, struct ipfobj) -# define SIOCAUTHR _IOWR(r, 77, struct ipfobj) -# define SIOCSTAT1 _IOWR(r, 78, struct ipfobj) -# define SIOCSTLCK _IOWR(r, 79, u_int) -# define SIOCSTPUT _IOWR(r, 80, struct ipfobj) -# define SIOCSTGET _IOWR(r, 81, struct ipfobj) -# define SIOCSTGSZ _IOWR(r, 82, struct ipfobj) -# define SIOCSTAT2 _IOWR(r, 83, struct ipfobj) -# define SIOCSETLG _IOWR(r, 84, int) -# define SIOCGETLG _IOWR(r, 85, int) -# define SIOCFUNCL _IOWR(r, 86, struct ipfunc_resolve) -# define SIOCIPFGETNEXT _IOWR(r, 87, struct ipfobj) -# define SIOCIPFGET _IOWR(r, 88, struct ipfobj) -# define SIOCIPFSET _IOWR(r, 89, struct ipfobj) -# define SIOCIPFL6 _IOWR(r, 90, int) -# define SIOCIPFITER _IOWR(r, 91, struct ipfobj) -# define SIOCGENITER _IOWR(r, 92, struct ipfobj) -# define SIOCGTABL _IOWR(r, 93, struct ipfobj) -# define SIOCIPFDELTOK _IOWR(r, 94, int) -# define SIOCLOOKUPITER _IOWR(r, 95, struct ipfobj) -# define SIOCGTQTAB _IOWR(r, 96, struct ipfobj) -#endif -#define SIOCADDFR SIOCADAFR -#define SIOCDELFR SIOCRMAFR -#define SIOCINSFR SIOCINAFR -#define SIOCATHST SIOCSTAT1 -#define SIOCGFRST SIOCSTAT2 - - -struct ipscan; -struct ifnet; - - -typedef int (* lookupfunc_t) __P((void *, int, void *)); - -/* - * i6addr is used as a container for both IPv4 and IPv6 addresses, as well - * as other types of objects, depending on its qualifier. - */ -#ifdef USE_INET6 -typedef union i6addr { - u_32_t i6[4]; - struct in_addr in4; - struct in6_addr in6; - void *vptr[2]; - lookupfunc_t lptr[2]; - struct { - u_short type; - u_short subtype; - char label[12]; - } i6un; -} i6addr_t; -#else -typedef union i6addr { - u_32_t i6[4]; - struct in_addr in4; - void *vptr[2]; - lookupfunc_t lptr[2]; - struct { - u_short type; - u_short subtype; - char label[12]; - } i6un; -} i6addr_t; -#endif - -#define in4_addr in4.s_addr -#define iplookupnum i6[1] -#define iplookupname i6un.label -#define iplookuptype i6un.type -#define iplookupsubtype i6un.subtype -/* - * NOTE: These DO overlap the above on 64bit systems and this IS recognised. - */ -#define iplookupptr vptr[0] -#define iplookupfunc lptr[1] - -#define I60(x) (((u_32_t *)(x))[0]) -#define I61(x) (((u_32_t *)(x))[1]) -#define I62(x) (((u_32_t *)(x))[2]) -#define I63(x) (((u_32_t *)(x))[3]) -#define HI60(x) ntohl(((u_32_t *)(x))[0]) -#define HI61(x) ntohl(((u_32_t *)(x))[1]) -#define HI62(x) ntohl(((u_32_t *)(x))[2]) -#define HI63(x) ntohl(((u_32_t *)(x))[3]) - -#define IP6_EQ(a,b) ((I63(a) == I63(b)) && (I62(a) == I62(b)) && \ - (I61(a) == I61(b)) && (I60(a) == I60(b))) -#define IP6_NEQ(a,b) ((I63(a) != I63(b)) || (I62(a) != I62(b)) || \ - (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 NLADD(n,x) htonl(ntohl(n) + (x)) -#define IP6_INC(a) \ - { u_32_t *_i6 = (u_32_t *)(a); \ - _i6[3] = NLADD(_i6[3], 1); \ - if (_i6[3] == 0) { \ - _i6[2] = NLADD(_i6[2], 1); \ - if (_i6[2] == 0) { \ - _i6[1] = NLADD(_i6[1], 1); \ - if (_i6[1] == 0) { \ - _i6[0] = NLADD(_i6[0], 1); \ - } \ - } \ - } \ - } -#define IP6_ADD(a,x,d) \ - { 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])) { \ - _d->i6[1] = NLADD(_d->i6[1], 1); \ - if (ntohl(_d->i6[1]) < ntohl(_s->i6[1])) { \ - _d->i6[2] = NLADD(_d->i6[2], 1); \ - if (ntohl(_d->i6[2]) < ntohl(_s->i6[2])) { \ - _d->i6[3] = NLADD(_d->i6[3], 1); \ - } \ - } \ - } \ - } -#define IP6_AND(a,b,d) { i6addr_t *_s1 = (i6addr_t *)(a); \ - i6addr_t *_s2 = (i6addr_t *)(d); \ - 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]; \ - } -#define IP6_MERGE(a,b,c) \ - { 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]; \ - } - - -typedef struct fr_ip { - u_32_t fi_v:4; /* IP version */ - u_32_t fi_xx:4; /* spare */ - u_32_t fi_tos:8; /* IP packet TOS */ - u_32_t fi_ttl:8; /* IP packet TTL */ - u_32_t fi_p:8; /* IP packet protocol */ - 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 */ - u_32_t fi_flx; /* packet flags */ - u_32_t fi_tcpmsk; /* TCP options set/reset */ - u_32_t fi_res1; /* RESERVED */ -} fr_ip_t; - -/* - * For use in fi_flx - */ -#define FI_TCPUDP 0x0001 /* TCP/UCP implied comparison*/ -#define FI_OPTIONS 0x0002 -#define FI_FRAG 0x0004 -#define FI_SHORT 0x0008 -#define FI_NATED 0x0010 -#define FI_MULTICAST 0x0020 -#define FI_BROADCAST 0x0040 -#define FI_MBCAST 0x0080 -#define FI_STATE 0x0100 -#define FI_BADNAT 0x0200 -#define FI_BAD 0x0400 -#define FI_OOW 0x0800 /* Out of state window, else match */ -#define FI_ICMPERR 0x1000 -#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_ICMPCMP 0x0003 /* Flags we can check for ICMP error packets */ -#define FI_WITH 0xeffe /* Not FI_TCPUDP */ -#define FI_V6EXTHDR 0x10000 -#define FI_COALESCE 0x20000 -#define FI_NEWNAT 0x40000 -#define FI_NOCKSUM 0x20000000 /* don't do a L4 checksum validation */ -#define FI_DONTCACHE 0x40000000 /* don't cache the result */ -#define FI_IGNORE 0x80000000 - -#define fi_saddr fi_src.in4.s_addr -#define fi_daddr fi_dst.in4.s_addr -#define fi_srcnum fi_src.iplookupnum -#define fi_dstnum fi_dst.iplookupnum -#define fi_srcname fi_src.iplookupname -#define fi_dstname fi_dst.iplookupname -#define fi_srctype fi_src.iplookuptype -#define fi_dsttype fi_dst.iplookuptype -#define fi_srcsubtype fi_src.iplookupsubtype -#define fi_dstsubtype fi_dst.iplookupsubtype -#define fi_srcptr fi_src.iplookupptr -#define fi_dstptr fi_dst.iplookupptr -#define fi_srcfunc fi_src.iplookupfunc -#define fi_dstfunc fi_dst.iplookupfunc - - -/* - * These are both used by the state and NAT code to indicate that one port or - * the other should be treated as a wildcard. - * NOTE: When updating, check bit masks in ip_state.h and update there too. - */ -#define SI_W_SPORT 0x00000100 -#define SI_W_DPORT 0x00000200 -#define SI_WILDP (SI_W_SPORT|SI_W_DPORT) -#define SI_W_SADDR 0x00000400 -#define SI_W_DADDR 0x00000800 -#define SI_WILDA (SI_W_SADDR|SI_W_DADDR) -#define SI_NEWFR 0x00001000 -#define SI_CLONE 0x00002000 -#define SI_CLONED 0x00004000 - - -typedef struct fr_info { - 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; - 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 */ - u_32_t fin_rule; /* rule # last matched */ - 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; - int fin_ipoff; /* # bytes from buffer start to hdr */ - u_short fin_id; /* IP packet id field */ - 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; - void *fin_nattag; - void *fin_exthdr; - ip_t *fin_ip; - mb_t **fin_mp; /* pointer to pointer to mbuf */ - mb_t *fin_m; /* pointer to mbuf */ -#ifdef MENTAT - mb_t *fin_qfm; /* pointer to mblk where pkt starts */ - void *fin_qpi; - char fin_ifname[LIFNAMSIZ]; -#endif -#ifdef __sgi - void *fin_hbuf; -#endif -} fr_info_t; - -#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_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 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 struct ipfunc_resolve { - char ipfu_name[32]; - ipfunc_t ipfu_addr; - ipfuncinit_t ipfu_init; -} ipfunc_resolve_t; - -/* - * Size for compares on fr_info structures - */ -#define FI_CSIZE offsetof(fr_info_t, fin_icode) -#define FI_LCSIZE offsetof(fr_info_t, fin_dp) - -/* - * Size for copying cache fr_info structure - */ -#define FI_COPYSIZE offsetof(fr_info_t, fin_dp) - -/* - * Structure for holding IPFilter's tag information - */ -#define IPFTAG_LEN 16 -typedef struct { - union { - u_32_t iptu_num[4]; - char iptu_tag[IPFTAG_LEN]; - } ipt_un; - int ipt_not; -} ipftag_t; - -#define ipt_tag ipt_un.iptu_tag -#define ipt_num ipt_un.iptu_num - - -/* - * 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]; -} frdest_t; - -#define fd_ip fd_ip6.in4 - - -/* - * 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 >< */ -} 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 - * a filter rule. - */ -typedef struct frtuc { - u_char ftu_tcpfm; /* tcp flags mask */ - u_char ftu_tcpf; /* tcp flags */ - frpcmp_t ftu_src; - frpcmp_t ftu_dst; -} frtuc_t; - -#define ftu_scmp ftu_src.frp_cmp -#define ftu_dcmp ftu_dst.frp_cmp -#define ftu_sport ftu_src.frp_port -#define ftu_dport ftu_dst.frp_port -#define ftu_stop ftu_src.frp_top -#define ftu_dtop ftu_dst.frp_top - -#define FR_TCPFMAX 0x3f - -/* - * 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 */ - - 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 */ -} fripf_t; - -#define fri_dlookup fri_mip.fi_dst -#define fri_slookup fri_mip.fi_src -#define fri_dstnum fri_mip.fi_dstnum -#define fri_srcnum fri_mip.fi_srcnum -#define fri_dstname fri_mip.fi_dstname -#define fri_srcname fri_mip.fi_srcname -#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 struct frentry * (* frentfunc_t) __P((fr_info_t *)); - -typedef struct frentry { - ipfmutex_t fr_lock; - struct frentry *fr_next; - struct frentry **fr_grp; - struct ipscan *fr_isc; - 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_statecnt; /* state count - for limit rules */ - /* - * 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 -'' - * with the rule loaded using ``ipf -f ipf.conf'' - thus it can't be - * on the other side of fr_func. - */ - int fr_flineno; /* line number from conf file */ - /* - * These are only incremented when a packet matches this rule and - * it is the last match - */ - U_QUAD_T fr_hits; - U_QUAD_T fr_bytes; - - /* - * For PPS rate limiting - */ - struct timeval fr_lastpkt; - int fr_curpps; - - union { - void *fru_data; - caddr_t fru_caddr; - fripf_t *fru_ipf; - frentfunc_t fru_func; - } fr_dun; - - /* - * Fields after this may not change whilst in the kernel. - */ - ipfunc_t fr_func; /* call this function */ - int fr_dsize; - int fr_pps; - int fr_statemax; /* max reference count */ - u_32_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_loglevel; /* syslog log facility + priority */ - u_int fr_age[2]; /* non-TCP timeouts */ - u_char fr_v; - 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 */ - 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. - */ - u_int fr_cksum; /* checksum on filter rules for performance */ -} frentry_t; - -#define fr_caddr fr_dun.fru_caddr -#define fr_data fr_dun.fru_data -#define fr_dfunc fr_dun.fru_func -#define fr_ipf fr_dun.fru_ipf -#define fr_ip fr_ipf->fri_ip -#define fr_mip fr_ipf->fri_mip -#define fr_icmpm fr_ipf->fri_icmpm -#define fr_icmp fr_ipf->fri_icmp -#define fr_tuc fr_ipf->fri_tuc -#define fr_satype fr_ipf->fri_satype -#define fr_datype fr_ipf->fri_datype -#define fr_sifpidx fr_ipf->fri_sifpidx -#define fr_difpidx fr_ipf->fri_difpidx -#define fr_proto fr_ip.fi_p -#define fr_mproto fr_mip.fi_p -#define fr_ttl fr_ip.fi_ttl -#define fr_mttl fr_mip.fi_ttl -#define fr_tos fr_ip.fi_tos -#define fr_mtos fr_mip.fi_tos -#define fr_tcpfm fr_tuc.ftu_tcpfm -#define fr_tcpf fr_tuc.ftu_tcpf -#define fr_scmp fr_tuc.ftu_scmp -#define fr_dcmp fr_tuc.ftu_dcmp -#define fr_dport fr_tuc.ftu_dport -#define fr_sport fr_tuc.ftu_sport -#define fr_stop fr_tuc.ftu_stop -#define fr_dtop fr_tuc.ftu_dtop -#define fr_dst fr_ip.fi_dst.in4 -#define fr_daddr fr_ip.fi_dst.in4.s_addr -#define fr_src fr_ip.fi_src.in4 -#define fr_saddr fr_ip.fi_src.in4.s_addr -#define fr_dmsk fr_mip.fi_dst.in4 -#define fr_dmask fr_mip.fi_dst.in4.s_addr -#define fr_smsk fr_mip.fi_src.in4 -#define fr_smask fr_mip.fi_src.in4.s_addr -#define fr_dstnum fr_ip.fi_dstnum -#define fr_srcnum fr_ip.fi_srcnum -#define fr_dlookup fr_ip.fi_dst -#define fr_slookup fr_ip.fi_src -#define fr_dstname fr_ip.fi_dstname -#define fr_srcname fr_ip.fi_srcname -#define fr_dsttype fr_ip.fi_dsttype -#define fr_srctype fr_ip.fi_srctype -#define fr_dstsubtype fr_ip.fi_dstsubtype -#define fr_srcsubtype fr_ip.fi_srcsubtype -#define fr_dstptr fr_mip.fi_dstptr -#define fr_srcptr fr_mip.fi_srcptr -#define fr_dstfunc fr_mip.fi_dstfunc -#define fr_srcfunc fr_mip.fi_srcfunc -#define fr_optbits fr_ip.fi_optmsk -#define fr_optmask fr_mip.fi_optmsk -#define fr_secbits fr_ip.fi_secmsk -#define fr_secmask fr_mip.fi_secmsk -#define fr_authbits fr_ip.fi_auth -#define fr_authmask fr_mip.fi_auth -#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] -#define fr_rif fr_tifs[1] - -#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)) - -/* - * 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_CMDMASK 0x0000f -#define FR_LOG 0x00010 /* Log */ -#define FR_LOGB 0x00011 /* Log-fail */ -#define FR_LOGP 0x00012 /* Log-pass */ -#define FR_LOGMASK (FR_LOG|FR_CMDMASK) -#define FR_CALLNOW 0x00020 /* call another function (fr_func) if matches */ -#define FR_NOTSRCIP 0x00040 -#define FR_NOTDSTIP 0x00080 -#define FR_QUICK 0x00100 /* match & stop processing list */ -#define FR_KEEPFRAG 0x00200 /* keep fragment information */ -#define FR_KEEPSTATE 0x00400 /* keep `connection' state information */ -#define FR_FASTROUTE 0x00800 /* bypass normal routing */ -#define FR_RETRST 0x01000 /* Return TCP RST packet - reset connection */ -#define FR_RETICMP 0x02000 /* Return ICMP unreachable packet */ -#define FR_FAKEICMP 0x03000 /* Return ICMP unreachable with fake source */ -#define FR_OUTQUE 0x04000 /* outgoing packets */ -#define FR_INQUE 0x08000 /* ingoing packets */ -#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_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_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) -#define FR_ISPASS(x) (((x) & FR_CMDMASK) == FR_PASS) -#define FR_ISAUTH(x) (((x) & FR_CMDMASK) == FR_AUTH) -#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_ISNOMATCH(x) ((x) & FR_NOMATCH) -#define FR_INOUT (FR_INQUE|FR_OUTQUE) - -/* - * recognized flags for SIOCGETFF and SIOCSETFF, and get put in fr_flags - */ -#define FF_LOGPASS 0x10000000 -#define FF_LOGBLOCK 0x20000000 -#define FF_LOGNOMATCH 0x40000000 -#define FF_LOGGING (FF_LOGPASS|FF_LOGBLOCK|FF_LOGNOMATCH) -#define FF_BLOCKNONIP 0x80000000 /* Solaris2 Only */ - - -/* - * Structure that passes information on what/how to flush to the kernel. - */ -typedef struct ipfflush { - int ipflu_how; - int ipflu_arg; -} ipfflush_t; - - -/* - * - */ -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 */ -} ipfgetctl_t; - -typedef struct ipfsetctl { - int ipfs_which; /* 0 = min 1 = current 2 = max 3 = default */ - u_int ipfs_value; /* min value */ - char ipfs_name[40]; /* tag name for this control */ -} ipfsetctl_t; - - -/* - * Some of the statistics below are in their own counters, but most are kept - * in this single structure so that they can all easily be collected and - * copied back as required. - */ -typedef struct filterstats { - u_long fr_pass; /* packets allowed */ - u_long fr_block; /* packets denied */ - u_long fr_nom; /* packets which don't match any rule */ - u_long fr_short; /* packets which are short */ - u_long fr_ppkl; /* packets allowed and logged */ - u_long fr_bpkl; /* packets denied and logged */ - u_long fr_npkl; /* packets unmatched and logged */ - 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 */ - u_long fr_nfr; /* new fragment state kept */ - u_long fr_cfr; /* add new fragment state but complete pkt */ - u_long fr_bads; /* bad attempts to allocate packet state */ - u_long fr_ads; /* new packet state kept */ - u_long fr_chit; /* cached hit */ - u_long fr_tcpbad; /* TCP checksum check failures */ - u_long fr_pull[2]; /* good and bad pullup attempts */ - 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; - -/* - * Log structure. Each packet header logged is prepended by one of these. - * Following this in the log records read from the device will be an ipflog - * structure which is then followed by any packet data. - */ -typedef struct iplog { - u_32_t ipl_magic; - u_int ipl_count; - struct timeval ipl_time; - size_t ipl_dsize; - struct iplog *ipl_next; -} iplog_t; - -#define ipl_sec ipl_time.tv_sec -#define ipl_usec ipl_time.tv_usec - -#define IPL_MAGIC 0x49504c4d /* 'IPLM' */ -#define IPL_MAGIC_NAT 0x49504c4e /* 'IPLN' */ -#define IPL_MAGIC_STATE 0x49504c53 /* 'IPLS' */ -#define IPLOG_SIZE sizeof(iplog_t) - -typedef struct ipflog { -#if (defined(NetBSD) && (NetBSD <= 1991011) && (NetBSD >= 199603)) || \ - (defined(OpenBSD) && (OpenBSD >= 199603)) -#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; - 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]; -} ipflog_t; - -#ifndef IPF_LOGGING -# define IPF_LOGGING 0 -#endif -#ifndef IPF_DEFAULT_PASS -# define IPF_DEFAULT_PASS FR_PASS -#endif - -#define DEFAULT_IPFLOGSIZE 8192 -#ifndef IPFILTER_LOGSIZE -# define IPFILTER_LOGSIZE DEFAULT_IPFLOGSIZE -#else -# if IPFILTER_LOGSIZE < DEFAULT_IPFLOGSIZE -# error IPFILTER_LOGSIZE too small. Must be >= DEFAULT_IPFLOGSIZE -# endif -#endif - -#define IPF_OPTCOPY 0x07ff00 /* bit mask of copied options */ - -/* - * Device filenames for reading log information. Use ipf on Solaris2 because - * ipl is already a name used by something else. - */ -#ifndef IPL_NAME -# if SOLARIS -# define IPL_NAME "/dev/ipf" -# else -# define IPL_NAME "/dev/ipl" -# endif -#endif -/* - * Pathnames for various IP Filter control devices. Used by LKM - * and userland, so defined here. - */ -#define IPNAT_NAME "/dev/ipnat" -#define IPSTATE_NAME "/dev/ipstate" -#define IPAUTH_NAME "/dev/ipauth" -#define IPSYNC_NAME "/dev/ipsync" -#define IPSCAN_NAME "/dev/ipscan" -#define IPLOOKUP_NAME "/dev/iplookup" - -#define IPL_LOGIPF 0 /* Minor device #'s for accessing logs */ -#define IPL_LOGNAT 1 -#define IPL_LOGSTATE 2 -#define IPL_LOGAUTH 3 -#define IPL_LOGSYNC 4 -#define IPL_LOGSCAN 5 -#define IPL_LOGLOOKUP 6 -#define IPL_LOGCOUNT 7 -#define IPL_LOGMAX 7 -#define IPL_LOGSIZE IPL_LOGMAX + 1 -#define IPL_LOGALL -1 -#define IPL_LOGNONE -2 - -/* - * 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 */ -} 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 -#define IPF_FEAT_LOOKUP 0x004 -#define IPF_FEAT_BPF 0x008 -#define IPF_FEAT_COMPILED 0x010 -#define IPF_FEAT_CKSUM 0x020 -#define IPF_FEAT_SYNC 0x040 -#define IPF_FEAT_SCAN 0x080 -#define IPF_FEAT_IPV6 0x100 - -typedef struct optlist { - u_short ol_val; - int ol_bit; -} optlist_t; - - -/* - * 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]; -} frgroup_t; - -#define FG_NAME(g) (*(g)->fg_name == '\0' ? "" : (g)->fg_name) - - -/* - * Used by state and NAT tables - */ -typedef struct icmpinfo { - 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; -} 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; -} tcpdata_t; - -#define TCP_WSCALE_MAX 14 - -#define TCP_WSCALE_SEEN 0x00000001 -#define TCP_WSCALE_FIRST 0x00000002 -#define TCP_SACK_PERMIT 0x00000004 - - -typedef struct tcpinfo { - u_short ts_sport; - u_short ts_dport; - tcpdata_t ts_data[2]; -} tcpinfo_t; - - -/* - * 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; -}; - -typedef struct grehdr { - union { - struct grebits gru_bits; - u_short gru_flags; - } gr_un; - u_short gr_len; - u_short gr_call; -} grehdr_t; - -#define gr_flags gr_un.gru_flags -#define gr_bits gr_un.gru_bits -#define gr_ptype gr_bits.grb_ptype -#define gr_C gr_bits.grb_C -#define gr_R gr_bits.grb_R -#define gr_K gr_bits.grb_K -#define gr_S gr_bits.grb_S -#define gr_s gr_bits.grb_s -#define gr_recur gr_bits.grb_recur -#define gr_A gr_bits.grb_A -#define gr_ver gr_bits.grb_ver - -/* - * GRE information tracked by "keep state" - */ -typedef struct greinfo { - u_short gs_call[2]; - u_short gs_flags; - u_short gs_ptype; -} greinfo_t; - -#define GRE_REV(x) ((ntohs(x) >> 13) & 7) - - -/* - * 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; - /* Following the sequence number field is 0 or more bytes of */ - /* authentication data, as specified by ah_plen - RFC 2402. */ -} authhdr_t; - - -/* - * Timeout tail queue list member - */ -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 */ -} ipftqent_t; - -#define TQE_RULEBASED 0x00000001 - - -/* - * Timeout tail queue head for IPFilter - */ -typedef struct ipftq { - ipfmutex_t ifq_lock; - 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; -} 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 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; - - -/* - * 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 */ -} ipfobj_t; - -#define IPFOBJ_FRENTRY 0 /* struct frentry */ -#define IPFOBJ_IPFSTAT 1 /* struct friostat */ -#define IPFOBJ_IPFINFO 2 /* struct fr_info */ -#define IPFOBJ_AUTHSTAT 3 /* struct fr_authstat */ -#define IPFOBJ_FRAGSTAT 4 /* struct ipfrstat */ -#define IPFOBJ_IPNAT 5 /* struct ipnat */ -#define IPFOBJ_NATSTAT 6 /* struct natstat */ -#define IPFOBJ_STATESAVE 7 /* struct ipstate_save */ -#define IPFOBJ_NATSAVE 8 /* struct nat_save */ -#define IPFOBJ_NATLOOKUP 9 /* struct natlookup */ -#define IPFOBJ_IPSTATE 10 /* struct ipstate */ -#define IPFOBJ_STATESTAT 11 /* struct ips_stat */ -#define IPFOBJ_FRAUTH 12 /* struct frauth */ -#define IPFOBJ_TUNEABLE 13 /* struct ipftune */ -#define IPFOBJ_NAT 14 /* struct nat */ -#define IPFOBJ_IPFITER 15 /* struct ipfruleiter */ -#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? */ - - -typedef union ipftunevalptr { - void *ipftp_void; - u_long *ipftp_long; - u_int *ipftp_int; - u_short *ipftp_short; - u_char *ipftp_char; -} ipftunevalptr_t; - -typedef struct ipftuneable { - ipftunevalptr_t ipft_una; - const char *ipft_name; - u_long ipft_min; - u_long ipft_max; - int ipft_sz; - int ipft_flags; - struct ipftuneable *ipft_next; -} ipftuneable_t; - -#define ipft_addr ipft_una.ipftp_void -#define ipft_plong ipft_una.ipftp_long -#define ipft_pint ipft_una.ipftp_int -#define ipft_pshort ipft_una.ipftp_short -#define ipft_pchar ipft_una.ipftp_char - -#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; - u_long ipft_min; - u_long ipft_max; - int ipft_sz; - int ipft_flags; - char ipft_name[80]; -} ipftune_t; - -#define ipft_vlong ipft_un.ipftu_long -#define ipft_vint ipft_un.ipftu_int -#define ipft_vshort ipft_un.ipftu_short -#define ipft_vchar ipft_un.ipftu_char - -/* - * - */ -typedef struct ipfruleiter { - int iri_inout; - char iri_group[FR_GROUPLEN]; - int iri_active; - int iri_nrules; - int iri_v; - frentry_t *iri_rule; -} ipfruleiter_t; - -/* - * Values for iri_inout - */ -#define F_IN 0 -#define F_OUT 1 -#define F_ACIN 2 -#define F_ACOUT 3 - - -typedef struct ipfgeniter { - int igi_type; - int igi_nitems; - void *igi_data; -} ipfgeniter_t; - -#define IPFGENITER_IPF 0 -#define IPFGENITER_NAT 1 -#define IPFGENITER_IPNAT 2 -#define IPFGENITER_FRAG 3 -#define IPFGENITER_AUTH 4 -#define IPFGENITER_STATE 5 -#define IPFGENITER_NATFRAG 6 -#define IPFGENITER_HOSTMAP 7 -#define IPFGENITER_LOOKUP 8 - -typedef struct ipftable { - int ita_type; - void *ita_table; -} ipftable_t; - -#define IPFTABLE_BUCKETS 1 -#define IPFTABLE_BUCKETS_NATIN 2 -#define IPFTABLE_BUCKETS_NATOUT 3 - - -/* - * - */ -typedef struct ipftoken { - struct ipftoken *ipt_next; - struct ipftoken **ipt_pnext; - void *ipt_ctx; - void *ipt_data; - u_long ipt_die; - int ipt_type; - int ipt_uid; - int ipt_subtype; - int ipt_alive; -} 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 - -/* - * 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 (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 debug __P((char *, ...)); -extern void verbose __P((char *, ...)); -# define FR_VERBOSE(verb_pr) verbose verb_pr -# define FR_DEBUG(verb_pr) debug verb_pr -#endif - - -#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 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 void m_freem __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 **)); -# if SOLARIS -# if SOLARIS2 >= 7 -extern int iplioctl __P((dev_t, int, intptr_t, int, cred_t *, int *)); -# else -extern int iplioctl __P((dev_t, int, int *, int, cred_t *, int *)); -# endif -extern int iplopen __P((dev_t *, int, int, cred_t *)); -extern int iplclose __P((dev_t, int, int, cred_t *)); -extern int 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)); -# endif -extern int fr_qout __P((queue_t *, mblk_t *)); -# else /* MENTAT */ -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 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 ipfilter_sgi_attach __P((void)); -extern void ipfilter_sgi_detach __P((void)); -extern void ipfilter_sgi_intfsync __P((void)); -# else -# ifdef IPFILTER_LKM -extern int iplidentify __P((char *)); -# endif -# if (_BSDI_VERSION >= 199510) || (__FreeBSD_version >= 220000) || \ - (NetBSD >= 199511) || defined(__OpenBSD__) -# if defined(__NetBSD__) || (_BSDI_VERSION >= 199701) || \ - defined(__OpenBSD__) || (__FreeBSD_version >= 300000) -# if (__FreeBSD_version >= 500024) -# if (__FreeBSD_version >= 502116) -extern int iplioctl __P((struct cdev*, u_long, caddr_t, int, struct thread *)); -# else -extern int iplioctl __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 *)); -# else -# if (__NetBSD_Version__ >= 399001400) -extern int iplioctl __P((dev_t, u_long, caddr_t, int, struct lwp *)); -# else -extern int iplioctl __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 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)); -# 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)); -# 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 */ - -# if defined(__FreeBSD_version) -extern int ipf_pfil_hook __P((void)); -extern int ipf_pfil_unhook __P((void)); -extern void ipf_event_reg __P((void)); -extern void ipf_event_dereg __P((void)); -# endif - -#endif /* #ifndef _KERNEL */ - -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; - -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)); -extern char *getifname __P((struct ifnet *)); -extern int ipfattach __P((void)); -extern int ipfdetach __P((void)); -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)); -#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 *, - struct sockaddr_in *, struct in_addr *, - struct in_addr *)); -extern int fr_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 *)); -#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 *)); - -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 -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[]; - -#endif /* __IP_FIL_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c b/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c deleted file mode 100644 index fbecdad..0000000 --- a/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c +++ /dev/null @@ -1,1645 +0,0 @@ -/* - * Copyright (C) 1993-2003 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 $"; -#endif - -#if defined(KERNEL) || defined(_KERNEL) -# undef KERNEL -# undef _KERNEL -# define KERNEL 1 -# define _KERNEL 1 -#endif -#if defined(__FreeBSD_version) && (__FreeBSD_version >= 400000) && \ - !defined(KLD_MODULE) && !defined(IPFILTER_LKM) -# include "opt_inet6.h" -#endif -#if defined(__FreeBSD_version) && (__FreeBSD_version >= 440000) && \ - !defined(KLD_MODULE) && !defined(IPFILTER_LKM) -# 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 -#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 - -#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> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/ip_var.h> -#include <netinet/tcp.h> -#if defined(__osf__) -# include <netinet/tcp_timer.h> -#endif -#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> -#endif -#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_auth.h" -#ifdef IPFILTER_SYNC -#include "netinet/ip_sync.h" -#endif -#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) -extern int path_mtu_discovery; -#endif - -# ifdef IPFILTER_M_IPFILTER -MALLOC_DEFINE(M_IPFILTER, "IP Filter", "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 -int ipf_locks_done = 0; - -#if (__FreeBSD_version >= 300000) -struct callout_handle fr_slowtimer_ch; -#endif -struct selinfo ipfselwait[IPL_LOGSIZE]; - -#if (__FreeBSD_version >= 500011) -# include <sys/conf.h> -# if defined(NETBSD_PF) -# include <net/pfil.h> -# include <netinet/ipprotosw.h> -/* - * We provide the fr_checkp name just to minimize changes later. - */ -int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp)); -# endif /* NETBSD_PF */ -#endif /* __FreeBSD_version >= 500011 */ - - -#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; -{ - frsync(NULL); -} -#endif - - -#if (__FreeBSD_version >= 501108) && defined(_KERNEL) - -static int -fr_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); -} - -# ifdef USE_INET6 -# include <netinet/ip6.h> - -static int -fr_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)); -} -# endif -#endif /* __FreeBSD_version >= 501108 */ -#if defined(IPFILTER_LKM) -int iplidentify(s) -char *s; -{ - if (strcmp(s, "ipl") == 0) - return 1; - return 0; -} -#endif /* IPFILTER_LKM */ - - -int ipfattach() -{ -#ifdef USE_SPL - int s; -#endif - - SPL_NET(s); - if (fr_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) { - SPL_X(s); - return EIO; - } - - - if (fr_checkp != fr_check) { - fr_savep = fr_checkp; - fr_checkp = fr_check; - } - - bzero((char *)ipfselwait, sizeof(ipfselwait)); - bzero((char *)frcache, sizeof(frcache)); - fr_running = 1; - - if (fr_control_forwarding & 1) - ipforwarding = 1; - - 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 - return 0; -} - - -/* - * Disable the filter by removing the hooks from the IP input/output - * stream. - */ -int ipfdetach() -{ -#ifdef USE_SPL - int s; -#endif - if (fr_control_forwarding & 2) - 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 */ - -#ifndef NETBSD_PF - if (fr_checkp != NULL) - fr_checkp = fr_savep; - fr_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); - - 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; - } - - SPL_X(s); - - return 0; -} - - -/* - * Filter ioctl interface. - */ -int iplioctl(dev, cmd, data, mode -# if defined(_KERNEL) && ((BSD >= 199506) || (__FreeBSD_version >= 220000)) -, p) -# if (__FreeBSD_version >= 500024) -struct thread *p; -# if (__FreeBSD_version >= 500043) -# define p_uid td_ucred->cr_ruid -# else -# 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; -{ - int error = 0, unit = 0; - SPL_INT(s); - -#if (BSD >= 199306) && defined(_KERNEL) - if ((securelevel >= 3) && (mode & FWRITE)) - return EPERM; -#endif - - unit = GET_MINOR(dev); - if ((IPL_LOGMAX < unit) || (unit < 0)) - return ENXIO; - - if (fr_running <= 0) { - if (unit != IPL_LOGIPF) - return EIO; - if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && - cmd != SIOCIPFSET && cmd != SIOCFRENB && - cmd != SIOCGETFS && cmd != SIOCGETFF) - return EIO; - } - - SPL_NET(s); - READ_ENTER(&ipf_global); - - error = fr_ioctlswitch(unit, data, cmd, mode, p->p_uid, p); - if (error != -1) { - RWLOCK_EXIT(&ipf_global); - SPL_X(s); - return error; - } - - RWLOCK_EXIT(&ipf_global); - SPL_X(s); - - return error; -} - - -#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 - * requires a large amount of setting up and isn't any more efficient. - */ -int fr_send_reset(fin) -fr_info_t *fin; -{ - struct tcphdr *tcp, *tcp2; - int tlen = 0, hlen; - struct mbuf *m; -#ifdef USE_INET6 - ip6_t *ip6; -#endif - ip_t *ip; - - tcp = fin->fin_dp; - if (tcp->th_flags & TH_RST) - return -1; /* feedback loop */ - - if (fr_checkl4sum(fin) == -1) - return -1; - - tlen = fin->fin_dlen - (TCP_OFF(tcp) << 2) + - ((tcp->th_flags & TH_SYN) ? 1 : 0) + - ((tcp->th_flags & TH_FIN) ? 1 : 0); - -#ifdef USE_INET6 - hlen = (fin->fin_v == 6) ? sizeof(ip6_t) : sizeof(ip_t); -#else - hlen = sizeof(ip_t); -#endif -#ifdef MGETHDR - MGETHDR(m, M_DONTWAIT, MT_HEADER); -#else - MGET(m, M_DONTWAIT, MT_HEADER); -#endif - if (m == NULL) - return -1; - if (sizeof(*tcp2) + hlen > MLEN) { - MCLGET(m, M_DONTWAIT); - if ((m->m_flags & M_EXT) == 0) { - FREE_MB_T(m); - return -1; - } - } - - m->m_len = sizeof(*tcp2) + hlen; -#if (BSD >= 199103) - m->m_data += max_linkhdr; - m->m_pkthdr.len = m->m_len; - m->m_pkthdr.rcvif = (struct ifnet *)0; -#endif - ip = mtod(m, struct ip *); - bzero((char *)ip, hlen); -#ifdef USE_INET6 - ip6 = (ip6_t *)ip; -#endif - tcp2 = (struct tcphdr *)((char *)ip + hlen); - tcp2->th_sport = tcp->th_dport; - tcp2->th_dport = tcp->th_sport; - - if (tcp->th_flags & TH_ACK) { - tcp2->th_seq = tcp->th_ack; - tcp2->th_flags = TH_RST; - tcp2->th_ack = 0; - } else { - tcp2->th_seq = 0; - tcp2->th_ack = ntohl(tcp->th_seq); - tcp2->th_ack += tlen; - tcp2->th_ack = htonl(tcp2->th_ack); - tcp2->th_flags = TH_RST|TH_ACK; - } - TCP_X2_A(tcp2, 0); - TCP_OFF_A(tcp2, sizeof(*tcp2) >> 2); - tcp2->th_win = tcp->th_win; - tcp2->th_sum = 0; - tcp2->th_urp = 0; - -#ifdef USE_INET6 - if (fin->fin_v == 6) { - ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; - 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; - tcp2->th_sum = in6_cksum(m, IPPROTO_TCP, - sizeof(*ip6), sizeof(*tcp2)); - return fr_send_ip(fin, m, &m); - } -#endif - ip->ip_p = IPPROTO_TCP; - ip->ip_len = htons(sizeof(struct tcphdr)); - 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); -} - - -static int fr_send_ip(fin, m, mpp) -fr_info_t *fin; -mb_t *m, **mpp; -{ - fr_info_t fnew; - ip_t *ip, *oip; - int hlen; - - ip = mtod(m, ip_t *); - bzero((char *)&fnew, sizeof(fnew)); - - IP_V_A(ip, fin->fin_v); - switch (fin->fin_v) - { - case 4 : - fnew.fin_v = 4; - oip = fin->fin_ip; - 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 = path_mtu_discovery ? IP_DF : 0; -#else - ip->ip_off = 0; -#endif - ip->ip_ttl = ip_defttl; - ip->ip_sum = 0; - hlen = sizeof(*oip); - break; -#ifdef USE_INET6 - case 6 : - { - ip6_t *ip6 = (ip6_t *)ip; - - ip6->ip6_vfc = 0x60; - ip6->ip6_hlim = IPDEFTTL; - - fnew.fin_v = 6; - hlen = sizeof(*ip6); - break; - } -#endif - default : - return EINVAL; - } -#ifdef IPSEC - m->m_pkthdr.rcvif = NULL; -#endif - - fnew.fin_ifp = fin->fin_ifp; - fnew.fin_flx = FI_NOCKSUM; - fnew.fin_m = m; - fnew.fin_ip = ip; - fnew.fin_mp = mpp; - fnew.fin_hlen = hlen; - fnew.fin_dp = (char *)ip + hlen; - (void) fr_makefrip(hlen, ip, &fnew); - - return fr_fastroute(m, mpp, &fnew, NULL); -} - - -int fr_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; - void *ifp; -#ifdef USE_INET6 - ip6_t *ip6; - struct in6_addr dst6; -#endif - ip_t *ip, *ip2; - - if ((type < 0) || (type >= ICMP_MAXTYPE)) - return -1; - - code = fin->fin_icode; -#ifdef USE_INET6 - if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) - return -1; -#endif - - if (fr_checkl4sum(fin) == -1) - return -1; -#ifdef MGETHDR - MGETHDR(m, M_DONTWAIT, MT_HEADER); -#else - MGET(m, M_DONTWAIT, MT_HEADER); -#endif - if (m == NULL) - return -1; - avail = MHLEN; - - xtra = 0; - hlen = 0; - ohlen = 0; - ifp = fin->fin_ifp; - if (fin->fin_v == 4) { - if ((fin->fin_p == IPPROTO_ICMP) && - !(fin->fin_flx & FI_SHORT)) - switch (ntohs(fin->fin_data[0]) >> 8) - { - case ICMP_ECHO : - case ICMP_TSTAMP : - case ICMP_IREQ : - case ICMP_MASKREQ : - break; - default : - FREE_MB_T(m); - return 0; - } - - if (dst == 0) { - if (fr_ifpaddr(4, FRI_NORMAL, ifp, - &dst4, NULL) == -1) { - FREE_MB_T(m); - return -1; - } - } else - dst4.s_addr = fin->fin_daddr; - - hlen = sizeof(ip_t); - ohlen = fin->fin_hlen; - if (fin->fin_hlen < fin->fin_plen) - xtra = MIN(fin->fin_dlen, 8); - else - xtra = 0; - } - -#ifdef USE_INET6 - else if (fin->fin_v == 6) { - hlen = sizeof(ip6_t); - ohlen = sizeof(ip6_t); - type = icmptoicmp6types[type]; - if (type == ICMP6_DST_UNREACH) - code = icmptoicmp6unreach[code]; - - if (hlen + sizeof(*icmp) + max_linkhdr + - fin->fin_plen > avail) { - MCLGET(m, M_DONTWAIT); - if ((m->m_flags & M_EXT) == 0) { - FREE_MB_T(m); - return -1; - } - avail = MCLBYTES; - } - xtra = MIN(fin->fin_plen, - avail - hlen - sizeof(*icmp) - max_linkhdr); - if (dst == 0) { - if (fr_ifpaddr(6, FRI_NORMAL, ifp, - (struct in_addr *)&dst6, NULL) == -1) { - FREE_MB_T(m); - return -1; - } - } else - dst6 = fin->fin_dst6; - } -#endif - else { - FREE_MB_T(m); - return -1; - } - - iclen = hlen + sizeof(*icmp); - avail -= (max_linkhdr + iclen); - if (avail < 0) { - FREE_MB_T(m); - return -1; - } - if (xtra > avail) - xtra = avail; - iclen += xtra; - m->m_data += max_linkhdr; - m->m_pkthdr.rcvif = (struct ifnet *)0; - m->m_pkthdr.len = iclen; - m->m_len = iclen; - ip = mtod(m, ip_t *); - icmp = (struct icmp *)((char *)ip + hlen); - ip2 = (ip_t *)&icmp->icmp_ip; - - icmp->icmp_type = type; - icmp->icmp_code = fin->fin_icode; - icmp->icmp_cksum = 0; -#ifdef icmp_nextmtu - if (type == ICMP_UNREACH && - fin->fin_icode == ICMP_UNREACH_NEEDFRAG && ifp) - icmp->icmp_nextmtu = htons(((struct ifnet *)ifp)->if_mtu); -#endif - - bcopy((char *)fin->fin_ip, (char *)ip2, ohlen); - -#ifdef USE_INET6 - ip6 = (ip6_t *)ip; - if (fin->fin_v == 6) { - ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; - 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; - if (xtra > 0) - bcopy((char *)fin->fin_ip + ohlen, - (char *)&icmp->icmp_ip + ohlen, xtra); - icmp->icmp_cksum = in6_cksum(m, IPPROTO_ICMPV6, - sizeof(*ip6), iclen - hlen); - } 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; - - if (xtra > 0) - bcopy((char *)fin->fin_ip + ohlen, - (char *)&icmp->icmp_ip + ohlen, xtra); - icmp->icmp_cksum = ipf_cksum((u_short *)icmp, - sizeof(*icmp) + 8); - ip->ip_len = iclen; - ip->ip_p = IPPROTO_ICMP; - } - err = fr_send_ip(fin, m, &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 */ - - -int fr_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 = m0; - register struct route *ro; - int len, off, error = 0, hlen, code; - struct ifnet *ifp, *sifp; - struct sockaddr_in *dst; - struct route iproute; - u_short ip_off; - frentry_t *fr; - - ro = NULL; - -#ifdef M_WRITABLE - /* - * HOT FIX/KLUDGE: - * - * If the mbuf we're about to send is not writable (because of - * a cluster reference, for example) we'll need to make a copy - * of it since this routine modifies the contents. - * - * If you have non-crappy network hardware that can transmit data - * from the mbuf, rather than making a copy, this is gonna be a - * problem. - */ - if (M_WRITABLE(m) == 0) { - m0 = m_dup(m, M_DONTWAIT); - if (m0 != 0) { - FREE_MB_T(m); - m = m0; - *mpp = m; - } else { - error = ENOBUFS; - FREE_MB_T(m); - goto done; - } - } -#endif - -#ifdef USE_INET6 - if (fin->fin_v == 6) { - /* - * 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 - } -#endif - - hlen = fin->fin_hlen; - ip = mtod(m0, struct ip *); - - /* - * Route packet. - */ - ro = &iproute; - bzero((caddr_t)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 (fdp != NULL) - ifp = fdp->fd_ifp; - else - ifp = fin->fin_ifp; - - if ((ifp == NULL) && (!fr || !(fr->fr_flags & FR_FASTROUTE))) { - error = -2; - goto bad; - } - - if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0)) - dst->sin_addr = fdp->fd_ip; - - dst->sin_len = sizeof(*dst); - rtalloc(ro); - - if ((ifp == NULL) && (ro->ro_rt != NULL)) - ifp = ro->ro_rt->rt_ifp; - - if ((ro->ro_rt == NULL) || (ifp == NULL)) { - if (in_localaddr(ip->ip_dst)) - error = EHOSTUNREACH; - else - error = ENETUNREACH; - goto bad; - } - if (ro->ro_rt->rt_flags & RTF_GATEWAY) - dst = (struct sockaddr_in *)ro->ro_rt->rt_gateway; - if (ro->ro_rt) - ro->ro_rt->rt_use++; - - /* - * For input packets which are being "fastrouted", they won't - * go back through output filtering and miss their chance to get - * NAT'd and counted. Duplicated packets aren't considered to be - * part of the normal packet stream, so do not NAT them or pass - * them through stateful checking, etc. - */ - if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) { - sifp = fin->fin_ifp; - fin->fin_ifp = ifp; - fin->fin_out = 1; - (void) fr_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); - } - - switch (fr_checknatout(fin, NULL)) - { - case 0 : - break; - case 1 : - fr_natderef((nat_t **)&fin->fin_nat); - ip->ip_sum = 0; - break; - case -1 : - error = -1; - goto done; - break; - } - - fin->fin_ifp = sifp; - fin->fin_out = 0; - } else - ip->ip_sum = 0; - /* - * 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 (!ip->ip_sum) - ip->ip_sum = in_cksum(m, hlen); - error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, - ro->ro_rt); - goto done; - } - /* - * Too large for interface; fragment if possible. - * Must be able to put at least 8 bytes per fragment. - */ - ip_off = ntohs(ip->ip_off); - if (ip_off & IP_DF) { - error = EMSGSIZE; - goto bad; - } - len = (ifp->if_mtu - hlen) &~ 7; - if (len < 8) { - error = EMSGSIZE; - goto bad; - } - - { - int mhlen, firstlen = len; - struct mbuf **mnext = &m->m_act; - - /* - * Loop through length of segment after first fragment, - * make new header and copy data of each part and link onto chain. - */ - m0 = m; - mhlen = sizeof (struct ip); - for (off = hlen + len; off < ip->ip_len; off += len) { -#ifdef MGETHDR - MGETHDR(m, M_DONTWAIT, MT_HEADER); -#else - MGET(m, M_DONTWAIT, MT_HEADER); -#endif - if (m == 0) { - m = m0; - error = ENOBUFS; - goto bad; - } - m->m_data += max_linkhdr; - mhip = mtod(m, struct ip *); - bcopy((char *)ip, (char *)mhip, sizeof(*ip)); - if (hlen > sizeof (struct ip)) { - mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); - IP_HL_A(mhip, mhlen >> 2); - } - m->m_len = mhlen; - mhip->ip_off = ((off - hlen) >> 3) + ip_off; - if (off + len >= ip->ip_len) - len = ip->ip_len - off; - else - mhip->ip_off |= IP_MF; - mhip->ip_len = htons((u_short)(len + mhlen)); - *mnext = m; - m->m_next = m_copy(m0, off, len); - if (m->m_next == 0) { - error = ENOBUFS; /* ??? */ - goto sendorfree; - } - m->m_pkthdr.len = mhlen + len; - m->m_pkthdr.rcvif = NULL; - mhip->ip_off = htons((u_short)mhip->ip_off); - mhip->ip_sum = 0; - mhip->ip_sum = in_cksum(m, mhlen); - mnext = &m->m_act; - } - /* - * Update first fragment by trimming what's been copied out - * and updating header, then send each fragment (in order). - */ - m_adj(m0, hlen + firstlen - ip->ip_len); - ip->ip_len = htons((u_short)(hlen + firstlen)); - ip->ip_off = htons((u_short)IP_MF); - ip->ip_sum = 0; - ip->ip_sum = in_cksum(m0, hlen); -sendorfree: - for (m = m0; m; m = m0) { - m0 = m->m_act; - m->m_act = 0; - if (error == 0) - error = (*ifp->if_output)(ifp, m, - (struct sockaddr *)dst, ro->ro_rt); - else - FREE_MB_T(m); - } - } -done: - if (!error) - fr_frouteok[0]++; - else - fr_frouteok[1]++; - - if ((ro != NULL) && (ro->ro_rt != NULL)) { - RTFREE(ro->ro_rt); - } - *mpp = NULL; - return 0; -bad: - if (error == EMSGSIZE) { - sifp = fin->fin_ifp; - code = fin->fin_icode; - fin->fin_icode = ICMP_UNREACH_NEEDFRAG; - fin->fin_ifp = ifp; - (void) fr_send_icmp_err(ICMP_UNREACH, fin, 1); - fin->fin_ifp = sifp; - fin->fin_icode = code; - } - FREE_MB_T(m); - goto done; -} - - -int fr_verifysrc(fin) -fr_info_t *fin; -{ - struct sockaddr_in *dst; - struct route iproute; - - bzero((char *)&iproute, sizeof(iproute)); - dst = (struct sockaddr_in *)&iproute.ro_dst; - dst->sin_len = sizeof(*dst); - dst->sin_family = AF_INET; - dst->sin_addr = fin->fin_src; - rtalloc(&iproute); - if (iproute.ro_rt == NULL) - return 0; - return (fin->fin_ifp == iproute.ro_rt->rt_ifp); -} - - -/* - * 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; -{ -#ifdef USE_INET6 - struct in6_addr *inp6 = NULL; -#endif - struct sockaddr *sock, *mask; - struct sockaddr_in *sin; - struct ifaddr *ifa; - struct ifnet *ifp; - - if ((ifptr == NULL) || (ifptr == (void *)-1)) - return -1; - - sin = NULL; - ifp = ifptr; - - if (v == 4) - inp->s_addr = 0; -#ifdef USE_INET6 - else if (v == 6) - bzero((char *)inp, sizeof(struct in6_addr)); -#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) { - sin = (struct sockaddr_in *)sock; - if ((v == 4) && (sin->sin_family == AF_INET)) - break; -#ifdef USE_INET6 - if ((v == 6) && (sin->sin_family == AF_INET6)) { - inp6 = &((struct sockaddr_in6 *)sin)->sin6_addr; - if (!IN6_IS_ADDR_LINKLOCAL(inp6) && - !IN6_IS_ADDR_LOOPBACK(inp6)) - break; - } -#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; - } - - if (ifa == NULL || sin == NULL) - return -1; - - mask = ifa->ifa_netmask; - if (atype == FRI_BROADCAST) - sock = ifa->ifa_broadaddr; - else if (atype == FRI_PEERADDR) - sock = ifa->ifa_dstaddr; - - if (sock == NULL) - return -1; - -#ifdef USE_INET6 - if (v == 6) { - return fr_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); -} - - -u_32_t fr_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 */ -/* 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; -{ -#ifndef RANDOM_IP_ID - static u_short ipid = 0; - u_short id; - - MUTEX_ENTER(&ipf_rw); - id = ipid++; - MUTEX_EXIT(&ipf_rw); -#else - u_short id; - - id = ip_randomid(); -#endif - - return id; -} - - -INLINE void fr_checkv4sum(fin) -fr_info_t *fin; -{ -#ifdef CSUM_DATA_VALID - int manual = 0; - u_short sum; - ip_t *ip; - mb_t *m; - - if ((fin->fin_flx & FI_NOCKSUM) != 0) - return; - - if (fin->fin_cksum != 0) - return; - - m = fin->fin_m; - if (m == NULL) { - manual = 1; - goto skipauto; - } - ip = fin->fin_ip; - - 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_p)); - sum ^= 0xffff; - if (sum != 0) { - fin->fin_flx |= FI_BAD; - fin->fin_cksum = -1; - } else { - fin->fin_cksum = 1; - } - } else - manual = 1; -skipauto: -# ifdef IPFILTER_CKSUM - if (manual != 0) - if (fr_checkl4sum(fin) == -1) - fin->fin_flx |= FI_BAD; -# else - ; -# endif -#else -# ifdef IPFILTER_CKSUM - if (fr_checkl4sum(fin) == -1) - fin->fin_flx |= FI_BAD; -# endif -#endif -} - - -#ifdef USE_INET6 -INLINE void fr_checkv6sum(fin) -fr_info_t *fin; -{ -# ifdef IPFILTER_CKSUM - if (fr_checkl4sum(fin) == -1) - fin->fin_flx |= FI_BAD; -# endif -} -#endif /* USE_INET6 */ - - -size_t mbufchainlen(m0) -struct mbuf *m0; -{ - size_t len; - - if ((m0->m_flags & M_PKTHDR) != 0) { - len = m0->m_pkthdr.len; - } else { - struct mbuf *m; - - for (m = m0, len = 0; m != NULL; m = m->m_next) - len += m->m_len; - } - return len; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_pullup */ -/* Returns: NULL == pullup failed, else pointer to protocol header */ -/* Parameters: m(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 */ -/* 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 */ -/* of buffers that starts at *fin->fin_mp. */ -/* ------------------------------------------------------------------------ */ -void *fr_pullup(min, fin, len) -mb_t *min; -fr_info_t *fin; -int len; -{ - int out = fin->fin_out, dpoff, ipoff; - mb_t *m = min; - char *ip; - - if (m == NULL) - return NULL; - - ip = (char *)fin->fin_ip; - if ((fin->fin_flx & FI_COALESCE) != 0) - return ip; - - ipoff = fin->fin_ipoff; - if (fin->fin_dp != NULL) - dpoff = (char *)fin->fin_dp - (char *)ip; - else - dpoff = 0; - - if (M_LEN(m) < len) { -#ifdef MHLEN - /* - * Assume that M_PKTHDR is set and just work with what is left - * rather than check.. - * Should not make any real difference, anyway. - */ - if (len > MHLEN) -#else - if (len > MLEN) -#endif - { -#ifdef HAVE_M_PULLDOWN - if (m_pulldown(m, 0, len, NULL) == NULL) - m = NULL; -#else - FREE_MB_T(*fin->fin_mp); - m = NULL; -#endif - } else - { - m = m_pullup(m, len); - } - *fin->fin_mp = m; - if (m == NULL) { - fin->fin_m = NULL; - ATOMIC_INCL(frstats[out].fr_pull[1]); - return NULL; - } - - 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; - - if (len == fin->fin_plen) - fin->fin_flx |= FI_COALESCE; - return ip; -} - - -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 { -#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; -} - -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_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_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 - - return (0); -} - -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); -# endif - if (ph_inet == NULL -# ifdef USE_INET6 - && ph_inet6 == NULL -# endif - ) - return ENODEV; - - if (ph_inet != NULL) - pfil_add_hook((void *)fr_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_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); -} - -void -ipf_event_reg(void) -{ -#if (__FreeBSD_version >= 502103) - ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \ - ipf_ifevent, NULL, \ - EVENTHANDLER_PRI_ANY); - ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \ - ipf_ifevent, NULL, \ - EVENTHANDLER_PRI_ANY); - ipf_clonetag = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \ - NULL, EVENTHANDLER_PRI_ANY); -#endif -} - -void -ipf_event_dereg(void) -{ -#if (__FreeBSD_version >= 502103) - if (ipf_arrivetag != NULL) { - EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag); - } - if (ipf_departtag != NULL) { - EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag); - } - if (ipf_clonetag != NULL) { - EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag); - } -#endif -} diff --git a/sys/contrib/ipfilter/netinet/ip_frag.c b/sys/contrib/ipfilter/netinet/ip_frag.c deleted file mode 100644 index fd738f2..0000000 --- a/sys/contrib/ipfilter/netinet/ip_frag.c +++ /dev/null @@ -1,990 +0,0 @@ -/* - * Copyright (C) 1993-2003 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> -#ifdef __hpux -# include <sys/timeout.h> -#endif -#if !defined(_KERNEL) -# include <stdio.h> -# include <string.h> -# include <stdlib.h> -# define _KERNEL -# ifdef __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(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__) -# if defined(_KERNEL) && !defined(__sgi) && !defined(AIX) -# include <sys/kernel.h> -# endif -#else -# include <sys/byteorder.h> -# ifdef _KERNEL -# include <sys/dditypes.h> -# endif -# include <sys/stream.h> -# include <sys/kmem.h> -#endif -#include <net/if.h> -#ifdef sun -# include <net/af.h> -#endif -#include <net/route.h> -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#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_auth.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 -/* END OF INCLUDES */ - -#if !defined(lint) -static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.12 2007/09/20 12:51:51 darrenr Exp $"; -#endif - - -ipfr_t *ipfr_list = NULL; -ipfr_t **ipfr_tail = &ipfr_list; - -ipfr_t *ipfr_natlist = NULL; -ipfr_t **ipfr_nattail = &ipfr_natlist; - -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; - -int fr_ipfrttl = 120; /* 60 seconds */ -int fr_frag_lock = 0; -int fr_frag_init = 0; -u_long fr_ticks = 0; - - -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 *)); - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_fraginit */ -/* Returns: int - 0 == success, -1 == error */ -/* Parameters: Nil */ -/* */ -/* Initialise the hash tables for the fragment cache lookups. */ -/* ------------------------------------------------------------------------ */ -int fr_fraginit() -{ - 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 *)); - - 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) - return -1; - bzero((char *)ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *)); - - RWLOCK_INIT(&ipf_frag, "ipf fragment rwlock"); - fr_frag_init = 1; - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_fragunload */ -/* Returns: Nil */ -/* Parameters: Nil */ -/* */ -/* Free all memory allocated whilst running and from initialisation. */ -/* ------------------------------------------------------------------------ */ -void fr_fragunload() -{ - if (fr_frag_init == 1) { - fr_fragclear(); - - RW_DESTROY(&ipf_frag); - fr_frag_init = 0; - } - - if (ipfr_heads != NULL) - KFREES(ipfr_heads, ipfr_size * sizeof(ipfr_t *)); - ipfr_heads = NULL; - - if (ipfr_nattab != NULL) - KFREES(ipfr_nattab, ipfr_size * sizeof(ipfr_t *)); - ipfr_nattab = NULL; - - if (ipfr_ipidtab != NULL) - KFREES(ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *)); - ipfr_ipidtab = NULL; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_fragstats */ -/* Returns: ipfrstat_t* - pointer to struct with current frag stats */ -/* Parameters: Nil */ -/* */ -/* Updates ipfr_stats with current information and returns a pointer to it */ -/* ------------------------------------------------------------------------ */ -ipfrstat_t *fr_fragstats() -{ - ipfr_stats.ifs_table = ipfr_heads; - ipfr_stats.ifs_nattab = ipfr_nattab; - ipfr_stats.ifs_inuse = ipfr_inuse; - return &ipfr_stats; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipfr_newfrag */ -/* 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 */ -/* */ -/* Add a new entry to the fragment cache, registering it as having come */ -/* through this box, with the result of the filter operation. */ -/* ------------------------------------------------------------------------ */ -static ipfr_t *ipfr_newfrag(fin, pass, table) -fr_info_t *fin; -u_32_t pass; -ipfr_t *table[]; -{ - ipfr_t *fra, frag; - u_int idx, off; - frentry_t *fr; - ip_t *ip; - - if (ipfr_inuse >= IPFT_SIZE) - return NULL; - - if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) - return NULL; - - ip = fin->fin_ip; - - if (pass & FR_FRSTRICT) - if (fin->fin_off != 0) - 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_ifp = fin->fin_ifp; - idx *= 127; - idx %= IPFT_SIZE; - - frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; - frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; - frag.ipfr_auth = fin->fin_fi.fi_auth; - - /* - * first, make sure it isn't already there... - */ - 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; - } - - /* - * 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++; - return NULL; - } - - fr = fin->fin_fr; - fra->ipfr_rule = fr; - if (fr != NULL) { - MUTEX_ENTER(&fr->fr_lock); - fr->fr_ref++; - MUTEX_EXIT(&fr->fr_lock); - } - - /* - * Insert the fragment into the fragment table, copy the struct used - * in the search using bcopy rather than reassign each field. - * Set the ttl to the default. - */ - if ((fra->ipfr_hnext = table[idx]) != NULL) - table[idx]->ipfr_hprev = &fra->ipfr_hnext; - fra->ipfr_hprev = table + idx; - 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; - - /* - * 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++; - return fra; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_newfrag */ -/* 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; -{ - ipfr_t *fra; - - if ((fin->fin_v != 4) || (fr_frag_lock != 0)) - return -1; - - WRITE_ENTER(&ipf_frag); - fra = ipfr_newfrag(fin, pass, ipfr_heads); - if (fra != NULL) { - *ipfr_tail = fra; - fra->ipfr_prev = ipfr_tail; - ipfr_tail = &fra->ipfr_next; - if (ipfr_list == NULL) - ipfr_list = fra; - fra->ipfr_next = NULL; - } - RWLOCK_EXIT(&ipf_frag); - return fra ? 0 : -1; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_nat_newfrag */ -/* Returns: int - 0 == success, -1 == error */ -/* Parameters: fin(I) - pointer to packet information */ -/* nat(I) - pointer to NAT structure */ -/* */ -/* 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; -{ - ipfr_t *fra; - - if ((fin->fin_v != 4) || (fr_frag_lock != 0)) - return 0; - - WRITE_ENTER(&ipf_natfrag); - fra = ipfr_newfrag(fin, pass, ipfr_nattab); - if (fra != NULL) { - fra->ipfr_data = nat; - nat->nat_data = fra; - *ipfr_nattail = fra; - fra->ipfr_prev = ipfr_nattail; - ipfr_nattail = &fra->ipfr_next; - fra->ipfr_next = NULL; - } - RWLOCK_EXIT(&ipf_natfrag); - return fra ? 0 : -1; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_ipid_newfrag */ -/* Returns: int - 0 == success, -1 == error */ -/* Parameters: fin(I) - pointer to packet information */ -/* ipid(I) - new IP ID for this fragmented packet */ -/* */ -/* 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; -{ - ipfr_t *fra; - - if ((fin->fin_v != 4) || (fr_frag_lock)) - return 0; - - WRITE_ENTER(&ipf_ipidfrag); - fra = ipfr_newfrag(fin, 0, ipfr_ipidtab); - if (fra != NULL) { - fra->ipfr_data = (void *)((u_long)ipid); - *ipfr_ipidtail = fra; - fra->ipfr_prev = ipfr_ipidtail; - ipfr_ipidtail = &fra->ipfr_next; - fra->ipfr_next = NULL; - } - RWLOCK_EXIT(&ipf_ipidfrag); - return fra ? 0 : -1; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_fraglookup */ -/* 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 */ -/* table(I) - pointer to fragment cache table to search */ -/* */ -/* Check the fragment cache to see if there is already a record of this */ -/* packet with its filter result known. */ -/* ------------------------------------------------------------------------ */ -static ipfr_t *fr_fraglookup(fin, table) -fr_info_t *fin; -ipfr_t *table[]; -{ - ipfr_t *f, frag; - u_int idx; - ip_t *ip; - - if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) - return NULL; - - /* - * For fragments, we record protocol, packet id, TOS and both IP#'s - * (these should all be the same for all fragments of a packet). - * - * 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_ifp = fin->fin_ifp; - idx *= 127; - idx %= IPFT_SIZE; - - frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; - frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; - frag.ipfr_auth = fin->fin_fi.fi_auth; - - /* - * check the table, careful to only compare the right amount of data - */ - 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; - if (f->ipfr_seen0) { - if (off == 0) { - ATOMIC_INCL(ipfr_stats.ifs_retrans0); - continue; - } - } else if (off == 0) - f->ipfr_seen0 = 1; - - if (f != table[idx]) { - ipfr_t **fp; - - /* - * Move fragment info. to the top of the list - * to speed up searches. First, delink... - */ - fp = f->ipfr_hprev; - (*fp) = f->ipfr_hnext; - if (f->ipfr_hnext != NULL) - f->ipfr_hnext->ipfr_hprev = fp; - /* - * Then put back at the top of the chain. - */ - f->ipfr_hnext = table[idx]; - table[idx]->ipfr_hprev = &f->ipfr_hnext; - f->ipfr_hprev = table + idx; - table[idx] = f; - } - - /* - * If we've follwed the fragments, and this is the - * 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); - return f; - } - return NULL; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_nat_knownfrag */ -/* 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 *nat; - ipfr_t *ipf; - - if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_natlist) - return NULL; - READ_ENTER(&ipf_natfrag); - ipf = fr_fraglookup(fin, ipfr_nattab); - if (ipf != NULL) { - nat = ipf->ipfr_data; - /* - * This is the last fragment for this packet. - */ - if ((ipf->ipfr_ttl == fr_ticks + 1) && (nat != NULL)) { - nat->nat_data = NULL; - ipf->ipfr_data = NULL; - } - } else - nat = NULL; - RWLOCK_EXIT(&ipf_natfrag); - return nat; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_ipid_knownfrag */ -/* 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; -{ - ipfr_t *ipf; - u_32_t id; - - if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_ipidlist) - return 0xffffffff; - - READ_ENTER(&ipf_ipidfrag); - ipf = fr_fraglookup(fin, ipfr_ipidtab); - if (ipf != NULL) - id = (u_32_t)((u_long)ipf->ipfr_data & 0xffffffff); - else - id = 0xffffffff; - RWLOCK_EXIT(&ipf_ipidfrag); - return id; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_knownfrag */ -/* 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 */ -/* passp(O) - pointer to where to store rule flags resturned */ -/* */ -/* Functional interface for normal lookups of the fragment cache. If a */ -/* 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 *fr = NULL; - ipfr_t *fra; - u_32_t pass; - - if ((fin->fin_v != 4) || (fr_frag_lock) || (ipfr_list == NULL)) - return NULL; - - READ_ENTER(&ipf_frag); - fra = fr_fraglookup(fin, ipfr_heads); - if (fra != NULL) { - fr = fra->ipfr_rule; - fin->fin_fr = fr; - if (fr != NULL) { - pass = fr->fr_flags; - if ((pass & FR_LOGFIRST) != 0) - pass &= ~(FR_LOGFIRST|FR_LOG); - *passp = pass; - } - } - 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 */ -/* 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; -{ - ipfr_t *fr; - - WRITE_ENTER(&ipf_natfrag); - for (fr = ipfr_natlist; fr; fr = fr->ipfr_next) - if (fr->ipfr_data == ptr) - fr->ipfr_data = NULL; - RWLOCK_EXIT(&ipf_natfrag); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_fragdelete */ -/* Returns: Nil */ -/* Parameters: fra(I) - pointer to fragment structure to delete */ -/* tail(IO) - pointer to the pointer to the tail of the frag */ -/* list */ -/* */ -/* Remove a fragment cache table entry from the table & list. Also free */ -/* 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; -{ - - if (fra->ipfr_next) - fra->ipfr_next->ipfr_prev = fra->ipfr_prev; - *fra->ipfr_prev = fra->ipfr_next; - if (*tail == &fra->ipfr_next) - *tail = fra->ipfr_prev; - - if (fra->ipfr_hnext) - fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev; - *fra->ipfr_hprev = fra->ipfr_hnext; - - if (fra->ipfr_rule != NULL) { - (void) fr_derefrule(&fra->ipfr_rule); - } - - if (fra->ipfr_ref <= 0) - fr_fragfree(fra); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_fragfree */ -/* 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; -{ - KFREE(fra); - ipfr_stats.ifs_expire++; - ipfr_inuse--; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_fragclear */ -/* 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() -{ - ipfr_t *fra; - nat_t *nat; - - WRITE_ENTER(&ipf_frag); - while ((fra = ipfr_list) != NULL) { - fra->ipfr_ref--; - fr_fragdelete(fra, &ipfr_tail); - } - ipfr_tail = &ipfr_list; - RWLOCK_EXIT(&ipf_frag); - - WRITE_ENTER(&ipf_nat); - WRITE_ENTER(&ipf_natfrag); - while ((fra = 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); - } - ipfr_nattail = &ipfr_natlist; - RWLOCK_EXIT(&ipf_natfrag); - RWLOCK_EXIT(&ipf_nat); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_fragexpire */ -/* Returns: Nil */ -/* Parameters: Nil */ -/* */ -/* Expire entries in the fragment cache table that have been there too long */ -/* ------------------------------------------------------------------------ */ -void fr_fragexpire() -{ - ipfr_t **fp, *fra; - nat_t *nat; - SPL_INT(s); - - if (fr_frag_lock) - return; - - SPL_NET(s); - WRITE_ENTER(&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. - */ - for (fp = &ipfr_list; ((fra = *fp) != NULL); ) { - if (fra->ipfr_ttl > fr_ticks) - break; - fra->ipfr_ref--; - fr_fragdelete(fra, &ipfr_tail); - } - RWLOCK_EXIT(&ipf_frag); - - WRITE_ENTER(&ipf_ipidfrag); - for (fp = &ipfr_ipidlist; ((fra = *fp) != NULL); ) { - if (fra->ipfr_ttl > fr_ticks) - break; - fra->ipfr_ref--; - fr_fragdelete(fra, &ipfr_ipidtail); - } - RWLOCK_EXIT(&ipf_ipidfrag); - - /* - * Same again for the NAT table, except that if the structure also - * still points to a NAT structure, and the NAT structure points back - * at the one to be free'd, NULL the reference from the NAT struct. - * NOTE: We need to grab both mutex's early, and in this order so as - * to prevent a deadlock if both try to expire at the same time. - * The extra if() statement here is because it locks out all NAT - * 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) - break; - nat = fra->ipfr_data; - if (nat != NULL) { - if (nat->nat_data == fra) - nat->nat_data = NULL; - } - fra->ipfr_ref--; - fr_fragdelete(fra, &ipfr_nattail); - } - RWLOCK_EXIT(&ipf_natfrag); - RWLOCK_EXIT(&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 -{ - 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 -} -#endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */ - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_nextfrag */ -/* 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 */ -/* fragment cache. It increases the reference count on the one currently */ -/* 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. */ -/* ------------------------------------------------------------------------ */ -int fr_nextfrag(token, itp, top, tail -#ifdef USE_MUTEXES -, lock -#endif -) -ipftoken_t *token; -ipfgeniter_t *itp; -ipfr_t **top, ***tail; -#ifdef USE_MUTEXES -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; - } - - READ_ENTER(lock); - if (frag == NULL) - next = *top; - else - next = frag->ipfr_next; - - if (next != NULL) { - ATOMIC_INC(next->ipfr_ref); - token->ipt_data = next; - } else { - bzero(&zero, sizeof(zero)); - next = &zero; - token->ipt_data = NULL; - } - RWLOCK_EXIT(lock); - - if (frag != NULL) { -#ifdef USE_MUTEXES - fr_fragderef(&frag, lock); -#else - fr_fragderef(&frag); -#endif - } - - error = COPYOUT(next, itp->igi_data, sizeof(*next)); - if (error != 0) - error = EFAULT; - - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_fragderef */ -/* Returns: Nil */ -/* Parameters: frp(IO) - pointer to fragment structure to deference */ -/* lock(I) - lock associated with the fragment */ -/* */ -/* This function dereferences a fragment structure (ipfr_t). The pointer */ -/* passed in will always be reset back to NULL, even if the structure is */ -/* 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 -#ifdef USE_MUTEXES -, lock -#endif -) -ipfr_t **frp; -#ifdef USE_MUTEXES -ipfrwlock_t *lock; -#endif -{ - ipfr_t *fra; - - fra = *frp; - *frp = NULL; - - WRITE_ENTER(lock); - fra->ipfr_ref--; - if (fra->ipfr_ref <= 0) - fr_fragfree(fra); - RWLOCK_EXIT(lock); -} diff --git a/sys/contrib/ipfilter/netinet/ip_frag.h b/sys/contrib/ipfilter/netinet/ip_frag.h deleted file mode 100644 index d3e89005..0000000 --- a/sys/contrib/ipfilter/netinet/ip_frag.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 1993-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * @(#)ip_frag.h 1.5 3/24/96 - * $Id: ip_frag.h,v 2.23.2.5 2006/12/23 11:11:47 darrenr Exp $ - */ - -#ifndef __IP_FRAG_H__ -#define __IP_FRAG_H__ - -#define IPFT_SIZE 257 - -typedef struct ipfr { - struct ipfr *ipfr_hnext, **ipfr_hprev; - struct ipfr *ipfr_next, **ipfr_prev; - void *ipfr_data; - frentry_t *ipfr_rule; - u_long ipfr_ttl; - int ipfr_ref; - u_short ipfr_off; - u_short 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; - 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_pass; -} ipfr_t; - - -typedef struct ipfrstat { - u_long ifs_exists; /* add & already exists */ - u_long ifs_nomem; - u_long ifs_new; - u_long ifs_hits; - u_long ifs_expire; - u_long ifs_inuse; - u_long ifs_retrans0; - u_long ifs_short; - struct ipfr **ifs_table; - struct ipfr **ifs_nattab; -} ipfrstat_t; - -#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 - -#endif /* __IP_FRAG_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c deleted file mode 100644 index c352027..0000000 --- a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c +++ /dev/null @@ -1,1428 +0,0 @@ -/* - * Copyright (C) 1997-2003 by Darren Reed - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * Simple FTP transparent proxy for in-kernel use. For use with the NAT - * code. - * - * $Id: ip_ftp_pxy.c,v 2.88.2.22 2007/05/10 09:30:39 darrenr Exp $ - */ - -#define IPF_FTP_PROXY - -#define IPF_MINPORTLEN 18 -#define IPF_MAXPORTLEN 30 -#define IPF_MIN227LEN 39 -#define IPF_MAX227LEN 51 -#define IPF_MIN229LEN 47 -#define IPF_MAX229LEN 51 - -#define FTPXY_GO 0 -#define FTPXY_INIT 1 -#define FTPXY_USER_1 2 -#define FTPXY_USOK_1 3 -#define FTPXY_PASS_1 4 -#define FTPXY_PAOK_1 5 -#define FTPXY_AUTH_1 6 -#define FTPXY_AUOK_1 7 -#define FTPXY_ADAT_1 8 -#define FTPXY_ADOK_1 9 -#define FTPXY_ACCT_1 10 -#define FTPXY_ACOK_1 11 -#define FTPXY_USER_2 12 -#define FTPXY_USOK_2 13 -#define FTPXY_PASS_2 14 -#define FTPXY_PAOK_2 15 - -/* - * Values for FTP commands. Numerics cover 0-999 - */ -#define FTPXY_C_PASV 1000 - -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 - */ - -static frentry_t ftppxyfr; -static ipftuneable_t ftptune = { - { &ippr_ftp_debug }, - "ippr_ftp_debug", - 0, - 10, - sizeof(ippr_ftp_debug), - 0, - NULL -}; - - -/* - * Initialize local structures. - */ -int ippr_ftp_init() -{ - 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; -} - - -void ippr_ftp_fini() -{ - (void) fr_delipftune(&ftptune); - - if (ftp_proxy_init == 1) { - MUTEX_DESTROY(&ftppxyfr.fr_lock); - ftp_proxy_init = 0; - } -} - - -int ippr_ftp_new(fin, aps, nat) -fr_info_t *fin; -ap_session_t *aps; -nat_t *nat; -{ - ftpinfo_t *ftp; - ftpside_t *f; - - KMALLOC(ftp, ftpinfo_t *); - if (ftp == NULL) - return -1; - - fin = fin; /* LINT */ - nat = nat; /* LINT */ - - aps->aps_data = ftp; - aps->aps_psiz = sizeof(ftpinfo_t); - - bzero((char *)ftp, sizeof(*ftp)); - f = &ftp->ftp_side[0]; - f->ftps_rptr = f->ftps_buf; - f->ftps_wptr = f->ftps_buf; - f = &ftp->ftp_side[1]; - f->ftps_rptr = f->ftps_buf; - f->ftps_wptr = f->ftps_buf; - ftp->ftp_passok = FTPXY_INIT; - ftp->ftp_incok = 0; - return 0; -} - - -int ippr_ftp_port(fin, ip, nat, f, dlen) -fr_info_t *fin; -ip_t *ip; -nat_t *nat; -ftpside_t *f; -int dlen; -{ - tcphdr_t *tcp, tcph, *tcp2 = &tcph; - 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; - 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; - - /* - * 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", - dlen); - return 0; - } - /* - * Skip the PORT command + space - */ - s = f->ftps_rptr + 5; - /* - * Pick out the address components, two at a time. - */ - a1 = ippr_ftp_atoi(&s); - if (s == NULL) { - if (ippr_ftp_debug > 1) - printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 1); - return 0; - } - a2 = ippr_ftp_atoi(&s); - if (s == NULL) { - if (ippr_ftp_debug > 1) - printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 2); - return 0; - } - - /* - * Check that IP address in the PORT/PASV reply is the same as the - * sender of the command - prevents using PORT for port scanning. - */ - a1 <<= 16; - a1 |= a2; - if (((nat->nat_dir == NAT_OUTBOUND) && - (a1 != ntohl(nat->nat_inip.s_addr))) || - ((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"); - return APR_ERR(1); - } - - a5 = ippr_ftp_atoi(&s); - if (s == NULL) { - if (ippr_ftp_debug > 1) - printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 3); - return 0; - } - if (*s == ')') - s++; - - /* - * check for CR-LF at the end. - */ - if (*s == '\n') - s--; - if ((*s == '\r') && (*(s + 1) == '\n')) { - s += 2; - a6 = a5 & 0xff; - } else { - if (ippr_ftp_debug > 1) - printf("ippr_ftp_port:missing %s\n", "cr-lf"); - return 0; - } - - 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); - 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! */ -#if defined(SNPRINTF) && defined(_KERNEL) - SNPRINTF(newbuf, sizeof(newbuf), "%s %u,%u,%u,%u,%u,%u\r\n", - "PORT", a1, a2, a3, a4, a5, a6); -#else - (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", - "PORT", a1, a2, a3, a4, a5, a6); -#endif - - 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", - inc); - return 0; - } - -#if !defined(_KERNEL) - bcopy(newbuf, 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, newbuf); - - if (inc != 0) { - ip->ip_len += inc; - fin->fin_dlen += inc; - fin->fin_plen += inc; - } - - /* - * 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; - /* - * 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; - 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; - } - - 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); - } - ip->ip_len = slen; - ip->ip_src = swip; - ip->ip_dst = swip2; - } - 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; -{ - char *rptr, *wptr, cmd[6], c; - ftpside_t *f; - int inc, i; - - inc = 0; - f = &ftp->ftp_side[0]; - rptr = f->ftps_rptr; - wptr = f->ftps_wptr; - - for (i = 0; (i < 5) && (i < dlen); i++) { - c = rptr[i]; - if (ISALPHA(c)) { - cmd[i] = TOUPPER(c); - } else { - cmd[i] = c; - } - } - cmd[i] = '\0'; - - ftp->ftp_incok = 0; - if (!strncmp(cmd, "USER ", 5) || !strncmp(cmd, "XAUT ", 5)) { - if (ftp->ftp_passok == FTPXY_ADOK_1 || - ftp->ftp_passok == FTPXY_AUOK_1) { - ftp->ftp_passok = FTPXY_USER_2; - ftp->ftp_incok = 1; - } else { - ftp->ftp_passok = FTPXY_USER_1; - ftp->ftp_incok = 1; - } - } else if (!strncmp(cmd, "AUTH ", 5)) { - ftp->ftp_passok = FTPXY_AUTH_1; - ftp->ftp_incok = 1; - } else if (!strncmp(cmd, "PASS ", 5)) { - if (ftp->ftp_passok == FTPXY_USOK_1) { - ftp->ftp_passok = FTPXY_PASS_1; - ftp->ftp_incok = 1; - } else if (ftp->ftp_passok == FTPXY_USOK_2) { - ftp->ftp_passok = FTPXY_PASS_2; - ftp->ftp_incok = 1; - } - } else if ((ftp->ftp_passok == FTPXY_AUOK_1) && - !strncmp(cmd, "ADAT ", 5)) { - ftp->ftp_passok = FTPXY_ADAT_1; - ftp->ftp_incok = 1; - } else if ((ftp->ftp_passok == FTPXY_PAOK_1 || - ftp->ftp_passok == FTPXY_PAOK_2) && - !strncmp(cmd, "ACCT ", 5)) { - ftp->ftp_passok = FTPXY_ACCT_1; - ftp->ftp_incok = 1; - } else if ((ftp->ftp_passok == FTPXY_GO) && !ippr_ftp_pasvonly && - !strncmp(cmd, "PORT ", 5)) { - inc = ippr_ftp_port(fin, ip, nat, f, dlen); - } else if (ippr_ftp_insecure && !ippr_ftp_pasvonly && - !strncmp(cmd, "PORT ", 5)) { - inc = ippr_ftp_port(fin, ip, nat, f, dlen); - } - - while ((*rptr++ != '\n') && (rptr < wptr)) - ; - f->ftps_rptr = rptr; - return inc; -} - - -int ippr_ftp_pasv(fin, ip, nat, ftp, dlen) -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]; - const char *brackets[2]; - u_short a5, a6; - 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); - return 0; - } - - f = &ftp->ftp_side[1]; - -#define PASV_REPLEN 24 - /* - * Check for PASV reply message. - */ - if (dlen < IPF_MIN227LEN) { - if (ippr_ftp_debug > 1) - printf("ippr_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); - return 0; - } - - brackets[0] = ""; - brackets[1] = ""; - /* - * Skip the PASV reply + space - */ - s = f->ftps_rptr + PASV_REPLEN; - while (*s && !ISDIGIT(*s)) { - if (*s == '(') { - brackets[0] = "("; - brackets[1] = ")"; - } - s++; - } - - /* - * Pick out the address components, two at a time. - */ - a1 = ippr_ftp_atoi(&s); - if (s == NULL) { - if (ippr_ftp_debug > 1) - printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 1); - return 0; - } - a2 = ippr_ftp_atoi(&s); - if (s == NULL) { - if (ippr_ftp_debug > 1) - printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 2); - return 0; - } - - /* - * check that IP address in the PASV reply is the same as the - * sender of the command - prevents using PASV for port scanning. - */ - a1 <<= 16; - a1 |= a2; - - if (((nat->nat_dir == NAT_INBOUND) && - (a1 != ntohl(nat->nat_inip.s_addr))) || - ((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"); - return 0; - } - - a5 = ippr_ftp_atoi(&s); - if (s == NULL) { - if (ippr_ftp_debug > 1) - printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 3); - return 0; - } - - if (*s == ')') - s++; - if (*s == '.') - s++; - if (*s == '\n') - s--; - /* - * 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"); - return 0; - } - - a6 = a5 & 0xff; - a5 >>= 8; - /* - * Calculate new address parts for 227 reply - */ - if (nat->nat_dir == NAT_INBOUND) { - data_ip = nat->nat_outip.s_addr; - a1 = ntohl(data_ip); - } else - data_ip = htonl(a1); - - a2 = (a1 >> 16) & 0xff; - a3 = (a1 >> 8) & 0xff; - a4 = a1 & 0xff; - a1 >>= 24; - -#if defined(SNPRINTF) && defined(_KERNEL) - SNPRINTF(newbuf, sizeof(newbuf), "%s %s%u,%u,%u,%u,%u,%u%s\r\n", - "227 Entering Passive Mode", brackets[0], a1, a2, a3, a4, - a5, a6, brackets[1]); -#else - (void) sprintf(newbuf, "%s %s%u,%u,%u,%u,%u,%u%s\r\n", - "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); -} - -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 inc, off, nflags, sflags; - tcphdr_t *tcp, tcph, *tcp2; - struct in_addr swip, swip2; - struct in_addr data_addr; - size_t nlen, olen; - fr_info_t fi; - nat_t *nat2; - 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; - - data_addr.s_addr = data_ip; - tcp2 = &tcph; - inc = 0; - - - 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", - 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; - } - - /* - * Add skeleton NAT entry for connection which will come back the - * other way. - */ - 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); - else - nat2 = nat_inlookup(&fi, nflags|NAT_SEARCH, - 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 = 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; - } - - 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); - } - - ip->ip_len = slen; - ip->ip_src = swip; - ip->ip_dst = swip2; - } - return inc; -} - - -int ippr_ftp_server(fin, ip, nat, ftp, dlen) -fr_info_t *fin; -ip_t *ip; -nat_t *nat; -ftpinfo_t *ftp; -int dlen; -{ - char *rptr, *wptr; - ftpside_t *f; - int inc; - - inc = 0; - f = &ftp->ftp_side[1]; - rptr = f->ftps_rptr; - wptr = f->ftps_wptr; - - if (*rptr == ' ') - goto server_cmd_ok; - if (!ISDIGIT(*rptr) || !ISDIGIT(*(rptr + 1)) || !ISDIGIT(*(rptr + 2))) - return 0; - if (ftp->ftp_passok == FTPXY_GO) { - if (!strncmp(rptr, "227 ", 4)) - inc = ippr_ftp_pasv(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); - } else if (*rptr == '5' || *rptr == '4') - ftp->ftp_passok = FTPXY_INIT; - else if (ftp->ftp_incok) { - if (*rptr == '3') { - if (ftp->ftp_passok == FTPXY_ACCT_1) - ftp->ftp_passok = FTPXY_GO; - else - ftp->ftp_passok++; - } else if (*rptr == '2') { - switch (ftp->ftp_passok) - { - case FTPXY_USER_1 : - case FTPXY_USER_2 : - case FTPXY_PASS_1 : - case FTPXY_PASS_2 : - case FTPXY_ACCT_1 : - ftp->ftp_passok = FTPXY_GO; - break; - default : - ftp->ftp_passok += 3; - break; - } - } - } -server_cmd_ok: - ftp->ftp_incok = 0; - - while ((*rptr++ != '\n') && (rptr < wptr)) - ; - f->ftps_rptr = rptr; - return inc; -} - - -/* - * Look to see if the buffer starts with something which we recognise as - * being the correct syntax for the FTP protocol. - */ -int ippr_ftp_client_valid(ftps, buf, len) -ftpside_t *ftps; -char *buf; -size_t len; -{ - register char *s, c, pc; - register size_t i = len; - char cmd[5]; - - s = buf; - - if (ftps->ftps_junk == 1) - return 1; - - if (i < 5) { - if (ippr_ftp_debug > 3) - printf("ippr_ftp_client_valid:i(%d) < 5\n", (int)i); - return 2; - } - - i--; - c = *s++; - - if (ISALPHA(c)) { - cmd[0] = TOUPPER(c); - c = *s++; - i--; - if (ISALPHA(c)) { - cmd[1] = TOUPPER(c); - c = *s++; - i--; - if (ISALPHA(c)) { - cmd[2] = TOUPPER(c); - c = *s++; - i--; - if (ISALPHA(c)) { - cmd[3] = TOUPPER(c); - c = *s++; - i--; - if ((c != ' ') && (c != '\r')) - goto bad_client_command; - } else if ((c != ' ') && (c != '\r')) - goto bad_client_command; - } else - goto bad_client_command; - } else - goto bad_client_command; - } else { -bad_client_command: - if (ippr_ftp_debug > 3) - printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*.*s]\n", - "ippr_ftp_client_valid", - ftps->ftps_junk, (int)len, (int)i, c, - (int)len, (int)len, buf); - return 1; - } - - for (; i; i--) { - pc = c; - 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; - return 0; - } - } -#if !defined(_KERNEL) - printf("ippr_ftp_client_valid:junk after cmd[%*.*s]\n", - (int)len, (int)len, buf); -#endif - return 2; -} - - -int ippr_ftp_server_valid(ftps, buf, len) -ftpside_t *ftps; -char *buf; -size_t len; -{ - register char *s, c, pc; - register size_t i = len; - int cmd; - - s = buf; - cmd = 0; - - if (ftps->ftps_junk == 1) - return 1; - - if (i < 5) { - if (ippr_ftp_debug > 3) - printf("ippr_ftp_servert_valid:i(%d) < 5\n", (int)i); - return 2; - } - - c = *s++; - i--; - if (c == ' ') - goto search_eol; - - if (ISDIGIT(c)) { - cmd = (c - '0') * 100; - c = *s++; - i--; - if (ISDIGIT(c)) { - cmd += (c - '0') * 10; - c = *s++; - i--; - if (ISDIGIT(c)) { - cmd += (c - '0'); - c = *s++; - i--; - if ((c != '-') && (c != ' ')) - goto bad_server_command; - } else - goto bad_server_command; - } else - goto bad_server_command; - } else { -bad_server_command: - if (ippr_ftp_debug > 3) - printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*.*s]\n", - "ippr_ftp_server_valid", - ftps->ftps_junk, (int)len, (int)i, - c, (int)len, (int)len, buf); - return 1; - } -search_eol: - for (; i; i--) { - pc = c; - c = *s++; - if ((pc == '\r') && (c == '\n')) { - ftps->ftps_cmds = cmd; - return 0; - } - } - if (ippr_ftp_debug > 3) - printf("ippr_ftp_server_valid:junk after cmd[%*.*s]\n", - (int)len, (int)len, buf); - return 2; -} - - -int ippr_ftp_valid(ftp, side, buf, len) -ftpinfo_t *ftp; -int side; -char *buf; -size_t len; -{ - ftpside_t *ftps; - int ret; - - ftps = &ftp->ftp_side[side]; - - if (side == 0) - ret = ippr_ftp_client_valid(ftps, buf, len); - else - ret = ippr_ftp_server_valid(ftps, buf, len); - return ret; -} - - -/* - * For map rules, the following applies: - * rv == 0 for outbound processing, - * rv == 1 for inbound processing. - * For rdr rules, the following applies: - * 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 mlen, len, off, inc, i, sel, sel2, ok, ackoff, seqoff; - char *rptr, *wptr, *s; - u_32_t thseq, thack; - ap_session_t *aps; - ftpside_t *f, *t; - tcphdr_t *tcp; - ip_t *ip; - mb_t *m; - - m = fin->fin_m; - ip = fin->fin_ip; - tcp = (tcphdr_t *)fin->fin_dp; - off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; - - f = &ftp->ftp_side[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); - - if ((mlen == 0) && ((tcp->th_flags & TH_OPENING) == TH_OPENING)) { - f->ftps_seq[0] = thseq + 1; - t->ftps_seq[0] = thack; - return 0; - } else if (mlen < 0) { - return 0; - } - - aps = nat->nat_aps; - - sel = aps->aps_sel[1 - rv]; - sel2 = aps->aps_sel[rv]; - if (rv == 0) { - seqoff = aps->aps_seqoff[sel]; - if (aps->aps_seqmin[sel] > seqoff + thseq) - seqoff = aps->aps_seqoff[!sel]; - ackoff = aps->aps_ackoff[sel2]; - if (aps->aps_ackmin[sel2] > ackoff + thack) - ackoff = aps->aps_ackoff[!sel2]; - } else { - seqoff = aps->aps_ackoff[sel]; - if (ippr_ftp_debug > 2) - 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) - printf("ackoff %d thack %x seqmin %x\n", ackoff, thack, - aps->aps_seqmin[sel2]); - if (ackoff > 0) { - if (aps->aps_seqmin[sel2] > ackoff + thack) - ackoff = aps->aps_seqoff[!sel2]; - } else { - if (aps->aps_seqmin[sel2] > thack) - ackoff = aps->aps_seqoff[!sel2]; - } - } - if (ippr_ftp_debug > 2) { - 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); - printf("sel %d seqmin %x/%x offset %d/%d\n", sel, - aps->aps_seqmin[sel], aps->aps_seqmin[sel2], - aps->aps_seqoff[sel], aps->aps_seqoff[sel2]); - printf("sel %d ackmin %x/%x offset %d/%d\n", sel2, - aps->aps_ackmin[sel], aps->aps_ackmin[sel2], - aps->aps_ackoff[sel], aps->aps_ackoff[sel2]); - } - - /* - * XXX - Ideally, this packet should get dropped because we now know - * that it is out of order (and there is no real danger in doing so - * apart from causing packets to go through here ordered). - */ - if (ippr_ftp_debug > 2) { - printf("rv %d t:seq[0] %x seq[1] %x %d/%d\n", - rv, t->ftps_seq[0], t->ftps_seq[1], seqoff, ackoff); - } - - ok = 0; - if (t->ftps_seq[0] == 0) { - t->ftps_seq[0] = thack; - ok = 1; - } else { - if (ackoff == 0) { - if (t->ftps_seq[0] == thack) - ok = 1; - else if (t->ftps_seq[1] == thack) { - t->ftps_seq[0] = thack; - ok = 1; - } - } else { - if (t->ftps_seq[0] + ackoff == thack) - ok = 1; - else if (t->ftps_seq[0] == thack + ackoff) - ok = 1; - else if (t->ftps_seq[1] + ackoff == thack) { - t->ftps_seq[0] = thack - ackoff; - ok = 1; - } else if (t->ftps_seq[1] == thack + ackoff) { - t->ftps_seq[0] = thack - ackoff; - ok = 1; - } - } - } - - if (ippr_ftp_debug > 2) { - 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], - ackoff, thack); - } - return APR_ERR(1); - } - - if (ippr_ftp_debug > 2) { - printf("ippr_ftp_process:f:seq[0] %x seq[1] %x\n", - f->ftps_seq[0], f->ftps_seq[1]); - } - - if (tcp->th_flags & TH_FIN) { - if (thseq == f->ftps_seq[1]) { - 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]); - } - return APR_ERR(1); - } - } - f->ftps_len = 0; - return 0; - } - - ok = 0; - if ((thseq == f->ftps_seq[0]) || (thseq == f->ftps_seq[1])) { - ok = 1; - /* - * Retransmitted data packet. - */ - } else if ((thseq + mlen == f->ftps_seq[0]) || - (thseq + mlen == f->ftps_seq[1])) { - ok = 1; - } - - if (ok == 0) { - inc = thseq - f->ftps_seq[0]; - if (ippr_ftp_debug > 1) { - 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]); - printf("ackmin %x ackoff %d\n", aps->aps_ackmin[sel], - aps->aps_ackoff[sel]); - printf("seqmin %x seqoff %d\n", aps->aps_seqmin[sel], - aps->aps_seqoff[sel]); - } - - return APR_ERR(1); - } - - inc = 0; - rptr = f->ftps_rptr; - wptr = f->ftps_wptr; - f->ftps_seq[0] = thseq; - f->ftps_seq[1] = f->ftps_seq[0] + mlen; - f->ftps_len = mlen; - - while (mlen > 0) { - len = MIN(mlen, sizeof(f->ftps_buf) - (wptr - rptr)); - COPYDATA(m, off, len, wptr); - mlen -= len; - off += len; - wptr += len; - - if (ippr_ftp_debug > 3) - printf("%s:len %d/%d off %d wptr %lx junk %d [%*.*s]\n", - "ippr_ftp_process", - len, mlen, off, (u_long)wptr, f->ftps_junk, - len, len, rptr); - - f->ftps_wptr = wptr; - if (f->ftps_junk != 0) { - i = f->ftps_junk; - f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, - wptr - rptr); - - if (ippr_ftp_debug > 5) - printf("%s:junk %d -> %d\n", - "ippr_ftp_process", i, f->ftps_junk); - - if (f->ftps_junk != 0) { - if (wptr - rptr == sizeof(f->ftps_buf)) { - if (ippr_ftp_debug > 4) - printf("%s:full buffer\n", - "ippr_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)) { - len = wptr - rptr; - f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, len); - - if (ippr_ftp_debug > 3) { - printf("%s=%d len %d rv %d ptr %lx/%lx ", - "ippr_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) { - f->ftps_rptr = rptr; - if (rv) - inc += ippr_ftp_server(fin, ip, nat, - ftp, len); - else - inc += ippr_ftp_client(fin, ip, nat, - ftp, len); - rptr = f->ftps_rptr; - wptr = f->ftps_wptr; - } - } - - /* - * 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)) { - /* f->ftps_seq[1] += inc; */ - - if (ippr_ftp_debug > 1) - printf("%s:cmds == 0 junk == 1\n", - "ippr_ftp_process"); - return APR_ERR(2); - } - - if ((f->ftps_junk != 0) && (rptr < wptr)) { - for (s = rptr; s < wptr; s++) { - if ((*s == '\r') && (s + 1 < wptr) && - (*(s + 1) == '\n')) { - rptr = s + 2; - f->ftps_junk = 0; - break; - } - } - } - - if (rptr == wptr) { - rptr = wptr = f->ftps_buf; - } else { - /* - * Compact the buffer back to the start. The junk - * flag should already be set and because we're not - * throwing away any data, it is preserved from its - * current state. - */ - if (rptr > f->ftps_buf) { - bcopy(rptr, f->ftps_buf, len); - wptr -= rptr - f->ftps_buf; - rptr = f->ftps_buf; - } - } - f->ftps_rptr = rptr; - f->ftps_wptr = wptr; - } - - /* f->ftps_seq[1] += inc; */ - if (tcp->th_flags & TH_FIN) - f->ftps_seq[1]++; - if (ippr_ftp_debug > 3) { -#ifdef __sgi - mlen = fin->fin_plen; -#else - mlen = MSGDSIZE(m); -#endif - mlen -= off; - printf("ftps_seq[1] = %x inc %d len %d\n", - f->ftps_seq[1], inc, mlen); - } - - f->ftps_rptr = rptr; - f->ftps_wptr = wptr; - return APR_INC(inc); -} - - -int ippr_ftp_out(fin, aps, nat) -fr_info_t *fin; -ap_session_t *aps; -nat_t *nat; -{ - ftpinfo_t *ftp; - int rev; - - ftp = aps->aps_data; - if (ftp == NULL) - return 0; - - rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; - 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); -} - - -int ippr_ftp_in(fin, aps, nat) -fr_info_t *fin; -ap_session_t *aps; -nat_t *nat; -{ - ftpinfo_t *ftp; - int rev; - - ftp = aps->aps_data; - if (ftp == NULL) - return 0; - - rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; - 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); -} - - -/* - * ippr_ftp_atoi - implement a version of atoi which processes numbers in - * pairs separated by commas (which are expected to be in the range 0 - 255), - * returning a 16 bit number combining either side of the , as the MSB and - * LSB. - */ -u_short ippr_ftp_atoi(ptr) -char **ptr; -{ - register char *s = *ptr, c; - register u_char i = 0, j = 0; - - while (((c = *s++) != '\0') && ISDIGIT(c)) { - i *= 10; - i += c - '0'; - } - if (c != ',') { - *ptr = NULL; - return 0; - } - while (((c = *s++) != '\0') && ISDIGIT(c)) { - j *= 10; - j += c - '0'; - } - *ptr = s; - i &= 0xff; - j &= 0xff; - return (i << 8) | j; -} - - -int ippr_ftp_epsv(fin, ip, nat, f, dlen) -fr_info_t *fin; -ip_t *ip; -nat_t *nat; -ftpside_t *f; -int dlen; -{ - char newbuf[IPF_FTPBUFSZ]; - char *s; - u_short ap = 0; - -#define EPSV_REPLEN 33 - /* - * Check for EPSV reply message. - */ - if (dlen < IPF_MIN229LEN) - return (0); - else if (strncmp(f->ftps_rptr, - "229 Entering Extended Passive Mode", EPSV_REPLEN)) - return (0); - - /* - * Skip the EPSV command + space - */ - s = f->ftps_rptr + 33; - while (*s && !ISDIGIT(*s)) - s++; - - /* - * As per RFC 2428, there are no addres components in the EPSV - * response. So we'll go straight to getting the port. - */ - while (*s && ISDIGIT(*s)) { - ap *= 10; - ap += *s++ - '0'; - } - - if (!*s) - return 0; - - if (*s == '|') - s++; - if (*s == ')') - s++; - if (*s == '\n') - s--; - /* - * check for CR-LF at the end. - */ - if ((*s == '\r') && (*(s + 1) == '\n')) { - s += 2; - } else - return 0; - -#if defined(SNPRINTF) && defined(_KERNEL) - SNPRINTF(newbuf, sizeof(newbuf), "%s (|||%u|)\r\n", - "229 Entering Extended Passive Mode", ap); -#else - (void) sprintf(newbuf, "%s (|||%u|)\r\n", - "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); -} diff --git a/sys/contrib/ipfilter/netinet/ip_h323_pxy.c b/sys/contrib/ipfilter/netinet/ip_h323_pxy.c deleted file mode 100644 index 7fc6227..0000000 --- a/sys/contrib/ipfilter/netinet/ip_h323_pxy.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright 2001, QNX Software Systems Ltd. All Rights Reserved - * - * This source code has been published by QNX Software Systems Ltd. (QSSL). - * However, any use, reproduction, modification, distribution or transfer of - * this software, or any software which includes or is based upon any of this - * code, is only permitted under the terms of the QNX Open Community License - * version 1.0 (see licensing.qnx.com for details) or as otherwise expressly - * authorized by a written license agreement from QSSL. For more information, - * please email licensing@qnx.com. - * - * For more details, see QNX_OCL.txt provided with this distribution. - */ - -/* - * Simple H.323 proxy - * - * by xtang@canada.com - * ported to ipfilter 3.4.20 by Michael Grant mg-ipf@grant.org - */ - -#if __FreeBSD_version >= 220000 && defined(_KERNEL) -# include <sys/fcntl.h> -# include <sys/filio.h> -#else -# ifndef linux -# include <sys/ioctl.h> -# endif -#endif - -#define IPF_H323_PROXY - -int ippr_h323_init __P((void)); -void ippr_h323_fini __P((void)); -int ippr_h323_new __P((fr_info_t *, ap_session_t *, nat_t *)); -void ippr_h323_del __P((ap_session_t *)); -int ippr_h323_out __P((fr_info_t *, ap_session_t *, nat_t *)); -int ippr_h323_in __P((fr_info_t *, ap_session_t *, nat_t *)); - -int ippr_h245_new __P((fr_info_t *, ap_session_t *, nat_t *)); -int ippr_h245_out __P((fr_info_t *, ap_session_t *, nat_t *)); -int ippr_h245_in __P((fr_info_t *, ap_session_t *, nat_t *)); - -static frentry_t h323_fr; - -int h323_proxy_init = 0; - -static int find_port __P((int, caddr_t, int datlen, int *, u_short *)); - - -static int find_port(ipaddr, data, datlen, off, port) -int ipaddr; -caddr_t data; -int datlen, *off; -unsigned short *port; -{ - u_32_t addr, netaddr; - u_char *dp; - int offset; - - if (datlen < 6) - return -1; - - *port = 0; - offset = *off; - dp = (u_char *)data; - netaddr = ntohl(ipaddr); - - for (offset = 0; offset <= datlen - 6; offset++, dp++) { - addr = (dp[0] << 24) | (dp[1] << 16) | (dp[2] << 8) | dp[3]; - if (netaddr == addr) - { - *port = (*(dp + 4) << 8) | *(dp + 5); - break; - } - } - *off = offset; - return (offset > datlen - 6) ? -1 : 0; -} - -/* - * Initialize local structures. - */ -int ippr_h323_init() -{ - bzero((char *)&h323_fr, sizeof(h323_fr)); - h323_fr.fr_ref = 1; - h323_fr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; - MUTEX_INIT(&h323_fr.fr_lock, "H323 proxy rule lock"); - h323_proxy_init = 1; - - return 0; -} - - -void ippr_h323_fini() -{ - if (h323_proxy_init == 1) { - MUTEX_DESTROY(&h323_fr.fr_lock); - h323_proxy_init = 0; - } -} - - -int ippr_h323_new(fin, aps, nat) -fr_info_t *fin; -ap_session_t *aps; -nat_t *nat; -{ - fin = fin; /* LINT */ - nat = nat; /* LINT */ - - aps->aps_data = NULL; - aps->aps_psiz = 0; - - return 0; -} - - -void ippr_h323_del(aps) -ap_session_t *aps; -{ - int i; - ipnat_t *ipn; - - if (aps->aps_data) { - for (i = 0, ipn = aps->aps_data; - i < (aps->aps_psiz / sizeof(ipnat_t)); - i++, ipn = (ipnat_t *)((char *)ipn + sizeof(*ipn))) - { - /* - * Check the comment in ippr_h323_in() function, - * just above fr_nat_ioctl() call. - * We are lucky here because this function is not - * called with ipf_nat locked. - */ - if (fr_nat_ioctl((caddr_t)ipn, SIOCRMNAT, NAT_SYSSPACE| - NAT_LOCKHELD|FWRITE) == -1) { - /*EMPTY*/; - /* log the error */ - } - } - KFREES(aps->aps_data, aps->aps_psiz); - /* avoid double free */ - aps->aps_data = NULL; - aps->aps_psiz = 0; - } - return; -} - - -int ippr_h323_in(fin, aps, nat) -fr_info_t *fin; -ap_session_t *aps; -nat_t *nat; -{ - int ipaddr, off, datlen; - unsigned short port; - caddr_t data; - tcphdr_t *tcp; - ip_t *ip; - - ip = fin->fin_ip; - tcp = (tcphdr_t *)fin->fin_dp; - ipaddr = ip->ip_src.s_addr; - - data = (caddr_t)tcp + (TCP_OFF(tcp) << 2); - datlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); - if (find_port(ipaddr, data, datlen, &off, &port) == 0) { - ipnat_t *ipn; - char *newarray; - - /* setup a nat rule to set a h245 proxy on tcp-port "port" - * it's like: - * map <if> <inter_ip>/<mask> -> <gate_ip>/<mask> proxy port <port> <port>/tcp - */ - KMALLOCS(newarray, char *, aps->aps_psiz + sizeof(*ipn)); - if (newarray == NULL) { - return -1; - } - ipn = (ipnat_t *)&newarray[aps->aps_psiz]; - bcopy((caddr_t)nat->nat_ptr, (caddr_t)ipn, sizeof(ipnat_t)); - (void) strncpy(ipn->in_plabel, "h245", APR_LABELLEN); - - ipn->in_inip = nat->nat_inip.s_addr; - ipn->in_inmsk = 0xffffffff; - ipn->in_dport = htons(port); - /* - * we got a problem here. we need to call fr_nat_ioctl() to add - * the h245 proxy rule, but since we already hold (READ locked) - * the nat table rwlock (ipf_nat), if we go into fr_nat_ioctl(), - * it will try to WRITE lock it. This will causing dead lock - * on RTP. - * - * The quick & dirty solution here is release the read lock, - * call fr_nat_ioctl() and re-lock it. - * A (maybe better) solution is do a UPGRADE(), and instead - * of calling fr_nat_ioctl(), we add the nat rule ourself. - */ - RWLOCK_EXIT(&ipf_nat); - if (fr_nat_ioctl((caddr_t)ipn, SIOCADNAT, - NAT_SYSSPACE|FWRITE) == -1) { - READ_ENTER(&ipf_nat); - return -1; - } - READ_ENTER(&ipf_nat); - if (aps->aps_data != NULL && aps->aps_psiz > 0) { - bcopy(aps->aps_data, newarray, aps->aps_psiz); - KFREES(aps->aps_data, aps->aps_psiz); - } - aps->aps_data = newarray; - aps->aps_psiz += sizeof(*ipn); - } - return 0; -} - - -int ippr_h245_new(fin, aps, nat) -fr_info_t *fin; -ap_session_t *aps; -nat_t *nat; -{ - fin = fin; /* LINT */ - nat = nat; /* LINT */ - - aps->aps_data = NULL; - aps->aps_psiz = 0; - return 0; -} - - -int ippr_h245_out(fin, aps, nat) -fr_info_t *fin; -ap_session_t *aps; -nat_t *nat; -{ - int ipaddr, off, datlen; - tcphdr_t *tcp; - caddr_t data; - u_short port; - ip_t *ip; - - aps = aps; /* LINT */ - - ip = fin->fin_ip; - tcp = (tcphdr_t *)fin->fin_dp; - ipaddr = nat->nat_inip.s_addr; - data = (caddr_t)tcp + (TCP_OFF(tcp) << 2); - datlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); - if (find_port(ipaddr, data, datlen, &off, &port) == 0) { - fr_info_t fi; - nat_t *nat2; - -/* port = htons(port); */ - nat2 = nat_outlookup(fin->fin_ifp, IPN_UDP, IPPROTO_UDP, - ip->ip_src, ip->ip_dst); - if (nat2 == NULL) { - struct ip newip; - struct udphdr udp; - - bcopy((caddr_t)ip, (caddr_t)&newip, sizeof(newip)); - newip.ip_len = fin->fin_hlen + sizeof(udp); - newip.ip_p = IPPROTO_UDP; - newip.ip_src = nat->nat_inip; - - bzero((char *)&udp, sizeof(udp)); - udp.uh_sport = port; - - bcopy((caddr_t)fin, (caddr_t)&fi, sizeof(fi)); - fi.fin_fi.fi_p = IPPROTO_UDP; - fi.fin_data[0] = port; - fi.fin_data[1] = 0; - fi.fin_dp = (char *)&udp; - - nat2 = nat_new(&fi, nat->nat_ptr, NULL, - NAT_SLAVE|IPN_UDP|SI_W_DPORT, - NAT_OUTBOUND); - if (nat2 != NULL) { - (void) nat_proto(&fi, nat2, IPN_UDP); - nat_update(&fi, nat2, nat2->nat_ptr); - - nat2->nat_ptr->in_hits++; -#ifdef IPFILTER_LOG - nat_log(nat2, (u_int)(nat->nat_ptr->in_redir)); -#endif - bcopy((caddr_t)&ip->ip_src.s_addr, - data + off, 4); - bcopy((caddr_t)&nat2->nat_outport, - data + off + 4, 2); - } - } - } - return 0; -} diff --git a/sys/contrib/ipfilter/netinet/ip_htable.c b/sys/contrib/ipfilter/netinet/ip_htable.c deleted file mode 100644 index 1bed371..0000000 --- a/sys/contrib/ipfilter/netinet/ip_htable.c +++ /dev/null @@ -1,640 +0,0 @@ -/* - * Copyright (C) 1993-2001, 2003 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/param.h> -#include <sys/types.h> -#include <sys/errno.h> -#include <sys/time.h> -#include <sys/file.h> -#if !defined(_KERNEL) -# include <stdlib.h> -# include <string.h> -# define _KERNEL -# ifdef __OpenBSD__ -struct file; -# endif -# include <sys/uio.h> -# undef _KERNEL -#endif -#include <sys/socket.h> -#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) -# include <sys/malloc.h> -#endif -#if defined(__FreeBSD__) -# include <sys/cdefs.h> -# include <sys/proc.h> -#endif -#if !defined(__svr4__) && !defined(__SVR4) && !defined(__hpux) && \ - !defined(linux) -# include <sys/mbuf.h> -#endif -#if defined(_KERNEL) -# include <sys/systm.h> -#else -# include <stdio.h> -#endif -#include <netinet/in.h> -#include <net/if.h> - -#include "netinet/ip_compat.h" -#include "netinet/ip_fil.h" -#include "netinet/ip_lookup.h" -#include "netinet/ip_htable.h" -/* 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 $"; -#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 }; - -iphtable_t *ipf_htables[IPL_LOGSIZE] = { NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL }; - - -void fr_htable_unload() -{ - iplookupflush_t fop; - - fop.iplf_unit = IPL_LOGALL; - (void)fr_flushhtable(&fop); -} - - -int fr_gethtablestat(op) -iplookupop_t *op; -{ - iphtstat_t stats; - - if (op->iplo_size != sizeof(stats)) - 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]; - - return COPYOUT(&stats, op->iplo_struct, sizeof(stats)); - -} - - -/* - * Create a new hash table using the template passed. - */ -int fr_newhtable(op) -iplookupop_t *op; -{ - iphtable_t *iph, *oiph; - char name[FR_GROUPLEN]; - int err, i, unit; - - unit = op->iplo_unit; - if ((op->iplo_arg & IPHASH_ANON) == 0) { - iph = fr_existshtable(unit, op->iplo_name); - if (iph != NULL) { - if ((iph->iph_flags & IPHASH_DELETE) == 0) - return EEXIST; - iph->iph_flags &= ~IPHASH_DELETE; - return 0; - } - } - - KMALLOC(iph, iphtable_t *); - if (iph == NULL) { - ipht_nomem[op->iplo_unit]++; - 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; - } - - if ((op->iplo_arg & IPHASH_ANON) != 0) { - i = IPHASH_ANON; - do { - i++; -#if defined(SNPRINTF) && defined(_KERNEL) - SNPRINTF(name, sizeof(name), "%u", i); -#else - (void)sprintf(name, "%u", i); -#endif - for (oiph = ipf_htables[unit]; oiph != NULL; - oiph = oiph->iph_next) - if (strncmp(oiph->iph_name, name, - sizeof(oiph->iph_name)) == 0) - break; - } while (oiph != NULL); - - (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; - } - - KMALLOCS(iph->iph_table, iphtent_t **, - iph->iph_size * sizeof(*iph->iph_table)); - if (iph->iph_table == NULL) { - KFREE(iph); - ipht_nomem[unit]++; - return ENOMEM; - } - - bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); - iph->iph_masks = 0; - iph->iph_list = NULL; - - 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]++; - - return 0; -} - - -/* - */ -int fr_removehtable(unit, name) -int unit; -char *name; -{ - iphtable_t *iph; - - iph = fr_findhtable(unit, name); - if (iph == NULL) - return ESRCH; - - if (iph->iph_unit != unit) { - return EINVAL; - } - - if (iph->iph_ref != 0) { - (void) fr_clearhtable(iph); - iph->iph_flags |= IPHASH_DELETE; - return 0; - } - - fr_delhtable(iph); - - return 0; -} - - -int fr_clearhtable(iph) -iphtable_t *iph; -{ - iphtent_t *ipe; - - while ((ipe = iph->iph_list) != NULL) - if (fr_delhtent(iph, ipe) != 0) - return 1; - return 0; -} - - -int fr_delhtable(iph) -iphtable_t *iph; -{ - - if (fr_clearhtable(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; - - ipf_nhtables[iph->iph_unit]--; - - return fr_derefhtable(iph); -} - - -/* - * Delete an entry from a hash table. - */ -int fr_delhtent(iph, ipe) -iphtable_t *iph; -iphtent_t *ipe; -{ - - 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_pnext != NULL) - *ipe->ipe_pnext = ipe->ipe_next; - if (ipe->ipe_next != NULL) - ipe->ipe_next->ipe_pnext = ipe->ipe_pnext; - - switch (iph->iph_type & ~IPHASH_ANON) - { - case IPHASH_GROUPMAP : - if (ipe->ipe_group != NULL) - fr_delgroup(ipe->ipe_group, IPL_LOGIPF, fr_active); - break; - - default : - ipe->ipe_ptr = NULL; - ipe->ipe_value = 0; - break; - } - - return fr_derefhtent(ipe); -} - - -int fr_derefhtable(iph) -iphtable_t *iph; -{ - 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); - } - - return refs; -} - - -int fr_derefhtent(ipe) -iphtent_t *ipe; -{ - - ipe->ipe_ref--; - if (ipe->ipe_ref == 0) { - ipf_nhtnodes[ipe->ipe_unit]--; - - KFREE(ipe); - - return 0; - } - - return ipe->ipe_ref; -} - - -iphtable_t *fr_existshtable(unit, name) -int unit; -char *name; -{ - 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; - return iph; -} - - -iphtable_t *fr_findhtable(unit, name) -int unit; -char *name; -{ - iphtable_t *iph; - - iph = fr_existshtable(unit, name); - if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0) - return iph; - - return NULL; -} - - -size_t fr_flushhtable(op) -iplookupflush_t *op; -{ - iphtable_t *iph; - size_t freed; - int i; - - freed = 0; - - for (i = 0; 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) { - freed++; - } else { - iph->iph_flags |= IPHASH_DELETE; - } - } - } - } - - return freed; -} - - -/* - * Add an entry to a hash table. - */ -int fr_addhtent(iph, ipeo) -iphtable_t *iph; -iphtent_t *ipeo; -{ - iphtent_t *ipe; - u_int hv; - int bits; - - KMALLOC(ipe, iphtent_t *); - if (ipe == NULL) - 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); - - hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr, - iph->iph_size); - ipe->ipe_ref = 1; - ipe->ipe_hnext = iph->iph_table[hv]; - ipe->ipe_phnext = iph->iph_table + hv; - - if (iph->iph_table[hv] != NULL) - 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; - - if ((bits >= 0) && (bits != 32)) - iph->iph_masks |= 1 << bits; - - switch (iph->iph_type & ~IPHASH_ANON) - { - case IPHASH_GROUPMAP : - ipe->ipe_ptr = fr_addgroup(ipe->ipe_group, NULL, - iph->iph_flags, IPL_LOGIPF, - fr_active); - break; - - default : - ipe->ipe_ptr = NULL; - ipe->ipe_value = 0; - break; - } - - ipe->ipe_unit = iph->iph_unit; - ipf_nhtnodes[ipe->ipe_unit]++; - - return 0; -} - - -void *fr_iphmfindgroup(tptr, aptr) -void *tptr, *aptr; -{ - struct in_addr *addr; - iphtable_t *iph; - iphtent_t *ipe; - void *rval; - - READ_ENTER(&ip_poolrw); - iph = tptr; - addr = aptr; - - ipe = fr_iphmfind(iph, addr); - if (ipe != NULL) - rval = ipe->ipe_ptr; - else - rval = NULL; - RWLOCK_EXIT(&ip_poolrw); - return rval; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_iphmfindip */ -/* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */ -/* Parameters: tptr(I) - pointer to the pool to search */ -/* ipversion(I) - IP protocol version (4 or 6) */ -/* aptr(I) - pointer to address information */ -/* */ -/* Search the hash table for a given address and return a search result. */ -/* ------------------------------------------------------------------------ */ -int fr_iphmfindip(tptr, ipversion, aptr) -void *tptr, *aptr; -int ipversion; -{ - 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) - rval = 0; - else - rval = 1; - RWLOCK_EXIT(&ip_poolrw); - return rval; -} - - -/* Locks: ip_poolrw */ -static iphtent_t *fr_iphmfind(iph, addr) -iphtable_t *iph; -struct in_addr *addr; -{ - u_32_t hmsk, msk, ips; - iphtent_t *ipe; - u_int hv; - - hmsk = iph->iph_masks; - msk = 0xffffffff; -maskloop: - ips = ntohl(addr->s_addr) & msk; - hv = IPE_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) { - continue; - } - break; - } - - if ((ipe == NULL) && (hmsk != 0)) { - while (hmsk != 0) { - msk <<= 1; - if (hmsk & 0x80000000) - break; - hmsk <<= 1; - } - if (hmsk != 0) { - hmsk <<= 1; - goto maskloop; - } - } - return ipe; -} - - -int fr_htable_getnext(token, ilp) -ipftoken_t *token; -ipflookupiter_t *ilp; -{ - iphtent_t *node, zn, *nextnode; - iphtable_t *iph, zp, *nextiph; - int err; - - err = 0; - iph = NULL; - node = NULL; - nextiph = NULL; - nextnode = NULL; - - READ_ENTER(&ip_poolrw); - - switch (ilp->ili_otype) - { - case IPFLOOKUPITER_LIST : - iph = token->ipt_data; - if (iph == NULL) { - nextiph = ipf_htables[(int)ilp->ili_unit]; - } else { - nextiph = iph->iph_next; - } - - if (nextiph != NULL) { - ATOMIC_INC(nextiph->iph_ref); - token->ipt_data = nextiph; - } else { - bzero((char *)&zp, sizeof(zp)); - nextiph = &zp; - token->ipt_data = NULL; - } - break; - - case IPFLOOKUPITER_NODE : - node = token->ipt_data; - if (node == NULL) { - iph = fr_findhtable(ilp->ili_unit, ilp->ili_name); - if (iph == NULL) - err = ESRCH; - else { - nextnode = iph->iph_list; - } - } else { - nextnode = node->ipe_next; - } - - if (nextnode != NULL) { - ATOMIC_INC(nextnode->ipe_ref); - token->ipt_data = nextnode; - } else { - bzero((char *)&zn, sizeof(zn)); - nextnode = &zn; - token->ipt_data = NULL; - } - break; - default : - err = EINVAL; - break; - } - - RWLOCK_EXIT(&ip_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) - err = EFAULT; - 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) - err = EFAULT; - break; - } - - return err; -} - - -void fr_htable_iterderef(otype, unit, data) -u_int otype; -int unit; -void *data; -{ - - if (data == NULL) - return; - - if (unit < 0 || unit > IPL_LOGMAX) - return; - - switch (otype) - { - case IPFLOOKUPITER_LIST : - WRITE_ENTER(&ip_poolrw); - fr_derefhtable((iphtable_t *)data); - RWLOCK_EXIT(&ip_poolrw); - break; - - case IPFLOOKUPITER_NODE : - WRITE_ENTER(&ip_poolrw); - fr_derefhtent((iphtent_t *)data); - RWLOCK_EXIT(&ip_poolrw); - break; - default : - break; - } -} - -#endif /* IPFILTER_LOOKUP */ diff --git a/sys/contrib/ipfilter/netinet/ip_htable.h b/sys/contrib/ipfilter/netinet/ip_htable.h deleted file mode 100644 index 2c08812..0000000 --- a/sys/contrib/ipfilter/netinet/ip_htable.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef __IP_HTABLE_H__ -#define __IP_HTABLE_H__ - -#include "netinet/ip_lookup.h" - -typedef struct iphtent_s { - struct iphtent_s *ipe_next, **ipe_pnext; - struct iphtent_s *ipe_hnext, **ipe_phnext; - void *ipe_ptr; - i6addr_t ipe_addr; - i6addr_t ipe_mask; - int ipe_ref; - int ipe_unit; - union { - char ipeu_char[16]; - u_long ipeu_long; - u_int ipeu_int; - }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)) - - -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; - 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 */ - char iph_name[FR_GROUPLEN]; /* hash table number */ -} iphtable_t; - -/* iph_type */ -#define IPHASH_LOOKUP 0 -#define IPHASH_GROUPMAP 1 -#define IPHASH_DELETE 2 -#define IPHASH_ANON 0x80000000 - - -typedef struct iphtstat_s { - iphtable_t *iphs_tables; - u_long iphs_numtables; - u_long iphs_numnodes; - u_long iphs_nomem; - u_long iphs_pad[16]; -} 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 *)); - -#endif /* __IP_HTABLE_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c b/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c deleted file mode 100644 index e88a6b9..0000000 --- a/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (C) 2001-2003 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 $ - * - */ -#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]; - -int ipsec_proxy_init = 0; -int ipsec_proxy_ttl = 60; - -/* - * IPSec application proxy initialization. - */ -int ippr_ipsec_init() -{ - bzero((char *)&ipsecfr, sizeof(ipsecfr)); - ipsecfr.fr_ref = 1; - ipsecfr.fr_flags = FR_OUTQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; - MUTEX_INIT(&ipsecfr.fr_lock, "IPsec proxy rule lock"); - ipsec_proxy_init = 1; - - ipsecnattqe = fr_addtimeoutqueue(&nat_utqe, ipsec_proxy_ttl); - if (ipsecnattqe == NULL) - return -1; - ipsecstatetqe = fr_addtimeoutqueue(&ips_utqe, ipsec_proxy_ttl); - if (ipsecstatetqe == NULL) { - if (fr_deletetimeoutqueue(ipsecnattqe) == 0) - fr_freetimeoutqueue(ipsecnattqe); - ipsecnattqe = 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; - return 0; -} - - -void ippr_ipsec_fini() -{ - if (ipsecnattqe != NULL) { - if (fr_deletetimeoutqueue(ipsecnattqe) == 0) - fr_freetimeoutqueue(ipsecnattqe); - } - ipsecnattqe = NULL; - if (ipsecstatetqe != NULL) { - if (fr_deletetimeoutqueue(ipsecstatetqe) == 0) - fr_freetimeoutqueue(ipsecstatetqe); - } - ipsecstatetqe = NULL; - - if (ipsec_proxy_init == 1) { - MUTEX_DESTROY(&ipsecfr.fr_lock); - ipsec_proxy_init = 0; - } -} - - -/* - * Setup for a new IPSEC proxy. - */ -int ippr_ipsec_new(fin, aps, nat) -fr_info_t *fin; -ap_session_t *aps; -nat_t *nat; -{ - ipsec_pxy_t *ipsec; - fr_info_t fi; - ipnat_t *ipn; - char *ptr; - int p, off, dlen, ttl; - mb_t *m; - ip_t *ip; - - off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff; - bzero(ipsec_buffer, sizeof(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); - - if (nat_outlookup(fin, 0, IPPROTO_ESP, nat->nat_inip, - 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) - return -1; - - ipsec = aps->aps_data; - bzero((char *)ipsec, sizeof(*ipsec)); - - /* - * Create NAT rule against which the tunnel/transport mapping is - * created. This is required because the current NAT rule does not - * describe ESP but UDP instead. - */ - ipn = &ipsec->ipsc_rule; - 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_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_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_redir = NAT_MAP; - bcopy(nat->nat_ptr->in_ifnames[0], ipn->in_ifnames[0], - sizeof(ipn->in_ifnames[0])); - ipn->in_p = IPPROTO_ESP; - - 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_data[0] = 0; - fi.fin_data[1] = 0; - p = ip->ip_p; - ip->ip_p = IPPROTO_ESP; - fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG); - fi.fin_flx |= FI_IGNORE; - - ptr = 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)); - /* - * The responder cookie should only be non-zero if the initiator - * cookie is non-zero. Therefore, it is safe to assume(!) that the - * cookies are both set after copying if the responder is non-zero. - */ - if ((ipsec->ipsc_rcookie[0]|ipsec->ipsc_rcookie[1]) != 0) - ipsec->ipsc_rckset = 1; - - ipsec->ipsc_nat = nat_new(&fi, ipn, &ipsec->ipsc_nat, - NAT_SLAVE|SI_WILDP, NAT_OUTBOUND); - if (ipsec->ipsc_nat != NULL) { - (void) nat_proto(&fi, ipsec->ipsc_nat, 0); - nat_update(&fi, ipsec->ipsc_nat, ipn); - - 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); - } - ip->ip_p = p & 0xff; - return 0; -} - - -/* - * 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; -{ - ipsec_pxy_t *ipsec; - fr_info_t fi; - ip_t *ip; - int p; - - if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND)) - return 0; - - if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND)) - return 0; - - ipsec = aps->aps_data; - - if (ipsec != NULL) { - ip = fin->fin_ip; - p = ip->ip_p; - - 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_data[0] = 0; - fi.fin_data[1] = 0; - ip->ip_p = IPPROTO_ESP; - fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG); - fi.fin_flx |= FI_IGNORE; - } - - /* - * Update NAT timeout/create NAT if missing. - */ - if (ipsec->ipsc_nat != NULL) - fr_queueback(&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); - if (ipsec->ipsc_nat != NULL) { - (void) nat_proto(&fi, ipsec->ipsc_nat, 0); - nat_update(&fi, ipsec->ipsc_nat, - &ipsec->ipsc_rule); - } - } - - /* - * Update state timeout/create state if missing. - */ - READ_ENTER(&ipf_state); - if (ipsec->ipsc_state != NULL) { - fr_queueback(&ipsec->ipsc_state->is_sti); - ipsec->ipsc_state->is_die = nat->nat_age; - RWLOCK_EXIT(&ipf_state); - } else { - RWLOCK_EXIT(&ipf_state); - fi.fin_data[0] = 0; - fi.fin_data[1] = 0; - ipsec->ipsc_state = fr_addstate(&fi, - &ipsec->ipsc_state, - SI_WILDP); - if (fi.fin_state != NULL) - fr_statederef((ipstate_t **)&fi.fin_state); - } - ip->ip_p = p; - } - return 0; -} - - -/* - * This extends the NAT matching to be based on the cookies associated with - * a session and found at the front of IKE packets. The cookies are always - * in the same order (not reversed depending on packet flow direction as with - * UDP/TCP port numbers). - */ -int ippr_ipsec_match(fin, aps, nat) -fr_info_t *fin; -ap_session_t *aps; -nat_t *nat; -{ - ipsec_pxy_t *ipsec; - u_32_t cookies[4]; - mb_t *m; - int off; - - nat = nat; /* LINT */ - - if ((fin->fin_dlen < sizeof(cookies)) || (fin->fin_flx & FI_FRAG)) - return -1; - - off = fin->fin_plen - fin->fin_dlen + fin->fin_ipoff; - ipsec = aps->aps_data; - m = fin->fin_m; - COPYDATA(m, off, sizeof(cookies), (char *)cookies); - - if ((cookies[0] != ipsec->ipsc_icookie[0]) || - (cookies[1] != ipsec->ipsc_icookie[1])) - return -1; - - if (ipsec->ipsc_rckset == 0) { - if ((cookies[2]|cookies[3]) == 0) { - return 0; - } - ipsec->ipsc_rckset = 1; - ipsec->ipsc_rcookie[0] = cookies[2]; - ipsec->ipsc_rcookie[1] = cookies[3]; - return 0; - } - - if ((cookies[2] != ipsec->ipsc_rcookie[0]) || - (cookies[3] != ipsec->ipsc_rcookie[1])) - return -1; - return 0; -} - - -/* - * clean up after ourselves. - */ -void ippr_ipsec_del(aps) -ap_session_t *aps; -{ - ipsec_pxy_t *ipsec; - - ipsec = aps->aps_data; - - if (ipsec != NULL) { - /* - * Don't bother changing any of the NAT structure details, - * *_del() is on a callback from aps_free(), from nat_delete() - */ - - READ_ENTER(&ipf_state); - if (ipsec->ipsc_state != NULL) { - ipsec->ipsc_state->is_die = fr_ticks + 1; - ipsec->ipsc_state->is_me = NULL; - fr_queuefront(&ipsec->ipsc_state->is_sti); - } - RWLOCK_EXIT(&ipf_state); - - ipsec->ipsc_state = NULL; - ipsec->ipsc_nat = NULL; - } -} diff --git a/sys/contrib/ipfilter/netinet/ip_irc_pxy.c b/sys/contrib/ipfilter/netinet/ip_irc_pxy.c deleted file mode 100644 index 5bb252a..0000000 --- a/sys/contrib/ipfilter/netinet/ip_irc_pxy.c +++ /dev/null @@ -1,433 +0,0 @@ -/* - * Copyright (C) 2000-2003 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 $ - */ - -#define IPF_IRC_PROXY - -#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)); -u_short ipf_irc_atoi __P((char **)); - -static frentry_t ircnatfr; - -int irc_proxy_init = 0; - - -/* - * Initialize local structures. - */ -int ippr_irc_init() -{ - 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() -{ - if (irc_proxy_init == 1) { - MUTEX_DESTROY(&ircnatfr.fr_lock); - irc_proxy_init = 0; - } -} - - -const char *ippr_irc_dcctypes[] = { - "CHAT ", /* CHAT chat ipnumber portnumber */ - "SEND ", /* SEND filename ipnumber portnumber */ - "MOVE ", - "TSEND ", - "SCHAT ", - NULL, -}; - - -/* - * :A PRIVMSG B :^ADCC CHAT chat 0 0^A\r\n - * PRIVMSG B ^ADCC CHAT chat 0 0^A\r\n - */ - - -int ippr_irc_complete(ircp, buf, len) -ircinfo_t *ircp; -char *buf; -size_t len; -{ - register char *s, c; - register size_t i; - u_32_t l; - int j, k; - - ircp->irc_ipnum = 0; - ircp->irc_port = 0; - - if (len < 31) - return 0; - s = buf; - c = *s++; - i = len - 1; - - if ((c != ':') && (c != 'P')) - return 0; - - if (c == ':') { - /* - * Loosely check that the source is a nickname of some sort - */ - s++; - c = *s; - ircp->irc_snick = s; - if (!ISALPHA(c)) - return 0; - i--; - for (c = *s; !ISSPACE(c) && (i > 0); i--) - c = *s++; - if (i < 31) - return 0; - if (c != 'P') - return 0; - } else - ircp->irc_snick = NULL; - - /* - * Check command string - */ - if (strncmp(s, "PRIVMSG ", 8)) - return 0; - i -= 8; - s += 8; - c = *s; - ircp->irc_dnick = s; - - /* - * Loosely check that the destination is a nickname of some sort - */ - if (!ISALPHA(c)) - return 0; - for (; !ISSPACE(c) && (i > 0); i--) - c = *s++; - if (i < 20) - return 0; - s++, - i--; - - /* - * Look for a ^A to start the DCC - */ - c = *s; - if (c == ':') { - s++; - c = *s; - } - - if (strncmp(s, "\001DCC ", 4)) - return 0; - - i -= 4; - s += 4; - - /* - * 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)) - break; - } - if (!ippr_irc_dcctypes[j]) - return 0; - - ircp->irc_type = s; - i -= k; - s += k; - - if (i < 11) - return 0; - - /* - * Check for the arg - */ - c = *s; - if (ISSPACE(c)) - return 0; - ircp->irc_arg = s; - for (; (c != ' ') && (c != '\001') && (i > 0); i--) - c = *s++; - - if (c == '\001') /* In reality a ^A can quote another ^A...*/ - return 0; - - if (i < 5) - return 0; - - s++; - i--; - c = *s; - if (!ISDIGIT(c)) - return 0; - ircp->irc_addr = s; - /* - * Get the IP# - */ - for (l = 0; ISDIGIT(c) && (i > 0); i--) { - l *= 10; - l += c - '0'; - c = *s++; - } - - if (i < 4) - return 0; - - if (c != ' ') - return 0; - - ircp->irc_ipnum = l; - s++; - i--; - c = *s; - if (!ISDIGIT(c)) - return 0; - /* - * Get the port# - */ - for (l = 0; ISDIGIT(c) && (i > 0); i--) { - l *= 10; - l += c - '0'; - c = *s++; - } - if (i < 3) - return 0; - if (strncmp(s, "\001\r\n", 3)) - return 0; - s += 3; - ircp->irc_len = s - buf; - ircp->irc_port = l; - return 1; -} - - -int ippr_irc_new(fin, aps, nat) -fr_info_t *fin; -ap_session_t *aps; -nat_t *nat; -{ - ircinfo_t *irc; - - KMALLOC(irc, ircinfo_t *); - if (irc == NULL) - return -1; - - fin = fin; /* LINT */ - nat = nat; /* LINT */ - - aps->aps_data = irc; - aps->aps_psiz = sizeof(ircinfo_t); - - bzero((char *)irc, sizeof(*irc)); - return 0; -} - - -int ippr_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; - size_t nlen = 0, olen; - struct in_addr swip; - u_short a5, sp; - ircinfo_t *irc; - fr_info_t fi; - nat_t *nat2; - u_int a1; - ip_t *ip; - mb_t *m; -#ifdef MENTAT - mb_t *m1; -#endif - - m = fin->fin_m; - ip = fin->fin_ip; - tcp = (tcphdr_t *)fin->fin_dp; - bzero(ctcpbuf, sizeof(ctcpbuf)); - off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; - -#ifdef __sgi - dlen = fin->fin_plen - off; -#else - dlen = MSGDSIZE(m) - off; -#endif - if (dlen <= 0) - return 0; - COPYDATA(m, off, MIN(sizeof(ctcpbuf), dlen), ctcpbuf); - - if (dlen <= 0) - return 0; - ctcpbuf[sizeof(ctcpbuf) - 1] = '\0'; - *newbuf = '\0'; - - irc = nat->nat_aps->aps_data; - if (ippr_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. - */ - if (irc->irc_ipnum != ntohl(nat->nat_inip.s_addr)) - return 0; - - a5 = irc->irc_port; - - /* - * Calculate new address parts for the DCC command - */ - a1 = ntohl(ip->ip_src.s_addr); - olen = irc->irc_len; - i = irc->irc_addr - ctcpbuf; - i++; - (void) strncpy(newbuf, ctcpbuf, i); - /* DO NOT change these! */ -#if defined(SNPRINTF) && defined(KERNEL) - SNPRINTF(newbuf, sizeof(newbuf) - i, "%u %u\001\r\n", a1, a5); -#else - (void) sprintf(newbuf, "%u %u\001\r\n", a1, a5); -#endif - - nlen = strlen(newbuf); - inc = nlen - olen; - - if ((inc + ip->ip_len) > 65535) - return 0; - -#ifdef MENTAT - for (m1 = m; m1->b_cont; m1 = m1->b_cont) - ; - if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) { - mblk_t *nm; - - /* alloc enough to keep same trailer space for lower driver */ - nm = allocb(nlen, BPRI_MED); - PANIC((!nm),("ippr_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")); - - linkb(m1, nm); - } else { -# if SOLARIS && defined(ICK_VALID) - if (m1->b_datap->db_struiolim == m1->b_wptr) - m1->b_datap->db_struiolim += inc; - m1->b_datap->db_struioflag &= ~STRUIO_IP; -# endif - m1->b_wptr += inc; - } -#else - if (inc < 0) - m_adj(m, inc); - /* the mbuf chain will be extended if necessary by m_copyback() */ -#endif - COPYBACK(m, off, nlen, newbuf); - - if (inc != 0) { -#if defined(MENTAT) || defined(__sgi) - register u_32_t sum1, sum2; - - sum1 = ip->ip_len; - sum2 = ip->ip_len + inc; - - /* Because ~1 == -2, We really need ~1 == -1 */ - if (sum1 > sum2) - sum2--; - sum2 -= sum1; - sum2 = (sum2 & 0xffff) + (sum2 >> 16); - - fix_outcksum(fin, &ip->ip_sum, sum2); -#endif - ip->ip_len += inc; - } - - /* - * Add skeleton NAT entry for connection which will come back the - * other way. - */ - sp = htons(a5); - /* - * Don't allow the PORT command to specify a port < 1024 due to - * security crap. - */ - if (ntohs(sp) < 1024) - return 0; - - /* - * The server may not make the connection back from port 20, but - * it is the most likely so use it here to check for a conflicting - * mapping. - */ - 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, - ip->ip_dst); - if (nat2 == NULL) { - 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; - fi.fin_fr = &ircnatfr; - 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, - NAT_SLAVE|IPN_TCP|SI_W_DPORT, NAT_OUTBOUND); - if (nat2 != NULL) { - (void) nat_proto(&fi, nat2, 0); - nat_update(&fi, nat2, nat2->nat_ptr); - - (void) fr_addstate(&fi, NULL, SI_W_DPORT); - if (fi.fin_state != NULL) - fr_statederef((ipstate_t **)&fi.fin_state); - } - ip->ip_src = swip; - } - return inc; -} - - -int ippr_irc_out(fin, aps, nat) -fr_info_t *fin; -ap_session_t *aps; -nat_t *nat; -{ - aps = aps; /* LINT */ - return ippr_irc_send(fin, nat); -} diff --git a/sys/contrib/ipfilter/netinet/ip_log.c b/sys/contrib/ipfilter/netinet/ip_log.c deleted file mode 100644 index aed828e..0000000 --- a/sys/contrib/ipfilter/netinet/ip_log.c +++ /dev/null @@ -1,700 +0,0 @@ -/* - * Copyright (C) 1997-2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * $Id: ip_log.c,v 2.75.2.19 2007/09/09 11:32:06 darrenr Exp $ - */ -#include <sys/param.h> -#if defined(KERNEL) || defined(_KERNEL) -# undef KERNEL -# undef _KERNEL -# 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 -#endif -#ifndef SOLARIS -# define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) -#endif -#include <sys/errno.h> -#include <sys/types.h> -#include <sys/file.h> -#ifndef _KERNEL -# include <stdio.h> -# include <string.h> -# include <stdlib.h> -# include <ctype.h> -# define _KERNEL -# define KERNEL -# ifdef __OpenBSD__ -struct file; -# endif -# include <sys/uio.h> -# undef _KERNEL -# undef KERNEL -#endif -#if __FreeBSD_version >= 220000 && defined(_KERNEL) -# include <sys/fcntl.h> -# include <sys/filio.h> -#else -# include <sys/ioctl.h> -#endif -#include <sys/time.h> -#if defined(_KERNEL) -# include <sys/systm.h> -# if defined(NetBSD) && (__NetBSD_Version__ >= 104000000) -# include <sys/proc.h> -# endif -#endif /* _KERNEL */ -#if !SOLARIS && !defined(__hpux) && !defined(linux) -# if (NetBSD > 199609) || (OpenBSD > 199603) || (__FreeBSD_version >= 300000) -# include <sys/dirent.h> -# else -# include <sys/dir.h> -# endif -# include <sys/mbuf.h> -# include <sys/select.h> -# if __FreeBSD_version >= 500000 -# include <sys/selinfo.h> -# endif -#else -# if !defined(__hpux) && defined(_KERNEL) -# include <sys/filio.h> -# include <sys/cred.h> -# include <sys/ddi.h> -# include <sys/sunddi.h> -# include <sys/ksynch.h> -# include <sys/kmem.h> -# include <sys/mkdev.h> -# include <sys/dditypes.h> -# include <sys/cmn_err.h> -# endif /* !__hpux */ -#endif /* !SOLARIS && !__hpux */ -#if !defined(linux) -# include <sys/protosw.h> -#endif -#include <sys/socket.h> - -#include <net/if.h> -#ifdef sun -# include <net/af.h> -#endif -#if __FreeBSD_version >= 300000 -# include <net/if_var.h> -#endif -#include <net/route.h> -#include <netinet/in.h> -#ifdef __sgi -# include <sys/ddi.h> -# ifdef IFF_DRVRLOCK /* IRIX6 */ -# include <sys/hashing.h> -# endif -#endif -#if !defined(__hpux) && !defined(linux) && \ - !(defined(__sgi) && !defined(IFF_DRVRLOCK)) /*IRIX<6*/ -# include <netinet/in_var.h> -#endif -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/tcp.h> -#include <netinet/udp.h> -#include <netinet/ip_icmp.h> -#ifdef USE_INET6 -# include <netinet/icmp6.h> -#endif -#if !defined(linux) -# include <netinet/ip_var.h> -#endif -#ifndef _KERNEL -# include <syslog.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_auth.h" -#if (__FreeBSD_version >= 300000) || defined(__NetBSD__) -# include <sys/malloc.h> -#endif -/* END OF INCLUDES */ - -#ifdef IPFILTER_LOG - -# if defined(IPL_SELECT) -# 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 */ - -# if defined(linux) && defined(_KERNEL) -wait_queue_head_t iplh_linux[IPL_LOGSIZE]; -# endif -# if SOLARIS && defined(_KERNEL) -extern kcondvar_t iplwait; -extern struct pollhead iplpollhead[IPL_LOGSIZE]; -# endif - -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 }; - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_loginit */ -/* Returns: int - 0 == success (always returned) */ -/* Parameters: Nil */ -/* */ -/* Initialise log buffers & pointers. Also iniialised the CRC to a local */ -/* secret for use in calculating the "last log checksum". */ -/* ------------------------------------------------------------------------ */ -int fr_loginit() -{ - 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])); -# ifdef IPL_SELECT - iplog_ss[i].read_waiter = 0; - iplog_ss[i].state = 0; -# endif -# if defined(linux) && defined(_KERNEL) - init_waitqueue_head(iplh_linux + i); -# endif - } - -# if SOLARIS && defined(_KERNEL) - cv_init(&iplwait, "ipl condvar", CV_DRIVER, NULL); -# endif - MUTEX_INIT(&ipl_mutex, "ipf log mutex"); - - ipl_log_init = 1; - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_logunload */ -/* Returns: Nil */ -/* Parameters: Nil */ -/* */ -/* Clean up any log data that has accumulated without being read. */ -/* ------------------------------------------------------------------------ */ -void fr_logunload() -{ - int i; - - if (ipl_log_init == 0) - return; - - for (i = IPL_LOGMAX; i >= 0; i--) - (void) ipflog_clear(i); - -# if SOLARIS && defined(_KERNEL) - cv_destroy(&iplwait); -# endif - MUTEX_DESTROY(&ipl_mutex); - - ipl_log_init = 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipflog */ -/* Returns: int - 0 == success, -1 == failure */ -/* Parameters: fin(I) - pointer to packet information */ -/* flags(I) - flags from filter rules */ -/* */ -/* Create a log record for a packet given that it has been triggered by a */ -/* rule (or the default setting). Calculate the transport protocol header */ -/* size using predetermined size of a couple of popular protocols and thus */ -/* how much data to copy into the log, including part of the data body if */ -/* requested. */ -/* ------------------------------------------------------------------------ */ -int ipflog(fin, flags) -fr_info_t *fin; -u_int flags; -{ - register size_t hlen; - int types[2], mlen; - size_t sizes[2]; - void *ptrs[2]; - ipflog_t ipfl; - u_char p; - mb_t *m; -# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) && \ - !defined(_INET_IP_STACK_H) - qif_t *ifp; -# else - struct ifnet *ifp; -# endif /* SOLARIS || __hpux */ - - m = fin->fin_m; - if (m == NULL) - return -1; - - 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; - /* - * calculate header size. - */ - if (fin->fin_off == 0) { - p = fin->fin_fi.fi_p; - if (p == IPPROTO_TCP) - hlen += MIN(sizeof(tcphdr_t), fin->fin_dlen); - else if (p == IPPROTO_UDP) - hlen += MIN(sizeof(udphdr_t), fin->fin_dlen); - else if (p == IPPROTO_ICMP) { - struct icmp *icmp; - - icmp = (struct icmp *)fin->fin_dp; - - /* - * For ICMP, if the packet is an error packet, also - * include the information about the packet which - * caused the error. - */ - switch (icmp->icmp_type) - { - case ICMP_UNREACH : - case ICMP_SOURCEQUENCH : - case ICMP_REDIRECT : - case ICMP_TIMXCEED : - case ICMP_PARAMPROB : - hlen += MIN(sizeof(struct icmp) + 8, - fin->fin_dlen); - break; - default : - hlen += MIN(sizeof(struct icmp), - fin->fin_dlen); - break; - } - } -# ifdef USE_INET6 - else if (p == IPPROTO_ICMPV6) { - struct icmp6_hdr *icmp; - - icmp = (struct icmp6_hdr *)fin->fin_dp; - - /* - * For ICMPV6, if the packet is an error packet, also - * include the information about the packet which - * caused the error. - */ - if (icmp->icmp6_type < 128) { - hlen += MIN(sizeof(struct icmp6_hdr) + 8, - fin->fin_dlen); - } else { - hlen += MIN(sizeof(struct icmp6_hdr), - fin->fin_dlen); - } - } -# endif - } - /* - * Get the interface number and name to which this packet is - * currently associated. - */ -# if (SOLARIS || defined(__hpux)) && defined(_KERNEL) && \ - !defined(_INET_IP_STACK_H) - ipfl.fl_unit = (u_int)ifp->qf_ppa; - 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)) - COPYIFNAME(fin->fin_v, ifp, ipfl.fl_ifname); -# else - ipfl.fl_unit = (u_int)ifp->if_unit; -# if defined(_KERNEL) - if ((ipfl.fl_ifname[0] = ifp->if_name[0])) - if ((ipfl.fl_ifname[1] = ifp->if_name[1])) - if ((ipfl.fl_ifname[2] = ifp->if_name[2])) - ipfl.fl_ifname[3] = ifp->if_name[3]; -# else - COPYIFNAME(fin->fin_v, ifp, 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) { - mlen = (flags & FR_LOGBODY) ? MIN(mlen, 128) : 0; - } else if ((flags & FR_LOGBODY) == 0) { - mlen = 0; - } - if (mlen < 0) - mlen = 0; - ipfl.fl_plen = (u_char)mlen; - ipfl.fl_hlen = (u_char)hlen; - ipfl.fl_rule = fin->fin_rule; - (void) strncpy(ipfl.fl_group, fin->fin_group, FR_GROUPLEN); - if (fin->fin_fr != NULL) { - ipfl.fl_loglevel = fin->fin_fr->fr_loglevel; - ipfl.fl_logtag = fin->fin_fr->fr_logtag; - } else { - ipfl.fl_loglevel = 0xffff; - ipfl.fl_logtag = FR_NOLOGTAG; - } - if (fin->fin_nattag != NULL) - bcopy(fin->fin_nattag, (void *)&ipfl.fl_nattag, - sizeof(ipfl.fl_nattag)); - ipfl.fl_flags = flags; - ipfl.fl_dir = fin->fin_out; - ipfl.fl_lflags = fin->fin_flx; - ptrs[0] = (void *)&ipfl; - sizes[0] = sizeof(ipfl); - types[0] = 0; -# if defined(MENTAT) && defined(_KERNEL) - /* - * Are we copied from the mblk or an aligned array ? - */ - if (fin->fin_ip == (ip_t *)m->b_rptr) { - ptrs[1] = m; - sizes[1] = hlen + mlen; - types[1] = 1; - } else { - ptrs[1] = fin->fin_ip; - sizes[1] = hlen + mlen; - types[1] = 0; - } -# else - ptrs[1] = m; - sizes[1] = hlen + mlen; - types[1] = 1; -# endif /* MENTAT */ - return ipllog(IPL_LOGIPF, fin, ptrs, sizes, types, 2); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipllog */ -/* Returns: int - 0 == success, -1 == failure */ -/* Parameters: dev(I) - device that owns this log record */ -/* fin(I) - pointer to packet information */ -/* items(I) - array of pointers to log data */ -/* itemsz(I) - array of size of valid memory pointed to */ -/* types(I) - type of data pointed to by items pointers */ -/* cnt(I) - number of elements in arrays items/itemsz/types */ -/* */ -/* Takes an array of parameters and constructs one record to include the */ -/* 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; -{ - u_char *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]; - - /* - * 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); - 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. - */ - ipl = (iplog_t *)buf; - ipl->ipl_magic = ipl_magic[dev]; - ipl->ipl_count = 1; - ipl->ipl_next = NULL; - ipl->ipl_dsize = len; -#ifdef _KERNEL - GETKTIME(&ipl->ipl_sec); -#else - ipl->ipl_sec = 0; - ipl->ipl_usec = 0; -#endif - - /* - * Loop through all the items to be logged, copying each one to the - * buffer. Use bcopy for normal data or the mb_t copyout routine. - */ - for (i = 0, ptr = buf + sizeof(*ipl); i < cnt; i++) { - if (types[i] == 0) { - bcopy(items[i], ptr, itemsz[i]); - } else if (types[i] == 1) { - COPYDATA(items[i], 0, itemsz[i], (char *)ptr); - } - ptr += itemsz[i]; - } - SPL_NET(s); - MUTEX_ENTER(&ipl_mutex); - ipll[dev] = ipl; - *iplh[dev] = ipl; - iplh[dev] = &ipl->ipl_next; - - /* - * 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); -# else - MUTEX_EXIT(&ipl_mutex); - WAKEUP(iplh, dev); - POLLWAKEUP(dev); -# endif - SPL_X(s); -# ifdef IPL_SELECT - iplog_input_ready(dev); -# 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 */ -/* */ -/* Called to handle a read on an IPFilter device. Returns only complete */ -/* log messages - will not partially copy a log record out to userland. */ -/* */ -/* 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; -{ - size_t dlen, copied; - int error = 0; - iplog_t *ipl; - SPL_INT(s); - - /* - * Sanity checks. Make sure the minor # is valid and we're copying - * a valid chunk of data. - */ - if (IPL_LOGMAX < unit) - return ENXIO; - if (uio->uio_resid == 0) - return 0; - if ((uio->uio_resid < sizeof(iplog_t)) || - (uio->uio_resid > ipl_logsize)) - return EINVAL; - - /* - * Lock the log so we can snapshot the variables. Wait for a signal - * if the log is empty. - */ - SPL_NET(s); - MUTEX_ENTER(&ipl_mutex); - - while (iplt[unit] == NULL) { -# if SOLARIS && defined(_KERNEL) - if (!cv_wait_sig(&iplwait, &ipl_mutex.ipf_lk)) { - MUTEX_EXIT(&ipl_mutex); - return EINTR; - } -# else -# if defined(__hpux) && defined(_KERNEL) - lock_t *l; - -# ifdef IPL_SELECT - if (uio->uio_fpflags & (FNBLOCK|FNDELAY)) { - /* this is no blocking system call */ - MUTEX_EXIT(&ipl_mutex); - return 0; - } -# endif - - MUTEX_EXIT(&ipl_mutex); - l = get_sleep_lock(&iplh[unit]); - error = sleep(&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); -# else - MUTEX_EXIT(&ipl_mutex); - SPL_X(s); - error = SLEEP(unit + iplh, "ipl sleep"); -# endif /* __osf__ */ -# endif /* __hpux */ - if (error) - return error; - SPL_NET(s); - MUTEX_ENTER(&ipl_mutex); -# endif /* SOLARIS */ - } - -# if (BSD >= 199101) || defined(__FreeBSD__) || defined(__osf__) - uio->uio_rw = UIO_READ; -# endif - - for (copied = 0; (ipl = 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); - 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; - break; - } - MUTEX_ENTER(&ipl_mutex); - KFREES(ipl, dlen); - SPL_NET(s); - } - if (!iplt[unit]) { - iplused[unit] = 0; - iplh[unit] = &iplt[unit]; - ipll[unit] = NULL; - } - - MUTEX_EXIT(&ipl_mutex); - SPL_X(s); - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipflog_clear */ -/* Returns: int - number of log bytes cleared. */ -/* Parameters: 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; -{ - 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); - } - iplh[unit] = &iplt[unit]; - ipll[unit] = NULL; - used = iplused[unit]; - iplused[unit] = 0; - bzero((char *)&iplcrc[unit], FI_CSIZE); - MUTEX_EXIT(&ipl_mutex); - 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 */ -/* */ -/* 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; -{ - return iplt[unit] != NULL; -} -#endif /* IPFILTER_LOG */ diff --git a/sys/contrib/ipfilter/netinet/ip_lookup.c b/sys/contrib/ipfilter/netinet/ip_lookup.c deleted file mode 100644 index e33a6fe..0000000 --- a/sys/contrib/ipfilter/netinet/ip_lookup.c +++ /dev/null @@ -1,695 +0,0 @@ -/* - * Copyright (C) 2002-2003 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/param.h> -#include <sys/errno.h> -#include <sys/types.h> -#include <sys/time.h> -#include <sys/file.h> -#if __FreeBSD_version >= 220000 && defined(_KERNEL) -# include <sys/fcntl.h> -# include <sys/filio.h> -#else -# include <sys/ioctl.h> -#endif -#if !defined(_KERNEL) -# include <string.h> -# define _KERNEL -# ifdef __OpenBSD__ -struct file; -# endif -# include <sys/uio.h> -# 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> -#endif -#if defined(_KERNEL) -# include <sys/systm.h> -# if !defined(__SVR4) && !defined(__svr4__) -# include <sys/mbuf.h> -# endif -#endif -#include <netinet/in.h> - -#include "netinet/ip_compat.h" -#include "netinet/ip_fil.h" -#include "netinet/ip_pool.h" -#include "netinet/ip_htable.h" -#include "netinet/ip_lookup.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 $"; -#endif - -#ifdef IPFILTER_LOOKUP -int ip_lookup_inited = 0; - -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 *)); - - -/* ------------------------------------------------------------------------ */ -/* Function: iplookup_init */ -/* Returns: int - 0 = success, else error */ -/* Parameters: Nil */ -/* */ -/* Initialise all of the subcomponents of the lookup infrstructure. */ -/* ------------------------------------------------------------------------ */ -int ip_lookup_init() -{ - - if (ip_pool_init() == -1) - return -1; - - RWLOCK_INIT(&ip_poolrw, "ip pool rwlock"); - - ip_lookup_inited = 1; - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: iplookup_unload */ -/* Returns: int - 0 = success, else error */ -/* Parameters: Nil */ -/* */ -/* 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. */ -/* ------------------------------------------------------------------------ */ -void ip_lookup_unload() -{ - ip_pool_fini(); - fr_htable_unload(); - - if (ip_lookup_inited == 1) { - RW_DESTROY(&ip_poolrw); - ip_lookup_inited = 0; - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: iplookup_ioctl */ -/* Returns: int - 0 = success, else error */ -/* Parameters: 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 */ -/* */ -/* 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 err; - SPL_INT(s); - - mode = mode; /* LINT */ - - SPL_NET(s); - - switch (cmd) - { - case SIOCLOOKUPADDNODE : - case SIOCLOOKUPADDNODEW : - WRITE_ENTER(&ip_poolrw); - err = iplookup_addnode(data); - RWLOCK_EXIT(&ip_poolrw); - break; - - case SIOCLOOKUPDELNODE : - case SIOCLOOKUPDELNODEW : - WRITE_ENTER(&ip_poolrw); - err = iplookup_delnode(data); - RWLOCK_EXIT(&ip_poolrw); - break; - - case SIOCLOOKUPADDTABLE : - WRITE_ENTER(&ip_poolrw); - err = iplookup_addtable(data); - RWLOCK_EXIT(&ip_poolrw); - break; - - case SIOCLOOKUPDELTABLE : - WRITE_ENTER(&ip_poolrw); - err = iplookup_deltable(data); - RWLOCK_EXIT(&ip_poolrw); - break; - - case SIOCLOOKUPSTAT : - case SIOCLOOKUPSTATW : - WRITE_ENTER(&ip_poolrw); - err = iplookup_stats(data); - RWLOCK_EXIT(&ip_poolrw); - break; - - case SIOCLOOKUPFLUSH : - WRITE_ENTER(&ip_poolrw); - err = iplookup_flush(data); - RWLOCK_EXIT(&ip_poolrw); - break; - - case SIOCLOOKUPITER : - err = iplookup_iterate(data, uid, ctx); - break; - - case SIOCIPFDELTOK : - err = iplookup_deltok(data, uid, ctx); - break; - - default : - err = EINVAL; - break; - } - SPL_X(s); - return err; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: iplookup_addnode */ -/* Returns: int - 0 = success, else error */ -/* Parameters: 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; -{ - ip_pool_node_t node, *m; - iplookupop_t op; - iphtable_t *iph; - iphtent_t hte; - ip_pool_t *p; - int err; - - err = BCOPYIN(data, &op, sizeof(op)); - if (err != 0) - return EFAULT; - - if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) - 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; - - default : - err = EINVAL; - break; - } - return err; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: iplookup_delnode */ -/* Returns: int - 0 = success, else error */ -/* Parameters: 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; -{ - ip_pool_node_t node, *m; - iplookupop_t op; - iphtable_t *iph; - iphtent_t hte; - ip_pool_t *p; - int err; - - err = BCOPYIN(data, &op, sizeof(op)); - if (err != 0) - return EFAULT; - - if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) - 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; - - default : - err = EINVAL; - break; - } - return err; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: iplookup_addtable */ -/* Returns: int - 0 = success, else error */ -/* Parameters: 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; -{ - iplookupop_t op; - int err; - - err = BCOPYIN(data, &op, sizeof(op)); - if (err != 0) - return EFAULT; - - if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) - 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; - - default : - err = EINVAL; - break; - } - - /* - * For anonymous pools, copy back the operation struct because in the - * case of success it will contain the new table's name. - */ - if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) { - err = BCOPYOUT(&op, data, sizeof(op)); - if (err != 0) - err = EFAULT; - } - - return err; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: iplookup_deltable */ -/* Returns: int - 0 = success, else error */ -/* Parameters: 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; -{ - iplookupop_t op; - int err; - - err = BCOPYIN(data, &op, sizeof(op)); - if (err != 0) - return EFAULT; - - if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) - 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; - - default : - err = EINVAL; - break; - } - return err; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: iplookup_stats */ -/* Returns: int - 0 = success, else error */ -/* Parameters: 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; -{ - iplookupop_t op; - int err; - - err = BCOPYIN(data, &op, sizeof(op)); - if (err != 0) - return EFAULT; - - if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) - return EINVAL; - - switch (op.iplo_type) - { - case IPLT_POOL : - err = ip_pool_statistics(&op); - break; - - case IPLT_HASH : - err = fr_gethtablestat(&op); - break; - - default : - err = EINVAL; - break; - } - return err; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: iplookup_flush */ -/* Returns: int - 0 = success, else error */ -/* Parameters: 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; -{ - int err, unit, num, type; - iplookupflush_t flush; - - err = BCOPYIN(data, &flush, sizeof(flush)); - if (err != 0) - return EFAULT; - - unit = flush.iplf_unit; - if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL)) - return EINVAL; - - flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0'; - - type = flush.iplf_type; - 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); - } - - if (err == 0) { - flush.iplf_count = num; - err = BCOPYOUT(&flush, data, sizeof(flush)); - if (err != 0) - err = EFAULT; - } - return err; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ip_lookup_delref */ -/* Returns: void */ -/* Parameters: 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; -{ - 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; - } - RWLOCK_EXIT(&ip_poolrw); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: iplookup_iterate */ -/* Returns: int - 0 = success, else error */ -/* Parameters: 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; -{ - ipflookupiter_t iter; - ipftoken_t *token; - int err; - SPL_INT(s); - - err = fr_inobj(data, &iter, IPFOBJ_LOOKUPITER); - if (err != 0) - return err; - - if (iter.ili_unit > IPL_LOGMAX) - return EINVAL; - - if (iter.ili_ival != IPFGENITER_LOOKUP) - return EINVAL; - - SPL_SCHED(s); - token = ipf_findtoken(iter.ili_key, uid, ctx); - if (token == NULL) { - RWLOCK_EXIT(&ipf_tokens); - SPL_X(s); - 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; - } - RWLOCK_EXIT(&ipf_tokens); - SPL_X(s); - - return err; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: iplookup_iterderef */ -/* Returns: int - 0 = success, else error */ -/* Parameters: 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. */ -/* ------------------------------------------------------------------------ */ -void ip_lookup_iterderef(type, data) -u_32_t type; -void *data; -{ - iplookupiterkey_t key; - - key.ilik_key = type; - - if (key.ilik_unstr.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; - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: iplookup_deltok */ -/* Returns: int - 0 = success, else error */ -/* Parameters: data(I) - pointer to data from ioctl call */ -/* uid(I) - uid of caller */ -/* ctx(I) - pointer to give the uid context */ -/* */ -/* Deletes the token identified by the combination of (type,uid,ctx) */ -/* "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 error, key; - SPL_INT(s); - - SPL_SCHED(s); - error = BCOPYIN(data, &key, sizeof(key)); - if (error == 0) - error = ipf_deltoken(key, uid, ctx); - SPL_X(s); - return error; -} - - -#else /* IPFILTER_LOOKUP */ - -/*ARGSUSED*/ -int ip_lookup_ioctl(data, cmd, mode, uid, ctx) -caddr_t data; -ioctlcmd_t cmd; -int mode, uid; -void *ctx; -{ - return EIO; -} -#endif /* IPFILTER_LOOKUP */ diff --git a/sys/contrib/ipfilter/netinet/ip_lookup.h b/sys/contrib/ipfilter/netinet/ip_lookup.h deleted file mode 100644 index 3886df1..0000000 --- a/sys/contrib/ipfilter/netinet/ip_lookup.h +++ /dev/null @@ -1,95 +0,0 @@ - -#ifndef __IP_LOOKUP_H__ -#define __IP_LOOKUP_H__ - -#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51) -# define SIOCLOOKUPADDTABLE _IOWR('r', 60, struct iplookupop) -# define SIOCLOOKUPDELTABLE _IOWR('r', 61, struct iplookupop) -# define SIOCLOOKUPSTAT _IOWR('r', 64, struct iplookupop) -# define SIOCLOOKUPSTATW _IOW('r', 64, struct iplookupop) -# define SIOCLOOKUPFLUSH _IOWR('r', 65, struct iplookupflush) -# define SIOCLOOKUPADDNODE _IOWR('r', 67, struct iplookupop) -# define SIOCLOOKUPADDNODEW _IOW('r', 67, struct iplookupop) -# define SIOCLOOKUPDELNODE _IOWR('r', 68, struct iplookupop) -# define SIOCLOOKUPDELNODEW _IOW('r', 68, struct iplookupop) -#else -# define SIOCLOOKUPADDTABLE _IOWR(r, 60, struct iplookupop) -# define SIOCLOOKUPDELTABLE _IOWR(r, 61, struct iplookupop) -# define SIOCLOOKUPSTAT _IOWR(r, 64, struct iplookupop) -# define SIOCLOOKUPSTATW _IOW(r, 64, struct iplookupop) -# define SIOCLOOKUPFLUSH _IOWR(r, 65, struct iplookupflush) -# define SIOCLOOKUPADDNODE _IOWR(r, 67, struct iplookupop) -# define SIOCLOOKUPADDNODEW _IOW(r, 67, struct iplookupop) -# define SIOCLOOKUPDELNODE _IOWR(r, 68, struct iplookupop) -# define SIOCLOOKUPDELNODEW _IOW(r, 68, struct iplookupop) -#endif - -typedef struct iplookupop { - int iplo_type; /* IPLT_* */ - int iplo_unit; /* IPL_LOG* */ - u_int iplo_arg; - char iplo_name[FR_GROUPLEN]; - size_t iplo_size; /* sizeof struct at iplo_struct */ - void *iplo_struct; -} iplookupop_t; - -#define LOOKUP_ANON 0x80000000 - - -typedef struct iplookupflush { - int iplf_type; /* IPLT_* */ - int iplf_unit; /* IPL_LOG* */ - u_int iplf_arg; - size_t iplf_count; - char iplf_name[FR_GROUPLEN]; -} iplookupflush_t; - -typedef struct iplookuplink { - int ipll_type; /* IPLT_* */ - int ipll_unit; /* IPL_LOG* */ - u_int ipll_num; - char ipll_group[FR_GROUPLEN]; -} iplookuplink_t; - -#define IPLT_ALL -1 -#define IPLT_NONE 0 -#define IPLT_POOL 1 -#define IPLT_HASH 2 - -#define IPLT_ANON 0x80000000 - - -typedef union { - struct iplookupiterkey { - char ilik_ival; - u_char ilik_type; /* IPLT_* */ - u_char ilik_otype; - u_char ilik_unit; /* IPL_LOG* */ - } ilik_unstr; - u_32_t ilik_key; -} iplookupiterkey_t; - -typedef struct ipflookupiter { - int ili_nitems; - iplookupiterkey_t ili_lkey; - char ili_name[FR_GROUPLEN]; - void *ili_data; -} ipflookupiter_t; - -#define ili_key ili_lkey.ilik_key -#define ili_ival ili_lkey.ilik_unstr.ilik_ival -#define ili_unit ili_lkey.ilik_unstr.ilik_unit -#define ili_type ili_lkey.ilik_unstr.ilik_type -#define ili_otype ili_lkey.ilik_unstr.ilik_otype - -#define IPFLOOKUPITER_LIST 0 -#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 *)); - -#endif /* __IP_LOOKUP_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_nat.c b/sys/contrib/ipfilter/netinet/ip_nat.c deleted file mode 100644 index 3df1850..0000000 --- a/sys/contrib/ipfilter/netinet/ip_nat.c +++ /dev/null @@ -1,5457 +0,0 @@ -/* - * Copyright (C) 1995-2003 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(__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__ -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> -# 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> - -#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" -#ifdef IPFILTER_SYNC -#include "netinet/ip_sync.h" -#endif -#if (__FreeBSD_version >= 300000) -# include <sys/malloc.h> -#endif -/* END OF INCLUDES */ - -#undef SOCKADDR_IN -#define SOCKADDR_IN struct sockaddr_in - -#if !defined(lint) -static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.195.2.102 2007/10/16 10:08:10 darrenr Exp $"; -#endif - - -/* ======================================================================== */ -/* How the NAT is organised and works. */ -/* */ -/* Inside (interface y) NAT Outside (interface x) */ -/* -------------------- -+- ------------------------------------- */ -/* Packet going | out, processsed by fr_checknatout() for x */ -/* ------------> | ------------> */ -/* src=10.1.1.1 | src=192.1.1.1 */ -/* | */ -/* | in, processed by fr_checknatin() for x */ -/* <------------ | <------------ */ -/* dst=10.1.1.1 | dst=192.1.1.1 */ -/* -------------------- -+- ------------------------------------- */ -/* fr_checknatout() - changes ip_src and if required, sport */ -/* - creates a new mapping, if required. */ -/* fr_checknatin() - 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; -#ifdef IPFILTER_LOG -int nat_logging = 1; -#else -int 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 - -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)); -static int fr_natgetsz __P((caddr_t)); -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 */ -/* Returns: int - 0 == success, -1 == failure */ -/* Parameters: Nil */ -/* */ -/* Initialise all of the NAT locks, tables and other structures. */ -/* ------------------------------------------------------------------------ */ -int fr_natinit() -{ - 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 - return -1; - - KMALLOCS(nat_table[1], nat_t **, sizeof(nat_t *) * ipf_nattable_sz); - if (nat_table[1] != NULL) - bzero((char *)nat_table[1], ipf_nattable_sz * sizeof(nat_t *)); - else - return -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 - 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 - 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 - return -5; - 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) - return -6; - bzero((char *)nat_stats.ns_bucketlen[0], - ipf_nattable_sz * sizeof(u_long)); - - KMALLOCS(nat_stats.ns_bucketlen[1], u_long *, - ipf_nattable_sz * sizeof(u_long)); - if (nat_stats.ns_bucketlen[1] == NULL) - return -7; - - bzero((char *)nat_stats.ns_bucketlen[1], - ipf_nattable_sz * sizeof(u_long)); - - if (fr_nat_maxbucket == 0) { - for (i = ipf_nattable_sz; i > 0; i >>= 1) - fr_nat_maxbucket++; - fr_nat_maxbucket *= 2; - } - - fr_sttab_init(nat_tqb); - /* - * 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; -#ifdef LARGE_NAT - else if (nat_tqb[i].ifq_ttl > fr_defnatage) - nat_tqb[i].ifq_ttl = fr_defnatage; -#endif - } - - /* - * Increase this because we may have "keep state" following - * this too and packet storms can occur if this is removed - * too quickly. - */ - nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = nat_tqb[IPF_TCPS_LAST_ACK].ifq_ttl; - - 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"); - - fr_nat_init = 1; - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_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. */ -/* ------------------------------------------------------------------------ */ -static void nat_addrdr(n) -ipnat_t *n; -{ - ipnat_t **np; - u_32_t j; - u_int hv; - 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; - while (*np != NULL) - np = &(*np)->in_rnext; - n->in_rnext = NULL; - n->in_prnext = np; - n->in_hv = hv; - *np = n; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_addnat */ -/* 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. */ -/* ------------------------------------------------------------------------ */ -static void nat_addnat(n) -ipnat_t *n; -{ - ipnat_t **np; - u_32_t j; - u_int hv; - 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; - while (*np != NULL) - np = &(*np)->in_mnext; - n->in_mnext = NULL; - n->in_pmnext = np; - n->in_hv = hv; - *np = n; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: 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; -{ - if (n->in_rnext) - n->in_rnext->in_prnext = n->in_prnext; - *n->in_prnext = n->in_rnext; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_delnat */ -/* 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; -{ - if (n->in_mnext != NULL) - n->in_mnext->in_pmnext = n->in_pmnext; - *n->in_pmnext = n->in_mnext; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: 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 */ -/* 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 *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; -{ - hostmap_t *hm; - u_int hv; - - 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) && - ((np == NULL) || (np == hm->hm_ipnat)) && - ((port == 0) || (port == hm->hm_port))) { - hm->hm_ref++; - return hm; - } - - if (np == NULL) - 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_ipnat = np; - hm->hm_srcip = src; - hm->hm_dstip = dst; - hm->hm_mapip = map; - hm->hm_ref = 1; - hm->hm_port = port; - } - return hm; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_hostmapdel */ -/* Returns: Nil */ -/* Parameters: hmp(I) - pointer to hostmap structure pointer */ -/* Write Locks: ipf_nat */ -/* */ -/* 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; -{ - struct hostmap *hm; - - hm = *hmp; - *hmp = NULL; - - hm->hm_ref--; - if (hm->hm_ref == 0) { - if (hm->hm_hnext) - hm->hm_hnext->hm_phnext = hm->hm_phnext; - *hm->hm_phnext = hm->hm_hnext; - if (hm->hm_next) - hm->hm_next->hm_pnext = hm->hm_pnext; - *hm->hm_pnext = hm->hm_next; - KFREE(hm); - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fix_outcksum */ -/* Returns: Nil */ -/* Parameters: fin(I) - pointer to packet information */ -/* sp(I) - location of 16bit checksum to update */ -/* n((I) - amount to adjust checksum by */ -/* */ -/* 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; -{ - u_short sumshort; - u_32_t sum1; - - if (n == 0) - return; - - if (n & NAT_HW_CKSUM) { - n &= 0xffff; - n += fin->fin_dlen; - n = (n & 0xffff) + (n >> 16); - *sp = n & 0xffff; - return; - } - sum1 = (~ntohs(*sp)) & 0xffff; - sum1 += (n); - sum1 = (sum1 >> 16) + (sum1 & 0xffff); - /* Again */ - sum1 = (sum1 >> 16) + (sum1 & 0xffff); - sumshort = ~(u_short)sum1; - *(sp) = htons(sumshort); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fix_incksum */ -/* Returns: Nil */ -/* Parameters: fin(I) - pointer to packet information */ -/* sp(I) - location of 16bit checksum to update */ -/* n((I) - amount to adjust checksum by */ -/* */ -/* 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; -{ - u_short sumshort; - u_32_t sum1; - - if (n == 0) - return; - - if (n & NAT_HW_CKSUM) { - n &= 0xffff; - n += fin->fin_dlen; - n = (n & 0xffff) + (n >> 16); - *sp = n & 0xffff; - return; - } - sum1 = (~ntohs(*sp)) & 0xffff; - sum1 += ~(n) & 0xffff; - sum1 = (sum1 >> 16) + (sum1 & 0xffff); - /* Again */ - sum1 = (sum1 >> 16) + (sum1 & 0xffff); - sumshort = ~(u_short)sum1; - *(sp) = htons(sumshort); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fix_datacksum */ -/* Returns: Nil */ -/* Parameters: sp(I) - location of 16bit checksum to update */ -/* n((I) - amount to adjust checksum by */ -/* */ -/* Fix_datacksum is used *only* for the adjustments of checksums in the */ -/* data section of an IP packet. */ -/* */ -/* The only situation in which you need to do this is when NAT'ing an */ -/* ICMP error message. Such a message, contains in its body the IP header */ -/* of the original IP packet, that causes the error. */ -/* */ -/* You can't use fix_incksum or fix_outcksum in that case, because for the */ -/* kernel the data section of the ICMP error is just data, and no special */ -/* processing like hardware cksum or ntohs processing have been done by the */ -/* kernel on the data section. */ -/* ------------------------------------------------------------------------ */ -void fix_datacksum(sp, n) -u_short *sp; -u_32_t n; -{ - u_short sumshort; - u_32_t sum1; - - if (n == 0) - return; - - sum1 = (~ntohs(*sp)) & 0xffff; - sum1 += (n); - sum1 = (sum1 >> 16) + (sum1 & 0xffff); - /* Again */ - sum1 = (sum1 >> 16) + (sum1 & 0xffff); - sumshort = ~(u_short)sum1; - *(sp) = htons(sumshort); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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 */ -/* */ -/* 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; -{ - ipnat_t *nat, *nt, *n = NULL, **np = NULL; - int error = 0, ret, arg, getlock; - ipnat_t natd; - SPL_INT(s); - -#if (BSD >= 199306) && defined(_KERNEL) -# if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 399002000) - if ((mode & FWRITE) && - kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_FIREWALL, - KAUTH_REQ_NETWORK_FIREWALL_FW, - NULL, NULL, NULL)) { - return EPERM; - } -# else - if ((securelevel >= 2) && (mode & FWRITE)) { - return EPERM; - } -# endif -#endif - -#if defined(__osf__) && defined(_KERNEL) - getlock = 0; -#else - getlock = (mode & NAT_LOCKHELD) ? 0 : 1; -#endif - - nat = NULL; /* XXX gcc -Wuninitialized */ - if (cmd == (ioctlcmd_t)SIOCADNAT) { - KMALLOC(nt, ipnat_t *); - } else { - nt = NULL; - } - - if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) { - if (mode & NAT_SYSSPACE) { - bcopy(data, (char *)&natd, sizeof(natd)); - error = 0; - } else { - error = fr_inobj(data, &natd, IPFOBJ_IPNAT); - } - } - - if (error != 0) - goto done; - - /* - * 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; - 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; - } - } - - switch (cmd) - { -#ifdef IPFILTER_LOG - case SIOCIPFFB : - { - int tmp; - - if (!(mode & FWRITE)) - error = EPERM; - else { - tmp = ipflog_clear(IPL_LOGNAT); - error = BCOPYOUT((char *)&tmp, (char *)data, - sizeof(tmp)); - if (error != 0) - error = EFAULT; - } - break; - } - - case SIOCSETLG : - if (!(mode & FWRITE)) - error = EPERM; - else { - error = BCOPYIN((char *)data, (char *)&nat_logging, - sizeof(nat_logging)); - if (error != 0) - error = EFAULT; - } - break; - - case SIOCGETLG : - error = BCOPYOUT((char *)&nat_logging, (char *)data, - sizeof(nat_logging)); - if (error != 0) - error = EFAULT; - break; - - case FIONREAD : - arg = iplused[IPL_LOGNAT]; - error = BCOPYOUT(&arg, data, sizeof(arg)); - if (error != 0) - error = EFAULT; - break; -#endif - case SIOCADNAT : - if (!(mode & FWRITE)) { - error = EPERM; - } else if (n != NULL) { - error = EEXIST; - } else if (nt == NULL) { - error = ENOMEM; - } - if (error != 0) { - MUTEX_EXIT(&ipf_natio); - break; - } - bcopy((char *)nat, (char *)nt, sizeof(*n)); - error = nat_siocaddnat(nt, np, getlock); - MUTEX_EXIT(&ipf_natio); - if (error == 0) - nt = NULL; - break; - - case SIOCRMNAT : - if (!(mode & FWRITE)) { - error = EPERM; - n = NULL; - } else if (n == NULL) { - error = ESRCH; - } - - if (error != 0) { - MUTEX_EXIT(&ipf_natio); - break; - } - nat_siocdelnat(n, np, getlock); - - MUTEX_EXIT(&ipf_natio); - 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); - break; - - case SIOCGNATL : - { - natlookup_t nl; - - if (getlock) { - READ_ENTER(&ipf_nat); - } - error = fr_inobj(data, &nl, IPFOBJ_NATLOOKUP); - if (error == 0) { - if (nat_lookupredir(&nl) != NULL) { - error = fr_outobj(data, &nl, IPFOBJ_NATLOOKUP); - } else { - error = ESRCH; - } - } - if (getlock) { - RWLOCK_EXIT(&ipf_nat); - } - break; - } - - case SIOCIPFFL : /* old SIOCFLNAT & SIOCCNATL */ - if (!(mode & FWRITE)) { - error = EPERM; - break; - } - if (getlock) { - WRITE_ENTER(&ipf_nat); - } - - error = BCOPYIN(data, &arg, sizeof(arg)); - if (error != 0) - error = EFAULT; - else { - if (arg == 0) - ret = nat_flushtable(); - else if (arg == 1) - ret = nat_clearlist(); - else - ret = nat_extraflush(arg); - } - - if (getlock) { - RWLOCK_EXIT(&ipf_nat); - } - if (error == 0) { - error = BCOPYOUT(&ret, data, sizeof(ret)); - } - break; - - case SIOCPROXY : - error = appr_ioctl(data, cmd, mode, ctx); - break; - - case SIOCSTLCK : - if (!(mode & FWRITE)) { - error = EPERM; - } else { - error = fr_lock(data, &fr_nat_lock); - } - break; - - case SIOCSTPUT : - if ((mode & FWRITE) != 0) { - error = fr_natputent(data, getlock); - } else { - error = EACCES; - } - break; - - case SIOCSTGSZ : - if (fr_nat_lock) { - if (getlock) { - READ_ENTER(&ipf_nat); - } - error = fr_natgetsz(data); - if (getlock) { - RWLOCK_EXIT(&ipf_nat); - } - } else - error = EACCES; - break; - - case SIOCSTGET : - if (fr_nat_lock) { - if (getlock) { - READ_ENTER(&ipf_nat); - } - error = fr_natgetent(data); - if (getlock) { - RWLOCK_EXIT(&ipf_nat); - } - } else - error = EACCES; - break; - - case SIOCGENITER : - { - ipfgeniter_t iter; - ipftoken_t *token; - - 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); - } - SPL_X(s); - break; - } - - case SIOCIPFDELTOK : - error = BCOPYIN((caddr_t)data, (caddr_t)&arg, sizeof(arg)); - if (error == 0) { - SPL_SCHED(s); - error = ipf_deltoken(arg, uid, ctx); - SPL_X(s); - } else { - error = EFAULT; - } - break; - - case SIOCGTQTAB : - error = fr_outobj(data, nat_tqb, IPFOBJ_STATETQTAB); - break; - - case SIOCGTABL : - error = nat_gettable(data); - break; - - default : - error = EINVAL; - break; - } -done: - if (nt != NULL) - KFREE(nt); - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_siocaddnat */ -/* 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 */ -/* */ -/* 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; -{ - int error = 0, i, j; - - if (nat_resolverule(n) != 0) - return ENOENT; - - if ((n->in_age[0] == 0) && (n->in_age[1] != 0)) - 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); - /* - * Multiply by the number of ports made available. - */ - 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; - } - } - - /* Otherwise, these fields are preset */ - - if (getlock) { - WRITE_ENTER(&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]); - - if (n->in_redir & NAT_REDIRECT) { - n->in_flags &= ~IPN_NOTDST; - nat_addrdr(n); - } - if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) { - n->in_flags &= ~IPN_NOTSRC; - nat_addnat(n); - } - MUTEX_INIT(&n->in_lock, "ipnat rule lock"); - - n = NULL; - nat_stats.ns_rules++; -#if SOLARIS && !defined(_INET_IP_STACK_H) - pfil_delayed_copy = 0; -#endif - if (getlock) { - RWLOCK_EXIT(&ipf_nat); /* WRITE */ - } - - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_resolvrule */ -/* Returns: Nil */ -/* Parameters: 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; -{ - n->in_ifnames[0][LIFNAMSIZ - 1] = '\0'; - n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], 4); - - 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[1] = n->in_ifps[0]; - } else { - n->in_ifps[1] = fr_resolvenic(n->in_ifnames[1], 4); - } - - if (n->in_plabel[0] != '\0') { - n->in_apr = appr_lookup(n->in_p, n->in_plabel); - if (n->in_apr == NULL) - return -1; - } - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: 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 */ -/* */ -/* 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; -{ - 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]); - } - } - - if (n->in_tqehead[1] != NULL) { - if (fr_deletetimeoutqueue(n->in_tqehead[1]) == 0) { - fr_freetimeoutqueue(n->in_tqehead[1]); - } - } - - *np = n->in_next; - - 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 */ - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_natgetsz */ -/* Returns: int - 0 == success, != 0 is the error value. */ -/* Parameters: data(I) - pointer to natget structure with kernel pointer */ -/* get the size of. */ -/* */ -/* 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) -caddr_t data; -{ - ap_session_t *aps; - nat_t *nat, *n; - natget_t ng; - - if (BCOPYIN(data, &ng, sizeof(ng)) != 0) - return EFAULT; - - nat = ng.ng_ptr; - if (!nat) { - nat = nat_instances; - ng.ng_sz = 0; - /* - * Empty list so the size returned is 0. Simple. - */ - if (nat == NULL) { - if (BCOPYOUT(&ng, data, sizeof(ng)) != 0) - return EFAULT; - return 0; - } - } else { - /* - * Make sure the pointer we're copying from exists in the - * current list of entries. Security precaution to prevent - * copying of random kernel data. - */ - for (n = nat_instances; n; n = n->nat_next) - if (n == nat) - break; - if (!n) - return ESRCH; - } - - /* - * Incluse any space required for proxy data structures. - */ - ng.ng_sz = sizeof(nat_save_t); - aps = nat->nat_aps; - if (aps != NULL) { - ng.ng_sz += sizeof(ap_session_t) - 4; - if (aps->aps_data != 0) - ng.ng_sz += aps->aps_psiz; - } - - if (BCOPYOUT(&ng, data, sizeof(ng)) != 0) - return EFAULT; - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_natgetent */ -/* 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. */ -/* */ -/* 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) -caddr_t data; -{ - int error, outsize; - ap_session_t *aps; - nat_save_t *ipn, ipns; - nat_t *n, *nat; - - error = fr_inobj(data, &ipns, IPFOBJ_NATSAVE); - if (error != 0) - return error; - - if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920)) - return EINVAL; - - KMALLOCS(ipn, nat_save_t *, ipns.ipn_dsize); - if (ipn == NULL) - return ENOMEM; - - ipn->ipn_dsize = ipns.ipn_dsize; - nat = ipns.ipn_next; - if (nat == NULL) { - nat = nat_instances; - if (nat == NULL) { - if (nat_instances == NULL) - error = ENOENT; - goto finished; - } - } else { - /* - * Make sure the pointer we're copying from exists in the - * current list of entries. Security precaution to prevent - * copying of random kernel data. - */ - for (n = nat_instances; n; n = n->nat_next) - if (n == nat) - break; - if (n == NULL) { - error = ESRCH; - goto finished; - } - } - ipn->ipn_next = nat->nat_next; - - /* - * Copy the NAT structure. - */ - bcopy((char *)nat, &ipn->ipn_nat, sizeof(*nat)); - - /* - * If we have a pointer to the NAT rule it belongs to, save that too. - */ - if (nat->nat_ptr != NULL) - bcopy((char *)nat->nat_ptr, (char *)&ipn->ipn_ipnat, - sizeof(ipn->ipn_ipnat)); - - /* - * If we also know the NAT entry has an associated filter rule, - * save that too. - */ - if (nat->nat_fr != NULL) - bcopy((char *)nat->nat_fr, (char *)&ipn->ipn_fr, - sizeof(ipn->ipn_fr)); - - /* - * Last but not least, if there is an application proxy session set - * up for this NAT entry, then copy that out too, including any - * private data saved along side it by the proxy. - */ - aps = nat->nat_aps; - outsize = ipn->ipn_dsize - sizeof(*ipn) + sizeof(ipn->ipn_data); - if (aps != NULL) { - char *s; - - if (outsize < sizeof(*aps)) { - error = ENOBUFS; - goto finished; - } - - s = ipn->ipn_data; - bcopy((char *)aps, s, sizeof(*aps)); - s += sizeof(*aps); - outsize -= sizeof(*aps); - if ((aps->aps_data != NULL) && (outsize >= aps->aps_psiz)) - bcopy(aps->aps_data, s, aps->aps_psiz); - else - error = ENOBUFS; - } - if (error == 0) { - error = fr_outobjsz(data, ipn, IPFOBJ_NATSAVE, ipns.ipn_dsize); - } - -finished: - if (ipn != NULL) { - KFREES(ipn, ipns.ipn_dsize); - } - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_natputent */ -/* 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 */ -/* getlock(I) - flag indicating whether or not a write lock */ -/* on ipf_nat 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; -{ - nat_save_t ipn, *ipnn; - ap_session_t *aps; - nat_t *n, *nat; - frentry_t *fr; - fr_info_t fin; - ipnat_t *in; - int error; - - error = fr_inobj(data, &ipn, IPFOBJ_NATSAVE); - if (error != 0) - return error; - - /* - * Initialise early because of code at junkput label. - */ - in = NULL; - aps = NULL; - nat = NULL; - ipnn = NULL; - fr = NULL; - - /* - * New entry, copy in the rest of the NAT entry if it's size is more - * than just the nat_t structure. - */ - if (ipn.ipn_dsize > sizeof(ipn)) { - if (ipn.ipn_dsize > 81920) { - error = ENOMEM; - goto junkput; - } - - KMALLOCS(ipnn, nat_save_t *, ipn.ipn_dsize); - if (ipnn == NULL) - return ENOMEM; - - error = fr_inobjsz(data, ipnn, IPFOBJ_NATSAVE, ipn.ipn_dsize); - if (error != 0) { - error = EFAULT; - goto junkput; - } - } else - ipnn = &ipn; - - KMALLOC(nat, nat_t *); - if (nat == NULL) { - error = ENOMEM; - goto junkput; - } - - bcopy((char *)&ipnn->ipn_nat, (char *)nat, sizeof(*nat)); - /* - * Initialize all these so that nat_delete() doesn't cause a crash. - */ - bzero((char *)nat, offsetof(struct nat, nat_tqe)); - nat->nat_tqe.tqe_pnext = NULL; - nat->nat_tqe.tqe_next = NULL; - nat->nat_tqe.tqe_ifq = NULL; - nat->nat_tqe.tqe_parent = nat; - - /* - * Restore the rule associated with this nat session - */ - in = ipnn->ipn_nat.nat_ptr; - if (in != NULL) { - KMALLOC(in, ipnat_t *); - nat->nat_ptr = in; - if (in == NULL) { - error = ENOMEM; - goto junkput; - } - bzero((char *)in, offsetof(struct ipnat, in_next6)); - bcopy((char *)&ipnn->ipn_ipnat, (char *)in, sizeof(*in)); - in->in_use = 1; - in->in_flags |= IPN_DELETE; - - ATOMIC_INC(nat_stats.ns_rules); - - if (nat_resolverule(in) != 0) { - error = ESRCH; - goto junkput; - } - } - - /* - * Check that the NAT entry doesn't already exist in the kernel. - * - * 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); - if (getlock) { - READ_ENTER(&ipf_nat); - } - n = nat_inlookup(&fin, nat->nat_flags, fin.fin_p, - nat->nat_oip, nat->nat_inip); - if (getlock) { - RWLOCK_EXIT(&ipf_nat); - } - if (n != NULL) { - 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); - if (getlock) { - READ_ENTER(&ipf_nat); - } - n = nat_outlookup(&fin, nat->nat_flags, fin.fin_p, - nat->nat_outip, nat->nat_oip); - if (getlock) { - RWLOCK_EXIT(&ipf_nat); - } - if (n != NULL) { - error = EEXIST; - goto junkput; - } - } else { - error = EINVAL; - goto junkput; - } - - /* - * Restore ap_session_t structure. Include the private data allocated - * if it was there. - */ - aps = nat->nat_aps; - if (aps != NULL) { - KMALLOC(aps, ap_session_t *); - nat->nat_aps = aps; - if (aps == NULL) { - error = ENOMEM; - goto junkput; - } - bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps)); - if (in != NULL) - aps->aps_apr = in->in_apr; - else - aps->aps_apr = NULL; - if (aps->aps_psiz != 0) { - if (aps->aps_psiz > 81920) { - error = ENOMEM; - goto junkput; - } - KMALLOCS(aps->aps_data, void *, aps->aps_psiz); - if (aps->aps_data == NULL) { - error = ENOMEM; - goto junkput; - } - bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data, - aps->aps_psiz); - } else { - aps->aps_psiz = 0; - aps->aps_data = NULL; - } - } - - /* - * If there was a filtering rule associated with this entry then - * build up a new one. - */ - fr = nat->nat_fr; - if (fr != NULL) { - if ((nat->nat_flags & SI_NEWFR) != 0) { - KMALLOC(fr, frentry_t *); - nat->nat_fr = fr; - if (fr == NULL) { - error = ENOMEM; - goto junkput; - } - ipnn->ipn_nat.nat_fr = fr; - fr->fr_ref = 1; - (void) fr_outobj(data, ipnn, IPFOBJ_NATSAVE); - bcopy((char *)&ipnn->ipn_fr, (char *)fr, sizeof(*fr)); - - fr->fr_ref = 1; - fr->fr_dsize = 0; - fr->fr_data = NULL; - fr->fr_type = FR_T_NONE; - - MUTEX_NUKE(&fr->fr_lock); - MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock"); - } else { - if (getlock) { - READ_ENTER(&ipf_nat); - } - for (n = nat_instances; n; n = n->nat_next) - if (n->nat_fr == fr) - break; - - if (n != NULL) { - MUTEX_ENTER(&fr->fr_lock); - fr->fr_ref++; - MUTEX_EXIT(&fr->fr_lock); - } - if (getlock) { - RWLOCK_EXIT(&ipf_nat); - } - - if (!n) { - error = ESRCH; - goto junkput; - } - } - } - - if (ipnn != &ipn) { - KFREES(ipnn, ipn.ipn_dsize); - ipnn = NULL; - } - - 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; - } - if (getlock) { - RWLOCK_EXIT(&ipf_nat); - } - - if (error == 0) - return 0; - - error = ENOMEM; - -junkput: - if (fr != NULL) - (void) fr_derefrule(&fr); - - if ((ipnn != NULL) && (ipnn != &ipn)) { - KFREES(ipnn, ipn.ipn_dsize); - } - if (nat != NULL) { - if (aps != NULL) { - if (aps->aps_data != NULL) { - KFREES(aps->aps_data, aps->aps_psiz); - } - KFREE(aps); - } - if (in != NULL) { - if (in->in_apr) - appr_free(in->in_apr); - KFREE(in); - } - KFREE(nat); - } - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_delete */ -/* Returns: Nil */ -/* Parameters: natd(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; -{ - struct ipnat *ipn; - int removed = 0; - - if (logtype != 0 && nat_logging != 0) - nat_log(nat, logtype); - - /* - * Take it as a general indication that all the pointers are set if - * nat_pnext is set. - */ - 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]]--; - - *nat->nat_pnext = nat->nat_next; - if (nat->nat_next != NULL) { - nat->nat_next->nat_pnext = nat->nat_pnext; - nat->nat_next = NULL; - } - nat->nat_pnext = NULL; - - *nat->nat_phnext[0] = nat->nat_hnext[0]; - if (nat->nat_hnext[0] != NULL) { - nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0]; - nat->nat_hnext[0] = NULL; - } - nat->nat_phnext[0] = NULL; - - *nat->nat_phnext[1] = nat->nat_hnext[1]; - if (nat->nat_hnext[1] != NULL) { - nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1]; - nat->nat_hnext[1] = NULL; - } - nat->nat_phnext[1] = NULL; - - if ((nat->nat_flags & SI_WILDP) != 0) - nat_stats.ns_wilds--; - } - - if (nat->nat_me != NULL) { - *nat->nat_me = NULL; - nat->nat_me = NULL; - } - - if (nat->nat_tqe.tqe_ifq != NULL) - fr_deletequeueentry(&nat->nat_tqe); - - if (logtype == NL_EXPIRE) - nat_stats.ns_expire++; - - MUTEX_ENTER(&nat->nat_lock); - /* - * NL_DESTROY should only be passed in when we've got nat_ref >= 2. - * This happens when a nat'd packet is blocked and we want to throw - * away the NAT session. - */ - if (logtype == NL_DESTROY) { - if (nat->nat_ref > 2) { - nat->nat_ref -= 2; - MUTEX_EXIT(&nat->nat_lock); - if (removed) - 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++; - return; - } - 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 (nat->nat_fr != NULL) - (void) fr_derefrule(&nat->nat_fr); - - if (nat->nat_hm != NULL) - fr_hostmapdel(&nat->nat_hm); - - /* - * If there is an active reference from the nat entry to its parent - * rule, decrement the rule's reference count and free it too if no - * longer being used. - */ - ipn = nat->nat_ptr; - if (ipn != NULL) { - fr_ipnatderef(&ipn); - } - - MUTEX_DESTROY(&nat->nat_lock); - - aps_free(nat->nat_aps); - nat_stats.ns_inuse--; - - /* - * 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); - - KFREE(nat); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_flushtable */ -/* Returns: int - number of NAT rules deleted */ -/* Parameters: Nil */ -/* */ -/* 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. */ -/* ------------------------------------------------------------------------ */ -/* - * nat_flushtable - clear the NAT table of all mapping entries. - */ -static int nat_flushtable() -{ - nat_t *nat; - int j = 0; - - /* - * 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); - j++; - } - - nat_stats.ns_inuse = 0; - return j; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_clearlist */ -/* Returns: int - number of NAT/RDR rules deleted */ -/* Parameters: Nil */ -/* */ -/* 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() -{ - ipnat_t *n, **np = &nat_list; - int i = 0; - - if (nat_rules != NULL) - bzero((char *)nat_rules, sizeof(*nat_rules) * ipf_natrules_sz); - if (rdr_rules != NULL) - bzero((char *)rdr_rules, sizeof(*rdr_rules) * ipf_rdrrules_sz); - - while ((n = *np) != 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; - } - i++; - } -#if SOLARIS && !defined(_INET_IP_STACK_H) - pfil_delayed_copy = 1; -#endif - nat_masks = 0; - rdr_masks = 0; - return i; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_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. */ -/* ------------------------------------------------------------------------ */ -static INLINE int nat_newmap(fin, nat, ni) -fr_info_t *fin; -nat_t *nat; -natinfo_t *ni; -{ - u_short st_port, dport, sport, port, sp, dp; - struct in_addr in, inb; - hostmap_t *hm; - u_32_t flags; - u_32_t st_ip; - 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_nip; - st_port = np->in_pnext; - flags = ni->nai_flags; - sport = ni->nai_sport; - dport = ni->nai_dport; - - /* - * 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.s_addr = htonl(np->in_nip); - if (l == 0) { - /* - * Check to see if there is an existing NAT - * setup for this IP address pair. - */ - hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, - in, 0); - if (hm != NULL) - in.s_addr = hm->hm_mapip.s_addr; - } else if ((l == 1) && (hm != NULL)) { - fr_hostmapdel(&hm); - } - in.s_addr = ntohl(in.s_addr); - - nat->nat_hm = hm; - - if ((np->in_outmsk == 0xffffffff) && (np->in_pnext == 0)) { - if (l > 0) - return -1; - } - - if (np->in_redir == NAT_BIMAP && - np->in_inmsk == np->in_outmsk) { - /* - * 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 = ntohl(in.s_addr); - - } else if (np->in_redir & NAT_MAPBLK) { - if ((l >= np->in_ppip) || ((l > 0) && - !(flags & IPN_TCPUDP))) - return -1; - /* - * map-block - Calculate destination address. - */ - in.s_addr = ntohl(fin->fin_saddr); - in.s_addr &= ntohl(~np->in_inmsk); - inb.s_addr = in.s_addr; - in.s_addr /= np->in_ippip; - in.s_addr &= ntohl(~np->in_outmsk); - in.s_addr += ntohl(np->in_outip); - /* - * Calculate destination port. - */ - if ((flags & IPN_TCPUDP) && - (np->in_ppip != 0)) { - port = ntohs(sport) + l; - port %= np->in_ppip; - port += np->in_ppip * - (inb.s_addr % np->in_ippip); - port += MAPBLK_MINPORT; - port = htons(port); - } - - } else if ((np->in_outip == 0) && - (np->in_outmsk == 0xffffffff)) { - /* - * 0/32 - use the interface's IP address. - */ - if ((l > 0) || - fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp, - &in, NULL) == -1) - return -1; - in.s_addr = ntohl(in.s_addr); - - } else if ((np->in_outip == 0) && (np->in_outmsk == 0)) { - /* - * 0/0 - use the original source address/port. - */ - if (l > 0) - 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++; - - natl = NULL; - - if ((flags & IPN_TCPUDP) && - ((np->in_redir & NAT_MAPBLK) == 0) && - (np->in_flags & IPN_AUTOPORTMAP)) { - /* - * "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 (np->in_ppip != 0) { - port = ntohs(sport); - port += (l % np->in_ppip); - port %= np->in_ppip; - port += np->in_ppip * - (ntohl(fin->fin_saddr) % - np->in_ippip); - port += MAPBLK_MINPORT; - port = htons(port); - } - - } else if (((np->in_redir & NAT_MAPBLK) == 0) && - (flags & IPN_TCPUDPICMP) && (np->in_pnext != 0)) { - /* - * Standard port translation. Select next port. - */ - port = htons(np->in_pnext++); - - 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_flags & IPN_IPRANGE) { - if (np->in_nip > ntohl(np->in_outmsk)) - np->in_nip = ntohl(np->in_outip); - } else { - if ((np->in_outmsk != 0xffffffff) && - ((np->in_nip + 1) & ntohl(np->in_outmsk)) > - ntohl(np->in_outip)) - np->in_nip = ntohl(np->in_outip) + 1; - } - - if ((port == 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. - */ - inb.s_addr = htonl(in.s_addr); - 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[0] = sp; - fin->fin_data[1] = dp; - - /* - * Has the search wrapped around and come back to the - * start ? - */ - if ((natl != NULL) && - (np->in_pnext != 0) && (st_port == np->in_pnext) && - (np->in_nip != 0) && (st_ip == np->in_nip)) - 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; - 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); - } - - if (flags & IPN_TCPUDP) { - nat->nat_inport = sport; - nat->nat_outport = port; /* sport */ - nat->nat_oport = dport; - ((tcphdr_t *)fin->fin_dp)->th_sport = port; - } else if (flags & IPN_ICMPQUERY) { - ((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 - } - ni->nai_ip.s_addr = in.s_addr; - ni->nai_port = port; - ni->nai_nport = dport; - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: 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 */ -/* 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. */ -/* ------------------------------------------------------------------------ */ -static INLINE int nat_newrdr(fin, nat, ni) -fr_info_t *fin; -nat_t *nat; -natinfo_t *ni; -{ - u_short nport, dport, sport; - struct in_addr in, inb; - u_short sp, dp; - hostmap_t *hm; - u_32_t flags; - ipnat_t *np; - nat_t *natl; - int move; - - move = 1; - hm = NULL; - in.s_addr = 0; - np = ni->nai_np; - flags = ni->nai_flags; - sport = ni->nai_sport; - dport = ni->nai_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 = nat_hostmap(NULL, fin->fin_src, fin->fin_dst, in, - (u_32_t)dport); - if (hm != NULL) { - in.s_addr = ntohl(hm->hm_mapip.s_addr); - 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.s_addr = np->in_nip; - - 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); - if (hm != NULL) { - in.s_addr = hm->hm_mapip.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); - move = 0; - } else { - np->in_nip = ntohl(np->in_inip); - } - } - - } 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) - return -1; - in.s_addr = ntohl(in.s_addr); - - } else if ((np->in_inip == 0) && (np->in_inmsk== 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) { - /* - * 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 = ntohl(in.s_addr); - } else { - in.s_addr = ntohl(np->in_inip); - } - - if ((np->in_pnext == 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_pmin != np->in_pmax)) { - nport = ntohs(dport) - ntohs(np->in_pmin) + - ntohs(np->in_pnext); - nport = htons(nport); - } else - nport = np->in_pnext; - } - - /* - * When the redirect-to address is set to 0.0.0.0, just - * assume a blank `forwarding' of the packet. We don't - * setup any translation for this either. - */ - if (in.s_addr == 0) { - if (nport == dport) - return -1; - in.s_addr = ntohl(fin->fin_daddr); - } - - /* - * 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.) - */ - inb.s_addr = htonl(in.s_addr); - 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 = 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) - return -1; - - nat->nat_inip.s_addr = htonl(in.s_addr); - nat->nat_outip = fin->fin_dst; - nat->nat_oip = 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; - - if (flags & IPN_TCPUDP) { - nat->nat_inport = nport; - nat->nat_outport = dport; - nat->nat_oport = sport; - ((tcphdr_t *)fin->fin_dp)->th_dport = nport; - } else if (flags & IPN_ICMPQUERY) { - ((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 - } - - return move; -} - -/* ------------------------------------------------------------------------ */ -/* Function: nat_new */ -/* Returns: nat_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 *nat_new(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; - hostmap_t *hm = NULL; - struct in_addr in; - nat_t *nat, *natl; - 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; - return NULL; - } - - move = 1; - nflags = np->in_flags & flags; - 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++; - /* - * 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); - } - 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) { - /* - * 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 icmp_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 = ((icmphdr_t *)fin->fin_dp)->icmp_id; - ni.nai_dport = ni.nai_sport; - } - - 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); - } - - /* - * Search the current table for a match. - */ - 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, - fin->fin_src, fin->fin_dst); - if (natl != NULL) { - KFREE(nat); - nat = natl; - goto done; - } - - move = nat_newmap(fin, nat, &ni); - if (move == -1) - goto badnat; - - np = ni.nai_np; - in = ni.nai_ip; - } else { - /* - * NAT_INBOUND is used only for redirects rules - */ - natl = 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; - } - port = ni.nai_port; - nport = ni.nai_nport; - - 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); - } - } - - if (flags & IPN_TCPUDP) { - sport = ni.nai_sport; - dport = ni.nai_dport; - } else if (flags & IPN_ICMPQUERY) { - sport = ni.nai_sport; - dport = 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]; - - 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)); - - ni.nai_sum2 = LONG_SUM(in.s_addr); - - 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 (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; - goto done; -badnat: - nat_stats.ns_badnat++; - if ((hm = nat->nat_hm) != NULL) - fr_hostmapdel(&hm); - KFREE(nat); - nat = NULL; -done: - if ((flags & NAT_SLAVE) == 0) { - MUTEX_EXIT(&ipf_nat_new); - } - return nat; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: 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; -{ - frentry_t *fr; - ipnat_t *np; - - np = ni->nai_np; - - if (np->in_ifps[0] != NULL) { - COPYIFNAME(4, np->in_ifps[0], nat->nat_ifnames[0]); - } - if (np->in_ifps[1] != NULL) { - COPYIFNAME(4, np->in_ifps[1], nat->nat_ifnames[1]); - } -#ifdef IPFILTER_SYNC - if ((nat->nat_flags & SI_CLONE) == 0) - nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat); -#endif - - 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); - - if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0)) - if (appr_new(fin, nat) == -1) - return -1; - - 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; - if (fr != NULL) { - MUTEX_ENTER(&fr->fr_lock); - fr->fr_ref++; - MUTEX_EXIT(&fr->fr_lock); - } - return 0; - } - - /* - * nat_insert failed, so cleanup time... - */ - 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 */ -/* */ -/* 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; -{ - u_int hv1, hv2; - nat_t **natp; - - /* - * 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); - } 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); - } - - if (nat_stats.ns_bucketlen[0][hv1] >= fr_nat_maxbucket || - nat_stats.ns_bucketlen[1][hv2] >= fr_nat_maxbucket) { - return -1; - } - - nat->nat_hv[0] = hv1; - nat->nat_hv[1] = hv2; - - 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; - - nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0'; - nat->nat_ifps[0] = fr_resolvenic(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_next = nat_instances; - nat->nat_pnext = &nat_instances; - if (nat_instances) - nat_instances->nat_pnext = &nat->nat_next; - nat_instances = nat; - - natp = &nat_table[0][hv1]; - if (*natp) - (*natp)->nat_phnext[0] = &nat->nat_hnext[0]; - nat->nat_phnext[0] = natp; - nat->nat_hnext[0] = *natp; - *natp = nat; - nat_stats.ns_bucketlen[0][hv1]++; - - natp = &nat_table[1][hv2]; - 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][hv2]++; - - fr_setnatqueue(nat, rev); - - nat_stats.ns_added++; - nat_stats.ns_inuse++; - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_icmperrorlookup */ -/* Returns: nat_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 *nat_icmperrorlookup(fin, dir) -fr_info_t *fin; -int dir; -{ - int flags = 0, type, minlen; - icmphdr_t *icmp, *orgicmp; - tcphdr_t *tcp = NULL; - u_short data[2]; - nat_t *nat; - ip_t *oip; - u_int p; - - icmp = fin->fin_dp; - type = icmp->icmp_type; - /* - * Does it at least have the return (basic) IP header ? - * Only a basic IP header (no options) should be with an ICMP error - * header. Also, if it's not an error type, then return. - */ - if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR)) - return NULL; - - /* - * Check packet size - */ - oip = (ip_t *)((char *)fin->fin_dp + 8); - minlen = IP_HL(oip) << 2; - if ((minlen < sizeof(ip_t)) || - (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)) - return NULL; - /* - * Is the buffer big enough for all of it ? It's the size of the IP - * header claimed in the encapsulated part which is of concern. It - * may be too big to be in this buffer but not so big that it's - * outside the ICMP packet, leading to TCP deref's causing problems. - * This is possible because we don't know how big oip_hl is when we - * do the pullup early in fr_check() and thus can't gaurantee it is - * all here now. - */ -#ifdef _KERNEL - { - mb_t *m; - - m = fin->fin_m; -# if defined(MENTAT) - if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr) - return NULL; -# else - if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > - (char *)fin->fin_ip + M_LEN(m)) - return NULL; -# endif - } -#endif - - if (fin->fin_daddr != oip->ip_src.s_addr) - return NULL; - - p = oip->ip_p; - if (p == IPPROTO_TCP) - flags = IPN_TCP; - else if (p == IPPROTO_UDP) - flags = IPN_UDP; - else if (p == IPPROTO_ICMP) { - orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2)); - - /* see if this is related to an ICMP query */ - if (nat_icmpquerytype4(orgicmp->icmp_type)) { - data[0] = fin->fin_data[0]; - data[1] = fin->fin_data[1]; - fin->fin_data[0] = 0; - fin->fin_data[1] = orgicmp->icmp_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 = nat_inlookup(fin, flags, p, oip->ip_dst, - oip->ip_src); - else - nat = 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) - return NULL; - - data[0] = fin->fin_data[0]; - data[1] = fin->fin_data[1]; - tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2)); - fin->fin_data[0] = ntohs(tcp->th_dport); - fin->fin_data[1] = ntohs(tcp->th_sport); - - if (dir == NAT_INBOUND) { - nat = nat_inlookup(fin, flags, p, oip->ip_dst, - oip->ip_src); - } else { - nat = 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 (dir == NAT_INBOUND) - return nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src); - else - return nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_icmperror */ -/* Returns: nat_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 *nat_icmperror(fin, nflags, dir) -fr_info_t *fin; -u_int *nflags; -int dir; -{ - u_32_t sum1, sum2, sumd, sumd2; - struct in_addr a1, a2; - int flags, dlen, odst; - icmphdr_t *icmp; - u_short *csump; - tcphdr_t *tcp; - nat_t *nat; - ip_t *oip; - void *dp; - - if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) - return NULL; - /* - * nat_icmperrorlookup() will return NULL for `defective' packets. - */ - if ((fin->fin_v != 4) || !(nat = nat_icmperrorlookup(fin, dir))) - return NULL; - - tcp = NULL; - csump = NULL; - flags = 0; - sumd2 = 0; - *nflags = IPN_ICMPERR; - icmp = fin->fin_dp; - oip = (ip_t *)&icmp->icmp_ip; - dp = (((char *)oip) + (IP_HL(oip) << 2)); - if (oip->ip_p == IPPROTO_TCP) { - tcp = (tcphdr_t *)dp; - csump = (u_short *)&tcp->th_sum; - flags = IPN_TCP; - } else if (oip->ip_p == IPPROTO_UDP) { - udphdr_t *udp; - - udp = (udphdr_t *)dp; - tcp = (tcphdr_t *)dp; - csump = (u_short *)&udp->uh_sum; - flags = IPN_UDP; - } else if (oip->ip_p == IPPROTO_ICMP) - 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 fr_checknatout - * 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 oip->ip_sum. However, these - * two changes cancel each other out (if the delta for - * the IP address is x, then the delta for ip_sum is minus x), - * so no change in the icmp_cksum is necessary. - * - * 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)=nat_outip, OIP_DST(b)=nat_oip - * - * 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 - * - * 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 - * - * 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 - * - */ - 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); - oip->ip_src.s_addr = htonl(a1.s_addr); - } else { - a1.s_addr = ntohl(nat->nat_outip.s_addr); - 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); - } - - 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)) { - /* - * 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_inport); - sum2 = ntohs(tcp->th_sport); - - tcp->th_sport = htons(sum1); - } else { - sum1 = ntohs(nat->nat_outport); - sum2 = ntohs(tcp->th_dport); - - tcp->th_dport = htons(sum1); - } - - sumd += sum1 - 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 (oip->ip_p == IPPROTO_UDP) { - if ((dlen >= 8) && (*csump != 0)) { - fix_datacksum(csump, sumd); - } else { - sumd2 = sum1 - sum2; - if (sum2 > sum1) - sumd2--; - } - } else if (oip->ip_p == IPPROTO_TCP) { - if (dlen >= 18) { - fix_datacksum(csump, sumd); - } else { - sumd2 = sum2 - sum1; - if (sum1 > sum2) - sumd2--; - } - } - - 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); - } - } - } - } else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) { - icmphdr_t *orgicmp; - - /* - * XXX - what if this is bogus hl and we go off the end ? - * In this case, nat_icmperrorlookup() will have returned NULL. - */ - orgicmp = (icmphdr_t *)dp; - - if (odst == 1) { - if (orgicmp->icmp_id != nat->nat_inport) { - - /* - * 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->icmp_id with - * a delta (say x) and you compensate that - * in origicmp->icmp_cksum with a delta - * minus x, you don't have to adjust the - * overall icmp->icmp_cksum - */ - sum1 = ntohs(orgicmp->icmp_id); - sum2 = ntohs(nat->nat_inport); - CALC_SUMD(sum1, sum2, sumd); - orgicmp->icmp_id = nat->nat_inport; - fix_datacksum(&orgicmp->icmp_cksum, sumd); - } - } /* nat_dir == NAT_INBOUND is impossible for icmp queries */ - } - return nat; -} - - -/* - * NB: these lookups don't lock access to the list, it assumed that it has - * already been done! - */ - -/* ------------------------------------------------------------------------ */ -/* Function: nat_inlookup */ -/* Returns: nat_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 ipf_nat 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; -{ - u_short sport, dport; - grehdr_t *gre; - ipnat_t *ipn; - u_int sflags; - nat_t *nat; - int nflags; - u_32_t dst; - void *ifp; - u_int hv; - - ifp = fin->fin_ifp; - sport = 0; - dport = 0; - gre = NULL; - dst = mapdst.s_addr; - 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_ICMP : - 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_FN(dst, dport, 0xffffffff); - hv = NAT_HASH_FN(src.s_addr, hv + sport, ipf_nattable_sz); - nat = nat_table[1][hv]; - for (; nat; nat = nat->nat_hnext[1]) { - 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_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]) - 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) - continue; - if (nat->nat_outport != dport) - continue; - break; - default : - break; - } - - ipn = nat->nat_ptr; - if ((ipn != NULL) && (nat->nat_aps != NULL)) - if (appr_match(fin, nat) != 0) - continue; - 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)) - return NULL; - if (nat_stats.ns_wilds == 0) - return NULL; - - RWLOCK_EXIT(&ipf_nat); - - hv = NAT_HASH_FN(dst, 0, 0xffffffff); - hv = NAT_HASH_FN(src.s_addr, hv, ipf_nattable_sz); - - WRITE_ENTER(&ipf_nat); - - nat = nat_table[1][hv]; - 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) - continue; - - nflags = nat->nat_flags; - if (!(nflags & (NAT_TCPUDP|SI_WILDP))) - continue; - - if (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); - if (nat == NULL) - break; - } else { - MUTEX_ENTER(&ipf_nat_new); - nat_stats.ns_wilds--; - MUTEX_EXIT(&ipf_nat_new); - } - nat->nat_oport = sport; - nat->nat_outport = dport; - nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT); - nat_tabmove(nat); - break; - } - } - - MUTEX_DOWNGRADE(&ipf_nat); - - return nat; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_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 nat_tabmove(nat) -nat_t *nat; -{ - nat_t **natp; - u_int hv; - - 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]; - nat_stats.ns_bucketlen[0][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]; - nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--; - - /* - * 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]; - 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]++; - - 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]; - 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]++; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_outlookup */ -/* Returns: nat_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 ipf_nat 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 ipf_nat 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; -{ - 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; - - switch (p) - { - case IPPROTO_TCP : - case IPPROTO_UDP : - sport = htons(fin->fin_data[0]); - dport = htons(fin->fin_data[1]); - break; - case IPPROTO_ICMP : - 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_FN(srcip, sport, 0xffffffff); - hv = NAT_HASH_FN(dst.s_addr, hv + dport, ipf_nattable_sz); - nat = nat_table[0][hv]; - for (; nat; nat = nat->nat_hnext[0]) { - 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_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]) - continue; - break; -#endif - case IPPROTO_TCP : - case IPPROTO_UDP : - if (nat->nat_oport != dport) - continue; - if (nat->nat_inport != sport) - continue; - break; - default : - break; - } - - ipn = nat->nat_ptr; - if ((ipn != NULL) && (nat->nat_aps != NULL)) - if (appr_match(fin, nat) != 0) - continue; - 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)) - return NULL; - if (nat_stats.ns_wilds == 0) - return NULL; - - RWLOCK_EXIT(&ipf_nat); - - hv = NAT_HASH_FN(srcip, 0, 0xffffffff); - hv = NAT_HASH_FN(dst.s_addr, hv, ipf_nattable_sz); - - WRITE_ENTER(&ipf_nat); - - nat = 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)) - continue; - - nflags = nat->nat_flags; - if (!(nflags & (NAT_TCPUDP|SI_WILDP))) - continue; - - if (nat_wildok(nat, (int)sport, (int)dport, nflags, - NAT_OUTBOUND) == 1) { - if ((fin->fin_flx & FI_IGNORE) != 0) - break; - if ((nflags & SI_CLONE) != 0) { - nat = fr_natclone(fin, nat); - if (nat == NULL) - break; - } else { - MUTEX_ENTER(&ipf_nat_new); - nat_stats.ns_wilds--; - MUTEX_EXIT(&ipf_nat_new); - } - 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); - break; - } - } - - MUTEX_DOWNGRADE(&ipf_nat); - - return nat; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: 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 */ -/* 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 *nat_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_ICMP; - - /* - * 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 = 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; - } - } 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, - 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) { - np->nl_flags &= ~IPN_FINDFORWARD; - } - } - - np->nl_realip = nat->nat_outip; - np->nl_realport = nat->nat_outport; - } - } - - return nat; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: 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. */ -/* ------------------------------------------------------------------------ */ -static int nat_match(fin, np) -fr_info_t *fin; -ipnat_t *np; -{ - frtuc_t *ft; - - if (fin->fin_v != 4) - return 0; - - if (np->in_p && fin->fin_p != np->in_p) - return 0; - - if (fin->fin_out) { - if (!(np->in_redir & (NAT_MAP|NAT_MAPBLK))) - return 0; - if (((fin->fin_fi.fi_saddr & np->in_inmsk) != np->in_inip) - ^ ((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; - } - - 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 fr_tcpudpchk(fin, ft); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_update */ -/* Returns: Nil */ -/* Parameters: nat(I) - pointer to NAT structure */ -/* np(I) - pointer to NAT rule */ -/* */ -/* 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(). */ -/* ------------------------------------------------------------------------ */ -void nat_update(fin, nat, np) -fr_info_t *fin; -nat_t *nat; -ipnat_t *np; -{ - ipftq_t *ifq, *ifq2; - ipftqent_t *tqe; - - MUTEX_ENTER(&nat->nat_lock); - tqe = &nat->nat_tqe; - ifq = tqe->tqe_ifq; - - /* - * We allow over-riding of NAT timeouts from NAT rules, even for - * TCP, however, if it is TCP and there is no rule timeout set, - * then do not update the timeout here. - */ - if (np != NULL) - ifq2 = np->in_tqehead[fin->fin_rev]; - 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); - } else { - if (ifq2 == NULL) { - if (nat->nat_p == IPPROTO_UDP) - ifq2 = &nat_udptq; - else if (nat->nat_p == IPPROTO_ICMP) - ifq2 = &nat_icmptq; - else - ifq2 = &nat_iptq; - } - - fr_movequeue(tqe, ifq, ifq2); - } - MUTEX_EXIT(&nat->nat_lock); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_checknatout */ -/* 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 fr_checknatout(fin, passp) -fr_info_t *fin; -u_32_t *passp; -{ - struct ifnet *ifp, *sifp; - 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) - return 0; - - natfailed = 0; - fr = fin->fin_fr; - sifp = fin->fin_ifp; - if (fr != NULL) { - ifp = fr->fr_tifs[fin->fin_rev].fd_ifp; - 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_ICMP : - icmp = fin->fin_dp; - - /* - * This is an incoming packet, so the destination is - * the icmp_id and the source port equals 0 - */ - if (nat_icmpquerytype4(icmp->icmp_type)) - nflags = IPN_ICMPQUERY; - break; - default : - break; - } - - if ((nflags & IPN_TCPUDP)) - tcp = fin->fin_dp; - } - - ipa = fin->fin_saddr; - - READ_ENTER(&ipf_nat); - - if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && - (nat = nat_icmperror(fin, &nflags, NAT_OUTBOUND))) - /*EMPTY*/; - else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) - natadd = 0; - else if ((nat = 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; - - /* - * 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) - { - if ((np->in_ifps[1] && (np->in_ifps[1] != ifp))) - continue; - if (np->in_v != fin->fin_v) - continue; - if (np->in_p && (np->in_p != 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)) - continue; - } else if ((ipa & np->in_inmsk) != np->in_inip) - continue; - - if ((fr != NULL) && - !fr_matchtag(&np->in_tag, &fr->fr_nattag)) - continue; - - if (*np->in_plabel != '\0') { - if (((np->in_flags & IPN_FILTER) == 0) && - (np->in_dport != tcp->th_dport)) - continue; - if (appr_ok(fin, tcp, np) == 0) - continue; - } - - if ((nat = nat_new(fin, np, NULL, nflags, - NAT_OUTBOUND))) { - 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_DOWNGRADE(&ipf_nat); - } - - if (nat != NULL) { - rval = fr_natout(fin, nat, natadd, nflags); - if (rval == 1) { - MUTEX_ENTER(&nat->nat_lock); - nat->nat_ref++; - MUTEX_EXIT(&nat->nat_lock); - nat->nat_touched = fr_ticks; - fin->fin_nat = nat; - } - } else - rval = natfailed; - RWLOCK_EXIT(&ipf_nat); - - if (rval == -1) { - if (passp != NULL) - *passp = FR_BLOCK; - fin->fin_flx |= FI_BADNAT; - } - fin->fin_ifp = sifp; - return rval; -} - -/* ------------------------------------------------------------------------ */ -/* Function: fr_natout */ -/* 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. */ -/* ------------------------------------------------------------------------ */ -int fr_natout(fin, nat, natadd, nflags) -fr_info_t *fin; -nat_t *nat; -int natadd; -u_32_t nflags; -{ - icmphdr_t *icmp; - u_short *csump; - tcphdr_t *tcp; - ipnat_t *np; - 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); - - /* - * Fix up checksums, not by recalculating them, but - * simply computing adjustments. - * This is only done for STREAMS based IP implementations where the - * checksum has already been calculated by IP. In all other cases, - * 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; - - 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); - } -#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); - } -#endif - } - - if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { - if ((nat->nat_outport != 0) && (nflags & IPN_TCPUDP)) { - tcp = fin->fin_dp; - - tcp->th_sport = nat->nat_outport; - fin->fin_data[0] = ntohs(nat->nat_outport); - } - - if ((nat->nat_outport != 0) && (nflags & IPN_ICMPQUERY)) { - icmp = fin->fin_dp; - icmp->icmp_id = nat->nat_outport; - } - - csump = nat_proto(fin, nat, nflags); - } - - fin->fin_ip->ip_src = nat->nat_outip; - - nat_update(fin, nat, np); - - /* - * 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]); - } -#ifdef IPFILTER_SYNC - ipfsync_update(SMC_NAT, fin, nat->nat_sync); -#endif - /* ------------------------------------------------------------- */ - /* 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. */ - /* ------------------------------------------------------------- */ - if ((np != NULL) && (np->in_apr != NULL)) { - i = appr_check(fin, nat); - if (i == 0) - i = 1; - } else - i = 1; - ATOMIC_INCL(nat_stats.ns_mapped[1]); - fin->fin_flx |= FI_NATED; - return i; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_checknatin */ -/* 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 fr_checknatin(fin, passp) -fr_info_t *fin; -u_32_t *passp; -{ - u_int nflags, natadd; - 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) - return 0; - - tcp = NULL; - icmp = 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_ICMP : - icmp = fin->fin_dp; - - /* - * This is an incoming packet, so the destination is - * the icmp_id and the source port equals 0 - */ - if (nat_icmpquerytype4(icmp->icmp_type)) { - nflags = IPN_ICMPQUERY; - dport = icmp->icmp_id; - } break; - default : - break; - } - - if ((nflags & IPN_TCPUDP)) { - tcp = fin->fin_dp; - dport = tcp->th_dport; - } - } - - in = fin->fin_dst; - - READ_ENTER(&ipf_nat); - - if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) && - (nat = nat_icmperror(fin, &nflags, NAT_INBOUND))) - /*EMPTY*/; - else if ((fin->fin_flx & FI_FRAG) && (nat = fr_nat_knownfrag(fin))) - natadd = 0; - else if ((nat = 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; - - 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) { - if (np->in_ifps[0] && (np->in_ifps[0] != ifp)) - continue; - if (np->in_v != fin->fin_v) - continue; - if (np->in_p && (np->in_p != 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)) - continue; - } else { - if ((in.s_addr & np->in_outmsk) != np->in_outip) - continue; - if (np->in_pmin && - ((ntohs(np->in_pmax) < ntohs(dport)) || - (ntohs(dport) < ntohs(np->in_pmin)))) - continue; - } - - if (*np->in_plabel != '\0') { - if (!appr_ok(fin, tcp, np)) { - continue; - } - } - - nat = nat_new(fin, np, NULL, nflags, NAT_INBOUND); - if (nat != NULL) { - np->in_hits++; - break; - } else - natfailed = -1; - } - - if ((np == NULL) && (rmsk != 0)) { - while (rmsk) { - msk <<= 1; - if (rmsk & 0x80000000) - break; - rmsk <<= 1; - } - if (rmsk != 0) { - rmsk <<= 1; - goto maskloop; - } - } - MUTEX_DOWNGRADE(&ipf_nat); - } - if (nat != NULL) { - rval = fr_natin(fin, nat, natadd, nflags); - if (rval == 1) { - MUTEX_ENTER(&nat->nat_lock); - nat->nat_ref++; - MUTEX_EXIT(&nat->nat_lock); - nat->nat_touched = fr_ticks; - fin->fin_nat = nat; - } - } else - rval = natfailed; - RWLOCK_EXIT(&ipf_nat); - - if (rval == -1) { - if (passp != NULL) - *passp = FR_BLOCK; - fin->fin_flx |= FI_BADNAT; - } - return rval; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_natin */ -/* 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) */ -/* */ -/* 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; -{ - icmphdr_t *icmp; - u_short *csump; - tcphdr_t *tcp; - ipnat_t *np; - 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); - - /* ------------------------------------------------------------- */ - /* 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. */ - /* ------------------------------------------------------------- */ - if (np->in_apr != NULL) { - i = appr_check(fin, nat); - if (i == -1) { - 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; - - /* - * 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. - */ -#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); -#endif - - 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); - } - - - if ((nat->nat_inport != 0) && (nflags & IPN_ICMPQUERY)) { - icmp = fin->fin_dp; - - icmp->icmp_id = nat->nat_inport; - } - - csump = nat_proto(fin, nat, nflags); - } - - nat_update(fin, nat, np); - - /* - * 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]); - } - 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; - return 1; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: 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. */ -/* Parameters: fin(I) - pointer to packet information */ -/* nat(I) - pointer to NAT structure */ -/* nflags(I) - NAT flags set for this packet */ -/* */ -/* Return the pointer to the checksum field for each protocol so understood.*/ -/* If support for making other changes to a protocol header is required, */ -/* 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; -{ - icmphdr_t *icmp; - u_short *csump; - tcphdr_t *tcp; - udphdr_t *udp; - - csump = NULL; - if (fin->fin_out == 0) { - fin->fin_rev = (nat->nat_dir == NAT_OUTBOUND); - } else { - fin->fin_rev = (nat->nat_dir == NAT_INBOUND); - } - - switch (fin->fin_p) - { - case IPPROTO_TCP : - tcp = fin->fin_dp; - - 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); - - break; - - case IPPROTO_UDP : - udp = fin->fin_dp; - - if (udp->uh_sum) - csump = &udp->uh_sum; - break; - - case IPPROTO_ICMP : - icmp = fin->fin_dp; - - if ((nflags & IPN_ICMPQUERY) != 0) { - if (icmp->icmp_cksum != 0) - 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); - - MUTEX_DESTROY(&ipf_nat_new); - MUTEX_DESTROY(&ipf_natio); - - MUTEX_DESTROY(&nat_udptq.ifq_lock); - MUTEX_DESTROY(&nat_icmptq.ifq_lock); - MUTEX_DESTROY(&nat_iptq.ifq_lock); - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_natexpire */ -/* Returns: Nil */ -/* Parameters: Nil */ -/* */ -/* Check all of the timeout queues for entries at the top which need to be */ -/* expired. */ -/* ------------------------------------------------------------------------ */ -void fr_natexpire() -{ - 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) { - for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { - if (tqe->tqe_die > fr_ticks) - break; - tqn = tqe->tqe_next; - nat_delete(tqe->tqe_parent, NL_EXPIRE); - } - } - - for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) { - ifqnext = ifq->ifq_next; - - for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) { - if (tqe->tqe_die > fr_ticks) - break; - tqn = tqe->tqe_next; - nat_delete(tqe->tqe_parent, NL_EXPIRE); - } - } - - for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) { - ifqnext = ifq->ifq_next; - - if (((ifq->ifq_flags & IFQF_DELETE) != 0) && - (ifq->ifq_ref == 0)) { - fr_freetimeoutqueue(ifq); - } - } - - if (fr_nat_doflush != 0) { - nat_extraflush(2); - fr_nat_doflush = 0; - } - - RWLOCK_EXIT(&ipf_nat); - SPL_X(s); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_natsync */ -/* Returns: Nil */ -/* Parameters: 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; -{ - u_32_t sum1, sum2, sumd; - struct in_addr in; - ipnat_t *n; - nat_t *nat; - void *ifp2; - SPL_INT(s); - - if (fr_running <= 0) - return; - - /* - * Change IP addresses for NAT sessions for any protocol except TCP - * since it will break the TCP connection anyway. The only rules - * which will get changed are those which are "map ... -> 0/32", - * where the rule specifies the address is taken from the interface. - */ - SPL_NET(s); - WRITE_ENTER(&ipf_nat); - - if (fr_running <= 0) { - RWLOCK_EXIT(&ipf_nat); - return; - } - - for (nat = 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 (((ifp == NULL) || (ifp == nat->nat_ifps[0]) || - (ifp == nat->nat_ifps[1]))) { - nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0], 4); - if (nat->nat_ifnames[1][0] != '\0') { - nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1], - 4); - } else - nat->nat_ifps[1] = nat->nat_ifps[0]; - ifp2 = nat->nat_ifps[0]; - if (ifp2 == NULL) - continue; - - /* - * 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; - - if (sum1 == sum2) - continue; - /* - * Readjust the checksum adjustment to take into - * account the new IP#. - */ - CALC_SUMD(sum1, sum2, sumd); - /* XXX - dont change for TCP when solaris does - * hardware checksumming. - */ - sumd += nat->nat_sumd[0]; - nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); - nat->nat_sumd[1] = nat->nat_sumd[0]; - } - } - - for (n = nat_list; (n != NULL); n = n->in_next) { - if ((ifp == NULL) || (n->in_ifps[0] == ifp)) - n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], 4); - if ((ifp == NULL) || (n->in_ifps[1] == ifp)) - n->in_ifps[1] = fr_resolvenic(n->in_ifnames[1], 4); - } - RWLOCK_EXIT(&ipf_nat); - SPL_X(s); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_icmpquerytype4 */ -/* 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; -{ - - /* - * 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 ICMP_ECHOREPLY: - case ICMP_ECHO: - /* route aedvertisement/solliciation is currently unsupported: */ - /* it would require rewriting the ICMP data section */ - case ICMP_TSTAMP: - case ICMP_TSTAMPREPLY: - case ICMP_IREQ: - case ICMP_IREQREPLY: - case ICMP_MASKREQ: - case ICMP_MASKREPLY: - return 1; - default: - return 0; - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_log */ -/* Returns: Nil */ -/* Parameters: nat(I) - pointer to NAT structure */ -/* type(I) - type of log entry to create */ -/* */ -/* Creates a NAT log entry. */ -/* ------------------------------------------------------------------------ */ -void nat_log(nat, type) -struct nat *nat; -u_int type; -{ -#ifdef IPFILTER_LOG -# ifndef LARGE_NAT - struct ipnat *np; - int rulen; -# endif - struct natlog natl; - void *items[1]; - 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; - 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_rule = -1; -# ifndef LARGE_NAT - if (nat->nat_ptr != NULL) { - for (rulen = 0, np = nat_list; np; np = np->in_next, rulen++) - if (np == nat->nat_ptr) { - natl.nl_rule = rulen; - break; - } - } -# endif - items[0] = &natl; - sizes[0] = sizeof(natl); - types[0] = 0; - - (void) ipllog(IPL_LOGNAT, NULL, items, sizes, types, 1); -#endif -} - - -#if defined(__OpenBSD__) -/* ------------------------------------------------------------------------ */ -/* Function: 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; -{ - frsync(ifp); - return; -} -#endif - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_ipnatderef */ -/* Returns: Nil */ -/* Parameters: isp(I) - pointer to pointer to NAT rule */ -/* Write Locks: ipf_nat */ -/* */ -/* ------------------------------------------------------------------------ */ -void fr_ipnatderef(inp) -ipnat_t **inp; -{ - ipnat_t *in; - - in = *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 - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_natderef */ -/* Returns: Nil */ -/* Parameters: isp(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. */ -/* */ -/* IF nat_ref == 1 when this function is called, then we have an orphan nat */ -/* structure *because* it only gets called on paths _after_ nat_ref has been*/ -/* incremented. If nat_ref == 1 then we shouldn't decrement it here */ -/* because nat_delete() will do that and send nat_ref to -1. */ -/* */ -/* 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; -{ - nat_t *nat; - - nat = *natp; - *natp = NULL; - - MUTEX_ENTER(&nat->nat_lock); - if (nat->nat_ref > 1) { - nat->nat_ref--; - MUTEX_EXIT(&nat->nat_lock); - return; - } - MUTEX_EXIT(&nat->nat_lock); - - WRITE_ENTER(&ipf_nat); - nat_delete(nat, NL_EXPIRE); - RWLOCK_EXIT(&ipf_nat); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_natclone */ -/* Returns: ipstate_t* - NULL == cloning failed, */ -/* else pointer to new state structure */ -/* Parameters: fin(I) - pointer to packet information */ -/* is(I) - pointer to master state structure */ -/* Write Lock: ipf_nat */ -/* */ -/* Create a "duplcate" state table entry from the master. */ -/* ------------------------------------------------------------------------ */ -static nat_t *fr_natclone(fin, nat) -fr_info_t *fin; -nat_t *nat; -{ - frentry_t *fr; - nat_t *clone; - ipnat_t *np; - - KMALLOC(clone, nat_t *); - if (clone == NULL) - return NULL; - bcopy((char *)nat, (char *)clone, sizeof(*clone)); - - MUTEX_NUKE(&clone->nat_lock); - - clone->nat_aps = NULL; - /* - * Initialize all these so that nat_delete() doesn't cause a crash. - */ - clone->nat_tqe.tqe_pnext = NULL; - clone->nat_tqe.tqe_next = NULL; - clone->nat_tqe.tqe_ifq = NULL; - clone->nat_tqe.tqe_parent = clone; - - clone->nat_flags &= ~SI_CLONE; - clone->nat_flags |= SI_CLONED; - - if (clone->nat_hm) - clone->nat_hm->hm_ref++; - - if (nat_insert(clone, fin->fin_rev) == -1) { - KFREE(clone); - return NULL; - } - np = clone->nat_ptr; - if (np != NULL) { - if (nat_logging) - nat_log(clone, (u_int)np->in_redir); - np->in_use++; - } - fr = clone->nat_fr; - if (fr != NULL) { - MUTEX_ENTER(&fr->fr_lock); - fr->fr_ref++; - 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); - } -#ifdef IPFILTER_SYNC - clone->nat_sync = ipfsync_new(SMC_NAT, fin, clone); -#endif - if (nat_logging) - nat_log(clone, NL_CLONE); - return clone; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_wildok */ -/* Returns: int - 1 == packet's ports match wildcards */ -/* 0 == packet's ports don't match wildcards */ -/* Parameters: nat(I) - NAT entry */ -/* sport(I) - source port */ -/* dport(I) - destination port */ -/* flags(I) - wildcard flags */ -/* dir(I) - packet direction */ -/* */ -/* 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; -{ - /* - * When called by dir is set to - * nat_inlookup NAT_INBOUND (0) - * nat_outlookup NAT_OUTBOUND (1) - * - * We simply combine the packet's direction in dir with the original - * "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) - { - case 3: /* outbound packet / outbound entry */ - if (((nat->nat_inport == sport) || - (flags & SI_W_SPORT)) && - ((nat->nat_oport == 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))) - 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))) - return 1; - break; - case 0: /* inbound packet / inbound entry */ - if (((nat->nat_oport == sport) || - (flags & SI_W_SPORT)) && - ((nat->nat_outport == dport) || - (flags & SI_W_DPORT))) - return 1; - break; - default: - break; - } - - return(0); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_mssclamp */ -/* Returns: Nil */ -/* Parameters: tcp(I) - pointer to TCP header */ -/* maxmss(I) - value to clamp the TCP MSS to */ -/* fin(I) - pointer to packet information */ -/* csump(I) - pointer to TCP checksum */ -/* */ -/* Check for MSS option and clamp it if necessary. If found and changed, */ -/* 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; -{ - u_char *cp, *ep, opt; - int hlen, advance; - u_32_t mss, sumd; - - hlen = TCP_OFF(tcp) << 2; - if (hlen > sizeof(*tcp)) { - cp = (u_char *)tcp + sizeof(*tcp); - ep = (u_char *)tcp + hlen; - - while (cp < ep) { - opt = cp[0]; - if (opt == TCPOPT_EOL) - break; - else if (opt == TCPOPT_NOP) { - cp++; - continue; - } - - if (cp + 1 >= ep) - break; - advance = cp[1]; - if ((cp + advance > ep) || (advance <= 0)) - break; - switch (opt) - { - case TCPOPT_MAXSEG: - if (advance != 4) - break; - mss = cp[2] * 256 + cp[3]; - if (mss > maxmss) { - cp[2] = maxmss / 256; - cp[3] = maxmss & 0xff; - CALC_SUMD(mss, maxmss, sumd); - fix_outcksum(fin, csump, sumd); - } - break; - default: - /* ignore unknown options */ - break; - } - - cp += advance; - } - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_setnatqueue */ -/* Returns: Nil */ -/* Parameters: nat(I)- pointer to NAT structure */ -/* rev(I) - forward(0) or reverse(1) direction */ -/* 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; -{ - ipftq_t *oifq, *nifq; - - if (nat->nat_ptr != NULL) - nifq = nat->nat_ptr->in_tqehead[rev]; - else - nifq = NULL; - - if (nifq == NULL) { - switch (nat->nat_p) - { - case IPPROTO_UDP : - nifq = &nat_udptq; - break; - case IPPROTO_ICMP : - nifq = &nat_icmptq; - break; - case IPPROTO_TCP : - nifq = nat_tqb + nat->nat_tqe.tqe_state[rev]; - break; - default : - nifq = &nat_iptq; - break; - } - } - - oifq = nat->nat_tqe.tqe_ifq; - /* - * If it's currently on a timeout queue, move it from one queue to - * another, else put it on the end of the newly determined queue. - */ - if (oifq != NULL) - fr_movequeue(&nat->nat_tqe, oifq, nifq); - else - fr_queueappend(&nat->nat_tqe, nifq, nat); - return; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_getnext */ -/* Returns: int - 0 == ok, else error */ -/* Parameters: 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; -{ - hostmap_t *hm, *nexthm = NULL, zerohm; - ipnat_t *ipn, *nextipnat = NULL, zeroipn; - nat_t *nat, *nextnat = NULL, zeronat; - int error = 0, count; - char *dst; - - count = itp->igi_nitems; - if (count < 1) - return ENOSPC; - - READ_ENTER(&ipf_nat); - - switch (itp->igi_type) - { - case IPFGENITER_HOSTMAP : - hm = t->ipt_data; - if (hm == NULL) { - nexthm = ipf_hm_maplist; - } else { - nexthm = hm->hm_next; - } - break; - - case IPFGENITER_IPNAT : - ipn = t->ipt_data; - if (ipn == NULL) { - nextipnat = nat_list; - } else { - nextipnat = ipn->in_next; - } - break; - - case IPFGENITER_NAT : - nat = t->ipt_data; - if (nat == NULL) { - nextnat = nat_instances; - } else { - nextnat = nat->nat_next; - } - break; - default : - RWLOCK_EXIT(&ipf_nat); - 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; - } - } - - - switch (itp->igi_type) - { - case IPFGENITER_HOSTMAP : - if (hm != NULL) { - WRITE_ENTER(&ipf_nat); - fr_hostmapdel(&hm); - RWLOCK_EXIT(&ipf_nat); - } - break; - case IPFGENITER_IPNAT : - if (ipn != NULL) { - fr_ipnatderef(&ipn); - } - break; - case IPFGENITER_NAT : - if (nat != NULL) { - fr_natderef(&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; - - 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; - } - - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_extraflush */ -/* Returns: int - 0 == success, -1 == failure */ -/* Parameters: which(I) - how to flush the active NAT table */ -/* Write Locks: ipf_nat */ -/* */ -/* Flush nat tables. Three actions currently defined: */ -/* which == 0 : flush all nat table entries */ -/* which == 1 : flush TCP connections which have started to close but are */ -/* stuck for some reason. */ -/* which == 2 : flush TCP connections which have been idle for a long time, */ -/* starting at > 4 days idle and working back in successive half-*/ -/* days to at most 12 hours old. If this fails to free enough */ -/* slots then work backwards in half hour slots to 30 minutes. */ -/* 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; -{ - ipftq_t *ifq, *ifqnext; - nat_t *nat, **natp; - ipftqent_t *tqn; - int removed; - SPL_INT(s); - - removed = 0; - - SPL_NET(s); - - switch (which) - { - case 0 : - /* - * Style 0 flush removes everything... - */ - for (natp = &nat_instances; ((nat = *natp) != NULL); ) { - nat_delete(nat, NL_FLUSH); - removed++; - } - break; - - case 1 : - /* - * 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 (tqn = ifq->ifq_head; tqn != NULL; ) { - nat = tqn->tqe_parent; - tqn = tqn->tqe_next; - if (nat->nat_p != IPPROTO_TCP) - break; - nat_delete(nat, NL_EXPIRE); - removed++; - } - } - - /* - * Also need to look through the user defined queues. - */ - for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) { - ifqnext = ifq->ifq_next; - for (tqn = ifq->ifq_head; tqn != NULL; ) { - nat = tqn->tqe_parent; - tqn = tqn->tqe_next; - if (nat->nat_p != IPPROTO_TCP) - continue; - - if ((nat->nat_tcpstate[0] > - IPF_TCPS_ESTABLISHED) && - (nat->nat_tcpstate[1] > - IPF_TCPS_ESTABLISHED)) { - nat_delete(nat, NL_EXPIRE); - removed++; - } - } - } - break; - - /* - * Args 5-11 correspond to flushing those particular states - * for TCP connections. - */ - case IPF_TCPS_CLOSE_WAIT : - case IPF_TCPS_FIN_WAIT_1 : - case IPF_TCPS_CLOSING : - case IPF_TCPS_LAST_ACK : - case IPF_TCPS_FIN_WAIT_2 : - case IPF_TCPS_TIME_WAIT : - case IPF_TCPS_CLOSED : - tqn = nat_tqb[which].ifq_head; - while (tqn != NULL) { - nat = tqn->tqe_parent; - tqn = tqn->tqe_next; - nat_delete(nat, NL_FLUSH); - removed++; - } - break; - - default : - if (which < 30) - break; - - /* - * 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); - removed++; - } else - natp = &nat->nat_next; - } - break; - } - - if (which != 2) { - SPL_X(s); - return removed; - } - - /* - * Asked to remove inactive entries because the table is full. - */ - 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); - } - - SPL_X(s); - return removed; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_flush_entry */ -/* Returns: 0 - always succeeds */ -/* Parameters: entry(I) - pointer to NAT entry */ -/* Write Locks: ipf_nat */ -/* */ -/* This function is a stepping stone between ipf_queueflush() and */ -/* nat_dlete(). It is used so we can provide a uniform interface via the */ -/* 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; -{ - nat_delete(entry, NL_FLUSH); - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: nat_gettable */ -/* Returns: int - 0 = success, else error */ -/* Parameters: 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; -{ - ipftable_t table; - int error; - - error = fr_inobj(data, &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)); - break; - - case IPFTABLE_BUCKETS_NATOUT : - error = COPYOUT(nat_stats.ns_bucketlen[1], table.ita_table, - ipf_nattable_sz * sizeof(u_long)); - break; - - default : - return EINVAL; - } - - if (error != 0) { - error = EFAULT; - } - return error; -} diff --git a/sys/contrib/ipfilter/netinet/ip_nat.h b/sys/contrib/ipfilter/netinet/ip_nat.h deleted file mode 100644 index f25c0d8..0000000 --- a/sys/contrib/ipfilter/netinet/ip_nat.h +++ /dev/null @@ -1,469 +0,0 @@ -/* - * Copyright (C) 1995-2001, 2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * @(#)ip_nat.h 1.5 2/4/96 - * $Id: ip_nat.h,v 2.90.2.20 2007/09/25 08:27:32 darrenr Exp $ - */ - -#ifndef __IP_NAT_H__ -#define __IP_NAT_H__ - -#ifndef SOLARIS -#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) -#endif - -#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51) -#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) -#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) -#endif - -#undef LARGE_NAT /* define this if you're setting up a system to NAT - * LARGE numbers of networks/hosts - i.e. in the - * hundreds or thousands. In such a case, you should - * also change the RDR_SIZE and NAT_SIZE below to more - * appropriate sizes. The figures below were used for - * a setup with 1000-2000 networks to NAT. - */ -#ifndef NAT_SIZE -# ifdef LARGE_NAT -# define NAT_SIZE 2047 -# else -# define NAT_SIZE 127 -# endif -#endif -#ifndef RDR_SIZE -# ifdef LARGE_NAT -# define RDR_SIZE 2047 -# else -# define RDR_SIZE 127 -# endif -#endif -#ifndef HOSTMAP_SIZE -# ifdef LARGE_NAT -# define HOSTMAP_SIZE 8191 -# else -# define HOSTMAP_SIZE 2047 -# endif -#endif -#ifndef NAT_TABLE_MAX -/* - * This is newly introduced and for the sake of "least surprise", the numbers - * present aren't what we'd normally use for creating a proper hash table. - */ -# ifdef LARGE_NAT -# define NAT_TABLE_MAX 180000 -# else -# define NAT_TABLE_MAX 30000 -# endif -#endif -#ifndef NAT_TABLE_SZ -# ifdef LARGE_NAT -# define NAT_TABLE_SZ 16383 -# else -# define NAT_TABLE_SZ 2047 -# endif -#endif -#ifndef APR_LABELLEN -#define APR_LABELLEN 16 -#endif -#define NAT_HW_CKSUM 0x80000000 - -#define DEF_NAT_AGE 1200 /* 10 minutes (600 seconds) */ - -struct ipstate; -struct ap_session; - -typedef struct nat { - ipfmutex_t nat_lock; - struct nat *nat_next; - struct nat **nat_pnext; - struct nat *nat_hnext[2]; - struct nat **nat_phnext[2]; - struct hostmap *nat_hm; - void *nat_data; - struct nat **nat_me; - struct ipstate *nat_state; - struct ap_session *nat_aps; /* proxy session */ - frentry_t *nat_fr; /* filter rule ptr if appropriate */ - struct ipnat *nat_ptr; /* pointer back to the rule */ - void *nat_ifps[2]; - void *nat_sync; - ipftqent_t nat_tqe; - 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 */ - U_QUAD_T nat_pkts[2]; - U_QUAD_T nat_bytes[2]; - union { - udpinfo_t nat_unu; - 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 */ - int nat_dir; - int nat_ref; /* reference count */ - 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]; -} nat_t; - -#define nat_inip nat_inip6.in4 -#define nat_outip nat_outip6.in4 -#define nat_oip nat_oip6.in4 -#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_tcpstate nat_tqe.tqe_state -#define nat_die nat_tqe.tqe_die -#define nat_touched nat_tqe.tqe_touched - -/* - * Values for nat_dir - */ -#define NAT_INBOUND 0 -#define NAT_OUTBOUND 1 - -/* - * Definitions for nat_flags - */ -#define NAT_TCP 0x0001 /* IPN_TCP */ -#define NAT_UDP 0x0002 /* IPN_UDP */ -#define NAT_ICMPERR 0x0004 /* IPN_ICMPERR */ -#define NAT_ICMPQUERY 0x0008 /* IPN_ICMPQUERY */ -#define NAT_SEARCH 0x0010 -#define NAT_SLAVE 0x0020 /* Slave connection for a proxy */ -#define NAT_NOTRULEPORT 0x0040 /* Don't use the port # in the NAT rule */ - -#define NAT_TCPUDP (NAT_TCP|NAT_UDP) -#define NAT_TCPUDPICMP (NAT_TCP|NAT_UDP|NAT_ICMPERR) -#define NAT_TCPUDPICMPQ (NAT_TCP|NAT_UDP|NAT_ICMPQUERY) -#define NAT_FROMRULE (NAT_TCP|NAT_UDP) - -/* 0x0100 reserved for FI_W_SPORT */ -/* 0x0200 reserved for FI_W_DPORT */ -/* 0x0400 reserved for FI_W_SADDR */ -/* 0x0800 reserved for FI_W_DADDR */ -/* 0x1000 reserved for FI_W_NEWFR */ -/* 0x2000 reserved for SI_CLONE */ -/* 0x4000 reserved for SI_CLONED */ -/* 0x8000 reserved for SI_IGNOREPKT */ - -#define NAT_DEBUG 0x800000 - -typedef struct ipnat { - ipfmutex_t in_lock; - struct ipnat *in_next; /* NAT rule list next */ - struct ipnat *in_rnext; /* rdr rule hash next */ - struct ipnat **in_prnext; /* prior rdr next ptr */ - struct ipnat *in_mnext; /* map rule hash next */ - struct ipnat **in_pmnext; /* prior map next ptr */ - struct ipftq *in_tqehead[2]; - void *in_ifps[2]; - void *in_apr; - char *in_comment; - i6addr_t in_next6; - u_long in_space; - u_long in_hits; - u_int in_use; - u_int in_hv; - int in_flineno; /* conf. file line number */ - u_short in_pnext; - u_char in_v; - u_char in_xxx; - /* From here to the end is covered by IPN_CMPSIZ */ - 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]; - 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. */ - ipftag_t in_tag; -} 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 -#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 - -/* - * Bit definitions for in_flags - */ -#define IPN_ANY 0x00000 -#define IPN_TCP 0x00001 -#define IPN_UDP 0x00002 -#define IPN_TCPUDP (IPN_TCP|IPN_UDP) -#define IPN_ICMPERR 0x00004 -#define IPN_TCPUDPICMP (IPN_TCP|IPN_UDP|IPN_ICMPERR) -#define IPN_ICMPQUERY 0x00008 -#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_USERFLAGS (IPN_TCPUDP|IPN_AUTOPORTMAP|IPN_IPRANGE|IPN_SPLIT|\ - IPN_ROUNDR|IPN_FILTER|IPN_NOTSRC|IPN_NOTDST|\ - IPN_FRAG|IPN_STICKY|IPN_FIXEDDPORT|IPN_ICMPQUERY) - -/* - * Values for in_redir - */ -#define NAT_MAP 0x01 -#define NAT_REDIRECT 0x02 -#define NAT_BIMAP (NAT_MAP|NAT_REDIRECT) -#define NAT_MAPBLK 0x04 - -#define MAPBLK_MINPORT 1024 /* don't use reserved ports for src port */ -#define USABLE_PORTS (65536 - MAPBLK_MINPORT) - -#define IPN_CMPSIZ (sizeof(ipnat_t) - offsetof(ipnat_t, in_flags)) - -typedef struct natlookup { - struct in_addr nl_inip; - struct in_addr nl_outip; - struct in_addr nl_realip; - int nl_flags; - u_short nl_inport; - u_short nl_outport; - u_short nl_realport; -} natlookup_t; - - -typedef struct nat_save { - void *ipn_next; - struct nat ipn_nat; - struct ipnat ipn_ipnat; - struct frentry ipn_fr; - int ipn_dsize; - char ipn_data[4]; -} nat_save_t; - -#define ipn_rule ipn_nat.nat_fr - -typedef struct natget { - void *ng_ptr; - int ng_sz; -} natget_t; - - -/* - * This structure gets used to help NAT sessions keep the same NAT rule (and - * thus translation for IP address) when: - * (a) round-robin redirects are in use - * (b) different IP add - */ -typedef struct hostmap { - struct hostmap *hm_hnext; - struct hostmap **hm_phnext; - 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; - u_32_t hm_port; - int hm_ref; -} hostmap_t; - - -/* - * Structure used to pass information in to nat_newmap and nat_newrdr. - */ -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; - u_short nai_port; - u_short nai_nport; - u_short nai_sport; - u_short nai_dport; -} natinfo_t; - - -typedef struct natstat { - u_long ns_mapped[2]; - u_long ns_rules; - u_long ns_added; - u_long ns_expire; - u_long ns_inuse; - u_long ns_logged; - u_long ns_logfail; - 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; -} 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; - U_QUAD_T nl_pkts[2]; - U_QUAD_T nl_bytes[2]; - u_char nl_p; -} 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_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 CALC_SUMD(s1, s2, sd) { \ - (s1) = ((s1) & 0xffff) + ((s1) >> 16); \ - (s2) = ((s2) & 0xffff) + ((s2) >> 16); \ - /* Do it twice */ \ - (s1) = ((s1) & 0xffff) + ((s1) >> 16); \ - (s2) = ((s2) & 0xffff) + ((s2) >> 16); \ - /* Because ~1 == -2, We really need ~1 == -1 */ \ - if ((s1) > (s2)) (s2)--; \ - (sd) = (s2) - (s1); \ - (sd) = ((sd) & 0xffff) + ((sd) >> 16); } - -#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; - -#if defined(__OpenBSD__) -extern void 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, - 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 **)); - -#endif /* __IP_NAT_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_netbios_pxy.c b/sys/contrib/ipfilter/netinet/ip_netbios_pxy.c deleted file mode 100644 index 1a0b2a2..0000000 --- a/sys/contrib/ipfilter/netinet/ip_netbios_pxy.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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 $ - */ - -/*- - * Copyright (c) 2002-2003 Paul J. Ledbetter III - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: ip_netbios_pxy.c,v 2.8.2.1 2005/08/20 13:48:23 darrenr Exp $ - */ - -#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 *)); - -static frentry_t netbiosfr; - -int netbios_proxy_init = 0; - -/* - * Initialize local structures. - */ -int ippr_netbios_init() -{ - bzero((char *)&netbiosfr, sizeof(netbiosfr)); - netbiosfr.fr_ref = 1; - netbiosfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; - MUTEX_INIT(&netbiosfr.fr_lock, "NETBIOS proxy rule lock"); - netbios_proxy_init = 1; - - return 0; -} - - -void ippr_netbios_fini() -{ - if (netbios_proxy_init == 1) { - MUTEX_DESTROY(&netbiosfr.fr_lock); - netbios_proxy_init = 0; - } -} - - -int ippr_netbios_out(fin, aps, nat) -fr_info_t *fin; -ap_session_t *aps; -nat_t *nat; -{ - char dgmbuf[6]; - int off, dlen; - udphdr_t *udp; - ip_t *ip; - mb_t *m; - - aps = aps; /* LINT */ - nat = nat; /* LINT */ - - m = fin->fin_m; - dlen = fin->fin_dlen - sizeof(*udp); - /* - * no net bios datagram could possibly be shorter than this - */ - if (dlen < 11) - return 0; - - ip = fin->fin_ip; - udp = (udphdr_t *)fin->fin_dp; - off = (char *)udp - (char *)ip + sizeof(*udp) + fin->fin_ipoff; - - /* - * move past the - * ip header; - * udp header; - * 4 bytes into the net bios dgm header. - * According to rfc1002, this should be the exact location of - * the source address/port - */ - off += 4; - - /* Copy NATed source Address/port*/ - dgmbuf[0] = (char)((ip->ip_src.s_addr ) &0xFF); - dgmbuf[1] = (char)((ip->ip_src.s_addr >> 8) &0xFF); - dgmbuf[2] = (char)((ip->ip_src.s_addr >> 16)&0xFF); - dgmbuf[3] = (char)((ip->ip_src.s_addr >> 24)&0xFF); - - dgmbuf[4] = (char)((udp->uh_sport )&0xFF); - dgmbuf[5] = (char)((udp->uh_sport >> 8)&0xFF); - - /* replace data in packet */ - COPYBACK(m, off, sizeof(dgmbuf), dgmbuf); - - return 0; -} diff --git a/sys/contrib/ipfilter/netinet/ip_pool.c b/sys/contrib/ipfilter/netinet/ip_pool.c deleted file mode 100644 index eab3310..0000000 --- a/sys/contrib/ipfilter/netinet/ip_pool.c +++ /dev/null @@ -1,992 +0,0 @@ -/* - * Copyright (C) 1993-2001, 2003 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 - -#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 <net/if.h> -#include <netinet/in.h> - -#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 - -/* 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 $"; -#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 }; - - -#ifdef TEST_POOL -void treeprint __P((ip_pool_t *)); - -int -main(argc, argv) - int argc; - char *argv[]; -{ - addrfamily_t a, b; - iplookupop_t op; - ip_pool_t *ipo; - i6addr_t ip; - - RWLOCK_INIT(&ip_poolrw, "poolrw"); - ip_pool_init(); - - bzero((char *)&a, sizeof(a)); - bzero((char *)&b, sizeof(b)); - bzero((char *)&ip, sizeof(ip)); - bzero((char *)&op, sizeof(op)); - 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); -#ifdef DEBUG_POOL -treeprint(ipo); -#endif - ip.in4.s_addr = 0x0a00aabb; - printf("search(%#x) = %d (0)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); - - ip.in4.s_addr = 0x0a000001; - printf("search(%#x) = %d (0)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); - - ip.in4.s_addr = 0x0a000101; - printf("search(%#x) = %d (0)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); - - ip.in4.s_addr = 0x0a010001; - printf("search(%#x) = %d (1)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); - - ip.in4.s_addr = 0x0a010101; - printf("search(%#x) = %d (1)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); - - ip.in4.s_addr = 0x0a010201; - printf("search(%#x) = %d (0)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); - - ip.in4.s_addr = 0x0a010203; - printf("search(%#x) = %d (1)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); - - ip.in4.s_addr = 0x0a01020f; - printf("search(%#x) = %d (1)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); - - ip.in4.s_addr = 0x0b00aabb; - printf("search(%#x) = %d (-1)\n", ip.in4.s_addr, - ip_pool_search(ipo, 4, &ip)); - -#ifdef DEBUG_POOL -treeprint(ipo); -#endif - - ip_pool_fini(); - - return 0; -} - - -void -treeprint(ipo) -ip_pool_t *ipo; -{ - ip_pool_node_t *c; - - for (c = ipo->ipo_list; c != NULL; c = c->ipn_next) - printf("Node %p(%s) (%#x/%#x) = %d hits %lu\n", - c, c->ipn_name, c->ipn_addr.adf_addr.in4.s_addr, - c->ipn_mask.adf_addr.in4.s_addr, - c->ipn_info, c->ipn_hits); -} -#endif /* TEST_POOL */ - - -/* ------------------------------------------------------------------------ */ -/* Function: ip_pool_init */ -/* Returns: int - 0 = success, else error */ -/* */ -/* Initialise the routing table data structures where required. */ -/* ------------------------------------------------------------------------ */ -int ip_pool_init() -{ - - bzero((char *)&ipoolstat, sizeof(ipoolstat)); - -#if (!defined(_KERNEL) || (BSD < 199306)) - rn_init(); -#endif - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ip_pool_fini */ -/* Returns: int - 0 = success, else error */ -/* 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*/ -/* used to delete the pools one by one to ensure they're properly freed up. */ -/* ------------------------------------------------------------------------ */ -void ip_pool_fini() -{ - ip_pool_t *p, *q; - int i; - - for (i = 0; i <= IPL_LOGMAX; i++) { - for (q = ip_pool_list[i]; (p = q) != NULL; ) { - q = p->ipo_next; - (void) ip_pool_destroy(i, p->ipo_name); - } - } - -#if (!defined(_KERNEL) || (BSD < 199306)) - rn_fini(); -#endif -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ip_pool_statistics */ -/* Returns: int - 0 = success, else error */ -/* Parameters: op(I) - pointer to lookup operation arguments */ -/* */ -/* 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; -{ - ip_pool_stat_t stats; - int unit, i, err = 0; - - if (op->iplo_size != sizeof(ipoolstat)) - return EINVAL; - - bcopy((char *)&ipoolstat, (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) { - if (op->iplo_name[0] != '\0') - stats.ipls_list[unit] = ip_pool_exists(unit, - op->iplo_name); - else - stats.ipls_list[unit] = ip_pool_list[unit]; - } else - err = EINVAL; - if (err == 0) - err = COPYOUT(&stats, op->iplo_struct, sizeof(stats)); - return err; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ip_pool_exists */ -/* Returns: int - 0 = success, else error */ -/* Parameters: ipo(I) - pointer to the pool getting the new node. */ -/* */ -/* 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; -{ - ip_pool_t *p; - - for (p = ip_pool_list[unit]; 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. */ -/* */ -/* 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; -{ - ip_pool_t *p; - - p = ip_pool_exists(unit, name); - if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE)) - return NULL; - - return p; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ip_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) - */ -/* */ -/* 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; -{ - 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); - return (ip_pool_node_t *)n; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ip_pool_search */ -/* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */ -/* Parameters: tptr(I) - pointer to the pool to search */ -/* version(I) - IP protocol version (4 or 6) */ -/* dptr(I) - pointer to address information */ -/* */ -/* 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; -{ - struct radix_node *rn; - ip_pool_node_t *m; - i6addr_t *addr; - addrfamily_t v; - ip_pool_t *ipo; - int rv; - - ipo = tptr; - if (ipo == NULL) - return -1; - - rv = 1; - 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_addr.in4 = addr->in4; -#ifdef USE_INET6 - } else if (ipversion == 6) { - v.adf_len += sizeof(addr->in6); - v.adf_addr.in6 = addr->in6; -#endif - } else - return -1; - - READ_ENTER(&ip_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); - - if ((rn != NULL) && ((rn->rn_flags & RNF_ROOT) == 0)) { - m = (ip_pool_node_t *)rn; - ipo->ipo_hits++; - m->ipn_hits++; - rv = m->ipn_info; - } - RWLOCK_EXIT(&ip_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) */ -/* */ -/* 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; -{ - struct radix_node *rn; - ip_pool_node_t *x; - - KMALLOC(x, ip_pool_node_t *); - if (x == NULL) { - return ENOMEM; - } - - bzero(x, sizeof(*x)); - - x->ipn_info = info; - (void)strncpy(x->ipn_name, ipo->ipo_name, sizeof(x->ipn_name)); - - 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); - - 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); -#ifdef DEBUG_POOL - printf("Added %p at %p\n", x, rn); -#endif - - if (rn == NULL) { - KFREE(x); - 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; - - ipoolstat.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) */ -/* */ -/* Creates a new group according to the paramters passed in via the */ -/* iplookupop structure. Does not check to see if the group already exists */ -/* when being inserted - assume this has already been done. If the pool is */ -/* marked as being anonymous, give it a new, unique, identifier. Call any */ -/* other functions required to initialise the structure. */ -/* */ -/* If the structure is flagged for deletion then reset the flag and return, */ -/* 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; -{ - char name[FR_GROUPLEN]; - int poolnum, unit; - ip_pool_t *h; - - unit = op->iplo_unit; - - if ((op->iplo_arg & LOOKUP_ANON) == 0) { - h = ip_pool_exists(unit, op->iplo_name); - if (h != NULL) { - if ((h->ipo_flags & IPOOL_DELETE) == 0) - return EEXIST; - h->ipo_flags &= ~IPOOL_DELETE; - return 0; - } - } - - KMALLOC(h, ip_pool_t *); - if (h == NULL) - return ENOMEM; - bzero(h, sizeof(*h)); - - if (rn_inithead((void **)&h->ipo_head, - offsetof(addrfamily_t, adf_addr) << 3) == 0) { - KFREE(h); - return ENOMEM; - } - - if ((op->iplo_arg & LOOKUP_ANON) != 0) { - ip_pool_t *p; - - h->ipo_flags |= IPOOL_ANON; - poolnum = LOOKUP_ANON; - -#if defined(SNPRINTF) && defined(_KERNEL) - SNPRINTF(name, sizeof(name), "%x", poolnum); -#else - (void)sprintf(name, "%x", poolnum); -#endif - - for (p = ip_pool_list[unit]; p != NULL; ) { - if (strncmp(name, p->ipo_name, - sizeof(p->ipo_name)) == 0) { - poolnum++; -#if defined(SNPRINTF) && defined(_KERNEL) - SNPRINTF(name, sizeof(name), "%x", poolnum); -#else - (void)sprintf(name, "%x", poolnum); -#endif - p = ip_pool_list[unit]; - } else - p = p->ipo_next; - } - - (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name)); - (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name)); - } else { - (void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name)); - } - - h->ipo_ref = 1; - h->ipo_list = NULL; - 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; - - ipoolstat.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) */ -/* */ -/* Remove a node from the pool given by ipo. */ -/* ------------------------------------------------------------------------ */ -int ip_pool_remove(ipo, ipe) -ip_pool_t *ipo; -ip_pool_node_t *ipe; -{ - - 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); - - ip_pool_node_deref(ipe); - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ip_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) */ -/* */ -/* 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 */ -/* 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. */ -/* ------------------------------------------------------------------------ */ -int ip_pool_destroy(unit, name) -int unit; -char *name; -{ - ip_pool_t *ipo; - - ipo = ip_pool_exists(unit, name); - if (ipo == NULL) - return ESRCH; - - if (ipo->ipo_ref != 1) { - ip_pool_clearnodes(ipo); - ipo->ipo_flags |= IPOOL_DELETE; - return 0; - } - - ip_pool_free(ipo); - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ip_pool_flush */ -/* Returns: int - number of pools deleted */ -/* Parameters: fp(I) - which pool(s) to flush */ -/* Locks: WRITE(ip_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 */ -/* 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. */ -/* ------------------------------------------------------------------------ */ -int ip_pool_flush(fp) -iplookupflush_t *fp; -{ - 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++) { - 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)); - q = p->ipo_next; - err = ip_pool_destroy(op.iplo_unit, op.iplo_name); - if (err == 0) - num++; - else - break; - } - } - return num; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ip_pool_free */ -/* Returns: void */ -/* Parameters: ipo(I) - pointer to pool structure */ -/* Locks: WRITE(ip_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 */ -/* 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. */ -/* ------------------------------------------------------------------------ */ -void ip_pool_free(ipo) -ip_pool_t *ipo; -{ - - ip_pool_clearnodes(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); - KFREE(ipo); - - ipoolstat.ipls_pools--; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ip_pool_clearnodes */ -/* Returns: void */ -/* Parameters: ipo(I) - pointer to pool structure */ -/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ -/* */ -/* Deletes all nodes stored in a pool structure. */ -/* ------------------------------------------------------------------------ */ -static void ip_pool_clearnodes(ipo) -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); - - ipoolstat.ipls_nodes--; - } - RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); - - ipo->ipo_list = NULL; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ip_pool_deref */ -/* Returns: void */ -/* Parameters: ipo(I) - pointer to pool structure */ -/* Locks: WRITE(ip_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; -{ - - ipo->ipo_ref--; - - if (ipo->ipo_ref == 0) - ip_pool_free(ipo); - - else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE)) - ip_pool_destroy(ipo->ipo_unit, ipo->ipo_name); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ip_pool_node_deref */ -/* Returns: void */ -/* Parameters: ipn(I) - pointer to pool structure */ -/* Locks: WRITE(ip_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; -{ - - ipn->ipn_ref--; - - if (ipn->ipn_ref == 0) { - KFREE(ipn); - ipoolstat.ipls_nodes--; - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ip_pool_getnext */ -/* Returns: void */ -/* Parameters: token(I) - pointer to pool structure */ -/* Parameters: ilp(IO) - pointer to pool iterating structure */ -/* */ -/* ------------------------------------------------------------------------ */ -int ip_pool_getnext(token, ilp) -ipftoken_t *token; -ipflookupiter_t *ilp; -{ - ip_pool_node_t *node, zn, *nextnode; - ip_pool_t *ipo, zp, *nextipo; - int err; - - err = 0; - node = NULL; - nextnode = NULL; - ipo = NULL; - nextipo = NULL; - - READ_ENTER(&ip_poolrw); - - switch (ilp->ili_otype) - { - case IPFLOOKUPITER_LIST : - ipo = token->ipt_data; - if (ipo == NULL) { - nextipo = ip_pool_list[(int)ilp->ili_unit]; - } else { - nextipo = ipo->ipo_next; - } - - if (nextipo != NULL) { - ATOMIC_INC(nextipo->ipo_ref); - token->ipt_data = nextipo; - } else { - bzero((char *)&zp, sizeof(zp)); - nextipo = &zp; - token->ipt_data = NULL; - } - break; - - case IPFLOOKUPITER_NODE : - node = token->ipt_data; - if (node == NULL) { - ipo = ip_pool_exists(ilp->ili_unit, ilp->ili_name); - if (ipo == NULL) - err = ESRCH; - else { - nextnode = ipo->ipo_list; - ipo = NULL; - } - } else { - nextnode = node->ipn_next; - } - - if (nextnode != NULL) { - ATOMIC_INC(nextnode->ipn_ref); - token->ipt_data = nextnode; - } else { - bzero((char *)&zn, sizeof(zn)); - nextnode = &zn; - token->ipt_data = NULL; - } - break; - default : - err = EINVAL; - break; - } - - RWLOCK_EXIT(&ip_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) - err = EFAULT; - 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) - err = EFAULT; - break; - } - - return err; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ip_pool_iterderef */ -/* Returns: void */ -/* Parameters: ipn(I) - pointer to pool structure */ -/* Locks: WRITE(ip_poolrw) */ -/* */ -/* ------------------------------------------------------------------------ */ -void ip_pool_iterderef(otype, unit, data) -u_int otype; -int unit; -void *data; -{ - - if (data == NULL) - return; - - if (unit < 0 || unit > IPL_LOGMAX) - return; - - switch (otype) - { - case IPFLOOKUPITER_LIST : - WRITE_ENTER(&ip_poolrw); - ip_pool_deref((ip_pool_t *)data); - RWLOCK_EXIT(&ip_poolrw); - break; - - case IPFLOOKUPITER_NODE : - WRITE_ENTER(&ip_poolrw); - ip_pool_node_deref((ip_pool_node_t *)data); - RWLOCK_EXIT(&ip_poolrw); - break; - default : - break; - } -} - - -# if defined(_KERNEL) && ((BSD >= 198911) && !defined(__osf__) && \ - !defined(__hpux) && !defined(__sgi)) -static int -rn_freenode(struct radix_node *n, void *p) -{ - struct radix_node_head *rnh = p; - struct radix_node *d; - - d = rnh->rnh_deladdr(n->rn_key, NULL, rnh); - if (d != NULL) { - FreeS(d, max_keylen + 2 * sizeof (*d)); - } - 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); - - Free(rnh); -} -# endif -#endif /* IPFILTER_LOOKUP */ diff --git a/sys/contrib/ipfilter/netinet/ip_pool.h b/sys/contrib/ipfilter/netinet/ip_pool.h deleted file mode 100644 index 9968ef0..0000000 --- a/sys/contrib/ipfilter/netinet/ip_pool.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 1993-2001, 2003 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 $ - */ - -#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" - -#define IP_POOL_NOMATCH 0 -#define IP_POOL_POSITIVE 1 - -typedef struct ip_pool_node { - struct radix_node ipn_nodes[2]; - addrfamily_t ipn_addr; - addrfamily_t ipn_mask; - int ipn_info; - int ipn_ref; -char ipn_name[FR_GROUPLEN]; -u_long ipn_hits; - struct ip_pool_node *ipn_next, **ipn_pnext; -} 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]; -} 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; - - -extern ip_pool_stat_t ipoolstat; -extern ip_pool_t *ip_pool_list[IPL_LOGSIZE]; - -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 *)); - -#endif /* __IP_POOL_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_pptp_pxy.c b/sys/contrib/ipfilter/netinet/ip_pptp_pxy.c deleted file mode 100644 index 3924d4b..0000000 --- a/sys/contrib/ipfilter/netinet/ip_pptp_pxy.c +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Copyright (C) 2002-2003 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 $ - * - */ -#define IPF_PPTP_PROXY - -typedef struct pptp_hdr { - u_short pptph_len; - u_short pptph_type; - u_32_t pptph_cookie; -} pptp_hdr_t; - -#define PPTP_MSGTYPE_CTL 1 -#define PPTP_MTCTL_STARTREQ 1 -#define PPTP_MTCTL_STARTREP 2 -#define PPTP_MTCTL_STOPREQ 3 -#define PPTP_MTCTL_STOPREP 4 -#define PPTP_MTCTL_ECHOREQ 5 -#define PPTP_MTCTL_ECHOREP 6 -#define PPTP_MTCTL_OUTREQ 7 -#define PPTP_MTCTL_OUTREP 8 -#define PPTP_MTCTL_INREQ 9 -#define PPTP_MTCTL_INREP 10 -#define PPTP_MTCTL_INCONNECT 11 -#define PPTP_MTCTL_CLEAR 12 -#define PPTP_MTCTL_DISCONNECT 13 -#define PPTP_MTCTL_WANERROR 14 -#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 *)); - -static frentry_t pptpfr; - -int pptp_proxy_init = 0; -int ippr_pptp_debug = 0; -int ippr_pptp_gretimeout = IPF_TTLVAL(120); /* 2 minutes */ - - -/* - * PPTP application proxy initialization. - */ -int ippr_pptp_init() -{ - 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_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() -{ - if (pptp_proxy_init == 1) { - MUTEX_DESTROY(&pptpfr.fr_lock); - pptp_proxy_init = 0; - } -} - - -/* - * Setup for a new PPTP proxy. - * - * 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; -{ - pptp_pxy_t *pptp; - ipnat_t *ipn; - ip_t *ip; - - ip = fin->fin_ip; - - if (nat_outlookup(fin, 0, IPPROTO_GRE, nat->nat_inip, - ip->ip_dst) != NULL) { - if (ippr_pptp_debug > 0) - printf("ippr_pptp_new: GRE session %s\n", - "already exists"); - 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"); - return -1; - } - - /* - * 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_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; - - pptp->pptp_side[0].pptps_wptr = pptp->pptp_side[0].pptps_buffer; - pptp->pptp_side[1].pptps_wptr = pptp->pptp_side[1].pptps_buffer; - return 0; -} - - -void ippr_pptp_donatstate(fin, nat, pptp) -fr_info_t *fin; -nat_t *nat; -pptp_pxy_t *pptp; -{ - fr_info_t fi; - grehdr_t gre; - nat_t *nat2; - u_char p; - ip_t *ip; - - ip = fin->fin_ip; - p = ip->ip_p; - - nat2 = pptp->pptp_nat; - 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) || - (nat->nat_dir == NAT_INBOUND && !fin->fin_out)) { - fi.fin_data[0] = pptp->pptp_call[0]; - fi.fin_data[1] = pptp->pptp_call[1]; - } else { - fi.fin_data[0] = pptp->pptp_call[1]; - fi.fin_data[1] = pptp->pptp_call[0]; - } - ip = fin->fin_ip; - ip->ip_p = IPPROTO_GRE; - fi.fin_flx &= ~(FI_TCPUDP|FI_STATE|FI_FRAG); - 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; - } - } - - /* - * Update NAT timeout/create NAT if missing. - */ - if (nat2 != NULL) - fr_queueback(&nat2->nat_tqe); - else { - nat2 = nat_new(&fi, &pptp->pptp_rule, &pptp->pptp_nat, - NAT_SLAVE, nat->nat_dir); - pptp->pptp_nat = nat2; - if (nat2 != NULL) { - (void) nat_proto(&fi, nat2, 0); - nat_update(&fi, nat2, nat2->nat_ptr); - } - } - - READ_ENTER(&ipf_state); - if (pptp->pptp_state != NULL) { - fr_queueback(&pptp->pptp_state->is_sti); - RWLOCK_EXIT(&ipf_state); - } else { - RWLOCK_EXIT(&ipf_state); - if (nat2 != NULL) { - if (nat->nat_dir == NAT_INBOUND) - fi.fin_fi.fi_daddr = nat2->nat_inip.s_addr; - else - fi.fin_fi.fi_saddr = nat2->nat_inip.s_addr; - } - 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); - } - ip->ip_p = p; - return; -} - - -/* - * Try and build up the next PPTP message in the TCP stream and if we can - * 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; -{ - static const char *funcname = "ippr_pptp_nextmessage"; - pptp_side_t *pptps; - u_32_t start, end; - pptp_hdr_t *hdr; - tcphdr_t *tcp; - int dlen, off; - u_short len; - char *msg; - - tcp = fin->fin_dp; - dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); - start = ntohl(tcp->th_seq); - pptps = &pptp->pptp_side[rev]; - off = (char *)tcp - (char *)fin->fin_ip + (TCP_OFF(tcp) << 2) + - fin->fin_ipoff; - - if (dlen <= 0) - return 0; - /* - * If the complete data packet is before what we expect to see - * "next", just ignore it as the chances are we've already seen it. - * The next if statement following this one really just causes packets - * ahead of what we've seen to be dropped, implying that something in - * the middle went missing and we want to see that first. - */ - end = start + dlen; - if (pptps->pptps_next > end && pptps->pptps_next > start) - return 0; - - if (pptps->pptps_next != start) { - if (ippr_pptp_debug > 5) - printf("%s: next (%x) != start (%x)\n", funcname, - pptps->pptps_next, start); - return -1; - } - - msg = (char *)fin->fin_dp + (TCP_OFF(tcp) << 2); - - while (dlen > 0) { - off += pptps->pptps_bytes; - if (pptps->pptps_gothdr == 0) { - /* - * PPTP has an 8 byte header that inclues the cookie. - * The start of every message should include one and - * it should match 1a2b3c4d. Byte order is ignored, - * deliberately, when printing out the error. - */ - len = MIN(8 - pptps->pptps_bytes, dlen); - COPYDATA(fin->fin_m, off, len, pptps->pptps_wptr); - pptps->pptps_bytes += len; - pptps->pptps_wptr += len; - hdr = (pptp_hdr_t *)pptps->pptps_buffer; - if (pptps->pptps_bytes == 8) { - pptps->pptps_next += 8; - if (ntohl(hdr->pptph_cookie) != 0x1a2b3c4d) { - if (ippr_pptp_debug > 1) - printf("%s: bad cookie (%x)\n", - funcname, - hdr->pptph_cookie); - return -1; - } - } - dlen -= len; - msg += len; - off += len; - - pptps->pptps_gothdr = 1; - len = ntohs(hdr->pptph_len); - pptps->pptps_len = len; - pptps->pptps_nexthdr += len; - - /* - * If a message is too big for the buffer, just set - * the fields for the next message to come along. - * The messages defined in RFC 2637 will not exceed - * 512 bytes (in total length) so this is likely a - * bad data packet, anyway. - */ - if (len > sizeof(pptps->pptps_buffer)) { - if (ippr_pptp_debug > 3) - printf("%s: message too big (%d)\n", - funcname, len); - pptps->pptps_next = pptps->pptps_nexthdr; - pptps->pptps_wptr = pptps->pptps_buffer; - pptps->pptps_gothdr = 0; - pptps->pptps_bytes = 0; - pptps->pptps_len = 0; - break; - } - } - - len = MIN(pptps->pptps_len - pptps->pptps_bytes, dlen); - COPYDATA(fin->fin_m, off, len, pptps->pptps_wptr); - pptps->pptps_bytes += len; - pptps->pptps_wptr += len; - pptps->pptps_next += len; - - if (pptps->pptps_len > pptps->pptps_bytes) - break; - - ippr_pptp_message(fin, nat, pptp, pptps); - pptps->pptps_wptr = pptps->pptps_buffer; - pptps->pptps_gothdr = 0; - pptps->pptps_bytes = 0; - pptps->pptps_len = 0; - - start += len; - msg += len; - dlen -= len; - } - - return 0; -} - - -/* - * 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; -{ - 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); - break; - - default : - break; - } - return 0; -} - - -/* - * 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; -{ - u_short *buffer = (u_short *)(pptps->pptps_buffer); - pptp_side_t *pptpo; - - if (pptps == &pptp->pptp_side[0]) - pptpo = &pptp->pptp_side[1]; - else - pptpo = &pptp->pptp_side[0]; - - /* - * Breakout to handle all the various messages. Most are just state - * transition. - */ - switch (ntohs(buffer[4])) - { - case PPTP_MTCTL_STARTREQ : - pptps->pptps_state = PPTP_MTCTL_STARTREQ; - break; - case PPTP_MTCTL_STARTREP : - if (pptpo->pptps_state == PPTP_MTCTL_STARTREQ) - pptps->pptps_state = PPTP_MTCTL_STARTREP; - break; - case PPTP_MTCTL_STOPREQ : - pptps->pptps_state = PPTP_MTCTL_STOPREQ; - break; - case PPTP_MTCTL_STOPREP : - if (pptpo->pptps_state == PPTP_MTCTL_STOPREQ) - pptps->pptps_state = PPTP_MTCTL_STOPREP; - break; - case PPTP_MTCTL_ECHOREQ : - pptps->pptps_state = PPTP_MTCTL_ECHOREQ; - break; - case PPTP_MTCTL_ECHOREP : - if (pptpo->pptps_state == PPTP_MTCTL_ECHOREQ) - pptps->pptps_state = PPTP_MTCTL_ECHOREP; - break; - case PPTP_MTCTL_OUTREQ : - pptps->pptps_state = PPTP_MTCTL_OUTREQ; - break; - case PPTP_MTCTL_OUTREP : - if (pptpo->pptps_state == PPTP_MTCTL_OUTREQ) { - pptps->pptps_state = PPTP_MTCTL_OUTREP; - pptp->pptp_call[0] = buffer[7]; - pptp->pptp_call[1] = buffer[6]; - ippr_pptp_donatstate(fin, nat, pptp); - } - break; - case PPTP_MTCTL_INREQ : - pptps->pptps_state = PPTP_MTCTL_INREQ; - break; - case PPTP_MTCTL_INREP : - if (pptpo->pptps_state == PPTP_MTCTL_INREQ) { - pptps->pptps_state = PPTP_MTCTL_INREP; - pptp->pptp_call[0] = buffer[7]; - pptp->pptp_call[1] = buffer[6]; - ippr_pptp_donatstate(fin, nat, pptp); - } - break; - case PPTP_MTCTL_INCONNECT : - pptps->pptps_state = PPTP_MTCTL_INCONNECT; - break; - case PPTP_MTCTL_CLEAR : - pptps->pptps_state = PPTP_MTCTL_CLEAR; - break; - case PPTP_MTCTL_DISCONNECT : - pptps->pptps_state = PPTP_MTCTL_DISCONNECT; - break; - case PPTP_MTCTL_WANERROR : - pptps->pptps_state = PPTP_MTCTL_WANERROR; - break; - case PPTP_MTCTL_LINKINFO : - pptps->pptps_state = PPTP_MTCTL_LINKINFO; - break; - } - - return 0; -} - - -/* - * 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; -{ - pptp_pxy_t *pptp; - tcphdr_t *tcp; - int rev; - - if ((fin->fin_out == 1) && (nat->nat_dir == NAT_INBOUND)) - rev = 1; - else if ((fin->fin_out == 0) && (nat->nat_dir == NAT_OUTBOUND)) - rev = 1; - else - rev = 0; - - tcp = (tcphdr_t *)fin->fin_dp; - if ((tcp->th_flags & TH_OPENING) == TH_OPENING) { - pptp = (pptp_pxy_t *)aps->aps_data; - pptp->pptp_side[1 - rev].pptps_next = ntohl(tcp->th_ack); - pptp->pptp_side[1 - rev].pptps_nexthdr = ntohl(tcp->th_ack); - 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, - rev); -} - - -/* - * clean up after ourselves. - */ -void ippr_pptp_del(aps) -ap_session_t *aps; -{ - pptp_pxy_t *pptp; - - pptp = aps->aps_data; - - if (pptp != NULL) { - /* - * Don't bother changing any of the NAT structure details, - * *_del() is on a callback from aps_free(), from nat_delete() - */ - - READ_ENTER(&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); - } - RWLOCK_EXIT(&ipf_state); - - pptp->pptp_state = NULL; - pptp->pptp_nat = NULL; - } -} diff --git a/sys/contrib/ipfilter/netinet/ip_proxy.c b/sys/contrib/ipfilter/netinet/ip_proxy.c deleted file mode 100644 index 04e9f89..0000000 --- a/sys/contrib/ipfilter/netinet/ip_proxy.c +++ /dev/null @@ -1,858 +0,0 @@ -/* - * Copyright (C) 1997-2003 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(AIX) -# include <sys/fcntl.h> -#endif -#if !defined(_KERNEL) && !defined(__KERNEL__) -# include <stdio.h> -# include <string.h> -# include <stdlib.h> -# include <ctype.h> -# define _KERNEL -# ifdef __OpenBSD__ -struct file; -# endif -# include <sys/uio.h> -# undef _KERNEL -#endif -#if !defined(linux) -# include <sys/protosw.h> -#endif -#include <sys/socket.h> -#if defined(_KERNEL) -# if !defined(__NetBSD__) && !defined(sun) && !defined(__osf__) && \ - !defined(__OpenBSD__) && !defined(__hpux) && !defined(__sgi) && \ - !defined(AIX) -# include <sys/ctype.h> -# endif -# include <sys/systm.h> -# if !defined(__SVR4) && !defined(__svr4__) -# include <sys/mbuf.h> -# endif -#endif -#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 -#if defined(__SVR4) || defined(__svr4__) -# include <sys/byteorder.h> -# ifdef _KERNEL -# include <sys/dditypes.h> -# endif -# include <sys/stream.h> -# include <sys/kmem.h> -#endif -#if __FreeBSD__ > 2 -# include <sys/queue.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> -#ifndef 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_state.h" -#include "netinet/ip_proxy.h" -#if (__FreeBSD_version >= 300000) -# include <sys/malloc.h> -#endif - -#include "netinet/ip_ftp_pxy.c" -#include "netinet/ip_rcmd_pxy.c" -# include "netinet/ip_pptp_pxy.c" -#if defined(_KERNEL) -# include "netinet/ip_irc_pxy.c" -# include "netinet/ip_raudio_pxy.c" -# include "netinet/ip_h323_pxy.c" -# include "netinet/ip_netbios_pxy.c" -#endif -#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 $"; -#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[] = { -#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 }, -#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 }, -#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 }, -#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 }, -#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 }, -#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 }, -#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 }, -#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 }, -#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 }, -#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 }, -# 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 }, -#endif - { NULL, "", '\0', 0, 0, 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; -{ - aproxy_t *a; - - for (a = ap_proxies; a->apr_p; a++) - if ((a->apr_p == ap->apr_p) && - !strncmp(a->apr_label, ap->apr_label, - sizeof(ap->apr_label))) { - if (ipf_proxy_debug > 1) - printf("appr_add: %s/%d already present (B)\n", - a->apr_label, a->apr_p); - return -1; - } - - for (a = ap_proxylist; (a != NULL); a = a->apr_next) - 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", - 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)(); - 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; -{ - aproxy_t *a; - int error; - - a = appr_lookup(ctl->apc_p, ctl->apc_label); - if (a == NULL) { - if (ipf_proxy_debug > 1) - printf("appr_ctl: can't find %s/%d\n", - ctl->apc_label, ctl->apc_p); - error = ESRCH; - } else if (a->apr_ctl == NULL) { - if (ipf_proxy_debug > 1) - printf("appr_ctl: no ctl function for %s/%d\n", - ctl->apc_label, ctl->apc_p); - 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", - 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; -{ - aproxy_t *a, **app; - - 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; - } - return 0; - } - 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; -{ - aproxy_t *apr = nat->in_apr; - u_short dport = nat->in_dport; - - if ((apr == NULL) || (apr->apr_flags & APR_DELETE) || - (fin->fin_p != apr->apr_p)) - return 0; - if ((tcp == NULL) && dport) - return 0; - return 1; -} - - -int appr_ioctl(data, cmd, mode, ctx) -caddr_t data; -ioctlcmd_t cmd; -int mode; -void *ctx; -{ - ap_ctl_t ctl; - u_char *ptr; - int error; - - mode = mode; /* LINT */ - - switch (cmd) - { - case SIOCPROXY : - error = BCOPYIN(data, &ctl, sizeof(ctl)); - if (error != 0) - return EFAULT; - ptr = NULL; - - if (ctl.apc_dsize > 0) { - KMALLOCS(ptr, u_char *, ctl.apc_dsize); - if (ptr == NULL) - error = ENOMEM; - else { - error = copyinptr(ctl.apc_data, ptr, - ctl.apc_dsize); - if (error == 0) - ctl.apc_data = ptr; - } - } else { - ctl.apc_data = NULL; - error = 0; - } - - if (error == 0) - error = appr_ctl(&ctl); - - if (ptr != NULL) { - KFREES(ptr, ctl.apc_dsize); - } - break; - - default : - 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; -{ - 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", - (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", - 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", - (u_long)apr, apr ? apr->apr_flags : 0); - return -1; - } - - 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); - return -1; - } - } - return 0; -} - - -/* - * 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; -{ - 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 ((nat->nat_ptr == NULL) || (nat->nat_aps != NULL)) { - if (ipf_proxy_debug > 0) - printf("appr_new: nat_ptr %lx nat_aps %lx\n", - (u_long)nat->nat_ptr, (u_long)nat->nat_aps); - return -1; - } - - apr = nat->nat_ptr->in_apr; - - 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", - 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", - (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 ((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", - (u_long)apr->apr_new); - return -1; - } - aps->aps_nat = nat; - aps->aps_next = ap_sess_list; - ap_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; -{ -#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) -# if 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; - ip_t *ip; - short rv; - int err; -#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) - u_32_t s1, s2, sd; -#endif - - if (fin->fin_flx & FI_BAD) { - if (ipf_proxy_debug > 0) - printf("appr_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", - fin->fin_p); - if (fin->fin_p == IPPROTO_TCP) - frstats[fin->fin_out].fr_tcpbad++; - return -1; - } -#endif - - aps = nat->nat_aps; - if ((aps != NULL) && (aps->aps_p == fin->fin_p)) { - /* - * 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); - return -1; - } -#endif - ip = fin->fin_ip; - - switch (fin->fin_p) - { - case IPPROTO_TCP : - tcp = (tcphdr_t *)fin->fin_dp; - -#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && 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*/ - case IPPROTO_UDP : - udp = (udphdr_t *)fin->fin_dp; - break; - default : - break; - } - - apr = aps->aps_apr; - err = 0; - if (fin->fin_out != 0) { - if (apr->apr_outpkt != NULL) - err = (*apr->apr_outpkt)(fin, aps, nat); - } else { - if (apr->apr_inpkt != NULL) - err = (*apr->apr_inpkt)(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", - fin->fin_out, err, rv); - if (rv == 1) - return -1; - - if (rv == 2) { - appr_free(apr); - nat->nat_aps = NULL; - return -1; - } - - /* - * If err != 0 then the data size of the packet has changed - * so we need to recalculate the header checksums for the - * packet. - */ -#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); - } -#endif - - /* - * For TCP packets, we may need to adjust the sequence and - * acknowledgement numbers to reflect changes in size of the - * data stream. - * - * For both TCP and UDP, recalculate the layer 4 checksum, - * regardless, as we can't tell (here) if data has been - * 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 - } 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 - } - aps->aps_bytes += fin->fin_plen; - aps->aps_pkts++; - return 1; - } - return 0; -} - - -/* - * 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; -{ - aproxy_t *ap; - - if (ipf_proxy_debug > 8) - printf("appr_lookup(%d,%s)\n", pr, name); - - for (ap = ap_proxies; ap->apr_p; ap++) - 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); - return NULL; -} - - -void appr_free(ap) -aproxy_t *ap; -{ - ap->apr_ref--; -} - - -void aps_free(aps) -ap_session_t *aps; -{ - ap_session_t *a, **ap; - aproxy_t *apr; - - if (!aps) - return; - - for (ap = &ap_sess_list; ((a = *ap) != NULL); ap = &a->aps_next) - if (a == aps) { - *ap = a->aps_next; - break; - } - - apr = aps->aps_apr; - if ((apr != NULL) && (apr->apr_del != NULL)) - (*apr->apr_del)(aps); - - if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) - KFREES(aps->aps_data, aps->aps_psiz); - KFREE(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; -{ - int sel, ch = 0, out, nlen; - u_32_t seq1, seq2; - tcphdr_t *tcp; - short inc2; - - tcp = (tcphdr_t *)fin->fin_dp; - out = fin->fin_out; - /* - * fin->fin_plen has already been adjusted by 'inc'. - */ - nlen = fin->fin_plen; - nlen -= (IP_HL(ip) << 2) + (TCP_OFF(tcp) << 2); - - inc2 = inc; - inc = (int)inc2; - - if (out != 0) { - seq1 = (u_32_t)ntohl(tcp->th_seq); - sel = aps->aps_sel[out]; - - /* switch to other set ? */ - if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) && - (seq1 > aps->aps_seqmin[!sel])) { - if (ipf_proxy_debug > 7) - printf("proxy out switch set seq %d -> %d %x > %x\n", - sel, !sel, seq1, - aps->aps_seqmin[!sel]); - sel = aps->aps_sel[out] = !sel; - } - - if (aps->aps_seqoff[sel]) { - seq2 = aps->aps_seqmin[sel] - aps->aps_seqoff[sel]; - if (seq1 > seq2) { - seq2 = aps->aps_seqoff[sel]; - seq1 += seq2; - tcp->th_seq = htonl(seq1); - ch = 1; - } - } - - if (inc && (seq1 > aps->aps_seqmin[!sel])) { - aps->aps_seqmin[sel] = seq1 + nlen - 1; - aps->aps_seqoff[sel] = aps->aps_seqoff[sel] + inc; - if (ipf_proxy_debug > 7) - printf("proxy seq set %d at %x to %d + %d\n", - sel, aps->aps_seqmin[sel], - aps->aps_seqoff[sel], inc); - } - - /***/ - - seq1 = ntohl(tcp->th_ack); - sel = aps->aps_sel[1 - out]; - - /* switch to other set ? */ - if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) && - (seq1 > aps->aps_ackmin[!sel])) { - if (ipf_proxy_debug > 7) - printf("proxy out switch set ack %d -> %d %x > %x\n", - sel, !sel, seq1, - aps->aps_ackmin[!sel]); - sel = aps->aps_sel[1 - out] = !sel; - } - - if (aps->aps_ackoff[sel] && (seq1 > aps->aps_ackmin[sel])) { - seq2 = aps->aps_ackoff[sel]; - tcp->th_ack = htonl(seq1 - seq2); - ch = 1; - } - } else { - seq1 = ntohl(tcp->th_seq); - sel = aps->aps_sel[out]; - - /* switch to other set ? */ - if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) && - (seq1 > aps->aps_ackmin[!sel])) { - if (ipf_proxy_debug > 7) - printf("proxy in switch set ack %d -> %d %x > %x\n", - sel, !sel, seq1, aps->aps_ackmin[!sel]); - sel = aps->aps_sel[out] = !sel; - } - - if (aps->aps_ackoff[sel]) { - seq2 = aps->aps_ackmin[sel] - aps->aps_ackoff[sel]; - if (seq1 > seq2) { - seq2 = aps->aps_ackoff[sel]; - seq1 += seq2; - tcp->th_seq = htonl(seq1); - ch = 1; - } - } - - if (inc && (seq1 > aps->aps_ackmin[!sel])) { - aps->aps_ackmin[!sel] = seq1 + nlen - 1; - aps->aps_ackoff[!sel] = aps->aps_ackoff[sel] + inc; - - if (ipf_proxy_debug > 7) - printf("proxy ack set %d at %x to %d + %d\n", - !sel, aps->aps_seqmin[!sel], - aps->aps_seqoff[sel], inc); - } - - /***/ - - seq1 = ntohl(tcp->th_ack); - sel = aps->aps_sel[1 - out]; - - /* switch to other set ? */ - if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) && - (seq1 > aps->aps_seqmin[!sel])) { - if (ipf_proxy_debug > 7) - 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) - printf("sel %d seqoff %d seq1 %x seqmin %x\n", - sel, aps->aps_seqoff[sel], seq1, - aps->aps_seqmin[sel]); - if (seq1 > aps->aps_seqmin[sel]) { - seq2 = aps->aps_seqoff[sel]; - tcp->th_ack = htonl(seq1 - seq2); - ch = 1; - } - } - } - - if (ipf_proxy_debug > 8) - printf("appr_fixseqack: seq %x ack %x\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() -{ - 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; - } - } - return err; -} - - -/* - * Unload hook for kernel application proxies. - * Call the finialise routine for all the compiled in kernel proxies. - */ -void appr_unload() -{ - aproxy_t *ap; - - 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)(); -} diff --git a/sys/contrib/ipfilter/netinet/ip_proxy.h b/sys/contrib/ipfilter/netinet/ip_proxy.h deleted file mode 100644 index e370022..0000000 --- a/sys/contrib/ipfilter/netinet/ip_proxy.h +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright (C) 1997-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * $Id: ip_proxy.h,v 2.31.2.5 2007/04/16 21:06:52 darrenr Exp $ - */ - -#ifndef __IP_PROXY_H__ -#define __IP_PROXY_H__ - -#ifndef SOLARIS -#define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) -#endif - -#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51) -#define SIOCPROXY _IOWR('r', 64, struct ap_control) -#else -#define SIOCPROXY _IOWR(r, 64, struct ap_control) -#endif - -#ifndef APR_LABELLEN -#define APR_LABELLEN 16 -#endif -#define AP_SESS_SIZE 53 - -struct nat; -struct ipnat; -struct ipstate; - -typedef struct ap_tcp { - u_short apt_sport; /* source port */ - u_short apt_dport; /* destination port */ - short apt_sel[2]; /* {seq,ack}{off,min} set selector */ - short apt_seqoff[2]; /* sequence # difference */ - u_32_t apt_seqmin[2]; /* don't change seq-off until after this */ - short apt_ackoff[2]; /* sequence # difference */ - u_32_t apt_ackmin[2]; /* don't change seq-off until after this */ - u_char apt_state[2]; /* connection state */ -} ap_tcp_t; - -typedef struct ap_udp { - u_short apu_sport; /* source port */ - u_short apu_dport; /* destination port */ -} ap_udp_t; - -typedef struct ap_session { - struct aproxy *aps_apr; - union { - 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; - -#define aps_sport aps_un.apu_tcp.apt_sport -#define aps_dport aps_un.apu_tcp.apt_dport -#define aps_sel aps_un.apu_tcp.apt_sel -#define aps_seqoff aps_un.apu_tcp.apt_seqoff -#define aps_seqmin aps_un.apu_tcp.apt_seqmin -#define aps_state aps_un.apu_tcp.apt_state -#define aps_ackoff aps_un.apu_tcp.apt_ackoff -#define aps_ackmin aps_un.apu_tcp.apt_ackmin - - -typedef struct ap_control { - char apc_label[APR_LABELLEN]; - u_char apc_p; - /* - * The following fields are upto the proxy's apr_ctl routine to deal - * with. When the proxy gets this in kernel space, apc_data will - * point to a malloc'd region of memory of apc_dsize bytes. If the - * proxy wants to keep that memory, it must set apc_data to NULL - * before it returns. It is expected if this happens that it will - * take care to free it in apr_fini or otherwise as appropriate. - * apc_cmd is provided as a standard place to put simple commands, - * with apc_arg being available to put a simple arg. - */ - u_long apc_cmd; - u_long apc_arg; - void *apc_data; - size_t apc_dsize; -} ap_ctl_t; - - -typedef struct aproxy { - struct aproxy *apr_next; - char apr_label[APR_LABELLEN]; /* Proxy label # */ - u_char apr_p; /* protocol */ - int apr_ref; /* +1 per rule referencing it */ - int apr_flags; - int (* apr_init) __P((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_match) __P((fr_info_t *, ap_session_t *, struct nat *)); - int (* apr_ctl) __P((struct aproxy *, struct ap_control *)); -} aproxy_t; - -#define APR_DELETE 1 - -#define APR_ERR(x) ((x) << 16) -#define APR_EXIT(x) (((x) >> 16) & 0xffff) -#define APR_INC(x) ((x) & 0xffff) - -/* - * 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') || \ - ((x) == '\t') || ((x) == '\b')) -#endif - -/* - * 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. - */ -#define IPF_FTPBUFSZ 80 /* This *MUST* be >= 53! */ - -typedef struct ftpside { - char *ftps_rptr; - char *ftps_wptr; - 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_cmds; - char ftps_buf[FTP_BUFSZ]; -} ftpside_t; - -typedef struct ftpinfo { - int ftp_passok; - int ftp_incok; - ftpside_t ftp_side[2]; -} ftpinfo_t; - - -/* - * For the irc proxy. - */ -typedef struct ircinfo { - size_t irc_len; - char *irc_snick; - char *irc_dnick; - char *irc_type; - char *irc_arg; - char *irc_addr; - u_32_t irc_ipnum; - u_short irc_port; -} ircinfo_t; - - -/* - * Real audio proxy structure and #defines - */ -typedef struct raudio_s { - int rap_seenpna; - int rap_seenver; - int rap_version; - int rap_eos; /* End Of Startup */ - int rap_gotid; - int rap_gotlen; - int rap_mode; - int rap_sdone; - u_short rap_plport; - u_short rap_prport; - u_short rap_srport; - char rap_svr[19]; - u_32_t rap_sbf; /* flag to indicate which of the 19 bytes have - * been filled - */ - u_32_t rap_sseq; -} raudio_t; - -#define RA_ID_END 0 -#define RA_ID_UDP 1 -#define RA_ID_ROBUST 7 - -#define RAP_M_UDP 1 -#define RAP_M_ROBUST 2 -#define RAP_M_TCP 4 -#define RAP_M_UDP_ROBUST (RAP_M_UDP|RAP_M_ROBUST) - - -/* - * MSN RPC proxy - */ -typedef struct msnrpcinfo { - u_int mri_flags; - int mri_cmd[2]; - u_int mri_valid; - struct in_addr mri_raddr; - u_short mri_rport; -} msnrpcinfo_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; - 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 -#define RPCB_RES_PMAP 0 /* Response contains a v2 port. */ -#define RPCB_RES_STRING 1 /* " " " v3 (GETADDR) string. */ -#define RPCB_RES_LIST 2 /* " " " v4 (GETADDRLIST) list. */ -#define RPCB_MAXREQS 32 /* Arbitrary limit on tracked transactions */ - -#define RPCB_REQMIN 40 -#define RPCB_REQMAX 888 -#define RPCB_REPMIN 20 -#define RPCB_REPMAX 604 /* XXX double check this! */ - -/* - * These macros determine the number of bytes between p and the end of - * r->rs_buf relative to l. - */ -#define RPCB_BUF_END(r) (char *)((r)->rm_msgbuf + (r)->rm_buflen) -#define RPCB_BUF_GEQ(r, p, l) \ - ((RPCB_BUF_END((r)) > (char *)(p)) && \ - ((RPCB_BUF_END((r)) - (char *)(p)) >= (l))) -#define RPCB_BUF_EQ(r, p, l) \ - (RPCB_BUF_END((r)) == ((char *)(p) + (l))) - -/* - * The following correspond to RPC(B) detailed in RFC183[13]. - */ -#define RPCB_CALL 0 -#define RPCB_REPLY 1 -#define RPCB_MSG_VERSION 2 -#define RPCB_PROG 100000 -#define RPCB_GETPORT 3 -#define RPCB_GETADDR 3 -#define RPCB_GETADDRLIST 11 -#define RPCB_MSG_ACCEPTED 0 -#define RPCB_MSG_DENIED 1 - -/* BEGIN (Generic XDR structures) */ -typedef struct xdr_string { - u_32_t *xs_len; - char *xs_str; -} xdr_string_t; - -typedef struct xdr_auth { - /* u_32_t xa_flavor; */ - xdr_string_t xa_string; -} xdr_auth_t; - -typedef struct xdr_uaddr { - u_32_t xu_ip; - u_short xu_port; - xdr_string_t xu_str; -} xdr_uaddr_t; - -typedef struct xdr_proto { - u_int xp_proto; - xdr_string_t xp_str; -} xdr_proto_t; - -#define xu_xslen xu_str.xs_len -#define xu_xsstr xu_str.xs_str -#define xp_xslen xp_str.xs_len -#define xp_xsstr xp_str.xs_str -/* END (Generic XDR structures) */ - -/* BEGIN (RPC call structures) */ -typedef struct pmap_args { - /* u_32_t pa_prog; */ - /* u_32_t pa_vers; */ - u_32_t *pa_prot; - /* u_32_t pa_port; */ -} pmap_args_t; - -typedef struct rpcb_args { - /* u_32_t *ra_prog; */ - /* u_32_t *ra_vers; */ - xdr_proto_t ra_netid; - xdr_uaddr_t ra_maddr; - /* xdr_string_t ra_owner; */ -} rpcb_args_t; - -typedef struct rpc_call { - /* u_32_t rc_rpcvers; */ - /* u_32_t rc_prog; */ - u_32_t *rc_vers; - u_32_t *rc_proc; - xdr_auth_t rc_authcred; - xdr_auth_t rc_authverf; - union { - pmap_args_t ra_pmapargs; - rpcb_args_t ra_rpcbargs; - } rpcb_args; -} rpc_call_t; - -#define rc_pmapargs rpcb_args.ra_pmapargs -#define rc_rpcbargs rpcb_args.ra_rpcbargs -/* END (RPC call structures) */ - -/* BEGIN (RPC reply structures) */ -typedef struct rpcb_entry { - xdr_uaddr_t re_maddr; - xdr_proto_t re_netid; - /* u_32_t re_semantics; */ - xdr_string_t re_family; - xdr_proto_t re_proto; - u_32_t *re_more; /* 1 == another entry follows */ -} rpcb_entry_t; - -typedef struct rpcb_listp { - u_32_t *rl_list; /* 1 == list follows */ - int rl_cnt; - rpcb_entry_t rl_entries[2]; /* TCP / UDP only */ -} rpcb_listp_t; - -typedef struct rpc_resp { - /* u_32_t rr_acceptdeny; */ - /* Omitted 'message denied' fork; we don't care about rejects. */ - xdr_auth_t rr_authverf; - /* u_32_t *rr_astat; */ - union { - u_32_t *resp_pmap; - xdr_uaddr_t resp_getaddr; - rpcb_listp_t resp_getaddrlist; - } rpcb_reply; -} rpc_resp_t; - -#define rr_v2 rpcb_reply.resp_pmap -#define rr_v3 rpcb_reply.resp_getaddr -#define rr_v4 rpcb_reply.resp_getaddrlist -/* END (RPC reply structures) */ - -/* BEGIN (RPC message structure & macros) */ -typedef struct rpc_msg { - char rm_msgbuf[RPCB_MAXMSG]; /* RPCB data buffer */ - u_int rm_buflen; - u_32_t *rm_xid; - /* u_32_t Call vs Reply */ - union { - rpc_call_t rb_call; - rpc_resp_t rb_resp; - } rm_body; -} rpc_msg_t; - -#define rm_call rm_body.rb_call -#define rm_resp rm_body.rb_resp -/* END (RPC message structure & macros) */ - -/* - * These code paths aren't hot enough to warrant per transaction - * mutexes. - */ -typedef struct rpcb_xact { - struct rpcb_xact *rx_next; - struct rpcb_xact **rx_pnext; - u_32_t rx_xid; /* RPC transmission ID */ - u_int rx_type; /* RPCB response type */ - u_int rx_ref; /* reference count */ - u_int rx_proto; /* transport protocol (v2 only) */ -} rpcb_xact_t; - -typedef struct rpcb_session { - ipfmutex_t rs_rxlock; - rpcb_xact_t *rs_rxlist; -} rpcb_session_t; - -/* - * For an explanation, please see the following: - * RFC1832 - Sections 3.11, 4.4, and 4.5. - */ -#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 *)); - -#endif /* __IP_PROXY_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c deleted file mode 100644 index 76e8b9f..0000000 --- a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright (C) 1998-2003 by Darren Reed - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * $Id: ip_raudio_pxy.c,v 1.40.2.4 2006/07/14 06:12:17 darrenr Exp $ - */ - -#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 *)); - -static frentry_t raudiofr; - -int raudio_proxy_init = 0; - - -/* - * Real Audio application proxy initialization. - */ -int ippr_raudio_init() -{ - bzero((char *)&raudiofr, sizeof(raudiofr)); - raudiofr.fr_ref = 1; - raudiofr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; - MUTEX_INIT(&raudiofr.fr_lock, "Real Audio proxy rule lock"); - raudio_proxy_init = 1; - - return 0; -} - - -void ippr_raudio_fini() -{ - if (raudio_proxy_init == 1) { - MUTEX_DESTROY(&raudiofr.fr_lock); - raudio_proxy_init = 0; - } -} - - -/* - * 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; -{ - raudio_t *rap; - - 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); - rap->rap_mode = RAP_M_TCP; /* default is for TCP */ - return 0; -} - - - -int ippr_raudio_out(fin, aps, nat) -fr_info_t *fin; -ap_session_t *aps; -nat_t *nat; -{ - raudio_t *rap = aps->aps_data; - unsigned char membuf[512 + 1], *s; - u_short id = 0; - tcphdr_t *tcp; - int off, dlen; - int len = 0; - mb_t *m; - - nat = nat; /* LINT */ - - /* - * If we've already processed the start messages, then nothing left - * for the proxy to do. - */ - if (rap->rap_eos == 1) - return 0; - - m = fin->fin_m; - tcp = (tcphdr_t *)fin->fin_dp; - off = (char *)tcp - (char *)fin->fin_ip; - off += (TCP_OFF(tcp) << 2) + fin->fin_ipoff; - -#ifdef __sgi - dlen = fin->fin_plen - off; -#else - dlen = MSGDSIZE(m) - off; -#endif - if (dlen <= 0) - return 0; - - if (dlen > sizeof(membuf)) - dlen = sizeof(membuf); - - bzero((char *)membuf, sizeof(membuf)); - COPYDATA(m, off, dlen, (char *)membuf); - /* - * In all the startup parsing, ensure that we don't go outside - * the packet buffer boundary. - */ - /* - * Look for the start of connection "PNA" string if not seen yet. - */ - if (rap->rap_seenpna == 0) { - s = (u_char *)memstr("PNA", (char *)membuf, 3, dlen); - if (s == NULL) - return 0; - s += 3; - rap->rap_seenpna = 1; - } else - s = membuf; - - /* - * Directly after the PNA will be the version number of this - * connection. - */ - if (rap->rap_seenpna == 1 && rap->rap_seenver == 0) { - if ((s + 1) - membuf < dlen) { - rap->rap_version = (*s << 8) | *(s + 1); - s += 2; - rap->rap_seenver = 1; - } else - return 0; - } - - /* - * Now that we've been past the PNA and version number, we're into the - * startup messages block. This ends when a message with an ID of 0. - */ - while ((rap->rap_eos == 0) && ((s + 1) - membuf < dlen)) { - if (rap->rap_gotid == 0) { - id = (*s << 8) | *(s + 1); - s += 2; - rap->rap_gotid = 1; - if (id == RA_ID_END) { - rap->rap_eos = 1; - break; - } - } else if (rap->rap_gotlen == 0) { - len = (*s << 8) | *(s + 1); - s += 2; - rap->rap_gotlen = 1; - } - - if (rap->rap_gotid == 1 && rap->rap_gotlen == 1) { - if (id == RA_ID_UDP) { - rap->rap_mode &= ~RAP_M_TCP; - rap->rap_mode |= RAP_M_UDP; - rap->rap_plport = (*s << 8) | *(s + 1); - } else if (id == RA_ID_ROBUST) { - rap->rap_mode |= RAP_M_ROBUST; - rap->rap_prport = (*s << 8) | *(s + 1); - } - s += len; - rap->rap_gotlen = 0; - rap->rap_gotid = 0; - } - } - return 0; -} - - -int ippr_raudio_in(fin, aps, nat) -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; - struct in_addr swa, swb; - int off, dlen, slen; - int a1, a2, a3, a4; - u_short sp, dp; - fr_info_t fi; - tcp_seq seq; - nat_t *nat2; - u_char swp; - ip_t *ip; - mb_t *m; - - /* - * Wait until we've seen the end of the start messages and even then - * only proceed further if we're using UDP. If they want to use TCP - * then data is sent back on the same channel that is already open. - */ - if (rap->rap_sdone != 0) - return 0; - - m = fin->fin_m; - tcp = (tcphdr_t *)fin->fin_dp; - off = (char *)tcp - (char *)fin->fin_ip; - off += (TCP_OFF(tcp) << 2) + fin->fin_ipoff; - -#ifdef __sgi - dlen = fin->fin_plen - off; -#else - dlen = MSGDSIZE(m) - off; -#endif - if (dlen <= 0) - return 0; - - if (dlen > sizeof(membuf)) - dlen = sizeof(membuf); - - bzero((char *)membuf, sizeof(membuf)); - COPYDATA(m, off, dlen, (char *)membuf); - - seq = ntohl(tcp->th_seq); - /* - * Check to see if the data in this packet is of interest to us. - * We only care for the first 19 bytes coming back from the server. - */ - if (rap->rap_sseq == 0) { - s = (u_char *)memstr("PNA", (char *)membuf, 3, dlen); - if (s == NULL) - return 0; - a1 = s - membuf; - dlen -= a1; - a1 = 0; - rap->rap_sseq = seq; - a2 = MIN(dlen, sizeof(rap->rap_svr)); - } else if (seq <= rap->rap_sseq + sizeof(rap->rap_svr)) { - /* - * seq # which is the start of data and from that the offset - * into the buffer array. - */ - a1 = seq - rap->rap_sseq; - a2 = MIN(dlen, sizeof(rap->rap_svr)); - a2 -= a1; - s = membuf; - } else - return 0; - - for (a3 = a1, a4 = a2; (a4 > 0) && (a3 < 19) && (a3 >= 0); a4--,a3++) { - rap->rap_sbf |= (1 << a3); - rap->rap_svr[a3] = *s++; - } - - if ((rap->rap_sbf != 0x7ffff) || (!rap->rap_eos)) /* 19 bits */ - return 0; - rap->rap_sdone = 1; - - s = (u_char *)rap->rap_svr + 11; - if (((*s << 8) | *(s + 1)) == RA_ID_ROBUST) { - s += 2; - rap->rap_srport = (*s << 8) | *(s + 1); - } - - ip = fin->fin_ip; - swp = ip->ip_p; - swa = ip->ip_src; - swb = ip->ip_dst; - - ip->ip_p = IPPROTO_UDP; - ip->ip_src = nat->nat_inip; - ip->ip_dst = nat->nat_oip; - - bcopy((char *)fin, (char *)&fi, sizeof(fi)); - bzero((char *)tcp2, sizeof(*tcp2)); - 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; - fi.fin_dlen = sizeof(*tcp2); - 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); - - if (((rap->rap_mode & RAP_M_UDP_ROBUST) == RAP_M_UDP_ROBUST) && - (rap->rap_srport != 0)) { - dp = rap->rap_srport; - sp = rap->rap_prport; - tcp2->th_sport = htons(sp); - tcp2->th_dport = htons(dp); - fi.fin_data[0] = dp; - fi.fin_data[1] = sp; - fi.fin_out = 0; - nat2 = nat_new(&fi, nat->nat_ptr, NULL, - NAT_SLAVE|IPN_UDP | (sp ? 0 : SI_W_SPORT), - NAT_OUTBOUND); - if (nat2 != NULL) { - (void) nat_proto(&fi, nat2, IPN_UDP); - nat_update(&fi, nat2, nat2->nat_ptr); - - (void) fr_addstate(&fi, NULL, (sp ? 0 : SI_W_SPORT)); - if (fi.fin_state != NULL) - fr_statederef((ipstate_t **)&fi.fin_state); - } - } - - if ((rap->rap_mode & RAP_M_UDP) == RAP_M_UDP) { - sp = rap->rap_plport; - tcp2->th_sport = htons(sp); - tcp2->th_dport = 0; /* XXX - don't specify remote port */ - fi.fin_data[0] = sp; - fi.fin_data[1] = 0; - fi.fin_out = 1; - nat2 = nat_new(&fi, nat->nat_ptr, NULL, - NAT_SLAVE|IPN_UDP|SI_W_DPORT, - NAT_OUTBOUND); - if (nat2 != NULL) { - (void) nat_proto(&fi, nat2, IPN_UDP); - nat_update(&fi, nat2, nat2->nat_ptr); - - (void) fr_addstate(&fi, NULL, SI_W_DPORT); - if (fi.fin_state != NULL) - fr_statederef((ipstate_t **)&fi.fin_state); - } - } - - ip->ip_p = swp; - ip->ip_len = slen; - ip->ip_src = swa; - ip->ip_dst = swb; - return 0; -} diff --git a/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c b/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c deleted file mode 100644 index 0af3f9b..0000000 --- a/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (C) 1998-2003 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 $ - * - * Simple RCMD transparent proxy for in-kernel use. For use with the NAT - * code. - */ - -#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 *)); -u_short ipf_rcmd_atoi __P((char *)); -int ippr_rcmd_portmsg __P((fr_info_t *, ap_session_t *, nat_t *)); - -static frentry_t rcmdfr; - -int rcmd_proxy_init = 0; - - -/* - * RCMD application proxy initialization. - */ -int ippr_rcmd_init() -{ - bzero((char *)&rcmdfr, sizeof(rcmdfr)); - rcmdfr.fr_ref = 1; - rcmdfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; - MUTEX_INIT(&rcmdfr.fr_lock, "RCMD proxy rule lock"); - rcmd_proxy_init = 1; - - return 0; -} - - -void ippr_rcmd_fini() -{ - if (rcmd_proxy_init == 1) { - MUTEX_DESTROY(&rcmdfr.fr_lock); - rcmd_proxy_init = 0; - } -} - - -/* - * Setup for a new RCMD proxy. - */ -int ippr_rcmd_new(fin, aps, nat) -fr_info_t *fin; -ap_session_t *aps; -nat_t *nat; -{ - tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp; - - 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) { -#ifdef IP_RCMD_PROXY_DEBUG - printf("ippr_rcmd_new:KMALLOCS(%d) failed\n", sizeof(u_32_t)); -#endif - return -1; - } - *(u_32_t *)aps->aps_data = 0; - aps->aps_sport = tcp->th_sport; - aps->aps_dport = tcp->th_dport; - return 0; -} - - -/* - * ipf_rcmd_atoi - implement a simple version of atoi - */ -u_short ipf_rcmd_atoi(ptr) -char *ptr; -{ - register char *s = ptr, c; - register u_short i = 0; - - while (((c = *s++) != '\0') && ISDIGIT(c)) { - i *= 10; - i += c - '0'; - } - return i; -} - - -int ippr_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; - char portbuf[8], *s; - fr_info_t fi; - u_short sp; - nat_t *nat2; - 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; -#endif - if (dlen <= 0) - return 0; - - bzero(portbuf, sizeof(portbuf)); - COPYDATA(m, off, MIN(sizeof(portbuf), dlen), portbuf); - - portbuf[sizeof(portbuf) - 1] = '\0'; - s = portbuf; - sp = ipf_rcmd_atoi(s); - if (sp == 0) { -#ifdef IP_RCMD_PROXY_DEBUG - printf("ippr_rcmd_portmsg:sp == 0 dlen %d [%s]\n", - dlen, portbuf); -#endif - return 0; - } - - /* - * Add skeleton NAT entry for connection which will come back the - * other way. - */ - 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; - - if (nat->nat_dir == NAT_OUTBOUND) { - fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; - ip->ip_src = nat->nat_inip; - } else { - fi.fin_fi.fi_saddr = nat->nat_oip.s_addr; - ip->ip_src = nat->nat_oip; - 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, 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); - } - ip->ip_len = slen; - ip->ip_src = swip; - ip->ip_dst = swip2; - } - return 0; -} - - -int ippr_rcmd_out(fin, aps, nat) -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 0; -} - - -int ippr_rcmd_in(fin, aps, nat) -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 0; -} diff --git a/sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c b/sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c deleted file mode 100644 index da76fde..0000000 --- a/sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c +++ /dev/null @@ -1,1464 +0,0 @@ -/* - * Copyright (C) 2002-2003 by Ryan Beasley <ryanb@goddamnbastard.org> - * - * See the IPFILTER.LICENCE file for details on licencing. - */ -/* - * Overview: - * This is an in-kernel application proxy for Sun's RPCBIND (nee portmap) - * protocol as defined in RFC1833. It is far from complete, mostly - * lacking in less-likely corner cases, but it's definitely functional. - * - * Invocation: - * rdr <int> <e_ip>/32 port <e_p> -> <i_ip> port <i_p> udp proxy rpcbu - * - * If the host running IP Filter is the same as the RPC server, it's - * perfectly legal for both the internal and external addresses and ports - * to match. - * - * When triggered by appropriate IP NAT rules, this proxy works by - * examining data contained in received packets. Requests and replies are - * modified, NAT and state table entries created, etc., as necessary. - */ -/* - * TODO / NOTES - * - * o Must implement locking to protect proxy session data. - * o Fragmentation isn't supported. - * o Only supports UDP. - * o Doesn't support multiple RPC records in a single request. - * o Errors should be more fine-grained. (e.g., malloc failure vs. - * illegal RPCB request / reply) - * o Even with the limit on the total amount of recorded transactions, - * should there be a timeout on transaction removal? - * o There is a potential collision between cloning, wildcard NAT and - * state entries. There should be an appr_getport routine for - * to avoid this. - * 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 $ - */ - -#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 *, - 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 *, - 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 *, - mb_t *, u_int)); -static int ippr_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 *, - 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 *, - mb_t *, u_int)); -static int ippr_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)); - -/* - * Global variables - */ -static frentry_t rpcbfr; /* Skeleton rule for reference by entities - this proxy creates. */ -static int rpcbcnt; /* Upper bound of allocated RPCB sessions. */ - /* XXX rpcbcnt still requires locking. */ - -int rpcb_proxy_init = 0; - - -/* - * Since rpc_msg contains only pointers, one should use this macro as a - * handy way to get to the goods. (In case you're wondering about the name, - * this started as BYTEREF -> BREF -> B.) - */ -#define B(r) (u_32_t)ntohl(*(r)) - -/* - * Public subroutines - */ - -/* -------------------------------------------------------------------- */ -/* Function: ippr_rpcb_init */ -/* Returns: int - 0 == success */ -/* Parameters: (void) */ -/* */ -/* Initialize the filter rule entry and session limiter. */ -/* -------------------------------------------------------------------- */ -int -ippr_rpcb_init() -{ - rpcbcnt = 0; - - bzero((char *)&rpcbfr, sizeof(rpcbfr)); - rpcbfr.fr_ref = 1; - 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. */ -/* -------------------------------------------------------------------- */ -void -ippr_rpcb_fini() -{ - if (rpcb_proxy_init == 1) { - MUTEX_DESTROY(&rpcbfr.fr_lock); - rpcb_proxy_init = 0; - } -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_rpcb_new */ -/* Returns: int - -1 == failure, 0 == success */ -/* Parameters: fin(I) - pointer to packet information */ -/* aps(I) - pointer to proxy session structure */ -/* nat(I) - pointer to NAT session structure */ -/* */ -/* Allocate resources for per-session proxy structures. */ -/* -------------------------------------------------------------------- */ -int -ippr_rpcb_new(fin, aps, nat) - fr_info_t *fin; - ap_session_t *aps; - nat_t *nat; -{ - rpcb_session_t *rs; - - fin = fin; /* LINT */ - nat = nat; /* LINT */ - - KMALLOC(rs, rpcb_session_t *); - if (rs == NULL) - return(-1); - - bzero((char *)rs, sizeof(*rs)); - MUTEX_INIT(&rs->rs_rxlock, "ipf Sun RPCB proxy session lock"); - - aps->aps_data = rs; - - return(0); -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_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) - ap_session_t *aps; -{ - rpcb_session_t *rs; - rs = (rpcb_session_t *)aps->aps_data; - - MUTEX_ENTER(&rs->rs_rxlock); - ippr_rpcb_flush(rs); - MUTEX_EXIT(&rs->rs_rxlock); - MUTEX_DESTROY(&rs->rs_rxlock); -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_rpcb_in */ -/* Returns: int - APR_ERR(1) == drop the packet, */ -/* APR_ERR(2) == kill the proxy session, */ -/* else change in packet length (in bytes) */ -/* Parameters: fin(I) - pointer to packet information */ -/* ip(I) - pointer to packet header */ -/* aps(I) - pointer to proxy session structure */ -/* nat(I) - pointer to NAT session structure */ -/* */ -/* Given a presumed RPCB request, perform some minor tests and pass off */ -/* for decoding. Also pass packet off for a rewrite if necessary. */ -/* -------------------------------------------------------------------- */ -int -ippr_rpcb_in(fin, aps, nat) - fr_info_t *fin; - ap_session_t *aps; - nat_t *nat; -{ - rpc_msg_t rpcmsg, *rm; - rpcb_session_t *rs; - u_int off, dlen; - mb_t *m; - int rv; - - /* Disallow fragmented or illegally short packets. */ - if ((fin->fin_flx & (FI_FRAG|FI_SHORT)) != 0) - return(APR_ERR(1)); - - /* Perform basic variable initialization. */ - rs = (rpcb_session_t *)aps->aps_data; - - m = fin->fin_m; - off = (char *)fin->fin_dp - (char *)fin->fin_ip; - off += sizeof(udphdr_t) + fin->fin_ipoff; - dlen = fin->fin_dlen - sizeof(udphdr_t); - - /* Disallow packets outside legal range for supported requests. */ - if ((dlen < RPCB_REQMIN) || (dlen > RPCB_REQMAX)) - return(APR_ERR(1)); - - /* Copy packet over to convenience buffer. */ - rm = &rpcmsg; - bzero((char *)rm, sizeof(*rm)); - COPYDATA(m, off, dlen, (caddr_t)&rm->rm_msgbuf); - rm->rm_buflen = dlen; - - /* Send off to decode request. */ - rv = ippr_rpcb_decodereq(fin, nat, rs, rm); - - switch(rv) - { - case -1: - return(APR_ERR(1)); - /*NOTREACHED*/ - break; - case 0: - break; - case 1: - rv = ippr_rpcb_modreq(fin, nat, rm, m, off); - break; - default: - /*CONSTANTCONDITION*/ - IPF_PANIC(1, ("illegal rv %d (ippr_rpcb_req)", rv)); - } - - return(rv); -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_rpcb_out */ -/* Returns: int - APR_ERR(1) == drop the packet, */ -/* APR_ERR(2) == kill the proxy session, */ -/* else change in packet length (in bytes) */ -/* Parameters: fin(I) - pointer to packet information */ -/* ip(I) - pointer to packet header */ -/* aps(I) - pointer to proxy session structure */ -/* nat(I) - pointer to NAT session structure */ -/* */ -/* Given a presumed RPCB reply, perform some minor tests and pass off */ -/* for decoding. If the message indicates a successful request with */ -/* valid addressing information, create NAT and state structures to */ -/* allow direct communication between RPC client and server. */ -/* -------------------------------------------------------------------- */ -int -ippr_rpcb_out(fin, aps, nat) - fr_info_t *fin; - ap_session_t *aps; - nat_t *nat; -{ - rpc_msg_t rpcmsg, *rm; - rpcb_session_t *rs; - rpcb_xact_t *rx; - u_int off, dlen; - int rv, diff; - mb_t *m; - - /* Disallow fragmented or illegally short packets. */ - if ((fin->fin_flx & (FI_FRAG|FI_SHORT)) != 0) - return(APR_ERR(1)); - - /* Perform basic variable initialization. */ - rs = (rpcb_session_t *)aps->aps_data; - rx = NULL; - - m = fin->fin_m; - off = (char *)fin->fin_dp - (char *)fin->fin_ip; - off += sizeof(udphdr_t) + fin->fin_ipoff; - dlen = fin->fin_dlen - sizeof(udphdr_t); - diff = 0; - - /* Disallow packets outside legal range for supported requests. */ - if ((dlen < RPCB_REPMIN) || (dlen > RPCB_REPMAX)) - return(APR_ERR(1)); - - /* Copy packet over to convenience buffer. */ - rm = &rpcmsg; - bzero((char *)rm, sizeof(*rm)); - COPYDATA(m, off, dlen, (caddr_t)&rm->rm_msgbuf); - rm->rm_buflen = dlen; - - rx = NULL; /* XXX gcc */ - - /* Send off to decode reply. */ - rv = ippr_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); - MUTEX_EXIT(&rs->rs_rxlock); - } - return(APR_ERR(1)); - /*NOTREACHED*/ - break; - case 0: /* Negative reply / request rejected */ - break; - case 1: /* Positive reply */ - /* - * With the IP address embedded in a GETADDR(LIST) reply, - * we'll need to rewrite the packet in the very possible - * event that the internal & external addresses aren't the - * 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 (rx->rx_type == RPCB_RES_STRING) - diff = ippr_rpcb_modv3(fin, nat, rm, m, off); - else if (rx->rx_type == RPCB_RES_LIST) - diff = ippr_rpcb_modv4(fin, nat, rm, m, off); - } - break; - default: - /*CONSTANTCONDITION*/ - IPF_PANIC(1, ("illegal rv %d (ippr_rpcb_decoderep)", rv)); - } - - if (rx != NULL) { - MUTEX_ENTER(&rs->rs_rxlock); - /* XXX Gross hack - I'm overloading the reference - * counter to deal with both threads and retransmitted - * requests. One deref signals that this thread is - * finished with rx, and the other signals that we've - * processed its reply. - */ - ippr_rpcb_deref(rs, rx); - ippr_rpcb_deref(rs, rx); - MUTEX_EXIT(&rs->rs_rxlock); - } - - return(diff); -} - -/* - * Private support subroutines - */ - -/* -------------------------------------------------------------------- */ -/* Function: ippr_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) - rpcb_session_t *rs; -{ - rpcb_xact_t *r1, *r2; - - r1 = rs->rs_rxlist; - if (r1 == NULL) - return; - - while (r1 != NULL) { - r2 = r1; - r1 = r1->rx_next; - KFREE(r2); - } -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_rpcb_decodereq */ -/* Returns: int - -1 == bad request or critical failure, */ -/* 0 == request successfully decoded, */ -/* 1 == request successfully decoded; requires */ -/* address rewrite/modification */ -/* Parameters: fin(I) - pointer to packet information */ -/* nat(I) - pointer to NAT session structure */ -/* rs(I) - pointer to RPCB session structure */ -/* rm(I) - pointer to RPC message structure */ -/* */ -/* Take a presumed RPCB request, decode it, and store the results in */ -/* the transaction list. If the internal target address needs to be */ -/* modified, store its location in ptr. */ -/* WARNING: It's the responsibility of the caller to make sure there */ -/* is enough room in rs_buf for the basic RPC message "preamble". */ -/* -------------------------------------------------------------------- */ -static int -ippr_rpcb_decodereq(fin, nat, rs, rm) - fr_info_t *fin; - nat_t *nat; - rpcb_session_t *rs; - rpc_msg_t *rm; -{ - rpcb_args_t *ra; - u_32_t xdr, *p; - rpc_call_t *rc; - rpcb_xact_t rx; - int mod; - - p = (u_32_t *)rm->rm_msgbuf; - mod = 0; - - bzero((char *)&rx, sizeof(rx)); - rc = &rm->rm_call; - - rm->rm_xid = p; - rx.rx_xid = B(p++); /* Record this message's XID. */ - - /* Parse out and test the RPC header. */ - if ((B(p++) != RPCB_CALL) || - (B(p++) != RPCB_MSG_VERSION) || - (B(p++) != RPCB_PROG)) - return(-1); - - /* Record the RPCB version and procedure. */ - rc->rc_vers = p++; - rc->rc_proc = p++; - - /* Bypass RPC authentication stuff. */ - if (ippr_rpcb_skipauth(rm, &rc->rc_authcred, &p) != 0) - return(-1); - if (ippr_rpcb_skipauth(rm, &rc->rc_authverf, &p) != 0) - return(-1); - - /* Compare RPCB version and procedure numbers. */ - switch(B(rc->rc_vers)) - { - case 2: - /* This proxy only supports PMAP_GETPORT. */ - if (B(rc->rc_proc) != RPCB_GETPORT) - return(-1); - - /* Portmap requests contain four 4 byte parameters. */ - if (RPCB_BUF_EQ(rm, p, 16) == 0) - return(-1); - - p += 2; /* Skip requested program and version numbers. */ - - /* Sanity check the requested protocol. */ - xdr = B(p); - if (!(xdr == IPPROTO_UDP || xdr == IPPROTO_TCP)) - return(-1); - - rx.rx_type = RPCB_RES_PMAP; - rx.rx_proto = xdr; - break; - case 3: - case 4: - /* GETADDRLIST is exclusive to v4; GETADDR for v3 & v4 */ - switch(B(rc->rc_proc)) - { - case RPCB_GETADDR: - rx.rx_type = RPCB_RES_STRING; - rx.rx_proto = (u_int)fin->fin_p; - break; - case RPCB_GETADDRLIST: - if (B(rc->rc_vers) != 4) - return(-1); - rx.rx_type = RPCB_RES_LIST; - break; - default: - return(-1); - } - - ra = &rc->rc_rpcbargs; - - /* Decode the 'struct rpcb' request. */ - if (ippr_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)) - 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)) - mod = 1; - break; - default: - return(-1); - } - - MUTEX_ENTER(&rs->rs_rxlock); - if (ippr_rpcb_insert(rs, &rx) != 0) { - MUTEX_EXIT(&rs->rs_rxlock); - return(-1); - } - MUTEX_EXIT(&rs->rs_rxlock); - - return(mod); -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_rpcb_skipauth */ -/* Returns: int -- -1 == illegal auth parameters (lengths) */ -/* 0 == valid parameters, pointer advanced */ -/* Parameters: rm(I) - pointer to RPC message structure */ -/* auth(I) - pointer to RPC auth structure */ -/* buf(IO) - pointer to location within convenience buffer */ -/* */ -/* Record auth data length & location of auth data, then advance past */ -/* it. */ -/* -------------------------------------------------------------------- */ -static int -ippr_rpcb_skipauth(rm, auth, buf) - rpc_msg_t *rm; - xdr_auth_t *auth; - u_32_t **buf; -{ - u_32_t *p, xdr; - - p = *buf; - - /* Make sure we have enough space for expected fixed auth parms. */ - if (RPCB_BUF_GEQ(rm, p, 8) == 0) - return(-1); - - p++; /* We don't care about auth_flavor. */ - - auth->xa_string.xs_len = p; - xdr = B(p++); /* Length of auth_data */ - - /* Test for absurdity / illegality of auth_data length. */ - if ((XDRALIGN(xdr) < xdr) || (RPCB_BUF_GEQ(rm, p, XDRALIGN(xdr)) == 0)) - return(-1); - - auth->xa_string.xs_str = (char *)p; - - p += XDRALIGN(xdr); /* Advance our location. */ - - *buf = (u_32_t *)p; - - return(0); -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_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) - rpcb_session_t *rs; - rpcb_xact_t *rx; -{ - rpcb_xact_t *rxp; - - rxp = ippr_rpcb_lookup(rs, rx->rx_xid); - if (rxp != NULL) { - ++rxp->rx_ref; - return(0); - } - - if (rpcbcnt == RPCB_MAXREQS) - return(-1); - - KMALLOC(rxp, rpcb_xact_t *); - if (rxp == NULL) - return(-1); - - bcopy((char *)rx, (char *)rxp, sizeof(*rx)); - - if (rs->rs_rxlist != NULL) - rs->rs_rxlist->rx_pnext = &rxp->rx_next; - - rxp->rx_pnext = &rs->rs_rxlist; - rxp->rx_next = rs->rs_rxlist; - rs->rs_rxlist = rxp; - - rxp->rx_ref = 1; - - ++rpcbcnt; - - return(0); -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_rpcb_xdrrpcb */ -/* Returns: int -- -1 == failure to properly decode the request */ -/* 0 == rpcb successfully decoded */ -/* Parameters: rs(I) - pointer to RPCB session structure */ -/* p(I) - pointer to location within session buffer */ -/* rpcb(O) - pointer to rpcb (xdr type) structure */ -/* */ -/* Decode a XDR encoded rpcb structure and record its contents in rpcb */ -/* within only the context of TCP/UDP over IP networks. */ -/* -------------------------------------------------------------------- */ -static int -ippr_rpcb_xdrrpcb(rm, p, ra) - rpc_msg_t *rm; - u_32_t *p; - rpcb_args_t *ra; -{ - if (!RPCB_BUF_GEQ(rm, p, 20)) - return(-1); - - /* Bypass target program & version. */ - p += 2; - - /* Decode r_netid. Must be "tcp" or "udp". */ - if (ippr_rpcb_getproto(rm, &ra->ra_netid, &p) != 0) - return(-1); - - /* Decode r_maddr. */ - if (ippr_rpcb_getuaddr(rm, &ra->ra_maddr, &p) != 0) - return(-1); - - /* Advance to r_owner and make sure it's empty. */ - if (!RPCB_BUF_EQ(rm, p, 4) || (B(p) != 0)) - return(-1); - - return(0); -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_rpcb_getuaddr */ -/* Returns: int -- -1 == illegal string, */ -/* 0 == string parsed; contents recorded */ -/* Parameters: rm(I) - pointer to RPC message structure */ -/* xu(I) - pointer to universal address structure */ -/* p(IO) - pointer to location within message buffer */ -/* */ -/* Decode the IP address / port at p and record them in xu. */ -/* -------------------------------------------------------------------- */ -static int -ippr_rpcb_getuaddr(rm, xu, p) - rpc_msg_t *rm; - xdr_uaddr_t *xu; - u_32_t **p; -{ - char *c, *i, *b, *pp; - u_int d, dd, l, t; - char uastr[24]; - - /* Test for string length. */ - if (!RPCB_BUF_GEQ(rm, *p, 4)) - return(-1); - - xu->xu_xslen = (*p)++; - xu->xu_xsstr = (char *)*p; - - /* Length check */ - l = B(xu->xu_xslen); - if (l < 11 || l > 23 || !RPCB_BUF_GEQ(rm, *p, XDRALIGN(l))) - return(-1); - - /* Advance p */ - *(char **)p += XDRALIGN(l); - - /* Copy string to local buffer & terminate C style */ - bcopy(xu->xu_xsstr, uastr, l); - uastr[l] = '\0'; - - i = (char *)&xu->xu_ip; - pp = (char *)&xu->xu_port; - - /* - * Expected format: a.b.c.d.e.f where [a-d] correspond to bytes of - * an IP address and [ef] are the bytes of a L4 port. - */ - if (!(ISDIGIT(uastr[0]) && ISDIGIT(uastr[l-1]))) - return(-1); - b = uastr; - for (c = &uastr[1], d = 0, dd = 0; c < &uastr[l-1]; c++) { - if (ISDIGIT(*c)) { - dd = 0; - continue; - } - if (*c == '.') { - if (dd != 0) - return(-1); - - /* Check for ASCII byte. */ - *c = '\0'; - t = ippr_rpcb_atoi(b); - if (t > 255) - return(-1); - - /* Aim b at beginning of the next byte. */ - b = c + 1; - - /* Switch off IP addr vs port parsing. */ - if (d < 4) - i[d++] = t & 0xff; - else - pp[d++ - 4] = t & 0xff; - - dd = 1; - continue; - } - return(-1); - } - if (d != 5) /* String must contain exactly 5 periods. */ - return(-1); - - /* Handle the last byte (port low byte) */ - t = ippr_rpcb_atoi(b); - if (t > 255) - return(-1); - pp[d - 4] = t & 0xff; - - return(0); -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_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) - char *ptr; -{ - register char *s = ptr, c; - register u_int i = 0; - - while (((c = *s++) != '\0') && ISDIGIT(c)) { - i *= 10; - i += c - '0'; - } - return i; -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_rpcb_modreq */ -/* Returns: int -- change in datagram length */ -/* APR_ERR(2) - critical failure */ -/* Parameters: fin(I) - pointer to packet information */ -/* nat(I) - pointer to NAT session */ -/* rm(I) - pointer to RPC message structure */ -/* m(I) - pointer to mbuf chain */ -/* off(I) - current offset within mbuf chain */ -/* */ -/* When external and internal addresses differ, we rewrite the former */ -/* with the latter. (This is exclusive to protocol versions 3 & 4). */ -/* -------------------------------------------------------------------- */ -static int -ippr_rpcb_modreq(fin, nat, rm, m, off) - fr_info_t *fin; - nat_t *nat; - rpc_msg_t *rm; - mb_t *m; - u_int off; -{ - u_int len, xlen, pos, bogo; - rpcb_args_t *ra; - char uaddr[24]; - udphdr_t *udp; - char *i, *p; - int diff; - - ra = &rm->rm_call.rc_rpcbargs; - i = (char *)&nat->nat_inip.s_addr; - p = (char *)&nat->nat_inport; - - /* Form new string. */ - bzero(uaddr, sizeof(uaddr)); /* Just in case we need padding. */ -#if defined(SNPRINTF) && defined(_KERNEL) - SNPRINTF(uaddr, sizeof(uaddr), -#else - (void) sprintf(uaddr, -#endif - "%u.%u.%u.%u.%u.%u", i[0] & 0xff, i[1] & 0xff, - i[2] & 0xff, i[3] & 0xff, p[0] & 0xff, p[1] & 0xff); - len = strlen(uaddr); - xlen = XDRALIGN(len); - - /* Determine mbuf offset to start writing to. */ - pos = (char *)ra->ra_maddr.xu_xslen - rm->rm_msgbuf; - off += pos; - - /* Write new string length. */ - bogo = htonl(len); - COPYBACK(m, off, 4, (caddr_t)&bogo); - off += 4; - - /* Write new string. */ - COPYBACK(m, off, xlen, uaddr); - off += xlen; - - /* Write in zero r_owner. */ - bogo = 0; - COPYBACK(m, off, 4, (caddr_t)&bogo); - - /* Determine difference in data lengths. */ - diff = xlen - XDRALIGN(B(ra->ra_maddr.xu_xslen)); - - /* - * If our new string has a different length, make necessary - * adjustments. - */ - 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; - /* XXX Storage lengths. */ - } - - return(diff); -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_rpcb_decoderep */ -/* Returns: int - -1 == bad request or critical failure, */ -/* 0 == valid, negative reply */ -/* 1 == vaddlid, positive reply; needs no changes */ -/* Parameters: fin(I) - pointer to packet information */ -/* nat(I) - pointer to NAT session structure */ -/* rs(I) - pointer to RPCB session structure */ -/* rm(I) - pointer to RPC message structure */ -/* rxp(O) - pointer to RPCB transaction structure */ -/* */ -/* Take a presumed RPCB reply, extract the XID, search for the original */ -/* request information, and determine whether the request was accepted */ -/* or rejected. With a valid accepted reply, go ahead and create NAT */ -/* and state entries, and finish up by rewriting the packet as */ -/* required. */ -/* */ -/* WARNING: It's the responsibility of the caller to make sure there */ -/* is enough room in rs_buf for the basic RPC message "preamble". */ -/* -------------------------------------------------------------------- */ -static int -ippr_rpcb_decoderep(fin, nat, rs, rm, rxp) - fr_info_t *fin; - nat_t *nat; - rpcb_session_t *rs; - rpc_msg_t *rm; - rpcb_xact_t **rxp; -{ - rpcb_listp_t *rl; - rpcb_entry_t *re; - rpcb_xact_t *rx; - u_32_t xdr, *p; - rpc_resp_t *rr; - int rv, cnt; - - p = (u_32_t *)rm->rm_msgbuf; - - bzero((char *)&rx, sizeof(rx)); - rr = &rm->rm_resp; - - rm->rm_xid = p; - xdr = B(p++); /* Record this message's XID. */ - - /* Lookup XID */ - MUTEX_ENTER(&rs->rs_rxlock); - if ((rx = ippr_rpcb_lookup(rs, xdr)) == NULL) { - MUTEX_EXIT(&rs->rs_rxlock); - return(-1); - } - ++rx->rx_ref; /* per thread reference */ - MUTEX_EXIT(&rs->rs_rxlock); - - *rxp = rx; - - /* Test call vs reply */ - if (B(p++) != RPCB_REPLY) - return(-1); - - /* Test reply_stat */ - switch(B(p++)) - { - case RPCB_MSG_DENIED: - return(0); - case RPCB_MSG_ACCEPTED: - break; - default: - return(-1); - } - - /* Bypass RPC authentication stuff. */ - if (ippr_rpcb_skipauth(rm, &rr->rr_authverf, &p) != 0) - return(-1); - - /* Test accept status */ - if (!RPCB_BUF_GEQ(rm, p, 4)) - return(-1); - if (B(p++) != 0) - return(0); - - /* Parse out the expected reply */ - switch(rx->rx_type) - { - case RPCB_RES_PMAP: - /* 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) - return(-1); - break; - case RPCB_RES_STRING: - /* Expecting a XDR string; need 4 bytes for length */ - if (!RPCB_BUF_GEQ(rm, p, 4)) - return(-1); - - rr->rr_v3.xu_str.xs_len = p++; - rr->rr_v3.xu_str.xs_str = (char *)p; - - xdr = B(rr->rr_v3.xu_xslen); - - /* A null string indicates an unregistered service */ - if ((xdr == 0) && RPCB_BUF_EQ(rm, p, 0)) - return(0); - - /* Decode the target IP address / port. */ - if (ippr_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) - return(-1); - - /* Create NAT & state table entries. */ - if (ippr_rpcb_getnat(fin, nat, rx->rx_proto, - (u_int)rr->rr_v3.xu_port) != 0) - return(-1); - break; - case RPCB_RES_LIST: - if (!RPCB_BUF_GEQ(rm, p, 4)) - return(-1); - /* rpcb_entry_list_ptr */ - switch(B(p)) - { - case 0: - return(0); - /*NOTREACHED*/ - break; - case 1: - break; - default: - return(-1); - } - rl = &rr->rr_v4; - rl->rl_list = p++; - cnt = 0; - - for(;;) { - re = &rl->rl_entries[rl->rl_cnt]; - if (ippr_rpcb_getuaddr(rm, &re->re_maddr, &p) != 0) - return(-1); - if (ippr_rpcb_getproto(rm, &re->re_netid, &p) != 0) - return(-1); - /* re_semantics & re_pfamily length */ - if (!RPCB_BUF_GEQ(rm, p, 12)) - return(-1); - p++; /* Skipping re_semantics. */ - xdr = B(p++); - if ((xdr != 4) || strncmp((char *)p, "inet", 4)) - return(-1); - p++; - if (ippr_rpcb_getproto(rm, &re->re_proto, &p) != 0) - return(-1); - if (!RPCB_BUF_GEQ(rm, p, 4)) - return(-1); - re->re_more = p; - if (B(re->re_more) > 1) /* 0,1 only legal values */ - return(-1); - ++rl->rl_cnt; - ++cnt; - if (B(re->re_more) == 0) - break; - /* Replies in max out at 2; TCP and/or UDP */ - if (cnt > 2) - return(-1); - p++; - } - - 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, - re->re_proto.xp_proto, - (u_int)re->re_maddr.xu_port); - if (rv != 0) - return(-1); - } - break; - default: - /*CONSTANTCONDITION*/ - IPF_PANIC(1, ("illegal rx_type %d", rx->rx_type)); - } - - return(1); -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_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) - rpcb_session_t *rs; - u_32_t xid; -{ - rpcb_xact_t *rx; - - if (rs->rs_rxlist == NULL) - return(NULL); - - for (rx = rs->rs_rxlist; rx != NULL; rx = rx->rx_next) - if (rx->rx_xid == xid) - break; - - return(rx); -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_rpcb_deref */ -/* Returns: (void) */ -/* Parameters: rs(I) - pointer to RPCB session */ -/* rx(I) - pointer to RPC transaction struct to remove */ -/* force(I) - indicates to delete entry regardless of */ -/* reference count */ -/* Locking: rs->rs_rxlock must be held write only */ -/* */ -/* Free the RPCB transaction record rx from the chain of entries. */ -/* -------------------------------------------------------------------- */ -static void -ippr_rpcb_deref(rs, rx) - rpcb_session_t *rs; - rpcb_xact_t *rx; -{ - rs = rs; /* LINT */ - - if (rx == NULL) - return; - - if (--rx->rx_ref != 0) - return; - - if (rx->rx_next != NULL) - rx->rx_next->rx_pnext = rx->rx_pnext; - - *rx->rx_pnext = rx->rx_next; - - KFREE(rx); - - --rpcbcnt; -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_rpcb_getproto */ -/* Returns: int - -1 == illegal protocol/netid, */ -/* 0 == legal protocol/netid */ -/* Parameters: rm(I) - pointer to RPC message structure */ -/* xp(I) - pointer to netid structure */ -/* p(IO) - pointer to location within packet buffer */ -/* */ -/* Decode netid/proto stored at p and record its numeric value. */ -/* -------------------------------------------------------------------- */ -static int -ippr_rpcb_getproto(rm, xp, p) - rpc_msg_t *rm; - xdr_proto_t *xp; - u_32_t **p; -{ - u_int len; - - /* Must have 4 bytes for length & 4 bytes for "tcp" or "udp". */ - if (!RPCB_BUF_GEQ(rm, p, 8)) - return(-1); - - xp->xp_xslen = (*p)++; - xp->xp_xsstr = (char *)*p; - - /* Test the string length. */ - len = B(xp->xp_xslen); - if (len != 3) - return(-1); - - /* Test the actual string & record the protocol accordingly. */ - if (!strncmp((char *)xp->xp_xsstr, "tcp\0", 4)) - xp->xp_proto = IPPROTO_TCP; - else if (!strncmp((char *)xp->xp_xsstr, "udp\0", 4)) - xp->xp_proto = IPPROTO_UDP; - else { - return(-1); - } - - /* Advance past the string. */ - (*p)++; - - return(0); -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_rpcb_getnat */ -/* Returns: int -- -1 == failed to create table entries, */ -/* 0 == success */ -/* Parameters: fin(I) - pointer to packet information */ -/* nat(I) - pointer to NAT table entry */ -/* proto(I) - transport protocol for new entries */ -/* port(I) - new port to use w/ wildcard table entries */ -/* */ -/* Create state and NAT entries to handle an anticipated connection */ -/* attempt between RPC client and server. */ -/* -------------------------------------------------------------------- */ -static int -ippr_rpcb_getnat(fin, nat, proto, port) - fr_info_t *fin; - nat_t *nat; - u_int proto; - u_int port; -{ - ipnat_t *ipn, ipnat; - tcphdr_t tcp; - ipstate_t *is; - fr_info_t fi; - nat_t *natl; - int nflags; - - ipn = nat->nat_ptr; - - /* 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; - - bzero((char *)&tcp, sizeof(tcp)); - tcp.th_dport = htons(port); - - if (proto == IPPROTO_TCP) { - tcp.th_win = htons(8192); - TCP_OFF_A(&tcp, sizeof(tcphdr_t) >> 2); - fi.fin_dlen = sizeof(tcphdr_t); - tcp.th_flags = TH_SYN; - nflags = NAT_TCP; - } else { - fi.fin_dlen = sizeof(udphdr_t); - nflags = NAT_UDP; - } - - nflags |= SI_W_SPORT|NAT_SEARCH; - fi.fin_dp = &tcp; - fi.fin_plen = fi.fin_hlen + fi.fin_dlen; - - /* - * Search for existing NAT & state entries. Pay close attention to - * mutexes / locks grabbed from lookup routines, as not doing so could - * lead to bad things. - * - * 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); - if (is != NULL) { - RWLOCK_EXIT(&ipf_state); - } - - RWLOCK_EXIT(&ipf_nat); - - WRITE_ENTER(&ipf_nat); - natl = nat_inlookup(&fi, nflags, proto, fi.fin_src, fi.fin_dst); - - if ((natl != NULL) && (is != NULL)) { - MUTEX_DOWNGRADE(&ipf_nat); - return(0); - } - - /* Slightly modify the following structures for actual use in creating - * NAT and/or state entries. We're primarily concerned with stripping - * flags that may be detrimental to the creation process or simply - * shouldn't be associated with a table entry. - */ - fi.fin_fr = &rpcbfr; - fi.fin_flx &= ~FI_IGNORE; - nflags &= ~NAT_SEARCH; - - if (natl == NULL) { - /* 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? - */ - /* Generate template/bogus NAT rule. */ - 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_space = 1; - ipn->in_ippip = 1; - if (ipn->in_flags & IPN_FILTER) { - ipn->in_scmp = 0; - ipn->in_dcmp = 0; - } - *ipn->in_plabel = '\0'; - - /* Create NAT entry. return NULL if this fails. */ - natl = nat_new(&fi, ipn, NULL, nflags|SI_CLONE|NAT_SLAVE, - NAT_INBOUND); - - bcopy((char *)&ipnat, (char *)ipn, sizeof(ipnat)); - - if (natl == NULL) { - MUTEX_DOWNGRADE(&ipf_nat); - return(-1); - } - - ipn->in_use++; - (void) nat_proto(&fi, natl, nflags); - nat_update(&fi, natl, natl->nat_ptr); - } - MUTEX_DOWNGRADE(&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) { - /* - * XXX nat_delete is private to ip_nat.c. Should - * check w/ Darren about this one. - * - * nat_delete(natl, NL_EXPIRE); - */ - return(-1); - } - if (fi.fin_state != NULL) - fr_statederef((ipstate_t **)&fi.fin_state); - } - - return(0); -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_rpcb_modv3 */ -/* Returns: int -- change in packet length */ -/* Parameters: fin(I) - pointer to packet information */ -/* nat(I) - pointer to NAT session */ -/* rm(I) - pointer to RPC message structure */ -/* m(I) - pointer to mbuf chain */ -/* off(I) - offset within mbuf chain */ -/* */ -/* Write a new universal address string to this packet, adjusting */ -/* lengths as necessary. */ -/* -------------------------------------------------------------------- */ -static int -ippr_rpcb_modv3(fin, nat, rm, m, off) - fr_info_t *fin; - nat_t *nat; - rpc_msg_t *rm; - mb_t *m; - u_int off; -{ - u_int len, xlen, pos, bogo; - rpc_resp_t *rr; - char uaddr[24]; - char *i, *p; - int diff; - - rr = &rm->rm_resp; - i = (char *)&nat->nat_outip.s_addr; - p = (char *)&rr->rr_v3.xu_port; - - /* Form new string. */ - bzero(uaddr, sizeof(uaddr)); /* Just in case we need padding. */ -#if defined(SNPRINTF) && defined(_KERNEL) - SNPRINTF(uaddr, sizeof(uaddr), -#else - (void) sprintf(uaddr, -#endif - "%u.%u.%u.%u.%u.%u", i[0] & 0xff, i[1] & 0xff, - i[2] & 0xff, i[3] & 0xff, p[0] & 0xff, p[1] & 0xff); - len = strlen(uaddr); - xlen = XDRALIGN(len); - - /* Determine mbuf offset to write to. */ - pos = (char *)rr->rr_v3.xu_xslen - rm->rm_msgbuf; - off += pos; - - /* Write new string length. */ - bogo = htonl(len); - COPYBACK(m, off, 4, (caddr_t)&bogo); - off += 4; - - /* Write new string. */ - COPYBACK(m, off, xlen, uaddr); - - /* Determine difference in data lengths. */ - diff = xlen - XDRALIGN(B(rr->rr_v3.xu_xslen)); - - /* - * If our new string has a different length, make necessary - * adjustments. - */ - if (diff != 0) - ippr_rpcb_fixlen(fin, diff); - - return(diff); -} - -/* -------------------------------------------------------------------- */ -/* Function: ippr_rpcb_modv4 */ -/* Returns: int -- change in packet length */ -/* Parameters: fin(I) - pointer to packet information */ -/* nat(I) - pointer to NAT session */ -/* rm(I) - pointer to RPC message structure */ -/* m(I) - pointer to mbuf chain */ -/* off(I) - offset within mbuf chain */ -/* */ -/* Write new rpcb_entry list, adjusting lengths as necessary. */ -/* -------------------------------------------------------------------- */ -static int -ippr_rpcb_modv4(fin, nat, rm, m, off) - fr_info_t *fin; - nat_t *nat; - rpc_msg_t *rm; - mb_t *m; - u_int off; -{ - u_int len, xlen, pos, bogo; - rpcb_listp_t *rl; - rpcb_entry_t *re; - rpc_resp_t *rr; - char uaddr[24]; - int diff, cnt; - char *i, *p; - - diff = 0; - rr = &rm->rm_resp; - rl = &rr->rr_v4; - - i = (char *)&nat->nat_outip.s_addr; - - /* Determine mbuf offset to write to. */ - re = &rl->rl_entries[0]; - pos = (char *)re->re_maddr.xu_xslen - rm->rm_msgbuf; - off += pos; - - for (cnt = 0; cnt < rl->rl_cnt; cnt++) { - re = &rl->rl_entries[cnt]; - p = (char *)&re->re_maddr.xu_port; - - /* Form new string. */ - bzero(uaddr, sizeof(uaddr)); /* Just in case we need - padding. */ -#if defined(SNPRINTF) && defined(_KERNEL) - SNPRINTF(uaddr, sizeof(uaddr), -#else - (void) sprintf(uaddr, -#endif - "%u.%u.%u.%u.%u.%u", i[0] & 0xff, - i[1] & 0xff, i[2] & 0xff, i[3] & 0xff, - p[0] & 0xff, p[1] & 0xff); - len = strlen(uaddr); - xlen = XDRALIGN(len); - - /* Write new string length. */ - bogo = htonl(len); - COPYBACK(m, off, 4, (caddr_t)&bogo); - off += 4; - - /* Write new string. */ - COPYBACK(m, off, xlen, uaddr); - off += xlen; - - /* Record any change in length. */ - diff += xlen - XDRALIGN(B(re->re_maddr.xu_xslen)); - - /* If the length changed, copy back the rest of this entry. */ - len = ((char *)re->re_more + 4) - - (char *)re->re_netid.xp_xslen; - if (diff != 0) { - COPYBACK(m, off, len, (caddr_t)re->re_netid.xp_xslen); - } - off += len; - } - - /* - * If our new string has a different length, make necessary - * adjustments. - */ - if (diff != 0) - ippr_rpcb_fixlen(fin, diff); - - return(diff); -} - - -/* -------------------------------------------------------------------- */ -/* Function: ippr_rpcb_fixlen */ -/* Returns: (void) */ -/* Parameters: fin(I) - pointer to packet information */ -/* len(I) - change in packet length */ -/* */ -/* Adjust various packet related lengths held in structure and packet */ -/* header fields. */ -/* -------------------------------------------------------------------- */ -static void -ippr_rpcb_fixlen(fin, len) - fr_info_t *fin; - int len; -{ - udphdr_t *udp; - - 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; -} - -#undef B diff --git a/sys/contrib/ipfilter/netinet/ip_rules.c b/sys/contrib/ipfilter/netinet/ip_rules.c deleted file mode 100644 index f080ec5b..0000000 --- a/sys/contrib/ipfilter/netinet/ip_rules.c +++ /dev/null @@ -1,229 +0,0 @@ -/* $FreeBSD$ */ - -/* -* Copyright (C) 1993-2000 by Darren Reed. -* -* Redistribution and use in source and binary forms are permitted -* provided that this notice is preserved and due credit is given -* to the original author and the contributors. -*/ - -#include <sys/types.h> -#include <sys/time.h> -#include <sys/socket.h> -#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__sgi) -# include <sys/systm.h> -#endif -#include <sys/errno.h> -#include <sys/param.h> -#if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux) -# include <sys/mbuf.h> -#endif -#if defined(__FreeBSD__) && (__FreeBSD_version > 220000) -# include <sys/sockio.h> -#else -# include <sys/ioctl.h> -#endif /* FreeBSD */ -#include <net/if.h> -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/tcp.h> -#include "netinet/ip_compat.h" -#include "netinet/ip_fil.h" - -#include "netinet/ip_rules.h" - -#ifndef _KERNEL -# include <string.h> -#endif /* _KERNEL */ - -#ifdef IPFILTER_COMPILED - -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 -}; - -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 -}; - -frentry_t *ipf_rules_in_[1] = { - (frentry_t *)&in_rule__0 -}; - -frentry_t *ipfrule_match_in_(fin, passp) -fr_info_t *fin; -u_32_t *passp; -{ - frentry_t *fr = NULL; - - fr = (frentry_t *)&in_rule__0; - 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; -{ - frentry_t *fr = NULL; - - fr = (frentry_t *)&out_rule__0; - return fr; -} -static frentry_t ipfrule_out_; - -int ipfrule_add_out_() -{ - int i, j, err = 0, max; - frentry_t *fp; - - max = sizeof(ipf_rules_out_)/sizeof(frentry_t *); - for (i = 0; i < max; i++) { - fp = ipf_rules_out_[i]; - fp->fr_next = NULL; - for (j = i + 1; j < max; j++) - if (strncmp(fp->fr_group, - ipf_rules_out_[j]->fr_group, - FR_GROUPLEN) == 0) { - fp->fr_next = ipf_rules_out_[j]; - break; - } - } - - fp = &ipfrule_out_; - bzero((char *)fp, sizeof(*fp)); - fp->fr_type = FR_T_CALLFUNC|FR_T_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_func = (ipfunc_t)ipfrule_match_out_; - err = frrequest(IPL_LOGIPF, SIOCADDFR, (caddr_t)fp, fr_active, 0); - return err; -} - - -int ipfrule_remove_out_() -{ - int err = 0, i; - frentry_t *fp; - - /* - * Try to remove the outbound rule. - */ - if (ipfrule_out_.fr_ref > 0) { - err = EBUSY; - } else { - i = sizeof(ipf_rules_out_)/sizeof(frentry_t *) - 1; - for (; i >= 0; i--) { - fp = ipf_rules_out_[i]; - if (fp->fr_ref > 1) { - err = EBUSY; - break; - } - } - } - if (err == 0) - err = frrequest(IPL_LOGIPF, SIOCDELFR, - (caddr_t)&ipfrule_out_, fr_active, 0); - if (err) - return err; - - - return err; -} -static frentry_t ipfrule_in_; - -int ipfrule_add_in_() -{ - int i, j, err = 0, max; - frentry_t *fp; - - max = sizeof(ipf_rules_in_)/sizeof(frentry_t *); - for (i = 0; i < max; i++) { - fp = ipf_rules_in_[i]; - fp->fr_next = NULL; - for (j = i + 1; j < max; j++) - if (strncmp(fp->fr_group, - ipf_rules_in_[j]->fr_group, - FR_GROUPLEN) == 0) { - fp->fr_next = ipf_rules_in_[j]; - break; - } - } - - fp = &ipfrule_in_; - bzero((char *)fp, sizeof(*fp)); - fp->fr_type = FR_T_CALLFUNC|FR_T_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_func = (ipfunc_t)ipfrule_match_in_; - err = frrequest(IPL_LOGIPF, SIOCADDFR, (caddr_t)fp, fr_active, 0); - return err; -} - - -int ipfrule_remove_in_() -{ - int err = 0, i; - frentry_t *fp; - - /* - * Try to remove the inbound rule. - */ - if (ipfrule_in_.fr_ref > 0) { - err = EBUSY; - } else { - i = sizeof(ipf_rules_in_)/sizeof(frentry_t *) - 1; - for (; i >= 0; i--) { - fp = ipf_rules_in_[i]; - if (fp->fr_ref > 1) { - err = EBUSY; - break; - } - } - } - if (err == 0) - err = frrequest(IPL_LOGIPF, SIOCDELFR, - (caddr_t)&ipfrule_in_, fr_active, 0); - if (err) - return err; - - - return err; -} - -int ipfrule_add() -{ - int err; - - err = ipfrule_add_out_(); - if (err != 0) - return err; - err = ipfrule_add_in_(); - if (err != 0) - return err; - return 0; -} - - -int ipfrule_remove() -{ - int err; - - err = ipfrule_remove_out_(); - if (err != 0) - return err; - err = ipfrule_remove_in_(); - if (err != 0) - return err; - return 0; -} -#endif /* IPFILTER_COMPILED */ diff --git a/sys/contrib/ipfilter/netinet/ip_rules.h b/sys/contrib/ipfilter/netinet/ip_rules.h deleted file mode 100644 index 37e3646..0000000 --- a/sys/contrib/ipfilter/netinet/ip_rules.h +++ /dev/null @@ -1,16 +0,0 @@ -/* $FreeBSD$ */ - -extern int ipfrule_add __P((void)); -extern int ipfrule_remove __P((void)); - -extern frentry_t *ipfrule_match_out_ __P((fr_info_t *, u_32_t *)); -extern frentry_t *ipf_rules_out_[1]; - -extern int ipfrule_add_out_ __P((void)); -extern int ipfrule_remove_out_ __P((void)); - -extern frentry_t *ipfrule_match_in_ __P((fr_info_t *, u_32_t *)); -extern frentry_t *ipf_rules_in_[1]; - -extern int ipfrule_add_in_ __P((void)); -extern int ipfrule_remove_in_ __P((void)); diff --git a/sys/contrib/ipfilter/netinet/ip_scan.c b/sys/contrib/ipfilter/netinet/ip_scan.c deleted file mode 100644 index 54acb2a..0000000 --- a/sys/contrib/ipfilter/netinet/ip_scan.c +++ /dev/null @@ -1,601 +0,0 @@ -/* - * Copyright (C) 1995-2001 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/param.h> -#if defined(__hpux) && (HPUXREV >= 1111) && !defined(_KERNEL) -# include <sys/kern_svcs.h> -#endif -#include <sys/types.h> -#include <sys/time.h> -#include <sys/errno.h> -#if !defined(_KERNEL) -# 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(__svr4__) && !defined(__SVR4) -# include <sys/mbuf.h> -# endif -#endif -#include <sys/socket.h> -#if !defined(__hpux) && !defined(__osf__) && !defined(linux) && !defined(AIX) -# include <sys/ioccom.h> -#endif -#ifdef __FreeBSD__ -# include <sys/filio.h> -# include <sys/malloc.h> -#else -# include <sys/ioctl.h> -#endif - -#include <netinet/in.h> -#include <netinet/in_systm.h> -#include <netinet/ip.h> -#include <netinet/tcp.h> - -#include <net/if.h> - - -#include "netinet/ip_compat.h" -#include "netinet/ip_fil.h" -#include "netinet/ip_state.h" -#include "netinet/ip_scan.h" -/* END OF INCLUDES */ - -#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 $"; -#endif - -#ifdef IPFILTER_SCAN /* endif at bottom of file */ - - -ipscan_t *ipsc_list = NULL, - *ipsc_tail = NULL; -ipscanstat_t ipsc_stat; -# ifdef USE_MUTEXES -ipfrwlock_t ipsc_rwlock; -# endif - -# ifndef isalpha -# define isalpha(x) (((x) >= 'A' && 'Z' >= (x)) || \ - ((x) >= 'a' && 'z' >= (x))) -# 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 *)); - -static int ipsc_inited = 0; - - -int ipsc_init() -{ - RWLOCK_INIT(&ipsc_rwlock, "ip scan rwlock"); - ipsc_inited = 1; - return 0; -} - - -void fr_scanunload() -{ - if (ipsc_inited == 1) { - RW_DESTROY(&ipsc_rwlock); - ipsc_inited = 0; - } -} - - -int ipsc_add(data) -caddr_t data; -{ - ipscan_t *i, *isc; - int err; - - KMALLOC(isc, ipscan_t *); - if (!isc) - return ENOMEM; - - err = copyinptr(data, isc, sizeof(*isc)); - if (err) { - KFREE(isc); - return err; - } - - WRITE_ENTER(&ipsc_rwlock); - - i = ipsc_lookup(isc->ipsc_tag); - if (i) { - RWLOCK_EXIT(&ipsc_rwlock); - KFREE(isc); - return EEXIST; - } - - if (ipsc_tail) { - ipsc_tail->ipsc_next = isc; - isc->ipsc_pnext = &ipsc_tail->ipsc_next; - ipsc_tail = isc; - } else { - ipsc_list = isc; - ipsc_tail = isc; - isc->ipsc_pnext = &ipsc_list; - } - isc->ipsc_next = NULL; - - isc->ipsc_hits = 0; - isc->ipsc_fref = 0; - isc->ipsc_sref = 0; - isc->ipsc_active = 0; - - ipsc_stat.iscs_entries++; - RWLOCK_EXIT(&ipsc_rwlock); - return 0; -} - - -int ipsc_delete(data) -caddr_t data; -{ - ipscan_t isc, *i; - int err; - - err = copyinptr(data, &isc, sizeof(isc)); - if (err) - return err; - - WRITE_ENTER(&ipsc_rwlock); - - i = ipsc_lookup(isc.ipsc_tag); - if (i == NULL) - err = ENOENT; - else { - if (i->ipsc_fref) { - RWLOCK_EXIT(&ipsc_rwlock); - return EBUSY; - } - - *i->ipsc_pnext = i->ipsc_next; - if (i->ipsc_next) - i->ipsc_next->ipsc_pnext = i->ipsc_pnext; - else { - if (i->ipsc_pnext == &ipsc_list) - ipsc_tail = NULL; - else - ipsc_tail = *(*i->ipsc_pnext)->ipsc_pnext; - } - - ipsc_stat.iscs_entries--; - KFREE(i); - } - RWLOCK_EXIT(&ipsc_rwlock); - return err; -} - - -struct ipscan *ipsc_lookup(tag) -char *tag; -{ - ipscan_t *i; - - for (i = ipsc_list; i; i = i->ipsc_next) - if (!strcmp(i->ipsc_tag, tag)) - return i; - return NULL; -} - - -int ipsc_attachfr(fr) -struct frentry *fr; -{ - ipscan_t *i; - - if (fr->fr_isctag[0]) { - READ_ENTER(&ipsc_rwlock); - i = ipsc_lookup(fr->fr_isctag); - if (i != NULL) { - ATOMIC_INC32(i->ipsc_fref); - } - RWLOCK_EXIT(&ipsc_rwlock); - if (i == NULL) - return ENOENT; - fr->fr_isc = i; - } - return 0; -} - - -int ipsc_attachis(is) -struct ipstate *is; -{ - frentry_t *fr; - ipscan_t *i; - - READ_ENTER(&ipsc_rwlock); - fr = is->is_rule; - if (fr) { - i = fr->fr_isc; - if ((i != NULL) && (i != (ipscan_t *)-1)) { - is->is_isc = i; - ATOMIC_INC32(i->ipsc_sref); - if (i->ipsc_clen) - is->is_flags |= IS_SC_CLIENT; - else - is->is_flags |= IS_SC_MATCHC; - if (i->ipsc_slen) - is->is_flags |= IS_SC_SERVER; - else - is->is_flags |= IS_SC_MATCHS; - } - } - RWLOCK_EXIT(&ipsc_rwlock); - return 0; -} - - -int ipsc_detachfr(fr) -struct frentry *fr; -{ - ipscan_t *i; - - i = fr->fr_isc; - if (i != NULL) { - ATOMIC_DEC32(i->ipsc_fref); - } - return 0; -} - - -int ipsc_detachis(is) -struct ipstate *is; -{ - ipscan_t *i; - - READ_ENTER(&ipsc_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); - return 0; -} - - -/* - * 'string' compare for scanning - */ -int ipsc_matchstr(sp, str, n) -sinfo_t *sp; -char *str; -int n; -{ - char *s, *t, *up; - int i = n; - - if (i > sp->s_len) - i = sp->s_len; - up = str; - - for (s = sp->s_txt, t = sp->s_msk; i; i--, s++, t++, up++) - switch ((int)*t) - { - case '.' : - if (*s != *up) - return 1; - break; - case '?' : - if (!ISALPHA(*up) || ((*s & 0x5f) != (*up & 0x5f))) - return 1; - break; - case '*' : - break; - } - return 0; -} - - -/* - * 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 i, j, k, n, ret = 0, flags; - - flags = is->is_flags; - - /* - * If we've already matched more than what is on offer, then - * assume we have a better match already and forget this one. - */ - if (maxm != NULL) { - if (isc->ipsc_clen < maxm[0]) - return 0; - if (isc->ipsc_slen < maxm[1]) - return 0; - j = maxm[0]; - k = maxm[1]; - } else { - j = 0; - k = 0; - } - - if (!isc->ipsc_clen) - ret = 1; - else if (((flags & (IS_SC_MATCHC|IS_SC_CLIENT)) == IS_SC_CLIENT) && - cl && isc->ipsc_clen) { - 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)) { - i++; - ret |= 1; - if (n > j) - j = n; - } - } - } - - if (!isc->ipsc_slen) - ret |= 2; - else if (((flags & (IS_SC_MATCHS|IS_SC_SERVER)) == IS_SC_SERVER) && - sl && isc->ipsc_slen) { - 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)) { - i++; - ret |= 2; - if (n > k) - k = n; - } - } - } - - if (maxm && (ret == 3)) { - maxm[0] = j; - maxm[1] = k; - } - return ret; -} - - -int ipsc_match(is) -ipstate_t *is; -{ - int i, j, k, n, cl, sl, maxm[2]; - ipscan_t *isc, *lm; - tcpdata_t *t; - - for (cl = 0, n = is->is_smsk[0]; n & 1; n >>= 1) - cl++; - for (sl = 0, n = is->is_smsk[1]; n & 1; n >>= 1) - sl++; - - j = 0; - isc = is->is_isc; - if (isc != NULL) { - /* - * Known object to scan for. - */ - i = ipsc_matchisc(isc, is, cl, sl, NULL); - if (i & 1) { - is->is_flags |= IS_SC_MATCHC; - is->is_flags &= ~IS_SC_CLIENT; - } else if (cl >= isc->ipsc_clen) - is->is_flags &= ~IS_SC_CLIENT; - if (i & 2) { - is->is_flags |= IS_SC_MATCHS; - is->is_flags &= ~IS_SC_SERVER; - } else if (sl >= isc->ipsc_slen) - is->is_flags &= ~IS_SC_SERVER; - } else { - i = 0; - 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); - if (i) { - /* - * We only want to remember the best match - * and the number of times we get a best - * match. - */ - if ((j == 3) && (i < 3)) - continue; - if ((i == 3) && (j != 3)) - k = 1; - else - k++; - j = i; - lm = isc; - } - } - if (k == 1) - isc = lm; - if (isc == NULL) - return 0; - - /* - * No matches or partial matches, so reset the respective - * search flag. - */ - if (!(j & 1)) - is->is_flags &= ~IS_SC_CLIENT; - - if (!(j & 2)) - is->is_flags &= ~IS_SC_SERVER; - - /* - * If we found the best match, then set flags appropriately. - */ - if ((j == 3) && (k == 1)) { - is->is_flags &= ~(IS_SC_SERVER|IS_SC_CLIENT); - is->is_flags |= (IS_SC_MATCHS|IS_SC_MATCHC); - } - } - - /* - * If the acknowledged side of a connection has moved past the data in - * which we are interested, then reset respective flag. - */ - t = &is->is_tcp.ts_data[0]; - if (t->td_end > is->is_s0[0] + 15) - is->is_flags &= ~IS_SC_CLIENT; - - t = &is->is_tcp.ts_data[1]; - if (t->td_end > is->is_s0[1] + 15) - is->is_flags &= ~IS_SC_SERVER; - - /* - * Matching complete ? - */ - j = ISC_A_NONE; - if ((is->is_flags & IS_SC_MATCHALL) == IS_SC_MATCHALL) { - j = isc->ipsc_action; - ipsc_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))) { - /* - * Matching failed... - */ - j = isc->ipsc_else; - ipsc_stat.iscs_else++; - } - - switch (j) - { - case ISC_A_CLOSE : - /* - * If as a result of a successful match we are to - * close a connection, change the "keep state" info. - * to block packets and generate TCP RST's. - */ - is->is_pass &= ~FR_RETICMP; - is->is_pass |= FR_RETRST; - break; - default : - break; - } - - return i; -} - - -/* - * check if a packet matches what we're scanning for - */ -int ipsc_packet(fin, is) -fr_info_t *fin; -ipstate_t *is; -{ - int i, j, rv, dlen, off, thoff; - u_32_t seq, s0; - tcphdr_t *tcp; - - rv = !IP6_EQ(&fin->fin_fi.fi_src, &is->is_src); - tcp = fin->fin_dp; - seq = ntohl(tcp->th_seq); - - if (!is->is_s0[rv]) - return 1; - - /* - * check if this packet has more data that falls within the first - * 16 bytes sent in either direction. - */ - s0 = is->is_s0[rv]; - off = seq - s0; - if ((off > 15) || (off < 0)) - return 1; - thoff = TCP_OFF(tcp) << 2; - dlen = fin->fin_dlen - thoff; - if (dlen <= 0) - return 1; - if (dlen > 16) - dlen = 16; - if (off + dlen > 16) - dlen = 16 - off; - - j = 0xffff >> (16 - dlen); - i = (0xffff & j) << off; -#ifdef _KERNEL - COPYDATA(*(mb_t **)fin->fin_mp, fin->fin_plen - fin->fin_dlen + thoff, - dlen, (caddr_t)is->is_sbuf[rv] + off); -#endif - is->is_smsk[rv] |= i; - for (j = 0, i = is->is_smsk[rv]; i & 1; i >>= 1) - j++; - if (j == 0) - return 1; - - (void) ipsc_match(is); -#if 0 - /* - * There is the potential here for plain text passwords to get - * buffered and stored for some time... - */ - if (!(is->is_flags & IS_SC_CLIENT)) - bzero(is->is_sbuf[0], sizeof(is->is_sbuf[0])); - if (!(is->is_flags & IS_SC_SERVER)) - bzero(is->is_sbuf[1], sizeof(is->is_sbuf[1])); -#endif - return 0; -} - - -int fr_scan_ioctl(data, cmd, mode, uid, ctx) -caddr_t data; -ioctlcmd_t cmd; -int mode, uid; -void *ctx; -{ - ipscanstat_t ipscs; - int err = 0; - - switch (cmd) - { - case SIOCADSCA : - err = ipsc_add(data); - break; - case SIOCRMSCA : - err = ipsc_delete(data); - break; - case SIOCGSCST : - bcopy((char *)&ipsc_stat, (char *)&ipscs, sizeof(ipscs)); - ipscs.iscs_list = ipsc_list; - err = BCOPYOUT(&ipscs, data, sizeof(ipscs)); - if (err != 0) - err = EFAULT; - break; - default : - err = EINVAL; - break; - } - - return err; -} -#endif /* IPFILTER_SCAN */ diff --git a/sys/contrib/ipfilter/netinet/ip_scan.h b/sys/contrib/ipfilter/netinet/ip_scan.h deleted file mode 100644 index 4772d28..0000000 --- a/sys/contrib/ipfilter/netinet/ip_scan.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 1993-2001 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 $ - */ - -#ifndef __IP_SCAN_H__ -#define __IP_SCAN_H__ 1 - -#ifdef sun -# include <sys/ioccom.h> -#endif - -#define IPSCAN_NAME "/dev/ipscan" -#define IPL_SCAN IPSCAN_NAME -#define ISC_TLEN 16 - - -struct fr_info; -struct frentry; -struct ip; -struct ipstate; - - -#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51) -# define SIOCADSCA _IOWR('r', 60, struct ipscan *) -# define SIOCRMSCA _IOWR('r', 61, struct ipscan *) -# define SIOCGSCST _IOWR('r', 62, struct ipscan *) -#else -# define SIOCADSCA _IOWR(r, 60, struct ipscan *) -# define SIOCRMSCA _IOWR(r, 61, struct ipscan *) -# define SIOCGSCST _IOWR(r, 62, struct ipscan *) -#endif - -struct action { - int act_val; /* what to do */ - struct in_addr act_ip; /* redirect IP# */ - u_short act_port; /* redirect port number */ - int act_else; /* what to do */ - struct in_addr act_eip; /* redirect IP# */ - u_short act_eport; /* redirect port number */ -}; - - -typedef struct sinfo { - char s_txt[ISC_TLEN]; /* text to match */ - char s_msk[ISC_TLEN]; /* mask of the above to check */ - int s_len; /* length of server text */ -} sinfo_t; - - -typedef struct ipscan { - struct ipscan *ipsc_next; - struct ipscan **ipsc_pnext; - char ipsc_tag[ISC_TLEN]; /* table entry protocol tag */ - sinfo_t ipsc_si[2]; /* client/server side information */ - int ipsc_hits; /* times this has been matched */ - int ipsc_active; /* # of active matches */ - int ipsc_fref; /* # of references from filter rules */ - int ipsc_sref; /* # of references from state entries */ - struct action ipsc_act; -} ipscan_t; - - -#define ipsc_cl ipsc_si[0] -#define ipsc_sl ipsc_si[1] -#define ipsc_ctxt ipsc_cl.s_txt -#define ipsc_cmsk ipsc_cl.s_msk -#define ipsc_clen ipsc_cl.s_len -#define ipsc_stxt ipsc_sl.s_txt -#define ipsc_smsk ipsc_sl.s_msk -#define ipsc_slen ipsc_sl.s_len -#define ipsc_action ipsc_act.act_val -#define ipsc_ip ipsc_act.act_ip -#define ipsc_port ipsc_act.act_port -#define ipsc_else ipsc_act.act_else -#define ipsc_eip ipsc_act.act_eip -#define ipsc_eport ipsc_act.act_eport - -#define ISC_A_NONE 0 -#define ISC_A_TRACK 1 -#define ISC_A_CLOSE 2 -#define ISC_A_REDIRECT 3 - - -typedef struct ipscanstat { - struct ipscan *iscs_list; - u_long iscs_acted; - u_long iscs_else; - int iscs_entries; -} 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)); - -#endif /* __IP_SCAN_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c deleted file mode 100644 index a63f924..0000000 --- a/sys/contrib/ipfilter/netinet/ip_state.c +++ /dev/null @@ -1,4197 +0,0 @@ -/* - * Copyright (C) 1995-2003 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/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" -#endif -#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 -#endif -#if defined(_KERNEL) && (__FreeBSD_version >= 220000) -# include <sys/filio.h> -# include <sys/fcntl.h> -# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM) -# include "opt_ipfilter.h" -# endif -#else -# include <sys/ioctl.h> -#endif -#include <sys/time.h> -#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 - -#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> -#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> -#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_sync.h" -#endif -#ifdef IPFILTER_SCAN -#include "netinet/ip_scan.h" -#endif -#ifdef USE_INET6 -#include <netinet/icmp6.h> -#endif -#if (__FreeBSD_version >= 300000) -# include <sys/malloc.h> -# if defined(_KERNEL) && !defined(IPFILTER_LKM) -# include <sys/libkern.h> -# include <sys/systm.h> -# endif -#endif -/* END OF INCLUDES */ - - -#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 $"; -#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; - -#ifdef USE_INET6 -static ipstate_t *fr_checkicmp6matchingstate __P((fr_info_t *)); -#endif -static ipstate_t *fr_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)); - -#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; - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_stateinit */ -/* Returns: int - 0 == success, -1 == failure */ -/* Parameters: Nil */ -/* */ -/* Initialise all the global variables used within the state code. */ -/* This action also includes initiailising locks. */ -/* ------------------------------------------------------------------------ */ -int fr_stateinit() -{ - int i; - - KMALLOCS(ips_table, ipstate_t **, fr_statesize * sizeof(ipstate_t *)); - if (ips_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) - return -2; - for (i = 0; i < fr_statesize; i++) { - /* - * XXX - ips_seed[X] should be a random number of sorts. - */ -#if (__FreeBSD_version >= 400000) - ips_seed[i] = arc4random(); -#else - ips_seed[i] = ((u_long)ips_seed + i) * fr_statesize; - ips_seed[i] ^= 0xa5a55a5a; - ips_seed[i] *= (u_long)ips_seed; - ips_seed[i] ^= 0x5a5aa5a5; - ips_seed[i] *= fr_statemax; -#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(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 */ -/* */ -/* Release and destroy any resources acquired or initialised so that */ -/* IPFilter can be unloaded or re-initialised. */ -/* ------------------------------------------------------------------------ */ -void fr_stateunload() -{ - ipftq_t *ifq, *ifqnext; - ipstate_t *is; - - while ((is = ips_list) != NULL) - fr_delstate(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 - */ - for (ifq = ips_utqe; 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 (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); - } - - if (ips_table != NULL) { - KFREES(ips_table, fr_statesize * sizeof(*ips_table)); - ips_table = NULL; - } - - if (ips_seed != NULL) { - KFREES(ips_seed, fr_statesize * sizeof(*ips_seed)); - ips_seed = NULL; - } - - if (ips_stats.iss_bucketlen != NULL) { - KFREES(ips_stats.iss_bucketlen, fr_statesize * sizeof(u_long)); - ips_stats.iss_bucketlen = NULL; - } - - if (fr_state_maxbucket_reset == 1) - fr_state_maxbucket = 0; - - if (fr_state_init == 1) { - fr_state_init = 0; - RW_DESTROY(&ipf_state); - MUTEX_DESTROY(&ipf_stinsert); - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_statetstats */ -/* Returns: ips_state_t* - pointer to state stats structure */ -/* Parameters: Nil */ -/* */ -/* Put all the current numbers and pointers into a single struct and return */ -/* a pointer to it. */ -/* ------------------------------------------------------------------------ */ -static ips_stat_t *fr_statetstats() -{ - 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; -} - -/* ------------------------------------------------------------------------ */ -/* Function: fr_state_remove */ -/* Returns: int - 0 == success, != 0 == failure */ -/* Parameters: 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; -{ - ipstate_t *sp, st; - int error; - - sp = &st; - error = fr_inobj(data, &st, IPFOBJ_IPSTATE); - if (error) - return EFAULT; - - WRITE_ENTER(&ipf_state); - for (sp = ips_list; sp; sp = sp->is_next) - if ((sp->is_p == st.is_p) && (sp->is_v == st.is_v) && - !bcmp((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, - 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); - return 0; - } - RWLOCK_EXIT(&ipf_state); - return ESRCH; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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 */ -/* */ -/* 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 arg, ret, error = 0; - SPL_INT(s); - - switch (cmd) - { - /* - * Delete an entry from the state table. - */ - case SIOCDELST : - error = fr_state_remove(data); - break; - - /* - * Flush the state table - */ - case SIOCIPFFL : - error = BCOPYIN(data, (char *)&arg, sizeof(arg)); - if (error != 0) { - 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) - error = EFAULT; - } - break; - -#ifdef USE_INET6 - case SIOCIPFL6 : - error = BCOPYIN(data, (char *)&arg, sizeof(arg)); - if (error != 0) { - 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) - error = EFAULT; - } - break; -#endif -#ifdef IPFILTER_LOG - /* - * Flush the state log. - */ - case SIOCIPFFB : - if (!(mode & FWRITE)) - error = EPERM; - else { - int tmp; - - tmp = ipflog_clear(IPL_LOGSTATE); - error = BCOPYOUT((char *)&tmp, data, sizeof(tmp)); - if (error != 0) - error = EFAULT; - } - break; - - /* - * Turn logging of state information on/off. - */ - case SIOCSETLG : - if (!(mode & FWRITE)) - error = EPERM; - else { - error = BCOPYIN((char *)data, (char *)&ipstate_logging, - sizeof(ipstate_logging)); - if (error != 0) - error = EFAULT; - } - break; - - /* - * Return the current state of logging. - */ - case SIOCGETLG : - error = BCOPYOUT((char *)&ipstate_logging, (char *)data, - sizeof(ipstate_logging)); - if (error != 0) - 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) - error = EFAULT; - break; -#endif - - /* - * Get the current state statistics. - */ - case SIOCGETFS : - error = fr_outobj(data, fr_statetstats(), IPFOBJ_STATESTAT); - break; - - /* - * Lock/Unlock the state table. (Locking prevents any changes, which - * means no packets match). - */ - case SIOCSTLCK : - if (!(mode & FWRITE)) { - error = EPERM; - } else { - error = fr_lock(data, &fr_state_lock); - } - break; - - /* - * Add an entry to the current state table. - */ - case SIOCSTPUT : - if (!fr_state_lock || !(mode &FWRITE)) { - error = EACCES; - break; - } - error = fr_stputent(data); - break; - - /* - * Get a state table entry. - */ - case SIOCSTGET : - if (!fr_state_lock) { - error = EACCES; - break; - } - error = fr_stgetent(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 = EFAULT; - break; - - case SIOCGENITER : - { - ipftoken_t *token; - ipfgeniter_t iter; - - error = fr_inobj(data, &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 - error = ESRCH; - RWLOCK_EXIT(&ipf_tokens); - SPL_X(s); - break; - } - - case SIOCGTABL : - error = fr_stgettable(data); - break; - - case SIOCIPFDELTOK : - error = BCOPYIN(data, (char *)&arg, sizeof(arg)); - if (error != 0) { - error = EFAULT; - } else { - SPL_SCHED(s); - error = ipf_deltoken(arg, uid, ctx); - SPL_X(s); - } - break; - - case SIOCGTQTAB : - error = fr_outobj(data, ips_tqtqb, IPFOBJ_STATETQTAB); - break; - - default : - error = EINVAL; - break; - } - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_stgetent */ -/* Returns: int - 0 == success, != 0 == failure */ -/* Parameters: 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 */ -/* as well. The entry to copy out is taken from the value of "ips_next" in */ -/* 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; -{ - ipstate_t *is, *isn; - ipstate_save_t ips; - int error; - - error = fr_inobj(data, &ips, IPFOBJ_STATESAVE); - if (error != 0) - return error; - - isn = ips.ips_next; - if (isn == NULL) { - isn = ips_list; - if (isn == NULL) { - if (ips.ips_next == NULL) - return ENOENT; - return 0; - } - } else { - /* - * Make sure the pointer we're copying from exists in the - * current list of entries. Security precaution to prevent - * copying of random kernel data. - */ - for (is = ips_list; is; is = is->is_next) - if (is == isn) - break; - if (!is) - return ESRCH; - } - ips.ips_next = isn->is_next; - bcopy((char *)isn, (char *)&ips.ips_is, sizeof(ips.ips_is)); - ips.ips_rule = isn->is_rule; - if (isn->is_rule != NULL) - bcopy((char *)isn->is_rule, (char *)&ips.ips_fr, - sizeof(ips.ips_fr)); - error = fr_outobj(data, &ips, IPFOBJ_STATESAVE); - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_stputent */ -/* Returns: int - 0 == success, != 0 == failure */ -/* Parameters: 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; -{ - ipstate_t *is, *isn; - ipstate_save_t ips; - int error, out, i; - frentry_t *fr; - char *name; - - error = fr_inobj(data, &ips, IPFOBJ_STATESAVE); - if (error) - return EFAULT; - - KMALLOC(isn, ipstate_t *); - if (isn == NULL) - return ENOMEM; - - bcopy((char *)&ips.ips_is, (char *)isn, sizeof(*isn)); - bzero((char *)isn, offsetof(struct ipstate, is_pkts)); - isn->is_sti.tqe_pnext = NULL; - isn->is_sti.tqe_next = NULL; - isn->is_sti.tqe_ifq = NULL; - isn->is_sti.tqe_parent = isn; - isn->is_ifp[0] = NULL; - isn->is_ifp[1] = NULL; - isn->is_ifp[2] = NULL; - isn->is_ifp[3] = NULL; - isn->is_sync = NULL; - fr = ips.ips_rule; - - if (fr == NULL) { - READ_ENTER(&ipf_state); - fr_stinsert(isn, 0); - MUTEX_EXIT(&isn->is_lock); - RWLOCK_EXIT(&ipf_state); - return 0; - } - - if (isn->is_flags & SI_NEWFR) { - KMALLOC(fr, frentry_t *); - if (fr == NULL) { - KFREE(isn); - return ENOMEM; - } - bcopy((char *)&ips.ips_fr, (char *)fr, sizeof(*fr)); - out = fr->fr_flags & FR_OUTQUE ? 1 : 0; - isn->is_rule = fr; - ips.ips_is.is_rule = fr; - MUTEX_NUKE(&fr->fr_lock); - MUTEX_INIT(&fr->fr_lock, "state filter rule lock"); - - /* - * 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); - name = isn->is_ifname[i]; - isn->is_ifp[i] = fr_resolvenic(name, isn->is_v); - } - - fr->fr_ref = 0; - fr->fr_dsize = 0; - 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); - - /* - * send a copy back to userland of what we ended up - * to allow for verification. - */ - error = fr_outobj(data, &ips, IPFOBJ_STATESAVE); - if (error) { - KFREE(isn); - MUTEX_DESTROY(&fr->fr_lock); - KFREE(fr); - return EFAULT; - } - READ_ENTER(&ipf_state); - fr_stinsert(isn, 0); - MUTEX_EXIT(&isn->is_lock); - RWLOCK_EXIT(&ipf_state); - - } else { - READ_ENTER(&ipf_state); - for (is = ips_list; is; is = is->is_next) - if (is->is_rule == fr) { - fr_stinsert(isn, 0); - MUTEX_EXIT(&isn->is_lock); - break; - } - - if (is == NULL) { - KFREE(isn); - isn = NULL; - } - RWLOCK_EXIT(&ipf_state); - - return (isn == NULL) ? ESRCH : 0; - } - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_stinsert */ -/* Returns: Nil */ -/* Parameters: is(I) - pointer to state structure */ -/* rev(I) - flag indicating forward/reverse 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. */ -/* */ -/* Locking: it is assumed that some kind of lock on ipf_state is held. */ -/* Exits with is_lock initialised and held. */ -/* ------------------------------------------------------------------------ */ -void fr_stinsert(is, rev) -ipstate_t *is; -int rev; -{ - 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); - } - - /* - * 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; - is->is_hv = hv; - - /* - * We need to get both of these locks...the first because it is - * possible that once the insert is complete another packet might - * come along, match the entry and want to update it. - */ - MUTEX_ENTER(&is->is_lock); - MUTEX_ENTER(&ipf_stinsert); - - /* - * 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; - 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); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_addstate */ -/* Returns: ipstate_t* - NULL == failure, else pointer to new state */ -/* Parameters: 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 */ -/* */ -/* Creates a new IP state structure from the packet information collected. */ -/* Inserts it into the state table and appends to the bottom of the active */ -/* list. If the capacity of the table has reached the maximum allowed then */ -/* the call will fail and a flush is scheduled for the next timeout call. */ -/* */ -/* NOTE: The use of stsave to point to nat_state will result in memory */ -/* corruption. It should only be used to point to objects that will */ -/* 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; -{ - ipstate_t *is, ips; - struct icmp *ic; - u_int pass, hv; - frentry_t *fr; - tcphdr_t *tcp; - grehdr_t *gre; - int out; - - if (fr_state_lock || - (fin->fin_flx & (FI_SHORT|FI_STATE|FI_FRAGBODY|FI_BAD))) - return NULL; - - if ((fin->fin_flx & FI_OOW) && !(fin->fin_tcpf & TH_SYN)) - return NULL; - - /* - * If a "keep state" rule has reached the maximum number of references - * to it, then schedule an automatic flush in case we can clear out - * some "dead old wood". Note that because the lock isn't held on - * fr it is possible that we could overflow. The cost of overflowing - * is being ignored here as the number by which it can overflow is - * a product of the number of simultaneous threads that could be - * executing in here, so a limit of 100 won't result in 200, but could - * result in 101 or 102. - */ - 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 ((fr->fr_statemax != 0) && - (fr->fr_statecnt >= fr->fr_statemax)) { - ATOMIC_INCL(ips_stats.iss_maxref); - return NULL; - } - } - - pass = (fr == NULL) ? 0 : fr->fr_flags; - - ic = NULL; - tcp = NULL; - out = fin->fin_out; - is = &ips; - bzero((char *)is, sizeof(*is)); - is->is_die = 1 + fr_ticks; - - /* - * Copy and calculate... - */ - hv = (is->is_p = fin->fin_fi.fi_p); - is->is_src = fin->fin_fi.fi_src; - hv += is->is_saddr; - is->is_dst = fin->fin_fi.fi_dst; - hv += is->is_daddr; -#ifdef USE_INET6 - if (fin->fin_v == 6) { - /* - * For ICMPv6, we check to see if the destination address is - * a multicast address. If it is, do not include it in the - * calculation of the hash because the correct reply will come - * back from a real address, not a multicast address. - */ - if ((is->is_p == IPPROTO_ICMPV6) && - IN6_IS_ADDR_MULTICAST(&is->is_dst.in6)) { - /* - * So you can do keep state with neighbour discovery. - * - * Here we could use the address from the neighbour - * solicit message to put in the state structure and - * we could use that without a wildcard flag too... - */ - flags |= SI_W_DADDR; - hv -= is->is_daddr; - } else { - hv += is->is_dst.i6[1]; - hv += is->is_dst.i6[2]; - hv += is->is_dst.i6[3]; - } - hv += is->is_src.i6[1]; - hv += is->is_src.i6[2]; - hv += is->is_src.i6[3]; - } -#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; - } - } - - switch (is->is_p) - { -#ifdef USE_INET6 - case IPPROTO_ICMPV6 : - ic = fin->fin_dp; - - 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; - case ICMP6_MEMBERSHIP_QUERY : - case ND_ROUTER_SOLICIT : - case ND_NEIGHBOR_SOLICIT : - case ICMP6_NI_QUERY : - is->is_icmp.ici_type = ic->icmp_type; - break; - default : - return NULL; - } - ATOMIC_INCL(ips_stats.iss_icmp); - break; -#endif - case IPPROTO_ICMP : - ic = fin->fin_dp; - - switch (ic->icmp_type) - { - case ICMP_ECHO : - case ICMP_TSTAMP : - case ICMP_IREQ : - case ICMP_MASKREQ : - is->is_icmp.ici_type = ic->icmp_type; - hv += (is->is_icmp.ici_id = ic->icmp_id); - break; - default : - return NULL; - } - ATOMIC_INCL(ips_stats.iss_icmp); - break; - - case IPPROTO_GRE : - gre = fin->fin_dp; - - is->is_gre.gs_flags = gre->gr_flags; - is->is_gre.gs_ptype = gre->gr_ptype; - if (GRE_REV(is->is_gre.gs_flags) == 1) { - is->is_call[0] = fin->fin_data[0]; - is->is_call[1] = fin->fin_data[1]; - } - break; - - case IPPROTO_TCP : - tcp = fin->fin_dp; - - if (tcp->th_flags & TH_RST) - return NULL; - /* - * The endian of the ports doesn't matter, but the ack and - * sequence numbers do as we do mathematics on them later. - */ - is->is_sport = htons(fin->fin_data[0]); - is->is_dport = htons(fin->fin_data[1]); - if ((flags & (SI_W_DPORT|SI_W_SPORT)) == 0) { - hv += is->is_sport; - hv += is->is_dport; - } - - /* - * If this is a real packet then initialise fields in the - * state information structure from the TCP header information. - */ - - is->is_maxdwin = 1; - is->is_maxswin = ntohs(tcp->th_win); - if (is->is_maxswin == 0) - is->is_maxswin = 1; - - if ((fin->fin_flx & FI_IGNORE) == 0) { - is->is_send = ntohl(tcp->th_seq) + fin->fin_dlen - - (TCP_OFF(tcp) << 2) + - ((tcp->th_flags & TH_SYN) ? 1 : 0) + - ((tcp->th_flags & TH_FIN) ? 1 : 0); - is->is_maxsend = is->is_send; - - /* - * Window scale option is only present in - * SYN/SYN-ACK packet. - */ - 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) { - fin->fin_flx |= FI_BAD; - } - } - - if ((fin->fin_out != 0) && (pass & FR_NEWISN) != 0) { - fr_checknewisn(fin, is); - fr_fixoutisn(fin, is); - } - - if ((tcp->th_flags & TH_OPENING) == TH_SYN) - flags |= IS_TCPFSM; - else { - is->is_maxdwin = is->is_maxswin * 2; - is->is_dend = ntohl(tcp->th_ack); - is->is_maxdend = ntohl(tcp->th_ack); - is->is_maxdwin *= 2; - } - } - - /* - * 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 : - tcp = fin->fin_dp; - - is->is_sport = htons(fin->fin_data[0]); - is->is_dport = htons(fin->fin_data[1]); - if ((flags & (SI_W_DPORT|SI_W_SPORT)) == 0) { - hv += tcp->th_dport; - hv += tcp->th_sport; - } - ATOMIC_INCL(ips_stats.iss_udp); - break; - - default : - break; - } - 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) - break; - } - if (is != NULL) - return NULL; - - if (ips_stats.iss_bucketlen[hv] >= fr_state_maxbucket) { - ATOMIC_INCL(ips_stats.iss_bucketfull); - return NULL; - } - KMALLOC(is, ipstate_t *); - if (is == NULL) { - ATOMIC_INCL(ips_stats.iss_nomem); - return NULL; - } - bcopy((char *)&ips, (char *)is, sizeof(*is)); - /* - * Do not do the modulous here, it is done in fr_stinsert(). - */ - if (fr != NULL) { - (void) strncpy(is->is_group, fr->fr_group, FR_GROUPLEN); - if (fr->fr_age[0] != 0) { - is->is_tqehead[0] = fr_addtimeoutqueue(&ips_utqe, - fr->fr_age[0]); - 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]); - 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. - */ - is->is_ref = 2; - is->is_pass = pass; - 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; - 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_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); - } - is->is_rulen = fin->fin_rule; - - - if (pass & FR_LOGFIRST) - is->is_pass &= ~(FR_LOGFIRST|FR_LOG); - - READ_ENTER(&ipf_state); - - fr_stinsert(is, fin->fin_rev); - - if (fin->fin_p == IPPROTO_TCP) { - /* - * 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. - */ - (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); - } -#ifdef IPFILTER_SYNC - 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); - - 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); - - return is; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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 */ -/* 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; -{ - 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) - return 0; - len -= sizeof(*tcp); - - off = fin->fin_plen - fin->fin_dlen + sizeof(*tcp) + fin->fin_ipoff; - - m = fin->fin_m; - mlen = MSGDSIZE(m) - off; - if (len > mlen) { - len = mlen; - retval = 0; - } else { - retval = 1; - } - - COPYDATA(m, off, len, buf); - - for (s = buf; len > 0; ) { - opt = *s; - if (opt == TCPOPT_EOL) - break; - else if (opt == TCPOPT_NOP) - ol = 1; - else { - if (len < 2) - break; - ol = (int)*(s + 1); - if (ol < 2 || ol > len) - break; - - /* - * Extract the TCP options we are interested in out of - * the header and store them in the the tcpdata struct. - */ - switch (opt) - { - case TCPOPT_WINDOW : - if (ol == TCPOLEN_WINDOW) { - i = (int)*(s + 2); - if (i > TCP_WSCALE_MAX) - i = TCP_WSCALE_MAX; - else if (i < 0) - i = 0; - td->td_winscale = i; - td->td_winflags |= TCP_WSCALE_SEEN| - TCP_WSCALE_FIRST; - } else - retval = -1; - break; - case TCPOPT_MAXSEG : - /* - * So, if we wanted to set the TCP MAXSEG, - * it should be done here... - */ - if (ol == TCPOLEN_MAXSEG) { - i = (int)*(s + 2); - i <<= 8; - i += (int)*(s + 3); - td->td_maxseg = i; - } else - retval = -1; - break; - case TCPOPT_SACK_PERMITTED : - if (ol == TCPOLEN_SACK_PERMITTED) - td->td_winflags |= TCP_SACK_PERMIT; - else - retval = -1; - break; - } - } - len -= ol; - s += ol; - } - return retval; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_tcpstate */ -/* Returns: int - 1 == packet matches state entry, 0 == it does not */ -/* Parameters: fin(I) - pointer to packet information */ -/* tcp(I) - pointer to TCP packet header */ -/* is(I) - pointer to master state structure */ -/* */ -/* Check to see if a packet with TCP headers fits within the TCP window. */ -/* Change timeout depending on whether new packet is a SYN-ACK returning */ -/* for a 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; -{ - int source, ret = 0, flags; - tcpdata_t *fdata, *tdata; - - source = !fin->fin_rev; - 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]; - tdata = &is->is_tcp.ts_data[source]; - - MUTEX_ENTER(&is->is_lock); - - /* - * If a SYN packet is received for a connection that is on the way out - * but hasn't yet departed then advance this session along the way. - */ - if ((tcp->th_flags & TH_OPENING) == TH_SYN) { - 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); - MUTEX_EXIT(&is->is_lock); - return 0; - } - } - - ret = fr_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); - if (ret == 0) { - MUTEX_EXIT(&is->is_lock); - return 0; - } - - /* - * set s0's as appropriate. Use syn-ack packet as it - * contains both pieces of required information. - */ - /* - * Window scale option is only present in SYN/SYN-ACK packet. - * Compare with ~TH_FIN to mask out T/TCP setups. - */ - flags = tcp->th_flags & ~(TH_FIN|TH_ECNALL); - if (flags == (TH_SYN|TH_ACK)) { - 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) - fin->fin_flx |= FI_BAD; - } - if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN)) - fr_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) - fin->fin_flx |= FI_BAD; - } - - if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN)) - fr_checknewisn(fin, is); - - } - ret = 1; - } else { - fin->fin_flx |= FI_OOW; - } - MUTEX_EXIT(&is->is_lock); - return ret; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_checknewisn */ -/* Returns: Nil */ -/* Parameters: fin(I) - pointer to packet information */ -/* is(I) - pointer to master state structure */ -/* */ -/* Check to see if this TCP connection is expecting and needs a new */ -/* sequence number for a particular direction of the connection. */ -/* */ -/* 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; -{ - u_32_t sumd, old, new; - tcphdr_t *tcp; - int i; - - i = fin->fin_rev; - tcp = fin->fin_dp; - - if (((i == 0) && !(is->is_flags & IS_ISNSYN)) || - ((i == 1) && !(is->is_flags & IS_ISNACK))) { - old = ntohl(tcp->th_seq); - new = fr_newisn(fin); - is->is_isninc[i] = new - old; - CALC_SUMD(old, new, sumd); - is->is_sumd[i] = (sumd & 0xffff) + (sumd >> 16); - - is->is_flags |= ((i == 0) ? IS_ISNSYN : IS_ISNACK); - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_tcpinwindow */ -/* Returns: int - 1 == packet inside TCP "window", 0 == not inside, */ -/* 2 == packet seq number matches next expected */ -/* Parameters: fin(I) - pointer to packet information */ -/* fdata(I) - pointer to tcp state informatio (forward) */ -/* tdata(I) - pointer to tcp state informatio (reverse) */ -/* tcp(I) - pointer to TCP packet header */ -/* */ -/* Given a packet has matched addresses and ports, check to see if it 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; -{ - tcp_seq seq, ack, end; - int ackskew, tcpflags; - u_32_t win, maxwin; - int dsize, inseq; - - /* - * Find difference between last checked packet and this packet. - */ - tcpflags = tcp->th_flags; - seq = ntohl(tcp->th_seq); - ack = ntohl(tcp->th_ack); - if (tcpflags & TH_SYN) - win = ntohs(tcp->th_win); - else - win = ntohs(tcp->th_win) << fdata->td_winscale; - - /* - * A window of 0 produces undesirable behaviour from this function. - */ - if (win == 0) - win = 1; - - dsize = fin->fin_dlen - (TCP_OFF(tcp) << 2) + - ((tcpflags & TH_SYN) ? 1 : 0) + ((tcpflags & TH_FIN) ? 1 : 0); - - /* - * if window scaling is present, the scaling is only allowed - * for windows not in the first SYN packet. In that packet the - * window is 65535 to specify the largest window possible - * for receivers not implementing the window scale option. - * Currently, we do not assume TTCP here. That means that - * if we see a second packet from a host (after the initial - * SYN), we can assume that the receiver of the SYN did - * already send back the SYN/ACK (and thus that we know if - * the receiver also does window scaling) - */ - if (!(tcpflags & TH_SYN) && (fdata->td_winflags & TCP_WSCALE_FIRST)) { - fdata->td_winflags &= ~TCP_WSCALE_FIRST; - fdata->td_maxwin = win; - } - - end = seq + dsize; - - if ((fdata->td_end == 0) && - (!(flags & IS_TCPFSM) || - ((tcpflags & TH_OPENING) == TH_OPENING))) { - /* - * Must be a (outgoing) SYN-ACK in reply to a SYN. - */ - fdata->td_end = end - 1; - fdata->td_maxwin = 1; - fdata->td_maxend = end + win; - } - - if (!(tcpflags & TH_ACK)) { /* Pretend an ack was sent */ - ack = tdata->td_end; - } else if (((tcpflags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) && - (ack == 0)) { - /* gross hack to get around certain broken tcp stacks */ - ack = tdata->td_end; - } - - maxwin = tdata->td_maxwin; - ackskew = tdata->td_end - ack; - - /* - * Strict sequencing only allows in-order delivery. - */ - if (seq != fdata->td_end) { - if ((flags & IS_STRICT) != 0) { - return 0; - } - } - - inseq = 0; - if ((SEQ_GE(fdata->td_maxend, end)) && - (SEQ_GE(seq, fdata->td_end - maxwin)) && -/* XXX what about big packets */ -#define MAXACKWINDOW 66000 - (-ackskew <= (MAXACKWINDOW)) && - ( ackskew <= (MAXACKWINDOW << fdata->td_winscale))) { - inseq = 1; - /* - * Microsoft Windows will send the next packet to the right of the - * window if SACK is in use. - */ - } else if ((seq == fdata->td_maxend) && (ackskew == 0) && - (fdata->td_winflags & TCP_SACK_PERMIT) && - (tdata->td_winflags & TCP_SACK_PERMIT)) { - inseq = 1; - /* - * Sometimes a TCP RST will be generated with only the ACK field - * set to non-zero. - */ - } else if ((seq == 0) && (tcpflags == (TH_RST|TH_ACK)) && - (ackskew >= -1) && (ackskew <= 1)) { - inseq = 1; - } else if (!(flags & IS_TCPFSM)) { - int i; - - i = (fin->fin_rev << 1) + fin->fin_out; - -#if 0 - if (is_pkts[i]0 == 0) { - /* - * Picking up a connection in the middle, the "next" - * packet seen from a direction that is new should be - * accepted, even if it appears out of sequence. - */ - inseq = 1; - } else -#endif - if (!(fdata->td_winflags & - (TCP_WSCALE_SEEN|TCP_WSCALE_FIRST))) { - /* - * No TCPFSM and no window scaling, so make some - * extra guesses. - */ - if ((seq == fdata->td_maxend) && (ackskew == 0)) - inseq = 1; - else if (SEQ_GE(seq + maxwin, fdata->td_end - maxwin)) - inseq = 1; - } - } - - /* TRACE(inseq, fdata, tdata, seq, end, ack, ackskew, win, maxwin) */ - - if (inseq) { - /* if ackskew < 0 then this should be due to fragmented - * packets. There is no way to know the length of the - * total packet in advance. - * We do know the total length from the fragment cache though. - * Note however that there might be more sessions with - * exactly the same source and destination parameters in the - * state cache (and source and destination is the only stuff - * that is saved in the fragment cache). Note further that - * some TCP connections in the state cache are hashed with - * sport and dport as well which makes it not worthwhile to - * look for them. - * Thus, when ackskew is negative but still seems to belong - * to this session, we bump up the destinations end value. - */ - if (ackskew < 0) - tdata->td_end = ack; - - /* update max window seen */ - if (fdata->td_maxwin < win) - fdata->td_maxwin = win; - if (SEQ_GT(end, fdata->td_end)) - fdata->td_end = end; - if (SEQ_GE(ack + win, tdata->td_maxend)) - tdata->td_maxend = ack + win; - return 1; - } - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_stclone */ -/* Returns: ipstate_t* - NULL == cloning failed, */ -/* else pointer to new state structure */ -/* Parameters: fin(I) - pointer to packet information */ -/* tcp(I) - pointer to TCP/UDP header */ -/* is(I) - pointer to master state structure */ -/* */ -/* 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; -{ - ipstate_t *clone; - u_32_t send; - - if (ips_num == fr_statemax) { - ATOMIC_INCL(ips_stats.iss_max); - fr_state_doflush = 1; - return NULL; - } - KMALLOC(clone, ipstate_t *); - if (clone == NULL) - return NULL; - bcopy((char *)is, (char *)clone, sizeof(*clone)); - - MUTEX_NUKE(&clone->is_lock); - - clone->is_die = ONE_DAY + fr_ticks; - clone->is_state[0] = 0; - clone->is_state[1] = 0; - send = ntohl(tcp->th_seq) + fin->fin_dlen - (TCP_OFF(tcp) << 2) + - ((tcp->th_flags & TH_SYN) ? 1 : 0) + - ((tcp->th_flags & TH_FIN) ? 1 : 0); - - if (fin->fin_rev == 1) { - clone->is_dend = send; - clone->is_maxdend = send; - clone->is_send = 0; - clone->is_maxswin = 1; - clone->is_maxdwin = ntohs(tcp->th_win); - if (clone->is_maxdwin == 0) - clone->is_maxdwin = 1; - } else { - clone->is_send = send; - clone->is_maxsend = send; - clone->is_dend = 0; - clone->is_maxdwin = 1; - clone->is_maxswin = ntohs(tcp->th_win); - if (clone->is_maxswin == 0) - clone->is_maxswin = 1; - } - - clone->is_flags &= ~SI_CLONE; - clone->is_flags |= SI_CLONED; - fr_stinsert(clone, fin->fin_rev); - clone->is_ref = 2; - if (clone->is_p == IPPROTO_TCP) { - (void) fr_tcp_age(&clone->is_sti, fin, ips_tqtqb, - clone->is_flags); - } - 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 - return clone; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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 */ -/* */ -/* 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; -{ - int ret = 0, rev, out, flags, flx = 0, idx; - u_short sp, dp; - u_32_t cflx; - void *ifp; - - rev = IP6_NEQ(&is->is_dst, dst); - ifp = fin->fin_ifp; - out = fin->fin_out; - flags = is->is_flags; - sp = 0; - dp = 0; - - if (tcp != NULL) { - sp = htons(fin->fin_sport); - dp = ntohs(fin->fin_dport); - } - if (!rev) { - if (tcp != NULL) { - if (!(flags & SI_W_SPORT) && (sp != is->is_sport)) - rev = 1; - else if (!(flags & SI_W_DPORT) && (dp != is->is_dport)) - rev = 1; - } - } - - idx = (out << 1) + rev; - - /* - * If the interface for this 'direction' is set, make sure it matches. - * An interface name that is not set matches any, as does a name of *. - */ - if ((is->is_ifp[idx] == ifp) || (is->is_ifp[idx] == NULL && - (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '-' || - *is->is_ifname[idx] == '*'))) - ret = 1; - - if (ret == 0) - return NULL; - ret = 0; - - /* - * Match addresses and ports. - */ - if (rev == 0) { - 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)&& - (dp == is->is_dport || flags & SI_W_DPORT)) - ret = 1; - } else { - ret = 1; - } - } - } else { - 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)&& - (sp == is->is_dport || flags & SI_W_DPORT)) - ret = 1; - } else { - ret = 1; - } - } - } - - if (ret == 0) - return NULL; - - /* - * Whether or not this should be here, is questionable, but the aim - * is to get this out of the main line. - */ - if (tcp == NULL) - flags = is->is_flags & ~(SI_WILDP|SI_NEWFR|SI_CLONE|SI_CLONED); - - /* - * Only one of the source or destination address can be flaged as a - * wildcard. Fill in the missing address, if set. - * For IPv6, if the address being copied in is multicast, then - * don't reset the wild flag - multicast causes it to be set in the - * first place! - */ - if ((flags & (SI_W_SADDR|SI_W_DADDR))) { - fr_ip_t *fi = &fin->fin_fi; - - 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; - } - } else { -#ifdef USE_INET6 - if (is->is_v == 6 && - IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6)) - /*EMPTY*/; - else -#endif - { - 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 - { - 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; - } - } - } - if ((is->is_flags & (SI_WILDA|SI_WILDP)) == 0) { - ATOMIC_DECL(ips_stats.iss_wild); - } - } - - flx = fin->fin_flx & cmask; - cflx = is->is_flx[out][rev]; - - /* - * Match up any flags set from IP options. - */ - 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)) - 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; - } - - if ((flags & (SI_W_SPORT|SI_W_DPORT))) { - if ((flags & SI_CLONE) != 0) { - ipstate_t *clone; - - clone = fr_stclone(fin, tcp, is); - if (clone == NULL) - return NULL; - is = clone; - } else { - ATOMIC_DECL(ips_stats.iss_wild); - } - - if ((flags & SI_W_SPORT) != 0) { - if (rev == 0) { - is->is_sport = sp; - is->is_send = ntohl(tcp->th_seq); - } else { - is->is_sport = dp; - is->is_send = ntohl(tcp->th_ack); - } - is->is_maxsend = is->is_send + 1; - } else if ((flags & SI_W_DPORT) != 0) { - if (rev == 0) { - is->is_dport = dp; - is->is_dend = ntohl(tcp->th_ack); - } else { - is->is_dport = sp; - is->is_dend = ntohl(tcp->th_seq); - } - 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); - } - - 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; - } - } - - /* - * Check if the interface name for this "direction" is set and if not, - * fill it in. - */ - 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]); - } - fin->fin_rev = rev; - return is; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_checkicmpmatchingstate */ -/* Returns: Nil */ -/* Parameters: fin(I) - pointer to packet information */ -/* */ -/* If we've got an ICMP error message, using the information stored in the */ -/* ICMP packet, look for a matching state table entry. */ -/* */ -/* 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; -{ - 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; - icmphdr_t *icmp; - fr_info_t ofin; - tcphdr_t *tcp; - int type, len; - ip_t *oip; - u_int hv; - - /* - * Does it at least have the return (basic) IP header ? - * Is it an actual recognised ICMP error type? - * Only a basic IP header (no options) should be with - * an ICMP error header. - */ - if ((fin->fin_v != 4) || (fin->fin_hlen != sizeof(ip_t)) || - (fin->fin_plen < ICMPERR_MINPKTLEN) || - !(fin->fin_flx & FI_ICMPERR)) - return NULL; - ic = fin->fin_dp; - type = ic->icmp_type; - - oip = (ip_t *)((char *)ic + ICMPERR_ICMPHLEN); - /* - * 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)) - return NULL; - - /* - * Sanity Checks. - */ - len = fin->fin_dlen - ICMPERR_ICMPHLEN; - if ((len <= 0) || ((IP_HL(oip) << 2) > len)) - return NULL; - - /* - * Is the buffer big enough for all of it ? It's the size of the IP - * header claimed in the encapsulated part which is of concern. It - * may be too big to be in this buffer but not so big that it's - * outside the ICMP packet, leading to TCP deref's causing problems. - * This is possible because we don't know how big oip_hl is when we - * do the pullup early in fr_check() and thus can't guarantee it is - * all here now. - */ -#ifdef _KERNEL - { - mb_t *m; - - m = fin->fin_m; -# if defined(MENTAT) - if ((char *)oip + len > (char *)m->b_wptr) - return NULL; -# else - if ((char *)oip + len > (char *)fin->fin_ip + m->m_len) - return NULL; -# endif - } -#endif - bcopy((char *)fin, (char *)&ofin, sizeof(*fin)); - - /* - * in the IPv4 case we must zero the i6addr union otherwise - * the IP6_EQ and IP6_NEQ macros produce the wrong results because - * of the 'junk' in the unused part of the union - */ - bzero((char *)&src, sizeof(src)); - bzero((char *)&dst, sizeof(dst)); - - /* - * we make an fin entry to be able to feed it to - * matchsrcdst note that not all fields are encessary - * but this is the cleanest way. Note further we fill - * in fin_mp such that if someone uses it we'll get - * a kernel panic. fr_matchsrcdst does not use this. - * - * watch out here, as ip is in host order and oip in network - * order. Any change we make must be undone afterwards, like - * oip->ip_off - it is still in network byte order so fix it. - */ - savelen = oip->ip_len; - oip->ip_len = len; - oip->ip_off = ntohs(oip->ip_off); - - 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); - ofin.fin_ifp = fin->fin_ifp; - ofin.fin_out = !fin->fin_out; - /* - * Reset the short and bad flag here because in fr_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. - */ - oip->ip_len = savelen; - oip->ip_off = htons(oip->ip_off); - - switch (oip->ip_p) - { - case IPPROTO_ICMP : - /* - * an ICMP error can only be generated as a result of an - * ICMP query, not as the response on an ICMP error - * - * XXX theoretically ICMP_ECHOREP and the other reply's are - * ICMP query's as well, but adding them here seems strange XXX - */ - if ((ofin.fin_flx & FI_ICMPERR) != 0) - 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); ) { - 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, - 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]++; - return is; - } - } - RWLOCK_EXIT(&ipf_state); - return NULL; - case IPPROTO_TCP : - case IPPROTO_UDP : - break; - default : - 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 = DOUBLE_HASH(hv); - - READ_ENTER(&ipf_state); - for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) { - isp = &is->is_hnext; - /* - * Only allow this icmp though if the - * encapsulated packet was allowed through the - * other way around. Note that the minimal amount - * of info present does not allow for checking against - * tcp internals such as seq and ack numbers. Only the - * ports are known to be present and can be even if the - * 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; - } - } - RWLOCK_EXIT(&ipf_state); - return NULL; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_ipsmove */ -/* Returns: Nil */ -/* Parameters: is(I) - pointer to state table entry */ -/* hv(I) - new hash value for state table entry */ -/* Write Locks: ipf_state */ -/* */ -/* 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; -{ - ipstate_t **isp; - u_int hvm; - - hvm = is->is_hv; - /* - * Remove the hash from the old location... - */ - isp = is->is_phnext; - 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]--; - - /* - * ...and put the hash in the new one. - */ - hvm = DOUBLE_HASH(hv); - is->is_hv = hvm; - isp = &ips_table[hvm]; - if (*isp) - (*isp)->is_phnext = &is->is_hnext; - else - ips_stats.iss_inuse++; - ips_stats.iss_bucketlen[hvm]++; - is->is_phnext = isp; - is->is_hnext = *isp; - *isp = is; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_stlookup */ -/* 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. */ -/* */ -/* Search the state table for a matching entry to the packet described by */ -/* the contents of *fin. */ -/* */ -/* 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; -{ - u_int hv, hvm, pr, v, tryagain; - ipstate_t *is, **isp; - u_short dport, sport; - i6addr_t src, dst; - struct icmp *ic; - ipftq_t *ifq; - int oow; - - is = NULL; - ifq = NULL; - tcp = fin->fin_dp; - ic = (struct icmp *)tcp; - hv = (pr = fin->fin_fi.fi_p); - src = fin->fin_fi.fi_src; - dst = fin->fin_fi.fi_dst; - hv += src.in4.s_addr; - hv += dst.in4.s_addr; - - v = fin->fin_fi.fi_v; -#ifdef USE_INET6 - if (v == 6) { - hv += fin->fin_fi.fi_src.i6[1]; - hv += fin->fin_fi.fi_src.i6[2]; - hv += fin->fin_fi.fi_src.i6[3]; - - if ((fin->fin_p == IPPROTO_ICMPV6) && - IN6_IS_ADDR_MULTICAST(&fin->fin_fi.fi_dst.in6)) { - hv -= dst.in4.s_addr; - } else { - hv += fin->fin_fi.fi_dst.i6[1]; - hv += fin->fin_fi.fi_dst.i6[2]; - hv += fin->fin_fi.fi_dst.i6[3]; - } - } -#endif - if ((v == 4) && - (fin->fin_flx & (FI_MULTICAST|FI_BROADCAST|FI_MBCAST))) { - if (fin->fin_out == 0) { - hv -= src.in4.s_addr; - } else { - hv -= dst.in4.s_addr; - } - } - - /* - * Search the hash table for matching packet header info. - */ - switch (pr) - { -#ifdef USE_INET6 - case IPPROTO_ICMPV6 : - tryagain = 0; - if (v == 6) { - if ((ic->icmp_type == ICMP6_ECHO_REQUEST) || - (ic->icmp_type == ICMP6_ECHO_REPLY)) { - hv += ic->icmp_id; - } - } - READ_ENTER(&ipf_state); -icmp6again: - hvm = DOUBLE_HASH(hv); - for (isp = &ips_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); - if (is != NULL && - fr_matchicmpqueryreply(v, &is->is_icmp, - ic, fin->fin_rev)) { - if (fin->fin_rev) - ifq = &ips_icmpacktq; - else - ifq = &ips_icmptq; - break; - } - } - - if (is != NULL) { - if ((tryagain != 0) && !(is->is_flags & SI_W_DADDR)) { - 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]; - fr_ipsmove(is, hv); - MUTEX_DOWNGRADE(&ipf_state); - } - break; - } - RWLOCK_EXIT(&ipf_state); - - /* - * No matching icmp state entry. Perhaps this is a - * response to another state entry. - * - * XXX With some ICMP6 packets, the "other" address is already - * in the packet, after the ICMP6 header, and this could be - * used in place of the multicast address. However, taking - * 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)) { - 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); - goto icmp6again; - } - - is = fr_checkicmp6matchingstate(fin); - if (is != NULL) - return is; - break; -#endif - - case IPPROTO_ICMP : - if (v == 4) { - hv += ic->icmp_id; - } - hv = DOUBLE_HASH(hv); - READ_ENTER(&ipf_state); - for (isp = &ips_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); - if ((is != NULL) && - (ic->icmp_id == is->is_icmp.ici_id) && - fr_matchicmpqueryreply(v, &is->is_icmp, - ic, fin->fin_rev)) { - if (fin->fin_rev) - ifq = &ips_icmpacktq; - else - ifq = &ips_icmptq; - break; - } - } - if (is == NULL) { - RWLOCK_EXIT(&ipf_state); - } - break; - - case IPPROTO_TCP : - case IPPROTO_UDP : - ifqp = NULL; - sport = htons(fin->fin_data[0]); - hv += sport; - dport = htons(fin->fin_data[1]); - hv += dport; - oow = 0; - tryagain = 0; - READ_ENTER(&ipf_state); -retry_tcpudp: - hvm = DOUBLE_HASH(hv); - for (isp = &ips_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); - if (is != NULL) { - if (pr == IPPROTO_TCP) { - if (!fr_tcpstate(fin, tcp, is)) { - oow |= fin->fin_flx & FI_OOW; - continue; - } - } - break; - } - } - if (is != NULL) { - if (tryagain && - !(is->is_flags & (SI_CLONE|SI_WILDP|SI_WILDA))) { - hv += dport; - hv += sport; - fr_ipsmove(is, hv); - MUTEX_DOWNGRADE(&ipf_state); - } - break; - } - RWLOCK_EXIT(&ipf_state); - - if (ips_stats.iss_wild) { - if (tryagain == 0) { - hv -= dport; - hv -= sport; - } else if (tryagain == 1) { - hv = fin->fin_fi.fi_p; - /* - * If we try to pretend this is a reply to a - * multicast/broadcast packet then we need to - * exclude part of the address from the hash - * calculation. - */ - if (fin->fin_out == 0) { - hv += src.in4.s_addr; - } else { - hv += dst.in4.s_addr; - } - hv += dport; - hv += sport; - } - tryagain++; - if (tryagain <= 2) { - WRITE_ENTER(&ipf_state); - goto retry_tcpudp; - } - } - fin->fin_flx |= oow; - break; - -#if 0 - case IPPROTO_GRE : - gre = fin->fin_dp; - if (GRE_REV(gre->gr_flags) == 1) { - hv += gre->gr_call; - } - /* FALLTHROUGH */ -#endif - default : - ifqp = NULL; - hvm = DOUBLE_HASH(hv); - READ_ENTER(&ipf_state); - for (isp = &ips_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); - if (is != NULL) { - ifq = &ips_iptq; - break; - } - } - if (is == NULL) { - RWLOCK_EXIT(&ipf_state); - } - break; - } - - if (is != NULL) { - if (((is->is_sti.tqe_flags & TQE_RULEBASED) != 0) && - (is->is_tqehead[fin->fin_rev] != NULL)) - ifq = is->is_tqehead[fin->fin_rev]; - if (ifq != NULL && ifqp != NULL) - *ifqp = ifq; - } - 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 */ -/* Returns: frentry_t* - NULL == search failed, */ -/* else pointer to rule for matching state */ -/* Parameters: ifp(I) - pointer to interface */ -/* 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; -{ - ipstate_t *is; - frentry_t *fr; - tcphdr_t *tcp; - ipftq_t *ifq; - u_int pass; - - if (fr_state_lock || (ips_list == NULL) || - (fin->fin_flx & (FI_SHORT|FI_STATE|FI_FRAGBODY|FI_BAD))) - return NULL; - - is = NULL; - if ((fin->fin_flx & FI_TCPUDP) || - (fin->fin_fi.fi_p == IPPROTO_ICMP) -#ifdef USE_INET6 - || (fin->fin_fi.fi_p == IPPROTO_ICMPV6) -#endif - ) - tcp = fin->fin_dp; - else - tcp = 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); - switch (fin->fin_p) - { -#ifdef USE_INET6 - case IPPROTO_ICMPV6 : - if (is != NULL) - break; - if (fin->fin_v == 6) { - is = fr_checkicmp6matchingstate(fin); - if (is != NULL) - goto matched; - } - break; -#endif - case IPPROTO_ICMP : - if (is != NULL) - break; - /* - * No matching icmp state entry. Perhaps this is a - * response to another state entry. - */ - is = fr_checkicmpmatchingstate(fin); - if (is != NULL) - goto matched; - break; - case IPPROTO_TCP : - if (is == NULL) - break; - - if (is->is_pass & FR_NEWISN) { - if (fin->fin_out == 0) - fr_fixinisn(fin, is); - else if (fin->fin_out == 1) - fr_fixoutisn(fin, is); - } - break; - default : - if (fin->fin_rev) - ifq = &ips_udpacktq; - else - ifq = &ips_udptq; - break; - } - if (is == NULL) { - ATOMIC_INCL(ips_stats.iss_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) - return NULL; - if (fr_matchtag(&fr->fr_nattag, fin->fin_nattag) != 0) - return NULL; - } - (void) strncpy(fin->fin_group, 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_state = is; - is->is_touched = fr_ticks; - MUTEX_ENTER(&is->is_lock); - is->is_ref++; - MUTEX_EXIT(&is->is_lock); - RWLOCK_EXIT(&ipf_state); - fin->fin_flx |= FI_STATE; - if ((pass & FR_LOGFIRST) != 0) - pass &= ~(FR_LOGFIRST|FR_LOG); - *passp = pass; - return fr; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_fixoutisn */ -/* Returns: Nil */ -/* 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; -{ - tcphdr_t *tcp; - int rev; - u_32_t seq; - - tcp = fin->fin_dp; - rev = fin->fin_rev; - if ((is->is_flags & IS_ISNSYN) != 0) { - if (rev == 0) { - 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]); - } - } - if ((is->is_flags & IS_ISNACK) != 0) { - if (rev == 1) { - 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]); - } - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_fixinisn */ -/* Returns: Nil */ -/* Parameters: fin(I) - pointer to packet information */ -/* is(I) - pointer to master state structure */ -/* */ -/* 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; -{ - tcphdr_t *tcp; - int rev; - u_32_t ack; - - tcp = fin->fin_dp; - rev = fin->fin_rev; - if ((is->is_flags & IS_ISNSYN) != 0) { - if (rev == 1) { - 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]); - } - } - if ((is->is_flags & IS_ISNACK) != 0) { - if (rev == 0) { - 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]); - } - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_statesync */ -/* Returns: Nil */ -/* Parameters: 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 */ -/* changed since last time. */ -/* */ -/* 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; -{ - ipstate_t *is; - int i; - - if (fr_running <= 0) - return; - - WRITE_ENTER(&ipf_state); - - if (fr_running <= 0) { - RWLOCK_EXIT(&ipf_state); - return; - } - - for (is = ips_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_v); - } - } - RWLOCK_EXIT(&ipf_state); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_delstate */ -/* Returns: int - 0 = entry deleted, else reference count on struct */ -/* Parameters: is(I) - pointer to state structure to delete */ -/* why(I) - if not 0, log reason why it was deleted */ -/* Write Locks: ipf_state */ -/* */ -/* Deletes a state entry from the enumerated list as well as the hash table */ -/* 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; -{ - - /* - * Since we want to delete this, remove it from the state table, - * where it can be found & used, first. - */ - if (is->is_phnext != NULL) { - *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]--; - - is->is_phnext = NULL; - is->is_hnext = NULL; - } - - /* - * Because ips_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); - } - is->is_flags &= ~(SI_WILDP|SI_WILDA); - } - - /* - * 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; - } - - /* - * 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 - * 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_ref > 1) { - is->is_ref--; - MUTEX_EXIT(&is->is_lock); - return is->is_ref; - } - MUTEX_EXIT(&is->is_lock); - - 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 (is->is_tqehead[1] != NULL) { - if (fr_deletetimeoutqueue(is->is_tqehead[1]) == 0) - fr_freetimeoutqueue(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 - - /* - * Now remove it from the linked list of known states - */ - if (is->is_pnext != NULL) { - *is->is_pnext = is->is_next; - - if (is->is_next != NULL) - is->is_next->is_pnext = is->is_pnext; - - is->is_pnext = NULL; - is->is_next = NULL; - } - - if (ipstate_logging != 0 && why != 0) - ipstate_log(is, why); - - if (is->is_p == IPPROTO_TCP) - ips_stats.iss_fin++; - else - ips_stats.iss_expire++; - - if (is->is_rule != NULL) { - is->is_rule->fr_statecnt--; - (void) fr_derefrule(&is->is_rule); - } - - MUTEX_DESTROY(&is->is_lock); - KFREE(is); - ips_num--; - - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_timeoutstate */ -/* Returns: Nil */ -/* Parameters: Nil */ -/* */ -/* 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() -{ - 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) - for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { - if (tqe->tqe_die > fr_ticks) - break; - tqn = tqe->tqe_next; - is = tqe->tqe_parent; - fr_delstate(is, ISL_EXPIRE); - } - - for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) { - ifqnext = ifq->ifq_next; - - for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { - if (tqe->tqe_die > fr_ticks) - break; - tqn = tqe->tqe_next; - is = tqe->tqe_parent; - fr_delstate(is, ISL_EXPIRE); - } - } - - for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) { - ifqnext = ifq->ifq_next; - - if (((ifq->ifq_flags & IFQF_DELETE) != 0) && - (ifq->ifq_ref == 0)) { - fr_freetimeoutqueue(ifq); - } - } - - if (fr_state_doflush) { - (void) fr_state_flush(2, 0); - fr_state_doflush = 0; - } - - RWLOCK_EXIT(&ipf_state); - SPL_X(s); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_state_flush */ -/* Returns: int - 0 == success, -1 == failure */ -/* Parameters: Nil */ -/* Write Locks: ipf_state */ -/* */ -/* Flush state tables. Three actions currently defined: */ -/* which == 0 : flush all state table entries */ -/* which == 1 : flush TCP connections which have started to close but are */ -/* stuck for some reason. */ -/* which == 2 : flush TCP connections which have been idle for a long time, */ -/* starting at > 4 days idle and working back in successive half-*/ -/* days to at most 12 hours old. If this fails to free enough */ -/* slots then work backwards in half hour slots to 30 minutes. */ -/* 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; -{ - ipftq_t *ifq, *ifqnext; - ipftqent_t *tqe, *tqn; - ipstate_t *is, **isp; - int removed; - SPL_INT(s); - - removed = 0; - - SPL_NET(s); - - switch (which) - { - case 0 : - /* - * Style 0 flush removes everything... - */ - for (isp = &ips_list; ((is = *isp) != NULL); ) { - if ((proto != 0) && (is->is_v != proto)) { - isp = &is->is_next; - continue; - } - if (fr_delstate(is, ISL_FLUSH) == 0) - removed++; - else - isp = &is->is_next; - } - break; - - case 1 : - /* - * 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 (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) - removed++; - } - } - - /* - * Also need to look through the user defined queues. - */ - for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) { - ifqnext = 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) - continue; - - if ((is->is_state[0] > IPF_TCPS_ESTABLISHED) && - (is->is_state[1] > IPF_TCPS_ESTABLISHED)) { - if (fr_delstate(is, ISL_EXPIRE) == 0) - removed++; - } - } - } - break; - - case 2 : - break; - - /* - * Args 5-11 correspond to flushing those particular states - * for TCP connections. - */ - case IPF_TCPS_CLOSE_WAIT : - case IPF_TCPS_FIN_WAIT_1 : - case IPF_TCPS_CLOSING : - case IPF_TCPS_LAST_ACK : - case IPF_TCPS_FIN_WAIT_2 : - case IPF_TCPS_TIME_WAIT : - case IPF_TCPS_CLOSED : - tqn = ips_tqtqb[which].ifq_head; - while (tqn != NULL) { - tqe = tqn; - tqn = tqe->tqe_next; - is = tqe->tqe_parent; - if (fr_delstate(is, ISL_FLUSH) == 0) - removed++; - } - break; - - default : - if (which < 30) - break; - - /* - * 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); ) { - if ((proto == 0) || (is->is_v == proto)) { - if (fr_ticks - is->is_touched > which) { - if (fr_delstate(is, ISL_FLUSH) == 0) { - removed++; - continue; - } - } - } - isp = &is->is_next; - } - break; - } - - if (which != 2) { - SPL_X(s); - return removed; - } - - /* - * Asked to remove inactive entries because the table is full. - */ - 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); - } - - SPL_X(s); - return removed; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_state_flush_entry */ -/* Returns: int - 0 = entry deleted, else not deleted */ -/* Parameters: 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. */ -/* ------------------------------------------------------------------------ */ -static int fr_state_flush_entry(entry) -void *entry; -{ - return fr_delstate(entry, ISL_FLUSH); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_tcp_age */ -/* Returns: int - 1 == state transition made, 0 == no change (rejected) */ -/* Parameters: tq(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 */ -/* */ -/* Rewritten by Arjan de Vet <Arjan.deVet@adv.iae.nl>, 2000-07-29: */ -/* */ -/* - (try to) base state transitions on real evidence only, */ -/* i.e. packets that are sent and have been received by ipfilter; */ -/* diagram 18.12 of TCP/IP volume 1 by W. Richard Stevens was used. */ -/* */ -/* - deal with half-closed connections correctly; */ -/* */ -/* - store the state of the source in state[0] such that ipfstat */ -/* displays the state as source/dest instead of dest/source; the calls */ -/* to fr_tcp_age have been changed accordingly. */ -/* */ -/* Internal Parameters: */ -/* */ -/* state[0] = state of source (host that initiated connection) */ -/* state[1] = state of dest (host that accepted the connection) */ -/* */ -/* dir == 0 : a packet from source to dest */ -/* dir == 1 : a packet from dest to source */ -/* */ -/* A typical procession for a connection is as follows: */ -/* */ -/* +--------------+-------------------+ */ -/* | Side '0' | Side '1' | */ -/* +--------------+-------------------+ */ -/* | 0 -> 1 (SYN) | | */ -/* | | 0 -> 2 (SYN-ACK) | */ -/* | 1 -> 3 (ACK) | | */ -/* | | 2 -> 4 (ACK-PUSH) | */ -/* | 3 -> 4 (ACK) | | */ -/* | ... | ... | */ -/* | | 4 -> 6 (FIN-ACK) | */ -/* | 4 -> 5 (ACK) | | */ -/* | | 6 -> 6 (ACK-PUSH) | */ -/* | 5 -> 5 (ACK) | | */ -/* | 5 -> 8 (FIN) | | */ -/* | | 6 -> 10 (ACK) | */ -/* +--------------+-------------------+ */ -/* */ -/* 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 dlen, ostate, nstate, rval, dir; - u_char tcpflags; - tcphdr_t *tcp; - - tcp = fin->fin_dp; - - rval = 0; - dir = fin->fin_rev; - tcpflags = tcp->th_flags; - dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); - - if (tcpflags & TH_RST) { - if (!(tcpflags & TH_PUSH) && !dlen) - nstate = IPF_TCPS_CLOSED; - else - nstate = 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 */ - if ((tcpflags & TH_OPENING) == TH_OPENING) { - /* - * 'dir' received an S and sends SA in - * response, LISTEN -> SYN_RECEIVED - */ - nstate = IPF_TCPS_SYN_RECEIVED; - rval = 1; - } else if ((tcpflags & TH_OPENING) == TH_SYN) { - /* 'dir' sent S, LISTEN -> SYN_SENT */ - nstate = IPF_TCPS_SYN_SENT; - rval = 1; - } - /* - * the next piece of code makes it possible to get - * already established connections into the state table - * after a restart or reload of the filter rules; this - * does not work when a strict 'flags S keep state' is - * used for tcp connections of course - */ - if (((flags & IS_TCPFSM) == 0) && - ((tcpflags & TH_ACKMASK) == TH_ACK)) { - /* - * we saw an A, guess 'dir' is in ESTABLISHED - * mode - */ - switch (ostate) - { - case IPF_TCPS_LISTEN : - case IPF_TCPS_SYN_RECEIVED : - nstate = IPF_TCPS_HALF_ESTAB; - rval = 1; - break; - case IPF_TCPS_HALF_ESTAB : - case IPF_TCPS_ESTABLISHED : - nstate = IPF_TCPS_ESTABLISHED; - rval = 1; - break; - default : - break; - } - } - /* - * TODO: besides regular ACK packets we can have other - * packets as well; it is yet to be determined how we - * should initialize the states in those cases - */ - break; - - case IPF_TCPS_SYN_SENT: /* 1 */ - if ((tcpflags & ~(TH_ECN|TH_CWR)) == TH_SYN) { - /* - * A retransmitted SYN packet. We do not reset - * the timeout here to fr_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 - * passed the check for its flags being valid - * in the TCP FSM. Setting rval to 2 has the - * result of not resetting the timeout. - */ - rval = 2; - } else if ((tcpflags & (TH_SYN|TH_FIN|TH_ACK)) == - TH_ACK) { - /* - * we see an A from 'dir' which is in SYN_SENT - * state: 'dir' sent an A in response to an SA - * which it received, SYN_SENT -> ESTABLISHED - */ - nstate = IPF_TCPS_ESTABLISHED; - rval = 1; - } else if (tcpflags & TH_FIN) { - /* - * we see an F from 'dir' which is in SYN_SENT - * state and wants to close its side of the - * connection; SYN_SENT -> FIN_WAIT_1 - */ - nstate = IPF_TCPS_FIN_WAIT_1; - rval = 1; - } else if ((tcpflags & TH_OPENING) == TH_OPENING) { - /* - * we see an SA from 'dir' which is already in - * SYN_SENT state, this means we have a - * simultaneous open; SYN_SENT -> SYN_RECEIVED - */ - nstate = IPF_TCPS_SYN_RECEIVED; - rval = 1; - } - break; - - case IPF_TCPS_SYN_RECEIVED: /* 2 */ - if ((tcpflags & (TH_SYN|TH_FIN|TH_ACK)) == TH_ACK) { - /* - * we see an A from 'dir' which was in - * SYN_RECEIVED state so it must now be in - * established state, SYN_RECEIVED -> - * ESTABLISHED - */ - nstate = IPF_TCPS_ESTABLISHED; - rval = 1; - } else if ((tcpflags & ~(TH_ECN|TH_CWR)) == - TH_OPENING) { - /* - * We see an SA from 'dir' which is already in - * SYN_RECEIVED state. - */ - rval = 2; - } else if (tcpflags & TH_FIN) { - /* - * we see an F from 'dir' which is in - * SYN_RECEIVED state and wants to close its - * side of the connection; SYN_RECEIVED -> - * FIN_WAIT_1 - */ - nstate = IPF_TCPS_FIN_WAIT_1; - rval = 1; - } - break; - - case IPF_TCPS_HALF_ESTAB: /* 3 */ - if (tcpflags & TH_FIN) { - nstate = IPF_TCPS_FIN_WAIT_1; - rval = 1; - } else if ((tcpflags & TH_ACKMASK) == TH_ACK) { - /* - * If we've picked up a connection in mid - * flight, we could be looking at a follow on - * packet from the same direction as the one - * that created this state. Recognise it but - * do not advance the entire connection's - * state. - */ - switch (ostate) - { - case IPF_TCPS_LISTEN : - case IPF_TCPS_SYN_SENT : - case IPF_TCPS_SYN_RECEIVED : - rval = 1; - break; - case IPF_TCPS_HALF_ESTAB : - case IPF_TCPS_ESTABLISHED : - nstate = IPF_TCPS_ESTABLISHED; - rval = 1; - break; - default : - break; - } - } - break; - - case IPF_TCPS_ESTABLISHED: /* 4 */ - rval = 1; - if (tcpflags & TH_FIN) { - /* - * 'dir' closed its side of the connection; - * this gives us a half-closed connection; - * ESTABLISHED -> FIN_WAIT_1 - */ - if (ostate == IPF_TCPS_FIN_WAIT_1) { - nstate = IPF_TCPS_CLOSING; - } else { - nstate = IPF_TCPS_FIN_WAIT_1; - } - } else if (tcpflags & TH_ACK) { - /* - * an ACK, should we exclude other flags here? - */ - if (ostate == IPF_TCPS_FIN_WAIT_1) { - /* - * We know the other side did an active - * close, so we are ACKing the recvd - * FIN packet (does the window matching - * code guarantee this?) and go into - * CLOSE_WAIT state; this gives us a - * half-closed connection - */ - nstate = IPF_TCPS_CLOSE_WAIT; - } else if (ostate < IPF_TCPS_CLOSE_WAIT) { - /* - * still a fully established - * connection reset timeout - */ - nstate = IPF_TCPS_ESTABLISHED; - } - } - break; - - case IPF_TCPS_CLOSE_WAIT: /* 5 */ - rval = 1; - if (tcpflags & TH_FIN) { - /* - * application closed and 'dir' sent a FIN, - * we're now going into LAST_ACK state - */ - nstate = IPF_TCPS_LAST_ACK; - } else { - /* - * we remain in CLOSE_WAIT because the other - * side has closed already and we did not - * close our side yet; reset timeout - */ - nstate = IPF_TCPS_CLOSE_WAIT; - } - break; - - case IPF_TCPS_FIN_WAIT_1: /* 6 */ - rval = 1; - if ((tcpflags & TH_ACK) && - ostate > IPF_TCPS_CLOSE_WAIT) { - /* - * if the other side is not active anymore - * it has sent us a FIN packet that we are - * ack'ing now with an ACK; this means both - * sides have now closed the connection and - * we go into TIME_WAIT - */ - /* - * XXX: how do we know we really are ACKing - * the FIN packet here? does the window code - * guarantee that? - */ - nstate = IPF_TCPS_TIME_WAIT; - } else { - /* - * we closed our side of the connection - * already but the other side is still active - * (ESTABLISHED/CLOSE_WAIT); continue with - * this half-closed connection - */ - nstate = IPF_TCPS_FIN_WAIT_1; - } - break; - - case IPF_TCPS_CLOSING: /* 7 */ - if ((tcpflags & (TH_FIN|TH_ACK)) == TH_ACK) { - nstate = IPF_TCPS_TIME_WAIT; - } - rval = 2; - 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; - } - /* - * we cannot detect when we go out of LAST_ACK state to - * CLOSED because that is based on the reception of ACK - * packets; ipfilter can only detect that a packet - * has been sent by a host - */ - break; - - case IPF_TCPS_FIN_WAIT_2: /* 9 */ - /* NOT USED */ - break; - - case IPF_TCPS_TIME_WAIT: /* 10 */ - /* we're in 2MSL timeout now */ - if (ostate == IPF_TCPS_LAST_ACK) { - nstate = IPF_TCPS_CLOSED; - } - rval = 1; - break; - - case IPF_TCPS_CLOSED: /* 11 */ - rval = 2; - 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 - abort(); -#endif - break; - } - } - - /* - * If rval == 2 then do not update the queue position, but treat the - * packet as being ok. - */ - if (rval == 2) - rval = 1; - else if (rval == 1) { - tqe->tqe_state[dir] = nstate; - if ((tqe->tqe_flags & TQE_RULEBASED) == 0) - fr_movequeue(tqe, tqe->tqe_ifq, tqtab + nstate); - } - - return rval; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipstate_log */ -/* Returns: Nil */ -/* Parameters: 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; -{ -#ifdef IPFILTER_LOG - struct ipslog ipsl; - size_t sizes[1]; - void *items[1]; - int types[1]; - - /* - * Copy information out of the ipstate_t structure and into the - * structure used for logging. - */ - ipsl.isl_type = type; - ipsl.isl_pkts[0] = is->is_pkts[0] + is->is_icmppkts[0]; - ipsl.isl_bytes[0] = is->is_bytes[0]; - ipsl.isl_pkts[1] = is->is_pkts[1] + is->is_icmppkts[1]; - ipsl.isl_bytes[1] = is->is_bytes[1]; - ipsl.isl_pkts[2] = is->is_pkts[2] + is->is_icmppkts[2]; - ipsl.isl_bytes[2] = is->is_bytes[2]; - ipsl.isl_pkts[3] = is->is_pkts[3] + is->is_icmppkts[3]; - ipsl.isl_bytes[3] = is->is_bytes[3]; - ipsl.isl_src = is->is_src; - ipsl.isl_dst = is->is_dst; - ipsl.isl_p = is->is_p; - ipsl.isl_v = is->is_v; - ipsl.isl_flags = is->is_flags; - ipsl.isl_tag = is->is_tag; - ipsl.isl_rulen = is->is_rulen; - (void) strncpy(ipsl.isl_group, is->is_group, FR_GROUPLEN); - - if (ipsl.isl_p == IPPROTO_TCP || ipsl.isl_p == IPPROTO_UDP) { - ipsl.isl_sport = is->is_sport; - ipsl.isl_dport = is->is_dport; - if (ipsl.isl_p == IPPROTO_TCP) { - ipsl.isl_state[0] = is->is_state[0]; - ipsl.isl_state[1] = is->is_state[1]; - } - } else if (ipsl.isl_p == IPPROTO_ICMP) { - ipsl.isl_itype = is->is_icmp.ici_type; - } else if (ipsl.isl_p == IPPROTO_ICMPV6) { - ipsl.isl_itype = is->is_icmp.ici_type; - } else { - ipsl.isl_ps.isl_filler[0] = 0; - ipsl.isl_ps.isl_filler[1] = 0; - } - - items[0] = &ipsl; - sizes[0] = sizeof(ipsl); - types[0] = 0; - - if (ipllog(IPL_LOGSTATE, NULL, items, sizes, types, 1)) { - ATOMIC_INCL(ips_stats.iss_logged); - } else { - ATOMIC_INCL(ips_stats.iss_logfail); - } -#endif -} - - -#ifdef USE_INET6 -/* ------------------------------------------------------------------------ */ -/* Function: fr_checkicmp6matchingstate */ -/* Returns: ipstate_t* - NULL == no match found, */ -/* else pointer to matching state entry */ -/* Parameters: fin(I) - pointer to packet information */ -/* Locks: NULL == no locks, else Read Lock on ipf_state */ -/* */ -/* 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; -{ - struct icmp6_hdr *ic6, *oic; - int type, backward, i; - ipstate_t *is, **isp; - u_short sport, dport; - i6addr_t dst, src; - u_short savelen; - icmpinfo_t *ic; - fr_info_t ofin; - tcphdr_t *tcp; - ip6_t *oip6; - u_char pr; - u_int hv; - - /* - * Does it at least have the return (basic) IP header ? - * Is it an actual recognised ICMP error type? - * Only a basic IP header (no options) should be with - * an ICMP error header. - */ - if ((fin->fin_v != 6) || (fin->fin_plen < ICMP6ERR_MINPKTLEN) || - !(fin->fin_flx & FI_ICMPERR)) - return NULL; - - ic6 = fin->fin_dp; - type = ic6->icmp6_type; - - oip6 = (ip6_t *)((char *)ic6 + ICMPERR_ICMPHLEN); - if (fin->fin_plen < sizeof(*oip6)) - return NULL; - - bcopy((char *)fin, (char *)&ofin, sizeof(*fin)); - ofin.fin_v = 6; - ofin.fin_ifp = fin->fin_ifp; - ofin.fin_out = !fin->fin_out; - ofin.fin_m = NULL; /* if dereferenced, panic XXX */ - ofin.fin_mp = NULL; /* if dereferenced, panic XXX */ - - /* - * We make a fin entry to be able to feed it to - * 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. - * - * 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; - ofin.fin_flx = FI_NOCKSUM; - ofin.fin_ip = (ip_t *)oip6; - (void) fr_makefrip(sizeof(*oip6), (ip_t *)oip6, &ofin); - ofin.fin_flx &= ~(FI_BAD|FI_SHORT); - oip6->ip6_plen = savelen; - - if (oip6->ip6_nxt == IPPROTO_ICMPV6) { - oic = (struct icmp6_hdr *)(oip6 + 1); - /* - * an ICMP error can only be generated as a result of an - * ICMP query, not as the response on an ICMP error - * - * XXX theoretically ICMP_ECHOREP and the other reply's are - * ICMP query's as well, but adding them here seems strange XXX - */ - if (!(oic->icmp6_type & ICMP6_INFOMSG_MASK)) - return NULL; - - /* - * perform a lookup of the ICMP packet in the state table - */ - hv = (pr = oip6->ip6_nxt); - src.in6 = oip6->ip6_src; - hv += src.in4.s_addr; - dst.in6 = oip6->ip6_dst; - hv += dst.in4.s_addr; - hv += oic->icmp6_id; - hv += oic->icmp6_seq; - hv = DOUBLE_HASH(hv); - - READ_ENTER(&ipf_state); - for (isp = &ips_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, - &dst, NULL, FI_ICMPCMP))) { - /* - * in the state table ICMP query's are stored - * with the type of the corresponding ICMP - * response. Correct here - */ - 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; - } - } - } - RWLOCK_EXIT(&ipf_state); - return NULL; - } - - hv = (pr = oip6->ip6_nxt); - src.in6 = oip6->ip6_src; - hv += src.i6[0]; - hv += src.i6[1]; - hv += src.i6[2]; - hv += src.i6[3]; - dst.in6 = oip6->ip6_dst; - hv += dst.i6[0]; - hv += dst.i6[1]; - hv += dst.i6[2]; - hv += dst.i6[3]; - - if ((oip6->ip6_nxt == IPPROTO_TCP) || (oip6->ip6_nxt == IPPROTO_UDP)) { - tcp = (tcphdr_t *)(oip6 + 1); - dport = tcp->th_dport; - sport = tcp->th_sport; - hv += dport; - hv += sport; - } else - tcp = NULL; - hv = DOUBLE_HASH(hv); - - READ_ENTER(&ipf_state); - for (isp = &ips_table[hv]; ((is = *isp) != NULL); ) { - isp = &is->is_hnext; - /* - * Only allow this icmp though if the - * encapsulated packet was allowed through the - * other way around. Note that the minimal amount - * of info present does not allow for checking against - * tcp internals such as seq and ack numbers. - */ - if ((is->is_p != pr) || (is->is_v != 6) || - (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 - */ - return is; - } - } - RWLOCK_EXIT(&ipf_state); - return NULL; -} -#endif - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_sttab_init */ -/* Returns: Nil */ -/* Parameters: 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; -{ - 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; - 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; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_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; -{ - int i; - - for (i = IPF_TCP_NSTATES - 1; i >= 0; i--) - MUTEX_DESTROY(&tqp[i].ifq_lock); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_statederef */ -/* Returns: Nil */ -/* Parameters: 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. */ -/* */ -/* This function is only called when cleaning up after increasing is_ref by */ -/* one earlier in the 'code path' so if is_ref is 1 when entering, we do */ -/* have an orphan, otherwise not. However there is a possible race between */ -/* the entry being deleted via flushing with an ioctl call (that calls the */ -/* delete function directly) and the tail end of packet processing so we */ -/* need to grab is_lock before doing the check to synchronise the two code */ -/* paths. */ -/* */ -/* When operating in userland (ipftest), we have no timers to clear a state */ -/* entry. Therefore, we make a few simple tests before deleting an entry */ -/* outright. We compare states on each side looking for a combination of */ -/* TIME_WAIT (should really be FIN_WAIT_2?) and LAST_ACK. Then we factor */ -/* in packet direction with the interface list to make sure we don't */ -/* prematurely delete an entry on a final inbound packet that's we're also */ -/* supposed to route elsewhere. */ -/* */ -/* Internal parameters: */ -/* state[0] = state of source (host that initiated connection) */ -/* state[1] = state of dest (host that accepted the connection) */ -/* */ -/* dir == 0 : a packet from source to dest */ -/* dir == 1 : a packet from dest to source */ -/* ------------------------------------------------------------------------ */ -void fr_statederef(isp) -ipstate_t **isp; -{ - ipstate_t *is; - - is = *isp; - *isp = NULL; - - MUTEX_ENTER(&is->is_lock); - if (is->is_ref > 1) { - is->is_ref--; - 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); - } -#endif - return; - } - MUTEX_EXIT(&is->is_lock); - - WRITE_ENTER(&ipf_state); - fr_delstate(is, ISL_EXPIRE); - RWLOCK_EXIT(&ipf_state); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_setstatequeue */ -/* Returns: Nil */ -/* Parameters: 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; -{ - ipftq_t *oifq, *nifq; - - - if ((is->is_sti.tqe_flags & TQE_RULEBASED) != 0) - nifq = is->is_tqehead[rev]; - else - nifq = NULL; - - if (nifq == NULL) { - switch (is->is_p) - { -#ifdef USE_INET6 - case IPPROTO_ICMPV6 : - if (rev == 1) - nifq = &ips_icmpacktq; - else - nifq = &ips_icmptq; - break; -#endif - case IPPROTO_ICMP : - if (rev == 1) - nifq = &ips_icmpacktq; - else - nifq = &ips_icmptq; - break; - case IPPROTO_TCP : - nifq = ips_tqtqb + is->is_state[rev]; - break; - - case IPPROTO_UDP : - if (rev == 1) - nifq = &ips_udpacktq; - else - nifq = &ips_udptq; - break; - - default : - nifq = &ips_iptq; - break; - } - } - - oifq = is->is_sti.tqe_ifq; - /* - * If it's currently on a timeout queue, move it from one queue to - * another, else put it on the end of the newly determined queue. - */ - if (oifq != NULL) - fr_movequeue(&is->is_sti, oifq, nifq); - else - fr_queueappend(&is->is_sti, nifq, is); - return; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_stateiter */ -/* Returns: int - 0 == success, else error */ -/* Parameters: token(I) - pointer to ipftoken structure */ -/* itp(I) - pointer to ipfgeniter 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.) */ -/* ------------------------------------------------------------------------ */ -static int fr_stateiter(token, itp) -ipftoken_t *token; -ipfgeniter_t *itp; -{ - ipstate_t *is, *next, zero; - int error, count; - char *dst; - - if (itp->igi_data == NULL) - return EFAULT; - - if (itp->igi_nitems < 1) - return ENOSPC; - - if (itp->igi_type != IPFGENITER_STATE) - return EINVAL; - - is = token->ipt_data; - if (is == (void *)-1) { - ipf_freetoken(token); - return ESRCH; - } - - error = 0; - dst = itp->igi_data; - - READ_ENTER(&ipf_state); - if (is == NULL) { - next = ips_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 (is != NULL) { - fr_statederef(&is); - } - - return error; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_stgettable */ -/* Returns: int - 0 = success, else error */ -/* Parameters: 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; -{ - ipftable_t table; - int error; - - error = fr_inobj(data, &table, IPFOBJ_GTABLE); - if (error != 0) - return error; - - if (table.ita_type != IPFTABLE_BUCKETS) - return EINVAL; - - error = COPYOUT(ips_stats.iss_bucketlen, table.ita_table, - fr_statesize * sizeof(u_long)); - if (error != 0) - error = EFAULT; - return error; -} diff --git a/sys/contrib/ipfilter/netinet/ip_state.h b/sys/contrib/ipfilter/netinet/ip_state.h deleted file mode 100644 index 71dae1d..0000000 --- a/sys/contrib/ipfilter/netinet/ip_state.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (C) 1995-2001 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * @(#)ip_state.h 1.3 1/12/96 (C) 1995 Darren Reed - * $Id: ip_state.h,v 2.68.2.10 2007/10/16 09:33:24 darrenr Exp $ - */ -#ifndef __IP_STATE_H__ -#define __IP_STATE_H__ - -#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51) -# define SIOCDELST _IOW('r', 61, struct ipfobj) -#else -# define SIOCDELST _IOW(r, 61, struct ipfobj) -#endif - -struct ipscan; - -#ifndef IPSTATE_SIZE -# define IPSTATE_SIZE 5737 -#endif -#ifndef IPSTATE_MAX -# 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) - - -typedef struct ipstate { - ipfmutex_t is_lock; - struct ipstate *is_next; - struct ipstate **is_pnext; - struct ipstate *is_hnext; - struct ipstate **is_phnext; - struct ipstate **is_me; - void *is_ifp[4]; - void *is_sync; - frentry_t *is_rule; - struct ipftq *is_tqehead[2]; - struct ipscan *is_isc; - U_QUAD_T is_pkts[4]; - U_QUAD_T is_bytes[4]; - U_QUAD_T is_icmppkts[4]; - struct ipftqent is_sti; - u_int is_frage[2]; - int is_ref; /* reference count */ - int is_isninc[2]; - u_short is_sumd[2]; - i6addr_t is_src; - i6addr_t is_dst; - u_int is_pass; - u_char is_p; /* Protocol */ - u_char is_v; - u_32_t is_hv; - u_32_t is_tag; - u_32_t is_opt[2]; /* packet options set */ - u_32_t is_optmsk[2]; /* " " mask */ - u_short is_sec; /* security options set */ - u_short is_secmsk; /* " " mask */ - u_short is_auth; /* authentication options set */ - u_short is_authmsk; /* " " mask */ - union { - icmpinfo_t is_ics; - tcpinfo_t is_ts; - udpinfo_t is_us; - greinfo_t is_ug; - } is_ps; - u_32_t is_flags; - int is_flx[2][2]; - u_32_t is_rulen; /* rule number when created */ - u_32_t is_s0[2]; - u_short is_smsk[2]; - char is_group[FR_GROUPLEN]; - char is_sbuf[2][16]; - char is_ifname[4][LIFNAMSIZ]; -} ipstate_t; - -#define is_die is_sti.tqe_die -#define is_state is_sti.tqe_state -#define is_touched is_sti.tqe_touched -#define is_saddr is_src.in4.s_addr -#define is_daddr is_dst.in4.s_addr -#define is_icmp is_ps.is_ics -#define is_type is_icmp.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 -#define is_dend is_tcp.ts_data[1].td_end -#define is_maxswin is_tcp.ts_data[0].td_maxwin -#define is_maxdwin is_tcp.ts_data[1].td_maxwin -#define is_maxsend is_tcp.ts_data[0].td_maxend -#define is_maxdend is_tcp.ts_data[1].td_maxend -#define is_swinscale is_tcp.ts_data[0].td_winscale -#define is_dwinscale is_tcp.ts_data[1].td_winscale -#define is_swinflags is_tcp.ts_data[0].td_winflags -#define is_dwinflags is_tcp.ts_data[1].td_winflags -#define is_sport is_tcp.ts_sport -#define is_dport is_tcp.ts_dport -#define is_ifpin is_ifp[0] -#define is_ifpout is_ifp[2] -#define is_gre is_ps.is_ug -#define is_call is_gre.gs_call - -#define IS_WSPORT SI_W_SPORT /* 0x00100 */ -#define IS_WDPORT SI_W_DPORT /* 0x00200 */ -#define IS_WSADDR SI_W_SADDR /* 0x00400 */ -#define IS_WDADDR SI_W_DADDR /* 0x00800 */ -#define IS_NEWFR SI_NEWFR /* 0x01000 */ -#define IS_CLONE SI_CLONE /* 0x02000 */ -#define IS_CLONED SI_CLONED /* 0x04000 */ -#define IS_TCPFSM 0x10000 -#define IS_STRICT 0x20000 -#define IS_ISNSYN 0x40000 -#define IS_ISNACK 0x80000 -#define IS_STATESYNC 0x100000 -/* - * IS_SC flags are for scan-operations that need to be recognised in state. - */ -#define IS_SC_CLIENT 0x10000000 -#define IS_SC_SERVER 0x20000000 -#define IS_SC_MATCHC 0x40000000 -#define IS_SC_MATCHS 0x80000000 -#define IS_SC_MATCHALL (IS_SC_MATCHC|IS_SC_MATCHC) -#define IS_SC_ALL (IS_SC_MATCHC|IS_SC_MATCHC|IS_SC_CLIENT|IS_SC_SERVER) - -/* - * Flags that can be passed into fr_addstate - */ -#define IS_INHERITED 0x0fffff00 - -#define TH_OPENING (TH_SYN|TH_ACK) -/* - * is_flags: - * Bits 0 - 3 are use as a mask with the current packet's bits to check for - * whether it is short, tcp/udp, a fragment or the presence of IP options. - * Bits 4 - 7 are set from the initial packet and contain what the packet - * anded with bits 0-3 must match. - * Bits 8,9 are used to indicate wildcard source/destination port matching. - * Bits 10,11 are reserved for other wildcard flag compatibility. - * Bits 12,13 are for scaning. - */ - -typedef struct ipstate_save { - void *ips_next; - struct ipstate ips_is; - struct frentry ips_fr; -} ipstate_save_t; - -#define ips_rule ips_is.is_rule - - -typedef struct ipslog { - U_QUAD_T isl_pkts[4]; - U_QUAD_T isl_bytes[4]; - i6addr_t isl_src; - i6addr_t isl_dst; - u_32_t isl_tag; - u_short isl_type; - union { - u_short isl_filler[2]; - u_short isl_ports[2]; - u_short isl_icmp; - } isl_ps; - u_char isl_v; - u_char isl_p; - u_char isl_flags; - u_char isl_state[2]; - u_32_t isl_rulen; - char isl_group[FR_GROUPLEN]; -} ipslog_t; - -#define isl_sport isl_ps.isl_ports[0] -#define isl_dport isl_ps.isl_ports[1] -#define isl_itype isl_ps.isl_icmp - -#define ISL_NEW 0 -#define ISL_CLONE 1 -#define ISL_EXPIRE 0xffff -#define ISL_FLUSH 0xfffe -#define ISL_REMOVE 0xfffd -#define ISL_INTERMEDIATE 0xfffc -#define ISL_KILLED 0xfffb -#define ISL_ORPHAN 0xfffa -#define ISL_UNLOAD 0xfff9 - - -typedef struct ips_stat { - u_long iss_hits; - u_long iss_miss; - u_long iss_max; - u_long iss_maxref; - u_long iss_tcp; - u_long iss_udp; - u_long iss_icmp; - 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; - ipstate_t **iss_table; - ipstate_t *iss_list; - u_long *iss_bucketlen; - ipftq_t *iss_tcptab; -} 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]; - -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 *, - 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)); - -#endif /* __IP_STATE_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_sync.c b/sys/contrib/ipfilter/netinet/ip_sync.c deleted file mode 100644 index b145539..0000000 --- a/sys/contrib/ipfilter/netinet/ip_sync.c +++ /dev/null @@ -1,1018 +0,0 @@ -/* - * Copyright (C) 1995-1998 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/file.h> -#if !defined(_KERNEL) && !defined(__KERNEL__) -# include <stdio.h> -# include <stdlib.h> -# include <string.h> -# define _KERNEL -# define KERNEL -# ifdef __OpenBSD__ -struct file; -# endif -# include <sys/uio.h> -# undef _KERNEL -# undef KERNEL -#else -# include <sys/systm.h> -# if !defined(__SVR4) && !defined(__svr4__) -# include <sys/mbuf.h> -# endif -#endif -#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104000000) -# include <sys/proc.h> -#endif -#if defined(_KERNEL) && (__FreeBSD_version >= 220000) -# include <sys/filio.h> -# include <sys/fcntl.h> -# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM) -# include "opt_ipfilter.h" -# endif -#else -# include <sys/ioctl.h> -#endif -#include <sys/time.h> -#if !defined(linux) -# include <sys/protosw.h> -#endif -#include <sys/socket.h> -#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 - -#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> -#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> -#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_sync.h" -#ifdef USE_INET6 -#include <netinet/icmp6.h> -#endif -#if (__FreeBSD_version >= 300000) -# include <sys/malloc.h> -# if defined(_KERNEL) && !defined(IPFILTER_LKM) -# include <sys/libkern.h> -# include <sys/systm.h> -# endif -#endif -/* 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 $"; -#endif - -#define SYNC_STATETABSZ 256 -#define SYNC_NATTABSZ 256 - -#ifdef IPFILTER_SYNC -ipfmutex_t ipf_syncadd, ipsl_mutex; -ipfrwlock_t ipf_syncstate, ipf_syncnat; -#if SOLARIS && defined(_KERNEL) -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(sparc) && !defined(__hppa) -void ipfsync_tcporder __P((int, struct tcpdata *)); -void ipfsync_natorder __P((int, struct nat *)); -void ipfsync_storder __P((int, struct ipstate *)); -# endif - - -/* ------------------------------------------------------------------------ */ -/* Function: ipfsync_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() -{ - 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"); -# if SOLARIS && defined(_KERNEL) - cv_init(&ipslwait, "ipsl condvar", CV_DRIVER, NULL); -# endif - - bzero((char *)syncnattab, sizeof(syncnattab)); - bzero((char *)syncstatetab, sizeof(syncstatetab)); - - return 0; -} - - -# if !defined(sparc) && !defined(__hppa) -/* ------------------------------------------------------------------------ */ -/* Function: ipfsync_tcporder */ -/* Returns: Nil */ -/* Parameters: way(I) - direction of byte order conversion. */ -/* td(IO) - pointer to data to be converted. */ -/* */ -/* 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; -{ - if (way) { - td->td_maxwin = htons(td->td_maxwin); - td->td_end = htonl(td->td_end); - td->td_maxend = htonl(td->td_maxend); - } else { - td->td_maxwin = ntohs(td->td_maxwin); - td->td_end = ntohl(td->td_end); - td->td_maxend = ntohl(td->td_maxend); - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipfsync_natorder */ -/* Returns: Nil */ -/* Parameters: way(I) - direction of byte order conversion. */ -/* nat(IO) - pointer to data to be converted. */ -/* */ -/* 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; -{ - if (way) { - n->nat_age = htonl(n->nat_age); - n->nat_flags = htonl(n->nat_flags); - n->nat_ipsumd = htonl(n->nat_ipsumd); - n->nat_use = htonl(n->nat_use); - n->nat_dir = htonl(n->nat_dir); - } else { - n->nat_age = ntohl(n->nat_age); - n->nat_flags = ntohl(n->nat_flags); - n->nat_ipsumd = ntohl(n->nat_ipsumd); - n->nat_use = ntohl(n->nat_use); - n->nat_dir = ntohl(n->nat_dir); - } -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipfsync_storder */ -/* Returns: Nil */ -/* Parameters: way(I) - direction of byte order conversion. */ -/* ips(IO) - pointer to data to be converted. */ -/* */ -/* 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; -{ - ipfsync_tcporder(way, &ips->is_tcp.ts_data[0]); - ipfsync_tcporder(way, &ips->is_tcp.ts_data[1]); - - if (way) { - ips->is_hv = htonl(ips->is_hv); - ips->is_die = htonl(ips->is_die); - ips->is_pass = htonl(ips->is_pass); - ips->is_flags = htonl(ips->is_flags); - ips->is_opt[0] = htonl(ips->is_opt[0]); - ips->is_opt[1] = htonl(ips->is_opt[1]); - ips->is_optmsk[0] = htonl(ips->is_optmsk[0]); - ips->is_optmsk[1] = htonl(ips->is_optmsk[1]); - ips->is_sec = htons(ips->is_sec); - ips->is_secmsk = htons(ips->is_secmsk); - ips->is_auth = htons(ips->is_auth); - ips->is_authmsk = htons(ips->is_authmsk); - ips->is_s0[0] = htonl(ips->is_s0[0]); - ips->is_s0[1] = htonl(ips->is_s0[1]); - ips->is_smsk[0] = htons(ips->is_smsk[0]); - ips->is_smsk[1] = htons(ips->is_smsk[1]); - } else { - ips->is_hv = ntohl(ips->is_hv); - ips->is_die = ntohl(ips->is_die); - ips->is_pass = ntohl(ips->is_pass); - ips->is_flags = ntohl(ips->is_flags); - ips->is_opt[0] = ntohl(ips->is_opt[0]); - ips->is_opt[1] = ntohl(ips->is_opt[1]); - ips->is_optmsk[0] = ntohl(ips->is_optmsk[0]); - ips->is_optmsk[1] = ntohl(ips->is_optmsk[1]); - ips->is_sec = ntohs(ips->is_sec); - ips->is_secmsk = ntohs(ips->is_secmsk); - ips->is_auth = ntohs(ips->is_auth); - ips->is_authmsk = ntohs(ips->is_authmsk); - ips->is_s0[0] = ntohl(ips->is_s0[0]); - ips->is_s0[1] = ntohl(ips->is_s0[1]); - ips->is_smsk[0] = ntohl(ips->is_smsk[0]); - ips->is_smsk[1] = ntohl(ips->is_smsk[1]); - } -} -# else /* !defined(sparc) && !defined(__hppa) */ -# define ipfsync_tcporder(x,y) -# define ipfsync_natorder(x,y) -# define ipfsync_storder(x,y) -# endif /* !defined(sparc) && !defined(__hppa) */ - -/* enable this for debugging */ - -# ifdef _KERNEL -/* ------------------------------------------------------------------------ */ -/* Function: ipfsync_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; -{ - synchdr_t sh; - - /* - * THIS MUST BE SUFFICIENT LARGE TO STORE - * ANY POSSIBLE DATA TYPE - */ - char data[2048]; - - int err = 0; - -# if (BSD >= 199306) || defined(__FreeBSD__) || defined(__osf__) - uio->uio_rw = UIO_WRITE; -# endif - - /* Try to get bytes */ - while (uio->uio_resid > 0) { - - if (uio->uio_resid >= sizeof(sh)) { - - err = UIOMOVE(&sh, sizeof(sh), UIO_WRITE, uio); - - if (err) { - if (ipf_sync_debug > 2) - printf("uiomove(header) failed: %d\n", - err); - return err; - } - - /* convert to host order */ - sh.sm_magic = ntohl(sh.sm_magic); - sh.sm_len = ntohl(sh.sm_len); - sh.sm_num = ntohl(sh.sm_num); - - if (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", - "magic"); - return EINVAL; - } - - if (sh.sm_v != 4 && sh.sm_v != 6) { - if (ipf_sync_debug > 2) - printf("uiomove(header) invalid %s\n", - "protocol"); - return EINVAL; - } - - if (sh.sm_cmd > SMC_MAXCMD) { - if (ipf_sync_debug > 2) - printf("uiomove(header) invalid %s\n", - "command"); - return EINVAL; - } - - - if (sh.sm_table > SMC_MAXTBL) { - if (ipf_sync_debug > 2) - printf("uiomove(header) invalid %s\n", - "table"); - return EINVAL; - } - - } else { - /* unsufficient data, wait until next call */ - if (ipf_sync_debug > 2) - printf("uiomove(header) insufficient data"); - return EAGAIN; - } - - - /* - * 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) - printf("uiomove(data zero length %s\n", - "not supported"); - return EINVAL; - } - - if (uio->uio_resid >= sh.sm_len) { - - err = UIOMOVE(data, sh.sm_len, UIO_WRITE, uio); - - if (err) { - if (ipf_sync_debug > 2) - printf("uiomove(data) failed: %d\n", - err); - return err; - } - - if (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); - else if (sh.sm_table == SMC_NAT) - err = ipfsync_nat(&sh, data); - if (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) - printf("uiomove(data) %s %d bytes, got %d\n", - "insufficient data, need", - sh.sm_len, uio->uio_resid); - return EAGAIN; - } - } - - /* no more data */ - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipfsync_read */ -/* Returns: int - 0 == success, else error value. */ -/* Parameters: uio(O) - pointer to information about where to store data */ -/* */ -/* This function is called when a user program wants to read some data */ -/* 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; -{ - syncupdent_t *su; - synclogent_t *sl; - int err = 0; - - if ((uio->uio_resid & 3) || (uio->uio_resid < 8)) - return EINVAL; - -# if (BSD >= 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); - return EINTR; - } -# else -# ifdef __hpux - { - lock_t *l; - - l = get_sleep_lock(&sl_tail); - err = sleep(&sl_tail, PZERO+1); - if (err) { - MUTEX_EXIT(&ipsl_mutex); - return EINTR; - } - spinunlock(l); - } -# else /* __hpux */ -# ifdef __osf__ - err = mpsleep(&sl_tail, PSUSP|PCATCH, "ipl sleep", 0, - &ipsl_mutex, MS_LOCK_SIMPLE); - if (err) - return EINTR; -# else - MUTEX_EXIT(&ipsl_mutex); - err = SLEEP(&sl_tail, "ipl sleep"); - if (err) - return EINTR; - MUTEX_ENTER(&ipsl_mutex); -# endif /* __osf__ */ -# endif /* __hpux */ -# endif /* SOLARIS */ - } - MUTEX_EXIT(&ipsl_mutex); - - READ_ENTER(&ipf_syncstate); - while ((sl_tail < sl_idx) && (uio->uio_resid > sizeof(*sl))) { - sl = synclog + sl_tail++; - err = UIOMOVE(sl, sizeof(*sl), UIO_READ, uio); - if (err != 0) - break; - } - - while ((su_tail < su_idx) && (uio->uio_resid > sizeof(*su))) { - su = syncupd + su_tail; - su_tail++; - err = UIOMOVE(su, sizeof(*su), UIO_READ, uio); - if (err != 0) - break; - 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); - return err; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipfsync_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 */ -/* */ -/* Updates the state table according to information passed in the sync */ -/* header. As required, more data is fetched from the uio structure but */ -/* varies depending on the contents of the sync header. This function can */ -/* 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; -{ - synctcp_update_t su; - ipstate_t *is, sn; - synclist_t *sl; - frentry_t *fr; - u_int hv; - int err = 0; - - hv = sp->sm_num & (SYNC_STATETABSZ - 1); - - switch (sp->sm_cmd) - { - case SMC_CREATE : - - bcopy(data, &sn, sizeof(sn)); - KMALLOC(is, ipstate_t *); - if (is == NULL) { - err = ENOMEM; - break; - } - - KMALLOC(sl, synclist_t *); - if (sl == NULL) { - err = ENOMEM; - KFREE(is); - break; - } - - 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); - - /* - * 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); - if (fr != NULL) { - MUTEX_ENTER(&fr->fr_lock); - fr->fr_ref++; - fr->fr_statecnt++; - MUTEX_EXIT(&fr->fr_lock); - } - RWLOCK_EXIT(&ipf_mutex); - - if (ipf_sync_debug > 4) - printf("[%d] Filter rules = %p\n", sp->sm_num, fr); - - is->is_rule = fr; - is->is_sync = sl; - - sl->sl_idx = -1; - sl->sl_ips = is; - bcopy(sp, &sl->sl_hdr, sizeof(struct synchdr)); - - WRITE_ENTER(&ipf_syncstate); - WRITE_ENTER(&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); - /* - * Do not initialise the interface pointers for the state - * entry as the full complement of interface names may not - * be present. - * - * Put this state entry on its timeout queue. - */ - /*fr_setstatequeue(is, sp->sm_rev);*/ - break; - - case SMC_UPDATE : - bcopy(data, &su, sizeof(su)); - - if (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) - if (sl->sl_hdr.sm_num == sp->sm_num) - break; - if (sl == NULL) { - if (ipf_sync_debug > 1) - printf("[%d] State not found - can't update\n", - sp->sm_num); - RWLOCK_EXIT(&ipf_syncstate); - err = ENOENT; - break; - } - - READ_ENTER(&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, - sl->sl_hdr.sm_cmd, sl->sl_hdr.sm_table, - sl->sl_hdr.sm_rev); - - is = sl->sl_ips; - - MUTEX_ENTER(&is->is_lock); - switch (sp->sm_p) - { - case IPPROTO_TCP : - /* XXX FV --- shouldn't we do ntohl/htonl???? XXX */ - is->is_send = su.stu_data[0].td_end; - is->is_maxsend = su.stu_data[0].td_maxend; - is->is_maxswin = su.stu_data[0].td_maxwin; - is->is_state[0] = su.stu_state[0]; - is->is_dend = su.stu_data[1].td_end; - is->is_maxdend = su.stu_data[1].td_maxend; - is->is_maxdwin = su.stu_data[1].td_maxwin; - is->is_state[1] = su.stu_state[1]; - break; - default : - break; - } - - if (ipf_sync_debug > 6) - printf("[%d] Setting timers for state\n", sp->sm_num); - - fr_setstatequeue(is, sp->sm_rev); - - MUTEX_EXIT(&is->is_lock); - break; - - default : - err = EINVAL; - break; - } - - if (err == 0) { - RWLOCK_EXIT(&ipf_state); - RWLOCK_EXIT(&ipf_syncstate); - } - - if (ipf_sync_debug > 6) - printf("[%d] Update completed with error %d\n", - sp->sm_num, err); - - return err; -} -# endif /* _KERNEL */ - - -/* ------------------------------------------------------------------------ */ -/* Function: ipfsync_del */ -/* Returns: Nil */ -/* Parameters: sl(I) - pointer to synclist object to delete */ -/* */ -/* Deletes an object from the synclist table and free's its memory. */ -/* ------------------------------------------------------------------------ */ -void ipfsync_del(sl) -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); - KFREE(sl); -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipfsync_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 */ -/* */ -/* Updates the NAT table according to information passed in the sync */ -/* header. As required, more data is fetched from the uio structure but */ -/* varies depending on the contents of the sync header. This function can */ -/* 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; -{ - syncupdent_t su; - nat_t *n, *nat; - synclist_t *sl; - u_int hv = 0; - int err; - - READ_ENTER(&ipf_syncstate); - - switch (sp->sm_cmd) - { - case SMC_CREATE : - KMALLOC(n, nat_t *); - if (n == NULL) { - err = ENOMEM; - break; - } - - KMALLOC(sl, synclist_t *); - if (sl == NULL) { - err = ENOMEM; - KFREE(n); - break; - } - - nat = (nat_t *)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); - n->nat_sync = sl; - - 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); - break; - - case SMC_UPDATE : - bcopy(data, &su, sizeof(su)); - - READ_ENTER(&ipf_syncstate); - for (sl = syncstatetab[hv]; (sl != NULL); sl = sl->sl_next) - if (sl->sl_hdr.sm_num == sp->sm_num) - break; - if (sl == NULL) { - err = ENOENT; - break; - } - - READ_ENTER(&ipf_nat); - - nat = sl->sl_ipn; - - MUTEX_ENTER(&nat->nat_lock); - fr_setnatqueue(nat, sl->sl_rev); - MUTEX_EXIT(&nat->nat_lock); - - RWLOCK_EXIT(&ipf_nat); - - break; - - default : - err = EINVAL; - break; - } - - RWLOCK_EXIT(&ipf_syncstate); - return 0; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipfsync_new */ -/* Returns: synclist_t* - NULL == failure, else pointer to new synclist */ -/* data structure. */ -/* Parameters: tab(I) - type of synclist_t to create */ -/* fin(I) - pointer to packet information */ -/* ptr(I) - pointer to owning object */ -/* */ -/* 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 *sl, *ss; - synclogent_t *sle; - u_int hv, sz; - - if (sl_idx == SYNCLOG_SZ) - return NULL; - KMALLOC(sl, synclist_t *); - if (sl == NULL) - return NULL; - - MUTEX_ENTER(&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; - } - - 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. - * XXX - an attacker could lunch an DoS attack, of sorts, if they are - * the only one causing new table entries by only keeping open every - * 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); - - sl->sl_magic = htonl(SYNHDRMAGIC); - sl->sl_v = fin->fin_v; - sl->sl_p = fin->fin_p; - sl->sl_cmd = SMC_CREATE; - sl->sl_idx = -1; - sl->sl_table = tab; - sl->sl_rev = fin->fin_rev; - if (tab == SMC_STATE) { - sl->sl_ips = ptr; - sz = sizeof(*sl->sl_ips); - } else if (tab == SMC_NAT) { - sl->sl_ipn = ptr; - sz = sizeof(*sl->sl_ipn); - } else { - ptr = NULL; - sz = 0; - } - sl->sl_len = sz; - - /* - * 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++; - bcopy((char *)&sl->sl_hdr, (char *)&sle->sle_hdr, - sizeof(sle->sle_hdr)); - sle->sle_hdr.sm_num = htonl(sle->sle_hdr.sm_num); - sle->sle_hdr.sm_len = htonl(sle->sle_hdr.sm_len); - if (ptr != NULL) { - bcopy((char *)ptr, (char *)&sle->sle_un, sz); - if (tab == SMC_STATE) { - ipfsync_storder(1, &sle->sle_un.sleu_ips); - } else if (tab == SMC_NAT) { - ipfsync_natorder(1, &sle->sle_un.sleu_ipn); - } - } - MUTEX_EXIT(&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 - return sl; -} - - -/* ------------------------------------------------------------------------ */ -/* Function: ipfsync_update */ -/* Returns: Nil */ -/* Parameters: tab(I) - type of synclist_t to create */ -/* fin(I) - pointer to packet information */ -/* sl(I) - pointer to synchronisation object */ -/* */ -/* 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; -{ - synctcp_update_t *st; - syncupdent_t *slu; - ipstate_t *ips; - nat_t *nat; - - if (fin->fin_out == 0 || sl == NULL) - return; - - WRITE_ENTER(&ipf_syncstate); - MUTEX_ENTER(&ipf_syncadd); - if (sl->sl_idx == -1) { - slu = syncupd + su_idx; - sl->sl_idx = su_idx++; - bcopy((char *)&sl->sl_hdr, (char *)&slu->sup_hdr, - sizeof(slu->sup_hdr)); - slu->sup_hdr.sm_magic = htonl(SYNHDRMAGIC); - slu->sup_hdr.sm_sl = sl; - slu->sup_hdr.sm_cmd = SMC_UPDATE; - slu->sup_hdr.sm_table = tab; - slu->sup_hdr.sm_num = htonl(sl->sl_num); - slu->sup_hdr.sm_len = htonl(sizeof(struct synctcp_update)); - slu->sup_hdr.sm_rev = fin->fin_rev; -# if 0 - if (fin->fin_p == IPPROTO_TCP) { - st->stu_len[0] = 0; - st->stu_len[1] = 0; - } -# endif - } else - slu = syncupd + sl->sl_idx; - MUTEX_EXIT(&ipf_syncadd); - MUTEX_DOWNGRADE(&ipf_syncstate); - - /* - * Only TCP has complex timeouts, others just use default timeouts. - * For TCP, we only need to track the connection state and window. - */ - if (fin->fin_p == IPPROTO_TCP) { - st = &slu->sup_tcp; - if (tab == SMC_STATE) { - ips = sl->sl_ips; - st->stu_age = htonl(ips->is_die); - st->stu_data[0].td_end = ips->is_send; - st->stu_data[0].td_maxend = ips->is_maxsend; - st->stu_data[0].td_maxwin = ips->is_maxswin; - st->stu_state[0] = ips->is_state[0]; - st->stu_data[1].td_end = ips->is_dend; - st->stu_data[1].td_maxend = ips->is_maxdend; - st->stu_data[1].td_maxwin = ips->is_maxdwin; - st->stu_state[1] = ips->is_state[1]; - } else if (tab == SMC_NAT) { - nat = sl->sl_ipn; - st->stu_age = htonl(nat->nat_age); - } - } - RWLOCK_EXIT(&ipf_syncstate); - - 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 -} - - -/* ------------------------------------------------------------------------ */ -/* Function: fr_sync_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 */ -/* */ -/* 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; -{ - return EINVAL; -} - - -int ipfsync_canread() -{ - return !((sl_tail == sl_idx) && (su_tail == su_idx)); -} - - -int ipfsync_canwrite() -{ - return 1; -} -#endif /* IPFILTER_SYNC */ diff --git a/sys/contrib/ipfilter/netinet/ip_sync.h b/sys/contrib/ipfilter/netinet/ip_sync.h deleted file mode 100644 index 8104db3..0000000 --- a/sys/contrib/ipfilter/netinet/ip_sync.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 1993-2001 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 $ - */ - -#ifndef __IP_SYNC_H__ -#define __IP_SYNC_H__ - -typedef struct synchdr { - u_32_t sm_magic; /* magic */ - u_char sm_v; /* version: 4,6 */ - u_char sm_p; /* protocol */ - u_char sm_cmd; /* command */ - u_char sm_table; /* NAT, STATE, etc */ - u_int sm_num; /* table entry number */ - int sm_rev; /* forward/reverse */ - int sm_len; /* length of the data section */ - struct synclist *sm_sl; /* back pointer to parent */ -} synchdr_t; - - -#define SYNHDRMAGIC 0x0FF51DE5 - -/* - * Commands - * No delete required as expirey will take care of that! - */ -#define SMC_CREATE 0 /* pass ipstate_t after synchdr_t */ -#define SMC_UPDATE 1 -#define SMC_MAXCMD 1 - -/* - * Tables - */ -#define SMC_NAT 0 -#define SMC_STATE 1 -#define SMC_MAXTBL 1 - - -/* - * Only TCP requires "more" information than just a reference to the entry - * for which an update is being made. - */ -typedef struct synctcp_update { - u_long stu_age; - tcpdata_t stu_data[2]; - int stu_state[2]; -} synctcp_update_t; - - -typedef struct synclist { - struct synclist *sl_next; - struct synclist **sl_pnext; - int sl_idx; /* update index */ - struct synchdr sl_hdr; - union { - struct ipstate *slu_ips; - struct nat *slu_ipn; - void *slu_ptr; - } sl_un; -} synclist_t; - -#define sl_ptr sl_un.slu_ptr -#define sl_ips sl_un.slu_ips -#define sl_ipn sl_un.slu_ipn -#define sl_magic sl_hdr.sm_magic -#define sl_v sl_hdr.sm_v -#define sl_p sl_hdr.sm_p -#define sl_cmd sl_hdr.sm_cmd -#define sl_rev sl_hdr.sm_rev -#define sl_table sl_hdr.sm_table -#define sl_num sl_hdr.sm_num -#define sl_len sl_hdr.sm_len - -/* - * NOTE: SYNCLOG_SZ is defined *low*. It should be the next power of two - * up for whatever number of packets per second you expect to see. Be - * warned: this index's a table of large elements (upto 272 bytes in size - * each), and thus a size of 8192, for example, results in a 2MB table. - * The lesson here is not to use small machines for running fast firewalls - * (100BaseT) in sync, where you might have upwards of 10k pps. - */ -#define SYNCLOG_SZ 256 - -typedef struct synclogent { - struct synchdr sle_hdr; - union { - struct ipstate sleu_ips; - struct nat sleu_ipn; - } sle_un; -} synclogent_t; - -typedef struct syncupdent { /* 28 or 32 bytes */ - struct synchdr sup_hdr; - 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 */ diff --git a/sys/contrib/ipfilter/netinet/ipl.h b/sys/contrib/ipfilter/netinet/ipl.h deleted file mode 100644 index 614250a..0000000 --- a/sys/contrib/ipfilter/netinet/ipl.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (C) 1993-2001, 2003 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - * - * @(#)ipl.h 1.21 6/5/96 - * $Id: ipl.h,v 2.52.2.30 2007/10/16 09:41:00 darrenr Exp $ - */ - -#ifndef __IPL_H__ -#define __IPL_H__ - -#define IPL_VERSION "IP Filter: v4.1.28" - -#define IPFILTER_VERSION 4012800 - -#endif diff --git a/sys/contrib/ipfilter/netinet/mlfk_ipl.c b/sys/contrib/ipfilter/netinet/mlfk_ipl.c deleted file mode 100644 index 7718bd9..0000000 --- a/sys/contrib/ipfilter/netinet/mlfk_ipl.c +++ /dev/null @@ -1,359 +0,0 @@ -/* - * Copyright (C) 2000 by Darren Reed. - * - * See the IPFILTER.LICENCE file for details on licencing. - */ - - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/conf.h> -#include <sys/socket.h> -#include <sys/sysctl.h> -#include <sys/select.h> -#if __FreeBSD_version >= 500000 -# include <sys/selinfo.h> -#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> - -#if __FreeBSD_version >= 502116 -static struct cdev *ipf_devs[IPL_LOGSIZE]; -#else -static dev_t ipf_devs[IPL_LOGSIZE]; -#endif - -static int sysctl_ipf_int ( SYSCTL_HANDLER_ARGS ); -static int ipf_modload(void); -static int ipf_modunload(void); - -SYSCTL_DECL(_net_inet); -#define SYSCTL_IPF(parent, nbr, name, access, ptr, val, descr) \ - SYSCTL_OID(parent, nbr, name, CTLTYPE_INT|access, \ - ptr, val, sysctl_ipf_int, "I", descr); -#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, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpidletimeout, CTLFLAG_RWO, - &fr_tcpidletimeout, 0, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcphalfclosed, CTLFLAG_RWO, - &fr_tcphalfclosed, 0, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosewait, CTLFLAG_RWO, - &fr_tcpclosewait, 0, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcplastack, CTLFLAG_RWO, - &fr_tcplastack, 0, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcptimeout, CTLFLAG_RWO, - &fr_tcptimeout, 0, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_tcpclosed, CTLFLAG_RWO, - &fr_tcpclosed, 0, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udptimeout, CTLFLAG_RWO, - &fr_udptimeout, 0, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_udpacktimeout, CTLFLAG_RWO, - &fr_udpacktimeout, 0, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_icmptimeout, CTLFLAG_RWO, - &fr_icmptimeout, 0, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_defnatage, CTLFLAG_RWO, - &fr_defnatage, 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, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statesize, CTLFLAG_RWO, - &fr_statesize, 0, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_statemax, CTLFLAG_RWO, - &fr_statemax, 0, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_nattable_sz, CTLFLAG_RWO, - &ipf_nattable_sz, 0, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_natrules_sz, CTLFLAG_RWO, - &ipf_natrules_sz, 0, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_rdrrules_sz, CTLFLAG_RWO, - &ipf_rdrrules_sz, 0, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, ipf_hostmap_sz, CTLFLAG_RWO, - &ipf_hostmap_sz, 0, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authsize, CTLFLAG_RWO, - &fr_authsize, 0, ""); -SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD, - &fr_authused, 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, ""); - -#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 struct cdevsw ipl_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 - .d_maj = CDEV_MAJOR, -# 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, - /* mmap */ nommap, - /* strategy */ nostrategy, - /* name */ "ipl", - /* maj */ CDEV_MAJOR, - /* dump */ nodump, - /* psize */ nopsize, - /* flags */ 0, -# if (__FreeBSD_version < 500043) - /* bmaj */ -1, -# endif -# if (__FreeBSD_version > 430000) - /* kqfilter */ NULL -# endif -}; -#endif - -static char *ipf_devfiles[] = { IPL_NAME, IPNAT_NAME, IPSTATE_NAME, IPAUTH_NAME, - IPSYNC_NAME, IPSCAN_NAME, IPLOOKUP_NAME, NULL }; - - -static int -ipfilter_modevent(module_t mod, int type, void *unused) -{ - int error = 0; - - switch (type) - { - case MOD_LOAD : - error = ipf_modload(); - break; - - case MOD_UNLOAD : - error = ipf_modunload(); - break; - default: - error = EINVAL; - break; - } - return error; -} - - -static int -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"); - - error = ipfattach(); - if (error) { - RW_DESTROY(&ipf_global); - RW_DESTROY(&ipf_mutex); - RW_DESTROY(&ipf_frcache); - return error; - } - - for (i = 0; i < IPL_LOGSIZE; i++) - ipf_devs[i] = NULL; - - for (i = 0; (str = ipf_devfiles[i]); i++) { - c = NULL; - for(j = strlen(str); j > 0; j--) - if (str[j] == '/') { - c = str + j + 1; - break; - } - if (!c) - c = str; - ipf_devs[i] = make_dev(&ipl_cdevsw, i, 0, 0, 0600, c); - } - - error = ipf_pfil_hook(); - if (error != 0) - return error; - ipf_event_reg(); - - if (FR_ISPASS(fr_pass)) - defpass = "pass"; - else if (FR_ISBLOCK(fr_pass)) - defpass = "block"; - else - defpass = "no-match -> block"; - - printf("%s initialized. Default = %s all, Logging = %s%s\n", - ipfilter_version, defpass, -#ifdef IPFILTER_LOG - "enabled", -#else - "disabled", -#endif -#ifdef IPFILTER_COMPILED - " (COMPILED)" -#else - "" -#endif - ); - return 0; -} - - -static int -ipf_modunload() -{ - int error, i; - - if (fr_refcnt) - return EBUSY; - - if (fr_running >= 0) { - ipf_pfil_unhook(); - ipf_event_dereg(); - WRITE_ENTER(&ipf_global); - error = ipfdetach(); - RWLOCK_EXIT(&ipf_global); - if (error != 0) - return error; - } else - error = 0; - - RW_DESTROY(&ipf_global); - RW_DESTROY(&ipf_mutex); - RW_DESTROY(&ipf_frcache); - - fr_running = -2; - - for (i = 0; ipf_devfiles[i]; i++) { - if (ipf_devs[i] != NULL) - destroy_dev(ipf_devs[i]); - } - - printf("%s unloaded\n", ipfilter_version); - - return error; -} - - -static moduledata_t ipfiltermod = { - "ipfilter", - ipfilter_modevent, - 0 -}; - - -DECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); -#ifdef MODULE_VERSION -MODULE_VERSION(ipfilter, 1); -#endif - - -#ifdef SYSCTL_IPF -int -sysctl_ipf_int ( SYSCTL_HANDLER_ARGS ) -{ - int error = 0; - - if (arg1) - error = SYSCTL_OUT(req, arg1, sizeof(int)); - else - error = SYSCTL_OUT(req, &arg2, sizeof(int)); - - if (error || !req->newptr) - return (error); - - if (!arg1) - error = EPERM; - else { - if ((oidp->oid_kind & CTLFLAG_OFF) && (fr_running > 0)) - error = EBUSY; - else - error = SYSCTL_IN(req, arg1, sizeof(int)); - } - return (error); -} -#endif - - -static int -#if __FreeBSD_version >= 500043 -iplpoll(struct cdev *dev, int events, struct thread *td) -#else -iplpoll(dev_t dev, int events, struct proc *td) -#endif -{ - u_int xmin = GET_MINOR(dev); - int revents; - - if (xmin < 0 || xmin > IPL_LOGMAX) - return 0; - - revents = 0; - - switch (xmin) - { - case IPL_LOGIPF : - case IPL_LOGNAT : - case IPL_LOGSTATE : -#ifdef IPFILTER_LOG - if ((events & (POLLIN | POLLRDNORM)) && ipflog_canread(xmin)) - revents |= events & (POLLIN | POLLRDNORM); -#endif - break; - case IPL_LOGAUTH : - if ((events & (POLLIN | POLLRDNORM)) && fr_auth_waiting()) - revents |= events & (POLLIN | POLLRDNORM); - break; - case IPL_LOGSYNC : -#ifdef IPFILTER_SYNC - if ((events & (POLLIN | POLLRDNORM)) && ipfsync_canread()) - revents |= events & (POLLIN | POLLRDNORM); - if ((events & (POLLOUT | POLLWRNORM)) && ipfsync_canwrite()) - revents |= events & (POLLOUT | POLLWRNORM); -#endif - break; - case IPL_LOGSCAN : - case IPL_LOGLOOKUP : - default : - break; - } - - if ((revents == 0) && ((events & (POLLIN|POLLRDNORM)) != 0)) - selrecord(td, &ipfselwait[xmin]); - - return revents; -} diff --git a/sys/contrib/ipfilter/netinet/y b/sys/contrib/ipfilter/netinet/y deleted file mode 100644 index d9aa671..0000000 --- a/sys/contrib/ipfilter/netinet/y +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN DSA PRIVATE KEY----- -MIIBuwIBAAKBgQCXGsxsgDt2euTDP/IQGY4O4CsKH9NXzI3dQ44L0w3PLYr/JQuY -kB8TLuCFZPIO/nlkubnCQGNnmcyUBlIA654Y7FEPBhLa4BWT6cpF4rfVzCQMq4W9 -ZqXv549OZ0Ejg6ciJ/Udhhjx/TMn6sIojEZmHBdToTtK54119hC6eOxnQwIVAIO3 -p+t6ASypQY8M+h96GZlVmkHRAoGAfK41snqWLcHspLYsIHu2tUwip7GqPPNe7Iej -CX17PiPbt9S5ph8aI6hPVmAUoKpfEb8OMDak3sFAFoDnve/FgOsZS+HKRpJRqUtW -PbBrhvRkQ5N4SWOzK54GXt/aWRTcUoVDz29QiakTfrZtdHeiJTbVNR36JdQ/nIHO -VWTWpcMCgYA4oHMrfK7/LMrjKWOLW8bXanvgL+nMoFVChYqzfBptvd492chAokKa -cr8NJDeT10i98TYooi0AvEthor9PVBDFMA0fj+LdM95HZTr6NIMAtxik8Ici4e7X -S4xWlsjTJQO6Kx7Hfuyt9EH2QkraLXFiFFKudGdvHqHeZ0q3iJ5JXwIVAIGBuoE0 -wrpIyJQuIMYL5HJxQ8wt ------END DSA PRIVATE KEY----- diff --git a/sys/contrib/ipfilter/netinet/y.pub b/sys/contrib/ipfilter/netinet/y.pub deleted file mode 100644 index a225f39..0000000 --- a/sys/contrib/ipfilter/netinet/y.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-dss AAAAB3NzaC1kc3MAAACBAJcazGyAO3Z65MM/8hAZjg7gKwof01fMjd1DjgvTDc8tiv8lC5iQHxMu4IVk8g7+eWS5ucJAY2eZzJQGUgDrnhjsUQ8GEtrgFZPpykXit9XMJAyrhb1mpe/nj05nQSODpyIn9R2GGPH9MyfqwiiMRmYcF1OhO0rnjXX2ELp47GdDAAAAFQCDt6fregEsqUGPDPofehmZVZpB0QAAAIB8rjWyepYtweyktiwge7a1TCKnsao8817sh6MJfXs+I9u31LmmHxojqE9WYBSgql8Rvw4wNqTewUAWgOe978WA6xlL4cpGklGpS1Y9sGuG9GRDk3hJY7MrngZe39pZFNxShUPPb1CJqRN+tm10d6IlNtU1Hfol1D+cgc5VZNalwwAAAIA4oHMrfK7/LMrjKWOLW8bXanvgL+nMoFVChYqzfBptvd492chAokKacr8NJDeT10i98TYooi0AvEthor9PVBDFMA0fj+LdM95HZTr6NIMAtxik8Ici4e7XS4xWlsjTJQO6Kx7Hfuyt9EH2QkraLXFiFFKudGdvHqHeZ0q3iJ5JXw== darrenr@freefall.freebsd.org |