summaryrefslogtreecommitdiffstats
path: root/sys/contrib/ipfilter/netinet/fil.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/ipfilter/netinet/fil.c')
-rw-r--r--sys/contrib/ipfilter/netinet/fil.c8151
1 files changed, 5504 insertions, 2647 deletions
diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c
index e8e543a..b392397 100644
--- a/sys/contrib/ipfilter/netinet/fil.c
+++ b/sys/contrib/ipfilter/netinet/fil.c
@@ -1,9 +1,14 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1993-2003 by Darren Reed.
+ * Copyright (C) 2012 by Darren Reed.
*
* See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * Copyright 2008 Sun Microsystems.
+ *
+ * $Id$
+ *
*/
#if defined(KERNEL) || defined(_KERNEL)
# undef KERNEL
@@ -15,15 +20,6 @@
#include <sys/types.h>
#include <sys/param.h>
#include <sys/time.h>
-#if defined(__NetBSD__)
-# if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL)
-# if (__NetBSD_Version__ < 301000000)
-# include "opt_ipfilter_log.h"
-# else
-# include "opt_ipfilter.h"
-# endif
-# endif
-#endif
#if defined(_KERNEL) && defined(__FreeBSD_version) && \
(__FreeBSD_version >= 220000)
# if (__FreeBSD_version >= 400000)
@@ -82,23 +78,9 @@ struct file;
#ifdef sun
# include <net/af.h>
#endif
-#if !defined(_KERNEL) && (defined(__FreeBSD__) || defined(SOLARIS2))
-# if (__FreeBSD_version >= 504000)
-# undef _RADIX_H_
-# endif
-# include "radix_ipf.h"
-#endif
-#ifdef __osf__
-# include "radix_ipf.h"
-#else
-# include <net/route.h>
-#endif
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
-#if !defined(linux)
-# include <netinet/ip_var.h>
-#endif
#if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */
# include <sys/hashing.h>
# include <netinet/in_var.h>
@@ -121,7 +103,6 @@ struct file;
# include <netinet6/in6_var.h>
# endif
#endif
-#include <netinet/tcpip.h>
#include "netinet/ip_fil.h"
#include "netinet/ip_nat.h"
#include "netinet/ip_frag.h"
@@ -131,9 +112,8 @@ struct file;
#ifdef IPFILTER_SCAN
# include "netinet/ip_scan.h"
#endif
-#ifdef IPFILTER_SYNC
-# include "netinet/ip_sync.h"
-#endif
+#include "netinet/ip_sync.h"
+#include "netinet/ip_lookup.h"
#include "netinet/ip_pool.h"
#include "netinet/ip_htable.h"
#ifdef IPFILTER_COMPILED
@@ -144,14 +124,18 @@ struct file;
#endif
#if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000)
# include <sys/malloc.h>
-# if defined(_KERNEL) && !defined(IPFILTER_LKM)
-# include "opt_ipfilter.h"
-# endif
#endif
#include "netinet/ipl.h"
-/* END OF INCLUDES */
-#include <machine/in_cksum.h>
+#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000)
+# include <sys/callout.h>
+extern struct callout ipf_slowtimer_ch;
+#endif
+#if defined(__OpenBSD__)
+# include <sys/timeout.h>
+extern struct timeout ipf_slowtimer_ch;
+#endif
+/* END OF INCLUDES */
#if !defined(lint)
static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed";
@@ -162,101 +146,80 @@ static const char rcsid[] = "@(#)$FreeBSD$";
#ifndef _KERNEL
# include "ipf.h"
# include "ipt.h"
-# include "bpf-ipf.h"
extern int opts;
+extern int blockreason;
#endif /* _KERNEL */
+#define LBUMP(x) softc->x++
+#define LBUMPD(x, y) do { softc->x.y++; DT(y); } while (0)
-fr_info_t frcache[2][8];
-struct filterstats frstats[2];
-struct frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } },
- *ipfilter6[2][2] = { { NULL, NULL }, { NULL, NULL } },
- *ipacct6[2][2] = { { NULL, NULL }, { NULL, NULL } },
- *ipacct[2][2] = { { NULL, NULL }, { NULL, NULL } },
- *ipnatrules[2][2] = { { NULL, NULL }, { NULL, NULL } };
-struct frgroup *ipfgroups[IPL_LOGSIZE][2];
-char ipfilter_version[] = IPL_VERSION;
-int fr_refcnt = 0;
-/*
- * For fr_running:
- * 0 == loading, 1 = running, -1 = disabled, -2 = unloading
- */
-int fr_running = 0;
-int fr_flags = IPF_LOGGING;
-int fr_active = 0;
-int fr_control_forwarding = 0;
-int fr_update_ipid = 0;
-u_short fr_ip_id = 0;
-int fr_chksrc = 0; /* causes a system crash if enabled */
-int fr_minttl = 4;
-int fr_icmpminfragmtu = 68;
-u_long fr_frouteok[2] = {0, 0};
-u_long fr_userifqs = 0;
-u_long fr_badcoalesces[2] = {0, 0};
-u_char ipf_iss_secret[32];
-#if defined(IPFILTER_DEFAULT_BLOCK)
-int fr_pass = FR_BLOCK|FR_NOMATCH;
-#else
-int fr_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH;
-#endif
-int fr_features = 0
-#ifdef IPFILTER_LKM
- | IPF_FEAT_LKM
-#endif
-#ifdef IPFILTER_LOG
- | IPF_FEAT_LOG
-#endif
-#ifdef IPFILTER_LOOKUP
- | IPF_FEAT_LOOKUP
-#endif
-#ifdef IPFILTER_BPF
- | IPF_FEAT_BPF
-#endif
-#ifdef IPFILTER_COMPILED
- | IPF_FEAT_COMPILED
-#endif
-#ifdef IPFILTER_CKSUM
- | IPF_FEAT_CKSUM
-#endif
-#ifdef IPFILTER_SYNC
- | IPF_FEAT_SYNC
-#endif
-#ifdef IPFILTER_SCAN
- | IPF_FEAT_SCAN
-#endif
-#ifdef USE_INET6
- | IPF_FEAT_IPV6
+static INLINE int ipf_check_ipf __P((fr_info_t *, frentry_t *, int));
+static u_32_t ipf_checkcipso __P((fr_info_t *, u_char *, int));
+static u_32_t ipf_checkripso __P((u_char *));
+static u_32_t ipf_decaps __P((fr_info_t *, u_32_t, int));
+#ifdef IPFILTER_LOG
+static frentry_t *ipf_dolog __P((fr_info_t *, u_32_t *));
#endif
- ;
-
-static INLINE int fr_ipfcheck __P((fr_info_t *, frentry_t *, int));
-static int fr_portcheck __P((frpcmp_t *, u_short *));
-static int frflushlist __P((int, minor_t, int *, frentry_t **));
-static ipfunc_t fr_findfunc __P((ipfunc_t));
-static frentry_t *fr_firewall __P((fr_info_t *, u_32_t *));
-static int fr_funcinit __P((frentry_t *fr));
-static INLINE void frpr_ah __P((fr_info_t *));
-static INLINE void frpr_esp __P((fr_info_t *));
-static INLINE void frpr_gre __P((fr_info_t *));
-static INLINE void frpr_udp __P((fr_info_t *));
-static INLINE void frpr_tcp __P((fr_info_t *));
-static INLINE void frpr_icmp __P((fr_info_t *));
-static INLINE void frpr_ipv4hdr __P((fr_info_t *));
-static INLINE int frpr_pullup __P((fr_info_t *, int));
-static INLINE void frpr_short __P((fr_info_t *, int));
-static INLINE int frpr_tcpcommon __P((fr_info_t *));
-static INLINE int frpr_udpcommon __P((fr_info_t *));
-static int fr_updateipid __P((fr_info_t *));
-#ifdef IPFILTER_LOOKUP
-static int fr_grpmapinit __P((frentry_t *fr));
-static INLINE void *fr_resolvelookup __P((u_int, u_int, i6addr_t *, lookupfunc_t *));
+static int ipf_flushlist __P((ipf_main_softc_t *, int *,
+ frentry_t **));
+static int ipf_flush_groups __P((ipf_main_softc_t *, frgroup_t **,
+ int));
+static ipfunc_t ipf_findfunc __P((ipfunc_t));
+static void *ipf_findlookup __P((ipf_main_softc_t *, int,
+ frentry_t *,
+ i6addr_t *, i6addr_t *));
+static frentry_t *ipf_firewall __P((fr_info_t *, u_32_t *));
+static int ipf_fr_matcharray __P((fr_info_t *, int *));
+static int ipf_frruleiter __P((ipf_main_softc_t *, void *, int,
+ void *));
+static void ipf_funcfini __P((ipf_main_softc_t *, frentry_t *));
+static int ipf_funcinit __P((ipf_main_softc_t *, frentry_t *));
+static int ipf_geniter __P((ipf_main_softc_t *, ipftoken_t *,
+ ipfgeniter_t *));
+static void ipf_getstat __P((ipf_main_softc_t *,
+ struct friostat *, int));
+static int ipf_group_flush __P((ipf_main_softc_t *, frgroup_t *));
+static void ipf_group_free __P((frgroup_t *));
+static int ipf_grpmapfini __P((struct ipf_main_softc_s *,
+ frentry_t *));
+static int ipf_grpmapinit __P((struct ipf_main_softc_s *,
+ frentry_t *));
+static frentry_t *ipf_nextrule __P((ipf_main_softc_t *, int, int,
+ frentry_t *, int));
+static int ipf_portcheck __P((frpcmp_t *, u_32_t));
+static INLINE int ipf_pr_ah __P((fr_info_t *));
+static INLINE void ipf_pr_esp __P((fr_info_t *));
+static INLINE void ipf_pr_gre __P((fr_info_t *));
+static INLINE void ipf_pr_udp __P((fr_info_t *));
+static INLINE void ipf_pr_tcp __P((fr_info_t *));
+static INLINE void ipf_pr_icmp __P((fr_info_t *));
+static INLINE void ipf_pr_ipv4hdr __P((fr_info_t *));
+static INLINE void ipf_pr_short __P((fr_info_t *, int));
+static INLINE int ipf_pr_tcpcommon __P((fr_info_t *));
+static INLINE int ipf_pr_udpcommon __P((fr_info_t *));
+static void ipf_rule_delete __P((ipf_main_softc_t *, frentry_t *f,
+ int, int));
+static void ipf_rule_expire_insert __P((ipf_main_softc_t *,
+ frentry_t *, int));
+static int ipf_synclist __P((ipf_main_softc_t *, frentry_t *,
+ void *));
+static void ipf_token_flush __P((ipf_main_softc_t *));
+static void ipf_token_unlink __P((ipf_main_softc_t *,
+ ipftoken_t *));
+static ipftuneable_t *ipf_tune_findbyname __P((ipftuneable_t *,
+ const char *));
+static ipftuneable_t *ipf_tune_findbycookie __P((ipftuneable_t **, void *,
+ void **));
+static int ipf_updateipid __P((fr_info_t *));
+static int ipf_settimeout __P((struct ipf_main_softc_s *,
+ struct ipftuneable *,
+ ipftuneval_t *));
+#if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && \
+ !defined(__FreeBSD__)) || \
+ FREEBSD_LT_REV(501000) || NETBSD_LT_REV(105000000) || \
+ OPENBSD_LT_REV(200006)
+static int ppsratecheck(struct timeval *, int *, int);
#endif
-static void frsynclist __P((frentry_t *, void *));
-static ipftuneable_t *fr_findtunebyname __P((const char *));
-static ipftuneable_t *fr_findtunebycookie __P((void *, void **));
-static int ipf_geniter __P((ipftoken_t *, ipfgeniter_t *));
-static int ipf_frruleiter __P((void *, int, void *));
-static void ipf_unlinktoken __P((ipftoken_t *));
/*
@@ -265,7 +228,7 @@ static void ipf_unlinktoken __P((ipftoken_t *));
* hand side to allow for binary searching of the array and include a trailer
* with a 0 for the bitmask for linear searches to easily find the end with.
*/
-const struct optlist ipopts[20] = {
+static const struct optlist ipopts[20] = {
{ IPOPT_NOP, 0x000001 },
{ IPOPT_RR, 0x000002 },
{ IPOPT_ZSU, 0x000004 },
@@ -289,7 +252,7 @@ const struct optlist ipopts[20] = {
};
#ifdef USE_INET6
-struct optlist ip6exthdr[] = {
+static struct optlist ip6exthdr[] = {
{ IPPROTO_HOPOPTS, 0x000001 },
{ IPPROTO_IPV6, 0x000002 },
{ IPPROTO_ROUTING, 0x000004 },
@@ -303,20 +266,10 @@ struct optlist ip6exthdr[] = {
};
#endif
-struct optlist tcpopts[] = {
- { TCPOPT_NOP, 0x000001 },
- { TCPOPT_MAXSEG, 0x000002 },
- { TCPOPT_WINDOW, 0x000004 },
- { TCPOPT_SACK_PERMITTED, 0x000008 },
- { TCPOPT_SACK, 0x000010 },
- { TCPOPT_TIMESTAMP, 0x000020 },
- { 0, 0x000000 }
-};
-
/*
* bit values for identifying presence of individual IP security options
*/
-const struct optlist secopt[8] = {
+static const struct optlist secopt[8] = {
{ IPSO_CLASS_RES4, 0x01 },
{ IPSO_CLASS_TOPS, 0x02 },
{ IPSO_CLASS_SECR, 0x04 },
@@ -327,16 +280,143 @@ const struct optlist secopt[8] = {
{ IPSO_CLASS_RES1, 0x80 }
};
+char ipfilter_version[] = IPL_VERSION;
+
+int ipf_features = 0
+#ifdef IPFILTER_LKM
+ | IPF_FEAT_LKM
+#endif
+#ifdef IPFILTER_LOG
+ | IPF_FEAT_LOG
+#endif
+ | IPF_FEAT_LOOKUP
+#ifdef IPFILTER_BPF
+ | IPF_FEAT_BPF
+#endif
+#ifdef IPFILTER_COMPILED
+ | IPF_FEAT_COMPILED
+#endif
+#ifdef IPFILTER_CKSUM
+ | IPF_FEAT_CKSUM
+#endif
+ | IPF_FEAT_SYNC
+#ifdef IPFILTER_SCAN
+ | IPF_FEAT_SCAN
+#endif
+#ifdef USE_INET6
+ | IPF_FEAT_IPV6
+#endif
+ ;
+
/*
* Table of functions available for use with call rules.
*/
-static ipfunc_resolve_t fr_availfuncs[] = {
-#ifdef IPFILTER_LOOKUP
- { "fr_srcgrpmap", fr_srcgrpmap, fr_grpmapinit },
- { "fr_dstgrpmap", fr_dstgrpmap, fr_grpmapinit },
+static ipfunc_resolve_t ipf_availfuncs[] = {
+ { "srcgrpmap", ipf_srcgrpmap, ipf_grpmapinit, ipf_grpmapfini },
+ { "dstgrpmap", ipf_dstgrpmap, ipf_grpmapinit, ipf_grpmapfini },
+ { "", NULL, NULL, NULL }
+};
+
+static ipftuneable_t ipf_main_tuneables[] = {
+ { { (void *)offsetof(struct ipf_main_softc_s, ipf_flags) },
+ "ipf_flags", 0, 0xffffffff,
+ stsizeof(ipf_main_softc_t, ipf_flags),
+ 0, NULL, NULL },
+ { { (void *)offsetof(struct ipf_main_softc_s, ipf_active) },
+ "active", 0, 0,
+ stsizeof(ipf_main_softc_t, ipf_active),
+ IPFT_RDONLY, NULL, NULL },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_control_forwarding) },
+ "control_forwarding", 0, 1,
+ stsizeof(ipf_main_softc_t, ipf_control_forwarding),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_update_ipid) },
+ "update_ipid", 0, 1,
+ stsizeof(ipf_main_softc_t, ipf_update_ipid),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_chksrc) },
+ "chksrc", 0, 1,
+ stsizeof(ipf_main_softc_t, ipf_chksrc),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_minttl) },
+ "min_ttl", 0, 1,
+ stsizeof(ipf_main_softc_t, ipf_minttl),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_icmpminfragmtu) },
+ "icmp_minfragmtu", 0, 1,
+ stsizeof(ipf_main_softc_t, ipf_icmpminfragmtu),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_pass) },
+ "default_pass", 0, 0xffffffff,
+ stsizeof(ipf_main_softc_t, ipf_pass),
+ 0, NULL, NULL },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcpidletimeout) },
+ "tcp_idle_timeout", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcpidletimeout),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosewait) },
+ "tcp_close_wait", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcpclosewait),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcplastack) },
+ "tcp_last_ack", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcplastack),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimeout) },
+ "tcp_timeout", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcptimeout),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynsent) },
+ "tcp_syn_sent", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcpsynsent),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynrecv) },
+ "tcp_syn_received", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcpsynrecv),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosed) },
+ "tcp_closed", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcpclosed),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcphalfclosed) },
+ "tcp_half_closed", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcphalfclosed),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimewait) },
+ "tcp_time_wait", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_tcptimewait),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_udptimeout) },
+ "udp_timeout", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_udptimeout),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_udpacktimeout) },
+ "udp_ack_timeout", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_udpacktimeout),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_icmptimeout) },
+ "icmp_timeout", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_icmptimeout),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_icmpacktimeout) },
+ "icmp_ack_timeout", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_icmpacktimeout),
+ 0, NULL, ipf_settimeout },
+ { { (void *)offsetof(ipf_main_softc_t, ipf_iptimeout) },
+ "ip_timeout", 1, 0x7fffffff,
+ stsizeof(ipf_main_softc_t, ipf_iptimeout),
+ 0, NULL, ipf_settimeout },
+#if defined(INSTANCES) && defined(_KERNEL)
+ { { (void *)offsetof(ipf_main_softc_t, ipf_get_loopback) },
+ "intercept_loopback", 0, 1,
+ stsizeof(ipf_main_softc_t, ipf_get_loopback),
+ 0, NULL, ipf_set_loopback },
#endif
- { "", NULL, NULL }
+ { { 0 },
+ NULL, 0, 0,
+ 0,
+ 0, NULL, NULL }
};
@@ -346,39 +426,41 @@ static ipfunc_resolve_t fr_availfuncs[] = {
* current packet. There are different routines for the same protocol
* for each of IPv4 and IPv6. Adding a new protocol, for which there
* will "special" inspection for setup, is now more easily done by adding
- * a new routine and expanding the frpr_ipinit*() function rather than by
+ * a new routine and expanding the ipf_pr_ipinit*() function rather than by
* adding more code to a growing switch statement.
*/
#ifdef USE_INET6
-static INLINE int frpr_ah6 __P((fr_info_t *));
-static INLINE void frpr_esp6 __P((fr_info_t *));
-static INLINE void frpr_gre6 __P((fr_info_t *));
-static INLINE void frpr_udp6 __P((fr_info_t *));
-static INLINE void frpr_tcp6 __P((fr_info_t *));
-static INLINE void frpr_icmp6 __P((fr_info_t *));
-static INLINE int frpr_ipv6hdr __P((fr_info_t *));
-static INLINE void frpr_short6 __P((fr_info_t *, int));
-static INLINE int frpr_hopopts6 __P((fr_info_t *));
-static INLINE int frpr_mobility6 __P((fr_info_t *));
-static INLINE int frpr_routing6 __P((fr_info_t *));
-static INLINE int frpr_dstopts6 __P((fr_info_t *));
-static INLINE int frpr_fragment6 __P((fr_info_t *));
-static INLINE int frpr_ipv6exthdr __P((fr_info_t *, int, int));
-
-
-/* ------------------------------------------------------------------------ */
-/* Function: frpr_short6 */
+static INLINE int ipf_pr_ah6 __P((fr_info_t *));
+static INLINE void ipf_pr_esp6 __P((fr_info_t *));
+static INLINE void ipf_pr_gre6 __P((fr_info_t *));
+static INLINE void ipf_pr_udp6 __P((fr_info_t *));
+static INLINE void ipf_pr_tcp6 __P((fr_info_t *));
+static INLINE void ipf_pr_icmp6 __P((fr_info_t *));
+static INLINE void ipf_pr_ipv6hdr __P((fr_info_t *));
+static INLINE void ipf_pr_short6 __P((fr_info_t *, int));
+static INLINE int ipf_pr_hopopts6 __P((fr_info_t *));
+static INLINE int ipf_pr_mobility6 __P((fr_info_t *));
+static INLINE int ipf_pr_routing6 __P((fr_info_t *));
+static INLINE int ipf_pr_dstopts6 __P((fr_info_t *));
+static INLINE int ipf_pr_fragment6 __P((fr_info_t *));
+static INLINE struct ip6_ext *ipf_pr_ipv6exthdr __P((fr_info_t *, int, int));
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_pr_short6 */
/* Returns: void */
-/* Parameters: fin(I) - pointer to packet information */
+/* Parameters: fin(I) - pointer to packet information */
+/* xmin(I) - minimum header size */
/* */
/* IPv6 Only */
/* This is function enforces the 'is a packet too short to be legit' rule */
/* for IPv6 and marks the packet with FI_SHORT if so. See function comment */
-/* for frpr_short() for more details. */
+/* for ipf_pr_short() for more details. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_short6(fin, xmin)
-fr_info_t *fin;
-int xmin;
+static INLINE void
+ipf_pr_short6(fin, xmin)
+ fr_info_t *fin;
+ int xmin;
{
if (fin->fin_dlen < xmin)
@@ -387,8 +469,8 @@ int xmin;
/* ------------------------------------------------------------------------ */
-/* Function: frpr_ipv6hdr */
-/* Returns: int - 0 = IPv6 packet intact, -1 = packet lost */
+/* Function: ipf_pr_ipv6hdr */
+/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* IPv6 Only */
@@ -397,8 +479,9 @@ int xmin;
/* analyzer may pullup or free the packet itself so we need to be vigiliant */
/* of that possibility arising. */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_ipv6hdr(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_ipv6hdr(fin)
+ fr_info_t *fin;
{
ip6_t *ip6 = (ip6_t *)fin->fin_ip;
int p, go = 1, i, hdrcount;
@@ -412,57 +495,68 @@ fr_info_t *fin;
fi->fi_auth = 0;
p = ip6->ip6_nxt;
+ fin->fin_crc = p;
fi->fi_ttl = ip6->ip6_hlim;
fi->fi_src.in6 = ip6->ip6_src;
+ fin->fin_crc += fi->fi_src.i6[0];
+ fin->fin_crc += fi->fi_src.i6[1];
+ fin->fin_crc += fi->fi_src.i6[2];
+ fin->fin_crc += fi->fi_src.i6[3];
fi->fi_dst.in6 = ip6->ip6_dst;
- fin->fin_id = (u_short)(ip6->ip6_flow & 0xffff);
+ fin->fin_crc += fi->fi_dst.i6[0];
+ fin->fin_crc += fi->fi_dst.i6[1];
+ fin->fin_crc += fi->fi_dst.i6[2];
+ fin->fin_crc += fi->fi_dst.i6[3];
+ fin->fin_id = 0;
+ if (IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6))
+ fin->fin_flx |= FI_MULTICAST|FI_MBCAST;
hdrcount = 0;
- while (go && !(fin->fin_flx & (FI_BAD|FI_SHORT))) {
+ while (go && !(fin->fin_flx & FI_SHORT)) {
switch (p)
{
case IPPROTO_UDP :
- frpr_udp6(fin);
+ ipf_pr_udp6(fin);
go = 0;
break;
case IPPROTO_TCP :
- frpr_tcp6(fin);
+ ipf_pr_tcp6(fin);
go = 0;
break;
case IPPROTO_ICMPV6 :
- frpr_icmp6(fin);
+ ipf_pr_icmp6(fin);
go = 0;
break;
case IPPROTO_GRE :
- frpr_gre6(fin);
+ ipf_pr_gre6(fin);
go = 0;
break;
case IPPROTO_HOPOPTS :
- p = frpr_hopopts6(fin);
+ p = ipf_pr_hopopts6(fin);
break;
case IPPROTO_MOBILITY :
- p = frpr_mobility6(fin);
+ p = ipf_pr_mobility6(fin);
break;
case IPPROTO_DSTOPTS :
- p = frpr_dstopts6(fin);
+ p = ipf_pr_dstopts6(fin);
break;
case IPPROTO_ROUTING :
- p = frpr_routing6(fin);
+ p = ipf_pr_routing6(fin);
break;
case IPPROTO_AH :
- p = frpr_ah6(fin);
+ p = ipf_pr_ah6(fin);
break;
case IPPROTO_ESP :
- frpr_esp6(fin);
+ ipf_pr_esp6(fin);
go = 0;
break;
@@ -480,7 +574,13 @@ fr_info_t *fin;
break;
case IPPROTO_FRAGMENT :
- p = frpr_fragment6(fin);
+ p = ipf_pr_fragment6(fin);
+ /*
+ * Given that the only fragments we want to let through
+ * (where fin_off != 0) are those where the non-first
+ * fragments only have data, we can safely stop looking
+ * at headers if this is a non-leading fragment.
+ */
if (fin->fin_off != 0)
go = 0;
break;
@@ -501,39 +601,61 @@ fr_info_t *fin;
* header.
*/
if ((go != 0) && (p != IPPROTO_NONE) &&
- (frpr_pullup(fin, 0) == -1)) {
+ (ipf_pr_pullup(fin, 0) == -1)) {
p = IPPROTO_NONE;
- go = 0;
+ break;
}
}
- fi->fi_p = p;
/*
- * Some of the above functions, like frpr_esp6(), can call fr_pullup
+ * Some of the above functions, like ipf_pr_esp6(), can call ipf_pullup
* and destroy whatever packet was here. The caller of this function
- * expects us to return -1 if there is a problem with fr_pullup.
+ * expects us to return if there is a problem with ipf_pullup.
*/
- if (fin->fin_m == NULL)
- return -1;
+ if (fin->fin_m == NULL) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
- return 0;
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_bad);
+ return;
+ }
+
+ fi->fi_p = p;
+
+ /*
+ * IPv6 fragment case 1 - see comment for ipf_pr_fragment6().
+ * "go != 0" imples the above loop hasn't arrived at a layer 4 header.
+ */
+ if ((go != 0) && (fin->fin_flx & FI_FRAG) && (fin->fin_off == 0)) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+
+ fin->fin_flx |= FI_BAD;
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_badfrag);
+ LBUMP(ipf_stats[fin->fin_out].fr_v6_bad);
+ }
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_ipv6exthdr */
-/* Returns: int - value of the next header or IPPROTO_NONE if error */
+/* Function: ipf_pr_ipv6exthdr */
+/* Returns: struct ip6_ext * - pointer to the start of the next header */
+/* or NULL if there is a prolblem. */
/* Parameters: fin(I) - pointer to packet information */
/* multiple(I) - flag indicating yes/no if multiple occurances */
/* of this extension header are allowed. */
/* proto(I) - protocol number for this extension header */
/* */
/* IPv6 Only */
-/* ------------------------------------------------------------------------ */
-static INLINE int frpr_ipv6exthdr(fin, multiple, proto)
-fr_info_t *fin;
-int multiple, proto;
+/* This function embodies a number of common checks that all IPv6 extension */
+/* headers must be subjected to. For example, making sure the packet is */
+/* big enough for it to be in, checking if it is repeated and setting a */
+/* flag to indicate its presence. */
+/* ------------------------------------------------------------------------ */
+static INLINE struct ip6_ext *
+ipf_pr_ipv6exthdr(fin, multiple, proto)
+ fr_info_t *fin;
+ int multiple, proto;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
struct ip6_ext *hdr;
u_short shift;
int i;
@@ -543,11 +665,14 @@ int multiple, proto;
/* 8 is default length of extension hdr */
if ((fin->fin_dlen - 8) < 0) {
fin->fin_flx |= FI_SHORT;
- return IPPROTO_NONE;
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_short);
+ return NULL;
}
- if (frpr_pullup(fin, 8) == -1)
- return IPPROTO_NONE;
+ if (ipf_pr_pullup(fin, 8) == -1) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_pullup);
+ return NULL;
+ }
hdr = fin->fin_dp;
switch (proto)
@@ -562,9 +687,21 @@ int multiple, proto;
if (shift > fin->fin_dlen) { /* Nasty extension header length? */
fin->fin_flx |= FI_BAD;
- return IPPROTO_NONE;
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_hlen);
+ return NULL;
}
+ fin->fin_dp = (char *)fin->fin_dp + shift;
+ fin->fin_dlen -= shift;
+
+ /*
+ * If we have seen a fragment header, do not set any flags to indicate
+ * the presence of this extension header as it has no impact on the
+ * end result until after it has been defragmented.
+ */
+ if (fin->fin_flx & FI_FRAG)
+ return hdr;
+
for (i = 0; ip6exthdr[i].ol_bit != 0; i++)
if (ip6exthdr[i].ol_val == proto) {
/*
@@ -578,149 +715,196 @@ int multiple, proto;
break;
}
- fin->fin_exthdr = fin->fin_dp;
- fin->fin_dp = (char *)fin->fin_dp + shift;
- fin->fin_dlen -= shift;
-
- return hdr->ip6e_nxt;
+ return hdr;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_hopopts6 */
+/* Function: ipf_pr_hopopts6 */
/* Returns: int - value of the next header or IPPROTO_NONE if error */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* IPv6 Only */
/* This is function checks pending hop by hop options extension header */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_hopopts6(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_hopopts6(fin)
+ fr_info_t *fin;
{
- return frpr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
+ struct ip6_ext *hdr;
+
+ hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
+ if (hdr == NULL)
+ return IPPROTO_NONE;
+ return hdr->ip6e_nxt;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_mobility6 */
+/* Function: ipf_pr_mobility6 */
/* Returns: int - value of the next header or IPPROTO_NONE if error */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* IPv6 Only */
/* This is function checks the IPv6 mobility extension header */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_mobility6(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_mobility6(fin)
+ fr_info_t *fin;
{
- return frpr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY);
+ struct ip6_ext *hdr;
+
+ hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY);
+ if (hdr == NULL)
+ return IPPROTO_NONE;
+ return hdr->ip6e_nxt;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_routing6 */
+/* Function: ipf_pr_routing6 */
/* Returns: int - value of the next header or IPPROTO_NONE if error */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* IPv6 Only */
/* This is function checks pending routing extension header */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_routing6(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_routing6(fin)
+ fr_info_t *fin;
{
- struct ip6_ext *hdr;
+ struct ip6_routing *hdr;
- if (frpr_ipv6exthdr(fin, 0, IPPROTO_ROUTING) == IPPROTO_NONE)
+ hdr = (struct ip6_routing *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_ROUTING);
+ if (hdr == NULL)
return IPPROTO_NONE;
- hdr = fin->fin_exthdr;
- if ((hdr->ip6e_len & 1) != 0) {
- /*
- * The routing header data is made up of 128 bit IPv6 addresses
- * which means it must be a multiple of 2 lots of 8 in length.
- */
- fin->fin_flx |= FI_BAD;
+ switch (hdr->ip6r_type)
+ {
+ case 0 :
/*
- * Compensate for the changes made in frpr_ipv6exthdr()
+ * Nasty extension header length?
*/
- fin->fin_dlen += 8 + (hdr->ip6e_len << 3);
- fin->fin_dp = hdr;
- return IPPROTO_NONE;
+ if (((hdr->ip6r_len >> 1) < hdr->ip6r_segleft) ||
+ (hdr->ip6r_segleft && (hdr->ip6r_len & 1))) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+
+ fin->fin_flx |= FI_BAD;
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_rh_bad);
+ return IPPROTO_NONE;
+ }
+ break;
+
+ default :
+ break;
}
- return hdr->ip6e_nxt;
+ return hdr->ip6r_nxt;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_fragment6 */
+/* Function: ipf_pr_fragment6 */
/* Returns: int - value of the next header or IPPROTO_NONE if error */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* IPv6 Only */
/* Examine the IPv6 fragment header and extract fragment offset information.*/
/* */
-/* We don't know where the transport layer header (or whatever is next is), */
-/* as it could be behind destination options (amongst others). Because */
-/* there is no fragment cache, there is no knowledge about whether or not an*/
-/* upper layer header has been seen (or where it ends) and thus we are not */
-/* able to continue processing beyond this header with any confidence. */
-/* ------------------------------------------------------------------------ */
-static INLINE int frpr_fragment6(fin)
-fr_info_t *fin;
+/* Fragments in IPv6 are extraordinarily difficult to deal with - much more */
+/* so than in IPv4. There are 5 cases of fragments with IPv6 that all */
+/* packets with a fragment header can fit into. They are as follows: */
+/* */
+/* 1. [IPv6][0-n EH][FH][0-n EH] (no L4HDR present) */
+/* 2. [IPV6][0-n EH][FH][0-n EH][L4HDR part] (short) */
+/* 3. [IPV6][0-n EH][FH][L4HDR part][0-n data] (short) */
+/* 4. [IPV6][0-n EH][FH][0-n EH][L4HDR][0-n data] */
+/* 5. [IPV6][0-n EH][FH][data] */
+/* */
+/* IPV6 = IPv6 header, FH = Fragment Header, */
+/* 0-n EH = 0 or more extension headers, 0-n data = 0 or more bytes of data */
+/* */
+/* Packets that match 1, 2, 3 will be dropped as the only reasonable */
+/* scenario in which they happen is in extreme circumstances that are most */
+/* likely to be an indication of an attack rather than normal traffic. */
+/* A type 3 packet may be sent by an attacked after a type 4 packet. There */
+/* are two rules that can be used to guard against type 3 packets: L4 */
+/* headers must always be in a packet that has the offset field set to 0 */
+/* and no packet is allowed to overlay that where offset = 0. */
+/* ------------------------------------------------------------------------ */
+static INLINE int
+ipf_pr_fragment6(fin)
+ fr_info_t *fin;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
struct ip6_frag *frag;
- int extoff;
fin->fin_flx |= FI_FRAG;
- if (frpr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT) == IPPROTO_NONE)
- return IPPROTO_NONE;
-
- extoff = (char *)fin->fin_exthdr - (char *)fin->fin_dp;
-
- if (frpr_pullup(fin, sizeof(*frag)) == -1)
+ frag = (struct ip6_frag *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT);
+ if (frag == NULL) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_frag_bad);
return IPPROTO_NONE;
+ }
- fin->fin_exthdr = (char *)fin->fin_dp + extoff;
- frag = fin->fin_exthdr;
- /*
- * Fragment but no fragmentation info set? Bad packet...
- */
- if (frag->ip6f_offlg == 0) {
- fin->fin_flx |= FI_BAD;
- return IPPROTO_NONE;
+ if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0) {
+ /*
+ * Any fragment that isn't the last fragment must have its
+ * length as a multiple of 8.
+ */
+ if ((fin->fin_plen & 7) != 0)
+ fin->fin_flx |= FI_BAD;
}
+ fin->fin_fraghdr = frag;
+ fin->fin_id = frag->ip6f_ident;
fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK);
- fin->fin_off <<= 3;
if (fin->fin_off != 0)
fin->fin_flx |= FI_FRAGBODY;
- fin->fin_dp = (char *)fin->fin_dp + sizeof(*frag);
- fin->fin_dlen -= sizeof(*frag);
+ /*
+ * Jumbograms aren't handled, so the max. length is 64k
+ */
+ if ((fin->fin_off << 3) + fin->fin_dlen > 65535)
+ fin->fin_flx |= FI_BAD;
+ /*
+ * We don't know where the transport layer header (or whatever is next
+ * is), as it could be behind destination options (amongst others) so
+ * return the fragment header as the type of packet this is. Note that
+ * this effectively disables the fragment cache for > 1 protocol at a
+ * time.
+ */
return frag->ip6f_nxt;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_dstopts6 */
+/* Function: ipf_pr_dstopts6 */
/* Returns: int - value of the next header or IPPROTO_NONE if error */
/* Parameters: fin(I) - pointer to packet information */
-/* nextheader(I) - stores next header value */
/* */
/* IPv6 Only */
/* This is function checks pending destination options extension header */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_dstopts6(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_dstopts6(fin)
+ fr_info_t *fin;
{
- return frpr_ipv6exthdr(fin, 1, IPPROTO_DSTOPTS);
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ struct ip6_ext *hdr;
+
+ hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_DSTOPTS);
+ if (hdr == NULL) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_dst_bad);
+ return IPPROTO_NONE;
+ }
+ return hdr->ip6e_nxt;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_icmp6 */
+/* Function: ipf_pr_icmp6 */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -728,14 +912,19 @@ fr_info_t *fin;
/* This routine is mainly concerned with determining the minimum valid size */
/* for an ICMPv6 packet. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_icmp6(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_icmp6(fin)
+ fr_info_t *fin;
{
int minicmpsz = sizeof(struct icmp6_hdr);
struct icmp6_hdr *icmp6;
- if (frpr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1)
+ if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_icmp6_pullup);
return;
+ }
if (fin->fin_dlen > 1) {
ip6_t *ip6;
@@ -744,12 +933,18 @@ fr_info_t *fin;
fin->fin_data[0] = *(u_short *)icmp6;
+ if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0)
+ fin->fin_flx |= FI_ICMPQUERY;
+
switch (icmp6->icmp6_type)
{
case ICMP6_ECHO_REPLY :
case ICMP6_ECHO_REQUEST :
+ if (fin->fin_dlen >= 6)
+ fin->fin_data[1] = icmp6->icmp6_id;
minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t);
break;
+
case ICMP6_DST_UNREACH :
case ICMP6_PACKET_TOO_BIG :
case ICMP6_TIME_EXCEEDED :
@@ -760,10 +955,13 @@ fr_info_t *fin;
break;
if (M_LEN(fin->fin_m) < fin->fin_plen) {
- if (fr_coalesce(fin) != 1)
+ if (ipf_coalesce(fin) != 1)
return;
}
+ if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN) == -1)
+ return;
+
/*
* If the destination of this packet doesn't match the
* source of the original packet then this packet is
@@ -774,19 +972,25 @@ fr_info_t *fin;
if (IP6_NEQ(&fin->fin_fi.fi_dst,
(i6addr_t *)&ip6->ip6_src))
fin->fin_flx |= FI_BAD;
-
break;
default :
break;
}
}
- frpr_short6(fin, minicmpsz);
+ ipf_pr_short6(fin, minicmpsz);
+ if ((fin->fin_flx & (FI_SHORT|FI_BAD)) == 0) {
+ u_char p = fin->fin_p;
+
+ fin->fin_p = IPPROTO_ICMPV6;
+ ipf_checkv6sum(fin);
+ fin->fin_p = p;
+ }
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_udp6 */
+/* Function: ipf_pr_udp6 */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -794,24 +998,23 @@ fr_info_t *fin;
/* Analyse the packet for IPv6/UDP properties. */
/* Is not expected to be called for fragmented packets. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_udp6(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_udp6(fin)
+ fr_info_t *fin;
{
- frpr_short6(fin, sizeof(struct udphdr));
-
- if (frpr_udpcommon(fin) == 0) {
+ if (ipf_pr_udpcommon(fin) == 0) {
u_char p = fin->fin_p;
fin->fin_p = IPPROTO_UDP;
- fr_checkv6sum(fin);
+ ipf_checkv6sum(fin);
fin->fin_p = p;
}
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_tcp6 */
+/* Function: ipf_pr_tcp6 */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -819,24 +1022,23 @@ fr_info_t *fin;
/* Analyse the packet for IPv6/TCP properties. */
/* Is not expected to be called for fragmented packets. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_tcp6(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_tcp6(fin)
+ fr_info_t *fin;
{
- frpr_short6(fin, sizeof(struct tcphdr));
-
- if (frpr_tcpcommon(fin) == 0) {
+ if (ipf_pr_tcpcommon(fin) == 0) {
u_char p = fin->fin_p;
fin->fin_p = IPPROTO_TCP;
- fr_checkv6sum(fin);
+ ipf_checkv6sum(fin);
fin->fin_p = p;
}
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_esp6 */
+/* Function: ipf_pr_esp6 */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -847,19 +1049,23 @@ fr_info_t *fin;
/* is 32bits as well, it is not possible(?) to determine the version from a */
/* simple packet header. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_esp6(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_esp6(fin)
+ fr_info_t *fin;
{
- frpr_short6(fin, sizeof(grehdr_t));
+ if ((fin->fin_off == 0) && (ipf_pr_pullup(fin, 8) == -1)) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
- (void) frpr_pullup(fin, 8);
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_esp_pullup);
+ return;
+ }
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_ah6 */
-/* Returns: void */
+/* Function: ipf_pr_ah6 */
+/* Returns: int - value of the next header or IPPROTO_NONE if error */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* IPv6 Only */
@@ -867,37 +1073,51 @@ fr_info_t *fin;
/* The minimum length is taken to be the combination of all fields in the */
/* header being present and no authentication data (null algorithm used.) */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_ah6(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_ah6(fin)
+ fr_info_t *fin;
{
authhdr_t *ah;
- frpr_short6(fin, 12);
+ fin->fin_flx |= FI_AH;
+
+ ah = (authhdr_t *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS);
+ if (ah == NULL) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
- if (frpr_pullup(fin, sizeof(*ah)) == -1)
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_ah_bad);
return IPPROTO_NONE;
+ }
- ah = (authhdr_t *)fin->fin_dp;
+ ipf_pr_short6(fin, sizeof(*ah));
+
+ /*
+ * No need for another pullup, ipf_pr_ipv6exthdr() will pullup
+ * enough data to satisfy ah_next (the very first one.)
+ */
return ah->ah_next;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_gre6 */
+/* Function: ipf_pr_gre6 */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* Analyse the packet for GRE properties. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_gre6(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_gre6(fin)
+ fr_info_t *fin;
{
grehdr_t *gre;
- frpr_short6(fin, sizeof(grehdr_t));
+ if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
- if (frpr_pullup(fin, sizeof(grehdr_t)) == -1)
+ LBUMPD(ipf_stats[fin->fin_out], fr_v6_gre_pullup);
return;
+ }
gre = fin->fin_dp;
if (GRE_REV(gre->gr_flags) == 1)
@@ -907,13 +1127,13 @@ fr_info_t *fin;
/* ------------------------------------------------------------------------ */
-/* Function: frpr_pullup */
+/* Function: ipf_pr_pullup */
/* Returns: int - 0 == pullup succeeded, -1 == failure */
/* Parameters: fin(I) - pointer to packet information */
/* plen(I) - length (excluding L3 header) to pullup */
/* */
/* Short inline function to cut down on code duplication to perform a call */
-/* to fr_pullup to ensure there is the required amount of data, */
+/* to ipf_pullup to ensure there is the required amount of data, */
/* consecutively in the packet buffer. */
/* */
/* This function pulls up 'extra' data at the location of fin_dp. fin_dp */
@@ -924,23 +1144,32 @@ fr_info_t *fin;
/* is necessary to add those we can already assume to be pulled up (fin_dp */
/* - fin_ip) to what is passed through. */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_pullup(fin, plen)
-fr_info_t *fin;
-int plen;
+int
+ipf_pr_pullup(fin, plen)
+ fr_info_t *fin;
+ int plen;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+
if (fin->fin_m != NULL) {
if (fin->fin_dp != NULL)
plen += (char *)fin->fin_dp -
((char *)fin->fin_ip + fin->fin_hlen);
plen += fin->fin_hlen;
- if (M_LEN(fin->fin_m) < plen) {
+ if (M_LEN(fin->fin_m) < plen + fin->fin_ipoff) {
#if defined(_KERNEL)
- if (fr_pullup(fin->fin_m, fin, plen) == NULL)
+ if (ipf_pullup(fin->fin_m, fin, plen) == NULL) {
+ DT(ipf_pullup_fail);
+ LBUMP(ipf_stats[fin->fin_out].fr_pull[1]);
return -1;
+ }
+ LBUMP(ipf_stats[fin->fin_out].fr_pull[0]);
#else
+ LBUMP(ipf_stats[fin->fin_out].fr_pull[1]);
/*
- * Fake fr_pullup failing
+ * Fake ipf_pullup failing
*/
+ fin->fin_reason = FRB_PULLUP;
*fin->fin_mp = NULL;
fin->fin_m = NULL;
fin->fin_ip = NULL;
@@ -953,7 +1182,7 @@ int plen;
/* ------------------------------------------------------------------------ */
-/* Function: frpr_short */
+/* Function: ipf_pr_short */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* xmin(I) - minimum header size */
@@ -964,9 +1193,10 @@ int plen;
/* start within the layer 4 header (hdrmin) or if it is at offset 0, the */
/* entire layer 4 header must be present (min). */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_short(fin, xmin)
-fr_info_t *fin;
-int xmin;
+static INLINE void
+ipf_pr_short(fin, xmin)
+ fr_info_t *fin;
+ int xmin;
{
if (fin->fin_off == 0) {
@@ -979,7 +1209,7 @@ int xmin;
/* ------------------------------------------------------------------------ */
-/* Function: frpr_icmp */
+/* Function: ipf_pr_icmp */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -991,110 +1221,111 @@ int xmin;
/* */
/* XXX - other ICMP sanity checks? */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_icmp(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_icmp(fin)
+ fr_info_t *fin;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
int minicmpsz = sizeof(struct icmp);
icmphdr_t *icmp;
ip_t *oip;
+ ipf_pr_short(fin, ICMPERR_ICMPHLEN);
+
if (fin->fin_off != 0) {
- frpr_short(fin, ICMPERR_ICMPHLEN);
+ LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_frag);
return;
}
- if (frpr_pullup(fin, ICMPERR_ICMPHLEN) == -1)
+ if (ipf_pr_pullup(fin, ICMPERR_ICMPHLEN) == -1) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_pullup);
return;
+ }
- if (fin->fin_dlen > 1) {
- icmp = fin->fin_dp;
+ icmp = fin->fin_dp;
- fin->fin_data[0] = *(u_short *)icmp;
+ fin->fin_data[0] = *(u_short *)icmp;
+ fin->fin_data[1] = icmp->icmp_id;
- if (fin->fin_dlen >= 6) /* ID field */
- fin->fin_data[1] = icmp->icmp_id;
+ switch (icmp->icmp_type)
+ {
+ case ICMP_ECHOREPLY :
+ case ICMP_ECHO :
+ /* Router discovery messaes - RFC 1256 */
+ case ICMP_ROUTERADVERT :
+ case ICMP_ROUTERSOLICIT :
+ fin->fin_flx |= FI_ICMPQUERY;
+ minicmpsz = ICMP_MINLEN;
+ break;
+ /*
+ * type(1) + code(1) + cksum(2) + id(2) seq(2) +
+ * 3 * timestamp(3 * 4)
+ */
+ case ICMP_TSTAMP :
+ case ICMP_TSTAMPREPLY :
+ fin->fin_flx |= FI_ICMPQUERY;
+ minicmpsz = 20;
+ break;
+ /*
+ * type(1) + code(1) + cksum(2) + id(2) seq(2) +
+ * mask(4)
+ */
+ case ICMP_IREQ :
+ case ICMP_IREQREPLY :
+ case ICMP_MASKREQ :
+ case ICMP_MASKREPLY :
+ fin->fin_flx |= FI_ICMPQUERY;
+ minicmpsz = 12;
+ break;
+ /*
+ * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+)
+ */
+ case ICMP_UNREACH :
+#ifdef icmp_nextmtu
+ if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) {
+ if (icmp->icmp_nextmtu < softc->ipf_icmpminfragmtu)
+ fin->fin_flx |= FI_BAD;
+ }
+#endif
+ case ICMP_SOURCEQUENCH :
+ case ICMP_REDIRECT :
+ case ICMP_TIMXCEED :
+ case ICMP_PARAMPROB :
+ fin->fin_flx |= FI_ICMPERR;
+ if (ipf_coalesce(fin) != 1) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_icmp_coalesce);
+ return;
+ }
- switch (icmp->icmp_type)
- {
- case ICMP_ECHOREPLY :
- case ICMP_ECHO :
- /* Router discovery messaes - RFC 1256 */
- case ICMP_ROUTERADVERT :
- case ICMP_ROUTERSOLICIT :
- minicmpsz = ICMP_MINLEN;
- break;
/*
- * type(1) + code(1) + cksum(2) + id(2) seq(2) +
- * 3 * timestamp(3 * 4)
+ * ICMP error packets should not be generated for IP
+ * packets that are a fragment that isn't the first
+ * fragment.
*/
- case ICMP_TSTAMP :
- case ICMP_TSTAMPREPLY :
- minicmpsz = 20;
- break;
- /*
- * type(1) + code(1) + cksum(2) + id(2) seq(2) +
- * mask(4)
- */
- case ICMP_MASKREQ :
- case ICMP_MASKREPLY :
- minicmpsz = 12;
- break;
+ oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN);
+ if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0)
+ fin->fin_flx |= FI_BAD;
+
/*
- * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+)
+ * If the destination of this packet doesn't match the
+ * source of the original packet then this packet is
+ * not correct.
*/
- case ICMP_UNREACH :
-#ifdef icmp_nextmtu
- if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) {
- if (icmp->icmp_nextmtu < fr_icmpminfragmtu)
- fin->fin_flx |= FI_BAD;
- }
-#endif
- case ICMP_SOURCEQUENCH :
- case ICMP_REDIRECT :
- case ICMP_TIMXCEED :
- case ICMP_PARAMPROB :
- fin->fin_flx |= FI_ICMPERR;
- if (fr_coalesce(fin) != 1)
- return;
- /*
- * ICMP error packets should not be generated for IP
- * packets that are a fragment that isn't the first
- * fragment.
- */
- oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN);
- if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0)
- fin->fin_flx |= FI_BAD;
-
- /*
- * If the destination of this packet doesn't match the
- * source of the original packet then this packet is
- * not correct.
- */
- if (oip->ip_src.s_addr != fin->fin_daddr)
- fin->fin_flx |= FI_BAD;
-
- /*
- * If the destination of this packet doesn't match the
- * source of the original packet then this packet is
- * not correct.
- */
- if (oip->ip_src.s_addr != fin->fin_daddr)
- fin->fin_flx |= FI_BAD;
- break;
- default :
- break;
- }
+ if (oip->ip_src.s_addr != fin->fin_daddr)
+ fin->fin_flx |= FI_BAD;
+ break;
+ default :
+ break;
}
- frpr_short(fin, minicmpsz);
+ ipf_pr_short(fin, minicmpsz);
- if ((fin->fin_flx & FI_FRAG) == 0)
- fr_checkv4sum(fin);
+ ipf_checkv4sum(fin);
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_tcpcommon */
+/* Function: ipf_pr_tcpcommon */
/* Returns: int - 0 = header ok, 1 = bad packet, -1 = buffer error */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -1103,27 +1334,35 @@ fr_info_t *fin;
/* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */
/* valid and mark the packet as bad if not. */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_tcpcommon(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_tcpcommon(fin)
+ fr_info_t *fin;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
int flags, tlen;
tcphdr_t *tcp;
fin->fin_flx |= FI_TCPUDP;
- if (fin->fin_off != 0)
+ if (fin->fin_off != 0) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_tcp_frag);
return 0;
+ }
- if (frpr_pullup(fin, sizeof(*tcp)) == -1)
+ if (ipf_pr_pullup(fin, sizeof(*tcp)) == -1) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup);
return -1;
- tcp = fin->fin_dp;
+ }
+ tcp = fin->fin_dp;
if (fin->fin_dlen > 3) {
fin->fin_sport = ntohs(tcp->th_sport);
fin->fin_dport = ntohs(tcp->th_dport);
}
- if ((fin->fin_flx & FI_SHORT) != 0)
+ if ((fin->fin_flx & FI_SHORT) != 0) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_tcp_short);
return 1;
+ }
/*
* Use of the TCP data offset *must* result in a value that is at
@@ -1131,6 +1370,7 @@ fr_info_t *fin;
*/
tlen = TCP_OFF(tcp) << 2;
if (tlen < sizeof(tcphdr_t)) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_tcp_small);
fin->fin_flx |= FI_BAD;
return 1;
}
@@ -1189,6 +1429,10 @@ fr_info_t *fin;
fin->fin_flx |= FI_BAD;
}
}
+ if (fin->fin_flx & FI_BAD) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_tcp_bad_flags);
+ return 1;
+ }
/*
* At this point, it's not exactly clear what is to be gained by
@@ -1198,11 +1442,14 @@ fr_info_t *fin;
* Now if we were to analyse the header for passive fingerprinting,
* then that might add some weight to adding this...
*/
- if (tlen == sizeof(tcphdr_t))
+ if (tlen == sizeof(tcphdr_t)) {
return 0;
+ }
- if (frpr_pullup(fin, tlen) == -1)
+ if (ipf_pr_pullup(fin, tlen) == -1) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup);
return -1;
+ }
#if 0
tcp = fin->fin_dp;
@@ -1249,23 +1496,27 @@ fr_info_t *fin;
/* ------------------------------------------------------------------------ */
-/* Function: frpr_udpcommon */
+/* Function: ipf_pr_udpcommon */
/* Returns: int - 0 = header ok, 1 = bad packet */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* Extract the UDP source and destination ports, if present. If compiled */
/* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */
/* ------------------------------------------------------------------------ */
-static INLINE int frpr_udpcommon(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_udpcommon(fin)
+ fr_info_t *fin;
{
udphdr_t *udp;
fin->fin_flx |= FI_TCPUDP;
if (!fin->fin_off && (fin->fin_dlen > 3)) {
- if (frpr_pullup(fin, sizeof(*udp)) == -1) {
+ if (ipf_pr_pullup(fin, sizeof(*udp)) == -1) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+
fin->fin_flx |= FI_SHORT;
+ LBUMPD(ipf_stats[fin->fin_out], fr_udp_pullup);
return 1;
}
@@ -1280,49 +1531,47 @@ fr_info_t *fin;
/* ------------------------------------------------------------------------ */
-/* Function: frpr_tcp */
+/* Function: ipf_pr_tcp */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* IPv4 Only */
/* Analyse the packet for IPv4/TCP properties. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_tcp(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_tcp(fin)
+ fr_info_t *fin;
{
- frpr_short(fin, sizeof(tcphdr_t));
+ ipf_pr_short(fin, sizeof(tcphdr_t));
- if (frpr_tcpcommon(fin) == 0) {
- if ((fin->fin_flx & FI_FRAG) == 0)
- fr_checkv4sum(fin);
- }
+ if (ipf_pr_tcpcommon(fin) == 0)
+ ipf_checkv4sum(fin);
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_udp */
+/* Function: ipf_pr_udp */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* IPv4 Only */
/* Analyse the packet for IPv4/UDP properties. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_udp(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_udp(fin)
+ fr_info_t *fin;
{
- frpr_short(fin, sizeof(udphdr_t));
+ ipf_pr_short(fin, sizeof(udphdr_t));
- if (frpr_udpcommon(fin) == 0) {
- if ((fin->fin_flx & FI_FRAG) == 0)
- fr_checkv4sum(fin);
- }
+ if (ipf_pr_udpcommon(fin) == 0)
+ ipf_checkv4sum(fin);
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_esp */
+/* Function: ipf_pr_esp */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -1332,78 +1581,107 @@ fr_info_t *fin;
/* is 32bits as well, it is not possible(?) to determine the version from a */
/* simple packet header. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_esp(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_esp(fin)
+ fr_info_t *fin;
{
if (fin->fin_off == 0) {
- frpr_short(fin, 8);
- (void) frpr_pullup(fin, 8);
- }
+ ipf_pr_short(fin, 8);
+ if (ipf_pr_pullup(fin, 8) == -1) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ LBUMPD(ipf_stats[fin->fin_out], fr_v4_esp_pullup);
+ }
+ }
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_ah */
-/* Returns: void */
+/* Function: ipf_pr_ah */
+/* Returns: int - value of the next header or IPPROTO_NONE if error */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* Analyse the packet for AH properties. */
/* The minimum length is taken to be the combination of all fields in the */
/* header being present and no authentication data (null algorithm used.) */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_ah(fin)
-fr_info_t *fin;
+static INLINE int
+ipf_pr_ah(fin)
+ fr_info_t *fin;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
authhdr_t *ah;
int len;
- frpr_short(fin, sizeof(*ah));
+ fin->fin_flx |= FI_AH;
+ ipf_pr_short(fin, sizeof(*ah));
- if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0))
- return;
+ if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0)) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v4_ah_bad);
+ return IPPROTO_NONE;
+ }
- if (frpr_pullup(fin, sizeof(*ah)) == -1)
- return;
+ if (ipf_pr_pullup(fin, sizeof(*ah)) == -1) {
+ DT(fr_v4_ah_pullup_1);
+ LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup);
+ return IPPROTO_NONE;
+ }
ah = (authhdr_t *)fin->fin_dp;
len = (ah->ah_plen + 2) << 2;
- frpr_short(fin, len);
+ ipf_pr_short(fin, len);
+ if (ipf_pr_pullup(fin, len) == -1) {
+ DT(fr_v4_ah_pullup_2);
+ LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup);
+ return IPPROTO_NONE;
+ }
+
+ /*
+ * Adjust fin_dp and fin_dlen for skipping over the authentication
+ * header.
+ */
+ fin->fin_dp = (char *)fin->fin_dp + len;
+ fin->fin_dlen -= len;
+ return ah->ah_next;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_gre */
+/* Function: ipf_pr_gre */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* Analyse the packet for GRE properties. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_gre(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_gre(fin)
+ fr_info_t *fin;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
grehdr_t *gre;
- frpr_short(fin, sizeof(*gre));
+ ipf_pr_short(fin, sizeof(grehdr_t));
- if (fin->fin_off != 0)
+ if (fin->fin_off != 0) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_frag);
return;
+ }
- if (frpr_pullup(fin, sizeof(*gre)) == -1)
+ if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_pullup);
return;
-
- if (fin->fin_off == 0) {
- gre = fin->fin_dp;
- if (GRE_REV(gre->gr_flags) == 1)
- fin->fin_data[0] = gre->gr_call;
}
+
+ gre = fin->fin_dp;
+ if (GRE_REV(gre->gr_flags) == 1)
+ fin->fin_data[0] = gre->gr_call;
}
/* ------------------------------------------------------------------------ */
-/* Function: frpr_ipv4hdr */
+/* Function: ipf_pr_ipv4hdr */
/* Returns: void */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -1411,8 +1689,9 @@ fr_info_t *fin;
/* Analyze the IPv4 header and set fields in the fr_info_t structure. */
/* Check all options present and flag their presence if any exist. */
/* ------------------------------------------------------------------------ */
-static INLINE void frpr_ipv4hdr(fin)
-fr_info_t *fin;
+static INLINE void
+ipf_pr_ipv4hdr(fin)
+ fr_info_t *fin;
{
u_short optmsk = 0, secmsk = 0, auth = 0;
int hlen, ol, mv, p, i;
@@ -1428,16 +1707,14 @@ fr_info_t *fin;
ip = fin->fin_ip;
p = ip->ip_p;
fi->fi_p = p;
+ fin->fin_crc = p;
fi->fi_tos = ip->ip_tos;
fin->fin_id = ip->ip_id;
- off = ip->ip_off;
+ off = ntohs(ip->ip_off);
/* Get both TTL and protocol */
fi->fi_p = ip->ip_p;
fi->fi_ttl = ip->ip_ttl;
-#if 0
- (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4));
-#endif
/* Zero out bits not used in IPv6 address */
fi->fi_src.i6[1] = 0;
@@ -1448,7 +1725,11 @@ fr_info_t *fin;
fi->fi_dst.i6[3] = 0;
fi->fi_saddr = ip->ip_src.s_addr;
+ fin->fin_crc += fi->fi_saddr;
fi->fi_daddr = ip->ip_dst.s_addr;
+ fin->fin_crc += fi->fi_daddr;
+ if (IN_CLASSD(ntohl(fi->fi_daddr)))
+ fin->fin_flx |= FI_MULTICAST|FI_MBCAST;
/*
* set packet attribute flags based on the offset and
@@ -1463,12 +1744,12 @@ fr_info_t *fin;
if (off != 0) {
fin->fin_flx |= FI_FRAGBODY;
off <<= 3;
- if ((off + fin->fin_dlen > 65535) ||
+ if ((off + fin->fin_dlen > 65535) ||
(fin->fin_dlen == 0) ||
((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) {
- /*
+ /*
* The length of the packet, starting at its
- * offset cannot exceed 65535 (0xffff) as the
+ * offset cannot exceed 65535 (0xffff) as the
* length of an IP packet is only 16 bits.
*
* Any fragment that isn't the last fragment
@@ -1484,25 +1765,30 @@ fr_info_t *fin;
/*
* Call per-protocol setup and checking
*/
+ if (p == IPPROTO_AH) {
+ /*
+ * Treat AH differently because we expect there to be another
+ * layer 4 header after it.
+ */
+ p = ipf_pr_ah(fin);
+ }
+
switch (p)
{
case IPPROTO_UDP :
- frpr_udp(fin);
+ ipf_pr_udp(fin);
break;
case IPPROTO_TCP :
- frpr_tcp(fin);
+ ipf_pr_tcp(fin);
break;
case IPPROTO_ICMP :
- frpr_icmp(fin);
- break;
- case IPPROTO_AH :
- frpr_ah(fin);
+ ipf_pr_icmp(fin);
break;
case IPPROTO_ESP :
- frpr_esp(fin);
+ ipf_pr_esp(fin);
break;
case IPPROTO_GRE :
- frpr_gre(fin);
+ ipf_pr_gre(fin);
break;
}
@@ -1545,32 +1831,37 @@ fr_info_t *fin;
}
for (i = 9, mv = 4; mv >= 0; ) {
op = ipopts + i;
+
if ((opt == (u_char)op->ol_val) && (ol > 4)) {
- optmsk |= op->ol_bit;
- if (opt == IPOPT_SECURITY) {
- const struct optlist *sp;
- u_char sec;
- int j, m;
-
- sec = *(s + 2); /* classification */
- for (j = 3, m = 2; m >= 0; ) {
- sp = secopt + j;
- if (sec == sp->ol_val) {
- secmsk |= sp->ol_bit;
- auth = *(s + 3);
- auth *= 256;
- auth += *(s + 4);
- break;
- }
- if (sec < sp->ol_val)
- j -= m;
- else
- j += m;
- m--;
+ u_32_t doi;
+
+ switch (opt)
+ {
+ case IPOPT_SECURITY :
+ if (optmsk & op->ol_bit) {
+ fin->fin_flx |= FI_BAD;
+ } else {
+ doi = ipf_checkripso(s);
+ secmsk = doi >> 16;
+ auth = doi & 0xffff;
}
+ break;
+
+ case IPOPT_CIPSO :
+
+ if (optmsk & op->ol_bit) {
+ fin->fin_flx |= FI_BAD;
+ } else {
+ doi = ipf_checkcipso(fin,
+ s, ol);
+ secmsk = doi >> 16;
+ auth = doi & 0xffff;
+ }
+ break;
}
- break;
+ optmsk |= op->ol_bit;
}
+
if (opt < op->ol_val)
i -= mv;
else
@@ -1593,8 +1884,142 @@ fr_info_t *fin;
/* ------------------------------------------------------------------------ */
-/* Function: fr_makefrip */
+/* Function: ipf_checkripso */
/* Returns: void */
+/* Parameters: s(I) - pointer to start of RIPSO option */
+/* */
+/* ------------------------------------------------------------------------ */
+static u_32_t
+ipf_checkripso(s)
+ u_char *s;
+{
+ const struct optlist *sp;
+ u_short secmsk = 0, auth = 0;
+ u_char sec;
+ int j, m;
+
+ sec = *(s + 2); /* classification */
+ for (j = 3, m = 2; m >= 0; ) {
+ sp = secopt + j;
+ if (sec == sp->ol_val) {
+ secmsk |= sp->ol_bit;
+ auth = *(s + 3);
+ auth *= 256;
+ auth += *(s + 4);
+ break;
+ }
+ if (sec < sp->ol_val)
+ j -= m;
+ else
+ j += m;
+ m--;
+ }
+
+ return (secmsk << 16) | auth;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_checkcipso */
+/* Returns: u_32_t - 0 = failure, else the doi from the header */
+/* Parameters: fin(IO) - pointer to packet information */
+/* s(I) - pointer to start of CIPSO option */
+/* ol(I) - length of CIPSO option field */
+/* */
+/* This function returns the domain of integrity (DOI) field from the CIPSO */
+/* header and returns that whilst also storing the highest sensitivity */
+/* value found in the fr_info_t structure. */
+/* */
+/* No attempt is made to extract the category bitmaps as these are defined */
+/* by the user (rather than the protocol) and can be rather numerous on the */
+/* end nodes. */
+/* ------------------------------------------------------------------------ */
+static u_32_t
+ipf_checkcipso(fin, s, ol)
+ fr_info_t *fin;
+ u_char *s;
+ int ol;
+{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+ fr_ip_t *fi;
+ u_32_t doi;
+ u_char *t, tag, tlen, sensitivity;
+ int len;
+
+ if (ol < 6 || ol > 40) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_bad);
+ fin->fin_flx |= FI_BAD;
+ return 0;
+ }
+
+ fi = &fin->fin_fi;
+ fi->fi_sensitivity = 0;
+ /*
+ * The DOI field MUST be there.
+ */
+ bcopy(s + 2, &doi, sizeof(doi));
+
+ t = (u_char *)s + 6;
+ for (len = ol - 6; len >= 2; len -= tlen, t+= tlen) {
+ tag = *t;
+ tlen = *(t + 1);
+ if (tlen > len || tlen < 4 || tlen > 34) {
+ LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_tlen);
+ fin->fin_flx |= FI_BAD;
+ return 0;
+ }
+
+ sensitivity = 0;
+ /*
+ * Tag numbers 0, 1, 2, 5 are laid out in the CIPSO Internet
+ * draft (16 July 1992) that has expired.
+ */
+ if (tag == 0) {
+ fin->fin_flx |= FI_BAD;
+ continue;
+ } else if (tag == 1) {
+ if (*(t + 2) != 0) {
+ fin->fin_flx |= FI_BAD;
+ continue;
+ }
+ sensitivity = *(t + 3);
+ /* Category bitmap for categories 0-239 */
+
+ } else if (tag == 4) {
+ if (*(t + 2) != 0) {
+ fin->fin_flx |= FI_BAD;
+ continue;
+ }
+ sensitivity = *(t + 3);
+ /* Enumerated categories, 16bits each, upto 15 */
+
+ } else if (tag == 5) {
+ if (*(t + 2) != 0) {
+ fin->fin_flx |= FI_BAD;
+ continue;
+ }
+ sensitivity = *(t + 3);
+ /* Range of categories (2*16bits), up to 7 pairs */
+
+ } else if (tag > 127) {
+ /* Custom defined DOI */
+ ;
+ } else {
+ fin->fin_flx |= FI_BAD;
+ continue;
+ }
+
+ if (sensitivity > fi->fi_sensitivity)
+ fi->fi_sensitivity = sensitivity;
+ }
+
+ return doi;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_makefrip */
+/* Returns: int - 0 == packet ok, -1 == packet freed */
/* Parameters: hlen(I) - length of IP packet header */
/* ip(I) - pointer to the IP header */
/* fin(IO) - pointer to packet information */
@@ -1604,15 +2029,15 @@ fr_info_t *fin;
/* in the fr_info_t structure pointer to by fin. At present, it is assumed */
/* this function will be called with either an IPv4 or IPv6 packet. */
/* ------------------------------------------------------------------------ */
-int fr_makefrip(hlen, ip, fin)
-int hlen;
-ip_t *ip;
-fr_info_t *fin;
+int
+ipf_makefrip(hlen, ip, fin)
+ int hlen;
+ ip_t *ip;
+ fr_info_t *fin;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
int v;
- fin->fin_nat = NULL;
- fin->fin_state = NULL;
fin->fin_depth = 0;
fin->fin_hlen = (u_short)hlen;
fin->fin_ip = ip;
@@ -1623,43 +2048,43 @@ fr_info_t *fin;
v = fin->fin_v;
if (v == 4) {
- fin->fin_plen = ip->ip_len;
+ fin->fin_plen = ntohs(ip->ip_len);
fin->fin_dlen = fin->fin_plen - hlen;
-
- frpr_ipv4hdr(fin);
+ ipf_pr_ipv4hdr(fin);
#ifdef USE_INET6
} else if (v == 6) {
fin->fin_plen = ntohs(((ip6_t *)ip)->ip6_plen);
fin->fin_dlen = fin->fin_plen;
fin->fin_plen += hlen;
- if (frpr_ipv6hdr(fin) == -1)
- return -1;
+ ipf_pr_ipv6hdr(fin);
#endif
}
- if (fin->fin_ip == NULL)
+ if (fin->fin_ip == NULL) {
+ LBUMP(ipf_stats[fin->fin_out].fr_ip_freed);
return -1;
+ }
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_portcheck */
+/* Function: ipf_portcheck */
/* Returns: int - 1 == port matched, 0 == port match failed */
/* Parameters: frp(I) - pointer to port check `expression' */
-/* pop(I) - pointer to port number to evaluate */
+/* pop(I) - port number to evaluate */
/* */
/* Perform a comparison of a port number against some other(s), using a */
/* structure with compare information stored in it. */
/* ------------------------------------------------------------------------ */
-static INLINE int fr_portcheck(frp, pop)
-frpcmp_t *frp;
-u_short *pop;
+static INLINE int
+ipf_portcheck(frp, pop)
+ frpcmp_t *frp;
+ u_32_t pop;
{
- u_short tup, po;
int err = 1;
+ u_32_t po;
- tup = *pop;
po = frp->frp_port;
/*
@@ -1668,39 +2093,39 @@ u_short *pop;
switch (frp->frp_cmp)
{
case FR_EQUAL :
- if (tup != po) /* EQUAL */
+ if (pop != po) /* EQUAL */
err = 0;
break;
case FR_NEQUAL :
- if (tup == po) /* NOTEQUAL */
+ if (pop == po) /* NOTEQUAL */
err = 0;
break;
case FR_LESST :
- if (tup >= po) /* LESSTHAN */
+ if (pop >= po) /* LESSTHAN */
err = 0;
break;
case FR_GREATERT :
- if (tup <= po) /* GREATERTHAN */
+ if (pop <= po) /* GREATERTHAN */
err = 0;
break;
case FR_LESSTE :
- if (tup > po) /* LT or EQ */
+ if (pop > po) /* LT or EQ */
err = 0;
break;
case FR_GREATERTE :
- if (tup < po) /* GT or EQ */
+ if (pop < po) /* GT or EQ */
err = 0;
break;
case FR_OUTRANGE :
- if (tup >= po && tup <= frp->frp_top) /* Out of range */
+ if (pop >= po && pop <= frp->frp_top) /* Out of range */
err = 0;
break;
case FR_INRANGE :
- if (tup <= po || tup >= frp->frp_top) /* In range */
+ if (pop <= po || pop >= frp->frp_top) /* In range */
err = 0;
break;
case FR_INCRANGE :
- if (tup < po || tup > frp->frp_top) /* Inclusive range */
+ if (pop < po || pop > frp->frp_top) /* Inclusive range */
err = 0;
break;
default :
@@ -1711,17 +2136,18 @@ u_short *pop;
/* ------------------------------------------------------------------------ */
-/* Function: fr_tcpudpchk */
+/* Function: ipf_tcpudpchk */
/* Returns: int - 1 == protocol matched, 0 == check failed */
-/* Parameters: fin(I) - pointer to packet information */
+/* Parameters: fda(I) - pointer to packet information */
/* ft(I) - pointer to structure with comparison data */
/* */
/* Compares the current pcket (assuming it is TCP/UDP) information with a */
/* structure containing information that we want to match against. */
/* ------------------------------------------------------------------------ */
-int fr_tcpudpchk(fin, ft)
-fr_info_t *fin;
-frtuc_t *ft;
+int
+ipf_tcpudpchk(fi, ft)
+ fr_ip_t *fi;
+ frtuc_t *ft;
{
int err = 1;
@@ -1732,13 +2158,13 @@ frtuc_t *ft;
* compare destination ports
*/
if (ft->ftu_dcmp)
- err = fr_portcheck(&ft->ftu_dst, &fin->fin_dport);
+ err = ipf_portcheck(&ft->ftu_dst, fi->fi_ports[1]);
/*
* compare source ports
*/
if (err && ft->ftu_scmp)
- err = fr_portcheck(&ft->ftu_src, &fin->fin_sport);
+ err = ipf_portcheck(&ft->ftu_src, fi->fi_ports[0]);
/*
* If we don't have all the TCP/UDP header, then how can we
@@ -1746,15 +2172,15 @@ frtuc_t *ft;
* TCP flags, then NO match. If not, then match (which should
* satisfy the "short" class too).
*/
- if (err && (fin->fin_p == IPPROTO_TCP)) {
- if (fin->fin_flx & FI_SHORT)
+ if (err && (fi->fi_p == IPPROTO_TCP)) {
+ if (fi->fi_flx & FI_SHORT)
return !(ft->ftu_tcpf | ft->ftu_tcpfm);
/*
* Match the flags ? If not, abort this match.
*/
if (ft->ftu_tcpfm &&
- ft->ftu_tcpf != (fin->fin_tcpf & ft->ftu_tcpfm)) {
- FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf,
+ ft->ftu_tcpf != (fi->fi_tcpf & ft->ftu_tcpfm)) {
+ FR_DEBUG(("f. %#x & %#x != %#x\n", fi->fi_tcpf,
ft->ftu_tcpfm, ft->ftu_tcpf));
err = 0;
}
@@ -1763,10 +2189,9 @@ frtuc_t *ft;
}
-
/* ------------------------------------------------------------------------ */
-/* Function: fr_ipfcheck */
-/* Returns: int - 0 == match, 1 == no match */
+/* Function: ipf_check_ipf */
+/* Returns: int - 0 == match, else no match */
/* Parameters: fin(I) - pointer to packet information */
/* fr(I) - pointer to filter rule */
/* portcmp(I) - flag indicating whether to attempt matching on */
@@ -1776,10 +2201,11 @@ frtuc_t *ft;
/* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */
/* this function. */
/* ------------------------------------------------------------------------ */
-static INLINE int fr_ipfcheck(fin, fr, portcmp)
-fr_info_t *fin;
-frentry_t *fr;
-int portcmp;
+static INLINE int
+ipf_check_ipf(fin, fr, portcmp)
+ fr_info_t *fin;
+ frentry_t *fr;
+ int portcmp;
{
u_32_t *ld, *lm, *lip;
fripf_t *fri;
@@ -1807,10 +2233,10 @@ int portcmp;
* are present (if any) in this packet.
*/
lip++, lm++, ld++;
- i |= ((*lip & *lm) != *ld);
+ i = ((*lip & *lm) != *ld);
FR_DEBUG(("1. %#08x & %#08x != %#08x\n",
ntohl(*lip), ntohl(*lm), ntohl(*ld)));
- if (i)
+ if (i != 0)
return 1;
lip++, lm++, ld++;
@@ -1820,16 +2246,15 @@ int portcmp;
/*
* Check the source address.
*/
-#ifdef IPFILTER_LOOKUP
if (fr->fr_satype == FRI_LOOKUP) {
- i = (*fr->fr_srcfunc)(fr->fr_srcptr, fi->fi_v, lip);
+ i = (*fr->fr_srcfunc)(fin->fin_main_soft, fr->fr_srcptr,
+ fi->fi_v, lip, fin->fin_plen);
if (i == -1)
return 1;
lip += 3;
lm += 3;
ld += 3;
} else {
-#endif
i = ((*lip & *lm) != *ld);
FR_DEBUG(("2a. %#08x & %#08x != %#08x\n",
ntohl(*lip), ntohl(*lm), ntohl(*ld)));
@@ -1851,27 +2276,24 @@ int portcmp;
lm += 3;
ld += 3;
}
-#ifdef IPFILTER_LOOKUP
}
-#endif
i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6;
- if (i)
+ if (i != 0)
return 1;
/*
* Check the destination address.
*/
lip++, lm++, ld++;
-#ifdef IPFILTER_LOOKUP
if (fr->fr_datype == FRI_LOOKUP) {
- i = (*fr->fr_dstfunc)(fr->fr_dstptr, fi->fi_v, lip);
+ i = (*fr->fr_dstfunc)(fin->fin_main_soft, fr->fr_dstptr,
+ fi->fi_v, lip, fin->fin_plen);
if (i == -1)
return 1;
lip += 3;
lm += 3;
ld += 3;
} else {
-#endif
i = ((*lip & *lm) != *ld);
FR_DEBUG(("3a. %#08x & %#08x != %#08x\n",
ntohl(*lip), ntohl(*lm), ntohl(*ld)));
@@ -1893,28 +2315,24 @@ int portcmp;
lm += 3;
ld += 3;
}
-#ifdef IPFILTER_LOOKUP
}
-#endif
i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7;
- if (i)
+ if (i != 0)
return 1;
/*
* IP addresses matched. The next 32bits contains:
* mast of old IP header security & authentication bits.
*/
lip++, lm++, ld++;
- i |= ((*lip & *lm) != *ld);
- FR_DEBUG(("4. %#08x & %#08x != %#08x\n",
- *lip, *lm, *ld));
+ i = (*ld - (*lip & *lm));
+ FR_DEBUG(("4. %#08x & %#08x != %#08x\n", *lip, *lm, *ld));
/*
* Next we have 32 bits of packet flags.
*/
lip++, lm++, ld++;
- i |= ((*lip & *lm) != *ld);
- FR_DEBUG(("5. %#08x & %#08x != %#08x\n",
- *lip, *lm, *ld));
+ i |= (*ld - (*lip & *lm));
+ FR_DEBUG(("5. %#08x & %#08x != %#08x\n", *lip, *lm, *ld));
if (i == 0) {
/*
@@ -1922,7 +2340,7 @@ int portcmp;
* looking for here...
*/
if (portcmp) {
- if (!fr_tcpudpchk(fin, &fr->fr_tuc))
+ if (!ipf_tcpudpchk(&fin->fin_fi, &fr->fr_tuc))
i = 1;
} else {
if (fr->fr_dcmp || fr->fr_scmp ||
@@ -1948,7 +2366,7 @@ int portcmp;
/* ------------------------------------------------------------------------ */
-/* Function: fr_scanlist */
+/* Function: ipf_scanlist */
/* Returns: int - result flags of scanning filter list */
/* Parameters: fin(I) - pointer to packet information */
/* pass(I) - default result to return for filtering */
@@ -1963,10 +2381,12 @@ int portcmp;
/* Could be per interface, but this gets real nasty when you don't have, */
/* or can't easily change, the kernel source code to . */
/* ------------------------------------------------------------------------ */
-int fr_scanlist(fin, pass)
-fr_info_t *fin;
-u_32_t pass;
+int
+ipf_scanlist(fin, pass)
+ fr_info_t *fin;
+ u_32_t pass;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
int rulen, portcmp, off, skip;
struct frentry *fr, *fnext;
u_32_t passt, passo;
@@ -1997,7 +2417,7 @@ u_32_t pass;
for (rulen = 0; fr; fr = fnext, rulen++) {
fnext = fr->fr_next;
if (skip != 0) {
- FR_VERBOSE(("%d (%#x)\n", skip, fr->fr_flags));
+ FR_VERBOSE(("SKIP %d (%#x)\n", skip, fr->fr_flags));
skip--;
continue;
}
@@ -2027,27 +2447,29 @@ u_32_t pass;
switch (fr->fr_type)
{
case FR_T_IPF :
- case FR_T_IPF|FR_T_BUILTIN :
- if (fr_ipfcheck(fin, fr, portcmp))
+ case FR_T_IPF_BUILTIN :
+ if (ipf_check_ipf(fin, fr, portcmp))
continue;
break;
#if defined(IPFILTER_BPF)
case FR_T_BPFOPC :
- case FR_T_BPFOPC|FR_T_BUILTIN :
+ case FR_T_BPFOPC_BUILTIN :
{
u_char *mc;
+ int wlen;
if (*fin->fin_mp == NULL)
continue;
- if (fin->fin_v != fr->fr_v)
+ if (fin->fin_family != fr->fr_family)
continue;
mc = (u_char *)fin->fin_m;
- if (!bpf_filter(fr->fr_data, mc, fin->fin_plen, 0))
+ wlen = fin->fin_dlen + fin->fin_hlen;
+ if (!bpf_filter(fr->fr_data, mc, wlen, 0))
continue;
break;
}
#endif
- case FR_T_CALLFUNC|FR_T_BUILTIN :
+ case FR_T_CALLFUNC_BUILTIN :
{
frentry_t *f;
@@ -2058,6 +2480,15 @@ u_32_t pass;
continue;
break;
}
+
+ case FR_T_IPFEXPR :
+ case FR_T_IPFEXPR_BUILTIN :
+ if (fin->fin_family != fr->fr_family)
+ continue;
+ if (ipf_fr_matcharray(fin, fr->fr_data) == 0)
+ continue;
+ break;
+
default :
break;
}
@@ -2065,23 +2496,14 @@ u_32_t pass;
if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) {
if (fin->fin_nattag == NULL)
continue;
- if (fr_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0)
+ if (ipf_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0)
continue;
}
- FR_VERBOSE(("=%s.%d *", fr->fr_group, rulen));
+ FR_VERBOSE(("=%d/%d.%d *", fr->fr_grhead, fr->fr_group, rulen));
passt = fr->fr_flags;
/*
- * Allowing a rule with the "keep state" flag set to match
- * packets that have been tagged "out of window" by the TCP
- * state tracking is foolish as the attempt to add a new
- * state entry to the table will fail.
- */
- if ((passt & FR_KEEPSTATE) && (fin->fin_flx & FI_OOW))
- continue;
-
- /*
* If the rule is a "call now" rule, then call the function
* in the rule, if it exists and use the results from that.
* If the function pointer is bad, just make like we ignore
@@ -2091,7 +2513,7 @@ u_32_t pass;
frentry_t *frs;
ATOMIC_INC64(fr->fr_hits);
- if ((fr->fr_func != NULL) &&
+ if ((fr->fr_func == NULL) ||
(fr->fr_func == (ipfunc_t)-1))
continue;
@@ -2111,43 +2533,69 @@ u_32_t pass;
* Just log this packet...
*/
if ((passt & FR_LOGMASK) == FR_LOG) {
- if (ipflog(fin, passt) == -1) {
+ if (ipf_log_pkt(fin, passt) == -1) {
if (passt & FR_LOGORBLOCK) {
+ DT(frb_logfail);
passt &= ~FR_CMDMASK;
passt |= FR_BLOCK|FR_QUICK;
+ fin->fin_reason = FRB_LOGFAIL;
}
- ATOMIC_INCL(frstats[fin->fin_out].fr_skip);
}
- ATOMIC_INCL(frstats[fin->fin_out].fr_pkl);
- fin->fin_flx |= FI_DONTCACHE;
}
#endif /* IPFILTER_LOG */
+
+ MUTEX_ENTER(&fr->fr_lock);
fr->fr_bytes += (U_QUAD_T)fin->fin_plen;
+ fr->fr_hits++;
+ MUTEX_EXIT(&fr->fr_lock);
+ fin->fin_rule = rulen;
+
passo = pass;
- if (FR_ISSKIP(passt))
+ if (FR_ISSKIP(passt)) {
skip = fr->fr_arg;
- else if ((passt & FR_LOGMASK) != FR_LOG)
+ continue;
+ } else if (((passt & FR_LOGMASK) != FR_LOG) &&
+ ((passt & FR_LOGMASK) != FR_DECAPSULATE)) {
pass = passt;
+ }
+
if (passt & (FR_RETICMP|FR_FAKEICMP))
fin->fin_icode = fr->fr_icode;
- FR_DEBUG(("pass %#x\n", pass));
- ATOMIC_INC64(fr->fr_hits);
- fin->fin_rule = rulen;
- (void) strncpy(fin->fin_group, fr->fr_group, FR_GROUPLEN);
- if (fr->fr_grp != NULL) {
- fin->fin_fr = *fr->fr_grp;
- passt = fr_scanlist(fin, pass);
+
+ if (fr->fr_group != -1) {
+ (void) strncpy(fin->fin_group,
+ FR_NAME(fr, fr_group),
+ strlen(FR_NAME(fr, fr_group)));
+ } else {
+ fin->fin_group[0] = '\0';
+ }
+
+ FR_DEBUG(("pass %#x/%#x/%x\n", passo, pass, passt));
+
+ if (fr->fr_grphead != NULL) {
+ fin->fin_fr = fr->fr_grphead->fg_start;
+ FR_VERBOSE(("group %s\n", FR_NAME(fr, fr_grhead)));
+
+ if (FR_ISDECAPS(passt))
+ passt = ipf_decaps(fin, pass, fr->fr_icode);
+ else
+ passt = ipf_scanlist(fin, pass);
+
if (fin->fin_fr == NULL) {
fin->fin_rule = rulen;
- (void) strncpy(fin->fin_group, fr->fr_group,
- FR_GROUPLEN);
+ if (fr->fr_group != -1)
+ (void) strncpy(fin->fin_group,
+ fr->fr_names +
+ fr->fr_group,
+ strlen(fr->fr_names +
+ fr->fr_group));
fin->fin_fr = fr;
passt = pass;
}
pass = passt;
}
- if (passt & FR_QUICK) {
+ if (pass & FR_QUICK) {
/*
* Finally, if we've asked to track state for this
* packet, set it up. Add state for "quick" rules
@@ -2155,15 +2603,15 @@ u_32_t pass;
* the rule to "not match" and keep on processing
* filter rules.
*/
- if ((pass & FR_KEEPSTATE) &&
+ if ((pass & FR_KEEPSTATE) && !FR_ISAUTH(pass) &&
!(fin->fin_flx & FI_STATE)) {
int out = fin->fin_out;
fin->fin_fr = fr;
- if (fr_addstate(fin, NULL, 0) != NULL) {
- ATOMIC_INCL(frstats[out].fr_ads);
+ if (ipf_state_add(softc, fin, NULL, 0) == 0) {
+ LBUMPD(ipf_stats[out], fr_ads);
} else {
- ATOMIC_INCL(frstats[out].fr_bads);
+ LBUMPD(ipf_stats[out], fr_bads);
pass = passo;
continue;
}
@@ -2177,7 +2625,7 @@ u_32_t pass;
/* ------------------------------------------------------------------------ */
-/* Function: fr_acctpkt */
+/* Function: ipf_acctpkt */
/* Returns: frentry_t* - always returns NULL */
/* Parameters: fin(I) - pointer to packet information */
/* passp(IO) - pointer to current/new filter decision (unused) */
@@ -2186,32 +2634,29 @@ u_32_t pass;
/* IP protocol version. */
/* */
/* N.B.: this function returns NULL to match the prototype used by other */
-/* functions called from the IPFilter "mainline" in fr_check(). */
+/* functions called from the IPFilter "mainline" in ipf_check(). */
/* ------------------------------------------------------------------------ */
-frentry_t *fr_acctpkt(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+frentry_t *
+ipf_acctpkt(fin, passp)
+ fr_info_t *fin;
+ u_32_t *passp;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
char group[FR_GROUPLEN];
frentry_t *fr, *frsave;
u_32_t pass, rulen;
passp = passp;
-#ifdef USE_INET6
- if (fin->fin_v == 6)
- fr = ipacct6[fin->fin_out][fr_active];
- else
-#endif
- fr = ipacct[fin->fin_out][fr_active];
+ fr = softc->ipf_acct[fin->fin_out][softc->ipf_active];
if (fr != NULL) {
frsave = fin->fin_fr;
bcopy(fin->fin_group, group, FR_GROUPLEN);
rulen = fin->fin_rule;
fin->fin_fr = fr;
- pass = fr_scanlist(fin, FR_NOMATCH);
+ pass = ipf_scanlist(fin, FR_NOMATCH);
if (FR_ISACCOUNT(pass)) {
- ATOMIC_INCL(frstats[0].fr_acct);
+ LBUMPD(ipf_stats[0], fr_acct);
}
fin->fin_fr = frsave;
bcopy(group, fin->fin_group, FR_GROUPLEN);
@@ -2222,7 +2667,7 @@ u_32_t *passp;
/* ------------------------------------------------------------------------ */
-/* Function: fr_firewall */
+/* Function: ipf_firewall */
/* Returns: frentry_t* - returns pointer to matched rule, if no matches */
/* were found, returns NULL. */
/* Parameters: fin(I) - pointer to packet information */
@@ -2234,12 +2679,13 @@ u_32_t *passp;
/* matching rule is found, take any appropriate actions as defined by the */
/* rule - except logging. */
/* ------------------------------------------------------------------------ */
-static frentry_t *fr_firewall(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+static frentry_t *
+ipf_firewall(fin, passp)
+ fr_info_t *fin;
+ u_32_t *passp;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
frentry_t *fr;
- fr_info_t *fc;
u_32_t pass;
int out;
@@ -2247,56 +2693,28 @@ u_32_t *passp;
pass = *passp;
/*
- * If a packet is found in the auth table, then skip checking
- * the access lists for permission but we do need to consider
- * the result as if it were from the ACL's.
+ * This rule cache will only affect packets that are not being
+ * statefully filtered.
*/
- fc = &frcache[out][CACHE_HASH(fin)];
- READ_ENTER(&ipf_frcache);
- if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) {
- /*
- * copy cached data so we can unlock the mutexes earlier.
- */
- bcopy((char *)fc, (char *)fin, FI_COPYSIZE);
- RWLOCK_EXIT(&ipf_frcache);
- ATOMIC_INCL(frstats[out].fr_chit);
-
- if ((fr = fin->fin_fr) != NULL) {
- ATOMIC_INC64(fr->fr_hits);
- pass = fr->fr_flags;
- }
- } else {
- RWLOCK_EXIT(&ipf_frcache);
+ fin->fin_fr = softc->ipf_rules[out][softc->ipf_active];
+ if (fin->fin_fr != NULL)
+ pass = ipf_scanlist(fin, softc->ipf_pass);
-#ifdef USE_INET6
- if (fin->fin_v == 6)
- fin->fin_fr = ipfilter6[out][fr_active];
- else
-#endif
- fin->fin_fr = ipfilter[out][fr_active];
- if (fin->fin_fr != NULL)
- pass = fr_scanlist(fin, fr_pass);
-
- if (((pass & FR_KEEPSTATE) == 0) &&
- ((fin->fin_flx & FI_DONTCACHE) == 0)) {
- WRITE_ENTER(&ipf_frcache);
- bcopy((char *)fin, (char *)fc, FI_COPYSIZE);
- RWLOCK_EXIT(&ipf_frcache);
- }
- if ((pass & FR_NOMATCH)) {
- ATOMIC_INCL(frstats[out].fr_nom);
- }
- fr = fin->fin_fr;
+ if ((pass & FR_NOMATCH)) {
+ LBUMPD(ipf_stats[out], fr_nom);
}
+ fr = fin->fin_fr;
/*
* Apply packets per second rate-limiting to a rule as required.
*/
if ((fr != NULL) && (fr->fr_pps != 0) &&
!ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) {
- pass &= ~(FR_CMDMASK|FR_DUP|FR_RETICMP|FR_RETRST);
+ DT2(frb_ppsrate, fr_info_t *, fin, frentry_t *, fr);
+ pass &= ~(FR_CMDMASK|FR_RETICMP|FR_RETRST);
pass |= FR_BLOCK;
- ATOMIC_INCL(frstats[out].fr_ppshit);
+ LBUMPD(ipf_stats[out], fr_ppshit);
+ fin->fin_reason = FRB_PPSRATE;
}
/*
@@ -2305,15 +2723,15 @@ u_32_t *passp;
* we've dropped it already.
*/
if (FR_ISAUTH(pass)) {
- if (fr_newauth(fin->fin_m, fin) != 0) {
-#ifdef _KERNEL
+ if (ipf_auth_new(fin->fin_m, fin) != 0) {
+ DT1(frb_authnew, fr_info_t *, fin);
fin->fin_m = *fin->fin_mp = NULL;
-#else
- ;
-#endif
+ fin->fin_reason = FRB_AUTHNEW;
fin->fin_error = 0;
- } else
+ } else {
+ IPFERROR(1);
fin->fin_error = ENOSPC;
+ }
}
if ((fr != NULL) && (fr->fr_func != NULL) &&
@@ -2327,8 +2745,7 @@ u_32_t *passp;
* is treated as "not a pass", hence the packet is blocked.
*/
if (FR_ISPREAUTH(pass)) {
- if ((fin->fin_fr = ipauth) != NULL)
- pass = fr_scanlist(fin, fr_pass);
+ pass = ipf_auth_pre_scanlist(softc, fin, pass);
}
/*
@@ -2337,27 +2754,25 @@ u_32_t *passp;
*/
if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) {
if (fin->fin_flx & FI_FRAG) {
- if (fr_newfrag(fin, pass) == -1) {
- ATOMIC_INCL(frstats[out].fr_bnfr);
+ if (ipf_frag_new(softc, fin, pass) == -1) {
+ LBUMP(ipf_stats[out].fr_bnfr);
} else {
- ATOMIC_INCL(frstats[out].fr_nfr);
+ LBUMP(ipf_stats[out].fr_nfr);
}
} else {
- ATOMIC_INCL(frstats[out].fr_cfr);
+ LBUMP(ipf_stats[out].fr_cfr);
}
}
fr = fin->fin_fr;
-
- if (passp != NULL)
- *passp = pass;
+ *passp = pass;
return fr;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_check */
+/* Function: ipf_check */
/* Returns: int - 0 == packet allowed through, */
/* User space: */
/* -1 == packet blocked */
@@ -2375,7 +2790,7 @@ u_32_t *passp;
/* qpi(I) - pointer to STREAMS queue information for this */
/* interface & direction. */
/* */
-/* fr_check() is the master function for all IPFilter packet processing. */
+/* ipf_check() is the master function for all IPFilter packet processing. */
/* It orchestrates: Network Address Translation (NAT), checking for packet */
/* authorisation (or pre-authorisation), presence of related state info., */
/* generating log entries, IP packet accounting, routing of packets as */
@@ -2386,31 +2801,34 @@ u_32_t *passp;
/* freed. Packets passed may be returned with the pointer pointed to by */
/* by "mp" changed to a new buffer. */
/* ------------------------------------------------------------------------ */
-int fr_check(ip, hlen, ifp, out
+int
+ipf_check(ctx, ip, hlen, ifp, out
#if defined(_KERNEL) && defined(MENTAT)
-, qif, mp)
-void *qif;
+ , qif, mp)
+ void *qif;
#else
-, mp)
+ , mp)
#endif
-mb_t **mp;
-ip_t *ip;
-int hlen;
-void *ifp;
-int out;
+ mb_t **mp;
+ ip_t *ip;
+ int hlen;
+ void *ifp;
+ int out;
+ void *ctx;
{
/*
* The above really sucks, but short of writing a diff
*/
+ ipf_main_softc_t *softc = ctx;
fr_info_t frinfo;
fr_info_t *fin = &frinfo;
- u_32_t pass = fr_pass;
+ u_32_t pass = softc->ipf_pass;
frentry_t *fr = NULL;
int v = IP_V(ip);
mb_t *mc = NULL;
mb_t *m;
/*
- * The first part of fr_check() deals with making sure that what goes
+ * The first part of ipf_check() deals with making sure that what goes
* into the filtering engine makes some sense. Information about the
* the packet is distilled, collected into a fr_info_t structure and
* the an attempt to ensure the buffer the packet is in is big enough
@@ -2420,7 +2838,7 @@ int out;
# ifdef MENTAT
qpktinfo_t *qpi = qif;
-# if !defined(_INET_IP_STACK_H)
+# ifdef __sparc
if ((u_int)ip & 0x3)
return 2;
# endif
@@ -2428,18 +2846,17 @@ int out;
SPL_INT(s);
# endif
- READ_ENTER(&ipf_global);
-
- if (fr_running <= 0) {
- RWLOCK_EXIT(&ipf_global);
+ if (softc->ipf_running <= 0) {
return 0;
}
bzero((char *)fin, sizeof(*fin));
# ifdef MENTAT
- if (qpi->qpi_flags & QF_GROUP)
- fin->fin_flx |= FI_MBCAST;
+ if (qpi->qpi_flags & QF_BROADCAST)
+ fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
+ if (qpi->qpi_flags & QF_MULTICAST)
+ fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
m = qpi->qpi_m;
fin->fin_qfm = m;
fin->fin_qpi = qpi;
@@ -2467,7 +2884,8 @@ int out;
*/
m->m_flags &= ~M_CANFASTFWD;
# endif /* M_CANFASTFWD */
-# ifdef CSUM_DELAY_DATA
+# if defined(CSUM_DELAY_DATA) && (!defined(__FreeBSD_version) || \
+ (__FreeBSD_version < 501108))
/*
* disable delayed checksums.
*/
@@ -2478,10 +2896,20 @@ int out;
# endif /* CSUM_DELAY_DATA */
# endif /* MENTAT */
#else
- READ_ENTER(&ipf_global);
-
bzero((char *)fin, sizeof(*fin));
m = *mp;
+# if defined(M_MCAST)
+ if ((m->m_flags & M_MCAST) != 0)
+ fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
+# endif
+# if defined(M_MLOOP)
+ if ((m->m_flags & M_MLOOP) != 0)
+ fin->fin_flx |= FI_MBCAST|FI_MULTICAST;
+# endif
+# if defined(M_BCAST)
+ if ((m->m_flags & M_BCAST) != 0)
+ fin->fin_flx |= FI_MBCAST|FI_BROADCAST;
+# endif
#endif /* _KERNEL */
fin->fin_v = v;
@@ -2493,6 +2921,7 @@ int out;
fin->fin_error = ENETUNREACH;
fin->fin_hlen = (u_short)hlen;
fin->fin_dp = (char *)ip + hlen;
+ fin->fin_main_soft = softc;
fin->fin_ipoff = (char *)ip - MTOD(m, char *);
@@ -2500,27 +2929,29 @@ int out;
#ifdef USE_INET6
if (v == 6) {
- ATOMIC_INCL(frstats[out].fr_ipv6);
+ LBUMP(ipf_stats[out].fr_ipv6);
/*
* Jumbo grams are quite likely too big for internal buffer
* structures to handle comfortably, for now, so just drop
* them.
*/
if (((ip6_t *)ip)->ip6_plen == 0) {
+ DT1(frb_jumbo, ip6_t *, (ip6_t *)ip);
pass = FR_BLOCK|FR_NOMATCH;
+ fin->fin_reason = FRB_JUMBO;
goto finished;
}
+ fin->fin_family = AF_INET6;
} else
#endif
{
-#if ((defined(OpenBSD) && (OpenBSD >= 200311)) || (__FreeBSD_version >= 1000019)) && defined(_KERNEL)
- ip->ip_len = ntohs(ip->ip_len);
- ip->ip_off = ntohs(ip->ip_off);
-#endif
+ fin->fin_family = AF_INET;
}
- if (fr_makefrip(hlen, ip, fin) == -1) {
+ if (ipf_makefrip(hlen, ip, fin) == -1) {
+ DT1(frb_makefrip, fr_info_t *, fin);
pass = FR_BLOCK|FR_NOMATCH;
+ fin->fin_reason = FRB_MAKEFRIP;
goto finished;
}
@@ -2533,21 +2964,19 @@ int out;
if (!out) {
if (v == 4) {
-#ifdef _KERNEL
- if (fr_chksrc && !fr_verifysrc(fin)) {
- ATOMIC_INCL(frstats[0].fr_badsrc);
+ if (softc->ipf_chksrc && !ipf_verifysrc(fin)) {
+ LBUMPD(ipf_stats[0], fr_v4_badsrc);
fin->fin_flx |= FI_BADSRC;
}
-#endif
- if (fin->fin_ip->ip_ttl < fr_minttl) {
- ATOMIC_INCL(frstats[0].fr_badttl);
+ if (fin->fin_ip->ip_ttl < softc->ipf_minttl) {
+ LBUMPD(ipf_stats[0], fr_v4_badttl);
fin->fin_flx |= FI_LOWTTL;
}
}
#ifdef USE_INET6
else if (v == 6) {
- if (((ip6_t *)ip)->ip6_hlim < fr_minttl) {
- ATOMIC_INCL(frstats[0].fr_badttl);
+ if (((ip6_t *)ip)->ip6_hlim < softc->ipf_minttl) {
+ LBUMPD(ipf_stats[0], fr_v6_badttl);
fin->fin_flx |= FI_LOWTTL;
}
}
@@ -2555,120 +2984,135 @@ int out;
}
if (fin->fin_flx & FI_SHORT) {
- ATOMIC_INCL(frstats[out].fr_short);
+ LBUMPD(ipf_stats[out], fr_short);
}
- READ_ENTER(&ipf_mutex);
+ READ_ENTER(&softc->ipf_mutex);
- /*
- * Check auth now. This, combined with the check below to see if apass
- * is 0 is to ensure that we don't count the packet twice, which can
- * otherwise occur when we reprocess it. As it is, we only count it
- * after it has no auth. table matchup. This also stops NAT from
- * occuring until after the packet has been auth'd.
- */
- fr = fr_checkauth(fin, &pass);
if (!out) {
- if (fr_checknatin(fin, &pass) == -1) {
- goto filterdone;
+ switch (fin->fin_v)
+ {
+ case 4 :
+ if (ipf_nat_checkin(fin, &pass) == -1) {
+ goto filterdone;
+ }
+ break;
+#ifdef USE_INET6
+ case 6 :
+ if (ipf_nat6_checkin(fin, &pass) == -1) {
+ goto filterdone;
+ }
+ break;
+#endif
+ default :
+ break;
}
}
- if (!out)
- (void) fr_acctpkt(fin, NULL);
+ /*
+ * Check auth now.
+ * If a packet is found in the auth table, then skip checking
+ * the access lists for permission but we do need to consider
+ * the result as if it were from the ACL's. In addition, being
+ * found in the auth table means it has been seen before, so do
+ * not pass it through accounting (again), lest it be counted twice.
+ */
+ fr = ipf_auth_check(fin, &pass);
+ if (!out && (fr == NULL))
+ (void) ipf_acctpkt(fin, NULL);
if (fr == NULL) {
- if ((fin->fin_flx & (FI_FRAG|FI_BAD)) == FI_FRAG) {
- fr = fr_knownfrag(fin, &pass);
- /*
- * Reset the keep state flag here so that we don't
- * try and add a new state entry because of it, leading
- * to a blocked packet because the add will fail.
- */
- if (fr != NULL)
- pass &= ~FR_KEEPSTATE;
- }
+ if ((fin->fin_flx & FI_FRAG) != 0)
+ fr = ipf_frag_known(fin, &pass);
+
if (fr == NULL)
- fr = fr_checkstate(fin, &pass);
+ fr = ipf_state_check(fin, &pass);
}
if ((pass & FR_NOMATCH) || (fr == NULL))
- fr = fr_firewall(fin, &pass);
+ fr = ipf_firewall(fin, &pass);
/*
* If we've asked to track state for this packet, set it up.
- * Here rather than fr_firewall because fr_checkauth may decide
+ * Here rather than ipf_firewall because ipf_checkauth may decide
* to return a packet for "keep state"
*/
if ((pass & FR_KEEPSTATE) && (fin->fin_m != NULL) &&
!(fin->fin_flx & FI_STATE)) {
- if (fr_addstate(fin, NULL, 0) != NULL) {
- ATOMIC_INCL(frstats[out].fr_ads);
+ if (ipf_state_add(softc, fin, NULL, 0) == 0) {
+ LBUMP(ipf_stats[out].fr_ads);
} else {
- ATOMIC_INCL(frstats[out].fr_bads);
+ LBUMP(ipf_stats[out].fr_bads);
if (FR_ISPASS(pass)) {
+ DT(frb_stateadd);
pass &= ~FR_CMDMASK;
pass |= FR_BLOCK;
+ fin->fin_reason = FRB_STATEADD;
}
}
}
fin->fin_fr = fr;
+ if ((fr != NULL) && !(fin->fin_flx & FI_STATE)) {
+ fin->fin_dif = &fr->fr_dif;
+ fin->fin_tif = &fr->fr_tifs[fin->fin_rev];
+ }
/*
* Only count/translate packets which will be passed on, out the
* interface.
*/
if (out && FR_ISPASS(pass)) {
- (void) fr_acctpkt(fin, NULL);
+ (void) ipf_acctpkt(fin, NULL);
- if (fr_checknatout(fin, &pass) == -1) {
- ;
- } else if ((fr_update_ipid != 0) && (v == 4)) {
- if (fr_updateipid(fin) == -1) {
- ATOMIC_INCL(frstats[1].fr_ipud);
- pass &= ~FR_CMDMASK;
- pass |= FR_BLOCK;
- } else {
- ATOMIC_INCL(frstats[0].fr_ipud);
+ switch (fin->fin_v)
+ {
+ case 4 :
+ if (ipf_nat_checkout(fin, &pass) == -1) {
+ ;
+ } else if ((softc->ipf_update_ipid != 0) && (v == 4)) {
+ if (ipf_updateipid(fin) == -1) {
+ DT(frb_updateipid);
+ LBUMP(ipf_stats[1].fr_ipud);
+ pass &= ~FR_CMDMASK;
+ pass |= FR_BLOCK;
+ fin->fin_reason = FRB_UPDATEIPID;
+ } else {
+ LBUMP(ipf_stats[0].fr_ipud);
+ }
}
+ break;
+#ifdef USE_INET6
+ case 6 :
+ (void) ipf_nat6_checkout(fin, &pass);
+ break;
+#endif
+ default :
+ break;
}
}
filterdone:
#ifdef IPFILTER_LOG
- if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
- (void) fr_dolog(fin, &pass);
+ if ((softc->ipf_flags & FF_LOGGING) || (pass & FR_LOGMASK)) {
+ (void) ipf_dolog(fin, &pass);
}
#endif
/*
- * The FI_STATE flag is cleared here so that calling fr_checkstate
+ * The FI_STATE flag is cleared here so that calling ipf_state_check
* will work when called from inside of fr_fastroute. Although
* there is a similar flag, FI_NATED, for NAT, it does have the same
* impact on code execution.
*/
- if (fin->fin_state != NULL) {
- fr_statederef((ipstate_t **)&fin->fin_state);
- fin->fin_flx ^= FI_STATE;
- }
-
- if (fin->fin_nat != NULL) {
- if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT)) {
- WRITE_ENTER(&ipf_nat);
- nat_delete((nat_t *)fin->fin_nat, NL_DESTROY);
- RWLOCK_EXIT(&ipf_nat);
- fin->fin_nat = NULL;
- } else {
- fr_natderef((nat_t **)&fin->fin_nat);
- }
- }
+ fin->fin_flx &= ~FI_STATE;
+#if defined(FASTROUTE_RECURSION)
/*
- * Up the reference on fr_lock and exit ipf_mutex. fr_fastroute
- * only frees up the lock on ipf_global and the generation of a
- * packet below could cause a recursive call into IPFilter.
- * Hang onto the filter rule just in case someone decides to remove
- * or flush it in the meantime.
+ * Up the reference on fr_lock and exit ipf_mutex. The generation of
+ * a packet below can sometimes cause a recursive call into IPFilter.
+ * On those platforms where that does happen, we need to hang onto
+ * the filter rule just in case someone decides to remove or flush it
+ * in the meantime.
*/
if (fr != NULL) {
MUTEX_ENTER(&fr->fr_lock);
@@ -2676,16 +3120,17 @@ filterdone:
MUTEX_EXIT(&fr->fr_lock);
}
- RWLOCK_EXIT(&ipf_mutex);
+ RWLOCK_EXIT(&softc->ipf_mutex);
+#endif
if ((pass & FR_RETMASK) != 0) {
/*
* Should we return an ICMP packet to indicate error
* status passing through the packet filter ?
* WARNING: ICMP error packets AND TCP RST packets should
- * ONLY be sent in repsonse to incoming packets. Sending them
- * in response to outbound packets can result in a panic on
- * some operating systems.
+ * ONLY be sent in repsonse to incoming packets. Sending
+ * them in response to outbound packets can result in a
+ * panic on some operating systems.
*/
if (!out) {
if (pass & FR_RETICMP) {
@@ -2695,13 +3140,14 @@ filterdone:
dst = 1;
else
dst = 0;
- (void) fr_send_icmp_err(ICMP_UNREACH, fin, dst);
- ATOMIC_INCL(frstats[0].fr_ret);
+ (void) ipf_send_icmp_err(ICMP_UNREACH, fin,
+ dst);
+ LBUMP(ipf_stats[0].fr_ret);
} else if (((pass & FR_RETMASK) == FR_RETRST) &&
!(fin->fin_flx & FI_SHORT)) {
if (((fin->fin_flx & FI_OOW) != 0) ||
- (fr_send_reset(fin) == 0)) {
- ATOMIC_INCL(frstats[1].fr_ret);
+ (ipf_send_reset(fin) == 0)) {
+ LBUMP(ipf_stats[1].fr_ret);
}
}
@@ -2710,61 +3156,81 @@ filterdone:
* takes over disposing of this packet.
*/
if (FR_ISAUTH(pass) && (fin->fin_m != NULL)) {
+ DT1(frb_authcapture, fr_info_t *, fin);
fin->fin_m = *fin->fin_mp = NULL;
+ fin->fin_reason = FRB_AUTHCAPTURE;
+ m = NULL;
}
} else {
- if (pass & FR_RETRST)
+ if (pass & FR_RETRST) {
fin->fin_error = ECONNRESET;
+ }
}
}
/*
+ * After the above so that ICMP unreachables and TCP RSTs get
+ * created properly.
+ */
+ if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT))
+ ipf_nat_uncreate(fin);
+
+ /*
* If we didn't drop off the bottom of the list of rules (and thus
* the 'current' rule fr is not NULL), then we may have some extra
* instructions about what to do with a packet.
* Once we're finished return to our caller, freeing the packet if
- * we are dropping it (* BSD ONLY *).
+ * we are dropping it.
*/
if (fr != NULL) {
frdest_t *fdp;
- fdp = &fr->fr_tifs[fin->fin_rev];
+ /*
+ * Generate a duplicated packet first because ipf_fastroute
+ * can lead to fin_m being free'd... not good.
+ */
+ fdp = fin->fin_dif;
+ if ((fdp != NULL) && (fdp->fd_ptr != NULL) &&
+ (fdp->fd_ptr != (void *)-1)) {
+ mc = M_COPY(fin->fin_m);
+ if (mc != NULL)
+ ipf_fastroute(mc, &mc, fin, fdp);
+ }
+ fdp = fin->fin_tif;
if (!out && (pass & FR_FASTROUTE)) {
/*
- * For fastroute rule, no destioation interface defined
+ * For fastroute rule, no destination interface defined
* so pass NULL as the frdest_t parameter
*/
- (void) fr_fastroute(fin->fin_m, mp, fin, NULL);
+ (void) ipf_fastroute(fin->fin_m, mp, fin, NULL);
m = *mp = NULL;
- } else if ((fdp->fd_ifp != NULL) &&
- (fdp->fd_ifp != (struct ifnet *)-1)) {
+ } else if ((fdp != NULL) && (fdp->fd_ptr != NULL) &&
+ (fdp->fd_ptr != (struct ifnet *)-1)) {
/* this is for to rules: */
- (void) fr_fastroute(fin->fin_m, mp, fin, fdp);
+ ipf_fastroute(fin->fin_m, mp, fin, fdp);
m = *mp = NULL;
}
- /*
- * Generate a duplicated packet.
- */
- if ((pass & FR_DUP) != 0) {
- mc = M_DUPLICATE(fin->fin_m);
- if (mc != NULL)
- (void) fr_fastroute(mc, &mc, fin, &fr->fr_dif);
- }
-
- (void) fr_derefrule(&fr);
+#if defined(FASTROUTE_RECURSION)
+ (void) ipf_derefrule(softc, &fr);
+#endif
}
+#if !defined(FASTROUTE_RECURSION)
+ RWLOCK_EXIT(&softc->ipf_mutex);
+#endif
finished:
if (!FR_ISPASS(pass)) {
- ATOMIC_INCL(frstats[out].fr_block);
+ LBUMP(ipf_stats[out].fr_block);
if (*mp != NULL) {
+#ifdef _KERNEL
FREE_MB_T(*mp);
+#endif
m = *mp = NULL;
}
} else {
- ATOMIC_INCL(frstats[out].fr_pass);
+ LBUMP(ipf_stats[out].fr_pass);
#if defined(_KERNEL) && defined(__sgi)
if ((fin->fin_hbuf != NULL) &&
(mtod(fin->fin_m, struct ip *) != fin->fin_ip)) {
@@ -2774,21 +3240,20 @@ finished:
}
SPL_X(s);
- RWLOCK_EXIT(&ipf_global);
#ifdef _KERNEL
-# if (defined(OpenBSD) && (OpenBSD >= 200311)) || (__FreeBSD_version >= 1000019)
- if (FR_ISPASS(pass) && (v == 4)) {
- ip = fin->fin_ip;
- ip->ip_len = ntohs(ip->ip_len);
- ip->ip_off = ntohs(ip->ip_off);
- }
-# endif
- return (FR_ISPASS(pass)) ? 0 : fin->fin_error;
+ if (FR_ISPASS(pass))
+ return 0;
+ LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]);
+ return fin->fin_error;
#else /* _KERNEL */
+ if (*mp != NULL)
+ (*mp)->mb_ifp = fin->fin_ifp;
+ blockreason = fin->fin_reason;
FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass));
- if ((pass & FR_NOMATCH) != 0)
- return 1;
+ /*if ((pass & FR_CMDMASK) == (softc->ipf_pass & FR_CMDMASK))*/
+ if ((pass & FR_NOMATCH) != 0)
+ return 1;
if ((pass & FR_RETMASK) != 0)
switch (pass & FR_RETMASK)
@@ -2821,7 +3286,7 @@ finished:
#ifdef IPFILTER_LOG
/* ------------------------------------------------------------------------ */
-/* Function: fr_dolog */
+/* Function: ipf_dolog */
/* Returns: frentry_t* - returns contents of fin_fr (no change made) */
/* Parameters: fin(I) - pointer to packet information */
/* passp(IO) - pointer to current/new filter decision (unused) */
@@ -2829,43 +3294,47 @@ finished:
/* Checks flags set to see how a packet should be logged, if it is to be */
/* logged. Adjust statistics based on its success or not. */
/* ------------------------------------------------------------------------ */
-frentry_t *fr_dolog(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+frentry_t *
+ipf_dolog(fin, passp)
+ fr_info_t *fin;
+ u_32_t *passp;
{
+ ipf_main_softc_t *softc = fin->fin_main_soft;
u_32_t pass;
int out;
out = fin->fin_out;
pass = *passp;
- if ((fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
+ if ((softc->ipf_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) {
pass |= FF_LOGNOMATCH;
- ATOMIC_INCL(frstats[out].fr_npkl);
+ LBUMPD(ipf_stats[out], fr_npkl);
goto logit;
+
} else if (((pass & FR_LOGMASK) == FR_LOGP) ||
- (FR_ISPASS(pass) && (fr_flags & FF_LOGPASS))) {
+ (FR_ISPASS(pass) && (softc->ipf_flags & FF_LOGPASS))) {
if ((pass & FR_LOGMASK) != FR_LOGP)
pass |= FF_LOGPASS;
- ATOMIC_INCL(frstats[out].fr_ppkl);
+ LBUMPD(ipf_stats[out], fr_ppkl);
goto logit;
+
} else if (((pass & FR_LOGMASK) == FR_LOGB) ||
- (FR_ISBLOCK(pass) && (fr_flags & FF_LOGBLOCK))) {
+ (FR_ISBLOCK(pass) && (softc->ipf_flags & FF_LOGBLOCK))) {
if ((pass & FR_LOGMASK) != FR_LOGB)
pass |= FF_LOGBLOCK;
- ATOMIC_INCL(frstats[out].fr_bpkl);
-logit:
- if (ipflog(fin, pass) == -1) {
- ATOMIC_INCL(frstats[out].fr_skip);
+ LBUMPD(ipf_stats[out], fr_bpkl);
+logit:
+ if (ipf_log_pkt(fin, pass) == -1) {
/*
* If the "or-block" option has been used then
* block the packet if we failed to log it.
*/
- if ((pass & FR_LOGORBLOCK) &&
- FR_ISPASS(pass)) {
+ if ((pass & FR_LOGORBLOCK) && FR_ISPASS(pass)) {
+ DT1(frb_logfail2, u_int, pass);
pass &= ~FR_CMDMASK;
pass |= FR_BLOCK;
+ fin->fin_reason = FRB_LOGFAIL2;
}
}
*passp = pass;
@@ -2886,9 +3355,10 @@ logit:
/* */
/* N.B.: addr should be 16bit aligned. */
/* ------------------------------------------------------------------------ */
-u_short ipf_cksum(addr, len)
-u_short *addr;
-int len;
+u_short
+ipf_cksum(addr, len)
+ u_short *addr;
+ int len;
{
u_32_t sum = 0;
@@ -2911,11 +3381,10 @@ int len;
/* ------------------------------------------------------------------------ */
/* Function: fr_cksum */
/* Returns: u_short - layer 4 checksum */
-/* Parameters: m(I ) - pointer to buffer holding packet */
+/* Parameters: fin(I) - pointer to packet information */
/* ip(I) - pointer to IP header */
/* l4proto(I) - protocol to caclulate checksum for */
/* l4hdr(I) - pointer to layer 4 header */
-/* l3len(I) - length of layer 4 data plus layer 3 header */
/* */
/* Calculates the TCP checksum for the packet held in "m", using the data */
/* in the IP header "ip" to seed it. */
@@ -2924,31 +3393,31 @@ int len;
/* and the TCP header. We also assume that data blocks aren't allocated in */
/* odd sizes. */
/* */
-/* For IPv6, l3len excludes extension header size. */
-/* */
-/* Expects ip_len to be in host byte order when called. */
+/* Expects ip_len and ip_off to be in network byte order when called. */
/* ------------------------------------------------------------------------ */
-u_short fr_cksum(m, ip, l4proto, l4hdr, l3len)
-mb_t *m;
-ip_t *ip;
-int l4proto, l3len;
-void *l4hdr;
+u_short
+fr_cksum(fin, ip, l4proto, l4hdr)
+ fr_info_t *fin;
+ ip_t *ip;
+ int l4proto;
+ void *l4hdr;
{
- u_short *sp, slen, sumsave, l4hlen, *csump;
+ u_short *sp, slen, sumsave, *csump;
u_int sum, sum2;
int hlen;
+ int off;
#ifdef USE_INET6
ip6_t *ip6;
#endif
csump = NULL;
sumsave = 0;
- l4hlen = 0;
sp = NULL;
slen = 0;
hlen = 0;
sum = 0;
+ sum = htons((u_short)l4proto);
/*
* Add up IP Header portion
*/
@@ -2956,9 +3425,7 @@ void *l4hdr;
if (IP_V(ip) == 4) {
#endif
hlen = IP_HL(ip) << 2;
- slen = l3len - hlen;
- sum = htons((u_short)l4proto);
- sum += htons(slen);
+ off = hlen;
sp = (u_short *)&ip->ip_src;
sum += *sp++; /* ip_src */
sum += *sp++;
@@ -2968,9 +3435,7 @@ void *l4hdr;
} else if (IP_V(ip) == 6) {
ip6 = (ip6_t *)ip;
hlen = sizeof(*ip6);
- slen = l3len - hlen;
- sum = htons((u_short)l4proto);
- sum += htons(slen);
+ off = ((char *)fin->fin_dp - (char *)fin->fin_ip);
sp = (u_short *)&ip6->ip6_src;
sum += *sp++; /* ip6_src */
sum += *sp++;
@@ -2980,6 +3445,7 @@ void *l4hdr;
sum += *sp++;
sum += *sp++;
sum += *sp++;
+ /* This needs to be routing header aware. */
sum += *sp++; /* ip6_dst */
sum += *sp++;
sum += *sp++;
@@ -2988,25 +3454,31 @@ void *l4hdr;
sum += *sp++;
sum += *sp++;
sum += *sp++;
+ } else {
+ return 0xffff;
}
#endif
+ slen = fin->fin_plen - off;
+ sum += htons(slen);
switch (l4proto)
{
case IPPROTO_UDP :
csump = &((udphdr_t *)l4hdr)->uh_sum;
- l4hlen = sizeof(udphdr_t);
break;
case IPPROTO_TCP :
csump = &((tcphdr_t *)l4hdr)->th_sum;
- l4hlen = sizeof(tcphdr_t);
break;
case IPPROTO_ICMP :
csump = &((icmphdr_t *)l4hdr)->icmp_cksum;
- l4hlen = 4;
- sum = 0;
+ sum = 0; /* Pseudo-checksum is not included */
+ break;
+#ifdef USE_INET6
+ case IPPROTO_ICMPV6 :
+ csump = &((struct icmp6_hdr *)l4hdr)->icmp6_cksum;
break;
+#endif
default :
break;
}
@@ -3016,298 +3488,18 @@ void *l4hdr;
*csump = 0;
}
- l4hlen = l4hlen; /* LINT */
-
-#ifdef _KERNEL
-# ifdef MENTAT
- {
- void *rp = m->b_rptr;
-
- if ((unsigned char *)ip > m->b_rptr && (unsigned char *)ip < m->b_wptr)
- m->b_rptr = (u_char *)ip;
- sum2 = ip_cksum(m, hlen, sum); /* hlen == offset */
- m->b_rptr = rp;
- sum2 = (u_short)(~sum2 & 0xffff);
- }
-# else /* MENTAT */
-# if defined(BSD) || defined(sun)
-# if BSD >= 199103
- m->m_data += hlen;
-# else
- m->m_off += hlen;
-# endif
- m->m_len -= hlen;
- sum2 = in_cksum(m, slen);
- m->m_len += hlen;
-# if BSD >= 199103
- m->m_data -= hlen;
-# else
- m->m_off -= hlen;
-# endif
- /*
- * Both sum and sum2 are partial sums, so combine them together.
- */
- sum += ~sum2 & 0xffff;
- while (sum > 0xffff)
- sum = (sum & 0xffff) + (sum >> 16);
- sum2 = ~sum & 0xffff;
-# else /* defined(BSD) || defined(sun) */
-{
- union {
- u_char c[2];
- u_short s;
- } bytes;
- u_short len = ip->ip_len;
-# if defined(__sgi)
- int add;
-# endif
-
- /*
- * Add up IP Header portion
- */
- if (sp != (u_short *)l4hdr)
- sp = (u_short *)l4hdr;
-
- switch (l4proto)
- {
- case IPPROTO_UDP :
- sum += *sp++; /* sport */
- sum += *sp++; /* dport */
- sum += *sp++; /* udp length */
- sum += *sp++; /* checksum */
- break;
-
- case IPPROTO_TCP :
- sum += *sp++; /* sport */
- sum += *sp++; /* dport */
- sum += *sp++; /* seq */
- sum += *sp++;
- sum += *sp++; /* ack */
- sum += *sp++;
- sum += *sp++; /* off */
- sum += *sp++; /* win */
- sum += *sp++; /* checksum */
- sum += *sp++; /* urp */
- break;
- case IPPROTO_ICMP :
- sum = *sp++; /* type/code */
- sum += *sp++; /* checksum */
- break;
- }
-
-# ifdef __sgi
- /*
- * In case we had to copy the IP & TCP header out of mbufs,
- * skip over the mbuf bits which are the header
- */
- if ((char *)ip != mtod(m, char *)) {
- hlen = (char *)sp - (char *)ip;
- while (hlen) {
- add = MIN(hlen, m->m_len);
- sp = (u_short *)(mtod(m, caddr_t) + add);
- hlen -= add;
- if (add == m->m_len) {
- m = m->m_next;
- if (!hlen) {
- if (!m)
- break;
- sp = mtod(m, u_short *);
- }
- PANIC((!m),("fr_cksum(1): not enough data"));
- }
- }
- }
-# endif
-
- len -= (l4hlen + hlen);
- if (len <= 0)
- goto nodata;
-
- while (len > 1) {
- if (((char *)sp - mtod(m, char *)) >= m->m_len) {
- m = m->m_next;
- PANIC((!m),("fr_cksum(2): not enough data"));
- sp = mtod(m, u_short *);
- }
- if (((char *)(sp + 1) - mtod(m, char *)) > m->m_len) {
- bytes.c[0] = *(u_char *)sp;
- m = m->m_next;
- PANIC((!m),("fr_cksum(3): not enough data"));
- sp = mtod(m, u_short *);
- bytes.c[1] = *(u_char *)sp;
- sum += bytes.s;
- sp = (u_short *)((u_char *)sp + 1);
- }
- if ((u_long)sp & 1) {
- bcopy((char *)sp++, (char *)&bytes.s, sizeof(bytes.s));
- sum += bytes.s;
- } else
- sum += *sp++;
- len -= 2;
- }
-
- if (len != 0)
- sum += ntohs(*(u_char *)sp << 8);
-nodata:
- while (sum > 0xffff)
- sum = (sum & 0xffff) + (sum >> 16);
- sum2 = (u_short)(~sum & 0xffff);
-}
-# endif /* defined(BSD) || defined(sun) */
-# endif /* MENTAT */
-#else /* _KERNEL */
- /*
- * Add up IP Header portion
- */
- if (sp != (u_short *)l4hdr)
- sp = (u_short *)l4hdr;
-
- for (; slen > 1; slen -= 2)
- sum += *sp++;
- if (slen)
- sum += ntohs(*(u_char *)sp << 8);
- while (sum > 0xffff)
- sum = (sum & 0xffff) + (sum >> 16);
- sum2 = (u_short)(~sum & 0xffff);
-#endif /* _KERNEL */
+ sum2 = ipf_pcksum(fin, off, sum);
if (csump != NULL)
*csump = sumsave;
return sum2;
}
-#if defined(_KERNEL) && ( ((BSD < 199103) && !defined(MENTAT)) || \
- defined(__sgi) ) && !defined(linux) && !defined(_AIX51)
-/*
- * Copyright (c) 1982, 1986, 1988, 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
- * $Id: fil.c,v 2.243.2.125 2007/10/10 09:27:20 darrenr Exp $
- */
-/*
- * Copy data from an mbuf chain starting "off" bytes from the beginning,
- * continuing for "len" bytes, into the indicated buffer.
- */
-void
-m_copydata(m, off, len, cp)
- mb_t *m;
- int off;
- int len;
- caddr_t cp;
-{
- unsigned count;
-
- if (off < 0 || len < 0)
- panic("m_copydata");
- while (off > 0) {
- if (m == 0)
- panic("m_copydata");
- if (off < m->m_len)
- break;
- off -= m->m_len;
- m = m->m_next;
- }
- while (len > 0) {
- if (m == 0)
- panic("m_copydata");
- count = MIN(m->m_len - off, len);
- bcopy(mtod(m, caddr_t) + off, cp, count);
- len -= count;
- cp += count;
- off = 0;
- m = m->m_next;
- }
-}
-
-
-/*
- * Copy data from a buffer back into the indicated mbuf chain,
- * starting "off" bytes from the beginning, extending the mbuf
- * chain if necessary.
- */
-void
-m_copyback(m0, off, len, cp)
- struct mbuf *m0;
- int off;
- int len;
- caddr_t cp;
-{
- int mlen;
- struct mbuf *m = m0, *n;
- int totlen = 0;
-
- if (m0 == 0)
- return;
- while (off > (mlen = m->m_len)) {
- off -= mlen;
- totlen += mlen;
- if (m->m_next == 0) {
- n = m_getclr(M_DONTWAIT, m->m_type);
- if (n == 0)
- goto out;
- n->m_len = min(MLEN, len + off);
- m->m_next = n;
- }
- m = m->m_next;
- }
- while (len > 0) {
- mlen = min(m->m_len - off, len);
- bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
- cp += mlen;
- len -= mlen;
- mlen += off;
- off = 0;
- totlen += mlen;
- if (len == 0)
- break;
- if (m->m_next == 0) {
- n = m_get(M_DONTWAIT, m->m_type);
- if (n == 0)
- break;
- n->m_len = min(MLEN, len);
- m->m_next = n;
- }
- m = m->m_next;
- }
-out:
-#if 0
- if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
- m->m_pkthdr.len = totlen;
-#endif
- return;
-}
-#endif /* (_KERNEL) && ( ((BSD < 199103) && !MENTAT) || __sgi) */
-
-
/* ------------------------------------------------------------------------ */
-/* Function: fr_findgroup */
+/* Function: ipf_findgroup */
/* Returns: frgroup_t * - NULL = group not found, else pointer to group */
-/* Parameters: group(I) - group name to search for */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* group(I) - group name to search for */
/* unit(I) - device to which this group belongs */
/* set(I) - which set of rules (inactive/inactive) this is */
/* fgpp(O) - pointer to place to store pointer to the pointer */
@@ -3316,11 +3508,13 @@ out:
/* */
/* Search amongst the defined groups for a particular group number. */
/* ------------------------------------------------------------------------ */
-frgroup_t *fr_findgroup(group, unit, set, fgpp)
-char *group;
-minor_t unit;
-int set;
-frgroup_t ***fgpp;
+frgroup_t *
+ipf_findgroup(softc, group, unit, set, fgpp)
+ ipf_main_softc_t *softc;
+ char *group;
+ minor_t unit;
+ int set;
+ frgroup_t ***fgpp;
{
frgroup_t *fg, **fgp;
@@ -3328,7 +3522,7 @@ frgroup_t ***fgpp;
* Which list of groups to search in is dependent on which list of
* rules are being operated on.
*/
- fgp = &ipfgroups[unit][set];
+ fgp = &softc->ipf_groups[unit][set];
while ((fg = *fgp) != NULL) {
if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0)
@@ -3343,10 +3537,11 @@ frgroup_t ***fgpp;
/* ------------------------------------------------------------------------ */
-/* Function: fr_addgroup */
+/* Function: ipf_group_add */
/* Returns: frgroup_t * - NULL == did not create group, */
/* != NULL == pointer to the group */
-/* Parameters: num(I) - group number to add */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* num(I) - group number to add */
/* head(I) - rule pointer that is using this as the head */
/* flags(I) - rule flags which describe the type of rule it is */
/* unit(I) - device to which this group will belong to */
@@ -3356,12 +3551,14 @@ frgroup_t ***fgpp;
/* Add a new group head, or if it already exists, increase the reference */
/* count to it. */
/* ------------------------------------------------------------------------ */
-frgroup_t *fr_addgroup(group, head, flags, unit, set)
-char *group;
-void *head;
-u_32_t flags;
-minor_t unit;
-int set;
+frgroup_t *
+ipf_group_add(softc, group, head, flags, unit, set)
+ ipf_main_softc_t *softc;
+ char *group;
+ void *head;
+ u_32_t flags;
+ minor_t unit;
+ int set;
{
frgroup_t *fg, **fgp;
u_32_t gflags;
@@ -3375,8 +3572,10 @@ int set;
fgp = NULL;
gflags = flags & FR_INOUT;
- fg = fr_findgroup(group, unit, set, &fgp);
+ fg = ipf_findgroup(softc, group, unit, set, &fgp);
if (fg != NULL) {
+ if (fg->fg_head == NULL && head != NULL)
+ fg->fg_head = head;
if (fg->fg_flags == 0)
fg->fg_flags = gflags;
else if (gflags != fg->fg_flags)
@@ -3384,14 +3583,16 @@ int set;
fg->fg_ref++;
return fg;
}
+
KMALLOC(fg, frgroup_t *);
if (fg != NULL) {
fg->fg_head = head;
fg->fg_start = NULL;
fg->fg_next = *fgp;
- bcopy(group, fg->fg_name, FR_GROUPLEN);
+ bcopy(group, fg->fg_name, strlen(group) + 1);
fg->fg_flags = gflags;
fg->fg_ref = 1;
+ fg->fg_set = &softc->ipf_groups[unit][set];
*fgp = fg;
}
return fg;
@@ -3399,38 +3600,82 @@ int set;
/* ------------------------------------------------------------------------ */
-/* Function: fr_delgroup */
-/* Returns: Nil */
-/* Parameters: group(I) - group name to delete */
-/* unit(I) - device to which this group belongs */
-/* set(I) - which set of rules (inactive/inactive) this is */
+/* Function: ipf_group_del */
+/* Returns: int - number of rules deleted */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* group(I) - group name to delete */
+/* fr(I) - filter rule from which group is referenced */
/* Write Locks: ipf_mutex */
/* */
-/* Attempt to delete a group head. */
-/* Only do this when its reference count reaches 0. */
+/* This function is called whenever a reference to a group is to be dropped */
+/* and thus its reference count needs to be lowered and the group free'd if */
+/* the reference count reaches zero. Passing in fr is really for the sole */
+/* purpose of knowing when the head rule is being deleted. */
/* ------------------------------------------------------------------------ */
-void fr_delgroup(group, unit, set)
-char *group;
-minor_t unit;
-int set;
+void
+ipf_group_del(softc, group, fr)
+ ipf_main_softc_t *softc;
+ frgroup_t *group;
+ frentry_t *fr;
{
- frgroup_t *fg, **fgp;
- fg = fr_findgroup(group, unit, set, &fgp);
- if (fg == NULL)
- return;
+ if (group->fg_head == fr)
+ group->fg_head = NULL;
+
+ group->fg_ref--;
+ if ((group->fg_ref == 0) && (group->fg_start == NULL))
+ ipf_group_free(group);
+}
+
- fg->fg_ref--;
- if (fg->fg_ref == 0) {
- *fgp = fg->fg_next;
- KFREE(fg);
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_group_free */
+/* Returns: Nil */
+/* Parameters: group(I) - pointer to filter rule group */
+/* */
+/* Remove the group from the list of groups and free it. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_group_free(group)
+ frgroup_t *group;
+{
+ frgroup_t **gp;
+
+ for (gp = group->fg_set; *gp != NULL; gp = &(*gp)->fg_next) {
+ if (*gp == group) {
+ *gp = group->fg_next;
+ break;
+ }
}
+ KFREE(group);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_getrulen */
+/* Function: ipf_group_flush */
+/* Returns: int - number of rules flush from group */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* Parameters: group(I) - pointer to filter rule group */
+/* */
+/* Remove all of the rules that currently are listed under the given group. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_group_flush(softc, group)
+ ipf_main_softc_t *softc;
+ frgroup_t *group;
+{
+ int gone = 0;
+
+ (void) ipf_flushlist(softc, &gone, &group->fg_start);
+
+ return gone;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_getrulen */
/* Returns: frentry_t * - NULL == not found, else pointer to rule n */
+/* Parameters: softc(I) - pointer to soft context main structure */
/* Parameters: unit(I) - device for which to count the rule's number */
/* flags(I) - which set of rules to find the rule in */
/* group(I) - group name */
@@ -3439,18 +3684,20 @@ int set;
/* Find rule # n in group # g and return a pointer to it. Return NULl if */
/* group # g doesn't exist or there are less than n rules in the group. */
/* ------------------------------------------------------------------------ */
-frentry_t *fr_getrulen(unit, group, n)
-int unit;
-char *group;
-u_32_t n;
+frentry_t *
+ipf_getrulen(softc, unit, group, n)
+ ipf_main_softc_t *softc;
+ int unit;
+ char *group;
+ u_32_t n;
{
frentry_t *fr;
frgroup_t *fg;
- fg = fr_findgroup(group, unit, fr_active, NULL);
+ fg = ipf_findgroup(softc, group, unit, softc->ipf_active, NULL);
if (fg == NULL)
return NULL;
- for (fr = fg->fg_head; fr && n; fr = fr->fr_next, n--)
+ for (fr = fg->fg_start; fr && n; fr = fr->fr_next, n--)
;
if (n != 0)
return NULL;
@@ -3459,41 +3706,9 @@ u_32_t n;
/* ------------------------------------------------------------------------ */
-/* Function: fr_rulen */
-/* Returns: int - >= 0 - rule number, -1 == search failed */
-/* Parameters: unit(I) - device for which to count the rule's number */
-/* fr(I) - pointer to rule to match */
-/* */
-/* Return the number for a rule on a specific filtering device. */
-/* ------------------------------------------------------------------------ */
-int fr_rulen(unit, fr)
-int unit;
-frentry_t *fr;
-{
- frentry_t *fh;
- frgroup_t *fg;
- u_32_t n = 0;
-
- if (fr == NULL)
- return -1;
- fg = fr_findgroup(fr->fr_group, unit, fr_active, NULL);
- if (fg == NULL)
- return -1;
- for (fh = fg->fg_head; fh; n++, fh = fh->fr_next)
- if (fh == fr)
- break;
- if (fh == NULL)
- return -1;
- return n;
-}
-
-
-/* ------------------------------------------------------------------------ */
-/* Function: frflushlist */
+/* Function: ipf_flushlist */
/* Returns: int - >= 0 - number of flushed rules */
-/* Parameters: set(I) - which set of rules (inactive/inactive) this is */
-/* unit(I) - device for which to flush rules */
-/* flags(I) - which set of rules to flush */
+/* Parameters: softc(I) - pointer to soft context main structure */
/* nfreedp(O) - pointer to int where flush count is stored */
/* listp(I) - pointer to list to flush pointer */
/* Write Locks: ipf_mutex */
@@ -3507,11 +3722,11 @@ frentry_t *fr;
/* */
/* NOTE: Rules not loaded from user space cannot be flushed. */
/* ------------------------------------------------------------------------ */
-static int frflushlist(set, unit, nfreedp, listp)
-int set;
-minor_t unit;
-int *nfreedp;
-frentry_t **listp;
+static int
+ipf_flushlist(softc, nfreedp, listp)
+ ipf_main_softc_t *softc;
+ int *nfreedp;
+ frentry_t **listp;
{
int freed = 0;
frentry_t *fp;
@@ -3523,18 +3738,27 @@ frentry_t **listp;
continue;
}
*listp = fp->fr_next;
- if (fp->fr_grp != NULL) {
- (void) frflushlist(set, unit, nfreedp, fp->fr_grp);
+ if (fp->fr_next != NULL)
+ fp->fr_next->fr_pnext = fp->fr_pnext;
+ fp->fr_pnext = NULL;
+
+ if (fp->fr_grphead != NULL) {
+ freed += ipf_group_flush(softc, fp->fr_grphead);
+ fp->fr_names[fp->fr_grhead] = '\0';
}
- if (fp->fr_grhead != NULL) {
- fr_delgroup(fp->fr_grhead, unit, set);
- *fp->fr_grhead = '\0';
+ if (fp->fr_icmpgrp != NULL) {
+ freed += ipf_group_flush(softc, fp->fr_icmpgrp);
+ fp->fr_names[fp->fr_icmphead] = '\0';
}
- ASSERT(fp->fr_ref > 0);
+ if (fp->fr_srctrack.ht_max_nodes)
+ ipf_rb_ht_flush(&fp->fr_srctrack);
+
fp->fr_next = NULL;
- if (fr_derefrule(&fp) == 0)
+
+ ASSERT(fp->fr_ref > 0);
+ if (ipf_derefrule(softc, &fp) == 0)
freed++;
}
*nfreedp += freed;
@@ -3543,61 +3767,47 @@ frentry_t **listp;
/* ------------------------------------------------------------------------ */
-/* Function: frflush */
+/* Function: ipf_flush */
/* Returns: int - >= 0 - number of flushed rules */
-/* Parameters: unit(I) - device for which to flush rules */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* unit(I) - device for which to flush rules */
/* flags(I) - which set of rules to flush */
/* */
/* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */
/* and IPv6) as defined by the value of flags. */
/* ------------------------------------------------------------------------ */
-int frflush(unit, proto, flags)
-minor_t unit;
-int proto, flags;
+int
+ipf_flush(softc, unit, flags)
+ ipf_main_softc_t *softc;
+ minor_t unit;
+ int flags;
{
int flushed = 0, set;
- WRITE_ENTER(&ipf_mutex);
- bzero((char *)frcache, sizeof(frcache));
+ WRITE_ENTER(&softc->ipf_mutex);
- set = fr_active;
+ set = softc->ipf_active;
if ((flags & FR_INACTIVE) == FR_INACTIVE)
set = 1 - set;
if (flags & FR_OUTQUE) {
- if (proto == 0 || proto == 6) {
- (void) frflushlist(set, unit,
- &flushed, &ipfilter6[1][set]);
- (void) frflushlist(set, unit,
- &flushed, &ipacct6[1][set]);
- }
- if (proto == 0 || proto == 4) {
- (void) frflushlist(set, unit,
- &flushed, &ipfilter[1][set]);
- (void) frflushlist(set, unit,
- &flushed, &ipacct[1][set]);
- }
+ ipf_flushlist(softc, &flushed, &softc->ipf_rules[1][set]);
+ ipf_flushlist(softc, &flushed, &softc->ipf_acct[1][set]);
}
if (flags & FR_INQUE) {
- if (proto == 0 || proto == 6) {
- (void) frflushlist(set, unit,
- &flushed, &ipfilter6[0][set]);
- (void) frflushlist(set, unit,
- &flushed, &ipacct6[0][set]);
- }
- if (proto == 0 || proto == 4) {
- (void) frflushlist(set, unit,
- &flushed, &ipfilter[0][set]);
- (void) frflushlist(set, unit,
- &flushed, &ipacct[0][set]);
- }
+ ipf_flushlist(softc, &flushed, &softc->ipf_rules[0][set]);
+ ipf_flushlist(softc, &flushed, &softc->ipf_acct[0][set]);
}
- RWLOCK_EXIT(&ipf_mutex);
+
+ flushed += ipf_flush_groups(softc, &softc->ipf_groups[unit][set],
+ flags & (FR_INQUE|FR_OUTQUE));
+
+ RWLOCK_EXIT(&softc->ipf_mutex);
if (unit == IPL_LOGIPF) {
int tmp;
- tmp = frflush(IPL_LOGCOUNT, proto, flags);
+ tmp = ipf_flush(softc, IPL_LOGCOUNT, flags);
if (tmp >= 0)
flushed += tmp;
}
@@ -3606,6 +3816,59 @@ int proto, flags;
/* ------------------------------------------------------------------------ */
+/* Function: ipf_flush_groups */
+/* Returns: int - >= 0 - number of flushed rules */
+/* Parameters: softc(I) - soft context pointerto work with */
+/* grhead(I) - pointer to the start of the group list to flush */
+/* flags(I) - which set of rules to flush */
+/* */
+/* Walk through all of the groups under the given group head and remove all */
+/* of those that match the flags passed in. The for loop here is bit more */
+/* complicated than usual because the removal of a rule with ipf_derefrule */
+/* may end up removing not only the structure pointed to by "fg" but also */
+/* what is fg_next and fg_next after that. So if a filter rule is actually */
+/* removed from the group then it is necessary to start again. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_flush_groups(softc, grhead, flags)
+ ipf_main_softc_t *softc;
+ frgroup_t **grhead;
+ int flags;
+{
+ frentry_t *fr, **frp;
+ frgroup_t *fg, **fgp;
+ int flushed = 0;
+ int removed = 0;
+
+ for (fgp = grhead; (fg = *fgp) != NULL; ) {
+ while ((fg != NULL) && ((fg->fg_flags & flags) == 0))
+ fg = fg->fg_next;
+ if (fg == NULL)
+ break;
+ removed = 0;
+ frp = &fg->fg_start;
+ while ((removed == 0) && ((fr = *frp) != NULL)) {
+ if ((fr->fr_flags & flags) == 0) {
+ frp = &fr->fr_next;
+ } else {
+ if (fr->fr_next != NULL)
+ fr->fr_next->fr_pnext = fr->fr_pnext;
+ *frp = fr->fr_next;
+ fr->fr_pnext = NULL;
+ fr->fr_next = NULL;
+ (void) ipf_derefrule(softc, &fr);
+ flushed++;
+ removed++;
+ }
+ }
+ if (removed == 0)
+ fgp = &fg->fg_next;
+ }
+ return flushed;
+}
+
+
+/* ------------------------------------------------------------------------ */
/* Function: memstr */
/* Returns: char * - NULL if failed, != NULL pointer to matching bytes */
/* Parameters: src(I) - pointer to byte sequence to match */
@@ -3616,10 +3879,11 @@ int proto, flags;
/* Search dst for a sequence of bytes matching those at src and extend for */
/* slen bytes. */
/* ------------------------------------------------------------------------ */
-char *memstr(src, dst, slen, dlen)
-const char *src;
-char *dst;
-size_t slen, dlen;
+char *
+memstr(src, dst, slen, dlen)
+ const char *src;
+ char *dst;
+ size_t slen, dlen;
{
char *s = NULL;
@@ -3634,7 +3898,7 @@ size_t slen, dlen;
return s;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_fixskip */
+/* Function: ipf_fixskip */
/* Returns: Nil */
/* Parameters: listp(IO) - pointer to start of list with skip rule */
/* rp(I) - rule added/removed with skip in it. */
@@ -3645,9 +3909,10 @@ size_t slen, dlen;
/* Adjust all the rules in a list which would have skip'd past the position */
/* where we are inserting to skip to the right place given the change. */
/* ------------------------------------------------------------------------ */
-void fr_fixskip(listp, rp, addremove)
-frentry_t **listp, *rp;
-int addremove;
+void
+ipf_fixskip(listp, rp, addremove)
+ frentry_t **listp, *rp;
+ int addremove;
{
int rules, rn;
frentry_t *fp;
@@ -3676,8 +3941,9 @@ int addremove;
/* consecutive 1's is different to that passed, return -1, else return # */
/* of bits. */
/* ------------------------------------------------------------------------ */
-int count4bits(ip)
-u_32_t ip;
+int
+count4bits(ip)
+ u_32_t ip;
{
u_32_t ipn;
int cnt = 0, i, j;
@@ -3700,7 +3966,6 @@ u_32_t ip;
}
-# if 0
/* ------------------------------------------------------------------------ */
/* Function: count6bits */
/* Returns: int - >= 0 - number of consecutive bits in input */
@@ -3709,8 +3974,10 @@ u_32_t ip;
/* IPv6 ONLY */
/* count consecutive 1's in bit mask. */
/* ------------------------------------------------------------------------ */
-int count6bits(msk)
-u_32_t *msk;
+# ifdef USE_INET6
+int
+count6bits(msk)
+ u_32_t *msk;
{
int i = 0, k;
u_32_t j;
@@ -3730,8 +3997,8 @@ u_32_t *msk;
/* ------------------------------------------------------------------------ */
-/* Function: frsynclist */
-/* Returns: void */
+/* Function: ipf_synclist */
+/* Returns: int - 0 = no failures, else indication of first failure */
/* Parameters: fr(I) - start of filter list to sync interface names for */
/* ifp(I) - interface pointer for limiting sync lookups */
/* Write Locks: ipf_mutex */
@@ -3740,16 +4007,33 @@ u_32_t *msk;
/* pointers. Where dynamic addresses are used, also update the IP address */
/* used in the rule. The interface pointer is used to limit the lookups to */
/* a specific set of matching names if it is non-NULL. */
-/* ------------------------------------------------------------------------ */
-static void frsynclist(fr, ifp)
-frentry_t *fr;
-void *ifp;
+/* Errors can occur when resolving the destination name of to/dup-to fields */
+/* when the name points to a pool and that pool doest not exist. If this */
+/* does happen then it is necessary to check if there are any lookup refs */
+/* that need to be dropped before returning with an error. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_synclist(softc, fr, ifp)
+ ipf_main_softc_t *softc;
+ frentry_t *fr;
+ void *ifp;
{
+ frentry_t *frt, *start = fr;
frdest_t *fdp;
+ char *name;
+ int error;
+ void *ifa;
int v, i;
+ error = 0;
+
for (; fr; fr = fr->fr_next) {
- v = fr->fr_v;
+ if (fr->fr_family == AF_INET)
+ v = 4;
+ else if (fr->fr_family == AF_INET6)
+ v = 6;
+ else
+ v = 0;
/*
* Lookup all the interface names that are part of the rule.
@@ -3757,102 +4041,124 @@ void *ifp;
for (i = 0; i < 4; i++) {
if ((ifp != NULL) && (fr->fr_ifas[i] != ifp))
continue;
- fr->fr_ifas[i] = fr_resolvenic(fr->fr_ifnames[i], v);
+ if (fr->fr_ifnames[i] == -1)
+ continue;
+ name = FR_NAME(fr, fr_ifnames[i]);
+ fr->fr_ifas[i] = ipf_resolvenic(softc, name, v);
}
- if (fr->fr_type == FR_T_IPF) {
+ if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) {
if (fr->fr_satype != FRI_NORMAL &&
fr->fr_satype != FRI_LOOKUP) {
- (void)fr_ifpaddr(v, fr->fr_satype,
- fr->fr_ifas[fr->fr_sifpidx],
- &fr->fr_src, &fr->fr_smsk);
+ ifa = ipf_resolvenic(softc, fr->fr_names +
+ fr->fr_sifpidx, v);
+ ipf_ifpaddr(softc, v, fr->fr_satype, ifa,
+ &fr->fr_src6, &fr->fr_smsk6);
}
if (fr->fr_datype != FRI_NORMAL &&
fr->fr_datype != FRI_LOOKUP) {
- (void)fr_ifpaddr(v, fr->fr_datype,
- fr->fr_ifas[fr->fr_difpidx],
- &fr->fr_dst, &fr->fr_dmsk);
+ ifa = ipf_resolvenic(softc, fr->fr_names +
+ fr->fr_sifpidx, v);
+ ipf_ifpaddr(softc, v, fr->fr_datype, ifa,
+ &fr->fr_dst6, &fr->fr_dmsk6);
}
}
fdp = &fr->fr_tifs[0];
- if ((ifp == NULL) || (fdp->fd_ifp == ifp))
- fr_resolvedest(fdp, v);
+ if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
+ error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
+ if (error != 0)
+ goto unwind;
+ }
fdp = &fr->fr_tifs[1];
- if ((ifp == NULL) || (fdp->fd_ifp == ifp))
- fr_resolvedest(fdp, v);
+ if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
+ error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
+ if (error != 0)
+ goto unwind;
+ }
fdp = &fr->fr_dif;
- if ((ifp == NULL) || (fdp->fd_ifp == ifp)) {
- fr_resolvedest(fdp, v);
-
- fr->fr_flags &= ~FR_DUP;
- if ((fdp->fd_ifp != (void *)-1) &&
- (fdp->fd_ifp != NULL))
- fr->fr_flags |= FR_DUP;
- }
-
-#ifdef IPFILTER_LOOKUP
- if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP &&
- fr->fr_srcptr == NULL) {
- fr->fr_srcptr = fr_resolvelookup(fr->fr_srctype,
- fr->fr_srcsubtype,
- &fr->fr_slookup,
- &fr->fr_srcfunc);
- }
- if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP &&
- fr->fr_dstptr == NULL) {
- fr->fr_dstptr = fr_resolvelookup(fr->fr_dsttype,
- fr->fr_dstsubtype,
- &fr->fr_dlookup,
- &fr->fr_dstfunc);
+ if ((ifp == NULL) || (fdp->fd_ptr == ifp)) {
+ error = ipf_resolvedest(softc, fr->fr_names, fdp, v);
+ if (error != 0)
+ goto unwind;
+ }
+
+ if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
+ (fr->fr_satype == FRI_LOOKUP) && (fr->fr_srcptr == NULL)) {
+ fr->fr_srcptr = ipf_lookup_res_num(softc,
+ fr->fr_srctype,
+ IPL_LOGIPF,
+ fr->fr_srcnum,
+ &fr->fr_srcfunc);
+ }
+ if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
+ (fr->fr_datype == FRI_LOOKUP) && (fr->fr_dstptr == NULL)) {
+ fr->fr_dstptr = ipf_lookup_res_num(softc,
+ fr->fr_dsttype,
+ IPL_LOGIPF,
+ fr->fr_dstnum,
+ &fr->fr_dstfunc);
}
-#endif
}
+ return 0;
+
+unwind:
+ for (frt = start; frt != fr; fr = fr->fr_next) {
+ if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
+ (frt->fr_satype == FRI_LOOKUP) && (frt->fr_srcptr != NULL))
+ ipf_lookup_deref(softc, frt->fr_srctype,
+ frt->fr_srcptr);
+ if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) &&
+ (frt->fr_datype == FRI_LOOKUP) && (frt->fr_dstptr != NULL))
+ ipf_lookup_deref(softc, frt->fr_dsttype,
+ frt->fr_dstptr);
+ }
+ return error;
}
-#ifdef _KERNEL
/* ------------------------------------------------------------------------ */
-/* Function: frsync */
+/* Function: ipf_sync */
/* Returns: void */
/* Parameters: Nil */
/* */
-/* frsync() is called when we suspect that the interface list or */
+/* ipf_sync() is called when we suspect that the interface list or */
/* information about interfaces (like IP#) has changed. Go through all */
/* filter rules, NAT entries and the state table and check if anything */
/* needs to be changed/updated. */
/* ------------------------------------------------------------------------ */
-void frsync(ifp)
-void *ifp;
+int
+ipf_sync(softc, ifp)
+ ipf_main_softc_t *softc;
+ void *ifp;
{
int i;
# if !SOLARIS
- fr_natsync(ifp);
- fr_statesync(ifp);
+ ipf_nat_sync(softc, ifp);
+ ipf_state_sync(softc, ifp);
+ ipf_lookup_sync(softc, ifp);
# endif
- WRITE_ENTER(&ipf_mutex);
- frsynclist(ipacct[0][fr_active], ifp);
- frsynclist(ipacct[1][fr_active], ifp);
- frsynclist(ipfilter[0][fr_active], ifp);
- frsynclist(ipfilter[1][fr_active], ifp);
- frsynclist(ipacct6[0][fr_active], ifp);
- frsynclist(ipacct6[1][fr_active], ifp);
- frsynclist(ipfilter6[0][fr_active], ifp);
- frsynclist(ipfilter6[1][fr_active], ifp);
+ WRITE_ENTER(&softc->ipf_mutex);
+ (void) ipf_synclist(softc, softc->ipf_acct[0][softc->ipf_active], ifp);
+ (void) ipf_synclist(softc, softc->ipf_acct[1][softc->ipf_active], ifp);
+ (void) ipf_synclist(softc, softc->ipf_rules[0][softc->ipf_active], ifp);
+ (void) ipf_synclist(softc, softc->ipf_rules[1][softc->ipf_active], ifp);
for (i = 0; i < IPL_LOGSIZE; i++) {
frgroup_t *g;
- for (g = ipfgroups[i][0]; g != NULL; g = g->fg_next)
- frsynclist(g->fg_start, ifp);
- for (g = ipfgroups[i][1]; g != NULL; g = g->fg_next)
- frsynclist(g->fg_start, ifp);
+ for (g = softc->ipf_groups[i][0]; g != NULL; g = g->fg_next)
+ (void) ipf_synclist(softc, g->fg_start, ifp);
+ for (g = softc->ipf_groups[i][1]; g != NULL; g = g->fg_next)
+ (void) ipf_synclist(softc, g->fg_start, ifp);
}
- RWLOCK_EXIT(&ipf_mutex);
+ RWLOCK_EXIT(&softc->ipf_mutex);
+
+ return 0;
}
@@ -3872,9 +4178,11 @@ void *ifp;
/* to start copying from (src) and a pointer to where to store it (dst). */
/* NB: src - pointer to user space pointer, dst - kernel space pointer */
/* ------------------------------------------------------------------------ */
-int copyinptr(src, dst, size)
-void *src, *dst;
-size_t size;
+int
+copyinptr(softc, src, dst, size)
+ ipf_main_softc_t *softc;
+ void *src, *dst;
+ size_t size;
{
caddr_t ca;
int error;
@@ -3887,8 +4195,10 @@ size_t size;
bcopy(src, (caddr_t)&ca, sizeof(ca));
# endif
error = COPYIN(ca, dst, size);
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(3);
error = EFAULT;
+ }
return error;
}
@@ -3904,24 +4214,29 @@ size_t size;
/* to start copying from (src) and a pointer to where to store it (dst). */
/* NB: src - kernel space pointer, dst - pointer to user space pointer. */
/* ------------------------------------------------------------------------ */
-int copyoutptr(src, dst, size)
-void *src, *dst;
-size_t size;
+int
+copyoutptr(softc, src, dst, size)
+ ipf_main_softc_t *softc;
+ void *src, *dst;
+ size_t size;
{
caddr_t ca;
int error;
bcopy(dst, (caddr_t)&ca, sizeof(ca));
error = COPYOUT(src, ca, size);
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(4);
error = EFAULT;
+ }
return error;
}
+#ifdef _KERNEL
#endif
/* ------------------------------------------------------------------------ */
-/* Function: fr_lock */
+/* Function: ipf_lock */
/* Returns: int - 0 = success, else error */
/* Parameters: data(I) - pointer to lock value to set */
/* lockp(O) - pointer to location to store old lock value */
@@ -3929,9 +4244,10 @@ size_t size;
/* Get the new value for the lock integer, set it and return the old value */
/* in *lockp. */
/* ------------------------------------------------------------------------ */
-int fr_lock(data, lockp)
-caddr_t data;
-int *lockp;
+int
+ipf_lock(data, lockp)
+ caddr_t data;
+ int *lockp;
{
int arg, err;
@@ -3947,51 +4263,78 @@ int *lockp;
/* ------------------------------------------------------------------------ */
-/* Function: fr_getstat */
+/* Function: ipf_getstat */
/* Returns: Nil */
-/* Parameters: fiop(I) - pointer to ipfilter stats structure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* fiop(I) - pointer to ipfilter stats structure */
+/* rev(I) - version claim by program doing ioctl */
/* */
/* Stores a copy of current pointers, counters, etc, in the friostat */
/* structure. */
-/* ------------------------------------------------------------------------ */
-void fr_getstat(fiop)
-friostat_t *fiop;
+/* If IPFILTER_COMPAT is compiled, we pretend to be whatever version the */
+/* program is looking for. This ensure that validation of the version it */
+/* expects will always succeed. Thus kernels with IPFILTER_COMPAT will */
+/* allow older binaries to work but kernels without it will not. */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+static void
+ipf_getstat(softc, fiop, rev)
+ ipf_main_softc_t *softc;
+ friostat_t *fiop;
+ int rev;
{
- int i, j;
-
- bcopy((char *)frstats, (char *)fiop->f_st, sizeof(filterstats_t) * 2);
- fiop->f_locks[IPL_LOGSTATE] = fr_state_lock;
- fiop->f_locks[IPL_LOGNAT] = fr_nat_lock;
- fiop->f_locks[IPL_LOGIPF] = fr_frag_lock;
- fiop->f_locks[IPL_LOGAUTH] = fr_auth_lock;
-
- for (i = 0; i < 2; i++)
- for (j = 0; j < 2; j++) {
- fiop->f_ipf[i][j] = ipfilter[i][j];
- fiop->f_acct[i][j] = ipacct[i][j];
- fiop->f_ipf6[i][j] = ipfilter6[i][j];
- fiop->f_acct6[i][j] = ipacct6[i][j];
- }
-
- fiop->f_ticks = fr_ticks;
- fiop->f_active = fr_active;
- fiop->f_froute[0] = fr_frouteok[0];
- fiop->f_froute[1] = fr_frouteok[1];
+ int i;
- fiop->f_running = fr_running;
+ bcopy((char *)softc->ipf_stats, (char *)fiop->f_st,
+ sizeof(ipf_statistics_t) * 2);
+ fiop->f_locks[IPL_LOGSTATE] = -1;
+ fiop->f_locks[IPL_LOGNAT] = -1;
+ fiop->f_locks[IPL_LOGIPF] = -1;
+ fiop->f_locks[IPL_LOGAUTH] = -1;
+
+ fiop->f_ipf[0][0] = softc->ipf_rules[0][0];
+ fiop->f_acct[0][0] = softc->ipf_acct[0][0];
+ fiop->f_ipf[0][1] = softc->ipf_rules[0][1];
+ fiop->f_acct[0][1] = softc->ipf_acct[0][1];
+ fiop->f_ipf[1][0] = softc->ipf_rules[1][0];
+ fiop->f_acct[1][0] = softc->ipf_acct[1][0];
+ fiop->f_ipf[1][1] = softc->ipf_rules[1][1];
+ fiop->f_acct[1][1] = softc->ipf_acct[1][1];
+
+ fiop->f_ticks = softc->ipf_ticks;
+ fiop->f_active = softc->ipf_active;
+ fiop->f_froute[0] = softc->ipf_frouteok[0];
+ fiop->f_froute[1] = softc->ipf_frouteok[1];
+ fiop->f_rb_no_mem = softc->ipf_rb_no_mem;
+ fiop->f_rb_node_max = softc->ipf_rb_node_max;
+
+ fiop->f_running = softc->ipf_running;
for (i = 0; i < IPL_LOGSIZE; i++) {
- fiop->f_groups[i][0] = ipfgroups[i][0];
- fiop->f_groups[i][1] = ipfgroups[i][1];
+ fiop->f_groups[i][0] = softc->ipf_groups[i][0];
+ fiop->f_groups[i][1] = softc->ipf_groups[i][1];
}
#ifdef IPFILTER_LOG
+ fiop->f_log_ok = ipf_log_logok(softc, IPL_LOGIPF);
+ fiop->f_log_fail = ipf_log_failures(softc, IPL_LOGIPF);
fiop->f_logging = 1;
#else
+ fiop->f_log_ok = 0;
+ fiop->f_log_fail = 0;
fiop->f_logging = 0;
#endif
- fiop->f_defpass = fr_pass;
- fiop->f_features = fr_features;
+ fiop->f_defpass = softc->ipf_pass;
+ fiop->f_features = ipf_features;
+
+#ifdef IPFILTER_COMPAT
+ sprintf(fiop->f_version, "IP Filter: v%d.%d.%d",
+ (rev / 1000000) % 100,
+ (rev / 10000) % 100,
+ (rev / 100) % 100);
+#else
+ rev = rev;
(void) strncpy(fiop->f_version, ipfilter_version,
sizeof(fiop->f_version));
+#endif
}
@@ -4042,7 +4385,7 @@ int icmpreplytype4[ICMP_MAXTYPE + 1];
/* ------------------------------------------------------------------------ */
-/* Function: fr_matchicmpqueryreply */
+/* Function: ipf_matchicmpqueryreply */
/* Returns: int - 1 if "icmp" is a valid reply to "ic" else 0. */
/* Parameters: v(I) - IP protocol version (4 or 6) */
/* ic(I) - ICMP information */
@@ -4053,11 +4396,12 @@ int icmpreplytype4[ICMP_MAXTYPE + 1];
/* reply to one as described by what's in ic. If it is a match, return 1, */
/* else return 0 for no match. */
/* ------------------------------------------------------------------------ */
-int fr_matchicmpqueryreply(v, ic, icmp, rev)
-int v;
-icmpinfo_t *ic;
-icmphdr_t *icmp;
-int rev;
+int
+ipf_matchicmpqueryreply(v, ic, icmp, rev)
+ int v;
+ icmpinfo_t *ic;
+ icmphdr_t *icmp;
+ int rev;
{
int ictype;
@@ -4091,88 +4435,6 @@ int rev;
}
-#ifdef IPFILTER_LOOKUP
-/* ------------------------------------------------------------------------ */
-/* Function: fr_resolvelookup */
-/* Returns: void * - NULL = failure, else success. */
-/* Parameters: type(I) - type of lookup these parameters are for. */
-/* subtype(I) - whether the info below contains number/name */
-/* info(I) - pointer to name/number of the lookup data */
-/* funcptr(IO) - pointer to pointer for storing IP address */
-/* searching function. */
-/* */
-/* Search for the "table" number passed in amongst those configured for */
-/* that particular type. If the type is recognised then the function to */
-/* call to do the IP address search will be change, regardless of whether */
-/* or not the "table" number exists. */
-/* ------------------------------------------------------------------------ */
-static void *fr_resolvelookup(type, subtype, info, funcptr)
-u_int type, subtype;
-i6addr_t *info;
-lookupfunc_t *funcptr;
-{
- char label[FR_GROUPLEN], *name;
- iphtable_t *iph;
- ip_pool_t *ipo;
- void *ptr;
-
- if (subtype == 0) {
-#if defined(SNPRINTF) && defined(_KERNEL)
- SNPRINTF(label, sizeof(label), "%u", info->iplookupnum);
-#else
- (void) sprintf(label, "%u", info->iplookupnum);
-#endif
- name = label;
- } else if (subtype == 1) {
- /*
- * Because iplookupname is currently only a 12 character
- * string and FR_GROUPLEN is 16, copy all of it into the
- * label buffer and add on a NULL at the end.
- */
- strncpy(label, info->iplookupname, sizeof(info->iplookupname));
- label[sizeof(info->iplookupname)] = '\0';
- name = label;
- } else {
- return NULL;
- }
-
- READ_ENTER(&ip_poolrw);
-
- switch (type)
- {
- case IPLT_POOL :
-# if (defined(__osf__) && defined(_KERNEL))
- ptr = NULL;
- *funcptr = NULL;
-# else
- ipo = ip_pool_find(IPL_LOGIPF, name);
- ptr = ipo;
- if (ipo != NULL) {
- ATOMIC_INC32(ipo->ipo_ref);
- }
- *funcptr = ip_pool_search;
-# endif
- break;
- case IPLT_HASH :
- iph = fr_findhtable(IPL_LOGIPF, name);
- ptr = iph;
- if (iph != NULL) {
- ATOMIC_INC32(iph->iph_ref);
- }
- *funcptr = fr_iphmfindip;
- break;
- default:
- ptr = NULL;
- *funcptr = NULL;
- break;
- }
- RWLOCK_EXIT(&ip_poolrw);
-
- return ptr;
-}
-#endif
-
-
/* ------------------------------------------------------------------------ */
/* Function: frrequest */
/* Returns: int - 0 == success, > 0 == errno value */
@@ -4190,54 +4452,98 @@ lookupfunc_t *funcptr;
/* of the rule structure being loaded. If a rule has user defined timeouts */
/* then make sure they are created and initialised before exiting. */
/* ------------------------------------------------------------------------ */
-int frrequest(unit, req, data, set, makecopy)
-int unit;
-ioctlcmd_t req;
-int set, makecopy;
-caddr_t data;
+int
+frrequest(softc, unit, req, data, set, makecopy)
+ ipf_main_softc_t *softc;
+ int unit;
+ ioctlcmd_t req;
+ int set, makecopy;
+ caddr_t data;
{
+ int error = 0, in, family, addrem, need_free = 0;
frentry_t frd, *fp, *f, **fprev, **ftail;
- int error = 0, in, v;
- void *ptr, *uptr;
+ void *ptr, *uptr, *cptr;
u_int *p, *pp;
frgroup_t *fg;
char *group;
+ ptr = NULL;
+ cptr = NULL;
fg = NULL;
fp = &frd;
if (makecopy != 0) {
- error = fr_inobj(data, fp, IPFOBJ_FRENTRY);
- if (error)
- return EFAULT;
- if ((fp->fr_flags & FR_T_BUILTIN) != 0)
+ bzero(fp, sizeof(frd));
+ error = ipf_inobj(softc, data, NULL, fp, IPFOBJ_FRENTRY);
+ if (error) {
+ return error;
+ }
+ if ((fp->fr_type & FR_T_BUILTIN) != 0) {
+ IPFERROR(6);
return EINVAL;
+ }
+ KMALLOCS(f, frentry_t *, fp->fr_size);
+ if (f == NULL) {
+ IPFERROR(131);
+ return ENOMEM;
+ }
+ bzero(f, fp->fr_size);
+ error = ipf_inobjsz(softc, data, f, IPFOBJ_FRENTRY,
+ fp->fr_size);
+ if (error) {
+ KFREES(f, fp->fr_size);
+ return error;
+ }
+
+ fp = f;
+ f = NULL;
+ fp->fr_dnext = NULL;
fp->fr_ref = 0;
fp->fr_flags |= FR_COPIED;
} else {
fp = (frentry_t *)data;
- if ((fp->fr_type & FR_T_BUILTIN) == 0)
+ if ((fp->fr_type & FR_T_BUILTIN) == 0) {
+ IPFERROR(7);
return EINVAL;
+ }
fp->fr_flags &= ~FR_COPIED;
}
if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) ||
- ((fp->fr_dsize != 0) && (fp->fr_data == NULL)))
- return EINVAL;
+ ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) {
+ IPFERROR(8);
+ error = EINVAL;
+ goto donenolock;
+ }
- v = fp->fr_v;
+ family = fp->fr_family;
uptr = fp->fr_data;
+ if (req == (ioctlcmd_t)SIOCINAFR || req == (ioctlcmd_t)SIOCINIFR ||
+ req == (ioctlcmd_t)SIOCADAFR || req == (ioctlcmd_t)SIOCADIFR)
+ addrem = 0;
+ else if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR)
+ addrem = 1;
+ else if (req == (ioctlcmd_t)SIOCZRLST)
+ addrem = 2;
+ else {
+ IPFERROR(9);
+ error = EINVAL;
+ goto donenolock;
+ }
+
/*
* Only filter rules for IPv4 or IPv6 are accepted.
*/
- if (v == 4)
+ if (family == AF_INET) {
/*EMPTY*/;
#ifdef USE_INET6
- else if (v == 6)
+ } else if (family == AF_INET6) {
/*EMPTY*/;
#endif
- else {
- return EINVAL;
+ } else if (family != 0) {
+ IPFERROR(10);
+ error = EINVAL;
+ goto donenolock;
}
/*
@@ -4246,37 +4552,110 @@ caddr_t data;
* rule.
*/
if ((makecopy == 1) && (fp->fr_func != NULL)) {
- if (fr_findfunc(fp->fr_func) == NULL)
- return ESRCH;
- error = fr_funcinit(fp);
- if (error != 0)
- return error;
+ if (ipf_findfunc(fp->fr_func) == NULL) {
+ IPFERROR(11);
+ error = ESRCH;
+ goto donenolock;
+ }
+
+ if (addrem == 0) {
+ error = ipf_funcinit(softc, fp);
+ if (error != 0)
+ goto donenolock;
+ }
+ }
+ if ((fp->fr_flags & FR_CALLNOW) &&
+ ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) {
+ IPFERROR(142);
+ error = ESRCH;
+ goto donenolock;
+ }
+ if (((fp->fr_flags & FR_CMDMASK) == FR_CALL) &&
+ ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) {
+ IPFERROR(143);
+ error = ESRCH;
+ goto donenolock;
}
ptr = NULL;
- /*
- * Check that the group number does exist and that its use (in/out)
- * matches what the rule is.
- */
- if (!strncmp(fp->fr_grhead, "0", FR_GROUPLEN))
- *fp->fr_grhead = '\0';
- group = fp->fr_group;
- if (!strncmp(group, "0", FR_GROUPLEN))
- *group = '\0';
+ cptr = NULL;
if (FR_ISACCOUNT(fp->fr_flags))
unit = IPL_LOGCOUNT;
- if ((req != (int)SIOCZRLST) && (*group != '\0')) {
- fg = fr_findgroup(group, unit, set, NULL);
- if (fg == NULL)
- return ESRCH;
- if (fg->fg_flags == 0)
- fg->fg_flags = fp->fr_flags & FR_INOUT;
- else if (fg->fg_flags != (fp->fr_flags & FR_INOUT))
- return ESRCH;
+ /*
+ * Check that each group name in the rule has a start index that
+ * is valid.
+ */
+ if (fp->fr_icmphead != -1) {
+ if ((fp->fr_icmphead < 0) ||
+ (fp->fr_icmphead >= fp->fr_namelen)) {
+ IPFERROR(136);
+ error = EINVAL;
+ goto donenolock;
+ }
+ if (!strcmp(FR_NAME(fp, fr_icmphead), "0"))
+ fp->fr_names[fp->fr_icmphead] = '\0';
}
+ if (fp->fr_grhead != -1) {
+ if ((fp->fr_grhead < 0) ||
+ (fp->fr_grhead >= fp->fr_namelen)) {
+ IPFERROR(137);
+ error = EINVAL;
+ goto donenolock;
+ }
+ if (!strcmp(FR_NAME(fp, fr_grhead), "0"))
+ fp->fr_names[fp->fr_grhead] = '\0';
+ }
+
+ if (fp->fr_group != -1) {
+ if ((fp->fr_group < 0) ||
+ (fp->fr_group >= fp->fr_namelen)) {
+ IPFERROR(138);
+ error = EINVAL;
+ goto donenolock;
+ }
+ if ((req != (int)SIOCZRLST) && (fp->fr_group != -1)) {
+ /*
+ * Allow loading rules that are in groups to cause
+ * them to be created if they don't already exit.
+ */
+ group = FR_NAME(fp, fr_group);
+ if (addrem == 0) {
+ fg = ipf_group_add(softc, group, NULL,
+ fp->fr_flags, unit, set);
+ fp->fr_grp = fg;
+ } else {
+ fg = ipf_findgroup(softc, group, unit,
+ set, NULL);
+ if (fg == NULL) {
+ IPFERROR(12);
+ error = ESRCH;
+ goto donenolock;
+ }
+ }
+
+ if (fg->fg_flags == 0) {
+ fg->fg_flags = fp->fr_flags & FR_INOUT;
+ } else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) {
+ IPFERROR(13);
+ error = ESRCH;
+ goto donenolock;
+ }
+ }
+ } else {
+ /*
+ * If a rule is going to be part of a group then it does
+ * not matter whether it is an in or out rule, but if it
+ * isn't in a group, then it does...
+ */
+ if ((fp->fr_flags & (FR_INQUE|FR_OUTQUE)) == 0) {
+ IPFERROR(14);
+ error = EINVAL;
+ goto donenolock;
+ }
+ }
in = (fp->fr_flags & FR_INQUE) ? 0 : 1;
/*
@@ -4284,27 +4663,30 @@ caddr_t data;
*/
ftail = NULL;
fprev = NULL;
- if (unit == IPL_LOGAUTH)
- fprev = &ipauth;
- else if (v == 4) {
- if (FR_ISACCOUNT(fp->fr_flags))
- fprev = &ipacct[in][set];
- else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0)
- fprev = &ipfilter[in][set];
- } else if (v == 6) {
+ if (unit == IPL_LOGAUTH) {
+ if ((fp->fr_tifs[0].fd_ptr != NULL) ||
+ (fp->fr_tifs[1].fd_ptr != NULL) ||
+ (fp->fr_dif.fd_ptr != NULL) ||
+ (fp->fr_flags & FR_FASTROUTE)) {
+ softc->ipf_interror = 145;
+ error = EINVAL;
+ goto donenolock;
+ }
+ fprev = ipf_auth_rulehead(softc);
+ } else {
if (FR_ISACCOUNT(fp->fr_flags))
- fprev = &ipacct6[in][set];
+ fprev = &softc->ipf_acct[in][set];
else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0)
- fprev = &ipfilter6[in][set];
+ fprev = &softc->ipf_rules[in][set];
+ }
+ if (fprev == NULL) {
+ IPFERROR(15);
+ error = ESRCH;
+ goto donenolock;
}
- if (fprev == NULL)
- return ESRCH;
- if (*group != '\0') {
- if (!fg && !(fg = fr_findgroup(group, unit, set, NULL)))
- return ESRCH;
+ if (fg != NULL)
fprev = &fg->fg_start;
- }
/*
* Copy in extra data for the rule.
@@ -4312,51 +4694,82 @@ caddr_t data;
if (fp->fr_dsize != 0) {
if (makecopy != 0) {
KMALLOCS(ptr, void *, fp->fr_dsize);
- if (!ptr)
- return ENOMEM;
- error = COPYIN(uptr, ptr, fp->fr_dsize);
- if (error != 0)
- error = EFAULT;
+ if (ptr == NULL) {
+ IPFERROR(16);
+ error = ENOMEM;
+ goto donenolock;
+ }
+
+ /*
+ * The bcopy case is for when the data is appended
+ * to the rule by ipf_in_compat().
+ */
+ if (uptr >= (void *)fp &&
+ uptr < (void *)((char *)fp + fp->fr_size)) {
+ bcopy(uptr, ptr, fp->fr_dsize);
+ error = 0;
+ } else {
+ error = COPYIN(uptr, ptr, fp->fr_dsize);
+ if (error != 0) {
+ IPFERROR(17);
+ error = EFAULT;
+ goto donenolock;
+ }
+ }
} else {
ptr = uptr;
- error = 0;
- }
- if (error != 0) {
- KFREES(ptr, fp->fr_dsize);
- return ENOMEM;
}
fp->fr_data = ptr;
- } else
+ } else {
fp->fr_data = NULL;
+ }
/*
* Perform per-rule type sanity checks of their members.
+ * All code after this needs to be aware that allocated memory
+ * may need to be free'd before exiting.
*/
switch (fp->fr_type & ~FR_T_BUILTIN)
{
#if defined(IPFILTER_BPF)
case FR_T_BPFOPC :
- if (fp->fr_dsize == 0)
- return EINVAL;
+ if (fp->fr_dsize == 0) {
+ IPFERROR(19);
+ error = EINVAL;
+ break;
+ }
if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) {
- if (makecopy && fp->fr_data != NULL) {
- KFREES(fp->fr_data, fp->fr_dsize);
- }
- return EINVAL;
+ IPFERROR(20);
+ error = EINVAL;
+ break;
}
break;
#endif
case FR_T_IPF :
- if (fp->fr_dsize != sizeof(fripf_t))
- return EINVAL;
+ /*
+ * Preparation for error case at the bottom of this function.
+ */
+ if (fp->fr_datype == FRI_LOOKUP)
+ fp->fr_dstptr = NULL;
+ if (fp->fr_satype == FRI_LOOKUP)
+ fp->fr_srcptr = NULL;
+
+ if (fp->fr_dsize != sizeof(fripf_t)) {
+ IPFERROR(21);
+ error = EINVAL;
+ break;
+ }
/*
* Allowing a rule with both "keep state" and "with oow" is
* pointless because adding a state entry to the table will
* fail with the out of window (oow) flag set.
*/
- if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW))
- return EINVAL;
+ if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) {
+ IPFERROR(22);
+ error = EINVAL;
+ break;
+ }
switch (fp->fr_satype)
{
@@ -4365,26 +4778,30 @@ caddr_t data;
case FRI_NETWORK :
case FRI_NETMASKED :
case FRI_PEERADDR :
- if (fp->fr_sifpidx < 0 || fp->fr_sifpidx > 3) {
- if (makecopy && fp->fr_data != NULL) {
- KFREES(fp->fr_data, fp->fr_dsize);
- }
- return EINVAL;
+ if (fp->fr_sifpidx < 0) {
+ IPFERROR(23);
+ error = EINVAL;
}
break;
-#ifdef IPFILTER_LOOKUP
case FRI_LOOKUP :
- fp->fr_srcptr = fr_resolvelookup(fp->fr_srctype,
- fp->fr_srcsubtype,
- &fp->fr_slookup,
- &fp->fr_srcfunc);
- if (fp->fr_srcptr == NULL)
- return ESRCH;
+ fp->fr_srcptr = ipf_findlookup(softc, unit, fp,
+ &fp->fr_src6,
+ &fp->fr_smsk6);
+ if (fp->fr_srcfunc == NULL) {
+ IPFERROR(132);
+ error = ESRCH;
+ break;
+ }
+ break;
+ case FRI_NORMAL :
break;
-#endif
default :
+ IPFERROR(133);
+ error = EINVAL;
break;
}
+ if (error != 0)
+ break;
switch (fp->fr_datype)
{
@@ -4393,45 +4810,84 @@ caddr_t data;
case FRI_NETWORK :
case FRI_NETMASKED :
case FRI_PEERADDR :
- if (fp->fr_difpidx < 0 || fp->fr_difpidx > 3) {
- if (makecopy && fp->fr_data != NULL) {
- KFREES(fp->fr_data, fp->fr_dsize);
- }
- return EINVAL;
+ if (fp->fr_difpidx < 0) {
+ IPFERROR(24);
+ error = EINVAL;
}
break;
-#ifdef IPFILTER_LOOKUP
case FRI_LOOKUP :
- fp->fr_dstptr = fr_resolvelookup(fp->fr_dsttype,
- fp->fr_dstsubtype,
- &fp->fr_dlookup,
- &fp->fr_dstfunc);
- if (fp->fr_dstptr == NULL)
- return ESRCH;
+ fp->fr_dstptr = ipf_findlookup(softc, unit, fp,
+ &fp->fr_dst6,
+ &fp->fr_dmsk6);
+ if (fp->fr_dstfunc == NULL) {
+ IPFERROR(134);
+ error = ESRCH;
+ }
break;
-#endif
- default :
+ case FRI_NORMAL :
break;
+ default :
+ IPFERROR(135);
+ error = EINVAL;
}
break;
+
case FR_T_NONE :
- break;
case FR_T_CALLFUNC :
- break;
case FR_T_COMPIPF :
break;
+
+ case FR_T_IPFEXPR :
+ if (ipf_matcharray_verify(fp->fr_data, fp->fr_dsize) == -1) {
+ IPFERROR(25);
+ error = EINVAL;
+ }
+ break;
+
default :
- if (makecopy && fp->fr_data != NULL) {
- KFREES(fp->fr_data, fp->fr_dsize);
+ IPFERROR(26);
+ error = EINVAL;
+ break;
+ }
+ if (error != 0)
+ goto donenolock;
+
+ if (fp->fr_tif.fd_name != -1) {
+ if ((fp->fr_tif.fd_name < 0) ||
+ (fp->fr_tif.fd_name >= fp->fr_namelen)) {
+ IPFERROR(139);
+ error = EINVAL;
+ goto donenolock;
+ }
+ }
+
+ if (fp->fr_dif.fd_name != -1) {
+ if ((fp->fr_dif.fd_name < 0) ||
+ (fp->fr_dif.fd_name >= fp->fr_namelen)) {
+ IPFERROR(140);
+ error = EINVAL;
+ goto donenolock;
+ }
+ }
+
+ if (fp->fr_rif.fd_name != -1) {
+ if ((fp->fr_rif.fd_name < 0) ||
+ (fp->fr_rif.fd_name >= fp->fr_namelen)) {
+ IPFERROR(141);
+ error = EINVAL;
+ goto donenolock;
}
- return EINVAL;
}
/*
* Lookup all the interface names that are part of the rule.
*/
- frsynclist(fp, NULL);
+ error = ipf_synclist(softc, fp, NULL);
+ if (error != 0)
+ goto donenolock;
fp->fr_statecnt = 0;
+ if (fp->fr_srctrack.ht_max_nodes != 0)
+ ipf_rb_ht_init(&fp->fr_srctrack);
/*
* Look for an existing matching filter rule, but don't include the
@@ -4447,7 +4903,7 @@ caddr_t data;
for (p = (u_int *)fp->fr_data; p < pp; p++)
fp->fr_cksum += *p;
- WRITE_ENTER(&ipf_mutex);
+ WRITE_ENTER(&softc->ipf_mutex);
/*
* Now that the filter rule lists are locked, we can walk the
@@ -4462,13 +4918,15 @@ caddr_t data;
}
fprev = ftail;
}
- bzero((char *)frcache, sizeof(frcache));
for (; (f = *ftail) != NULL; ftail = &f->fr_next) {
+ DT2(rule_cmp, frentry_t *, fp, frentry_t *, f);
if ((fp->fr_cksum != f->fr_cksum) ||
+ (fp->fr_size != f->fr_size) ||
(f->fr_dsize != fp->fr_dsize))
continue;
- if (bcmp((char *)&f->fr_func, (char *)&fp->fr_func, FR_CMPSIZ))
+ if (bcmp((char *)&f->fr_func, (char *)&fp->fr_func,
+ fp->fr_size - offsetof(struct frentry, fr_func)) != 0)
continue;
if ((!ptr && !f->fr_data) ||
(ptr && f->fr_data &&
@@ -4479,10 +4937,11 @@ caddr_t data;
/*
* If zero'ing statistics, copy current to caller and zero.
*/
- if (req == (ioctlcmd_t)SIOCZRLST) {
- if (f == NULL)
+ if (addrem == 2) {
+ if (f == NULL) {
+ IPFERROR(27);
error = ESRCH;
- else {
+ } else {
/*
* Copy and reduce lock because of impending copyout.
* Well we should, but if we do then the atomicity of
@@ -4491,22 +4950,24 @@ caddr_t data;
* only resets them to 0 if they are successfully
* copied out into user space.
*/
- bcopy((char *)f, (char *)fp, sizeof(*f));
- /* MUTEX_DOWNGRADE(&ipf_mutex); */
+ bcopy((char *)f, (char *)fp, f->fr_size);
+ /* MUTEX_DOWNGRADE(&softc->ipf_mutex); */
/*
* When we copy this rule back out, set the data
* pointer to be what it was in user space.
*/
fp->fr_data = uptr;
- error = fr_outobj(data, fp, IPFOBJ_FRENTRY);
+ error = ipf_outobj(softc, data, fp, IPFOBJ_FRENTRY);
if (error == 0) {
if ((f->fr_dsize != 0) && (uptr != NULL))
error = COPYOUT(f->fr_data, uptr,
f->fr_dsize);
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(28);
error = EFAULT;
+ }
if (error == 0) {
f->fr_hits = 0;
f->fr_bytes = 0;
@@ -4514,14 +4975,17 @@ caddr_t data;
}
}
- if ((ptr != NULL) && (makecopy != 0)) {
- KFREES(ptr, fp->fr_dsize);
+ if (makecopy != 0) {
+ if (ptr != NULL) {
+ KFREES(ptr, fp->fr_dsize);
+ }
+ KFREES(fp, fp->fr_size);
}
- RWLOCK_EXIT(&ipf_mutex);
+ RWLOCK_EXIT(&softc->ipf_mutex);
return error;
}
- if (!f) {
+ if (!f) {
/*
* At the end of this, ftail must point to the place where the
* new rule is to be saved/inserted/added.
@@ -4539,7 +5003,6 @@ caddr_t data;
}
f = NULL;
ptr = NULL;
- error = 0;
} else if (req == (ioctlcmd_t)SIOCINAFR ||
req == (ioctlcmd_t)SIOCINIFR) {
while ((f = *fprev) != NULL) {
@@ -4547,34 +5010,35 @@ caddr_t data;
break;
fprev = &f->fr_next;
}
- ftail = fprev;
- if (fp->fr_hits != 0) {
+ ftail = fprev;
+ if (fp->fr_hits != 0) {
while (fp->fr_hits && (f = *ftail)) {
if (f->fr_collect != fp->fr_collect)
break;
fprev = ftail;
- ftail = &f->fr_next;
+ ftail = &f->fr_next;
fp->fr_hits--;
}
- }
- f = NULL;
- ptr = NULL;
- error = 0;
+ }
+ f = NULL;
+ ptr = NULL;
}
}
/*
* Request to remove a rule.
*/
- if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR) {
- if (!f)
+ if (addrem == 1) {
+ if (!f) {
+ IPFERROR(29);
error = ESRCH;
- else {
+ } else {
/*
* Do not allow activity from user space to interfere
* with rules not loaded that way.
*/
if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) {
+ IPFERROR(30);
error = EPERM;
goto done;
}
@@ -4584,101 +5048,265 @@ caddr_t data;
* something else (eg state information.)
*/
if (f->fr_ref > 1) {
+ IPFERROR(31);
error = EBUSY;
goto done;
}
#ifdef IPFILTER_SCAN
- if (f->fr_isctag[0] != '\0' &&
+ if (f->fr_isctag != -1 &&
(f->fr_isc != (struct ipscan *)-1))
- ipsc_detachfr(f);
+ ipf_scan_detachfr(f);
#endif
+
if (unit == IPL_LOGAUTH) {
- error = fr_preauthcmd(req, f, ftail);
+ error = ipf_auth_precmd(softc, req, f, ftail);
goto done;
}
- if (*f->fr_grhead != '\0')
- fr_delgroup(f->fr_grhead, unit, set);
- fr_fixskip(ftail, f, -1);
- *ftail = f->fr_next;
- f->fr_next = NULL;
- (void) fr_derefrule(&f);
+
+ ipf_rule_delete(softc, f, unit, set);
+
+ need_free = makecopy;
}
} else {
/*
* Not removing, so we must be adding/inserting a rule.
*/
- if (f)
+ if (f != NULL) {
+ IPFERROR(32);
error = EEXIST;
- else {
- if (unit == IPL_LOGAUTH) {
- error = fr_preauthcmd(req, fp, ftail);
- goto done;
- }
- if (makecopy) {
- KMALLOC(f, frentry_t *);
- } else
- f = fp;
- if (f != NULL) {
- if (fp != f)
- bcopy((char *)fp, (char *)f,
- sizeof(*f));
- MUTEX_NUKE(&f->fr_lock);
- MUTEX_INIT(&f->fr_lock, "filter rule lock");
-#ifdef IPFILTER_SCAN
- if (f->fr_isctag[0] != '\0' &&
- ipsc_attachfr(f))
- f->fr_isc = (struct ipscan *)-1;
-#endif
- f->fr_hits = 0;
- if (makecopy != 0)
- f->fr_ref = 1;
- f->fr_next = *ftail;
- *ftail = f;
- if (req == (ioctlcmd_t)SIOCINIFR ||
- req == (ioctlcmd_t)SIOCINAFR)
- fr_fixskip(ftail, f, 1);
- f->fr_grp = NULL;
- group = f->fr_grhead;
- if (*group != '\0') {
- fg = fr_addgroup(group, f, f->fr_flags,
- unit, set);
- if (fg != NULL)
- f->fr_grp = &fg->fg_start;
- }
- } else
- error = ENOMEM;
+ goto done;
+ }
+ if (unit == IPL_LOGAUTH) {
+ error = ipf_auth_precmd(softc, req, fp, ftail);
+ goto done;
+ }
+
+ MUTEX_NUKE(&fp->fr_lock);
+ MUTEX_INIT(&fp->fr_lock, "filter rule lock");
+ if (fp->fr_die != 0)
+ ipf_rule_expire_insert(softc, fp, set);
+
+ fp->fr_hits = 0;
+ if (makecopy != 0)
+ fp->fr_ref = 1;
+ fp->fr_pnext = ftail;
+ fp->fr_next = *ftail;
+ *ftail = fp;
+ if (addrem == 0)
+ ipf_fixskip(ftail, fp, 1);
+
+ fp->fr_icmpgrp = NULL;
+ if (fp->fr_icmphead != -1) {
+ group = FR_NAME(fp, fr_icmphead);
+ fg = ipf_group_add(softc, group, fp, 0, unit, set);
+ fp->fr_icmpgrp = fg;
+ }
+
+ fp->fr_grphead = NULL;
+ if (fp->fr_grhead != -1) {
+ group = FR_NAME(fp, fr_grhead);
+ fg = ipf_group_add(softc, group, fp, fp->fr_flags,
+ unit, set);
+ fp->fr_grphead = fg;
}
}
done:
- RWLOCK_EXIT(&ipf_mutex);
- if ((ptr != NULL) && (error != 0) && (makecopy != 0)) {
- KFREES(ptr, fp->fr_dsize);
+ RWLOCK_EXIT(&softc->ipf_mutex);
+donenolock:
+ if (need_free || (error != 0)) {
+ if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) {
+ if ((fp->fr_satype == FRI_LOOKUP) &&
+ (fp->fr_srcptr != NULL))
+ ipf_lookup_deref(softc, fp->fr_srctype,
+ fp->fr_srcptr);
+ if ((fp->fr_datype == FRI_LOOKUP) &&
+ (fp->fr_dstptr != NULL))
+ ipf_lookup_deref(softc, fp->fr_dsttype,
+ fp->fr_dstptr);
+ }
+ if (fp->fr_grp != NULL) {
+ WRITE_ENTER(&softc->ipf_mutex);
+ ipf_group_del(softc, fp->fr_grp, fp);
+ RWLOCK_EXIT(&softc->ipf_mutex);
+ }
+ if ((ptr != NULL) && (makecopy != 0)) {
+ KFREES(ptr, fp->fr_dsize);
+ }
+ KFREES(fp, fp->fr_size);
}
return (error);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_funcinit */
+/* Function: ipf_rule_delete */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* f(I) - pointer to the rule being deleted */
+/* ftail(I) - pointer to the pointer to f */
+/* unit(I) - device for which this is for */
+/* set(I) - 1 or 0 (filter set) */
+/* */
+/* This function attempts to do what it can to delete a filter rule: remove */
+/* it from any linked lists and remove any groups it is responsible for. */
+/* But in the end, removing a rule can only drop the reference count - we */
+/* must use that as the guide for whether or not it can be freed. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_rule_delete(softc, f, unit, set)
+ ipf_main_softc_t *softc;
+ frentry_t *f;
+ int unit, set;
+{
+
+ /*
+ * If fr_pdnext is set, then the rule is on the expire list, so
+ * remove it from there.
+ */
+ if (f->fr_pdnext != NULL) {
+ *f->fr_pdnext = f->fr_dnext;
+ if (f->fr_dnext != NULL)
+ f->fr_dnext->fr_pdnext = f->fr_pdnext;
+ f->fr_pdnext = NULL;
+ f->fr_dnext = NULL;
+ }
+
+ ipf_fixskip(f->fr_pnext, f, -1);
+ if (f->fr_pnext != NULL)
+ *f->fr_pnext = f->fr_next;
+ if (f->fr_next != NULL)
+ f->fr_next->fr_pnext = f->fr_pnext;
+ f->fr_pnext = NULL;
+ f->fr_next = NULL;
+
+ (void) ipf_derefrule(softc, &f);
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rule_expire_insert */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* f(I) - pointer to rule to be added to expire list */
+/* set(I) - 1 or 0 (filter set) */
+/* */
+/* If the new rule has a given expiration time, insert it into the list of */
+/* expiring rules with the ones to be removed first added to the front of */
+/* the list. The insertion is O(n) but it is kept sorted for quick scans at */
+/* expiration interval checks. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_rule_expire_insert(softc, f, set)
+ ipf_main_softc_t *softc;
+ frentry_t *f;
+ int set;
+{
+ frentry_t *fr;
+
+ /*
+ */
+
+ f->fr_die = softc->ipf_ticks + IPF_TTLVAL(f->fr_die);
+ for (fr = softc->ipf_rule_explist[set]; fr != NULL;
+ fr = fr->fr_dnext) {
+ if (f->fr_die < fr->fr_die)
+ break;
+ if (fr->fr_dnext == NULL) {
+ /*
+ * We've got to the last rule and everything
+ * wanted to be expired before this new node,
+ * so we have to tack it on the end...
+ */
+ fr->fr_dnext = f;
+ f->fr_pdnext = &fr->fr_dnext;
+ fr = NULL;
+ break;
+ }
+ }
+
+ if (softc->ipf_rule_explist[set] == NULL) {
+ softc->ipf_rule_explist[set] = f;
+ f->fr_pdnext = &softc->ipf_rule_explist[set];
+ } else if (fr != NULL) {
+ f->fr_dnext = fr;
+ f->fr_pdnext = fr->fr_pdnext;
+ fr->fr_pdnext = &f->fr_dnext;
+ }
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_findlookup */
+/* Returns: NULL = failure, else success */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* unit(I) - ipf device we want to find match for */
+/* fp(I) - rule for which lookup is for */
+/* addrp(I) - pointer to lookup information in address struct */
+/* maskp(O) - pointer to lookup information for storage */
+/* */
+/* When using pools and hash tables to store addresses for matching in */
+/* rules, it is necessary to resolve both the object referred to by the */
+/* name or address (and return that pointer) and also provide the means by */
+/* which to determine if an address belongs to that object to make the */
+/* packet matching quicker. */
+/* ------------------------------------------------------------------------ */
+static void *
+ipf_findlookup(softc, unit, fr, addrp, maskp)
+ ipf_main_softc_t *softc;
+ int unit;
+ frentry_t *fr;
+ i6addr_t *addrp, *maskp;
+{
+ void *ptr = NULL;
+
+ switch (addrp->iplookupsubtype)
+ {
+ case 0 :
+ ptr = ipf_lookup_res_num(softc, unit, addrp->iplookuptype,
+ addrp->iplookupnum,
+ &maskp->iplookupfunc);
+ break;
+ case 1 :
+ if (addrp->iplookupname < 0)
+ break;
+ if (addrp->iplookupname >= fr->fr_namelen)
+ break;
+ ptr = ipf_lookup_res_name(softc, unit, addrp->iplookuptype,
+ fr->fr_names + addrp->iplookupname,
+ &maskp->iplookupfunc);
+ break;
+ default :
+ break;
+ }
+
+ return ptr;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_funcinit */
/* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */
-/* Parameters: fr(I) - pointer to filter rule */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* fr(I) - pointer to filter rule */
/* */
/* If a rule is a call rule, then check if the function it points to needs */
/* an init function to be called now the rule has been loaded. */
/* ------------------------------------------------------------------------ */
-static int fr_funcinit(fr)
-frentry_t *fr;
+static int
+ipf_funcinit(softc, fr)
+ ipf_main_softc_t *softc;
+ frentry_t *fr;
{
ipfunc_resolve_t *ft;
int err;
+ IPFERROR(34);
err = ESRCH;
- for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++)
+ for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
if (ft->ipfu_addr == fr->fr_func) {
err = 0;
if (ft->ipfu_init != NULL)
- err = (*ft->ipfu_init)(fr);
+ err = (*ft->ipfu_init)(softc, fr);
break;
}
return err;
@@ -4686,18 +5314,45 @@ frentry_t *fr;
/* ------------------------------------------------------------------------ */
-/* Function: fr_findfunc */
+/* Function: ipf_funcfini */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* fr(I) - pointer to filter rule */
+/* */
+/* For a given filter rule, call the matching "fini" function if the rule */
+/* is using a known function that would have resulted in the "init" being */
+/* called for ealier. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_funcfini(softc, fr)
+ ipf_main_softc_t *softc;
+ frentry_t *fr;
+{
+ ipfunc_resolve_t *ft;
+
+ for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
+ if (ft->ipfu_addr == fr->fr_func) {
+ if (ft->ipfu_fini != NULL)
+ (void) (*ft->ipfu_fini)(softc, fr);
+ break;
+ }
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_findfunc */
/* Returns: ipfunc_t - pointer to function if found, else NULL */
/* Parameters: funcptr(I) - function pointer to lookup */
/* */
/* Look for a function in the table of known functions. */
/* ------------------------------------------------------------------------ */
-static ipfunc_t fr_findfunc(funcptr)
-ipfunc_t funcptr;
+static ipfunc_t
+ipf_findfunc(funcptr)
+ ipfunc_t funcptr;
{
ipfunc_resolve_t *ft;
- for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++)
+ for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
if (ft->ipfu_addr == funcptr)
return funcptr;
return NULL;
@@ -4705,7 +5360,7 @@ ipfunc_t funcptr;
/* ------------------------------------------------------------------------ */
-/* Function: fr_resolvefunc */
+/* Function: ipf_resolvefunc */
/* Returns: int - 0 == success, else error */
/* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */
/* */
@@ -4714,46 +5369,55 @@ ipfunc_t funcptr;
/* function pointer if the name is set. When found, fill in the other one */
/* so that the entire, complete, structure can be copied back to user space.*/
/* ------------------------------------------------------------------------ */
-int fr_resolvefunc(data)
-void *data;
+int
+ipf_resolvefunc(softc, data)
+ ipf_main_softc_t *softc;
+ void *data;
{
ipfunc_resolve_t res, *ft;
- int err;
+ int error;
- err = BCOPYIN(data, &res, sizeof(res));
- if (err != 0)
+ error = BCOPYIN(data, &res, sizeof(res));
+ if (error != 0) {
+ IPFERROR(123);
return EFAULT;
+ }
if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') {
- for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++)
+ for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
if (strncmp(res.ipfu_name, ft->ipfu_name,
sizeof(res.ipfu_name)) == 0) {
res.ipfu_addr = ft->ipfu_addr;
res.ipfu_init = ft->ipfu_init;
- if (COPYOUT(&res, data, sizeof(res)) != 0)
+ if (COPYOUT(&res, data, sizeof(res)) != 0) {
+ IPFERROR(35);
return EFAULT;
+ }
return 0;
}
}
if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') {
- for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++)
+ for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++)
if (ft->ipfu_addr == res.ipfu_addr) {
(void) strncpy(res.ipfu_name, ft->ipfu_name,
sizeof(res.ipfu_name));
res.ipfu_init = ft->ipfu_init;
- if (COPYOUT(&res, data, sizeof(res)) != 0)
+ if (COPYOUT(&res, data, sizeof(res)) != 0) {
+ IPFERROR(36);
return EFAULT;
+ }
return 0;
}
}
+ IPFERROR(37);
return ESRCH;
}
-#if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__FreeBSD__)) || \
- (defined(__FreeBSD__) && (__FreeBSD_version < 501000)) || \
- (defined(__NetBSD__) && (__NetBSD_Version__ < 105000000)) || \
- (defined(__OpenBSD__) && (OpenBSD < 200006))
+#if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && \
+ !defined(__FreeBSD__)) || \
+ FREEBSD_LT_REV(501000) || NETBSD_LT_REV(105000000) || \
+ OPENBSD_LT_REV(200006)
/*
* From: NetBSD
* ppsratecheck(): packets (or events) per second limitation.
@@ -4803,17 +5467,20 @@ ppsratecheck(lasttime, curpps, maxpps)
/* ------------------------------------------------------------------------ */
-/* Function: fr_derefrule */
+/* Function: ipf_derefrule */
/* Returns: int - 0 == rule freed up, else rule not freed */
/* Parameters: fr(I) - pointer to filter rule */
/* */
/* Decrement the reference counter to a rule by one. If it reaches zero, */
/* free it and any associated storage space being used by it. */
/* ------------------------------------------------------------------------ */
-int fr_derefrule(frp)
-frentry_t **frp;
+int
+ipf_derefrule(softc, frp)
+ ipf_main_softc_t *softc;
+ frentry_t **frp;
{
frentry_t *fr;
+ frdest_t *fdp;
fr = *frp;
*frp = NULL;
@@ -4824,18 +5491,41 @@ frentry_t **frp;
MUTEX_EXIT(&fr->fr_lock);
MUTEX_DESTROY(&fr->fr_lock);
-#ifdef IPFILTER_LOOKUP
- if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP)
- ip_lookup_deref(fr->fr_srctype, fr->fr_srcptr);
- if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP)
- ip_lookup_deref(fr->fr_dsttype, fr->fr_dstptr);
-#endif
+ ipf_funcfini(softc, fr);
+
+ fdp = &fr->fr_tif;
+ if (fdp->fd_type == FRD_DSTLIST)
+ ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
+
+ fdp = &fr->fr_rif;
+ if (fdp->fd_type == FRD_DSTLIST)
+ ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
+
+ fdp = &fr->fr_dif;
+ if (fdp->fd_type == FRD_DSTLIST)
+ ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr);
+
+ if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
+ fr->fr_satype == FRI_LOOKUP)
+ ipf_lookup_deref(softc, fr->fr_srctype, fr->fr_srcptr);
+ if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF &&
+ fr->fr_datype == FRI_LOOKUP)
+ ipf_lookup_deref(softc, fr->fr_dsttype, fr->fr_dstptr);
+
+ if (fr->fr_grp != NULL)
+ ipf_group_del(softc, fr->fr_grp, fr);
+
+ if (fr->fr_grphead != NULL)
+ ipf_group_del(softc, fr->fr_grphead, fr);
+
+ if (fr->fr_icmpgrp != NULL)
+ ipf_group_del(softc, fr->fr_icmpgrp, fr);
- if (fr->fr_dsize) {
- KFREES(fr->fr_data, fr->fr_dsize);
- }
if ((fr->fr_flags & FR_COPIED) != 0) {
- KFREE(fr);
+ if (fr->fr_dsize) {
+ KFREES(fr->fr_data, fr->fr_dsize);
+ }
+ KFREES(fr, fr->fr_size);
return 0;
}
return 1;
@@ -4846,17 +5536,18 @@ frentry_t **frp;
}
-#ifdef IPFILTER_LOOKUP
/* ------------------------------------------------------------------------ */
-/* Function: fr_grpmapinit */
+/* Function: ipf_grpmapinit */
/* Returns: int - 0 == success, else ESRCH because table entry not found*/
/* Parameters: fr(I) - pointer to rule to find hash table for */
/* */
/* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr. */
-/* fr_ptr is later used by fr_srcgrpmap and fr_dstgrpmap. */
+/* fr_ptr is later used by ipf_srcgrpmap and ipf_dstgrpmap. */
/* ------------------------------------------------------------------------ */
-static int fr_grpmapinit(fr)
-frentry_t *fr;
+static int
+ipf_grpmapinit(softc, fr)
+ ipf_main_softc_t *softc;
+ frentry_t *fr;
{
char name[FR_GROUPLEN];
iphtable_t *iph;
@@ -4866,18 +5557,45 @@ frentry_t *fr;
#else
(void) sprintf(name, "%d", fr->fr_arg);
#endif
- iph = fr_findhtable(IPL_LOGIPF, name);
- if (iph == NULL)
+ iph = ipf_lookup_find_htable(softc, IPL_LOGIPF, name);
+ if (iph == NULL) {
+ IPFERROR(38);
return ESRCH;
- if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT))
+ }
+ if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) {
+ IPFERROR(39);
return ESRCH;
+ }
+ iph->iph_ref++;
fr->fr_ptr = iph;
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_srcgrpmap */
+/* Function: ipf_grpmapfini */
+/* Returns: int - 0 == success, else ESRCH because table entry not found*/
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* fr(I) - pointer to rule to release hash table for */
+/* */
+/* For rules that have had ipf_grpmapinit called, ipf_lookup_deref needs to */
+/* be called to undo what ipf_grpmapinit caused to be done. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_grpmapfini(softc, fr)
+ ipf_main_softc_t *softc;
+ frentry_t *fr;
+{
+ iphtable_t *iph;
+ iph = fr->fr_ptr;
+ if (iph != NULL)
+ ipf_lookup_deref(softc, IPLT_HASH, iph);
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_srcgrpmap */
/* Returns: frentry_t * - pointer to "new last matching" rule or NULL */
/* Parameters: fin(I) - pointer to packet information */
/* passp(IO) - pointer to current/new filter decision (unused) */
@@ -4886,26 +5604,28 @@ frentry_t *fr;
/* the key, and descend into that group and continue matching rules against */
/* the packet. */
/* ------------------------------------------------------------------------ */
-frentry_t *fr_srcgrpmap(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+frentry_t *
+ipf_srcgrpmap(fin, passp)
+ fr_info_t *fin;
+ u_32_t *passp;
{
frgroup_t *fg;
void *rval;
- rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, &fin->fin_src);
+ rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr,
+ &fin->fin_src);
if (rval == NULL)
return NULL;
fg = rval;
fin->fin_fr = fg->fg_start;
- (void) fr_scanlist(fin, *passp);
+ (void) ipf_scanlist(fin, *passp);
return fin->fin_fr;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_dstgrpmap */
+/* Function: ipf_dstgrpmap */
/* Returns: frentry_t * - pointer to "new last matching" rule or NULL */
/* Parameters: fin(I) - pointer to packet information */
/* passp(IO) - pointer to current/new filter decision (unused) */
@@ -4914,37 +5634,39 @@ u_32_t *passp;
/* address as the key, and descend into that group and continue matching */
/* rules against the packet. */
/* ------------------------------------------------------------------------ */
-frentry_t *fr_dstgrpmap(fin, passp)
-fr_info_t *fin;
-u_32_t *passp;
+frentry_t *
+ipf_dstgrpmap(fin, passp)
+ fr_info_t *fin;
+ u_32_t *passp;
{
frgroup_t *fg;
void *rval;
- rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, &fin->fin_dst);
+ rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr,
+ &fin->fin_dst);
if (rval == NULL)
return NULL;
fg = rval;
fin->fin_fr = fg->fg_start;
- (void) fr_scanlist(fin, *passp);
+ (void) ipf_scanlist(fin, *passp);
return fin->fin_fr;
}
-#endif /* IPFILTER_LOOKUP */
/*
* Queue functions
* ===============
- * These functions manage objects on queues for efficient timeouts. There are
- * a number of system defined queues as well as user defined timeouts. It is
- * expected that a lock is held in the domain in which the queue belongs
- * (i.e. either state or NAT) when calling any of these functions that prevents
- * fr_freetimeoutqueue() from being called at the same time as any other.
+ * These functions manage objects on queues for efficient timeouts. There
+ * are a number of system defined queues as well as user defined timeouts.
+ * It is expected that a lock is held in the domain in which the queue
+ * belongs (i.e. either state or NAT) when calling any of these functions
+ * that prevents ipf_freetimeoutqueue() from being called at the same time
+ * as any other.
*/
/* ------------------------------------------------------------------------ */
-/* Function: fr_addtimeoutqueue */
+/* Function: ipf_addtimeoutqueue */
/* Returns: struct ifqtq * - NULL if malloc fails, else pointer to */
/* timeout queue with given interval. */
/* Parameters: parent(I) - pointer to pointer to parent node of this list */
@@ -4960,16 +5682,18 @@ u_32_t *passp;
/* It is assumed that the caller of this function has an appropriate lock */
/* held (exclusively) in the domain that encompases 'parent'. */
/* ------------------------------------------------------------------------ */
-ipftq_t *fr_addtimeoutqueue(parent, seconds)
-ipftq_t **parent;
-u_int seconds;
+ipftq_t *
+ipf_addtimeoutqueue(softc, parent, seconds)
+ ipf_main_softc_t *softc;
+ ipftq_t **parent;
+ u_int seconds;
{
ipftq_t *ifq;
u_int period;
period = seconds * IPF_HZ_DIVIDE;
- MUTEX_ENTER(&ipf_timeoutlock);
+ MUTEX_ENTER(&softc->ipf_timeoutlock);
for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) {
if (ifq->ifq_ttl == period) {
/*
@@ -4980,7 +5704,7 @@ u_int seconds;
ifq->ifq_flags &= ~IFQF_DELETE;
ifq->ifq_ref++;
MUTEX_EXIT(&ifq->ifq_lock);
- MUTEX_EXIT(&ipf_timeoutlock);
+ MUTEX_EXIT(&softc->ipf_timeoutlock);
return ifq;
}
@@ -4988,25 +5712,22 @@ u_int seconds;
KMALLOC(ifq, ipftq_t *);
if (ifq != NULL) {
- ifq->ifq_ttl = period;
- ifq->ifq_head = NULL;
- ifq->ifq_tail = &ifq->ifq_head;
+ MUTEX_NUKE(&ifq->ifq_lock);
+ IPFTQ_INIT(ifq, period, "ipftq mutex");
ifq->ifq_next = *parent;
ifq->ifq_pnext = parent;
- ifq->ifq_ref = 1;
ifq->ifq_flags = IFQF_USER;
+ ifq->ifq_ref++;
*parent = ifq;
- fr_userifqs++;
- MUTEX_NUKE(&ifq->ifq_lock);
- MUTEX_INIT(&ifq->ifq_lock, "ipftq mutex");
+ softc->ipf_userifqs++;
}
- MUTEX_EXIT(&ipf_timeoutlock);
+ MUTEX_EXIT(&softc->ipf_timeoutlock);
return ifq;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_deletetimeoutqueue */
+/* Function: ipf_deletetimeoutqueue */
/* Returns: int - new reference count value of the timeout queue */
/* Parameters: ifq(I) - timeout queue which is losing a reference. */
/* Locks: ifq->ifq_lock */
@@ -5020,8 +5741,9 @@ u_int seconds;
/* way because the locking may not be sufficient to safely do a free when */
/* this function is called. */
/* ------------------------------------------------------------------------ */
-int fr_deletetimeoutqueue(ifq)
-ipftq_t *ifq;
+int
+ipf_deletetimeoutqueue(ifq)
+ ipftq_t *ifq;
{
ifq->ifq_ref--;
@@ -5034,7 +5756,7 @@ ipftq_t *ifq;
/* ------------------------------------------------------------------------ */
-/* Function: fr_freetimeoutqueue */
+/* Function: ipf_freetimeoutqueue */
/* Parameters: ifq(I) - timeout queue which is losing a reference. */
/* Returns: Nil */
/* */
@@ -5043,17 +5765,18 @@ ipftq_t *ifq;
/* held (exclusively) in the domain that encompases the callers "domain". */
/* The ifq_lock for this structure should not be held. */
/* */
-/* Remove a user definde timeout queue from the list of queues it is in and */
+/* Remove a user defined timeout queue from the list of queues it is in and */
/* tidy up after this is done. */
/* ------------------------------------------------------------------------ */
-void fr_freetimeoutqueue(ifq)
-ipftq_t *ifq;
+void
+ipf_freetimeoutqueue(softc, ifq)
+ ipf_main_softc_t *softc;
+ ipftq_t *ifq;
{
-
if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) ||
((ifq->ifq_flags & IFQF_USER) == 0)) {
- printf("fr_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n",
+ printf("ipf_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n",
(u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl,
ifq->ifq_ref);
return;
@@ -5065,26 +5788,28 @@ ipftq_t *ifq;
*ifq->ifq_pnext = ifq->ifq_next;
if (ifq->ifq_next != NULL)
ifq->ifq_next->ifq_pnext = ifq->ifq_pnext;
+ ifq->ifq_next = NULL;
+ ifq->ifq_pnext = NULL;
MUTEX_DESTROY(&ifq->ifq_lock);
- ATOMIC_DEC(fr_userifqs);
+ ATOMIC_DEC(softc->ipf_userifqs);
KFREE(ifq);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_deletequeueentry */
+/* Function: ipf_deletequeueentry */
/* Returns: Nil */
/* Parameters: tqe(I) - timeout queue entry to delete */
-/* ifq(I) - timeout queue to remove entry from */
/* */
/* Remove a tail queue entry from its queue and make it an orphan. */
-/* fr_deletetimeoutqueue is called to make sure the reference count on the */
-/* queue is correct. We can't, however, call fr_freetimeoutqueue because */
+/* ipf_deletetimeoutqueue is called to make sure the reference count on the */
+/* queue is correct. We can't, however, call ipf_freetimeoutqueue because */
/* the correct lock(s) may not be held that would make it safe to do so. */
/* ------------------------------------------------------------------------ */
-void fr_deletequeueentry(tqe)
-ipftqent_t *tqe;
+void
+ipf_deletequeueentry(tqe)
+ ipftqent_t *tqe;
{
ipftq_t *ifq;
@@ -5103,21 +5828,23 @@ ipftqent_t *tqe;
tqe->tqe_ifq = NULL;
}
- (void) fr_deletetimeoutqueue(ifq);
+ (void) ipf_deletetimeoutqueue(ifq);
+ ASSERT(ifq->ifq_ref > 0);
MUTEX_EXIT(&ifq->ifq_lock);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_queuefront */
+/* Function: ipf_queuefront */
/* Returns: Nil */
/* Parameters: tqe(I) - pointer to timeout queue entry */
/* */
/* Move a queue entry to the front of the queue, if it isn't already there. */
/* ------------------------------------------------------------------------ */
-void fr_queuefront(tqe)
-ipftqent_t *tqe;
+void
+ipf_queuefront(tqe)
+ ipftqent_t *tqe;
{
ipftq_t *ifq;
@@ -5143,21 +5870,27 @@ ipftqent_t *tqe;
/* ------------------------------------------------------------------------ */
-/* Function: fr_queueback */
+/* Function: ipf_queueback */
/* Returns: Nil */
-/* Parameters: tqe(I) - pointer to timeout queue entry */
+/* Parameters: ticks(I) - ipf tick time to use with this call */
+/* tqe(I) - pointer to timeout queue entry */
/* */
/* Move a queue entry to the back of the queue, if it isn't already there. */
+/* We use use ticks to calculate the expiration and mark for when we last */
+/* touched the structure. */
/* ------------------------------------------------------------------------ */
-void fr_queueback(tqe)
-ipftqent_t *tqe;
+void
+ipf_queueback(ticks, tqe)
+ u_long ticks;
+ ipftqent_t *tqe;
{
ipftq_t *ifq;
ifq = tqe->tqe_ifq;
if (ifq == NULL)
return;
- tqe->tqe_die = fr_ticks + ifq->ifq_ttl;
+ tqe->tqe_die = ticks + ifq->ifq_ttl;
+ tqe->tqe_touched = ticks;
MUTEX_ENTER(&ifq->ifq_lock);
if (tqe->tqe_next != NULL) { /* at the end already ? */
@@ -5180,18 +5913,23 @@ ipftqent_t *tqe;
/* ------------------------------------------------------------------------ */
-/* Function: fr_queueappend */
+/* Function: ipf_queueappend */
/* Returns: Nil */
-/* Parameters: tqe(I) - pointer to timeout queue entry */
+/* Parameters: ticks(I) - ipf tick time to use with this call */
+/* tqe(I) - pointer to timeout queue entry */
/* ifq(I) - pointer to timeout queue */
/* parent(I) - owing object pointer */
/* */
/* Add a new item to this queue and put it on the very end. */
+/* We use use ticks to calculate the expiration and mark for when we last */
+/* touched the structure. */
/* ------------------------------------------------------------------------ */
-void fr_queueappend(tqe, ifq, parent)
-ipftqent_t *tqe;
-ipftq_t *ifq;
-void *parent;
+void
+ipf_queueappend(ticks, tqe, ifq, parent)
+ u_long ticks;
+ ipftqent_t *tqe;
+ ipftq_t *ifq;
+ void *parent;
{
MUTEX_ENTER(&ifq->ifq_lock);
@@ -5201,14 +5939,15 @@ void *parent;
ifq->ifq_tail = &tqe->tqe_next;
tqe->tqe_next = NULL;
tqe->tqe_ifq = ifq;
- tqe->tqe_die = fr_ticks + ifq->ifq_ttl;
+ tqe->tqe_die = ticks + ifq->ifq_ttl;
+ tqe->tqe_touched = ticks;
ifq->ifq_ref++;
MUTEX_EXIT(&ifq->ifq_lock);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_movequeue */
+/* Function: ipf_movequeue */
/* Returns: Nil */
/* Parameters: tq(I) - pointer to timeout queue information */
/* oifp(I) - old timeout queue entry was on */
@@ -5218,58 +5957,82 @@ void *parent;
/* If it notices that the current entry is already last and does not need */
/* to move queue, the return. */
/* ------------------------------------------------------------------------ */
-void fr_movequeue(tqe, oifq, nifq)
-ipftqent_t *tqe;
-ipftq_t *oifq, *nifq;
+void
+ipf_movequeue(ticks, tqe, oifq, nifq)
+ u_long ticks;
+ ipftqent_t *tqe;
+ ipftq_t *oifq, *nifq;
{
+
/*
- * Is the operation here going to be a no-op ?
+ * If the queue hasn't changed and we last touched this entry at the
+ * same ipf time, then we're not going to achieve anything by either
+ * changing the ttl or moving it on the queue.
+ */
+ if (oifq == nifq && tqe->tqe_touched == ticks)
+ return;
+
+ /*
+ * For any of this to be outside the lock, there is a risk that two
+ * packets entering simultaneously, with one changing to a different
+ * queue and one not, could end up with things in a bizarre state.
*/
MUTEX_ENTER(&oifq->ifq_lock);
- if ((oifq != nifq) || (*oifq->ifq_tail != tqe)) {
- /*
- * Remove from the old queue
- */
- *tqe->tqe_pnext = tqe->tqe_next;
- if (tqe->tqe_next)
- tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
- else
- oifq->ifq_tail = tqe->tqe_pnext;
- tqe->tqe_next = NULL;
- /*
- * If we're moving from one queue to another, release the
- * lock on the old queue and get a lock on the new queue.
- * For user defined queues, if we're moving off it, call
- * delete in case it can now be freed.
- */
- if (oifq != nifq) {
- tqe->tqe_ifq = NULL;
+ tqe->tqe_touched = ticks;
+ tqe->tqe_die = ticks + nifq->ifq_ttl;
+ /*
+ * Is the operation here going to be a no-op ?
+ */
+ if (oifq == nifq) {
+ if ((tqe->tqe_next == NULL) ||
+ (tqe->tqe_next->tqe_die == tqe->tqe_die)) {
+ MUTEX_EXIT(&oifq->ifq_lock);
+ return;
+ }
+ }
- (void) fr_deletetimeoutqueue(oifq);
+ /*
+ * Remove from the old queue
+ */
+ *tqe->tqe_pnext = tqe->tqe_next;
+ if (tqe->tqe_next)
+ tqe->tqe_next->tqe_pnext = tqe->tqe_pnext;
+ else
+ oifq->ifq_tail = tqe->tqe_pnext;
+ tqe->tqe_next = NULL;
- MUTEX_EXIT(&oifq->ifq_lock);
+ /*
+ * If we're moving from one queue to another, release the
+ * lock on the old queue and get a lock on the new queue.
+ * For user defined queues, if we're moving off it, call
+ * delete in case it can now be freed.
+ */
+ if (oifq != nifq) {
+ tqe->tqe_ifq = NULL;
- MUTEX_ENTER(&nifq->ifq_lock);
+ (void) ipf_deletetimeoutqueue(oifq);
- tqe->tqe_ifq = nifq;
- nifq->ifq_ref++;
- }
+ MUTEX_EXIT(&oifq->ifq_lock);
- /*
- * Add to the bottom of the new queue
- */
- tqe->tqe_die = fr_ticks + nifq->ifq_ttl;
- tqe->tqe_pnext = nifq->ifq_tail;
- *nifq->ifq_tail = tqe;
- nifq->ifq_tail = &tqe->tqe_next;
+ MUTEX_ENTER(&nifq->ifq_lock);
+
+ tqe->tqe_ifq = nifq;
+ nifq->ifq_ref++;
}
+
+ /*
+ * Add to the bottom of the new queue
+ */
+ tqe->tqe_pnext = nifq->ifq_tail;
+ *nifq->ifq_tail = tqe;
+ nifq->ifq_tail = &tqe->tqe_next;
MUTEX_EXIT(&nifq->ifq_lock);
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_updateipid */
+/* Function: ipf_updateipid */
/* Returns: int - 0 == success, -1 == error (packet should be droppped) */
/* Parameters: fin(I) - pointer to packet information */
/* */
@@ -5280,23 +6043,24 @@ ipftq_t *oifq, *nifq;
/* the fragment cache for non-leading fragments. If a non-leading fragment */
/* has no match in the cache, return an error. */
/* ------------------------------------------------------------------------ */
-static int fr_updateipid(fin)
-fr_info_t *fin;
+static int
+ipf_updateipid(fin)
+ fr_info_t *fin;
{
u_short id, ido, sums;
u_32_t sumd, sum;
ip_t *ip;
if (fin->fin_off != 0) {
- sum = fr_ipid_knownfrag(fin);
+ sum = ipf_frag_ipidknown(fin);
if (sum == 0xffffffff)
return -1;
sum &= 0xffff;
id = (u_short)sum;
} else {
- id = fr_nextipid(fin);
+ id = ipf_nextipid(fin);
if (fin->fin_off == 0 && (fin->fin_flx & FI_FRAG) != 0)
- (void) fr_ipid_newfrag(fin, (u_32_t)id);
+ (void) ipf_frag_ipidnew(fin, (u_32_t)id);
}
ip = fin->fin_ip;
@@ -5317,7 +6081,7 @@ fr_info_t *fin;
#ifdef NEED_FRGETIFNAME
/* ------------------------------------------------------------------------ */
-/* Function: fr_getifname */
+/* Function: ipf_getifname */
/* Returns: char * - pointer to interface name */
/* Parameters: ifp(I) - pointer to network interface */
/* buffer(O) - pointer to where to store interface name */
@@ -5326,9 +6090,10 @@ fr_info_t *fin;
/* expected to be at least LIFNAMSIZ in bytes big. If buffer is passed in */
/* as a NULL pointer then return a pointer to a static array. */
/* ------------------------------------------------------------------------ */
-char *fr_getifname(ifp, buffer)
-struct ifnet *ifp;
-char *buffer;
+char *
+ipf_getifname(ifp, buffer)
+ struct ifnet *ifp;
+ char *buffer;
{
static char namebuf[LIFNAMSIZ];
# if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \
@@ -5350,7 +6115,7 @@ char *buffer;
;
unit = ifp->if_unit;
space = LIFNAMSIZ - (s - buffer);
- if (space > 0) {
+ if ((space > 0) && (unit >= 0)) {
# if defined(SNPRINTF) && defined(_KERNEL)
SNPRINTF(temp, sizeof(temp), "%d", unit);
# else
@@ -5365,7 +6130,7 @@ char *buffer;
/* ------------------------------------------------------------------------ */
-/* Function: fr_ioctlswitch */
+/* Function: ipf_ioctlswitch */
/* Returns: int - -1 continue processing, else ioctl return value */
/* Parameters: unit(I) - device unit opened */
/* data(I) - pointer to ioctl data */
@@ -5376,63 +6141,99 @@ char *buffer;
/* */
/* Based on the value of unit, call the appropriate ioctl handler or return */
/* EIO if ipfilter is not running. Also checks if write perms are req'd */
-/* for the device in order to execute the ioctl. */
+/* for the device in order to execute the ioctl. A special case is made */
+/* SIOCIPFINTERROR so that the same code isn't required in every handler. */
+/* The context data pointer is passed through as this is used as the key */
+/* for locating a matching token for continued access for walking lists, */
+/* etc. */
/* ------------------------------------------------------------------------ */
-int fr_ioctlswitch(unit, data, cmd, mode, uid, ctx)
-int unit, mode, uid;
-ioctlcmd_t cmd;
-void *data, *ctx;
+int
+ipf_ioctlswitch(softc, unit, data, cmd, mode, uid, ctx)
+ ipf_main_softc_t *softc;
+ int unit, mode, uid;
+ ioctlcmd_t cmd;
+ void *data, *ctx;
{
int error = 0;
+ switch (cmd)
+ {
+ case SIOCIPFINTERROR :
+ error = BCOPYOUT(&softc->ipf_interror, data,
+ sizeof(softc->ipf_interror));
+ if (error != 0) {
+ IPFERROR(40);
+ error = EFAULT;
+ }
+ return error;
+ default :
+ break;
+ }
+
switch (unit)
{
case IPL_LOGIPF :
- error = fr_ipf_ioctl(data, cmd, mode, uid, ctx);
+ error = ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx);
break;
case IPL_LOGNAT :
- if (fr_running > 0)
- error = fr_nat_ioctl(data, cmd, mode, uid, ctx);
- else
+ if (softc->ipf_running > 0) {
+ error = ipf_nat_ioctl(softc, data, cmd, mode,
+ uid, ctx);
+ } else {
+ IPFERROR(42);
error = EIO;
+ }
break;
case IPL_LOGSTATE :
- if (fr_running > 0)
- error = fr_state_ioctl(data, cmd, mode, uid, ctx);
- else
+ if (softc->ipf_running > 0) {
+ error = ipf_state_ioctl(softc, data, cmd, mode,
+ uid, ctx);
+ } else {
+ IPFERROR(43);
error = EIO;
+ }
break;
case IPL_LOGAUTH :
- if (fr_running > 0)
- error = fr_auth_ioctl(data, cmd, mode, uid, ctx);
- else
+ if (softc->ipf_running > 0) {
+ error = ipf_auth_ioctl(softc, data, cmd, mode,
+ uid, ctx);
+ } else {
+ IPFERROR(44);
error = EIO;
+ }
break;
case IPL_LOGSYNC :
-#ifdef IPFILTER_SYNC
- if (fr_running > 0)
- error = fr_sync_ioctl(data, cmd, mode, uid, ctx);
- else
-#endif
+ if (softc->ipf_running > 0) {
+ error = ipf_sync_ioctl(softc, data, cmd, mode,
+ uid, ctx);
+ } else {
error = EIO;
+ IPFERROR(45);
+ }
break;
case IPL_LOGSCAN :
#ifdef IPFILTER_SCAN
- if (fr_running > 0)
- error = fr_scan_ioctl(data, cmd, mode, uid, ctx);
+ if (softc->ipf_running > 0)
+ error = ipf_scan_ioctl(softc, data, cmd, mode,
+ uid, ctx);
else
#endif
+ {
error = EIO;
+ IPFERROR(46);
+ }
break;
case IPL_LOGLOOKUP :
-#ifdef IPFILTER_LOOKUP
- if (fr_running > 0)
- error = ip_lookup_ioctl(data, cmd, mode, uid, ctx);
- else
-#endif
+ if (softc->ipf_running > 0) {
+ error = ipf_lookup_ioctl(softc, data, cmd, mode,
+ uid, ctx);
+ } else {
error = EIO;
+ IPFERROR(47);
+ }
break;
default :
+ IPFERROR(48);
error = EIO;
break;
}
@@ -5443,200 +6244,244 @@ void *data, *ctx;
/*
* This array defines the expected size of objects coming into the kernel
- * for the various recognised object types.
+ * for the various recognised object types. The first column is flags (see
+ * below), 2nd column is current size, 3rd column is the version number of
+ * when the current size became current.
+ * Flags:
+ * 1 = minimum size, not absolute size
*/
-static int fr_objbytes[IPFOBJ_COUNT][2] = {
- { 1, sizeof(struct frentry) }, /* frentry */
- { 0, sizeof(struct friostat) },
- { 0, sizeof(struct fr_info) },
- { 0, sizeof(struct fr_authstat) },
- { 0, sizeof(struct ipfrstat) },
- { 0, sizeof(struct ipnat) },
- { 0, sizeof(struct natstat) },
- { 0, sizeof(struct ipstate_save) },
- { 1, sizeof(struct nat_save) }, /* nat_save */
- { 0, sizeof(struct natlookup) },
- { 1, sizeof(struct ipstate) }, /* ipstate */
- { 0, sizeof(struct ips_stat) },
- { 0, sizeof(struct frauth) },
- { 0, sizeof(struct ipftune) },
- { 0, sizeof(struct nat) }, /* nat_t */
- { 0, sizeof(struct ipfruleiter) },
- { 0, sizeof(struct ipfgeniter) },
- { 0, sizeof(struct ipftable) },
- { 0, sizeof(struct ipflookupiter) },
+static int ipf_objbytes[IPFOBJ_COUNT][3] = {
+ { 1, sizeof(struct frentry), 5010000 }, /* 0 */
+ { 1, sizeof(struct friostat), 5010000 },
+ { 0, sizeof(struct fr_info), 5010000 },
+ { 0, sizeof(struct ipf_authstat), 4010100 },
+ { 0, sizeof(struct ipfrstat), 5010000 },
+ { 1, sizeof(struct ipnat), 5010000 }, /* 5 */
+ { 0, sizeof(struct natstat), 5010000 },
+ { 0, sizeof(struct ipstate_save), 5010000 },
+ { 1, sizeof(struct nat_save), 5010000 },
+ { 0, sizeof(struct natlookup), 5010000 },
+ { 1, sizeof(struct ipstate), 5010000 }, /* 10 */
+ { 0, sizeof(struct ips_stat), 5010000 },
+ { 0, sizeof(struct frauth), 5010000 },
+ { 0, sizeof(struct ipftune), 4010100 },
+ { 0, sizeof(struct nat), 5010000 },
+ { 0, sizeof(struct ipfruleiter), 4011400 }, /* 15 */
+ { 0, sizeof(struct ipfgeniter), 4011400 },
+ { 0, sizeof(struct ipftable), 4011400 },
+ { 0, sizeof(struct ipflookupiter), 4011400 },
{ 0, sizeof(struct ipftq) * IPF_TCP_NSTATES },
+ { 1, 0, 0 }, /* IPFEXPR */
+ { 0, 0, 0 }, /* PROXYCTL */
+ { 0, sizeof (struct fripf), 5010000 }
};
/* ------------------------------------------------------------------------ */
-/* Function: fr_inobj */
+/* Function: ipf_inobj */
/* Returns: int - 0 = success, else failure */
-/* Parameters: data(I) - pointer to ioctl data */
-/* ptr(I) - pointer to store real data in */
-/* type(I) - type of structure being moved */
+/* Parameters: softc(I) - soft context pointerto work with */
+/* data(I) - pointer to ioctl data */
+/* objp(O) - where to store ipfobj structure */
+/* ptr(I) - pointer to data to copy out */
+/* type(I) - type of structure being moved */
/* */
/* Copy in the contents of what the ipfobj_t points to. In future, we */
/* add things to check for version numbers, sizes, etc, to make it backward */
/* compatible at the ABI for user land. */
+/* If objp is not NULL then we assume that the caller wants to see what is */
+/* in the ipfobj_t structure being copied in. As an example, this can tell */
+/* the caller what version of ipfilter the ioctl program was written to. */
/* ------------------------------------------------------------------------ */
-int fr_inobj(data, ptr, type)
-void *data;
-void *ptr;
-int type;
+int
+ipf_inobj(softc, data, objp, ptr, type)
+ ipf_main_softc_t *softc;
+ void *data;
+ ipfobj_t *objp;
+ void *ptr;
+ int type;
{
ipfobj_t obj;
- int error = 0;
+ int error;
+ int size;
- if ((type < 0) || (type >= IPFOBJ_COUNT))
+ if ((type < 0) || (type >= IPFOBJ_COUNT)) {
+ IPFERROR(49);
return EINVAL;
+ }
- error = BCOPYIN(data, &obj, sizeof(obj));
- if (error != 0)
+ if (objp == NULL)
+ objp = &obj;
+ error = BCOPYIN(data, objp, sizeof(*objp));
+ if (error != 0) {
+ IPFERROR(124);
return EFAULT;
+ }
- if (obj.ipfo_type != type)
+ if (objp->ipfo_type != type) {
+ IPFERROR(50);
return EINVAL;
+ }
-#ifndef IPFILTER_COMPAT
- if ((fr_objbytes[type][0] & 1) != 0) {
- if (obj.ipfo_size < fr_objbytes[type][1])
+ if (objp->ipfo_rev >= ipf_objbytes[type][2]) {
+ if ((ipf_objbytes[type][0] & 1) != 0) {
+ if (objp->ipfo_size < ipf_objbytes[type][1]) {
+ IPFERROR(51);
+ return EINVAL;
+ }
+ size = ipf_objbytes[type][1];
+ } else if (objp->ipfo_size == ipf_objbytes[type][1]) {
+ size = objp->ipfo_size;
+ } else {
+ IPFERROR(52);
return EINVAL;
- } else if (obj.ipfo_size != fr_objbytes[type][1]) {
- return EINVAL;
- }
+ }
+ error = COPYIN(objp->ipfo_ptr, ptr, size);
+ if (error != 0) {
+ IPFERROR(55);
+ error = EFAULT;
+ }
+ } else {
+#ifdef IPFILTER_COMPAT
+ error = ipf_in_compat(softc, objp, ptr, 0);
#else
- if (obj.ipfo_rev != IPFILTER_VERSION)
- /* XXX compatibility hook here */
- ;
- if ((fr_objbytes[type][0] & 1) != 0) {
- if (obj.ipfo_size < fr_objbytes[type][1])
- /* XXX compatibility hook here */
- return EINVAL;
- } else if (obj.ipfo_size != fr_objbytes[type][1])
- /* XXX compatibility hook here */
- return EINVAL;
+ IPFERROR(54);
+ error = EINVAL;
#endif
-
- if ((fr_objbytes[type][0] & 1) != 0) {
- error = COPYIN(obj.ipfo_ptr, ptr, fr_objbytes[type][1]);
- } else {
- error = COPYIN(obj.ipfo_ptr, ptr, obj.ipfo_size);
}
- if (error != 0)
- error = EFAULT;
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_inobjsz */
+/* Function: ipf_inobjsz */
/* Returns: int - 0 = success, else failure */
-/* Parameters: data(I) - pointer to ioctl data */
-/* ptr(I) - pointer to store real data in */
-/* type(I) - type of structure being moved */
-/* sz(I) - size of data to copy */
+/* Parameters: softc(I) - soft context pointerto work with */
+/* data(I) - pointer to ioctl data */
+/* ptr(I) - pointer to store real data in */
+/* type(I) - type of structure being moved */
+/* sz(I) - size of data to copy */
/* */
-/* As per fr_inobj, except the size of the object to copy in is passed in */
+/* As per ipf_inobj, except the size of the object to copy in is passed in */
/* but it must not be smaller than the size defined for the type and the */
/* type must allow for varied sized objects. The extra requirement here is */
/* that sz must match the size of the object being passed in - this is not */
-/* not possible nor required in fr_inobj(). */
+/* not possible nor required in ipf_inobj(). */
/* ------------------------------------------------------------------------ */
-int fr_inobjsz(data, ptr, type, sz)
-void *data;
-void *ptr;
-int type, sz;
+int
+ipf_inobjsz(softc, data, ptr, type, sz)
+ ipf_main_softc_t *softc;
+ void *data;
+ void *ptr;
+ int type, sz;
{
ipfobj_t obj;
int error;
- if ((type < 0) || (type >= IPFOBJ_COUNT))
- return EINVAL;
- if (((fr_objbytes[type][0] & 1) == 0) || (sz < fr_objbytes[type][1]))
+ if ((type < 0) || (type >= IPFOBJ_COUNT)) {
+ IPFERROR(56);
return EINVAL;
+ }
error = BCOPYIN(data, &obj, sizeof(obj));
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(125);
return EFAULT;
+ }
- if (obj.ipfo_type != type)
+ if (obj.ipfo_type != type) {
+ IPFERROR(58);
return EINVAL;
+ }
-#ifndef IPFILTER_COMPAT
- if (obj.ipfo_size != sz)
- return EINVAL;
+ if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
+ if (((ipf_objbytes[type][0] & 1) == 0) ||
+ (sz < ipf_objbytes[type][1])) {
+ IPFERROR(57);
+ return EINVAL;
+ }
+ error = COPYIN(obj.ipfo_ptr, ptr, sz);
+ if (error != 0) {
+ IPFERROR(61);
+ error = EFAULT;
+ }
+ } else {
+#ifdef IPFILTER_COMPAT
+ error = ipf_in_compat(softc, &obj, ptr, sz);
#else
- if (obj.ipfo_rev != IPFILTER_VERSION)
- /* XXX compatibility hook here */
- ;
- if (obj.ipfo_size != sz)
- /* XXX compatibility hook here */
- return EINVAL;
+ IPFERROR(60);
+ error = EINVAL;
#endif
-
- error = COPYIN(obj.ipfo_ptr, ptr, sz);
- if (error != 0)
- error = EFAULT;
+ }
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_outobjsz */
+/* Function: ipf_outobjsz */
/* Returns: int - 0 = success, else failure */
/* Parameters: data(I) - pointer to ioctl data */
/* ptr(I) - pointer to store real data in */
/* type(I) - type of structure being moved */
/* sz(I) - size of data to copy */
/* */
-/* As per fr_outobj, except the size of the object to copy out is passed in */
+/* As per ipf_outobj, except the size of the object to copy out is passed in*/
/* but it must not be smaller than the size defined for the type and the */
/* type must allow for varied sized objects. The extra requirement here is */
/* that sz must match the size of the object being passed in - this is not */
-/* not possible nor required in fr_outobj(). */
+/* not possible nor required in ipf_outobj(). */
/* ------------------------------------------------------------------------ */
-int fr_outobjsz(data, ptr, type, sz)
-void *data;
-void *ptr;
-int type, sz;
+int
+ipf_outobjsz(softc, data, ptr, type, sz)
+ ipf_main_softc_t *softc;
+ void *data;
+ void *ptr;
+ int type, sz;
{
ipfobj_t obj;
int error;
- if ((type < 0) || (type >= IPFOBJ_COUNT) ||
- ((fr_objbytes[type][0] & 1) == 0) ||
- (sz < fr_objbytes[type][1]))
+ if ((type < 0) || (type >= IPFOBJ_COUNT)) {
+ IPFERROR(62);
return EINVAL;
+ }
error = BCOPYIN(data, &obj, sizeof(obj));
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(127);
return EFAULT;
+ }
- if (obj.ipfo_type != type)
+ if (obj.ipfo_type != type) {
+ IPFERROR(63);
return EINVAL;
+ }
-#ifndef IPFILTER_COMPAT
- if (obj.ipfo_size != sz)
- return EINVAL;
+ if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
+ if (((ipf_objbytes[type][0] & 1) == 0) ||
+ (sz < ipf_objbytes[type][1])) {
+ IPFERROR(146);
+ return EINVAL;
+ }
+ error = COPYOUT(ptr, obj.ipfo_ptr, sz);
+ if (error != 0) {
+ IPFERROR(66);
+ error = EFAULT;
+ }
+ } else {
+#ifdef IPFILTER_COMPAT
+ error = ipf_out_compat(softc, &obj, ptr);
#else
- if (obj.ipfo_rev != IPFILTER_VERSION)
- /* XXX compatibility hook here */
- ;
- if (obj.ipfo_size != sz)
- /* XXX compatibility hook here */
- return EINVAL;
+ IPFERROR(65);
+ error = EINVAL;
#endif
-
- error = COPYOUT(ptr, obj.ipfo_ptr, sz);
- if (error != 0)
- error = EFAULT;
+ }
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_outobj */
+/* Function: ipf_outobj */
/* Returns: int - 0 = success, else failure */
/* Parameters: data(I) - pointer to ioctl data */
/* ptr(I) - pointer to store real data in */
@@ -5646,75 +6491,134 @@ int type, sz;
/* future, we add things to check for version numbers, sizes, etc, to make */
/* it backward compatible at the ABI for user land. */
/* ------------------------------------------------------------------------ */
-int fr_outobj(data, ptr, type)
-void *data;
-void *ptr;
-int type;
+int
+ipf_outobj(softc, data, ptr, type)
+ ipf_main_softc_t *softc;
+ void *data;
+ void *ptr;
+ int type;
{
ipfobj_t obj;
int error;
- if ((type < 0) || (type >= IPFOBJ_COUNT))
+ if ((type < 0) || (type >= IPFOBJ_COUNT)) {
+ IPFERROR(67);
return EINVAL;
+ }
error = BCOPYIN(data, &obj, sizeof(obj));
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(126);
return EFAULT;
+ }
- if (obj.ipfo_type != type)
+ if (obj.ipfo_type != type) {
+ IPFERROR(68);
return EINVAL;
+ }
-#ifndef IPFILTER_COMPAT
- if ((fr_objbytes[type][0] & 1) != 0) {
- if (obj.ipfo_size < fr_objbytes[type][1])
+ if (obj.ipfo_rev >= ipf_objbytes[type][2]) {
+ if ((ipf_objbytes[type][0] & 1) != 0) {
+ if (obj.ipfo_size < ipf_objbytes[type][1]) {
+ IPFERROR(69);
+ return EINVAL;
+ }
+ } else if (obj.ipfo_size != ipf_objbytes[type][1]) {
+ IPFERROR(70);
return EINVAL;
- } else if (obj.ipfo_size != fr_objbytes[type][1])
- return EINVAL;
+ }
+
+ error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size);
+ if (error != 0) {
+ IPFERROR(73);
+ error = EFAULT;
+ }
+ } else {
+#ifdef IPFILTER_COMPAT
+ error = ipf_out_compat(softc, &obj, ptr);
#else
- if (obj.ipfo_rev != IPFILTER_VERSION)
- /* XXX compatibility hook here */
- ;
- if ((fr_objbytes[type][0] & 1) != 0) {
- if (obj.ipfo_size < fr_objbytes[type][1])
- /* XXX compatibility hook here */
- return EINVAL;
- } else if (obj.ipfo_size != fr_objbytes[type][1])
- /* XXX compatibility hook here */
- return EINVAL;
+ IPFERROR(72);
+ error = EINVAL;
#endif
+ }
+ return error;
+}
- error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size);
- if (error != 0)
- error = EFAULT;
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_outobjk */
+/* Returns: int - 0 = success, else failure */
+/* Parameters: obj(I) - pointer to data description structure */
+/* ptr(I) - pointer to kernel data to copy out */
+/* */
+/* In the above functions, the ipfobj_t structure is copied into the kernel,*/
+/* telling ipfilter how to copy out data. In this instance, the ipfobj_t is */
+/* already populated with information and now we just need to use it. */
+/* There is no need for this function to have a "type" parameter as there */
+/* is no point in validating information that comes from the kernel with */
+/* itself. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_outobjk(softc, obj, ptr)
+ ipf_main_softc_t *softc;
+ ipfobj_t *obj;
+ void *ptr;
+{
+ int type = obj->ipfo_type;
+ int error;
+
+ if ((type < 0) || (type >= IPFOBJ_COUNT)) {
+ IPFERROR(147);
+ return EINVAL;
+ }
+
+ if (obj->ipfo_rev >= ipf_objbytes[type][2]) {
+ if ((ipf_objbytes[type][0] & 1) != 0) {
+ if (obj->ipfo_size < ipf_objbytes[type][1]) {
+ IPFERROR(148);
+ return EINVAL;
+ }
+
+ } else if (obj->ipfo_size != ipf_objbytes[type][1]) {
+ IPFERROR(149);
+ return EINVAL;
+ }
+
+ error = COPYOUT(ptr, obj->ipfo_ptr, obj->ipfo_size);
+ if (error != 0) {
+ IPFERROR(150);
+ error = EFAULT;
+ }
+ } else {
+#ifdef IPFILTER_COMPAT
+ error = ipf_out_compat(softc, obj, ptr);
+#else
+ IPFERROR(151);
+ error = EINVAL;
+#endif
+ }
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_checkl4sum */
+/* Function: ipf_checkl4sum */
/* Returns: int - 0 = good, -1 = bad, 1 = cannot check */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* If possible, calculate the layer 4 checksum for the packet. If this is */
/* not possible, return without indicating a failure or success but in a */
-/* way that is ditinguishable. */
+/* way that is ditinguishable. This function should only be called by the */
+/* ipf_checkv6sum() for each platform. */
/* ------------------------------------------------------------------------ */
-int fr_checkl4sum(fin)
-fr_info_t *fin;
+INLINE int
+ipf_checkl4sum(fin)
+ fr_info_t *fin;
{
u_short sum, hdrsum, *csump;
udphdr_t *udp;
int dosum;
- if ((fin->fin_flx & FI_NOCKSUM) != 0)
- return 0;
-
- if (fin->fin_cksum == 1)
- return 0;
-
- if (fin->fin_cksum == -1)
- return -1;
-
/*
* If the TCP packet isn't a fragment, isn't too short and otherwise
* isn't already considered "bad", then validate the checksum. If
@@ -5728,48 +6632,44 @@ fr_info_t *fin;
dosum = 0;
sum = 0;
-#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID)
- if (dohwcksum && ((*fin->fin_mp)->b_ick_flag == ICK_VALID)) {
- hdrsum = 0;
- sum = 0;
- } else {
-#endif
- switch (fin->fin_p)
- {
- case IPPROTO_TCP :
- csump = &((tcphdr_t *)fin->fin_dp)->th_sum;
+ switch (fin->fin_p)
+ {
+ case IPPROTO_TCP :
+ csump = &((tcphdr_t *)fin->fin_dp)->th_sum;
+ dosum = 1;
+ break;
+
+ case IPPROTO_UDP :
+ udp = fin->fin_dp;
+ if (udp->uh_sum != 0) {
+ csump = &udp->uh_sum;
dosum = 1;
- break;
+ }
+ break;
- case IPPROTO_UDP :
- udp = fin->fin_dp;
- if (udp->uh_sum != 0) {
- csump = &udp->uh_sum;
- dosum = 1;
- }
- break;
+#ifdef USE_INET6
+ case IPPROTO_ICMPV6 :
+ csump = &((struct icmp6_hdr *)fin->fin_dp)->icmp6_cksum;
+ dosum = 1;
+ break;
+#endif
- case IPPROTO_ICMP :
- csump = &((struct icmp *)fin->fin_dp)->icmp_cksum;
- dosum = 1;
- break;
+ case IPPROTO_ICMP :
+ csump = &((struct icmp *)fin->fin_dp)->icmp_cksum;
+ dosum = 1;
+ break;
- default :
- return 1;
- /*NOTREACHED*/
- }
+ default :
+ return 1;
+ /*NOTREACHED*/
+ }
- if (csump != NULL)
- hdrsum = *csump;
+ if (csump != NULL)
+ hdrsum = *csump;
- if (dosum) {
- sum = fr_cksum(fin->fin_m, fin->fin_ip,
- fin->fin_p, fin->fin_dp,
- fin->fin_dlen + fin->fin_hlen);
- }
-#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID)
+ if (dosum) {
+ sum = fr_cksum(fin, fin->fin_ip, fin->fin_p, fin->fin_dp);
}
-#endif
#if !defined(_KERNEL)
if (sum == hdrsum) {
FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum));
@@ -5777,17 +6677,18 @@ fr_info_t *fin;
FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum));
}
#endif
+ DT2(l4sums, u_short, hdrsum, u_short, sum);
if (hdrsum == sum) {
- fin->fin_cksum = 1;
+ fin->fin_cksum = FI_CK_SUMOK;
return 0;
}
- fin->fin_cksum = -1;
+ fin->fin_cksum = FI_CK_BAD;
return -1;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_ifpfillv4addr */
+/* Function: ipf_ifpfillv4addr */
/* Returns: int - 0 = address update, -1 = address not updated */
/* Parameters: atype(I) - type of network address update to perform */
/* sin(I) - pointer to source of address information */
@@ -5802,10 +6703,11 @@ fr_info_t *fin;
/* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */
/* value. */
/* ------------------------------------------------------------------------ */
-int fr_ifpfillv4addr(atype, sin, mask, inp, inpmask)
-int atype;
-struct sockaddr_in *sin, *mask;
-struct in_addr *inp, *inpmask;
+int
+ipf_ifpfillv4addr(atype, sin, mask, inp, inpmask)
+ int atype;
+ struct sockaddr_in *sin, *mask;
+ struct in_addr *inp, *inpmask;
{
if (inpmask != NULL && atype != FRI_NETMASKED)
inpmask->s_addr = 0xffffffff;
@@ -5826,7 +6728,7 @@ struct in_addr *inp, *inpmask;
#ifdef USE_INET6
/* ------------------------------------------------------------------------ */
-/* Function: fr_ifpfillv6addr */
+/* Function: ipf_ifpfillv6addr */
/* Returns: int - 0 = address update, -1 = address not updated */
/* Parameters: atype(I) - type of network address update to perform */
/* sin(I) - pointer to source of address information */
@@ -5841,44 +6743,43 @@ struct in_addr *inp, *inpmask;
/* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */
/* value. */
/* ------------------------------------------------------------------------ */
-int fr_ifpfillv6addr(atype, sin, mask, inp, inpmask)
-int atype;
-struct sockaddr_in6 *sin, *mask;
-struct in_addr *inp, *inpmask;
+int
+ipf_ifpfillv6addr(atype, sin, mask, inp, inpmask)
+ int atype;
+ struct sockaddr_in6 *sin, *mask;
+ i6addr_t *inp, *inpmask;
{
- i6addr_t *src, *dst, *and, *dmask;
+ i6addr_t *src, *and;
src = (i6addr_t *)&sin->sin6_addr;
and = (i6addr_t *)&mask->sin6_addr;
- dst = (i6addr_t *)inp;
- dmask = (i6addr_t *)inpmask;
if (inpmask != NULL && atype != FRI_NETMASKED) {
- dmask->i6[0] = 0xffffffff;
- dmask->i6[1] = 0xffffffff;
- dmask->i6[2] = 0xffffffff;
- dmask->i6[3] = 0xffffffff;
+ inpmask->i6[0] = 0xffffffff;
+ inpmask->i6[1] = 0xffffffff;
+ inpmask->i6[2] = 0xffffffff;
+ inpmask->i6[3] = 0xffffffff;
}
if (atype == FRI_NETWORK || atype == FRI_NETMASKED) {
if (atype == FRI_NETMASKED) {
if (inpmask == NULL)
return -1;
- dmask->i6[0] = and->i6[0];
- dmask->i6[1] = and->i6[1];
- dmask->i6[2] = and->i6[2];
- dmask->i6[3] = and->i6[3];
+ inpmask->i6[0] = and->i6[0];
+ inpmask->i6[1] = and->i6[1];
+ inpmask->i6[2] = and->i6[2];
+ inpmask->i6[3] = and->i6[3];
}
- dst->i6[0] = src->i6[0] & and->i6[0];
- dst->i6[1] = src->i6[1] & and->i6[1];
- dst->i6[2] = src->i6[2] & and->i6[2];
- dst->i6[3] = src->i6[3] & and->i6[3];
+ inp->i6[0] = src->i6[0] & and->i6[0];
+ inp->i6[1] = src->i6[1] & and->i6[1];
+ inp->i6[2] = src->i6[2] & and->i6[2];
+ inp->i6[3] = src->i6[3] & and->i6[3];
} else {
- dst->i6[0] = src->i6[0];
- dst->i6[1] = src->i6[1];
- dst->i6[2] = src->i6[2];
- dst->i6[3] = src->i6[3];
+ inp->i6[0] = src->i6[0];
+ inp->i6[1] = src->i6[1];
+ inp->i6[2] = src->i6[2];
+ inp->i6[3] = src->i6[3];
}
return 0;
}
@@ -5886,7 +6787,7 @@ struct in_addr *inp, *inpmask;
/* ------------------------------------------------------------------------ */
-/* Function: fr_matchtag */
+/* Function: ipf_matchtag */
/* Returns: 0 == mismatch, 1 == match. */
/* Parameters: tag1(I) - pointer to first tag to compare */
/* tag2(I) - pointer to second tag to compare */
@@ -5898,8 +6799,9 @@ struct in_addr *inp, *inpmask;
/* comparison. This function should only be called with both tag1 and tag2 */
/* as non-NULL pointers. */
/* ------------------------------------------------------------------------ */
-int fr_matchtag(tag1, tag2)
-ipftag_t *tag1, *tag2;
+int
+ipf_matchtag(tag1, tag2)
+ ipftag_t *tag1, *tag2;
{
if (tag1 == tag2)
return 1;
@@ -5917,16 +6819,18 @@ ipftag_t *tag1, *tag2;
/* ------------------------------------------------------------------------ */
-/* Function: fr_coalesce */
+/* Function: ipf_coalesce */
/* Returns: 1 == success, -1 == failure, 0 == no change */
/* Parameters: fin(I) - pointer to packet information */
/* */
/* Attempt to get all of the packet data into a single, contiguous buffer. */
/* If this call returns a failure then the buffers have also been freed. */
/* ------------------------------------------------------------------------ */
-int fr_coalesce(fin)
-fr_info_t *fin;
+int
+ipf_coalesce(fin)
+ fr_info_t *fin;
{
+
if ((fin->fin_flx & FI_COALESCE) != 0)
return 1;
@@ -5938,11 +6842,15 @@ fr_info_t *fin;
return 0;
#if defined(_KERNEL)
- if (fr_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) {
- ATOMIC_INCL(fr_badcoalesces[fin->fin_out]);
+ if (ipf_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) {
+ ipf_main_softc_t *softc = fin->fin_main_soft;
+
+ DT1(frb_coalesce, fr_info_t *, fin);
+ LBUMP(ipf_stats[fin->fin_out].fr_badcoalesces);
# ifdef MENTAT
FREE_MB_T(*fin->fin_mp);
# endif
+ fin->fin_reason = FRB_COALESCE;
*fin->fin_mp = NULL;
fin->fin_m = NULL;
return -1;
@@ -5967,114 +6875,10 @@ fr_info_t *fin;
* The obvious implication is if neither of these are set then the value can be
* changed at any time without harm.
*/
-ipftuneable_t ipf_tuneables[] = {
- /* filtering */
- { { &fr_flags }, "fr_flags", 0, 0xffffffff,
- sizeof(fr_flags), 0, NULL },
- { { &fr_active }, "fr_active", 0, 0,
- sizeof(fr_active), IPFT_RDONLY, NULL },
- { { &fr_control_forwarding }, "fr_control_forwarding", 0, 1,
- sizeof(fr_control_forwarding), 0, NULL },
- { { &fr_update_ipid }, "fr_update_ipid", 0, 1,
- sizeof(fr_update_ipid), 0, NULL },
- { { &fr_chksrc }, "fr_chksrc", 0, 1,
- sizeof(fr_chksrc), 0, NULL },
- { { &fr_minttl }, "fr_minttl", 0, 1,
- sizeof(fr_minttl), 0, NULL },
- { { &fr_icmpminfragmtu }, "fr_icmpminfragmtu", 0, 1,
- sizeof(fr_icmpminfragmtu), 0, NULL },
- { { &fr_pass }, "fr_pass", 0, 0xffffffff,
- sizeof(fr_pass), 0, NULL },
- /* state */
- { { &fr_tcpidletimeout }, "fr_tcpidletimeout", 1, 0x7fffffff,
- sizeof(fr_tcpidletimeout), IPFT_WRDISABLED, NULL },
- { { &fr_tcpclosewait }, "fr_tcpclosewait", 1, 0x7fffffff,
- sizeof(fr_tcpclosewait), IPFT_WRDISABLED, NULL },
- { { &fr_tcplastack }, "fr_tcplastack", 1, 0x7fffffff,
- sizeof(fr_tcplastack), IPFT_WRDISABLED, NULL },
- { { &fr_tcptimeout }, "fr_tcptimeout", 1, 0x7fffffff,
- sizeof(fr_tcptimeout), IPFT_WRDISABLED, NULL },
- { { &fr_tcpclosed }, "fr_tcpclosed", 1, 0x7fffffff,
- sizeof(fr_tcpclosed), IPFT_WRDISABLED, NULL },
- { { &fr_tcphalfclosed }, "fr_tcphalfclosed", 1, 0x7fffffff,
- sizeof(fr_tcphalfclosed), IPFT_WRDISABLED, NULL },
- { { &fr_udptimeout }, "fr_udptimeout", 1, 0x7fffffff,
- sizeof(fr_udptimeout), IPFT_WRDISABLED, NULL },
- { { &fr_udpacktimeout }, "fr_udpacktimeout", 1, 0x7fffffff,
- sizeof(fr_udpacktimeout), IPFT_WRDISABLED, NULL },
- { { &fr_icmptimeout }, "fr_icmptimeout", 1, 0x7fffffff,
- sizeof(fr_icmptimeout), IPFT_WRDISABLED, NULL },
- { { &fr_icmpacktimeout }, "fr_icmpacktimeout", 1, 0x7fffffff,
- sizeof(fr_icmpacktimeout), IPFT_WRDISABLED, NULL },
- { { &fr_iptimeout }, "fr_iptimeout", 1, 0x7fffffff,
- sizeof(fr_iptimeout), IPFT_WRDISABLED, NULL },
- { { &fr_statemax }, "fr_statemax", 1, 0x7fffffff,
- sizeof(fr_statemax), 0, NULL },
- { { &fr_statesize }, "fr_statesize", 1, 0x7fffffff,
- sizeof(fr_statesize), IPFT_WRDISABLED, NULL },
- { { &fr_state_lock }, "fr_state_lock", 0, 1,
- sizeof(fr_state_lock), IPFT_RDONLY, NULL },
- { { &fr_state_maxbucket }, "fr_state_maxbucket", 1, 0x7fffffff,
- sizeof(fr_state_maxbucket), IPFT_WRDISABLED, NULL },
- { { &fr_state_maxbucket_reset }, "fr_state_maxbucket_reset", 0, 1,
- sizeof(fr_state_maxbucket_reset), IPFT_WRDISABLED, NULL },
- { { &ipstate_logging }, "ipstate_logging", 0, 1,
- sizeof(ipstate_logging), 0, NULL },
- /* nat */
- { { &fr_nat_lock }, "fr_nat_lock", 0, 1,
- sizeof(fr_nat_lock), IPFT_RDONLY, NULL },
- { { &ipf_nattable_sz }, "ipf_nattable_sz", 1, 0x7fffffff,
- sizeof(ipf_nattable_sz), IPFT_WRDISABLED, NULL },
- { { &ipf_nattable_max }, "ipf_nattable_max", 1, 0x7fffffff,
- sizeof(ipf_nattable_max), 0, NULL },
- { { &ipf_natrules_sz }, "ipf_natrules_sz", 1, 0x7fffffff,
- sizeof(ipf_natrules_sz), IPFT_WRDISABLED, NULL },
- { { &ipf_rdrrules_sz }, "ipf_rdrrules_sz", 1, 0x7fffffff,
- sizeof(ipf_rdrrules_sz), IPFT_WRDISABLED, NULL },
- { { &ipf_hostmap_sz }, "ipf_hostmap_sz", 1, 0x7fffffff,
- sizeof(ipf_hostmap_sz), IPFT_WRDISABLED, NULL },
- { { &fr_nat_maxbucket }, "fr_nat_maxbucket", 1, 0x7fffffff,
- sizeof(fr_nat_maxbucket), 0, NULL },
- { { &fr_nat_maxbucket_reset }, "fr_nat_maxbucket_reset", 0, 1,
- sizeof(fr_nat_maxbucket_reset), IPFT_WRDISABLED, NULL },
- { { &nat_logging }, "nat_logging", 0, 1,
- sizeof(nat_logging), 0, NULL },
- { { &fr_defnatage }, "fr_defnatage", 1, 0x7fffffff,
- sizeof(fr_defnatage), IPFT_WRDISABLED, NULL },
- { { &fr_defnatipage }, "fr_defnatipage", 1, 0x7fffffff,
- sizeof(fr_defnatipage), IPFT_WRDISABLED, NULL },
- { { &fr_defnaticmpage }, "fr_defnaticmpage", 1, 0x7fffffff,
- sizeof(fr_defnaticmpage), IPFT_WRDISABLED, NULL },
- { { &fr_nat_doflush }, "fr_nat_doflush", 0, 1,
- sizeof(fr_nat_doflush), 0, NULL },
- /* proxy */
- { { &ipf_proxy_debug }, "ipf_proxy_debug", 0, 10,
- sizeof(ipf_proxy_debug), 0, 0 },
- /* frag */
- { { &ipfr_size }, "ipfr_size", 1, 0x7fffffff,
- sizeof(ipfr_size), IPFT_WRDISABLED, NULL },
- { { &fr_ipfrttl }, "fr_ipfrttl", 1, 0x7fffffff,
- sizeof(fr_ipfrttl), IPFT_WRDISABLED, NULL },
-#ifdef IPFILTER_LOG
- /* log */
- { { &ipl_suppress }, "ipl_suppress", 0, 1,
- sizeof(ipl_suppress), 0, NULL },
- { { &ipl_logmax }, "ipl_logmax", 0, 0x7fffffff,
- sizeof(ipl_logmax), IPFT_WRDISABLED, NULL },
- { { &ipl_logall }, "ipl_logall", 0, 1,
- sizeof(ipl_logall), 0, NULL },
- { { &ipl_logsize }, "ipl_logsize", 0, 0x80000,
- sizeof(ipl_logsize), 0, NULL },
-#endif
- { { NULL }, NULL, 0, 0,
- 0, 0, NULL }
-};
-
-static ipftuneable_t *ipf_tunelist = NULL;
/* ------------------------------------------------------------------------ */
-/* Function: fr_findtunebycookie */
+/* Function: ipf_tune_findbycookie */
/* Returns: NULL = search failed, else pointer to tune struct */
/* Parameters: cookie(I) - cookie value to search for amongst tuneables */
/* next(O) - pointer to place to store the cookie for the */
@@ -6085,12 +6889,14 @@ static ipftuneable_t *ipf_tunelist = NULL;
/* a matching value for "cookie" - ie its address. When returning a match, */
/* the next one to be found may be returned inside next. */
/* ------------------------------------------------------------------------ */
-static ipftuneable_t *fr_findtunebycookie(cookie, next)
-void *cookie, **next;
+static ipftuneable_t *
+ipf_tune_findbycookie(ptop, cookie, next)
+ ipftuneable_t **ptop;
+ void *cookie, **next;
{
ipftuneable_t *ta, **tap;
- for (ta = ipf_tuneables; ta->ipft_name != NULL; ta++)
+ for (ta = *ptop; ta->ipft_name != NULL; ta++)
if (ta == cookie) {
if (next != NULL) {
/*
@@ -6104,12 +6910,12 @@ void *cookie, **next;
if ((ta + 1)->ipft_name != NULL)
*next = ta + 1;
else
- *next = &ipf_tunelist;
+ *next = ptop;
}
return ta;
}
- for (tap = &ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next)
+ for (tap = ptop; (ta = *tap) != NULL; tap = &ta->ipft_next)
if (tap == cookie) {
if (next != NULL)
*next = &ta->ipft_next;
@@ -6123,7 +6929,7 @@ void *cookie, **next;
/* ------------------------------------------------------------------------ */
-/* Function: fr_findtunebyname */
+/* Function: ipf_tune_findbyname */
/* Returns: NULL = search failed, else pointer to tune struct */
/* Parameters: name(I) - name of the tuneable entry to find. */
/* */
@@ -6131,44 +6937,192 @@ void *cookie, **next;
/* for an entry with a matching name. If we can find one, return a pointer */
/* to the matching structure. */
/* ------------------------------------------------------------------------ */
-static ipftuneable_t *fr_findtunebyname(name)
-const char *name;
+static ipftuneable_t *
+ipf_tune_findbyname(top, name)
+ ipftuneable_t *top;
+ const char *name;
{
ipftuneable_t *ta;
- for (ta = ipf_tuneables; ta->ipft_name != NULL; ta++)
+ for (ta = top; ta != NULL; ta = ta->ipft_next)
if (!strcmp(ta->ipft_name, name)) {
return ta;
}
- for (ta = ipf_tunelist; ta != NULL; ta = ta->ipft_next)
- if (!strcmp(ta->ipft_name, name)) {
- return ta;
+ return NULL;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_tune_add_array */
+/* Returns: int - 0 == success, else failure */
+/* Parameters: newtune - pointer to new tune array to add to tuneables */
+/* */
+/* Appends tune structures from the array passed in (newtune) to the end of */
+/* the current list of "dynamic" tuneable parameters. */
+/* If any entry to be added is already present (by name) then the operation */
+/* is aborted - entries that have been added are removed before returning. */
+/* An entry with no name (NULL) is used as the indication that the end of */
+/* the array has been reached. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_tune_add_array(softc, newtune)
+ ipf_main_softc_t *softc;
+ ipftuneable_t *newtune;
+{
+ ipftuneable_t *nt, *dt;
+ int error = 0;
+
+ for (nt = newtune; nt->ipft_name != NULL; nt++) {
+ error = ipf_tune_add(softc, nt);
+ if (error != 0) {
+ for (dt = newtune; dt != nt; dt++) {
+ (void) ipf_tune_del(softc, dt);
+ }
}
+ }
- return NULL;
+ return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_addipftune */
+/* Function: ipf_tune_array_link */
+/* Returns: 0 == success, -1 == failure */
+/* Parameters: softc(I) - soft context pointerto work with */
+/* array(I) - pointer to an array of tuneables */
+/* */
+/* Given an array of tunables (array), append them to the current list of */
+/* tuneables for this context (softc->ipf_tuners.) To properly prepare the */
+/* the array for being appended to the list, initialise all of the next */
+/* pointers so we don't need to walk parts of it with ++ and others with */
+/* next. The array is expected to have an entry with a NULL name as the */
+/* terminator. Trying to add an array with no non-NULL names will return as */
+/* a failure. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_tune_array_link(softc, array)
+ ipf_main_softc_t *softc;
+ ipftuneable_t *array;
+{
+ ipftuneable_t *t, **p;
+
+ t = array;
+ if (t->ipft_name == NULL)
+ return -1;
+
+ for (; t[1].ipft_name != NULL; t++)
+ t[0].ipft_next = &t[1];
+ t->ipft_next = NULL;
+
+ /*
+ * Since a pointer to the last entry isn't kept, we need to find it
+ * each time we want to add new variables to the list.
+ */
+ for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next)
+ if (t->ipft_name == NULL)
+ break;
+ *p = array;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_tune_array_unlink */
+/* Returns: 0 == success, -1 == failure */
+/* Parameters: softc(I) - soft context pointerto work with */
+/* array(I) - pointer to an array of tuneables */
+/* */
+/* ------------------------------------------------------------------------ */
+int
+ipf_tune_array_unlink(softc, array)
+ ipf_main_softc_t *softc;
+ ipftuneable_t *array;
+{
+ ipftuneable_t *t, **p;
+
+ for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next)
+ if (t == array)
+ break;
+ if (t == NULL)
+ return -1;
+
+ for (; t[1].ipft_name != NULL; t++)
+ ;
+
+ *p = t->ipft_next;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_tune_array_copy */
+/* Returns: NULL = failure, else pointer to new array */
+/* Parameters: base(I) - pointer to structure base */
+/* size(I) - size of the array at template */
+/* template(I) - original array to copy */
+/* */
+/* Allocate memory for a new set of tuneable values and copy everything */
+/* from template into the new region of memory. The new region is full of */
+/* uninitialised pointers (ipft_next) so set them up. Now, ipftp_offset... */
+/* */
+/* NOTE: the following assumes that sizeof(long) == sizeof(void *) */
+/* In the array template, ipftp_offset is the offset (in bytes) of the */
+/* location of the tuneable value inside the structure pointed to by base. */
+/* As ipftp_offset is a union over the pointers to the tuneable values, if */
+/* we add base to the copy's ipftp_offset, copy ends up with a pointer in */
+/* ipftp_void that points to the stored value. */
+/* ------------------------------------------------------------------------ */
+ipftuneable_t *
+ipf_tune_array_copy(base, size, template)
+ void *base;
+ size_t size;
+ ipftuneable_t *template;
+{
+ ipftuneable_t *copy;
+ int i;
+
+
+ KMALLOCS(copy, ipftuneable_t *, size);
+ if (copy == NULL) {
+ return NULL;
+ }
+ bcopy(template, copy, size);
+
+ for (i = 0; copy[i].ipft_name; i++) {
+ copy[i].ipft_una.ipftp_offset += (u_long)base;
+ copy[i].ipft_next = copy + i + 1;
+ }
+
+ return copy;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_tune_add */
/* Returns: int - 0 == success, else failure */
-/* Parameters: newtune - pointer to new tune struct to add to tuneables */
+/* Parameters: newtune - pointer to new tune entry to add to tuneables */
/* */
-/* Appends the tune structure pointer to by "newtune" to the end of the */
-/* current list of "dynamic" tuneable parameters. Once added, the owner */
-/* of the object is not expected to ever change "ipft_next". */
+/* Appends tune structures from the array passed in (newtune) to the end of */
+/* the current list of "dynamic" tuneable parameters. Once added, the */
+/* owner of the object is not expected to ever change "ipft_next". */
/* ------------------------------------------------------------------------ */
-int fr_addipftune(newtune)
-ipftuneable_t *newtune;
+int
+ipf_tune_add(softc, newtune)
+ ipf_main_softc_t *softc;
+ ipftuneable_t *newtune;
{
ipftuneable_t *ta, **tap;
- ta = fr_findtunebyname(newtune->ipft_name);
- if (ta != NULL)
+ ta = ipf_tune_findbyname(softc->ipf_tuners, newtune->ipft_name);
+ if (ta != NULL) {
+ IPFERROR(74);
return EEXIST;
+ }
- for (tap = &ipf_tunelist; *tap != NULL; tap = &(*tap)->ipft_next)
+ for (tap = &softc->ipf_tuners; *tap != NULL; tap = &(*tap)->ipft_next)
;
newtune->ipft_next = NULL;
@@ -6178,33 +7132,72 @@ ipftuneable_t *newtune;
/* ------------------------------------------------------------------------ */
-/* Function: fr_delipftune */
+/* Function: ipf_tune_del */
/* Returns: int - 0 == success, else failure */
-/* Parameters: oldtune - pointer to tune struct to remove from the list of */
+/* Parameters: oldtune - pointer to tune entry to remove from the list of */
/* current dynamic tuneables */
/* */
/* Search for the tune structure, by pointer, in the list of those that are */
/* dynamically added at run time. If found, adjust the list so that this */
/* structure is no longer part of it. */
/* ------------------------------------------------------------------------ */
-int fr_delipftune(oldtune)
-ipftuneable_t *oldtune;
+int
+ipf_tune_del(softc, oldtune)
+ ipf_main_softc_t *softc;
+ ipftuneable_t *oldtune;
{
ipftuneable_t *ta, **tap;
+ int error = 0;
- for (tap = &ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next)
+ for (tap = &softc->ipf_tuners; (ta = *tap) != NULL;
+ tap = &ta->ipft_next) {
if (ta == oldtune) {
*tap = oldtune->ipft_next;
oldtune->ipft_next = NULL;
- return 0;
+ break;
}
+ }
- return ESRCH;
+ if (ta == NULL) {
+ error = ESRCH;
+ IPFERROR(75);
+ }
+ return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_ipftune */
+/* Function: ipf_tune_del_array */
+/* Returns: int - 0 == success, else failure */
+/* Parameters: oldtune - pointer to tuneables array */
+/* */
+/* Remove each tuneable entry in the array from the list of "dynamic" */
+/* tunables. If one entry should fail to be found, an error will be */
+/* returned and no further ones removed. */
+/* An entry with a NULL name is used as the indicator of the last entry in */
+/* the array. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_tune_del_array(softc, oldtune)
+ ipf_main_softc_t *softc;
+ ipftuneable_t *oldtune;
+{
+ ipftuneable_t *ot;
+ int error = 0;
+
+ for (ot = oldtune; ot->ipft_name != NULL; ot++) {
+ error = ipf_tune_del(softc, ot);
+ if (error != 0)
+ break;
+ }
+
+ return error;
+
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_tune */
/* Returns: int - 0 == success, else failure */
/* Parameters: cmd(I) - ioctl command number */
/* data(I) - pointer to ioctl data structure */
@@ -6216,16 +7209,18 @@ ipftuneable_t *oldtune;
/* and 'destruction' routines of the various components of ipfilter are all */
/* each responsible for handling their own values being too big. */
/* ------------------------------------------------------------------------ */
-int fr_ipftune(cmd, data)
-ioctlcmd_t cmd;
-void *data;
+int
+ipf_ipftune(softc, cmd, data)
+ ipf_main_softc_t *softc;
+ ioctlcmd_t cmd;
+ void *data;
{
ipftuneable_t *ta;
ipftune_t tu;
void *cookie;
int error;
- error = fr_inobj(data, &tu, IPFOBJ_TUNEABLE);
+ error = ipf_inobj(softc, data, NULL, &tu, IPFOBJ_TUNEABLE);
if (error != 0)
return error;
@@ -6246,9 +7241,10 @@ void *data;
* at the front of the list.
*/
if (cookie != NULL) {
- ta = fr_findtunebycookie(cookie, &tu.ipft_cookie);
+ ta = ipf_tune_findbycookie(&softc->ipf_tuners,
+ cookie, &tu.ipft_cookie);
} else {
- ta = ipf_tuneables;
+ ta = softc->ipf_tuners;
tu.ipft_cookie = ta + 1;
}
if (ta != NULL) {
@@ -6256,8 +7252,10 @@ void *data;
* Entry found, but does the data pointed to by that
* row fit in what we can return?
*/
- if (ta->ipft_sz > sizeof(tu.ipft_un))
+ if (ta->ipft_sz > sizeof(tu.ipft_un)) {
+ IPFERROR(76);
return EINVAL;
+ }
tu.ipft_vlong = 0;
if (ta->ipft_sz == sizeof(u_long))
@@ -6277,7 +7275,7 @@ void *data;
MIN(sizeof(tu.ipft_name),
strlen(ta->ipft_name) + 1));
}
- error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE);
+ error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
break;
case SIOCIPFGET :
@@ -6286,13 +7284,16 @@ void *data;
* Search by name or by cookie value for a particular entry
* in the tuning paramter table.
*/
+ IPFERROR(77);
error = ESRCH;
if (cookie != NULL) {
- ta = fr_findtunebycookie(cookie, NULL);
+ ta = ipf_tune_findbycookie(&softc->ipf_tuners,
+ cookie, NULL);
if (ta != NULL)
error = 0;
} else if (tu.ipft_name[0] != '\0') {
- ta = fr_findtunebyname(tu.ipft_name);
+ ta = ipf_tune_findbyname(softc->ipf_tuners,
+ tu.ipft_name);
if (ta != NULL)
error = 0;
}
@@ -6317,7 +7318,7 @@ void *data;
tu.ipft_min = ta->ipft_min;
tu.ipft_max = ta->ipft_max;
tu.ipft_flags = ta->ipft_flags;
- error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE);
+ error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
} else if (cmd == (ioctlcmd_t)SIOCIPFSET) {
/*
@@ -6328,35 +7329,49 @@ void *data;
u_long in;
if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) &&
- (fr_running > 0)) {
+ (softc->ipf_running > 0)) {
+ IPFERROR(78);
error = EBUSY;
break;
}
in = tu.ipft_vlong;
if (in < ta->ipft_min || in > ta->ipft_max) {
+ IPFERROR(79);
error = EINVAL;
break;
}
- if (ta->ipft_sz == sizeof(u_long)) {
+ if (ta->ipft_func != NULL) {
+ SPL_INT(s);
+
+ SPL_NET(s);
+ error = (*ta->ipft_func)(softc, ta,
+ &tu.ipft_un);
+ SPL_X(s);
+
+ } else if (ta->ipft_sz == sizeof(u_long)) {
tu.ipft_vlong = *ta->ipft_plong;
*ta->ipft_plong = in;
+
} else if (ta->ipft_sz == sizeof(u_int)) {
tu.ipft_vint = *ta->ipft_pint;
*ta->ipft_pint = (u_int)(in & 0xffffffff);
+
} else if (ta->ipft_sz == sizeof(u_short)) {
tu.ipft_vshort = *ta->ipft_pshort;
*ta->ipft_pshort = (u_short)(in & 0xffff);
+
} else if (ta->ipft_sz == sizeof(u_char)) {
tu.ipft_vchar = *ta->ipft_pchar;
*ta->ipft_pchar = (u_char)(in & 0xff);
}
- error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE);
+ error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE);
}
break;
default :
+ IPFERROR(80);
error = EINVAL;
break;
}
@@ -6366,109 +7381,7 @@ void *data;
/* ------------------------------------------------------------------------ */
-/* Function: fr_initialise */
-/* Returns: int - 0 == success, < 0 == failure */
-/* Parameters: None. */
-/* */
-/* Call of the initialise functions for all the various subsystems inside */
-/* of IPFilter. If any of them should fail, return immeadiately a failure */
-/* BUT do not try to recover from the error here. */
-/* ------------------------------------------------------------------------ */
-int fr_initialise()
-{
- int i;
-
- bzero(&frstats, sizeof(frstats));
-
-#ifdef IPFILTER_LOG
- i = fr_loginit();
- if (i < 0)
- return -10 + i;
-#endif
- i = fr_natinit();
- if (i < 0)
- return -20 + i;
-
- i = fr_stateinit();
- if (i < 0)
- return -30 + i;
-
- i = fr_authinit();
- if (i < 0)
- return -40 + i;
-
- i = fr_fraginit();
- if (i < 0)
- return -50 + i;
-
- i = appr_init();
- if (i < 0)
- return -60 + i;
-
-#ifdef IPFILTER_SYNC
- i = ipfsync_init();
- if (i < 0)
- return -70 + i;
-#endif
-#ifdef IPFILTER_SCAN
- i = ipsc_init();
- if (i < 0)
- return -80 + i;
-#endif
-#ifdef IPFILTER_LOOKUP
- i = ip_lookup_init();
- if (i < 0)
- return -90 + i;
-#endif
-#ifdef IPFILTER_COMPILED
- ipfrule_add();
-#endif
- return 0;
-}
-
-
-/* ------------------------------------------------------------------------ */
-/* Function: fr_deinitialise */
-/* Returns: None. */
-/* Parameters: None. */
-/* */
-/* Call all the various subsystem cleanup routines to deallocate memory or */
-/* destroy locks or whatever they've done that they need to now undo. */
-/* The order here IS important as there are some cross references of */
-/* internal data structures. */
-/* ------------------------------------------------------------------------ */
-void fr_deinitialise()
-{
- fr_fragunload();
- fr_authunload();
- fr_natunload();
- fr_stateunload();
-#ifdef IPFILTER_SCAN
- fr_scanunload();
-#endif
- appr_unload();
-
-#ifdef IPFILTER_COMPILED
- ipfrule_remove();
-#endif
-
- (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
- (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE);
- (void) frflush(IPL_LOGCOUNT, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
- (void) frflush(IPL_LOGCOUNT, 0, FR_INQUE|FR_OUTQUE);
-
-#ifdef IPFILTER_LOOKUP
- ip_lookup_unload();
-#endif
-
-#ifdef IPFILTER_LOG
- fr_logunload();
-#endif
-}
-
-
-/* ------------------------------------------------------------------------ */
-/* Function: fr_zerostats */
+/* Function: ipf_zerostats */
/* Returns: int - 0 = success, else failure */
/* Parameters: data(O) - pointer to pointer for copying data back to */
/* */
@@ -6476,30 +7389,38 @@ void fr_deinitialise()
/* current ones in the kernel. The lock is only held across the bzero() as */
/* the copyout may result in paging (ie network activity.) */
/* ------------------------------------------------------------------------ */
-int fr_zerostats(data)
-void *data;
+int
+ipf_zerostats(softc, data)
+ ipf_main_softc_t *softc;
+ caddr_t data;
{
friostat_t fio;
+ ipfobj_t obj;
int error;
- fr_getstat(&fio);
- error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT);
- if (error)
- return EFAULT;
+ error = ipf_inobj(softc, data, &obj, &fio, IPFOBJ_IPFSTAT);
+ if (error != 0)
+ return error;
+ ipf_getstat(softc, &fio, obj.ipfo_rev);
+ error = ipf_outobj(softc, data, &fio, IPFOBJ_IPFSTAT);
+ if (error != 0)
+ return error;
- WRITE_ENTER(&ipf_mutex);
- bzero(&frstats, sizeof(frstats));
- RWLOCK_EXIT(&ipf_mutex);
+ WRITE_ENTER(&softc->ipf_mutex);
+ bzero(&softc->ipf_stats, sizeof(softc->ipf_stats));
+ RWLOCK_EXIT(&softc->ipf_mutex);
return 0;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_resolvedest */
+/* Function: ipf_resolvedest */
/* Returns: Nil */
-/* Parameters: fdp(IO) - pointer to destination information to resolve */
-/* v(I) - IP protocol version to match */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* base(I) - where strings are stored */
+/* fdp(IO) - pointer to destination information to resolve */
+/* v(I) - IP protocol version to match */
/* */
/* Looks up an interface name in the frdest structure pointed to by fdp and */
/* if a matching name can be found for the particular IP protocol version */
@@ -6507,52 +7428,66 @@ void *data;
/* found, then set the interface pointer to be -1 as NULL is considered to */
/* indicate there is no information at all in the structure. */
/* ------------------------------------------------------------------------ */
-void fr_resolvedest(fdp, v)
-frdest_t *fdp;
-int v;
+int
+ipf_resolvedest(softc, base, fdp, v)
+ ipf_main_softc_t *softc;
+ char *base;
+ frdest_t *fdp;
+ int v;
{
+ int errval = 0;
void *ifp;
ifp = NULL;
- v = v; /* LINT */
- if (*fdp->fd_ifname != '\0') {
- ifp = GETIFP(fdp->fd_ifname, v);
- if (ifp == NULL)
- ifp = (void *)-1;
+ if (fdp->fd_name != -1) {
+ if (fdp->fd_type == FRD_DSTLIST) {
+ ifp = ipf_lookup_res_name(softc, IPL_LOGIPF,
+ IPLT_DSTLIST,
+ base + fdp->fd_name,
+ NULL);
+ if (ifp == NULL) {
+ IPFERROR(144);
+ errval = ESRCH;
+ }
+ } else {
+ ifp = GETIFP(base + fdp->fd_name, v);
+ if (ifp == NULL)
+ ifp = (void *)-1;
+ }
}
- fdp->fd_ifp = ifp;
+ fdp->fd_ptr = ifp;
+
+ if ((ifp != NULL) && (ifp != (void *)-1)) {
+ fdp->fd_local = ipf_deliverlocal(softc, v, ifp, &fdp->fd_ip6);
+ }
+
+ return errval;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_resolvenic */
+/* Function: ipf_resolvenic */
/* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */
/* pointer to interface structure for NIC */
-/* Parameters: name(I) - complete interface name */
+/* Parameters: softc(I)- pointer to soft context main structure */
+/* name(I) - complete interface name */
/* v(I) - IP protocol version */
/* */
/* Look for a network interface structure that firstly has a matching name */
/* to that passed in and that is also being used for that IP protocol */
/* version (necessary on some platforms where there are separate listings */
/* for both IPv4 and IPv6 on the same physical NIC. */
-/* */
-/* One might wonder why name gets terminated with a \0 byte in here. The */
-/* reason is an interface name could get into the kernel structures of ipf */
-/* in any number of ways and so long as they all use the same sized array */
-/* to put the name in, it makes sense to ensure it gets null terminated */
-/* before it is used for its intended purpose - finding its match in the */
-/* kernel's list of configured interfaces. */
-/* */
-/* NOTE: This SHOULD ONLY be used with IPFilter structures that have an */
-/* array for the name that is LIFNAMSIZ bytes (at least) in length. */
/* ------------------------------------------------------------------------ */
-void *fr_resolvenic(name, v)
-char *name;
-int v;
+void *
+ipf_resolvenic(softc, name, v)
+ ipf_main_softc_t *softc;
+ char *name;
+ int v;
{
void *nic;
+ softc = softc; /* gcc -Wextra */
if (name[0] == '\0')
return NULL;
@@ -6560,8 +7495,6 @@ int v;
return NULL;
}
- name[LIFNAMSIZ - 1] = '\0';
-
nic = GETIFP(name, v);
if (nic == NULL)
nic = (void *)-1;
@@ -6569,68 +7502,121 @@ int v;
}
-ipftoken_t *ipftokenhead = NULL, **ipftokentail = &ipftokenhead;
-
-
/* ------------------------------------------------------------------------ */
-/* Function: ipf_expiretokens */
+/* Function: ipf_token_expire */
/* Returns: None. */
-/* Parameters: None. */
+/* Parameters: softc(I) - pointer to soft context main structure */
/* */
/* This function is run every ipf tick to see if there are any tokens that */
/* have been held for too long and need to be freed up. */
/* ------------------------------------------------------------------------ */
-void ipf_expiretokens()
+void
+ipf_token_expire(softc)
+ ipf_main_softc_t *softc;
{
ipftoken_t *it;
- WRITE_ENTER(&ipf_tokens);
- while ((it = ipftokenhead) != NULL) {
- if (it->ipt_die > fr_ticks)
+ WRITE_ENTER(&softc->ipf_tokens);
+ while ((it = softc->ipf_token_head) != NULL) {
+ if (it->ipt_die > softc->ipf_ticks)
break;
- ipf_freetoken(it);
+ ipf_token_deref(softc, it);
+ }
+ RWLOCK_EXIT(&softc->ipf_tokens);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_token_flush */
+/* Returns: None. */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Loop through all of the existing tokens and call deref to see if they */
+/* can be freed. Normally a function like this might just loop on */
+/* ipf_token_head but there is a chance that a token might have a ref count */
+/* of greater than one and in that case the the reference would drop twice */
+/* by code that is only entitled to drop it once. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_token_flush(softc)
+ ipf_main_softc_t *softc;
+{
+ ipftoken_t *it, *next;
+
+ WRITE_ENTER(&softc->ipf_tokens);
+ for (it = softc->ipf_token_head; it != NULL; it = next) {
+ next = it->ipt_next;
+ (void) ipf_token_deref(softc, it);
}
- RWLOCK_EXIT(&ipf_tokens);
+ RWLOCK_EXIT(&softc->ipf_tokens);
}
/* ------------------------------------------------------------------------ */
-/* Function: ipf_deltoken */
+/* Function: ipf_token_del */
/* Returns: int - 0 = success, else error */
-/* Parameters: type(I) - the token type to match */
+/* Parameters: softc(I)- pointer to soft context main structure */
+/* type(I) - the token type to match */
/* uid(I) - uid owning the token */
/* ptr(I) - context pointer for the token */
/* */
/* This function looks for a a token in the current list that matches up */
/* the fields (type, uid, ptr). If none is found, ESRCH is returned, else */
-/* call ipf_freetoken() to remove it from the list. */
+/* call ipf_token_dewref() to remove it from the list. In the event that */
+/* the token has a reference held elsewhere, setting ipt_complete to 2 */
+/* enables debugging to distinguish between the two paths that ultimately */
+/* lead to a token to be deleted. */
/* ------------------------------------------------------------------------ */
-int ipf_deltoken(type, uid, ptr)
-int type, uid;
-void *ptr;
+int
+ipf_token_del(softc, type, uid, ptr)
+ ipf_main_softc_t *softc;
+ int type, uid;
+ void *ptr;
{
ipftoken_t *it;
- int error = ESRCH;
+ int error;
- WRITE_ENTER(&ipf_tokens);
- for (it = ipftokenhead; it != NULL; it = it->ipt_next)
+ IPFERROR(82);
+ error = ESRCH;
+
+ WRITE_ENTER(&softc->ipf_tokens);
+ for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) {
if (ptr == it->ipt_ctx && type == it->ipt_type &&
uid == it->ipt_uid) {
- ipf_freetoken(it);
+ it->ipt_complete = 2;
+ ipf_token_deref(softc, it);
error = 0;
break;
+ }
}
- RWLOCK_EXIT(&ipf_tokens);
+ RWLOCK_EXIT(&softc->ipf_tokens);
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: ipf_findtoken */
+/* Function: ipf_token_mark_complete */
+/* Returns: None. */
+/* Parameters: token(I) - pointer to token structure */
+/* */
+/* Mark a token as being ineligable for being found with ipf_token_find. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_token_mark_complete(token)
+ ipftoken_t *token;
+{
+ if (token->ipt_complete == 0)
+ token->ipt_complete = 1;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_token_find */
/* Returns: ipftoken_t * - NULL if no memory, else pointer to token */
-/* Parameters: type(I) - the token type to match */
+/* Parameters: softc(I)- pointer to soft context main structure */
+/* type(I) - the token type to match */
/* uid(I) - uid owning the token */
/* ptr(I) - context pointer for the token */
/* */
@@ -6638,97 +7624,115 @@ void *ptr;
/* matches the tuple (type, uid, ptr). If one cannot be found then one is */
/* allocated. If one is found then it is moved to the top of the list of */
/* currently active tokens. */
-/* */
-/* NOTE: It is by design that this function returns holding a read lock on */
-/* ipf_tokens. Callers must make sure they release it! */
/* ------------------------------------------------------------------------ */
-ipftoken_t *ipf_findtoken(type, uid, ptr)
-int type, uid;
-void *ptr;
+ipftoken_t *
+ipf_token_find(softc, type, uid, ptr)
+ ipf_main_softc_t *softc;
+ int type, uid;
+ void *ptr;
{
ipftoken_t *it, *new;
KMALLOC(new, ipftoken_t *);
+ if (new != NULL)
+ bzero((char *)new, sizeof(*new));
- WRITE_ENTER(&ipf_tokens);
- for (it = ipftokenhead; it != NULL; it = it->ipt_next) {
- if (it->ipt_alive == 0)
- continue;
- if (ptr == it->ipt_ctx && type == it->ipt_type &&
- uid == it->ipt_uid)
+ WRITE_ENTER(&softc->ipf_tokens);
+ for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) {
+ if ((ptr == it->ipt_ctx) && (type == it->ipt_type) &&
+ (uid == it->ipt_uid) && (it->ipt_complete < 2))
break;
}
if (it == NULL) {
it = new;
new = NULL;
- if (it == NULL)
+ if (it == NULL) {
+ RWLOCK_EXIT(&softc->ipf_tokens);
return NULL;
- it->ipt_data = NULL;
+ }
it->ipt_ctx = ptr;
it->ipt_uid = uid;
it->ipt_type = type;
- it->ipt_next = NULL;
- it->ipt_alive = 1;
+ it->ipt_ref = 1;
} else {
if (new != NULL) {
KFREE(new);
new = NULL;
}
- ipf_unlinktoken(it);
+ if (it->ipt_complete > 0)
+ it = NULL;
+ else
+ ipf_token_unlink(softc, it);
}
- it->ipt_pnext = ipftokentail;
- *ipftokentail = it;
- ipftokentail = &it->ipt_next;
- it->ipt_next = NULL;
- it->ipt_die = fr_ticks + 2;
+ if (it != NULL) {
+ it->ipt_pnext = softc->ipf_token_tail;
+ *softc->ipf_token_tail = it;
+ softc->ipf_token_tail = &it->ipt_next;
+ it->ipt_next = NULL;
+ it->ipt_ref++;
- MUTEX_DOWNGRADE(&ipf_tokens);
+ it->ipt_die = softc->ipf_ticks + 20;
+ }
+
+ RWLOCK_EXIT(&softc->ipf_tokens);
return it;
}
/* ------------------------------------------------------------------------ */
-/* Function: ipf_unlinktoken */
+/* Function: ipf_token_unlink */
/* Returns: None. */
-/* Parameters: token(I) - pointer to token structure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* token(I) - pointer to token structure */
+/* Write Locks: ipf_tokens */
/* */
/* This function unlinks a token structure from the linked list of tokens */
/* that "own" it. The head pointer never needs to be explicitly adjusted */
/* but the tail does due to the linked list implementation. */
/* ------------------------------------------------------------------------ */
-static void ipf_unlinktoken(token)
-ipftoken_t *token;
+static void
+ipf_token_unlink(softc, token)
+ ipf_main_softc_t *softc;
+ ipftoken_t *token;
{
- if (ipftokentail == &token->ipt_next)
- ipftokentail = token->ipt_pnext;
+ if (softc->ipf_token_tail == &token->ipt_next)
+ softc->ipf_token_tail = token->ipt_pnext;
*token->ipt_pnext = token->ipt_next;
if (token->ipt_next != NULL)
token->ipt_next->ipt_pnext = token->ipt_pnext;
+ token->ipt_next = NULL;
+ token->ipt_pnext = NULL;
}
/* ------------------------------------------------------------------------ */
-/* Function: ipf_freetoken */
-/* Returns: None. */
-/* Parameters: token(I) - pointer to token structure */
+/* Function: ipf_token_deref */
+/* Returns: int - 0 == token freed, else reference count */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* token(I) - pointer to token structure */
+/* Write Locks: ipf_tokens */
/* */
-/* This function unlinks a token from the linked list and on the path to */
-/* free'ing the data, it calls the dereference function that is associated */
-/* with the type of data pointed to by the token as it is considered to */
-/* hold a reference to it. */
+/* Drop the reference count on the token structure and if it drops to zero, */
+/* call the dereference function for the token type because it is then */
+/* possible to free the token data structure. */
/* ------------------------------------------------------------------------ */
-void ipf_freetoken(token)
-ipftoken_t *token;
+int
+ipf_token_deref(softc, token)
+ ipf_main_softc_t *softc;
+ ipftoken_t *token;
{
void *data, **datap;
- ipf_unlinktoken(token);
+ ASSERT(token->ipt_ref > 0);
+ token->ipt_ref--;
+ if (token->ipt_ref > 0)
+ return token->ipt_ref;
data = token->ipt_data;
datap = &data;
@@ -6737,54 +7741,96 @@ ipftoken_t *token;
switch (token->ipt_type)
{
case IPFGENITER_IPF :
- (void) fr_derefrule((frentry_t **)datap);
+ (void) ipf_derefrule(softc, (frentry_t **)datap);
break;
case IPFGENITER_IPNAT :
- WRITE_ENTER(&ipf_nat);
- fr_ipnatderef((ipnat_t **)datap);
- RWLOCK_EXIT(&ipf_nat);
+ WRITE_ENTER(&softc->ipf_nat);
+ ipf_nat_rule_deref(softc, (ipnat_t **)datap);
+ RWLOCK_EXIT(&softc->ipf_nat);
break;
case IPFGENITER_NAT :
- fr_natderef((nat_t **)datap);
+ ipf_nat_deref(softc, (nat_t **)datap);
break;
case IPFGENITER_STATE :
- fr_statederef((ipstate_t **)datap);
+ ipf_state_deref(softc, (ipstate_t **)datap);
break;
case IPFGENITER_FRAG :
-#ifdef USE_MUTEXES
- fr_fragderef((ipfr_t **)datap, &ipf_frag);
-#else
- fr_fragderef((ipfr_t **)datap);
-#endif
+ ipf_frag_pkt_deref(softc, (ipfr_t **)datap);
break;
case IPFGENITER_NATFRAG :
-#ifdef USE_MUTEXES
- fr_fragderef((ipfr_t **)datap, &ipf_natfrag);
-#else
- fr_fragderef((ipfr_t **)datap);
-#endif
+ ipf_frag_nat_deref(softc, (ipfr_t **)datap);
break;
case IPFGENITER_HOSTMAP :
- WRITE_ENTER(&ipf_nat);
- fr_hostmapdel((hostmap_t **)datap);
- RWLOCK_EXIT(&ipf_nat);
+ WRITE_ENTER(&softc->ipf_nat);
+ ipf_nat_hostmapdel(softc, (hostmap_t **)datap);
+ RWLOCK_EXIT(&softc->ipf_nat);
break;
default :
-#ifdef IPFILTER_LOOKUP
- ip_lookup_iterderef(token->ipt_type, data);
-#endif
+ ipf_lookup_iterderef(softc, token->ipt_type, data);
break;
}
}
+ ipf_token_unlink(softc, token);
KFREE(token);
+ return 0;
}
/* ------------------------------------------------------------------------ */
+/* Function: ipf_nextrule */
+/* Returns: frentry_t * - NULL == no more rules, else pointer to next */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* fr(I) - pointer to filter rule */
+/* out(I) - 1 == out rules, 0 == input rules */
+/* */
+/* Starting with "fr", find the next rule to visit. This includes visiting */
+/* the list of rule groups if either fr is NULL (empty list) or it is the */
+/* last rule in the list. When walking rule lists, it is either input or */
+/* output rules that are returned, never both. */
+/* ------------------------------------------------------------------------ */
+static frentry_t *
+ipf_nextrule(softc, active, unit, fr, out)
+ ipf_main_softc_t *softc;
+ int active, unit;
+ frentry_t *fr;
+ int out;
+{
+ frentry_t *next;
+ frgroup_t *fg;
+
+ if (fr != NULL && fr->fr_group != -1) {
+ fg = ipf_findgroup(softc, fr->fr_names + fr->fr_group,
+ unit, active, NULL);
+ if (fg != NULL)
+ fg = fg->fg_next;
+ } else {
+ fg = softc->ipf_groups[unit][active];
+ }
+
+ while (fg != NULL) {
+ next = fg->fg_start;
+ while (next != NULL) {
+ if (out) {
+ if (next->fr_flags & FR_OUTQUE)
+ return next;
+ } else if (next->fr_flags & FR_INQUE) {
+ return next;
+ }
+ next = next->fr_next;
+ }
+ if (next == NULL)
+ fg = fg->fg_next;
+ }
+
+ return NULL;
+}
+
+/* ------------------------------------------------------------------------ */
/* Function: ipf_getnextrule */
/* Returns: int - 0 = success, else error */
-/* Parameters: t(I) - pointer to destination information to resolve */
+/* Parameters: softc(I)- pointer to soft context main structure */
+/* t(I) - pointer to destination information to resolve */
/* ptr(I) - pointer to ipfobj_t to copyin from user space */
/* */
/* This function's first job is to bring in the ipfruleiter_t structure via */
@@ -6795,47 +7841,72 @@ ipftoken_t *token;
/* When we have found the rule to return, increase its reference count and */
/* if we used an existing rule to get here, decrease its reference count. */
/* ------------------------------------------------------------------------ */
-int ipf_getnextrule(ipftoken_t *t, void *ptr)
+int
+ipf_getnextrule(softc, t, ptr)
+ ipf_main_softc_t *softc;
+ ipftoken_t *t;
+ void *ptr;
{
frentry_t *fr, *next, zero;
- int error, count, out;
ipfruleiter_t it;
+ int error, out;
frgroup_t *fg;
+ ipfobj_t obj;
+ int predict;
char *dst;
+ int unit;
- if (t == NULL || ptr == NULL)
+ if (t == NULL || ptr == NULL) {
+ IPFERROR(84);
return EFAULT;
- error = fr_inobj(ptr, &it, IPFOBJ_IPFITER);
+ }
+
+ error = ipf_inobj(softc, ptr, &obj, &it, IPFOBJ_IPFITER);
if (error != 0)
return error;
- if ((it.iri_inout < 0) || (it.iri_inout > 3))
+
+ if ((it.iri_inout < 0) || (it.iri_inout > 3)) {
+ IPFERROR(85);
return EINVAL;
- if ((it.iri_active != 0) && (it.iri_active != 1))
+ }
+ if ((it.iri_active != 0) && (it.iri_active != 1)) {
+ IPFERROR(86);
return EINVAL;
- if (it.iri_nrules == 0)
+ }
+ if (it.iri_nrules == 0) {
+ IPFERROR(87);
return ENOSPC;
- if (it.iri_rule == NULL)
+ }
+ if (it.iri_rule == NULL) {
+ IPFERROR(88);
return EFAULT;
+ }
- out = it.iri_inout & F_OUT;
+ fg = NULL;
fr = t->ipt_data;
- READ_ENTER(&ipf_mutex);
+ if ((it.iri_inout & F_OUT) != 0)
+ out = 1;
+ else
+ out = 0;
+ if ((it.iri_inout & F_ACIN) != 0)
+ unit = IPL_LOGCOUNT;
+ else
+ unit = IPL_LOGIPF;
+
+ READ_ENTER(&softc->ipf_mutex);
if (fr == NULL) {
if (*it.iri_group == '\0') {
- if ((it.iri_inout & F_ACIN) != 0) {
- if (it.iri_v == 4)
- next = ipacct[out][it.iri_active];
- else
- next = ipacct6[out][it.iri_active];
+ if (unit == IPL_LOGCOUNT) {
+ next = softc->ipf_acct[out][it.iri_active];
} else {
- if (it.iri_v == 4)
- next = ipfilter[out][it.iri_active];
- else
- next = ipfilter6[out][it.iri_active];
+ next = softc->ipf_rules[out][it.iri_active];
}
+ if (next == NULL)
+ next = ipf_nextrule(softc, it.iri_active,
+ unit, NULL, out);
} else {
- fg = fr_findgroup(it.iri_group, IPL_LOGIPF,
- it.iri_active, NULL);
+ fg = ipf_findgroup(softc, it.iri_group, unit,
+ it.iri_active, NULL);
if (fg != NULL)
next = fg->fg_start;
else
@@ -6843,113 +7914,133 @@ int ipf_getnextrule(ipftoken_t *t, void *ptr)
}
} else {
next = fr->fr_next;
+ if (next == NULL)
+ next = ipf_nextrule(softc, it.iri_active, unit,
+ fr, out);
}
+ if (next != NULL && next->fr_next != NULL)
+ predict = 1;
+ else if (ipf_nextrule(softc, it.iri_active, unit, next, out) != NULL)
+ predict = 1;
+ else
+ predict = 0;
+
+ if (fr != NULL)
+ (void) ipf_derefrule(softc, &fr);
+
+ obj.ipfo_type = IPFOBJ_FRENTRY;
dst = (char *)it.iri_rule;
- count = it.iri_nrules;
- /*
- * The ipfruleiter may ask for more than 1 rule at a time to be
- * copied out, so long as that many exist in the list to start with!
- */
- for (;;) {
- if (next != NULL) {
- if (count == 1) {
- MUTEX_ENTER(&next->fr_lock);
- next->fr_ref++;
- MUTEX_EXIT(&next->fr_lock);
- t->ipt_data = next;
- }
- } else {
- bzero(&zero, sizeof(zero));
- next = &zero;
- count = 1;
- t->ipt_data = NULL;
- }
- RWLOCK_EXIT(&ipf_mutex);
- error = COPYOUT(next, dst, sizeof(*next));
- if (error != 0)
- return EFAULT;
+ if (next != NULL) {
+ obj.ipfo_size = next->fr_size;
+ MUTEX_ENTER(&next->fr_lock);
+ next->fr_ref++;
+ MUTEX_EXIT(&next->fr_lock);
+ t->ipt_data = next;
+ } else {
+ obj.ipfo_size = sizeof(frentry_t);
+ bzero(&zero, sizeof(zero));
+ next = &zero;
+ t->ipt_data = NULL;
+ }
+ it.iri_rule = predict ? next : NULL;
+ if (predict == 0)
+ ipf_token_mark_complete(t);
+
+ RWLOCK_EXIT(&softc->ipf_mutex);
+ obj.ipfo_ptr = dst;
+ error = ipf_outobjk(softc, &obj, next);
+ if (error == 0 && t->ipt_data != NULL) {
+ dst += obj.ipfo_size;
if (next->fr_data != NULL) {
- dst += sizeof(*next);
- error = COPYOUT(next->fr_data, dst, next->fr_dsize);
- if (error != 0)
- error = EFAULT;
+ ipfobj_t dobj;
+
+ if (next->fr_type == FR_T_IPFEXPR)
+ dobj.ipfo_type = IPFOBJ_IPFEXPR;
else
- dst += next->fr_dsize;
+ dobj.ipfo_type = IPFOBJ_FRIPF;
+ dobj.ipfo_size = next->fr_dsize;
+ dobj.ipfo_rev = obj.ipfo_rev;
+ dobj.ipfo_ptr = dst;
+ error = ipf_outobjk(softc, &dobj, next->fr_data);
}
-
- if ((count == 1) || (error != 0))
- break;
-
- count--;
-
- READ_ENTER(&ipf_mutex);
- next = next->fr_next;
}
- if (fr != NULL) {
- (void) fr_derefrule(&fr);
- }
+ if ((fr != NULL) && (next == &zero))
+ (void) ipf_derefrule(softc, &fr);
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_frruleiter */
+/* Function: ipf_frruleiter */
/* Returns: int - 0 = success, else error */
-/* Parameters: data(I) - the token type to match */
+/* Parameters: softc(I)- pointer to soft context main structure */
+/* data(I) - the token type to match */
/* uid(I) - uid owning the token */
/* ptr(I) - context pointer for the token */
/* */
-/* This function serves as a stepping stone between fr_ipf_ioctl and */
+/* This function serves as a stepping stone between ipf_ipf_ioctl and */
/* ipf_getnextrule. It's role is to find the right token in the kernel for */
/* the process doing the ioctl and use that to ask for the next rule. */
/* ------------------------------------------------------------------------ */
-static int ipf_frruleiter(data, uid, ctx)
-void *data, *ctx;
-int uid;
+static int
+ipf_frruleiter(softc, data, uid, ctx)
+ ipf_main_softc_t *softc;
+ void *data, *ctx;
+ int uid;
{
ipftoken_t *token;
+ ipfruleiter_t it;
+ ipfobj_t obj;
int error;
- token = ipf_findtoken(IPFGENITER_IPF, uid, ctx);
- if (token != NULL)
- error = ipf_getnextrule(token, data);
- else
- error = EFAULT;
- RWLOCK_EXIT(&ipf_tokens);
+ token = ipf_token_find(softc, IPFGENITER_IPF, uid, ctx);
+ if (token != NULL) {
+ error = ipf_getnextrule(softc, token, data);
+ WRITE_ENTER(&softc->ipf_tokens);
+ ipf_token_deref(softc, token);
+ RWLOCK_EXIT(&softc->ipf_tokens);
+ } else {
+ error = ipf_inobj(softc, data, &obj, &it, IPFOBJ_IPFITER);
+ if (error != 0)
+ return error;
+ it.iri_rule = NULL;
+ error = ipf_outobj(softc, data, &it, IPFOBJ_IPFITER);
+ }
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_geniter */
+/* Function: ipf_geniter */
/* Returns: int - 0 = success, else error */
-/* Parameters: token(I) - pointer to ipftoken_t structure */
-/* itp(I) - */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* token(I) - pointer to ipftoken_t structure */
+/* itp(I) - pointer to iterator data */
/* */
+/* Decide which iterator function to call using information passed through */
+/* the ipfgeniter_t structure at itp. */
/* ------------------------------------------------------------------------ */
-static int ipf_geniter(token, itp)
-ipftoken_t *token;
-ipfgeniter_t *itp;
+static int
+ipf_geniter(softc, token, itp)
+ ipf_main_softc_t *softc;
+ ipftoken_t *token;
+ ipfgeniter_t *itp;
{
int error;
switch (itp->igi_type)
{
case IPFGENITER_FRAG :
-#ifdef USE_MUTEXES
- error = fr_nextfrag(token, itp,
- &ipfr_list, &ipfr_tail, &ipf_frag);
-#else
- error = fr_nextfrag(token, itp, &ipfr_list, &ipfr_tail);
-#endif
+ error = ipf_frag_pkt_next(softc, token, itp);
break;
default :
+ IPFERROR(92);
error = EINVAL;
break;
}
@@ -6959,41 +8050,50 @@ ipfgeniter_t *itp;
/* ------------------------------------------------------------------------ */
-/* Function: fr_genericiter */
+/* Function: ipf_genericiter */
/* Returns: int - 0 = success, else error */
-/* Parameters: data(I) - the token type to match */
+/* Parameters: softc(I)- pointer to soft context main structure */
+/* data(I) - the token type to match */
/* uid(I) - uid owning the token */
/* ptr(I) - context pointer for the token */
/* */
+/* Handle the SIOCGENITER ioctl for the ipfilter device. The primary role */
/* ------------------------------------------------------------------------ */
-int ipf_genericiter(data, uid, ctx)
-void *data, *ctx;
-int uid;
+int
+ipf_genericiter(softc, data, uid, ctx)
+ ipf_main_softc_t *softc;
+ void *data, *ctx;
+ int uid;
{
ipftoken_t *token;
ipfgeniter_t iter;
int error;
- error = fr_inobj(data, &iter, IPFOBJ_GENITER);
+ error = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_GENITER);
if (error != 0)
return error;
- token = ipf_findtoken(iter.igi_type, uid, ctx);
+ token = ipf_token_find(softc, iter.igi_type, uid, ctx);
if (token != NULL) {
token->ipt_subtype = iter.igi_type;
- error = ipf_geniter(token, &iter);
- } else
- error = EFAULT;
- RWLOCK_EXIT(&ipf_tokens);
+ error = ipf_geniter(softc, token, &iter);
+ WRITE_ENTER(&softc->ipf_tokens);
+ ipf_token_deref(softc, token);
+ RWLOCK_EXIT(&softc->ipf_tokens);
+ } else {
+ IPFERROR(93);
+ error = 0;
+ }
return error;
}
/* ------------------------------------------------------------------------ */
-/* Function: fr_ipf_ioctl */
+/* Function: ipf_ipf_ioctl */
/* Returns: int - 0 = success, else error */
-/* Parameters: data(I) - the token type to match */
+/* Parameters: softc(I)- pointer to soft context main structure */
+/* data(I) - the token type to match */
/* cmd(I) - the ioctl command number */
/* mode(I) - mode flags for the ioctl */
/* uid(I) - uid owning the token */
@@ -7002,231 +8102,283 @@ int uid;
/* This function handles all of the ioctl command that are actually isssued */
/* to the /dev/ipl device. */
/* ------------------------------------------------------------------------ */
-int fr_ipf_ioctl(data, cmd, mode, uid, ctx)
-caddr_t data;
-ioctlcmd_t cmd;
-int mode, uid;
-void *ctx;
+int
+ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx)
+ ipf_main_softc_t *softc;
+ caddr_t data;
+ ioctlcmd_t cmd;
+ int mode, uid;
+ void *ctx;
{
friostat_t fio;
int error, tmp;
+ ipfobj_t obj;
SPL_INT(s);
switch (cmd)
{
case SIOCFRENB :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(94);
error = EPERM;
- else {
+ } else {
error = BCOPYIN(data, &tmp, sizeof(tmp));
if (error != 0) {
+ IPFERROR(95);
error = EFAULT;
break;
}
- WRITE_ENTER(&ipf_global);
+ WRITE_ENTER(&softc->ipf_global);
if (tmp) {
- if (fr_running > 0)
+ if (softc->ipf_running > 0)
error = 0;
else
- error = ipfattach();
+ error = ipfattach(softc);
if (error == 0)
- fr_running = 1;
+ softc->ipf_running = 1;
else
- (void) ipfdetach();
+ (void) ipfdetach(softc);
} else {
- error = ipfdetach();
+ if (softc->ipf_running == 1)
+ error = ipfdetach(softc);
+ else
+ error = 0;
if (error == 0)
- fr_running = -1;
+ softc->ipf_running = -1;
}
- RWLOCK_EXIT(&ipf_global);
+ RWLOCK_EXIT(&softc->ipf_global);
}
break;
case SIOCIPFSET :
if (!(mode & FWRITE)) {
+ IPFERROR(96);
error = EPERM;
break;
}
/* FALLTHRU */
case SIOCIPFGETNEXT :
case SIOCIPFGET :
- error = fr_ipftune(cmd, (void *)data);
+ error = ipf_ipftune(softc, cmd, (void *)data);
break;
case SIOCSETFF :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(97);
error = EPERM;
- else {
- error = BCOPYIN(data, &fr_flags, sizeof(fr_flags));
- if (error != 0)
+ } else {
+ error = BCOPYIN(data, &softc->ipf_flags,
+ sizeof(softc->ipf_flags));
+ if (error != 0) {
+ IPFERROR(98);
error = EFAULT;
+ }
}
break;
case SIOCGETFF :
- error = BCOPYOUT(&fr_flags, data, sizeof(fr_flags));
- if (error != 0)
+ error = BCOPYOUT(&softc->ipf_flags, data,
+ sizeof(softc->ipf_flags));
+ if (error != 0) {
+ IPFERROR(99);
error = EFAULT;
+ }
break;
case SIOCFUNCL :
- error = fr_resolvefunc((void *)data);
+ error = ipf_resolvefunc(softc, (void *)data);
break;
case SIOCINAFR :
case SIOCRMAFR :
case SIOCADAFR :
case SIOCZRLST :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(100);
error = EPERM;
- else
- error = frrequest(IPL_LOGIPF, cmd, data, fr_active, 1);
+ } else {
+ error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data,
+ softc->ipf_active, 1);
+ }
break;
case SIOCINIFR :
case SIOCRMIFR :
case SIOCADIFR :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(101);
error = EPERM;
- else
- error = frrequest(IPL_LOGIPF, cmd, data,
- 1 - fr_active, 1);
+ } else {
+ error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data,
+ 1 - softc->ipf_active, 1);
+ }
break;
case SIOCSWAPA :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(102);
error = EPERM;
- else {
- WRITE_ENTER(&ipf_mutex);
- bzero((char *)frcache, sizeof(frcache[0]) * 2);
- error = BCOPYOUT(&fr_active, data, sizeof(fr_active));
- if (error != 0)
+ } else {
+ WRITE_ENTER(&softc->ipf_mutex);
+ error = BCOPYOUT(&softc->ipf_active, data,
+ sizeof(softc->ipf_active));
+ if (error != 0) {
+ IPFERROR(103);
error = EFAULT;
- else
- fr_active = 1 - fr_active;
- RWLOCK_EXIT(&ipf_mutex);
+ } else {
+ softc->ipf_active = 1 - softc->ipf_active;
+ }
+ RWLOCK_EXIT(&softc->ipf_mutex);
}
break;
case SIOCGETFS :
- fr_getstat(&fio);
- error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT);
+ error = ipf_inobj(softc, (void *)data, &obj, &fio,
+ IPFOBJ_IPFSTAT);
+ if (error != 0)
+ break;
+ ipf_getstat(softc, &fio, obj.ipfo_rev);
+ error = ipf_outobj(softc, (void *)data, &fio, IPFOBJ_IPFSTAT);
break;
case SIOCFRZST :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(104);
error = EPERM;
- else
- error = fr_zerostats(data);
+ } else
+ error = ipf_zerostats(softc, (caddr_t)data);
break;
case SIOCIPFFL :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(105);
error = EPERM;
- else {
+ } else {
error = BCOPYIN(data, &tmp, sizeof(tmp));
if (!error) {
- tmp = frflush(IPL_LOGIPF, 4, tmp);
+ tmp = ipf_flush(softc, IPL_LOGIPF, tmp);
error = BCOPYOUT(&tmp, data, sizeof(tmp));
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(106);
error = EFAULT;
- } else
+ }
+ } else {
+ IPFERROR(107);
error = EFAULT;
+ }
}
break;
#ifdef USE_INET6
case SIOCIPFL6 :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(108);
error = EPERM;
- else {
+ } else {
error = BCOPYIN(data, &tmp, sizeof(tmp));
if (!error) {
- tmp = frflush(IPL_LOGIPF, 6, tmp);
+ tmp = ipf_flush(softc, IPL_LOGIPF, tmp);
error = BCOPYOUT(&tmp, data, sizeof(tmp));
- if (error != 0)
+ if (error != 0) {
+ IPFERROR(109);
error = EFAULT;
- } else
+ }
+ } else {
+ IPFERROR(110);
error = EFAULT;
+ }
}
break;
#endif
case SIOCSTLCK :
- error = BCOPYIN(data, &tmp, sizeof(tmp));
- if (error == 0) {
- fr_state_lock = tmp;
- fr_nat_lock = tmp;
- fr_frag_lock = tmp;
- fr_auth_lock = tmp;
- } else
- error = EFAULT;
+ if (!(mode & FWRITE)) {
+ IPFERROR(122);
+ error = EPERM;
+ } else {
+ error = BCOPYIN(data, &tmp, sizeof(tmp));
+ if (error == 0) {
+ ipf_state_setlock(softc->ipf_state_soft, tmp);
+ ipf_nat_setlock(softc->ipf_nat_soft, tmp);
+ ipf_frag_setlock(softc->ipf_frag_soft, tmp);
+ ipf_auth_setlock(softc->ipf_auth_soft, tmp);
+ } else {
+ IPFERROR(111);
+ error = EFAULT;
+ }
+ }
break;
#ifdef IPFILTER_LOG
case SIOCIPFFB :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(112);
error = EPERM;
- else {
- tmp = ipflog_clear(IPL_LOGIPF);
+ } else {
+ tmp = ipf_log_clear(softc, IPL_LOGIPF);
error = BCOPYOUT(&tmp, data, sizeof(tmp));
- if (error)
+ if (error) {
+ IPFERROR(113);
error = EFAULT;
+ }
}
break;
#endif /* IPFILTER_LOG */
case SIOCFRSYN :
- if (!(mode & FWRITE))
+ if (!(mode & FWRITE)) {
+ IPFERROR(114);
error = EPERM;
- else {
- WRITE_ENTER(&ipf_global);
-#ifdef MENTAT
+ } else {
+ WRITE_ENTER(&softc->ipf_global);
+#if (defined(MENTAT) && defined(_KERNEL)) && !defined(INSTANCES)
error = ipfsync();
#else
- frsync(NULL);
+ ipf_sync(softc, NULL);
error = 0;
#endif
- RWLOCK_EXIT(&ipf_global);
+ RWLOCK_EXIT(&softc->ipf_global);
}
break;
case SIOCGFRST :
- error = fr_outobj((void *)data, fr_fragstats(),
- IPFOBJ_FRAGSTAT);
+ error = ipf_outobj(softc, (void *)data,
+ ipf_frag_stats(softc->ipf_frag_soft),
+ IPFOBJ_FRAGSTAT);
break;
#ifdef IPFILTER_LOG
case FIONREAD :
- tmp = (int)iplused[IPL_LOGIPF];
-
+ tmp = ipf_log_bytesused(softc, IPL_LOGIPF);
error = BCOPYOUT(&tmp, data, sizeof(tmp));
break;
#endif
case SIOCIPFITER :
SPL_SCHED(s);
- error = ipf_frruleiter(data, uid, ctx);
+ error = ipf_frruleiter(softc, data, uid, ctx);
SPL_X(s);
break;
case SIOCGENITER :
SPL_SCHED(s);
- error = ipf_genericiter(data, uid, ctx);
+ error = ipf_genericiter(softc, data, uid, ctx);
SPL_X(s);
break;
case SIOCIPFDELTOK :
- SPL_SCHED(s);
error = BCOPYIN(data, &tmp, sizeof(tmp));
- if (error == 0)
- error = ipf_deltoken(tmp, uid, ctx);
- SPL_X(s);
+ if (error == 0) {
+ SPL_SCHED(s);
+ error = ipf_token_del(softc, tmp, uid, ctx);
+ SPL_X(s);
+ }
break;
default :
+ IPFERROR(115);
error = EINVAL;
break;
}
@@ -7236,90 +8388,610 @@ void *ctx;
/* ------------------------------------------------------------------------ */
+/* Function: ipf_decaps */
+/* Returns: int - -1 == decapsulation failed, else bit mask of */
+/* flags indicating packet filtering decision. */
+/* Parameters: fin(I) - pointer to packet information */
+/* pass(I) - IP protocol version to match */
+/* l5proto(I) - layer 5 protocol to decode UDP data as. */
+/* */
+/* This function is called for packets that are wrapt up in other packets, */
+/* for example, an IP packet that is the entire data segment for another IP */
+/* packet. If the basic constraints for this are satisfied, change the */
+/* buffer to point to the start of the inner packet and start processing */
+/* rules belonging to the head group this rule specifies. */
+/* ------------------------------------------------------------------------ */
+u_32_t
+ipf_decaps(fin, pass, l5proto)
+ fr_info_t *fin;
+ u_32_t pass;
+ int l5proto;
+{
+ fr_info_t fin2, *fino = NULL;
+ int elen, hlen, nh;
+ grehdr_t gre;
+ ip_t *ip;
+ mb_t *m;
+
+ if ((fin->fin_flx & FI_COALESCE) == 0)
+ if (ipf_coalesce(fin) == -1)
+ goto cantdecaps;
+
+ m = fin->fin_m;
+ hlen = fin->fin_hlen;
+
+ switch (fin->fin_p)
+ {
+ case IPPROTO_UDP :
+ /*
+ * In this case, the specific protocol being decapsulated
+ * inside UDP frames comes from the rule.
+ */
+ nh = fin->fin_fr->fr_icode;
+ break;
+
+ case IPPROTO_GRE : /* 47 */
+ bcopy(fin->fin_dp, (char *)&gre, sizeof(gre));
+ hlen += sizeof(grehdr_t);
+ if (gre.gr_R|gre.gr_s)
+ goto cantdecaps;
+ if (gre.gr_C)
+ hlen += 4;
+ if (gre.gr_K)
+ hlen += 4;
+ if (gre.gr_S)
+ hlen += 4;
+
+ nh = IPPROTO_IP;
+
+ /*
+ * If the routing options flag is set, validate that it is
+ * there and bounce over it.
+ */
+#if 0
+ /* This is really heavy weight and lots of room for error, */
+ /* so for now, put it off and get the simple stuff right. */
+ if (gre.gr_R) {
+ u_char off, len, *s;
+ u_short af;
+ int end;
+
+ end = 0;
+ s = fin->fin_dp;
+ s += hlen;
+ aplen = fin->fin_plen - hlen;
+ while (aplen > 3) {
+ af = (s[0] << 8) | s[1];
+ off = s[2];
+ len = s[3];
+ aplen -= 4;
+ s += 4;
+ if (af == 0 && len == 0) {
+ end = 1;
+ break;
+ }
+ if (aplen < len)
+ break;
+ s += len;
+ aplen -= len;
+ }
+ if (end != 1)
+ goto cantdecaps;
+ hlen = s - (u_char *)fin->fin_dp;
+ }
+#endif
+ break;
+
+#ifdef IPPROTO_IPIP
+ case IPPROTO_IPIP : /* 4 */
+#endif
+ nh = IPPROTO_IP;
+ break;
+
+ default : /* Includes ESP, AH is special for IPv4 */
+ goto cantdecaps;
+ }
+
+ switch (nh)
+ {
+ case IPPROTO_IP :
+ case IPPROTO_IPV6 :
+ break;
+ default :
+ goto cantdecaps;
+ }
+
+ bcopy((char *)fin, (char *)&fin2, sizeof(fin2));
+ fino = fin;
+ fin = &fin2;
+ elen = hlen;
+#if defined(MENTAT) && defined(_KERNEL)
+ m->b_rptr += elen;
+#else
+ m->m_data += elen;
+ m->m_len -= elen;
+#endif
+ fin->fin_plen -= elen;
+
+ ip = (ip_t *)((char *)fin->fin_ip + elen);
+
+ /*
+ * Make sure we have at least enough data for the network layer
+ * header.
+ */
+ if (IP_V(ip) == 4)
+ hlen = IP_HL(ip) << 2;
+#ifdef USE_INET6
+ else if (IP_V(ip) == 6)
+ hlen = sizeof(ip6_t);
+#endif
+ else
+ goto cantdecaps2;
+
+ if (fin->fin_plen < hlen)
+ goto cantdecaps2;
+
+ fin->fin_dp = (char *)ip + hlen;
+
+ if (IP_V(ip) == 4) {
+ /*
+ * Perform IPv4 header checksum validation.
+ */
+ if (ipf_cksum((u_short *)ip, hlen))
+ goto cantdecaps2;
+ }
+
+ if (ipf_makefrip(hlen, ip, fin) == -1) {
+cantdecaps2:
+ if (m != NULL) {
+#if defined(MENTAT) && defined(_KERNEL)
+ m->b_rptr -= elen;
+#else
+ m->m_data -= elen;
+ m->m_len += elen;
+#endif
+ }
+cantdecaps:
+ DT1(frb_decapfrip, fr_info_t *, fin);
+ pass &= ~FR_CMDMASK;
+ pass |= FR_BLOCK|FR_QUICK;
+ fin->fin_reason = FRB_DECAPFRIP;
+ return -1;
+ }
+
+ pass = ipf_scanlist(fin, pass);
+
+ /*
+ * Copy the packet filter "result" fields out of the fr_info_t struct
+ * that is local to the decapsulation processing and back into the
+ * one we were called with.
+ */
+ fino->fin_flx = fin->fin_flx;
+ fino->fin_rev = fin->fin_rev;
+ fino->fin_icode = fin->fin_icode;
+ fino->fin_rule = fin->fin_rule;
+ (void) strncpy(fino->fin_group, fin->fin_group, FR_GROUPLEN);
+ fino->fin_fr = fin->fin_fr;
+ fino->fin_error = fin->fin_error;
+ fino->fin_mp = fin->fin_mp;
+ fino->fin_m = fin->fin_m;
+ m = fin->fin_m;
+ if (m != NULL) {
+#if defined(MENTAT) && defined(_KERNEL)
+ m->b_rptr -= elen;
+#else
+ m->m_data -= elen;
+ m->m_len += elen;
+#endif
+ }
+ return pass;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_matcharray_load */
+/* Returns: int - 0 = success, else error */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* data(I) - pointer to ioctl data */
+/* objp(I) - ipfobj_t structure to load data into */
+/* arrayptr(I) - pointer to location to store array pointer */
+/* */
+/* This function loads in a mathing array through the ipfobj_t struct that */
+/* describes it. Sanity checking and array size limitations are enforced */
+/* in this function to prevent userspace from trying to load in something */
+/* that is insanely big. Once the size of the array is known, the memory */
+/* required is malloc'd and returned through changing *arrayptr. The */
+/* contents of the array are verified before returning. Only in the event */
+/* of a successful call is the caller required to free up the malloc area. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_matcharray_load(softc, data, objp, arrayptr)
+ ipf_main_softc_t *softc;
+ caddr_t data;
+ ipfobj_t *objp;
+ int **arrayptr;
+{
+ int arraysize, *array, error;
+
+ *arrayptr = NULL;
+
+ error = BCOPYIN(data, objp, sizeof(*objp));
+ if (error != 0) {
+ IPFERROR(116);
+ return EFAULT;
+ }
+
+ if (objp->ipfo_type != IPFOBJ_IPFEXPR) {
+ IPFERROR(117);
+ return EINVAL;
+ }
+
+ if (((objp->ipfo_size & 3) != 0) || (objp->ipfo_size == 0) ||
+ (objp->ipfo_size > 1024)) {
+ IPFERROR(118);
+ return EINVAL;
+ }
+
+ arraysize = objp->ipfo_size * sizeof(*array);
+ KMALLOCS(array, int *, arraysize);
+ if (array == NULL) {
+ IPFERROR(119);
+ return ENOMEM;
+ }
+
+ error = COPYIN(objp->ipfo_ptr, array, arraysize);
+ if (error != 0) {
+ KFREES(array, arraysize);
+ IPFERROR(120);
+ return EFAULT;
+ }
+
+ if (ipf_matcharray_verify(array, arraysize) != 0) {
+ KFREES(array, arraysize);
+ IPFERROR(121);
+ return EINVAL;
+ }
+
+ *arrayptr = array;
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_matcharray_verify */
+/* Returns: Nil */
+/* Parameters: array(I) - pointer to matching array */
+/* arraysize(I) - number of elements in the array */
+/* */
+/* Verify the contents of a matching array by stepping through each element */
+/* in it. The actual commands in the array are not verified for */
+/* correctness, only that all of the sizes are correctly within limits. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_matcharray_verify(array, arraysize)
+ int *array, arraysize;
+{
+ int i, nelem, maxidx;
+ ipfexp_t *e;
+
+ nelem = arraysize / sizeof(*array);
+
+ /*
+ * Currently, it makes no sense to have an array less than 6
+ * elements long - the initial size at the from, a single operation
+ * (minimum 4 in length) and a trailer, for a total of 6.
+ */
+ if ((array[0] < 6) || (arraysize < 24) || (arraysize > 4096)) {
+ return -1;
+ }
+
+ /*
+ * Verify the size of data pointed to by array with how long
+ * the array claims to be itself.
+ */
+ if (array[0] * sizeof(*array) != arraysize) {
+ return -1;
+ }
+
+ maxidx = nelem - 1;
+ /*
+ * The last opcode in this array should be an IPF_EXP_END.
+ */
+ if (array[maxidx] != IPF_EXP_END) {
+ return -1;
+ }
+
+ for (i = 1; i < maxidx; ) {
+ e = (ipfexp_t *)(array + i);
+
+ /*
+ * The length of the bits to check must be at least 1
+ * (or else there is nothing to comapre with!) and it
+ * cannot exceed the length of the data present.
+ */
+ if ((e->ipfe_size < 1 ) ||
+ (e->ipfe_size + i > maxidx)) {
+ return -1;
+ }
+ i += e->ipfe_size;
+ }
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_fr_matcharray */
+/* Returns: int - 0 = match failed, else positive match */
+/* Parameters: fin(I) - pointer to packet information */
+/* array(I) - pointer to matching array */
+/* */
+/* This function is used to apply a matching array against a packet and */
+/* return an indication of whether or not the packet successfully matches */
+/* all of the commands in it. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_fr_matcharray(fin, array)
+ fr_info_t *fin;
+ int *array;
+{
+ int i, n, *x, rv, p;
+ ipfexp_t *e;
+
+ rv = 0;
+ n = array[0];
+ x = array + 1;
+
+ for (; n > 0; x += 3 + x[3], rv = 0) {
+ e = (ipfexp_t *)x;
+ if (e->ipfe_cmd == IPF_EXP_END)
+ break;
+ n -= e->ipfe_size;
+
+ /*
+ * The upper 16 bits currently store the protocol value.
+ * This is currently used with TCP and UDP port compares and
+ * allows "tcp.port = 80" without requiring an explicit
+ " "ip.pr = tcp" first.
+ */
+ p = e->ipfe_cmd >> 16;
+ if ((p != 0) && (p != fin->fin_p))
+ break;
+
+ switch (e->ipfe_cmd)
+ {
+ case IPF_EXP_IP_PR :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (fin->fin_p == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_IP_SRCADDR :
+ if (fin->fin_v != 4)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= ((fin->fin_saddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]);
+ }
+ break;
+
+ case IPF_EXP_IP_DSTADDR :
+ if (fin->fin_v != 4)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= ((fin->fin_daddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]);
+ }
+ break;
+
+ case IPF_EXP_IP_ADDR :
+ if (fin->fin_v != 4)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= ((fin->fin_saddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]) ||
+ ((fin->fin_daddr &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]);
+ }
+ break;
+
+#ifdef USE_INET6
+ case IPF_EXP_IP6_SRCADDR :
+ if (fin->fin_v != 6)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= IP6_MASKEQ(&fin->fin_src6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]);
+ }
+ break;
+
+ case IPF_EXP_IP6_DSTADDR :
+ if (fin->fin_v != 6)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= IP6_MASKEQ(&fin->fin_dst6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]);
+ }
+ break;
+
+ case IPF_EXP_IP6_ADDR :
+ if (fin->fin_v != 6)
+ break;
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= IP6_MASKEQ(&fin->fin_src6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]) ||
+ IP6_MASKEQ(&fin->fin_dst6,
+ &e->ipfe_arg0[i * 8 + 4],
+ &e->ipfe_arg0[i * 8]);
+ }
+ break;
+#endif
+
+ case IPF_EXP_UDP_PORT :
+ case IPF_EXP_TCP_PORT :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (fin->fin_sport == e->ipfe_arg0[i]) ||
+ (fin->fin_dport == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_UDP_SPORT :
+ case IPF_EXP_TCP_SPORT :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (fin->fin_sport == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_UDP_DPORT :
+ case IPF_EXP_TCP_DPORT :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= (fin->fin_dport == e->ipfe_arg0[i]);
+ }
+ break;
+
+ case IPF_EXP_TCP_FLAGS :
+ for (i = 0; !rv && i < e->ipfe_narg; i++) {
+ rv |= ((fin->fin_tcpf &
+ e->ipfe_arg0[i * 2 + 1]) ==
+ e->ipfe_arg0[i * 2]);
+ }
+ break;
+ }
+ rv ^= e->ipfe_not;
+
+ if (rv == 0)
+ break;
+ }
+
+ return rv;
+}
+
+
+/* ------------------------------------------------------------------------ */
/* Function: ipf_queueflush */
/* Returns: int - number of entries flushed (0 = none) */
-/* Parameters: deletefn(I) - function to call to delete entry */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* deletefn(I) - function to call to delete entry */
/* ipfqs(I) - top of the list of ipf internal queues */
/* userqs(I) - top of the list of user defined timeouts */
/* */
/* This fucntion gets called when the state/NAT hash tables fill up and we */
-/* need to try a bit harder to free up some space. The algorithm used is */
-/* to look for the oldest entries on each timeout queue and free them if */
-/* they are within the given window we are considering. Where the window */
-/* starts and the steps taken to increase its size depend upon how long ipf */
-/* has been running (fr_ticks.) Anything modified in the last 30 seconds */
-/* is not touched. */
+/* need to try a bit harder to free up some space. The algorithm used here */
+/* split into two parts but both halves have the same goal: to reduce the */
+/* number of connections considered to be "active" to the low watermark. */
+/* There are two steps in doing this: */
+/* 1) Remove any TCP connections that are already considered to be "closed" */
+/* but have not yet been removed from the state table. The two states */
+/* TCPS_TIME_WAIT and TCPS_CLOSED are considered to be the perfect */
+/* candidates for this style of removal. If freeing up entries in */
+/* CLOSED or both CLOSED and TIME_WAIT brings us to the low watermark, */
+/* we do not go on to step 2. */
+/* */
+/* 2) Look for the oldest entries on each timeout queue and free them if */
+/* they are within the given window we are considering. Where the */
+/* window starts and the steps taken to increase its size depend upon */
+/* how long ipf has been running (ipf_ticks.) Anything modified in the */
+/* last 30 seconds is not touched. */
/* touched */
-/* die fr_ticks 30*1.5 1800*1.5 | 43200*1.5 */
+/* die ipf_ticks 30*1.5 1800*1.5 | 43200*1.5 */
/* | | | | | | */
/* future <--+----------+--------+-----------+-----+-----+-----------> past */
/* now \_int=30s_/ \_int=1hr_/ \_int=12hr */
/* */
/* Points to note: */
/* - tqe_die is the time, in the future, when entries die. */
-/* - tqe_die - fr_ticks is how long left the connection has to live in ipf */
+/* - tqe_die - ipf_ticks is how long left the connection has to live in ipf */
/* ticks. */
/* - tqe_touched is when the entry was last used by NAT/state */
-/* - the closer tqe_touched is to fr_ticks, the further tqe_die will be for */
-/* any given timeout queue and vice versa. */
+/* - the closer tqe_touched is to ipf_ticks, the further tqe_die will be */
+/* ipf_ticks any given timeout queue and vice versa. */
/* - both tqe_die and tqe_touched increase over time */
/* - timeout queues are sorted with the highest value of tqe_die at the */
/* bottom and therefore the smallest values of each are at the top */
+/* - the pointer passed in as ipfqs should point to an array of timeout */
+/* queues representing each of the TCP states */
/* */
/* We start by setting up a maximum range to scan for things to move of */
/* iend (newest) to istart (oldest) in chunks of "interval". If nothing is */
/* found in that range, "interval" is adjusted (so long as it isn't 30) and */
-/* we start again with a new value for "iend" and "istart". The downside */
-/* of the current implementation is that it may return removing just 1 entry*/
-/* every time (pathological case) where it could remove more. */
+/* we start again with a new value for "iend" and "istart". This is */
+/* continued until we either finish the scan of 30 second intervals or the */
+/* low water mark is reached. */
/* ------------------------------------------------------------------------ */
-int ipf_queueflush(deletefn, ipfqs, userqs)
-ipftq_delete_fn_t deletefn;
-ipftq_t *ipfqs, *userqs;
+int
+ipf_queueflush(softc, deletefn, ipfqs, userqs, activep, size, low)
+ ipf_main_softc_t *softc;
+ ipftq_delete_fn_t deletefn;
+ ipftq_t *ipfqs, *userqs;
+ u_int *activep;
+ int size, low;
{
u_long interval, istart, iend;
ipftq_t *ifq, *ifqnext;
ipftqent_t *tqe, *tqn;
- int removed;
+ int removed = 0;
+
+ for (tqn = ipfqs[IPF_TCPS_CLOSED].ifq_head; ((tqe = tqn) != NULL); ) {
+ tqn = tqe->tqe_next;
+ if ((*deletefn)(softc, tqe->tqe_parent) == 0)
+ removed++;
+ }
+ if ((*activep * 100 / size) > low) {
+ for (tqn = ipfqs[IPF_TCPS_TIME_WAIT].ifq_head;
+ ((tqe = tqn) != NULL); ) {
+ tqn = tqe->tqe_next;
+ if ((*deletefn)(softc, tqe->tqe_parent) == 0)
+ removed++;
+ }
+ }
+
+ if ((*activep * 100 / size) <= low) {
+ return removed;
+ }
/*
* NOTE: Use of "* 15 / 10" is required here because if "* 1.5" is
* used then the operations are upgraded to floating point
* and kernels don't like floating point...
*/
- if (fr_ticks > IPF_TTLVAL(43200 * 15 / 10)) {
+ if (softc->ipf_ticks > IPF_TTLVAL(43200 * 15 / 10)) {
istart = IPF_TTLVAL(86400 * 4);
interval = IPF_TTLVAL(43200);
- } else if (fr_ticks > IPF_TTLVAL(1800 * 15 / 10)) {
+ } else if (softc->ipf_ticks > IPF_TTLVAL(1800 * 15 / 10)) {
istart = IPF_TTLVAL(43200);
interval = IPF_TTLVAL(1800);
- } else if (fr_ticks > IPF_TTLVAL(30 * 15 / 10)) {
+ } else if (softc->ipf_ticks > IPF_TTLVAL(30 * 15 / 10)) {
istart = IPF_TTLVAL(1800);
interval = IPF_TTLVAL(30);
} else {
return 0;
}
- if (istart > fr_ticks) {
- if (fr_ticks - interval < interval)
+ if (istart > softc->ipf_ticks) {
+ if (softc->ipf_ticks - interval < interval)
istart = interval;
else
- istart = (fr_ticks / interval) * interval;
+ istart = (softc->ipf_ticks / interval) * interval;
}
- iend = fr_ticks - interval;
- removed = 0;
+ iend = softc->ipf_ticks - interval;
- for (;;) {
+ while ((*activep * 100 / size) > low) {
u_long try;
- try = fr_ticks - istart;
+ try = softc->ipf_ticks - istart;
for (ifq = ipfqs; ifq != NULL; ifq = ifq->ifq_next) {
for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) {
if (try < tqe->tqe_touched)
break;
tqn = tqe->tqe_next;
- if ((*deletefn)(tqe->tqe_parent) == 0)
+ if ((*deletefn)(softc, tqe->tqe_parent) == 0)
removed++;
}
}
@@ -7331,14 +9003,12 @@ ipftq_t *ipfqs, *userqs;
if (try < tqe->tqe_touched)
break;
tqn = tqe->tqe_next;
- if ((*deletefn)(tqe->tqe_parent) == 0)
+ if ((*deletefn)(softc, tqe->tqe_parent) == 0)
removed++;
}
}
if (try >= iend) {
- if (removed > 0)
- break;
if (interval == IPF_TTLVAL(43200)) {
interval = IPF_TTLVAL(1800);
} else if (interval == IPF_TTLVAL(1800)) {
@@ -7346,13 +9016,1200 @@ ipftq_t *ipfqs, *userqs;
} else {
break;
}
- if (interval >= fr_ticks)
+ if (interval >= softc->ipf_ticks)
break;
- iend = fr_ticks - interval;
+ iend = softc->ipf_ticks - interval;
}
istart -= interval;
}
return removed;
}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_deliverlocal */
+/* Returns: int - 1 = local address, 0 = non-local address */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* ipversion(I) - IP protocol version (4 or 6) */
+/* ifp(I) - network interface pointer */
+/* ipaddr(I) - IPv4/6 destination address */
+/* */
+/* This fucntion is used to determine in the address "ipaddr" belongs to */
+/* the network interface represented by ifp. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_deliverlocal(softc, ipversion, ifp, ipaddr)
+ ipf_main_softc_t *softc;
+ int ipversion;
+ void *ifp;
+ i6addr_t *ipaddr;
+{
+ i6addr_t addr;
+ int islocal = 0;
+
+ if (ipversion == 4) {
+ if (ipf_ifpaddr(softc, 4, FRI_NORMAL, ifp, &addr, NULL) == 0) {
+ if (addr.in4.s_addr == ipaddr->in4.s_addr)
+ islocal = 1;
+ }
+
+#ifdef USE_INET6
+ } else if (ipversion == 6) {
+ if (ipf_ifpaddr(softc, 6, FRI_NORMAL, ifp, &addr, NULL) == 0) {
+ if (IP6_EQ(&addr, ipaddr))
+ islocal = 1;
+ }
+#endif
+ }
+
+ return islocal;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_settimeout */
+/* Returns: int - 0 = success, -1 = failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* t(I) - pointer to tuneable array entry */
+/* p(I) - pointer to values passed in to apply */
+/* */
+/* This function is called to set the timeout values for each distinct */
+/* queue timeout that is available. When called, it calls into both the */
+/* state and NAT code, telling them to update their timeout queues. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_settimeout(softc, t, p)
+ struct ipf_main_softc_s *softc;
+ ipftuneable_t *t;
+ ipftuneval_t *p;
+{
+
+ /*
+ * ipf_interror should be set by the functions called here, not
+ * by this function - it's just a middle man.
+ */
+ if (ipf_state_settimeout(softc, t, p) == -1)
+ return -1;
+ if (ipf_nat_settimeout(softc, t, p) == -1)
+ return -1;
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_apply_timeout */
+/* Returns: int - 0 = success, -1 = failure */
+/* Parameters: head(I) - pointer to tuneable array entry */
+/* seconds(I) - pointer to values passed in to apply */
+/* */
+/* This function applies a timeout of "seconds" to the timeout queue that */
+/* is pointed to by "head". All entries on this list have an expiration */
+/* set to be the current tick value of ipf plus the ttl. Given that this */
+/* function should only be called when the delta is non-zero, the task is */
+/* to walk the entire list and apply the change. The sort order will not */
+/* change. The only catch is that this is O(n) across the list, so if the */
+/* queue has lots of entries (10s of thousands or 100s of thousands), it */
+/* could take a relatively long time to work through them all. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_apply_timeout(head, seconds)
+ ipftq_t *head;
+ u_int seconds;
+{
+ u_int oldtimeout, newtimeout;
+ ipftqent_t *tqe;
+ int delta;
+
+ MUTEX_ENTER(&head->ifq_lock);
+ oldtimeout = head->ifq_ttl;
+ newtimeout = IPF_TTLVAL(seconds);
+ delta = oldtimeout - newtimeout;
+
+ head->ifq_ttl = newtimeout;
+
+ for (tqe = head->ifq_head; tqe != NULL; tqe = tqe->tqe_next) {
+ tqe->tqe_die += delta;
+ }
+ MUTEX_EXIT(&head->ifq_lock);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_settimeout_tcp */
+/* Returns: int - 0 = successfully applied, -1 = failed */
+/* Parameters: t(I) - pointer to tuneable to change */
+/* p(I) - pointer to new timeout information */
+/* tab(I) - pointer to table of TCP queues */
+/* */
+/* This function applies the new timeout (p) to the TCP tunable (t) and */
+/* updates all of the entries on the relevant timeout queue by calling */
+/* ipf_apply_timeout(). */
+/* ------------------------------------------------------------------------ */
+int
+ipf_settimeout_tcp(t, p, tab)
+ ipftuneable_t *t;
+ ipftuneval_t *p;
+ ipftq_t *tab;
+{
+ if (!strcmp(t->ipft_name, "tcp_idle_timeout") ||
+ !strcmp(t->ipft_name, "tcp_established")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_ESTABLISHED], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_close_wait")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_CLOSE_WAIT], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_last_ack")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_LAST_ACK], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_timeout")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int);
+ ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int);
+ ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_listen")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_half_established")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_closing")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_syn_received")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_SYN_RECEIVED], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_syn_sent")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_SYN_SENT], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_closed")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_half_closed")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int);
+ } else if (!strcmp(t->ipft_name, "tcp_time_wait")) {
+ ipf_apply_timeout(&tab[IPF_TCPS_TIME_WAIT], p->ipftu_int);
+ } else {
+ /*
+ * ipf_interror isn't set here because it should be set
+ * by whatever called this function.
+ */
+ return -1;
+ }
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_main_soft_create */
+/* Returns: NULL = failure, else success */
+/* Parameters: arg(I) - pointer to soft context structure if already allocd */
+/* */
+/* Create the foundation soft context structure. In circumstances where it */
+/* is not required to dynamically allocate the context, a pointer can be */
+/* passed in (rather than NULL) to a structure to be initialised. */
+/* The main thing of interest is that a number of locks are initialised */
+/* here instead of in the where might be expected - in the relevant create */
+/* function elsewhere. This is done because the current locking design has */
+/* some areas where these locks are used outside of their module. */
+/* Possibly the most important exercise that is done here is setting of all */
+/* the timeout values, allowing them to be changed before init(). */
+/* ------------------------------------------------------------------------ */
+void *
+ipf_main_soft_create(arg)
+ void *arg;
+{
+ ipf_main_softc_t *softc;
+
+ if (arg == NULL) {
+ KMALLOC(softc, ipf_main_softc_t *);
+ if (softc == NULL)
+ return NULL;
+ } else {
+ softc = arg;
+ }
+
+ bzero((char *)softc, sizeof(*softc));
+
+ /*
+ * This serves as a flag as to whether or not the softc should be
+ * free'd when _destroy is called.
+ */
+ softc->ipf_dynamic_softc = (arg == NULL) ? 1 : 0;
+
+ softc->ipf_tuners = ipf_tune_array_copy(softc,
+ sizeof(ipf_main_tuneables),
+ ipf_main_tuneables);
+ if (softc->ipf_tuners == NULL) {
+ ipf_main_soft_destroy(softc);
+ return NULL;
+ }
+
+ MUTEX_INIT(&softc->ipf_rw, "ipf rw mutex");
+ MUTEX_INIT(&softc->ipf_timeoutlock, "ipf timeout lock");
+ RWLOCK_INIT(&softc->ipf_global, "ipf filter load/unload mutex");
+ RWLOCK_INIT(&softc->ipf_mutex, "ipf filter rwlock");
+ RWLOCK_INIT(&softc->ipf_tokens, "ipf token rwlock");
+ RWLOCK_INIT(&softc->ipf_state, "ipf state rwlock");
+ RWLOCK_INIT(&softc->ipf_nat, "ipf IP NAT rwlock");
+ RWLOCK_INIT(&softc->ipf_poolrw, "ipf pool rwlock");
+ RWLOCK_INIT(&softc->ipf_frag, "ipf frag rwlock");
+
+ softc->ipf_token_head = NULL;
+ softc->ipf_token_tail = &softc->ipf_token_head;
+
+ softc->ipf_tcpidletimeout = FIVE_DAYS;
+ softc->ipf_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL);
+ softc->ipf_tcplastack = IPF_TTLVAL(30);
+ softc->ipf_tcptimewait = IPF_TTLVAL(2 * TCP_MSL);
+ softc->ipf_tcptimeout = IPF_TTLVAL(2 * TCP_MSL);
+ softc->ipf_tcpsynsent = IPF_TTLVAL(2 * TCP_MSL);
+ softc->ipf_tcpsynrecv = IPF_TTLVAL(2 * TCP_MSL);
+ softc->ipf_tcpclosed = IPF_TTLVAL(30);
+ softc->ipf_tcphalfclosed = IPF_TTLVAL(2 * 3600);
+ softc->ipf_udptimeout = IPF_TTLVAL(120);
+ softc->ipf_udpacktimeout = IPF_TTLVAL(12);
+ softc->ipf_icmptimeout = IPF_TTLVAL(60);
+ softc->ipf_icmpacktimeout = IPF_TTLVAL(6);
+ softc->ipf_iptimeout = IPF_TTLVAL(60);
+
+#if defined(IPFILTER_DEFAULT_BLOCK)
+ softc->ipf_pass = FR_BLOCK|FR_NOMATCH;
+#else
+ softc->ipf_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH;
+#endif
+ softc->ipf_minttl = 4;
+ softc->ipf_icmpminfragmtu = 68;
+ softc->ipf_flags = IPF_LOGGING;
+
+ return softc;
+}
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_main_soft_init */
+/* Returns: 0 = success, -1 = failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* A null-op function that exists as a placeholder so that the flow in */
+/* other functions is obvious. */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+int
+ipf_main_soft_init(softc)
+ ipf_main_softc_t *softc;
+{
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_main_soft_destroy */
+/* Returns: void */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Undo everything that we did in ipf_main_soft_create. */
+/* */
+/* The most important check that needs to be made here is whether or not */
+/* the structure was allocated by ipf_main_soft_create() by checking what */
+/* value is stored in ipf_dynamic_main. */
+/* ------------------------------------------------------------------------ */
+/*ARGSUSED*/
+void
+ipf_main_soft_destroy(softc)
+ ipf_main_softc_t *softc;
+{
+
+ RW_DESTROY(&softc->ipf_frag);
+ RW_DESTROY(&softc->ipf_poolrw);
+ RW_DESTROY(&softc->ipf_nat);
+ RW_DESTROY(&softc->ipf_state);
+ RW_DESTROY(&softc->ipf_tokens);
+ RW_DESTROY(&softc->ipf_mutex);
+ RW_DESTROY(&softc->ipf_global);
+ MUTEX_DESTROY(&softc->ipf_timeoutlock);
+ MUTEX_DESTROY(&softc->ipf_rw);
+
+ if (softc->ipf_tuners != NULL) {
+ KFREES(softc->ipf_tuners, sizeof(ipf_main_tuneables));
+ }
+ if (softc->ipf_dynamic_softc == 1) {
+ KFREE(softc);
+ }
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_main_soft_fini */
+/* Returns: 0 = success, -1 = failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Clean out the rules which have been added since _init was last called, */
+/* the only dynamic part of the mainline. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_main_soft_fini(softc)
+ ipf_main_softc_t *softc;
+{
+ (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
+ (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE);
+ (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE|FR_INACTIVE);
+ (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE);
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_main_load */
+/* Returns: 0 = success, -1 = failure */
+/* Parameters: none */
+/* */
+/* Handle global initialisation that needs to be done for the base part of */
+/* IPFilter. At present this just amounts to initialising some ICMP lookup */
+/* arrays that get used by the state/NAT code. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_main_load()
+{
+ int i;
+
+ /* fill icmp reply type table */
+ for (i = 0; i <= ICMP_MAXTYPE; i++)
+ icmpreplytype4[i] = -1;
+ icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY;
+ icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY;
+ icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY;
+ icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY;
+
+#ifdef USE_INET6
+ /* fill icmp reply type table */
+ for (i = 0; i <= ICMP6_MAXTYPE; i++)
+ icmpreplytype6[i] = -1;
+ icmpreplytype6[ICMP6_ECHO_REQUEST] = ICMP6_ECHO_REPLY;
+ icmpreplytype6[ICMP6_MEMBERSHIP_QUERY] = ICMP6_MEMBERSHIP_REPORT;
+ icmpreplytype6[ICMP6_NI_QUERY] = ICMP6_NI_REPLY;
+ icmpreplytype6[ND_ROUTER_SOLICIT] = ND_ROUTER_ADVERT;
+ icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT;
+#endif
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_main_unload */
+/* Returns: 0 = success, -1 = failure */
+/* Parameters: none */
+/* */
+/* A null-op function that exists as a placeholder so that the flow in */
+/* other functions is obvious. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_main_unload()
+{
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_load_all */
+/* Returns: 0 = success, -1 = failure */
+/* Parameters: none */
+/* */
+/* Work through all of the subsystems inside IPFilter and call the load */
+/* function for each in an order that won't lead to a crash :) */
+/* ------------------------------------------------------------------------ */
+int
+ipf_load_all()
+{
+ if (ipf_main_load() == -1)
+ return -1;
+
+ if (ipf_state_main_load() == -1)
+ return -1;
+
+ if (ipf_nat_main_load() == -1)
+ return -1;
+
+ if (ipf_frag_main_load() == -1)
+ return -1;
+
+ if (ipf_auth_main_load() == -1)
+ return -1;
+
+ if (ipf_proxy_main_load() == -1)
+ return -1;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_unload_all */
+/* Returns: 0 = success, -1 = failure */
+/* Parameters: none */
+/* */
+/* Work through all of the subsystems inside IPFilter and call the unload */
+/* function for each in an order that won't lead to a crash :) */
+/* ------------------------------------------------------------------------ */
+int
+ipf_unload_all()
+{
+ if (ipf_proxy_main_unload() == -1)
+ return -1;
+
+ if (ipf_auth_main_unload() == -1)
+ return -1;
+
+ if (ipf_frag_main_unload() == -1)
+ return -1;
+
+ if (ipf_nat_main_unload() == -1)
+ return -1;
+
+ if (ipf_state_main_unload() == -1)
+ return -1;
+
+ if (ipf_main_unload() == -1)
+ return -1;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_create_all */
+/* Returns: NULL = failure, else success */
+/* Parameters: arg(I) - pointer to soft context main structure */
+/* */
+/* Work through all of the subsystems inside IPFilter and call the create */
+/* function for each in an order that won't lead to a crash :) */
+/* ------------------------------------------------------------------------ */
+ipf_main_softc_t *
+ipf_create_all(arg)
+ void *arg;
+{
+ ipf_main_softc_t *softc;
+
+ softc = ipf_main_soft_create(arg);
+ if (softc == NULL)
+ return NULL;
+
+#ifdef IPFILTER_LOG
+ softc->ipf_log_soft = ipf_log_soft_create(softc);
+ if (softc->ipf_log_soft == NULL) {
+ ipf_destroy_all(softc);
+ return NULL;
+ }
+#endif
+
+ softc->ipf_lookup_soft = ipf_lookup_soft_create(softc);
+ if (softc->ipf_lookup_soft == NULL) {
+ ipf_destroy_all(softc);
+ return NULL;
+ }
+
+ softc->ipf_sync_soft = ipf_sync_soft_create(softc);
+ if (softc->ipf_sync_soft == NULL) {
+ ipf_destroy_all(softc);
+ return NULL;
+ }
+
+ softc->ipf_state_soft = ipf_state_soft_create(softc);
+ if (softc->ipf_state_soft == NULL) {
+ ipf_destroy_all(softc);
+ return NULL;
+ }
+
+ softc->ipf_nat_soft = ipf_nat_soft_create(softc);
+ if (softc->ipf_nat_soft == NULL) {
+ ipf_destroy_all(softc);
+ return NULL;
+ }
+
+ softc->ipf_frag_soft = ipf_frag_soft_create(softc);
+ if (softc->ipf_frag_soft == NULL) {
+ ipf_destroy_all(softc);
+ return NULL;
+ }
+
+ softc->ipf_auth_soft = ipf_auth_soft_create(softc);
+ if (softc->ipf_auth_soft == NULL) {
+ ipf_destroy_all(softc);
+ return NULL;
+ }
+
+ softc->ipf_proxy_soft = ipf_proxy_soft_create(softc);
+ if (softc->ipf_proxy_soft == NULL) {
+ ipf_destroy_all(softc);
+ return NULL;
+ }
+
+ return softc;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_destroy_all */
+/* Returns: void */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Work through all of the subsystems inside IPFilter and call the destroy */
+/* function for each in an order that won't lead to a crash :) */
+/* */
+/* Every one of these functions is expected to succeed, so there is no */
+/* checking of return values. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_destroy_all(softc)
+ ipf_main_softc_t *softc;
+{
+
+ if (softc->ipf_state_soft != NULL) {
+ ipf_state_soft_destroy(softc, softc->ipf_state_soft);
+ softc->ipf_state_soft = NULL;
+ }
+
+ if (softc->ipf_nat_soft != NULL) {
+ ipf_nat_soft_destroy(softc, softc->ipf_nat_soft);
+ softc->ipf_nat_soft = NULL;
+ }
+
+ if (softc->ipf_frag_soft != NULL) {
+ ipf_frag_soft_destroy(softc, softc->ipf_frag_soft);
+ softc->ipf_frag_soft = NULL;
+ }
+
+ if (softc->ipf_auth_soft != NULL) {
+ ipf_auth_soft_destroy(softc, softc->ipf_auth_soft);
+ softc->ipf_auth_soft = NULL;
+ }
+
+ if (softc->ipf_proxy_soft != NULL) {
+ ipf_proxy_soft_destroy(softc, softc->ipf_proxy_soft);
+ softc->ipf_proxy_soft = NULL;
+ }
+
+ if (softc->ipf_sync_soft != NULL) {
+ ipf_sync_soft_destroy(softc, softc->ipf_sync_soft);
+ softc->ipf_sync_soft = NULL;
+ }
+
+ if (softc->ipf_lookup_soft != NULL) {
+ ipf_lookup_soft_destroy(softc, softc->ipf_lookup_soft);
+ softc->ipf_lookup_soft = NULL;
+ }
+
+#ifdef IPFILTER_LOG
+ if (softc->ipf_log_soft != NULL) {
+ ipf_log_soft_destroy(softc, softc->ipf_log_soft);
+ softc->ipf_log_soft = NULL;
+ }
+#endif
+
+ ipf_main_soft_destroy(softc);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_init_all */
+/* Returns: 0 = success, -1 = failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Work through all of the subsystems inside IPFilter and call the init */
+/* function for each in an order that won't lead to a crash :) */
+/* ------------------------------------------------------------------------ */
+int
+ipf_init_all(softc)
+ ipf_main_softc_t *softc;
+{
+
+ if (ipf_main_soft_init(softc) == -1)
+ return -1;
+
+#ifdef IPFILTER_LOG
+ if (ipf_log_soft_init(softc, softc->ipf_log_soft) == -1)
+ return -1;
+#endif
+
+ if (ipf_lookup_soft_init(softc, softc->ipf_lookup_soft) == -1)
+ return -1;
+
+ if (ipf_sync_soft_init(softc, softc->ipf_sync_soft) == -1)
+ return -1;
+
+ if (ipf_state_soft_init(softc, softc->ipf_state_soft) == -1)
+ return -1;
+
+ if (ipf_nat_soft_init(softc, softc->ipf_nat_soft) == -1)
+ return -1;
+
+ if (ipf_frag_soft_init(softc, softc->ipf_frag_soft) == -1)
+ return -1;
+
+ if (ipf_auth_soft_init(softc, softc->ipf_auth_soft) == -1)
+ return -1;
+
+ if (ipf_proxy_soft_init(softc, softc->ipf_proxy_soft) == -1)
+ return -1;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_fini_all */
+/* Returns: 0 = success, -1 = failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* Work through all of the subsystems inside IPFilter and call the fini */
+/* function for each in an order that won't lead to a crash :) */
+/* ------------------------------------------------------------------------ */
+int
+ipf_fini_all(softc)
+ ipf_main_softc_t *softc;
+{
+
+ ipf_token_flush(softc);
+
+ if (ipf_proxy_soft_fini(softc, softc->ipf_proxy_soft) == -1)
+ return -1;
+
+ if (ipf_auth_soft_fini(softc, softc->ipf_auth_soft) == -1)
+ return -1;
+
+ if (ipf_frag_soft_fini(softc, softc->ipf_frag_soft) == -1)
+ return -1;
+
+ if (ipf_nat_soft_fini(softc, softc->ipf_nat_soft) == -1)
+ return -1;
+
+ if (ipf_state_soft_fini(softc, softc->ipf_state_soft) == -1)
+ return -1;
+
+ if (ipf_sync_soft_fini(softc, softc->ipf_sync_soft) == -1)
+ return -1;
+
+ if (ipf_lookup_soft_fini(softc, softc->ipf_lookup_soft) == -1)
+ return -1;
+
+#ifdef IPFILTER_LOG
+ if (ipf_log_soft_fini(softc, softc->ipf_log_soft) == -1)
+ return -1;
+#endif
+
+ if (ipf_main_soft_fini(softc) == -1)
+ return -1;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rule_expire */
+/* Returns: Nil */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* */
+/* At present this function exists just to support temporary addition of */
+/* firewall rules. Both inactive and active lists are scanned for items to */
+/* purge, as by rights, the expiration is computed as soon as the rule is */
+/* loaded in. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rule_expire(softc)
+ ipf_main_softc_t *softc;
+{
+ frentry_t *fr;
+
+ if ((softc->ipf_rule_explist[0] == NULL) &&
+ (softc->ipf_rule_explist[1] == NULL))
+ return;
+
+ WRITE_ENTER(&softc->ipf_mutex);
+
+ while ((fr = softc->ipf_rule_explist[0]) != NULL) {
+ /*
+ * Because the list is kept sorted on insertion, the fist
+ * one that dies in the future means no more work to do.
+ */
+ if (fr->fr_die > softc->ipf_ticks)
+ break;
+ ipf_rule_delete(softc, fr, IPL_LOGIPF, 0);
+ }
+
+ while ((fr = softc->ipf_rule_explist[1]) != NULL) {
+ /*
+ * Because the list is kept sorted on insertion, the fist
+ * one that dies in the future means no more work to do.
+ */
+ if (fr->fr_die > softc->ipf_ticks)
+ break;
+ ipf_rule_delete(softc, fr, IPL_LOGIPF, 1);
+ }
+
+ RWLOCK_EXIT(&softc->ipf_mutex);
+}
+
+
+static int ipf_ht_node_cmp __P((struct host_node_s *, struct host_node_s *));
+static void ipf_ht_node_make_key __P((host_track_t *, host_node_t *, int,
+ i6addr_t *));
+
+host_node_t RBI_ZERO(ipf_rb);
+RBI_CODE(ipf_rb, host_node_t, hn_entry, ipf_ht_node_cmp)
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_ht_node_cmp */
+/* Returns: int - 0 == nodes are the same, .. */
+/* Parameters: k1(I) - pointer to first key to compare */
+/* k2(I) - pointer to second key to compare */
+/* */
+/* The "key" for the node is a combination of two fields: the address */
+/* family and the address itself. */
+/* */
+/* Because we're not actually interpreting the address data, it isn't */
+/* necessary to convert them to/from network/host byte order. The mask is */
+/* just used to remove bits that aren't significant - it doesn't matter */
+/* where they are, as long as they're always in the same place. */
+/* */
+/* As with IP6_EQ, comparing IPv6 addresses starts at the bottom because */
+/* this is where individual ones will differ the most - but not true for */
+/* for /48's, etc. */
+/* ------------------------------------------------------------------------ */
+static int
+ipf_ht_node_cmp(k1, k2)
+ struct host_node_s *k1, *k2;
+{
+ int i;
+
+ i = (k2->hn_addr.adf_family - k1->hn_addr.adf_family);
+ if (i != 0)
+ return i;
+
+ if (k1->hn_addr.adf_family == AF_INET)
+ return (k2->hn_addr.adf_addr.in4.s_addr -
+ k1->hn_addr.adf_addr.in4.s_addr);
+
+ i = k2->hn_addr.adf_addr.i6[3] - k1->hn_addr.adf_addr.i6[3];
+ if (i != 0)
+ return i;
+ i = k2->hn_addr.adf_addr.i6[2] - k1->hn_addr.adf_addr.i6[2];
+ if (i != 0)
+ return i;
+ i = k2->hn_addr.adf_addr.i6[1] - k1->hn_addr.adf_addr.i6[1];
+ if (i != 0)
+ return i;
+ i = k2->hn_addr.adf_addr.i6[0] - k1->hn_addr.adf_addr.i6[0];
+ return i;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_ht_node_make_key */
+/* Returns: Nil */
+/* parameters: htp(I) - pointer to address tracking structure */
+/* key(I) - where to store masked address for lookup */
+/* family(I) - protocol family of address */
+/* addr(I) - pointer to network address */
+/* */
+/* Using the "netmask" (number of bits) stored parent host tracking struct, */
+/* copy the address passed in into the key structure whilst masking out the */
+/* bits that we don't want. */
+/* */
+/* Because the parser will set ht_netmask to 128 if there is no protocol */
+/* specified (the parser doesn't know if it should be a v4 or v6 rule), we */
+/* have to be wary of that and not allow 32-128 to happen. */
+/* ------------------------------------------------------------------------ */
+static void
+ipf_ht_node_make_key(htp, key, family, addr)
+ host_track_t *htp;
+ host_node_t *key;
+ int family;
+ i6addr_t *addr;
+{
+ key->hn_addr.adf_family = family;
+ if (family == AF_INET) {
+ u_32_t mask;
+ int bits;
+
+ key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in4);
+ bits = htp->ht_netmask;
+ if (bits >= 32) {
+ mask = 0xffffffff;
+ } else {
+ mask = htonl(0xffffffff << (32 - bits));
+ }
+ key->hn_addr.adf_addr.in4.s_addr = addr->in4.s_addr & mask;
+#ifdef USE_INET6
+ } else {
+ int bits = htp->ht_netmask;
+
+ key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in6);
+ if (bits > 96) {
+ key->hn_addr.adf_addr.i6[3] = addr->i6[3] &
+ htonl(0xffffffff << (128 - bits));
+ key->hn_addr.adf_addr.i6[2] = addr->i6[2];
+ key->hn_addr.adf_addr.i6[1] = addr->i6[2];
+ key->hn_addr.adf_addr.i6[0] = addr->i6[2];
+ } else if (bits > 64) {
+ key->hn_addr.adf_addr.i6[3] = 0;
+ key->hn_addr.adf_addr.i6[2] = addr->i6[2] &
+ htonl(0xffffffff << (96 - bits));
+ key->hn_addr.adf_addr.i6[1] = addr->i6[1];
+ key->hn_addr.adf_addr.i6[0] = addr->i6[0];
+ } else if (bits > 32) {
+ key->hn_addr.adf_addr.i6[3] = 0;
+ key->hn_addr.adf_addr.i6[2] = 0;
+ key->hn_addr.adf_addr.i6[1] = addr->i6[1] &
+ htonl(0xffffffff << (64 - bits));
+ key->hn_addr.adf_addr.i6[0] = addr->i6[0];
+ } else {
+ key->hn_addr.adf_addr.i6[3] = 0;
+ key->hn_addr.adf_addr.i6[2] = 0;
+ key->hn_addr.adf_addr.i6[1] = 0;
+ key->hn_addr.adf_addr.i6[0] = addr->i6[0] &
+ htonl(0xffffffff << (32 - bits));
+ }
+ }
+#endif
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_ht_node_add */
+/* Returns: int - 0 == success, -1 == failure */
+/* Parameters: softc(I) - pointer to soft context main structure */
+/* htp(I) - pointer to address tracking structure */
+/* family(I) - protocol family of address */
+/* addr(I) - pointer to network address */
+/* */
+/* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */
+/* ipf_ht_node_del FROM RUNNING CONCURRENTLY ON THE SAME htp. */
+/* */
+/* After preparing the key with the address information to find, look in */
+/* the red-black tree to see if the address is known. A successful call to */
+/* this function can mean one of two things: a new node was added to the */
+/* tree or a matching node exists and we're able to bump up its activity. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_ht_node_add(softc, htp, family, addr)
+ ipf_main_softc_t *softc;
+ host_track_t *htp;
+ int family;
+ i6addr_t *addr;
+{
+ host_node_t *h;
+ host_node_t k;
+
+ ipf_ht_node_make_key(htp, &k, family, addr);
+
+ h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k);
+ if (h == NULL) {
+ if (htp->ht_cur_nodes >= htp->ht_max_nodes)
+ return -1;
+ KMALLOC(h, host_node_t *);
+ if (h == NULL) {
+ DT(ipf_rb_no_mem);
+ LBUMP(ipf_rb_no_mem);
+ return -1;
+ }
+
+ /*
+ * If there was a macro to initialise the RB node then that
+ * would get used here, but there isn't...
+ */
+ bzero((char *)h, sizeof(*h));
+ h->hn_addr = k.hn_addr;
+ h->hn_addr.adf_family = k.hn_addr.adf_family;
+ RBI_INSERT(ipf_rb, &htp->ht_root, h);
+ htp->ht_cur_nodes++;
+ } else {
+ if ((htp->ht_max_per_node != 0) &&
+ (h->hn_active >= htp->ht_max_per_node)) {
+ DT(ipf_rb_node_max);
+ LBUMP(ipf_rb_node_max);
+ return -1;
+ }
+ }
+
+ h->hn_active++;
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_ht_node_del */
+/* Returns: int - 0 == success, -1 == failure */
+/* parameters: htp(I) - pointer to address tracking structure */
+/* family(I) - protocol family of address */
+/* addr(I) - pointer to network address */
+/* */
+/* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */
+/* ipf_ht_node_add FROM RUNNING CONCURRENTLY ON THE SAME htp. */
+/* */
+/* Try and find the address passed in amongst the leavese on this tree to */
+/* be friend. If found then drop the active account for that node drops by */
+/* one. If that count reaches 0, it is time to free it all up. */
+/* ------------------------------------------------------------------------ */
+int
+ipf_ht_node_del(htp, family, addr)
+ host_track_t *htp;
+ int family;
+ i6addr_t *addr;
+{
+ host_node_t *h;
+ host_node_t k;
+
+ ipf_ht_node_make_key(htp, &k, family, addr);
+
+ h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k);
+ if (h == NULL) {
+ return -1;
+ } else {
+ h->hn_active--;
+ if (h->hn_active == 0) {
+ (void) RBI_DELETE(ipf_rb, &htp->ht_root, h);
+ htp->ht_cur_nodes--;
+ KFREE(h);
+ }
+ }
+
+ return 0;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rb_ht_init */
+/* Returns: Nil */
+/* Parameters: head(I) - pointer to host tracking structure */
+/* */
+/* Initialise the host tracking structure to be ready for use above. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rb_ht_init(head)
+ host_track_t *head;
+{
+ RBI_INIT(ipf_rb, &head->ht_root);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rb_ht_freenode */
+/* Returns: Nil */
+/* Parameters: head(I) - pointer to host tracking structure */
+/* arg(I) - additional argument from walk caller */
+/* */
+/* Free an actual host_node_t structure. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rb_ht_freenode(node, arg)
+ host_node_t *node;
+ void *arg;
+{
+ KFREE(node);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_rb_ht_flush */
+/* Returns: Nil */
+/* Parameters: head(I) - pointer to host tracking structure */
+/* */
+/* Remove all of the nodes in the tree tracking hosts by calling a walker */
+/* and free'ing each one. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_rb_ht_flush(head)
+ host_track_t *head;
+{
+ RBI_WALK(ipf_rb, &head->ht_root, ipf_rb_ht_freenode, NULL);
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_slowtimer */
+/* Returns: Nil */
+/* Parameters: ptr(I) - pointer to main ipf soft context structure */
+/* */
+/* Slowly expire held state for fragments. Timeouts are set * in */
+/* expectation of this being called twice per second. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_slowtimer(softc)
+ ipf_main_softc_t *softc;
+{
+
+ ipf_token_expire(softc);
+ ipf_frag_expire(softc);
+ ipf_state_expire(softc);
+ ipf_nat_expire(softc);
+ ipf_auth_expire(softc);
+ ipf_lookup_expire(softc);
+ ipf_rule_expire(softc);
+ ipf_sync_expire(softc);
+ softc->ipf_ticks++;
+# if defined(__OpenBSD__)
+ timeout_add(&ipf_slowtimer_ch, hz/2);
+# endif
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_inet_mask_add */
+/* Returns: Nil */
+/* Parameters: bits(I) - pointer to nat context information */
+/* mtab(I) - pointer to mask hash table structure */
+/* */
+/* When called, bits represents the mask of a new NAT rule that has just */
+/* been added. This function inserts a bitmask into the array of masks to */
+/* search when searching for a matching NAT rule for a packet. */
+/* Prevention of duplicate masks is achieved by checking the use count for */
+/* a given netmask. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_inet_mask_add(bits, mtab)
+ int bits;
+ ipf_v4_masktab_t *mtab;
+{
+ u_32_t mask;
+ int i, j;
+
+ mtab->imt4_masks[bits]++;
+ if (mtab->imt4_masks[bits] > 1)
+ return;
+
+ if (bits == 0)
+ mask = 0;
+ else
+ mask = 0xffffffff << (32 - bits);
+
+ for (i = 0; i < 33; i++) {
+ if (ntohl(mtab->imt4_active[i]) < mask) {
+ for (j = 32; j > i; j--)
+ mtab->imt4_active[j] = mtab->imt4_active[j - 1];
+ mtab->imt4_active[i] = htonl(mask);
+ break;
+ }
+ }
+ mtab->imt4_max++;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_inet_mask_del */
+/* Returns: Nil */
+/* Parameters: bits(I) - number of bits set in the netmask */
+/* mtab(I) - pointer to mask hash table structure */
+/* */
+/* Remove the 32bit bitmask represented by "bits" from the collection of */
+/* netmasks stored inside of mtab. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_inet_mask_del(bits, mtab)
+ int bits;
+ ipf_v4_masktab_t *mtab;
+{
+ u_32_t mask;
+ int i, j;
+
+ mtab->imt4_masks[bits]--;
+ if (mtab->imt4_masks[bits] > 0)
+ return;
+
+ mask = htonl(0xffffffff << (32 - bits));
+ for (i = 0; i < 33; i++) {
+ if (mtab->imt4_active[i] == mask) {
+ for (j = i + 1; j < 33; j++)
+ mtab->imt4_active[j - 1] = mtab->imt4_active[j];
+ break;
+ }
+ }
+ mtab->imt4_max--;
+ ASSERT(mtab->imt4_max >= 0);
+}
+
+
+#ifdef USE_INET6
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_inet6_mask_add */
+/* Returns: Nil */
+/* Parameters: bits(I) - number of bits set in mask */
+/* mask(I) - pointer to mask to add */
+/* mtab(I) - pointer to mask hash table structure */
+/* */
+/* When called, bitcount represents the mask of a IPv6 NAT map rule that */
+/* has just been added. This function inserts a bitmask into the array of */
+/* masks to search when searching for a matching NAT rule for a packet. */
+/* Prevention of duplicate masks is achieved by checking the use count for */
+/* a given netmask. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_inet6_mask_add(bits, mask, mtab)
+ int bits;
+ i6addr_t *mask;
+ ipf_v6_masktab_t *mtab;
+{
+ i6addr_t zero;
+ int i, j;
+
+ mtab->imt6_masks[bits]++;
+ if (mtab->imt6_masks[bits] > 1)
+ return;
+
+ if (bits == 0) {
+ mask = &zero;
+ zero.i6[0] = 0;
+ zero.i6[1] = 0;
+ zero.i6[2] = 0;
+ zero.i6[3] = 0;
+ }
+
+ for (i = 0; i < 129; i++) {
+ if (IP6_LT(&mtab->imt6_active[i], mask)) {
+ for (j = 128; j > i; j--)
+ mtab->imt6_active[j] = mtab->imt6_active[j - 1];
+ mtab->imt6_active[i] = *mask;
+ break;
+ }
+ }
+ mtab->imt6_max++;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* Function: ipf_inet6_mask_del */
+/* Returns: Nil */
+/* Parameters: bits(I) - number of bits set in mask */
+/* mask(I) - pointer to mask to remove */
+/* mtab(I) - pointer to mask hash table structure */
+/* */
+/* Remove the 128bit bitmask represented by "bits" from the collection of */
+/* netmasks stored inside of mtab. */
+/* ------------------------------------------------------------------------ */
+void
+ipf_inet6_mask_del(bits, mask, mtab)
+ int bits;
+ i6addr_t *mask;
+ ipf_v6_masktab_t *mtab;
+{
+ i6addr_t zero;
+ int i, j;
+
+ mtab->imt6_masks[bits]--;
+ if (mtab->imt6_masks[bits] > 0)
+ return;
+
+ if (bits == 0)
+ mask = &zero;
+ zero.i6[0] = 0;
+ zero.i6[1] = 0;
+ zero.i6[2] = 0;
+ zero.i6[3] = 0;
+
+ for (i = 0; i < 129; i++) {
+ if (IP6_EQ(&mtab->imt6_active[i], mask)) {
+ for (j = i + 1; j < 129; j++) {
+ mtab->imt6_active[j - 1] = mtab->imt6_active[j];
+ if (IP6_EQ(&mtab->imt6_active[j - 1], &zero))
+ break;
+ }
+ break;
+ }
+ }
+ mtab->imt6_max--;
+ ASSERT(mtab->imt6_max >= 0);
+}
+#endif
OpenPOWER on IntegriCloud