1 /*- 2 * Copyright (c) 2008 Paolo Pisati 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/eventhandler.h> 33 #include <sys/malloc.h> 34 #include <sys/mbuf.h> 35 #include <sys/kernel.h> 36 #include <sys/lock.h> 37 #include <sys/module.h> 38 #include <sys/rwlock.h> 39 40 #define IPFW_INTERNAL /* Access to protected data structures in ip_fw.h. */ 41 42 #include <netinet/libalias/alias.h> 43 #include <netinet/libalias/alias_local.h> 44 45 #include <net/if.h> 46 #include <net/if_var.h> 47 #include <netinet/in.h> 48 #include <netinet/ip.h> 49 #include <netinet/ip_var.h> 50 #include <netinet/ip_fw.h> 51 #include <netinet/tcp.h> 52 #include <netinet/udp.h> 53 54 #include <netpfil/ipfw/ip_fw_private.h> 55 56 #include <machine/in_cksum.h> /* XXX for in_cksum */ 57 58 static eventhandler_tag ifaddr_event_tag; 59 60 static void 61 ifaddr_change(void *arg __unused, struct ifnet *ifp) 62 { 63 struct cfg_nat *ptr; 64 struct ifaddr *ifa; 65 struct ip_fw_chain *chain; 66 67 KASSERT(curvnet == ifp->if_vnet, 68 ("curvnet(%p) differs from iface vnet(%p)", curvnet, ifp->if_vnet)); 69 chain = &V_layer3_chain; 70 IPFW_WLOCK(chain); 71 /* Check every nat entry... */ 72 LIST_FOREACH(ptr, &chain->nat, _next) { 73 /* ...using nic 'ifp->if_xname' as dynamic alias address. */ 74 if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) != 0) 75 continue; 76 if_addr_rlock(ifp); 77 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 78 if (ifa->ifa_addr == NULL) 79 continue; 80 if (ifa->ifa_addr->sa_family != AF_INET) 81 continue; 82 ptr->ip = ((struct sockaddr_in *) 83 (ifa->ifa_addr))->sin_addr; 84 LibAliasSetAddress(ptr->lib, ptr->ip); 85 } 86 if_addr_runlock(ifp); 87 } 88 IPFW_WUNLOCK(chain); 89 } 90 91 /* 92 * delete the pointers for nat entry ix, or all of them if ix < 0 93 */ 94 static void 95 flush_nat_ptrs(struct ip_fw_chain *chain, const int ix) 96 { 97 int i; 98 ipfw_insn_nat *cmd; 99 100 IPFW_WLOCK_ASSERT(chain); 101 for (i = 0; i < chain->n_rules; i++) { 102 cmd = (ipfw_insn_nat *)ACTION_PTR(chain->map[i]); 103 /* XXX skip log and the like ? */ 104 if (cmd->o.opcode == O_NAT && cmd->nat != NULL && 105 (ix < 0 || cmd->nat->id == ix)) 106 cmd->nat = NULL; 107 } 108 } 109 110 static void 111 del_redir_spool_cfg(struct cfg_nat *n, struct redir_chain *head) 112 { 113 struct cfg_redir *r, *tmp_r; 114 struct cfg_spool *s, *tmp_s; 115 int i, num; 116 117 LIST_FOREACH_SAFE(r, head, _next, tmp_r) { 118 num = 1; /* Number of alias_link to delete. */ 119 switch (r->mode) { 120 case REDIR_PORT: 121 num = r->pport_cnt; 122 /* FALLTHROUGH */ 123 case REDIR_ADDR: 124 case REDIR_PROTO: 125 /* Delete all libalias redirect entry. */ 126 for (i = 0; i < num; i++) 127 LibAliasRedirectDelete(n->lib, r->alink[i]); 128 /* Del spool cfg if any. */ 129 LIST_FOREACH_SAFE(s, &r->spool_chain, _next, tmp_s) { 130 LIST_REMOVE(s, _next); 131 free(s, M_IPFW); 132 } 133 free(r->alink, M_IPFW); 134 LIST_REMOVE(r, _next); 135 free(r, M_IPFW); 136 break; 137 default: 138 printf("unknown redirect mode: %u\n", r->mode); 139 /* XXX - panic?!?!? */ 140 break; 141 } 142 } 143 } 144 145 static void 146 add_redir_spool_cfg(char *buf, struct cfg_nat *ptr) 147 { 148 struct cfg_redir *r, *ser_r; 149 struct cfg_spool *s, *ser_s; 150 int cnt, off, i; 151 152 for (cnt = 0, off = 0; cnt < ptr->redir_cnt; cnt++) { 153 ser_r = (struct cfg_redir *)&buf[off]; 154 r = malloc(SOF_REDIR, M_IPFW, M_WAITOK | M_ZERO); 155 memcpy(r, ser_r, SOF_REDIR); 156 LIST_INIT(&r->spool_chain); 157 off += SOF_REDIR; 158 r->alink = malloc(sizeof(struct alias_link *) * r->pport_cnt, 159 M_IPFW, M_WAITOK | M_ZERO); 160 switch (r->mode) { 161 case REDIR_ADDR: 162 r->alink[0] = LibAliasRedirectAddr(ptr->lib, r->laddr, 163 r->paddr); 164 break; 165 case REDIR_PORT: 166 for (i = 0 ; i < r->pport_cnt; i++) { 167 /* If remotePort is all ports, set it to 0. */ 168 u_short remotePortCopy = r->rport + i; 169 if (r->rport_cnt == 1 && r->rport == 0) 170 remotePortCopy = 0; 171 r->alink[i] = LibAliasRedirectPort(ptr->lib, 172 r->laddr, htons(r->lport + i), r->raddr, 173 htons(remotePortCopy), r->paddr, 174 htons(r->pport + i), r->proto); 175 if (r->alink[i] == NULL) { 176 r->alink[0] = NULL; 177 break; 178 } 179 } 180 break; 181 case REDIR_PROTO: 182 r->alink[0] = LibAliasRedirectProto(ptr->lib ,r->laddr, 183 r->raddr, r->paddr, r->proto); 184 break; 185 default: 186 printf("unknown redirect mode: %u\n", r->mode); 187 break; 188 } 189 /* XXX perhaps return an error instead of panic ? */ 190 if (r->alink[0] == NULL) 191 panic("LibAliasRedirect* returned NULL"); 192 /* LSNAT handling. */ 193 for (i = 0; i < r->spool_cnt; i++) { 194 ser_s = (struct cfg_spool *)&buf[off]; 195 s = malloc(SOF_REDIR, M_IPFW, M_WAITOK | M_ZERO); 196 memcpy(s, ser_s, SOF_SPOOL); 197 LibAliasAddServer(ptr->lib, r->alink[0], 198 s->addr, htons(s->port)); 199 off += SOF_SPOOL; 200 /* Hook spool entry. */ 201 LIST_INSERT_HEAD(&r->spool_chain, s, _next); 202 } 203 /* And finally hook this redir entry. */ 204 LIST_INSERT_HEAD(&ptr->redir_chain, r, _next); 205 } 206 } 207 208 /* 209 * ipfw_nat - perform mbuf header translation. 210 * 211 * Note V_layer3_chain has to be locked while calling ipfw_nat() in 212 * 'global' operation mode (t == NULL). 213 * 214 */ 215 static int 216 ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m) 217 { 218 struct mbuf *mcl; 219 struct ip *ip; 220 /* XXX - libalias duct tape */ 221 int ldt, retval, found; 222 struct ip_fw_chain *chain; 223 char *c; 224 225 ldt = 0; 226 retval = 0; 227 mcl = m_megapullup(m, m->m_pkthdr.len); 228 if (mcl == NULL) { 229 args->m = NULL; 230 return (IP_FW_DENY); 231 } 232 ip = mtod(mcl, struct ip *); 233 234 /* 235 * XXX - Libalias checksum offload 'duct tape': 236 * 237 * locally generated packets have only pseudo-header checksum 238 * calculated and libalias will break it[1], so mark them for 239 * later fix. Moreover there are cases when libalias modifies 240 * tcp packet data[2], mark them for later fix too. 241 * 242 * [1] libalias was never meant to run in kernel, so it does 243 * not have any knowledge about checksum offloading, and 244 * expects a packet with a full internet checksum. 245 * Unfortunately, packets generated locally will have just the 246 * pseudo header calculated, and when libalias tries to adjust 247 * the checksum it will actually compute a wrong value. 248 * 249 * [2] when libalias modifies tcp's data content, full TCP 250 * checksum has to be recomputed: the problem is that 251 * libalias does not have any idea about checksum offloading. 252 * To work around this, we do not do checksumming in LibAlias, 253 * but only mark the packets in th_x2 field. If we receive a 254 * marked packet, we calculate correct checksum for it 255 * aware of offloading. Why such a terrible hack instead of 256 * recalculating checksum for each packet? 257 * Because the previous checksum was not checked! 258 * Recalculating checksums for EVERY packet will hide ALL 259 * transmission errors. Yes, marked packets still suffer from 260 * this problem. But, sigh, natd(8) has this problem, too. 261 * 262 * TODO: -make libalias mbuf aware (so 263 * it can handle delayed checksum and tso) 264 */ 265 266 if (mcl->m_pkthdr.rcvif == NULL && 267 mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA) 268 ldt = 1; 269 270 c = mtod(mcl, char *); 271 272 /* Check if this is 'global' instance */ 273 if (t == NULL) { 274 if (args->oif == NULL) { 275 /* Wrong direction, skip processing */ 276 args->m = mcl; 277 return (IP_FW_NAT); 278 } 279 280 found = 0; 281 chain = &V_layer3_chain; 282 IPFW_RLOCK_ASSERT(chain); 283 /* Check every nat entry... */ 284 LIST_FOREACH(t, &chain->nat, _next) { 285 if ((t->mode & PKT_ALIAS_SKIP_GLOBAL) != 0) 286 continue; 287 retval = LibAliasOutTry(t->lib, c, 288 mcl->m_len + M_TRAILINGSPACE(mcl), 0); 289 if (retval == PKT_ALIAS_OK) { 290 /* Nat instance recognises state */ 291 found = 1; 292 break; 293 } 294 } 295 if (found != 1) { 296 /* No instance found, return ignore */ 297 args->m = mcl; 298 return (IP_FW_NAT); 299 } 300 } else { 301 if (args->oif == NULL) 302 retval = LibAliasIn(t->lib, c, 303 mcl->m_len + M_TRAILINGSPACE(mcl)); 304 else 305 retval = LibAliasOut(t->lib, c, 306 mcl->m_len + M_TRAILINGSPACE(mcl)); 307 } 308 309 /* 310 * We drop packet when: 311 * 1. libalias returns PKT_ALIAS_ERROR; 312 * 2. For incoming packets: 313 * a) for unresolved fragments; 314 * b) libalias returns PKT_ALIAS_IGNORED and 315 * PKT_ALIAS_DENY_INCOMING flag is set. 316 */ 317 if (retval == PKT_ALIAS_ERROR || 318 (args->oif == NULL && (retval == PKT_ALIAS_UNRESOLVED_FRAGMENT || 319 (retval == PKT_ALIAS_IGNORED && 320 (t->mode & PKT_ALIAS_DENY_INCOMING) != 0)))) { 321 /* XXX - should i add some logging? */ 322 m_free(mcl); 323 args->m = NULL; 324 return (IP_FW_DENY); 325 } 326 327 if (retval == PKT_ALIAS_RESPOND) 328 mcl->m_flags |= M_SKIP_FIREWALL; 329 mcl->m_pkthdr.len = mcl->m_len = ntohs(ip->ip_len); 330 331 /* 332 * XXX - libalias checksum offload 333 * 'duct tape' (see above) 334 */ 335 336 if ((ip->ip_off & htons(IP_OFFMASK)) == 0 && 337 ip->ip_p == IPPROTO_TCP) { 338 struct tcphdr *th; 339 340 th = (struct tcphdr *)(ip + 1); 341 if (th->th_x2) 342 ldt = 1; 343 } 344 345 if (ldt) { 346 struct tcphdr *th; 347 struct udphdr *uh; 348 uint16_t ip_len, cksum; 349 350 ip_len = ntohs(ip->ip_len); 351 cksum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, 352 htons(ip->ip_p + ip_len - (ip->ip_hl << 2))); 353 354 switch (ip->ip_p) { 355 case IPPROTO_TCP: 356 th = (struct tcphdr *)(ip + 1); 357 /* 358 * Maybe it was set in 359 * libalias... 360 */ 361 th->th_x2 = 0; 362 th->th_sum = cksum; 363 mcl->m_pkthdr.csum_data = 364 offsetof(struct tcphdr, th_sum); 365 break; 366 case IPPROTO_UDP: 367 uh = (struct udphdr *)(ip + 1); 368 uh->uh_sum = cksum; 369 mcl->m_pkthdr.csum_data = 370 offsetof(struct udphdr, uh_sum); 371 break; 372 } 373 /* No hw checksum offloading: do it ourselves */ 374 if ((mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA) == 0) { 375 in_delayed_cksum(mcl); 376 mcl->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 377 } 378 } 379 args->m = mcl; 380 return (IP_FW_NAT); 381 } 382 383 static struct cfg_nat * 384 lookup_nat(struct nat_list *l, int nat_id) 385 { 386 struct cfg_nat *res; 387 388 LIST_FOREACH(res, l, _next) { 389 if (res->id == nat_id) 390 break; 391 } 392 return res; 393 } 394 395 static int 396 ipfw_nat_cfg(struct sockopt *sopt) 397 { 398 struct cfg_nat *cfg, *ptr; 399 char *buf; 400 struct ip_fw_chain *chain = &V_layer3_chain; 401 size_t len; 402 int gencnt, error = 0; 403 404 len = sopt->sopt_valsize; 405 buf = malloc(len, M_TEMP, M_WAITOK | M_ZERO); 406 if ((error = sooptcopyin(sopt, buf, len, sizeof(struct cfg_nat))) != 0) 407 goto out; 408 409 cfg = (struct cfg_nat *)buf; 410 if (cfg->id < 0) { 411 error = EINVAL; 412 goto out; 413 } 414 415 /* 416 * Find/create nat rule. 417 */ 418 IPFW_WLOCK(chain); 419 gencnt = chain->gencnt; 420 ptr = lookup_nat(&chain->nat, cfg->id); 421 if (ptr == NULL) { 422 IPFW_WUNLOCK(chain); 423 /* New rule: allocate and init new instance. */ 424 ptr = malloc(sizeof(struct cfg_nat), M_IPFW, M_WAITOK | M_ZERO); 425 ptr->lib = LibAliasInit(NULL); 426 LIST_INIT(&ptr->redir_chain); 427 } else { 428 /* Entry already present: temporarily unhook it. */ 429 LIST_REMOVE(ptr, _next); 430 flush_nat_ptrs(chain, cfg->id); 431 IPFW_WUNLOCK(chain); 432 } 433 434 /* 435 * Basic nat configuration. 436 */ 437 ptr->id = cfg->id; 438 /* 439 * XXX - what if this rule doesn't nat any ip and just 440 * redirect? 441 * do we set aliasaddress to 0.0.0.0? 442 */ 443 ptr->ip = cfg->ip; 444 ptr->redir_cnt = cfg->redir_cnt; 445 ptr->mode = cfg->mode; 446 LibAliasSetMode(ptr->lib, cfg->mode, cfg->mode); 447 LibAliasSetAddress(ptr->lib, ptr->ip); 448 memcpy(ptr->if_name, cfg->if_name, IF_NAMESIZE); 449 450 /* 451 * Redir and LSNAT configuration. 452 */ 453 /* Delete old cfgs. */ 454 del_redir_spool_cfg(ptr, &ptr->redir_chain); 455 /* Add new entries. */ 456 add_redir_spool_cfg(&buf[(sizeof(struct cfg_nat))], ptr); 457 458 IPFW_WLOCK(chain); 459 /* Extra check to avoid race with another ipfw_nat_cfg() */ 460 if (gencnt != chain->gencnt && 461 ((cfg = lookup_nat(&chain->nat, ptr->id)) != NULL)) 462 LIST_REMOVE(cfg, _next); 463 LIST_INSERT_HEAD(&chain->nat, ptr, _next); 464 chain->gencnt++; 465 IPFW_WUNLOCK(chain); 466 467 out: 468 free(buf, M_TEMP); 469 return (error); 470 } 471 472 static int 473 ipfw_nat_del(struct sockopt *sopt) 474 { 475 struct cfg_nat *ptr; 476 struct ip_fw_chain *chain = &V_layer3_chain; 477 int i; 478 479 sooptcopyin(sopt, &i, sizeof i, sizeof i); 480 /* XXX validate i */ 481 IPFW_WLOCK(chain); 482 ptr = lookup_nat(&chain->nat, i); 483 if (ptr == NULL) { 484 IPFW_WUNLOCK(chain); 485 return (EINVAL); 486 } 487 LIST_REMOVE(ptr, _next); 488 flush_nat_ptrs(chain, i); 489 IPFW_WUNLOCK(chain); 490 del_redir_spool_cfg(ptr, &ptr->redir_chain); 491 LibAliasUninit(ptr->lib); 492 free(ptr, M_IPFW); 493 return (0); 494 } 495 496 static int 497 ipfw_nat_get_cfg(struct sockopt *sopt) 498 { 499 struct ip_fw_chain *chain = &V_layer3_chain; 500 struct cfg_nat *n; 501 struct cfg_redir *r; 502 struct cfg_spool *s; 503 char *data; 504 int gencnt, nat_cnt, len, error; 505 506 nat_cnt = 0; 507 len = sizeof(nat_cnt); 508 509 IPFW_RLOCK(chain); 510 retry: 511 gencnt = chain->gencnt; 512 /* Estimate memory amount */ 513 LIST_FOREACH(n, &chain->nat, _next) { 514 nat_cnt++; 515 len += sizeof(struct cfg_nat); 516 LIST_FOREACH(r, &n->redir_chain, _next) { 517 len += sizeof(struct cfg_redir); 518 LIST_FOREACH(s, &r->spool_chain, _next) 519 len += sizeof(struct cfg_spool); 520 } 521 } 522 IPFW_RUNLOCK(chain); 523 524 data = malloc(len, M_TEMP, M_WAITOK | M_ZERO); 525 bcopy(&nat_cnt, data, sizeof(nat_cnt)); 526 527 nat_cnt = 0; 528 len = sizeof(nat_cnt); 529 530 IPFW_RLOCK(chain); 531 if (gencnt != chain->gencnt) { 532 free(data, M_TEMP); 533 goto retry; 534 } 535 /* Serialize all the data. */ 536 LIST_FOREACH(n, &chain->nat, _next) { 537 bcopy(n, &data[len], sizeof(struct cfg_nat)); 538 len += sizeof(struct cfg_nat); 539 LIST_FOREACH(r, &n->redir_chain, _next) { 540 bcopy(r, &data[len], sizeof(struct cfg_redir)); 541 len += sizeof(struct cfg_redir); 542 LIST_FOREACH(s, &r->spool_chain, _next) { 543 bcopy(s, &data[len], sizeof(struct cfg_spool)); 544 len += sizeof(struct cfg_spool); 545 } 546 } 547 } 548 IPFW_RUNLOCK(chain); 549 550 error = sooptcopyout(sopt, data, len); 551 free(data, M_TEMP); 552 553 return (error); 554 } 555 556 static int 557 ipfw_nat_get_log(struct sockopt *sopt) 558 { 559 uint8_t *data; 560 struct cfg_nat *ptr; 561 int i, size; 562 struct ip_fw_chain *chain; 563 564 chain = &V_layer3_chain; 565 566 IPFW_RLOCK(chain); 567 /* one pass to count, one to copy the data */ 568 i = 0; 569 LIST_FOREACH(ptr, &chain->nat, _next) { 570 if (ptr->lib->logDesc == NULL) 571 continue; 572 i++; 573 } 574 size = i * (LIBALIAS_BUF_SIZE + sizeof(int)); 575 data = malloc(size, M_IPFW, M_NOWAIT | M_ZERO); 576 if (data == NULL) { 577 IPFW_RUNLOCK(chain); 578 return (ENOSPC); 579 } 580 i = 0; 581 LIST_FOREACH(ptr, &chain->nat, _next) { 582 if (ptr->lib->logDesc == NULL) 583 continue; 584 bcopy(&ptr->id, &data[i], sizeof(int)); 585 i += sizeof(int); 586 bcopy(ptr->lib->logDesc, &data[i], LIBALIAS_BUF_SIZE); 587 i += LIBALIAS_BUF_SIZE; 588 } 589 IPFW_RUNLOCK(chain); 590 sooptcopyout(sopt, data, size); 591 free(data, M_IPFW); 592 return(0); 593 } 594 595 static int 596 vnet_ipfw_nat_init(const void *arg __unused) 597 { 598 599 V_ipfw_nat_ready = 1; 600 return (0); 601 } 602 603 static int 604 vnet_ipfw_nat_uninit(const void *arg __unused) 605 { 606 struct cfg_nat *ptr, *ptr_temp; 607 struct ip_fw_chain *chain; 608 609 chain = &V_layer3_chain; 610 IPFW_WLOCK(chain); 611 LIST_FOREACH_SAFE(ptr, &chain->nat, _next, ptr_temp) { 612 LIST_REMOVE(ptr, _next); 613 del_redir_spool_cfg(ptr, &ptr->redir_chain); 614 LibAliasUninit(ptr->lib); 615 free(ptr, M_IPFW); 616 } 617 flush_nat_ptrs(chain, -1 /* flush all */); 618 V_ipfw_nat_ready = 0; 619 IPFW_WUNLOCK(chain); 620 return (0); 621 } 622 623 static void 624 ipfw_nat_init(void) 625 { 626 627 /* init ipfw hooks */ 628 ipfw_nat_ptr = ipfw_nat; 629 lookup_nat_ptr = lookup_nat; 630 ipfw_nat_cfg_ptr = ipfw_nat_cfg; 631 ipfw_nat_del_ptr = ipfw_nat_del; 632 ipfw_nat_get_cfg_ptr = ipfw_nat_get_cfg; 633 ipfw_nat_get_log_ptr = ipfw_nat_get_log; 634 635 ifaddr_event_tag = EVENTHANDLER_REGISTER(ifaddr_event, ifaddr_change, 636 NULL, EVENTHANDLER_PRI_ANY); 637 } 638 639 static void 640 ipfw_nat_destroy(void) 641 { 642 643 EVENTHANDLER_DEREGISTER(ifaddr_event, ifaddr_event_tag); 644 /* deregister ipfw_nat */ 645 ipfw_nat_ptr = NULL; 646 lookup_nat_ptr = NULL; 647 ipfw_nat_cfg_ptr = NULL; 648 ipfw_nat_del_ptr = NULL; 649 ipfw_nat_get_cfg_ptr = NULL; 650 ipfw_nat_get_log_ptr = NULL; 651 } 652 653 static int 654 ipfw_nat_modevent(module_t mod, int type, void *unused) 655 { 656 int err = 0; 657 658 switch (type) { 659 case MOD_LOAD: 660 break; 661 662 case MOD_UNLOAD: 663 break; 664 665 default: 666 return EOPNOTSUPP; 667 break; 668 } 669 return err; 670 } 671 672 static moduledata_t ipfw_nat_mod = { 673 "ipfw_nat", 674 ipfw_nat_modevent, 675 0 676 }; 677 678 /* Define startup order. */ 679 #define IPFW_NAT_SI_SUB_FIREWALL (SI_SUB_PROTO_IFATTACHDOMAIN + 1) 680 #define IPFW_NAT_MODEVENT_ORDER (SI_ORDER_ANY - 255) 681 #define IPFW_NAT_MODULE_ORDER (IPFW_NAT_MODEVENT_ORDER + 1) 682 #define IPFW_NAT_VNET_ORDER (IPFW_NAT_MODEVENT_ORDER + 2) 683 684 DECLARE_MODULE(ipfw_nat, ipfw_nat_mod, IPFW_NAT_SI_SUB_FIREWALL, SI_ORDER_ANY); 685 MODULE_DEPEND(ipfw_nat, libalias, 1, 1, 1); 686 MODULE_DEPEND(ipfw_nat, ipfw, 2, 2, 2); 687 MODULE_VERSION(ipfw_nat, 1); 688 689 SYSINIT(ipfw_nat_init, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_MODULE_ORDER, 690 ipfw_nat_init, NULL); 691 VNET_SYSINIT(vnet_ipfw_nat_init, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_VNET_ORDER, 692 vnet_ipfw_nat_init, NULL); 693 694 SYSUNINIT(ipfw_nat_destroy, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_MODULE_ORDER, 695 ipfw_nat_destroy, NULL); 696 VNET_SYSUNINIT(vnet_ipfw_nat_uninit, IPFW_NAT_SI_SUB_FIREWALL, 697 IPFW_NAT_VNET_ORDER, vnet_ipfw_nat_uninit, NULL); 698 699 /* end of file */ 700