<< | Thread Index | >> ]    [ << | Date Index | >> ]

Subject: Patch for CIPE to use NAT with iptables
From: Rik Faith <faith,AT,alephnull,DOT,com>
Date: Wed, 31 Oct 2001 15:35:16 +0100

PROBLEM

    Consider using CIPE with the following network topology:

    A <---LAN---> FW <---WAN---> PEER
                  ^
                  |- - - CIPE - - -> INT

    A    is a machine behind your firewall
    FW   is your firewall, running CIPE
    PEER is the CIPE peer listed in /etc/cipe/options
    INT  is an internal machine on the VPN network that CIPE creates

    LAN  is the network behind FW
    WAN  is the connection from the FW to the Internet
    CIPE is a virtual network that's created by tunneling packets from
         FW through PEER

    WANIP  is the IP address of your WAN interface on FW
    CIPEIP is the IP address of your CIPE interface ("me") on FW

    You would like to use a rule like this to provide access from A to
    INT:

    iptables -A POSTROUTING -j SNAT -t nat -o cipcb0 --to-source CIPEIP

    When a packet is sent from A to INT, the following currently
    happens [using (source,destination) notation and CIPE 1.5.2]:
        1) (A,INT) is routed to cipcb0
        2) The POSTROUTING rule changes this packet to (CIPEIP,INT)
        3) The cipcb kernel module encrypts this packet and encapsulates
           it with (WANIP,PEER), injecting it back into the kernel with
           the ip_send(skb) call.
        4) The POSTROUTING rule changes this packet to (CIPEIP,PEER),
           causing the PEER machine to send the reply to CIPEIP instead
           of WANIP.  So, you never see the return packet.

SOLUTION SPACE

    The solution to this problem is to prevent the POSTROUTING mangling
    that happens in (4) above.  My first attempt to do this involved a
    kernel _hack_ to the lowest-level netfilter code in ip_nat_core.c.
    I sent this to Rusty, who replied with a better patch (against the
    CIPE code) that makes CIPE work well with current netfilter support.
    I've attached Rusty's email below -- it contains a patch (that I've
    tested with CIPE 1.5.2 and Linux 2.4.13-ac4) and some explanation of
    the solution.





To: 

Rik Faith <faith,AT,alephnull,DOT,com>


Subject: 

Re: netfilter+CIPE+NAT 


From: 

Rusty Russell <rusty,AT,rustcorp,DOT,com,DOT,au>


Date: 

Tue, 30 Oct 2001 10:23:54 +1100


Cc: 

Olaf Titz <olaf,AT,bigred,DOT,inka,DOT,de>




In message <15318.53171.109991.850849,AT,light,DOT,alephnull,DOT,com> you 
write:
> Rusty,
>     Thanks for your previous help with netfilter.  I have a new
>     problem.  Have you seen:
>     http://sites.inka.de/bigred/archive/cipe-l/2001-08/msg00117.html

Hi Rik,

        Looked at the CIPE source, and it doesn't follow the netfilter
requirements for tunnels (not surprisingly, since they didn't exist
before 2.3.x).  They are:

        MUST:
        o  Release skb->nfct if you're going to make the packet
           unrecognisable (ie. decapsulating/encapsulating).  You
           don't need to do this if you unwrap it into a *new* skb,
           but if you're going to do it in place, you must do this.

                Otherwise: the NAT code will use the old connection
                tracking information to mangle the packet, with bad
                consequences.

        SHOULD:
        o  Make sure the encapsulated packets go through the LOCAL_OUT
           hook, and decapsulated packets go through the PRE_ROUTING
           hook (most tunnels use ip_rcv(), which does this for you).

                Otherwise: the user will not be able to filter as they
                expect to with tunnels.

Olaf, I've got a patch (untested!): does this make sense to you?   
Rusty.
--
Premature optmztion is rt of all evl. --DK

diff -ur cipe-1.5.2/cipe/output.c cipe-1.5.2-netfilter/cipe/output.c
--- cipe-1.5.2/cipe/output.c    Wed May  2 07:23:42 2001
+++ cipe-1.5.2-netfilter/cipe/output.c  Mon Oct 29 16:04:30 2001
@@ -20,6 +20,11 @@
 #include <linux/if_arp.h>
 #include <linux/socket.h>
 #include <linux/version.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+#include <linux/netfilter_ipv4.h>
+#else
+#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
+#endif
 
 #ifdef DEBUG
 
@@ -83,6 +88,13 @@
 }
 #endif
 
+/* Need this wrapper because NF_HOOK takes the function address, and
+   ip_send was declared "extern inline" in the vague past. --RR */
+static inline int do_ip_send(struct sk_buff *skb)
+{
+       return ip_send(skb);
+}
+
 int cipe_xmit(struct sk_buff *skb, struct NET_DEVICE *dev)
 {
         struct cipe *tunnel = (struct cipe*)(dev->priv);
@@ -149,6 +161,16 @@
                goto tx_error_out;
 #endif
 
+       /* Tell the netfilter framework that this packet is not the
+           same as the one before! */
+#ifdef CONFIG_NETFILTER
+       nf_conntrack_put(skb->nfct);
+       skb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+       skb->nf_debug = 0;
+#endif
+#endif
+
 #if 0
         dprintk(DEB_OUT, (KERN_DEBUG "routing dst=%s src=%s tos=%x oif=%d\n",
                           cipe_ntoa(0, dst), cipe_ntoa(1, tunnel->myaddr),
@@ -322,7 +344,10 @@
         if (cipe_debug&DEB_PKOU)
             cipe_dump_packet("sending", skb, 0);
 #endif
-       ip_send(skb);
+
+       /* Send "new" packet from local host */
+       NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
+               do_ip_send);
         tunnel->recursion--;
        return 0;
 





<< | Thread Index | >> ]    [ << | Date Index | >> ]