This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / net / ipv4 / netfilter / ipt_REJECT.c
index d0a5e05..b2e0574 100644 (file)
@@ -22,7 +22,6 @@
 #include <net/ip.h>
 #include <net/tcp.h>
 #include <net/route.h>
-#include <net/dst.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv4/ipt_REJECT.h>
 #ifdef CONFIG_BRIDGE_NETFILTER
@@ -39,8 +38,21 @@ MODULE_DESCRIPTION("iptables REJECT target module");
 #define DEBUGP(format, args...)
 #endif
 
-static inline struct rtable *route_reverse(struct sk_buff *skb, 
-                                          struct tcphdr *tcph, int hook)
+/* If the original packet is part of a connection, but the connection
+   is not confirmed, our manufactured reply will not be associated
+   with it, so we need to do this manually. */
+static void connection_attach(struct sk_buff *new_skb, struct sk_buff *skb)
+{
+       void (*attach)(struct sk_buff *, struct sk_buff *);
+
+       /* Avoid module unload race with ip_ct_attach being NULLed out */
+       if (skb->nfct && (attach = ip_ct_attach) != NULL) {
+               mb(); /* Just to be sure: must be read before executing this */
+               attach(new_skb, skb);
+       }
+}
+
+static inline struct rtable *route_reverse(struct sk_buff *skb, int hook)
 {
        struct iphdr *iph = skb->nh.iph;
        struct dst_entry *odst;
@@ -77,22 +89,9 @@ static inline struct rtable *route_reverse(struct sk_buff *skb,
                dst_release(&rt->u.dst);
                rt = (struct rtable *)skb->dst;
                skb->dst = odst;
-
-               fl.nl_u.ip4_u.daddr = iph->saddr;
-               fl.nl_u.ip4_u.saddr = iph->daddr;
-               fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
        }
 
        if (rt->u.dst.error) {
-               dst_release(&rt->u.dst);
-               return NULL;
-       }
-
-       fl.proto = IPPROTO_TCP;
-       fl.fl_ip_sport = tcph->dest;
-       fl.fl_ip_dport = tcph->source;
-
-       if (xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0)) {
                dst_release(&rt->u.dst);
                rt = NULL;
        }
@@ -125,7 +124,7 @@ static void send_reset(struct sk_buff *oldskb, int hook)
                return;
 
        /* FIXME: Check checksum --RR */
-       if ((rt = route_reverse(oldskb, oth, hook)) == NULL)
+       if ((rt = route_reverse(oldskb, hook)) == NULL)
                return;
 
        hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
@@ -210,7 +209,7 @@ static void send_reset(struct sk_buff *oldskb, int hook)
        if (nskb->len > dst_pmtu(nskb->dst))
                goto free_nskb;
 
-       nf_ct_attach(nskb, oldskb);
+       connection_attach(nskb, oldskb);
 
        NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
                ip_finish_output);
@@ -297,23 +296,10 @@ static void send_unreach(struct sk_buff *skb_in, int code)
        tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL;
 
        {
-               struct flowi fl = {
-                       .nl_u = {
-                               .ip4_u = {
-                                       .daddr = skb_in->nh.iph->saddr,
-                                       .saddr = saddr,
-                                       .tos = RT_TOS(tos)
-                               }
-                       },
-                       .proto = IPPROTO_ICMP,
-                       .uli_u = {
-                               .icmpt = {
-                                       .type = ICMP_DEST_UNREACH,
-                                       .code = code
-                               }
-                       }
-               };
-
+               struct flowi fl = { .nl_u = { .ip4_u =
+                                             { .daddr = skb_in->nh.iph->saddr,
+                                               .saddr = saddr,
+                                               .tos = RT_TOS(tos) } } };
                if (ip_route_output_key(&rt, &fl))
                        return;
        }
@@ -374,7 +360,7 @@ static void send_unreach(struct sk_buff *skb_in, int code)
        icmph->checksum = ip_compute_csum((unsigned char *)icmph,
                                          length - sizeof(struct iphdr));
 
-       nf_ct_attach(nskb, skb_in);
+       connection_attach(nskb, skb_in);
 
        NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
                ip_finish_output);