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

Cache object: 9a0d5c5bce2cd4b2729121bb9cdba221


[ 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.