Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * udp_diag.c   Module for monitoring UDP transport protocols sockets.
0004  *
0005  * Authors: Pavel Emelyanov, <xemul@parallels.com>
0006  */
0007 
0008 
0009 #include <linux/module.h>
0010 #include <linux/inet_diag.h>
0011 #include <linux/udp.h>
0012 #include <net/udp.h>
0013 #include <net/udplite.h>
0014 #include <linux/sock_diag.h>
0015 
0016 static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
0017             struct netlink_callback *cb,
0018             const struct inet_diag_req_v2 *req,
0019             struct nlattr *bc, bool net_admin)
0020 {
0021     if (!inet_diag_bc_sk(bc, sk))
0022         return 0;
0023 
0024     return inet_sk_diag_fill(sk, NULL, skb, cb, req, NLM_F_MULTI,
0025                  net_admin);
0026 }
0027 
0028 static int udp_dump_one(struct udp_table *tbl,
0029             struct netlink_callback *cb,
0030             const struct inet_diag_req_v2 *req)
0031 {
0032     struct sk_buff *in_skb = cb->skb;
0033     int err;
0034     struct sock *sk = NULL;
0035     struct sk_buff *rep;
0036     struct net *net = sock_net(in_skb->sk);
0037 
0038     rcu_read_lock();
0039     if (req->sdiag_family == AF_INET)
0040         /* src and dst are swapped for historical reasons */
0041         sk = __udp4_lib_lookup(net,
0042                 req->id.idiag_src[0], req->id.idiag_sport,
0043                 req->id.idiag_dst[0], req->id.idiag_dport,
0044                 req->id.idiag_if, 0, tbl, NULL);
0045 #if IS_ENABLED(CONFIG_IPV6)
0046     else if (req->sdiag_family == AF_INET6)
0047         sk = __udp6_lib_lookup(net,
0048                 (struct in6_addr *)req->id.idiag_src,
0049                 req->id.idiag_sport,
0050                 (struct in6_addr *)req->id.idiag_dst,
0051                 req->id.idiag_dport,
0052                 req->id.idiag_if, 0, tbl, NULL);
0053 #endif
0054     if (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
0055         sk = NULL;
0056     rcu_read_unlock();
0057     err = -ENOENT;
0058     if (!sk)
0059         goto out_nosk;
0060 
0061     err = sock_diag_check_cookie(sk, req->id.idiag_cookie);
0062     if (err)
0063         goto out;
0064 
0065     err = -ENOMEM;
0066     rep = nlmsg_new(nla_total_size(sizeof(struct inet_diag_msg)) +
0067             inet_diag_msg_attrs_size() +
0068             nla_total_size(sizeof(struct inet_diag_meminfo)) + 64,
0069             GFP_KERNEL);
0070     if (!rep)
0071         goto out;
0072 
0073     err = inet_sk_diag_fill(sk, NULL, rep, cb, req, 0,
0074                 netlink_net_capable(in_skb, CAP_NET_ADMIN));
0075     if (err < 0) {
0076         WARN_ON(err == -EMSGSIZE);
0077         kfree_skb(rep);
0078         goto out;
0079     }
0080     err = nlmsg_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid);
0081 
0082 out:
0083     if (sk)
0084         sock_put(sk);
0085 out_nosk:
0086     return err;
0087 }
0088 
0089 static void udp_dump(struct udp_table *table, struct sk_buff *skb,
0090              struct netlink_callback *cb,
0091              const struct inet_diag_req_v2 *r)
0092 {
0093     bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN);
0094     struct net *net = sock_net(skb->sk);
0095     struct inet_diag_dump_data *cb_data;
0096     int num, s_num, slot, s_slot;
0097     struct nlattr *bc;
0098 
0099     cb_data = cb->data;
0100     bc = cb_data->inet_diag_nla_bc;
0101     s_slot = cb->args[0];
0102     num = s_num = cb->args[1];
0103 
0104     for (slot = s_slot; slot <= table->mask; s_num = 0, slot++) {
0105         struct udp_hslot *hslot = &table->hash[slot];
0106         struct sock *sk;
0107 
0108         num = 0;
0109 
0110         if (hlist_empty(&hslot->head))
0111             continue;
0112 
0113         spin_lock_bh(&hslot->lock);
0114         sk_for_each(sk, &hslot->head) {
0115             struct inet_sock *inet = inet_sk(sk);
0116 
0117             if (!net_eq(sock_net(sk), net))
0118                 continue;
0119             if (num < s_num)
0120                 goto next;
0121             if (!(r->idiag_states & (1 << sk->sk_state)))
0122                 goto next;
0123             if (r->sdiag_family != AF_UNSPEC &&
0124                     sk->sk_family != r->sdiag_family)
0125                 goto next;
0126             if (r->id.idiag_sport != inet->inet_sport &&
0127                 r->id.idiag_sport)
0128                 goto next;
0129             if (r->id.idiag_dport != inet->inet_dport &&
0130                 r->id.idiag_dport)
0131                 goto next;
0132 
0133             if (sk_diag_dump(sk, skb, cb, r, bc, net_admin) < 0) {
0134                 spin_unlock_bh(&hslot->lock);
0135                 goto done;
0136             }
0137 next:
0138             num++;
0139         }
0140         spin_unlock_bh(&hslot->lock);
0141     }
0142 done:
0143     cb->args[0] = slot;
0144     cb->args[1] = num;
0145 }
0146 
0147 static void udp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
0148               const struct inet_diag_req_v2 *r)
0149 {
0150     udp_dump(&udp_table, skb, cb, r);
0151 }
0152 
0153 static int udp_diag_dump_one(struct netlink_callback *cb,
0154                  const struct inet_diag_req_v2 *req)
0155 {
0156     return udp_dump_one(&udp_table, cb, req);
0157 }
0158 
0159 static void udp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
0160         void *info)
0161 {
0162     r->idiag_rqueue = udp_rqueue_get(sk);
0163     r->idiag_wqueue = sk_wmem_alloc_get(sk);
0164 }
0165 
0166 #ifdef CONFIG_INET_DIAG_DESTROY
0167 static int __udp_diag_destroy(struct sk_buff *in_skb,
0168                   const struct inet_diag_req_v2 *req,
0169                   struct udp_table *tbl)
0170 {
0171     struct net *net = sock_net(in_skb->sk);
0172     struct sock *sk;
0173     int err;
0174 
0175     rcu_read_lock();
0176 
0177     if (req->sdiag_family == AF_INET)
0178         sk = __udp4_lib_lookup(net,
0179                 req->id.idiag_dst[0], req->id.idiag_dport,
0180                 req->id.idiag_src[0], req->id.idiag_sport,
0181                 req->id.idiag_if, 0, tbl, NULL);
0182 #if IS_ENABLED(CONFIG_IPV6)
0183     else if (req->sdiag_family == AF_INET6) {
0184         if (ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_dst) &&
0185             ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_src))
0186             sk = __udp4_lib_lookup(net,
0187                     req->id.idiag_dst[3], req->id.idiag_dport,
0188                     req->id.idiag_src[3], req->id.idiag_sport,
0189                     req->id.idiag_if, 0, tbl, NULL);
0190 
0191         else
0192             sk = __udp6_lib_lookup(net,
0193                     (struct in6_addr *)req->id.idiag_dst,
0194                     req->id.idiag_dport,
0195                     (struct in6_addr *)req->id.idiag_src,
0196                     req->id.idiag_sport,
0197                     req->id.idiag_if, 0, tbl, NULL);
0198     }
0199 #endif
0200     else {
0201         rcu_read_unlock();
0202         return -EINVAL;
0203     }
0204 
0205     if (sk && !refcount_inc_not_zero(&sk->sk_refcnt))
0206         sk = NULL;
0207 
0208     rcu_read_unlock();
0209 
0210     if (!sk)
0211         return -ENOENT;
0212 
0213     if (sock_diag_check_cookie(sk, req->id.idiag_cookie)) {
0214         sock_put(sk);
0215         return -ENOENT;
0216     }
0217 
0218     err = sock_diag_destroy(sk, ECONNABORTED);
0219 
0220     sock_put(sk);
0221 
0222     return err;
0223 }
0224 
0225 static int udp_diag_destroy(struct sk_buff *in_skb,
0226                 const struct inet_diag_req_v2 *req)
0227 {
0228     return __udp_diag_destroy(in_skb, req, &udp_table);
0229 }
0230 
0231 static int udplite_diag_destroy(struct sk_buff *in_skb,
0232                 const struct inet_diag_req_v2 *req)
0233 {
0234     return __udp_diag_destroy(in_skb, req, &udplite_table);
0235 }
0236 
0237 #endif
0238 
0239 static const struct inet_diag_handler udp_diag_handler = {
0240     .dump        = udp_diag_dump,
0241     .dump_one    = udp_diag_dump_one,
0242     .idiag_get_info  = udp_diag_get_info,
0243     .idiag_type  = IPPROTO_UDP,
0244     .idiag_info_size = 0,
0245 #ifdef CONFIG_INET_DIAG_DESTROY
0246     .destroy     = udp_diag_destroy,
0247 #endif
0248 };
0249 
0250 static void udplite_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
0251                   const struct inet_diag_req_v2 *r)
0252 {
0253     udp_dump(&udplite_table, skb, cb, r);
0254 }
0255 
0256 static int udplite_diag_dump_one(struct netlink_callback *cb,
0257                  const struct inet_diag_req_v2 *req)
0258 {
0259     return udp_dump_one(&udplite_table, cb, req);
0260 }
0261 
0262 static const struct inet_diag_handler udplite_diag_handler = {
0263     .dump        = udplite_diag_dump,
0264     .dump_one    = udplite_diag_dump_one,
0265     .idiag_get_info  = udp_diag_get_info,
0266     .idiag_type  = IPPROTO_UDPLITE,
0267     .idiag_info_size = 0,
0268 #ifdef CONFIG_INET_DIAG_DESTROY
0269     .destroy     = udplite_diag_destroy,
0270 #endif
0271 };
0272 
0273 static int __init udp_diag_init(void)
0274 {
0275     int err;
0276 
0277     err = inet_diag_register(&udp_diag_handler);
0278     if (err)
0279         goto out;
0280     err = inet_diag_register(&udplite_diag_handler);
0281     if (err)
0282         goto out_lite;
0283 out:
0284     return err;
0285 out_lite:
0286     inet_diag_unregister(&udp_diag_handler);
0287     goto out;
0288 }
0289 
0290 static void __exit udp_diag_exit(void)
0291 {
0292     inet_diag_unregister(&udplite_diag_handler);
0293     inet_diag_unregister(&udp_diag_handler);
0294 }
0295 
0296 module_init(udp_diag_init);
0297 module_exit(udp_diag_exit);
0298 MODULE_LICENSE("GPL");
0299 MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-17 /* AF_INET - IPPROTO_UDP */);
0300 MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-136 /* AF_INET - IPPROTO_UDPLITE */);