X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fnetfilter%2Fipt_REJECT.c;h=0bba3c2bb786b831ae9c3bb68213181395ea266e;hb=9464c7cf61b9433057924c36e6e02f303a00e768;hp=d0a5e05f86524a160214074062c9a21cea4eb015;hpb=5167311cae6aa3a5ff5afd39f88c32a435c969ef;p=linux-2.6.git diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index d0a5e05f8..0bba3c2bb 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -92,10 +92,7 @@ static inline struct rtable *route_reverse(struct sk_buff *skb, 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; - } + xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0); return rt; } @@ -104,6 +101,7 @@ static inline struct rtable *route_reverse(struct sk_buff *skb, static void send_reset(struct sk_buff *oldskb, int hook) { struct sk_buff *nskb; + struct iphdr *iph = oldskb->nh.iph; struct tcphdr _otcph, *oth, *tcph; struct rtable *rt; u_int16_t tmp_port; @@ -124,7 +122,10 @@ static void send_reset(struct sk_buff *oldskb, int hook) if (oth->rst) return; - /* FIXME: Check checksum --RR */ + /* Check checksum */ + if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP)) + return; + if ((rt = route_reverse(oldskb, oth, hook)) == NULL) return; @@ -145,12 +146,7 @@ static void send_reset(struct sk_buff *oldskb, int hook) /* This packet will not be the same as the other: clear nf fields */ nf_reset(nskb); - nskb->nfcache = 0; nskb->nfmark = 0; -#ifdef CONFIG_BRIDGE_NETFILTER - nf_bridge_put(nskb->nf_bridge); - nskb->nf_bridge = NULL; -#endif tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); @@ -196,7 +192,7 @@ static void send_reset(struct sk_buff *oldskb, int hook) sizeof(struct tcphdr), 0)); /* Adjust IP TTL, DF */ - nskb->nh.iph->ttl = MAXTTL; + nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT); /* Set DF, id = 0 */ nskb->nh.iph->frag_off = htons(IP_DF); nskb->nh.iph->id = 0; @@ -207,183 +203,29 @@ static void send_reset(struct sk_buff *oldskb, int hook) nskb->nh.iph->ihl); /* "Never happens" */ - if (nskb->len > dst_pmtu(nskb->dst)) + if (nskb->len > dst_mtu(nskb->dst)) goto free_nskb; nf_ct_attach(nskb, oldskb); NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev, - ip_finish_output); + dst_output); return; free_nskb: kfree_skb(nskb); } -static void send_unreach(struct sk_buff *skb_in, int code) +static inline 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; - u8 tos; - int hh_len, length; - struct rtable *rt = (struct rtable*)skb_in->dst; - unsigned char *data; - - if (!rt) - return; - - /* FIXME: Use sysctl number. --RR */ - if (!xrlim_allow(&rt->u.dst, 1*HZ)) - return; - - iph = skb_in->nh.iph; - - /* No replies to physical multicast/broadcast */ - if (skb_in->pkt_type!=PACKET_HOST) - return; - - /* Now check at the protocol level */ - if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST)) - return; - - /* Only reply to fragment 0. */ - if (iph->frag_off&htons(IP_OFFSET)) - return; - - /* Ensure we have at least 8 bytes of proto header. */ - 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 (skb_copy_bits(skb_in, skb_in->nh.iph->ihl*4, - icmph, sizeof(*icmph)) < 0) - return; - - /* Between echo-reply (0) and timestamp (13), - everything except echo-request (8) is an error. - Also, anything greater than NR_ICMP_TYPES is - unknown, and hence should be treated as an error... */ - if ((icmph->type < ICMP_TIMESTAMP - && icmph->type != ICMP_ECHOREPLY - && icmph->type != ICMP_ECHO) - || icmph->type > NR_ICMP_TYPES) - return; - } - - saddr = iph->daddr; - if (!(rt->rt_flags & RTCF_LOCAL)) - saddr = 0; - - 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 - } - } - }; - - if (ip_route_output_key(&rt, &fl)) - return; - } - /* RFC says return as much as we can without exceeding 576 bytes. */ - length = skb_in->len + sizeof(struct iphdr) + sizeof(struct icmphdr); - - if (length > dst_pmtu(&rt->u.dst)) - length = dst_pmtu(&rt->u.dst); - if (length > 576) - length = 576; - - hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); - - nskb = alloc_skb(hh_len + length, GFP_ATOMIC); - if (!nskb) { - ip_rt_put(rt); - return; - } - - nskb->priority = 0; - nskb->dst = &rt->u.dst; - skb_reserve(nskb, hh_len); - - /* Set up IP header */ - iph = nskb->nh.iph - = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); - iph->version=4; - iph->ihl=5; - iph->tos=tos; - iph->tot_len = htons(length); - - /* PMTU discovery never applies to ICMP packets. */ - iph->frag_off = 0; - - iph->ttl = MAXTTL; - ip_select_ident(iph, &rt->u.dst, NULL); - iph->protocol=IPPROTO_ICMP; - iph->saddr=rt->rt_src; - iph->daddr=rt->rt_dst; - iph->check=0; - iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); - - /* Set up ICMP header. */ - icmph = nskb->h.icmph - = (struct icmphdr *)skb_put(nskb, sizeof(struct icmphdr)); - icmph->type = ICMP_DEST_UNREACH; - icmph->code = code; - icmph->un.gateway = 0; - icmph->checksum = 0; - - /* Copy as much of original packet as will fit */ - data = skb_put(nskb, - length - sizeof(struct iphdr) - sizeof(struct icmphdr)); - - skb_copy_bits(skb_in, 0, data, - length - sizeof(struct iphdr) - sizeof(struct icmphdr)); - - icmph->checksum = ip_compute_csum((unsigned char *)icmph, - length - sizeof(struct iphdr)); - - nf_ct_attach(nskb, skb_in); - - NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev, - ip_finish_output); + icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0); } static unsigned int reject(struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, unsigned int hooknum, + const struct xt_target *target, const void *targinfo, void *userinfo) { @@ -430,29 +272,14 @@ static unsigned int reject(struct sk_buff **pskb, } static int check(const char *tablename, - const struct ipt_entry *e, + const void *e_void, + const struct xt_target *target, void *targinfo, unsigned int targinfosize, unsigned int hook_mask) { const struct ipt_reject_info *rejinfo = targinfo; - - if (targinfosize != IPT_ALIGN(sizeof(struct ipt_reject_info))) { - DEBUGP("REJECT: targinfosize %u != 0\n", targinfosize); - return 0; - } - - /* Only allow these for packet filtering. */ - if (strcmp(tablename, "filter") != 0) { - DEBUGP("REJECT: bad table `%s'.\n", tablename); - return 0; - } - if ((hook_mask & ~((1 << NF_IP_LOCAL_IN) - | (1 << NF_IP_FORWARD) - | (1 << NF_IP_LOCAL_OUT))) != 0) { - DEBUGP("REJECT: bad hook mask %X\n", hook_mask); - return 0; - } + const struct ipt_entry *e = e_void; if (rejinfo->with == IPT_ICMP_ECHOREPLY) { printk("REJECT: ECHOREPLY no longer supported.\n"); @@ -465,26 +292,29 @@ static int check(const char *tablename, return 0; } } - return 1; } static struct ipt_target ipt_reject_reg = { .name = "REJECT", .target = reject, + .targetsize = sizeof(struct ipt_reject_info), + .table = "filter", + .hooks = (1 << NF_IP_LOCAL_IN) | (1 << NF_IP_FORWARD) | + (1 << NF_IP_LOCAL_OUT), .checkentry = check, .me = THIS_MODULE, }; -static int __init init(void) +static int __init ipt_reject_init(void) { return ipt_register_target(&ipt_reject_reg); } -static void __exit fini(void) +static void __exit ipt_reject_fini(void) { ipt_unregister_target(&ipt_reject_reg); } -module_init(init); -module_exit(fini); +module_init(ipt_reject_init); +module_exit(ipt_reject_fini);