patch-2.2.11 linux/net/ipv4/ip_masq.c
Next file: linux/net/ipv4/ip_masq_irc.c
Previous file: linux/net/ipv4/ip_fw.c
Back to the patch index
Back to the overall index
- Lines: 357
- Date:
Mon Aug 9 12:05:10 1999
- Orig file:
v2.2.10/linux/net/ipv4/ip_masq.c
- Orig date:
Tue Mar 16 21:52:05 1999
diff -u --recursive --new-file v2.2.10/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c
@@ -4,7 +4,7 @@
*
* Copyright (c) 1994 Pauline Middelink
*
- * $Id: ip_masq.c,v 1.34 1999/03/17 01:53:51 davem Exp $
+ * $Id: ip_masq.c,v 1.34.2.2 1999/08/07 10:56:28 davem Exp $
*
*
* See ip_fw.c for original log
@@ -46,6 +46,7 @@
* Juan Jose Ciarlante : make masq_proto_doff() robust against fake sized/corrupted packets
* Kai Bankett : do not toss other IP protos in proto_doff()
* Dan Kegel : pointed correct NAT behavior for UDP streams
+ * Julian Anastasov : use daddr and dport as hash keys
*
*/
@@ -315,9 +316,7 @@
* Will cycle in MASQ_PORT boundaries.
*/
static __u16 masq_port = PORT_MASQ_BEGIN;
-#ifdef __SMP__
static spinlock_t masq_port_lock = SPIN_LOCK_UNLOCKED;
-#endif
/*
* free ports counters (UDP & TCP)
@@ -366,17 +365,24 @@
EXPORT_SYMBOL(ip_masq_control_del);
EXPORT_SYMBOL(ip_masq_control_get);
EXPORT_SYMBOL(ip_masq_user_hook);
-EXPORT_SYMBOL(ip_masq_m_tab);
EXPORT_SYMBOL(ip_masq_state_name);
EXPORT_SYMBOL(ip_masq_select_addr);
EXPORT_SYMBOL(__ip_masq_lock);
+EXPORT_SYMBOL(ip_masq_m_table);
+EXPORT_SYMBOL(ip_masq_s_table);
+EXPORT_SYMBOL(ip_masq_d_table);
/*
- * 2 ip_masq hash tables: for input and output pkts lookups.
+ * 3 ip_masq hash double linked tables:
+ * 2 for input m{addr,port} and output s{addr,port} pkts lookups.
+ * 1 for extra modules support (daddr)
*/
+
+#define IP_MASQ_NTABLES 3
-struct ip_masq *ip_masq_m_tab[IP_MASQ_TAB_SIZE];
-struct ip_masq *ip_masq_s_tab[IP_MASQ_TAB_SIZE];
+struct list_head ip_masq_m_table[IP_MASQ_TAB_SIZE];
+struct list_head ip_masq_s_table[IP_MASQ_TAB_SIZE];
+struct list_head ip_masq_d_table[IP_MASQ_TAB_SIZE];
/*
* timeouts
@@ -450,21 +456,44 @@
__builtin_return_address(0));
return 0;
}
- /*
- * Hash by proto,m{addr,port}
- */
- hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport);
- ms->m_link = ip_masq_m_tab[hash];
- atomic_inc(&ms->refcnt);
- ip_masq_m_tab[hash] = ms;
+ atomic_add(IP_MASQ_NTABLES, &ms->refcnt);
+
+ if ((ms->flags & (MASQ_DADDR_PASS | MASQ_DPORT_PASS |
+ IP_MASQ_F_SIMPLE_HASH)) == 0)
+ /*
+ * Hash by proto,m{addr,port},d{addr,port}
+ */
+ hash = ip_masq_hash_key(ms->protocol,
+ ms->maddr^ms->daddr, ms->mport^ms->dport);
+ else
+ /*
+ * Hash by proto,m{addr,port}
+ */
+ hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport);
+
+ list_add(&ms->m_list, &ip_masq_m_table[hash]);
+
+ if ((ms->flags & (MASQ_DADDR_PASS | MASQ_DPORT_PASS |
+ IP_MASQ_F_NO_SADDR | IP_MASQ_F_NO_SPORT |
+ IP_MASQ_F_SIMPLE_HASH)) == 0)
+ /*
+ * Hash by proto,s{addr,port},d{addr,port}
+ */
+ hash = ip_masq_hash_key(ms->protocol,
+ ms->saddr^ms->daddr, ms->sport^ms->dport);
+ else
+ /*
+ * Hash by proto,s{addr,port}
+ */
+ hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport);
+
+ list_add(&ms->s_list, &ip_masq_s_table[hash]);
/*
- * Hash by proto,s{addr,port}
+ * Hash by proto,d{addr,port}
*/
- hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport);
- ms->s_link = ip_masq_s_tab[hash];
- atomic_inc(&ms->refcnt);
- ip_masq_s_tab[hash] = ms;
+ hash = ip_masq_hash_key(ms->protocol, ms->daddr, ms->dport);
+ list_add(&ms->d_list, &ip_masq_d_table[hash]);
ms->flags |= IP_MASQ_F_HASHED;
@@ -479,34 +508,16 @@
static int ip_masq_unhash(struct ip_masq *ms)
{
- unsigned hash;
- struct ip_masq ** ms_p;
if (!(ms->flags & IP_MASQ_F_HASHED)) {
IP_MASQ_ERR( "ip_masq_unhash(): request for unhash flagged, called from %p\n",
__builtin_return_address(0));
return 0;
}
- /*
- * UNhash by m{addr,port}
- */
- hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport);
- for (ms_p = &ip_masq_m_tab[hash]; *ms_p ; ms_p = &(*ms_p)->m_link)
- if (ms == (*ms_p)) {
- atomic_dec(&ms->refcnt);
- *ms_p = ms->m_link;
- break;
- }
+ list_del(&ms->m_list);
+ list_del(&ms->s_list);
+ list_del(&ms->d_list);
- /*
- * UNhash by s{addr,port}
- */
- hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport);
- for (ms_p = &ip_masq_s_tab[hash]; *ms_p ; ms_p = &(*ms_p)->s_link)
- if (ms == (*ms_p)) {
- atomic_dec(&ms->refcnt);
- *ms_p = ms->s_link;
- break;
- }
+ atomic_sub(IP_MASQ_NTABLES, &ms->refcnt);
ms->flags &= ~IP_MASQ_F_HASHED;
return 1;
@@ -535,10 +546,34 @@
{
unsigned hash;
struct ip_masq *ms = NULL;
+ struct list_head *l,*e;
+
+ hash = ip_masq_hash_key(protocol, d_addr^s_addr, d_port^s_port);
+
+ l = &ip_masq_m_table[hash];
+ for (e=l->next; e!=l; e=e->next) {
+ ms = list_entry(e, struct ip_masq, m_list);
+ if (s_port==ms->dport && s_addr==ms->daddr &&
+ d_port==ms->mport && protocol==ms->protocol &&
+ d_addr==ms->maddr &&
+ ((ms->flags & (MASQ_DADDR_PASS | MASQ_DPORT_PASS)) == 0)
+ ) {
+ IP_MASQ_DEBUG(2, "look/in %d %08X:%04hX->%08X:%04hX OK\n",
+ protocol,
+ s_addr,
+ s_port,
+ d_addr,
+ d_port);
+ atomic_inc(&ms->refcnt);
+ goto out;
+ }
+ }
hash = ip_masq_hash_key(protocol, d_addr, d_port);
- for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) {
+ l = &ip_masq_m_table[hash];
+ for (e=l->next; e!=l; e=e->next) {
+ ms = list_entry(e, struct ip_masq, m_list);
if (protocol==ms->protocol &&
(d_addr==ms->maddr && d_port==ms->mport) &&
(s_addr==ms->daddr || ms->flags & MASQ_DADDR_PASS) &&
@@ -561,6 +596,7 @@
d_addr,
d_port);
+ ms = NULL;
out:
return ms;
}
@@ -585,13 +621,40 @@
{
unsigned hash;
struct ip_masq *ms = NULL;
+ struct list_head *l,*e;
/*
* Check for "full" addressed entries
*/
+ hash = ip_masq_hash_key(protocol, s_addr^d_addr, s_port^d_port);
+
+ l = &ip_masq_s_table[hash];
+ for (e=l->next; e!=l; e=e->next) {
+ ms = list_entry(e, struct ip_masq, s_list);
+ if (d_addr==ms->daddr && d_port==ms->dport &&
+ s_addr==ms->saddr && s_port==ms->sport &&
+ protocol==ms->protocol &&
+ ((ms->flags & (MASQ_DADDR_PASS | MASQ_DPORT_PASS |
+ IP_MASQ_F_NO_SADDR | IP_MASQ_F_NO_SPORT)) == 0)
+ ) {
+ IP_MASQ_DEBUG(2, "lk/out0 %d %08X:%04hX->%08X:%04hX OK\n",
+ protocol,
+ s_addr,
+ s_port,
+ d_addr,
+ d_port);
+
+ atomic_inc(&ms->refcnt);
+ goto out;
+ }
+
+ }
+
hash = ip_masq_hash_key(protocol, s_addr, s_port);
- for(ms = ip_masq_s_tab[hash]; ms ; ms = ms->s_link) {
+ l = &ip_masq_s_table[hash];
+ for (e=l->next; e!=l; e=e->next) {
+ ms = list_entry(e, struct ip_masq, s_list);
if (protocol == ms->protocol &&
s_addr == ms->saddr && s_port == ms->sport &&
(d_addr==ms->daddr || ms->flags & MASQ_DADDR_PASS) &&
@@ -614,7 +677,9 @@
* Check for NO_SPORT entries
*/
hash = ip_masq_hash_key(protocol, s_addr, 0);
- for(ms = ip_masq_s_tab[hash]; ms ; ms = ms->s_link) {
+ l = &ip_masq_s_table[hash];
+ for (e=l->next; e!=l; e=e->next) {
+ ms = list_entry(e, struct ip_masq, s_list);
if (ms->flags & IP_MASQ_F_NO_SPORT &&
protocol == ms->protocol &&
s_addr == ms->saddr &&
@@ -639,6 +704,7 @@
d_addr,
d_port);
+ ms = NULL;
out:
return ms;
}
@@ -710,9 +776,9 @@
__ip_masq_put(ms);
/*
- * if refcnt==2 (2 hashes)
+ * if refcnt==IP_MASQ_NTABLES
*/
- if (atomic_read(&ms->refcnt)==2) {
+ if (atomic_read(&ms->refcnt)==IP_MASQ_NTABLES) {
__ip_masq_set_expire(ms, ms->timeout);
} else {
IP_MASQ_DEBUG(0, "did not set timer with refcnt=%d, called from %p\n",
@@ -845,6 +911,9 @@
}
MOD_INC_USE_COUNT;
memset(ms, 0, sizeof(*ms));
+ INIT_LIST_HEAD(&ms->s_list);
+ INIT_LIST_HEAD(&ms->m_list);
+ INIT_LIST_HEAD(&ms->d_list);
init_timer(&ms->timer);
ms->timer.data = (unsigned long)ms;
ms->timer.function = masq_expire;
@@ -1157,11 +1226,11 @@
*/
if ( ms->flags & IP_MASQ_F_NO_SPORT && ms->protocol == IPPROTO_TCP ) {
- ms->flags &= ~IP_MASQ_F_NO_SPORT;
write_lock(&__ip_masq_lock);
ip_masq_unhash(ms);
+ ms->flags &= ~IP_MASQ_F_NO_SPORT;
ms->sport = h.portp[0];
ip_masq_hash(ms); /* hash on new sport */
@@ -2011,16 +2080,30 @@
ms->daddr = iph->saddr;
} else {
if ( ms->flags & IP_MASQ_F_NO_DPORT ) { /* && ms->protocol == IPPROTO_TCP ) { */
+
+ write_lock(&__ip_masq_lock);
+
+ ip_masq_unhash(ms);
ms->flags &= ~IP_MASQ_F_NO_DPORT;
ms->dport = h.portp[0];
+ ip_masq_hash(ms); /* hash on new dport */
+
+ write_unlock(&__ip_masq_lock);
IP_MASQ_DEBUG(1, "ip_fw_demasquerade(): filled dport=%d\n",
ntohs(ms->dport));
}
if (ms->flags & IP_MASQ_F_NO_DADDR ) { /* && ms->protocol == IPPROTO_TCP) { */
+
+ write_lock(&__ip_masq_lock);
+
+ ip_masq_unhash(ms);
ms->flags &= ~IP_MASQ_F_NO_DADDR;
ms->daddr = iph->saddr;
+ ip_masq_hash(ms); /* hash on new daddr */
+
+ write_unlock(&__ip_masq_lock);
IP_MASQ_DEBUG(1, "ip_fw_demasquerade(): filled daddr=%lX\n",
ntohl(ms->daddr));
@@ -2162,7 +2245,7 @@
char temp[129];
int idx = 0;
int len=0;
-
+ struct list_head *l,*e;
if (offset < 128)
{
@@ -2183,8 +2266,9 @@
*/
read_lock_bh(&__ip_masq_lock);
- for(ms = ip_masq_m_tab[idx]; ms ; ms = ms->m_link)
- {
+ l = &ip_masq_m_table[idx];
+ for (e=l->next; e!=l; e=e->next) {
+ ms = list_entry(e, struct ip_masq, m_list);
pos += 128;
if (pos <= offset) {
len = 0;
@@ -2400,6 +2484,12 @@
*/
__initfunc(int ip_masq_init(void))
{
+ int idx;
+ for(idx = 0; idx < IP_MASQ_TAB_SIZE; idx++) {
+ INIT_LIST_HEAD(&ip_masq_s_table[idx]);
+ INIT_LIST_HEAD(&ip_masq_m_table[idx]);
+ INIT_LIST_HEAD(&ip_masq_d_table[idx]);
+ }
#ifdef CONFIG_PROC_FS
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_IPMSQHST, 13, "ip_masquerade",
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)