Skip to content

Commit

Permalink
ping: fix the dif and sdif check in ping_lookup
Browse files Browse the repository at this point in the history
commit 35a79e6 upstream.

When 'ping' changes to use PING socket instead of RAW socket by:

   # sysctl -w net.ipv4.ping_group_range="0 100"

There is another regression caused when matching sk_bound_dev_if
and dif, RAW socket is using inet_iif() while PING socket lookup
is using skb->dev->ifindex, the cmd below fails due to this:

  # ip link add dummy0 type dummy
  # ip link set dummy0 up
  # ip addr add 192.168.111.1/24 dev dummy0
  # ping -I dummy0 192.168.111.1 -c1

The issue was also reported on:

  iputils/iputils#104

But fixed in iputils in a wrong way by not binding to device when
destination IP is on device, and it will cause some of kselftests
to fail, as Jianlin noticed.

This patch is to use inet(6)_iif and inet(6)_sdif to get dif and
sdif for PING socket, and keep consistent with RAW socket.

Fixes: c319b4d ("net: ipv4: add IPPROTO_ICMP socket kind")
Reported-by: Jianlin Shi <jishi@redhat.com>
Signed-off-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
lxin authored and gregkh committed Feb 23, 2022
1 parent 392c424 commit b9ff566
Showing 1 changed file with 9 additions and 2 deletions.
11 changes: 9 additions & 2 deletions net/ipv4/ping.c
Expand Up @@ -172,16 +172,23 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
struct sock *sk = NULL;
struct inet_sock *isk;
struct hlist_nulls_node *hnode;
int dif = skb->dev->ifindex;
int dif, sdif;

if (skb->protocol == htons(ETH_P_IP)) {
dif = inet_iif(skb);
sdif = inet_sdif(skb);
pr_debug("try to find: num = %d, daddr = %pI4, dif = %d\n",
(int)ident, &ip_hdr(skb)->daddr, dif);
#if IS_ENABLED(CONFIG_IPV6)
} else if (skb->protocol == htons(ETH_P_IPV6)) {
dif = inet6_iif(skb);
sdif = inet6_sdif(skb);
pr_debug("try to find: num = %d, daddr = %pI6c, dif = %d\n",
(int)ident, &ipv6_hdr(skb)->daddr, dif);
#endif
} else {
pr_err("ping: protocol(%x) is not supported\n", ntohs(skb->protocol));
return NULL;
}

read_lock_bh(&ping_table.lock);
Expand Down Expand Up @@ -221,7 +228,7 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
}

if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif &&
sk->sk_bound_dev_if != inet_sdif(skb))
sk->sk_bound_dev_if != sdif)
continue;

sock_hold(sk);
Expand Down

0 comments on commit b9ff566

Please sign in to comment.