net: ip, diag -- Add diag interface for raw sockets
Subsystems (2)
PATCH v7 1/1 net: ip, diag -- Add diag interface for raw sockets
In criu we are actively using diag interface to collect sockets present in the system when dumping applications. And while for unix, tcp, udp[lite], packet, netlink it works as expected, the raw sockets do not have. Thus add it.
v2:
- add missing sock_put calls in raw_diag_dump_one (by eric.dumazet@)
- implement @destroy for diag requests (by dsa@)
v3:
- add export of raw_abort for IPv6 (by dsa@)
- pass net-admin flag into inet_sk_diag_fill due to changes in net-next branch (by dsa@)
v4:
- use @pad in struct inet_diag_req_v2 for raw socket protocol specification: raw module carries sockets which may have custom protocol passed from socket() syscall and sole @sdiag_protocol is not enough to match underlied ones
- start reporting protocol specifed in socket() call when sockets are raw ones for the same reason: user space tools like ss may parse this attribute and use it for socket matching
v5 (by eric.dumazet@):
- use sock_hold in raw_sock_get instead of atomic_inc, we're holding (raw_v4_hashinfo|raw_v6_hashinfo)->lock when looking up so counter won't be zero here.
v6:
- use sdiag_raw_protocol() helper which will access @pad structure used for raw sockets protocol specification:
we can't simply rename this member without breaking uapi
v7:
- sine sdiag_raw_protocol() helper is not suitable for uapi lets rather make an alias structure with proper names. __check_inet_diag_req_raw helper will catch if any of structure unintentionally changed.
---
include/net/raw.h | 6 include/net/rawv6.h | 7 + include/uapi/linux/inet_diag.h | 17 ++ net/ipv4/Kconfig | 8 + net/ipv4/Makefile | 1 net/ipv4/inet_diag.c | 9 + net/ipv4/raw.c | 21 ++- net/ipv4/raw_diag.c | 261 +++++++++++++++++++++++++++++++++++++++++ net/ipv6/raw.c | 7 - 9 files changed, 333 insertions(+), 4 deletions(-)
include/net/raw.h +6 -0
@@ -23,6 +23,12 @@extern struct proto raw_prot; +extern struct raw_hashinfo raw_v4_hashinfo; +struct sock *__raw_v4_lookup (struct net *net,struct sock *sk, +unsigned short num,__be32 raddr, +__be32 laddr,int dif); + +int raw_abort (struct sock *sk,int err);void raw_icmp_error (struct sk_buff *,int ,u32 );int raw_local_deliver (struct sk_buff *,int );
include/net/rawv6.h +7 -0
@@ -3,6 +3,13 @@#include <net/protocol.h> +extern struct raw_hashinfo raw_v6_hashinfo; +struct sock *__raw_v6_lookup (struct net *net,struct sock *sk, +unsigned short num,const struct in6_addr *loc_addr, +const struct in6_addr *rmt_addr,int dif); + +int raw_abort (struct sock *sk,int err); +void raw6_icmp_error (struct sk_buff *,int nexthdr,u8 type,u8 code,int inner_offset,__be32 );bool raw6_local_deliver (struct sk_buff *,int );
include/uapi/linux/inet_diag.h +17 -0
@@ -43,6 +43,23 @@ struct inet_diag_req_v2 {struct inet_diag_sockid id; }; +/* +* SOCK_RAW sockets require the underlied protocol to be +* additionally specified so we can use @pad member for +* this, but we can't rename it because userspace programs +* still may depend on this name. Instead lets use another +* structure definition as an alias for struct +* @inet_diag_req_v2. +*/ +struct inet_diag_req_raw { +__u8 sdiag_family; +__u8 sdiag_protocol; +__u8 idiag_ext; +__u8 sdiag_raw_protocol; +__u32 idiag_states; +struct inet_diag_sockid id; +}; +enum {INET_DIAG_REQ_NONE ,INET_DIAG_REQ_BYTECODE ,
net/ipv4/Kconfig +8 -0
@@ -430,6 +430,14 @@ config INET_UDP_DIAG Support for UDP socket monitoring interface used by the ss tool. If unsure, say Y. +config INET_RAW_DIAG + tristate "RAW: socket monitoring interface" + depends on INET_DIAG && (IPV6 || IPV6=n) + default n + ---help--- + Support for RAW socket monitoring interface used by the ss tool. + If unsure, say Y. + config INET_DIAG_DESTROY bool "INET: allow privileged process to administratively close sockets" depends on INET_DIAG
net/ipv4/Makefile +1 -0
@@ -40,6 +40,7 @@ obj-$(CONFIG_NETFILTER) += netfilter.o n obj-$(CONFIG_INET_DIAG) += inet_diag.o obj-$(CONFIG_INET_TCP_DIAG) += tcp_diag.o obj-$(CONFIG_INET_UDP_DIAG) += udp_diag.o +obj-$(CONFIG_INET_RAW_DIAG) += raw_diag.o obj-$(CONFIG_NET_TCPPROBE) += tcp_probe.o obj-$(CONFIG_TCP_CONG_BIC) += tcp_bic.o obj-$(CONFIG_TCP_CONG_CDG) += tcp_cdg.o
net/ipv4/inet_diag.c +9 -0
@@ -200,6 +200,15 @@ int inet_sk_diag_fill(struct sock *sk, sif (sock_diag_put_meminfo (sk, skb,INET_DIAG_SKMEMINFO )) goto errout; +/* +* RAW sockets might have user-defined protocols assigned, +* so report the one supplied on socket creation. +*/ +if (sk->sk_type ==SOCK_RAW ) { +if (nla_put_u8 (skb,INET_DIAG_PROTOCOL , sk->sk_protocol)) + goto errout; + } +if (!icsk) { handler->idiag_get_info (sk, r,NULL ); goto out;
net/ipv4/raw.c +19 -2
@@ -89,9 +89,10 @@ struct raw_frag_vec {int hlen; }; -static struct raw_hashinfo raw_v4_hashinfo = { +struct raw_hashinfo raw_v4_hashinfo = { .lock =__RW_LOCK_UNLOCKED (raw_v4_hashinfo.lock), }; +EXPORT_SYMBOL_GPL (raw_v4_hashinfo);int raw_hash_sk (struct sock *sk) {
@@ -120,7 +121,7 @@ void raw_unhash_sk(struct sock *sk) }EXPORT_SYMBOL_GPL (raw_unhash_sk); -static struct sock *__raw_v4_lookup (struct net *net,struct sock *sk, +struct sock *__raw_v4_lookup (struct net *net,struct sock *sk,unsigned short num,__be32 raddr,__be32 laddr,int dif) {sk_for_each_from (sk) {
@@ -136,6 +137,7 @@ static struct sock *__raw_v4_lookup(stru found:return sk; } +EXPORT_SYMBOL_GPL (__raw_v4_lookup);/* * 0 - deliver
@@ -918,6 +920,20 @@ static int compat_raw_ioctl(struct sock }#endif +int raw_abort (struct sock *sk,int err) +{ +lock_sock (sk); + + sk->sk_err = err; + sk->sk_error_report (sk); +udp_disconnect (sk,0 ); + +release_sock (sk); + +return 0 ; +} +EXPORT_SYMBOL_GPL (raw_abort); +struct proto raw_prot = { .name ="RAW" , .owner =THIS_MODULE ,
@@ -943,6 +959,7 @@ struct proto raw_prot = { .compat_getsockopt = compat_raw_getsockopt, .compat_ioctl = compat_raw_ioctl, #endif + .diag_destroy = raw_abort, };#ifdef CONFIG_PROC_FS
net/ipv4/raw_diag.c new file +261 -0
261 lines not on this page · raw message
net/ipv6/raw.c +5 -2
@@ -65,11 +65,12 @@#define ICMPV6_HDRLEN 4/* ICMPv6 header, RFC 4443 Section 2.1 */ -static struct raw_hashinfo raw_v6_hashinfo = { +struct raw_hashinfo raw_v6_hashinfo = { .lock =__RW_LOCK_UNLOCKED (raw_v6_hashinfo.lock), }; +EXPORT_SYMBOL_GPL (raw_v6_hashinfo); -static struct sock *__raw_v6_lookup (struct net *net,struct sock *sk, +struct sock *__raw_v6_lookup (struct net *net,struct sock *sk,unsigned short num,const struct in6_addr *loc_addr,const struct in6_addr *rmt_addr,int dif) {
@@ -102,6 +103,7 @@ static struct sock *__raw_v6_lookup(stru found:return sk; } +EXPORT_SYMBOL_GPL (__raw_v6_lookup);/* * 0 - deliver
@@ -1252,6 +1254,7 @@ struct proto rawv6_prot = { .compat_getsockopt = compat_rawv6_getsockopt, .compat_ioctl = compat_rawv6_ioctl, #endif + .diag_destroy = raw_abort, };#ifdef CONFIG_PROC_FS
From: Cyrill Gorcunov <[email protected]>
Date: Fri, 21 Oct 2016 13:03:44 +0300
Quoted 4 lines
In criu we are actively using diag interface to collect sockets present in the system when dumping applications. And while for unix, tcp, udp[lite], packet, netlink it works as expected, the raw sockets do not have. Thus add it.
Applied, thanks.
Quoted 9 lines · David Miller
From: Cyrill Gorcunov <[email protected]>
Date: Fri, 21 Oct 2016 13:03:44 +0300Quoted 4 lines
In criu we are actively using diag interface to collect sockets present in the system when dumping applications. And while for unix, tcp, udp[lite], packet, netlink it works as expected, the raw sockets do not have. Thus add it.
Applied, thanks.
Thanks to all for extensive comments and review!