inet_diag.c 26.8 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2
 * inet_diag.c	Module for monitoring INET transport protocols sockets.
L
Linus Torvalds 已提交
3 4 5 6 7 8 9 10 11
 *
 * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
 *
 *	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.
 */

12
#include <linux/kernel.h>
L
Linus Torvalds 已提交
13 14 15 16
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/random.h>
17
#include <linux/slab.h>
L
Linus Torvalds 已提交
18 19 20 21 22 23 24 25
#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>
26 27 28 29
#include <net/inet_connection_sock.h>
#include <net/inet_hashtables.h>
#include <net/inet_timewait_sock.h>
#include <net/inet6_hashtables.h>
30
#include <net/netlink.h>
L
Linus Torvalds 已提交
31 32 33 34

#include <linux/inet.h>
#include <linux/stddef.h>

35
#include <linux/inet_diag.h>
P
Pavel Emelyanov 已提交
36
#include <linux/sock_diag.h>
L
Linus Torvalds 已提交
37

38 39
static const struct inet_diag_handler **inet_diag_table;

40
struct inet_diag_entry {
A
Al Viro 已提交
41 42
	__be32 *saddr;
	__be32 *daddr;
L
Linus Torvalds 已提交
43 44 45 46 47 48
	u16 sport;
	u16 dport;
	u16 family;
	u16 userlocks;
};

49
static struct sock *sdiagnl;
L
Linus Torvalds 已提交
50

51
#define INET_DIAG_PUT(skb, attrtype, attrlen) \
52
	RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
L
Linus Torvalds 已提交
53

54 55 56 57 58 59 60 61 62 63 64 65
static inline int inet_diag_type2proto(int type)
{
	switch (type) {
	case TCPDIAG_GETSOCK:
		return IPPROTO_TCP;
	case DCCPDIAG_GETSOCK:
		return IPPROTO_DCCP;
	default:
		return 0;
	}
}

66 67
static DEFINE_MUTEX(inet_diag_table_mutex);

68
static const struct inet_diag_handler *inet_diag_lock_handler(int proto)
69
{
70
	if (!inet_diag_table[proto])
71
		request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
72
			       NETLINK_SOCK_DIAG, proto);
73 74

	mutex_lock(&inet_diag_table_mutex);
75
	if (!inet_diag_table[proto])
76 77
		return ERR_PTR(-ENOENT);

78
	return inet_diag_table[proto];
79 80 81 82 83 84 85 86
}

static inline void inet_diag_unlock_handler(
	const struct inet_diag_handler *handler)
{
	mutex_unlock(&inet_diag_table_mutex);
}

87 88 89 90
static int inet_csk_diag_fill(struct sock *sk,
			      struct sk_buff *skb,
			      int ext, u32 pid, u32 seq, u16 nlmsg_flags,
			      const struct nlmsghdr *unlh)
L
Linus Torvalds 已提交
91
{
92 93
	const struct inet_sock *inet = inet_sk(sk);
	const struct inet_connection_sock *icsk = inet_csk(sk);
94
	struct inet_diag_msg *r;
L
Linus Torvalds 已提交
95
	struct nlmsghdr  *nlh;
96
	void *info = NULL;
97
	struct inet_diag_meminfo  *minfo = NULL;
98
	unsigned char	 *b = skb_tail_pointer(skb);
99 100
	const struct inet_diag_handler *handler;

101
	handler = inet_diag_table[inet_diag_type2proto(unlh->nlmsg_type)];
102
	BUG_ON(handler == NULL);
L
Linus Torvalds 已提交
103

104
	nlh = NLMSG_PUT(skb, pid, seq, unlh->nlmsg_type, sizeof(*r));
L
Linus Torvalds 已提交
105
	nlh->nlmsg_flags = nlmsg_flags;
106

L
Linus Torvalds 已提交
107
	r = NLMSG_DATA(nlh);
108 109 110 111 112 113 114 115 116 117 118 119 120 121
	BUG_ON(sk->sk_state == TCP_TIME_WAIT);

	if (ext & (1 << (INET_DIAG_MEMINFO - 1)))
		minfo = INET_DIAG_PUT(skb, INET_DIAG_MEMINFO, sizeof(*minfo));

	if (ext & (1 << (INET_DIAG_INFO - 1)))
		info = INET_DIAG_PUT(skb, INET_DIAG_INFO,
				     handler->idiag_info_size);

	if ((ext & (1 << (INET_DIAG_CONG - 1))) && icsk->icsk_ca_ops) {
		const size_t len = strlen(icsk->icsk_ca_ops->name);

		strcpy(INET_DIAG_PUT(skb, INET_DIAG_CONG, len + 1),
		       icsk->icsk_ca_ops->name);
L
Linus Torvalds 已提交
122
	}
123

124 125 126 127
	r->idiag_family = sk->sk_family;
	r->idiag_state = sk->sk_state;
	r->idiag_timer = 0;
	r->idiag_retrans = 0;
L
Linus Torvalds 已提交
128

129 130 131
	r->id.idiag_if = sk->sk_bound_dev_if;
	r->id.idiag_cookie[0] = (u32)(unsigned long)sk;
	r->id.idiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1);
L
Linus Torvalds 已提交
132

E
Eric Dumazet 已提交
133 134 135 136
	r->id.idiag_sport = inet->inet_sport;
	r->id.idiag_dport = inet->inet_dport;
	r->id.idiag_src[0] = inet->inet_rcv_saddr;
	r->id.idiag_dst[0] = inet->inet_daddr;
L
Linus Torvalds 已提交
137

138 139 140 141 142 143
	/* 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)))
		RTA_PUT_U8(skb, INET_DIAG_TOS, inet->tos);

144
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
145
	if (r->idiag_family == AF_INET6) {
146
		const struct ipv6_pinfo *np = inet6_sk(sk);
L
Linus Torvalds 已提交
147

A
Alexey Dobriyan 已提交
148 149
		*(struct in6_addr *)r->id.idiag_src = np->rcv_saddr;
		*(struct in6_addr *)r->id.idiag_dst = np->daddr;
150 151
		if (ext & (1 << (INET_DIAG_TCLASS - 1)))
			RTA_PUT_U8(skb, INET_DIAG_TCLASS, np->tclass);
L
Linus Torvalds 已提交
152 153 154
	}
#endif

155
#define EXPIRES_IN_MS(tmo)  DIV_ROUND_UP((tmo - jiffies) * 1000, HZ)
L
Linus Torvalds 已提交
156

157
	if (icsk->icsk_pending == ICSK_TIME_RETRANS) {
158 159 160
		r->idiag_timer = 1;
		r->idiag_retrans = icsk->icsk_retransmits;
		r->idiag_expires = EXPIRES_IN_MS(icsk->icsk_timeout);
161
	} else if (icsk->icsk_pending == ICSK_TIME_PROBE0) {
162 163 164
		r->idiag_timer = 4;
		r->idiag_retrans = icsk->icsk_probes_out;
		r->idiag_expires = EXPIRES_IN_MS(icsk->icsk_timeout);
L
Linus Torvalds 已提交
165
	} else if (timer_pending(&sk->sk_timer)) {
166 167 168
		r->idiag_timer = 2;
		r->idiag_retrans = icsk->icsk_probes_out;
		r->idiag_expires = EXPIRES_IN_MS(sk->sk_timer.expires);
L
Linus Torvalds 已提交
169
	} else {
170 171
		r->idiag_timer = 0;
		r->idiag_expires = 0;
L
Linus Torvalds 已提交
172 173
	}
#undef EXPIRES_IN_MS
174

175 176
	r->idiag_uid = sock_i_uid(sk);
	r->idiag_inode = sock_i_ino(sk);
L
Linus Torvalds 已提交
177 178

	if (minfo) {
179
		minfo->idiag_rmem = sk_rmem_alloc_get(sk);
180 181
		minfo->idiag_wmem = sk->sk_wmem_queued;
		minfo->idiag_fmem = sk->sk_forward_alloc;
182
		minfo->idiag_tmem = sk_wmem_alloc_get(sk);
L
Linus Torvalds 已提交
183 184
	}

185
	handler->idiag_get_info(sk, r, info);
L
Linus Torvalds 已提交
186

187 188 189
	if (sk->sk_state < TCP_TIME_WAIT &&
	    icsk->icsk_ca_ops && icsk->icsk_ca_ops->get_info)
		icsk->icsk_ca_ops->get_info(sk, ext, skb);
L
Linus Torvalds 已提交
190

191
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
L
Linus Torvalds 已提交
192 193
	return skb->len;

194
rtattr_failure:
L
Linus Torvalds 已提交
195
nlmsg_failure:
196
	nlmsg_trim(skb, b);
197
	return -EMSGSIZE;
L
Linus Torvalds 已提交
198 199
}

200 201 202 203 204 205 206
static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
			       struct sk_buff *skb, int ext, u32 pid,
			       u32 seq, u16 nlmsg_flags,
			       const struct nlmsghdr *unlh)
{
	long tmo;
	struct inet_diag_msg *r;
207
	const unsigned char *previous_tail = skb_tail_pointer(skb);
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
	struct nlmsghdr *nlh = NLMSG_PUT(skb, pid, seq,
					 unlh->nlmsg_type, sizeof(*r));

	r = NLMSG_DATA(nlh);
	BUG_ON(tw->tw_state != TCP_TIME_WAIT);

	nlh->nlmsg_flags = nlmsg_flags;

	tmo = tw->tw_ttd - jiffies;
	if (tmo < 0)
		tmo = 0;

	r->idiag_family	      = tw->tw_family;
	r->idiag_retrans      = 0;
	r->id.idiag_if	      = tw->tw_bound_dev_if;
	r->id.idiag_cookie[0] = (u32)(unsigned long)tw;
	r->id.idiag_cookie[1] = (u32)(((unsigned long)tw >> 31) >> 1);
	r->id.idiag_sport     = tw->tw_sport;
	r->id.idiag_dport     = tw->tw_dport;
	r->id.idiag_src[0]    = tw->tw_rcv_saddr;
	r->id.idiag_dst[0]    = tw->tw_daddr;
	r->idiag_state	      = tw->tw_substate;
	r->idiag_timer	      = 3;
231
	r->idiag_expires      = DIV_ROUND_UP(tmo * 1000, HZ);
232 233 234 235 236 237 238 239 240
	r->idiag_rqueue	      = 0;
	r->idiag_wqueue	      = 0;
	r->idiag_uid	      = 0;
	r->idiag_inode	      = 0;
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
	if (tw->tw_family == AF_INET6) {
		const struct inet6_timewait_sock *tw6 =
						inet6_twsk((struct sock *)tw);

A
Alexey Dobriyan 已提交
241 242
		*(struct in6_addr *)r->id.idiag_src = tw6->tw_v6_rcv_saddr;
		*(struct in6_addr *)r->id.idiag_dst = tw6->tw_v6_daddr;
243 244
	}
#endif
245
	nlh->nlmsg_len = skb_tail_pointer(skb) - previous_tail;
246 247
	return skb->len;
nlmsg_failure:
248
	nlmsg_trim(skb, previous_tail);
249
	return -EMSGSIZE;
250 251
}

252 253 254 255 256 257 258 259 260 261 262
static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
			int ext, u32 pid, u32 seq, u16 nlmsg_flags,
			const struct nlmsghdr *unlh)
{
	if (sk->sk_state == TCP_TIME_WAIT)
		return inet_twsk_diag_fill((struct inet_timewait_sock *)sk,
					   skb, ext, pid, seq, nlmsg_flags,
					   unlh);
	return inet_csk_diag_fill(sk, skb, ext, pid, seq, nlmsg_flags, unlh);
}

263
static int inet_diag_get_exact(struct sk_buff *in_skb,
264 265
			       const struct nlmsghdr *nlh,
			       struct inet_diag_req *req)
L
Linus Torvalds 已提交
266 267 268 269
{
	int err;
	struct sock *sk;
	struct sk_buff *rep;
270 271 272
	struct inet_hashinfo *hashinfo;
	const struct inet_diag_handler *handler;

273
	handler = inet_diag_lock_handler(req->sdiag_protocol);
274 275 276 277
	if (IS_ERR(handler)) {
		err = PTR_ERR(handler);
		goto unlock;
	}
278

279
	hashinfo = handler->idiag_hashinfo;
280
	err = -EINVAL;
281

282
	if (req->sdiag_family == AF_INET) {
283
		sk = inet_lookup(&init_net, hashinfo, req->id.idiag_dst[0],
284 285
				 req->id.idiag_dport, req->id.idiag_src[0],
				 req->id.idiag_sport, req->id.idiag_if);
L
Linus Torvalds 已提交
286
	}
287
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
288
	else if (req->sdiag_family == AF_INET6) {
289
		sk = inet6_lookup(&init_net, hashinfo,
290 291 292 293 294
				  (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);
L
Linus Torvalds 已提交
295 296 297
	}
#endif
	else {
298
		goto unlock;
L
Linus Torvalds 已提交
299 300
	}

301
	err = -ENOENT;
L
Linus Torvalds 已提交
302
	if (sk == NULL)
303
		goto unlock;
L
Linus Torvalds 已提交
304 305

	err = -ESTALE;
306 307 308 309
	if ((req->id.idiag_cookie[0] != INET_DIAG_NOCOOKIE ||
	     req->id.idiag_cookie[1] != INET_DIAG_NOCOOKIE) &&
	    ((u32)(unsigned long)sk != req->id.idiag_cookie[0] ||
	     (u32)((((unsigned long)sk) >> 31) >> 1) != req->id.idiag_cookie[1]))
L
Linus Torvalds 已提交
310 311 312
		goto out;

	err = -ENOMEM;
313 314
	rep = alloc_skb(NLMSG_SPACE((sizeof(struct inet_diag_msg) +
				     sizeof(struct inet_diag_meminfo) +
315 316
				     handler->idiag_info_size + 64)),
			GFP_KERNEL);
L
Linus Torvalds 已提交
317 318 319
	if (!rep)
		goto out;

320 321 322 323 324 325 326 327
	err = sk_diag_fill(sk, rep, req->idiag_ext,
			   NETLINK_CB(in_skb).pid,
			   nlh->nlmsg_seq, 0, nlh);
	if (err < 0) {
		WARN_ON(err == -EMSGSIZE);
		kfree_skb(rep);
		goto out;
	}
328
	err = netlink_unicast(sdiagnl, rep, NETLINK_CB(in_skb).pid,
329
			      MSG_DONTWAIT);
L
Linus Torvalds 已提交
330 331 332 333 334 335
	if (err > 0)
		err = 0;

out:
	if (sk) {
		if (sk->sk_state == TCP_TIME_WAIT)
336
			inet_twsk_put((struct inet_timewait_sock *)sk);
L
Linus Torvalds 已提交
337 338 339
		else
			sock_put(sk);
	}
340 341
unlock:
	inet_diag_unlock_handler(handler);
L
Linus Torvalds 已提交
342 343 344
	return err;
}

A
Al Viro 已提交
345
static int bitstring_match(const __be32 *a1, const __be32 *a2, int bits)
L
Linus Torvalds 已提交
346 347 348 349 350 351 352 353 354 355
{
	int words = bits >> 5;

	bits &= 0x1f;

	if (words) {
		if (memcmp(a1, a2, words << 2))
			return 0;
	}
	if (bits) {
A
Al Viro 已提交
356 357
		__be32 w1, w2;
		__be32 mask;
L
Linus Torvalds 已提交
358 359 360 361 362 363 364 365 366 367 368 369 370 371

		w1 = a1[words];
		w2 = a2[words];

		mask = htonl((0xffffffff) << (32 - bits));

		if ((w1 ^ w2) & mask)
			return 0;
	}

	return 1;
}


372
static int inet_diag_bc_run(const void *bc, int len,
373
			    const struct inet_diag_entry *entry)
L
Linus Torvalds 已提交
374 375 376
{
	while (len > 0) {
		int yes = 1;
377
		const struct inet_diag_bc_op *op = bc;
L
Linus Torvalds 已提交
378 379

		switch (op->code) {
380
		case INET_DIAG_BC_NOP:
L
Linus Torvalds 已提交
381
			break;
382
		case INET_DIAG_BC_JMP:
L
Linus Torvalds 已提交
383 384
			yes = 0;
			break;
385
		case INET_DIAG_BC_S_GE:
L
Linus Torvalds 已提交
386 387
			yes = entry->sport >= op[1].no;
			break;
388
		case INET_DIAG_BC_S_LE:
389
			yes = entry->sport <= op[1].no;
L
Linus Torvalds 已提交
390
			break;
391
		case INET_DIAG_BC_D_GE:
L
Linus Torvalds 已提交
392 393
			yes = entry->dport >= op[1].no;
			break;
394
		case INET_DIAG_BC_D_LE:
L
Linus Torvalds 已提交
395 396
			yes = entry->dport <= op[1].no;
			break;
397
		case INET_DIAG_BC_AUTO:
L
Linus Torvalds 已提交
398 399
			yes = !(entry->userlocks & SOCK_BINDPORT_LOCK);
			break;
400
		case INET_DIAG_BC_S_COND:
401 402
		case INET_DIAG_BC_D_COND: {
			struct inet_diag_hostcond *cond;
A
Al Viro 已提交
403
			__be32 *addr;
L
Linus Torvalds 已提交
404

405
			cond = (struct inet_diag_hostcond *)(op + 1);
L
Linus Torvalds 已提交
406
			if (cond->port != -1 &&
407
			    cond->port != (op->code == INET_DIAG_BC_S_COND ?
L
Linus Torvalds 已提交
408 409 410 411
					     entry->sport : entry->dport)) {
				yes = 0;
				break;
			}
412

L
Linus Torvalds 已提交
413 414 415
			if (cond->prefix_len == 0)
				break;

416
			if (op->code == INET_DIAG_BC_S_COND)
L
Linus Torvalds 已提交
417 418 419 420
				addr = entry->saddr;
			else
				addr = entry->daddr;

421 422
			if (bitstring_match(addr, cond->addr,
					    cond->prefix_len))
L
Linus Torvalds 已提交
423 424 425 426 427
				break;
			if (entry->family == AF_INET6 &&
			    cond->family == AF_INET) {
				if (addr[0] == 0 && addr[1] == 0 &&
				    addr[2] == htonl(0xffff) &&
428
				    bitstring_match(addr + 3, cond->addr,
429
						    cond->prefix_len))
L
Linus Torvalds 已提交
430 431 432 433 434 435 436
					break;
			}
			yes = 0;
			break;
		}
		}

437
		if (yes) {
L
Linus Torvalds 已提交
438 439 440 441 442 443 444
			len -= op->yes;
			bc += op->yes;
		} else {
			len -= op->no;
			bc += op->no;
		}
	}
E
Eric Dumazet 已提交
445
	return len == 0;
L
Linus Torvalds 已提交
446 447 448 449 450
}

static int valid_cc(const void *bc, int len, int cc)
{
	while (len >= 0) {
451
		const struct inet_diag_bc_op *op = bc;
L
Linus Torvalds 已提交
452 453 454 455 456

		if (cc > len)
			return 0;
		if (cc == len)
			return 1;
457
		if (op->yes < 4 || op->yes & 3)
L
Linus Torvalds 已提交
458 459 460 461 462 463 464
			return 0;
		len -= op->yes;
		bc  += op->yes;
	}
	return 0;
}

465
static int inet_diag_bc_audit(const void *bytecode, int bytecode_len)
L
Linus Torvalds 已提交
466
{
467
	const void *bc = bytecode;
L
Linus Torvalds 已提交
468 469 470
	int  len = bytecode_len;

	while (len > 0) {
471
		const struct inet_diag_bc_op *op = bc;
L
Linus Torvalds 已提交
472 473 474

//printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len);
		switch (op->code) {
475 476 477 478 479 480 481 482
		case INET_DIAG_BC_AUTO:
		case INET_DIAG_BC_S_COND:
		case INET_DIAG_BC_D_COND:
		case INET_DIAG_BC_S_GE:
		case INET_DIAG_BC_S_LE:
		case INET_DIAG_BC_D_GE:
		case INET_DIAG_BC_D_LE:
		case INET_DIAG_BC_JMP:
483
			if (op->no < 4 || op->no > len + 4 || op->no & 3)
L
Linus Torvalds 已提交
484 485
				return -EINVAL;
			if (op->no < len &&
486
			    !valid_cc(bytecode, bytecode_len, len - op->no))
L
Linus Torvalds 已提交
487 488
				return -EINVAL;
			break;
489
		case INET_DIAG_BC_NOP:
L
Linus Torvalds 已提交
490 491 492 493
			break;
		default:
			return -EINVAL;
		}
494 495
		if (op->yes < 4 || op->yes > len + 4 || op->yes & 3)
			return -EINVAL;
496
		bc  += op->yes;
L
Linus Torvalds 已提交
497 498 499 500 501
		len -= op->yes;
	}
	return len == 0 ? 0 : -EINVAL;
}

502 503
static int inet_csk_diag_dump(struct sock *sk,
			      struct sk_buff *skb,
504
			      struct netlink_callback *cb,
505
			      struct inet_diag_req *r,
506
			      const struct nlattr *bc)
L
Linus Torvalds 已提交
507
{
508
	if (bc != NULL) {
509
		struct inet_diag_entry entry;
L
Linus Torvalds 已提交
510 511 512
		struct inet_sock *inet = inet_sk(sk);

		entry.family = sk->sk_family;
513
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
L
Linus Torvalds 已提交
514 515 516 517 518 519 520 521
		if (entry.family == AF_INET6) {
			struct ipv6_pinfo *np = inet6_sk(sk);

			entry.saddr = np->rcv_saddr.s6_addr32;
			entry.daddr = np->daddr.s6_addr32;
		} else
#endif
		{
E
Eric Dumazet 已提交
522 523
			entry.saddr = &inet->inet_rcv_saddr;
			entry.daddr = &inet->inet_daddr;
L
Linus Torvalds 已提交
524
		}
E
Eric Dumazet 已提交
525 526
		entry.sport = inet->inet_num;
		entry.dport = ntohs(inet->inet_dport);
L
Linus Torvalds 已提交
527 528
		entry.userlocks = sk->sk_userlocks;

529
		if (!inet_diag_bc_run(nla_data(bc), nla_len(bc), &entry))
L
Linus Torvalds 已提交
530 531 532
			return 0;
	}

533 534 535
	return inet_csk_diag_fill(sk, skb, r->idiag_ext,
				  NETLINK_CB(cb->skb).pid,
				  cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
L
Linus Torvalds 已提交
536 537
}

538 539
static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
			       struct sk_buff *skb,
540
			       struct netlink_callback *cb,
541
			       struct inet_diag_req *r,
542
			       const struct nlattr *bc)
543
{
544
	if (bc != NULL) {
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
		struct inet_diag_entry entry;

		entry.family = tw->tw_family;
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
		if (tw->tw_family == AF_INET6) {
			struct inet6_timewait_sock *tw6 =
						inet6_twsk((struct sock *)tw);
			entry.saddr = tw6->tw_v6_rcv_saddr.s6_addr32;
			entry.daddr = tw6->tw_v6_daddr.s6_addr32;
		} else
#endif
		{
			entry.saddr = &tw->tw_rcv_saddr;
			entry.daddr = &tw->tw_daddr;
		}
		entry.sport = tw->tw_num;
		entry.dport = ntohs(tw->tw_dport);
562
		entry.userlocks = 0;
563

564
		if (!inet_diag_bc_run(nla_data(bc), nla_len(bc), &entry))
565 566 567 568 569 570 571 572
			return 0;
	}

	return inet_twsk_diag_fill(tw, skb, r->idiag_ext,
				   NETLINK_CB(cb->skb).pid,
				   cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh);
}

573
static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
574 575
			      struct request_sock *req, u32 pid, u32 seq,
			      const struct nlmsghdr *unlh)
L
Linus Torvalds 已提交
576
{
577
	const struct inet_request_sock *ireq = inet_rsk(req);
L
Linus Torvalds 已提交
578
	struct inet_sock *inet = inet_sk(sk);
579
	unsigned char *b = skb_tail_pointer(skb);
580
	struct inet_diag_msg *r;
L
Linus Torvalds 已提交
581 582 583
	struct nlmsghdr *nlh;
	long tmo;

584
	nlh = NLMSG_PUT(skb, pid, seq, unlh->nlmsg_type, sizeof(*r));
L
Linus Torvalds 已提交
585 586 587
	nlh->nlmsg_flags = NLM_F_MULTI;
	r = NLMSG_DATA(nlh);

588 589 590 591
	r->idiag_family = sk->sk_family;
	r->idiag_state = TCP_SYN_RECV;
	r->idiag_timer = 1;
	r->idiag_retrans = req->retrans;
L
Linus Torvalds 已提交
592

593 594 595
	r->id.idiag_if = sk->sk_bound_dev_if;
	r->id.idiag_cookie[0] = (u32)(unsigned long)req;
	r->id.idiag_cookie[1] = (u32)(((unsigned long)req >> 31) >> 1);
L
Linus Torvalds 已提交
596 597 598 599 600

	tmo = req->expires - jiffies;
	if (tmo < 0)
		tmo = 0;

E
Eric Dumazet 已提交
601
	r->id.idiag_sport = inet->inet_sport;
602 603 604 605 606 607 608 609
	r->id.idiag_dport = ireq->rmt_port;
	r->id.idiag_src[0] = ireq->loc_addr;
	r->id.idiag_dst[0] = ireq->rmt_addr;
	r->idiag_expires = jiffies_to_msecs(tmo);
	r->idiag_rqueue = 0;
	r->idiag_wqueue = 0;
	r->idiag_uid = sock_i_uid(sk);
	r->idiag_inode = 0;
610
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
611
	if (r->idiag_family == AF_INET6) {
A
Alexey Dobriyan 已提交
612 613
		*(struct in6_addr *)r->id.idiag_src = inet6_rsk(req)->loc_addr;
		*(struct in6_addr *)r->id.idiag_dst = inet6_rsk(req)->rmt_addr;
L
Linus Torvalds 已提交
614 615
	}
#endif
616
	nlh->nlmsg_len = skb_tail_pointer(skb) - b;
L
Linus Torvalds 已提交
617 618 619 620

	return skb->len;

nlmsg_failure:
621
	nlmsg_trim(skb, b);
L
Linus Torvalds 已提交
622 623 624
	return -1;
}

625
static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
626
			       struct netlink_callback *cb,
627
			       struct inet_diag_req *r,
628
			       const struct nlattr *bc)
L
Linus Torvalds 已提交
629
{
630
	struct inet_diag_entry entry;
631
	struct inet_connection_sock *icsk = inet_csk(sk);
632
	struct listen_sock *lopt;
L
Linus Torvalds 已提交
633 634 635 636 637 638 639 640 641 642 643 644 645
	struct inet_sock *inet = inet_sk(sk);
	int j, s_j;
	int reqnum, s_reqnum;
	int err = 0;

	s_j = cb->args[3];
	s_reqnum = cb->args[4];

	if (s_j > 0)
		s_j--;

	entry.family = sk->sk_family;

646
	read_lock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
L
Linus Torvalds 已提交
647

648
	lopt = icsk->icsk_accept_queue.listen_opt;
L
Linus Torvalds 已提交
649 650 651
	if (!lopt || !lopt->qlen)
		goto out;

652
	if (bc != NULL) {
E
Eric Dumazet 已提交
653
		entry.sport = inet->inet_num;
L
Linus Torvalds 已提交
654 655 656
		entry.userlocks = sk->sk_userlocks;
	}

657
	for (j = s_j; j < lopt->nr_table_entries; j++) {
658
		struct request_sock *req, *head = lopt->syn_table[j];
L
Linus Torvalds 已提交
659 660 661

		reqnum = 0;
		for (req = head; req; reqnum++, req = req->dl_next) {
662 663
			struct inet_request_sock *ireq = inet_rsk(req);

L
Linus Torvalds 已提交
664 665
			if (reqnum < s_reqnum)
				continue;
666 667
			if (r->id.idiag_dport != ireq->rmt_port &&
			    r->id.idiag_dport)
L
Linus Torvalds 已提交
668 669 670 671
				continue;

			if (bc) {
				entry.saddr =
672
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
L
Linus Torvalds 已提交
673
					(entry.family == AF_INET6) ?
674
					inet6_rsk(req)->loc_addr.s6_addr32 :
L
Linus Torvalds 已提交
675
#endif
676
					&ireq->loc_addr;
677
				entry.daddr =
678
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
L
Linus Torvalds 已提交
679
					(entry.family == AF_INET6) ?
680
					inet6_rsk(req)->rmt_addr.s6_addr32 :
L
Linus Torvalds 已提交
681
#endif
682 683
					&ireq->rmt_addr;
				entry.dport = ntohs(ireq->rmt_port);
L
Linus Torvalds 已提交
684

685 686
				if (!inet_diag_bc_run(nla_data(bc),
						      nla_len(bc), &entry))
L
Linus Torvalds 已提交
687 688 689
					continue;
			}

690
			err = inet_diag_fill_req(skb, sk, req,
L
Linus Torvalds 已提交
691
					       NETLINK_CB(cb->skb).pid,
692
					       cb->nlh->nlmsg_seq, cb->nlh);
L
Linus Torvalds 已提交
693 694 695 696 697 698 699 700 701 702 703
			if (err < 0) {
				cb->args[3] = j + 1;
				cb->args[4] = reqnum;
				goto out;
			}
		}

		s_reqnum = 0;
	}

out:
704
	read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock);
L
Linus Torvalds 已提交
705 706 707 708

	return err;
}

709 710
static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
		struct inet_diag_req *r, struct nlattr *bc)
L
Linus Torvalds 已提交
711 712 713
{
	int i, num;
	int s_i, s_num;
714
	const struct inet_diag_handler *handler;
715
	struct inet_hashinfo *hashinfo;
716

717
	handler = inet_diag_lock_handler(r->sdiag_protocol);
718 719
	if (IS_ERR(handler))
		goto unlock;
720

721
	hashinfo = handler->idiag_hashinfo;
722

L
Linus Torvalds 已提交
723 724
	s_i = cb->args[1];
	s_num = num = cb->args[2];
725

L
Linus Torvalds 已提交
726
	if (cb->args[0] == 0) {
727
		if (!(r->idiag_states & (TCPF_LISTEN | TCPF_SYN_RECV)))
L
Linus Torvalds 已提交
728
			goto skip_listen_ht;
729

730
		for (i = s_i; i < INET_LHTABLE_SIZE; i++) {
L
Linus Torvalds 已提交
731
			struct sock *sk;
732
			struct hlist_nulls_node *node;
733
			struct inet_listen_hashbucket *ilb;
L
Linus Torvalds 已提交
734 735

			num = 0;
736 737
			ilb = &hashinfo->listening_hash[i];
			spin_lock_bh(&ilb->lock);
738
			sk_nulls_for_each(sk, node, &ilb->head) {
L
Linus Torvalds 已提交
739 740 741 742 743 744 745
				struct inet_sock *inet = inet_sk(sk);

				if (num < s_num) {
					num++;
					continue;
				}

E
Eric Dumazet 已提交
746
				if (r->id.idiag_sport != inet->inet_sport &&
747
				    r->id.idiag_sport)
L
Linus Torvalds 已提交
748 749
					goto next_listen;

750 751
				if (!(r->idiag_states & TCPF_LISTEN) ||
				    r->id.idiag_dport ||
L
Linus Torvalds 已提交
752 753 754
				    cb->args[3] > 0)
					goto syn_recv;

755
				if (inet_csk_diag_dump(sk, skb, cb, r, bc) < 0) {
756
					spin_unlock_bh(&ilb->lock);
L
Linus Torvalds 已提交
757 758 759 760
					goto done;
				}

syn_recv:
761
				if (!(r->idiag_states & TCPF_SYN_RECV))
L
Linus Torvalds 已提交
762 763
					goto next_listen;

764
				if (inet_diag_dump_reqs(skb, sk, cb, r, bc) < 0) {
765
					spin_unlock_bh(&ilb->lock);
L
Linus Torvalds 已提交
766 767 768 769 770 771 772 773
					goto done;
				}

next_listen:
				cb->args[3] = 0;
				cb->args[4] = 0;
				++num;
			}
774
			spin_unlock_bh(&ilb->lock);
L
Linus Torvalds 已提交
775 776 777 778 779 780 781 782 783 784

			s_num = 0;
			cb->args[3] = 0;
			cb->args[4] = 0;
		}
skip_listen_ht:
		cb->args[0] = 1;
		s_i = num = s_num = 0;
	}

785
	if (!(r->idiag_states & ~(TCPF_LISTEN | TCPF_SYN_RECV)))
786
		goto unlock;
L
Linus Torvalds 已提交
787

788
	for (i = s_i; i <= hashinfo->ehash_mask; i++) {
789
		struct inet_ehash_bucket *head = &hashinfo->ehash[i];
790
		spinlock_t *lock = inet_ehash_lockp(hashinfo, i);
L
Linus Torvalds 已提交
791
		struct sock *sk;
792
		struct hlist_nulls_node *node;
L
Linus Torvalds 已提交
793

794 795
		num = 0;

796 797
		if (hlist_nulls_empty(&head->chain) &&
			hlist_nulls_empty(&head->twchain))
798 799
			continue;

L
Linus Torvalds 已提交
800 801 802
		if (i > s_i)
			s_num = 0;

803
		spin_lock_bh(lock);
804
		sk_nulls_for_each(sk, node, &head->chain) {
L
Linus Torvalds 已提交
805 806 807 808
			struct inet_sock *inet = inet_sk(sk);

			if (num < s_num)
				goto next_normal;
809
			if (!(r->idiag_states & (1 << sk->sk_state)))
L
Linus Torvalds 已提交
810
				goto next_normal;
E
Eric Dumazet 已提交
811
			if (r->id.idiag_sport != inet->inet_sport &&
812
			    r->id.idiag_sport)
L
Linus Torvalds 已提交
813
				goto next_normal;
E
Eric Dumazet 已提交
814
			if (r->id.idiag_dport != inet->inet_dport &&
815
			    r->id.idiag_dport)
L
Linus Torvalds 已提交
816
				goto next_normal;
817
			if (inet_csk_diag_dump(sk, skb, cb, r, bc) < 0) {
818
				spin_unlock_bh(lock);
L
Linus Torvalds 已提交
819 820 821 822 823 824
				goto done;
			}
next_normal:
			++num;
		}

825
		if (r->idiag_states & TCPF_TIME_WAIT) {
826 827 828
			struct inet_timewait_sock *tw;

			inet_twsk_for_each(tw, node,
829
				    &head->twchain) {
L
Linus Torvalds 已提交
830 831 832

				if (num < s_num)
					goto next_dying;
833
				if (r->id.idiag_sport != tw->tw_sport &&
834
				    r->id.idiag_sport)
L
Linus Torvalds 已提交
835
					goto next_dying;
836
				if (r->id.idiag_dport != tw->tw_dport &&
837
				    r->id.idiag_dport)
L
Linus Torvalds 已提交
838
					goto next_dying;
839
				if (inet_twsk_diag_dump(tw, skb, cb, r, bc) < 0) {
840
					spin_unlock_bh(lock);
L
Linus Torvalds 已提交
841 842 843 844 845 846
					goto done;
				}
next_dying:
				++num;
			}
		}
847
		spin_unlock_bh(lock);
L
Linus Torvalds 已提交
848 849 850 851 852
	}

done:
	cb->args[1] = i;
	cb->args[2] = num;
853 854
unlock:
	inet_diag_unlock_handler(handler);
L
Linus Torvalds 已提交
855 856 857
	return skb->len;
}

858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887
static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
	struct nlattr *bc = NULL;
	int hdrlen = sizeof(struct inet_diag_req);

	if (nlmsg_attrlen(cb->nlh, hdrlen))
		bc = nlmsg_find_attr(cb->nlh, hdrlen, INET_DIAG_REQ_BYTECODE);

	return __inet_diag_dump(skb, cb, (struct inet_diag_req *)NLMSG_DATA(cb->nlh), bc);
}

static int inet_diag_dump_compat(struct sk_buff *skb, struct netlink_callback *cb)
{
	struct inet_diag_req_compat *rc = NLMSG_DATA(cb->nlh);
	struct inet_diag_req req;
	struct nlattr *bc = NULL;
	int hdrlen = sizeof(struct inet_diag_req_compat);

	req.sdiag_family = rc->idiag_family;
	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;

	if (nlmsg_attrlen(cb->nlh, hdrlen))
		bc = nlmsg_find_attr(cb->nlh, hdrlen, INET_DIAG_REQ_BYTECODE);

	return __inet_diag_dump(skb, cb, &req, bc);
}

888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
static int inet_diag_get_exact_compat(struct sk_buff *in_skb,
			       const struct nlmsghdr *nlh)
{
	struct inet_diag_req_compat *rc = NLMSG_DATA(nlh);
	struct inet_diag_req req;

	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;

	return inet_diag_get_exact(in_skb, nlh, &req);
}

903
static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
L
Linus Torvalds 已提交
904
{
905
	int hdrlen = sizeof(struct inet_diag_req_compat);
L
Linus Torvalds 已提交
906

907 908 909
	if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX ||
	    nlmsg_len(nlh) < hdrlen)
		return -EINVAL;
L
Linus Torvalds 已提交
910

911
	if (nlh->nlmsg_flags & NLM_F_DUMP) {
912 913
		if (nlmsg_attrlen(nlh, hdrlen)) {
			struct nlattr *attr;
L
Linus Torvalds 已提交
914

915 916 917 918 919 920 921
			attr = nlmsg_find_attr(nlh, hdrlen,
					       INET_DIAG_REQ_BYTECODE);
			if (attr == NULL ||
			    nla_len(attr) < sizeof(struct inet_diag_bc_op) ||
			    inet_diag_bc_audit(nla_data(attr), nla_len(attr)))
				return -EINVAL;
		}
L
Linus Torvalds 已提交
922

923
		return netlink_dump_start(sdiagnl, skb, nlh,
924
					  inet_diag_dump_compat, NULL, 0);
L
Linus Torvalds 已提交
925
	}
926

927
	return inet_diag_get_exact_compat(skb, nlh);
L
Linus Torvalds 已提交
928 929
}

P
Pavel Emelyanov 已提交
930 931 932 933 934 935 936 937
static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
{
	int hdrlen = sizeof(struct inet_diag_req);

	if (nlmsg_len(h) < hdrlen)
		return -EINVAL;

	if (h->nlmsg_flags & NLM_F_DUMP) {
938 939 940 941 942 943 944 945 946 947 948 949
		if (nlmsg_attrlen(h, hdrlen)) {
			struct nlattr *attr;
			attr = nlmsg_find_attr(h, hdrlen,
					       INET_DIAG_REQ_BYTECODE);
			if (attr == NULL ||
			    nla_len(attr) < sizeof(struct inet_diag_bc_op) ||
			    inet_diag_bc_audit(nla_data(attr), nla_len(attr)))
				return -EINVAL;
		}

		return netlink_dump_start(sdiagnl, skb, h,
					  inet_diag_dump, NULL, 0);
P
Pavel Emelyanov 已提交
950 951
	}

952
	return inet_diag_get_exact(skb, h, (struct inet_diag_req *)NLMSG_DATA(h));
P
Pavel Emelyanov 已提交
953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
}

static struct sock_diag_handler inet_diag_handler = {
	.family = AF_INET,
	.dump = inet_diag_handler_dump,
};

static struct sock_diag_handler inet6_diag_handler = {
	.family = AF_INET6,
	.dump = inet_diag_handler_dump,
};

static struct sock_diag_handler *sock_diag_handlers[AF_MAX];
static DEFINE_MUTEX(sock_diag_table_mutex);

int sock_diag_register(struct sock_diag_handler *hndl)
{
	int err = 0;

	if (hndl->family > AF_MAX)
		return -EINVAL;

	mutex_lock(&sock_diag_table_mutex);
	if (sock_diag_handlers[hndl->family])
		err = -EBUSY;
	else
		sock_diag_handlers[hndl->family] = hndl;
	mutex_unlock(&sock_diag_table_mutex);

	return err;
}

void sock_diag_unregister(struct sock_diag_handler *hnld)
{
	int family = hnld->family;

	if (family > AF_MAX)
		return;

	mutex_lock(&sock_diag_table_mutex);
	BUG_ON(sock_diag_handlers[family] != hnld);
	sock_diag_handlers[family] = NULL;
	mutex_unlock(&sock_diag_table_mutex);
}

static inline struct sock_diag_handler *sock_diag_lock_handler(int family)
{
	mutex_lock(&sock_diag_table_mutex);
	return sock_diag_handlers[family];
}

static inline void sock_diag_unlock_handler(struct sock_diag_handler *h)
{
	mutex_unlock(&sock_diag_table_mutex);
}

1009 1010
static int __sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
P
Pavel Emelyanov 已提交
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
	int err;
	struct sock_diag_req *req = NLMSG_DATA(nlh);
	struct sock_diag_handler *hndl;

	if (nlmsg_len(nlh) < sizeof(*req))
		return -EINVAL;

	hndl = sock_diag_lock_handler(req->sdiag_family);
	if (hndl == NULL)
		err = -ENOENT;
	else
		err = hndl->dump(skb, nlh);
	sock_diag_unlock_handler(hndl);

	return err;
1026 1027
}

1028 1029
static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
1030 1031 1032 1033 1034 1035 1036 1037 1038
	switch (nlh->nlmsg_type) {
	case TCPDIAG_GETSOCK:
	case DCCPDIAG_GETSOCK:
		return inet_diag_rcv_msg_compat(skb, nlh);
	case SOCK_DIAG_BY_FAMILY:
		return __sock_diag_rcv_msg(skb, nlh);
	default:
		return -EINVAL;
	}
1039 1040 1041
}

static DEFINE_MUTEX(sock_diag_mutex);
1042

1043
static void sock_diag_rcv(struct sk_buff *skb)
L
Linus Torvalds 已提交
1044
{
1045 1046 1047
	mutex_lock(&sock_diag_mutex);
	netlink_rcv_skb(skb, &sock_diag_rcv_msg);
	mutex_unlock(&sock_diag_mutex);
L
Linus Torvalds 已提交
1048 1049
}

1050 1051 1052 1053 1054
int inet_diag_register(const struct inet_diag_handler *h)
{
	const __u16 type = h->idiag_type;
	int err = -EINVAL;

1055
	if (type >= IPPROTO_MAX)
1056 1057
		goto out;

1058
	mutex_lock(&inet_diag_table_mutex);
1059 1060 1061 1062 1063
	err = -EEXIST;
	if (inet_diag_table[type] == NULL) {
		inet_diag_table[type] = h;
		err = 0;
	}
1064
	mutex_unlock(&inet_diag_table_mutex);
1065 1066 1067 1068 1069 1070 1071 1072 1073
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;

1074
	if (type >= IPPROTO_MAX)
1075 1076
		return;

1077
	mutex_lock(&inet_diag_table_mutex);
1078
	inet_diag_table[type] = NULL;
1079
	mutex_unlock(&inet_diag_table_mutex);
1080 1081 1082
}
EXPORT_SYMBOL_GPL(inet_diag_unregister);

1083
static int __init inet_diag_init(void)
L
Linus Torvalds 已提交
1084
{
1085
	const int inet_diag_table_size = (IPPROTO_MAX *
1086 1087 1088
					  sizeof(struct inet_diag_handler *));
	int err = -ENOMEM;

1089
	inet_diag_table = kzalloc(inet_diag_table_size, GFP_KERNEL);
1090 1091 1092
	if (!inet_diag_table)
		goto out;

1093 1094 1095
	sdiagnl = netlink_kernel_create(&init_net, NETLINK_SOCK_DIAG, 0,
					sock_diag_rcv, NULL, THIS_MODULE);
	if (sdiagnl == NULL)
1096
		goto out_free_table;
P
Pavel Emelyanov 已提交
1097 1098 1099 1100 1101 1102 1103 1104 1105

	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;

1106 1107
out:
	return err;
P
Pavel Emelyanov 已提交
1108 1109 1110 1111 1112

out_free_inet:
	sock_diag_unregister(&inet_diag_handler);
out_free_nl:
	netlink_kernel_release(sdiagnl);
1113 1114 1115
out_free_table:
	kfree(inet_diag_table);
	goto out;
L
Linus Torvalds 已提交
1116 1117
}

1118
static void __exit inet_diag_exit(void)
L
Linus Torvalds 已提交
1119
{
P
Pavel Emelyanov 已提交
1120 1121
	sock_diag_unregister(&inet6_diag_handler);
	sock_diag_unregister(&inet_diag_handler);
1122
	netlink_kernel_release(sdiagnl);
1123
	kfree(inet_diag_table);
L
Linus Torvalds 已提交
1124 1125
}

1126 1127
module_init(inet_diag_init);
module_exit(inet_diag_exit);
L
Linus Torvalds 已提交
1128
MODULE_LICENSE("GPL");
1129
MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_SOCK_DIAG);