2 * udp_diag.c Module for monitoring UDP transport protocols sockets.
4 * Authors: Pavel Emelyanov, <xemul@parallels.com>
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.
13 #include <linux/module.h>
14 #include <linux/inet_diag.h>
15 #include <linux/udp.h>
17 #include <net/udplite.h>
18 #include <linux/sock_diag.h>
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
)
25 if (!inet_diag_bc_sk(bc
, sk
))
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
);
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
)
39 struct sock
*sk
= NULL
;
41 struct net
*net
= sock_net(in_skb
->sk
);
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
,
55 (struct in6_addr
*)req
->id
.idiag_dst
,
57 req
->id
.idiag_if
, 0, tbl
, NULL
);
59 if (sk
&& !refcount_inc_not_zero(&sk
->sk_refcnt
))
66 err
= sock_diag_check_cookie(sk
, req
->id
.idiag_cookie
);
71 rep
= nlmsg_new(sizeof(struct inet_diag_msg
) +
72 sizeof(struct inet_diag_meminfo
) + 64,
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
));
83 WARN_ON(err
== -EMSGSIZE
);
87 err
= netlink_unicast(net
->diag_nlsk
, rep
, NETLINK_CB(in_skb
).portid
,
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
)
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
;
106 s_slot
= cb
->args
[0];
107 num
= s_num
= cb
->args
[1];
109 for (slot
= s_slot
; slot
<= table
->mask
; s_num
= 0, slot
++) {
110 struct udp_hslot
*hslot
= &table
->hash
[slot
];
115 if (hlist_empty(&hslot
->head
))
118 spin_lock_bh(&hslot
->lock
);
119 sk_for_each(sk
, &hslot
->head
) {
120 struct inet_sock
*inet
= inet_sk(sk
);
122 if (!net_eq(sock_net(sk
), net
))
126 if (!(r
->idiag_states
& (1 << sk
->sk_state
)))
128 if (r
->sdiag_family
!= AF_UNSPEC
&&
129 sk
->sk_family
!= r
->sdiag_family
)
131 if (r
->id
.idiag_sport
!= inet
->inet_sport
&&
134 if (r
->id
.idiag_dport
!= inet
->inet_dport
&&
138 if (sk_diag_dump(sk
, skb
, cb
, r
, bc
, net_admin
) < 0) {
139 spin_unlock_bh(&hslot
->lock
);
145 spin_unlock_bh(&hslot
->lock
);
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
)
155 udp_dump(&udp_table
, skb
, cb
, r
, bc
);
158 static int udp_diag_dump_one(struct sk_buff
*in_skb
, const struct nlmsghdr
*nlh
,
159 const struct inet_diag_req_v2
*req
)
161 return udp_dump_one(&udp_table
, in_skb
, nlh
, req
);
164 static void udp_diag_get_info(struct sock
*sk
, struct inet_diag_msg
*r
,
167 r
->idiag_rqueue
= udp_rqueue_get(sk
);
168 r
->idiag_wqueue
= sk_wmem_alloc_get(sk
);
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
)
176 struct net
*net
= sock_net(in_skb
->sk
);
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
);
197 sk
= __udp6_lib_lookup(net
,
198 (struct in6_addr
*)req
->id
.idiag_dst
,
200 (struct in6_addr
*)req
->id
.idiag_src
,
202 req
->id
.idiag_if
, 0, tbl
, NULL
);
210 if (sk
&& !refcount_inc_not_zero(&sk
->sk_refcnt
))
218 if (sock_diag_check_cookie(sk
, req
->id
.idiag_cookie
)) {
223 err
= sock_diag_destroy(sk
, ECONNABORTED
);
230 static int udp_diag_destroy(struct sk_buff
*in_skb
,
231 const struct inet_diag_req_v2
*req
)
233 return __udp_diag_destroy(in_skb
, req
, &udp_table
);
236 static int udplite_diag_destroy(struct sk_buff
*in_skb
,
237 const struct inet_diag_req_v2
*req
)
239 return __udp_diag_destroy(in_skb
, req
, &udplite_table
);
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
,
255 static void udplite_diag_dump(struct sk_buff
*skb
, struct netlink_callback
*cb
,
256 const struct inet_diag_req_v2
*r
,
259 udp_dump(&udplite_table
, skb
, cb
, r
, bc
);
262 static int udplite_diag_dump_one(struct sk_buff
*in_skb
, const struct nlmsghdr
*nlh
,
263 const struct inet_diag_req_v2
*req
)
265 return udp_dump_one(&udplite_table
, in_skb
, nlh
, req
);
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
,
279 static int __init
udp_diag_init(void)
283 err
= inet_diag_register(&udp_diag_handler
);
286 err
= inet_diag_register(&udplite_diag_handler
);
292 inet_diag_unregister(&udp_diag_handler
);
296 static void __exit
udp_diag_exit(void)
298 inet_diag_unregister(&udplite_diag_handler
);
299 inet_diag_unregister(&udp_diag_handler
);
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 */);