2019-05-27 09:55:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
[INET_DIAG]: Move the tcp_diag interface to the proper place
With this the previous setup is back, i.e. tcp_diag can be built as a module,
as dccp_diag and both share the infrastructure available in inet_diag.
If one selects CONFIG_INET_DIAG as module CONFIG_INET_TCP_DIAG will also be
built as a module, as will CONFIG_INET_DCCP_DIAG, if CONFIG_IP_DCCP was
selected static or as a module, if CONFIG_INET_DIAG is y, being statically
linked CONFIG_INET_TCP_DIAG will follow suit and CONFIG_INET_DCCP_DIAG will be
built in the same manner as CONFIG_IP_DCCP.
Now to aim at UDP, converting it to use inet_hashinfo, so that we can use
iproute2 for UDP sockets as well.
Ah, just to show an example of this new infrastructure working for DCCP :-)
[root@qemu ~]# ./ss -dane
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 0 *:5001 *:* ino:942 sk:cfd503a0
ESTAB 0 0 127.0.0.1:5001 127.0.0.1:32770 ino:943 sk:cfd50a60
ESTAB 0 0 127.0.0.1:32770 127.0.0.1:5001 ino:947 sk:cfd50700
TIME-WAIT 0 0 127.0.0.1:32769 127.0.0.1:5001 timer:(timewait,3.430ms,0) ino:0 sk:cf209620
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-08-12 19:59:17 +04:00
/*
* tcp_diag . c Module for monitoring TCP transport protocols sockets .
*
* Authors : Alexey Kuznetsov , < kuznet @ ms2 . inr . ac . ru >
*/
# include <linux/module.h>
2015-12-16 06:30:05 +03:00
# include <linux/net.h>
# include <linux/sock_diag.h>
[INET_DIAG]: Move the tcp_diag interface to the proper place
With this the previous setup is back, i.e. tcp_diag can be built as a module,
as dccp_diag and both share the infrastructure available in inet_diag.
If one selects CONFIG_INET_DIAG as module CONFIG_INET_TCP_DIAG will also be
built as a module, as will CONFIG_INET_DCCP_DIAG, if CONFIG_IP_DCCP was
selected static or as a module, if CONFIG_INET_DIAG is y, being statically
linked CONFIG_INET_TCP_DIAG will follow suit and CONFIG_INET_DCCP_DIAG will be
built in the same manner as CONFIG_IP_DCCP.
Now to aim at UDP, converting it to use inet_hashinfo, so that we can use
iproute2 for UDP sockets as well.
Ah, just to show an example of this new infrastructure working for DCCP :-)
[root@qemu ~]# ./ss -dane
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 0 *:5001 *:* ino:942 sk:cfd503a0
ESTAB 0 0 127.0.0.1:5001 127.0.0.1:32770 ino:943 sk:cfd50a60
ESTAB 0 0 127.0.0.1:32770 127.0.0.1:5001 ino:947 sk:cfd50700
TIME-WAIT 0 0 127.0.0.1:32769 127.0.0.1:5001 timer:(timewait,3.430ms,0) ino:0 sk:cf209620
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-08-12 19:59:17 +04:00
# include <linux/inet_diag.h>
# include <linux/tcp.h>
2017-08-31 19:59:39 +03:00
# include <net/netlink.h>
[INET_DIAG]: Move the tcp_diag interface to the proper place
With this the previous setup is back, i.e. tcp_diag can be built as a module,
as dccp_diag and both share the infrastructure available in inet_diag.
If one selects CONFIG_INET_DIAG as module CONFIG_INET_TCP_DIAG will also be
built as a module, as will CONFIG_INET_DCCP_DIAG, if CONFIG_IP_DCCP was
selected static or as a module, if CONFIG_INET_DIAG is y, being statically
linked CONFIG_INET_TCP_DIAG will follow suit and CONFIG_INET_DCCP_DIAG will be
built in the same manner as CONFIG_IP_DCCP.
Now to aim at UDP, converting it to use inet_hashinfo, so that we can use
iproute2 for UDP sockets as well.
Ah, just to show an example of this new infrastructure working for DCCP :-)
[root@qemu ~]# ./ss -dane
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 0 *:5001 *:* ino:942 sk:cfd503a0
ESTAB 0 0 127.0.0.1:5001 127.0.0.1:32770 ino:943 sk:cfd50a60
ESTAB 0 0 127.0.0.1:32770 127.0.0.1:5001 ino:947 sk:cfd50700
TIME-WAIT 0 0 127.0.0.1:32769 127.0.0.1:5001 timer:(timewait,3.430ms,0) ino:0 sk:cf209620
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-08-12 19:59:17 +04:00
# include <net/tcp.h>
static void tcp_diag_get_info ( struct sock * sk , struct inet_diag_msg * r ,
void * _info )
{
struct tcp_info * info = _info ;
2017-12-20 06:12:52 +03:00
if ( inet_sk_state_load ( sk ) = = TCP_LISTEN ) {
2019-11-06 01:11:53 +03:00
r - > idiag_rqueue = READ_ONCE ( sk - > sk_ack_backlog ) ;
2019-11-06 01:11:54 +03:00
r - > idiag_wqueue = READ_ONCE ( sk - > sk_max_ack_backlog ) ;
2015-06-15 18:26:20 +03:00
} else if ( sk - > sk_type = = SOCK_STREAM ) {
const struct tcp_sock * tp = tcp_sk ( sk ) ;
2019-10-11 06:17:40 +03:00
r - > idiag_rqueue = max_t ( int , READ_ONCE ( tp - > rcv_nxt ) -
READ_ONCE ( tp - > copied_seq ) , 0 ) ;
2019-10-11 06:17:41 +03:00
r - > idiag_wqueue = READ_ONCE ( tp - > write_seq ) - tp - > snd_una ;
2007-09-19 00:26:31 +04:00
}
2015-04-03 11:17:27 +03:00
if ( info )
[INET_DIAG]: Move the tcp_diag interface to the proper place
With this the previous setup is back, i.e. tcp_diag can be built as a module,
as dccp_diag and both share the infrastructure available in inet_diag.
If one selects CONFIG_INET_DIAG as module CONFIG_INET_TCP_DIAG will also be
built as a module, as will CONFIG_INET_DCCP_DIAG, if CONFIG_IP_DCCP was
selected static or as a module, if CONFIG_INET_DIAG is y, being statically
linked CONFIG_INET_TCP_DIAG will follow suit and CONFIG_INET_DCCP_DIAG will be
built in the same manner as CONFIG_IP_DCCP.
Now to aim at UDP, converting it to use inet_hashinfo, so that we can use
iproute2 for UDP sockets as well.
Ah, just to show an example of this new infrastructure working for DCCP :-)
[root@qemu ~]# ./ss -dane
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 0 *:5001 *:* ino:942 sk:cfd503a0
ESTAB 0 0 127.0.0.1:5001 127.0.0.1:32770 ino:943 sk:cfd50a60
ESTAB 0 0 127.0.0.1:32770 127.0.0.1:5001 ino:947 sk:cfd50700
TIME-WAIT 0 0 127.0.0.1:32769 127.0.0.1:5001 timer:(timewait,3.430ms,0) ino:0 sk:cf209620
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-08-12 19:59:17 +04:00
tcp_get_info ( sk , info ) ;
}
2017-08-31 19:59:39 +03:00
# ifdef CONFIG_TCP_MD5SIG
static void tcp_diag_md5sig_fill ( struct tcp_diag_md5sig * info ,
const struct tcp_md5sig_key * key )
{
info - > tcpm_family = key - > family ;
info - > tcpm_prefixlen = key - > prefixlen ;
info - > tcpm_keylen = key - > keylen ;
memcpy ( info - > tcpm_key , key - > key , key - > keylen ) ;
if ( key - > family = = AF_INET )
info - > tcpm_addr [ 0 ] = key - > addr . a4 . s_addr ;
# if IS_ENABLED(CONFIG_IPV6)
else if ( key - > family = = AF_INET6 )
memcpy ( & info - > tcpm_addr , & key - > addr . a6 ,
sizeof ( info - > tcpm_addr ) ) ;
# endif
}
static int tcp_diag_put_md5sig ( struct sk_buff * skb ,
const struct tcp_md5sig_info * md5sig )
{
const struct tcp_md5sig_key * key ;
struct tcp_diag_md5sig * info ;
struct nlattr * attr ;
int md5sig_count = 0 ;
hlist_for_each_entry_rcu ( key , & md5sig - > head , node )
md5sig_count + + ;
if ( md5sig_count = = 0 )
return 0 ;
attr = nla_reserve ( skb , INET_DIAG_MD5SIG ,
md5sig_count * sizeof ( struct tcp_diag_md5sig ) ) ;
if ( ! attr )
return - EMSGSIZE ;
info = nla_data ( attr ) ;
memset ( info , 0 , md5sig_count * sizeof ( struct tcp_diag_md5sig ) ) ;
hlist_for_each_entry_rcu ( key , & md5sig - > head , node ) {
tcp_diag_md5sig_fill ( info + + , key ) ;
if ( - - md5sig_count = = 0 )
break ;
}
return 0 ;
}
# endif
2019-08-30 13:25:48 +03:00
static int tcp_diag_put_ulp ( struct sk_buff * skb , struct sock * sk ,
const struct tcp_ulp_ops * ulp_ops )
{
struct nlattr * nest ;
int err ;
nest = nla_nest_start_noflag ( skb , INET_DIAG_ULP_INFO ) ;
if ( ! nest )
return - EMSGSIZE ;
err = nla_put_string ( skb , INET_ULP_INFO_NAME , ulp_ops - > name ) ;
if ( err )
goto nla_failure ;
if ( ulp_ops - > get_info )
err = ulp_ops - > get_info ( sk , skb ) ;
if ( err )
goto nla_failure ;
nla_nest_end ( skb , nest ) ;
return 0 ;
nla_failure :
nla_nest_cancel ( skb , nest ) ;
return err ;
}
2017-08-31 19:59:39 +03:00
static int tcp_diag_get_aux ( struct sock * sk , bool net_admin ,
struct sk_buff * skb )
{
2019-08-30 13:25:48 +03:00
struct inet_connection_sock * icsk = inet_csk ( sk ) ;
int err = 0 ;
2017-08-31 19:59:39 +03:00
# ifdef CONFIG_TCP_MD5SIG
if ( net_admin ) {
struct tcp_md5sig_info * md5sig ;
rcu_read_lock ( ) ;
md5sig = rcu_dereference ( tcp_sk ( sk ) - > md5sig_info ) ;
if ( md5sig )
err = tcp_diag_put_md5sig ( skb , md5sig ) ;
rcu_read_unlock ( ) ;
if ( err < 0 )
return err ;
}
# endif
2019-08-30 13:25:48 +03:00
if ( net_admin ) {
const struct tcp_ulp_ops * ulp_ops ;
ulp_ops = icsk - > icsk_ulp_ops ;
if ( ulp_ops )
err = tcp_diag_put_ulp ( skb , sk , ulp_ops ) ;
if ( err )
return err ;
}
2017-08-31 19:59:39 +03:00
return 0 ;
}
static size_t tcp_diag_get_aux_size ( struct sock * sk , bool net_admin )
{
2019-08-30 13:25:48 +03:00
struct inet_connection_sock * icsk = inet_csk ( sk ) ;
2017-08-31 19:59:39 +03:00
size_t size = 0 ;
# ifdef CONFIG_TCP_MD5SIG
if ( net_admin & & sk_fullsock ( sk ) ) {
const struct tcp_md5sig_info * md5sig ;
const struct tcp_md5sig_key * key ;
size_t md5sig_count = 0 ;
rcu_read_lock ( ) ;
md5sig = rcu_dereference ( tcp_sk ( sk ) - > md5sig_info ) ;
if ( md5sig ) {
hlist_for_each_entry_rcu ( key , & md5sig - > head , node )
md5sig_count + + ;
}
rcu_read_unlock ( ) ;
size + = nla_total_size ( md5sig_count *
sizeof ( struct tcp_diag_md5sig ) ) ;
}
# endif
2019-09-05 23:20:41 +03:00
if ( net_admin & & sk_fullsock ( sk ) ) {
2019-08-30 13:25:48 +03:00
const struct tcp_ulp_ops * ulp_ops ;
ulp_ops = icsk - > icsk_ulp_ops ;
if ( ulp_ops ) {
size + = nla_total_size ( 0 ) +
nla_total_size ( TCP_ULP_NAME_MAX ) ;
if ( ulp_ops - > get_info_size )
size + = ulp_ops - > get_info_size ( sk ) ;
}
}
2017-08-31 19:59:39 +03:00
return size ;
}
2011-12-09 10:23:18 +04:00
static void tcp_diag_dump ( struct sk_buff * skb , struct netlink_callback * cb ,
2015-03-10 17:15:54 +03:00
const struct inet_diag_req_v2 * r , struct nlattr * bc )
2011-12-09 10:23:18 +04:00
{
inet_diag_dump_icsk ( & tcp_hashinfo , skb , cb , r , bc ) ;
}
static int tcp_diag_dump_one ( struct sk_buff * in_skb , const struct nlmsghdr * nlh ,
2015-03-10 17:15:54 +03:00
const struct inet_diag_req_v2 * req )
2011-12-09 10:23:18 +04:00
{
return inet_diag_dump_one_icsk ( & tcp_hashinfo , in_skb , nlh , req ) ;
}
2015-12-16 06:30:05 +03:00
# ifdef CONFIG_INET_DIAG_DESTROY
static int tcp_diag_destroy ( struct sk_buff * in_skb ,
const struct inet_diag_req_v2 * req )
{
struct net * net = sock_net ( in_skb - > sk ) ;
struct sock * sk = inet_diag_find_one_icsk ( net , & tcp_hashinfo , req ) ;
2016-08-24 07:05:27 +03:00
int err ;
2015-12-16 06:30:05 +03:00
if ( IS_ERR ( sk ) )
return PTR_ERR ( sk ) ;
2016-08-24 07:05:27 +03:00
err = sock_diag_destroy ( sk , ECONNABORTED ) ;
sock_gen_put ( sk ) ;
return err ;
2015-12-16 06:30:05 +03:00
}
# endif
2008-11-20 02:43:27 +03:00
static const struct inet_diag_handler tcp_diag_handler = {
2017-08-31 19:59:39 +03:00
. dump = tcp_diag_dump ,
. dump_one = tcp_diag_dump_one ,
. idiag_get_info = tcp_diag_get_info ,
. idiag_get_aux = tcp_diag_get_aux ,
. idiag_get_aux_size = tcp_diag_get_aux_size ,
. idiag_type = IPPROTO_TCP ,
. idiag_info_size = sizeof ( struct tcp_info ) ,
2015-12-16 06:30:05 +03:00
# ifdef CONFIG_INET_DIAG_DESTROY
2017-08-31 19:59:39 +03:00
. destroy = tcp_diag_destroy ,
2015-12-16 06:30:05 +03:00
# endif
[INET_DIAG]: Move the tcp_diag interface to the proper place
With this the previous setup is back, i.e. tcp_diag can be built as a module,
as dccp_diag and both share the infrastructure available in inet_diag.
If one selects CONFIG_INET_DIAG as module CONFIG_INET_TCP_DIAG will also be
built as a module, as will CONFIG_INET_DCCP_DIAG, if CONFIG_IP_DCCP was
selected static or as a module, if CONFIG_INET_DIAG is y, being statically
linked CONFIG_INET_TCP_DIAG will follow suit and CONFIG_INET_DCCP_DIAG will be
built in the same manner as CONFIG_IP_DCCP.
Now to aim at UDP, converting it to use inet_hashinfo, so that we can use
iproute2 for UDP sockets as well.
Ah, just to show an example of this new infrastructure working for DCCP :-)
[root@qemu ~]# ./ss -dane
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 0 *:5001 *:* ino:942 sk:cfd503a0
ESTAB 0 0 127.0.0.1:5001 127.0.0.1:32770 ino:943 sk:cfd50a60
ESTAB 0 0 127.0.0.1:32770 127.0.0.1:5001 ino:947 sk:cfd50700
TIME-WAIT 0 0 127.0.0.1:32769 127.0.0.1:5001 timer:(timewait,3.430ms,0) ino:0 sk:cf209620
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
2005-08-12 19:59:17 +04:00
} ;
static int __init tcp_diag_init ( void )
{
return inet_diag_register ( & tcp_diag_handler ) ;
}
static void __exit tcp_diag_exit ( void )
{
inet_diag_unregister ( & tcp_diag_handler ) ;
}
module_init ( tcp_diag_init ) ;
module_exit ( tcp_diag_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
2011-12-15 06:43:27 +04:00
MODULE_ALIAS_NET_PF_PROTO_TYPE ( PF_NETLINK , NETLINK_SOCK_DIAG , 2 - 6 /* AF_INET - IPPROTO_TCP */ ) ;