patch-1.3.94 linux/net/ipv4/ip_masq.c
Next file: linux/net/ipv4/ip_masq_app.c
Previous file: linux/mm/page_io.c
Back to the patch index
Back to the overall index
- Lines: 356
- Date:
Mon Apr 22 11:27:00 1996
- Orig file:
v1.3.93/linux/net/ipv4/ip_masq.c
- Orig date:
Wed Apr 17 09:06:33 1996
diff -u --recursive --new-file v1.3.93/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c
@@ -73,6 +73,7 @@
X(ip_masq_set_expire),
X(ip_masq_free_ports),
X(ip_masq_expire),
+ X(ip_masq_out_get_2),
#include <linux/symtab_end.h>
};
@@ -127,14 +128,14 @@
hash = ip_masq_hash_key(ms->protocol, ms->maddr, ms->mport);
ms->m_link = ip_masq_m_tab[hash];
ip_masq_m_tab[hash] = ms;
-
+
/*
* Hash by proto,s{addr,port}
*/
hash = ip_masq_hash_key(ms->protocol, ms->saddr, ms->sport);
ms->s_link = ip_masq_s_tab[hash];
ip_masq_s_tab[hash] = ms;
-
+
ms->flags |= IP_MASQ_F_HASHED;
return 1;
@@ -172,7 +173,7 @@
*ms_p = ms->s_link;
break;
}
-
+
ms->flags &= ~IP_MASQ_F_HASHED;
return 1;
}
@@ -204,7 +205,7 @@
s_port = portptr[0];
d_addr = iph->daddr;
d_port = portptr[1];
-
+
hash = ip_masq_hash_key(protocol, d_addr, d_port);
for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) {
if ( protocol==ms->protocol &&
@@ -224,8 +225,6 @@
struct ip_masq *
ip_masq_out_get(struct iphdr *iph)
{
- unsigned hash;
- struct ip_masq *ms;
__u16 *portptr;
int protocol;
__u32 s_addr, d_addr;
@@ -237,7 +236,24 @@
s_port = portptr[0];
d_addr = iph->daddr;
d_port = portptr[1];
-
+
+ return ip_masq_out_get_2(protocol, s_addr, s_port, d_addr, d_port);
+}
+
+/*
+ * Returns ip_masq associated with supplied parameters, either
+ * broken out of the ip/tcp headers or directly supplied for those
+ * pathological protocols with address/port in the data stream
+ * (ftp, irc). addresses and ports are in network order.
+ * called for pkts coming from inside-to-OUTside the firewall.
+ */
+
+struct ip_masq *
+ip_masq_out_get_2(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+{
+ unsigned hash;
+ struct ip_masq *ms;
+
hash = ip_masq_hash_key(protocol, s_addr, s_port);
for(ms = ip_masq_s_tab[hash]; ms ; ms = ms->s_link) {
if (protocol == ms->protocol &&
@@ -245,7 +261,7 @@
d_addr == ms->daddr && d_port == ms->dport )
return ms;
}
-
+
return NULL;
}
@@ -259,7 +275,7 @@
{
unsigned hash;
struct ip_masq *ms;
-
+
hash = ip_masq_hash_key(protocol, m_addr, m_port);
for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) {
if ( protocol==ms->protocol &&
@@ -288,7 +304,7 @@
ip_masq_unbind_app(ms);
kfree_s(ms,sizeof(*ms));
}
-
+
restore_flags(flags);
}
@@ -304,9 +320,9 @@
int ports_tried, *free_ports_p;
unsigned long flags;
static int n_fails = 0;
-
+
free_ports_p = &ip_masq_free_ports[proto==IPPROTO_TCP];
-
+
if (*free_ports_p == 0) {
if (++n_fails < 5)
printk("ip_masq_new(proto=%s): no free ports.\n",
@@ -330,7 +346,8 @@
ms->daddr = daddr;
ms->dport = dport;
ms->flags = mflags;
-
+ ms->app_data = NULL;
+
if (proto == IPPROTO_UDP)
ms->flags |= IP_MASQ_F_NO_DADDR;
@@ -434,7 +451,7 @@
ntohl(iph->saddr), ntohs(portptr[0]),
ntohl(iph->daddr), ntohs(portptr[1]));
#endif
-
+
ms = ip_masq_out_get(iph);
if (ms!=NULL)
ip_masq_set_expire(ms,0);
@@ -442,8 +459,8 @@
/*
* Nope, not found, create a new entry for it
*/
-
- if (ms==NULL)
+
+ if (ms==NULL)
{
ms = ip_masq_new(dev, iph->protocol,
iph->saddr, portptr[0],
@@ -452,18 +469,18 @@
if (ms == NULL)
return;
}
-
+
/*
* Change the fragments origin
*/
-
+
size = skb->len - ((unsigned char *)portptr - skb->h.raw);
/*
* Set iph addr and port from ip_masq obj.
*/
iph->saddr = ms->maddr;
portptr[0] = ms->mport;
-
+
/*
* Attempt ip_masq_app call.
* will fix ip_masq and iph seq stuff
@@ -478,42 +495,48 @@
portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
size = skb->len - ((unsigned char *)portptr-skb->h.raw);
}
-
+
/*
* Adjust packet accordingly to protocol
*/
-
- if (iph->protocol==IPPROTO_UDP)
+
+ if (iph->protocol==IPPROTO_UDP)
{
timeout = ip_masq_expire->udp_timeout;
recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
}
- else
+ else
{
struct tcphdr *th;
th = (struct tcphdr *)portptr;
-
+
/*
* Timeout depends if FIN packet was seen
+ * Very short timeout if RST packet seen.
*/
- if (ms->flags & IP_MASQ_F_SAW_FIN || th->fin)
+ if (ms->flags & IP_MASQ_F_SAW_RST || th->rst)
+ {
+ timeout = 1;
+ ms->flags |= IP_MASQ_F_SAW_RST;
+ }
+ else if (ms->flags & IP_MASQ_F_SAW_FIN || th->fin)
{
timeout = ip_masq_expire->tcp_fin_timeout;
ms->flags |= IP_MASQ_F_SAW_FIN;
}
else timeout = ip_masq_expire->tcp_timeout;
-
+
skb->csum = csum_partial((void *)(th + 1), size - sizeof(*th), 0);
tcp_send_check(th,iph->saddr,iph->daddr,size,skb);
}
ip_masq_set_expire(ms, timeout);
ip_send_check(iph);
-
+
#ifdef DEBUG_CONFIG_IP_MASQUERADE
printk("O-routed from %lX:%X over %s\n",ntohl(ms->maddr),ntohs(ms->mport),dev->name);
#endif
}
-
+
/*
* Check if it's an masqueraded port, look it up,
* and send it on it's way...
@@ -530,10 +553,10 @@
__u16 *portptr;
struct ip_masq *ms;
unsigned short frag;
-
+
if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
return 0;
-
+
/*
* Toss fragments, since we handle them in ip_rcv()
*/
@@ -549,7 +572,7 @@
if (ntohs(portptr[1]) < PORT_MASQ_BEGIN ||
ntohs(portptr[1]) > PORT_MASQ_END)
return 0;
-
+
#ifdef DEBUG_CONFIG_IP_MASQUERADE
printk("Incoming %s %lX:%X -> %lX:%X\n",
masq_proto_name(iph->protocol),
@@ -559,17 +582,17 @@
/*
* reroute to original host:port if found...
*/
-
+
ms = ip_masq_in_get(iph);
-
+
if (ms != NULL)
{
int size;
-
+
/*
* Set dport if not defined yet.
*/
-
+
if ( ms->flags & IP_MASQ_F_NO_DPORT && ms->protocol == IPPROTO_TCP ) {
ms->flags &= ~IP_MASQ_F_NO_DPORT;
ms->dport = portptr[0];
@@ -589,34 +612,53 @@
size = skb->len - ((unsigned char *)portptr - skb->h.raw);
iph->daddr = ms->saddr;
portptr[1] = ms->sport;
-
+
/*
* Attempt ip_masq_app call.
* will fix ip_masq and iph ack_seq stuff
*/
-
+
if (ip_masq_app_pkt_in(ms, skb_p, dev) != 0)
{
/*
* skb has changed, update pointers.
*/
-
+
skb = *skb_p;
iph = skb->h.iph;
portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
size = skb->len - ((unsigned char *)portptr-skb->h.raw);
}
-
+
/*
- * Yug! adjust UDP/TCP and IP checksums
+ * Yug! adjust UDP/TCP and IP checksums, also update
+ * UDP timeouts since you cannot depend on traffic
+ * going through the other way to hold the timeout open.
+ * (With TCP the ACK packets hold the tunnel open).
+ * If a TCP RST is seen collapse the tunnel!
*/
if (iph->protocol==IPPROTO_UDP)
+ {
+ unsigned long timeout;
recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
+ ip_masq_set_expire(ms, 0);
+ ip_masq_set_expire(ms, ip_masq_expire->udp_timeout);
+ }
else
{
+ struct tcphdr *th;
skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1),
size - sizeof(struct tcphdr), 0);
tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,size,skb);
+ /* Check if TCP RST */
+ th = (struct tcphdr *)portptr;
+ if (th->rst)
+ {
+ ip_masq_set_expire(ms, 0);
+ ms->flags |= IP_MASQ_F_SAW_RST;
+ ip_masq_set_expire(ms, 1);
+ }
+
}
ip_send_check(iph);
#ifdef DEBUG_CONFIG_IP_MASQUERADE
@@ -624,7 +666,7 @@
#endif
return 1;
}
-
+
/* sorry, all this trouble for a no-hit :) */
return 0;
}
@@ -695,7 +737,7 @@
* Initialize ip masquerading
*/
int ip_masq_init(void)
-{
+{
register_symtab (&ip_masq_syms);
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_IPMSQHST, 13, "ip_masquerade",
@@ -704,6 +746,6 @@
ip_msqhst_procinfo
});
ip_masq_app_init();
-
+
return 0;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this