All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/13] Dumping AF_UNIX sockets via netlink
@ 2011-12-15 12:42 Pavel Emelyanov
  2011-12-15 12:42 ` [PATCH 1/13] sock_diag: Move the SOCK_DIAG_BY_FAMILY cmd declaration Pavel Emelyanov
                   ` (14 more replies)
  0 siblings, 15 replies; 18+ messages in thread
From: Pavel Emelyanov @ 2011-12-15 12:42 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

Make the unix_diag.ko module, which is the AF_UNIX client for the sock_diag.

Use the sock_i_ino() as the primary ID key for sockets. This is currently the
only unique (except for the sk address itself) ID of a unix socket and is de
facto used in the ss tool to identify sockets. Thus the basic nlk request and
response structures operate on this ID. Other socket info (sun_name, peer, etc.)
are reported in the respective NLA-s (patches 8 through 12).

There's a locking trickery in patch #11. I've tried to study it carefully and
checked with lockdep, but anyway, please, pay special attention to it.

The patch for ss tool is also included.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH 1/13] sock_diag: Move the SOCK_DIAG_BY_FAMILY cmd declaration
  2011-12-15 12:42 [PATCH 0/13] Dumping AF_UNIX sockets via netlink Pavel Emelyanov
@ 2011-12-15 12:42 ` Pavel Emelyanov
  2011-12-15 12:43 ` [PATCH 2/13] sock_diag: Fix module netlink aliases Pavel Emelyanov
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: Pavel Emelyanov @ 2011-12-15 12:42 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

It should belong to sock_diag, not inet_diag.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 include/linux/inet_diag.h |    1 -
 include/linux/sock_diag.h |    3 +++
 2 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
index 78972a1..a27e621 100644
--- a/include/linux/inet_diag.h
+++ b/include/linux/inet_diag.h
@@ -6,7 +6,6 @@
 /* Just some random number */
 #define TCPDIAG_GETSOCK 18
 #define DCCPDIAG_GETSOCK 19
-#define SOCK_DIAG_BY_FAMILY 20
 
 #define INET_DIAG_GETSOCK_MAX 24
 
diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h
index ba4933b..7999778 100644
--- a/include/linux/sock_diag.h
+++ b/include/linux/sock_diag.h
@@ -1,5 +1,8 @@
 #ifndef __SOCK_DIAG_H__
 #define __SOCK_DIAG_H__
+
+#define SOCK_DIAG_BY_FAMILY 20
+
 struct sk_buff;
 struct nlmsghdr;
 
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 2/13] sock_diag: Fix module netlink aliases
  2011-12-15 12:42 [PATCH 0/13] Dumping AF_UNIX sockets via netlink Pavel Emelyanov
  2011-12-15 12:42 ` [PATCH 1/13] sock_diag: Move the SOCK_DIAG_BY_FAMILY cmd declaration Pavel Emelyanov
@ 2011-12-15 12:43 ` Pavel Emelyanov
  2011-12-15 12:43 ` [PATCH 3/13] sock_diag: Generalize requests cookies managements Pavel Emelyanov
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: Pavel Emelyanov @ 2011-12-15 12:43 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

I've made a mistake when fixing the sock_/inet_diag aliases :(

1. The sock_diag layer should request the family-based alias,
   not just the IPPROTO_IP one;
2. The inet_diag layer should request for AF_INET+protocol alias,
   not just the protocol one.

Thus fix this.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 net/core/sock_diag.c |    4 ++--
 net/dccp/diag.c      |    2 +-
 net/ipv4/inet_diag.c |    7 ++++---
 net/ipv4/tcp_diag.c  |    2 +-
 net/ipv4/udp_diag.c  |    4 ++--
 5 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
index 9c27bcd..cee96f3 100644
--- a/net/core/sock_diag.c
+++ b/net/core/sock_diag.c
@@ -64,7 +64,7 @@ static inline struct sock_diag_handler *sock_diag_lock_handler(int family)
 {
 	if (sock_diag_handlers[family] == NULL)
 		request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
-				NETLINK_SOCK_DIAG, IPPROTO_IP);
+				NETLINK_SOCK_DIAG, family);
 
 	mutex_lock(&sock_diag_table_mutex);
 	return sock_diag_handlers[family];
@@ -103,7 +103,7 @@ static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 	case DCCPDIAG_GETSOCK:
 		if (inet_rcv_compat == NULL)
 			request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
-					NETLINK_SOCK_DIAG, IPPROTO_IP);
+					NETLINK_SOCK_DIAG, AF_INET);
 
 		mutex_lock(&sock_diag_table_mutex);
 		if (inet_rcv_compat != NULL)
diff --git a/net/dccp/diag.c b/net/dccp/diag.c
index e29214d..8f16257 100644
--- a/net/dccp/diag.c
+++ b/net/dccp/diag.c
@@ -83,4 +83,4 @@ module_exit(dccp_diag_fini);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Arnaldo Carvalho de Melo <acme@mandriva.com>");
 MODULE_DESCRIPTION("DCCP inet_diag handler");
-MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 33);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-33 /* AF_INET - IPPROTO_DCCP */);
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 575e28c..fa27313 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -54,8 +54,8 @@ static DEFINE_MUTEX(inet_diag_table_mutex);
 static const struct inet_diag_handler *inet_diag_lock_handler(int proto)
 {
 	if (!inet_diag_table[proto])
-		request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
-			       NETLINK_SOCK_DIAG, proto);
+		request_module("net-pf-%d-proto-%d-type-%d-%d", PF_NETLINK,
+			       NETLINK_SOCK_DIAG, AF_INET, proto);
 
 	mutex_lock(&inet_diag_table_mutex);
 	if (!inet_diag_table[proto])
@@ -1087,4 +1087,5 @@ static void __exit inet_diag_exit(void)
 module_init(inet_diag_init);
 module_exit(inet_diag_exit);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 0);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2 /* AF_INET */);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 10 /* AF_INET6 */);
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index 6334b1f..8cd357a 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -66,4 +66,4 @@ static void __exit tcp_diag_exit(void)
 module_init(tcp_diag_init);
 module_exit(tcp_diag_exit);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 6);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-6 /* AF_INET - IPPROTO_TCP */);
diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c
index 27910c1..fe9db86 100644
--- a/net/ipv4/udp_diag.c
+++ b/net/ipv4/udp_diag.c
@@ -197,5 +197,5 @@ static void __exit udp_diag_exit(void)
 module_init(udp_diag_init);
 module_exit(udp_diag_exit);
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 17);
-MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 136);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-17 /* AF_INET - IPPROTO_UDP */);
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-136 /* AF_INET - IPPROTO_UDPLITE */);
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 3/13] sock_diag: Generalize requests cookies managements
  2011-12-15 12:42 [PATCH 0/13] Dumping AF_UNIX sockets via netlink Pavel Emelyanov
  2011-12-15 12:42 ` [PATCH 1/13] sock_diag: Move the SOCK_DIAG_BY_FAMILY cmd declaration Pavel Emelyanov
  2011-12-15 12:43 ` [PATCH 2/13] sock_diag: Fix module netlink aliases Pavel Emelyanov
@ 2011-12-15 12:43 ` Pavel Emelyanov
  2011-12-15 12:44 ` [PATCH 4/13] af_unix: Export stuff required for diag module Pavel Emelyanov
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: Pavel Emelyanov @ 2011-12-15 12:43 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

The sk address is used as a cookie between dump/get_exact calls.
It will be required for unix socket sdumping, so move it from
inet_diag to sock_diag.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 include/linux/inet_diag.h |    1 -
 include/linux/sock_diag.h |    3 +++
 net/core/sock_diag.c      |   19 +++++++++++++++++++
 net/ipv4/inet_diag.c      |   23 ++++-------------------
 net/ipv4/udp_diag.c       |    2 +-
 5 files changed, 27 insertions(+), 21 deletions(-)

diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
index a27e621..afa5d5c 100644
--- a/include/linux/inet_diag.h
+++ b/include/linux/inet_diag.h
@@ -168,7 +168,6 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo,
 		struct inet_diag_req *req);
 
 int inet_diag_bc_sk(const struct nlattr *_bc, struct sock *sk);
-int inet_diag_check_cookie(struct sock *sk, struct inet_diag_req *req);
 
 extern int  inet_diag_register(const struct inet_diag_handler *handler);
 extern void inet_diag_unregister(const struct inet_diag_handler *handler);
diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h
index 7999778..379d5dc 100644
--- a/include/linux/sock_diag.h
+++ b/include/linux/sock_diag.h
@@ -22,5 +22,8 @@ void sock_diag_unregister(struct sock_diag_handler *h);
 void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh));
 void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh));
 
+int sock_diag_check_cookie(void *sk, __u32 *cookie);
+void sock_diag_save_cookie(void *sk, __u32 *cookie);
+
 extern struct sock *sock_diag_nlsk;
 #endif
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c
index cee96f3..711bdef 100644
--- a/net/core/sock_diag.c
+++ b/net/core/sock_diag.c
@@ -12,6 +12,25 @@ static struct sock_diag_handler *sock_diag_handlers[AF_MAX];
 static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh);
 static DEFINE_MUTEX(sock_diag_table_mutex);
 
+int sock_diag_check_cookie(void *sk, __u32 *cookie)
+{
+	if ((cookie[0] != INET_DIAG_NOCOOKIE ||
+	     cookie[1] != INET_DIAG_NOCOOKIE) &&
+	    ((u32)(unsigned long)sk != cookie[0] ||
+	     (u32)((((unsigned long)sk) >> 31) >> 1) != cookie[1]))
+		return -ESTALE;
+	else
+		return 0;
+}
+EXPORT_SYMBOL_GPL(sock_diag_check_cookie);
+
+void sock_diag_save_cookie(void *sk, __u32 *cookie)
+{
+	cookie[0] = (u32)(unsigned long)sk;
+	cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1);
+}
+EXPORT_SYMBOL_GPL(sock_diag_save_cookie);
+
 void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh))
 {
 	mutex_lock(&sock_diag_table_mutex);
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index fa27313..fb2e47f 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -102,8 +102,7 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk,
 	r->idiag_retrans = 0;
 
 	r->id.idiag_if = sk->sk_bound_dev_if;
-	r->id.idiag_cookie[0] = (u32)(unsigned long)sk;
-	r->id.idiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1);
+	sock_diag_save_cookie(sk, r->id.idiag_cookie);
 
 	r->id.idiag_sport = inet->inet_sport;
 	r->id.idiag_dport = inet->inet_dport;
@@ -221,8 +220,7 @@ static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
 	r->idiag_family	      = tw->tw_family;
 	r->idiag_retrans      = 0;
 	r->id.idiag_if	      = tw->tw_bound_dev_if;
-	r->id.idiag_cookie[0] = (u32)(unsigned long)tw;
-	r->id.idiag_cookie[1] = (u32)(((unsigned long)tw >> 31) >> 1);
+	sock_diag_save_cookie(tw, r->id.idiag_cookie);
 	r->id.idiag_sport     = tw->tw_sport;
 	r->id.idiag_dport     = tw->tw_dport;
 	r->id.idiag_src[0]    = tw->tw_rcv_saddr;
@@ -261,18 +259,6 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
 	return inet_csk_diag_fill(sk, skb, r, pid, seq, nlmsg_flags, unlh);
 }
 
-int inet_diag_check_cookie(struct sock *sk, struct inet_diag_req *req)
-{
-	if ((req->id.idiag_cookie[0] != INET_DIAG_NOCOOKIE ||
-	     req->id.idiag_cookie[1] != INET_DIAG_NOCOOKIE) &&
-	    ((u32)(unsigned long)sk != req->id.idiag_cookie[0] ||
-	     (u32)((((unsigned long)sk) >> 31) >> 1) != req->id.idiag_cookie[1]))
-		return -ESTALE;
-	else
-		return 0;
-}
-EXPORT_SYMBOL_GPL(inet_diag_check_cookie);
-
 int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_skb,
 		const struct nlmsghdr *nlh, struct inet_diag_req *req)
 {
@@ -304,7 +290,7 @@ int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *in_s
 	if (sk == NULL)
 		goto out_nosk;
 
-	err = inet_diag_check_cookie(sk, req);
+	err = sock_diag_check_cookie(sk, req->id.idiag_cookie);
 	if (err)
 		goto out;
 
@@ -617,8 +603,7 @@ static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
 	r->idiag_retrans = req->retrans;
 
 	r->id.idiag_if = sk->sk_bound_dev_if;
-	r->id.idiag_cookie[0] = (u32)(unsigned long)req;
-	r->id.idiag_cookie[1] = (u32)(((unsigned long)req >> 31) >> 1);
+	sock_diag_save_cookie(req, r->id.idiag_cookie);
 
 	tmo = req->expires - jiffies;
 	if (tmo < 0)
diff --git a/net/ipv4/udp_diag.c b/net/ipv4/udp_diag.c
index fe9db86..69f8a7c 100644
--- a/net/ipv4/udp_diag.c
+++ b/net/ipv4/udp_diag.c
@@ -57,7 +57,7 @@ static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
 	if (sk == NULL)
 		goto out_nosk;
 
-	err = inet_diag_check_cookie(sk, req);
+	err = sock_diag_check_cookie(sk, req->id.idiag_cookie);
 	if (err)
 		goto out;
 
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 4/13] af_unix: Export stuff required for diag module
  2011-12-15 12:42 [PATCH 0/13] Dumping AF_UNIX sockets via netlink Pavel Emelyanov
                   ` (2 preceding siblings ...)
  2011-12-15 12:43 ` [PATCH 3/13] sock_diag: Generalize requests cookies managements Pavel Emelyanov
@ 2011-12-15 12:44 ` Pavel Emelyanov
  2011-12-15 12:44 ` [PATCH 5/13] unix_diag: Basic module skeleton Pavel Emelyanov
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: Pavel Emelyanov @ 2011-12-15 12:44 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 include/net/af_unix.h |    3 +++
 net/unix/af_unix.c    |    9 ++++++---
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 91ab5b0..63b1781 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -11,10 +11,13 @@ extern void unix_notinflight(struct file *fp);
 extern void unix_gc(void);
 extern void wait_for_unix_gc(void);
 extern struct sock *unix_get_socket(struct file *filp);
+extern struct sock *unix_peer_get(struct sock *);
 
 #define UNIX_HASH_SIZE	256
 
 extern unsigned int unix_tot_inflight;
+extern spinlock_t unix_table_lock;
+extern struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1];
 
 struct unix_address {
 	atomic_t	refcnt;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index b595a3d..e1b9358 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -115,8 +115,10 @@
 #include <net/checksum.h>
 #include <linux/security.h>
 
-static struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1];
-static DEFINE_SPINLOCK(unix_table_lock);
+struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1];
+EXPORT_SYMBOL_GPL(unix_socket_table);
+DEFINE_SPINLOCK(unix_table_lock);
+EXPORT_SYMBOL_GPL(unix_table_lock);
 static atomic_long_t unix_nr_socks;
 
 #define unix_sockets_unbound	(&unix_socket_table[UNIX_HASH_SIZE])
@@ -172,7 +174,7 @@ static inline int unix_recvq_full(struct sock const *sk)
 	return skb_queue_len(&sk->sk_receive_queue) > sk->sk_max_ack_backlog;
 }
 
-static struct sock *unix_peer_get(struct sock *s)
+struct sock *unix_peer_get(struct sock *s)
 {
 	struct sock *peer;
 
@@ -183,6 +185,7 @@ static struct sock *unix_peer_get(struct sock *s)
 	unix_state_unlock(s);
 	return peer;
 }
+EXPORT_SYMBOL_GPL(unix_peer_get);
 
 static inline void unix_release_addr(struct unix_address *addr)
 {
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 5/13] unix_diag: Basic module skeleton
  2011-12-15 12:42 [PATCH 0/13] Dumping AF_UNIX sockets via netlink Pavel Emelyanov
                   ` (3 preceding siblings ...)
  2011-12-15 12:44 ` [PATCH 4/13] af_unix: Export stuff required for diag module Pavel Emelyanov
@ 2011-12-15 12:44 ` Pavel Emelyanov
  2011-12-15 12:44 ` [PATCH 6/13] unix_diag: Dumping all sockets core Pavel Emelyanov
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: Pavel Emelyanov @ 2011-12-15 12:44 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

Includes basic module_init/_exit functionality, dump/get_exact stubs
and declares the basic API structures for request and response.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 include/linux/unix_diag.h |   24 +++++++++++++++++++
 net/unix/diag.c           |   57 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 81 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/unix_diag.h
 create mode 100644 net/unix/diag.c

diff --git a/include/linux/unix_diag.h b/include/linux/unix_diag.h
new file mode 100644
index 0000000..445184a
--- /dev/null
+++ b/include/linux/unix_diag.h
@@ -0,0 +1,24 @@
+#ifndef __UNIX_DIAG_H__
+#define __UNIX_DIAG_H__
+
+struct unix_diag_req {
+	__u8	sdiag_family;
+	__u8	sdiag_protocol;
+	__u16	pad;
+	__u32	udiag_states;
+	__u32	udiag_ino;
+	__u32	udiag_show;
+	__u32	udiag_cookie[2];
+};
+
+struct unix_diag_msg {
+	__u8	udiag_family;
+	__u8	udiag_type;
+	__u8	udiag_state;
+	__u8	pad;
+
+	__u32	udiag_ino;
+	__u32	udiag_cookie[2];
+};
+
+#endif
diff --git a/net/unix/diag.c b/net/unix/diag.c
new file mode 100644
index 0000000..6be16c0
--- /dev/null
+++ b/net/unix/diag.c
@@ -0,0 +1,57 @@
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/sock_diag.h>
+#include <linux/unix_diag.h>
+#include <linux/skbuff.h>
+#include <net/netlink.h>
+#include <net/af_unix.h>
+#include <net/tcp_states.h>
+
+#define UNIX_DIAG_PUT(skb, attrtype, attrlen) \
+	RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
+
+static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	return 0;
+}
+
+static int unix_diag_get_exact(struct sk_buff *in_skb,
+			       const struct nlmsghdr *nlh,
+			       struct unix_diag_req *req)
+{
+	return -EAFNOSUPPORT;
+}
+
+static int unix_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
+{
+	int hdrlen = sizeof(struct unix_diag_req);
+
+	if (nlmsg_len(h) < hdrlen)
+		return -EINVAL;
+
+	if (h->nlmsg_flags & NLM_F_DUMP)
+		return netlink_dump_start(sock_diag_nlsk, skb, h,
+					  unix_diag_dump, NULL, 0);
+	else
+		return unix_diag_get_exact(skb, h, (struct unix_diag_req *)NLMSG_DATA(h));
+}
+
+static struct sock_diag_handler unix_diag_handler = {
+	.family = AF_UNIX,
+	.dump = unix_diag_handler_dump,
+};
+
+static int __init unix_diag_init(void)
+{
+	return sock_diag_register(&unix_diag_handler);
+}
+
+static void __exit unix_diag_exit(void)
+{
+	sock_diag_unregister(&unix_diag_handler);
+}
+
+module_init(unix_diag_init);
+module_exit(unix_diag_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 1 /* AF_LOCAL */);
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 6/13] unix_diag: Dumping all sockets core
  2011-12-15 12:42 [PATCH 0/13] Dumping AF_UNIX sockets via netlink Pavel Emelyanov
                   ` (4 preceding siblings ...)
  2011-12-15 12:44 ` [PATCH 5/13] unix_diag: Basic module skeleton Pavel Emelyanov
@ 2011-12-15 12:44 ` Pavel Emelyanov
  2011-12-15 12:45 ` [PATCH 7/13] unix_diag: Dumping exact socket core Pavel Emelyanov
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: Pavel Emelyanov @ 2011-12-15 12:44 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

Walk the unix sockets table and fill the core response structure,
which includes type, state and inode.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 net/unix/diag.c |   76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 75 insertions(+), 1 deletions(-)

diff --git a/net/unix/diag.c b/net/unix/diag.c
index 6be16c0..86d85ab 100644
--- a/net/unix/diag.c
+++ b/net/unix/diag.c
@@ -10,9 +10,83 @@
 #define UNIX_DIAG_PUT(skb, attrtype, attrlen) \
 	RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
 
+static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req,
+		u32 pid, u32 seq, u32 flags, int sk_ino)
+{
+	unsigned char *b = skb_tail_pointer(skb);
+	struct nlmsghdr *nlh;
+	struct unix_diag_msg *rep;
+
+	nlh = NLMSG_PUT(skb, pid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep));
+	nlh->nlmsg_flags = flags;
+
+	rep = NLMSG_DATA(nlh);
+
+	rep->udiag_family = AF_UNIX;
+	rep->udiag_type = sk->sk_type;
+	rep->udiag_state = sk->sk_state;
+	rep->udiag_ino = sk_ino;
+	sock_diag_save_cookie(sk, rep->udiag_cookie);
+
+	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
+	return skb->len;
+
+nlmsg_failure:
+	nlmsg_trim(skb, b);
+	return -EMSGSIZE;
+}
+
+static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req,
+		u32 pid, u32 seq, u32 flags)
+{
+	int sk_ino;
+
+	unix_state_lock(sk);
+	sk_ino = sock_i_ino(sk);
+	unix_state_unlock(sk);
+
+	if (!sk_ino)
+		return 0;
+
+	return sk_diag_fill(sk, skb, req, pid, seq, flags, sk_ino);
+}
+
 static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 {
-	return 0;
+	struct unix_diag_req *req;
+	int num, s_num, slot, s_slot;
+
+	req = NLMSG_DATA(cb->nlh);
+
+	s_slot = cb->args[0];
+	num = s_num = cb->args[1];
+
+	spin_lock(&unix_table_lock);
+	for (slot = s_slot; slot <= UNIX_HASH_SIZE; s_num = 0, slot++) {
+		struct sock *sk;
+		struct hlist_node *node;
+
+		num = 0;
+		sk_for_each(sk, node, &unix_socket_table[slot]) {
+			if (num < s_num)
+				goto next;
+			if (!(req->udiag_states & (1 << sk->sk_state)))
+				goto next;
+			if (sk_diag_dump(sk, skb, req,
+						NETLINK_CB(cb->skb).pid,
+						cb->nlh->nlmsg_seq,
+						NLM_F_MULTI) < 0)
+				goto done;
+next:
+			num++;
+		}
+	}
+done:
+	spin_unlock(&unix_table_lock);
+	cb->args[0] = slot;
+	cb->args[1] = num;
+
+	return skb->len;
 }
 
 static int unix_diag_get_exact(struct sk_buff *in_skb,
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 7/13] unix_diag: Dumping exact socket core
  2011-12-15 12:42 [PATCH 0/13] Dumping AF_UNIX sockets via netlink Pavel Emelyanov
                   ` (5 preceding siblings ...)
  2011-12-15 12:44 ` [PATCH 6/13] unix_diag: Dumping all sockets core Pavel Emelyanov
@ 2011-12-15 12:45 ` Pavel Emelyanov
  2011-12-15 12:45 ` [PATCH 8/13] unix_diag: Unix socket name NLA Pavel Emelyanov
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: Pavel Emelyanov @ 2011-12-15 12:45 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

The socket inode is used as a key for lookup. This is effectively
the only really unique ID of a unix socket, but using this for
search currently has one problem -- it is O(number of sockets) :(

Does it worth fixing this lookup or inventing some other ID for
unix sockets?

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 net/unix/diag.c |   67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 66 insertions(+), 1 deletions(-)

diff --git a/net/unix/diag.c b/net/unix/diag.c
index 86d85ab..d7bd48c 100644
--- a/net/unix/diag.c
+++ b/net/unix/diag.c
@@ -89,11 +89,76 @@ done:
 	return skb->len;
 }
 
+static struct sock *unix_lookup_by_ino(int ino)
+{
+	int i;
+	struct sock *sk;
+
+	spin_lock(&unix_table_lock);
+	for (i = 0; i <= UNIX_HASH_SIZE; i++) {
+		struct hlist_node *node;
+
+		sk_for_each(sk, node, &unix_socket_table[i])
+			if (ino == sock_i_ino(sk)) {
+				sock_hold(sk);
+				spin_unlock(&unix_table_lock);
+
+				return sk;
+			}
+	}
+
+	spin_unlock(&unix_table_lock);
+	return NULL;
+}
+
 static int unix_diag_get_exact(struct sk_buff *in_skb,
 			       const struct nlmsghdr *nlh,
 			       struct unix_diag_req *req)
 {
-	return -EAFNOSUPPORT;
+	int err = -EINVAL;
+	struct sock *sk;
+	struct sk_buff *rep;
+	unsigned int extra_len;
+
+	if (req->udiag_ino == 0)
+		goto out_nosk;
+
+	sk = unix_lookup_by_ino(req->udiag_ino);
+	err = -ENOENT;
+	if (sk == NULL)
+		goto out_nosk;
+
+	err = sock_diag_check_cookie(sk, req->udiag_cookie);
+	if (err)
+		goto out;
+
+	extra_len = 256;
+again:
+	err = -ENOMEM;
+	rep = alloc_skb(NLMSG_SPACE((sizeof(struct unix_diag_msg) + extra_len)),
+			GFP_KERNEL);
+	if (!rep)
+		goto out;
+
+	err = sk_diag_fill(sk, rep, req, NETLINK_CB(in_skb).pid,
+			   nlh->nlmsg_seq, 0, req->udiag_ino);
+	if (err < 0) {
+		kfree_skb(rep);
+		extra_len += 256;
+		if (extra_len >= PAGE_SIZE)
+			goto out;
+
+		goto again;
+	}
+	err = netlink_unicast(sock_diag_nlsk, rep, NETLINK_CB(in_skb).pid,
+			      MSG_DONTWAIT);
+	if (err > 0)
+		err = 0;
+out:
+	if (sk)
+		sock_put(sk);
+out_nosk:
+	return err;
 }
 
 static int unix_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 8/13] unix_diag: Unix socket name NLA
  2011-12-15 12:42 [PATCH 0/13] Dumping AF_UNIX sockets via netlink Pavel Emelyanov
                   ` (6 preceding siblings ...)
  2011-12-15 12:45 ` [PATCH 7/13] unix_diag: Dumping exact socket core Pavel Emelyanov
@ 2011-12-15 12:45 ` Pavel Emelyanov
  2011-12-15 12:45 ` [PATCH 9/13] unix_diag: Unix inode info NLA Pavel Emelyanov
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: Pavel Emelyanov @ 2011-12-15 12:45 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

Report the sun_path when requested as NLA. With leading '\0' if
present but without the leading AF_UNIX bits.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 include/linux/unix_diag.h |    8 ++++++++
 net/unix/diag.c           |   20 ++++++++++++++++++++
 2 files changed, 28 insertions(+), 0 deletions(-)

diff --git a/include/linux/unix_diag.h b/include/linux/unix_diag.h
index 445184a..cc4df34 100644
--- a/include/linux/unix_diag.h
+++ b/include/linux/unix_diag.h
@@ -11,6 +11,8 @@ struct unix_diag_req {
 	__u32	udiag_cookie[2];
 };
 
+#define UDIAG_SHOW_NAME		0x00000001	/* show name (not path) */
+
 struct unix_diag_msg {
 	__u8	udiag_family;
 	__u8	udiag_type;
@@ -21,4 +23,10 @@ struct unix_diag_msg {
 	__u32	udiag_cookie[2];
 };
 
+enum {
+	UNIX_DIAG_NAME,
+
+	UNIX_DIAG_MAX,
+};
+
 #endif
diff --git a/net/unix/diag.c b/net/unix/diag.c
index d7bd48c..161ce6c 100644
--- a/net/unix/diag.c
+++ b/net/unix/diag.c
@@ -10,6 +10,22 @@
 #define UNIX_DIAG_PUT(skb, attrtype, attrlen) \
 	RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
 
+static int sk_diag_dump_name(struct sock *sk, struct sk_buff *nlskb)
+{
+	struct unix_address *addr = unix_sk(sk)->addr;
+	char *s;
+
+	if (addr) {
+		s = UNIX_DIAG_PUT(nlskb, UNIX_DIAG_NAME, addr->len - sizeof(short));
+		memcpy(s, addr->name->sun_path, addr->len - sizeof(short));
+	}
+
+	return 0;
+
+rtattr_failure:
+	return -EMSGSIZE;
+}
+
 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req,
 		u32 pid, u32 seq, u32 flags, int sk_ino)
 {
@@ -28,6 +44,10 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_r
 	rep->udiag_ino = sk_ino;
 	sock_diag_save_cookie(sk, rep->udiag_cookie);
 
+	if ((req->udiag_show & UDIAG_SHOW_NAME) &&
+			sk_diag_dump_name(sk, skb))
+		goto nlmsg_failure;
+
 	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 9/13] unix_diag: Unix inode info NLA
  2011-12-15 12:42 [PATCH 0/13] Dumping AF_UNIX sockets via netlink Pavel Emelyanov
                   ` (7 preceding siblings ...)
  2011-12-15 12:45 ` [PATCH 8/13] unix_diag: Unix socket name NLA Pavel Emelyanov
@ 2011-12-15 12:45 ` Pavel Emelyanov
  2011-12-15 12:45 ` [PATCH 10/13] unix_diag: Unix peer inode NLA Pavel Emelyanov
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: Pavel Emelyanov @ 2011-12-15 12:45 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

Actually, the socket path if it's not anonymous doesn't give
a clue to which file the socket is bound to. Even if the path
is absolute, it can be unlinked and then new socket can be
bound to it.

With this NLA it's possible to check which file a particular
socket is really bound to.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 include/linux/unix_diag.h |    7 +++++++
 net/unix/diag.c           |   21 +++++++++++++++++++++
 2 files changed, 28 insertions(+), 0 deletions(-)

diff --git a/include/linux/unix_diag.h b/include/linux/unix_diag.h
index cc4df34..3e53adb 100644
--- a/include/linux/unix_diag.h
+++ b/include/linux/unix_diag.h
@@ -12,6 +12,7 @@ struct unix_diag_req {
 };
 
 #define UDIAG_SHOW_NAME		0x00000001	/* show name (not path) */
+#define UDIAG_SHOW_VFS		0x00000002	/* show VFS inode info */
 
 struct unix_diag_msg {
 	__u8	udiag_family;
@@ -25,8 +26,14 @@ struct unix_diag_msg {
 
 enum {
 	UNIX_DIAG_NAME,
+	UNIX_DIAG_VFS,
 
 	UNIX_DIAG_MAX,
 };
 
+struct unix_diag_vfs {
+	__u32	udiag_vfs_ino;
+	__u32	udiag_vfs_dev;
+};
+
 #endif
diff --git a/net/unix/diag.c b/net/unix/diag.c
index 161ce6c..83799ef 100644
--- a/net/unix/diag.c
+++ b/net/unix/diag.c
@@ -26,6 +26,23 @@ rtattr_failure:
 	return -EMSGSIZE;
 }
 
+static int sk_diag_dump_vfs(struct sock *sk, struct sk_buff *nlskb)
+{
+	struct dentry *dentry = unix_sk(sk)->dentry;
+	struct unix_diag_vfs *uv;
+
+	if (dentry) {
+		uv = UNIX_DIAG_PUT(nlskb, UNIX_DIAG_VFS, sizeof(*uv));
+		uv->udiag_vfs_ino = dentry->d_inode->i_ino;
+		uv->udiag_vfs_dev = dentry->d_sb->s_dev;
+	}
+
+	return 0;
+
+rtattr_failure:
+	return -EMSGSIZE;
+}
+
 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req,
 		u32 pid, u32 seq, u32 flags, int sk_ino)
 {
@@ -48,6 +65,10 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_r
 			sk_diag_dump_name(sk, skb))
 		goto nlmsg_failure;
 
+	if ((req->udiag_show & UDIAG_SHOW_VFS) &&
+			sk_diag_dump_vfs(sk, skb))
+		goto nlmsg_failure;
+
 	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 10/13] unix_diag: Unix peer inode NLA
  2011-12-15 12:42 [PATCH 0/13] Dumping AF_UNIX sockets via netlink Pavel Emelyanov
                   ` (8 preceding siblings ...)
  2011-12-15 12:45 ` [PATCH 9/13] unix_diag: Unix inode info NLA Pavel Emelyanov
@ 2011-12-15 12:45 ` Pavel Emelyanov
  2011-12-15 12:46 ` [PATCH 11/13] unix_diag: Pending connections IDs NLA Pavel Emelyanov
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: Pavel Emelyanov @ 2011-12-15 12:45 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

Report the peer socket inode ID as NLA. With this it's finally
possible to find out the other end of an interesting unix connection.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 include/linux/unix_diag.h |    2 ++
 net/unix/diag.c           |   24 ++++++++++++++++++++++++
 2 files changed, 26 insertions(+), 0 deletions(-)

diff --git a/include/linux/unix_diag.h b/include/linux/unix_diag.h
index 3e53adb..2d74a86 100644
--- a/include/linux/unix_diag.h
+++ b/include/linux/unix_diag.h
@@ -13,6 +13,7 @@ struct unix_diag_req {
 
 #define UDIAG_SHOW_NAME		0x00000001	/* show name (not path) */
 #define UDIAG_SHOW_VFS		0x00000002	/* show VFS inode info */
+#define UDIAG_SHOW_PEER		0x00000004	/* show peer socket info */
 
 struct unix_diag_msg {
 	__u8	udiag_family;
@@ -27,6 +28,7 @@ struct unix_diag_msg {
 enum {
 	UNIX_DIAG_NAME,
 	UNIX_DIAG_VFS,
+	UNIX_DIAG_PEER,
 
 	UNIX_DIAG_MAX,
 };
diff --git a/net/unix/diag.c b/net/unix/diag.c
index 83799ef..0e0fda7 100644
--- a/net/unix/diag.c
+++ b/net/unix/diag.c
@@ -43,6 +43,26 @@ rtattr_failure:
 	return -EMSGSIZE;
 }
 
+static int sk_diag_dump_peer(struct sock *sk, struct sk_buff *nlskb)
+{
+	struct sock *peer;
+	int ino;
+
+	peer = unix_peer_get(sk);
+	if (peer) {
+		unix_state_lock(peer);
+		ino = sock_i_ino(peer);
+		unix_state_unlock(peer);
+		sock_put(peer);
+
+		RTA_PUT_U32(nlskb, UNIX_DIAG_PEER, ino);
+	}
+
+	return 0;
+rtattr_failure:
+	return -EMSGSIZE;
+}
+
 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req,
 		u32 pid, u32 seq, u32 flags, int sk_ino)
 {
@@ -69,6 +89,10 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_r
 			sk_diag_dump_vfs(sk, skb))
 		goto nlmsg_failure;
 
+	if ((req->udiag_show & UDIAG_SHOW_PEER) &&
+			sk_diag_dump_peer(sk, skb))
+		goto nlmsg_failure;
+
 	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 11/13] unix_diag: Pending connections IDs NLA
  2011-12-15 12:42 [PATCH 0/13] Dumping AF_UNIX sockets via netlink Pavel Emelyanov
                   ` (9 preceding siblings ...)
  2011-12-15 12:45 ` [PATCH 10/13] unix_diag: Unix peer inode NLA Pavel Emelyanov
@ 2011-12-15 12:46 ` Pavel Emelyanov
  2011-12-15 12:46 ` [PATCH 12/13] unix_diag: Receive queue lenght NLA Pavel Emelyanov
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: Pavel Emelyanov @ 2011-12-15 12:46 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

When establishing a unix connection on stream sockets the
server end receives an skb with socket in its receive queue.

Report who is waiting for these ends to be accepted for
listening sockets via NLA.


There's a lokcing issue with this -- the unix sk state lock is
required to access the peer, and it is taken under the listening
sk's queue lock. Strictly speaking the queue lock should be taken
inside the state lock, but since in this case these two sockets
are different it shouldn't lead to deadlock.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 include/linux/unix_diag.h |    2 ++
 net/unix/diag.c           |   39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+), 0 deletions(-)

diff --git a/include/linux/unix_diag.h b/include/linux/unix_diag.h
index 2d74a86..03ffb7d 100644
--- a/include/linux/unix_diag.h
+++ b/include/linux/unix_diag.h
@@ -14,6 +14,7 @@ struct unix_diag_req {
 #define UDIAG_SHOW_NAME		0x00000001	/* show name (not path) */
 #define UDIAG_SHOW_VFS		0x00000002	/* show VFS inode info */
 #define UDIAG_SHOW_PEER		0x00000004	/* show peer socket info */
+#define UDIAG_SHOW_ICONS	0x00000008	/* show pending connections */
 
 struct unix_diag_msg {
 	__u8	udiag_family;
@@ -29,6 +30,7 @@ enum {
 	UNIX_DIAG_NAME,
 	UNIX_DIAG_VFS,
 	UNIX_DIAG_PEER,
+	UNIX_DIAG_ICONS,
 
 	UNIX_DIAG_MAX,
 };
diff --git a/net/unix/diag.c b/net/unix/diag.c
index 0e0fda7..9d9e808 100644
--- a/net/unix/diag.c
+++ b/net/unix/diag.c
@@ -63,6 +63,41 @@ rtattr_failure:
 	return -EMSGSIZE;
 }
 
+static int sk_diag_dump_icons(struct sock *sk, struct sk_buff *nlskb)
+{
+	struct sk_buff *skb;
+	u32 *buf;
+	int i;
+
+	if (sk->sk_state == TCP_LISTEN) {
+		spin_lock(&sk->sk_receive_queue.lock);
+		buf = UNIX_DIAG_PUT(nlskb, UNIX_DIAG_ICONS, sk->sk_receive_queue.qlen);
+		i = 0;
+		skb_queue_walk(&sk->sk_receive_queue, skb) {
+			struct sock *req, *peer;
+
+			req = skb->sk;
+			/*
+			 * The state lock is outer for the same sk's
+			 * queue lock. With the other's queue locked it's
+			 * OK to lock the state.
+			 */
+			unix_state_lock_nested(req);
+			peer = unix_sk(req)->peer;
+			if (peer)
+				buf[i++] = sock_i_ino(peer);
+			unix_state_unlock(req);
+		}
+		spin_unlock(&sk->sk_receive_queue.lock);
+	}
+
+	return 0;
+
+rtattr_failure:
+	spin_unlock(&sk->sk_receive_queue.lock);
+	return -EMSGSIZE;
+}
+
 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req,
 		u32 pid, u32 seq, u32 flags, int sk_ino)
 {
@@ -93,6 +128,10 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_r
 			sk_diag_dump_peer(sk, skb))
 		goto nlmsg_failure;
 
+	if ((req->udiag_show & UDIAG_SHOW_ICONS) &&
+			sk_diag_dump_icons(sk, skb))
+		goto nlmsg_failure;
+
 	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 12/13] unix_diag: Receive queue lenght NLA
  2011-12-15 12:42 [PATCH 0/13] Dumping AF_UNIX sockets via netlink Pavel Emelyanov
                   ` (10 preceding siblings ...)
  2011-12-15 12:46 ` [PATCH 11/13] unix_diag: Pending connections IDs NLA Pavel Emelyanov
@ 2011-12-15 12:46 ` Pavel Emelyanov
  2011-12-15 12:46 ` [PATCH 13/13] unix_diag: Write it into kbuild Pavel Emelyanov
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 18+ messages in thread
From: Pavel Emelyanov @ 2011-12-15 12:46 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 include/linux/unix_diag.h |    2 ++
 net/unix/diag.c           |   13 +++++++++++++
 2 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/include/linux/unix_diag.h b/include/linux/unix_diag.h
index 03ffb7d..3f7afb0 100644
--- a/include/linux/unix_diag.h
+++ b/include/linux/unix_diag.h
@@ -15,6 +15,7 @@ struct unix_diag_req {
 #define UDIAG_SHOW_VFS		0x00000002	/* show VFS inode info */
 #define UDIAG_SHOW_PEER		0x00000004	/* show peer socket info */
 #define UDIAG_SHOW_ICONS	0x00000008	/* show pending connections */
+#define UDIAG_SHOW_RQLEN	0x00000010	/* show skb receive queue len */
 
 struct unix_diag_msg {
 	__u8	udiag_family;
@@ -31,6 +32,7 @@ enum {
 	UNIX_DIAG_VFS,
 	UNIX_DIAG_PEER,
 	UNIX_DIAG_ICONS,
+	UNIX_DIAG_RQLEN,
 
 	UNIX_DIAG_MAX,
 };
diff --git a/net/unix/diag.c b/net/unix/diag.c
index 9d9e808..53b4833 100644
--- a/net/unix/diag.c
+++ b/net/unix/diag.c
@@ -98,6 +98,15 @@ rtattr_failure:
 	return -EMSGSIZE;
 }
 
+static int sk_diag_show_rqlen(struct sock *sk, struct sk_buff *nlskb)
+{
+	RTA_PUT_U32(nlskb, UNIX_DIAG_RQLEN, sk->sk_receive_queue.qlen);
+	return 0;
+
+rtattr_failure:
+	return -EMSGSIZE;
+}
+
 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req,
 		u32 pid, u32 seq, u32 flags, int sk_ino)
 {
@@ -132,6 +141,10 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_r
 			sk_diag_dump_icons(sk, skb))
 		goto nlmsg_failure;
 
+	if ((req->udiag_show & UDIAG_SHOW_RQLEN) &&
+			sk_diag_show_rqlen(sk, skb))
+		goto nlmsg_failure;
+
 	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
 	return skb->len;
 
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH 13/13] unix_diag: Write it into kbuild
  2011-12-15 12:42 [PATCH 0/13] Dumping AF_UNIX sockets via netlink Pavel Emelyanov
                   ` (11 preceding siblings ...)
  2011-12-15 12:46 ` [PATCH 12/13] unix_diag: Receive queue lenght NLA Pavel Emelyanov
@ 2011-12-15 12:46 ` Pavel Emelyanov
  2011-12-15 13:28 ` [PATCH] iproute: Dump unix sockets via netlink Pavel Emelyanov
  2011-12-16 18:50 ` [PATCH 0/13] Dumping AF_UNIX " David Miller
  14 siblings, 0 replies; 18+ messages in thread
From: Pavel Emelyanov @ 2011-12-15 12:46 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---
 net/unix/Kconfig  |    7 +++++++
 net/unix/Makefile |    3 +++
 2 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/net/unix/Kconfig b/net/unix/Kconfig
index 5a69733..52db53c 100644
--- a/net/unix/Kconfig
+++ b/net/unix/Kconfig
@@ -19,3 +19,10 @@ config UNIX
 
 	  Say Y unless you know what you are doing.
 
+config UNIX_DIAG
+	tristate "UNIX: socket monitoring interface"
+	depends on UNIX
+	default UNIX
+	---help---
+	  Support for UNIX socket monitoring interface used by the ss tool.
+	  If unsure, say Y.
diff --git a/net/unix/Makefile b/net/unix/Makefile
index b852a2b..b663c60 100644
--- a/net/unix/Makefile
+++ b/net/unix/Makefile
@@ -6,3 +6,6 @@ obj-$(CONFIG_UNIX)	+= unix.o
 
 unix-y			:= af_unix.o garbage.o
 unix-$(CONFIG_SYSCTL)	+= sysctl_net_unix.o
+
+obj-$(CONFIG_UNIX_DIAG)	+= unix_diag.o
+unix_diag-y		:= diag.o
-- 
1.5.5.6

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH] iproute: Dump unix sockets via netlink
  2011-12-15 12:42 [PATCH 0/13] Dumping AF_UNIX sockets via netlink Pavel Emelyanov
                   ` (12 preceding siblings ...)
  2011-12-15 12:46 ` [PATCH 13/13] unix_diag: Write it into kbuild Pavel Emelyanov
@ 2011-12-15 13:28 ` Pavel Emelyanov
  2012-01-20 20:51   ` Stephen Hemminger
  2011-12-16 18:50 ` [PATCH 0/13] Dumping AF_UNIX " David Miller
  14 siblings, 1 reply; 18+ messages in thread
From: Pavel Emelyanov @ 2011-12-15 13:28 UTC (permalink / raw)
  To: David Miller, Linux Netdev List

Get the same info as from /proc file plus the peer inode.

Applies on top of new sock diag patch and udp diag patch.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

---

diff --git a/include/linux/unix_diag.h b/include/linux/unix_diag.h
new file mode 100644
index 0000000..3f7afb0
--- /dev/null
+++ b/include/linux/unix_diag.h
@@ -0,0 +1,45 @@
+#ifndef __UNIX_DIAG_H__
+#define __UNIX_DIAG_H__
+
+struct unix_diag_req {
+	__u8	sdiag_family;
+	__u8	sdiag_protocol;
+	__u16	pad;
+	__u32	udiag_states;
+	__u32	udiag_ino;
+	__u32	udiag_show;
+	__u32	udiag_cookie[2];
+};
+
+#define UDIAG_SHOW_NAME		0x00000001	/* show name (not path) */
+#define UDIAG_SHOW_VFS		0x00000002	/* show VFS inode info */
+#define UDIAG_SHOW_PEER		0x00000004	/* show peer socket info */
+#define UDIAG_SHOW_ICONS	0x00000008	/* show pending connections */
+#define UDIAG_SHOW_RQLEN	0x00000010	/* show skb receive queue len */
+
+struct unix_diag_msg {
+	__u8	udiag_family;
+	__u8	udiag_type;
+	__u8	udiag_state;
+	__u8	pad;
+
+	__u32	udiag_ino;
+	__u32	udiag_cookie[2];
+};
+
+enum {
+	UNIX_DIAG_NAME,
+	UNIX_DIAG_VFS,
+	UNIX_DIAG_PEER,
+	UNIX_DIAG_ICONS,
+	UNIX_DIAG_RQLEN,
+
+	UNIX_DIAG_MAX,
+};
+
+struct unix_diag_vfs {
+	__u32	udiag_vfs_ino;
+	__u32	udiag_vfs_dev;
+};
+
+#endif
diff --git a/misc/ss.c b/misc/ss.c
index a5e232b..6f2995e 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -35,6 +35,7 @@
 
 #include <netinet/tcp.h>
 #include <linux/inet_diag.h>
+#include <linux/unix_diag.h>
 
 int resolve_hosts = 0;
 int resolve_services = 1;
@@ -2011,6 +2012,179 @@ void unix_list_print(struct unixstat *list, struct filter *f)
 	}
 }
 
+static int unix_show_sock(struct nlmsghdr *nlh, struct filter *f)
+{
+	struct unix_diag_msg *r = NLMSG_DATA(nlh);
+	struct rtattr *tb[UNIX_DIAG_MAX+1];
+	char name[128];
+	int peer_ino;
+	int rqlen;
+
+	parse_rtattr(tb, UNIX_DIAG_MAX, (struct rtattr*)(r+1),
+		     nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
+
+	if (netid_width)
+		printf("%-*s ", netid_width,
+				r->udiag_type == SOCK_STREAM ? "u_str" : "u_dgr");
+	if (state_width)
+		printf("%-*s ", state_width, sstate_name[r->udiag_state]);
+
+	if (tb[UNIX_DIAG_RQLEN])
+		rqlen = *(int *)RTA_DATA(tb[UNIX_DIAG_RQLEN]);
+	else
+		rqlen = 0;
+
+	printf("%-6d %-6d ", rqlen, 0);
+
+	if (tb[UNIX_DIAG_NAME]) {
+		int len = RTA_PAYLOAD(tb[UNIX_DIAG_NAME]);
+
+		memcpy(name, RTA_DATA(tb[UNIX_DIAG_NAME]), len);
+		name[len] = '\0';
+		if (name[0] == '\0')
+			name[0] = '@';
+	} else
+		sprintf(name, "*");
+
+	if (tb[UNIX_DIAG_PEER])
+		peer_ino = *(int *)RTA_DATA(tb[UNIX_DIAG_PEER]);
+	else
+		peer_ino = 0;
+
+	printf("%*s %-*d %*s %-*d",
+			addr_width, name,
+			serv_width, r->udiag_ino,
+			addr_width, "*", /* FIXME */
+			serv_width, peer_ino);
+
+	if (show_users) {
+		char ubuf[4096];
+		if (find_users(r->udiag_ino, ubuf, sizeof(ubuf)) > 0)
+			printf(" users:(%s)", ubuf);
+	}
+
+	printf("\n");
+
+	return 0;
+}
+
+static int unix_show_netlink(struct filter *f, FILE *dump_fp)
+{
+	int fd;
+	struct sockaddr_nl nladdr;
+	struct {
+		struct nlmsghdr nlh;
+		struct unix_diag_req r;
+	} req;
+	struct msghdr msg;
+	char	buf[8192];
+	struct iovec iov[3];
+
+	if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0)
+		return -1;
+
+	memset(&nladdr, 0, sizeof(nladdr));
+	nladdr.nl_family = AF_NETLINK;
+
+	req.nlh.nlmsg_len = sizeof(req);
+	req.nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
+	req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+	req.nlh.nlmsg_pid = 0;
+	req.nlh.nlmsg_seq = 123456;
+	memset(&req.r, 0, sizeof(req.r));
+	req.r.sdiag_family = AF_UNIX;
+	req.r.sdiag_protocol = 0; /* ignored */
+	req.r.udiag_states = f->states;
+	req.r.udiag_show = UDIAG_SHOW_NAME | UDIAG_SHOW_PEER | UDIAG_SHOW_RQLEN;
+
+	iov[0] = (struct iovec){
+		.iov_base = &req,
+		.iov_len = sizeof(req)
+	};
+
+	msg = (struct msghdr) {
+		.msg_name = (void*)&nladdr,
+		.msg_namelen = sizeof(nladdr),
+		.msg_iov = iov,
+		.msg_iovlen = f->f ? 3 : 1,
+	};
+
+	if (sendmsg(fd, &msg, 0) < 0)
+		return -1;
+
+	iov[0] = (struct iovec){
+		.iov_base = buf,
+		.iov_len = sizeof(buf)
+	};
+
+	while (1) {
+		int status;
+		struct nlmsghdr *h;
+
+		msg = (struct msghdr) {
+			(void*)&nladdr, sizeof(nladdr),
+			iov,	1,
+			NULL,	0,
+			0
+		};
+
+		status = recvmsg(fd, &msg, 0);
+
+		if (status < 0) {
+			if (errno == EINTR)
+				continue;
+			perror("OVERRUN");
+			continue;
+		}
+		if (status == 0) {
+			fprintf(stderr, "EOF on netlink\n");
+			return 0;
+		}
+
+		if (dump_fp)
+			fwrite(buf, 1, NLMSG_ALIGN(status), dump_fp);
+
+		h = (struct nlmsghdr*)buf;
+		while (NLMSG_OK(h, status)) {
+			int err;
+
+			if (/*h->nlmsg_pid != rth->local.nl_pid ||*/
+			    h->nlmsg_seq != 123456)
+				goto skip_it;
+
+			if (h->nlmsg_type == NLMSG_DONE)
+				return 0;
+			if (h->nlmsg_type == NLMSG_ERROR) {
+				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
+				if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+					fprintf(stderr, "ERROR truncated\n");
+				} else {
+					errno = -err->error;
+					perror("TCPDIAG answers");
+				}
+				return 0;
+			}
+			if (!dump_fp) {
+				err = unix_show_sock(h, f);
+				if (err < 0)
+					return err;
+			}
+
+skip_it:
+			h = NLMSG_NEXT(h, status);
+		}
+		if (msg.msg_flags & MSG_TRUNC) {
+			fprintf(stderr, "Message truncated\n");
+			continue;
+		}
+		if (status) {
+			fprintf(stderr, "!!!Remnant of size %d\n", status);
+			exit(1);
+		}
+	}
+	return 0;
+}
+
 int unix_show(struct filter *f)
 {
 	FILE *fp;
@@ -2020,6 +2194,10 @@ int unix_show(struct filter *f)
 	int  cnt;
 	struct unixstat *list = NULL;
 
+	if (!getenv("PROC_NET_UNIX") && !getenv("PROC_ROOT")
+	    && unix_show_netlink(f, NULL) == 0)
+		return 0;
+
 	if ((fp = net_unix_open()) == NULL)
 		return -1;
 	fgets(buf, sizeof(buf)-1, fp);

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH 0/13] Dumping AF_UNIX sockets via netlink
  2011-12-15 12:42 [PATCH 0/13] Dumping AF_UNIX sockets via netlink Pavel Emelyanov
                   ` (13 preceding siblings ...)
  2011-12-15 13:28 ` [PATCH] iproute: Dump unix sockets via netlink Pavel Emelyanov
@ 2011-12-16 18:50 ` David Miller
  2011-12-17  9:54   ` Pavel Emelyanov
  14 siblings, 1 reply; 18+ messages in thread
From: David Miller @ 2011-12-16 18:50 UTC (permalink / raw)
  To: xemul; +Cc: netdev

From: Pavel Emelyanov <xemul@parallels.com>
Date: Thu, 15 Dec 2011 16:42:18 +0400

> Make the unix_diag.ko module, which is the AF_UNIX client for the sock_diag.
> 
> Use the sock_i_ino() as the primary ID key for sockets. This is currently the
> only unique (except for the sk address itself) ID of a unix socket and is de
> facto used in the ss tool to identify sockets. Thus the basic nlk request and
> response structures operate on this ID. Other socket info (sun_name, peer, etc.)
> are reported in the respective NLA-s (patches 8 through 12).
> 
> There's a locking trickery in patch #11. I've tried to study it carefully and
> checked with lockdep, but anyway, please, pay special attention to it.
> 
> The patch for ss tool is also included.
> 
> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>

Looks good, applied.

I'm slightly confused by the module alias strings these diag modules
are using, can you explain it to me?

On one side it looks like it wants to see a suffix of "-${AF_INET}-${IPPROTO_TCP}"
but in the macros you pass in one numerical value, which is AF_INET minus the
protocol value.

How does that work?

Thanks.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH 0/13] Dumping AF_UNIX sockets via netlink
  2011-12-16 18:50 ` [PATCH 0/13] Dumping AF_UNIX " David Miller
@ 2011-12-17  9:54   ` Pavel Emelyanov
  0 siblings, 0 replies; 18+ messages in thread
From: Pavel Emelyanov @ 2011-12-17  9:54 UTC (permalink / raw)
  To: David Miller; +Cc: netdev

On 12/16/2011 10:50 PM, David Miller wrote:
> From: Pavel Emelyanov <xemul@parallels.com>
> Date: Thu, 15 Dec 2011 16:42:18 +0400
> 
>> Make the unix_diag.ko module, which is the AF_UNIX client for the sock_diag.
>>
>> Use the sock_i_ino() as the primary ID key for sockets. This is currently the
>> only unique (except for the sk address itself) ID of a unix socket and is de
>> facto used in the ss tool to identify sockets. Thus the basic nlk request and
>> response structures operate on this ID. Other socket info (sun_name, peer, etc.)
>> are reported in the respective NLA-s (patches 8 through 12).
>>
>> There's a locking trickery in patch #11. I've tried to study it carefully and
>> checked with lockdep, but anyway, please, pay special attention to it.
>>
>> The patch for ss tool is also included.
>>
>> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
> 
> Looks good, applied.
> 
> I'm slightly confused by the module alias strings these diag modules
> are using, can you explain it to me?
> 
> On one side it looks like it wants to see a suffix of "-${AF_INET}-${IPPROTO_TCP}"
> but in the macros you pass in one numerical value, which is AF_INET minus the
> protocol value.

You're right, the intention is to get the "family-protocol" pair, and the minus you
see (surrounded with numbers) is put into the stringify macro, which works like

  stringify(2-16) => "2-16"

since (as far as I understand this) C pre-processor doesn't perform arithmetic 
calculations.

> How does that work?
> 
> Thanks.
> .
> 

Thanks,
Pavel

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] iproute: Dump unix sockets via netlink
  2011-12-15 13:28 ` [PATCH] iproute: Dump unix sockets via netlink Pavel Emelyanov
@ 2012-01-20 20:51   ` Stephen Hemminger
  0 siblings, 0 replies; 18+ messages in thread
From: Stephen Hemminger @ 2012-01-20 20:51 UTC (permalink / raw)
  To: Pavel Emelyanov; +Cc: David Miller, Linux Netdev List

On Thu, 15 Dec 2011 17:28:15 +0400
Pavel Emelyanov <xemul@parallels.com> wrote:

> Get the same info as from /proc file plus the peer inode.
> 
> Applies on top of new sock diag patch and udp diag patch.
> 
> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
> 
> ---

Applied, but was missing sock_diag.h in include's.

Also, please update manual pages.

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2012-01-20 20:51 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-15 12:42 [PATCH 0/13] Dumping AF_UNIX sockets via netlink Pavel Emelyanov
2011-12-15 12:42 ` [PATCH 1/13] sock_diag: Move the SOCK_DIAG_BY_FAMILY cmd declaration Pavel Emelyanov
2011-12-15 12:43 ` [PATCH 2/13] sock_diag: Fix module netlink aliases Pavel Emelyanov
2011-12-15 12:43 ` [PATCH 3/13] sock_diag: Generalize requests cookies managements Pavel Emelyanov
2011-12-15 12:44 ` [PATCH 4/13] af_unix: Export stuff required for diag module Pavel Emelyanov
2011-12-15 12:44 ` [PATCH 5/13] unix_diag: Basic module skeleton Pavel Emelyanov
2011-12-15 12:44 ` [PATCH 6/13] unix_diag: Dumping all sockets core Pavel Emelyanov
2011-12-15 12:45 ` [PATCH 7/13] unix_diag: Dumping exact socket core Pavel Emelyanov
2011-12-15 12:45 ` [PATCH 8/13] unix_diag: Unix socket name NLA Pavel Emelyanov
2011-12-15 12:45 ` [PATCH 9/13] unix_diag: Unix inode info NLA Pavel Emelyanov
2011-12-15 12:45 ` [PATCH 10/13] unix_diag: Unix peer inode NLA Pavel Emelyanov
2011-12-15 12:46 ` [PATCH 11/13] unix_diag: Pending connections IDs NLA Pavel Emelyanov
2011-12-15 12:46 ` [PATCH 12/13] unix_diag: Receive queue lenght NLA Pavel Emelyanov
2011-12-15 12:46 ` [PATCH 13/13] unix_diag: Write it into kbuild Pavel Emelyanov
2011-12-15 13:28 ` [PATCH] iproute: Dump unix sockets via netlink Pavel Emelyanov
2012-01-20 20:51   ` Stephen Hemminger
2011-12-16 18:50 ` [PATCH 0/13] Dumping AF_UNIX " David Miller
2011-12-17  9:54   ` Pavel Emelyanov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.