patch-pre2.0.5 linux/net/ipv4/ip_masq.c
Next file: linux/net/ipv4/route.c
Previous file: linux/net/ipv4/ip_forward.c
Back to the patch index
Back to the overall index
- Lines: 208
- Date:
Thu May 16 16:35:56 1996
- Orig file:
pre2.0.4/linux/net/ipv4/ip_masq.c
- Orig date:
Tue May 7 16:22:41 1996
diff -u --recursive --new-file pre2.0.4/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c
@@ -12,7 +12,7 @@
* Juan Jose Ciarlante : Added hashed lookup by proto,maddr,mport and proto,saddr,sport
* Juan Jose Ciarlante : Fixed deadlock if free ports get exhausted
* Juan Jose Ciarlante : Added NO_ADDR status flag.
- *
+ * Nigel Metheringham : ICMP handling.
*
*/
@@ -27,8 +27,10 @@
#include <linux/in.h>
#include <linux/ip.h>
#include <net/protocol.h>
+#include <net/icmp.h>
#include <net/tcp.h>
#include <net/udp.h>
+#include <net/checksum.h>
#include <net/ip_masq.h>
#define IP_MASQ_TAB_SIZE 256 /* must be power of 2 */
@@ -192,8 +194,6 @@
struct ip_masq *
ip_masq_in_get(struct iphdr *iph)
{
- unsigned hash;
- struct ip_masq *ms;
__u16 *portptr;
int protocol;
__u32 s_addr, d_addr;
@@ -206,6 +206,29 @@
d_addr = iph->daddr;
d_port = portptr[1];
+ return ip_masq_in_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.
+ *
+ * NB. Cannot check destination address, just for the incoming port.
+ * reason: archie.doc.ac.uk has 6 interfaces, you send to
+ * phoenix and get a reply from any other interface(==dst)!
+ *
+ * [Only for UDP] - AC
+ */
+
+struct ip_masq *
+ip_masq_in_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, d_addr, d_port);
for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) {
if ( protocol==ms->protocol &&
@@ -293,7 +316,7 @@
#ifdef DEBUG_CONFIG_IP_MASQUERADE
printk("Masqueraded %s %lX:%X expired\n",
masq_proto_name(ms->protocol),
- ntohl(ms->src),ntohs(ms->sport));
+ ntohl(ms->saddr),ntohs(ms->sport));
#endif
save_flags(flags);
@@ -424,7 +447,7 @@
uh->check=0xFFFF;
}
-void ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev)
+int ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev)
{
struct sk_buff *skb=*skb_ptr;
struct iphdr *iph = skb->h.iph;
@@ -438,7 +461,7 @@
*/
if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
- return;
+ return -1;
/*
* Now hunt the list to see if we have an old entry
@@ -467,7 +490,7 @@
iph->daddr, portptr[1],
0);
if (ms == NULL)
- return;
+ return -1;
}
/*
@@ -535,8 +558,92 @@
#ifdef DEBUG_CONFIG_IP_MASQUERADE
printk("O-routed from %lX:%X over %s\n",ntohl(ms->maddr),ntohs(ms->mport),dev->name);
#endif
+
+ return 0;
}
+/*
+ * Handle ICMP messages.
+ * Find any that might be relevant, check against existing connections,
+ * forward to masqueraded host if relevant.
+ * Currently handles error types - unreachable, quench, ttl exceeded
+ */
+
+int ip_fw_demasq_icmp(struct sk_buff **skb_p, struct device *dev)
+{
+ struct sk_buff *skb = *skb_p;
+ struct iphdr *iph = skb->h.iph;
+ struct icmphdr *icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));
+ struct iphdr *ciph; /* The ip header contained within the ICMP */
+ __u16 *portptr; /* port numbers from TCP/UDP contained header */
+ struct ip_masq *ms;
+
+#ifdef DEBUG_CONFIG_IP_MASQUERADE
+ printk("Incoming ICMP (%d) %lX -> %lX\n",
+ icmph->type,
+ ntohl(iph->saddr), ntohl(iph->daddr));
+#endif
+
+ if ((icmph->type != ICMP_DEST_UNREACH) &&
+ (icmph->type != ICMP_SOURCE_QUENCH) &&
+ (icmph->type != ICMP_TIME_EXCEEDED))
+ return 0;
+
+ /* Now find the contained IP header */
+ ciph = (struct iphdr *) (icmph + 1);
+
+ /* We are only interested ICMPs generated from TCP or UDP packets */
+ if ((ciph->protocol != IPPROTO_UDP) && (ciph->protocol != IPPROTO_TCP))
+ return 0;
+
+ /*
+ * Find the ports involved - remember this packet was
+ * *outgoing* so the ports are reversed (and addresses)
+ */
+ portptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]);
+ if (ntohs(portptr[0]) < PORT_MASQ_BEGIN ||
+ ntohs(portptr[0]) > PORT_MASQ_END)
+ return 0;
+
+#ifdef DEBUG_CONFIG_IP_MASQUERADE
+ printk("Handling ICMP for %lX:%X -> %lX:%X\n",
+ ntohl(ciph->saddr), ntohs(portptr[0]),
+ ntohl(ciph->daddr), ntohs(portptr[1]));
+#endif
+
+ /* This is pretty much what ip_masq_in_get() does, except params are wrong way round */
+ ms = ip_masq_in_get_2(ciph->protocol, ciph->daddr, portptr[1], ciph->saddr, portptr[0]);
+
+ if (ms == NULL)
+ return 0;
+
+ /* Now we do real damage to this packet...! */
+ /* First change the dest IP address, and recalc checksum */
+ iph->daddr = ms->saddr;
+ ip_send_check(iph);
+
+ /* Now change the *source* address in the contained IP */
+ ciph->saddr = ms->saddr;
+ ip_send_check(ciph);
+
+ /* the TCP/UDP source port - cannot redo check */
+ portptr[0] = ms->sport;
+
+ /* And finally the ICMP checksum */
+ icmph->checksum = 0;
+ icmph->checksum = ip_compute_csum((unsigned char *) icmph,
+ skb->len - sizeof(struct iphdr));
+
+#ifdef DEBUG_CONFIG_IP_MASQUERADE
+ printk("Rewrote ICMP to %lX:%X -> %lX:%X\n",
+ ntohl(ciph->saddr), ntohs(portptr[0]),
+ ntohl(ciph->daddr), ntohs(portptr[1]));
+#endif
+
+ return 1;
+}
+
+
/*
* Check if it's an masqueraded port, look it up,
* and send it on its way...
@@ -554,7 +661,8 @@
struct ip_masq *ms;
unsigned short frag;
- if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
+ if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP
+ && iph->protocol!=IPPROTO_ICMP)
return 0;
/*
@@ -567,6 +675,9 @@
{
return 0;
}
+
+ if (iph->protocol == IPPROTO_ICMP)
+ return ip_fw_demasq_icmp(skb_p, dev);
portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
if (ntohs(portptr[1]) < PORT_MASQ_BEGIN ||
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