* [PATCH] net: ip, diag -- Add diag interface for raw sockets @ 2016-09-09 18:26 Cyrill Gorcunov 2016-09-09 19:55 ` Eric Dumazet 2016-09-10 16:31 ` David Ahern 0 siblings, 2 replies; 10+ messages in thread From: Cyrill Gorcunov @ 2016-09-09 18:26 UTC (permalink / raw) To: NETDEV, LKML Cc: David S. Miller, Eric Dumazet, Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI, Patrick McHardy, Andrey Vagin, Stephen Hemminger 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. CC: David S. Miller <davem@davemloft.net> CC: Eric Dumazet <eric.dumazet@gmail.com> CC: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> CC: James Morris <jmorris@namei.org> CC: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org> CC: Patrick McHardy <kaber@trash.net> CC: Andrey Vagin <avagin@openvz.org> CC: Stephen Hemminger <stephen@networkplumber.org> Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org> --- Take a look please, once time permit. Hopefully I didn't miss something obvious, tested as "ss -n -A raw" for modified iproute2 instance and c/r for trivial application which has raw sockets opened. A patch for ss tool is at https://goo.gl/VFQ93L for the reference, will send it out then. include/net/raw.h | 5 + include/net/rawv6.h | 5 + net/ipv4/Kconfig | 8 ++ net/ipv4/Makefile | 1 net/ipv4/raw.c | 6 + net/ipv4/raw_diag.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++ net/ipv6/raw.c | 6 + 7 files changed, 219 insertions(+), 4 deletions(-) Index: linux-ml.git/include/net/raw.h =================================================================== --- linux-ml.git.orig/include/net/raw.h +++ linux-ml.git/include/net/raw.h @@ -23,6 +23,11 @@ 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); + void raw_icmp_error(struct sk_buff *, int, u32); int raw_local_deliver(struct sk_buff *, int); Index: linux-ml.git/include/net/rawv6.h =================================================================== --- linux-ml.git.orig/include/net/rawv6.h +++ linux-ml.git/include/net/rawv6.h @@ -3,6 +3,11 @@ #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); + 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); Index: linux-ml.git/net/ipv4/Kconfig =================================================================== --- linux-ml.git.orig/net/ipv4/Kconfig +++ linux-ml.git/net/ipv4/Kconfig @@ -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 Index: linux-ml.git/net/ipv4/Makefile =================================================================== --- linux-ml.git.orig/net/ipv4/Makefile +++ linux-ml.git/net/ipv4/Makefile @@ -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 Index: linux-ml.git/net/ipv4/raw.c =================================================================== --- linux-ml.git.orig/net/ipv4/raw.c +++ linux-ml.git/net/ipv4/raw.c @@ -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 Index: linux-ml.git/net/ipv4/raw_diag.c =================================================================== --- /dev/null +++ linux-ml.git/net/ipv4/raw_diag.c @@ -0,0 +1,192 @@ +#include <linux/module.h> + +#include <linux/inet_diag.h> +#include <linux/sock_diag.h> + +#include <net/raw.h> +#include <net/rawv6.h> + +#ifdef pr_fmt +# undef pr_fmt +#endif + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +static struct raw_hashinfo * +raw_get_hashinfo(const struct inet_diag_req_v2 *r) +{ + if (r->sdiag_family == AF_INET) { + return &raw_v4_hashinfo; +#if IS_ENABLED(CONFIG_IPV6) + } else if (r->sdiag_family == AF_INET6) { + return &raw_v6_hashinfo; +#endif + } else { + pr_warn_once("Unexpected inet family %d\n", + r->sdiag_family); + WARN_ON_ONCE(1); + return ERR_PTR(-EINVAL); + } +} + +static struct sock *raw_lookup(struct net *net, struct sock *from, + const struct inet_diag_req_v2 *r) +{ + struct sock *sk = NULL; + + if (r->sdiag_family == AF_INET) + sk = __raw_v4_lookup(net, from, r->sdiag_protocol, + r->id.idiag_dst[0], + r->id.idiag_src[0], + r->id.idiag_if); +#if IS_ENABLED(CONFIG_IPV6) + else + sk = __raw_v6_lookup(net, from, r->sdiag_protocol, + (const struct in6_addr *)r->id.idiag_src, + (const struct in6_addr *)r->id.idiag_dst, + r->id.idiag_if); +#endif + return sk; +} + +static int raw_diag_dump_one(struct sk_buff *in_skb, + const struct nlmsghdr *nlh, + const struct inet_diag_req_v2 *r) +{ + struct raw_hashinfo *hashinfo = raw_get_hashinfo(r); + struct net *net = sock_net(in_skb->sk); + struct sock *sk = NULL, *s; + int err = -ENOENT, slot; + struct sk_buff *rep; + + if (IS_ERR(hashinfo)) + return PTR_ERR(hashinfo); + + read_lock(&hashinfo->lock); + for (slot = 0; slot < RAW_HTABLE_SIZE; slot++) { + sk_for_each(s, &hashinfo->ht[slot]) { + sk = raw_lookup(net, s, r); + if (sk) + break; + } + } + if (sk && !atomic_inc_not_zero(&sk->sk_refcnt)) + sk = NULL; + read_unlock(&hashinfo->lock); + if (!sk) + return -ENOENT; + + rep = nlmsg_new(sizeof(struct inet_diag_msg) + + sizeof(struct inet_diag_meminfo) + 64, + GFP_KERNEL); + if (!rep) + return -ENOMEM; + + err = inet_sk_diag_fill(sk, NULL, rep, r, + sk_user_ns(NETLINK_CB(in_skb).sk), + NETLINK_CB(in_skb).portid, + nlh->nlmsg_seq, 0, nlh); + if (err < 0) { + kfree_skb(rep); + return err; + } + + err = netlink_unicast(net->diag_nlsk, rep, + NETLINK_CB(in_skb).portid, + MSG_DONTWAIT); + if (err > 0) + err = 0; + return err; +} + +static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, + struct netlink_callback *cb, + const struct inet_diag_req_v2 *r, + struct nlattr *bc) +{ + if (!inet_diag_bc_sk(bc, sk)) + return 0; + + return inet_sk_diag_fill(sk, NULL, skb, r, + sk_user_ns(NETLINK_CB(cb->skb).sk), + NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh); +} + +static void raw_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, + const struct inet_diag_req_v2 *r, struct nlattr *bc) +{ + struct raw_hashinfo *hashinfo = raw_get_hashinfo(r); + struct net *net = sock_net(skb->sk); + int num, s_num, slot, s_slot; + struct sock *sk = NULL; + + if (IS_ERR(hashinfo)) + return; + + s_slot = cb->args[0]; + num = s_num = cb->args[1]; + + read_lock(&hashinfo->lock); + for (slot = s_slot; slot < RAW_HTABLE_SIZE; s_num = 0, slot++) { + num = 0; + + sk_for_each(sk, &hashinfo->ht[slot]) { + struct inet_sock *inet = inet_sk(sk); + + if (!net_eq(sock_net(sk), net)) + continue; + if (num < s_num) + goto next; + if (sk->sk_family != r->sdiag_family) + goto next; + if (r->id.idiag_sport != inet->inet_sport && + r->id.idiag_sport) + goto next; + if (r->id.idiag_dport != inet->inet_dport && + r->id.idiag_dport) + goto next; + if (sk_diag_dump(sk, skb, cb, r, bc) < 0) + goto out_unlock; +next: + num++; + } + } + +out_unlock: + read_unlock(&hashinfo->lock); + + cb->args[0] = slot; + cb->args[1] = num; +} + +static void raw_diag_get_info(struct sock *sk, struct inet_diag_msg *r, + void *info) +{ + r->idiag_rqueue = sk_rmem_alloc_get(sk); + r->idiag_wqueue = sk_wmem_alloc_get(sk); +} + +static const struct inet_diag_handler raw_diag_handler = { + .dump = raw_diag_dump, + .dump_one = raw_diag_dump_one, + .idiag_get_info = raw_diag_get_info, + .idiag_type = IPPROTO_RAW, + .idiag_info_size = 0, +}; + +static int __init raw_diag_init(void) +{ + return inet_diag_register(&raw_diag_handler); +} + +static void __exit raw_diag_exit(void) +{ + inet_diag_unregister(&raw_diag_handler); +} + +module_init(raw_diag_init); +module_exit(raw_diag_exit); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-255 /* AF_INET - IPPROTO_RAW */); +MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 10-255 /* AF_INET6 - IPPROTO_RAW */); Index: linux-ml.git/net/ipv6/raw.c =================================================================== --- linux-ml.git.orig/net/ipv6/raw.c +++ linux-ml.git/net/ipv6/raw.c @@ -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 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] net: ip, diag -- Add diag interface for raw sockets 2016-09-09 18:26 [PATCH] net: ip, diag -- Add diag interface for raw sockets Cyrill Gorcunov @ 2016-09-09 19:55 ` Eric Dumazet 2016-09-09 20:17 ` Cyrill Gorcunov 2016-09-10 16:31 ` David Ahern 1 sibling, 1 reply; 10+ messages in thread From: Eric Dumazet @ 2016-09-09 19:55 UTC (permalink / raw) To: Cyrill Gorcunov Cc: NETDEV, LKML, David S. Miller, Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI, Patrick McHardy, Andrey Vagin, Stephen Hemminger On Fri, 2016-09-09 at 21:26 +0300, Cyrill Gorcunov wrote: ... > +static int raw_diag_dump_one(struct sk_buff *in_skb, > + const struct nlmsghdr *nlh, > + const struct inet_diag_req_v2 *r) > +{ > + struct raw_hashinfo *hashinfo = raw_get_hashinfo(r); > + struct net *net = sock_net(in_skb->sk); > + struct sock *sk = NULL, *s; > + int err = -ENOENT, slot; > + struct sk_buff *rep; > + > + if (IS_ERR(hashinfo)) > + return PTR_ERR(hashinfo); > + > + read_lock(&hashinfo->lock); > + for (slot = 0; slot < RAW_HTABLE_SIZE; slot++) { > + sk_for_each(s, &hashinfo->ht[slot]) { > + sk = raw_lookup(net, s, r); > + if (sk) > + break; > + } > + } > + if (sk && !atomic_inc_not_zero(&sk->sk_refcnt)) > + sk = NULL; > + read_unlock(&hashinfo->lock); > + if (!sk) > + return -ENOENT; > + > + rep = nlmsg_new(sizeof(struct inet_diag_msg) + > + sizeof(struct inet_diag_meminfo) + 64, > + GFP_KERNEL); > + if (!rep) There is a missing sock_put(sk) > + return -ENOMEM; > + > + err = inet_sk_diag_fill(sk, NULL, rep, r, > + sk_user_ns(NETLINK_CB(in_skb).sk), > + NETLINK_CB(in_skb).portid, > + nlh->nlmsg_seq, 0, nlh); sock_put(sk); > + if (err < 0) { > + kfree_skb(rep); > + return err; > + } > + > + err = netlink_unicast(net->diag_nlsk, rep, > + NETLINK_CB(in_skb).portid, > + MSG_DONTWAIT); > + if (err > 0) > + err = 0; > + return err; > +} > + ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] net: ip, diag -- Add diag interface for raw sockets 2016-09-09 19:55 ` Eric Dumazet @ 2016-09-09 20:17 ` Cyrill Gorcunov 0 siblings, 0 replies; 10+ messages in thread From: Cyrill Gorcunov @ 2016-09-09 20:17 UTC (permalink / raw) To: Eric Dumazet Cc: NETDEV, LKML, David S. Miller, Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI, Patrick McHardy, Andrey Vagin, Stephen Hemminger On Fri, Sep 09, 2016 at 12:55:13PM -0700, Eric Dumazet wrote: > > + > > + rep = nlmsg_new(sizeof(struct inet_diag_msg) + > > + sizeof(struct inet_diag_meminfo) + 64, > > + GFP_KERNEL); > > + if (!rep) > > There is a missing sock_put(sk) > > > + return -ENOMEM; > > + > > + err = inet_sk_diag_fill(sk, NULL, rep, r, > > + sk_user_ns(NETLINK_CB(in_skb).sk), > > + NETLINK_CB(in_skb).portid, > > + nlh->nlmsg_seq, 0, nlh); > > sock_put(sk); Oh, missed. Thanks lot, Eric, will update! ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] net: ip, diag -- Add diag interface for raw sockets 2016-09-09 18:26 [PATCH] net: ip, diag -- Add diag interface for raw sockets Cyrill Gorcunov 2016-09-09 19:55 ` Eric Dumazet @ 2016-09-10 16:31 ` David Ahern 2016-09-10 19:31 ` Cyrill Gorcunov 2016-09-10 22:05 ` [PATCH v2] " Cyrill Gorcunov 1 sibling, 2 replies; 10+ messages in thread From: David Ahern @ 2016-09-10 16:31 UTC (permalink / raw) To: Cyrill Gorcunov, NETDEV, LKML Cc: David S. Miller, Eric Dumazet, Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI, Patrick McHardy, Andrey Vagin, Stephen Hemminger On 9/9/16 12:26 PM, Cyrill Gorcunov wrote: > 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. > > CC: David S. Miller <davem@davemloft.net> > CC: Eric Dumazet <eric.dumazet@gmail.com> > CC: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> > CC: James Morris <jmorris@namei.org> > CC: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org> > CC: Patrick McHardy <kaber@trash.net> > CC: Andrey Vagin <avagin@openvz.org> > CC: Stephen Hemminger <stephen@networkplumber.org> > Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org> > --- Would you mind adding the destroy capability as well? The udp version should be close to what is needed for raw sockets. See udp_diag_destroy and udp_abort. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] net: ip, diag -- Add diag interface for raw sockets 2016-09-10 16:31 ` David Ahern @ 2016-09-10 19:31 ` Cyrill Gorcunov 2016-09-10 22:05 ` [PATCH v2] " Cyrill Gorcunov 1 sibling, 0 replies; 10+ messages in thread From: Cyrill Gorcunov @ 2016-09-10 19:31 UTC (permalink / raw) To: David Ahern Cc: NETDEV, LKML, David S. Miller, Eric Dumazet, Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI, Patrick McHardy, Andrey Vagin, Stephen Hemminger On Sat, Sep 10, 2016 at 10:31:35AM -0600, David Ahern wrote: > On 9/9/16 12:26 PM, Cyrill Gorcunov wrote: > > 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. > > > > CC: David S. Miller <davem@davemloft.net> > > CC: Eric Dumazet <eric.dumazet@gmail.com> > > CC: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> > > CC: James Morris <jmorris@namei.org> > > CC: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org> > > CC: Patrick McHardy <kaber@trash.net> > > CC: Andrey Vagin <avagin@openvz.org> > > CC: Stephen Hemminger <stephen@networkplumber.org> > > Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org> > > --- > > Would you mind adding the destroy capability as well? The udp version should be close to > what is needed for raw sockets. See udp_diag_destroy and udp_abort. Sure, will do. ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2] net: ip, diag -- Add diag interface for raw sockets 2016-09-10 16:31 ` David Ahern 2016-09-10 19:31 ` Cyrill Gorcunov @ 2016-09-10 22:05 ` Cyrill Gorcunov 2016-09-10 22:28 ` David Ahern 1 sibling, 1 reply; 10+ messages in thread From: Cyrill Gorcunov @ 2016-09-10 22:05 UTC (permalink / raw) To: David Ahern Cc: NETDEV, LKML, David S. Miller, Eric Dumazet, Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI, Patrick McHardy, Andrey Vagin, Stephen Hemminger On Sat, Sep 10, 2016 at 10:31:35AM -0600, David Ahern wrote: > > Would you mind adding the destroy capability as well? The udp version > should be close to what is needed for raw sockets. See udp_diag_destroy > and udp_abort. Should be something like below. Didn't tested it yet so for review only. Will do testing at Monday. --- From: Cyrill Gorcunov <gorcunov@openvz.org> Subject: [PATCH v2] 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@) CC: David S. Miller <davem@davemloft.net> CC: Eric Dumazet <eric.dumazet@gmail.com> CC: David Ahern <dsa@cumulusnetworks.com> CC: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> CC: James Morris <jmorris@namei.org> CC: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org> CC: Patrick McHardy <kaber@trash.net> CC: Andrey Vagin <avagin@openvz.org> CC: Stephen Hemminger <stephen@networkplumber.org> Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org> --- Take a look please, once time permit. Hopefully I didn't miss something obvious, tested as "ss -n -A raw" for modified iproute2 instance and c/r for trivial application which has raw sockets opened. A patch for ss tool is at https://goo.gl/VFQ93L for the reference, will send it out then. include/net/raw.h | 5 + include/net/rawv6.h | 5 + net/ipv4/Kconfig | 8 + net/ipv4/Makefile | 1 net/ipv4/raw.c | 22 ++++- net/ipv4/raw_diag.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++++ net/ipv6/raw.c | 7 + 7 files changed, 263 insertions(+), 4 deletions(-) Index: linux-ml.git/include/net/raw.h =================================================================== --- linux-ml.git.orig/include/net/raw.h +++ linux-ml.git/include/net/raw.h @@ -23,6 +23,11 @@ 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); + void raw_icmp_error(struct sk_buff *, int, u32); int raw_local_deliver(struct sk_buff *, int); Index: linux-ml.git/include/net/rawv6.h =================================================================== --- linux-ml.git.orig/include/net/rawv6.h +++ linux-ml.git/include/net/rawv6.h @@ -3,6 +3,11 @@ #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); + 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); Index: linux-ml.git/net/ipv4/Kconfig =================================================================== --- linux-ml.git.orig/net/ipv4/Kconfig +++ linux-ml.git/net/ipv4/Kconfig @@ -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 Index: linux-ml.git/net/ipv4/Makefile =================================================================== --- linux-ml.git.orig/net/ipv4/Makefile +++ linux-ml.git/net/ipv4/Makefile @@ -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 Index: linux-ml.git/net/ipv4/raw.c =================================================================== --- linux-ml.git.orig/net/ipv4/raw.c +++ linux-ml.git/net/ipv4/raw.c @@ -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,21 @@ 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); + + sock_put(sk); + return 0; +} +EXPORT_SYMBOL_GPL(raw_abort); + struct proto raw_prot = { .name = "RAW", .owner = THIS_MODULE, @@ -943,6 +960,7 @@ struct proto raw_prot = { .compat_getsockopt = compat_raw_getsockopt, .compat_ioctl = compat_raw_ioctl, #endif + .diag_destroy = raw_abort, }; #ifdef CONFIG_PROC_FS Index: linux-ml.git/net/ipv4/raw_diag.c =================================================================== --- /dev/null +++ linux-ml.git/net/ipv4/raw_diag.c @@ -0,0 +1,219 @@ +#include <linux/module.h> + +#include <linux/inet_diag.h> +#include <linux/sock_diag.h> + +#include <net/raw.h> +#include <net/rawv6.h> + +#ifdef pr_fmt +# undef pr_fmt +#endif + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +static struct raw_hashinfo * +raw_get_hashinfo(const struct inet_diag_req_v2 *r) +{ + if (r->sdiag_family == AF_INET) { + return &raw_v4_hashinfo; +#if IS_ENABLED(CONFIG_IPV6) + } else if (r->sdiag_family == AF_INET6) { + return &raw_v6_hashinfo; +#endif + } else { + pr_warn_once("Unexpected inet family %d\n", + r->sdiag_family); + WARN_ON_ONCE(1); + return ERR_PTR(-EINVAL); + } +} + +static struct sock *raw_lookup(struct net *net, struct sock *from, + const struct inet_diag_req_v2 *r) +{ + struct sock *sk = NULL; + + if (r->sdiag_family == AF_INET) + sk = __raw_v4_lookup(net, from, r->sdiag_protocol, + r->id.idiag_dst[0], + r->id.idiag_src[0], + r->id.idiag_if); +#if IS_ENABLED(CONFIG_IPV6) + else + sk = __raw_v6_lookup(net, from, r->sdiag_protocol, + (const struct in6_addr *)r->id.idiag_src, + (const struct in6_addr *)r->id.idiag_dst, + r->id.idiag_if); +#endif + return sk; +} + +static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2 *r) +{ + struct raw_hashinfo *hashinfo = raw_get_hashinfo(r); + struct sock *sk = NULL, *s; + int slot; + + if (IS_ERR(hashinfo)) + return ERR_CAST(hashinfo); + + read_lock(&hashinfo->lock); + for (slot = 0; slot < RAW_HTABLE_SIZE; slot++) { + sk_for_each(s, &hashinfo->ht[slot]) { + sk = raw_lookup(net, s, r); + if (sk) + break; + } + } + if (sk && !atomic_inc_not_zero(&sk->sk_refcnt)) + sk = NULL; + read_unlock(&hashinfo->lock); + + return sk ? sk : ERR_PTR(-ENOENT); +} + +static int raw_diag_dump_one(struct sk_buff *in_skb, + const struct nlmsghdr *nlh, + const struct inet_diag_req_v2 *r) +{ + struct net *net = sock_net(in_skb->sk); + struct sk_buff *rep; + struct sock *sk; + int err; + + sk = raw_sock_get(net, r); + if (IS_ERR(sk)) + return PTR_ERR(sk); + + rep = nlmsg_new(sizeof(struct inet_diag_msg) + + sizeof(struct inet_diag_meminfo) + 64, + GFP_KERNEL); + if (!rep) { + sock_put(sk); + return -ENOMEM; + } + + err = inet_sk_diag_fill(sk, NULL, rep, r, + sk_user_ns(NETLINK_CB(in_skb).sk), + NETLINK_CB(in_skb).portid, + nlh->nlmsg_seq, 0, nlh); + sock_put(sk); + + if (err < 0) { + kfree_skb(rep); + return err; + } + + err = netlink_unicast(net->diag_nlsk, rep, + NETLINK_CB(in_skb).portid, + MSG_DONTWAIT); + if (err > 0) + err = 0; + return err; +} + +static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, + struct netlink_callback *cb, + const struct inet_diag_req_v2 *r, + struct nlattr *bc) +{ + if (!inet_diag_bc_sk(bc, sk)) + return 0; + + return inet_sk_diag_fill(sk, NULL, skb, r, + sk_user_ns(NETLINK_CB(cb->skb).sk), + NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh); +} + +static void raw_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, + const struct inet_diag_req_v2 *r, struct nlattr *bc) +{ + struct raw_hashinfo *hashinfo = raw_get_hashinfo(r); + struct net *net = sock_net(skb->sk); + int num, s_num, slot, s_slot; + struct sock *sk = NULL; + + if (IS_ERR(hashinfo)) + return; + + s_slot = cb->args[0]; + num = s_num = cb->args[1]; + + read_lock(&hashinfo->lock); + for (slot = s_slot; slot < RAW_HTABLE_SIZE; s_num = 0, slot++) { + num = 0; + + sk_for_each(sk, &hashinfo->ht[slot]) { + struct inet_sock *inet = inet_sk(sk); + + if (!net_eq(sock_net(sk), net)) + continue; + if (num < s_num) + goto next; + if (sk->sk_family != r->sdiag_family) + goto next; + if (r->id.idiag_sport != inet->inet_sport && + r->id.idiag_sport) + goto next; + if (r->id.idiag_dport != inet->inet_dport && + r->id.idiag_dport) + goto next; + if (sk_diag_dump(sk, skb, cb, r, bc) < 0) + goto out_unlock; +next: + num++; + } + } + +out_unlock: + read_unlock(&hashinfo->lock); + + cb->args[0] = slot; + cb->args[1] = num; +} + +static void raw_diag_get_info(struct sock *sk, struct inet_diag_msg *r, + void *info) +{ + r->idiag_rqueue = sk_rmem_alloc_get(sk); + r->idiag_wqueue = sk_wmem_alloc_get(sk); +} + +static int raw_diag_destroy(struct sk_buff *in_skb, + const struct inet_diag_req_v2 *r) +{ + struct net *net = sock_net(in_skb->sk); + struct sock *sk; + + sk = raw_sock_get(net, r); + if (IS_ERR(sk)) + return PTR_ERR(sk); + return sock_diag_destroy(sk, ECONNABORTED); +} + +static const struct inet_diag_handler raw_diag_handler = { + .dump = raw_diag_dump, + .dump_one = raw_diag_dump_one, + .idiag_get_info = raw_diag_get_info, + .idiag_type = IPPROTO_RAW, + .idiag_info_size = 0, + .destroy = raw_diag_destroy, +}; + +static int __init raw_diag_init(void) +{ + return inet_diag_register(&raw_diag_handler); +} + +static void __exit raw_diag_exit(void) +{ + inet_diag_unregister(&raw_diag_handler); +} + +module_init(raw_diag_init); +module_exit(raw_diag_exit); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-255 /* AF_INET - IPPROTO_RAW */); +MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 10-255 /* AF_INET6 - IPPROTO_RAW */); Index: linux-ml.git/net/ipv6/raw.c =================================================================== --- linux-ml.git.orig/net/ipv6/raw.c +++ linux-ml.git/net/ipv6/raw.c @@ -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 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2] net: ip, diag -- Add diag interface for raw sockets 2016-09-10 22:05 ` [PATCH v2] " Cyrill Gorcunov @ 2016-09-10 22:28 ` David Ahern 2016-09-11 19:17 ` [PATCH v3] " Cyrill Gorcunov 0 siblings, 1 reply; 10+ messages in thread From: David Ahern @ 2016-09-10 22:28 UTC (permalink / raw) To: Cyrill Gorcunov Cc: NETDEV, LKML, David S. Miller, Eric Dumazet, Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI, Patrick McHardy, Andrey Vagin, Stephen Hemminger On 9/10/16 4:05 PM, Cyrill Gorcunov wrote: > On Sat, Sep 10, 2016 at 10:31:35AM -0600, David Ahern wrote: >> >> Would you mind adding the destroy capability as well? The udp version >> should be close to what is needed for raw sockets. See udp_diag_destroy >> and udp_abort. > > Should be something like below. Didn't tested it yet so for review only. > Will do testing at Monday. doesn't compile: - raw_abort needs to be in a header for ipv6, and - inet_sk_diag_fill args have changed due to a recent commit ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v3] net: ip, diag -- Add diag interface for raw sockets 2016-09-10 22:28 ` David Ahern @ 2016-09-11 19:17 ` Cyrill Gorcunov 2016-09-13 15:57 ` David Miller 0 siblings, 1 reply; 10+ messages in thread From: Cyrill Gorcunov @ 2016-09-11 19:17 UTC (permalink / raw) To: David Ahern Cc: NETDEV, LKML, David S. Miller, Eric Dumazet, Alexey Kuznetsov, James Morris, Hideaki YOSHIFUJI, Patrick McHardy, Andrey Vagin, Stephen Hemminger On Sat, Sep 10, 2016 at 04:28:40PM -0600, David Ahern wrote: > On 9/10/16 4:05 PM, Cyrill Gorcunov wrote: > > On Sat, Sep 10, 2016 at 10:31:35AM -0600, David Ahern wrote: > >> > >> Would you mind adding the destroy capability as well? The udp version > >> should be close to what is needed for raw sockets. See udp_diag_destroy > >> and udp_abort. > > > > Should be something like below. Didn't tested it yet so for review only. > > Will do testing at Monday. > > doesn't compile: > - raw_abort needs to be in a header for ipv6, and > - inet_sk_diag_fill args have changed due to a recent commit Thanks for review, David. I updated against net-next. --- From: Cyrill Gorcunov <gorcunov@openvz.org> Subject: [PATCH v3] 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@) CC: David S. Miller <davem@davemloft.net> CC: Eric Dumazet <eric.dumazet@gmail.com> CC: David Ahern <dsa@cumulusnetworks.com> CC: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> CC: James Morris <jmorris@namei.org> CC: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org> CC: Patrick McHardy <kaber@trash.net> CC: Andrey Vagin <avagin@openvz.org> CC: Stephen Hemminger <stephen@networkplumber.org> Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org> --- include/net/raw.h | 5 + include/net/rawv6.h | 7 + net/ipv4/Kconfig | 8 + net/ipv4/Makefile | 1 net/ipv4/raw.c | 21 ++++ net/ipv4/raw_diag.c | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++++ net/ipv6/raw.c | 7 + 7 files changed, 271 insertions(+), 4 deletions(-) Index: linux-ml.git/include/net/raw.h =================================================================== --- linux-ml.git.orig/include/net/raw.h +++ linux-ml.git/include/net/raw.h @@ -23,6 +23,11 @@ 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); + void raw_icmp_error(struct sk_buff *, int, u32); int raw_local_deliver(struct sk_buff *, int); Index: linux-ml.git/include/net/rawv6.h =================================================================== --- linux-ml.git.orig/include/net/rawv6.h +++ linux-ml.git/include/net/rawv6.h @@ -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); Index: linux-ml.git/net/ipv4/Kconfig =================================================================== --- linux-ml.git.orig/net/ipv4/Kconfig +++ linux-ml.git/net/ipv4/Kconfig @@ -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 Index: linux-ml.git/net/ipv4/Makefile =================================================================== --- linux-ml.git.orig/net/ipv4/Makefile +++ linux-ml.git/net/ipv4/Makefile @@ -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 Index: linux-ml.git/net/ipv4/raw.c =================================================================== --- linux-ml.git.orig/net/ipv4/raw.c +++ linux-ml.git/net/ipv4/raw.c @@ -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 Index: linux-ml.git/net/ipv4/raw_diag.c =================================================================== --- /dev/null +++ linux-ml.git/net/ipv4/raw_diag.c @@ -0,0 +1,226 @@ +#include <linux/module.h> + +#include <linux/inet_diag.h> +#include <linux/sock_diag.h> + +#include <net/raw.h> +#include <net/rawv6.h> + +#ifdef pr_fmt +# undef pr_fmt +#endif + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +static struct raw_hashinfo * +raw_get_hashinfo(const struct inet_diag_req_v2 *r) +{ + if (r->sdiag_family == AF_INET) { + return &raw_v4_hashinfo; +#if IS_ENABLED(CONFIG_IPV6) + } else if (r->sdiag_family == AF_INET6) { + return &raw_v6_hashinfo; +#endif + } else { + pr_warn_once("Unexpected inet family %d\n", + r->sdiag_family); + WARN_ON_ONCE(1); + return ERR_PTR(-EINVAL); + } +} + +static struct sock *raw_lookup(struct net *net, struct sock *from, + const struct inet_diag_req_v2 *r) +{ + struct sock *sk = NULL; + + if (r->sdiag_family == AF_INET) + sk = __raw_v4_lookup(net, from, r->sdiag_protocol, + r->id.idiag_dst[0], + r->id.idiag_src[0], + r->id.idiag_if); +#if IS_ENABLED(CONFIG_IPV6) + else + sk = __raw_v6_lookup(net, from, r->sdiag_protocol, + (const struct in6_addr *)r->id.idiag_src, + (const struct in6_addr *)r->id.idiag_dst, + r->id.idiag_if); +#endif + return sk; +} + +static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2 *r) +{ + struct raw_hashinfo *hashinfo = raw_get_hashinfo(r); + struct sock *sk = NULL, *s; + int slot; + + if (IS_ERR(hashinfo)) + return ERR_CAST(hashinfo); + + read_lock(&hashinfo->lock); + for (slot = 0; slot < RAW_HTABLE_SIZE; slot++) { + sk_for_each(s, &hashinfo->ht[slot]) { + sk = raw_lookup(net, s, r); + if (sk) + break; + } + } + if (sk && !atomic_inc_not_zero(&sk->sk_refcnt)) + sk = NULL; + read_unlock(&hashinfo->lock); + + return sk ? sk : ERR_PTR(-ENOENT); +} + +static int raw_diag_dump_one(struct sk_buff *in_skb, + const struct nlmsghdr *nlh, + const struct inet_diag_req_v2 *r) +{ + struct net *net = sock_net(in_skb->sk); + struct sk_buff *rep; + struct sock *sk; + int err; + + sk = raw_sock_get(net, r); + if (IS_ERR(sk)) + return PTR_ERR(sk); + + rep = nlmsg_new(sizeof(struct inet_diag_msg) + + sizeof(struct inet_diag_meminfo) + 64, + GFP_KERNEL); + if (!rep) { + sock_put(sk); + return -ENOMEM; + } + + err = inet_sk_diag_fill(sk, NULL, rep, r, + sk_user_ns(NETLINK_CB(in_skb).sk), + NETLINK_CB(in_skb).portid, + nlh->nlmsg_seq, 0, nlh, + netlink_net_capable(in_skb, CAP_NET_ADMIN)); + sock_put(sk); + + if (err < 0) { + kfree_skb(rep); + return err; + } + + err = netlink_unicast(net->diag_nlsk, rep, + NETLINK_CB(in_skb).portid, + MSG_DONTWAIT); + if (err > 0) + err = 0; + return err; +} + +static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, + struct netlink_callback *cb, + const struct inet_diag_req_v2 *r, + struct nlattr *bc, bool net_admin) +{ + if (!inet_diag_bc_sk(bc, sk)) + return 0; + + return inet_sk_diag_fill(sk, NULL, skb, r, + sk_user_ns(NETLINK_CB(cb->skb).sk), + NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + cb->nlh, net_admin); +} + +static void raw_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, + const struct inet_diag_req_v2 *r, struct nlattr *bc) +{ + bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN); + struct raw_hashinfo *hashinfo = raw_get_hashinfo(r); + struct net *net = sock_net(skb->sk); + int num, s_num, slot, s_slot; + struct sock *sk = NULL; + + if (IS_ERR(hashinfo)) + return; + + s_slot = cb->args[0]; + num = s_num = cb->args[1]; + + read_lock(&hashinfo->lock); + for (slot = s_slot; slot < RAW_HTABLE_SIZE; s_num = 0, slot++) { + num = 0; + + sk_for_each(sk, &hashinfo->ht[slot]) { + struct inet_sock *inet = inet_sk(sk); + + if (!net_eq(sock_net(sk), net)) + continue; + if (num < s_num) + goto next; + if (sk->sk_family != r->sdiag_family) + goto next; + if (r->id.idiag_sport != inet->inet_sport && + r->id.idiag_sport) + goto next; + if (r->id.idiag_dport != inet->inet_dport && + r->id.idiag_dport) + goto next; + if (sk_diag_dump(sk, skb, cb, r, bc, net_admin) < 0) + goto out_unlock; +next: + num++; + } + } + +out_unlock: + read_unlock(&hashinfo->lock); + + cb->args[0] = slot; + cb->args[1] = num; +} + +static void raw_diag_get_info(struct sock *sk, struct inet_diag_msg *r, + void *info) +{ + r->idiag_rqueue = sk_rmem_alloc_get(sk); + r->idiag_wqueue = sk_wmem_alloc_get(sk); +} + +#ifdef CONFIG_INET_DIAG_DESTROY +static int raw_diag_destroy(struct sk_buff *in_skb, + const struct inet_diag_req_v2 *r) +{ + struct net *net = sock_net(in_skb->sk); + struct sock *sk; + + sk = raw_sock_get(net, r); + if (IS_ERR(sk)) + return PTR_ERR(sk); + return sock_diag_destroy(sk, ECONNABORTED); +} +#endif + +static const struct inet_diag_handler raw_diag_handler = { + .dump = raw_diag_dump, + .dump_one = raw_diag_dump_one, + .idiag_get_info = raw_diag_get_info, + .idiag_type = IPPROTO_RAW, + .idiag_info_size = 0, +#ifdef CONFIG_INET_DIAG_DESTROY + .destroy = raw_diag_destroy, +#endif +}; + +static int __init raw_diag_init(void) +{ + return inet_diag_register(&raw_diag_handler); +} + +static void __exit raw_diag_exit(void) +{ + inet_diag_unregister(&raw_diag_handler); +} + +module_init(raw_diag_init); +module_exit(raw_diag_exit); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-255 /* AF_INET - IPPROTO_RAW */); +MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 10-255 /* AF_INET6 - IPPROTO_RAW */); Index: linux-ml.git/net/ipv6/raw.c =================================================================== --- linux-ml.git.orig/net/ipv6/raw.c +++ linux-ml.git/net/ipv6/raw.c @@ -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 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3] net: ip, diag -- Add diag interface for raw sockets 2016-09-11 19:17 ` [PATCH v3] " Cyrill Gorcunov @ 2016-09-13 15:57 ` David Miller 2016-09-13 16:31 ` Cyrill Gorcunov 0 siblings, 1 reply; 10+ messages in thread From: David Miller @ 2016-09-13 15:57 UTC (permalink / raw) To: gorcunov Cc: dsa, netdev, linux-kernel, eric.dumazet, kuznet, jmorris, yoshfuji, kaber, avagin, stephen From: Cyrill Gorcunov <gorcunov@gmail.com> Date: Sun, 11 Sep 2016 22:17:15 +0300 > On Sat, Sep 10, 2016 at 04:28:40PM -0600, David Ahern wrote: >> On 9/10/16 4:05 PM, Cyrill Gorcunov wrote: >> > On Sat, Sep 10, 2016 at 10:31:35AM -0600, David Ahern wrote: >> >> >> >> Would you mind adding the destroy capability as well? The udp version >> >> should be close to what is needed for raw sockets. See udp_diag_destroy >> >> and udp_abort. >> > >> > Should be something like below. Didn't tested it yet so for review only. >> > Will do testing at Monday. >> >> doesn't compile: >> - raw_abort needs to be in a header for ipv6, and >> - inet_sk_diag_fill args have changed due to a recent commit > > Thanks for review, David. I updated against net-next. Please do not post new versions of patches as replies to existing discussions. Instead, make fresh patch postings to the list. Thanks. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3] net: ip, diag -- Add diag interface for raw sockets 2016-09-13 15:57 ` David Miller @ 2016-09-13 16:31 ` Cyrill Gorcunov 0 siblings, 0 replies; 10+ messages in thread From: Cyrill Gorcunov @ 2016-09-13 16:31 UTC (permalink / raw) To: David Miller Cc: dsa, netdev, linux-kernel, eric.dumazet, kuznet, jmorris, yoshfuji, kaber, avagin, stephen On Tue, Sep 13, 2016 at 11:57:35AM -0400, David Miller wrote: > > > > Thanks for review, David. I updated against net-next. > > Please do not post new versions of patches as replies to existing > discussions. > > Instead, make fresh patch postings to the list. Oh, will do. Sorry for inconvenience. ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2016-09-13 16:31 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2016-09-09 18:26 [PATCH] net: ip, diag -- Add diag interface for raw sockets Cyrill Gorcunov 2016-09-09 19:55 ` Eric Dumazet 2016-09-09 20:17 ` Cyrill Gorcunov 2016-09-10 16:31 ` David Ahern 2016-09-10 19:31 ` Cyrill Gorcunov 2016-09-10 22:05 ` [PATCH v2] " Cyrill Gorcunov 2016-09-10 22:28 ` David Ahern 2016-09-11 19:17 ` [PATCH v3] " Cyrill Gorcunov 2016-09-13 15:57 ` David Miller 2016-09-13 16:31 ` Cyrill Gorcunov
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).