Commit d13964f4 authored by Patrick McHardy's avatar Patrick McHardy Committed by David S. Miller

[IPV4/6]: Check if packet was actually delivered to a raw socket to decide...

[IPV4/6]: Check if packet was actually delivered to a raw socket to decide whether to send an ICMP unreachable
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0bd1b59b
...@@ -37,6 +37,6 @@ extern struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num, ...@@ -37,6 +37,6 @@ extern struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num,
unsigned long raddr, unsigned long laddr, unsigned long raddr, unsigned long laddr,
int dif); 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 */ #endif /* _RAW_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
extern struct hlist_head raw_v6_htable[RAWV6_HTABLE_SIZE]; extern struct hlist_head raw_v6_htable[RAWV6_HTABLE_SIZE];
extern rwlock_t raw_v6_lock; 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, 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,
......
...@@ -225,8 +225,8 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb) ...@@ -225,8 +225,8 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb)
/* If there maybe a raw socket we must check - if not we /* If there maybe a raw socket we must check - if not we
* don't care less * don't care less
*/ */
if (raw_sk) if (raw_sk && !raw_v4_input(skb, skb->nh.iph, hash))
raw_v4_input(skb, skb->nh.iph, hash); raw_sk = NULL;
if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) { if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) {
int ret; int ret;
......
...@@ -150,10 +150,11 @@ static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb) ...@@ -150,10 +150,11 @@ static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb)
* RFC 1122: SHOULD pass TOS value up to the transport layer. * RFC 1122: SHOULD pass TOS value up to the transport layer.
* -> It does. And not only TOS, but all IP header. * -> 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 sock *sk;
struct hlist_head *head; struct hlist_head *head;
int delivered = 0;
read_lock(&raw_v4_lock); read_lock(&raw_v4_lock);
head = &raw_v4_htable[hash]; head = &raw_v4_htable[hash];
...@@ -164,6 +165,7 @@ void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash) ...@@ -164,6 +165,7 @@ void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
skb->dev->ifindex); skb->dev->ifindex);
while (sk) { while (sk) {
delivered = 1;
if (iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) { if (iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) {
struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
...@@ -177,6 +179,7 @@ void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash) ...@@ -177,6 +179,7 @@ void raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash)
} }
out: out:
read_unlock(&raw_v4_lock); read_unlock(&raw_v4_lock);
return delivered;
} }
void raw_err (struct sock *sk, struct sk_buff *skb, u32 info) void raw_err (struct sock *sk, struct sk_buff *skb, u32 info)
......
...@@ -166,8 +166,8 @@ resubmit: ...@@ -166,8 +166,8 @@ resubmit:
nexthdr = skb->nh.raw[nhoff]; nexthdr = skb->nh.raw[nhoff];
raw_sk = sk_head(&raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)]); raw_sk = sk_head(&raw_v6_htable[nexthdr & (MAX_INET_PROTOS - 1)]);
if (raw_sk) if (raw_sk && !ipv6_raw_deliver(skb, nexthdr))
ipv6_raw_deliver(skb, nexthdr); raw_sk = NULL;
hash = nexthdr & (MAX_INET_PROTOS - 1); hash = nexthdr & (MAX_INET_PROTOS - 1);
if ((ipprot = rcu_dereference(inet6_protos[hash])) != NULL) { if ((ipprot = rcu_dereference(inet6_protos[hash])) != NULL) {
......
...@@ -141,11 +141,12 @@ static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb) ...@@ -141,11 +141,12 @@ static __inline__ int icmpv6_filter(struct sock *sk, struct sk_buff *skb)
* *
* Caller owns SKB so we must make clones. * 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 *saddr;
struct in6_addr *daddr; struct in6_addr *daddr;
struct sock *sk; struct sock *sk;
int delivered = 0;
__u8 hash; __u8 hash;
saddr = &skb->nh.ipv6h->saddr; saddr = &skb->nh.ipv6h->saddr;
...@@ -167,6 +168,7 @@ void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) ...@@ -167,6 +168,7 @@ void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, skb->dev->ifindex); sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr, skb->dev->ifindex);
while (sk) { while (sk) {
delivered = 1;
if (nexthdr != IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) { if (nexthdr != IPPROTO_ICMPV6 || !icmpv6_filter(sk, skb)) {
struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC);
...@@ -179,6 +181,7 @@ void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) ...@@ -179,6 +181,7 @@ void ipv6_raw_deliver(struct sk_buff *skb, int nexthdr)
} }
out: out:
read_unlock(&raw_v6_lock); read_unlock(&raw_v6_lock);
return delivered;
} }
/* This cleans up af_inet6 a bit. -DaveM */ /* This cleans up af_inet6 a bit. -DaveM */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment