1/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> 2 * 3 * This program is free software; you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License version 2 as 5 * published by the Free Software Foundation. 6 */ 7 8/* Kernel module implementing an IP set type: the hash:ip,port,net type */ 9 10#include <linux/jhash.h> 11#include <linux/module.h> 12#include <linux/ip.h> 13#include <linux/skbuff.h> 14#include <linux/errno.h> 15#include <linux/random.h> 16#include <net/ip.h> 17#include <net/ipv6.h> 18#include <net/netlink.h> 19#include <net/tcp.h> 20 21#include <linux/netfilter.h> 22#include <linux/netfilter/ipset/pfxlen.h> 23#include <linux/netfilter/ipset/ip_set.h> 24#include <linux/netfilter/ipset/ip_set_getport.h> 25#include <linux/netfilter/ipset/ip_set_hash.h> 26 27#define IPSET_TYPE_REV_MIN 0 28/* 1 SCTP and UDPLITE support added */ 29/* 2 Range as input support for IPv4 added */ 30/* 3 nomatch flag support added */ 31/* 4 Counters support added */ 32/* 5 Comments support added */ 33/* 6 Forceadd support added */ 34#define IPSET_TYPE_REV_MAX 7 /* skbinfo support added */ 35 36MODULE_LICENSE("GPL"); 37MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); 38IP_SET_MODULE_DESC("hash:ip,port,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); 39MODULE_ALIAS("ip_set_hash:ip,port,net"); 40 41/* Type specific function prefix */ 42#define HTYPE hash_ipportnet 43 44/* We squeeze the "nomatch" flag into cidr: we don't support cidr == 0 45 * However this way we have to store internally cidr - 1, 46 * dancing back and forth. 47 */ 48#define IP_SET_HASH_WITH_NETS_PACKED 49#define IP_SET_HASH_WITH_PROTO 50#define IP_SET_HASH_WITH_NETS 51 52/* IPv4 variant */ 53 54/* Member elements */ 55struct hash_ipportnet4_elem { 56 __be32 ip; 57 __be32 ip2; 58 __be16 port; 59 u8 cidr:7; 60 u8 nomatch:1; 61 u8 proto; 62}; 63 64/* Common functions */ 65 66static inline bool 67hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1, 68 const struct hash_ipportnet4_elem *ip2, 69 u32 *multi) 70{ 71 return ip1->ip == ip2->ip && 72 ip1->ip2 == ip2->ip2 && 73 ip1->cidr == ip2->cidr && 74 ip1->port == ip2->port && 75 ip1->proto == ip2->proto; 76} 77 78static inline int 79hash_ipportnet4_do_data_match(const struct hash_ipportnet4_elem *elem) 80{ 81 return elem->nomatch ? -ENOTEMPTY : 1; 82} 83 84static inline void 85hash_ipportnet4_data_set_flags(struct hash_ipportnet4_elem *elem, u32 flags) 86{ 87 elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH); 88} 89 90static inline void 91hash_ipportnet4_data_reset_flags(struct hash_ipportnet4_elem *elem, u8 *flags) 92{ 93 swap(*flags, elem->nomatch); 94} 95 96static inline void 97hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr) 98{ 99 elem->ip2 &= ip_set_netmask(cidr); 100 elem->cidr = cidr - 1; 101} 102 103static bool 104hash_ipportnet4_data_list(struct sk_buff *skb, 105 const struct hash_ipportnet4_elem *data) 106{ 107 u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; 108 109 if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) || 110 nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip2) || 111 nla_put_net16(skb, IPSET_ATTR_PORT, data->port) || 112 nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr + 1) || 113 nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) || 114 (flags && 115 nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)))) 116 goto nla_put_failure; 117 return 0; 118 119nla_put_failure: 120 return 1; 121} 122 123static inline void 124hash_ipportnet4_data_next(struct hash_ipportnet4_elem *next, 125 const struct hash_ipportnet4_elem *d) 126{ 127 next->ip = d->ip; 128 next->port = d->port; 129 next->ip2 = d->ip2; 130} 131 132#define MTYPE hash_ipportnet4 133#define PF 4 134#define HOST_MASK 32 135#include "ip_set_hash_gen.h" 136 137static int 138hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, 139 const struct xt_action_param *par, 140 enum ipset_adt adt, struct ip_set_adt_opt *opt) 141{ 142 const struct hash_ipportnet *h = set->data; 143 ipset_adtfn adtfn = set->variant->adt[adt]; 144 struct hash_ipportnet4_elem e = { 145 .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1, 146 }; 147 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 148 149 if (adt == IPSET_TEST) 150 e.cidr = HOST_MASK - 1; 151 152 if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC, 153 &e.port, &e.proto)) 154 return -EINVAL; 155 156 ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip); 157 ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2); 158 e.ip2 &= ip_set_netmask(e.cidr + 1); 159 160 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); 161} 162 163static int 164hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], 165 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) 166{ 167 const struct hash_ipportnet *h = set->data; 168 ipset_adtfn adtfn = set->variant->adt[adt]; 169 struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 }; 170 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 171 u32 ip = 0, ip_to = 0, p = 0, port, port_to; 172 u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2; 173 bool with_ports = false; 174 u8 cidr; 175 int ret; 176 177 if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || 178 !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || 179 !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || 180 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || 181 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || 182 !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || 183 !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || 184 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || 185 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || 186 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) 187 return -IPSET_ERR_PROTOCOL; 188 189 if (tb[IPSET_ATTR_LINENO]) 190 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); 191 192 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) || 193 ip_set_get_extensions(set, tb, &ext); 194 if (ret) 195 return ret; 196 197 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from); 198 if (ret) 199 return ret; 200 201 if (tb[IPSET_ATTR_CIDR2]) { 202 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); 203 if (!cidr || cidr > HOST_MASK) 204 return -IPSET_ERR_INVALID_CIDR; 205 e.cidr = cidr - 1; 206 } 207 208 if (tb[IPSET_ATTR_PORT]) 209 e.port = nla_get_be16(tb[IPSET_ATTR_PORT]); 210 else 211 return -IPSET_ERR_PROTOCOL; 212 213 if (tb[IPSET_ATTR_PROTO]) { 214 e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); 215 with_ports = ip_set_proto_with_ports(e.proto); 216 217 if (e.proto == 0) 218 return -IPSET_ERR_INVALID_PROTO; 219 } else 220 return -IPSET_ERR_MISSING_PROTO; 221 222 if (!(with_ports || e.proto == IPPROTO_ICMP)) 223 e.port = 0; 224 225 if (tb[IPSET_ATTR_CADT_FLAGS]) { 226 u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); 227 if (cadt_flags & IPSET_FLAG_NOMATCH) 228 flags |= (IPSET_FLAG_NOMATCH << 16); 229 } 230 231 with_ports = with_ports && tb[IPSET_ATTR_PORT_TO]; 232 if (adt == IPSET_TEST || 233 !(tb[IPSET_ATTR_CIDR] || tb[IPSET_ATTR_IP_TO] || with_ports || 234 tb[IPSET_ATTR_IP2_TO])) { 235 e.ip = htonl(ip); 236 e.ip2 = htonl(ip2_from & ip_set_hostmask(e.cidr + 1)); 237 ret = adtfn(set, &e, &ext, &ext, flags); 238 return ip_set_enomatch(ret, flags, adt, set) ? -ret : 239 ip_set_eexist(ret, flags) ? 0 : ret; 240 } 241 242 ip_to = ip; 243 if (tb[IPSET_ATTR_IP_TO]) { 244 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to); 245 if (ret) 246 return ret; 247 if (ip > ip_to) 248 swap(ip, ip_to); 249 } else if (tb[IPSET_ATTR_CIDR]) { 250 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); 251 252 if (!cidr || cidr > 32) 253 return -IPSET_ERR_INVALID_CIDR; 254 ip_set_mask_from_to(ip, ip_to, cidr); 255 } 256 257 port_to = port = ntohs(e.port); 258 if (tb[IPSET_ATTR_PORT_TO]) { 259 port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); 260 if (port > port_to) 261 swap(port, port_to); 262 } 263 264 ip2_to = ip2_from; 265 if (tb[IPSET_ATTR_IP2_TO]) { 266 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to); 267 if (ret) 268 return ret; 269 if (ip2_from > ip2_to) 270 swap(ip2_from, ip2_to); 271 if (ip2_from + UINT_MAX == ip2_to) 272 return -IPSET_ERR_HASH_RANGE; 273 } else 274 ip_set_mask_from_to(ip2_from, ip2_to, e.cidr + 1); 275 276 if (retried) 277 ip = ntohl(h->next.ip); 278 for (; !before(ip_to, ip); ip++) { 279 e.ip = htonl(ip); 280 p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port) 281 : port; 282 for (; p <= port_to; p++) { 283 e.port = htons(p); 284 ip2 = retried && 285 ip == ntohl(h->next.ip) && 286 p == ntohs(h->next.port) 287 ? ntohl(h->next.ip2) : ip2_from; 288 while (!after(ip2, ip2_to)) { 289 e.ip2 = htonl(ip2); 290 ip2_last = ip_set_range_to_cidr(ip2, ip2_to, 291 &cidr); 292 e.cidr = cidr - 1; 293 ret = adtfn(set, &e, &ext, &ext, flags); 294 295 if (ret && !ip_set_eexist(ret, flags)) 296 return ret; 297 else 298 ret = 0; 299 ip2 = ip2_last + 1; 300 } 301 } 302 } 303 return ret; 304} 305 306/* IPv6 variant */ 307 308struct hash_ipportnet6_elem { 309 union nf_inet_addr ip; 310 union nf_inet_addr ip2; 311 __be16 port; 312 u8 cidr:7; 313 u8 nomatch:1; 314 u8 proto; 315}; 316 317/* Common functions */ 318 319static inline bool 320hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1, 321 const struct hash_ipportnet6_elem *ip2, 322 u32 *multi) 323{ 324 return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) && 325 ipv6_addr_equal(&ip1->ip2.in6, &ip2->ip2.in6) && 326 ip1->cidr == ip2->cidr && 327 ip1->port == ip2->port && 328 ip1->proto == ip2->proto; 329} 330 331static inline int 332hash_ipportnet6_do_data_match(const struct hash_ipportnet6_elem *elem) 333{ 334 return elem->nomatch ? -ENOTEMPTY : 1; 335} 336 337static inline void 338hash_ipportnet6_data_set_flags(struct hash_ipportnet6_elem *elem, u32 flags) 339{ 340 elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH); 341} 342 343static inline void 344hash_ipportnet6_data_reset_flags(struct hash_ipportnet6_elem *elem, u8 *flags) 345{ 346 swap(*flags, elem->nomatch); 347} 348 349static inline void 350hash_ipportnet6_data_netmask(struct hash_ipportnet6_elem *elem, u8 cidr) 351{ 352 ip6_netmask(&elem->ip2, cidr); 353 elem->cidr = cidr - 1; 354} 355 356static bool 357hash_ipportnet6_data_list(struct sk_buff *skb, 358 const struct hash_ipportnet6_elem *data) 359{ 360 u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0; 361 362 if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) || 363 nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip2.in6) || 364 nla_put_net16(skb, IPSET_ATTR_PORT, data->port) || 365 nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr + 1) || 366 nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) || 367 (flags && 368 nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags)))) 369 goto nla_put_failure; 370 return 0; 371 372nla_put_failure: 373 return 1; 374} 375 376static inline void 377hash_ipportnet6_data_next(struct hash_ipportnet4_elem *next, 378 const struct hash_ipportnet6_elem *d) 379{ 380 next->port = d->port; 381} 382 383#undef MTYPE 384#undef PF 385#undef HOST_MASK 386 387#define MTYPE hash_ipportnet6 388#define PF 6 389#define HOST_MASK 128 390#define IP_SET_EMIT_CREATE 391#include "ip_set_hash_gen.h" 392 393static int 394hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, 395 const struct xt_action_param *par, 396 enum ipset_adt adt, struct ip_set_adt_opt *opt) 397{ 398 const struct hash_ipportnet *h = set->data; 399 ipset_adtfn adtfn = set->variant->adt[adt]; 400 struct hash_ipportnet6_elem e = { 401 .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1, 402 }; 403 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); 404 405 if (adt == IPSET_TEST) 406 e.cidr = HOST_MASK - 1; 407 408 if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC, 409 &e.port, &e.proto)) 410 return -EINVAL; 411 412 ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6); 413 ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip2.in6); 414 ip6_netmask(&e.ip2, e.cidr + 1); 415 416 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); 417} 418 419static int 420hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], 421 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) 422{ 423 const struct hash_ipportnet *h = set->data; 424 ipset_adtfn adtfn = set->variant->adt[adt]; 425 struct hash_ipportnet6_elem e = { .cidr = HOST_MASK - 1 }; 426 struct ip_set_ext ext = IP_SET_INIT_UEXT(set); 427 u32 port, port_to; 428 bool with_ports = false; 429 u8 cidr; 430 int ret; 431 432 if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || 433 !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || 434 !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || 435 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || 436 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || 437 !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || 438 !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || 439 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || 440 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || 441 !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE) || 442 tb[IPSET_ATTR_IP_TO] || 443 tb[IPSET_ATTR_CIDR])) 444 return -IPSET_ERR_PROTOCOL; 445 if (unlikely(tb[IPSET_ATTR_IP_TO])) 446 return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; 447 448 if (tb[IPSET_ATTR_LINENO]) 449 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); 450 451 ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) || 452 ip_set_get_extensions(set, tb, &ext); 453 if (ret) 454 return ret; 455 456 ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip2); 457 if (ret) 458 return ret; 459 460 if (tb[IPSET_ATTR_CIDR2]) { 461 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); 462 if (!cidr || cidr > HOST_MASK) 463 return -IPSET_ERR_INVALID_CIDR; 464 e.cidr = cidr - 1; 465 } 466 467 ip6_netmask(&e.ip2, e.cidr + 1); 468 469 if (tb[IPSET_ATTR_PORT]) 470 e.port = nla_get_be16(tb[IPSET_ATTR_PORT]); 471 else 472 return -IPSET_ERR_PROTOCOL; 473 474 if (tb[IPSET_ATTR_PROTO]) { 475 e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); 476 with_ports = ip_set_proto_with_ports(e.proto); 477 478 if (e.proto == 0) 479 return -IPSET_ERR_INVALID_PROTO; 480 } else 481 return -IPSET_ERR_MISSING_PROTO; 482 483 if (!(with_ports || e.proto == IPPROTO_ICMPV6)) 484 e.port = 0; 485 486 if (tb[IPSET_ATTR_CADT_FLAGS]) { 487 u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); 488 if (cadt_flags & IPSET_FLAG_NOMATCH) 489 flags |= (IPSET_FLAG_NOMATCH << 16); 490 } 491 492 if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) { 493 ret = adtfn(set, &e, &ext, &ext, flags); 494 return ip_set_enomatch(ret, flags, adt, set) ? -ret : 495 ip_set_eexist(ret, flags) ? 0 : ret; 496 } 497 498 port = ntohs(e.port); 499 port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]); 500 if (port > port_to) 501 swap(port, port_to); 502 503 if (retried) 504 port = ntohs(h->next.port); 505 for (; port <= port_to; port++) { 506 e.port = htons(port); 507 ret = adtfn(set, &e, &ext, &ext, flags); 508 509 if (ret && !ip_set_eexist(ret, flags)) 510 return ret; 511 else 512 ret = 0; 513 } 514 return ret; 515} 516 517static struct ip_set_type hash_ipportnet_type __read_mostly = { 518 .name = "hash:ip,port,net", 519 .protocol = IPSET_PROTOCOL, 520 .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2 | 521 IPSET_TYPE_NOMATCH, 522 .dimension = IPSET_DIM_THREE, 523 .family = NFPROTO_UNSPEC, 524 .revision_min = IPSET_TYPE_REV_MIN, 525 .revision_max = IPSET_TYPE_REV_MAX, 526 .create = hash_ipportnet_create, 527 .create_policy = { 528 [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, 529 [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, 530 [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, 531 [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, 532 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, 533 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, 534 }, 535 .adt_policy = { 536 [IPSET_ATTR_IP] = { .type = NLA_NESTED }, 537 [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, 538 [IPSET_ATTR_IP2] = { .type = NLA_NESTED }, 539 [IPSET_ATTR_IP2_TO] = { .type = NLA_NESTED }, 540 [IPSET_ATTR_PORT] = { .type = NLA_U16 }, 541 [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, 542 [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, 543 [IPSET_ATTR_CIDR2] = { .type = NLA_U8 }, 544 [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, 545 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, 546 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, 547 [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, 548 [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, 549 [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, 550 [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, 551 [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, 552 [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, 553 [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, 554 }, 555 .me = THIS_MODULE, 556}; 557 558static int __init 559hash_ipportnet_init(void) 560{ 561 return ip_set_type_register(&hash_ipportnet_type); 562} 563 564static void __exit 565hash_ipportnet_fini(void) 566{ 567 ip_set_type_unregister(&hash_ipportnet_type); 568} 569 570module_init(hash_ipportnet_init); 571module_exit(hash_ipportnet_fini); 572