root/net/ipv4/udp_diag.c

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

DEFINITIONS

This source file includes following definitions.
  1. sk_diag_dump
  2. udp_dump_one
  3. udp_dump
  4. udp_diag_dump
  5. udp_diag_dump_one
  6. udp_diag_get_info
  7. __udp_diag_destroy
  8. udp_diag_destroy
  9. udplite_diag_destroy
  10. udplite_diag_dump
  11. udplite_diag_dump_one
  12. udp_diag_init
  13. udp_diag_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * udp_diag.c   Module for monitoring UDP transport protocols sockets.
   4  *
   5  * Authors:     Pavel Emelyanov, <xemul@parallels.com>
   6  */
   7 
   8 
   9 #include <linux/module.h>
  10 #include <linux/inet_diag.h>
  11 #include <linux/udp.h>
  12 #include <net/udp.h>
  13 #include <net/udplite.h>
  14 #include <linux/sock_diag.h>
  15 
  16 static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
  17                         struct netlink_callback *cb,
  18                         const struct inet_diag_req_v2 *req,
  19                         struct nlattr *bc, bool net_admin)
  20 {
  21         if (!inet_diag_bc_sk(bc, sk))
  22                 return 0;
  23 
  24         return inet_sk_diag_fill(sk, NULL, skb, req,
  25                         sk_user_ns(NETLINK_CB(cb->skb).sk),
  26                         NETLINK_CB(cb->skb).portid,
  27                         cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh, net_admin);
  28 }
  29 
  30 static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
  31                         const struct nlmsghdr *nlh,
  32                         const struct inet_diag_req_v2 *req)
  33 {
  34         int err = -EINVAL;
  35         struct sock *sk = NULL;
  36         struct sk_buff *rep;
  37         struct net *net = sock_net(in_skb->sk);
  38 
  39         rcu_read_lock();
  40         if (req->sdiag_family == AF_INET)
  41                 /* src and dst are swapped for historical reasons */
  42                 sk = __udp4_lib_lookup(net,
  43                                 req->id.idiag_src[0], req->id.idiag_sport,
  44                                 req->id.idiag_dst[0], req->id.idiag_dport,
  45                                 req->id.idiag_if, 0, tbl, NULL);
  46 #if IS_ENABLED(CONFIG_IPV6)
  47         else if (req->sdiag_family == AF_INET6)
  48                 sk = __udp6_lib_lookup(net,
  49                                 (struct in6_addr *)req->id.idiag_src,
  50                                 req->id.idiag_sport,
  51                                 (struct in6_addr *)req->id.idiag_dst,
  52                                 req->id.idiag_dport,
  53                                 req->id.idiag_if, 0, tbl, NULL);
  54 #endif
  55         if (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
  56                 sk = NULL;
  57         rcu_read_unlock();
  58         err = -ENOENT;
  59         if (!sk)
  60                 goto out_nosk;
  61 
  62         err = sock_diag_check_cookie(sk, req->id.idiag_cookie);
  63         if (err)
  64                 goto out;
  65 
  66         err = -ENOMEM;
  67         rep = nlmsg_new(nla_total_size(sizeof(struct inet_diag_msg)) +
  68                         inet_diag_msg_attrs_size() +
  69                         nla_total_size(sizeof(struct inet_diag_meminfo)) + 64,
  70                         GFP_KERNEL);
  71         if (!rep)
  72                 goto out;
  73 
  74         err = inet_sk_diag_fill(sk, NULL, rep, req,
  75                            sk_user_ns(NETLINK_CB(in_skb).sk),
  76                            NETLINK_CB(in_skb).portid,
  77                            nlh->nlmsg_seq, 0, nlh,
  78                            netlink_net_capable(in_skb, CAP_NET_ADMIN));
  79         if (err < 0) {
  80                 WARN_ON(err == -EMSGSIZE);
  81                 kfree_skb(rep);
  82                 goto out;
  83         }
  84         err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid,
  85                               MSG_DONTWAIT);
  86         if (err > 0)
  87                 err = 0;
  88 out:
  89         if (sk)
  90                 sock_put(sk);
  91 out_nosk:
  92         return err;
  93 }
  94 
  95 static void udp_dump(struct udp_table *table, struct sk_buff *skb,
  96                      struct netlink_callback *cb,
  97                      const struct inet_diag_req_v2 *r, struct nlattr *bc)
  98 {
  99         bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN);
 100         struct net *net = sock_net(skb->sk);
 101         int num, s_num, slot, s_slot;
 102 
 103         s_slot = cb->args[0];
 104         num = s_num = cb->args[1];
 105 
 106         for (slot = s_slot; slot <= table->mask; s_num = 0, slot++) {
 107                 struct udp_hslot *hslot = &table->hash[slot];
 108                 struct sock *sk;
 109 
 110                 num = 0;
 111 
 112                 if (hlist_empty(&hslot->head))
 113                         continue;
 114 
 115                 spin_lock_bh(&hslot->lock);
 116                 sk_for_each(sk, &hslot->head) {
 117                         struct inet_sock *inet = inet_sk(sk);
 118 
 119                         if (!net_eq(sock_net(sk), net))
 120                                 continue;
 121                         if (num < s_num)
 122                                 goto next;
 123                         if (!(r->idiag_states & (1 << sk->sk_state)))
 124                                 goto next;
 125                         if (r->sdiag_family != AF_UNSPEC &&
 126                                         sk->sk_family != r->sdiag_family)
 127                                 goto next;
 128                         if (r->id.idiag_sport != inet->inet_sport &&
 129                             r->id.idiag_sport)
 130                                 goto next;
 131                         if (r->id.idiag_dport != inet->inet_dport &&
 132                             r->id.idiag_dport)
 133                                 goto next;
 134 
 135                         if (sk_diag_dump(sk, skb, cb, r, bc, net_admin) < 0) {
 136                                 spin_unlock_bh(&hslot->lock);
 137                                 goto done;
 138                         }
 139 next:
 140                         num++;
 141                 }
 142                 spin_unlock_bh(&hslot->lock);
 143         }
 144 done:
 145         cb->args[0] = slot;
 146         cb->args[1] = num;
 147 }
 148 
 149 static void udp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
 150                           const struct inet_diag_req_v2 *r, struct nlattr *bc)
 151 {
 152         udp_dump(&udp_table, skb, cb, r, bc);
 153 }
 154 
 155 static int udp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh,
 156                              const struct inet_diag_req_v2 *req)
 157 {
 158         return udp_dump_one(&udp_table, in_skb, nlh, req);
 159 }
 160 
 161 static void udp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
 162                 void *info)
 163 {
 164         r->idiag_rqueue = udp_rqueue_get(sk);
 165         r->idiag_wqueue = sk_wmem_alloc_get(sk);
 166 }
 167 
 168 #ifdef CONFIG_INET_DIAG_DESTROY
 169 static int __udp_diag_destroy(struct sk_buff *in_skb,
 170                               const struct inet_diag_req_v2 *req,
 171                               struct udp_table *tbl)
 172 {
 173         struct net *net = sock_net(in_skb->sk);
 174         struct sock *sk;
 175         int err;
 176 
 177         rcu_read_lock();
 178 
 179         if (req->sdiag_family == AF_INET)
 180                 sk = __udp4_lib_lookup(net,
 181                                 req->id.idiag_dst[0], req->id.idiag_dport,
 182                                 req->id.idiag_src[0], req->id.idiag_sport,
 183                                 req->id.idiag_if, 0, tbl, NULL);
 184 #if IS_ENABLED(CONFIG_IPV6)
 185         else if (req->sdiag_family == AF_INET6) {
 186                 if (ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_dst) &&
 187                     ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_src))
 188                         sk = __udp4_lib_lookup(net,
 189                                         req->id.idiag_dst[3], req->id.idiag_dport,
 190                                         req->id.idiag_src[3], req->id.idiag_sport,
 191                                         req->id.idiag_if, 0, tbl, NULL);
 192 
 193                 else
 194                         sk = __udp6_lib_lookup(net,
 195                                         (struct in6_addr *)req->id.idiag_dst,
 196                                         req->id.idiag_dport,
 197                                         (struct in6_addr *)req->id.idiag_src,
 198                                         req->id.idiag_sport,
 199                                         req->id.idiag_if, 0, tbl, NULL);
 200         }
 201 #endif
 202         else {
 203                 rcu_read_unlock();
 204                 return -EINVAL;
 205         }
 206 
 207         if (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
 208                 sk = NULL;
 209 
 210         rcu_read_unlock();
 211 
 212         if (!sk)
 213                 return -ENOENT;
 214 
 215         if (sock_diag_check_cookie(sk, req->id.idiag_cookie)) {
 216                 sock_put(sk);
 217                 return -ENOENT;
 218         }
 219 
 220         err = sock_diag_destroy(sk, ECONNABORTED);
 221 
 222         sock_put(sk);
 223 
 224         return err;
 225 }
 226 
 227 static int udp_diag_destroy(struct sk_buff *in_skb,
 228                             const struct inet_diag_req_v2 *req)
 229 {
 230         return __udp_diag_destroy(in_skb, req, &udp_table);
 231 }
 232 
 233 static int udplite_diag_destroy(struct sk_buff *in_skb,
 234                                 const struct inet_diag_req_v2 *req)
 235 {
 236         return __udp_diag_destroy(in_skb, req, &udplite_table);
 237 }
 238 
 239 #endif
 240 
 241 static const struct inet_diag_handler udp_diag_handler = {
 242         .dump            = udp_diag_dump,
 243         .dump_one        = udp_diag_dump_one,
 244         .idiag_get_info  = udp_diag_get_info,
 245         .idiag_type      = IPPROTO_UDP,
 246         .idiag_info_size = 0,
 247 #ifdef CONFIG_INET_DIAG_DESTROY
 248         .destroy         = udp_diag_destroy,
 249 #endif
 250 };
 251 
 252 static void udplite_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
 253                               const struct inet_diag_req_v2 *r,
 254                               struct nlattr *bc)
 255 {
 256         udp_dump(&udplite_table, skb, cb, r, bc);
 257 }
 258 
 259 static int udplite_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh,
 260                                  const struct inet_diag_req_v2 *req)
 261 {
 262         return udp_dump_one(&udplite_table, in_skb, nlh, req);
 263 }
 264 
 265 static const struct inet_diag_handler udplite_diag_handler = {
 266         .dump            = udplite_diag_dump,
 267         .dump_one        = udplite_diag_dump_one,
 268         .idiag_get_info  = udp_diag_get_info,
 269         .idiag_type      = IPPROTO_UDPLITE,
 270         .idiag_info_size = 0,
 271 #ifdef CONFIG_INET_DIAG_DESTROY
 272         .destroy         = udplite_diag_destroy,
 273 #endif
 274 };
 275 
 276 static int __init udp_diag_init(void)
 277 {
 278         int err;
 279 
 280         err = inet_diag_register(&udp_diag_handler);
 281         if (err)
 282                 goto out;
 283         err = inet_diag_register(&udplite_diag_handler);
 284         if (err)
 285                 goto out_lite;
 286 out:
 287         return err;
 288 out_lite:
 289         inet_diag_unregister(&udp_diag_handler);
 290         goto out;
 291 }
 292 
 293 static void __exit udp_diag_exit(void)
 294 {
 295         inet_diag_unregister(&udplite_diag_handler);
 296         inet_diag_unregister(&udp_diag_handler);
 297 }
 298 
 299 module_init(udp_diag_init);
 300 module_exit(udp_diag_exit);
 301 MODULE_LICENSE("GPL");
 302 MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-17 /* AF_INET - IPPROTO_UDP */);
 303 MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-136 /* AF_INET - IPPROTO_UDPLITE */);

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