netdev
[Top] [All Lists]

[PATCH] misc netfilter fixes against test3-2

To: torvalds@xxxxxxxxxxxxx
Subject: [PATCH] misc netfilter fixes against test3-2
From: Rusty Russell <rusty@xxxxxxxxxxxxxxxx>
Date: Fri, 07 Jul 2000 14:17:48 +1000
Cc: netdev@xxxxxxxxxxx
Sender: owner-netdev@xxxxxxxxxxx
Linus, please apply.

For the curious:

Bugs fixed: (most to least important)
        conntrack: ip_defrag crash fix                  Andi Kleen
        conntrack: local ICMPs on NAT'ed conns fix      Rusty
        MASQUERADE: reset on address change (diald)     Rusty
        ip_queue: Pass mark field                       James Morris
        ftp nat: don't overallocate space               Marc Boucher/Rusty
        MIRROR: must not track mirrored packets         Rusty

Enhancements:
        NAT: Set NFC_ALTERED bit only when skb altered  Rusty
        compat: Always set NFC_ALTERED: no rules        Rusty
        ftp conntrack: Always print partial matches     Rusty
        mac: matching in FORWARD chain                  Rusty

Cheers!
Rusty.

diff -urN -X /tmp/fileJ6etyF --minimal 
linux-2.4.0-test3-4/net/ipv4/netfilter/ip_fw_compat.c 
tmp-cleanpatch/net/ipv4/netfilter/ip_fw_compat.c
--- linux-2.4.0-test3-4/net/ipv4/netfilter/ip_fw_compat.c       Thu Jun 29 
01:26:09 2000
+++ tmp-cleanpatch/net/ipv4/netfilter/ip_fw_compat.c    Fri Jul  7 13:08:37 2000
@@ -86,7 +86,8 @@
        int ret = FW_BLOCK;
        u_int16_t redirpt;
 
-       (*pskb)->nfcache |= NFC_UNKNOWN;
+       /* Assume worse case: any hook could change packet */
+       (*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED;
        (*pskb)->ip_summed = CHECKSUM_NONE;
 
        switch (hooknum) {
diff -urN -X /tmp/fileJ6etyF --minimal 
linux-2.4.0-test3-4/net/ipv4/netfilter/ip_nat_core.c 
tmp-cleanpatch/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.4.0-test3-4/net/ipv4/netfilter/ip_nat_core.c        Thu Jun 29 
01:26:09 2000
+++ tmp-cleanpatch/net/ipv4/netfilter/ip_nat_core.c     Fri Jul  7 13:08:37 2000
@@ -663,8 +663,10 @@
 static void
 manip_pkt(u_int16_t proto, struct iphdr *iph, size_t len,
          const struct ip_conntrack_manip *manip,
-         enum ip_nat_manip_type maniptype)
+         enum ip_nat_manip_type maniptype,
+         __u32 *nfcache)
 {
+       *nfcache |= NFC_ALTERED;
        find_nat_proto(proto)->manip_pkt(iph, len, manip, maniptype);
 
        if (maniptype == IP_NAT_MANIP_SRC) {
@@ -718,7 +720,8 @@
                                  (*pskb)->nh.iph,
                                  (*pskb)->len,
                                  &info->manips[i].manip,
-                                 info->manips[i].maniptype);
+                                 info->manips[i].maniptype,
+                                 &(*pskb)->nfcache);
                }
        }
        helper = info->helper;
@@ -782,7 +785,8 @@
                        manip_pkt(inner->protocol, inner,
                                  skb->len - ((void *)inner - (void *)iph),
                                  &info->manips[i].manip,
-                                 !info->manips[i].maniptype);
+                                 !info->manips[i].maniptype,
+                                 &skb->nfcache);
                /* Outer packet needs to have IP header NATed like
                    it's a reply. */
                } else if (info->manips[i].direction == dir
@@ -795,7 +799,8 @@
                               IP_PARTS(info->manips[i].manip.ip));
                        manip_pkt(0, iph, skb->len,
                                  &info->manips[i].manip,
-                                 info->manips[i].maniptype);
+                                 info->manips[i].maniptype,
+                                 &skb->nfcache);
                }
        }
        READ_UNLOCK(&ip_nat_lock);
diff -urN -X /tmp/fileJ6etyF --minimal 
linux-2.4.0-test3-4/net/ipv4/netfilter/ip_nat_standalone.c 
tmp-cleanpatch/net/ipv4/netfilter/ip_nat_standalone.c
--- linux-2.4.0-test3-4/net/ipv4/netfilter/ip_nat_standalone.c  Thu Jun 29 
01:26:09 2000
+++ tmp-cleanpatch/net/ipv4/netfilter/ip_nat_standalone.c       Fri Jul  7 
13:08:37 2000
@@ -60,8 +60,7 @@
        IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
                       & __constant_htons(IP_MF|IP_OFFSET)));
 
-       /* FIXME: One day, fill in properly. --RR */
-       (*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED;
+       (*pskb)->nfcache |= NFC_UNKNOWN;
 
        /* If we had a hardware checksum before, it's now invalid */
        if ((*pskb)->pkt_type != PACKET_LOOPBACK)
diff -urN -X /tmp/fileEbRxnx --minimal 
linux-2.4.0-test3-4/net/ipv4/netfilter/ip_queue.c 
tmp-cleanpatch/net/ipv4/netfilter/ip_queue.c
--- linux-2.4.0-test3-4/net/ipv4/netfilter/ip_queue.c   Thu Jun 29 01:26:09 2000
+++ tmp-cleanpatch/net/ipv4/netfilter/ip_queue.c        Fri Jul  7 13:08:45 2000
@@ -6,6 +6,8 @@
  *
  * 2000-03-27: Simplified code (thanks to Andi Kleen for clues). (JM)
  * 2000-05-20: Fixed notifier problems (following Miguel Freitas' report). (JM)
+ * 2000-06-19: Fixed so nfmark is copied to metadata (reported by Sebastian 
+ *             Zander). (JM)
  *
  */
 #include <linux/module.h>
@@ -391,6 +393,7 @@
        pm->data_len = data_len;
        pm->timestamp_sec = e->skb->stamp.tv_sec;
        pm->timestamp_usec = e->skb->stamp.tv_usec;
+       pm->mark = e->skb->nfmark;
        pm->hook = e->info->hook;
        if (e->info->indev) strcpy(pm->indev_name, e->info->indev->name);
        else pm->indev_name[0] = '\0';
diff -urN -X /tmp/filenRRBei --minimal 
linux-2.4.0-test3-4/net/ipv4/netfilter/ip_conntrack_ftp.c 
tmp-cleanpatch/net/ipv4/netfilter/ip_conntrack_ftp.c
--- linux-2.4.0-test3-4/net/ipv4/netfilter/ip_conntrack_ftp.c   Thu Jun 29 
01:26:09 2000
+++ tmp-cleanpatch/net/ipv4/netfilter/ip_conntrack_ftp.c        Fri Jul  7 
13:08:51 2000
@@ -181,8 +181,9 @@
                   connection tracking, not packet filtering.
                   However, it is neccessary for accurate tracking in
                   this case. */
-               DEBUGP("conntrack_ftp: partial `%.*s'\n",
-                      (int)datalen, data);
+               if (net_ratelimit())
+                       printk("conntrack_ftp: partial %u+%u\n",
+                              ntohl(tcph->seq), datalen);
                return NF_DROP;
 
        case 0: /* no match */
diff -urN -X /tmp/fileLO7Uag --minimal 
linux-2.4.0-test3-4/net/ipv4/netfilter/ip_conntrack_core.c 
tmp-cleanpatch/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.4.0-test3-4/net/ipv4/netfilter/ip_conntrack_core.c  Thu Jun 29 
01:26:09 2000
+++ tmp-cleanpatch/net/ipv4/netfilter/ip_conntrack_core.c       Fri Jul  7 
13:09:03 2000
@@ -816,7 +816,9 @@
        unsigned int olddebug = skb->nf_debug;
 #endif
        if (sk) sock_hold(sk);
+       local_bh_disable(); 
        skb = ip_defrag(skb);
+       local_bh_enable(); 
        if (!skb) {
                if (sk) sock_put(sk);
                return skb;
diff -urN -X /tmp/filen7QCuR --minimal 
linux-2.4.0-test3-4/net/ipv4/netfilter/ipt_mac.c 
tmp-cleanpatch/net/ipv4/netfilter/ipt_mac.c
--- linux-2.4.0-test3-4/net/ipv4/netfilter/ipt_mac.c    Fri May 12 13:22:38 2000
+++ tmp-cleanpatch/net/ipv4/netfilter/ipt_mac.c Fri Jul  7 13:09:10 2000
@@ -33,9 +33,11 @@
                   unsigned int matchsize,
                   unsigned int hook_mask)
 {
+       /* FORWARD isn't always valid, but it's nice to be able to do --RR */
        if (hook_mask
-           & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN))) {
-               printk("ipt_mac: only valid for PRE_ROUTING or LOCAL_IN.\n");
+           & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_LOCAL_IN)
+               | (1 << NF_IP_FORWARD))) {
+               printk("ipt_mac: only valid for PRE_ROUTING, LOCAL_IN or 
FORWARD.\n");
                return 0;
        }
 
diff -urN -X /tmp/fileEFGdiT --minimal 
linux-2.4.0-test3-4/net/ipv4/netfilter/ipt_MASQUERADE.c 
tmp-cleanpatch/net/ipv4/netfilter/ipt_MASQUERADE.c
--- linux-2.4.0-test3-4/net/ipv4/netfilter/ipt_MASQUERADE.c     Thu Jun 29 
01:26:09 2000
+++ tmp-cleanpatch/net/ipv4/netfilter/ipt_MASQUERADE.c  Fri Jul  7 13:09:16 2000
@@ -127,8 +127,8 @@
 {
        struct net_device *dev = ptr;
 
-       if (event == NETDEV_DOWN) {
-               /* Device was downed.  Search entire table for
+       if (event == NETDEV_DOWN || event == NETDEV_CHANGEADDR) {
+               /* Device was downed/changed (diald)  Search entire table for
                   conntracks which were associated with that device,
                   and forget them. */
                IP_NF_ASSERT(dev->ifindex != 0);
diff -urN -X /tmp/filevIBgPs --minimal 
linux-2.4.0-test3-4/net/ipv4/netfilter/ip_conntrack_core.c 
tmp-cleanpatch/net/ipv4/netfilter/ip_conntrack_core.c
--- linux-2.4.0-test3-4/net/ipv4/netfilter/ip_conntrack_core.c  Thu Jun 29 
01:26:09 2000
+++ tmp-cleanpatch/net/ipv4/netfilter/ip_conntrack_core.c       Fri Jul  7 
13:09:22 2000
@@ -303,6 +303,7 @@
        struct ip_conntrack_tuple_hash *h;
 
        IP_NF_ASSERT(iph->protocol == IPPROTO_ICMP);
+       IP_NF_ASSERT(skb->nfct == NULL);
 
        iph = skb->nh.iph;
        hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);
@@ -350,10 +351,27 @@
                DEBUGP("icmp_error_track: Can't invert tuple\n");
                return NULL;
        }
+
+       *ctinfo = IP_CT_RELATED;
+
        h = ip_conntrack_find_get(&innertuple, NULL);
        if (!h) {
-               DEBUGP("icmp_error_track: no match\n");
-               return NULL;
+               /* Locally generated ICMPs will match inverted if they
+                  haven't been SNAT'ed yet */
+               /* FIXME: NAT code has to handle half-done double NAT --RR */
+               if (hooknum == NF_IP_LOCAL_OUT)
+                       h = ip_conntrack_find_get(&origtuple, NULL);
+
+               if (!h) {
+                       DEBUGP("icmp_error_track: no match\n");
+                       return NULL;
+               }
+               /* Reverse direction from that found */
+               if (DIRECTION(h) != IP_CT_DIR_REPLY)
+                       *ctinfo += IP_CT_IS_REPLY;
+       } else {
+               if (DIRECTION(h) == IP_CT_DIR_REPLY)
+                       *ctinfo += IP_CT_IS_REPLY;
        }
 
        /* REJECT target does this commonly, so allow locally
@@ -364,10 +382,6 @@
                ip_conntrack_put(h->ctrack);
                return NULL;
        }
-
-       *ctinfo = IP_CT_RELATED;
-       if (DIRECTION(h) == IP_CT_DIR_REPLY)
-               *ctinfo += IP_CT_IS_REPLY;
 
        /* Update skb to refer to this connection */
        skb->nfct = &h->ctrack->infos[*ctinfo];
diff -urN -X /tmp/filevIBgPs --minimal 
linux-2.4.0-test3-4/net/ipv4/netfilter/ip_nat_core.c 
tmp-cleanpatch/net/ipv4/netfilter/ip_nat_core.c
--- linux-2.4.0-test3-4/net/ipv4/netfilter/ip_nat_core.c        Thu Jun 29 
01:26:09 2000
+++ tmp-cleanpatch/net/ipv4/netfilter/ip_nat_core.c     Fri Jul  7 13:09:22 2000
@@ -467,7 +467,7 @@
 static unsigned int opposite_hook[NF_IP_NUMHOOKS]
 = { [NF_IP_PRE_ROUTING] = NF_IP_POST_ROUTING,
     [NF_IP_POST_ROUTING] = NF_IP_PRE_ROUTING,
-    [NF_IP_LOCAL_OUT] = NF_IP_PRE_ROUTING
+    [NF_IP_LOCAL_OUT] = NF_IP_POST_ROUTING
 };
 
 unsigned int
@@ -754,7 +754,7 @@
           (even though a "host unreachable" coming from the host
           itself is a bit wierd).
 
-          More explanation: some people use NAT for anonomizing.
+          More explanation: some people use NAT for anonymizing.
           Also, CERT recommends dropping all packets from private IP
           addresses (although ICMP errors from internal links with
           such addresses are not too uncommon, as Alan Cox points
@@ -785,8 +785,7 @@
                                  !info->manips[i].maniptype);
                /* Outer packet needs to have IP header NATed like
                    it's a reply. */
-               } else if (info->manips[i].direction == dir
-                        && info->manips[i].hooknum == hooknum) {
+               } else if (info->manips[i].hooknum == hooknum) {
                        /* Use mapping to map outer packet: 0 give no
                            per-proto mapping */
                        DEBUGP("icmp_reply: outer %s -> %u.%u.%u.%u\n",
diff -urN -X /tmp/fileciI17V --minimal 
linux-2.4.0-test3-4/net/ipv4/netfilter/ip_nat_ftp.c 
tmp-cleanpatch/net/ipv4/netfilter/ip_nat_ftp.c
--- linux-2.4.0-test3-4/net/ipv4/netfilter/ip_nat_ftp.c Wed Apr 12 17:43:07 2000
+++ tmp-cleanpatch/net/ipv4/netfilter/ip_nat_ftp.c      Fri Jul  7 13:09:28 2000
@@ -123,7 +123,8 @@
 
        if (newlen > (*pskb)->len + skb_tailroom(*pskb)) {
                struct sk_buff *newskb;
-               newskb = skb_copy_expand(*pskb, skb_headroom(*pskb), newlen,
+               newskb = skb_copy_expand(*pskb, skb_headroom(*pskb),
+                                        newlen - (*pskb)->len,
                                         GFP_ATOMIC);
                if (!newskb) {
                        DEBUGP("ftp: oom\n");
diff -urN -X /tmp/filev1eVOB --minimal 
linux-2.4.0-test3-4/net/ipv4/netfilter/ipt_MIRROR.c 
tmp-cleanpatch/net/ipv4/netfilter/ipt_MIRROR.c
--- linux-2.4.0-test3-4/net/ipv4/netfilter/ipt_MIRROR.c Fri May 12 13:22:38 2000
+++ tmp-cleanpatch/net/ipv4/netfilter/ipt_MIRROR.c      Fri Jul  7 13:09:42 2000
@@ -41,23 +41,25 @@
         struct iphdr *iph = skb->nh.iph;
        struct rtable *rt;
 
-       if (ip_route_output(&rt, iph->daddr, iph->saddr,
+       /* Backwards */
+       if (ip_route_output(&rt, iph->saddr, iph->daddr,
                            RT_TOS(iph->tos) | RTO_CONN,
                            0)) {
-               return -EINVAL;
+               return 0;
        }
-       /* check if the interface we are living by is the same as the one we 
arrived on */
 
+       /* check if the interface we are leaving by is the same as the
+           one we arrived on */
        if (skb->rx_dev == rt->u.dst.dev) {
                /* Drop old route. */
                dst_release(skb->dst);
                skb->dst = &rt->u.dst;
-               return 0;
+               return 1;
        }
-       else  return -EINVAL;
+       return 0;
 }
 
-static int
+static void
 ip_rewrite(struct sk_buff *skb)
 {
        struct iphdr *iph = skb->nh.iph;
@@ -69,10 +71,27 @@
        /* Rewrite IP header */
        iph->daddr = odaddr;
        iph->saddr = osaddr;
-
-       return 0;
 }
 
+/* Stolen from ip_finish_output2 */
+static void ip_direct_send(struct sk_buff *skb)
+{
+       struct dst_entry *dst = skb->dst;
+       struct hh_cache *hh = dst->hh;
+
+       if (hh) {
+               read_lock_bh(&hh->hh_lock);
+               memcpy(skb->data - 16, hh->hh_data, 16);
+               read_unlock_bh(&hh->hh_lock);
+               skb_push(skb, hh->hh_len);
+               hh->hh_output(skb);
+       } else if (dst->neighbour)
+               dst->neighbour->output(skb);
+       else {
+               printk(KERN_DEBUG "khm in MIRROR\n");
+               kfree(skb);
+       }
+}
 
 static unsigned int ipt_mirror_target(struct sk_buff **pskb,
                                      unsigned int hooknum,
@@ -82,8 +101,12 @@
                                      void *userinfo)
 {
        if ((*pskb)->dst != NULL) {
-               if (!ip_rewrite(*pskb) && !route_mirror(*pskb)) {
-                       ip_send(*pskb);
+               if (route_mirror(*pskb)) {
+                       ip_rewrite(*pskb);
+                       /* Don't let conntrack code see this packet:
+                           it will think we are starting a new
+                           connection! --RR */
+                       ip_direct_send(*pskb);
                        return NF_STOLEN;
                }
        }

--
Hacking time.

<Prev in Thread] Current Thread [Next in Thread>
  • [PATCH] misc netfilter fixes against test3-2, Rusty Russell <=