netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 2.6.13rc3] IPv6: Check interface bindings on IPv6 raw socket reception
@ 2005-07-23 18:04 Andrew McDonald
  2005-07-24  0:24 ` Patrick McHardy
  2005-07-27 21:38 ` David S. Miller
  0 siblings, 2 replies; 5+ messages in thread
From: Andrew McDonald @ 2005-07-23 18:04 UTC (permalink / raw)
  To: netdev; +Cc: yoshfuji, davem, linux-kernel

Take account of whether a socket is bound to a particular device when
selecting an IPv6 raw socket to receive a packet. Also perform this
check when receiving IPv6 packets with router alert options.

Signed-off-by: Andrew McDonald <andrew@mcdonald.org.uk>

diff -uprN linux-2.6.13-rc3.orig/include/net/rawv6.h linux-2.6.13-rc3/include/net/rawv6.h
--- linux-2.6.13-rc3.orig/include/net/rawv6.h	2004-10-18 22:53:52.000000000 +0100
+++ linux-2.6.13-rc3/include/net/rawv6.h	2005-07-23 13:18:46.000000000 +0100
@@ -10,7 +10,8 @@ extern rwlock_t raw_v6_lock;
 extern void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr);
 
 extern struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,
-				    struct in6_addr *loc_addr, struct in6_addr *rmt_addr);
+				    struct in6_addr *loc_addr, struct in6_addr *rmt_addr,
+				    int dif);
 
 extern int			rawv6_rcv(struct sock *sk,
 					  struct sk_buff *skb);
diff -uprN linux-2.6.13-rc3.orig/net/ipv6/icmp.c linux-2.6.13-rc3/net/ipv6/icmp.c
--- linux-2.6.13-rc3.orig/net/ipv6/icmp.c	2005-07-23 10:28:47.000000000 +0100
+++ linux-2.6.13-rc3/net/ipv6/icmp.c	2005-07-23 13:23:03.000000000 +0100
@@ -551,7 +551,8 @@ static void icmpv6_notify(struct sk_buff
 
 	read_lock(&raw_v6_lock);
 	if ((sk = sk_head(&raw_v6_htable[hash])) != NULL) {
-		while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr))) {
+		while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr,
+					    skb->dev->ifindex))) {
 			rawv6_err(sk, skb, NULL, type, code, inner_offset, info);
 			sk = sk_next(sk);
 		}
diff -uprN linux-2.6.13-rc3.orig/net/ipv6/ip6_output.c linux-2.6.13-rc3/net/ipv6/ip6_output.c
--- linux-2.6.13-rc3.orig/net/ipv6/ip6_output.c	2005-07-23 10:29:40.000000000 +0100
+++ linux-2.6.13-rc3/net/ipv6/ip6_output.c	2005-07-23 12:37:34.000000000 +0100
@@ -321,7 +321,9 @@ static int ip6_call_ra_chain(struct sk_b
 	read_lock(&ip6_ra_lock);
 	for (ra = ip6_ra_chain; ra; ra = ra->next) {
 		struct sock *sk = ra->sk;
-		if (sk && ra->sel == sel) {
+		if (sk && ra->sel == sel &&
+		    (!sk->sk_bound_dev_if ||
+		     sk->sk_bound_dev_if == skb->dev->ifindex)) {
 			if (last) {
 				struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
 				if (skb2)
diff -uprN linux-2.6.13-rc3.orig/net/ipv6/raw.c linux-2.6.13-rc3/net/ipv6/raw.c
--- linux-2.6.13-rc3.orig/net/ipv6/raw.c	2005-07-23 10:29:40.000000000 +0100
+++ linux-2.6.13-rc3/net/ipv6/raw.c	2005-07-23 17:07:58.000000000 +0100
@@ -81,7 +81,8 @@ static void raw_v6_unhash(struct sock *s
 
 /* Grumble... icmp and ip_input want to get at this... */
 struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,
-			     struct in6_addr *loc_addr, struct in6_addr *rmt_addr)
+			     struct in6_addr *loc_addr, struct in6_addr *rmt_addr,
+			     int dif)
 {
 	struct hlist_node *node;
 	int is_multicast = ipv6_addr_is_multicast(loc_addr);
@@ -94,6 +95,9 @@ struct sock *__raw_v6_lookup(struct sock
 			    !ipv6_addr_equal(&np->daddr, rmt_addr))
 				continue;
 
+			if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)
+				continue;
+
 			if (!ipv6_addr_any(&np->rcv_saddr)) {
 				if (ipv6_addr_equal(&np->rcv_saddr, loc_addr))
 					goto found;
@@ -160,7 +164,7 @@ void ipv6_raw_deliver(struct sk_buff *sk
 	if (sk == NULL)
 		goto out;
 
-	sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr);
+	sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, skb->dev->ifindex);
 
 	while (sk) {
 		if (nexthdr != IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) {
@@ -170,7 +174,8 @@ void ipv6_raw_deliver(struct sk_buff *sk
 			if (clone)
 				rawv6_rcv(sk, clone);
 		}
-		sk = __raw_v6_lookup(sk_next(sk), nexthdr, daddr, saddr);
+		sk = __raw_v6_lookup(sk_next(sk), nexthdr, daddr, saddr,
+				     skb->dev->ifindex);
 	}
 out:
 	read_unlock(&raw_v6_lock);

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2.6.13rc3] IPv6: Check interface bindings on IPv6 raw socket reception
  2005-07-23 18:04 [PATCH 2.6.13rc3] IPv6: Check interface bindings on IPv6 raw socket reception Andrew McDonald
@ 2005-07-24  0:24 ` Patrick McHardy
  2005-07-24  5:39   ` Patrick McHardy
  2005-07-27 21:38 ` David S. Miller
  1 sibling, 1 reply; 5+ messages in thread
From: Patrick McHardy @ 2005-07-24  0:24 UTC (permalink / raw)
  To: Andrew McDonald; +Cc: netdev, yoshfuji, davem, linux-kernel

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

Andrew McDonald wrote:
> Take account of whether a socket is bound to a particular device when
> selecting an IPv6 raw socket to receive a packet. Also perform this
> check when receiving IPv6 packets with router alert options.

I guess this one makes sense on top.


[-- Attachment #2: x --]
[-- Type: text/plain, Size: 4505 bytes --]

[IPV4/6]: Check if packet was actually delivered to a raw socket to decide whether to send an ICMP unreachable

Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit 0fc074eed6ad201d76392dcabbc156784570ea64
tree 913c87ad866f4abb23e9788c0170b81b564cfe7a
parent 36245c9aaddbed7e50d9600c8d1889ebee48a90f
author Patrick McHardy <kaber@trash.net> Sun, 24 Jul 2005 02:23:25 +0200
committer Patrick McHardy <kaber@trash.net> Sun, 24 Jul 2005 02:23:25 +0200

 include/net/raw.h    |    2 +-
 include/net/rawv6.h  |    2 +-
 net/ipv4/ip_input.c  |    4 ++--
 net/ipv4/raw.c       |    8 ++++++--
 net/ipv6/ip6_input.c |    4 ++--
 net/ipv6/raw.c       |    8 ++++++--
 6 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/include/net/raw.h b/include/net/raw.h
--- a/include/net/raw.h
+++ b/include/net/raw.h
@@ -37,6 +37,6 @@ extern struct sock *__raw_v4_lookup(stru
 				    unsigned long raddr, unsigned long laddr,
 				    int dif);
 
-extern void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash);
+extern int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash);
 
 #endif	/* _RAW_H */
diff --git a/include/net/rawv6.h b/include/net/rawv6.h
--- a/include/net/rawv6.h
+++ b/include/net/rawv6.h
@@ -7,7 +7,7 @@
 extern struct hlist_head raw_v6_htable[RAWV6_HTABLE_SIZE];
 extern rwlock_t raw_v6_lock;
 
-extern void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr);
+extern int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr);
 
 extern struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,
 				    struct in6_addr *loc_addr, struct in6_addr *rmt_addr,
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -225,8 +225,8 @@ static inline int ip_local_deliver_finis
 		/* If there maybe a raw socket we must check - if not we
 		 * don't care less
 		 */
-		if (raw_sk)
-			raw_v4_input(skb, skb->nh.iph, hash);
+		if (raw_sk && !raw_v4_input(skb, skb->nh.iph, hash))
+			raw_sk = NULL;
 
 		if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) {
 			int ret;
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -150,10 +150,11 @@ static __inline__ int icmp_filter(struct
  * RFC 1122: SHOULD pass TOS value up to the transport layer.
  * -> It does. And not only TOS, but all IP header.
  */
-void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
+int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
 {
 	struct sock *sk;
 	struct hlist_head *head;
+	int delivered = 0;
 
 	read_lock(&raw_v4_lock);
 	head = &raw_v4_htable[hash];
@@ -168,8 +169,10 @@ void raw_v4_input(struct sk_buff *skb, s
 			struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
 
 			/* Not releasing hash table! */
-			if (clone)
+			if (clone) {
 				raw_rcv(sk, clone);
+				delivered = 1;
+			}
 		}
 		sk = __raw_v4_lookup(sk_next(sk), iph->protocol,
 				     iph->saddr, iph->daddr,
@@ -177,6 +180,7 @@ void raw_v4_input(struct sk_buff *skb, s
 	}
 out:
 	read_unlock(&raw_v4_lock);
+	return delivered;
 }
 
 void raw_err (struct sock *sk, struct sk_buff *skb, u32 info)
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -166,8 +166,8 @@ resubmit:
 	nexthdr = skb->nh.raw[nhoff];
 
 	raw_sk = sk_head(&raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)]);
-	if (raw_sk)
-		ipv6_raw_deliver(skb, nexthdr);
+	if (raw_sk && !ipv6_raw_deliver(skb, nexthdr))
+		raw_sk = NULL;
 
 	hash = nexthdr & (MAX_INET_PROTOS - 1);
 	if ((ipprot = rcu_dereference(inet6_protos[hash])) != NULL) {
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -141,11 +141,12 @@ static __inline__ int icmpv6_filter(stru
  *
  *	Caller owns SKB so we must make clones.
  */
-void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
+int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
 {
 	struct in6_addr *saddr;
 	struct in6_addr *daddr;
 	struct sock *sk;
+	int delivered = 0;
 	__u8 hash;
 
 	saddr = &skb->nh.ipv6h->saddr;
@@ -171,14 +172,17 @@ void ipv6_raw_deliver(struct sk_buff *sk
 			struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
 
 			/* Not releasing hash table! */
-			if (clone)
+			if (clone) {
 				rawv6_rcv(sk, clone);
+				delivered = 1;
+			}
 		}
 		sk = __raw_v6_lookup(sk_next(sk), nexthdr, daddr, saddr,
 				     skb->dev->ifindex);
 	}
 out:
 	read_unlock(&raw_v6_lock);
+	return delivered;
 }
 
 /* This cleans up af_inet6 a bit. -DaveM */

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2.6.13rc3] IPv6: Check interface bindings on IPv6 raw socket reception
  2005-07-24  0:24 ` Patrick McHardy
@ 2005-07-24  5:39   ` Patrick McHardy
  2005-07-27 21:38     ` David S. Miller
  0 siblings, 1 reply; 5+ messages in thread
From: Patrick McHardy @ 2005-07-24  5:39 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: Andrew McDonald, netdev, yoshfuji, davem, linux-kernel

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

Patrick McHardy wrote:
> Andrew McDonald wrote:
> 
>> Take account of whether a socket is bound to a particular device when
>> selecting an IPv6 raw socket to receive a packet. Also perform this
>> check when receiving IPv6 packets with router alert options.
> 
> I guess this one makes sense on top.
> 
> [IPV4/6]: Check if packet was actually delivered to a raw socket to decide whether to send an ICMP unreachable

The Last patch didn't handle ICMP socket filters correctly, here is a
better one.

If a raw socket is bound to a single device the packet might not be
delivered even though there is a socket in the protocol hash. Send
back an ICMP protocol unreachable in this case.

[-- Attachment #2: x.diff --]
[-- Type: text/x-patch, Size: 4427 bytes --]

[IPV4/6]: Check if packet was actually delivered to a raw socket to decide whether to send an ICMP unreachable

Signed-off-by: Patrick McHardy <kaber@trash.net>

---
commit eb82d02518ac3a400663163995097749d91c7c4c
tree 1719713411b5e656ab5926ee633c39c0edfb1108
parent 36245c9aaddbed7e50d9600c8d1889ebee48a90f
author Patrick McHardy <kaber@trash.net> Sun, 24 Jul 2005 06:54:32 +0200
committer Patrick McHardy <kaber@trash.net> Sun, 24 Jul 2005 06:54:32 +0200

 include/net/raw.h    |    2 +-
 include/net/rawv6.h  |    2 +-
 net/ipv4/ip_input.c  |    4 ++--
 net/ipv4/raw.c       |    5 ++++-
 net/ipv6/ip6_input.c |    4 ++--
 net/ipv6/raw.c       |    5 ++++-
 6 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/include/net/raw.h b/include/net/raw.h
--- a/include/net/raw.h
+++ b/include/net/raw.h
@@ -37,6 +37,6 @@ extern struct sock *__raw_v4_lookup(stru
 				    unsigned long raddr, unsigned long laddr,
 				    int dif);
 
-extern void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash);
+extern int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash);
 
 #endif	/* _RAW_H */
diff --git a/include/net/rawv6.h b/include/net/rawv6.h
--- a/include/net/rawv6.h
+++ b/include/net/rawv6.h
@@ -7,7 +7,7 @@
 extern struct hlist_head raw_v6_htable[RAWV6_HTABLE_SIZE];
 extern rwlock_t raw_v6_lock;
 
-extern void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr);
+extern int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr);
 
 extern struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num,
 				    struct in6_addr *loc_addr, struct in6_addr *rmt_addr,
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -225,8 +225,8 @@ static inline int ip_local_deliver_finis
 		/* If there maybe a raw socket we must check - if not we
 		 * don't care less
 		 */
-		if (raw_sk)
-			raw_v4_input(skb, skb->nh.iph, hash);
+		if (raw_sk && !raw_v4_input(skb, skb->nh.iph, hash))
+			raw_sk = NULL;
 
 		if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) {
 			int ret;
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -150,10 +150,11 @@ static __inline__ int icmp_filter(struct
  * RFC 1122: SHOULD pass TOS value up to the transport layer.
  * -> It does. And not only TOS, but all IP header.
  */
-void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
+int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
 {
 	struct sock *sk;
 	struct hlist_head *head;
+	int delivered = 0;
 
 	read_lock(&raw_v4_lock);
 	head = &raw_v4_htable[hash];
@@ -164,6 +165,7 @@ void raw_v4_input(struct sk_buff *skb, s
 			     skb->dev->ifindex);
 
 	while (sk) {
+		delivered = 1;
 		if (iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) {
 			struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
 
@@ -177,6 +179,7 @@ void raw_v4_input(struct sk_buff *skb, s
 	}
 out:
 	read_unlock(&raw_v4_lock);
+	return delivered;
 }
 
 void raw_err (struct sock *sk, struct sk_buff *skb, u32 info)
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -166,8 +166,8 @@ resubmit:
 	nexthdr = skb->nh.raw[nhoff];
 
 	raw_sk = sk_head(&raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)]);
-	if (raw_sk)
-		ipv6_raw_deliver(skb, nexthdr);
+	if (raw_sk && !ipv6_raw_deliver(skb, nexthdr))
+		raw_sk = NULL;
 
 	hash = nexthdr & (MAX_INET_PROTOS - 1);
 	if ((ipprot = rcu_dereference(inet6_protos[hash])) != NULL) {
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -141,11 +141,12 @@ static __inline__ int icmpv6_filter(stru
  *
  *	Caller owns SKB so we must make clones.
  */
-void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
+int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
 {
 	struct in6_addr *saddr;
 	struct in6_addr *daddr;
 	struct sock *sk;
+	int delivered = 0;
 	__u8 hash;
 
 	saddr = &skb->nh.ipv6h->saddr;
@@ -167,6 +168,7 @@ void ipv6_raw_deliver(struct sk_buff *sk
 	sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, skb->dev->ifindex);
 
 	while (sk) {
+		delivered = 1;
 		if (nexthdr != IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) {
 			struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
 
@@ -179,6 +181,7 @@ void ipv6_raw_deliver(struct sk_buff *sk
 	}
 out:
 	read_unlock(&raw_v6_lock);
+	return delivered;
 }
 
 /* This cleans up af_inet6 a bit. -DaveM */

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2.6.13rc3] IPv6: Check interface bindings on IPv6 raw socket reception
  2005-07-23 18:04 [PATCH 2.6.13rc3] IPv6: Check interface bindings on IPv6 raw socket reception Andrew McDonald
  2005-07-24  0:24 ` Patrick McHardy
@ 2005-07-27 21:38 ` David S. Miller
  1 sibling, 0 replies; 5+ messages in thread
From: David S. Miller @ 2005-07-27 21:38 UTC (permalink / raw)
  To: andrew; +Cc: netdev, yoshfuji, linux-kernel

From: Andrew McDonald <andrew@mcdonald.org.uk>
Date: Sat, 23 Jul 2005 19:04:43 +0100

> Take account of whether a socket is bound to a particular device when
> selecting an IPv6 raw socket to receive a packet. Also perform this
> check when receiving IPv6 packets with router alert options.
> 
> Signed-off-by: Andrew McDonald <andrew@mcdonald.org.uk>

Applied, thanks Andrew.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2.6.13rc3] IPv6: Check interface bindings on IPv6 raw socket reception
  2005-07-24  5:39   ` Patrick McHardy
@ 2005-07-27 21:38     ` David S. Miller
  0 siblings, 0 replies; 5+ messages in thread
From: David S. Miller @ 2005-07-27 21:38 UTC (permalink / raw)
  To: kaber; +Cc: andrew, netdev, yoshfuji, linux-kernel

From: Patrick McHardy <kaber@trash.net>
Date: Sun, 24 Jul 2005 07:39:12 +0200

> [IPV4/6]: Check if packet was actually delivered to a raw socket to decide whether to send an ICMP unreachable
> 
> Signed-off-by: Patrick McHardy <kaber@trash.net>

Applied, thanks Patrick.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2005-07-27 21:38 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-07-23 18:04 [PATCH 2.6.13rc3] IPv6: Check interface bindings on IPv6 raw socket reception Andrew McDonald
2005-07-24  0:24 ` Patrick McHardy
2005-07-24  5:39   ` Patrick McHardy
2005-07-27 21:38     ` David S. Miller
2005-07-27 21:38 ` David S. Miller

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).