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/inet_diag.h>
19 #include <linux/sock_diag.h>
21 static int sk_diag_dump(struct sock
*sk
, struct sk_buff
*skb
,
22 struct netlink_callback
*cb
, struct inet_diag_req_v2
*req
,
25 if (!inet_diag_bc_sk(bc
, sk
))
28 return inet_sk_diag_fill(sk
, NULL
, skb
, req
, NETLINK_CB(cb
->skb
).pid
,
29 cb
->nlh
->nlmsg_seq
, NLM_F_MULTI
, cb
->nlh
);
32 static int udp_dump_one(struct udp_table
*tbl
, struct sk_buff
*in_skb
,
33 const struct nlmsghdr
*nlh
, struct inet_diag_req_v2
*req
)
39 if (req
->sdiag_family
== AF_INET
)
40 sk
= __udp4_lib_lookup(&init_net
,
41 req
->id
.idiag_src
[0], req
->id
.idiag_sport
,
42 req
->id
.idiag_dst
[0], req
->id
.idiag_dport
,
43 req
->id
.idiag_if
, tbl
);
44 #if IS_ENABLED(CONFIG_IPV6)
45 else if (req
->sdiag_family
== AF_INET6
)
46 sk
= __udp6_lib_lookup(&init_net
,
47 (struct in6_addr
*)req
->id
.idiag_src
,
49 (struct in6_addr
*)req
->id
.idiag_dst
,
51 req
->id
.idiag_if
, tbl
);
60 err
= sock_diag_check_cookie(sk
, req
->id
.idiag_cookie
);
65 rep
= alloc_skb(NLMSG_SPACE((sizeof(struct inet_diag_msg
) +
66 sizeof(struct inet_diag_meminfo
) +
71 err
= inet_sk_diag_fill(sk
, NULL
, rep
, req
,
72 NETLINK_CB(in_skb
).pid
,
73 nlh
->nlmsg_seq
, 0, nlh
);
75 WARN_ON(err
== -EMSGSIZE
);
79 err
= netlink_unicast(sock_diag_nlsk
, rep
, NETLINK_CB(in_skb
).pid
,
90 static void udp_dump(struct udp_table
*table
, struct sk_buff
*skb
, struct netlink_callback
*cb
,
91 struct inet_diag_req_v2
*r
, struct nlattr
*bc
)
93 int num
, s_num
, slot
, s_slot
;
96 num
= s_num
= cb
->args
[1];
98 for (slot
= s_slot
; slot
<= table
->mask
; num
= s_num
= 0, slot
++) {
100 struct hlist_nulls_node
*node
;
101 struct udp_hslot
*hslot
= &table
->hash
[slot
];
103 if (hlist_nulls_empty(&hslot
->head
))
106 spin_lock_bh(&hslot
->lock
);
107 sk_nulls_for_each(sk
, node
, &hslot
->head
) {
108 struct inet_sock
*inet
= inet_sk(sk
);
112 if (!(r
->idiag_states
& (1 << sk
->sk_state
)))
114 if (r
->sdiag_family
!= AF_UNSPEC
&&
115 sk
->sk_family
!= r
->sdiag_family
)
117 if (r
->id
.idiag_sport
!= inet
->inet_sport
&&
120 if (r
->id
.idiag_dport
!= inet
->inet_dport
&&
124 if (sk_diag_dump(sk
, skb
, cb
, r
, bc
) < 0) {
125 spin_unlock_bh(&hslot
->lock
);
131 spin_unlock_bh(&hslot
->lock
);
138 static void udp_diag_dump(struct sk_buff
*skb
, struct netlink_callback
*cb
,
139 struct inet_diag_req_v2
*r
, struct nlattr
*bc
)
141 udp_dump(&udp_table
, skb
, cb
, r
, bc
);
144 static int udp_diag_dump_one(struct sk_buff
*in_skb
, const struct nlmsghdr
*nlh
,
145 struct inet_diag_req_v2
*req
)
147 return udp_dump_one(&udp_table
, in_skb
, nlh
, req
);
150 static const struct inet_diag_handler udp_diag_handler
= {
151 .dump
= udp_diag_dump
,
152 .dump_one
= udp_diag_dump_one
,
153 .idiag_type
= IPPROTO_UDP
,
156 static void udplite_diag_dump(struct sk_buff
*skb
, struct netlink_callback
*cb
,
157 struct inet_diag_req_v2
*r
, struct nlattr
*bc
)
159 udp_dump(&udplite_table
, skb
, cb
, r
, bc
);
162 static int udplite_diag_dump_one(struct sk_buff
*in_skb
, const struct nlmsghdr
*nlh
,
163 struct inet_diag_req_v2
*req
)
165 return udp_dump_one(&udplite_table
, in_skb
, nlh
, req
);
168 static const struct inet_diag_handler udplite_diag_handler
= {
169 .dump
= udplite_diag_dump
,
170 .dump_one
= udplite_diag_dump_one
,
171 .idiag_type
= IPPROTO_UDPLITE
,
174 static int __init
udp_diag_init(void)
178 err
= inet_diag_register(&udp_diag_handler
);
181 err
= inet_diag_register(&udplite_diag_handler
);
187 inet_diag_unregister(&udp_diag_handler
);
191 static void __exit
udp_diag_exit(void)
193 inet_diag_unregister(&udplite_diag_handler
);
194 inet_diag_unregister(&udp_diag_handler
);
197 module_init(udp_diag_init
);
198 module_exit(udp_diag_exit
);
199 MODULE_LICENSE("GPL");
200 MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK
, NETLINK_SOCK_DIAG
, 2-17 /* AF_INET - IPPROTO_UDP */);
201 MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK
, NETLINK_SOCK_DIAG
, 2-136 /* AF_INET - IPPROTO_UDPLITE */);