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