X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fnetfilter%2Fipt_REJECT.c;h=7593090ee22248e7631c9dffd2eb5127ae1c8e4d;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=b2e05746a528d16f1d429554b3c4072eed9b374b;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index b2e05746a..7593090ee 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_BRIDGE_NETFILTER @@ -38,21 +39,8 @@ MODULE_DESCRIPTION("iptables REJECT target module"); #define DEBUGP(format, args...) #endif -/* 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) +static inline struct rtable *route_reverse(struct sk_buff *skb, + struct tcphdr *tcph, int hook) { struct iphdr *iph = skb->nh.iph; struct dst_entry *odst; @@ -89,9 +77,22 @@ static inline struct rtable *route_reverse(struct sk_buff *skb, int hook) 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; } @@ -124,7 +125,7 @@ static void send_reset(struct sk_buff *oldskb, int hook) return; /* FIXME: Check checksum --RR */ - if ((rt = route_reverse(oldskb, hook)) == NULL) + if ((rt = route_reverse(oldskb, oth, hook)) == NULL) return; hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); @@ -209,7 +210,7 @@ static void send_reset(struct sk_buff *oldskb, int hook) if (nskb->len > dst_pmtu(nskb->dst)) goto free_nskb; - connection_attach(nskb, oldskb); + nf_ct_attach(nskb, oldskb); NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev, ip_finish_output); @@ -222,7 +223,6 @@ static void send_reset(struct sk_buff *oldskb, int hook) static void send_unreach(struct sk_buff *skb_in, int code) { struct iphdr *iph; - struct udphdr *udph; struct icmphdr *icmph; struct sk_buff *nskb; u32 saddr; @@ -256,26 +256,13 @@ static void send_unreach(struct sk_buff *skb_in, int code) if (skb_in->len < skb_in->nh.iph->ihl*4 + 8) return; - /* if UDP checksum is set, verify it's correct */ - if (iph->protocol == IPPROTO_UDP - && skb_in->tail-(u8*)iph >= sizeof(struct udphdr)) { - int datalen = skb_in->len - (iph->ihl<<2); - udph = (struct udphdr *)((char *)iph + (iph->ihl<<2)); - if (udph->check - && csum_tcpudp_magic(iph->saddr, iph->daddr, - datalen, IPPROTO_UDP, - csum_partial((char *)udph, datalen, - 0)) != 0) - return; - } - /* If we send an ICMP error to an ICMP error a mess would result.. */ - if (iph->protocol == IPPROTO_ICMP - && skb_in->tail-(u8*)iph >= sizeof(struct icmphdr)) { - icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2)); + if (iph->protocol == IPPROTO_ICMP) { + struct icmphdr ihdr; - if (skb_copy_bits(skb_in, skb_in->nh.iph->ihl*4, - icmph, sizeof(*icmph)) < 0) + icmph = skb_header_pointer(skb_in, skb_in->nh.iph->ihl*4, + sizeof(ihdr), &ihdr); + if (!icmph) return; /* Between echo-reply (0) and timestamp (13), @@ -296,10 +283,23 @@ 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) } } }; + 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 + } + } + }; + if (ip_route_output_key(&rt, &fl)) return; } @@ -360,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)); - connection_attach(nskb, skb_in); + nf_ct_attach(nskb, skb_in); NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev, ip_finish_output);