summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/ipf/tools/ipfstat.c8
-rw-r--r--usr/src/cmd/ipf/tools/ipnat.c6
-rw-r--r--usr/src/uts/common/inet/ipf/fil.c14
-rw-r--r--usr/src/uts/common/inet/ipf/ip_nat.c91
-rw-r--r--usr/src/uts/common/inet/ipf/ip_state.c41
-rw-r--r--usr/src/uts/common/inet/ipf/netinet/ip_fil.h3
-rw-r--r--usr/src/uts/common/inet/ipf/netinet/ip_nat.h4
-rw-r--r--usr/src/uts/common/inet/ipf/netinet/ip_state.h3
8 files changed, 122 insertions, 48 deletions
diff --git a/usr/src/cmd/ipf/tools/ipfstat.c b/usr/src/cmd/ipf/tools/ipfstat.c
index 4945ffe8be..46707d6a34 100644
--- a/usr/src/cmd/ipf/tools/ipfstat.c
+++ b/usr/src/cmd/ipf/tools/ipfstat.c
@@ -7,8 +7,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __FreeBSD__
# ifndef __FreeBSD_cc_version
# include <osreldate.h>
@@ -1063,8 +1061,10 @@ ips_stat_t *ipsp;
ipsp->iss_max, ipsp->iss_nomem, ipsp->iss_bucketfull);
PRINTF("\t%lu maximum\n\t%lu no memory\n\t%lu bkts in use\n",
ipsp->iss_max, ipsp->iss_nomem, ipsp->iss_inuse);
- PRINTF("\t%lu active\n\t%lu expired\n\t%lu closed\n",
- ipsp->iss_active, ipsp->iss_expire, ipsp->iss_fin);
+ PRINTF("\t%lu active\n\t%lu expired\n",
+ ipsp->iss_active, ipsp->iss_expire);
+ PRINTF("\t%lu closed\n\t%u orphans\n",
+ ipsp->iss_fin, ipsp->iss_orphans);
PRINTF("State logging %sabled\n",
state_logging ? "en" : "dis");
diff --git a/usr/src/cmd/ipf/tools/ipnat.c b/usr/src/cmd/ipf/tools/ipnat.c
index 57a0bab951..83b2a416c3 100644
--- a/usr/src/cmd/ipf/tools/ipnat.c
+++ b/usr/src/cmd/ipf/tools/ipnat.c
@@ -9,8 +9,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
@@ -304,8 +302,8 @@ int fd, opts, alive;
nsp->ns_added, nsp->ns_expire);
printf("no memory\t%lu\tbad nat\t%lu\n",
nsp->ns_memfail, nsp->ns_badnat);
- printf("inuse\t%lu\nrules\t%lu\n",
- nsp->ns_inuse, nsp->ns_rules);
+ printf("inuse\t%lu\norphans\t%u\nrules\t%lu\n",
+ nsp->ns_inuse, nsp->ns_orphans, nsp->ns_rules);
printf("wilds\t%u\n", nsp->ns_wilds);
if (opts & OPT_VERBOSE)
printf("table %p list %p\n",
diff --git a/usr/src/uts/common/inet/ipf/fil.c b/usr/src/uts/common/inet/ipf/fil.c
index 7cdedaaa4b..ef1fcb8661 100644
--- a/usr/src/uts/common/inet/ipf/fil.c
+++ b/usr/src/uts/common/inet/ipf/fil.c
@@ -7,8 +7,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#if defined(KERNEL) || defined(_KERNEL)
# undef KERNEL
# undef _KERNEL
@@ -2550,8 +2548,16 @@ ipf_stack_t *ifs;
if (fin->fin_state != NULL)
fr_statederef((ipstate_t **)&fin->fin_state, ifs);
- if (fin->fin_nat != NULL)
- fr_natderef((nat_t **)&fin->fin_nat, ifs);
+ if (fin->fin_nat != NULL) {
+ if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT)) {
+ WRITE_ENTER(&ifs->ifs_ipf_nat);
+ nat_delete((nat_t *)fin->fin_nat, NL_DESTROY, ifs);
+ RWLOCK_EXIT(&ifs->ifs_ipf_nat);
+ fin->fin_nat = NULL;
+ } else {
+ fr_natderef((nat_t **)&fin->fin_nat, ifs);
+ }
+ }
/*
* Only allow FR_DUP to work if a rule matched - it makes no sense to
diff --git a/usr/src/uts/common/inet/ipf/ip_nat.c b/usr/src/uts/common/inet/ipf/ip_nat.c
index c77b883f31..dcdd2ab0a4 100644
--- a/usr/src/uts/common/inet/ipf/ip_nat.c
+++ b/usr/src/uts/common/inet/ipf/ip_nat.c
@@ -142,7 +142,6 @@ static int nat_flushtable __P((ipf_stack_t *));
static int nat_clearlist __P((ipf_stack_t *));
static void nat_addnat __P((struct ipnat *, ipf_stack_t *));
static void nat_addrdr __P((struct ipnat *, ipf_stack_t *));
-static void nat_delete __P((struct nat *, int, ipf_stack_t *));
static int fr_natgetent __P((caddr_t, ipf_stack_t *));
static int fr_natgetsz __P((caddr_t, ipf_stack_t *));
static int fr_natputent __P((caddr_t, int, ipf_stack_t *));
@@ -1570,6 +1569,15 @@ ipf_stack_t *ifs;
ifs->ifs_nat_doflush = 1;
/*
+ * If automatic flushing did not do its job, and the table
+ * has filled up, don't try to create a new entry.
+ */
+ if (ifs->ifs_nat_stats.ns_inuse >= ifs->ifs_ipf_nattable_max) {
+ ifs->ifs_nat_stats.ns_memfail++;
+ return ENOMEM;
+ }
+
+ /*
* Initialise early because of code at junkput label.
*/
in = NULL;
@@ -1870,36 +1878,36 @@ junkput:
/* Returns: Nil */
/* Parameters: natd(I) - pointer to NAT structure to delete */
/* logtype(I) - type of LOG record to create before deleting */
+/* ifs - ipf stack instance */
/* Write Lock: ipf_nat */
/* */
/* Delete a nat entry from the various lists and table. If NAT logging is */
/* enabled then generate a NAT log record for this event. */
/* ------------------------------------------------------------------------ */
-static void nat_delete(nat, logtype, ifs)
+void nat_delete(nat, logtype, ifs)
struct nat *nat;
int logtype;
ipf_stack_t *ifs;
{
struct ipnat *ipn;
+ int removed = 0;
if (logtype != 0 && ifs->ifs_nat_logging != 0)
nat_log(nat, logtype, ifs);
/*
- * Take it as a general indication that all the pointers are set if
- * nat_pnext is set.
+ * Start by removing the entry from the hash table of nat entries
+ * so it will not be "used" again.
+ *
+ * It will remain in the "list" of nat entries until all references
+ * have been accounted for.
*/
- if (nat->nat_pnext != NULL) {
+ if ((nat->nat_phnext[0] != NULL) && (nat->nat_phnext[1] != NULL)) {
+ removed = 1;
+
ifs->ifs_nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--;
ifs->ifs_nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--;
- *nat->nat_pnext = nat->nat_next;
- if (nat->nat_next != NULL) {
- nat->nat_next->nat_pnext = nat->nat_pnext;
- nat->nat_next = NULL;
- }
- nat->nat_pnext = NULL;
-
*nat->nat_phnext[0] = nat->nat_hnext[0];
if (nat->nat_hnext[0] != NULL) {
nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
@@ -1918,31 +1926,67 @@ ipf_stack_t *ifs;
ifs->ifs_nat_stats.ns_wilds--;
}
+ /*
+ * Next, remove it from the timeout queue it is in.
+ */
+ fr_deletequeueentry(&nat->nat_tqe);
+
if (nat->nat_me != NULL) {
*nat->nat_me = NULL;
nat->nat_me = NULL;
}
- fr_deletequeueentry(&nat->nat_tqe);
-
MUTEX_ENTER(&nat->nat_lock);
- if (nat->nat_ref > 1) {
+ if (logtype == NL_DESTROY) {
+ /*
+ * NL_DESTROY should only be passed when nat_ref >= 2.
+ * This happens when a nat'd packet is blocked, we have
+ * just created the nat table entry (reason why the ref
+ * count is 2 or higher), but and we want to throw away
+ * that NAT session as result of the blocked packet.
+ */
+ if (nat->nat_ref > 2) {
+ nat->nat_ref -= 2;
+ MUTEX_EXIT(&nat->nat_lock);
+ if (removed)
+ ifs->ifs_nat_stats.ns_orphans++;
+ return;
+ }
+ } else if (nat->nat_ref > 1) {
nat->nat_ref--;
MUTEX_EXIT(&nat->nat_lock);
+ if (removed)
+ ifs->ifs_nat_stats.ns_orphans++;
return;
}
MUTEX_EXIT(&nat->nat_lock);
+ nat->nat_ref = 0;
+
/*
- * At this point, nat_ref is 1, doing "--" would make it 0..
+ * If entry had already been removed,
+ * it means we're cleaning up an orphan.
*/
- nat->nat_ref = 0;
+ if (!removed)
+ ifs->ifs_nat_stats.ns_orphans--;
#ifdef IPFILTER_SYNC
if (nat->nat_sync)
ipfsync_del(nat->nat_sync);
#endif
+ /*
+ * Now remove it from master list of nat table entries
+ */
+ if (nat->nat_pnext != NULL) {
+ *nat->nat_pnext = nat->nat_next;
+ if (nat->nat_next != NULL) {
+ nat->nat_next->nat_pnext = nat->nat_pnext;
+ nat->nat_next = NULL;
+ }
+ nat->nat_pnext = NULL;
+ }
+
if (nat->nat_fr != NULL)
(void)fr_derefrule(&nat->nat_fr, ifs);
@@ -2528,6 +2572,10 @@ int direction;
if (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_lvl_hi)
ifs->ifs_nat_doflush = 1;
+ /*
+ * If automatic flushing did not do its job, and the table
+ * has filled up, don't try to create a new entry.
+ */
if (ifs->ifs_nat_stats.ns_inuse >= ifs->ifs_ipf_nattable_max) {
ifs->ifs_nat_stats.ns_memfail++;
return NULL;
@@ -2648,6 +2696,7 @@ int direction;
if (flags & SI_WILDP)
ifs->ifs_nat_stats.ns_wilds++;
+ fin->fin_flx |= FI_NEWNAT;
goto done;
badnat:
ifs->ifs_nat_stats.ns_badnat++;
@@ -3866,7 +3915,9 @@ u_32_t *passp;
nat_t *nat;
ipf_stack_t *ifs = fin->fin_ifs;
- if (ifs->ifs_nat_stats.ns_rules == 0 || ifs->ifs_fr_nat_lock != 0)
+ if (ifs->ifs_fr_nat_lock != 0)
+ return 0;
+ if (ifs->ifs_nat_stats.ns_rules == 0 && ifs->ifs_nat_instances == NULL)
return 0;
natfailed = 0;
@@ -4183,7 +4234,9 @@ u_32_t *passp;
u_32_t iph;
ipf_stack_t *ifs = fin->fin_ifs;
- if (ifs->ifs_nat_stats.ns_rules == 0 || ifs->ifs_fr_nat_lock != 0)
+ if (ifs->ifs_fr_nat_lock != 0)
+ return 0;
+ if (ifs->ifs_nat_stats.ns_rules == 0 && ifs->ifs_nat_instances == NULL)
return 0;
tcp = NULL;
diff --git a/usr/src/uts/common/inet/ipf/ip_state.c b/usr/src/uts/common/inet/ipf/ip_state.c
index 61da04693e..39c8eeb97b 100644
--- a/usr/src/uts/common/inet/ipf/ip_state.c
+++ b/usr/src/uts/common/inet/ipf/ip_state.c
@@ -3084,6 +3084,7 @@ ipf_stack_t *ifs;
/* Returns: Nil */
/* Parameters: is(I) - pointer to state structure to delete */
/* why(I) - if not 0, log reason why it was deleted */
+/* ifs - ipf stack instance */
/* Write Locks: ipf_state/ipf_global */
/* */
/* Deletes a state entry from the enumerated list as well as the hash table */
@@ -3095,25 +3096,20 @@ ipstate_t *is;
int why;
ipf_stack_t *ifs;
{
+ int removed = 0;
ASSERT(rw_write_held(&ifs->ifs_ipf_global.ipf_lk) == 0 ||
rw_write_held(&ifs->ifs_ipf_state.ipf_lk) == 0);
/*
- * Since we want to delete this, remove it from the state table,
- * where it can be found & used, first.
+ * Start by removing the entry from the hash table of state entries
+ * so it will not be "used" again.
+ *
+ * It will remain in the "list" of state entries until all references
+ * have been accounted for.
*/
- if (is->is_pnext != NULL) {
- *is->is_pnext = is->is_next;
-
- if (is->is_next != NULL)
- is->is_next->is_pnext = is->is_pnext;
-
- is->is_pnext = NULL;
- is->is_next = NULL;
- }
-
if (is->is_phnext != NULL) {
+ removed = 1;
*is->is_phnext = is->is_hnext;
if (is->is_hnext != NULL)
is->is_hnext->is_phnext = is->is_phnext;
@@ -3152,12 +3148,21 @@ ipf_stack_t *ifs;
if (is->is_ref > 1) {
is->is_ref--;
MUTEX_EXIT(&is->is_lock);
+ if (removed)
+ ifs->ifs_ips_stats.iss_orphans++;
return;
}
MUTEX_EXIT(&is->is_lock);
is->is_ref = 0;
+ /*
+ * If entry has already been removed from table,
+ * it means we're simply cleaning up an orphan.
+ */
+ if (!removed)
+ ifs->ifs_ips_stats.iss_orphans--;
+
if (is->is_tqehead[0] != NULL)
(void) fr_deletetimeoutqueue(is->is_tqehead[0]);
@@ -3172,6 +3177,18 @@ ipf_stack_t *ifs;
(void) ipsc_detachis(is);
#endif
+ /*
+ * Now remove it from master list of state table entries.
+ */
+ if (is->is_pnext != NULL) {
+ *is->is_pnext = is->is_next;
+ if (is->is_next != NULL) {
+ is->is_next->is_pnext = is->is_pnext;
+ is->is_next = NULL;
+ }
+ is->is_pnext = NULL;
+ }
+
if (ifs->ifs_ipstate_logging != 0 && why != 0)
ipstate_log(is, why, ifs);
diff --git a/usr/src/uts/common/inet/ipf/netinet/ip_fil.h b/usr/src/uts/common/inet/ipf/netinet/ip_fil.h
index 323944dc30..e51a234362 100644
--- a/usr/src/uts/common/inet/ipf/netinet/ip_fil.h
+++ b/usr/src/uts/common/inet/ipf/netinet/ip_fil.h
@@ -10,8 +10,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifndef __IP_FIL_H__
#define __IP_FIL_H__
@@ -280,6 +278,7 @@ typedef struct fr_ip {
#define FI_V6EXTHDR 0x10000
#define FI_COALESCE 0x20000
#define FI_ICMPQUERY 0x40000
+#define FI_NEWNAT 0x80000
#define FI_NOCKSUM 0x20000000 /* don't do a L4 checksum validation */
#define FI_DONTCACHE 0x40000000 /* don't cache the result */
#define FI_IGNORE 0x80000000
diff --git a/usr/src/uts/common/inet/ipf/netinet/ip_nat.h b/usr/src/uts/common/inet/ipf/netinet/ip_nat.h
index c78ae22223..df5312a45f 100644
--- a/usr/src/uts/common/inet/ipf/netinet/ip_nat.h
+++ b/usr/src/uts/common/inet/ipf/netinet/ip_nat.h
@@ -9,7 +9,6 @@
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
#ifndef __IP_NAT_H__
#define __IP_NAT_H__
@@ -409,6 +408,7 @@ typedef struct natstat {
nattrpnt_t *ns_trpntlist;
hostmap_t *ns_maplist;
u_long *ns_bucketlen[2];
+ u_int ns_orphans;
} natstat_t;
typedef struct natlog {
@@ -431,6 +431,7 @@ typedef struct natlog {
#define NL_NEWRDR NAT_REDIRECT
#define NL_NEWBIMAP NAT_BIMAP
#define NL_NEWBLOCK NAT_MAPBLK
+#define NL_DESTROY 0xfffc
#define NL_CLONE 0xfffd
#define NL_FLUSH 0xfffe
#define NL_EXPIRE 0xffff
@@ -487,6 +488,7 @@ extern nat_t *nat_maplookup __P((void *, u_int, struct in_addr,
extern nat_t *nat_lookupredir __P((natlookup_t *, ipf_stack_t *));
extern nat_t *nat_icmperrorlookup __P((fr_info_t *, int));
extern nat_t *nat_icmperror __P((fr_info_t *, u_int *, int));
+extern void nat_delete __P((struct nat *, int, ipf_stack_t *));
extern int nat_insert __P((nat_t *, int, ipf_stack_t *));
extern int fr_checknatout __P((fr_info_t *, u_32_t *));
diff --git a/usr/src/uts/common/inet/ipf/netinet/ip_state.h b/usr/src/uts/common/inet/ipf/netinet/ip_state.h
index 8f6568d0c2..6f76ca38e1 100644
--- a/usr/src/uts/common/inet/ipf/netinet/ip_state.h
+++ b/usr/src/uts/common/inet/ipf/netinet/ip_state.h
@@ -10,8 +10,6 @@
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifndef __IP_STATE_H__
#define __IP_STATE_H__
@@ -221,6 +219,7 @@ typedef struct ips_stat {
ipstate_t **iss_table;
ipstate_t *iss_list;
u_long *iss_bucketlen;
+ u_int iss_orphans;
} ips_stat_t;
typedef struct port_pair {