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