The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netpfil/ipfw/ip_fw_nat.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2008 Paolo Pisati
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/eventhandler.h>
   35 #include <sys/malloc.h>
   36 #include <sys/mbuf.h>
   37 #include <sys/kernel.h>
   38 #include <sys/lock.h>
   39 #include <sys/module.h>
   40 #include <sys/rwlock.h>
   41 #include <sys/rmlock.h>
   42 
   43 #include <netinet/libalias/alias.h>
   44 #include <netinet/libalias/alias_local.h>
   45 
   46 #include <net/if.h>
   47 #include <net/if_var.h>
   48 #include <netinet/in.h>
   49 #include <netinet/ip.h>
   50 #include <netinet/ip_var.h>
   51 #include <netinet/ip_fw.h>
   52 #include <netinet/tcp.h>
   53 #include <netinet/udp.h>
   54 
   55 #include <netpfil/ipfw/ip_fw_private.h>
   56 
   57 #include <machine/in_cksum.h>   /* XXX for in_cksum */
   58 
   59 struct cfg_spool {
   60         LIST_ENTRY(cfg_spool)   _next;          /* chain of spool instances */
   61         struct in_addr          addr;
   62         uint16_t                port;
   63 };
   64 
   65 /* Nat redirect configuration. */
   66 struct cfg_redir {
   67         LIST_ENTRY(cfg_redir)   _next;  /* chain of redir instances */
   68         uint16_t                mode;   /* type of redirect mode */
   69         uint16_t                proto;  /* protocol: tcp/udp */
   70         struct in_addr          laddr;  /* local ip address */
   71         struct in_addr          paddr;  /* public ip address */
   72         struct in_addr          raddr;  /* remote ip address */
   73         uint16_t                lport;  /* local port */
   74         uint16_t                pport;  /* public port */
   75         uint16_t                rport;  /* remote port  */
   76         uint16_t                pport_cnt;      /* number of public ports */
   77         uint16_t                rport_cnt;      /* number of remote ports */
   78         struct alias_link       **alink;        
   79         u_int16_t               spool_cnt; /* num of entry in spool chain */
   80         /* chain of spool instances */
   81         LIST_HEAD(spool_chain, cfg_spool) spool_chain;
   82 };
   83 
   84 /* Nat configuration data struct. */
   85 struct cfg_nat {
   86         /* chain of nat instances */
   87         LIST_ENTRY(cfg_nat)     _next;
   88         int                     id;             /* nat id  */
   89         struct in_addr          ip;             /* nat ip address */
   90         struct libalias         *lib;           /* libalias instance */
   91         int                     mode;           /* aliasing mode */
   92         int                     redir_cnt; /* number of entry in spool chain */
   93         /* chain of redir instances */
   94         LIST_HEAD(redir_chain, cfg_redir) redir_chain;  
   95         char                    if_name[IF_NAMESIZE];   /* interface name */
   96         u_short                 alias_port_lo;  /* low range for port aliasing */
   97         u_short                 alias_port_hi;  /* high range for port aliasing */
   98 };
   99 
  100 static eventhandler_tag ifaddr_event_tag;
  101 
  102 static void
  103 ifaddr_change(void *arg __unused, struct ifnet *ifp)
  104 {
  105         struct cfg_nat *ptr;
  106         struct ifaddr *ifa;
  107         struct ip_fw_chain *chain;
  108 
  109         KASSERT(curvnet == ifp->if_vnet,
  110             ("curvnet(%p) differs from iface vnet(%p)", curvnet, ifp->if_vnet));
  111 
  112         if (V_ipfw_vnet_ready == 0 || V_ipfw_nat_ready == 0)
  113                 return;
  114 
  115         chain = &V_layer3_chain;
  116         IPFW_UH_WLOCK(chain);
  117         /* Check every nat entry... */
  118         LIST_FOREACH(ptr, &chain->nat, _next) {
  119                 struct epoch_tracker et;
  120 
  121                 /* ...using nic 'ifp->if_xname' as dynamic alias address. */
  122                 if (strncmp(ptr->if_name, ifp->if_xname, IF_NAMESIZE) != 0)
  123                         continue;
  124                 NET_EPOCH_ENTER(et);
  125                 CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
  126                         if (ifa->ifa_addr == NULL)
  127                                 continue;
  128                         if (ifa->ifa_addr->sa_family != AF_INET)
  129                                 continue;
  130                         IPFW_WLOCK(chain);
  131                         ptr->ip = ((struct sockaddr_in *)
  132                             (ifa->ifa_addr))->sin_addr;
  133                         LibAliasSetAddress(ptr->lib, ptr->ip);
  134                         IPFW_WUNLOCK(chain);
  135                 }
  136                 NET_EPOCH_EXIT(et);
  137         }
  138         IPFW_UH_WUNLOCK(chain);
  139 }
  140 
  141 /*
  142  * delete the pointers for nat entry ix, or all of them if ix < 0
  143  */
  144 static void
  145 flush_nat_ptrs(struct ip_fw_chain *chain, const int ix)
  146 {
  147         ipfw_insn_nat *cmd;
  148         int i;
  149 
  150         IPFW_WLOCK_ASSERT(chain);
  151         for (i = 0; i < chain->n_rules; i++) {
  152                 cmd = (ipfw_insn_nat *)ipfw_get_action(chain->map[i]);
  153                 if (cmd->o.opcode == O_NAT && cmd->nat != NULL &&
  154                             (ix < 0 || cmd->nat->id == ix))
  155                         cmd->nat = NULL;
  156         }
  157 }
  158 
  159 static void
  160 del_redir_spool_cfg(struct cfg_nat *n, struct redir_chain *head)
  161 {
  162         struct cfg_redir *r, *tmp_r;
  163         struct cfg_spool *s, *tmp_s;
  164         int i, num;
  165 
  166         LIST_FOREACH_SAFE(r, head, _next, tmp_r) {
  167                 num = 1; /* Number of alias_link to delete. */
  168                 switch (r->mode) {
  169                 case NAT44_REDIR_PORT:
  170                         num = r->pport_cnt;
  171                         /* FALLTHROUGH */
  172                 case NAT44_REDIR_ADDR:
  173                 case NAT44_REDIR_PROTO:
  174                         /* Delete all libalias redirect entry. */
  175                         for (i = 0; i < num; i++)
  176                                 LibAliasRedirectDelete(n->lib, r->alink[i]);
  177                         /* Del spool cfg if any. */
  178                         LIST_FOREACH_SAFE(s, &r->spool_chain, _next, tmp_s) {
  179                                 LIST_REMOVE(s, _next);
  180                                 free(s, M_IPFW);
  181                         }
  182                         free(r->alink, M_IPFW);
  183                         LIST_REMOVE(r, _next);
  184                         free(r, M_IPFW);
  185                         break;
  186                 default:
  187                         printf("unknown redirect mode: %u\n", r->mode);
  188                         /* XXX - panic?!?!? */
  189                         break;
  190                 }
  191         }
  192 }
  193 
  194 static int
  195 add_redir_spool_cfg(char *buf, struct cfg_nat *ptr)
  196 {
  197         struct cfg_redir *r;
  198         struct cfg_spool *s;
  199         struct nat44_cfg_redir *ser_r;
  200         struct nat44_cfg_spool *ser_s;
  201 
  202         int cnt, off, i;
  203 
  204         for (cnt = 0, off = 0; cnt < ptr->redir_cnt; cnt++) {
  205                 ser_r = (struct nat44_cfg_redir *)&buf[off];
  206                 r = malloc(sizeof(*r), M_IPFW, M_WAITOK | M_ZERO);
  207                 r->mode = ser_r->mode;
  208                 r->laddr = ser_r->laddr;
  209                 r->paddr = ser_r->paddr;
  210                 r->raddr = ser_r->raddr;
  211                 r->lport = ser_r->lport;
  212                 r->pport = ser_r->pport;
  213                 r->rport = ser_r->rport;
  214                 r->pport_cnt = ser_r->pport_cnt;
  215                 r->rport_cnt = ser_r->rport_cnt;
  216                 r->proto = ser_r->proto;
  217                 r->spool_cnt = ser_r->spool_cnt;
  218                 //memcpy(r, ser_r, SOF_REDIR);
  219                 LIST_INIT(&r->spool_chain);
  220                 off += sizeof(struct nat44_cfg_redir);
  221                 r->alink = malloc(sizeof(struct alias_link *) * r->pport_cnt,
  222                     M_IPFW, M_WAITOK | M_ZERO);
  223                 switch (r->mode) {
  224                 case NAT44_REDIR_ADDR:
  225                         r->alink[0] = LibAliasRedirectAddr(ptr->lib, r->laddr,
  226                             r->paddr);
  227                         break;
  228                 case NAT44_REDIR_PORT:
  229                         for (i = 0 ; i < r->pport_cnt; i++) {
  230                                 /* If remotePort is all ports, set it to 0. */
  231                                 u_short remotePortCopy = r->rport + i;
  232                                 if (r->rport_cnt == 1 && r->rport == 0)
  233                                         remotePortCopy = 0;
  234                                 r->alink[i] = LibAliasRedirectPort(ptr->lib,
  235                                     r->laddr, htons(r->lport + i), r->raddr,
  236                                     htons(remotePortCopy), r->paddr,
  237                                     htons(r->pport + i), r->proto);
  238                                 if (r->alink[i] == NULL) {
  239                                         r->alink[0] = NULL;
  240                                         break;
  241                                 }
  242                         }
  243                         break;
  244                 case NAT44_REDIR_PROTO:
  245                         r->alink[0] = LibAliasRedirectProto(ptr->lib ,r->laddr,
  246                             r->raddr, r->paddr, r->proto);
  247                         break;
  248                 default:
  249                         printf("unknown redirect mode: %u\n", r->mode);
  250                         break;
  251                 }
  252                 if (r->alink[0] == NULL) {
  253                         printf("LibAliasRedirect* returned NULL\n");
  254                         free(r->alink, M_IPFW);
  255                         free(r, M_IPFW);
  256                         return (EINVAL);
  257                 }
  258                 /* LSNAT handling. */
  259                 for (i = 0; i < r->spool_cnt; i++) {
  260                         ser_s = (struct nat44_cfg_spool *)&buf[off];
  261                         s = malloc(sizeof(*s), M_IPFW, M_WAITOK | M_ZERO);
  262                         s->addr = ser_s->addr;
  263                         s->port = ser_s->port;
  264                         LibAliasAddServer(ptr->lib, r->alink[0],
  265                             s->addr, htons(s->port));
  266                         off += sizeof(struct nat44_cfg_spool);
  267                         /* Hook spool entry. */
  268                         LIST_INSERT_HEAD(&r->spool_chain, s, _next);
  269                 }
  270                 /* And finally hook this redir entry. */
  271                 LIST_INSERT_HEAD(&ptr->redir_chain, r, _next);
  272         }
  273 
  274         return (0);
  275 }
  276 
  277 static void
  278 free_nat_instance(struct cfg_nat *ptr)
  279 {
  280 
  281         del_redir_spool_cfg(ptr, &ptr->redir_chain);
  282         LibAliasUninit(ptr->lib);
  283         free(ptr, M_IPFW);
  284 }
  285 
  286 /*
  287  * ipfw_nat - perform mbuf header translation.
  288  *
  289  * Note V_layer3_chain has to be locked while calling ipfw_nat() in
  290  * 'global' operation mode (t == NULL).
  291  *
  292  */
  293 static int
  294 ipfw_nat(struct ip_fw_args *args, struct cfg_nat *t, struct mbuf *m)
  295 {
  296         struct mbuf *mcl;
  297         struct ip *ip;
  298         /* XXX - libalias duct tape */
  299         int ldt, retval, found;
  300         struct ip_fw_chain *chain;
  301         char *c;
  302 
  303         ldt = 0;
  304         retval = 0;
  305         mcl = m_megapullup(m, m->m_pkthdr.len);
  306         if (mcl == NULL) {
  307                 args->m = NULL;
  308                 return (IP_FW_DENY);
  309         }
  310         M_ASSERTMAPPED(mcl);
  311         ip = mtod(mcl, struct ip *);
  312 
  313         /*
  314          * XXX - Libalias checksum offload 'duct tape':
  315          *
  316          * locally generated packets have only pseudo-header checksum
  317          * calculated and libalias will break it[1], so mark them for
  318          * later fix.  Moreover there are cases when libalias modifies
  319          * tcp packet data[2], mark them for later fix too.
  320          *
  321          * [1] libalias was never meant to run in kernel, so it does
  322          * not have any knowledge about checksum offloading, and
  323          * expects a packet with a full internet checksum.
  324          * Unfortunately, packets generated locally will have just the
  325          * pseudo header calculated, and when libalias tries to adjust
  326          * the checksum it will actually compute a wrong value.
  327          *
  328          * [2] when libalias modifies tcp's data content, full TCP
  329          * checksum has to be recomputed: the problem is that
  330          * libalias does not have any idea about checksum offloading.
  331          * To work around this, we do not do checksumming in LibAlias,
  332          * but only mark the packets in th_x2 field. If we receive a
  333          * marked packet, we calculate correct checksum for it
  334          * aware of offloading.  Why such a terrible hack instead of
  335          * recalculating checksum for each packet?
  336          * Because the previous checksum was not checked!
  337          * Recalculating checksums for EVERY packet will hide ALL
  338          * transmission errors. Yes, marked packets still suffer from
  339          * this problem. But, sigh, natd(8) has this problem, too.
  340          *
  341          * TODO: -make libalias mbuf aware (so
  342          * it can handle delayed checksum and tso)
  343          */
  344 
  345         if (mcl->m_pkthdr.rcvif == NULL &&
  346             mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA)
  347                 ldt = 1;
  348 
  349         c = mtod(mcl, char *);
  350 
  351         /* Check if this is 'global' instance */
  352         if (t == NULL) {
  353                 if (args->flags & IPFW_ARGS_IN) {
  354                         /* Wrong direction, skip processing */
  355                         args->m = mcl;
  356                         return (IP_FW_NAT);
  357                 }
  358 
  359                 found = 0;
  360                 chain = &V_layer3_chain;
  361                 IPFW_RLOCK_ASSERT(chain);
  362                 /* Check every nat entry... */
  363                 LIST_FOREACH(t, &chain->nat, _next) {
  364                         if ((t->mode & PKT_ALIAS_SKIP_GLOBAL) != 0)
  365                                 continue;
  366                         retval = LibAliasOutTry(t->lib, c,
  367                             mcl->m_len + M_TRAILINGSPACE(mcl), 0);
  368                         if (retval == PKT_ALIAS_OK) {
  369                                 /* Nat instance recognises state */
  370                                 found = 1;
  371                                 break;
  372                         }
  373                 }
  374                 if (found != 1) {
  375                         /* No instance found, return ignore */
  376                         args->m = mcl;
  377                         return (IP_FW_NAT);
  378                 }
  379         } else {
  380                 if (args->flags & IPFW_ARGS_IN)
  381                         retval = LibAliasIn(t->lib, c,
  382                                 mcl->m_len + M_TRAILINGSPACE(mcl));
  383                 else
  384                         retval = LibAliasOut(t->lib, c,
  385                                 mcl->m_len + M_TRAILINGSPACE(mcl));
  386         }
  387 
  388         /*
  389          * We drop packet when:
  390          * 1. libalias returns PKT_ALIAS_ERROR;
  391          * 2. For incoming packets:
  392          *      a) for unresolved fragments;
  393          *      b) libalias returns PKT_ALIAS_IGNORED and
  394          *              PKT_ALIAS_DENY_INCOMING flag is set.
  395          */
  396         if (retval == PKT_ALIAS_ERROR ||
  397             ((args->flags & IPFW_ARGS_IN) &&
  398             (retval == PKT_ALIAS_UNRESOLVED_FRAGMENT ||
  399             (retval == PKT_ALIAS_IGNORED &&
  400             (t->mode & PKT_ALIAS_DENY_INCOMING) != 0)))) {
  401                 /* XXX - should i add some logging? */
  402                 m_free(mcl);
  403                 args->m = NULL;
  404                 return (IP_FW_DENY);
  405         }
  406 
  407         if (retval == PKT_ALIAS_RESPOND)
  408                 mcl->m_flags |= M_SKIP_FIREWALL;
  409         mcl->m_pkthdr.len = mcl->m_len = ntohs(ip->ip_len);
  410 
  411         /*
  412          * XXX - libalias checksum offload
  413          * 'duct tape' (see above)
  414          */
  415 
  416         if ((ip->ip_off & htons(IP_OFFMASK)) == 0 &&
  417             ip->ip_p == IPPROTO_TCP) {
  418                 struct tcphdr   *th;
  419 
  420                 th = (struct tcphdr *)(ip + 1);
  421                 if (th->th_x2 & (TH_RES1 >> 8))
  422                         ldt = 1;
  423         }
  424 
  425         if (ldt) {
  426                 struct tcphdr   *th;
  427                 struct udphdr   *uh;
  428                 uint16_t ip_len, cksum;
  429 
  430                 ip_len = ntohs(ip->ip_len);
  431                 cksum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr,
  432                     htons(ip->ip_p + ip_len - (ip->ip_hl << 2)));
  433 
  434                 switch (ip->ip_p) {
  435                 case IPPROTO_TCP:
  436                         th = (struct tcphdr *)(ip + 1);
  437                         /*
  438                          * Maybe it was set in
  439                          * libalias...
  440                          */
  441                         th->th_x2 &= ~(TH_RES1 >> 8);
  442                         th->th_sum = cksum;
  443                         mcl->m_pkthdr.csum_data =
  444                             offsetof(struct tcphdr, th_sum);
  445                         break;
  446                 case IPPROTO_UDP:
  447                         uh = (struct udphdr *)(ip + 1);
  448                         uh->uh_sum = cksum;
  449                         mcl->m_pkthdr.csum_data =
  450                             offsetof(struct udphdr, uh_sum);
  451                         break;
  452                 }
  453                 /* No hw checksum offloading: do it ourselves */
  454                 if ((mcl->m_pkthdr.csum_flags & CSUM_DELAY_DATA) == 0) {
  455                         in_delayed_cksum(mcl);
  456                         mcl->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
  457                 }
  458         }
  459         args->m = mcl;
  460         return (IP_FW_NAT);
  461 }
  462 
  463 static struct cfg_nat *
  464 lookup_nat(struct nat_list *l, int nat_id)
  465 {
  466         struct cfg_nat *res;
  467 
  468         LIST_FOREACH(res, l, _next) {
  469                 if (res->id == nat_id)
  470                         break;
  471         }
  472         return res;
  473 }
  474 
  475 static struct cfg_nat *
  476 lookup_nat_name(struct nat_list *l, char *name)
  477 {
  478         struct cfg_nat *res;
  479         int id;
  480         char *errptr;
  481 
  482         id = strtol(name, &errptr, 10);
  483         if (id == 0 || *errptr != '\0')
  484                 return (NULL);
  485 
  486         LIST_FOREACH(res, l, _next) {
  487                 if (res->id == id)
  488                         break;
  489         }
  490         return (res);
  491 }
  492 
  493 /* IP_FW3 configuration routines */
  494 
  495 static void
  496 nat44_config(struct ip_fw_chain *chain, struct nat44_cfg_nat *ucfg)
  497 {
  498         struct cfg_nat *ptr, *tcfg;
  499         int gencnt;
  500 
  501         /*
  502          * Find/create nat rule.
  503          */
  504         IPFW_UH_WLOCK(chain);
  505         gencnt = chain->gencnt;
  506         ptr = lookup_nat_name(&chain->nat, ucfg->name);
  507         if (ptr == NULL) {
  508                 IPFW_UH_WUNLOCK(chain);
  509                 /* New rule: allocate and init new instance. */
  510                 ptr = malloc(sizeof(struct cfg_nat), M_IPFW, M_WAITOK | M_ZERO);
  511                 ptr->lib = LibAliasInit(NULL);
  512                 LIST_INIT(&ptr->redir_chain);
  513         } else {
  514                 /* Entry already present: temporarily unhook it. */
  515                 IPFW_WLOCK(chain);
  516                 LIST_REMOVE(ptr, _next);
  517                 flush_nat_ptrs(chain, ptr->id);
  518                 IPFW_WUNLOCK(chain);
  519                 IPFW_UH_WUNLOCK(chain);
  520         }
  521 
  522         /*
  523          * Basic nat (re)configuration.
  524          */
  525         ptr->id = strtol(ucfg->name, NULL, 10);
  526         /*
  527          * XXX - what if this rule doesn't nat any ip and just
  528          * redirect?
  529          * do we set aliasaddress to 0.0.0.0?
  530          */
  531         ptr->ip = ucfg->ip;
  532         ptr->redir_cnt = ucfg->redir_cnt;
  533         ptr->mode = ucfg->mode;
  534         ptr->alias_port_lo = ucfg->alias_port_lo;
  535         ptr->alias_port_hi = ucfg->alias_port_hi;
  536         strlcpy(ptr->if_name, ucfg->if_name, sizeof(ptr->if_name));
  537         LibAliasSetMode(ptr->lib, ptr->mode, ~0);
  538         LibAliasSetAddress(ptr->lib, ptr->ip);
  539         LibAliasSetAliasPortRange(ptr->lib, ptr->alias_port_lo, ptr->alias_port_hi);
  540 
  541         /*
  542          * Redir and LSNAT configuration.
  543          */
  544         /* Delete old cfgs. */
  545         del_redir_spool_cfg(ptr, &ptr->redir_chain);
  546         /* Add new entries. */
  547         add_redir_spool_cfg((char *)(ucfg + 1), ptr);
  548         IPFW_UH_WLOCK(chain);
  549 
  550         /* Extra check to avoid race with another ipfw_nat_cfg() */
  551         tcfg = NULL;
  552         if (gencnt != chain->gencnt)
  553             tcfg = lookup_nat_name(&chain->nat, ucfg->name);
  554         IPFW_WLOCK(chain);
  555         if (tcfg != NULL)
  556                 LIST_REMOVE(tcfg, _next);
  557         LIST_INSERT_HEAD(&chain->nat, ptr, _next);
  558         IPFW_WUNLOCK(chain);
  559         chain->gencnt++;
  560 
  561         IPFW_UH_WUNLOCK(chain);
  562 
  563         if (tcfg != NULL)
  564                 free_nat_instance(ptr);
  565 }
  566 
  567 /*
  568  * Creates/configure nat44 instance
  569  * Data layout (v0)(current):
  570  * Request: [ ipfw_obj_header nat44_cfg_nat .. ]
  571  *
  572  * Returns 0 on success
  573  */
  574 static int
  575 nat44_cfg(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
  576     struct sockopt_data *sd)
  577 {
  578         ipfw_obj_header *oh;
  579         struct nat44_cfg_nat *ucfg;
  580         int id;
  581         size_t read;
  582         char *errptr;
  583 
  584         /* Check minimum header size */
  585         if (sd->valsize < (sizeof(*oh) + sizeof(*ucfg)))
  586                 return (EINVAL);
  587 
  588         oh = (ipfw_obj_header *)sd->kbuf;
  589 
  590         /* Basic length checks for TLVs */
  591         if (oh->ntlv.head.length != sizeof(oh->ntlv))
  592                 return (EINVAL);
  593 
  594         ucfg = (struct nat44_cfg_nat *)(oh + 1);
  595 
  596         /* Check if name is properly terminated and looks like number */
  597         if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
  598                 return (EINVAL);
  599         id = strtol(ucfg->name, &errptr, 10);
  600         if (id == 0 || *errptr != '\0')
  601                 return (EINVAL);
  602 
  603         read = sizeof(*oh) + sizeof(*ucfg);
  604         /* Check number of redirs */
  605         if (sd->valsize < read + ucfg->redir_cnt*sizeof(struct nat44_cfg_redir))
  606                 return (EINVAL);
  607 
  608         nat44_config(chain, ucfg);
  609         return (0);
  610 }
  611 
  612 /*
  613  * Destroys given nat instances.
  614  * Data layout (v0)(current):
  615  * Request: [ ipfw_obj_header ]
  616  *
  617  * Returns 0 on success
  618  */
  619 static int
  620 nat44_destroy(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
  621     struct sockopt_data *sd)
  622 {
  623         ipfw_obj_header *oh;
  624         struct cfg_nat *ptr;
  625         ipfw_obj_ntlv *ntlv;
  626 
  627         /* Check minimum header size */
  628         if (sd->valsize < sizeof(*oh))
  629                 return (EINVAL);
  630 
  631         oh = (ipfw_obj_header *)sd->kbuf;
  632 
  633         /* Basic length checks for TLVs */
  634         if (oh->ntlv.head.length != sizeof(oh->ntlv))
  635                 return (EINVAL);
  636 
  637         ntlv = &oh->ntlv;
  638         /* Check if name is properly terminated */
  639         if (strnlen(ntlv->name, sizeof(ntlv->name)) == sizeof(ntlv->name))
  640                 return (EINVAL);
  641 
  642         IPFW_UH_WLOCK(chain);
  643         ptr = lookup_nat_name(&chain->nat, ntlv->name);
  644         if (ptr == NULL) {
  645                 IPFW_UH_WUNLOCK(chain);
  646                 return (ESRCH);
  647         }
  648         IPFW_WLOCK(chain);
  649         LIST_REMOVE(ptr, _next);
  650         flush_nat_ptrs(chain, ptr->id);
  651         IPFW_WUNLOCK(chain);
  652         IPFW_UH_WUNLOCK(chain);
  653 
  654         free_nat_instance(ptr);
  655 
  656         return (0);
  657 }
  658 
  659 static void
  660 export_nat_cfg(struct cfg_nat *ptr, struct nat44_cfg_nat *ucfg)
  661 {
  662 
  663         snprintf(ucfg->name, sizeof(ucfg->name), "%d", ptr->id);
  664         ucfg->ip = ptr->ip;
  665         ucfg->redir_cnt = ptr->redir_cnt;
  666         ucfg->mode = ptr->mode;
  667         ucfg->alias_port_lo = ptr->alias_port_lo;
  668         ucfg->alias_port_hi = ptr->alias_port_hi;
  669         strlcpy(ucfg->if_name, ptr->if_name, sizeof(ucfg->if_name));
  670 }
  671 
  672 /*
  673  * Gets config for given nat instance
  674  * Data layout (v0)(current):
  675  * Request: [ ipfw_obj_header nat44_cfg_nat .. ]
  676  *
  677  * Returns 0 on success
  678  */
  679 static int
  680 nat44_get_cfg(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
  681     struct sockopt_data *sd)
  682 {
  683         ipfw_obj_header *oh;
  684         struct nat44_cfg_nat *ucfg;
  685         struct cfg_nat *ptr;
  686         struct cfg_redir *r;
  687         struct cfg_spool *s;
  688         struct nat44_cfg_redir *ser_r;
  689         struct nat44_cfg_spool *ser_s;
  690         size_t sz;
  691 
  692         sz = sizeof(*oh) + sizeof(*ucfg);
  693         /* Check minimum header size */
  694         if (sd->valsize < sz)
  695                 return (EINVAL);
  696 
  697         oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
  698 
  699         /* Basic length checks for TLVs */
  700         if (oh->ntlv.head.length != sizeof(oh->ntlv))
  701                 return (EINVAL);
  702 
  703         ucfg = (struct nat44_cfg_nat *)(oh + 1);
  704 
  705         /* Check if name is properly terminated */
  706         if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
  707                 return (EINVAL);
  708 
  709         IPFW_UH_RLOCK(chain);
  710         ptr = lookup_nat_name(&chain->nat, ucfg->name);
  711         if (ptr == NULL) {
  712                 IPFW_UH_RUNLOCK(chain);
  713                 return (ESRCH);
  714         }
  715 
  716         export_nat_cfg(ptr, ucfg);
  717 
  718         /* Estimate memory amount */
  719         sz = sizeof(ipfw_obj_header) + sizeof(struct nat44_cfg_nat);
  720         LIST_FOREACH(r, &ptr->redir_chain, _next) {
  721                 sz += sizeof(struct nat44_cfg_redir);
  722                 LIST_FOREACH(s, &r->spool_chain, _next)
  723                         sz += sizeof(struct nat44_cfg_spool);
  724         }
  725 
  726         ucfg->size = sz;
  727         if (sd->valsize < sz) {
  728                 /*
  729                  * Submitted buffer size is not enough.
  730                  * WE've already filled in @ucfg structure with
  731                  * relevant info including size, so we
  732                  * can return. Buffer will be flushed automatically.
  733                  */
  734                 IPFW_UH_RUNLOCK(chain);
  735                 return (ENOMEM);
  736         }
  737 
  738         /* Size OK, let's copy data */
  739         LIST_FOREACH(r, &ptr->redir_chain, _next) {
  740                 ser_r = (struct nat44_cfg_redir *)ipfw_get_sopt_space(sd,
  741                     sizeof(*ser_r));
  742                 ser_r->mode = r->mode;
  743                 ser_r->laddr = r->laddr;
  744                 ser_r->paddr = r->paddr;
  745                 ser_r->raddr = r->raddr;
  746                 ser_r->lport = r->lport;
  747                 ser_r->pport = r->pport;
  748                 ser_r->rport = r->rport;
  749                 ser_r->pport_cnt = r->pport_cnt;
  750                 ser_r->rport_cnt = r->rport_cnt;
  751                 ser_r->proto = r->proto;
  752                 ser_r->spool_cnt = r->spool_cnt;
  753 
  754                 LIST_FOREACH(s, &r->spool_chain, _next) {
  755                         ser_s = (struct nat44_cfg_spool *)ipfw_get_sopt_space(
  756                             sd, sizeof(*ser_s));
  757 
  758                         ser_s->addr = s->addr;
  759                         ser_s->port = s->port;
  760                 }
  761         }
  762 
  763         IPFW_UH_RUNLOCK(chain);
  764 
  765         return (0);
  766 }
  767 
  768 /*
  769  * Lists all nat44 instances currently available in kernel.
  770  * Data layout (v0)(current):
  771  * Request: [ ipfw_obj_lheader ]
  772  * Reply: [ ipfw_obj_lheader nat44_cfg_nat x N ]
  773  *
  774  * Returns 0 on success
  775  */
  776 static int
  777 nat44_list_nat(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
  778     struct sockopt_data *sd)
  779 {
  780         ipfw_obj_lheader *olh;
  781         struct nat44_cfg_nat *ucfg;
  782         struct cfg_nat *ptr;
  783         int nat_count;
  784 
  785         /* Check minimum header size */
  786         if (sd->valsize < sizeof(ipfw_obj_lheader))
  787                 return (EINVAL);
  788 
  789         olh = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*olh));
  790         IPFW_UH_RLOCK(chain);
  791         nat_count = 0;
  792         LIST_FOREACH(ptr, &chain->nat, _next)
  793                 nat_count++;
  794 
  795         olh->count = nat_count;
  796         olh->objsize = sizeof(struct nat44_cfg_nat);
  797         olh->size = sizeof(*olh) + olh->count * olh->objsize;
  798 
  799         if (sd->valsize < olh->size) {
  800                 IPFW_UH_RUNLOCK(chain);
  801                 return (ENOMEM);
  802         }
  803 
  804         LIST_FOREACH(ptr, &chain->nat, _next) {
  805                 ucfg = (struct nat44_cfg_nat *)ipfw_get_sopt_space(sd,
  806                     sizeof(*ucfg));
  807                 export_nat_cfg(ptr, ucfg);
  808         }
  809 
  810         IPFW_UH_RUNLOCK(chain);
  811 
  812         return (0);
  813 }
  814 
  815 /*
  816  * Gets log for given nat instance
  817  * Data layout (v0)(current):
  818  * Request: [ ipfw_obj_header nat44_cfg_nat ]
  819  * Reply: [ ipfw_obj_header nat44_cfg_nat LOGBUFFER ]
  820  *
  821  * Returns 0 on success
  822  */
  823 static int
  824 nat44_get_log(struct ip_fw_chain *chain, ip_fw3_opheader *op3,
  825     struct sockopt_data *sd)
  826 {
  827         ipfw_obj_header *oh;
  828         struct nat44_cfg_nat *ucfg;
  829         struct cfg_nat *ptr;
  830         void *pbuf;
  831         size_t sz;
  832 
  833         sz = sizeof(*oh) + sizeof(*ucfg);
  834         /* Check minimum header size */
  835         if (sd->valsize < sz)
  836                 return (EINVAL);
  837 
  838         oh = (struct _ipfw_obj_header *)ipfw_get_sopt_header(sd, sz);
  839 
  840         /* Basic length checks for TLVs */
  841         if (oh->ntlv.head.length != sizeof(oh->ntlv))
  842                 return (EINVAL);
  843 
  844         ucfg = (struct nat44_cfg_nat *)(oh + 1);
  845 
  846         /* Check if name is properly terminated */
  847         if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
  848                 return (EINVAL);
  849 
  850         IPFW_UH_RLOCK(chain);
  851         ptr = lookup_nat_name(&chain->nat, ucfg->name);
  852         if (ptr == NULL) {
  853                 IPFW_UH_RUNLOCK(chain);
  854                 return (ESRCH);
  855         }
  856 
  857         if (ptr->lib->logDesc == NULL) {
  858                 IPFW_UH_RUNLOCK(chain);
  859                 return (ENOENT);
  860         }
  861 
  862         export_nat_cfg(ptr, ucfg);
  863 
  864         /* Estimate memory amount */
  865         ucfg->size = sizeof(struct nat44_cfg_nat) + LIBALIAS_BUF_SIZE;
  866         if (sd->valsize < sz + sizeof(*oh)) {
  867                 /*
  868                  * Submitted buffer size is not enough.
  869                  * WE've already filled in @ucfg structure with
  870                  * relevant info including size, so we
  871                  * can return. Buffer will be flushed automatically.
  872                  */
  873                 IPFW_UH_RUNLOCK(chain);
  874                 return (ENOMEM);
  875         }
  876 
  877         pbuf = (void *)ipfw_get_sopt_space(sd, LIBALIAS_BUF_SIZE);
  878         memcpy(pbuf, ptr->lib->logDesc, LIBALIAS_BUF_SIZE);
  879 
  880         IPFW_UH_RUNLOCK(chain);
  881 
  882         return (0);
  883 }
  884 
  885 static struct ipfw_sopt_handler scodes[] = {
  886         { IP_FW_NAT44_XCONFIG,  0,      HDIR_SET,       nat44_cfg },
  887         { IP_FW_NAT44_DESTROY,  0,      HDIR_SET,       nat44_destroy },
  888         { IP_FW_NAT44_XGETCONFIG,       0,      HDIR_GET,       nat44_get_cfg },
  889         { IP_FW_NAT44_LIST_NAT, 0,      HDIR_GET,       nat44_list_nat },
  890         { IP_FW_NAT44_XGETLOG,  0,      HDIR_GET,       nat44_get_log },
  891 };
  892 
  893 /*
  894  * Legacy configuration routines
  895  */
  896 
  897 struct cfg_spool_legacy {
  898         LIST_ENTRY(cfg_spool_legacy)    _next;
  899         struct in_addr                  addr;
  900         u_short                         port;
  901 };
  902 
  903 struct cfg_redir_legacy {
  904         LIST_ENTRY(cfg_redir)   _next;
  905         u_int16_t               mode;
  906         struct in_addr          laddr;
  907         struct in_addr          paddr;
  908         struct in_addr          raddr;
  909         u_short                 lport;
  910         u_short                 pport;
  911         u_short                 rport;
  912         u_short                 pport_cnt;
  913         u_short                 rport_cnt;
  914         int                     proto;
  915         struct alias_link       **alink;
  916         u_int16_t               spool_cnt;
  917         LIST_HEAD(, cfg_spool_legacy) spool_chain;
  918 };
  919 
  920 struct cfg_nat_legacy {
  921         LIST_ENTRY(cfg_nat_legacy)      _next;
  922         int                             id;
  923         struct in_addr                  ip;
  924         char                            if_name[IF_NAMESIZE];
  925         int                             mode;
  926         struct libalias                 *lib;
  927         int                             redir_cnt;
  928         LIST_HEAD(, cfg_redir_legacy)   redir_chain;
  929 };
  930 
  931 static int
  932 ipfw_nat_cfg(struct sockopt *sopt)
  933 {
  934         struct cfg_nat_legacy *cfg;
  935         struct nat44_cfg_nat *ucfg;
  936         struct cfg_redir_legacy *rdir;
  937         struct nat44_cfg_redir *urdir;
  938         char *buf;
  939         size_t len, len2;
  940         int error, i;
  941 
  942         len = sopt->sopt_valsize;
  943         len2 = len + 128;
  944 
  945         /*
  946          * Allocate 2x buffer to store converted structures.
  947          * new redir_cfg has shrunk, so we're sure that
  948          * new buffer size is enough.
  949          */
  950         buf = malloc(roundup2(len, 8) + len2, M_TEMP, M_WAITOK | M_ZERO);
  951         error = sooptcopyin(sopt, buf, len, sizeof(struct cfg_nat_legacy));
  952         if (error != 0)
  953                 goto out;
  954 
  955         cfg = (struct cfg_nat_legacy *)buf;
  956         if (cfg->id < 0) {
  957                 error = EINVAL;
  958                 goto out;
  959         }
  960 
  961         ucfg = (struct nat44_cfg_nat *)&buf[roundup2(len, 8)];
  962         snprintf(ucfg->name, sizeof(ucfg->name), "%d", cfg->id);
  963         strlcpy(ucfg->if_name, cfg->if_name, sizeof(ucfg->if_name));
  964         ucfg->ip = cfg->ip;
  965         ucfg->mode = cfg->mode;
  966         ucfg->redir_cnt = cfg->redir_cnt;
  967 
  968         if (len < sizeof(*cfg) + cfg->redir_cnt * sizeof(*rdir)) {
  969                 error = EINVAL;
  970                 goto out;
  971         }
  972 
  973         urdir = (struct nat44_cfg_redir *)(ucfg + 1);
  974         rdir = (struct cfg_redir_legacy *)(cfg + 1);
  975         for (i = 0; i < cfg->redir_cnt; i++) {
  976                 urdir->mode = rdir->mode;
  977                 urdir->laddr = rdir->laddr;
  978                 urdir->paddr = rdir->paddr;
  979                 urdir->raddr = rdir->raddr;
  980                 urdir->lport = rdir->lport;
  981                 urdir->pport = rdir->pport;
  982                 urdir->rport = rdir->rport;
  983                 urdir->pport_cnt = rdir->pport_cnt;
  984                 urdir->rport_cnt = rdir->rport_cnt;
  985                 urdir->proto = rdir->proto;
  986                 urdir->spool_cnt = rdir->spool_cnt;
  987 
  988                 urdir++;
  989                 rdir++;
  990         }
  991 
  992         nat44_config(&V_layer3_chain, ucfg);
  993 
  994 out:
  995         free(buf, M_TEMP);
  996         return (error);
  997 }
  998 
  999 static int
 1000 ipfw_nat_del(struct sockopt *sopt)
 1001 {
 1002         struct cfg_nat *ptr;
 1003         struct ip_fw_chain *chain = &V_layer3_chain;
 1004         int i;
 1005 
 1006         sooptcopyin(sopt, &i, sizeof i, sizeof i);
 1007         /* XXX validate i */
 1008         IPFW_UH_WLOCK(chain);
 1009         ptr = lookup_nat(&chain->nat, i);
 1010         if (ptr == NULL) {
 1011                 IPFW_UH_WUNLOCK(chain);
 1012                 return (EINVAL);
 1013         }
 1014         IPFW_WLOCK(chain);
 1015         LIST_REMOVE(ptr, _next);
 1016         flush_nat_ptrs(chain, i);
 1017         IPFW_WUNLOCK(chain);
 1018         IPFW_UH_WUNLOCK(chain);
 1019         free_nat_instance(ptr);
 1020         return (0);
 1021 }
 1022 
 1023 static int
 1024 ipfw_nat_get_cfg(struct sockopt *sopt)
 1025 {
 1026         struct ip_fw_chain *chain = &V_layer3_chain;
 1027         struct cfg_nat *n;
 1028         struct cfg_nat_legacy *ucfg;
 1029         struct cfg_redir *r;
 1030         struct cfg_spool *s;
 1031         struct cfg_redir_legacy *ser_r;
 1032         struct cfg_spool_legacy *ser_s;
 1033         char *data;
 1034         int gencnt, nat_cnt, len, error;
 1035 
 1036         nat_cnt = 0;
 1037         len = sizeof(nat_cnt);
 1038 
 1039         IPFW_UH_RLOCK(chain);
 1040 retry:
 1041         gencnt = chain->gencnt;
 1042         /* Estimate memory amount */
 1043         LIST_FOREACH(n, &chain->nat, _next) {
 1044                 nat_cnt++;
 1045                 len += sizeof(struct cfg_nat_legacy);
 1046                 LIST_FOREACH(r, &n->redir_chain, _next) {
 1047                         len += sizeof(struct cfg_redir_legacy);
 1048                         LIST_FOREACH(s, &r->spool_chain, _next)
 1049                                 len += sizeof(struct cfg_spool_legacy);
 1050                 }
 1051         }
 1052         IPFW_UH_RUNLOCK(chain);
 1053 
 1054         data = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
 1055         bcopy(&nat_cnt, data, sizeof(nat_cnt));
 1056 
 1057         nat_cnt = 0;
 1058         len = sizeof(nat_cnt);
 1059 
 1060         IPFW_UH_RLOCK(chain);
 1061         if (gencnt != chain->gencnt) {
 1062                 free(data, M_TEMP);
 1063                 goto retry;
 1064         }
 1065         /* Serialize all the data. */
 1066         LIST_FOREACH(n, &chain->nat, _next) {
 1067                 ucfg = (struct cfg_nat_legacy *)&data[len];
 1068                 ucfg->id = n->id;
 1069                 ucfg->ip = n->ip;
 1070                 ucfg->redir_cnt = n->redir_cnt;
 1071                 ucfg->mode = n->mode;
 1072                 strlcpy(ucfg->if_name, n->if_name, sizeof(ucfg->if_name));
 1073                 len += sizeof(struct cfg_nat_legacy);
 1074                 LIST_FOREACH(r, &n->redir_chain, _next) {
 1075                         ser_r = (struct cfg_redir_legacy *)&data[len];
 1076                         ser_r->mode = r->mode;
 1077                         ser_r->laddr = r->laddr;
 1078                         ser_r->paddr = r->paddr;
 1079                         ser_r->raddr = r->raddr;
 1080                         ser_r->lport = r->lport;
 1081                         ser_r->pport = r->pport;
 1082                         ser_r->rport = r->rport;
 1083                         ser_r->pport_cnt = r->pport_cnt;
 1084                         ser_r->rport_cnt = r->rport_cnt;
 1085                         ser_r->proto = r->proto;
 1086                         ser_r->spool_cnt = r->spool_cnt;
 1087                         len += sizeof(struct cfg_redir_legacy);
 1088                         LIST_FOREACH(s, &r->spool_chain, _next) {
 1089                                 ser_s = (struct cfg_spool_legacy *)&data[len];
 1090                                 ser_s->addr = s->addr;
 1091                                 ser_s->port = s->port;
 1092                                 len += sizeof(struct cfg_spool_legacy);
 1093                         }
 1094                 }
 1095         }
 1096         IPFW_UH_RUNLOCK(chain);
 1097 
 1098         error = sooptcopyout(sopt, data, len);
 1099         free(data, M_TEMP);
 1100 
 1101         return (error);
 1102 }
 1103 
 1104 static int
 1105 ipfw_nat_get_log(struct sockopt *sopt)
 1106 {
 1107         uint8_t *data;
 1108         struct cfg_nat *ptr;
 1109         int i, size;
 1110         struct ip_fw_chain *chain;
 1111         IPFW_RLOCK_TRACKER;
 1112 
 1113         chain = &V_layer3_chain;
 1114 
 1115         IPFW_RLOCK(chain);
 1116         /* one pass to count, one to copy the data */
 1117         i = 0;
 1118         LIST_FOREACH(ptr, &chain->nat, _next) {
 1119                 if (ptr->lib->logDesc == NULL)
 1120                         continue;
 1121                 i++;
 1122         }
 1123         size = i * (LIBALIAS_BUF_SIZE + sizeof(int));
 1124         data = malloc(size, M_IPFW, M_NOWAIT | M_ZERO);
 1125         if (data == NULL) {
 1126                 IPFW_RUNLOCK(chain);
 1127                 return (ENOSPC);
 1128         }
 1129         i = 0;
 1130         LIST_FOREACH(ptr, &chain->nat, _next) {
 1131                 if (ptr->lib->logDesc == NULL)
 1132                         continue;
 1133                 bcopy(&ptr->id, &data[i], sizeof(int));
 1134                 i += sizeof(int);
 1135                 bcopy(ptr->lib->logDesc, &data[i], LIBALIAS_BUF_SIZE);
 1136                 i += LIBALIAS_BUF_SIZE;
 1137         }
 1138         IPFW_RUNLOCK(chain);
 1139         sooptcopyout(sopt, data, size);
 1140         free(data, M_IPFW);
 1141         return(0);
 1142 }
 1143 
 1144 static int
 1145 vnet_ipfw_nat_init(const void *arg __unused)
 1146 {
 1147 
 1148         V_ipfw_nat_ready = 1;
 1149         return (0);
 1150 }
 1151 
 1152 static int
 1153 vnet_ipfw_nat_uninit(const void *arg __unused)
 1154 {
 1155         struct cfg_nat *ptr, *ptr_temp;
 1156         struct ip_fw_chain *chain;
 1157 
 1158         chain = &V_layer3_chain;
 1159         IPFW_WLOCK(chain);
 1160         V_ipfw_nat_ready = 0;
 1161         LIST_FOREACH_SAFE(ptr, &chain->nat, _next, ptr_temp) {
 1162                 LIST_REMOVE(ptr, _next);
 1163                 free_nat_instance(ptr);
 1164         }
 1165         flush_nat_ptrs(chain, -1 /* flush all */);
 1166         IPFW_WUNLOCK(chain);
 1167         return (0);
 1168 }
 1169 
 1170 static void
 1171 ipfw_nat_init(void)
 1172 {
 1173 
 1174         /* init ipfw hooks */
 1175         ipfw_nat_ptr = ipfw_nat;
 1176         lookup_nat_ptr = lookup_nat;
 1177         ipfw_nat_cfg_ptr = ipfw_nat_cfg;
 1178         ipfw_nat_del_ptr = ipfw_nat_del;
 1179         ipfw_nat_get_cfg_ptr = ipfw_nat_get_cfg;
 1180         ipfw_nat_get_log_ptr = ipfw_nat_get_log;
 1181         IPFW_ADD_SOPT_HANDLER(1, scodes);
 1182 
 1183         ifaddr_event_tag = EVENTHANDLER_REGISTER(ifaddr_event, ifaddr_change,
 1184             NULL, EVENTHANDLER_PRI_ANY);
 1185 }
 1186 
 1187 static void
 1188 ipfw_nat_destroy(void)
 1189 {
 1190 
 1191         EVENTHANDLER_DEREGISTER(ifaddr_event, ifaddr_event_tag);
 1192         /* deregister ipfw_nat */
 1193         IPFW_DEL_SOPT_HANDLER(1, scodes);
 1194         ipfw_nat_ptr = NULL;
 1195         lookup_nat_ptr = NULL;
 1196         ipfw_nat_cfg_ptr = NULL;
 1197         ipfw_nat_del_ptr = NULL;
 1198         ipfw_nat_get_cfg_ptr = NULL;
 1199         ipfw_nat_get_log_ptr = NULL;
 1200 }
 1201 
 1202 static int
 1203 ipfw_nat_modevent(module_t mod, int type, void *unused)
 1204 {
 1205         int err = 0;
 1206 
 1207         switch (type) {
 1208         case MOD_LOAD:
 1209                 break;
 1210 
 1211         case MOD_UNLOAD:
 1212                 break;
 1213 
 1214         default:
 1215                 return EOPNOTSUPP;
 1216                 break;
 1217         }
 1218         return err;
 1219 }
 1220 
 1221 static moduledata_t ipfw_nat_mod = {
 1222         "ipfw_nat",
 1223         ipfw_nat_modevent,
 1224         0
 1225 };
 1226 
 1227 /* Define startup order. */
 1228 #define IPFW_NAT_SI_SUB_FIREWALL        SI_SUB_PROTO_FIREWALL
 1229 #define IPFW_NAT_MODEVENT_ORDER         (SI_ORDER_ANY - 128) /* after ipfw */
 1230 #define IPFW_NAT_MODULE_ORDER           (IPFW_NAT_MODEVENT_ORDER + 1)
 1231 #define IPFW_NAT_VNET_ORDER             (IPFW_NAT_MODEVENT_ORDER + 2)
 1232 
 1233 DECLARE_MODULE(ipfw_nat, ipfw_nat_mod, IPFW_NAT_SI_SUB_FIREWALL, SI_ORDER_ANY);
 1234 MODULE_DEPEND(ipfw_nat, libalias, 1, 1, 1);
 1235 MODULE_DEPEND(ipfw_nat, ipfw, 3, 3, 3);
 1236 MODULE_VERSION(ipfw_nat, 1);
 1237 
 1238 SYSINIT(ipfw_nat_init, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_MODULE_ORDER,
 1239     ipfw_nat_init, NULL);
 1240 VNET_SYSINIT(vnet_ipfw_nat_init, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_VNET_ORDER,
 1241     vnet_ipfw_nat_init, NULL);
 1242 
 1243 SYSUNINIT(ipfw_nat_destroy, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_MODULE_ORDER,
 1244     ipfw_nat_destroy, NULL);
 1245 VNET_SYSUNINIT(vnet_ipfw_nat_uninit, IPFW_NAT_SI_SUB_FIREWALL,
 1246     IPFW_NAT_VNET_ORDER, vnet_ipfw_nat_uninit, NULL);
 1247 
 1248 /* end of file */

Cache object: a9b39e2544f56d17a0b188a9301d9a8a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.