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
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user