Blame view

net/ipv4/udp_diag.c 5.37 KB
52b7c59bc   Pavel Emelyanov   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   Pavel Emelyanov   udp_diag: Basic s...
18
  #include <linux/sock_diag.h>
b6d640c22   Pavel Emelyanov   udp_diag: Impleme...
19
  static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
c8991362a   Pavel Emelyanov   inet_diag: Rename...
20
  		struct netlink_callback *cb, struct inet_diag_req_v2 *req,
b6d640c22   Pavel Emelyanov   udp_diag: Impleme...
21
22
23
24
  		struct nlattr *bc)
  {
  	if (!inet_diag_bc_sk(bc, sk))
  		return 0;
d06ca9564   Eric W. Biederman   userns: Teach ine...
25
  	return inet_sk_diag_fill(sk, NULL, skb, req,
e32123e59   Patrick McHardy   netlink: rename s...
26
  			sk_user_ns(NETLINK_CB(cb->skb).sk),
15e473046   Eric W. Biederman   netlink: Rename p...
27
  			NETLINK_CB(cb->skb).portid,
b6d640c22   Pavel Emelyanov   udp_diag: Impleme...
28
29
  			cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
  }
52b7c59bc   Pavel Emelyanov   udp_diag: Basic s...
30
  static int udp_dump_one(struct udp_table *tbl, struct sk_buff *in_skb,
c8991362a   Pavel Emelyanov   inet_diag: Rename...
31
  		const struct nlmsghdr *nlh, struct inet_diag_req_v2 *req)
52b7c59bc   Pavel Emelyanov   udp_diag: Basic s...
32
  {
a925aa00a   Pavel Emelyanov   udp_diag: Impleme...
33
34
35
  	int err = -EINVAL;
  	struct sock *sk;
  	struct sk_buff *rep;
51d7cccf0   Andrey Vagin   net: make sock di...
36
  	struct net *net = sock_net(in_skb->sk);
a925aa00a   Pavel Emelyanov   udp_diag: Impleme...
37
38
  
  	if (req->sdiag_family == AF_INET)
51d7cccf0   Andrey Vagin   net: make sock di...
39
  		sk = __udp4_lib_lookup(net,
a925aa00a   Pavel Emelyanov   udp_diag: Impleme...
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   Pavel Emelyanov   udp_diag: Fix the...
43
  #if IS_ENABLED(CONFIG_IPV6)
a925aa00a   Pavel Emelyanov   udp_diag: Impleme...
44
  	else if (req->sdiag_family == AF_INET6)
51d7cccf0   Andrey Vagin   net: make sock di...
45
  		sk = __udp6_lib_lookup(net,
a925aa00a   Pavel Emelyanov   udp_diag: Impleme...
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   Pavel Emelyanov   udp_diag: Fix the...
51
  #endif
a925aa00a   Pavel Emelyanov   udp_diag: Impleme...
52
53
54
55
56
57
  	else
  		goto out_nosk;
  
  	err = -ENOENT;
  	if (sk == NULL)
  		goto out_nosk;
f65c1b534   Pavel Emelyanov   sock_diag: Genera...
58
  	err = sock_diag_check_cookie(sk, req->id.idiag_cookie);
a925aa00a   Pavel Emelyanov   udp_diag: Impleme...
59
60
61
62
  	if (err)
  		goto out;
  
  	err = -ENOMEM;
573ce260b   Hong zhi guo   net-next: replace...
63
64
65
  	rep = nlmsg_new(sizeof(struct inet_diag_msg) +
  			sizeof(struct inet_diag_meminfo) + 64,
  			GFP_KERNEL);
a925aa00a   Pavel Emelyanov   udp_diag: Impleme...
66
67
68
69
  	if (!rep)
  		goto out;
  
  	err = inet_sk_diag_fill(sk, NULL, rep, req,
e32123e59   Patrick McHardy   netlink: rename s...
70
  			   sk_user_ns(NETLINK_CB(in_skb).sk),
15e473046   Eric W. Biederman   netlink: Rename p...
71
  			   NETLINK_CB(in_skb).portid,
a925aa00a   Pavel Emelyanov   udp_diag: Impleme...
72
73
74
75
76
77
  			   nlh->nlmsg_seq, 0, nlh);
  	if (err < 0) {
  		WARN_ON(err == -EMSGSIZE);
  		kfree_skb(rep);
  		goto out;
  	}
15e473046   Eric W. Biederman   netlink: Rename p...
78
  	err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid,
a925aa00a   Pavel Emelyanov   udp_diag: Impleme...
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   Pavel Emelyanov   udp_diag: Basic s...
87
88
89
  }
  
  static void udp_dump(struct udp_table *table, struct sk_buff *skb, struct netlink_callback *cb,
c8991362a   Pavel Emelyanov   inet_diag: Rename...
90
  		struct inet_diag_req_v2 *r, struct nlattr *bc)
52b7c59bc   Pavel Emelyanov   udp_diag: Basic s...
91
  {
b6d640c22   Pavel Emelyanov   udp_diag: Impleme...
92
  	int num, s_num, slot, s_slot;
51d7cccf0   Andrey Vagin   net: make sock di...
93
  	struct net *net = sock_net(skb->sk);
b6d640c22   Pavel Emelyanov   udp_diag: Impleme...
94
95
96
  
  	s_slot = cb->args[0];
  	num = s_num = cb->args[1];
86f3cddbc   Herbert Xu   udp_diag: Fix soc...
97
  	for (slot = s_slot; slot <= table->mask; s_num = 0, slot++) {
b6d640c22   Pavel Emelyanov   udp_diag: Impleme...
98
99
100
  		struct sock *sk;
  		struct hlist_nulls_node *node;
  		struct udp_hslot *hslot = &table->hash[slot];
86f3cddbc   Herbert Xu   udp_diag: Fix soc...
101
  		num = 0;
b6d640c22   Pavel Emelyanov   udp_diag: Impleme...
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   Andrey Vagin   net: make sock di...
108
109
  			if (!net_eq(sock_net(sk), net))
  				continue;
b6d640c22   Pavel Emelyanov   udp_diag: Impleme...
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   Pavel Emelyanov   udp_diag: Basic s...
136
137
138
  }
  
  static void udp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
c8991362a   Pavel Emelyanov   inet_diag: Rename...
139
  		struct inet_diag_req_v2 *r, struct nlattr *bc)
52b7c59bc   Pavel Emelyanov   udp_diag: Basic s...
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   Pavel Emelyanov   inet_diag: Rename...
145
  		struct inet_diag_req_v2 *req)
52b7c59bc   Pavel Emelyanov   udp_diag: Basic s...
146
147
148
  {
  	return udp_dump_one(&udp_table, in_skb, nlh, req);
  }
62ad6fcd7   Shan Wei   udp_diag: impleme...
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   Pavel Emelyanov   udp_diag: Basic s...
155
156
157
  static const struct inet_diag_handler udp_diag_handler = {
  	.dump		 = udp_diag_dump,
  	.dump_one	 = udp_diag_dump_one,
62ad6fcd7   Shan Wei   udp_diag: impleme...
158
  	.idiag_get_info  = udp_diag_get_info,
52b7c59bc   Pavel Emelyanov   udp_diag: Basic s...
159
160
161
162
  	.idiag_type	 = IPPROTO_UDP,
  };
  
  static void udplite_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
c8991362a   Pavel Emelyanov   inet_diag: Rename...
163
  		struct inet_diag_req_v2 *r, struct nlattr *bc)
52b7c59bc   Pavel Emelyanov   udp_diag: Basic s...
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   Pavel Emelyanov   inet_diag: Rename...
169
  		struct inet_diag_req_v2 *req)
52b7c59bc   Pavel Emelyanov   udp_diag: Basic s...
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   Shan Wei   udp_diag: impleme...
177
  	.idiag_get_info  = udp_diag_get_info,
52b7c59bc   Pavel Emelyanov   udp_diag: Basic s...
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   Pavel Emelyanov   sock_diag: Fix mo...
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 */);