net: ipv6: Add IPv6 support to the ping socket.
This adds the ability to send ICMPv6 echo requests without a raw socket. The equivalent ability for ICMPv4 was added in 2011. Instead of having separate code paths for IPv4 and IPv6, make most of the code in net/ipv4/ping.c dual-stack and only add a few IPv6-specific bits (like the protocol definition) to a new net/ipv6/ping.c. Hopefully this will reduce divergence and/or duplication of bugs in the future. Caveats: - Setting options via ancillary data (e.g., using IPV6_PKTINFO to specify the outgoing interface) is not yet supported. - There are no separate security settings for IPv4 and IPv6; everything is controlled by /proc/net/ipv4/ping_group_range. - The proc interface does not yet display IPv6 ping sockets properly. Tested with a patched copy of ping6 and using raw socket calls. Compiles and works with all of CONFIG_IPV6={n,m,y}. Signed-off-by: Lorenzo Colitti <lorenzo@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
6e2842f4bb
commit
6d0bfe2261
@@ -57,6 +57,7 @@
|
||||
|
||||
#include <net/ipv6.h>
|
||||
#include <net/ip6_checksum.h>
|
||||
#include <net/ping.h>
|
||||
#include <net/protocol.h>
|
||||
#include <net/raw.h>
|
||||
#include <net/rawv6.h>
|
||||
@@ -84,12 +85,18 @@ static inline struct sock *icmpv6_sk(struct net *net)
|
||||
static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
|
||||
u8 type, u8 code, int offset, __be32 info)
|
||||
{
|
||||
/* icmpv6_notify checks 8 bytes can be pulled, icmp6hdr is 8 bytes */
|
||||
struct icmp6hdr *icmp6 = (struct icmp6hdr *) (skb->data + offset);
|
||||
struct net *net = dev_net(skb->dev);
|
||||
|
||||
if (type == ICMPV6_PKT_TOOBIG)
|
||||
ip6_update_pmtu(skb, net, info, 0, 0);
|
||||
else if (type == NDISC_REDIRECT)
|
||||
ip6_redirect(skb, net, 0, 0);
|
||||
|
||||
if (!(type & ICMPV6_INFOMSG_MASK))
|
||||
if (icmp6->icmp6_type == ICMPV6_ECHO_REQUEST)
|
||||
ping_err(skb, offset, info);
|
||||
}
|
||||
|
||||
static int icmpv6_rcv(struct sk_buff *skb);
|
||||
@@ -224,7 +231,8 @@ static bool opt_unrec(struct sk_buff *skb, __u32 offset)
|
||||
return (*op & 0xC0) == 0x80;
|
||||
}
|
||||
|
||||
static int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, struct icmp6hdr *thdr, int len)
|
||||
int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
|
||||
struct icmp6hdr *thdr, int len)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct icmp6hdr *icmp6h;
|
||||
@@ -307,8 +315,8 @@ static void mip6_addr_swap(struct sk_buff *skb)
|
||||
static inline void mip6_addr_swap(struct sk_buff *skb) {}
|
||||
#endif
|
||||
|
||||
static struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *skb,
|
||||
struct sock *sk, struct flowi6 *fl6)
|
||||
struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *skb,
|
||||
struct sock *sk, struct flowi6 *fl6)
|
||||
{
|
||||
struct dst_entry *dst, *dst2;
|
||||
struct flowi6 fl2;
|
||||
@@ -697,7 +705,8 @@ static int icmpv6_rcv(struct sk_buff *skb)
|
||||
skb->csum = ~csum_unfold(csum_ipv6_magic(saddr, daddr, skb->len,
|
||||
IPPROTO_ICMPV6, 0));
|
||||
if (__skb_checksum_complete(skb)) {
|
||||
LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [%pI6 > %pI6]\n",
|
||||
LIMIT_NETDEBUG(KERN_DEBUG
|
||||
"ICMPv6 checksum failed [%pI6c > %pI6c]\n",
|
||||
saddr, daddr);
|
||||
goto csum_error;
|
||||
}
|
||||
@@ -718,7 +727,7 @@ static int icmpv6_rcv(struct sk_buff *skb)
|
||||
break;
|
||||
|
||||
case ICMPV6_ECHO_REPLY:
|
||||
/* we couldn't care less */
|
||||
ping_rcv(skb);
|
||||
break;
|
||||
|
||||
case ICMPV6_PKT_TOOBIG:
|
||||
|
Reference in New Issue
Block a user