ip_set_hash_ipportnet.c 15.9 KB
Newer Older
1
/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

/* Kernel module implementing an IP set type: the hash:ip,port,net type */

#include <linux/jhash.h>
#include <linux/module.h>
#include <linux/ip.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
#include <linux/random.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/netlink.h>
#include <net/tcp.h>

#include <linux/netfilter.h>
#include <linux/netfilter/ipset/pfxlen.h>
#include <linux/netfilter/ipset/ip_set.h>
#include <linux/netfilter/ipset/ip_set_getport.h>
#include <linux/netfilter/ipset/ip_set_hash.h>

27 28 29 30 31
#define IPSET_TYPE_REV_MIN	0
/*				1    SCTP and UDPLITE support added */
/*				2    Range as input support for IPv4 added */
/*				3    nomatch flag support added */
#define IPSET_TYPE_REV_MAX	4 /* Counters support added */
32

33 34
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
35
IP_SET_MODULE_DESC("hash:ip,port,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
36 37 38
MODULE_ALIAS("ip_set_hash:ip,port,net");

/* Type specific function prefix */
39
#define HTYPE		hash_ipportnet
40

41 42 43 44 45
/* We squeeze the "nomatch" flag into cidr: we don't support cidr == 0
 * However this way we have to store internally cidr - 1,
 * dancing back and forth.
 */
#define IP_SET_HASH_WITH_NETS_PACKED
46 47
#define IP_SET_HASH_WITH_PROTO
#define IP_SET_HASH_WITH_NETS
48

49 50 51
/* IPv4 variants */

/* Member elements */
52 53 54 55
struct hash_ipportnet4_elem {
	__be32 ip;
	__be32 ip2;
	__be16 port;
56 57
	u8 cidr:7;
	u8 nomatch:1;
58 59 60
	u8 proto;
};

61
struct hash_ipportnet4t_elem {
62 63 64
	__be32 ip;
	__be32 ip2;
	__be16 port;
65 66
	u8 cidr:7;
	u8 nomatch:1;
67 68 69 70
	u8 proto;
	unsigned long timeout;
};

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
struct hash_ipportnet4c_elem {
	__be32 ip;
	__be32 ip2;
	__be16 port;
	u8 cidr:7;
	u8 nomatch:1;
	u8 proto;
	struct ip_set_counter counter;
};

struct hash_ipportnet4ct_elem {
	__be32 ip;
	__be32 ip2;
	__be16 port;
	u8 cidr:7;
	u8 nomatch:1;
	u8 proto;
	struct ip_set_counter counter;
	unsigned long timeout;
};

92 93
/* Common functions */

94 95
static inline bool
hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1,
96 97
			   const struct hash_ipportnet4_elem *ip2,
			   u32 *multi)
98 99 100 101 102 103 104 105
{
	return ip1->ip == ip2->ip &&
	       ip1->ip2 == ip2->ip2 &&
	       ip1->cidr == ip2->cidr &&
	       ip1->port == ip2->port &&
	       ip1->proto == ip2->proto;
}

106 107
static inline int
hash_ipportnet4_do_data_match(const struct hash_ipportnet4_elem *elem)
108
{
109
	return elem->nomatch ? -ENOTEMPTY : 1;
110 111 112
}

static inline void
113
hash_ipportnet4_data_set_flags(struct hash_ipportnet4_elem *elem, u32 flags)
114
{
115
	elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH);
116 117
}

118
static inline void
119
hash_ipportnet4_data_reset_flags(struct hash_ipportnet4_elem *elem, u8 *flags)
120
{
121
	swap(*flags, elem->nomatch);
122 123
}

124 125 126 127
static inline void
hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr)
{
	elem->ip2 &= ip_set_netmask(cidr);
128
	elem->cidr = cidr - 1;
129 130 131 132 133 134
}

static bool
hash_ipportnet4_data_list(struct sk_buff *skb,
			  const struct hash_ipportnet4_elem *data)
{
135 136
	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;

D
David S. Miller 已提交
137 138 139 140 141 142 143 144
	if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
	    nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip2) ||
	    nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
	    nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr + 1) ||
	    nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
	    (flags &&
	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
		goto nla_put_failure;
145 146 147 148 149 150
	return 0;

nla_put_failure:
	return 1;
}

151 152 153
static inline void
hash_ipportnet4_data_next(struct hash_ipportnet4_elem *next,
			  const struct hash_ipportnet4_elem *d)
154
{
155 156 157
	next->ip = d->ip;
	next->port = d->port;
	next->ip2 = d->ip2;
158 159
}

160
#define MTYPE		hash_ipportnet4
161 162
#define PF		4
#define HOST_MASK	32
163
#include "ip_set_hash_gen.h"
164

165 166
static int
hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
167
		     const struct xt_action_param *par,
168
		     enum ipset_adt adt, struct ip_set_adt_opt *opt)
169
{
170
	const struct hash_ipportnet *h = set->data;
171
	ipset_adtfn adtfn = set->variant->adt[adt];
172
	struct hash_ipportnet4_elem e = {
173
		.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
174
	};
175
	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
176 177

	if (adt == IPSET_TEST)
178
		e.cidr = HOST_MASK - 1;
179

180
	if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
181
				 &e.port, &e.proto))
182 183
		return -EINVAL;

184 185 186
	ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
	ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2);
	e.ip2 &= ip_set_netmask(e.cidr + 1);
187

188
	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
189 190 191 192
}

static int
hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
193
		     enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
194
{
195
	const struct hash_ipportnet *h = set->data;
196
	ipset_adtfn adtfn = set->variant->adt[adt];
197 198
	struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 };
	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
199 200
	u32 ip = 0, ip_to = 0, p = 0, port, port_to;
	u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2;
201
	bool with_ports = false;
202
	u8 cidr;
203 204 205 206 207
	int ret;

	if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
		     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
208
		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
209 210 211
		     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
		     !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
212 213 214 215 216
		return -IPSET_ERR_PROTOCOL;

	if (tb[IPSET_ATTR_LINENO])
		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);

217 218
	ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
	      ip_set_get_extensions(set, tb, &ext);
219 220 221
	if (ret)
		return ret;

222
	ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from);
223 224 225
	if (ret)
		return ret;

226
	if (tb[IPSET_ATTR_CIDR2]) {
227 228
		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
		if (!cidr || cidr > HOST_MASK)
229
			return -IPSET_ERR_INVALID_CIDR;
230
		e.cidr = cidr - 1;
231
	}
232 233

	if (tb[IPSET_ATTR_PORT])
234
		e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
235 236 237 238
	else
		return -IPSET_ERR_PROTOCOL;

	if (tb[IPSET_ATTR_PROTO]) {
239 240
		e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
		with_ports = ip_set_proto_with_ports(e.proto);
241

242
		if (e.proto == 0)
243 244 245 246
			return -IPSET_ERR_INVALID_PROTO;
	} else
		return -IPSET_ERR_MISSING_PROTO;

247 248
	if (!(with_ports || e.proto == IPPROTO_ICMP))
		e.port = 0;
249

250
	if (tb[IPSET_ATTR_CADT_FLAGS]) {
251 252
		u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
		if (cadt_flags & IPSET_FLAG_NOMATCH)
253
			flags |= (IPSET_FLAG_NOMATCH << 16);
254 255
	}

256
	with_ports = with_ports && tb[IPSET_ATTR_PORT_TO];
257
	if (adt == IPSET_TEST ||
258 259
	    !(tb[IPSET_ATTR_CIDR] || tb[IPSET_ATTR_IP_TO] || with_ports ||
	      tb[IPSET_ATTR_IP2_TO])) {
260 261 262
		e.ip = htonl(ip);
		e.ip2 = htonl(ip2_from & ip_set_hostmask(e.cidr + 1));
		ret = adtfn(set, &e, &ext, &ext, flags);
263
		return ip_set_enomatch(ret, flags, adt, set) ? -ret :
264
		       ip_set_eexist(ret, flags) ? 0 : ret;
265 266
	}

267
	ip_to = ip;
268 269 270 271 272 273 274
	if (tb[IPSET_ATTR_IP_TO]) {
		ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
		if (ret)
			return ret;
		if (ip > ip_to)
			swap(ip, ip_to);
	} else if (tb[IPSET_ATTR_CIDR]) {
275
		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
276

277
		if (!cidr || cidr > 32)
278
			return -IPSET_ERR_INVALID_CIDR;
279
		ip_set_mask_from_to(ip, ip_to, cidr);
280
	}
281

282
	port_to = port = ntohs(e.port);
283
	if (tb[IPSET_ATTR_PORT_TO]) {
284 285 286
		port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
		if (port > port_to)
			swap(port, port_to);
287
	}
288 289

	ip2_to = ip2_from;
290 291 292 293 294 295 296 297
	if (tb[IPSET_ATTR_IP2_TO]) {
		ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to);
		if (ret)
			return ret;
		if (ip2_from > ip2_to)
			swap(ip2_from, ip2_to);
		if (ip2_from + UINT_MAX == ip2_to)
			return -IPSET_ERR_HASH_RANGE;
298 299
	} else
		ip_set_mask_from_to(ip2_from, ip2_to, e.cidr + 1);
300

301
	if (retried)
302
		ip = ntohl(h->next.ip);
303
	for (; !before(ip_to, ip); ip++) {
304
		e.ip = htonl(ip);
305 306
		p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
						       : port;
307
		for (; p <= port_to; p++) {
308
			e.port = htons(p);
309 310 311 312
			ip2 = retried
			      && ip == ntohl(h->next.ip)
			      && p == ntohs(h->next.port)
				? ntohl(h->next.ip2) : ip2_from;
313
			while (!after(ip2, ip2_to)) {
314
				e.ip2 = htonl(ip2);
315
				ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
316
								&cidr);
317 318
				e.cidr = cidr - 1;
				ret = adtfn(set, &e, &ext, &ext, flags);
319 320 321 322 323 324 325

				if (ret && !ip_set_eexist(ret, flags))
					return ret;
				else
					ret = 0;
				ip2 = ip2_last + 1;
			}
326
		}
327
	}
328 329 330
	return ret;
}

331
/* IPv6 variants */
332 333 334 335 336

struct hash_ipportnet6_elem {
	union nf_inet_addr ip;
	union nf_inet_addr ip2;
	__be16 port;
337 338
	u8 cidr:7;
	u8 nomatch:1;
339 340 341
	u8 proto;
};

342
struct hash_ipportnet6t_elem {
343 344 345
	union nf_inet_addr ip;
	union nf_inet_addr ip2;
	__be16 port;
346 347
	u8 cidr:7;
	u8 nomatch:1;
348 349 350 351
	u8 proto;
	unsigned long timeout;
};

352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
struct hash_ipportnet6c_elem {
	union nf_inet_addr ip;
	union nf_inet_addr ip2;
	__be16 port;
	u8 cidr:7;
	u8 nomatch:1;
	u8 proto;
	struct ip_set_counter counter;
};

struct hash_ipportnet6ct_elem {
	union nf_inet_addr ip;
	union nf_inet_addr ip2;
	__be16 port;
	u8 cidr:7;
	u8 nomatch:1;
	u8 proto;
	struct ip_set_counter counter;
	unsigned long timeout;
};

373 374
/* Common functions */

375 376
static inline bool
hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1,
377 378
			   const struct hash_ipportnet6_elem *ip2,
			   u32 *multi)
379
{
380 381
	return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
	       ipv6_addr_equal(&ip1->ip2.in6, &ip2->ip2.in6) &&
382 383 384 385 386
	       ip1->cidr == ip2->cidr &&
	       ip1->port == ip2->port &&
	       ip1->proto == ip2->proto;
}

387 388
static inline int
hash_ipportnet6_do_data_match(const struct hash_ipportnet6_elem *elem)
389
{
390
	return elem->nomatch ? -ENOTEMPTY : 1;
391 392
}

393
static inline void
394
hash_ipportnet6_data_set_flags(struct hash_ipportnet6_elem *elem, u32 flags)
395
{
396
	elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH);
397 398
}

399
static inline void
400
hash_ipportnet6_data_reset_flags(struct hash_ipportnet6_elem *elem, u8 *flags)
401
{
402
	swap(*flags, elem->nomatch);
403 404 405 406 407 408
}

static inline void
hash_ipportnet6_data_netmask(struct hash_ipportnet6_elem *elem, u8 cidr)
{
	ip6_netmask(&elem->ip2, cidr);
409
	elem->cidr = cidr - 1;
410 411 412 413 414 415
}

static bool
hash_ipportnet6_data_list(struct sk_buff *skb,
			  const struct hash_ipportnet6_elem *data)
{
416 417
	u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;

D
David S. Miller 已提交
418 419 420 421 422 423 424 425
	if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
	    nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip2.in6) ||
	    nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
	    nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr + 1) ||
	    nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
	    (flags &&
	     nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
		goto nla_put_failure;
426 427 428 429 430 431
	return 0;

nla_put_failure:
	return 1;
}

432 433 434
static inline void
hash_ipportnet6_data_next(struct hash_ipportnet4_elem *next,
			  const struct hash_ipportnet6_elem *d)
435
{
436
	next->port = d->port;
437 438
}

439
#undef MTYPE
440 441 442
#undef PF
#undef HOST_MASK

443
#define MTYPE		hash_ipportnet6
444 445
#define PF		6
#define HOST_MASK	128
446 447
#define IP_SET_EMIT_CREATE
#include "ip_set_hash_gen.h"
448

449 450
static int
hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
451
		     const struct xt_action_param *par,
452
		     enum ipset_adt adt, struct ip_set_adt_opt *opt)
453
{
454
	const struct hash_ipportnet *h = set->data;
455
	ipset_adtfn adtfn = set->variant->adt[adt];
456
	struct hash_ipportnet6_elem e = {
457
		.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
458
	};
459
	struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
460 461

	if (adt == IPSET_TEST)
462
		e.cidr = HOST_MASK - 1;
463

464
	if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
465
				 &e.port, &e.proto))
466 467
		return -EINVAL;

468 469 470
	ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
	ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2.in6);
	ip6_netmask(&e.ip2, e.cidr + 1);
471

472
	return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
473 474 475 476
}

static int
hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
477
		     enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
478
{
479
	const struct hash_ipportnet *h = set->data;
480
	ipset_adtfn adtfn = set->variant->adt[adt];
481 482
	struct hash_ipportnet6_elem e = { .cidr = HOST_MASK - 1 };
	struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
483
	u32 port, port_to;
484
	bool with_ports = false;
485
	u8 cidr;
486 487 488 489 490 491
	int ret;

	if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
		     !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
		     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
492
		     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
493 494
		     !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
		     !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) ||
495 496 497
		     tb[IPSET_ATTR_IP_TO] ||
		     tb[IPSET_ATTR_CIDR]))
		return -IPSET_ERR_PROTOCOL;
498 499
	if (unlikely(tb[IPSET_ATTR_IP_TO]))
		return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
500 501 502 503

	if (tb[IPSET_ATTR_LINENO])
		*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);

504 505
	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
	      ip_set_get_extensions(set, tb, &ext);
506 507 508
	if (ret)
		return ret;

509
	ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip2);
510 511 512
	if (ret)
		return ret;

513 514 515 516
	if (tb[IPSET_ATTR_CIDR2]) {
		cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
		if (!cidr || cidr > HOST_MASK)
			return -IPSET_ERR_INVALID_CIDR;
517
		e.cidr = cidr - 1;
518
	}
519

520
	ip6_netmask(&e.ip2, e.cidr + 1);
521 522

	if (tb[IPSET_ATTR_PORT])
523
		e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
524 525 526 527
	else
		return -IPSET_ERR_PROTOCOL;

	if (tb[IPSET_ATTR_PROTO]) {
528 529
		e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
		with_ports = ip_set_proto_with_ports(e.proto);
530

531
		if (e.proto == 0)
532 533 534 535
			return -IPSET_ERR_INVALID_PROTO;
	} else
		return -IPSET_ERR_MISSING_PROTO;

536 537
	if (!(with_ports || e.proto == IPPROTO_ICMPV6))
		e.port = 0;
538

539
	if (tb[IPSET_ATTR_CADT_FLAGS]) {
540 541
		u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
		if (cadt_flags & IPSET_FLAG_NOMATCH)
542
			flags |= (IPSET_FLAG_NOMATCH << 16);
543 544
	}

545
	if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
546
		ret = adtfn(set, &e, &ext, &ext, flags);
547
		return ip_set_enomatch(ret, flags, adt, set) ? -ret :
548
		       ip_set_eexist(ret, flags) ? 0 : ret;
549 550
	}

551
	port = ntohs(e.port);
552 553 554 555
	port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
	if (port > port_to)
		swap(port, port_to);

556
	if (retried)
557
		port = ntohs(h->next.port);
558
	for (; port <= port_to; port++) {
559 560
		e.port = htons(port);
		ret = adtfn(set, &e, &ext, &ext, flags);
561 562 563 564 565 566 567 568 569 570 571 572

		if (ret && !ip_set_eexist(ret, flags))
			return ret;
		else
			ret = 0;
	}
	return ret;
}

static struct ip_set_type hash_ipportnet_type __read_mostly = {
	.name		= "hash:ip,port,net",
	.protocol	= IPSET_PROTOCOL,
573 574
	.features	= IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2 |
			  IPSET_TYPE_NOMATCH,
575
	.dimension	= IPSET_DIM_THREE,
576
	.family		= NFPROTO_UNSPEC,
577 578
	.revision_min	= IPSET_TYPE_REV_MIN,
	.revision_max	= IPSET_TYPE_REV_MAX,
579 580 581 582 583 584 585
	.create		= hash_ipportnet_create,
	.create_policy	= {
		[IPSET_ATTR_HASHSIZE]	= { .type = NLA_U32 },
		[IPSET_ATTR_MAXELEM]	= { .type = NLA_U32 },
		[IPSET_ATTR_PROBES]	= { .type = NLA_U8 },
		[IPSET_ATTR_RESIZE]	= { .type = NLA_U8  },
		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
586
		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 },
587 588 589 590 591
	},
	.adt_policy	= {
		[IPSET_ATTR_IP]		= { .type = NLA_NESTED },
		[IPSET_ATTR_IP_TO]	= { .type = NLA_NESTED },
		[IPSET_ATTR_IP2]	= { .type = NLA_NESTED },
592
		[IPSET_ATTR_IP2_TO]	= { .type = NLA_NESTED },
593 594 595 596 597
		[IPSET_ATTR_PORT]	= { .type = NLA_U16 },
		[IPSET_ATTR_PORT_TO]	= { .type = NLA_U16 },
		[IPSET_ATTR_CIDR]	= { .type = NLA_U8 },
		[IPSET_ATTR_CIDR2]	= { .type = NLA_U8 },
		[IPSET_ATTR_PROTO]	= { .type = NLA_U8 },
598
		[IPSET_ATTR_CADT_FLAGS]	= { .type = NLA_U32 },
599 600
		[IPSET_ATTR_TIMEOUT]	= { .type = NLA_U32 },
		[IPSET_ATTR_LINENO]	= { .type = NLA_U32 },
601 602
		[IPSET_ATTR_BYTES]	= { .type = NLA_U64 },
		[IPSET_ATTR_PACKETS]	= { .type = NLA_U64 },
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
	},
	.me		= THIS_MODULE,
};

static int __init
hash_ipportnet_init(void)
{
	return ip_set_type_register(&hash_ipportnet_type);
}

static void __exit
hash_ipportnet_fini(void)
{
	ip_set_type_unregister(&hash_ipportnet_type);
}

module_init(hash_ipportnet_init);
module_exit(hash_ipportnet_fini);