patch-pre2.0.10 linux/net/ipv4/ip_masq.c
Next file: linux/net/ipv4/ip_masq_app.c
Previous file: linux/net/ipv4/ip_input.c
Back to the patch index
Back to the overall index
- Lines: 224
- Date:
Fri May 31 13:46:27 1996
- Orig file:
pre2.0.9/linux/net/ipv4/ip_masq.c
- Orig date:
Fri May 17 15:32:20 1996
diff -u --recursive --new-file pre2.0.9/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c
@@ -12,10 +12,13 @@
* 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.
+ * Nigel Metheringham : Added ICMP handling for demasquerade
+ * Nigel Metheringham : Checksum checking of masqueraded data
+ *
*
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -26,6 +29,7 @@
#include <linux/proc_fs.h>
#include <linux/in.h>
#include <linux/ip.h>
+#include <linux/inet.h>
#include <net/protocol.h>
#include <net/icmp.h>
#include <net/tcp.h>
@@ -458,6 +462,8 @@
/*
* We can only masquerade protocols with ports...
+ * [TODO]
+ * We may need to consider masq-ing some ICMP related to masq-ed protocols
*/
if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
@@ -575,8 +581,9 @@
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 */
+ __u16 *pptr; /* port numbers from TCP/UDP contained header */
struct ip_masq *ms;
+ unsigned short len = ntohs(iph->tot_len) - (iph->ihl * 4);
#ifdef DEBUG_CONFIG_IP_MASQUERADE
printk("Incoming ICMP (%d) %lX -> %lX\n",
@@ -600,19 +607,27 @@
* 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)
+ pptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]);
+ if (ntohs(pptr[0]) < PORT_MASQ_BEGIN ||
+ ntohs(pptr[0]) > PORT_MASQ_END)
return 0;
+ /* Ensure the checksum is correct */
+ if (ip_compute_csum((unsigned char *) icmph, len))
+ {
+ /* Failed checksum! */
+ printk(KERN_INFO "MASQ: ICMP: failed checksum from %s!\n", in_ntoa(iph->saddr));
+ return(-1);
+ }
+
#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]));
+ ntohl(ciph->saddr), ntohs(pptr[0]),
+ ntohl(ciph->daddr), ntohs(pptr[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]);
+ ms = ip_masq_in_get_2(ciph->protocol, ciph->daddr, pptr[1], ciph->saddr, pptr[0]);
if (ms == NULL)
return 0;
@@ -627,17 +642,16 @@
ip_send_check(ciph);
/* the TCP/UDP source port - cannot redo check */
- portptr[0] = ms->sport;
+ pptr[0] = ms->sport;
/* And finally the ICMP checksum */
icmph->checksum = 0;
- icmph->checksum = ip_compute_csum((unsigned char *) icmph,
- skb->len - sizeof(struct iphdr));
+ icmph->checksum = ip_compute_csum((unsigned char *) icmph, len);
#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]));
+ ntohl(ciph->saddr), ntohs(pptr[0]),
+ ntohl(ciph->daddr), ntohs(pptr[1]));
#endif
return 1;
@@ -659,30 +673,44 @@
struct iphdr *iph = skb->h.iph;
__u16 *portptr;
struct ip_masq *ms;
- unsigned short frag;
-
- if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP
- && iph->protocol!=IPPROTO_ICMP)
- return 0;
-
- /*
- * Toss fragments, since we handle them in ip_rcv()
- */
+ unsigned short len;
- frag = ntohs(iph->frag_off);
+ switch (iph->protocol) {
+ case IPPROTO_ICMP:
+ return(ip_fw_demasq_icmp(skb_p, dev));
+ case IPPROTO_TCP:
+ case IPPROTO_UDP:
+ /* Make sure packet is in the masq range */
+ portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
+ if (ntohs(portptr[1]) < PORT_MASQ_BEGIN ||
+ ntohs(portptr[1]) > PORT_MASQ_END)
+ return 0;
+ /* Check that the checksum is OK */
+ len = ntohs(iph->tot_len) - (iph->ihl * 4);
+ if ((iph->protocol == IPPROTO_UDP) && (portptr[3] == 0))
+ /* No UDP checksum */
+ break;
- if ((frag & IP_MF) != 0 || (frag & IP_OFFSET) != 0)
- {
+ switch (skb->ip_summed)
+ {
+ case CHECKSUM_NONE:
+ skb->csum = csum_partial((char *)portptr, len, 0);
+ case CHECKSUM_HW:
+ if (csum_tcpudp_magic(iph->saddr, iph->daddr, len,
+ iph->protocol, skb->csum))
+ {
+ printk(KERN_INFO "MASQ: failed TCP/UDP checksum from %s!\n",
+ in_ntoa(iph->saddr));
+ return -1;
+ }
+ default:
+ /* CHECKSUM_UNNECESSARY */
+ }
+ break;
+ default:
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 ||
- ntohs(portptr[1]) > PORT_MASQ_END)
- return 0;
#ifdef DEBUG_CONFIG_IP_MASQUERADE
printk("Incoming %s %lX:%X -> %lX:%X\n",
@@ -698,8 +726,6 @@
if (ms != NULL)
{
- int size;
-
/*
* Set dport if not defined yet.
*/
@@ -720,7 +746,6 @@
ntohs(ms->daddr));
#endif
}
- size = skb->len - ((unsigned char *)portptr - skb->h.raw);
iph->daddr = ms->saddr;
portptr[1] = ms->sport;
@@ -738,7 +763,7 @@
skb = *skb_p;
iph = skb->h.iph;
portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
- size = skb->len - ((unsigned char *)portptr-skb->h.raw);
+ len = ntohs(iph->tot_len) - (iph->ihl * 4);
}
/*
@@ -750,7 +775,7 @@
*/
if (iph->protocol==IPPROTO_UDP)
{
- recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
+ recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,len);
ip_masq_set_expire(ms, 0);
ip_masq_set_expire(ms, ip_masq_expire->udp_timeout);
}
@@ -758,8 +783,8 @@
{
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);
+ len - sizeof(struct tcphdr), 0);
+ tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,len,skb);
/* Check if TCP RST */
th = (struct tcphdr *)portptr;
if (th->rst)
@@ -849,12 +874,14 @@
int ip_masq_init(void)
{
register_symtab (&ip_masq_syms);
+#ifdef CONFIG_PROC_FS
proc_net_register(&(struct proc_dir_entry) {
PROC_NET_IPMSQHST, 13, "ip_masquerade",
S_IFREG | S_IRUGO, 1, 0, 0,
0, &proc_net_inode_operations,
ip_msqhst_procinfo
});
+#endif
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