Blame view
net/ipv4/udp_diag.c
5.37 KB
52b7c59bc
|
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
|
18 |
#include <linux/sock_diag.h> |
b6d640c22
|
19 |
static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, |
c8991362a
|
20 |
struct netlink_callback *cb, struct inet_diag_req_v2 *req, |
b6d640c22
|
21 22 23 24 |
struct nlattr *bc) { if (!inet_diag_bc_sk(bc, sk)) return 0; |
d06ca9564
|
25 |
return inet_sk_diag_fill(sk, NULL, skb, req, |
e32123e59
|
26 |
sk_user_ns(NETLINK_CB(cb->skb).sk), |
15e473046
|
27 |
NETLINK_CB(cb->skb).portid, |
b6d640c22
|
28 29 |
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh); } |
52b7c59bc
|
30 |
static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb, |
c8991362a
|
31 |
const struct nlmsghdr *nlh, struct inet_diag_req_v2 *req) |
52b7c59bc
|
32 |
{ |
a925aa00a
|
33 34 35 |
int err = -EINVAL; struct sock *sk; struct sk_buff *rep; |
51d7cccf0
|
36 |
struct net *net = sock_net(in_skb->sk); |
a925aa00a
|
37 38 |
if (req->sdiag_family == AF_INET) |
51d7cccf0
|
39 |
sk = __udp4_lib_lookup(net, |
a925aa00a
|
40 41 42 |
req->id.idiag_src[0], req->id.idiag_sport, req->id.idiag_dst[0], req->id.idiag_dport, req->id.idiag_if, tbl); |
86e62ad6b
|
43 |
#if IS_ENABLED(CONFIG_IPV6) |
a925aa00a
|
44 |
else if (req->sdiag_family == AF_INET6) |
51d7cccf0
|
45 |
sk = __udp6_lib_lookup(net, |
a925aa00a
|
46 47 48 49 50 |
(struct in6_addr *)req->id.idiag_src, req->id.idiag_sport, (struct in6_addr *)req->id.idiag_dst, req->id.idiag_dport, req->id.idiag_if, tbl); |
86e62ad6b
|
51 |
#endif |
a925aa00a
|
52 53 54 55 56 57 |
else goto out_nosk; err = -ENOENT; if (sk == NULL) goto out_nosk; |
f65c1b534
|
58 |
err = sock_diag_check_cookie(sk, req->id.idiag_cookie); |
a925aa00a
|
59 60 61 62 |
if (err) goto out; err = -ENOMEM; |
573ce260b
|
63 64 65 |
rep = nlmsg_new(sizeof(struct inet_diag_msg) + sizeof(struct inet_diag_meminfo) + 64, GFP_KERNEL); |
a925aa00a
|
66 67 68 69 |
if (!rep) goto out; err = inet_sk_diag_fill(sk, NULL, rep, req, |
e32123e59
|
70 |
sk_user_ns(NETLINK_CB(in_skb).sk), |
15e473046
|
71 |
NETLINK_CB(in_skb).portid, |
a925aa00a
|
72 73 74 75 76 77 |
nlh->nlmsg_seq, 0, nlh); if (err < 0) { WARN_ON(err == -EMSGSIZE); kfree_skb(rep); goto out; } |
15e473046
|
78 |
err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid, |
a925aa00a
|
79 80 81 82 83 84 85 86 |
MSG_DONTWAIT); if (err > 0) err = 0; out: if (sk) sock_put(sk); out_nosk: return err; |
52b7c59bc
|
87 88 89 |
} static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlink_callback *cb, |
c8991362a
|
90 |
struct inet_diag_req_v2 *r, struct nlattr *bc) |
52b7c59bc
|
91 |
{ |
b6d640c22
|
92 |
int num, s_num, slot, s_slot; |
51d7cccf0
|
93 |
struct net *net = sock_net(skb->sk); |
b6d640c22
|
94 95 96 |
s_slot = cb->args[0]; num = s_num = cb->args[1]; |
86f3cddbc
|
97 |
for (slot = s_slot; slot <= table->mask; s_num = 0, slot++) { |
b6d640c22
|
98 99 100 |
struct sock *sk; struct hlist_nulls_node *node; struct udp_hslot *hslot = &table->hash[slot]; |
86f3cddbc
|
101 |
num = 0; |
b6d640c22
|
102 103 104 105 106 107 |
if (hlist_nulls_empty(&hslot->head)) continue; spin_lock_bh(&hslot->lock); sk_nulls_for_each(sk, node, &hslot->head) { struct inet_sock *inet = inet_sk(sk); |
51d7cccf0
|
108 109 |
if (!net_eq(sock_net(sk), net)) continue; |
b6d640c22
|
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
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; if (sk_diag_dump(sk, skb, cb, r, bc) < 0) { spin_unlock_bh(&hslot->lock); goto done; } next: num++; } spin_unlock_bh(&hslot->lock); } done: cb->args[0] = slot; cb->args[1] = num; |
52b7c59bc
|
136 137 138 |
} static void udp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, |
c8991362a
|
139 |
struct inet_diag_req_v2 *r, struct nlattr *bc) |
52b7c59bc
|
140 141 142 143 144 |
{ udp_dump(&udp_table, skb, cb, r, bc); } static int udp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh, |
c8991362a
|
145 |
struct inet_diag_req_v2 *req) |
52b7c59bc
|
146 147 148 |
{ return udp_dump_one(&udp_table, in_skb, nlh, req); } |
62ad6fcd7
|
149 150 151 152 153 154 |
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); } |
52b7c59bc
|
155 156 157 |
static const struct inet_diag_handler udp_diag_handler = { .dump = udp_diag_dump, .dump_one = udp_diag_dump_one, |
62ad6fcd7
|
158 |
.idiag_get_info = udp_diag_get_info, |
52b7c59bc
|
159 160 161 162 |
.idiag_type = IPPROTO_UDP, }; static void udplite_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, |
c8991362a
|
163 |
struct inet_diag_req_v2 *r, struct nlattr *bc) |
52b7c59bc
|
164 165 166 167 168 |
{ udp_dump(&udplite_table, skb, cb, r, bc); } static int udplite_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh, |
c8991362a
|
169 |
struct inet_diag_req_v2 *req) |
52b7c59bc
|
170 171 172 173 174 175 176 |
{ 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
|
177 |
.idiag_get_info = udp_diag_get_info, |
52b7c59bc
|
178 179 180 181 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 |
.idiag_type = IPPROTO_UDPLITE, }; 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
|
207 208 |
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 */); |