root/net/ipv4/tcp_diag.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tcp_diag_get_info
  2. tcp_diag_md5sig_fill
  3. tcp_diag_put_md5sig
  4. tcp_diag_put_ulp
  5. tcp_diag_get_aux
  6. tcp_diag_get_aux_size
  7. tcp_diag_dump
  8. tcp_diag_dump_one
  9. tcp_diag_destroy
  10. tcp_diag_init
  11. tcp_diag_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * tcp_diag.c   Module for monitoring TCP transport protocols sockets.
   4  *
   5  * Authors:     Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
   6  */
   7 
   8 #include <linux/module.h>
   9 #include <linux/net.h>
  10 #include <linux/sock_diag.h>
  11 #include <linux/inet_diag.h>
  12 
  13 #include <linux/tcp.h>
  14 
  15 #include <net/netlink.h>
  16 #include <net/tcp.h>
  17 
  18 static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
  19                               void *_info)
  20 {
  21         struct tcp_info *info = _info;
  22 
  23         if (inet_sk_state_load(sk) == TCP_LISTEN) {
  24                 r->idiag_rqueue = sk->sk_ack_backlog;
  25                 r->idiag_wqueue = sk->sk_max_ack_backlog;
  26         } else if (sk->sk_type == SOCK_STREAM) {
  27                 const struct tcp_sock *tp = tcp_sk(sk);
  28 
  29                 r->idiag_rqueue = max_t(int, READ_ONCE(tp->rcv_nxt) -
  30                                              READ_ONCE(tp->copied_seq), 0);
  31                 r->idiag_wqueue = READ_ONCE(tp->write_seq) - tp->snd_una;
  32         }
  33         if (info)
  34                 tcp_get_info(sk, info);
  35 }
  36 
  37 #ifdef CONFIG_TCP_MD5SIG
  38 static void tcp_diag_md5sig_fill(struct tcp_diag_md5sig *info,
  39                                  const struct tcp_md5sig_key *key)
  40 {
  41         info->tcpm_family = key->family;
  42         info->tcpm_prefixlen = key->prefixlen;
  43         info->tcpm_keylen = key->keylen;
  44         memcpy(info->tcpm_key, key->key, key->keylen);
  45 
  46         if (key->family == AF_INET)
  47                 info->tcpm_addr[0] = key->addr.a4.s_addr;
  48         #if IS_ENABLED(CONFIG_IPV6)
  49         else if (key->family == AF_INET6)
  50                 memcpy(&info->tcpm_addr, &key->addr.a6,
  51                        sizeof(info->tcpm_addr));
  52         #endif
  53 }
  54 
  55 static int tcp_diag_put_md5sig(struct sk_buff *skb,
  56                                const struct tcp_md5sig_info *md5sig)
  57 {
  58         const struct tcp_md5sig_key *key;
  59         struct tcp_diag_md5sig *info;
  60         struct nlattr *attr;
  61         int md5sig_count = 0;
  62 
  63         hlist_for_each_entry_rcu(key, &md5sig->head, node)
  64                 md5sig_count++;
  65         if (md5sig_count == 0)
  66                 return 0;
  67 
  68         attr = nla_reserve(skb, INET_DIAG_MD5SIG,
  69                            md5sig_count * sizeof(struct tcp_diag_md5sig));
  70         if (!attr)
  71                 return -EMSGSIZE;
  72 
  73         info = nla_data(attr);
  74         memset(info, 0, md5sig_count * sizeof(struct tcp_diag_md5sig));
  75         hlist_for_each_entry_rcu(key, &md5sig->head, node) {
  76                 tcp_diag_md5sig_fill(info++, key);
  77                 if (--md5sig_count == 0)
  78                         break;
  79         }
  80 
  81         return 0;
  82 }
  83 #endif
  84 
  85 static int tcp_diag_put_ulp(struct sk_buff *skb, struct sock *sk,
  86                             const struct tcp_ulp_ops *ulp_ops)
  87 {
  88         struct nlattr *nest;
  89         int err;
  90 
  91         nest = nla_nest_start_noflag(skb, INET_DIAG_ULP_INFO);
  92         if (!nest)
  93                 return -EMSGSIZE;
  94 
  95         err = nla_put_string(skb, INET_ULP_INFO_NAME, ulp_ops->name);
  96         if (err)
  97                 goto nla_failure;
  98 
  99         if (ulp_ops->get_info)
 100                 err = ulp_ops->get_info(sk, skb);
 101         if (err)
 102                 goto nla_failure;
 103 
 104         nla_nest_end(skb, nest);
 105         return 0;
 106 
 107 nla_failure:
 108         nla_nest_cancel(skb, nest);
 109         return err;
 110 }
 111 
 112 static int tcp_diag_get_aux(struct sock *sk, bool net_admin,
 113                             struct sk_buff *skb)
 114 {
 115         struct inet_connection_sock *icsk = inet_csk(sk);
 116         int err = 0;
 117 
 118 #ifdef CONFIG_TCP_MD5SIG
 119         if (net_admin) {
 120                 struct tcp_md5sig_info *md5sig;
 121 
 122                 rcu_read_lock();
 123                 md5sig = rcu_dereference(tcp_sk(sk)->md5sig_info);
 124                 if (md5sig)
 125                         err = tcp_diag_put_md5sig(skb, md5sig);
 126                 rcu_read_unlock();
 127                 if (err < 0)
 128                         return err;
 129         }
 130 #endif
 131 
 132         if (net_admin) {
 133                 const struct tcp_ulp_ops *ulp_ops;
 134 
 135                 ulp_ops = icsk->icsk_ulp_ops;
 136                 if (ulp_ops)
 137                         err = tcp_diag_put_ulp(skb, sk, ulp_ops);
 138                 if (err)
 139                         return err;
 140         }
 141         return 0;
 142 }
 143 
 144 static size_t tcp_diag_get_aux_size(struct sock *sk, bool net_admin)
 145 {
 146         struct inet_connection_sock *icsk = inet_csk(sk);
 147         size_t size = 0;
 148 
 149 #ifdef CONFIG_TCP_MD5SIG
 150         if (net_admin && sk_fullsock(sk)) {
 151                 const struct tcp_md5sig_info *md5sig;
 152                 const struct tcp_md5sig_key *key;
 153                 size_t md5sig_count = 0;
 154 
 155                 rcu_read_lock();
 156                 md5sig = rcu_dereference(tcp_sk(sk)->md5sig_info);
 157                 if (md5sig) {
 158                         hlist_for_each_entry_rcu(key, &md5sig->head, node)
 159                                 md5sig_count++;
 160                 }
 161                 rcu_read_unlock();
 162                 size += nla_total_size(md5sig_count *
 163                                        sizeof(struct tcp_diag_md5sig));
 164         }
 165 #endif
 166 
 167         if (net_admin && sk_fullsock(sk)) {
 168                 const struct tcp_ulp_ops *ulp_ops;
 169 
 170                 ulp_ops = icsk->icsk_ulp_ops;
 171                 if (ulp_ops) {
 172                         size += nla_total_size(0) +
 173                                 nla_total_size(TCP_ULP_NAME_MAX);
 174                         if (ulp_ops->get_info_size)
 175                                 size += ulp_ops->get_info_size(sk);
 176                 }
 177         }
 178         return size;
 179 }
 180 
 181 static void tcp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
 182                           const struct inet_diag_req_v2 *r, struct nlattr *bc)
 183 {
 184         inet_diag_dump_icsk(&tcp_hashinfo, skb, cb, r, bc);
 185 }
 186 
 187 static int tcp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh,
 188                              const struct inet_diag_req_v2 *req)
 189 {
 190         return inet_diag_dump_one_icsk(&tcp_hashinfo, in_skb, nlh, req);
 191 }
 192 
 193 #ifdef CONFIG_INET_DIAG_DESTROY
 194 static int tcp_diag_destroy(struct sk_buff *in_skb,
 195                             const struct inet_diag_req_v2 *req)
 196 {
 197         struct net *net = sock_net(in_skb->sk);
 198         struct sock *sk = inet_diag_find_one_icsk(net, &tcp_hashinfo, req);
 199         int err;
 200 
 201         if (IS_ERR(sk))
 202                 return PTR_ERR(sk);
 203 
 204         err = sock_diag_destroy(sk, ECONNABORTED);
 205 
 206         sock_gen_put(sk);
 207 
 208         return err;
 209 }
 210 #endif
 211 
 212 static const struct inet_diag_handler tcp_diag_handler = {
 213         .dump                   = tcp_diag_dump,
 214         .dump_one               = tcp_diag_dump_one,
 215         .idiag_get_info         = tcp_diag_get_info,
 216         .idiag_get_aux          = tcp_diag_get_aux,
 217         .idiag_get_aux_size     = tcp_diag_get_aux_size,
 218         .idiag_type             = IPPROTO_TCP,
 219         .idiag_info_size        = sizeof(struct tcp_info),
 220 #ifdef CONFIG_INET_DIAG_DESTROY
 221         .destroy                = tcp_diag_destroy,
 222 #endif
 223 };
 224 
 225 static int __init tcp_diag_init(void)
 226 {
 227         return inet_diag_register(&tcp_diag_handler);
 228 }
 229 
 230 static void __exit tcp_diag_exit(void)
 231 {
 232         inet_diag_unregister(&tcp_diag_handler);
 233 }
 234 
 235 module_init(tcp_diag_init);
 236 module_exit(tcp_diag_exit);
 237 MODULE_LICENSE("GPL");
 238 MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-6 /* AF_INET - IPPROTO_TCP */);

/* [<][>][^][v][top][bottom][index][help] */