Blame view
net/ipv4/inet_diag.c
35.3 KB
2874c5fd2 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4c Linux-2.6.12-rc2 |
2 |
/* |
73c1f4a03 [TCPDIAG]: Just r... |
3 |
* inet_diag.c Module for monitoring INET transport protocols sockets. |
1da177e4c Linux-2.6.12-rc2 |
4 |
* |
1da177e4c Linux-2.6.12-rc2 |
5 |
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> |
1da177e4c Linux-2.6.12-rc2 |
6 |
*/ |
172589ccd [NET]: DIV_ROUND_... |
7 |
#include <linux/kernel.h> |
1da177e4c Linux-2.6.12-rc2 |
8 9 10 11 |
#include <linux/module.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/random.h> |
5a0e3ad6a include cleanup: ... |
12 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
13 14 15 16 17 18 19 20 |
#include <linux/cache.h> #include <linux/init.h> #include <linux/time.h> #include <net/icmp.h> #include <net/tcp.h> #include <net/ipv6.h> #include <net/inet_common.h> |
505cbfc57 [IPV6]: Generalis... |
21 22 23 24 |
#include <net/inet_connection_sock.h> #include <net/inet_hashtables.h> #include <net/inet_timewait_sock.h> #include <net/inet6_hashtables.h> |
085c20cac bpf: inet_diag: D... |
25 |
#include <net/bpf_sk_storage.h> |
dc5fc579b [NETLINK]: Use nl... |
26 |
#include <net/netlink.h> |
1da177e4c Linux-2.6.12-rc2 |
27 28 29 |
#include <linux/inet.h> #include <linux/stddef.h> |
a8c2190ee [INET_DIAG]: Rena... |
30 |
#include <linux/inet_diag.h> |
d366477a5 sock_diag: Initia... |
31 |
#include <linux/sock_diag.h> |
1da177e4c Linux-2.6.12-rc2 |
32 |
|
4f5736c4c [TCPDIAG]: Introd... |
33 |
static const struct inet_diag_handler **inet_diag_table; |
73c1f4a03 [TCPDIAG]: Just r... |
34 |
struct inet_diag_entry { |
e31c5e0e4 inet_diag: cleanups |
35 36 |
const __be32 *saddr; const __be32 *daddr; |
1da177e4c Linux-2.6.12-rc2 |
37 38 39 40 |
u16 sport; u16 dport; u16 family; u16 userlocks; |
637c841dd net: diag: Add su... |
41 |
u32 ifindex; |
a52e95abf net: diag: allow ... |
42 |
u32 mark; |
b1f3e43db inet_diag: add su... |
43 44 45 |
#ifdef CONFIG_SOCK_CGROUP_DATA u64 cgroup_id; #endif |
1da177e4c Linux-2.6.12-rc2 |
46 |
}; |
d523a328f [INET]: Fix inet_... |
47 |
static DEFINE_MUTEX(inet_diag_table_mutex); |
f13c95f0e inet_diag: Switch... |
48 |
static const struct inet_diag_handler *inet_diag_lock_handler(int proto) |
d523a328f [INET]: Fix inet_... |
49 |
{ |
3f935c75e inet_diag: suppor... |
50 51 52 53 |
if (proto < 0 || proto >= IPPROTO_MAX) { mutex_lock(&inet_diag_table_mutex); return ERR_PTR(-ENOENT); } |
f13c95f0e inet_diag: Switch... |
54 |
if (!inet_diag_table[proto]) |
bf2ae2e4b sock_diag: reques... |
55 |
sock_load_diag_module(AF_INET, proto); |
d523a328f [INET]: Fix inet_... |
56 57 |
mutex_lock(&inet_diag_table_mutex); |
f13c95f0e inet_diag: Switch... |
58 |
if (!inet_diag_table[proto]) |
d523a328f [INET]: Fix inet_... |
59 |
return ERR_PTR(-ENOENT); |
f13c95f0e inet_diag: Switch... |
60 |
return inet_diag_table[proto]; |
d523a328f [INET]: Fix inet_... |
61 |
} |
e31c5e0e4 inet_diag: cleanups |
62 |
static void inet_diag_unlock_handler(const struct inet_diag_handler *handler) |
d523a328f [INET]: Fix inet_... |
63 64 65 |
{ mutex_unlock(&inet_diag_table_mutex); } |
cb2050a7b sctp: export some... |
66 |
void inet_diag_msg_common_fill(struct inet_diag_msg *r, struct sock *sk) |
a4458343a inet_diag: factor... |
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
{ r->idiag_family = sk->sk_family; r->id.idiag_sport = htons(sk->sk_num); r->id.idiag_dport = sk->sk_dport; r->id.idiag_if = sk->sk_bound_dev_if; sock_diag_save_cookie(sk, r->id.idiag_cookie); #if IS_ENABLED(CONFIG_IPV6) if (sk->sk_family == AF_INET6) { *(struct in6_addr *)r->id.idiag_src = sk->sk_v6_rcv_saddr; *(struct in6_addr *)r->id.idiag_dst = sk->sk_v6_daddr; } else #endif { memset(&r->id.idiag_src, 0, sizeof(r->id.idiag_src)); memset(&r->id.idiag_dst, 0, sizeof(r->id.idiag_dst)); r->id.idiag_src[0] = sk->sk_rcv_saddr; r->id.idiag_dst[0] = sk->sk_daddr; } } |
cb2050a7b sctp: export some... |
89 |
EXPORT_SYMBOL_GPL(inet_diag_msg_common_fill); |
a4458343a inet_diag: factor... |
90 |
|
b37e88407 inet_diag: allow ... |
91 92 93 |
static size_t inet_sk_attr_size(struct sock *sk, const struct inet_diag_req_v2 *req, bool net_admin) |
c8e2c80d7 inet_diag: fix po... |
94 |
{ |
b37e88407 inet_diag: allow ... |
95 96 97 98 99 100 |
const struct inet_diag_handler *handler; size_t aux = 0; handler = inet_diag_table[req->sdiag_protocol]; if (handler && handler->idiag_get_aux_size) aux = handler->idiag_get_aux_size(sk, net_admin); |
c8e2c80d7 inet_diag: fix po... |
101 |
return nla_total_size(sizeof(struct tcp_info)) |
c8e2c80d7 inet_diag: fix po... |
102 |
+ nla_total_size(sizeof(struct inet_diag_msg)) |
83f73c5bb inet_diag: return... |
103 104 |
+ inet_diag_msg_attrs_size() + nla_total_size(sizeof(struct inet_diag_meminfo)) |
c8e2c80d7 inet_diag: fix po... |
105 106 107 |
+ nla_total_size(SK_MEMINFO_VARS * sizeof(u32)) + nla_total_size(TCP_CA_NAME_MAX) + nla_total_size(sizeof(struct tcpvegas_info)) |
b37e88407 inet_diag: allow ... |
108 |
+ aux |
c8e2c80d7 inet_diag: fix po... |
109 110 |
+ 64; } |
cb2050a7b sctp: export some... |
111 112 |
int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb, struct inet_diag_msg *r, int ext, |
d545caca8 net: inet: diag: ... |
113 114 |
struct user_namespace *user_ns, bool net_admin) |
cb2050a7b sctp: export some... |
115 116 |
{ const struct inet_sock *inet = inet_sk(sk); |
c10776161 ip: expose inet s... |
117 |
struct inet_diag_sockopt inet_sockopt; |
cb2050a7b sctp: export some... |
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
if (nla_put_u8(skb, INET_DIAG_SHUTDOWN, sk->sk_shutdown)) goto errout; /* IPv6 dual-stack sockets use inet->tos for IPv4 connections, * hence this needs to be included regardless of socket family. */ if (ext & (1 << (INET_DIAG_TOS - 1))) if (nla_put_u8(skb, INET_DIAG_TOS, inet->tos) < 0) goto errout; #if IS_ENABLED(CONFIG_IPV6) if (r->idiag_family == AF_INET6) { if (ext & (1 << (INET_DIAG_TCLASS - 1))) if (nla_put_u8(skb, INET_DIAG_TCLASS, inet6_sk(sk)->tclass) < 0) goto errout; if (((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) && nla_put_u8(skb, INET_DIAG_SKV6ONLY, ipv6_only_sock(sk))) goto errout; } #endif |
d545caca8 net: inet: diag: ... |
141 142 |
if (net_admin && nla_put_u32(skb, INET_DIAG_MARK, sk->sk_mark)) goto errout; |
83f73c5bb inet_diag: return... |
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
if (ext & (1 << (INET_DIAG_CLASS_ID - 1)) || ext & (1 << (INET_DIAG_TCLASS - 1))) { u32 classid = 0; #ifdef CONFIG_SOCK_CGROUP_DATA classid = sock_cgroup_classid(&sk->sk_cgrp_data); #endif /* Fallback to socket priority if class id isn't set. * Classful qdiscs use it as direct reference to class. * For cgroup2 classid is always zero. */ if (!classid) classid = sk->sk_priority; if (nla_put_u32(skb, INET_DIAG_CLASS_ID, classid)) goto errout; } |
6e3a401fc inet_diag: add cg... |
160 161 162 163 164 165 |
#ifdef CONFIG_SOCK_CGROUP_DATA if (nla_put_u64_64bit(skb, INET_DIAG_CGROUP_ID, cgroup_id(sock_cgroup_ptr(&sk->sk_cgrp_data)), INET_DIAG_PAD)) goto errout; #endif |
cb2050a7b sctp: export some... |
166 167 |
r->idiag_uid = from_kuid_munged(user_ns, sock_i_uid(sk)); r->idiag_inode = sock_i_ino(sk); |
c10776161 ip: expose inet s... |
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
memset(&inet_sockopt, 0, sizeof(inet_sockopt)); inet_sockopt.recverr = inet->recverr; inet_sockopt.is_icsk = inet->is_icsk; inet_sockopt.freebind = inet->freebind; inet_sockopt.hdrincl = inet->hdrincl; inet_sockopt.mc_loop = inet->mc_loop; inet_sockopt.transparent = inet->transparent; inet_sockopt.mc_all = inet->mc_all; inet_sockopt.nodefrag = inet->nodefrag; inet_sockopt.bind_address_no_port = inet->bind_address_no_port; inet_sockopt.recverr_rfc4884 = inet->recverr_rfc4884; inet_sockopt.defer_connect = inet->defer_connect; if (nla_put(skb, INET_DIAG_SOCKOPT, sizeof(inet_sockopt), &inet_sockopt)) goto errout; |
cb2050a7b sctp: export some... |
183 184 185 186 187 |
return 0; errout: return 1; } EXPORT_SYMBOL_GPL(inet_diag_msg_attrs_fill); |
d5e4d0a5e inet_diag: valida... |
188 189 |
static int inet_diag_parse_attrs(const struct nlmsghdr *nlh, int hdrlen, struct nlattr **req_nlas) |
3f935c75e inet_diag: suppor... |
190 191 192 193 194 195 |
{ struct nlattr *nla; int remaining; nlmsg_for_each_attr(nla, nlh, hdrlen, remaining) { int type = nla_type(nla); |
d5e4d0a5e inet_diag: valida... |
196 197 |
if (type == INET_DIAG_REQ_PROTOCOL && nla_len(nla) != sizeof(u32)) return -EINVAL; |
3f935c75e inet_diag: suppor... |
198 199 200 |
if (type < __INET_DIAG_REQ_MAX) req_nlas[type] = nla; } |
d5e4d0a5e inet_diag: valida... |
201 |
return 0; |
3f935c75e inet_diag: suppor... |
202 203 204 205 206 207 208 209 210 |
} static int inet_diag_get_protocol(const struct inet_diag_req_v2 *req, const struct inet_diag_dump_data *data) { if (data->req_nlas[INET_DIAG_REQ_PROTOCOL]) return nla_get_u32(data->req_nlas[INET_DIAG_REQ_PROTOCOL]); return req->sdiag_protocol; } |
085c20cac bpf: inet_diag: D... |
211 |
#define MAX_DUMP_ALLOC_SIZE (KMALLOC_MAX_SIZE - SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) |
3c4d05c80 inet_diag: Introd... |
212 |
int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, |
5682d393b inet_diag: Refact... |
213 214 215 |
struct sk_buff *skb, struct netlink_callback *cb, const struct inet_diag_req_v2 *req, u16 nlmsg_flags, bool net_admin) |
1da177e4c Linux-2.6.12-rc2 |
216 |
{ |
521f1cf1d inet_diag: fix ac... |
217 |
const struct tcp_congestion_ops *ca_ops; |
e31c5e0e4 inet_diag: cleanups |
218 |
const struct inet_diag_handler *handler; |
085c20cac bpf: inet_diag: D... |
219 |
struct inet_diag_dump_data *cb_data; |
e31c5e0e4 inet_diag: cleanups |
220 |
int ext = req->idiag_ext; |
73c1f4a03 [TCPDIAG]: Just r... |
221 |
struct inet_diag_msg *r; |
1da177e4c Linux-2.6.12-rc2 |
222 |
struct nlmsghdr *nlh; |
6e277ed59 inet_diag: Do not... |
223 |
struct nlattr *attr; |
4f5736c4c [TCPDIAG]: Introd... |
224 |
void *info = NULL; |
4f5736c4c [TCPDIAG]: Introd... |
225 |
|
085c20cac bpf: inet_diag: D... |
226 |
cb_data = cb->data; |
3f935c75e inet_diag: suppor... |
227 |
handler = inet_diag_table[inet_diag_get_protocol(req, cb_data)]; |
e31c5e0e4 inet_diag: cleanups |
228 |
BUG_ON(!handler); |
1da177e4c Linux-2.6.12-rc2 |
229 |
|
5682d393b inet_diag: Refact... |
230 231 |
nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, cb->nlh->nlmsg_type, sizeof(*r), nlmsg_flags); |
6e277ed59 inet_diag: Do not... |
232 |
if (!nlh) |
d106352d9 inet_diag: Move a... |
233 |
return -EMSGSIZE; |
4f5736c4c [TCPDIAG]: Introd... |
234 |
|
d106352d9 inet_diag: Move a... |
235 |
r = nlmsg_data(nlh); |
a58917f58 inet_diag: allow ... |
236 |
BUG_ON(!sk_fullsock(sk)); |
c7d58aabd [INET_DIAG]: Intr... |
237 |
|
a4458343a inet_diag: factor... |
238 |
inet_diag_msg_common_fill(r, sk); |
73c1f4a03 [TCPDIAG]: Just r... |
239 240 241 |
r->idiag_state = sk->sk_state; r->idiag_timer = 0; r->idiag_retrans = 0; |
1da177e4c Linux-2.6.12-rc2 |
242 |
|
5682d393b inet_diag: Refact... |
243 244 245 |
if (inet_diag_msg_attrs_fill(sk, skb, r, ext, sk_user_ns(NETLINK_CB(cb->skb).sk), net_admin)) |
e4e541a84 sock-diag: Report... |
246 |
goto errout; |
6e277ed59 inet_diag: Do not... |
247 248 249 |
if (ext & (1 << (INET_DIAG_MEMINFO - 1))) { struct inet_diag_meminfo minfo = { .idiag_rmem = sk_rmem_alloc_get(sk), |
ab4e846a8 tcp: annotate sk-... |
250 |
.idiag_wmem = READ_ONCE(sk->sk_wmem_queued), |
6e277ed59 inet_diag: Do not... |
251 252 253 254 255 256 |
.idiag_fmem = sk->sk_forward_alloc, .idiag_tmem = sk_wmem_alloc_get(sk), }; if (nla_put(skb, INET_DIAG_MEMINFO, sizeof(minfo), &minfo) < 0) goto errout; |
3c4d05c80 inet_diag: Introd... |
257 |
} |
c0636faa5 inet_diag: Add th... |
258 259 |
if (ext & (1 << (INET_DIAG_SKMEMINFO - 1))) if (sock_diag_put_meminfo(sk, skb, INET_DIAG_SKMEMINFO)) |
6e277ed59 inet_diag: Do not... |
260 |
goto errout; |
c0636faa5 inet_diag: Add th... |
261 |
|
432490f9d net: ip, diag -- ... |
262 263 264 265 266 267 268 269 |
/* * RAW sockets might have user-defined protocols assigned, * so report the one supplied on socket creation. */ if (sk->sk_type == SOCK_RAW) { if (nla_put_u8(skb, INET_DIAG_PROTOCOL, sk->sk_protocol)) goto errout; } |
e31c5e0e4 inet_diag: cleanups |
270 |
if (!icsk) { |
62ad6fcd7 udp_diag: impleme... |
271 |
handler->idiag_get_info(sk, r, NULL); |
3c4d05c80 inet_diag: Introd... |
272 273 |
goto out; } |
6ba8a3b19 tcp: Tail loss pr... |
274 |
if (icsk->icsk_pending == ICSK_TIME_RETRANS || |
57dde7f70 tcp: add reorderi... |
275 |
icsk->icsk_pending == ICSK_TIME_REO_TIMEOUT || |
6ba8a3b19 tcp: Tail loss pr... |
276 |
icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) { |
73c1f4a03 [TCPDIAG]: Just r... |
277 278 |
r->idiag_timer = 1; r->idiag_retrans = icsk->icsk_retransmits; |
b7de529c7 net: use jiffies_... |
279 |
r->idiag_expires = |
3828a93f5 inet_diag: use ji... |
280 |
jiffies_delta_to_msecs(icsk->icsk_timeout - jiffies); |
463c84b97 [NET]: Introduce ... |
281 |
} else if (icsk->icsk_pending == ICSK_TIME_PROBE0) { |
73c1f4a03 [TCPDIAG]: Just r... |
282 283 |
r->idiag_timer = 4; r->idiag_retrans = icsk->icsk_probes_out; |
b7de529c7 net: use jiffies_... |
284 |
r->idiag_expires = |
3828a93f5 inet_diag: use ji... |
285 |
jiffies_delta_to_msecs(icsk->icsk_timeout - jiffies); |
1da177e4c Linux-2.6.12-rc2 |
286 |
} else if (timer_pending(&sk->sk_timer)) { |
73c1f4a03 [TCPDIAG]: Just r... |
287 288 |
r->idiag_timer = 2; r->idiag_retrans = icsk->icsk_probes_out; |
b7de529c7 net: use jiffies_... |
289 |
r->idiag_expires = |
3828a93f5 inet_diag: use ji... |
290 |
jiffies_delta_to_msecs(sk->sk_timer.expires - jiffies); |
1da177e4c Linux-2.6.12-rc2 |
291 |
} else { |
73c1f4a03 [TCPDIAG]: Just r... |
292 293 |
r->idiag_timer = 0; r->idiag_expires = 0; |
1da177e4c Linux-2.6.12-rc2 |
294 |
} |
540722ffc [TCPDIAG]: Implem... |
295 |
|
3fd22af80 sock_diag: specif... |
296 |
if ((ext & (1 << (INET_DIAG_INFO - 1))) && handler->idiag_info_size) { |
6ed46d124 sock_diag: align ... |
297 298 299 |
attr = nla_reserve_64bit(skb, INET_DIAG_INFO, handler->idiag_info_size, INET_DIAG_PAD); |
6e277ed59 inet_diag: Do not... |
300 301 |
if (!attr) goto errout; |
3c4d05c80 inet_diag: Introd... |
302 |
|
6e277ed59 inet_diag: Do not... |
303 |
info = nla_data(attr); |
1da177e4c Linux-2.6.12-rc2 |
304 |
} |
521f1cf1d inet_diag: fix ac... |
305 306 307 308 309 310 311 312 313 |
if (ext & (1 << (INET_DIAG_CONG - 1))) { int err = 0; rcu_read_lock(); ca_ops = READ_ONCE(icsk->icsk_ca_ops); if (ca_ops) err = nla_put_string(skb, INET_DIAG_CONG, ca_ops->name); rcu_read_unlock(); if (err < 0) |
6e277ed59 inet_diag: Do not... |
314 |
goto errout; |
521f1cf1d inet_diag: fix ac... |
315 |
} |
6e277ed59 inet_diag: Do not... |
316 |
|
4f5736c4c [TCPDIAG]: Introd... |
317 |
handler->idiag_get_info(sk, r, info); |
1da177e4c Linux-2.6.12-rc2 |
318 |
|
b37e88407 inet_diag: allow ... |
319 320 321 |
if (ext & (1 << (INET_DIAG_INFO - 1)) && handler->idiag_get_aux) if (handler->idiag_get_aux(sk, net_admin, skb) < 0) goto errout; |
521f1cf1d inet_diag: fix ac... |
322 |
if (sk->sk_state < TCP_TIME_WAIT) { |
64f40ff5b tcp: prepare CC g... |
323 324 325 |
union tcp_cc_info info; size_t sz = 0; int attr; |
521f1cf1d inet_diag: fix ac... |
326 327 328 329 |
rcu_read_lock(); ca_ops = READ_ONCE(icsk->icsk_ca_ops); if (ca_ops && ca_ops->get_info) |
64f40ff5b tcp: prepare CC g... |
330 |
sz = ca_ops->get_info(sk, ext, &attr, &info); |
521f1cf1d inet_diag: fix ac... |
331 |
rcu_read_unlock(); |
64f40ff5b tcp: prepare CC g... |
332 |
if (sz && nla_put(skb, attr, sz, &info) < 0) |
521f1cf1d inet_diag: fix ac... |
333 334 |
goto errout; } |
1da177e4c Linux-2.6.12-rc2 |
335 |
|
085c20cac bpf: inet_diag: D... |
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 |
/* Keep it at the end for potential retry with a larger skb, * or else do best-effort fitting, which is only done for the * first_nlmsg. */ if (cb_data->bpf_stg_diag) { bool first_nlmsg = ((unsigned char *)nlh == skb->data); unsigned int prev_min_dump_alloc; unsigned int total_nla_size = 0; unsigned int msg_len; int err; msg_len = skb_tail_pointer(skb) - (unsigned char *)nlh; err = bpf_sk_storage_diag_put(cb_data->bpf_stg_diag, sk, skb, INET_DIAG_SK_BPF_STORAGES, &total_nla_size); if (!err) goto out; total_nla_size += msg_len; prev_min_dump_alloc = cb->min_dump_alloc; if (total_nla_size > prev_min_dump_alloc) cb->min_dump_alloc = min_t(u32, total_nla_size, MAX_DUMP_ALLOC_SIZE); if (!first_nlmsg) goto errout; if (cb->min_dump_alloc > prev_min_dump_alloc) /* Retry with pskb_expand_head() with * __GFP_DIRECT_RECLAIM */ goto errout; WARN_ON_ONCE(total_nla_size <= prev_min_dump_alloc); /* Send what we have for this sk * and move on to the next sk in the following * dump() */ } |
3c4d05c80 inet_diag: Introd... |
377 |
out: |
053c095a8 netlink: make nlm... |
378 379 |
nlmsg_end(skb, nlh); return 0; |
1da177e4c Linux-2.6.12-rc2 |
380 |
|
6e277ed59 inet_diag: Do not... |
381 382 |
errout: nlmsg_cancel(skb, nlh); |
26932566a [NETLINK]: Don't ... |
383 |
return -EMSGSIZE; |
1da177e4c Linux-2.6.12-rc2 |
384 |
} |
3c4d05c80 inet_diag: Introd... |
385 |
EXPORT_SYMBOL_GPL(inet_sk_diag_fill); |
33cf7c90f net: add real soc... |
386 |
static int inet_twsk_diag_fill(struct sock *sk, |
e31c5e0e4 inet_diag: cleanups |
387 |
struct sk_buff *skb, |
5682d393b inet_diag: Refact... |
388 389 |
struct netlink_callback *cb, u16 nlmsg_flags) |
c7d58aabd [INET_DIAG]: Intr... |
390 |
{ |
33cf7c90f net: add real soc... |
391 |
struct inet_timewait_sock *tw = inet_twsk(sk); |
c7d58aabd [INET_DIAG]: Intr... |
392 |
struct inet_diag_msg *r; |
6e277ed59 inet_diag: Do not... |
393 |
struct nlmsghdr *nlh; |
789f558cf tcp/dccp: get rid... |
394 |
long tmo; |
d106352d9 inet_diag: Move a... |
395 |
|
5682d393b inet_diag: Refact... |
396 397 398 |
nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, cb->nlh->nlmsg_type, sizeof(*r), nlmsg_flags); |
6e277ed59 inet_diag: Do not... |
399 |
if (!nlh) |
d106352d9 inet_diag: Move a... |
400 |
return -EMSGSIZE; |
c7d58aabd [INET_DIAG]: Intr... |
401 |
|
d106352d9 inet_diag: Move a... |
402 |
r = nlmsg_data(nlh); |
c7d58aabd [INET_DIAG]: Intr... |
403 |
BUG_ON(tw->tw_state != TCP_TIME_WAIT); |
a4458343a inet_diag: factor... |
404 |
inet_diag_msg_common_fill(r, sk); |
c7d58aabd [INET_DIAG]: Intr... |
405 |
r->idiag_retrans = 0; |
b1aac815c net: inet_diag: z... |
406 |
|
c7d58aabd [INET_DIAG]: Intr... |
407 408 |
r->idiag_state = tw->tw_substate; r->idiag_timer = 3; |
3828a93f5 inet_diag: use ji... |
409 410 |
tmo = tw->tw_timer.expires - jiffies; r->idiag_expires = jiffies_delta_to_msecs(tmo); |
c7d58aabd [INET_DIAG]: Intr... |
411 412 413 414 |
r->idiag_rqueue = 0; r->idiag_wqueue = 0; r->idiag_uid = 0; r->idiag_inode = 0; |
6e277ed59 inet_diag: Do not... |
415 |
|
053c095a8 netlink: make nlm... |
416 417 |
nlmsg_end(skb, nlh); return 0; |
c7d58aabd [INET_DIAG]: Intr... |
418 |
} |
a58917f58 inet_diag: allow ... |
419 |
static int inet_req_diag_fill(struct sock *sk, struct sk_buff *skb, |
5682d393b inet_diag: Refact... |
420 421 |
struct netlink_callback *cb, u16 nlmsg_flags, bool net_admin) |
a58917f58 inet_diag: allow ... |
422 |
{ |
d545caca8 net: inet: diag: ... |
423 |
struct request_sock *reqsk = inet_reqsk(sk); |
a58917f58 inet_diag: allow ... |
424 425 426 |
struct inet_diag_msg *r; struct nlmsghdr *nlh; long tmo; |
5682d393b inet_diag: Refact... |
427 428 |
nlh = nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, cb->nlh->nlmsg_type, sizeof(*r), nlmsg_flags); |
a58917f58 inet_diag: allow ... |
429 430 431 432 433 434 435 |
if (!nlh) return -EMSGSIZE; r = nlmsg_data(nlh); inet_diag_msg_common_fill(r, sk); r->idiag_state = TCP_SYN_RECV; r->idiag_timer = 1; |
d545caca8 net: inet: diag: ... |
436 |
r->idiag_retrans = reqsk->num_retrans; |
a58917f58 inet_diag: allow ... |
437 438 439 |
BUILD_BUG_ON(offsetof(struct inet_request_sock, ir_cookie) != offsetof(struct sock, sk_cookie)); |
fa76ce732 inet: get rid of ... |
440 |
tmo = inet_reqsk(sk)->rsk_timer.expires - jiffies; |
3828a93f5 inet_diag: use ji... |
441 |
r->idiag_expires = jiffies_delta_to_msecs(tmo); |
a58917f58 inet_diag: allow ... |
442 443 444 445 |
r->idiag_rqueue = 0; r->idiag_wqueue = 0; r->idiag_uid = 0; r->idiag_inode = 0; |
d545caca8 net: inet: diag: ... |
446 |
if (net_admin && nla_put_u32(skb, INET_DIAG_MARK, |
e33de7c53 inet_diag: Fix er... |
447 448 |
inet_rsk(reqsk)->ir_mark)) { nlmsg_cancel(skb, nlh); |
d545caca8 net: inet: diag: ... |
449 |
return -EMSGSIZE; |
e33de7c53 inet_diag: Fix er... |
450 |
} |
d545caca8 net: inet: diag: ... |
451 |
|
a58917f58 inet_diag: allow ... |
452 453 454 |
nlmsg_end(skb, nlh); return 0; } |
dff2c0353 [INET_DIAG]: Intr... |
455 |
static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, |
5682d393b inet_diag: Refact... |
456 |
struct netlink_callback *cb, |
34160ea3f inet_diag: add co... |
457 |
const struct inet_diag_req_v2 *r, |
5682d393b inet_diag: Refact... |
458 |
u16 nlmsg_flags, bool net_admin) |
dff2c0353 [INET_DIAG]: Intr... |
459 460 |
{ if (sk->sk_state == TCP_TIME_WAIT) |
5682d393b inet_diag: Refact... |
461 |
return inet_twsk_diag_fill(sk, skb, cb, nlmsg_flags); |
efe4208f4 ipv6: make lookup... |
462 |
|
a58917f58 inet_diag: allow ... |
463 |
if (sk->sk_state == TCP_NEW_SYN_RECV) |
5682d393b inet_diag: Refact... |
464 |
return inet_req_diag_fill(sk, skb, cb, nlmsg_flags, net_admin); |
a58917f58 inet_diag: allow ... |
465 |
|
5682d393b inet_diag: Refact... |
466 467 |
return inet_sk_diag_fill(sk, inet_csk(sk), skb, cb, r, nlmsg_flags, net_admin); |
dff2c0353 [INET_DIAG]: Intr... |
468 |
} |
b613f56ec net: diag: split ... |
469 470 471 |
struct sock *inet_diag_find_one_icsk(struct net *net, struct inet_hashinfo *hashinfo, const struct inet_diag_req_v2 *req) |
1da177e4c Linux-2.6.12-rc2 |
472 |
{ |
e31c5e0e4 inet_diag: cleanups |
473 |
struct sock *sk; |
d523a328f [INET]: Fix inet_... |
474 |
|
2d331915a tcp/dccp: use rcu... |
475 |
rcu_read_lock(); |
e31c5e0e4 inet_diag: cleanups |
476 |
if (req->sdiag_family == AF_INET) |
a583636a8 inet: refactor in... |
477 |
sk = inet_lookup(net, hashinfo, NULL, 0, req->id.idiag_dst[0], |
73c1f4a03 [TCPDIAG]: Just r... |
478 479 |
req->id.idiag_dport, req->id.idiag_src[0], req->id.idiag_sport, req->id.idiag_if); |
dfd56b8b3 net: use IS_ENABL... |
480 |
#if IS_ENABLED(CONFIG_IPV6) |
7c1306723 net: diag: suppor... |
481 482 483 |
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)) |
a583636a8 inet: refactor in... |
484 |
sk = inet_lookup(net, hashinfo, NULL, 0, req->id.idiag_dst[3], |
7c1306723 net: diag: suppor... |
485 486 487 |
req->id.idiag_dport, req->id.idiag_src[3], req->id.idiag_sport, req->id.idiag_if); else |
a583636a8 inet: refactor in... |
488 |
sk = inet6_lookup(net, hashinfo, NULL, 0, |
7c1306723 net: diag: suppor... |
489 490 491 492 493 494 |
(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); } |
1da177e4c Linux-2.6.12-rc2 |
495 |
#endif |
2d331915a tcp/dccp: use rcu... |
496 497 |
else { rcu_read_unlock(); |
b613f56ec net: diag: split ... |
498 |
return ERR_PTR(-EINVAL); |
2d331915a tcp/dccp: use rcu... |
499 500 |
} rcu_read_unlock(); |
e31c5e0e4 inet_diag: cleanups |
501 |
if (!sk) |
b613f56ec net: diag: split ... |
502 |
return ERR_PTR(-ENOENT); |
1da177e4c Linux-2.6.12-rc2 |
503 |
|
b613f56ec net: diag: split ... |
504 505 506 507 508 509 510 511 512 513 |
if (sock_diag_check_cookie(sk, req->id.idiag_cookie)) { sock_gen_put(sk); return ERR_PTR(-ENOENT); } return sk; } EXPORT_SYMBOL_GPL(inet_diag_find_one_icsk); int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, |
5682d393b inet_diag: Refact... |
514 |
struct netlink_callback *cb, |
b613f56ec net: diag: split ... |
515 516 |
const struct inet_diag_req_v2 *req) { |
5682d393b inet_diag: Refact... |
517 |
struct sk_buff *in_skb = cb->skb; |
b37e88407 inet_diag: allow ... |
518 |
bool net_admin = netlink_net_capable(in_skb, CAP_NET_ADMIN); |
b613f56ec net: diag: split ... |
519 520 521 522 523 524 525 526 |
struct net *net = sock_net(in_skb->sk); struct sk_buff *rep; struct sock *sk; int err; sk = inet_diag_find_one_icsk(net, hashinfo, req); if (IS_ERR(sk)) return PTR_ERR(sk); |
1da177e4c Linux-2.6.12-rc2 |
527 |
|
b37e88407 inet_diag: allow ... |
528 |
rep = nlmsg_new(inet_sk_attr_size(sk, req, net_admin), GFP_KERNEL); |
6e277ed59 inet_diag: Do not... |
529 530 |
if (!rep) { err = -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
531 |
goto out; |
6e277ed59 inet_diag: Do not... |
532 |
} |
1da177e4c Linux-2.6.12-rc2 |
533 |
|
5682d393b inet_diag: Refact... |
534 |
err = sk_diag_fill(sk, rep, cb, req, 0, net_admin); |
26932566a [NETLINK]: Don't ... |
535 536 |
if (err < 0) { WARN_ON(err == -EMSGSIZE); |
6e277ed59 inet_diag: Do not... |
537 |
nlmsg_free(rep); |
26932566a [NETLINK]: Don't ... |
538 539 |
goto out; } |
15e473046 netlink: Rename p... |
540 |
err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid, |
73c1f4a03 [TCPDIAG]: Just r... |
541 |
MSG_DONTWAIT); |
1da177e4c Linux-2.6.12-rc2 |
542 543 544 545 |
if (err > 0) err = 0; out: |
c1d607cc4 inet_diag: use so... |
546 547 |
if (sk) sock_gen_put(sk); |
476f7dbff inet_diag: Split ... |
548 549 |
return err; } |
1942c518c inet_diag: Genera... |
550 |
EXPORT_SYMBOL_GPL(inet_diag_dump_one_icsk); |
476f7dbff inet_diag: Split ... |
551 |
|
6eb5d2e08 net: diag: Suppor... |
552 |
static int inet_diag_cmd_exact(int cmd, struct sk_buff *in_skb, |
476f7dbff inet_diag: Split ... |
553 |
const struct nlmsghdr *nlh, |
3f935c75e inet_diag: suppor... |
554 |
int hdrlen, |
34160ea3f inet_diag: add co... |
555 |
const struct inet_diag_req_v2 *req) |
476f7dbff inet_diag: Split ... |
556 557 |
{ const struct inet_diag_handler *handler; |
3f935c75e inet_diag: suppor... |
558 559 560 561 |
struct inet_diag_dump_data dump_data; int err, protocol; memset(&dump_data, 0, sizeof(dump_data)); |
d5e4d0a5e inet_diag: valida... |
562 563 564 |
err = inet_diag_parse_attrs(nlh, hdrlen, dump_data.req_nlas); if (err) return err; |
3f935c75e inet_diag: suppor... |
565 |
protocol = inet_diag_get_protocol(req, &dump_data); |
476f7dbff inet_diag: Split ... |
566 |
|
3f935c75e inet_diag: suppor... |
567 |
handler = inet_diag_lock_handler(protocol); |
5682d393b inet_diag: Refact... |
568 |
if (IS_ERR(handler)) { |
476f7dbff inet_diag: Split ... |
569 |
err = PTR_ERR(handler); |
5682d393b inet_diag: Refact... |
570 571 572 573 |
} else if (cmd == SOCK_DIAG_BY_FAMILY) { struct netlink_callback cb = { .nlh = nlh, .skb = in_skb, |
3f935c75e inet_diag: suppor... |
574 |
.data = &dump_data, |
5682d393b inet_diag: Refact... |
575 576 577 |
}; err = handler->dump_one(&cb, req); } else if (cmd == SOCK_DESTROY && handler->destroy) { |
6eb5d2e08 net: diag: Suppor... |
578 |
err = handler->destroy(in_skb, req); |
5682d393b inet_diag: Refact... |
579 |
} else { |
6eb5d2e08 net: diag: Suppor... |
580 |
err = -EOPNOTSUPP; |
5682d393b inet_diag: Refact... |
581 |
} |
d523a328f [INET]: Fix inet_... |
582 |
inet_diag_unlock_handler(handler); |
476f7dbff inet_diag: Split ... |
583 |
|
1da177e4c Linux-2.6.12-rc2 |
584 585 |
return err; } |
9f8552996 [IPV4]: inet_diag... |
586 |
static int bitstring_match(const __be32 *a1, const __be32 *a2, int bits) |
1da177e4c Linux-2.6.12-rc2 |
587 588 589 590 591 592 593 594 595 596 |
{ int words = bits >> 5; bits &= 0x1f; if (words) { if (memcmp(a1, a2, words << 2)) return 0; } if (bits) { |
9f8552996 [IPV4]: inet_diag... |
597 598 |
__be32 w1, w2; __be32 mask; |
1da177e4c Linux-2.6.12-rc2 |
599 600 601 602 603 604 605 606 607 608 609 610 |
w1 = a1[words]; w2 = a2[words]; mask = htonl((0xffffffff) << (32 - bits)); if ((w1 ^ w2) & mask) return 0; } return 1; } |
87c22ea52 inet_diag: Reduce... |
611 |
static int inet_diag_bc_run(const struct nlattr *_bc, |
e31c5e0e4 inet_diag: cleanups |
612 |
const struct inet_diag_entry *entry) |
1da177e4c Linux-2.6.12-rc2 |
613 |
{ |
87c22ea52 inet_diag: Reduce... |
614 615 |
const void *bc = nla_data(_bc); int len = nla_len(_bc); |
1da177e4c Linux-2.6.12-rc2 |
616 617 |
while (len > 0) { int yes = 1; |
73c1f4a03 [TCPDIAG]: Just r... |
618 |
const struct inet_diag_bc_op *op = bc; |
1da177e4c Linux-2.6.12-rc2 |
619 620 |
switch (op->code) { |
73c1f4a03 [TCPDIAG]: Just r... |
621 |
case INET_DIAG_BC_NOP: |
1da177e4c Linux-2.6.12-rc2 |
622 |
break; |
73c1f4a03 [TCPDIAG]: Just r... |
623 |
case INET_DIAG_BC_JMP: |
1da177e4c Linux-2.6.12-rc2 |
624 625 |
yes = 0; break; |
bbb6189df inet_diag: Add eq... |
626 627 628 |
case INET_DIAG_BC_S_EQ: yes = entry->sport == op[1].no; break; |
73c1f4a03 [TCPDIAG]: Just r... |
629 |
case INET_DIAG_BC_S_GE: |
1da177e4c Linux-2.6.12-rc2 |
630 631 |
yes = entry->sport >= op[1].no; break; |
73c1f4a03 [TCPDIAG]: Just r... |
632 |
case INET_DIAG_BC_S_LE: |
b4ced2b76 netlink: With opc... |
633 |
yes = entry->sport <= op[1].no; |
1da177e4c Linux-2.6.12-rc2 |
634 |
break; |
bbb6189df inet_diag: Add eq... |
635 636 637 |
case INET_DIAG_BC_D_EQ: yes = entry->dport == op[1].no; break; |
73c1f4a03 [TCPDIAG]: Just r... |
638 |
case INET_DIAG_BC_D_GE: |
1da177e4c Linux-2.6.12-rc2 |
639 640 |
yes = entry->dport >= op[1].no; break; |
73c1f4a03 [TCPDIAG]: Just r... |
641 |
case INET_DIAG_BC_D_LE: |
1da177e4c Linux-2.6.12-rc2 |
642 643 |
yes = entry->dport <= op[1].no; break; |
73c1f4a03 [TCPDIAG]: Just r... |
644 |
case INET_DIAG_BC_AUTO: |
1da177e4c Linux-2.6.12-rc2 |
645 646 |
yes = !(entry->userlocks & SOCK_BINDPORT_LOCK); break; |
73c1f4a03 [TCPDIAG]: Just r... |
647 |
case INET_DIAG_BC_S_COND: |
a8c2190ee [INET_DIAG]: Rena... |
648 |
case INET_DIAG_BC_D_COND: { |
e31c5e0e4 inet_diag: cleanups |
649 650 |
const struct inet_diag_hostcond *cond; const __be32 *addr; |
1da177e4c Linux-2.6.12-rc2 |
651 |
|
e31c5e0e4 inet_diag: cleanups |
652 |
cond = (const struct inet_diag_hostcond *)(op + 1); |
1da177e4c Linux-2.6.12-rc2 |
653 |
if (cond->port != -1 && |
73c1f4a03 [TCPDIAG]: Just r... |
654 |
cond->port != (op->code == INET_DIAG_BC_S_COND ? |
1da177e4c Linux-2.6.12-rc2 |
655 656 657 658 |
entry->sport : entry->dport)) { yes = 0; break; } |
4e852c027 [INET_DIAG]: whit... |
659 |
|
73c1f4a03 [TCPDIAG]: Just r... |
660 |
if (op->code == INET_DIAG_BC_S_COND) |
1da177e4c Linux-2.6.12-rc2 |
661 662 663 |
addr = entry->saddr; else addr = entry->daddr; |
f67caec90 inet_diag: avoid ... |
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 |
if (cond->family != AF_UNSPEC && cond->family != entry->family) { if (entry->family == AF_INET6 && cond->family == AF_INET) { if (addr[0] == 0 && addr[1] == 0 && addr[2] == htonl(0xffff) && bitstring_match(addr + 3, cond->addr, cond->prefix_len)) break; } yes = 0; break; } if (cond->prefix_len == 0) break; |
4e852c027 [INET_DIAG]: whit... |
681 682 |
if (bitstring_match(addr, cond->addr, cond->prefix_len)) |
1da177e4c Linux-2.6.12-rc2 |
683 |
break; |
1da177e4c Linux-2.6.12-rc2 |
684 685 686 |
yes = 0; break; } |
637c841dd net: diag: Add su... |
687 688 689 690 691 692 693 694 |
case INET_DIAG_BC_DEV_COND: { u32 ifindex; ifindex = *((const u32 *)(op + 1)); if (ifindex != entry->ifindex) yes = 0; break; } |
a52e95abf net: diag: allow ... |
695 696 697 698 699 700 701 702 |
case INET_DIAG_BC_MARK_COND: { struct inet_diag_markcond *cond; cond = (struct inet_diag_markcond *)(op + 1); if ((entry->mark & cond->mask) != cond->mark) yes = 0; break; } |
b1f3e43db inet_diag: add su... |
703 704 705 706 707 708 709 710 711 712 |
#ifdef CONFIG_SOCK_CGROUP_DATA case INET_DIAG_BC_CGROUP_COND: { u64 cgroup_id; cgroup_id = get_unaligned((const u64 *)(op + 1)); if (cgroup_id != entry->cgroup_id) yes = 0; break; } #endif |
1da177e4c Linux-2.6.12-rc2 |
713 |
} |
4e852c027 [INET_DIAG]: whit... |
714 |
if (yes) { |
1da177e4c Linux-2.6.12-rc2 |
715 716 717 718 719 720 721 |
len -= op->yes; bc += op->yes; } else { len -= op->no; bc += op->no; } } |
a02cec215 net: return opera... |
722 |
return len == 0; |
1da177e4c Linux-2.6.12-rc2 |
723 |
} |
a4458343a inet_diag: factor... |
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 |
/* This helper is available for all sockets (ESTABLISH, TIMEWAIT, SYN_RECV) */ static void entry_fill_addrs(struct inet_diag_entry *entry, const struct sock *sk) { #if IS_ENABLED(CONFIG_IPV6) if (sk->sk_family == AF_INET6) { entry->saddr = sk->sk_v6_rcv_saddr.s6_addr32; entry->daddr = sk->sk_v6_daddr.s6_addr32; } else #endif { entry->saddr = &sk->sk_rcv_saddr; entry->daddr = &sk->sk_daddr; } } |
8d07d1518 inet_diag: Introd... |
740 741 |
int inet_diag_bc_sk(const struct nlattr *bc, struct sock *sk) { |
8d07d1518 inet_diag: Introd... |
742 |
struct inet_sock *inet = inet_sk(sk); |
e31c5e0e4 inet_diag: cleanups |
743 |
struct inet_diag_entry entry; |
8d07d1518 inet_diag: Introd... |
744 |
|
e31c5e0e4 inet_diag: cleanups |
745 |
if (!bc) |
8d07d1518 inet_diag: Introd... |
746 747 748 |
return 1; entry.family = sk->sk_family; |
a4458343a inet_diag: factor... |
749 |
entry_fill_addrs(&entry, sk); |
8d07d1518 inet_diag: Introd... |
750 751 |
entry.sport = inet->inet_num; entry.dport = ntohs(inet->inet_dport); |
637c841dd net: diag: Add su... |
752 |
entry.ifindex = sk->sk_bound_dev_if; |
a58917f58 inet_diag: allow ... |
753 |
entry.userlocks = sk_fullsock(sk) ? sk->sk_userlocks : 0; |
a52e95abf net: diag: allow ... |
754 755 756 757 758 759 |
if (sk_fullsock(sk)) entry.mark = sk->sk_mark; else if (sk->sk_state == TCP_NEW_SYN_RECV) entry.mark = inet_rsk(inet_reqsk(sk))->ir_mark; else entry.mark = 0; |
b1f3e43db inet_diag: add su... |
760 |
#ifdef CONFIG_SOCK_CGROUP_DATA |
ee1bd483c inet_diag: bc: re... |
761 762 |
entry.cgroup_id = sk_fullsock(sk) ? cgroup_id(sock_cgroup_ptr(&sk->sk_cgrp_data)) : 0; |
b1f3e43db inet_diag: add su... |
763 |
#endif |
8d07d1518 inet_diag: Introd... |
764 765 766 767 |
return inet_diag_bc_run(bc, &entry); } EXPORT_SYMBOL_GPL(inet_diag_bc_sk); |
1da177e4c Linux-2.6.12-rc2 |
768 769 770 |
static int valid_cc(const void *bc, int len, int cc) { while (len >= 0) { |
73c1f4a03 [TCPDIAG]: Just r... |
771 |
const struct inet_diag_bc_op *op = bc; |
1da177e4c Linux-2.6.12-rc2 |
772 773 774 775 776 |
if (cc > len) return 0; if (cc == len) return 1; |
eeb149727 inet_diag: fix in... |
777 |
if (op->yes < 4 || op->yes & 3) |
1da177e4c Linux-2.6.12-rc2 |
778 779 780 781 782 783 |
return 0; len -= op->yes; bc += op->yes; } return 0; } |
637c841dd net: diag: Add su... |
784 785 786 787 788 789 790 791 792 793 794 |
/* data is u32 ifindex */ static bool valid_devcond(const struct inet_diag_bc_op *op, int len, int *min_len) { /* Check ifindex space. */ *min_len += sizeof(u32); if (len < *min_len) return false; return true; } |
405c00594 inet_diag: valida... |
795 796 797 798 |
/* Validate an inet_diag_hostcond. */ static bool valid_hostcond(const struct inet_diag_bc_op *op, int len, int *min_len) { |
405c00594 inet_diag: valida... |
799 |
struct inet_diag_hostcond *cond; |
e31c5e0e4 inet_diag: cleanups |
800 |
int addr_len; |
405c00594 inet_diag: valida... |
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 |
/* Check hostcond space. */ *min_len += sizeof(struct inet_diag_hostcond); if (len < *min_len) return false; cond = (struct inet_diag_hostcond *)(op + 1); /* Check address family and address length. */ switch (cond->family) { case AF_UNSPEC: addr_len = 0; break; case AF_INET: addr_len = sizeof(struct in_addr); break; case AF_INET6: addr_len = sizeof(struct in6_addr); break; default: return false; } *min_len += addr_len; if (len < *min_len) return false; /* Check prefix length (in bits) vs address length (in bytes). */ if (cond->prefix_len > 8 * addr_len) return false; return true; } |
5e1f54201 inet_diag: valida... |
832 |
/* Validate a port comparison operator. */ |
e31c5e0e4 inet_diag: cleanups |
833 834 |
static bool valid_port_comparison(const struct inet_diag_bc_op *op, int len, int *min_len) |
5e1f54201 inet_diag: valida... |
835 836 837 838 839 840 841 |
{ /* Port comparisons put the port in a follow-on inet_diag_bc_op. */ *min_len += sizeof(struct inet_diag_bc_op); if (len < *min_len) return false; return true; } |
a52e95abf net: diag: allow ... |
842 843 |
static bool valid_markcond(const struct inet_diag_bc_op *op, int len, int *min_len) |
1da177e4c Linux-2.6.12-rc2 |
844 |
{ |
a52e95abf net: diag: allow ... |
845 846 847 |
*min_len += sizeof(struct inet_diag_markcond); return len >= *min_len; } |
b1f3e43db inet_diag: add su... |
848 849 850 851 852 853 854 855 |
#ifdef CONFIG_SOCK_CGROUP_DATA static bool valid_cgroupcond(const struct inet_diag_bc_op *op, int len, int *min_len) { *min_len += sizeof(u64); return len >= *min_len; } #endif |
a52e95abf net: diag: allow ... |
856 857 858 859 |
static int inet_diag_bc_audit(const struct nlattr *attr, const struct sk_buff *skb) { bool net_admin = netlink_net_capable(skb, CAP_NET_ADMIN); |
627cc4add net: diag: slight... |
860 861 862 863 864 865 866 867 |
const void *bytecode, *bc; int bytecode_len, len; if (!attr || nla_len(attr) < sizeof(struct inet_diag_bc_op)) return -EINVAL; bytecode = bc = nla_data(attr); len = bytecode_len = nla_len(attr); |
1da177e4c Linux-2.6.12-rc2 |
868 869 |
while (len > 0) { |
405c00594 inet_diag: valida... |
870 |
int min_len = sizeof(struct inet_diag_bc_op); |
e31c5e0e4 inet_diag: cleanups |
871 |
const struct inet_diag_bc_op *op = bc; |
1da177e4c Linux-2.6.12-rc2 |
872 |
|
1da177e4c Linux-2.6.12-rc2 |
873 |
switch (op->code) { |
73c1f4a03 [TCPDIAG]: Just r... |
874 875 |
case INET_DIAG_BC_S_COND: case INET_DIAG_BC_D_COND: |
405c00594 inet_diag: valida... |
876 877 |
if (!valid_hostcond(bc, len, &min_len)) return -EINVAL; |
5e1f54201 inet_diag: valida... |
878 |
break; |
637c841dd net: diag: Add su... |
879 880 881 882 |
case INET_DIAG_BC_DEV_COND: if (!valid_devcond(bc, len, &min_len)) return -EINVAL; break; |
bbb6189df inet_diag: Add eq... |
883 |
case INET_DIAG_BC_S_EQ: |
73c1f4a03 [TCPDIAG]: Just r... |
884 885 |
case INET_DIAG_BC_S_GE: case INET_DIAG_BC_S_LE: |
bbb6189df inet_diag: Add eq... |
886 |
case INET_DIAG_BC_D_EQ: |
73c1f4a03 [TCPDIAG]: Just r... |
887 888 |
case INET_DIAG_BC_D_GE: case INET_DIAG_BC_D_LE: |
5e1f54201 inet_diag: valida... |
889 |
if (!valid_port_comparison(bc, len, &min_len)) |
1da177e4c Linux-2.6.12-rc2 |
890 891 |
return -EINVAL; break; |
a52e95abf net: diag: allow ... |
892 893 894 895 896 897 |
case INET_DIAG_BC_MARK_COND: if (!net_admin) return -EPERM; if (!valid_markcond(bc, len, &min_len)) return -EINVAL; break; |
b1f3e43db inet_diag: add su... |
898 899 900 901 902 903 |
#ifdef CONFIG_SOCK_CGROUP_DATA case INET_DIAG_BC_CGROUP_COND: if (!valid_cgroupcond(bc, len, &min_len)) return -EINVAL; break; #endif |
5e1f54201 inet_diag: valida... |
904 905 |
case INET_DIAG_BC_AUTO: case INET_DIAG_BC_JMP: |
73c1f4a03 [TCPDIAG]: Just r... |
906 |
case INET_DIAG_BC_NOP: |
1da177e4c Linux-2.6.12-rc2 |
907 908 909 910 |
break; default: return -EINVAL; } |
5e1f54201 inet_diag: valida... |
911 912 913 914 915 916 917 918 |
if (op->code != INET_DIAG_BC_NOP) { if (op->no < min_len || op->no > len + 4 || op->no & 3) return -EINVAL; if (op->no < len && !valid_cc(bytecode, bytecode_len, len - op->no)) return -EINVAL; } |
405c00594 inet_diag: valida... |
919 |
if (op->yes < min_len || op->yes > len + 4 || op->yes & 3) |
eeb149727 inet_diag: fix in... |
920 |
return -EINVAL; |
4e852c027 [INET_DIAG]: whit... |
921 |
bc += op->yes; |
1da177e4c Linux-2.6.12-rc2 |
922 923 924 925 |
len -= op->yes; } return len == 0 ? 0 : -EINVAL; } |
496127290 inet_diag: remove... |
926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 |
static void twsk_build_assert(void) { BUILD_BUG_ON(offsetof(struct inet_timewait_sock, tw_family) != offsetof(struct sock, sk_family)); BUILD_BUG_ON(offsetof(struct inet_timewait_sock, tw_num) != offsetof(struct inet_sock, inet_num)); BUILD_BUG_ON(offsetof(struct inet_timewait_sock, tw_dport) != offsetof(struct inet_sock, inet_dport)); BUILD_BUG_ON(offsetof(struct inet_timewait_sock, tw_rcv_saddr) != offsetof(struct inet_sock, inet_rcv_saddr)); BUILD_BUG_ON(offsetof(struct inet_timewait_sock, tw_daddr) != offsetof(struct inet_sock, inet_daddr)); #if IS_ENABLED(CONFIG_IPV6) BUILD_BUG_ON(offsetof(struct inet_timewait_sock, tw_v6_rcv_saddr) != offsetof(struct sock, sk_v6_rcv_saddr)); BUILD_BUG_ON(offsetof(struct inet_timewait_sock, tw_v6_daddr) != offsetof(struct sock, sk_v6_daddr)); #endif } |
1942c518c inet_diag: Genera... |
951 |
void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb, |
e31c5e0e4 inet_diag: cleanups |
952 |
struct netlink_callback *cb, |
0df6d3284 inet_diag: Move t... |
953 |
const struct inet_diag_req_v2 *r) |
1da177e4c Linux-2.6.12-rc2 |
954 |
{ |
67db3e4bf tcp: no longer ho... |
955 |
bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN); |
0df6d3284 inet_diag: Move t... |
956 |
struct inet_diag_dump_data *cb_data = cb->data; |
51d7cccf0 net: make sock di... |
957 |
struct net *net = sock_net(skb->sk); |
079096f10 tcp/dccp: install... |
958 |
u32 idiag_states = r->idiag_states; |
67db3e4bf tcp: no longer ho... |
959 |
int i, num, s_i, s_num; |
0df6d3284 inet_diag: Move t... |
960 |
struct nlattr *bc; |
67db3e4bf tcp: no longer ho... |
961 |
struct sock *sk; |
4e852c027 [INET_DIAG]: whit... |
962 |
|
0df6d3284 inet_diag: Move t... |
963 |
bc = cb_data->inet_diag_nla_bc; |
079096f10 tcp/dccp: install... |
964 965 |
if (idiag_states & TCPF_SYN_RECV) idiag_states |= TCPF_NEW_SYN_RECV; |
1da177e4c Linux-2.6.12-rc2 |
966 967 |
s_i = cb->args[1]; s_num = num = cb->args[2]; |
4f5736c4c [TCPDIAG]: Introd... |
968 |
|
1da177e4c Linux-2.6.12-rc2 |
969 |
if (cb->args[0] == 0) { |
9652dc2eb tcp: relax listen... |
970 |
if (!(idiag_states & TCPF_LISTEN) || r->id.idiag_dport) |
1da177e4c Linux-2.6.12-rc2 |
971 |
goto skip_listen_ht; |
540722ffc [TCPDIAG]: Implem... |
972 |
|
0f7ff9274 [INET]: Just rena... |
973 |
for (i = s_i; i < INET_LHTABLE_SIZE; i++) { |
5caea4ea7 net: listening_ha... |
974 |
struct inet_listen_hashbucket *ilb; |
8dbd76e79 tcp/dccp: fix pos... |
975 |
struct hlist_nulls_node *node; |
1da177e4c Linux-2.6.12-rc2 |
976 977 |
num = 0; |
5caea4ea7 net: listening_ha... |
978 |
ilb = &hashinfo->listening_hash[i]; |
9652dc2eb tcp: relax listen... |
979 |
spin_lock(&ilb->lock); |
8dbd76e79 tcp/dccp: fix pos... |
980 |
sk_nulls_for_each(sk, node, &ilb->nulls_head) { |
1da177e4c Linux-2.6.12-rc2 |
981 |
struct inet_sock *inet = inet_sk(sk); |
51d7cccf0 net: make sock di... |
982 983 |
if (!net_eq(sock_net(sk), net)) continue; |
1da177e4c Linux-2.6.12-rc2 |
984 985 986 987 |
if (num < s_num) { num++; continue; } |
d23deaa07 inet_diag: Introd... |
988 |
if (r->sdiag_family != AF_UNSPEC && |
e31c5e0e4 inet_diag: cleanups |
989 |
sk->sk_family != r->sdiag_family) |
d23deaa07 inet_diag: Introd... |
990 |
goto next_listen; |
c720c7e83 inet: rename some... |
991 |
if (r->id.idiag_sport != inet->inet_sport && |
73c1f4a03 [TCPDIAG]: Just r... |
992 |
r->id.idiag_sport) |
1da177e4c Linux-2.6.12-rc2 |
993 |
goto next_listen; |
5682d393b inet_diag: Refact... |
994 995 996 997 998 999 |
if (!inet_diag_bc_sk(bc, sk)) goto next_listen; if (inet_sk_diag_fill(sk, inet_csk(sk), skb, cb, r, NLM_F_MULTI, net_admin) < 0) { |
9652dc2eb tcp: relax listen... |
1000 |
spin_unlock(&ilb->lock); |
1da177e4c Linux-2.6.12-rc2 |
1001 1002 1003 1004 |
goto done; } next_listen: |
1da177e4c Linux-2.6.12-rc2 |
1005 1006 |
++num; } |
9652dc2eb tcp: relax listen... |
1007 |
spin_unlock(&ilb->lock); |
1da177e4c Linux-2.6.12-rc2 |
1008 1009 |
s_num = 0; |
1da177e4c Linux-2.6.12-rc2 |
1010 |
} |
1da177e4c Linux-2.6.12-rc2 |
1011 1012 1013 1014 |
skip_listen_ht: cb->args[0] = 1; s_i = num = s_num = 0; } |
079096f10 tcp/dccp: install... |
1015 |
if (!(idiag_states & ~TCPF_LISTEN)) |
efb3cb428 inet_diag: Split ... |
1016 |
goto out; |
1da177e4c Linux-2.6.12-rc2 |
1017 |
|
67db3e4bf tcp: no longer ho... |
1018 |
#define SKARR_SZ 16 |
f373b53b5 tcp: replace ehas... |
1019 |
for (i = s_i; i <= hashinfo->ehash_mask; i++) { |
540722ffc [TCPDIAG]: Implem... |
1020 |
struct inet_ehash_bucket *head = &hashinfo->ehash[i]; |
7e3aab4a9 inet_diag: Missed... |
1021 |
spinlock_t *lock = inet_ehash_lockp(hashinfo, i); |
3ab5aee7f net: Convert TCP ... |
1022 |
struct hlist_nulls_node *node; |
67db3e4bf tcp: no longer ho... |
1023 1024 1025 |
struct sock *sk_arr[SKARR_SZ]; int num_arr[SKARR_SZ]; int idx, accum, res; |
6be547a61 inet_diag: Add em... |
1026 |
|
05dbc7b59 tcp/dccp: remove ... |
1027 |
if (hlist_nulls_empty(&head->chain)) |
6be547a61 inet_diag: Add em... |
1028 |
continue; |
1da177e4c Linux-2.6.12-rc2 |
1029 1030 |
if (i > s_i) s_num = 0; |
67db3e4bf tcp: no longer ho... |
1031 1032 1033 |
next_chunk: num = 0; accum = 0; |
7e3aab4a9 inet_diag: Missed... |
1034 |
spin_lock_bh(lock); |
3ab5aee7f net: Convert TCP ... |
1035 |
sk_nulls_for_each(sk, node, &head->chain) { |
67db3e4bf tcp: no longer ho... |
1036 |
int state; |
1da177e4c Linux-2.6.12-rc2 |
1037 |
|
51d7cccf0 net: make sock di... |
1038 1039 |
if (!net_eq(sock_net(sk), net)) continue; |
1da177e4c Linux-2.6.12-rc2 |
1040 1041 |
if (num < s_num) goto next_normal; |
70315d22d inet_diag: fix in... |
1042 1043 |
state = (sk->sk_state == TCP_TIME_WAIT) ? inet_twsk(sk)->tw_substate : sk->sk_state; |
079096f10 tcp/dccp: install... |
1044 |
if (!(idiag_states & (1 << state))) |
1da177e4c Linux-2.6.12-rc2 |
1045 |
goto next_normal; |
d23deaa07 inet_diag: Introd... |
1046 |
if (r->sdiag_family != AF_UNSPEC && |
05dbc7b59 tcp/dccp: remove ... |
1047 |
sk->sk_family != r->sdiag_family) |
d23deaa07 inet_diag: Introd... |
1048 |
goto next_normal; |
05dbc7b59 tcp/dccp: remove ... |
1049 |
if (r->id.idiag_sport != htons(sk->sk_num) && |
73c1f4a03 [TCPDIAG]: Just r... |
1050 |
r->id.idiag_sport) |
1da177e4c Linux-2.6.12-rc2 |
1051 |
goto next_normal; |
05dbc7b59 tcp/dccp: remove ... |
1052 |
if (r->id.idiag_dport != sk->sk_dport && |
4e852c027 [INET_DIAG]: whit... |
1053 |
r->id.idiag_dport) |
1da177e4c Linux-2.6.12-rc2 |
1054 |
goto next_normal; |
a58917f58 inet_diag: allow ... |
1055 1056 1057 1058 |
twsk_build_assert(); if (!inet_diag_bc_sk(bc, sk)) goto next_normal; |
f0c928d87 tcp: fix a race i... |
1059 1060 |
if (!refcount_inc_not_zero(&sk->sk_refcnt)) goto next_normal; |
67db3e4bf tcp: no longer ho... |
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 |
num_arr[accum] = num; sk_arr[accum] = sk; if (++accum == SKARR_SZ) break; next_normal: ++num; } spin_unlock_bh(lock); res = 0; for (idx = 0; idx < accum; idx++) { if (res >= 0) { |
5682d393b inet_diag: Refact... |
1072 1073 |
res = sk_diag_fill(sk_arr[idx], skb, cb, r, NLM_F_MULTI, net_admin); |
67db3e4bf tcp: no longer ho... |
1074 1075 |
if (res < 0) num = num_arr[idx]; |
1da177e4c Linux-2.6.12-rc2 |
1076 |
} |
67db3e4bf tcp: no longer ho... |
1077 |
sock_gen_put(sk_arr[idx]); |
1da177e4c Linux-2.6.12-rc2 |
1078 |
} |
67db3e4bf tcp: no longer ho... |
1079 1080 |
if (res < 0) break; |
acffb584c net: diag: add a ... |
1081 |
cond_resched(); |
67db3e4bf tcp: no longer ho... |
1082 1083 1084 1085 |
if (accum == SKARR_SZ) { s_num = num + 1; goto next_chunk; } |
1da177e4c Linux-2.6.12-rc2 |
1086 1087 1088 1089 1090 |
} done: cb->args[1] = i; cb->args[2] = num; |
efb3cb428 inet_diag: Split ... |
1091 1092 1093 |
out: ; } |
1942c518c inet_diag: Genera... |
1094 |
EXPORT_SYMBOL_GPL(inet_diag_dump_icsk); |
efb3cb428 inet_diag: Split ... |
1095 1096 |
static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, |
0df6d3284 inet_diag: Move t... |
1097 |
const struct inet_diag_req_v2 *r) |
efb3cb428 inet_diag: Split ... |
1098 |
{ |
3f935c75e inet_diag: suppor... |
1099 |
struct inet_diag_dump_data *cb_data = cb->data; |
efb3cb428 inet_diag: Split ... |
1100 |
const struct inet_diag_handler *handler; |
085c20cac bpf: inet_diag: D... |
1101 |
u32 prev_min_dump_alloc; |
3f935c75e inet_diag: suppor... |
1102 1103 1104 |
int protocol, err = 0; protocol = inet_diag_get_protocol(r, cb_data); |
efb3cb428 inet_diag: Split ... |
1105 |
|
085c20cac bpf: inet_diag: D... |
1106 1107 |
again: prev_min_dump_alloc = cb->min_dump_alloc; |
3f935c75e inet_diag: suppor... |
1108 |
handler = inet_diag_lock_handler(protocol); |
efb3cb428 inet_diag: Split ... |
1109 |
if (!IS_ERR(handler)) |
0df6d3284 inet_diag: Move t... |
1110 |
handler->dump(skb, cb, r); |
cacb6ba0f net: inet_diag --... |
1111 1112 |
else err = PTR_ERR(handler); |
d523a328f [INET]: Fix inet_... |
1113 |
inet_diag_unlock_handler(handler); |
efb3cb428 inet_diag: Split ... |
1114 |
|
085c20cac bpf: inet_diag: D... |
1115 1116 1117 1118 1119 1120 1121 1122 |
/* The skb is not large enough to fit one sk info and * inet_sk_diag_fill() has requested for a larger skb. */ if (!skb->len && cb->min_dump_alloc > prev_min_dump_alloc) { err = pskb_expand_head(skb, 0, cb->min_dump_alloc, GFP_KERNEL); if (!err) goto again; } |
cacb6ba0f net: inet_diag --... |
1123 |
return err ? : skb->len; |
1da177e4c Linux-2.6.12-rc2 |
1124 |
} |
25c4cd2b6 inet_diag: Switch... |
1125 1126 |
static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) { |
0df6d3284 inet_diag: Move t... |
1127 1128 1129 1130 1131 1132 1133 1134 1135 |
return __inet_diag_dump(skb, cb, nlmsg_data(cb->nlh)); } static int __inet_diag_dump_start(struct netlink_callback *cb, int hdrlen) { const struct nlmsghdr *nlh = cb->nlh; struct inet_diag_dump_data *cb_data; struct sk_buff *skb = cb->skb; struct nlattr *nla; |
3f935c75e inet_diag: suppor... |
1136 |
int err; |
0df6d3284 inet_diag: Move t... |
1137 1138 1139 1140 |
cb_data = kzalloc(sizeof(*cb_data), GFP_KERNEL); if (!cb_data) return -ENOMEM; |
d5e4d0a5e inet_diag: valida... |
1141 1142 1143 1144 1145 |
err = inet_diag_parse_attrs(nlh, hdrlen, cb_data->req_nlas); if (err) { kfree(cb_data); return err; } |
0df6d3284 inet_diag: Move t... |
1146 1147 1148 1149 1150 1151 1152 1153 |
nla = cb_data->inet_diag_nla_bc; if (nla) { err = inet_diag_bc_audit(nla, skb); if (err) { kfree(cb_data); return err; } } |
25c4cd2b6 inet_diag: Switch... |
1154 |
|
085c20cac bpf: inet_diag: D... |
1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 |
nla = cb_data->inet_diag_nla_bpf_stgs; if (nla) { struct bpf_sk_storage_diag *bpf_stg_diag; bpf_stg_diag = bpf_sk_storage_diag_alloc(nla); if (IS_ERR(bpf_stg_diag)) { kfree(cb_data); return PTR_ERR(bpf_stg_diag); } cb_data->bpf_stg_diag = bpf_stg_diag; } |
0df6d3284 inet_diag: Move t... |
1166 1167 1168 |
cb->data = cb_data; return 0; } |
25c4cd2b6 inet_diag: Switch... |
1169 |
|
0df6d3284 inet_diag: Move t... |
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 |
static int inet_diag_dump_start(struct netlink_callback *cb) { return __inet_diag_dump_start(cb, sizeof(struct inet_diag_req_v2)); } static int inet_diag_dump_start_compat(struct netlink_callback *cb) { return __inet_diag_dump_start(cb, sizeof(struct inet_diag_req)); } static int inet_diag_dump_done(struct netlink_callback *cb) { |
085c20cac bpf: inet_diag: D... |
1182 1183 1184 |
struct inet_diag_dump_data *cb_data = cb->data; bpf_sk_storage_diag_free(cb_data->bpf_stg_diag); |
0df6d3284 inet_diag: Move t... |
1185 1186 1187 |
kfree(cb->data); return 0; |
25c4cd2b6 inet_diag: Switch... |
1188 |
} |
e31c5e0e4 inet_diag: cleanups |
1189 |
static int inet_diag_type2proto(int type) |
a029fe26b inet_diag: Cleanu... |
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 |
{ switch (type) { case TCPDIAG_GETSOCK: return IPPROTO_TCP; case DCCPDIAG_GETSOCK: return IPPROTO_DCCP; default: return 0; } } |
e31c5e0e4 inet_diag: cleanups |
1200 1201 |
static int inet_diag_dump_compat(struct sk_buff *skb, struct netlink_callback *cb) |
25c4cd2b6 inet_diag: Switch... |
1202 |
{ |
d106352d9 inet_diag: Move a... |
1203 |
struct inet_diag_req *rc = nlmsg_data(cb->nlh); |
c8991362a inet_diag: Rename... |
1204 |
struct inet_diag_req_v2 req; |
25c4cd2b6 inet_diag: Switch... |
1205 |
|
d23deaa07 inet_diag: Introd... |
1206 |
req.sdiag_family = AF_UNSPEC; /* compatibility */ |
25c4cd2b6 inet_diag: Switch... |
1207 1208 1209 1210 |
req.sdiag_protocol = inet_diag_type2proto(cb->nlh->nlmsg_type); req.idiag_ext = rc->idiag_ext; req.idiag_states = rc->idiag_states; req.id = rc->id; |
0df6d3284 inet_diag: Move t... |
1211 |
return __inet_diag_dump(skb, cb, &req); |
25c4cd2b6 inet_diag: Switch... |
1212 |
} |
fe50ce284 inet_diag: Switch... |
1213 |
static int inet_diag_get_exact_compat(struct sk_buff *in_skb, |
e31c5e0e4 inet_diag: cleanups |
1214 |
const struct nlmsghdr *nlh) |
fe50ce284 inet_diag: Switch... |
1215 |
{ |
d106352d9 inet_diag: Move a... |
1216 |
struct inet_diag_req *rc = nlmsg_data(nlh); |
c8991362a inet_diag: Rename... |
1217 |
struct inet_diag_req_v2 req; |
fe50ce284 inet_diag: Switch... |
1218 1219 1220 1221 1222 1223 |
req.sdiag_family = rc->idiag_family; req.sdiag_protocol = inet_diag_type2proto(nlh->nlmsg_type); req.idiag_ext = rc->idiag_ext; req.idiag_states = rc->idiag_states; req.id = rc->id; |
3f935c75e inet_diag: suppor... |
1224 1225 |
return inet_diag_cmd_exact(SOCK_DIAG_BY_FAMILY, in_skb, nlh, sizeof(struct inet_diag_req), &req); |
fe50ce284 inet_diag: Switch... |
1226 |
} |
8d34172df sock_diag: Introd... |
1227 |
static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh) |
1da177e4c Linux-2.6.12-rc2 |
1228 |
{ |
3b09c84cb inet_diag: Rename... |
1229 |
int hdrlen = sizeof(struct inet_diag_req); |
51d7cccf0 net: make sock di... |
1230 |
struct net *net = sock_net(skb->sk); |
1da177e4c Linux-2.6.12-rc2 |
1231 |
|
ead592ba2 [IPv4] diag: Use ... |
1232 1233 1234 |
if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX || nlmsg_len(nlh) < hdrlen) return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
1235 |
|
b8f3ab429 Revert "netlink: ... |
1236 |
if (nlh->nlmsg_flags & NLM_F_DUMP) { |
0df6d3284 inet_diag: Move t... |
1237 1238 1239 1240 1241 1242 |
struct netlink_dump_control c = { .start = inet_diag_dump_start_compat, .done = inet_diag_dump_done, .dump = inet_diag_dump_compat, }; return netlink_dump_start(net->diag_nlsk, skb, nlh, &c); |
1da177e4c Linux-2.6.12-rc2 |
1243 |
} |
ead592ba2 [IPv4] diag: Use ... |
1244 |
|
fe50ce284 inet_diag: Switch... |
1245 |
return inet_diag_get_exact_compat(skb, nlh); |
1da177e4c Linux-2.6.12-rc2 |
1246 |
} |
6eb5d2e08 net: diag: Suppor... |
1247 |
static int inet_diag_handler_cmd(struct sk_buff *skb, struct nlmsghdr *h) |
d366477a5 sock_diag: Initia... |
1248 |
{ |
c8991362a inet_diag: Rename... |
1249 |
int hdrlen = sizeof(struct inet_diag_req_v2); |
51d7cccf0 net: make sock di... |
1250 |
struct net *net = sock_net(skb->sk); |
d366477a5 sock_diag: Initia... |
1251 1252 1253 |
if (nlmsg_len(h) < hdrlen) return -EINVAL; |
6eb5d2e08 net: diag: Suppor... |
1254 1255 |
if (h->nlmsg_type == SOCK_DIAG_BY_FAMILY && h->nlmsg_flags & NLM_F_DUMP) { |
0df6d3284 inet_diag: Move t... |
1256 1257 1258 1259 1260 1261 |
struct netlink_dump_control c = { .start = inet_diag_dump_start, .done = inet_diag_dump_done, .dump = inet_diag_dump, }; return netlink_dump_start(net->diag_nlsk, skb, h, &c); |
d366477a5 sock_diag: Initia... |
1262 |
} |
3f935c75e inet_diag: suppor... |
1263 1264 |
return inet_diag_cmd_exact(h->nlmsg_type, skb, h, hdrlen, nlmsg_data(h)); |
d366477a5 sock_diag: Initia... |
1265 |
} |
35ac838a9 sock_diag: implem... |
1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 |
static int inet_diag_handler_get_info(struct sk_buff *skb, struct sock *sk) { const struct inet_diag_handler *handler; struct nlmsghdr *nlh; struct nlattr *attr; struct inet_diag_msg *r; void *info = NULL; int err = 0; nlh = nlmsg_put(skb, 0, 0, SOCK_DIAG_BY_FAMILY, sizeof(*r), 0); if (!nlh) return -ENOMEM; r = nlmsg_data(nlh); memset(r, 0, sizeof(*r)); inet_diag_msg_common_fill(r, sk); |
e0df02e0c sock_diag: fetch ... |
1283 1284 |
if (sk->sk_type == SOCK_DGRAM || sk->sk_type == SOCK_STREAM) r->id.idiag_sport = inet_sk(sk)->inet_sport; |
35ac838a9 sock_diag: implem... |
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 |
r->idiag_state = sk->sk_state; if ((err = nla_put_u8(skb, INET_DIAG_PROTOCOL, sk->sk_protocol))) { nlmsg_cancel(skb, nlh); return err; } handler = inet_diag_lock_handler(sk->sk_protocol); if (IS_ERR(handler)) { inet_diag_unlock_handler(handler); nlmsg_cancel(skb, nlh); return PTR_ERR(handler); } attr = handler->idiag_info_size |
6ed46d124 sock_diag: align ... |
1300 1301 1302 |
? nla_reserve_64bit(skb, INET_DIAG_INFO, handler->idiag_info_size, INET_DIAG_PAD) |
35ac838a9 sock_diag: implem... |
1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 |
: NULL; if (attr) info = nla_data(attr); handler->idiag_get_info(sk, r, info); inet_diag_unlock_handler(handler); nlmsg_end(skb, nlh); return 0; } |
8dcf01fc0 net: sock_diag_ha... |
1313 |
static const struct sock_diag_handler inet_diag_handler = { |
d366477a5 sock_diag: Initia... |
1314 |
.family = AF_INET, |
6eb5d2e08 net: diag: Suppor... |
1315 |
.dump = inet_diag_handler_cmd, |
35ac838a9 sock_diag: implem... |
1316 |
.get_info = inet_diag_handler_get_info, |
6eb5d2e08 net: diag: Suppor... |
1317 |
.destroy = inet_diag_handler_cmd, |
d366477a5 sock_diag: Initia... |
1318 |
}; |
8dcf01fc0 net: sock_diag_ha... |
1319 |
static const struct sock_diag_handler inet6_diag_handler = { |
d366477a5 sock_diag: Initia... |
1320 |
.family = AF_INET6, |
6eb5d2e08 net: diag: Suppor... |
1321 |
.dump = inet_diag_handler_cmd, |
35ac838a9 sock_diag: implem... |
1322 |
.get_info = inet_diag_handler_get_info, |
6eb5d2e08 net: diag: Suppor... |
1323 |
.destroy = inet_diag_handler_cmd, |
d366477a5 sock_diag: Initia... |
1324 |
}; |
4f5736c4c [TCPDIAG]: Introd... |
1325 1326 1327 1328 |
int inet_diag_register(const struct inet_diag_handler *h) { const __u16 type = h->idiag_type; int err = -EINVAL; |
f13c95f0e inet_diag: Switch... |
1329 |
if (type >= IPPROTO_MAX) |
4f5736c4c [TCPDIAG]: Introd... |
1330 |
goto out; |
d523a328f [INET]: Fix inet_... |
1331 |
mutex_lock(&inet_diag_table_mutex); |
4f5736c4c [TCPDIAG]: Introd... |
1332 |
err = -EEXIST; |
e31c5e0e4 inet_diag: cleanups |
1333 |
if (!inet_diag_table[type]) { |
4f5736c4c [TCPDIAG]: Introd... |
1334 1335 1336 |
inet_diag_table[type] = h; err = 0; } |
d523a328f [INET]: Fix inet_... |
1337 |
mutex_unlock(&inet_diag_table_mutex); |
4f5736c4c [TCPDIAG]: Introd... |
1338 1339 1340 1341 1342 1343 1344 1345 |
out: return err; } EXPORT_SYMBOL_GPL(inet_diag_register); void inet_diag_unregister(const struct inet_diag_handler *h) { const __u16 type = h->idiag_type; |
f13c95f0e inet_diag: Switch... |
1346 |
if (type >= IPPROTO_MAX) |
4f5736c4c [TCPDIAG]: Introd... |
1347 |
return; |
d523a328f [INET]: Fix inet_... |
1348 |
mutex_lock(&inet_diag_table_mutex); |
4f5736c4c [TCPDIAG]: Introd... |
1349 |
inet_diag_table[type] = NULL; |
d523a328f [INET]: Fix inet_... |
1350 |
mutex_unlock(&inet_diag_table_mutex); |
4f5736c4c [TCPDIAG]: Introd... |
1351 1352 |
} EXPORT_SYMBOL_GPL(inet_diag_unregister); |
73c1f4a03 [TCPDIAG]: Just r... |
1353 |
static int __init inet_diag_init(void) |
1da177e4c Linux-2.6.12-rc2 |
1354 |
{ |
f13c95f0e inet_diag: Switch... |
1355 |
const int inet_diag_table_size = (IPPROTO_MAX * |
4f5736c4c [TCPDIAG]: Introd... |
1356 1357 |
sizeof(struct inet_diag_handler *)); int err = -ENOMEM; |
0da974f4f [NET]: Conversion... |
1358 |
inet_diag_table = kzalloc(inet_diag_table_size, GFP_KERNEL); |
4f5736c4c [TCPDIAG]: Introd... |
1359 1360 |
if (!inet_diag_table) goto out; |
d366477a5 sock_diag: Initia... |
1361 1362 1363 1364 1365 1366 1367 |
err = sock_diag_register(&inet_diag_handler); if (err) goto out_free_nl; err = sock_diag_register(&inet6_diag_handler); if (err) goto out_free_inet; |
8ef874bfc sock_diag: Move t... |
1368 |
sock_diag_register_inet_compat(inet_diag_rcv_msg_compat); |
4f5736c4c [TCPDIAG]: Introd... |
1369 1370 |
out: return err; |
d366477a5 sock_diag: Initia... |
1371 1372 1373 1374 |
out_free_inet: sock_diag_unregister(&inet_diag_handler); out_free_nl: |
4f5736c4c [TCPDIAG]: Introd... |
1375 1376 |
kfree(inet_diag_table); goto out; |
1da177e4c Linux-2.6.12-rc2 |
1377 |
} |
73c1f4a03 [TCPDIAG]: Just r... |
1378 |
static void __exit inet_diag_exit(void) |
1da177e4c Linux-2.6.12-rc2 |
1379 |
{ |
d366477a5 sock_diag: Initia... |
1380 1381 |
sock_diag_unregister(&inet6_diag_handler); sock_diag_unregister(&inet_diag_handler); |
8ef874bfc sock_diag: Move t... |
1382 |
sock_diag_unregister_inet_compat(inet_diag_rcv_msg_compat); |
4f5736c4c [TCPDIAG]: Introd... |
1383 |
kfree(inet_diag_table); |
1da177e4c Linux-2.6.12-rc2 |
1384 |
} |
73c1f4a03 [TCPDIAG]: Just r... |
1385 1386 |
module_init(inet_diag_init); module_exit(inet_diag_exit); |
1da177e4c Linux-2.6.12-rc2 |
1387 |
MODULE_LICENSE("GPL"); |
aec8dc62f sock_diag: Fix mo... |
1388 1389 |
MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2 /* AF_INET */); MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 10 /* AF_INET6 */); |