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