diff options
Diffstat (limited to 'usr/src')
| -rw-r--r-- | usr/src/cmd/ipf/tools/ipfstat.c | 8 | ||||
| -rw-r--r-- | usr/src/cmd/ipf/tools/ipnat.c | 6 | ||||
| -rw-r--r-- | usr/src/uts/common/inet/ipf/fil.c | 14 | ||||
| -rw-r--r-- | usr/src/uts/common/inet/ipf/ip_nat.c | 91 | ||||
| -rw-r--r-- | usr/src/uts/common/inet/ipf/ip_state.c | 41 | ||||
| -rw-r--r-- | usr/src/uts/common/inet/ipf/netinet/ip_fil.h | 3 | ||||
| -rw-r--r-- | usr/src/uts/common/inet/ipf/netinet/ip_nat.h | 4 | ||||
| -rw-r--r-- | usr/src/uts/common/inet/ipf/netinet/ip_state.h | 3 |
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 { |
