[2920] in linux-net channel archive

home help back first fref pref prev next nref lref last post

Re: IP masquerading and fragmentation

daemon@ATHENA.MIT.EDU (Nigel Metheringham)
Wed May 15 17:15:27 1996

To: Alan Cox <alan@cymru.net>
cc: linux-net@vger.rutgers.edu, masq@lists.indyramp.com
From: Nigel Metheringham <Nigel.Metheringham@theplanet.net>
In-reply-to: Your message of "Tue, 14 May 1996 17:57:35 BST."
             <199605141657.RAA02434@snowcrash.cymru.net> 
Date: 	Wed, 15 May 1996 19:41:46 +0100

This is a multipart MIME message.

--===_0_Wed_May_15_19:40:51_BST_1996
Content-Type: text/plain; charset=us-ascii


alan@cymru.net said:
} If you get an unreach or similar frame you get the ip header and 8 
} bytes + of tcp.udp header back. So you can demux it  (same as if it 
} was really for you and you had to demux to a socket).  


Alan,

I have a patch here that works all except for one thing...
I can't fudge the ICMP checksum correctly (the last couple of lines 
of the main part of the patch), and I can't see what I am doing wrong 
:-(

As I understand it the stuff must be aligned right for the 
ip_fast_csum routine, and the length I think is fudged correctly 
(another problem is how do you get the *right* length for this - I 
have assume that 8 bytes of protocol stuff are being added, which is 
the case for my tests).

Anyhow I have been round this loop several times and am getting 
nowhere - could you dig me out please!

Thanks
	Nigel.


--===_0_Wed_May_15_19:40:51_BST_1996
Content-Type: application/x-patch
Content-Description: icmp.patch

Index: linux/include/net/ip_masq.h
diff -c linux/include/net/ip_masq.h:1.1.1.1 linux/include/net/ip_masq.h:1.2
*** linux/include/net/ip_masq.h:1.1.1.1	Wed May 15 10:20:11 1996
--- linux/include/net/ip_masq.h	Wed May 15 14:41:44 1996
***************
*** 149,154 ****
--- 149,155 ----
   *	service routine(s).
   */
  extern struct ip_masq * ip_masq_out_get_2(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+ extern struct ip_masq * ip_masq_in_get_2(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
  
  /*
   *	/proc/net entry
Index: linux/net/ipv4/ip_masq.c
diff -c linux/net/ipv4/ip_masq.c:1.1.1.1 linux/net/ipv4/ip_masq.c:1.10
*** linux/net/ipv4/ip_masq.c:1.1.1.1	Wed May 15 10:20:29 1996
--- linux/net/ipv4/ip_masq.c	Wed May 15 19:35:48 1996
***************
*** 27,34 ****
--- 27,36 ----
  #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,199 ****
  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;
--- 194,199 ----
***************
*** 206,211 ****
--- 206,234 ----
          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,299 ****
  #ifdef DEBUG_CONFIG_IP_MASQUERADE
  	printk("Masqueraded %s %lX:%X expired\n",
  			masq_proto_name(ms->protocol),
! 			ntohl(ms->src),ntohs(ms->sport));
  #endif
  	
  	save_flags(flags);
--- 316,322 ----
  #ifdef DEBUG_CONFIG_IP_MASQUERADE
  	printk("Masqueraded %s %lX:%X expired\n",
  			masq_proto_name(ms->protocol),
! 			ntohl(ms->saddr),ntohs(ms->sport));
  #endif
  	
  	save_flags(flags);
***************
*** 537,542 ****
--- 560,647 ----
   #endif
   }
  
+ /*
+  *	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_fast_csum((unsigned char *) icmph, 
+ 				       (sizeof(struct icmphdr) >> 2 + ciph->ihl + 2));
+ 
+ #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,560 ****
   	struct ip_masq	*ms;
  	unsigned short  frag;
  
!  	if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
   		return 0;
  
  	/*
--- 659,666 ----
   	struct ip_masq	*ms;
  	unsigned short  frag;
  
!  	if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP 
! 	    && iph->protocol!=IPPROTO_ICMP)
   		return 0;
  
  	/*
***************
*** 567,572 ****
--- 673,681 ----
  	{
  		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 ||

--===_0_Wed_May_15_19:40:51_BST_1996
Content-Type: text/plain; charset=us-ascii

[ Nigel.Metheringham@theplanet.net   - Unix Applications Engineer ]
[ *Views expressed here are personal and not supported by PLAnet* ]
[ PLAnet Online : The White House     Tel : +44 113 2345566 x 612 ]
[ Melbourne Street, Leeds LS2 7PS UK. Fax : +44 113 2345656       ]

--===_0_Wed_May_15_19:40:51_BST_1996--




home help back first fref pref prev next nref lref last post