linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 2.6] re-sync ipt_REJECT with 2.4.x
@ 2003-07-25 20:52 Harald Welte
  0 siblings, 0 replies; only message in thread
From: Harald Welte @ 2003-07-25 20:52 UTC (permalink / raw)
  To: David Miller; +Cc: Netfilter Development Mailinglist, Linux Kernel Mailinglist

[-- Attachment #1: Type: text/plain, Size: 12494 bytes --]

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

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2003-07-25 21:20 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-07-25 20:52 [PATCH 2.6] re-sync ipt_REJECT with 2.4.x Harald Welte

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).