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_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) 1995-1997 by Darren Reed.
    3  *
    4  * Redistribution and use in source and binary forms are permitted
    5  * provided that this notice is preserved and due credit is given
    6  * to the original author and the contributors.
    7  *
    8  * Added redirect stuff and a LOT of bug fixes. (mcn@EnGarde.com)
    9  */
   10 #if !defined(lint)
   11 static const char sccsid[] = "@(#)ip_nat.c      1.11 6/5/96 (C) 1995 Darren Reed";
   12 static const char rcsid[] = "@(#)$FreeBSD$";
   13 #endif
   14 
   15 #include "opt_ipfilter.h"
   16 #define __FreeBSD_version 300000        /* it's a hack, but close enough */
   17 
   18 #if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL)
   19 #define _KERNEL
   20 #endif
   21 
   22 #if !defined(_KERNEL) && !defined(KERNEL)
   23 # include <stdio.h>
   24 # include <string.h>
   25 # include <stdlib.h>
   26 #endif
   27 #include <sys/errno.h>
   28 #include <sys/types.h>
   29 #include <sys/param.h>
   30 #include <sys/time.h>
   31 #include <sys/file.h>
   32 #if defined(KERNEL) && (__FreeBSD_version >= 220000)
   33 # include <sys/filio.h>
   34 # include <sys/fcntl.h>
   35 #else
   36 # include <sys/ioctl.h>
   37 #endif
   38 #include <sys/fcntl.h>
   39 #include <sys/uio.h>
   40 #ifndef linux
   41 # include <sys/protosw.h>
   42 #endif
   43 #include <sys/socket.h>
   44 #if defined(_KERNEL) && !defined(linux)
   45 # include <sys/systm.h>
   46 #endif
   47 #if !defined(__SVR4) && !defined(__svr4__)
   48 # ifndef linux
   49 #  include <sys/mbuf.h>
   50 # endif
   51 #else
   52 # include <sys/filio.h>
   53 # include <sys/byteorder.h>
   54 # include <sys/dditypes.h>
   55 # include <sys/stream.h>
   56 # include <sys/kmem.h>
   57 #endif
   58 #if __FreeBSD_version >= 300000
   59 # include <sys/queue.h>
   60 # include <sys/malloc.h>
   61 #endif
   62 #include <net/if.h>
   63 #if __FreeBSD_version >= 300000
   64 # include <net/if_var.h>
   65 #endif
   66 #ifdef sun
   67 #include <net/af.h>
   68 #endif
   69 #include <net/route.h>
   70 #include <netinet/in.h>
   71 #include <netinet/in_systm.h>
   72 #include <netinet/ip.h>
   73 
   74 #ifdef __sgi
   75 # ifdef IFF_DRVRLOCK /* IRIX6 */
   76 #include <sys/hashing.h>
   77 #include <netinet/in_var.h>
   78 # endif
   79 #endif
   80 
   81 #ifdef RFC1825
   82 #include <vpn/md5.h>
   83 #include <vpn/ipsec.h>
   84 extern struct ifnet vpnif;
   85 #endif
   86 
   87 #ifndef linux
   88 # include <netinet/ip_var.h>
   89 #endif
   90 #include <netinet/tcp.h>
   91 #include <netinet/udp.h>
   92 #include <netinet/ip_icmp.h>
   93 #include "netinet/ip_compat.h"
   94 #include <netinet/tcpip.h>
   95 #include "netinet/ip_fil.h"
   96 #include "netinet/ip_proxy.h"
   97 #include "netinet/ip_nat.h"
   98 #include "netinet/ip_frag.h"
   99 #include "netinet/ip_state.h"
  100 #ifndef MIN
  101 #define MIN(a,b)        (((a)<(b))?(a):(b))
  102 #endif
  103 #undef  SOCKADDR_IN
  104 #define SOCKADDR_IN     struct sockaddr_in
  105 
  106        nat_t    *nat_table[2][NAT_SIZE], *nat_instances = NULL;
  107 static ipnat_t  *nat_list = NULL;
  108 u_long  fr_defnatage = 1200,    /* 10 minutes (600 seconds) */
  109         fr_defnaticmpage = 6;   /* 3 seconds */
  110 static natstat_t nat_stats;
  111 #if     (SOLARIS || defined(__sgi)) && defined(_KERNEL)
  112 extern  kmutex_t        ipf_nat;
  113 #endif
  114 
  115 static  int     nat_flushtable __P((void));
  116 static  int     nat_clearlist __P((void));
  117 static  void    nat_delete __P((struct nat *));
  118 static  int     nat_ifpaddr __P((nat_t *, void *, struct in_addr *));
  119 
  120 
  121 #define LONG_SUM(in)    (((in) & 0xffff) + ((in) >> 16))
  122 
  123 #define CALC_SUMD(s1, s2, sd) { \
  124                             /* Do it twice */ \
  125                             (s1) = ((s1) & 0xffff) + ((s1) >> 16); \
  126                             (s1) = ((s1) & 0xffff) + ((s1) >> 16); \
  127                             /* Do it twice */ \
  128                             (s2) = ((s2) & 0xffff) + ((s2) >> 16); \
  129                             (s2) = ((s2) & 0xffff) + ((s2) >> 16); \
  130                             /* Because ~1 == -2, We really need ~1 == -1 */ \
  131                             if ((s1) > (s2)) (s2)--; \
  132                             (sd) = (s2) - (s1); \
  133                             (sd) = ((sd) & 0xffff) + ((sd) >> 16); }
  134 
  135 void fix_outcksum(sp, n)
  136 u_short *sp;
  137 u_32_t n;
  138 {
  139         register u_short sumshort;
  140         register u_32_t sum1;
  141 
  142         if (!n)
  143                 return;
  144         sum1 = (~ntohs(*sp)) & 0xffff;
  145         sum1 += (n);
  146         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
  147         /* Again */
  148         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
  149         sumshort = ~(u_short)sum1;
  150         *(sp) = htons(sumshort);
  151 }
  152 
  153 
  154 void fix_incksum(sp, n)
  155 u_short *sp;
  156 u_32_t n;
  157 {
  158         register u_short sumshort;
  159         register u_32_t sum1;
  160 
  161         if (!n)
  162                 return;
  163 #ifdef sparc
  164         sum1 = (~(*sp)) & 0xffff;
  165 #else
  166         sum1 = (~ntohs(*sp)) & 0xffff;
  167 #endif
  168         sum1 += ~(n) & 0xffff;
  169         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
  170         /* Again */
  171         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
  172         sumshort = ~(u_short)sum1;
  173         *(sp) = htons(sumshort);
  174 }
  175 
  176 
  177 /*
  178  * How the NAT is organised and works.
  179  *
  180  * Inside (interface y) NAT       Outside (interface x)
  181  * -------------------- -+- -------------------------------------
  182  * Packet going          |   out, processsed by ip_natout() for x
  183  * ------------>         |   ------------>
  184  * src=10.1.1.1          |   src=192.1.1.1
  185  *                       |
  186  *                       |   in, processed by ip_natin() for x
  187  * <------------         |   <------------
  188  * dst=10.1.1.1          |   dst=192.1.1.1
  189  * -------------------- -+- -------------------------------------
  190  * ip_natout() - changes ip_src and if required, sport
  191  *             - creates a new mapping, if required.
  192  * ip_natin()  - changes ip_dst and if required, dport
  193  *
  194  * In the NAT table, internal source is recorded as "in" and externally
  195  * seen as "out".
  196  */
  197 
  198 /*
  199  * Handle ioctls which manipulate the NAT.
  200  */
  201 int nat_ioctl(data, cmd, mode)
  202 #if defined(__NetBSD__) || defined(__OpenBSD__) || (__FreeBSD_version >= 300003)
  203 u_long cmd;
  204 #else
  205 int cmd;
  206 #endif
  207 caddr_t data;
  208 int mode;
  209 {
  210         register ipnat_t *nat, *n = NULL, **np = NULL;
  211         ipnat_t natd;
  212         int error = 0, ret;
  213 #if defined(_KERNEL) && !SOLARIS
  214         int s;
  215 #endif
  216 
  217         nat = NULL;     /* XXX gcc -Wuninitialized */
  218 
  219         /*
  220          * For add/delete, look to see if the NAT entry is already present
  221          */
  222         SPL_NET(s);
  223         MUTEX_ENTER(&ipf_nat);
  224         if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT)) {
  225                 IRCOPY(data, (char *)&natd, sizeof(natd));
  226                 nat = &natd;
  227                 nat->in_inip &= nat->in_inmsk;
  228                 nat->in_outip &= nat->in_outmsk;
  229                 for (np = &nat_list; (n = *np); np = &n->in_next)
  230                         if (!bcmp((char *)&nat->in_flags, (char *)&n->in_flags,
  231                                         IPN_CMPSIZ))
  232                                 break;
  233         }
  234 
  235         switch (cmd)
  236         {
  237         case SIOCADNAT :
  238                 if (!(mode & FWRITE)) {
  239                         error = EPERM;
  240                         break;
  241                 }
  242                 if (n) {
  243                         error = EEXIST;
  244                         break;
  245                 }
  246                 KMALLOC(n, ipnat_t *, sizeof(*n));
  247                 if (n == NULL) {
  248                         error = ENOMEM;
  249                         break;
  250                 }
  251                 bcopy((char *)nat, (char *)n, sizeof(*n));
  252                 n->in_ifp = (void *)GETUNIT(n->in_ifname);
  253                 if (!n->in_ifp)
  254                         n->in_ifp = (void *)-1;
  255                 n->in_apr = ap_match(n->in_p, n->in_plabel);
  256                 n->in_next = *np;
  257                 n->in_use = 0;
  258                 n->in_space = ~(0xffffffff & ntohl(n->in_outmsk));
  259                 if (n->in_space) /* lose 2: broadcast + network address */
  260                         n->in_space -= 2;
  261                 else
  262                         n->in_space = 1;        /* single IP# mapping */
  263                 if ((n->in_outmsk != 0xffffffff) && n->in_outmsk)
  264                         n->in_nip = ntohl(n->in_outip) + 1;
  265                 else
  266                         n->in_nip = ntohl(n->in_outip);
  267                 if (n->in_redir & NAT_MAP) {
  268                         n->in_pnext = ntohs(n->in_pmin);
  269                         /*
  270                          * Multiply by the number of ports made available.
  271                          */
  272                         if (ntohs(n->in_pmax) > ntohs(n->in_pmin))
  273                                 n->in_space *= (ntohs(n->in_pmax) -
  274                                                 ntohs(n->in_pmin));
  275                 }
  276                 /* Otherwise, these fields are preset */
  277                 *np = n;
  278                 nat_stats.ns_rules++;
  279                 break;
  280         case SIOCRMNAT :
  281                 if (!(mode & FWRITE)) {
  282                         error = EPERM;
  283                         break;
  284                 }
  285                 if (!n) {
  286                         error = ESRCH;
  287                         break;
  288                 }
  289                 *np = n->in_next;
  290                 if (!n->in_use) {
  291                         if (n->in_apr)
  292                                 ap_free(n->in_apr);
  293                         KFREE(n);
  294                         nat_stats.ns_rules--;
  295                 } else {
  296                         n->in_flags |= IPN_DELETE;
  297                         n->in_next = NULL;
  298                 }
  299                 break;
  300         case SIOCGNATS :
  301                 nat_stats.ns_table[0] = nat_table[0];
  302                 nat_stats.ns_table[1] = nat_table[1];
  303                 nat_stats.ns_list = nat_list;
  304                 IWCOPY((char *)&nat_stats, (char *)data, sizeof(nat_stats));
  305                 break;
  306         case SIOCGNATL :
  307             {
  308                 natlookup_t nl;
  309 
  310                 IRCOPY((char *)data, (char *)&nl, sizeof(nl));
  311 
  312                 if (nat_lookupredir(&nl)) {
  313                         IWCOPY((char *)&nl, (char *)data, sizeof(nl));
  314                 } else
  315                         error = ESRCH;
  316                 break;
  317             }
  318         case SIOCFLNAT :
  319                 if (!(mode & FWRITE)) {
  320                         error = EPERM;
  321                         break;
  322                 }
  323                 ret = nat_flushtable();
  324                 (void) ap_unload();
  325                 IWCOPY((caddr_t)&ret, data, sizeof(ret));
  326                 break;
  327         case SIOCCNATL :
  328                 if (!(mode & FWRITE)) {
  329                         error = EPERM;
  330                         break;
  331                 }
  332                 ret = nat_clearlist();
  333                 IWCOPY((caddr_t)&ret, data, sizeof(ret));
  334                 break;
  335         case FIONREAD :
  336 #ifdef  IPFILTER_LOG
  337                 IWCOPY((caddr_t)&iplused[IPL_LOGNAT], (caddr_t)data,
  338                        sizeof(iplused[IPL_LOGNAT]));
  339 #endif
  340                 break;
  341         }
  342         MUTEX_EXIT(&ipf_nat);
  343         SPL_X(s);
  344         return error;
  345 }
  346 
  347 
  348 /*
  349  * Delete a nat entry from the various lists and table.
  350  */
  351 static void nat_delete(natd)
  352 struct nat *natd;
  353 {
  354         register struct nat **natp, *nat;
  355         struct ipnat *ipn;
  356 
  357         for (natp = natd->nat_hstart[0]; (nat = *natp);
  358              natp = &nat->nat_hnext[0])
  359                 if (nat == natd) {
  360                         *natp = nat->nat_hnext[0];
  361                         break;
  362                 }
  363 
  364         for (natp = natd->nat_hstart[1]; (nat = *natp);
  365              natp = &nat->nat_hnext[1])
  366                 if (nat == natd) {
  367                         *natp = nat->nat_hnext[1];
  368                         break;
  369                 }
  370 
  371         /*
  372          * If there is an active reference from the nat entry to its parent
  373          * rule, decrement the rule's reference count and free it too if no
  374          * longer being used.
  375          */
  376         if ((ipn = natd->nat_ptr)) {
  377                 ipn->in_space++;
  378                 ipn->in_use--;
  379                 if (!ipn->in_use && (ipn->in_flags & IPN_DELETE)) {
  380                         if (ipn->in_apr)
  381                                 ap_free(ipn->in_apr);
  382                         KFREE(ipn);
  383                         nat_stats.ns_rules--;
  384                 }
  385         }
  386 
  387         /*
  388          * If there's a fragment table entry too for this nat entry, then
  389          * dereference that as well.
  390          */
  391         ipfr_forget((void *)natd);
  392         KFREE(natd);
  393 }
  394 
  395 
  396 /*
  397  * nat_flushtable - clear the NAT table of all mapping entries.
  398  */
  399 static int nat_flushtable()
  400 {
  401         register nat_t *nat, **natp;
  402         register int j = 0;
  403   
  404         /*
  405          * Everything will be deleted, so lets just make it the deletions
  406          * quicker.
  407          */
  408         bzero((char *)nat_table[0], sizeof(nat_table[0]));
  409         bzero((char *)nat_table[1], sizeof(nat_table[1]));
  410 
  411         for (natp = &nat_instances; (nat = *natp); ) {
  412                 *natp = nat->nat_next;
  413                 nat_delete(nat);
  414                 j++;
  415         }
  416 
  417         return j;
  418 }
  419 
  420 
  421 /*
  422  * nat_clearlist - delete all entries in the active NAT mapping list.
  423  */
  424 static int nat_clearlist()
  425 {
  426         register ipnat_t *n, **np = &nat_list;
  427         int i = 0;
  428 
  429         while ((n = *np)) {
  430                 *np = n->in_next;
  431                 if (!n->in_use) {
  432                         if (n->in_apr)
  433                                 ap_free(n->in_apr);
  434                         KFREE(n);
  435                         nat_stats.ns_rules--;
  436                         i++;
  437                 } else {
  438                         n->in_flags |= IPN_DELETE;
  439                         n->in_next = NULL;
  440                 }
  441         }
  442         nat_stats.ns_inuse = 0;
  443         return i;
  444 }
  445 
  446 
  447 /*
  448  * return the first IP Address associated with an interface
  449  */
  450 static int nat_ifpaddr(nat, ifptr, inp)
  451 nat_t *nat;
  452 void *ifptr;
  453 struct in_addr *inp;
  454 {
  455 #if SOLARIS
  456         ill_t *ill = ifptr;
  457 #else
  458         struct ifnet *ifp = ifptr;
  459 #endif
  460         struct in_addr in;
  461 
  462 #if SOLARIS
  463         in.s_addr = ntohl(ill->ill_ipif->ipif_local_addr);
  464 #else /* SOLARIS */
  465 # if linux
  466         ;
  467 # else /* linux */
  468         struct ifaddr *ifa;
  469         struct sockaddr_in *sin;
  470 
  471 #  if   (__FreeBSD_version >= 300000)
  472         ifa = TAILQ_FIRST(&ifp->if_addrhead);
  473 #  else
  474 #   if defined(__NetBSD__) || defined(__OpenBSD__)
  475         ifa = ifp->if_addrlist.tqh_first;
  476 #   else
  477 #    if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */
  478         ifa = &((struct in_ifaddr *)ifp->in_ifaddr)->ia_ifa;
  479 #    else
  480         ifa = ifp->if_addrlist;
  481 #    endif
  482 #   endif /* __NetBSD__ || __OpenBSD__ */
  483 #  endif /* __FreeBSD_version >= 300000 */
  484 #  if (BSD < 199306) && !(/*IRIX6*/defined(__sgi) && defined(IFF_DRVRLOCK))
  485         sin = (SOCKADDR_IN *)&ifa->ifa_addr;
  486 #  else
  487         sin = (SOCKADDR_IN *)ifa->ifa_addr;
  488         while (sin && ifa &&
  489                sin->sin_family != AF_INET) {
  490 #   if  (__FreeBSD_version >= 300000)
  491                 ifa = TAILQ_NEXT(ifa, ifa_link);
  492 #   else
  493 #    if defined(__NetBSD__) || defined(__OpenBSD__)
  494                 ifa = ifa->ifa_list.tqe_next;
  495 #    else
  496                 ifa = ifa->ifa_next;
  497 #    endif
  498 #   endif /* __FreeBSD_version >= 300000 */
  499                 if (ifa)
  500                         sin = (SOCKADDR_IN *)ifa->ifa_addr;
  501         }
  502         if (!ifa)
  503                 sin = NULL;
  504         if (!sin) {
  505                 KFREE(nat);
  506                 return -1;
  507         }
  508 #  endif /* (BSD < 199306) && (!__sgi && IFF_DRVLOCK) */
  509         in = sin->sin_addr;
  510         in.s_addr = ntohl(in.s_addr);
  511 # endif /* linux */
  512 #endif /* SOLARIS */
  513         *inp = in;
  514         return 0;
  515 }
  516 
  517 
  518 /*
  519  * Create a new NAT table entry.
  520  */
  521 nat_t *nat_new(np, ip, fin, flags, direction)
  522 ipnat_t *np;
  523 ip_t *ip;
  524 fr_info_t *fin;
  525 u_short flags;
  526 int direction;
  527 {
  528         register u_32_t sum1, sum2, sumd, l;
  529         u_short port = 0, sport = 0, dport = 0, nport = 0;
  530         struct in_addr in;
  531         tcphdr_t *tcp = NULL;
  532         nat_t *nat, **natp;
  533         u_short nflags;
  534 
  535         nflags = flags & np->in_flags;
  536         if (flags & IPN_TCPUDP) {
  537                 tcp = (tcphdr_t *)fin->fin_dp;
  538                 sport = tcp->th_sport;
  539                 dport = tcp->th_dport;
  540         }
  541 
  542         /* Give me a new nat */
  543         KMALLOC(nat, nat_t *, sizeof(*nat));
  544         if (nat == NULL)
  545                 return NULL;
  546 
  547         bzero((char *)nat, sizeof(*nat));
  548         nat->nat_flags = flags;
  549 
  550         /*
  551          * Search the current table for a match.
  552          */
  553         if (direction == NAT_OUTBOUND) {
  554                 /*
  555                  * If it's an outbound packet which doesn't match any existing
  556                  * record, then create a new port
  557                  */
  558                 l = 0;
  559                 do {
  560                         l++;
  561                         port = 0;
  562                         in.s_addr = np->in_nip;
  563                         if (!in.s_addr && (np->in_outmsk == 0xffffffff)) {
  564                                 if ((l > 1) ||
  565                                     nat_ifpaddr(nat, fin->fin_ifp, &in) == -1) {
  566                                         KFREE(nat);
  567                                         return NULL;
  568                                 }
  569                         } else if (!in.s_addr && !np->in_outmsk) {
  570                                 if (l > 1) {
  571                                         KFREE(nat);
  572                                         return NULL;
  573                                 }
  574                                 in.s_addr = ntohl(ip->ip_src.s_addr);
  575                                 if (nflags & IPN_TCPUDP)
  576                                         port = sport;
  577                         } else if (nflags & IPN_TCPUDP) {
  578                                 port = htons(np->in_pnext++);
  579                                 if (np->in_pnext >= ntohs(np->in_pmax)) {
  580                                         np->in_pnext = ntohs(np->in_pmin);
  581                                         np->in_space--;
  582                                         if (np->in_outmsk != 0xffffffff)
  583                                                 np->in_nip++;
  584                                 }
  585                         } else if (np->in_outmsk != 0xffffffff) {
  586                                 np->in_space--;
  587                                 np->in_nip++;
  588                         }
  589 
  590                         if (!port && (flags & IPN_TCPUDP))
  591                                 port = sport;
  592                         if ((np->in_nip & ntohl(np->in_outmsk)) >
  593                             ntohl(np->in_outip))
  594                                 np->in_nip = ntohl(np->in_outip) + 1;
  595                 } while (nat_inlookup(fin->fin_ifp, flags, ip->ip_dst,
  596                                       dport, in, port));
  597 
  598                 /* Setup the NAT table */
  599                 nat->nat_inip = ip->ip_src;
  600                 nat->nat_outip.s_addr = htonl(in.s_addr);
  601                 nat->nat_oip = ip->ip_dst;
  602 
  603                 sum1 = (ntohl(ip->ip_src.s_addr) & 0xffff) +
  604                         (ntohl(ip->ip_src.s_addr) >> 16) + ntohs(sport);
  605 
  606                 sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16) + ntohs(port);
  607 
  608                 if (flags & IPN_TCPUDP) {
  609                         nat->nat_inport = sport;
  610                         nat->nat_outport = port;
  611                         nat->nat_oport = dport;
  612                 }
  613         } else {
  614 
  615                 /*
  616                  * Otherwise, it's an inbound packet. Most likely, we don't
  617                  * want to rewrite source ports and source addresses. Instead,
  618                  * we want to rewrite to a fixed internal address and fixed
  619                  * internal port.
  620                  */
  621                 in.s_addr = ntohl(np->in_inip);
  622                 if (!(nport = np->in_pnext))
  623                         nport = dport;
  624 
  625                 nat->nat_inip.s_addr = htonl(in.s_addr);
  626                 nat->nat_outip = ip->ip_dst;
  627                 nat->nat_oip = ip->ip_src;
  628 
  629                 sum1 = (ntohl(ip->ip_dst.s_addr) & 0xffff) +
  630                         (ntohl(ip->ip_dst.s_addr) >> 16) + ntohs(dport);
  631 
  632                 sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16) + ntohs(nport);
  633 
  634                 if (flags & IPN_TCPUDP) {
  635                         nat->nat_inport = nport;
  636                         nat->nat_outport = dport;
  637                         nat->nat_oport = sport;
  638                 }
  639         }
  640 
  641         /* Do it twice */
  642         sum1 = (sum1 & 0xffff) + (sum1 >> 16);
  643         sum1 = (sum1 & 0xffff) + (sum1 >> 16);
  644 
  645         /* Do it twice */
  646         sum2 = (sum2 & 0xffff) + (sum2 >> 16);
  647         sum2 = (sum2 & 0xffff) + (sum2 >> 16);
  648 
  649         if (sum1 > sum2)
  650                 sum2--; /* Because ~1 == -2, We really need ~1 == -1 */
  651         sumd = sum2 - sum1;
  652         sumd = (sumd & 0xffff) + (sumd >> 16);
  653         nat->nat_sumd = (sumd & 0xffff) + (sumd >> 16);
  654 
  655         if ((flags & IPN_TCPUDP) && ((sport != port) || (dport != nport))) {
  656                 if (direction == NAT_OUTBOUND)
  657                         sum1 = (ntohl(ip->ip_src.s_addr) & 0xffff) +
  658                                 (ntohl(ip->ip_src.s_addr) >> 16);
  659                 else
  660                         sum1 = (ntohl(ip->ip_dst.s_addr) & 0xffff) +
  661                                 (ntohl(ip->ip_dst.s_addr) >> 16);
  662 
  663                 sum2 = (in.s_addr & 0xffff) + (in.s_addr >> 16);
  664 
  665                 /* Do it twice */
  666                 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
  667                 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
  668 
  669                 /* Do it twice */
  670                 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
  671                 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
  672 
  673                 if (sum1 > sum2)
  674                         sum2--; /* Because ~1 == -2, We really need ~1 == -1 */
  675                 sumd = sum2 - sum1;
  676                 sumd = (sumd & 0xffff) + (sumd >> 16);
  677                 nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
  678         } else
  679                 nat->nat_ipsumd = nat->nat_sumd;
  680 
  681         in.s_addr = htonl(in.s_addr);
  682         nat->nat_next = nat_instances;
  683         nat_instances = nat;
  684         natp = &nat_table[0][nat->nat_inip.s_addr % NAT_SIZE];
  685         nat->nat_hstart[0] = natp;
  686         nat->nat_hnext[0] = *natp;
  687         *natp = nat;
  688         natp = &nat_table[1][nat->nat_outip.s_addr % NAT_SIZE];
  689         nat->nat_hstart[1] = natp;
  690         nat->nat_hnext[1] = *natp;
  691         *natp = nat;
  692         nat->nat_ptr = np;
  693         nat->nat_bytes = 0;
  694         nat->nat_pkts = 0;
  695         nat->nat_ifp = fin->fin_ifp;
  696         nat->nat_dir = direction;
  697         if (direction == NAT_OUTBOUND) {
  698                 if (flags & IPN_TCPUDP)
  699                         tcp->th_sport = port;
  700         } else {
  701                 if (flags & IPN_TCPUDP)
  702                         tcp->th_dport = nport;
  703         }
  704         nat_stats.ns_added++;
  705         nat_stats.ns_inuse++;
  706         np->in_use++;
  707         return nat;
  708 }
  709 
  710 
  711 nat_t *nat_icmpinlookup(ip, fin)
  712 ip_t *ip;
  713 fr_info_t *fin;
  714 {
  715         icmphdr_t *icmp;
  716         tcphdr_t *tcp = NULL;
  717         ip_t *oip;
  718         int flags = 0, type;
  719 
  720         icmp = (icmphdr_t *)fin->fin_dp;
  721         /*
  722          * Does it at least have the return (basic) IP header ?
  723          * Only a basic IP header (no options) should be with an ICMP error
  724          * header.
  725          */
  726         if ((ip->ip_hl != 5) || (ip->ip_len < sizeof(*icmp) + sizeof(ip_t)))
  727                 return NULL;
  728         type = icmp->icmp_type;
  729         /*
  730          * If it's not an error type, then return.
  731          */
  732         if ((type != ICMP_UNREACH) && (type != ICMP_SOURCEQUENCH) &&
  733             (type != ICMP_REDIRECT) && (type != ICMP_TIMXCEED) &&
  734             (type != ICMP_PARAMPROB))
  735                 return NULL;
  736 
  737         oip = (ip_t *)((char *)fin->fin_dp + 8);
  738         if (oip->ip_p == IPPROTO_TCP)
  739                 flags = IPN_TCP;
  740         else if (oip->ip_p == IPPROTO_UDP)
  741                 flags = IPN_UDP;
  742         if (flags & IPN_TCPUDP) {
  743                 tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2));
  744                 return nat_inlookup(fin->fin_ifp, flags, oip->ip_dst,
  745                                     tcp->th_dport, oip->ip_src, tcp->th_sport);
  746         }
  747         return nat_inlookup(fin->fin_ifp, 0, oip->ip_src, 0, oip->ip_dst, 0);
  748 }
  749 
  750 
  751 /*
  752  * This should *ONLY* be used for incoming packets to make sure a NAT'd ICMP
  753  * packet gets correctly recognised.
  754  */
  755 nat_t *nat_icmpin(ip, fin, nflags)
  756 ip_t *ip;
  757 fr_info_t *fin;
  758 int *nflags;
  759 {
  760         icmphdr_t *icmp;
  761         nat_t *nat;
  762         ip_t *oip;
  763         int flags = 0;
  764 
  765         if (!(nat = nat_icmpinlookup(ip, fin)))
  766                 return NULL;
  767 
  768         *nflags = IPN_ICMPERR;
  769         icmp = (icmphdr_t *)fin->fin_dp;
  770         oip = (ip_t *)((char *)icmp + 8);
  771         if (oip->ip_p == IPPROTO_TCP)
  772                 flags = IPN_TCP;
  773         else if (oip->ip_p == IPPROTO_UDP)
  774                 flags = IPN_UDP;
  775         /*
  776          * Need to adjust ICMP header to include the real IP#'s and
  777          * port #'s.  Only apply a checksum change relative to the
  778          * IP address change is it will be modified again in ip_natout
  779          * for both address and port.  Two checksum changes are
  780          * necessary for the two header address changes.  Be careful
  781          * to only modify the checksum once for the port # and twice
  782          * for the IP#.
  783          */
  784         if (flags & IPN_TCPUDP) {
  785                 tcphdr_t *tcp = (tcphdr_t *)(oip + 1);
  786                 u_32_t  sum1, sum2, sumd;
  787                 struct in_addr in;
  788 
  789                 if (nat->nat_dir == NAT_OUTBOUND) {
  790                         sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr));
  791                         in = nat->nat_outip;
  792                         oip->ip_src = in;
  793                         tcp->th_sport = nat->nat_outport;
  794                 } else {
  795                         sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr));
  796                         in = nat->nat_inip;
  797                         oip->ip_dst = in;
  798                         tcp->th_dport = nat->nat_inport;
  799                 }
  800 
  801                 sum2 = LONG_SUM(in.s_addr);
  802 
  803                 CALC_SUMD(sum1, sum2, sumd);
  804                 sumd = (sumd & 0xffff) + (sumd >> 16);
  805 
  806                 if (nat->nat_dir == NAT_OUTBOUND) {
  807                         fix_incksum(&oip->ip_sum, sumd);
  808                         fix_incksum(&icmp->icmp_cksum, sumd);
  809                 } else {
  810                         fix_outcksum(&oip->ip_sum, sumd);
  811                         fix_outcksum(&icmp->icmp_cksum, sumd);
  812                 }
  813 
  814                 /*
  815                  * TCP checksum doesn't make it into the 1st eight
  816                  * bytes but UDP does.
  817                  */
  818                 if (ip->ip_p == IPPROTO_UDP) {
  819                         udphdr_t *udp = (udphdr_t *)tcp;
  820 
  821                         if (udp->uh_sum) {
  822                                 if (nat->nat_dir == NAT_OUTBOUND)
  823                                         fix_incksum(&udp->uh_sum,
  824                                                     nat->nat_sumd);
  825                                 else
  826                                         fix_outcksum(&udp->uh_sum,
  827                                                      nat->nat_sumd);
  828                         }
  829                 }
  830         } else
  831                 ip->ip_dst = nat->nat_outip;
  832         nat->nat_age = fr_defnaticmpage;
  833         return nat;
  834 }
  835 
  836 
  837 /*
  838  * NB: these lookups don't lock access to the list, it assume it has already
  839  * been done!
  840  */
  841 /*
  842  * Lookup a nat entry based on the mapped destination ip address/port and
  843  * real source address/port.  We use this lookup when receiving a packet,
  844  * we're looking for a table entry, based on the destination address.
  845  * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.
  846  */
  847 #ifdef __STDC__
  848 nat_t *nat_inlookup(void *ifp, int flags, struct in_addr src, u_short sport, struct in_addr mapdst, u_short mapdport)
  849 #else
  850 nat_t *nat_inlookup(ifp, flags, src, sport, mapdst, mapdport)
  851 void *ifp;
  852 register int flags;
  853 struct in_addr src , mapdst;
  854 u_short sport, mapdport;
  855 #endif
  856 {
  857         register nat_t *nat;
  858 
  859         flags &= IPN_TCPUDP;
  860 
  861         nat = nat_table[1][mapdst.s_addr % NAT_SIZE];
  862         for (; nat; nat = nat->nat_hnext[1])
  863                 if ((!ifp || ifp == nat->nat_ifp) &&
  864                     nat->nat_oip.s_addr == src.s_addr &&
  865                     nat->nat_outip.s_addr == mapdst.s_addr &&
  866                     flags == nat->nat_flags && (!flags ||
  867                      (nat->nat_oport == sport &&
  868                       nat->nat_outport == mapdport)))
  869                         return nat;
  870         return NULL;
  871 }
  872 
  873 
  874 /*
  875  * Lookup a nat entry based on the source 'real' ip address/port and
  876  * destination address/port.  We use this lookup when sending a packet out,
  877  * we're looking for a table entry, based on the source address.
  878  * NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.
  879  */
  880 #ifdef __STDC__
  881 nat_t *nat_outlookup(void *ifp, int flags, struct in_addr src, u_short sport, struct in_addr dst, u_short dport)
  882 #else
  883 nat_t *nat_outlookup(ifp, flags, src, sport, dst, dport)
  884 void *ifp;
  885 register int flags;
  886 struct in_addr src , dst;
  887 u_short sport, dport;
  888 #endif
  889 {
  890         register nat_t *nat;
  891 
  892         flags &= IPN_TCPUDP;
  893 
  894         nat = nat_table[0][src.s_addr % NAT_SIZE];
  895         for (; nat; nat = nat->nat_hnext[0]) {
  896                 if ((!ifp || ifp == nat->nat_ifp) &&
  897                     nat->nat_inip.s_addr == src.s_addr &&
  898                     nat->nat_oip.s_addr == dst.s_addr &&
  899                     flags == nat->nat_flags && (!flags ||
  900                      (nat->nat_inport == sport && nat->nat_oport == dport)))
  901                         return nat;
  902         }
  903         return NULL;
  904 }
  905 
  906 
  907 /*
  908  * Lookup a nat entry based on the mapped source ip address/port and
  909  * real destination address/port.  We use this lookup when sending a packet
  910  * out, we're looking for a table entry, based on the source address.
  911  */
  912 #ifdef __STDC__
  913 nat_t *nat_lookupmapip(void *ifp, int flags, struct in_addr mapsrc, u_short mapsport, struct in_addr dst, u_short dport)
  914 #else
  915 nat_t *nat_lookupmapip(ifp, flags, mapsrc, mapsport, dst, dport)
  916 void *ifp;
  917 register int flags;
  918 struct in_addr mapsrc , dst;
  919 u_short mapsport, dport;
  920 #endif
  921 {
  922         register nat_t *nat;
  923 
  924         flags &= IPN_TCPUDP;
  925 
  926         nat = nat_table[1][mapsrc.s_addr % NAT_SIZE];
  927         for (; nat; nat = nat->nat_hnext[0])
  928                 if ((!ifp || ifp == nat->nat_ifp) &&
  929                     nat->nat_oip.s_addr == dst.s_addr &&
  930                     nat->nat_outip.s_addr == mapsrc.s_addr &&
  931                     flags == nat->nat_flags && (!flags ||
  932                      (nat->nat_outport == mapsport &&
  933                       nat->nat_oport == dport)))
  934                         return nat;
  935         return NULL;
  936 }
  937 
  938 
  939 /*
  940  * Lookup the NAT tables to search for a matching redirect
  941  */
  942 nat_t *nat_lookupredir(np)
  943 register natlookup_t *np;
  944 {
  945         nat_t *nat;
  946 
  947         /*
  948          * If nl_inip is non null, this is a lookup based on the real
  949          * ip address. Else, we use the fake.
  950          */
  951         if ((nat = nat_outlookup(NULL, np->nl_flags, np->nl_inip,
  952                                  np->nl_inport, np->nl_outip,
  953                                  np->nl_outport))) {
  954                 np->nl_realip = nat->nat_outip;
  955                 np->nl_realport = nat->nat_outport;
  956         }
  957         return nat;
  958 }
  959 
  960 
  961 /*
  962  * Packets going out on the external interface go through this.
  963  * Here, the source address requires alteration, if anything.
  964  */
  965 int ip_natout(ip, hlen, fin)
  966 ip_t *ip;
  967 int hlen;
  968 fr_info_t *fin;
  969 {
  970         register ipnat_t *np;
  971         register u_32_t ipa;
  972         tcphdr_t *tcp = NULL;
  973         u_short nflags = 0, sport = 0, dport = 0, *csump = NULL;
  974         struct ifnet *ifp;
  975         frentry_t *fr;
  976         nat_t *nat;
  977         int natadd = 1;
  978 
  979         if ((fr = fin->fin_fr) && !(fr->fr_flags & FR_DUP) &&
  980             fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1)
  981                 ifp = fr->fr_tif.fd_ifp;
  982         else
  983                 ifp = fin->fin_ifp;
  984 
  985         if (!(ip->ip_off & 0x1fff) && !(fin->fin_fi.fi_fl & FI_SHORT)) {
  986                 if (ip->ip_p == IPPROTO_TCP)
  987                         nflags = IPN_TCP;
  988                 else if (ip->ip_p == IPPROTO_UDP)
  989                         nflags = IPN_UDP;
  990                 if (nflags) {
  991                         tcp = (tcphdr_t *)fin->fin_dp;
  992                         sport = tcp->th_sport;
  993                         dport = tcp->th_dport;
  994                 }
  995         }
  996 
  997         ipa = ip->ip_src.s_addr;
  998 
  999         MUTEX_ENTER(&ipf_nat);
 1000         if ((ip->ip_off & (IP_OFFMASK|IP_MF)) &&
 1001             (nat = ipfr_nat_knownfrag(ip, fin)))
 1002                 natadd = 0;
 1003         else if ((nat = nat_outlookup(ifp, nflags, ip->ip_src, sport,
 1004                                       ip->ip_dst, dport)))
 1005                 ;
 1006         else
 1007                 /*
 1008                  * If there is no current entry in the nat table for this IP#,
 1009                  * create one for it (if there is a matching rule).
 1010                  */
 1011                 for (np = nat_list; np; np = np->in_next)
 1012                         if ((np->in_ifp == ifp) && np->in_space &&
 1013                             (!np->in_flags || (np->in_flags & nflags)) &&
 1014                             ((ipa & np->in_inmsk) == np->in_inip) &&
 1015                             ((np->in_redir & NAT_MAP) ||
 1016                              (np->in_pnext == sport))) {
 1017                                 if (*np->in_plabel && !ap_ok(ip, tcp, np))
 1018                                         continue;
 1019                                 /*
 1020                                  * If it's a redirection, then we don't want to
 1021                                  * create new outgoing port stuff.
 1022                                  * Redirections are only for incoming
 1023                                  * connections.
 1024                                  */
 1025                                 if (!(np->in_redir & NAT_MAP))
 1026                                         continue;
 1027                                 if ((nat = nat_new(np, ip, fin, nflags,
 1028                                                     NAT_OUTBOUND)))
 1029 #ifdef  IPFILTER_LOG
 1030                                         nat_log(nat, (u_short)np->in_redir);
 1031 #else
 1032                                         ;
 1033 #endif
 1034                                 break;
 1035                         }
 1036 
 1037         if (nat) {
 1038                         if (natadd && fin->fin_fi.fi_fl & FI_FRAG)
 1039                                 ipfr_nat_newfrag(ip, fin, 0, nat);
 1040                         nat->nat_age = fr_defnatage;
 1041                         ip->ip_src = nat->nat_outip;
 1042                         nat->nat_bytes += ip->ip_len;
 1043                         nat->nat_pkts++;
 1044 
 1045                         /*
 1046                          * Fix up checksums, not by recalculating them, but
 1047                          * simply computing adjustments.
 1048                          */
 1049 #if SOLARIS || defined(__sgi)
 1050                         if (nat->nat_dir == NAT_OUTBOUND)
 1051                                 fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);
 1052                         else
 1053                                 fix_incksum(&ip->ip_sum, nat->nat_ipsumd);
 1054 #endif
 1055 
 1056                         if (nflags && !(ip->ip_off & 0x1fff) &&
 1057                             !(fin->fin_fi.fi_fl & FI_SHORT)) {
 1058 
 1059                                 if (nat->nat_outport)
 1060                                         tcp->th_sport = nat->nat_outport;
 1061 
 1062                                 if (ip->ip_p == IPPROTO_TCP) {
 1063                                         csump = &tcp->th_sum;
 1064                                         fr_tcp_age(&nat->nat_age,
 1065                                                    nat->nat_state, ip, fin,1);
 1066                                         /*
 1067                                          * Increase this because we may have
 1068                                          * "keep state" following this too and
 1069                                          * packet storms can occur if this is
 1070                                          * removed too quickly.
 1071                                          */
 1072                                         if (nat->nat_age == fr_tcpclosed)
 1073                                                 nat->nat_age = fr_tcplastack;
 1074                                 } else if (ip->ip_p == IPPROTO_UDP) {
 1075                                         udphdr_t *udp = (udphdr_t *)tcp;
 1076 
 1077                                         if (udp->uh_sum)
 1078                                                 csump = &udp->uh_sum;
 1079                                 } else if (ip->ip_p == IPPROTO_ICMP) {
 1080                                         icmphdr_t *ic = (icmphdr_t *)tcp;
 1081 
 1082                                         csump = &ic->icmp_cksum;
 1083                                 }
 1084                                 if (csump) {
 1085                                         if (nat->nat_dir == NAT_OUTBOUND)
 1086                                                 fix_outcksum(csump,
 1087                                                              nat->nat_sumd);
 1088                                         else
 1089                                                 fix_incksum(csump,
 1090                                                             nat->nat_sumd);
 1091                                 }
 1092                         }
 1093                         (void) ap_check(ip, tcp, fin, nat);
 1094                         nat_stats.ns_mapped[1]++;
 1095                         MUTEX_EXIT(&ipf_nat);
 1096                         return -2;
 1097                 }
 1098         MUTEX_EXIT(&ipf_nat);
 1099         return 0;
 1100 }
 1101 
 1102 
 1103 /*
 1104  * Packets coming in from the external interface go through this.
 1105  * Here, the destination address requires alteration, if anything.
 1106  */
 1107 int ip_natin(ip, hlen, fin)
 1108 ip_t *ip;
 1109 int hlen;
 1110 fr_info_t *fin;
 1111 {
 1112         register ipnat_t *np;
 1113         register struct in_addr in;
 1114         struct ifnet *ifp = fin->fin_ifp;
 1115         tcphdr_t *tcp = NULL;
 1116         u_short sport = 0, dport = 0, *csump = NULL;
 1117         nat_t *nat;
 1118         int nflags = 0, natadd = 1;
 1119 
 1120         if (!(ip->ip_off & 0x1fff) && !(fin->fin_fi.fi_fl & FI_SHORT)) {
 1121                 if (ip->ip_p == IPPROTO_TCP)
 1122                         nflags = IPN_TCP;
 1123                 else if (ip->ip_p == IPPROTO_UDP)
 1124                         nflags = IPN_UDP;
 1125                 if (nflags) {
 1126                         tcp = (tcphdr_t *)((char *)ip + hlen);
 1127                         dport = tcp->th_dport;
 1128                         sport = tcp->th_sport;
 1129                 }
 1130         }
 1131 
 1132         in = ip->ip_dst;
 1133 
 1134         MUTEX_ENTER(&ipf_nat);
 1135 
 1136         if ((ip->ip_p == IPPROTO_ICMP) && (nat = nat_icmpin(ip, fin, &nflags)))
 1137                 ;
 1138         else if ((ip->ip_off & IP_OFFMASK) &&
 1139                  (nat = ipfr_nat_knownfrag(ip, fin)))
 1140                 natadd = 0;
 1141         else if ((nat = nat_inlookup(fin->fin_ifp, nflags, ip->ip_src, sport,
 1142                                      ip->ip_dst, dport)))
 1143                 ;
 1144         else
 1145                 /*
 1146                  * If there is no current entry in the nat table for this IP#,
 1147                  * create one for it (if there is a matching rule).
 1148                  */
 1149                 for (np = nat_list; np; np = np->in_next)
 1150                         if ((np->in_ifp == ifp) &&
 1151                             (!np->in_flags || (nflags & np->in_flags)) &&
 1152                             ((in.s_addr & np->in_outmsk) == np->in_outip) &&
 1153                             (np->in_redir & NAT_REDIRECT) &&
 1154                              (!np->in_pmin || np->in_pmin == dport)) {
 1155                                 if ((nat = nat_new(np, ip, fin, nflags,
 1156                                                     NAT_INBOUND)))
 1157 #ifdef  IPFILTER_LOG
 1158                                         nat_log(nat, (u_short)np->in_redir);
 1159 #else
 1160                                         ;
 1161 #endif
 1162                                 break;
 1163                         }
 1164         if (nat) {
 1165                         if (natadd && fin->fin_fi.fi_fl & FI_FRAG)
 1166                                 ipfr_nat_newfrag(ip, fin, 0, nat);
 1167                         (void) ap_check(ip, tcp, fin, nat);
 1168 
 1169                         if (nflags != IPN_ICMPERR)
 1170                                 nat->nat_age = fr_defnatage;
 1171 
 1172                         ip->ip_dst = nat->nat_inip;
 1173                         nat->nat_bytes += ip->ip_len;
 1174                         nat->nat_pkts++;
 1175 
 1176                         /*
 1177                          * Fix up checksums, not by recalculating them, but
 1178                          * simply computing adjustments.
 1179                          */
 1180 #if SOLARIS || defined(__sgi)
 1181                         if (nat->nat_dir == NAT_OUTBOUND)
 1182                                 fix_incksum(&ip->ip_sum, nat->nat_ipsumd);
 1183                         else
 1184                                 fix_outcksum(&ip->ip_sum, nat->nat_ipsumd);
 1185 #endif
 1186                         if ((nflags & IPN_TCPUDP) && !(ip->ip_off & 0x1fff) &&
 1187                             !(fin->fin_fi.fi_fl & FI_SHORT)) {
 1188 
 1189                                 if (nat->nat_inport)
 1190                                         tcp->th_dport = nat->nat_inport;
 1191 
 1192                                 if (ip->ip_p == IPPROTO_TCP) {
 1193                                         csump = &tcp->th_sum;
 1194                                         fr_tcp_age(&nat->nat_age,
 1195                                                    nat->nat_state, ip, fin,0);
 1196                                         /*
 1197                                          * Increase this because we may have
 1198                                          * "keep state" following this too and
 1199                                          * packet storms can occur if this is
 1200                                          * removed too quickly.
 1201                                          */
 1202                                         if (nat->nat_age == fr_tcpclosed)
 1203                                                 nat->nat_age = fr_tcplastack;
 1204                                 } else if (ip->ip_p == IPPROTO_UDP) {
 1205                                         udphdr_t *udp = (udphdr_t *)tcp;
 1206 
 1207                                         if (udp->uh_sum)
 1208                                                 csump = &udp->uh_sum;
 1209                                 } else if (ip->ip_p == IPPROTO_ICMP) {
 1210                                         icmphdr_t *ic = (icmphdr_t *)tcp;
 1211 
 1212                                         csump = &ic->icmp_cksum;
 1213                                 }
 1214                                 if (csump) {
 1215                                         if (nat->nat_dir == NAT_OUTBOUND)
 1216                                                 fix_incksum(csump,
 1217                                                             nat->nat_sumd);
 1218                                         else
 1219                                                 fix_outcksum(csump,
 1220                                                              nat->nat_sumd);
 1221                                 }
 1222                         }
 1223                         nat_stats.ns_mapped[0]++;
 1224                         MUTEX_EXIT(&ipf_nat);
 1225                         return -2;
 1226                 }
 1227         MUTEX_EXIT(&ipf_nat);
 1228         return 0;
 1229 }
 1230 
 1231 
 1232 /*
 1233  * Free all memory used by NAT structures allocated at runtime.
 1234  */
 1235 void ip_natunload()
 1236 {
 1237         MUTEX_ENTER(&ipf_nat);
 1238         (void) nat_clearlist();
 1239         (void) nat_flushtable();
 1240         (void) ap_unload();
 1241         MUTEX_EXIT(&ipf_nat);
 1242 }
 1243 
 1244 
 1245 /*
 1246  * Slowly expire held state for NAT entries.  Timeouts are set in
 1247  * expectation of this being called twice per second.
 1248  */
 1249 void ip_natexpire()
 1250 {
 1251         register struct nat *nat, **natp;
 1252 #if defined(_KERNEL) && !SOLARIS
 1253         int s;
 1254 #endif
 1255 
 1256         SPL_NET(s);
 1257         MUTEX_ENTER(&ipf_nat);
 1258         for (natp = &nat_instances; (nat = *natp); ) {
 1259                 if (--nat->nat_age) {
 1260                         natp = &nat->nat_next;
 1261                         continue;
 1262                 }
 1263                 *natp = nat->nat_next;
 1264 #ifdef  IPFILTER_LOG
 1265                 nat_log(nat, NL_EXPIRE);
 1266 #endif
 1267                 nat_delete(nat);
 1268                 nat_stats.ns_expire++;
 1269         }
 1270 
 1271         ap_expire();
 1272 
 1273         MUTEX_EXIT(&ipf_nat);
 1274         SPL_X(s);
 1275 }
 1276 
 1277 
 1278 /*
 1279  */
 1280 #ifdef __STDC__
 1281 void ip_natsync(void *ifp)
 1282 #else
 1283 void ip_natsync(ifp)
 1284 void *ifp;
 1285 #endif
 1286 {
 1287         register nat_t *nat;
 1288         register u_32_t sum1, sum2, sumd;
 1289         struct in_addr in;
 1290         ipnat_t *np;
 1291 #if defined(_KERNEL) && !SOLARIS
 1292         int s;
 1293 #endif
 1294 
 1295         SPL_NET(s);
 1296         MUTEX_ENTER(&ipf_nat);
 1297         for (nat = nat_instances; nat; nat = nat->nat_next)
 1298                 if ((ifp == nat->nat_ifp) && (np = nat->nat_ptr))
 1299                         if ((np->in_outmsk == 0xffffffff) && !np->in_nip) {
 1300                                 /*
 1301                                  * Change the map-to address to be the same
 1302                                  * as the new one.
 1303                                  */
 1304                                 sum1 = nat->nat_outip.s_addr;
 1305                                 if (nat_ifpaddr(nat, ifp, &in) == -1)
 1306                                 nat->nat_outip.s_addr = htonl(in.s_addr);
 1307                                 sum2 = nat->nat_outip.s_addr;
 1308 
 1309                                 /*
 1310                                  * Readjust the checksum adjustment to take
 1311                                  * into account the new IP#.
 1312                                  *
 1313                                  * Do it twice
 1314                                  */
 1315                                 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
 1316                                 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
 1317 
 1318                                 /* Do it twice */
 1319                                 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
 1320                                 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
 1321 
 1322                                  /* Because ~1 == -2, We really need ~1 == -1 */
 1323                                 if (sum1 > sum2)
 1324                                         sum2--;
 1325                                 sumd = sum2 - sum1;
 1326                                 sumd = (sumd & 0xffff) + (sumd >> 16);
 1327                                 sumd += nat->nat_sumd;
 1328                                 nat->nat_sumd = (sumd & 0xffff) + (sumd >> 16);
 1329                         }
 1330         MUTEX_EXIT(&ipf_nat);
 1331         SPL_X(s);
 1332 }
 1333 
 1334 
 1335 #ifdef  IPFILTER_LOG
 1336 # ifdef __STDC__
 1337 void nat_log(struct nat *nat, u_short type)
 1338 # else
 1339 void nat_log(nat, type)
 1340 struct nat *nat;
 1341 u_short type;
 1342 # endif
 1343 {
 1344         struct ipnat *np;
 1345         struct natlog natl;
 1346         void *items[1];
 1347         size_t sizes[1];
 1348         int rulen, types[1];
 1349 
 1350         natl.nl_inip = nat->nat_inip;
 1351         natl.nl_outip = nat->nat_outip;
 1352         natl.nl_origip = nat->nat_oip;
 1353         natl.nl_bytes = nat->nat_bytes;
 1354         natl.nl_pkts = nat->nat_pkts;
 1355         natl.nl_origport = nat->nat_oport;
 1356         natl.nl_inport = nat->nat_inport;
 1357         natl.nl_outport = nat->nat_outport;
 1358         natl.nl_type = type;
 1359         natl.nl_rule = -1;
 1360         if (nat->nat_ptr) {
 1361                 for (rulen = 0, np = nat_list; np; np = np->in_next, rulen++)
 1362                         if (np == nat->nat_ptr) {
 1363                                 natl.nl_rule = rulen;
 1364                                 break;
 1365                         }
 1366         }
 1367         items[0] = &natl;
 1368         sizes[0] = sizeof(natl);
 1369         types[0] = 0;
 1370 
 1371         (void) ipllog(IPL_LOGNAT, 0, items, sizes, types, 1);
 1372 }
 1373 #endif

Cache object: d70d74180043f884d18e414d240d92ea


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