Re: IP masquerading and fragmentation

Nigel Metheringham (Nigel.Metheringham@theplanet.net)
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--