| diff -urN -X /tmp/fileVB9oIz --minimal tmp/include/linux/netfilter_ipv4/ipt_REJECT.h working-2.4.0-test3-9/include/linux/netfilter_ipv4/ipt_REJECT.h |
| --- tmp/include/linux/netfilter_ipv4/ipt_REJECT.h Tue Mar 28 04:35:56 2000 |
| +++ working-2.4.0-test3-9/include/linux/netfilter_ipv4/ipt_REJECT.h Tue Jul 11 17:36:54 2000 |
| @@ -6,7 +6,10 @@ |
| IPT_ICMP_HOST_UNREACHABLE, |
| IPT_ICMP_PROT_UNREACHABLE, |
| IPT_ICMP_PORT_UNREACHABLE, |
| - IPT_ICMP_ECHOREPLY |
| + IPT_ICMP_ECHOREPLY, |
| + IPT_ICMP_NET_PROHIBITED, |
| + IPT_ICMP_HOST_PROHIBITED, |
| + IPT_TCP_RESET |
| }; |
| |
| struct ipt_reject_info { |
| diff -urN -X /tmp/fileVB9oIz --minimal tmp/net/core/netfilter.c working-2.4.0-test3-9/net/core/netfilter.c |
| --- tmp/net/core/netfilter.c Fri Apr 14 10:19:57 2000 |
| +++ working-2.4.0-test3-9/net/core/netfilter.c Wed Jul 12 12:18:42 2000 |
| @@ -261,11 +261,11 @@ |
| if (skb->nf_debug != ((1 << NF_IP_PRE_ROUTING) |
| | (1 << NF_IP_FORWARD) |
| | (1 << NF_IP_POST_ROUTING))) { |
| - /* Fragments will have no owners, but still |
| - may be local */ |
| - if (!(skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) |
| - || skb->nf_debug != ((1 << NF_IP_LOCAL_OUT) |
| - | (1 << NF_IP_POST_ROUTING))){ |
| + /* Fragments, entunnelled packets, TCP RSTs |
| + generated by ipt_REJECT will have no |
| + owners, but still may be local */ |
| + if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT) |
| + | (1 << NF_IP_POST_ROUTING))){ |
| printk("ip_finish_output:" |
| " bad unowned skb = %p: ",skb); |
| debug_print_hooks_ip(skb->nf_debug); |
| diff -urN -X /tmp/fileVB9oIz --minimal tmp/net/ipv4/netfilter/ip_conntrack_core.c working-2.4.0-test3-9/net/ipv4/netfilter/ip_conntrack_core.c |
| --- tmp/net/ipv4/netfilter/ip_conntrack_core.c Tue Jul 11 12:08:17 2000 |
| +++ working-2.4.0-test3-9/net/ipv4/netfilter/ip_conntrack_core.c Tue Jul 11 17:12:08 2000 |
| @@ -551,6 +551,7 @@ |
| resolve_normal_ct(struct sk_buff *skb, |
| struct ip_conntrack_protocol *proto, |
| int *set_reply, |
| + unsigned int hooknum, |
| enum ip_conntrack_info *ctinfo) |
| { |
| struct ip_conntrack_tuple tuple; |
| @@ -573,6 +574,21 @@ |
| if (DIRECTION(h) == IP_CT_DIR_REPLY) { |
| /* Reply on unconfirmed connection => unclassifiable */ |
| if (!(h->ctrack->status & IPS_CONFIRMED)) { |
| + /* Exception: local TCP RSTs (generated by |
| + REJECT target). */ |
| + if (hooknum == NF_IP_LOCAL_OUT |
| + && h->tuple.dst.protonum == IPPROTO_TCP) { |
| + const struct tcphdr *tcph |
| + = (const struct tcphdr *) |
| + ((u_int32_t *)skb->nh.iph |
| + + skb->nh.iph->ihl); |
| + if (tcph->rst) { |
| + *ctinfo = IP_CT_ESTABLISHED |
| + + IP_CT_IS_REPLY; |
| + *set_reply = 0; |
| + goto set_skb; |
| + } |
| + } |
| DEBUGP("Reply on unconfirmed connection\n"); |
| ip_conntrack_put(h->ctrack); |
| return NULL; |
| @@ -598,6 +614,7 @@ |
| } |
| *set_reply = 0; |
| } |
| + set_skb: |
| skb->nfct = &h->ctrack->infos[*ctinfo]; |
| return h->ctrack; |
| } |
| @@ -669,7 +686,7 @@ |
| && icmp_error_track(*pskb, &ctinfo, hooknum)) |
| return NF_ACCEPT; |
| |
| - if (!(ct = resolve_normal_ct(*pskb, proto, &set_reply, &ctinfo))) |
| + if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo))) |
| /* Not valid part of a connection */ |
| return NF_ACCEPT; |
| |
| diff -urN -X /tmp/fileVB9oIz --minimal tmp/net/ipv4/netfilter/ip_conntrack_standalone.c working-2.4.0-test3-9/net/ipv4/netfilter/ip_conntrack_standalone.c |
| --- tmp/net/ipv4/netfilter/ip_conntrack_standalone.c Fri Apr 28 08:43:15 2000 |
| +++ working-2.4.0-test3-9/net/ipv4/netfilter/ip_conntrack_standalone.c Tue Jul 11 17:12:08 2000 |
| @@ -169,11 +169,15 @@ |
| const struct net_device *out, |
| int (*okfn)(struct sk_buff *)) |
| { |
| - /* We've seen it coming out the other side: confirm */ |
| + /* We've seen it coming out the other side: confirm (only if |
| + new packet: REJECT can generate TCP RESET response, or ICMP |
| + errors) */ |
| if ((*pskb)->nfct) { |
| struct ip_conntrack *ct |
| = (struct ip_conntrack *)(*pskb)->nfct->master; |
| - if (!(ct->status & IPS_CONFIRMED)) |
| + /* ctinfo is the index of the nfct inside the conntrack */ |
| + if ((*pskb)->nfct - ct->infos == IP_CT_NEW |
| + && !(ct->status & IPS_CONFIRMED)) |
| ip_conntrack_confirm(ct); |
| } |
| return NF_ACCEPT; |
| @@ -191,7 +195,8 @@ |
| if ((*pskb)->nfct) { |
| struct ip_conntrack *ct |
| = (struct ip_conntrack *)(*pskb)->nfct->master; |
| - if (!(ct->status & IPS_CONFIRMED)) |
| + if ((*pskb)->nfct - ct->infos == IP_CT_NEW |
| + && !(ct->status & IPS_CONFIRMED)) |
| ip_conntrack_confirm(ct); |
| } |
| |
| diff -urN -X /tmp/fileVB9oIz --minimal tmp/net/ipv4/netfilter/ip_fw_compat.c working-2.4.0-test3-9/net/ipv4/netfilter/ip_fw_compat.c |
| --- tmp/net/ipv4/netfilter/ip_fw_compat.c Tue Jul 11 12:08:17 2000 |
| +++ working-2.4.0-test3-9/net/ipv4/netfilter/ip_fw_compat.c Tue Jul 11 17:12:08 2000 |
| @@ -71,7 +71,8 @@ |
| struct ip_conntrack *ct |
| = (struct ip_conntrack *)skb->nfct->master; |
| |
| - if (!(ct->status & IPS_CONFIRMED)) |
| + if (skb->nfct - ct->infos == IP_CT_NEW |
| + && !(ct->status & IPS_CONFIRMED)) |
| ip_conntrack_confirm(ct); |
| } |
| } |
| diff -urN -X /tmp/fileVB9oIz --minimal tmp/net/ipv4/netfilter/ipt_REJECT.c working-2.4.0-test3-9/net/ipv4/netfilter/ipt_REJECT.c |
| --- tmp/net/ipv4/netfilter/ipt_REJECT.c Tue Jun 27 14:52:47 2000 |
| +++ working-2.4.0-test3-9/net/ipv4/netfilter/ipt_REJECT.c Wed Jul 12 17:46:26 2000 |
| @@ -7,6 +7,7 @@ |
| #include <linux/ip.h> |
| #include <net/icmp.h> |
| #include <net/ip.h> |
| +#include <net/tcp.h> |
| struct in_device; |
| #include <net/route.h> |
| #include <linux/netfilter_ipv4/ip_tables.h> |
| @@ -18,6 +19,113 @@ |
| #define DEBUGP(format, args...) |
| #endif |
| |
| +/* Send RST reply */ |
| +static void send_reset(struct sk_buff *oldskb) |
| +{ |
| + struct sk_buff *nskb; |
| + struct tcphdr *tcph; |
| + struct rtable *rt; |
| + unsigned int tcplen; |
| + int needs_ack; |
| + |
| + /* Clone skb (skb is about to be dropped, so we don't care) */ |
| + nskb = skb_clone(oldskb, GFP_ATOMIC); |
| + if (!nskb) |
| + return; |
| + |
| + /* This packet will not be the same as the other: clear nf fields */ |
| + nf_conntrack_put(nskb->nfct); |
| + nskb->nfct = NULL; |
| + nskb->nfcache = 0; |
| +#ifdef CONFIG_NETFILTER_DEBUG |
| + nskb->nf_debug = 0; |
| +#endif |
| + |
| + /* IP header checks: fragment, too short. */ |
| + if (nskb->nh.iph->frag_off & htons(IP_OFFSET) |
| + || nskb->len < (nskb->nh.iph->ihl<<2) + sizeof(struct tcphdr)) |
| + goto free_nskb; |
| + |
| + tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); |
| + tcplen = nskb->len - nskb->nh.iph->ihl*4; |
| + |
| + /* Check checksum. */ |
| + if (tcp_v4_check(tcph, tcplen, nskb->nh.iph->saddr, |
| + nskb->nh.iph->daddr, |
| + csum_partial((char *)tcph, tcplen, 0)) != 0) |
| + goto free_nskb; |
| + |
| + /* No RST for RST. */ |
| + if (tcph->rst) |
| + goto free_nskb; |
| + |
| + nskb->nh.iph->daddr = xchg(&nskb->nh.iph->saddr, nskb->nh.iph->daddr); |
| + tcph->source = xchg(&tcph->dest, tcph->source); |
| + |
| + /* Truncate to length (no data) */ |
| + tcph->doff = sizeof(struct tcphdr)/4; |
| + skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr)); |
| + |
| + if (tcph->ack) { |
| + needs_ack = 0; |
| + tcph->seq = tcph->ack_seq; |
| + tcph->ack_seq = 0; |
| + } else { |
| + needs_ack = 1; |
| + tcph->seq = 0; |
| + tcph->ack_seq = htonl(ntohl(tcph->seq) + tcph->syn + tcph->fin |
| + + tcplen - (tcph->doff<<2)); |
| + } |
| + |
| + /* Reset flags */ |
| + ((u_int8_t *)tcph)[13] = 0; |
| + tcph->rst = 1; |
| + if (needs_ack) |
| + tcph->ack = 1; |
| + |
| + tcph->window = 0; |
| + tcph->urg_ptr = 0; |
| + |
| + /* Adjust TCP checksum */ |
| + tcph->check = 0; |
| + tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), |
| + nskb->nh.iph->saddr, |
| + nskb->nh.iph->daddr, |
| + csum_partial((char *)tcph, |
| + sizeof(struct tcphdr), 0)); |
| + |
| + /* Adjust IP TTL, DF */ |
| + nskb->nh.iph->ttl = MAXTTL; |
| + /* Set DF, id = 0 */ |
| + nskb->nh.iph->frag_off = htons(IP_DF); |
| + nskb->nh.iph->id = 0; |
| + |
| + /* Adjust IP checksum */ |
| + nskb->nh.iph->check = 0; |
| + nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, |
| + nskb->nh.iph->ihl); |
| + |
| + /* Routing */ |
| + if (ip_route_output(&rt, nskb->nh.iph->daddr, nskb->nh.iph->saddr, |
| + RT_TOS(nskb->nh.iph->tos) | RTO_CONN, |
| + 0) != 0) |
| + goto free_nskb; |
| + |
| + dst_release(nskb->dst); |
| + nskb->dst = &rt->u.dst; |
| + |
| + /* "Never happens" */ |
| + if (nskb->len > nskb->dst->pmtu) |
| + goto free_nskb; |
| + |
| + NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev, |
| + ip_finish_output); |
| + return; |
| + |
| + free_nskb: |
| + kfree_skb(nskb); |
| +} |
| + |
| static unsigned int reject(struct sk_buff **pskb, |
| unsigned int hooknum, |
| const struct net_device *in, |
| @@ -43,6 +151,12 @@ |
| case IPT_ICMP_PORT_UNREACHABLE: |
| icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); |
| break; |
| + case IPT_ICMP_NET_PROHIBITED: |
| + icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0); |
| + break; |
| + case IPT_ICMP_HOST_PROHIBITED: |
| + icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0); |
| + break; |
| case IPT_ICMP_ECHOREPLY: { |
| struct icmphdr *icmph = (struct icmphdr *) |
| ((u_int32_t *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl); |
| @@ -64,6 +178,9 @@ |
| } |
| } |
| break; |
| + case IPT_TCP_RESET: |
| + send_reset(*pskb); |
| + break; |
| } |
| |
| return NF_DROP; |
| @@ -96,7 +213,7 @@ |
| |
| /* Only allow these for packet filtering. */ |
| if (strcmp(tablename, "filter") != 0) { |
| - DEBUGP("REJECT: bad table `%s'.\n", table); |
| + DEBUGP("REJECT: bad table `%s'.\n", tablename); |
| return 0; |
| } |
| if ((hook_mask & ~((1 << NF_IP_LOCAL_IN) |
| @@ -116,6 +233,18 @@ |
| /* Must contain ICMP match. */ |
| if (IPT_MATCH_ITERATE(e, find_ping_match) == 0) { |
| DEBUGP("REJECT: ECHOREPLY illegal for non-ping\n"); |
| + return 0; |
| + } |
| + } else if (rejinfo->with == IPT_TCP_RESET) { |
| + /* Must specify that it's a TCP packet */ |
| + if (e->ip.proto != IPPROTO_TCP |
| + || (e->ip.invflags & IPT_INV_PROTO)) { |
| + DEBUGP("REJECT: TCP_RESET illegal for non-tcp\n"); |
| + return 0; |
| + } |
| + /* Only for local input. Rest is too dangerous. */ |
| + if ((hook_mask & ~(1 << NF_IP_LOCAL_IN)) != 0) { |
| + DEBUGP("REJECT: TCP_RESET only from INPUT\n"); |
| return 0; |
| } |
| } |