Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d0bfe22 authored by Lorenzo Colitti's avatar Lorenzo Colitti Committed by David S. Miller
Browse files

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: default avatarLorenzo Colitti <lorenzo@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6e2842f4
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -260,6 +260,12 @@ static inline void fl6_sock_release(struct ip6_flowlabel *fl)

extern void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info);

int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6,
			       struct icmp6hdr *thdr, int len);

struct dst_entry *icmpv6_route_lookup(struct net *net, struct sk_buff *skb,
				      struct sock *sk, struct flowi6 *fl6);

extern int 			ip6_ra_control(struct sock *sk, int sel);

extern int			ipv6_parse_hopopts(struct sk_buff *skb);
+46 −3
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#ifndef _PING_H
#define _PING_H

#include <net/icmp.h>
#include <net/netns/hash.h>

/* PING_HTABLE_SIZE must be power of 2 */
@@ -28,6 +29,18 @@
 */
#define GID_T_MAX (((gid_t)~0U) >> 1)

/* Compatibility glue so we can support IPv6 when it's compiled as a module */
struct pingv6_ops {
	int (*ipv6_recv_error)(struct sock *sk, struct msghdr *msg, int len);
	int (*ip6_datagram_recv_ctl)(struct sock *sk, struct msghdr *msg,
				     struct sk_buff *skb);
	int (*icmpv6_err_convert)(u8 type, u8 code, int *err);
	void (*ipv6_icmp_error)(struct sock *sk, struct sk_buff *skb, int err,
				__be16 port, u32 info, u8 *payload);
	int (*ipv6_chk_addr)(struct net *net, const struct in6_addr *addr,
			     struct net_device *dev, int strict);
};

struct ping_table {
	struct hlist_nulls_head	hash[PING_HTABLE_SIZE];
	rwlock_t		lock;
@@ -39,10 +52,39 @@ struct ping_iter_state {
};

extern struct proto ping_prot;
extern struct ping_table ping_table;
#if IS_ENABLED(CONFIG_IPV6)
extern struct pingv6_ops pingv6_ops;
#endif

struct pingfakehdr {
	struct icmphdr icmph;
	struct iovec *iov;
	sa_family_t family;
	__wsum wcheck;
};

extern void ping_rcv(struct sk_buff *);
extern void ping_err(struct sk_buff *, u32 info);
int  ping_get_port(struct sock *sk, unsigned short ident);
void ping_hash(struct sock *sk);
void ping_unhash(struct sock *sk);

int  ping_init_sock(struct sock *sk);
void ping_close(struct sock *sk, long timeout);
int  ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len);
void ping_err(struct sk_buff *skb, int offset, u32 info);
int  ping_getfrag(void *from, char *to, int offset, int fraglen, int odd,
		  struct sk_buff *);

int  ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
		  size_t len, int noblock, int flags, int *addr_len);
int  ping_common_sendmsg(int family, struct msghdr *msg, size_t len,
			 void *user_icmph, size_t icmph_len);
int  ping_v4_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
		     size_t len);
int  ping_v6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
		     size_t len);
int  ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
void ping_rcv(struct sk_buff *skb);

#ifdef CONFIG_PROC_FS
extern int __init ping_proc_init(void);
@@ -50,6 +92,7 @@ extern void ping_proc_exit(void);
#endif

void __init ping_init(void);

int  __init pingv6_init(void);
void pingv6_exit(void);

#endif /* _PING_H */
+3 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ extern struct proto rawv6_prot;
extern struct proto udpv6_prot;
extern struct proto udplitev6_prot;
extern struct proto tcpv6_prot;
extern struct proto pingv6_prot;

struct flowi6;

@@ -21,6 +22,8 @@ extern int ipv6_frag_init(void);
extern void				ipv6_frag_exit(void);

/* transport protocols */
extern int				pingv6_init(void);
extern void				pingv6_exit(void);
extern int				rawv6_init(void);
extern void				rawv6_exit(void);
extern int				udpv6_init(void);
+3 −2
Original line number Diff line number Diff line
@@ -939,7 +939,8 @@ int icmp_rcv(struct sk_buff *skb)
void icmp_err(struct sk_buff *skb, u32 info)
{
	struct iphdr *iph = (struct iphdr *)skb->data;
	struct icmphdr *icmph = (struct icmphdr *)(skb->data+(iph->ihl<<2));
	int offset = iph->ihl<<2;
	struct icmphdr *icmph = (struct icmphdr *)(skb->data + offset);
	int type = icmp_hdr(skb)->type;
	int code = icmp_hdr(skb)->code;
	struct net *net = dev_net(skb->dev);
@@ -949,7 +950,7 @@ void icmp_err(struct sk_buff *skb, u32 info)
	 * triggered by ICMP_ECHOREPLY which sent from kernel.
	 */
	if (icmph->type != ICMP_ECHOREPLY) {
		ping_err(skb, info);
		ping_err(skb, offset, info);
		return;
	}

+397 −160

File changed.

Preview size limit exceeded, changes collapsed.

Loading