lkml.org 
[lkml]   [2003]   [Jul]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[PATCH 2.6] re-sync ipt_REJECT with 2.4.x
Hi Dave!

While merging the recent 2.4. patches into 2.6, I have detected that
2.6 ipt_MIRROR has become way out of sync.

The patch below brings ipt_REJECT 2.6.0-test1 in sync with the 2.4.21
version. You will receive the merge of the ipt_REJECt rp_filter fix as
an incrmental patch to this re-sync.

--- linux-2.6.0-test1/net/ipv4/netfilter/ipt_REJECT.c 2003-07-19 12:35:52.000000000 +0200
+++ linux-2.6.0-test1-nftest/net/ipv4/netfilter/ipt_REJECT.c 2003-07-19 14:14:23.000000000 +0200
@@ -36,133 +36,148 @@
}

/* Send RST reply */
-static unsigned int send_reset(struct sk_buff **pskb, int local)
+static void send_reset(struct sk_buff *oldskb, int local)
{
- struct tcphdr tcph;
+ struct sk_buff *nskb;
+ struct tcphdr *otcph, *tcph;
struct rtable *rt;
+ unsigned int otcplen;
u_int16_t tmp_port;
u_int32_t tmp_addr;
- int needs_ack, hh_len, datalen;
- struct nf_ct_info *oldnfct;
+ int needs_ack;
+ int hh_len;

- /* No RSTs for fragments. */
- if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET))
- return NF_DROP;
+ /* IP header checks: fragment, too short. */
+ if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)
+ || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr))
+ return;

- if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4,
- &tcph, sizeof(tcph)) < 0)
- return NF_DROP;
+ otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl);
+ otcplen = oldskb->len - oldskb->nh.iph->ihl*4;
+
+ if (skb_copy_bits(oldskb, oldskb->nh.iph->ihl*4,
+ otcph, sizeof(*otcph)) < 0)
+ return;

/* No RST for RST. */
- if (tcph.rst)
- return NF_DROP;
+ if (otcph->rst)
+ return;
+
+ /* Check checksum. */
+ if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr,
+ oldskb->nh.iph->daddr,
+ csum_partial((char *)otcph, otcplen, 0)) != 0)
+ return;

- /* FIXME: Check checksum. */
{
struct flowi fl = { .nl_u = { .ip4_u =
- { .daddr = (*pskb)->nh.iph->saddr,
+ { .daddr = oldskb->nh.iph->saddr,
.saddr = (local ?
- (*pskb)->nh.iph->daddr :
+ oldskb->nh.iph->daddr :
0),
- .tos = RT_TOS((*pskb)->nh.iph->tos) } } };
-
- /* Routing: if not headed for us, route won't like source */
- if (ip_route_output_key(&rt, &fl))
- return NF_DROP;
+ .tos = RT_TOS(oldskb->nh.iph->tos) } } };

- hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
- }
+ /* Routing: if not headed for us, route won't like source */
+ if (ip_route_output_key(&rt, &fl))
+ return;
+ }
+ hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;

- /* We're going to flip the header around, drop options and data. */
- if (!skb_ip_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(tcph))) {
- ip_rt_put(rt);
- return NF_DROP;
+ /* Copy skb (even if skb is about to be dropped, we can't just
+ clone it because there may be other things, such as tcpdump,
+ interested in it). We also need to expand headroom in case
+ hh_len of incoming interface < hh_len of outgoing interface */
+ nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb),
+ GFP_ATOMIC);
+ if (!nskb) {
+ dst_release(&rt->u.dst);
+ return;
}

- (*pskb)->h.th = (void *)(*pskb)->nh.iph + sizeof(tcph);
- datalen = (*pskb)->len - (*pskb)->nh.iph->ihl*4 - tcph.doff*4;
-
- /* Change over route. */
- dst_release((*pskb)->dst);
- (*pskb)->dst = &rt->u.dst;
+ dst_release(nskb->dst);
+ nskb->dst = &rt->u.dst;

/* This packet will not be the same as the other: clear nf fields */
- (*pskb)->nfcache = 0;
+ nf_conntrack_put(nskb->nfct);
+ nskb->nfct = NULL;
+ nskb->nfcache = 0;
#ifdef CONFIG_NETFILTER_DEBUG
- (*pskb)->nf_debug = 0;
+ nskb->nf_debug = 0;
#endif
- (*pskb)->nfmark = 0;
+ nskb->nfmark = 0;
+
+ tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);

/* Swap source and dest */
- tmp_addr = (*pskb)->nh.iph->saddr;
- (*pskb)->nh.iph->saddr = (*pskb)->nh.iph->daddr;
- (*pskb)->nh.iph->daddr = tmp_addr;
- tmp_port = (*pskb)->h.th->source;
- (*pskb)->h.th->source = (*pskb)->h.th->dest;
- (*pskb)->h.th->dest = tmp_port;
+ tmp_addr = nskb->nh.iph->saddr;
+ nskb->nh.iph->saddr = nskb->nh.iph->daddr;
+ nskb->nh.iph->daddr = tmp_addr;
+ tmp_port = tcph->source;
+ tcph->source = tcph->dest;
+ tcph->dest = tmp_port;

/* Truncate to length (no data) */
- (*pskb)->h.th->doff = sizeof(struct tcphdr)/4;
- skb_trim(*pskb, (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr));
- (*pskb)->nh.iph->tot_len = htons((*pskb)->len);
+ tcph->doff = sizeof(struct tcphdr)/4;
+ skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
+ nskb->nh.iph->tot_len = htons(nskb->len);

- if ((*pskb)->h.th->ack) {
+ if (tcph->ack) {
needs_ack = 0;
- (*pskb)->h.th->seq = tcph.ack_seq;
- (*pskb)->h.th->ack_seq = 0;
+ tcph->seq = otcph->ack_seq;
+ tcph->ack_seq = 0;
} else {
needs_ack = 1;
- (*pskb)->h.th->ack_seq = htonl(ntohl(tcph.seq)
- + tcph.syn + tcph.fin
- + datalen);
- (*pskb)->h.th->seq = 0;
+ tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin
+ + otcplen - (otcph->doff<<2));
+ tcph->seq = 0;
}

/* Reset flags */
- memset((*pskb)->h.raw + 13, 0, 1);
- (*pskb)->h.th->rst = 1;
- (*pskb)->h.th->ack = needs_ack;
+ ((u_int8_t *)tcph)[13] = 0;
+ tcph->rst = 1;
+ tcph->ack = needs_ack;

- (*pskb)->h.th->window = 0;
- (*pskb)->h.th->urg_ptr = 0;
+ tcph->window = 0;
+ tcph->urg_ptr = 0;

/* Adjust TCP checksum */
- (*pskb)->h.th->check = 0;
- (*pskb)->h.th->check
- = tcp_v4_check((*pskb)->h.th,
- sizeof(struct tcphdr),
- (*pskb)->nh.iph->saddr,
- (*pskb)->nh.iph->daddr,
- csum_partial((*pskb)->h.raw,
- sizeof(struct tcphdr), 0));
+ 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 */
- (*pskb)->nh.iph->ttl = MAXTTL;
+ nskb->nh.iph->ttl = MAXTTL;
/* Set DF, id = 0 */
- (*pskb)->nh.iph->frag_off = htons(IP_DF);
- (*pskb)->nh.iph->id = 0;
+ nskb->nh.iph->frag_off = htons(IP_DF);
+ nskb->nh.iph->id = 0;

/* Adjust IP checksum */
- (*pskb)->nh.iph->check = 0;
- (*pskb)->nh.iph->check = ip_fast_csum((*pskb)->nh.raw,
- (*pskb)->nh.iph->ihl);
+ nskb->nh.iph->check = 0;
+ nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph,
+ nskb->nh.iph->ihl);

/* "Never happens" */
- if ((*pskb)->len > dst_pmtu((*pskb)->dst))
- return NF_DROP;
+ if (nskb->len > dst_pmtu(nskb->dst))
+ goto free_nskb;

- /* Related to old connection. */
- oldnfct = (*pskb)->nfct;
- connection_attach(*pskb, oldnfct);
- nf_conntrack_put(oldnfct);
+ connection_attach(nskb, oldskb->nfct);

- NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, *pskb, NULL, (*pskb)->dst->dev,
+ NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
ip_finish_output);
- return NF_STOLEN;
+ return;
+
+ free_nskb:
+ kfree_skb(nskb);
}

-static void send_unreach(const struct sk_buff *skb_in, int code)
+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;
u8 tos;
@@ -177,6 +192,8 @@
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;
@@ -186,38 +203,52 @@
return;

/* Only reply to fragment 0. */
- if (skb_in->nh.iph->frag_off&htons(IP_OFFSET))
+ 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 (skb_in->nh.iph->protocol == IPPROTO_ICMP) {
- struct icmphdr icmph;
+ 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)
+ 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)
+ if ((icmph->type < ICMP_TIMESTAMP
+ && icmph->type != ICMP_ECHOREPLY
+ && icmph->type != ICMP_ECHO)
+ || icmph->type > NR_ICMP_TYPES)
return;
}

- saddr = skb_in->nh.iph->daddr;
+ saddr = iph->daddr;
if (!(rt->rt_flags & RTCF_LOCAL))
saddr = 0;

- tos = (skb_in->nh.iph->tos & IPTOS_TOS_MASK)
- | IPTOS_PREC_INTERNETCONTROL;
+ tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL;
+
{
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = skb_in->nh.iph->saddr,
@@ -247,38 +278,41 @@
skb_reserve(nskb, hh_len);

/* Set up IP header */
- nskb->nh.iph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
- nskb->nh.iph->version=4;
- nskb->nh.iph->ihl=5;
- nskb->nh.iph->tos=tos;
- nskb->nh.iph->tot_len = htons(length);
+ 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. */
- nskb->nh.iph->frag_off = 0;
+ iph->frag_off = 0;

- nskb->nh.iph->ttl = MAXTTL;
- ip_select_ident(nskb->nh.iph, &rt->u.dst, NULL);
- nskb->nh.iph->protocol=IPPROTO_ICMP;
- nskb->nh.iph->saddr=rt->rt_src;
- nskb->nh.iph->daddr=rt->rt_dst;
- nskb->nh.iph->check=0;
- nskb->nh.iph->check = ip_fast_csum(nskb->nh.raw,
- nskb->nh.iph->ihl);
+ 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. */
- nskb->h.icmph = (struct icmphdr *)skb_put(nskb,sizeof(struct icmphdr));
- nskb->h.icmph->type = ICMP_DEST_UNREACH;
- nskb->h.icmph->code = code;
- nskb->h.icmph->un.gateway = 0;
- nskb->h.icmph->checksum = 0;
+ 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));
- nskb->h.icmph->checksum = ip_compute_csum(nskb->h.raw,
- length-sizeof(struct iphdr));
+
+ icmph->checksum = ip_compute_csum((unsigned char *)icmph,
+ length - sizeof(struct iphdr));

connection_attach(nskb, skb_in->nfct);

@@ -323,7 +357,7 @@
send_unreach(*pskb, ICMP_HOST_ANO);
break;
case IPT_TCP_RESET:
- return send_reset(pskb, hooknum == NF_IP_LOCAL_IN);
+ send_reset(*pskb, hooknum == NF_IP_LOCAL_IN);
case IPT_ICMP_ECHOREPLY:
/* Doesn't happen. */
break;
--
- Harald Welte <laforge@netfilter.org> http://www.netfilter.org/
============================================================================
"Fragmentation is like classful addressing -- an interesting early
architectural error that shows how much experimentation was going
on while IP was being designed." -- Paul Vixie[unhandled content-type:application/pgp-signature]
\
 
 \ /
  Last update: 2005-03-22 13:47    [W:0.034 / U:0.548 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site