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         /*
  326          * We drop packet when:
  327          * 1. libalias returns PKT_ALIAS_ERROR;
  328          * 2. For incoming packets:
  329          *      a) for unresolved fragments;
  330          *      b) libalias returns PKT_ALIAS_IGNORED and
  331          *              PKT_ALIAS_DENY_INCOMING flag is set.
  332          */
  333         if (retval == PKT_ALIAS_ERROR ||
  334             (args->oif == NULL && (retval == PKT_ALIAS_UNRESOLVED_FRAGMENT ||
  335             (retval == PKT_ALIAS_IGNORED &&
  336             (t->lib->packetAliasMode & PKT_ALIAS_DENY_INCOMING) != 0)))) {
  337                 /* XXX - should i add some logging? */
  338                 m_free(mcl);
  339         badnat:
  340                 args->m = NULL;
  341                 return (IP_FW_DENY);
  342         }
  343         mcl->m_pkthdr.len = mcl->m_len = 
  344             ntohs(ip->ip_len);
  345 
  346         /* 
  347          * XXX - libalias checksum offload 
  348          * 'duct tape' (see above) 
  349          */
  350 
  351         if ((ip->ip_off & htons(IP_OFFMASK)) == 0 && 
  352             ip->ip_p == IPPROTO_TCP) {
  353                 struct tcphdr   *th; 
  354 
  355                 th = (struct tcphdr *)(ip + 1);
  356                 if (th->th_x2) 
  357                         ldt = 1;
  358         }
  359 
  360         if (ldt) {
  361                 struct tcphdr   *th;
  362                 struct udphdr   *uh;
  363                 u_short cksum;
  364 
  365                 ip->ip_len = ntohs(ip->ip_len);
  366                 cksum = in_pseudo(
  367                     ip->ip_src.s_addr,
  368                     ip->ip_dst.s_addr, 
  369                     htons(ip->ip_p + ip->ip_len - (ip->ip_hl << 2))
  370                 );
  371                                         
  372                 switch (ip->ip_p) {
  373                 case IPPROTO_TCP:
  374                         th = (struct tcphdr *)(ip + 1);
  375                         /* 
  376                          * Maybe it was set in 
  377                          * libalias... 
  378                          */
  379                         th->th_x2 = 0;
  380                         th->th_sum = cksum;
  381                         mcl->m_pkthdr.csum_data = 
  382                             offsetof(struct tcphdr, th_sum);
  383                         break;
  384                 case IPPROTO_UDP:
  385                         uh = (struct udphdr *)(ip + 1);
  386                         uh->uh_sum = cksum;
  387                         mcl->m_pkthdr.csum_data = 
  388                             offsetof(struct udphdr, uh_sum);
  389                         break;                                          
  390                 }
  391                 /* 
  392                  * No hw checksum offloading: do it 
  393                  * by ourself. 
  394                  */
  395                 if ((mcl->m_pkthdr.csum_flags & 
  396                      CSUM_DELAY_DATA) == 0) {
  397                         in_delayed_cksum(mcl);
  398                         mcl->m_pkthdr.csum_flags &= 
  399                             ~CSUM_DELAY_DATA;
  400                 }
  401                 ip->ip_len = htons(ip->ip_len);
  402         }
  403 
  404         if (args->eh == NULL) {
  405                 ip->ip_len = ntohs(ip->ip_len);
  406                 ip->ip_off = ntohs(ip->ip_off);
  407         }
  408 
  409         args->m = mcl;
  410         return (IP_FW_NAT);
  411 }
  412 
  413 static int 
  414 ipfw_nat_cfg(struct sockopt *sopt)
  415 {
  416         struct cfg_nat *ptr, *ser_n;
  417         char *buf;
  418 
  419         buf = malloc(NAT_BUF_LEN, M_IPFW, M_WAITOK | M_ZERO);
  420         sooptcopyin(sopt, buf, NAT_BUF_LEN, 
  421             sizeof(struct cfg_nat));
  422         ser_n = (struct cfg_nat *)buf;
  423 
  424         /* 
  425          * Find/create nat rule.
  426          */
  427         IPFW_WLOCK(&layer3_chain);
  428         LOOKUP_NAT(layer3_chain, ser_n->id, ptr);
  429         if (ptr == NULL) {
  430                 /* New rule: allocate and init new instance. */
  431                 ptr = malloc(sizeof(struct cfg_nat), 
  432                     M_IPFW, M_NOWAIT | M_ZERO);
  433                 if (ptr == NULL) {
  434                         IPFW_WUNLOCK(&layer3_chain);                            
  435                         free(buf, M_IPFW);
  436                         return (ENOSPC);
  437                 }
  438                 ptr->lib = LibAliasInit(NULL);
  439                 if (ptr->lib == NULL) {
  440                         IPFW_WUNLOCK(&layer3_chain);
  441                         free(ptr, M_IPFW);
  442                         free(buf, M_IPFW);
  443                         return (EINVAL);
  444                 }
  445                 LIST_INIT(&ptr->redir_chain);
  446         } else {
  447                 /* Entry already present: temporarly unhook it. */
  448                 UNHOOK_NAT(ptr);
  449                 flush_nat_ptrs(ser_n->id);
  450         }
  451         IPFW_WUNLOCK(&layer3_chain);
  452 
  453         /* 
  454          * Basic nat configuration.
  455          */
  456         ptr->id = ser_n->id;
  457         /* 
  458          * XXX - what if this rule doesn't nat any ip and just 
  459          * redirect? 
  460          * do we set aliasaddress to 0.0.0.0?
  461          */
  462         ptr->ip = ser_n->ip;
  463         ptr->redir_cnt = ser_n->redir_cnt;
  464         ptr->mode = ser_n->mode;
  465         LibAliasSetMode(ptr->lib, ser_n->mode, ser_n->mode);
  466         LibAliasSetAddress(ptr->lib, ptr->ip);
  467         memcpy(ptr->if_name, ser_n->if_name, IF_NAMESIZE);
  468 
  469         /* 
  470          * Redir and LSNAT configuration.
  471          */
  472         /* Delete old cfgs. */
  473         del_redir_spool_cfg(ptr, &ptr->redir_chain);
  474         /* Add new entries. */
  475         add_redir_spool_cfg(&buf[(sizeof(struct cfg_nat))], ptr);
  476         free(buf, M_IPFW);
  477         IPFW_WLOCK(&layer3_chain);
  478         HOOK_NAT(&layer3_chain.nat, ptr);
  479         IPFW_WUNLOCK(&layer3_chain);
  480         return (0);
  481 }
  482 
  483 static int
  484 ipfw_nat_del(struct sockopt *sopt)
  485 {
  486         struct cfg_nat *ptr;
  487         int i;
  488                 
  489         sooptcopyin(sopt, &i, sizeof i, sizeof i);
  490         IPFW_WLOCK(&layer3_chain);
  491         LOOKUP_NAT(layer3_chain, i, ptr);
  492         if (ptr == NULL) {
  493                 IPFW_WUNLOCK(&layer3_chain);
  494                 return (EINVAL);
  495         }
  496         UNHOOK_NAT(ptr);
  497         flush_nat_ptrs(i);
  498         IPFW_WUNLOCK(&layer3_chain);
  499         del_redir_spool_cfg(ptr, &ptr->redir_chain);
  500         LibAliasUninit(ptr->lib);
  501         free(ptr, M_IPFW);
  502         return (0);
  503 }
  504 
  505 static int
  506 ipfw_nat_get_cfg(struct sockopt *sopt)
  507 {       
  508         uint8_t *data;
  509         struct cfg_nat *n;
  510         struct cfg_redir *r;
  511         struct cfg_spool *s;
  512         int nat_cnt, off;
  513                 
  514         nat_cnt = 0;
  515         off = sizeof(nat_cnt);
  516 
  517         data = malloc(NAT_BUF_LEN, M_IPFW, M_WAITOK | M_ZERO);
  518         IPFW_RLOCK(&layer3_chain);
  519         /* Serialize all the data. */
  520         LIST_FOREACH(n, &layer3_chain.nat, _next) {
  521                 nat_cnt++;
  522                 if (off + SOF_NAT < NAT_BUF_LEN) {
  523                         bcopy(n, &data[off], SOF_NAT);
  524                         off += SOF_NAT;
  525                         LIST_FOREACH(r, &n->redir_chain, _next) {
  526                                 if (off + SOF_REDIR < NAT_BUF_LEN) {
  527                                         bcopy(r, &data[off], 
  528                                             SOF_REDIR);
  529                                         off += SOF_REDIR;
  530                                         LIST_FOREACH(s, &r->spool_chain, 
  531                                             _next) {
  532                                                 if (off + SOF_SPOOL < 
  533                                                     NAT_BUF_LEN) {
  534                                                         bcopy(s, &data[off],
  535                                                             SOF_SPOOL);
  536                                                         off += SOF_SPOOL;
  537                                                 } else
  538                                                         goto nospace;
  539                                         }
  540                                 } else
  541                                         goto nospace;
  542                         }
  543                 } else
  544                         goto nospace;
  545         }
  546         bcopy(&nat_cnt, data, sizeof(nat_cnt));
  547         IPFW_RUNLOCK(&layer3_chain);
  548         sooptcopyout(sopt, data, NAT_BUF_LEN);
  549         free(data, M_IPFW);
  550         return (0);
  551 nospace:
  552         IPFW_RUNLOCK(&layer3_chain);
  553         printf("serialized data buffer not big enough:"
  554             "please increase NAT_BUF_LEN\n");
  555         free(data, M_IPFW);
  556         return (ENOSPC);
  557 }
  558 
  559 static int
  560 ipfw_nat_get_log(struct sockopt *sopt)
  561 {
  562         uint8_t *data;
  563         struct cfg_nat *ptr;
  564         int i, size, cnt, sof;
  565 
  566         data = NULL;
  567         sof = LIBALIAS_BUF_SIZE;
  568         cnt = 0;
  569 
  570         IPFW_RLOCK(&layer3_chain);
  571         size = i = 0;
  572         LIST_FOREACH(ptr, &layer3_chain.nat, _next) {
  573                 if (ptr->lib->logDesc == NULL) 
  574                         continue;
  575                 cnt++;
  576                 size = cnt * (sof + sizeof(int));
  577                 data = realloc(data, size, M_IPFW, M_NOWAIT | M_ZERO);
  578                 if (data == NULL) {
  579                         IPFW_RUNLOCK(&layer3_chain);
  580                         return (ENOSPC);
  581                 }
  582                 bcopy(&ptr->id, &data[i], sizeof(int));
  583                 i += sizeof(int);
  584                 bcopy(ptr->lib->logDesc, &data[i], sof);
  585                 i += sof;
  586         }
  587         IPFW_RUNLOCK(&layer3_chain);
  588         sooptcopyout(sopt, data, size);
  589         free(data, M_IPFW);
  590         return(0);
  591 }
  592 
  593 static void
  594 ipfw_nat_init(void)
  595 {
  596 
  597         IPFW_WLOCK(&layer3_chain);
  598         /* init ipfw hooks */
  599         ipfw_nat_ptr = ipfw_nat;
  600         ipfw_nat_cfg_ptr = ipfw_nat_cfg;
  601         ipfw_nat_del_ptr = ipfw_nat_del;
  602         ipfw_nat_get_cfg_ptr = ipfw_nat_get_cfg;
  603         ipfw_nat_get_log_ptr = ipfw_nat_get_log;
  604         IPFW_WUNLOCK(&layer3_chain);
  605         ifaddr_event_tag = EVENTHANDLER_REGISTER(ifaddr_event, ifaddr_change, 
  606             NULL, EVENTHANDLER_PRI_ANY);
  607 }
  608 
  609 static void
  610 ipfw_nat_destroy(void)
  611 {
  612         struct ip_fw *rule;
  613         struct cfg_nat *ptr, *ptr_temp;
  614         
  615         IPFW_WLOCK(&layer3_chain);
  616         LIST_FOREACH_SAFE(ptr, &layer3_chain.nat, _next, ptr_temp) {
  617                 LIST_REMOVE(ptr, _next);
  618                 del_redir_spool_cfg(ptr, &ptr->redir_chain);
  619                 LibAliasUninit(ptr->lib);
  620                 free(ptr, M_IPFW);
  621         }
  622         EVENTHANDLER_DEREGISTER(ifaddr_event, ifaddr_event_tag);
  623         /* flush all nat ptrs */
  624         for (rule = layer3_chain.rules; rule; rule = rule->next) {
  625                 ipfw_insn_nat *cmd = (ipfw_insn_nat *)ACTION_PTR(rule);
  626                 if (cmd->o.opcode == O_NAT)
  627                         cmd->nat = NULL;
  628         }
  629         /* deregister ipfw_nat */
  630         ipfw_nat_ptr = NULL;
  631         IPFW_WUNLOCK(&layer3_chain);
  632 }
  633 
  634 static int
  635 ipfw_nat_modevent(module_t mod, int type, void *unused)
  636 {
  637         int err = 0;
  638 
  639         switch (type) {
  640         case MOD_LOAD:
  641                 ipfw_nat_init();
  642                 break;
  643 
  644         case MOD_UNLOAD:
  645                 ipfw_nat_destroy();
  646                 break;
  647 
  648         default:
  649                 return EOPNOTSUPP;
  650                 break;
  651         }
  652         return err;
  653 }
  654 
  655 static moduledata_t ipfw_nat_mod = {
  656         "ipfw_nat",
  657         ipfw_nat_modevent,
  658         0
  659 };
  660 
  661 DECLARE_MODULE(ipfw_nat, ipfw_nat_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
  662 MODULE_DEPEND(ipfw_nat, libalias, 1, 1, 1);
  663 MODULE_DEPEND(ipfw_nat, ipfw, 2, 2, 2);
  664 MODULE_VERSION(ipfw_nat, 1);

Cache object: 762a05b859e749c6fbca27a978eadb5d


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