[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> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
0bd1b59b15
commit
d13964f449
6 changed files with 14 additions and 8 deletions
|
@ -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 @@
|
||||||
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)
|
||||||
/* 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)
|
||||||
* 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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
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 @@ static inline int ip6_input_finish(struct sk_buff *skb)
|
||||||
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)
|
||||||
*
|
*
|
||||||
* 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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
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 */
|
||||||
|
|
Loading…
Reference in a new issue