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


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

FreeBSD/Linux Kernel Cross Reference
sys/netpfil/ipfilter/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 /*      $FreeBSD$       */
    2 
    3 /*
    4  * Copyright (C) 2012 by Darren Reed.
    5  *
    6  * See the IPFILTER.LICENCE file for details on licencing.
    7  */
    8 #if defined(KERNEL) || defined(_KERNEL)
    9 # undef KERNEL
   10 # undef _KERNEL
   11 # define        KERNEL  1
   12 # define        _KERNEL 1
   13 #endif
   14 #include <sys/errno.h>
   15 #include <sys/types.h>
   16 #include <sys/param.h>
   17 #include <sys/time.h>
   18 #include <sys/file.h>
   19 #if defined(_KERNEL) && \
   20     (defined(__NetBSD_Version) && (__NetBSD_Version >= 399002000))
   21 # include <sys/kauth.h>
   22 #endif
   23 #if !defined(_KERNEL)
   24 # include <stdio.h>
   25 # include <string.h>
   26 # include <stdlib.h>
   27 # define KERNEL
   28 # ifdef _OpenBSD__
   29 struct file;
   30 # endif
   31 # include <sys/uio.h>
   32 # undef KERNEL
   33 #endif
   34 #if defined(_KERNEL) && defined(__FreeBSD__)
   35 # include <sys/filio.h>
   36 # include <sys/fcntl.h>
   37 #else
   38 # include <sys/ioctl.h>
   39 #endif
   40 # include <sys/fcntl.h>
   41 # include <sys/protosw.h>
   42 #include <sys/socket.h>
   43 #if defined(_KERNEL)
   44 # include <sys/systm.h>
   45 # if defined(__FreeBSD__)
   46 #  include <sys/jail.h>
   47 # endif
   48 # if !defined(__SVR4)
   49 #  include <sys/mbuf.h>
   50 # endif
   51 #endif
   52 #if defined(__SVR4)
   53 # include <sys/filio.h>
   54 # include <sys/byteorder.h>
   55 # ifdef KERNEL
   56 #  include <sys/dditypes.h>
   57 # endif
   58 # include <sys/stream.h>
   59 # include <sys/kmem.h>
   60 #endif
   61 #if defined(__FreeBSD__)
   62 # include <sys/queue.h>
   63 #endif
   64 #include <net/if.h>
   65 #if defined(__FreeBSD__)
   66 # include <net/if_var.h>
   67 #endif
   68 #ifdef sun
   69 # include <net/af.h>
   70 #endif
   71 #include <netinet/in.h>
   72 #include <netinet/in_systm.h>
   73 #include <netinet/ip.h>
   74 
   75 #ifdef RFC1825
   76 # include <vpn/md5.h>
   77 # include <vpn/ipsec.h>
   78 extern struct ifnet vpnif;
   79 #endif
   80 
   81 # include <netinet/ip_var.h>
   82 #include <netinet/tcp.h>
   83 #include <netinet/udp.h>
   84 #include <netinet/ip_icmp.h>
   85 #include "netinet/ip_compat.h"
   86 #include <netinet/tcpip.h>
   87 #include "netinet/ipl.h"
   88 #include "netinet/ip_fil.h"
   89 #include "netinet/ip_nat.h"
   90 #include "netinet/ip_frag.h"
   91 #include "netinet/ip_state.h"
   92 #include "netinet/ip_proxy.h"
   93 #include "netinet/ip_lookup.h"
   94 #include "netinet/ip_dstlist.h"
   95 #include "netinet/ip_sync.h"
   96 #if defined(__FreeBSD__)
   97 # include <sys/malloc.h>
   98 #endif
   99 #ifdef HAS_SYS_MD5_H
  100 # include <sys/md5.h>
  101 #else
  102 # include "md5.h"
  103 #endif
  104 /* END OF INCLUDES */
  105 
  106 #undef  SOCKADDR_IN
  107 #define SOCKADDR_IN     struct sockaddr_in
  108 
  109 #if !defined(lint)
  110 static const char sccsid[] = "@(#)ip_nat.c      1.11 6/5/96 (C) 1995 Darren Reed";
  111 static const char rcsid[] = "@(#)$FreeBSD$";
  112 /* static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.195.2.102 2007/10/16 10:08:10 darrenr Exp $"; */
  113 #endif
  114 
  115 
  116 #define NATFSUM(n,v,f)  ((v) == 4 ? (n)->f.in4.s_addr : (n)->f.i6[0] + \
  117                          (n)->f.i6[1] + (n)->f.i6[2] + (n)->f.i6[3])
  118 #define NBUMP(x)        softn->(x)++
  119 #define NBUMPD(x, y)    do { \
  120                                 softn->x.y++; \
  121                                 DT(y); \
  122                         } while (0)
  123 #define NBUMPSIDE(y,x)  softn->ipf_nat_stats.ns_side[y].x++
  124 #define NBUMPSIDED(y,x) do { softn->ipf_nat_stats.ns_side[y].x++; \
  125                              DT(x); } while (0)
  126 #define NBUMPSIDEX(y,x,z) \
  127                         do { softn->ipf_nat_stats.ns_side[y].x++; \
  128                              DT(z); } while (0)
  129 #define NBUMPSIDEDF(y,x)do { softn->ipf_nat_stats.ns_side[y].x++; \
  130                              DT1(x, fr_info_t *, fin); } while (0)
  131 
  132 static ipftuneable_t ipf_nat_tuneables[] = {
  133         /* nat */
  134         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_lock) },
  135                 "nat_lock",     0,      1,
  136                 stsizeof(ipf_nat_softc_t, ipf_nat_lock),
  137                 IPFT_RDONLY,            NULL,   NULL },
  138         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_sz) },
  139                 "nat_table_size", 1,    0x7fffffff,
  140                 stsizeof(ipf_nat_softc_t, ipf_nat_table_sz),
  141                 0,                      NULL,   ipf_nat_rehash },
  142         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_max) },
  143                 "nat_table_max", 1,     0x7fffffff,
  144                 stsizeof(ipf_nat_softc_t, ipf_nat_table_max),
  145                 0,                      NULL,   NULL },
  146         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maprules_sz) },
  147                 "nat_rules_size", 1,    0x7fffffff,
  148                 stsizeof(ipf_nat_softc_t, ipf_nat_maprules_sz),
  149                 0,                      NULL,   ipf_nat_rehash_rules },
  150         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_rdrrules_sz) },
  151                 "rdr_rules_size", 1,    0x7fffffff,
  152                 stsizeof(ipf_nat_softc_t, ipf_nat_rdrrules_sz),
  153                 0,                      NULL,   ipf_nat_rehash_rules },
  154         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_hostmap_sz) },
  155                 "hostmap_size", 1,      0x7fffffff,
  156                 stsizeof(ipf_nat_softc_t, ipf_nat_hostmap_sz),
  157                 0,                      NULL,   ipf_nat_hostmap_rehash },
  158         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_maxbucket) },
  159                 "nat_maxbucket",1,      0x7fffffff,
  160                 stsizeof(ipf_nat_softc_t, ipf_nat_maxbucket),
  161                 0,                      NULL,   NULL },
  162         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_logging) },
  163                 "nat_logging",  0,      1,
  164                 stsizeof(ipf_nat_softc_t, ipf_nat_logging),
  165                 0,                      NULL,   NULL },
  166         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_doflush) },
  167                 "nat_doflush",  0,      1,
  168                 stsizeof(ipf_nat_softc_t, ipf_nat_doflush),
  169                 0,                      NULL,   NULL },
  170         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_low) },
  171                 "nat_table_wm_low",     1,      99,
  172                 stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_low),
  173                 0,                      NULL,   NULL },
  174         { { (void *)offsetof(ipf_nat_softc_t, ipf_nat_table_wm_high) },
  175                 "nat_table_wm_high",    2,      100,
  176                 stsizeof(ipf_nat_softc_t, ipf_nat_table_wm_high),
  177                 0,                      NULL,   NULL },
  178         { { 0 },
  179                 NULL,                   0,      0,
  180                 0,
  181                 0,                      NULL,   NULL }
  182 };
  183 
  184 /* ======================================================================== */
  185 /* How the NAT is organised and works.                                      */
  186 /*                                                                          */
  187 /* Inside (interface y) NAT       Outside (interface x)                     */
  188 /* -------------------- -+- -------------------------------------           */
  189 /* Packet going          |   out, processsed by ipf_nat_checkout() for x    */
  190 /* ------------>         |   ------------>                                  */
  191 /* src=10.1.1.1          |   src=192.1.1.1                                  */
  192 /*                       |                                                  */
  193 /*                       |   in, processed by ipf_nat_checkin() for x       */
  194 /* <------------         |   <------------                                  */
  195 /* dst=10.1.1.1          |   dst=192.1.1.1                                  */
  196 /* -------------------- -+- -------------------------------------           */
  197 /* ipf_nat_checkout() - changes ip_src and if required, sport               */
  198 /*             - creates a new mapping, if required.                        */
  199 /* ipf_nat_checkin()  - changes ip_dst and if required, dport               */
  200 /*                                                                          */
  201 /* In the NAT table, internal source is recorded as "in" and externally     */
  202 /* seen as "out".                                                           */
  203 /* ======================================================================== */
  204 
  205 
  206 #if SOLARIS && !defined(INSTANCES)
  207 extern  int             pfil_delayed_copy;
  208 #endif
  209 
  210 static  int     ipf_nat_flush_entry(ipf_main_softc_t *, void *);
  211 static  int     ipf_nat_getent(ipf_main_softc_t *, caddr_t, int);
  212 static  int     ipf_nat_getsz(ipf_main_softc_t *, caddr_t, int);
  213 static  int     ipf_nat_putent(ipf_main_softc_t *, caddr_t, int);
  214 static  void    ipf_nat_addmap(ipf_nat_softc_t *, ipnat_t *);
  215 static  void    ipf_nat_addrdr(ipf_nat_softc_t *, ipnat_t *);
  216 static  int     ipf_nat_builddivertmp(ipf_nat_softc_t *, ipnat_t *);
  217 static  int     ipf_nat_clearlist(ipf_main_softc_t *, ipf_nat_softc_t *);
  218 static  int     ipf_nat_cmp_rules(ipnat_t *, ipnat_t *);
  219 static  int     ipf_nat_decap(fr_info_t *, nat_t *);
  220 static  void    ipf_nat_delrule(ipf_main_softc_t *, ipf_nat_softc_t *,
  221                                      ipnat_t *, int);
  222 static  int     ipf_nat_extraflush(ipf_main_softc_t *, ipf_nat_softc_t *, int);
  223 static  int     ipf_nat_finalise(fr_info_t *, nat_t *);
  224 static  int     ipf_nat_flushtable(ipf_main_softc_t *, ipf_nat_softc_t *);
  225 static  int     ipf_nat_getnext(ipf_main_softc_t *, ipftoken_t *,
  226                                      ipfgeniter_t *, ipfobj_t *);
  227 static  int     ipf_nat_gettable(ipf_main_softc_t *, ipf_nat_softc_t *,
  228                                       char *);
  229 static  hostmap_t *ipf_nat_hostmap(ipf_nat_softc_t *, ipnat_t *,
  230                                         struct in_addr, struct in_addr,
  231                                         struct in_addr, u_32_t);
  232 static  int     ipf_nat_icmpquerytype(int);
  233 static  int     ipf_nat_iterator(ipf_main_softc_t *, ipftoken_t *,
  234                                       ipfgeniter_t *, ipfobj_t *);
  235 static  int     ipf_nat_match(fr_info_t *, ipnat_t *);
  236 static  int     ipf_nat_matcharray(nat_t *, int *, u_long);
  237 static  int     ipf_nat_matchflush(ipf_main_softc_t *, ipf_nat_softc_t *,
  238                                         caddr_t);
  239 static  void    ipf_nat_mssclamp(tcphdr_t *, u_32_t, fr_info_t *,
  240                                       u_short *);
  241 static  int     ipf_nat_newmap(fr_info_t *, nat_t *, natinfo_t *);
  242 static  int     ipf_nat_newdivert(fr_info_t *, nat_t *, natinfo_t *);
  243 static  int     ipf_nat_newrdr(fr_info_t *, nat_t *, natinfo_t *);
  244 static  int     ipf_nat_newrewrite(fr_info_t *, nat_t *, natinfo_t *);
  245 static  int     ipf_nat_nextaddr(fr_info_t *, nat_addr_t *, u_32_t *,
  246                                       u_32_t *);
  247 static  int     ipf_nat_nextaddrinit(ipf_main_softc_t *, char *,
  248                                           nat_addr_t *, int, void *);
  249 static  int     ipf_nat_resolverule(ipf_main_softc_t *, ipnat_t *);
  250 static  int     ipf_nat_ruleaddrinit(ipf_main_softc_t *,
  251                                           ipf_nat_softc_t *, ipnat_t *);
  252 static  void    ipf_nat_rule_fini(ipf_main_softc_t *, ipnat_t *);
  253 static  int     ipf_nat_rule_init(ipf_main_softc_t *, ipf_nat_softc_t *,
  254                                        ipnat_t *);
  255 static  int     ipf_nat_siocaddnat(ipf_main_softc_t *, ipf_nat_softc_t *,
  256                                         ipnat_t *, int);
  257 static  void    ipf_nat_siocdelnat(ipf_main_softc_t *, ipf_nat_softc_t *,
  258                                         ipnat_t *, int);
  259 static  void    ipf_nat_tabmove(ipf_nat_softc_t *, nat_t *);
  260 
  261 /* ------------------------------------------------------------------------ */
  262 /* Function:    ipf_nat_main_load                                           */
  263 /* Returns:     int - 0 == success, -1 == failure                           */
  264 /* Parameters:  Nil                                                         */
  265 /*                                                                          */
  266 /* The only global NAT structure that needs to be initialised is the filter */
  267 /* rule that is used with blocking packets.                                 */
  268 /* ------------------------------------------------------------------------ */
  269 int
  270 ipf_nat_main_load(void)
  271 {
  272 
  273         return (0);
  274 }
  275 
  276 
  277 /* ------------------------------------------------------------------------ */
  278 /* Function:    ipf_nat_main_unload                                         */
  279 /* Returns:     int - 0 == success, -1 == failure                           */
  280 /* Parameters:  Nil                                                         */
  281 /*                                                                          */
  282 /* A null-op function that exists as a placeholder so that the flow in      */
  283 /* other functions is obvious.                                              */
  284 /* ------------------------------------------------------------------------ */
  285 int
  286 ipf_nat_main_unload(void)
  287 {
  288         return (0);
  289 }
  290 
  291 
  292 /* ------------------------------------------------------------------------ */
  293 /* Function:    ipf_nat_soft_create                                         */
  294 /* Returns:     void * - NULL = failure, else pointer to NAT context        */
  295 /* Parameters:  softc(I) - pointer to soft context main structure           */
  296 /*                                                                          */
  297 /* Allocate the initial soft context structure for NAT and populate it with */
  298 /* some default values. Creating the tables is left until we call _init so  */
  299 /* that sizes can be changed before we get under way.                       */
  300 /* ------------------------------------------------------------------------ */
  301 void *
  302 ipf_nat_soft_create(ipf_main_softc_t *softc)
  303 {
  304         ipf_nat_softc_t *softn;
  305 
  306         KMALLOC(softn, ipf_nat_softc_t *);
  307         if (softn == NULL)
  308                 return (NULL);
  309 
  310         bzero((char *)softn, sizeof(*softn));
  311 
  312         softn->ipf_nat_tune = ipf_tune_array_copy(softn,
  313                                                   sizeof(ipf_nat_tuneables),
  314                                                   ipf_nat_tuneables);
  315         if (softn->ipf_nat_tune == NULL) {
  316                 ipf_nat_soft_destroy(softc, softn);
  317                 return (NULL);
  318         }
  319         if (ipf_tune_array_link(softc, softn->ipf_nat_tune) == -1) {
  320                 ipf_nat_soft_destroy(softc, softn);
  321                 return (NULL);
  322         }
  323 
  324         softn->ipf_nat_list_tail = &softn->ipf_nat_list;
  325 
  326         if (softc->ipf_large_nat) {
  327         softn->ipf_nat_table_max = NAT_TABLE_MAX_LARGE;
  328         softn->ipf_nat_table_sz = NAT_TABLE_SZ_LARGE;
  329         softn->ipf_nat_maprules_sz = NAT_SIZE_LARGE;
  330         softn->ipf_nat_rdrrules_sz = RDR_SIZE_LARGE;
  331         softn->ipf_nat_hostmap_sz = HOSTMAP_SIZE_LARGE;
  332         } else {
  333         softn->ipf_nat_table_max = NAT_TABLE_MAX_NORMAL;
  334         softn->ipf_nat_table_sz = NAT_TABLE_SZ_NORMAL;
  335         softn->ipf_nat_maprules_sz = NAT_SIZE_NORMAL;
  336         softn->ipf_nat_rdrrules_sz = RDR_SIZE_NORMAL;
  337         softn->ipf_nat_hostmap_sz = HOSTMAP_SIZE_NORMAL;
  338         }
  339         softn->ipf_nat_doflush = 0;
  340 #ifdef  IPFILTER_LOG
  341         softn->ipf_nat_logging = 1;
  342 #else
  343         softn->ipf_nat_logging = 0;
  344 #endif
  345 
  346         softn->ipf_nat_defage = DEF_NAT_AGE;
  347         softn->ipf_nat_defipage = IPF_TTLVAL(60);
  348         softn->ipf_nat_deficmpage = IPF_TTLVAL(3);
  349         softn->ipf_nat_table_wm_high = 99;
  350         softn->ipf_nat_table_wm_low = 90;
  351 
  352         return (softn);
  353 }
  354 
  355 /* ------------------------------------------------------------------------ */
  356 /* Function:    ipf_nat_soft_destroy                                        */
  357 /* Returns:     Nil                                                         */
  358 /* Parameters:  softc(I) - pointer to soft context main structure           */
  359 /*                                                                          */
  360 /* ------------------------------------------------------------------------ */
  361 void
  362 ipf_nat_soft_destroy(ipf_main_softc_t *softc, void *arg)
  363 {
  364         ipf_nat_softc_t *softn = arg;
  365 
  366         if (softn->ipf_nat_tune != NULL) {
  367                 ipf_tune_array_unlink(softc, softn->ipf_nat_tune);
  368                 KFREES(softn->ipf_nat_tune, sizeof(ipf_nat_tuneables));
  369                 softn->ipf_nat_tune = NULL;
  370         }
  371 
  372         KFREE(softn);
  373 }
  374 
  375 
  376 /* ------------------------------------------------------------------------ */
  377 /* Function:    ipf_nat_init                                                */
  378 /* Returns:     int - 0 == success, -1 == failure                           */
  379 /* Parameters:  softc(I) - pointer to soft context main structure           */
  380 /*                                                                          */
  381 /* Initialise all of the NAT locks, tables and other structures.            */
  382 /* ------------------------------------------------------------------------ */
  383 int
  384 ipf_nat_soft_init(ipf_main_softc_t *softc, void *arg)
  385 {
  386         ipf_nat_softc_t *softn = arg;
  387         ipftq_t *tq;
  388         int i;
  389 
  390         KMALLOCS(softn->ipf_nat_table[0], nat_t **, \
  391                  sizeof(nat_t *) * softn->ipf_nat_table_sz);
  392 
  393         if (softn->ipf_nat_table[0] != NULL) {
  394                 bzero((char *)softn->ipf_nat_table[0],
  395                       softn->ipf_nat_table_sz * sizeof(nat_t *));
  396         } else {
  397                 return (-1);
  398         }
  399 
  400         KMALLOCS(softn->ipf_nat_table[1], nat_t **, \
  401                  sizeof(nat_t *) * softn->ipf_nat_table_sz);
  402 
  403         if (softn->ipf_nat_table[1] != NULL) {
  404                 bzero((char *)softn->ipf_nat_table[1],
  405                       softn->ipf_nat_table_sz * sizeof(nat_t *));
  406         } else {
  407                 return (-2);
  408         }
  409 
  410         KMALLOCS(softn->ipf_nat_map_rules, ipnat_t **, \
  411                  sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz);
  412 
  413         if (softn->ipf_nat_map_rules != NULL) {
  414                 bzero((char *)softn->ipf_nat_map_rules,
  415                       softn->ipf_nat_maprules_sz * sizeof(ipnat_t *));
  416         } else {
  417                 return (-3);
  418         }
  419 
  420         KMALLOCS(softn->ipf_nat_rdr_rules, ipnat_t **, \
  421                  sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz);
  422 
  423         if (softn->ipf_nat_rdr_rules != NULL) {
  424                 bzero((char *)softn->ipf_nat_rdr_rules,
  425                       softn->ipf_nat_rdrrules_sz * sizeof(ipnat_t *));
  426         } else {
  427                 return (-4);
  428         }
  429 
  430         KMALLOCS(softn->ipf_hm_maptable, hostmap_t **, \
  431                  sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz);
  432 
  433         if (softn->ipf_hm_maptable != NULL) {
  434                 bzero((char *)softn->ipf_hm_maptable,
  435                       sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz);
  436         } else {
  437                 return (-5);
  438         }
  439         softn->ipf_hm_maplist = NULL;
  440 
  441         KMALLOCS(softn->ipf_nat_stats.ns_side[0].ns_bucketlen, u_int *,
  442                  softn->ipf_nat_table_sz * sizeof(u_int));
  443 
  444         if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen == NULL) {
  445                 return (-6);
  446         }
  447         bzero((char *)softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
  448               softn->ipf_nat_table_sz * sizeof(u_int));
  449 
  450         KMALLOCS(softn->ipf_nat_stats.ns_side[1].ns_bucketlen, u_int *,
  451                  softn->ipf_nat_table_sz * sizeof(u_int));
  452 
  453         if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen == NULL) {
  454                 return (-7);
  455         }
  456 
  457         bzero((char *)softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
  458               softn->ipf_nat_table_sz * sizeof(u_int));
  459 
  460         if (softn->ipf_nat_maxbucket == 0) {
  461                 for (i = softn->ipf_nat_table_sz; i > 0; i >>= 1)
  462                         softn->ipf_nat_maxbucket++;
  463                 softn->ipf_nat_maxbucket *= 2;
  464         }
  465 
  466         ipf_sttab_init(softc, softn->ipf_nat_tcptq);
  467         /*
  468          * Increase this because we may have "keep state" following this too
  469          * and packet storms can occur if this is removed too quickly.
  470          */
  471         softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack;
  472         softn->ipf_nat_tcptq[IPF_TCP_NSTATES - 1].ifq_next =
  473                                                         &softn->ipf_nat_udptq;
  474 
  475         IPFTQ_INIT(&softn->ipf_nat_udptq, softn->ipf_nat_defage,
  476                    "nat ipftq udp tab");
  477         softn->ipf_nat_udptq.ifq_next = &softn->ipf_nat_udpacktq;
  478 
  479         IPFTQ_INIT(&softn->ipf_nat_udpacktq, softn->ipf_nat_defage,
  480                    "nat ipftq udpack tab");
  481         softn->ipf_nat_udpacktq.ifq_next = &softn->ipf_nat_icmptq;
  482 
  483         IPFTQ_INIT(&softn->ipf_nat_icmptq, softn->ipf_nat_deficmpage,
  484                    "nat icmp ipftq tab");
  485         softn->ipf_nat_icmptq.ifq_next = &softn->ipf_nat_icmpacktq;
  486 
  487         IPFTQ_INIT(&softn->ipf_nat_icmpacktq, softn->ipf_nat_defage,
  488                    "nat icmpack ipftq tab");
  489         softn->ipf_nat_icmpacktq.ifq_next = &softn->ipf_nat_iptq;
  490 
  491         IPFTQ_INIT(&softn->ipf_nat_iptq, softn->ipf_nat_defipage,
  492                    "nat ip ipftq tab");
  493         softn->ipf_nat_iptq.ifq_next = &softn->ipf_nat_pending;
  494 
  495         IPFTQ_INIT(&softn->ipf_nat_pending, 1, "nat pending ipftq tab");
  496         softn->ipf_nat_pending.ifq_next = NULL;
  497 
  498         for (i = 0, tq = softn->ipf_nat_tcptq; i < IPF_TCP_NSTATES; i++, tq++) {
  499                 if (tq->ifq_ttl < softn->ipf_nat_deficmpage)
  500                         tq->ifq_ttl = softn->ipf_nat_deficmpage;
  501                 else if (tq->ifq_ttl > softn->ipf_nat_defage && softc->ipf_large_nat)
  502                         tq->ifq_ttl = softn->ipf_nat_defage;
  503         }
  504 
  505         /*
  506          * Increase this because we may have "keep state" following
  507          * this too and packet storms can occur if this is removed
  508          * too quickly.
  509          */
  510         softn->ipf_nat_tcptq[IPF_TCPS_CLOSED].ifq_ttl = softc->ipf_tcplastack;
  511 
  512         MUTEX_INIT(&softn->ipf_nat_new, "ipf nat new mutex");
  513         MUTEX_INIT(&softn->ipf_nat_io, "ipf nat io mutex");
  514 
  515         softn->ipf_nat_inited = 1;
  516 
  517         return (0);
  518 }
  519 
  520 
  521 /* ------------------------------------------------------------------------ */
  522 /* Function:    ipf_nat_soft_fini                                           */
  523 /* Returns:     Nil                                                         */
  524 /* Parameters:  softc(I) - pointer to soft context main structure           */
  525 /*                                                                          */
  526 /* Free all memory used by NAT structures allocated at runtime.             */
  527 /* ------------------------------------------------------------------------ */
  528 int
  529 ipf_nat_soft_fini(ipf_main_softc_t *softc, void *arg)
  530 {
  531         ipf_nat_softc_t *softn = arg;
  532         ipftq_t *ifq, *ifqnext;
  533 
  534         (void) ipf_nat_clearlist(softc, softn);
  535         (void) ipf_nat_flushtable(softc, softn);
  536 
  537         /*
  538          * Proxy timeout queues are not cleaned here because although they
  539          * exist on the NAT list, ipf_proxy_unload is called after unload
  540          * and the proxies actually are responsible for them being created.
  541          * Should the proxy timeouts have their own list?  There's no real
  542          * justification as this is the only complication.
  543          */
  544         for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) {
  545                 ifqnext = ifq->ifq_next;
  546                 if (ipf_deletetimeoutqueue(ifq) == 0)
  547                         ipf_freetimeoutqueue(softc, ifq);
  548         }
  549 
  550         if (softn->ipf_nat_table[0] != NULL) {
  551                 KFREES(softn->ipf_nat_table[0],
  552                        sizeof(nat_t *) * softn->ipf_nat_table_sz);
  553                 softn->ipf_nat_table[0] = NULL;
  554         }
  555         if (softn->ipf_nat_table[1] != NULL) {
  556                 KFREES(softn->ipf_nat_table[1],
  557                        sizeof(nat_t *) * softn->ipf_nat_table_sz);
  558                 softn->ipf_nat_table[1] = NULL;
  559         }
  560         if (softn->ipf_nat_map_rules != NULL) {
  561                 KFREES(softn->ipf_nat_map_rules,
  562                        sizeof(ipnat_t *) * softn->ipf_nat_maprules_sz);
  563                 softn->ipf_nat_map_rules = NULL;
  564         }
  565         if (softn->ipf_nat_rdr_rules != NULL) {
  566                 KFREES(softn->ipf_nat_rdr_rules,
  567                        sizeof(ipnat_t *) * softn->ipf_nat_rdrrules_sz);
  568                 softn->ipf_nat_rdr_rules = NULL;
  569         }
  570         if (softn->ipf_hm_maptable != NULL) {
  571                 KFREES(softn->ipf_hm_maptable,
  572                        sizeof(hostmap_t *) * softn->ipf_nat_hostmap_sz);
  573                 softn->ipf_hm_maptable = NULL;
  574         }
  575         if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) {
  576                 KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
  577                        sizeof(u_int) * softn->ipf_nat_table_sz);
  578                 softn->ipf_nat_stats.ns_side[0].ns_bucketlen = NULL;
  579         }
  580         if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) {
  581                 KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
  582                        sizeof(u_int) * softn->ipf_nat_table_sz);
  583                 softn->ipf_nat_stats.ns_side[1].ns_bucketlen = NULL;
  584         }
  585 
  586         if (softn->ipf_nat_inited == 1) {
  587                 softn->ipf_nat_inited = 0;
  588                 ipf_sttab_destroy(softn->ipf_nat_tcptq);
  589 
  590                 MUTEX_DESTROY(&softn->ipf_nat_new);
  591                 MUTEX_DESTROY(&softn->ipf_nat_io);
  592 
  593                 MUTEX_DESTROY(&softn->ipf_nat_udptq.ifq_lock);
  594                 MUTEX_DESTROY(&softn->ipf_nat_udpacktq.ifq_lock);
  595                 MUTEX_DESTROY(&softn->ipf_nat_icmptq.ifq_lock);
  596                 MUTEX_DESTROY(&softn->ipf_nat_icmpacktq.ifq_lock);
  597                 MUTEX_DESTROY(&softn->ipf_nat_iptq.ifq_lock);
  598                 MUTEX_DESTROY(&softn->ipf_nat_pending.ifq_lock);
  599         }
  600 
  601         return (0);
  602 }
  603 
  604 
  605 /* ------------------------------------------------------------------------ */
  606 /* Function:    ipf_nat_setlock                                             */
  607 /* Returns:     Nil                                                         */
  608 /* Parameters:  arg(I) - pointer to soft state information                  */
  609 /*              tmp(I) - new lock value                                     */
  610 /*                                                                          */
  611 /* Set the "lock status" of NAT to the value in tmp.                        */
  612 /* ------------------------------------------------------------------------ */
  613 void
  614 ipf_nat_setlock(void *arg, int tmp)
  615 {
  616         ipf_nat_softc_t *softn = arg;
  617 
  618         softn->ipf_nat_lock = tmp;
  619 }
  620 
  621 
  622 /* ------------------------------------------------------------------------ */
  623 /* Function:    ipf_nat_addrdr                                              */
  624 /* Returns:     Nil                                                         */
  625 /* Parameters:  n(I) - pointer to NAT rule to add                           */
  626 /*                                                                          */
  627 /* Adds a redirect rule to the hash table of redirect rules and the list of */
  628 /* loaded NAT rules.  Updates the bitmask indicating which netmasks are in  */
  629 /* use by redirect rules.                                                   */
  630 /* ------------------------------------------------------------------------ */
  631 static void
  632 ipf_nat_addrdr(ipf_nat_softc_t *softn, ipnat_t *n)
  633 {
  634         ipnat_t **np;
  635         u_32_t j;
  636         u_int hv;
  637         u_int rhv;
  638         int k;
  639 
  640         if (n->in_odstatype == FRI_NORMAL) {
  641                 k = count4bits(n->in_odstmsk);
  642                 ipf_inet_mask_add(k, &softn->ipf_nat_rdr_mask);
  643                 j = (n->in_odstaddr & n->in_odstmsk);
  644                 rhv = NAT_HASH_FN(j, 0, 0xffffffff);
  645         } else {
  646                 ipf_inet_mask_add(0, &softn->ipf_nat_rdr_mask);
  647                 j = 0;
  648                 rhv = 0;
  649         }
  650         hv = rhv % softn->ipf_nat_rdrrules_sz;
  651         np = softn->ipf_nat_rdr_rules + hv;
  652         while (*np != NULL)
  653                 np = &(*np)->in_rnext;
  654         n->in_rnext = NULL;
  655         n->in_prnext = np;
  656         n->in_hv[0] = hv;
  657         n->in_use++;
  658         *np = n;
  659 }
  660 
  661 
  662 /* ------------------------------------------------------------------------ */
  663 /* Function:    ipf_nat_addmap                                              */
  664 /* Returns:     Nil                                                         */
  665 /* Parameters:  n(I) - pointer to NAT rule to add                           */
  666 /*                                                                          */
  667 /* Adds a NAT map rule to the hash table of rules and the list of  loaded   */
  668 /* NAT rules.  Updates the bitmask indicating which netmasks are in use by  */
  669 /* redirect rules.                                                          */
  670 /* ------------------------------------------------------------------------ */
  671 static void
  672 ipf_nat_addmap(ipf_nat_softc_t *softn, ipnat_t *n)
  673 {
  674         ipnat_t **np;
  675         u_32_t j;
  676         u_int hv;
  677         u_int rhv;
  678         int k;
  679 
  680         if (n->in_osrcatype == FRI_NORMAL) {
  681                 k = count4bits(n->in_osrcmsk);
  682                 ipf_inet_mask_add(k, &softn->ipf_nat_map_mask);
  683                 j = (n->in_osrcaddr & n->in_osrcmsk);
  684                 rhv = NAT_HASH_FN(j, 0, 0xffffffff);
  685         } else {
  686                 ipf_inet_mask_add(0, &softn->ipf_nat_map_mask);
  687                 j = 0;
  688                 rhv = 0;
  689         }
  690         hv = rhv % softn->ipf_nat_maprules_sz;
  691         np = softn->ipf_nat_map_rules + hv;
  692         while (*np != NULL)
  693                 np = &(*np)->in_mnext;
  694         n->in_mnext = NULL;
  695         n->in_pmnext = np;
  696         n->in_hv[1] = rhv;
  697         n->in_use++;
  698         *np = n;
  699 }
  700 
  701 
  702 /* ------------------------------------------------------------------------ */
  703 /* Function:    ipf_nat_delrdr                                              */
  704 /* Returns:     Nil                                                         */
  705 /* Parameters:  n(I) - pointer to NAT rule to delete                        */
  706 /*                                                                          */
  707 /* Removes a redirect rule from the hash table of redirect rules.           */
  708 /* ------------------------------------------------------------------------ */
  709 void
  710 ipf_nat_delrdr(ipf_nat_softc_t *softn, ipnat_t *n)
  711 {
  712         if (n->in_odstatype == FRI_NORMAL) {
  713                 int k = count4bits(n->in_odstmsk);
  714                 ipf_inet_mask_del(k, &softn->ipf_nat_rdr_mask);
  715         } else {
  716                 ipf_inet_mask_del(0, &softn->ipf_nat_rdr_mask);
  717         }
  718         if (n->in_rnext)
  719                 n->in_rnext->in_prnext = n->in_prnext;
  720         *n->in_prnext = n->in_rnext;
  721         n->in_use--;
  722 }
  723 
  724 
  725 /* ------------------------------------------------------------------------ */
  726 /* Function:    ipf_nat_delmap                                              */
  727 /* Returns:     Nil                                                         */
  728 /* Parameters:  n(I) - pointer to NAT rule to delete                        */
  729 /*                                                                          */
  730 /* Removes a NAT map rule from the hash table of NAT map rules.             */
  731 /* ------------------------------------------------------------------------ */
  732 void
  733 ipf_nat_delmap(ipf_nat_softc_t *softn, ipnat_t *n)
  734 {
  735         if (n->in_osrcatype == FRI_NORMAL) {
  736                 int k = count4bits(n->in_osrcmsk);
  737                 ipf_inet_mask_del(k, &softn->ipf_nat_map_mask);
  738         } else {
  739                 ipf_inet_mask_del(0, &softn->ipf_nat_map_mask);
  740         }
  741         if (n->in_mnext != NULL)
  742                 n->in_mnext->in_pmnext = n->in_pmnext;
  743         *n->in_pmnext = n->in_mnext;
  744         n->in_use--;
  745 }
  746 
  747 
  748 /* ------------------------------------------------------------------------ */
  749 /* Function:    ipf_nat_hostmap                                             */
  750 /* Returns:     struct hostmap* - NULL if no hostmap could be created,      */
  751 /*                                else a pointer to the hostmapping to use  */
  752 /* Parameters:  np(I)   - pointer to NAT rule                               */
  753 /*              real(I) - real IP address                                   */
  754 /*              map(I)  - mapped IP address                                 */
  755 /*              port(I) - destination port number                           */
  756 /* Write Locks: ipf_nat                                                     */
  757 /*                                                                          */
  758 /* Check if an ip address has already been allocated for a given mapping    */
  759 /* that is not doing port based translation.  If is not yet allocated, then */
  760 /* create a new entry if a non-NULL NAT rule pointer has been supplied.     */
  761 /* ------------------------------------------------------------------------ */
  762 static struct hostmap *
  763 ipf_nat_hostmap(ipf_nat_softc_t *softn, ipnat_t *np, struct in_addr src,
  764         struct in_addr dst, struct in_addr map, u_32_t port)
  765 {
  766         hostmap_t *hm;
  767         u_int hv, rhv;
  768 
  769         hv = (src.s_addr ^ dst.s_addr);
  770         hv += src.s_addr;
  771         hv += dst.s_addr;
  772         rhv = hv;
  773         hv %= softn->ipf_nat_hostmap_sz;
  774         for (hm = softn->ipf_hm_maptable[hv]; hm; hm = hm->hm_hnext)
  775                 if ((hm->hm_osrcip.s_addr == src.s_addr) &&
  776                     (hm->hm_odstip.s_addr == dst.s_addr) &&
  777                     ((np == NULL) || (np == hm->hm_ipnat)) &&
  778                     ((port == 0) || (port == hm->hm_port))) {
  779                         softn->ipf_nat_stats.ns_hm_addref++;
  780                         hm->hm_ref++;
  781                         return (hm);
  782                 }
  783 
  784         if (np == NULL) {
  785                 softn->ipf_nat_stats.ns_hm_nullnp++;
  786                 return (NULL);
  787         }
  788 
  789         KMALLOC(hm, hostmap_t *);
  790         if (hm) {
  791                 hm->hm_next = softn->ipf_hm_maplist;
  792                 hm->hm_pnext = &softn->ipf_hm_maplist;
  793                 if (softn->ipf_hm_maplist != NULL)
  794                         softn->ipf_hm_maplist->hm_pnext = &hm->hm_next;
  795                 softn->ipf_hm_maplist = hm;
  796                 hm->hm_hnext = softn->ipf_hm_maptable[hv];
  797                 hm->hm_phnext = softn->ipf_hm_maptable + hv;
  798                 if (softn->ipf_hm_maptable[hv] != NULL)
  799                         softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
  800                 softn->ipf_hm_maptable[hv] = hm;
  801                 hm->hm_ipnat = np;
  802                 np->in_use++;
  803                 hm->hm_osrcip = src;
  804                 hm->hm_odstip = dst;
  805                 hm->hm_nsrcip = map;
  806                 hm->hm_ndstip.s_addr = 0;
  807                 hm->hm_ref = 1;
  808                 hm->hm_port = port;
  809                 hm->hm_hv = rhv;
  810                 hm->hm_v = 4;
  811                 softn->ipf_nat_stats.ns_hm_new++;
  812         } else {
  813                 softn->ipf_nat_stats.ns_hm_newfail++;
  814         }
  815         return (hm);
  816 }
  817 
  818 
  819 /* ------------------------------------------------------------------------ */
  820 /* Function:    ipf_nat_hostmapdel                                          */
  821 /* Returns:     Nil                                                         */
  822 /* Parameters:  hmp(I) - pointer to hostmap structure pointer               */
  823 /* Write Locks: ipf_nat                                                     */
  824 /*                                                                          */
  825 /* Decrement the references to this hostmap structure by one.  If this      */
  826 /* reaches zero then remove it and free it.                                 */
  827 /* ------------------------------------------------------------------------ */
  828 void
  829 ipf_nat_hostmapdel(ipf_main_softc_t *softc, struct hostmap **hmp)
  830 {
  831         struct hostmap *hm;
  832 
  833         hm = *hmp;
  834         *hmp = NULL;
  835 
  836         hm->hm_ref--;
  837         if (hm->hm_ref == 0) {
  838                 ipf_nat_rule_deref(softc, &hm->hm_ipnat);
  839                 if (hm->hm_hnext)
  840                         hm->hm_hnext->hm_phnext = hm->hm_phnext;
  841                 *hm->hm_phnext = hm->hm_hnext;
  842                 if (hm->hm_next)
  843                         hm->hm_next->hm_pnext = hm->hm_pnext;
  844                 *hm->hm_pnext = hm->hm_next;
  845                 KFREE(hm);
  846         }
  847 }
  848 
  849 
  850 /* ------------------------------------------------------------------------ */
  851 /* Function:    ipf_fix_outcksum                                            */
  852 /* Returns:     Nil                                                         */
  853 /* Parameters:  cksum(I) - ipf_cksum_t, value of fin_cksum                  */
  854 /*              sp(I)  - location of 16bit checksum to update               */
  855 /*              n(I)  - amount to adjust checksum by                        */
  856 /*              partial(I) - partial checksum                               */
  857 /*                                                                          */
  858 /* Adjusts the 16bit checksum by "n" for packets going out.                 */
  859 /* ------------------------------------------------------------------------ */
  860 void
  861 ipf_fix_outcksum(int cksum, u_short *sp, u_32_t n, u_32_t partial)
  862 {
  863         u_short sumshort;
  864         u_32_t sum1;
  865 
  866         if (n == 0)
  867                 return;
  868 
  869         if (cksum == 4) {
  870                 *sp = 0;
  871                 return;
  872         }
  873         if (cksum == 2) {
  874                 sum1 = partial;
  875                 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
  876                 *sp = htons(sum1);
  877                 return;
  878         }
  879         sum1 = (~ntohs(*sp)) & 0xffff;
  880         sum1 += (n);
  881         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
  882         /* Again */
  883         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
  884         sumshort = ~(u_short)sum1;
  885         *(sp) = htons(sumshort);
  886 }
  887 
  888 
  889 /* ------------------------------------------------------------------------ */
  890 /* Function:    ipf_fix_incksum                                             */
  891 /* Returns:     Nil                                                         */
  892 /* Parameters:  cksum(I) - ipf_cksum_t, value of fin_cksum                  */
  893 /*              sp(I)  - location of 16bit checksum to update               */
  894 /*              n(I)  - amount to adjust checksum by                        */
  895 /*              partial(I) - partial checksum                               */
  896 /*                                                                          */
  897 /* Adjusts the 16bit checksum by "n" for packets going in.                  */
  898 /* ------------------------------------------------------------------------ */
  899 void
  900 ipf_fix_incksum(int cksum, u_short *sp, u_32_t n, u_32_t partial)
  901 {
  902         u_short sumshort;
  903         u_32_t sum1;
  904 
  905         if (n == 0)
  906                 return;
  907 
  908         if (cksum == 4) {
  909                 *sp = 0;
  910                 return;
  911         }
  912         if (cksum == 2) {
  913                 sum1 = partial;
  914                 sum1 = (sum1 & 0xffff) + (sum1 >> 16);
  915                 *sp = htons(sum1);
  916                 return;
  917         }
  918 
  919         sum1 = (~ntohs(*sp)) & 0xffff;
  920         sum1 += ~(n) & 0xffff;
  921         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
  922         /* Again */
  923         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
  924         sumshort = ~(u_short)sum1;
  925         *(sp) = htons(sumshort);
  926 }
  927 
  928 
  929 /* ------------------------------------------------------------------------ */
  930 /* Function:    ipf_fix_datacksum                                           */
  931 /* Returns:     Nil                                                         */
  932 /* Parameters:  sp(I)  - location of 16bit checksum to update               */
  933 /*              n(I)  - amount to adjust checksum by                        */
  934 /*                                                                          */
  935 /* Fix_datacksum is used *only* for the adjustments of checksums in the     */
  936 /* data section of an IP packet.                                            */
  937 /*                                                                          */
  938 /* The only situation in which you need to do this is when NAT'ing an       */
  939 /* ICMP error message. Such a message, contains in its body the IP header   */
  940 /* of the original IP packet, that causes the error.                        */
  941 /*                                                                          */
  942 /* You can't use fix_incksum or fix_outcksum in that case, because for the  */
  943 /* kernel the data section of the ICMP error is just data, and no special   */
  944 /* processing like hardware cksum or ntohs processing have been done by the */
  945 /* kernel on the data section.                                              */
  946 /* ------------------------------------------------------------------------ */
  947 void
  948 ipf_fix_datacksum(u_short *sp, u_32_t n)
  949 {
  950         u_short sumshort;
  951         u_32_t sum1;
  952 
  953         if (n == 0)
  954                 return;
  955 
  956         sum1 = (~ntohs(*sp)) & 0xffff;
  957         sum1 += (n);
  958         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
  959         /* Again */
  960         sum1 = (sum1 >> 16) + (sum1 & 0xffff);
  961         sumshort = ~(u_short)sum1;
  962         *(sp) = htons(sumshort);
  963 }
  964 
  965 
  966 /* ------------------------------------------------------------------------ */
  967 /* Function:    ipf_nat_ioctl                                               */
  968 /* Returns:     int - 0 == success, != 0 == failure                         */
  969 /* Parameters:  softc(I) - pointer to soft context main structure           */
  970 /*              data(I)  - pointer to ioctl data                            */
  971 /*              cmd(I)   - ioctl command integer                            */
  972 /*              mode(I)  - file mode bits used with open                    */
  973 /*              uid(I)   - uid of calling process                           */
  974 /*              ctx(I)   - pointer used as key for finding context          */
  975 /*                                                                          */
  976 /* Processes an ioctl call made to operate on the IP Filter NAT device.     */
  977 /* ------------------------------------------------------------------------ */
  978 int
  979 ipf_nat_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd,
  980         int mode, int uid, void *ctx)
  981 {
  982         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
  983         int error = 0, ret, arg, getlock;
  984         ipnat_t *nat, *nt, *n;
  985         ipnat_t natd;
  986         SPL_INT(s);
  987 
  988 #if !SOLARIS && defined(_KERNEL)
  989 # if NETBSD_GE_REV(399002000)
  990         if ((mode & FWRITE) &&
  991              kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_FIREWALL,
  992                                      KAUTH_REQ_NETWORK_FIREWALL_FW,
  993                                      NULL, NULL, NULL))
  994 # else
  995 #  if defined(__FreeBSD__)
  996         if (securelevel_ge(curthread->td_ucred, 3) && (mode & FWRITE))
  997 #  else
  998         if ((securelevel >= 3) && (mode & FWRITE))
  999 #  endif
 1000 # endif
 1001         {
 1002                 IPFERROR(60001);
 1003                 return (EPERM);
 1004         }
 1005 # if defined(__FreeBSD__)
 1006         if (jailed_without_vnet(curthread->td_ucred)) {
 1007                 IPFERROR(60076);
 1008                 return (EOPNOTSUPP);
 1009         }
 1010 # endif
 1011 #endif
 1012 
 1013         getlock = (mode & NAT_LOCKHELD) ? 0 : 1;
 1014 
 1015         n = NULL;
 1016         nt = NULL;
 1017         nat = NULL;
 1018 
 1019         if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT) ||
 1020             (cmd == (ioctlcmd_t)SIOCPURGENAT)) {
 1021                 if (mode & NAT_SYSSPACE) {
 1022                         bcopy(data, (char *)&natd, sizeof(natd));
 1023                         nat = &natd;
 1024                         error = 0;
 1025                 } else {
 1026                         bzero(&natd, sizeof(natd));
 1027                         error = ipf_inobj(softc, data, NULL, &natd,
 1028                                           IPFOBJ_IPNAT);
 1029                         if (error != 0)
 1030                                 goto done;
 1031 
 1032                         if (natd.in_size < sizeof(ipnat_t)) {
 1033                                 error = EINVAL;
 1034                                 goto done;
 1035                         }
 1036                         KMALLOCS(nt, ipnat_t *, natd.in_size);
 1037                         if (nt == NULL) {
 1038                                 IPFERROR(60070);
 1039                                 error = ENOMEM;
 1040                                 goto done;
 1041                         }
 1042                         bzero(nt, natd.in_size);
 1043                         error = ipf_inobjsz(softc, data, nt, IPFOBJ_IPNAT,
 1044                                             natd.in_size);
 1045                         if (error)
 1046                                 goto done;
 1047                         nat = nt;
 1048                 }
 1049 
 1050                 /*
 1051                  * For add/delete, look to see if the NAT entry is
 1052                  * already present
 1053                  */
 1054                 nat->in_flags &= IPN_USERFLAGS;
 1055                 if ((nat->in_redir & NAT_MAPBLK) == 0) {
 1056                         if (nat->in_osrcatype == FRI_NORMAL ||
 1057                             nat->in_osrcatype == FRI_NONE)
 1058                                 nat->in_osrcaddr &= nat->in_osrcmsk;
 1059                         if (nat->in_odstatype == FRI_NORMAL ||
 1060                             nat->in_odstatype == FRI_NONE)
 1061                                 nat->in_odstaddr &= nat->in_odstmsk;
 1062                         if ((nat->in_flags & (IPN_SPLIT|IPN_SIPRANGE)) == 0) {
 1063                                 if (nat->in_nsrcatype == FRI_NORMAL)
 1064                                         nat->in_nsrcaddr &= nat->in_nsrcmsk;
 1065                                 if (nat->in_ndstatype == FRI_NORMAL)
 1066                                         nat->in_ndstaddr &= nat->in_ndstmsk;
 1067                         }
 1068                 }
 1069 
 1070                 error = ipf_nat_rule_init(softc, softn, nat);
 1071                 if (error != 0)
 1072                         goto done;
 1073 
 1074                 MUTEX_ENTER(&softn->ipf_nat_io);
 1075                 for (n = softn->ipf_nat_list; n != NULL; n = n->in_next)
 1076                         if (ipf_nat_cmp_rules(nat, n) == 0)
 1077                                 break;
 1078         }
 1079 
 1080         switch (cmd)
 1081         {
 1082 #ifdef  IPFILTER_LOG
 1083         case SIOCIPFFB :
 1084         {
 1085                 int tmp;
 1086 
 1087                 if (!(mode & FWRITE)) {
 1088                         IPFERROR(60002);
 1089                         error = EPERM;
 1090                 } else {
 1091                         tmp = ipf_log_clear(softc, IPL_LOGNAT);
 1092                         error = BCOPYOUT(&tmp, data, sizeof(tmp));
 1093                         if (error != 0) {
 1094                                 IPFERROR(60057);
 1095                                 error = EFAULT;
 1096                         }
 1097                 }
 1098                 break;
 1099         }
 1100 
 1101         case SIOCSETLG :
 1102                 if (!(mode & FWRITE)) {
 1103                         IPFERROR(60003);
 1104                         error = EPERM;
 1105                 } else {
 1106                         error = BCOPYIN(data, &softn->ipf_nat_logging,
 1107                                         sizeof(softn->ipf_nat_logging));
 1108                         if (error != 0)
 1109                                 error = EFAULT;
 1110                 }
 1111                 break;
 1112 
 1113         case SIOCGETLG :
 1114                 error = BCOPYOUT(&softn->ipf_nat_logging, data,
 1115                                  sizeof(softn->ipf_nat_logging));
 1116                 if (error != 0) {
 1117                         IPFERROR(60004);
 1118                         error = EFAULT;
 1119                 }
 1120                 break;
 1121 
 1122         case FIONREAD :
 1123                 arg = ipf_log_bytesused(softc, IPL_LOGNAT);
 1124                 error = BCOPYOUT(&arg, data, sizeof(arg));
 1125                 if (error != 0) {
 1126                         IPFERROR(60005);
 1127                         error = EFAULT;
 1128                 }
 1129                 break;
 1130 #endif
 1131         case SIOCADNAT :
 1132                 if (!(mode & FWRITE)) {
 1133                         IPFERROR(60006);
 1134                         error = EPERM;
 1135                 } else if (n != NULL) {
 1136                         natd.in_flineno = n->in_flineno;
 1137                         (void) ipf_outobj(softc, data, &natd, IPFOBJ_IPNAT);
 1138                         IPFERROR(60007);
 1139                         error = EEXIST;
 1140                 } else if (nt == NULL) {
 1141                         IPFERROR(60008);
 1142                         error = ENOMEM;
 1143                 }
 1144                 if (error != 0) {
 1145                         MUTEX_EXIT(&softn->ipf_nat_io);
 1146                         break;
 1147                 }
 1148                 if (nat != nt)
 1149                         bcopy((char *)nat, (char *)nt, sizeof(*n));
 1150                 error = ipf_nat_siocaddnat(softc, softn, nt, getlock);
 1151                 MUTEX_EXIT(&softn->ipf_nat_io);
 1152                 if (error == 0) {
 1153                         nat = NULL;
 1154                         nt = NULL;
 1155                 }
 1156                 break;
 1157 
 1158         case SIOCRMNAT :
 1159         case SIOCPURGENAT :
 1160                 if (!(mode & FWRITE)) {
 1161                         IPFERROR(60009);
 1162                         error = EPERM;
 1163                         n = NULL;
 1164                 } else if (n == NULL) {
 1165                         IPFERROR(60010);
 1166                         error = ESRCH;
 1167                 }
 1168 
 1169                 if (error != 0) {
 1170                         MUTEX_EXIT(&softn->ipf_nat_io);
 1171                         break;
 1172                 }
 1173                 if (cmd == (ioctlcmd_t)SIOCPURGENAT) {
 1174                         error = ipf_outobjsz(softc, data, n, IPFOBJ_IPNAT,
 1175                                              n->in_size);
 1176                         if (error) {
 1177                                 MUTEX_EXIT(&softn->ipf_nat_io);
 1178                                 goto done;
 1179                         }
 1180                         n->in_flags |= IPN_PURGE;
 1181                 }
 1182                 ipf_nat_siocdelnat(softc, softn, n, getlock);
 1183 
 1184                 MUTEX_EXIT(&softn->ipf_nat_io);
 1185                 n = NULL;
 1186                 break;
 1187 
 1188         case SIOCGNATS :
 1189             {
 1190                 natstat_t *nsp = &softn->ipf_nat_stats;
 1191 
 1192                 nsp->ns_side[0].ns_table = softn->ipf_nat_table[0];
 1193                 nsp->ns_side[1].ns_table = softn->ipf_nat_table[1];
 1194                 nsp->ns_list = softn->ipf_nat_list;
 1195                 nsp->ns_maptable = softn->ipf_hm_maptable;
 1196                 nsp->ns_maplist = softn->ipf_hm_maplist;
 1197                 nsp->ns_nattab_sz = softn->ipf_nat_table_sz;
 1198                 nsp->ns_nattab_max = softn->ipf_nat_table_max;
 1199                 nsp->ns_rultab_sz = softn->ipf_nat_maprules_sz;
 1200                 nsp->ns_rdrtab_sz = softn->ipf_nat_rdrrules_sz;
 1201                 nsp->ns_hostmap_sz = softn->ipf_nat_hostmap_sz;
 1202                 nsp->ns_instances = softn->ipf_nat_instances;
 1203                 nsp->ns_ticks = softc->ipf_ticks;
 1204 #ifdef IPFILTER_LOGGING
 1205                 nsp->ns_log_ok = ipf_log_logok(softc, IPF_LOGNAT);
 1206                 nsp->ns_log_fail = ipf_log_failures(softc, IPF_LOGNAT);
 1207 #else
 1208                 nsp->ns_log_ok = 0;
 1209                 nsp->ns_log_fail = 0;
 1210 #endif
 1211                 error = ipf_outobj(softc, data, nsp, IPFOBJ_NATSTAT);
 1212                 break;
 1213             }
 1214 
 1215         case SIOCGNATL :
 1216             {
 1217                 natlookup_t nl;
 1218 
 1219                 error = ipf_inobj(softc, data, NULL, &nl, IPFOBJ_NATLOOKUP);
 1220                 if (error == 0) {
 1221                         void *ptr;
 1222 
 1223                         if (getlock) {
 1224                                 READ_ENTER(&softc->ipf_nat);
 1225                         }
 1226 
 1227                         switch (nl.nl_v)
 1228                         {
 1229                         case 4 :
 1230                                 ptr = ipf_nat_lookupredir(&nl);
 1231                                 break;
 1232 #ifdef USE_INET6
 1233                         case 6 :
 1234                                 ptr = ipf_nat6_lookupredir(&nl);
 1235                                 break;
 1236 #endif
 1237                         default:
 1238                                 ptr = NULL;
 1239                                 break;
 1240                         }
 1241 
 1242                         if (getlock) {
 1243                                 RWLOCK_EXIT(&softc->ipf_nat);
 1244                         }
 1245                         if (ptr != NULL) {
 1246                                 error = ipf_outobj(softc, data, &nl,
 1247                                                    IPFOBJ_NATLOOKUP);
 1248                         } else {
 1249                                 IPFERROR(60011);
 1250                                 error = ESRCH;
 1251                         }
 1252                 }
 1253                 break;
 1254             }
 1255 
 1256         case SIOCIPFFL :        /* old SIOCFLNAT & SIOCCNATL */
 1257                 if (!(mode & FWRITE)) {
 1258                         IPFERROR(60012);
 1259                         error = EPERM;
 1260                         break;
 1261                 }
 1262                 if (getlock) {
 1263                         WRITE_ENTER(&softc->ipf_nat);
 1264                 }
 1265 
 1266                 error = BCOPYIN(data, &arg, sizeof(arg));
 1267                 if (error != 0) {
 1268                         IPFERROR(60013);
 1269                         error = EFAULT;
 1270                 } else {
 1271                         if (arg == 0)
 1272                                 ret = ipf_nat_flushtable(softc, softn);
 1273                         else if (arg == 1)
 1274                                 ret = ipf_nat_clearlist(softc, softn);
 1275                         else
 1276                                 ret = ipf_nat_extraflush(softc, softn, arg);
 1277                         ipf_proxy_flush(softc->ipf_proxy_soft, arg);
 1278                 }
 1279 
 1280                 if (getlock) {
 1281                         RWLOCK_EXIT(&softc->ipf_nat);
 1282                 }
 1283                 if (error == 0) {
 1284                         error = BCOPYOUT(&ret, data, sizeof(ret));
 1285                 }
 1286                 break;
 1287 
 1288         case SIOCMATCHFLUSH :
 1289                 if (!(mode & FWRITE)) {
 1290                         IPFERROR(60014);
 1291                         error = EPERM;
 1292                         break;
 1293                 }
 1294                 if (getlock) {
 1295                         WRITE_ENTER(&softc->ipf_nat);
 1296                 }
 1297 
 1298                 error = ipf_nat_matchflush(softc, softn, data);
 1299 
 1300                 if (getlock) {
 1301                         RWLOCK_EXIT(&softc->ipf_nat);
 1302                 }
 1303                 break;
 1304 
 1305         case SIOCPROXY :
 1306                 error = ipf_proxy_ioctl(softc, data, cmd, mode, ctx);
 1307                 break;
 1308 
 1309         case SIOCSTLCK :
 1310                 if (!(mode & FWRITE)) {
 1311                         IPFERROR(60015);
 1312                         error = EPERM;
 1313                 } else {
 1314                         error = ipf_lock(data, &softn->ipf_nat_lock);
 1315                 }
 1316                 break;
 1317 
 1318         case SIOCSTPUT :
 1319                 if ((mode & FWRITE) != 0) {
 1320                         error = ipf_nat_putent(softc, data, getlock);
 1321                 } else {
 1322                         IPFERROR(60016);
 1323                         error = EACCES;
 1324                 }
 1325                 break;
 1326 
 1327         case SIOCSTGSZ :
 1328                 if (softn->ipf_nat_lock) {
 1329                         error = ipf_nat_getsz(softc, data, getlock);
 1330                 } else {
 1331                         IPFERROR(60017);
 1332                         error = EACCES;
 1333                 }
 1334                 break;
 1335 
 1336         case SIOCSTGET :
 1337                 if (softn->ipf_nat_lock) {
 1338                         error = ipf_nat_getent(softc, data, getlock);
 1339                 } else {
 1340                         IPFERROR(60018);
 1341                         error = EACCES;
 1342                 }
 1343                 break;
 1344 
 1345         case SIOCGENITER :
 1346             {
 1347                 ipfgeniter_t iter;
 1348                 ipftoken_t *token;
 1349                 ipfobj_t obj;
 1350 
 1351                 error = ipf_inobj(softc, data, &obj, &iter, IPFOBJ_GENITER);
 1352                 if (error != 0)
 1353                         break;
 1354 
 1355                 SPL_SCHED(s);
 1356                 token = ipf_token_find(softc, iter.igi_type, uid, ctx);
 1357                 if (token != NULL) {
 1358                         error  = ipf_nat_iterator(softc, token, &iter, &obj);
 1359                         WRITE_ENTER(&softc->ipf_tokens);
 1360                         ipf_token_deref(softc, token);
 1361                         RWLOCK_EXIT(&softc->ipf_tokens);
 1362                 }
 1363                 SPL_X(s);
 1364                 break;
 1365             }
 1366 
 1367         case SIOCIPFDELTOK :
 1368                 error = BCOPYIN(data, &arg, sizeof(arg));
 1369                 if (error == 0) {
 1370                         SPL_SCHED(s);
 1371                         error = ipf_token_del(softc, arg, uid, ctx);
 1372                         SPL_X(s);
 1373                 } else {
 1374                         IPFERROR(60019);
 1375                         error = EFAULT;
 1376                 }
 1377                 break;
 1378 
 1379         case SIOCGTQTAB :
 1380                 error = ipf_outobj(softc, data, softn->ipf_nat_tcptq,
 1381                                    IPFOBJ_STATETQTAB);
 1382                 break;
 1383 
 1384         case SIOCGTABL :
 1385                 error = ipf_nat_gettable(softc, softn, data);
 1386                 break;
 1387 
 1388         default :
 1389                 IPFERROR(60020);
 1390                 error = EINVAL;
 1391                 break;
 1392         }
 1393 done:
 1394         if (nat != NULL)
 1395                 ipf_nat_rule_fini(softc, nat);
 1396         if (nt != NULL)
 1397                 KFREES(nt, nt->in_size);
 1398         return (error);
 1399 }
 1400 
 1401 
 1402 /* ------------------------------------------------------------------------ */
 1403 /* Function:    ipf_nat_siocaddnat                                          */
 1404 /* Returns:     int - 0 == success, != 0 == failure                         */
 1405 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1406 /*              softn(I) - pointer to NAT context structure                 */
 1407 /*              n(I)       - pointer to new NAT rule                        */
 1408 /*              np(I)      - pointer to where to insert new NAT rule        */
 1409 /*              getlock(I) - flag indicating if lock on  is held            */
 1410 /* Mutex Locks: ipf_nat_io                                                  */
 1411 /*                                                                          */
 1412 /* Handle SIOCADNAT.  Resolve and calculate details inside the NAT rule     */
 1413 /* from information passed to the kernel, then add it  to the appropriate   */
 1414 /* NAT rule table(s).                                                       */
 1415 /* ------------------------------------------------------------------------ */
 1416 static int
 1417 ipf_nat_siocaddnat(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, ipnat_t *n,
 1418         int getlock)
 1419 {
 1420         int error = 0;
 1421 
 1422         if (ipf_nat_resolverule(softc, n) != 0) {
 1423                 IPFERROR(60022);
 1424                 return (ENOENT);
 1425         }
 1426 
 1427         if ((n->in_age[0] == 0) && (n->in_age[1] != 0)) {
 1428                 IPFERROR(60023);
 1429                 return (EINVAL);
 1430         }
 1431 
 1432         if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) {
 1433                 /*
 1434                  * Prerecord whether or not the destination of the divert
 1435                  * is local or not to the interface the packet is going
 1436                  * to be sent out.
 1437                  */
 1438                 n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1],
 1439                                                 n->in_ifps[1], &n->in_ndstip6);
 1440         }
 1441 
 1442         if (getlock) {
 1443                 WRITE_ENTER(&softc->ipf_nat);
 1444         }
 1445         n->in_next = NULL;
 1446         n->in_pnext = softn->ipf_nat_list_tail;
 1447         *n->in_pnext = n;
 1448         softn->ipf_nat_list_tail = &n->in_next;
 1449         n->in_use++;
 1450 
 1451         if (n->in_redir & NAT_REDIRECT) {
 1452                 n->in_flags &= ~IPN_NOTDST;
 1453                 switch (n->in_v[0])
 1454                 {
 1455                 case 4 :
 1456                         ipf_nat_addrdr(softn, n);
 1457                         break;
 1458 #ifdef USE_INET6
 1459                 case 6 :
 1460                         ipf_nat6_addrdr(softn, n);
 1461                         break;
 1462 #endif
 1463                 default :
 1464                         break;
 1465                 }
 1466                 ATOMIC_INC32(softn->ipf_nat_stats.ns_rules_rdr);
 1467         }
 1468 
 1469         if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) {
 1470                 n->in_flags &= ~IPN_NOTSRC;
 1471                 switch (n->in_v[0])
 1472                 {
 1473                 case 4 :
 1474                         ipf_nat_addmap(softn, n);
 1475                         break;
 1476 #ifdef USE_INET6
 1477                 case 6 :
 1478                         ipf_nat6_addmap(softn, n);
 1479                         break;
 1480 #endif
 1481                 default :
 1482                         break;
 1483                 }
 1484                 ATOMIC_INC32(softn->ipf_nat_stats.ns_rules_map);
 1485         }
 1486 
 1487         if (n->in_age[0] != 0)
 1488                 n->in_tqehead[0] = ipf_addtimeoutqueue(softc,
 1489                                                        &softn->ipf_nat_utqe,
 1490                                                        n->in_age[0]);
 1491 
 1492         if (n->in_age[1] != 0)
 1493                 n->in_tqehead[1] = ipf_addtimeoutqueue(softc,
 1494                                                        &softn->ipf_nat_utqe,
 1495                                                        n->in_age[1]);
 1496 
 1497         MUTEX_INIT(&n->in_lock, "ipnat rule lock");
 1498 
 1499         n = NULL;
 1500         ATOMIC_INC32(softn->ipf_nat_stats.ns_rules);
 1501 #if SOLARIS && !defined(INSTANCES)
 1502         pfil_delayed_copy = 0;
 1503 #endif
 1504         if (getlock) {
 1505                 RWLOCK_EXIT(&softc->ipf_nat);                   /* WRITE */
 1506         }
 1507 
 1508         return (error);
 1509 }
 1510 
 1511 
 1512 /* ------------------------------------------------------------------------ */
 1513 /* Function:    ipf_nat_ruleaddrinit                                        */
 1514 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1515 /*              softn(I) - pointer to NAT context structure                 */
 1516 /*              n(I)     - pointer to NAT rule                              */
 1517 /*                                                                          */
 1518 /* Initialise all of the NAT address structures in a NAT rule.              */
 1519 /* ------------------------------------------------------------------------ */
 1520 static int
 1521 ipf_nat_ruleaddrinit(ipf_main_softc_t *softc, ipf_nat_softc_t *softn,
 1522         ipnat_t *n)
 1523 {
 1524         int idx, error;
 1525 
 1526         if ((n->in_ndst.na_atype == FRI_LOOKUP) &&
 1527             (n->in_ndst.na_type != IPLT_DSTLIST)) {
 1528                 IPFERROR(60071);
 1529                 return (EINVAL);
 1530         }
 1531         if ((n->in_nsrc.na_atype == FRI_LOOKUP) &&
 1532             (n->in_nsrc.na_type != IPLT_DSTLIST)) {
 1533                 IPFERROR(60069);
 1534                 return (EINVAL);
 1535         }
 1536 
 1537         if (n->in_redir == NAT_BIMAP) {
 1538                 n->in_ndstaddr = n->in_osrcaddr;
 1539                 n->in_ndstmsk = n->in_osrcmsk;
 1540                 n->in_odstaddr = n->in_nsrcaddr;
 1541                 n->in_odstmsk = n->in_nsrcmsk;
 1542 
 1543         }
 1544 
 1545         if (n->in_redir & NAT_REDIRECT)
 1546                 idx = 1;
 1547         else
 1548                 idx = 0;
 1549         /*
 1550          * Initialise all of the address fields.
 1551          */
 1552         error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc, 1,
 1553                                      n->in_ifps[idx]);
 1554         if (error != 0)
 1555                 return (error);
 1556 
 1557         error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst, 1,
 1558                                      n->in_ifps[idx]);
 1559         if (error != 0)
 1560                 return (error);
 1561 
 1562         error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc, 1,
 1563                                      n->in_ifps[idx]);
 1564         if (error != 0)
 1565                 return (error);
 1566 
 1567         error = ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst, 1,
 1568                                      n->in_ifps[idx]);
 1569         if (error != 0)
 1570                 return (error);
 1571 
 1572         if (n->in_redir & NAT_DIVERTUDP)
 1573                 ipf_nat_builddivertmp(softn, n);
 1574 
 1575         return (0);
 1576 }
 1577 
 1578 
 1579 /* ------------------------------------------------------------------------ */
 1580 /* Function:    ipf_nat_resolvrule                                          */
 1581 /* Returns:     Nil                                                         */
 1582 /* Parameters:  softc(I) - pointer to soft context main structure           */
 1583 /*              n(I)     - pointer to NAT rule                              */
 1584 /*                                                                          */
 1585 /* Handle SIOCADNAT.  Resolve and calculate details inside the NAT rule     */
 1586 /* from information passed to the kernel, then add it  to the appropriate   */
 1587 /* NAT rule table(s).                                                       */
 1588 /* ------------------------------------------------------------------------ */
 1589 static int
 1590 ipf_nat_resolverule(ipf_main_softc_t *softc, ipnat_t *n)
 1591 {
 1592         char *base;
 1593 
 1594         base = n->in_names;
 1595 
 1596         n->in_ifps[0] = ipf_resolvenic(softc, base + n->in_ifnames[0],
 1597                                        n->in_v[0]);
 1598 
 1599         if (n->in_ifnames[1] == -1) {
 1600                 n->in_ifnames[1] = n->in_ifnames[0];
 1601                 n->in_ifps[1] = n->in_ifps[0];
 1602         } else {
 1603                 n->in_ifps[1] = ipf_resolvenic(softc, base + n->in_ifnames[1],
 1604                                                n->in_v[1]);
 1605         }
 1606 
 1607         if (n->in_plabel != -1) {
 1608                 if (n->in_redir & NAT_REDIRECT)
 1609                         n->in_apr = ipf_proxy_lookup(softc->ipf_proxy_soft,
 1610                                                      n->in_pr[0],
 1611                                                      base + n->in_plabel);
 1612                 else
 1613                         n->in_apr = ipf_proxy_lookup(softc->ipf_proxy_soft,
 1614                                                      n->in_pr[1],
 1615                                                      base + n->in_plabel);
 1616                 if (n->in_apr == NULL)
 1617                         return (-1);
 1618         }
 1619         return (0);
 1620 }
 1621 
 1622 
 1623 /* ------------------------------------------------------------------------ */
 1624 /* Function:    ipf_nat_siocdelnat                                          */
 1625 /* Returns:     int - 0 == success, != 0 == failure                         */
 1626 /* Parameters:  softc(I)   - pointer to soft context main structure         */
 1627 /*              softn(I)   - pointer to NAT context structure               */
 1628 /*              n(I)       - pointer to new NAT rule                        */
 1629 /*              getlock(I) - flag indicating if lock on  is held            */
 1630 /* Mutex Locks: ipf_nat_io                                                  */
 1631 /*                                                                          */
 1632 /* Handle SIOCADNAT.  Resolve and calculate details inside the NAT rule     */
 1633 /* from information passed to the kernel, then add it  to the appropriate   */
 1634 /* NAT rule table(s).                                                       */
 1635 /* ------------------------------------------------------------------------ */
 1636 static void
 1637 ipf_nat_siocdelnat(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, ipnat_t *n,
 1638         int getlock)
 1639 {
 1640         if (getlock) {
 1641                 WRITE_ENTER(&softc->ipf_nat);
 1642         }
 1643 
 1644         ipf_nat_delrule(softc, softn, n, 1);
 1645 
 1646         if (getlock) {
 1647                 RWLOCK_EXIT(&softc->ipf_nat);                   /* READ/WRITE */
 1648         }
 1649 }
 1650 
 1651 
 1652 /* ------------------------------------------------------------------------ */
 1653 /* Function:    ipf_nat_getsz                                               */
 1654 /* Returns:     int - 0 == success, != 0 is the error value.                */
 1655 /* Parameters:  softc(I)   - pointer to soft context main structure         */
 1656 /*              data(I)    - pointer to natget structure with kernel        */
 1657 /*                           pointer get the size of.                       */
 1658 /*              getlock(I) - flag indicating whether or not the caller      */
 1659 /*                           holds a lock on ipf_nat                        */
 1660 /*                                                                          */
 1661 /* Handle SIOCSTGSZ.                                                        */
 1662 /* Return the size of the nat list entry to be copied back to user space.   */
 1663 /* The size of the entry is stored in the ng_sz field and the enture natget */
 1664 /* structure is copied back to the user.                                    */
 1665 /* ------------------------------------------------------------------------ */
 1666 static int
 1667 ipf_nat_getsz(ipf_main_softc_t *softc, caddr_t data, int getlock)
 1668 {
 1669         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 1670         ap_session_t *aps;
 1671         nat_t *nat, *n;
 1672         natget_t ng;
 1673         int error;
 1674 
 1675         error = BCOPYIN(data, &ng, sizeof(ng));
 1676         if (error != 0) {
 1677                 IPFERROR(60024);
 1678                 return (EFAULT);
 1679         }
 1680 
 1681         if (getlock) {
 1682                 READ_ENTER(&softc->ipf_nat);
 1683         }
 1684 
 1685         nat = ng.ng_ptr;
 1686         if (!nat) {
 1687                 nat = softn->ipf_nat_instances;
 1688                 ng.ng_sz = 0;
 1689                 /*
 1690                  * Empty list so the size returned is 0.  Simple.
 1691                  */
 1692                 if (nat == NULL) {
 1693                         if (getlock) {
 1694                                 RWLOCK_EXIT(&softc->ipf_nat);
 1695                         }
 1696                         error = BCOPYOUT(&ng, data, sizeof(ng));
 1697                         if (error != 0) {
 1698                                 IPFERROR(60025);
 1699                                 return (EFAULT);
 1700                         }
 1701                         return (0);
 1702                 }
 1703         } else {
 1704                 /*
 1705                  * Make sure the pointer we're copying from exists in the
 1706                  * current list of entries.  Security precaution to prevent
 1707                  * copying of random kernel data.
 1708                  */
 1709                 for (n = softn->ipf_nat_instances; n; n = n->nat_next)
 1710                         if (n == nat)
 1711                                 break;
 1712                 if (n == NULL) {
 1713                         if (getlock) {
 1714                                 RWLOCK_EXIT(&softc->ipf_nat);
 1715                         }
 1716                         IPFERROR(60026);
 1717                         return (ESRCH);
 1718                 }
 1719         }
 1720 
 1721         /*
 1722          * Include any space required for proxy data structures.
 1723          */
 1724         ng.ng_sz = sizeof(nat_save_t);
 1725         aps = nat->nat_aps;
 1726         if (aps != NULL) {
 1727                 ng.ng_sz += sizeof(ap_session_t) - 4;
 1728                 if (aps->aps_data != 0)
 1729                         ng.ng_sz += aps->aps_psiz;
 1730         }
 1731         if (getlock) {
 1732                 RWLOCK_EXIT(&softc->ipf_nat);
 1733         }
 1734 
 1735         error = BCOPYOUT(&ng, data, sizeof(ng));
 1736         if (error != 0) {
 1737                 IPFERROR(60027);
 1738                 return (EFAULT);
 1739         }
 1740         return (0);
 1741 }
 1742 
 1743 
 1744 /* ------------------------------------------------------------------------ */
 1745 /* Function:    ipf_nat_getent                                              */
 1746 /* Returns:     int - 0 == success, != 0 is the error value.                */
 1747 /* Parameters:  softc(I)   - pointer to soft context main structure         */
 1748 /*              data(I)    - pointer to natget structure with kernel pointer*/
 1749 /*                           to NAT structure to copy out.                  */
 1750 /*              getlock(I) - flag indicating whether or not the caller      */
 1751 /*                           holds a lock on ipf_nat                        */
 1752 /*                                                                          */
 1753 /* Handle SIOCSTGET.                                                        */
 1754 /* Copies out NAT entry to user space.  Any additional data held for a      */
 1755 /* proxy is also copied, as to is the NAT rule which was responsible for it */
 1756 /* ------------------------------------------------------------------------ */
 1757 static int
 1758 ipf_nat_getent(ipf_main_softc_t *softc, caddr_t data, int getlock)
 1759 {
 1760         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 1761         int error, outsize;
 1762         ap_session_t *aps;
 1763         nat_save_t *ipn, ipns;
 1764         nat_t *n, *nat;
 1765 
 1766         error = ipf_inobj(softc, data, NULL, &ipns, IPFOBJ_NATSAVE);
 1767         if (error != 0)
 1768                 return (error);
 1769 
 1770         if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920)) {
 1771                 IPFERROR(60028);
 1772                 return (EINVAL);
 1773         }
 1774 
 1775         KMALLOCS(ipn, nat_save_t *, ipns.ipn_dsize);
 1776         if (ipn == NULL) {
 1777                 IPFERROR(60029);
 1778                 return (ENOMEM);
 1779         }
 1780 
 1781         if (getlock) {
 1782                 READ_ENTER(&softc->ipf_nat);
 1783         }
 1784 
 1785         ipn->ipn_dsize = ipns.ipn_dsize;
 1786         nat = ipns.ipn_next;
 1787         if (nat == NULL) {
 1788                 nat = softn->ipf_nat_instances;
 1789                 if (nat == NULL) {
 1790                         if (softn->ipf_nat_instances == NULL) {
 1791                                 IPFERROR(60030);
 1792                                 error = ENOENT;
 1793                         }
 1794                         goto finished;
 1795                 }
 1796         } else {
 1797                 /*
 1798                  * Make sure the pointer we're copying from exists in the
 1799                  * current list of entries.  Security precaution to prevent
 1800                  * copying of random kernel data.
 1801                  */
 1802                 for (n = softn->ipf_nat_instances; n; n = n->nat_next)
 1803                         if (n == nat)
 1804                                 break;
 1805                 if (n == NULL) {
 1806                         IPFERROR(60031);
 1807                         error = ESRCH;
 1808                         goto finished;
 1809                 }
 1810         }
 1811         ipn->ipn_next = nat->nat_next;
 1812 
 1813         /*
 1814          * Copy the NAT structure.
 1815          */
 1816         bcopy((char *)nat, &ipn->ipn_nat, sizeof(*nat));
 1817 
 1818         /*
 1819          * If we have a pointer to the NAT rule it belongs to, save that too.
 1820          */
 1821         if (nat->nat_ptr != NULL)
 1822                 bcopy((char *)nat->nat_ptr, (char *)&ipn->ipn_ipnat,
 1823                       sizeof(nat->nat_ptr));
 1824 
 1825         /*
 1826          * If we also know the NAT entry has an associated filter rule,
 1827          * save that too.
 1828          */
 1829         if (nat->nat_fr != NULL)
 1830                 bcopy((char *)nat->nat_fr, (char *)&ipn->ipn_fr,
 1831                       sizeof(ipn->ipn_fr));
 1832 
 1833         /*
 1834          * Last but not least, if there is an application proxy session set
 1835          * up for this NAT entry, then copy that out too, including any
 1836          * private data saved along side it by the proxy.
 1837          */
 1838         aps = nat->nat_aps;
 1839         outsize = ipn->ipn_dsize - sizeof(*ipn) + sizeof(ipn->ipn_data);
 1840         if (aps != NULL) {
 1841                 char *s;
 1842 
 1843                 if (outsize < sizeof(*aps)) {
 1844                         IPFERROR(60032);
 1845                         error = ENOBUFS;
 1846                         goto finished;
 1847                 }
 1848 
 1849                 s = ipn->ipn_data;
 1850                 bcopy((char *)aps, s, sizeof(*aps));
 1851                 s += sizeof(*aps);
 1852                 outsize -= sizeof(*aps);
 1853                 if ((aps->aps_data != NULL) && (outsize >= aps->aps_psiz))
 1854                         bcopy(aps->aps_data, s, aps->aps_psiz);
 1855                 else {
 1856                         IPFERROR(60033);
 1857                         error = ENOBUFS;
 1858                 }
 1859         }
 1860         if (error == 0) {
 1861                 error = ipf_outobjsz(softc, data, ipn, IPFOBJ_NATSAVE,
 1862                                      ipns.ipn_dsize);
 1863         }
 1864 
 1865 finished:
 1866         if (ipn != NULL) {
 1867                 KFREES(ipn, ipns.ipn_dsize);
 1868         }
 1869         if (getlock) {
 1870                 RWLOCK_EXIT(&softc->ipf_nat);
 1871         }
 1872         return (error);
 1873 }
 1874 
 1875 
 1876 /* ------------------------------------------------------------------------ */
 1877 /* Function:    ipf_nat_putent                                              */
 1878 /* Returns:     int - 0 == success, != 0 is the error value.                */
 1879 /* Parameters:  softc(I)   - pointer to soft context main structure         */
 1880 /*              data(I)    - pointer to natget structure with NAT           */
 1881 /*                           structure information to load into the kernel  */
 1882 /*              getlock(I) - flag indicating whether or not a write lock    */
 1883 /*                           on is already held.                            */
 1884 /*                                                                          */
 1885 /* Handle SIOCSTPUT.                                                        */
 1886 /* Loads a NAT table entry from user space, including a NAT rule, proxy and */
 1887 /* firewall rule data structures, if pointers to them indicate so.          */
 1888 /* ------------------------------------------------------------------------ */
 1889 static int
 1890 ipf_nat_putent(ipf_main_softc_t *softc, caddr_t data, int getlock)
 1891 {
 1892         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 1893         nat_save_t ipn, *ipnn;
 1894         ap_session_t *aps;
 1895         nat_t *n, *nat;
 1896         frentry_t *fr;
 1897         fr_info_t fin;
 1898         ipnat_t *in;
 1899         int error;
 1900 
 1901         error = ipf_inobj(softc, data, NULL, &ipn, IPFOBJ_NATSAVE);
 1902         if (error != 0)
 1903                 return (error);
 1904 
 1905         /*
 1906          * Initialise early because of code at junkput label.
 1907          */
 1908         n = NULL;
 1909         in = NULL;
 1910         aps = NULL;
 1911         nat = NULL;
 1912         ipnn = NULL;
 1913         fr = NULL;
 1914 
 1915         /*
 1916          * New entry, copy in the rest of the NAT entry if it's size is more
 1917          * than just the nat_t structure.
 1918          */
 1919         if (ipn.ipn_dsize > sizeof(ipn)) {
 1920                 if (ipn.ipn_dsize > 81920) {
 1921                         IPFERROR(60034);
 1922                         error = ENOMEM;
 1923                         goto junkput;
 1924                 }
 1925 
 1926                 KMALLOCS(ipnn, nat_save_t *, ipn.ipn_dsize);
 1927                 if (ipnn == NULL) {
 1928                         IPFERROR(60035);
 1929                         return (ENOMEM);
 1930                 }
 1931 
 1932                 bzero(ipnn, ipn.ipn_dsize);
 1933                 error = ipf_inobjsz(softc, data, ipnn, IPFOBJ_NATSAVE,
 1934                                     ipn.ipn_dsize);
 1935                 if (error != 0) {
 1936                         goto junkput;
 1937                 }
 1938         } else
 1939                 ipnn = &ipn;
 1940 
 1941         KMALLOC(nat, nat_t *);
 1942         if (nat == NULL) {
 1943                 IPFERROR(60037);
 1944                 error = ENOMEM;
 1945                 goto junkput;
 1946         }
 1947 
 1948         bcopy((char *)&ipnn->ipn_nat, (char *)nat, sizeof(*nat));
 1949 
 1950         switch (nat->nat_v[0])
 1951         {
 1952         case 4:
 1953 #ifdef USE_INET6
 1954         case 6 :
 1955 #endif
 1956                 break;
 1957         default :
 1958                 IPFERROR(60061);
 1959                 error = EPROTONOSUPPORT;
 1960                 goto junkput;
 1961                 /*NOTREACHED*/
 1962         }
 1963 
 1964         /*
 1965          * Initialize all these so that ipf_nat_delete() doesn't cause a crash.
 1966          */
 1967         bzero((char *)nat, offsetof(struct nat, nat_tqe));
 1968         nat->nat_tqe.tqe_pnext = NULL;
 1969         nat->nat_tqe.tqe_next = NULL;
 1970         nat->nat_tqe.tqe_ifq = NULL;
 1971         nat->nat_tqe.tqe_parent = nat;
 1972 
 1973         /*
 1974          * Restore the rule associated with this nat session
 1975          */
 1976         in = ipnn->ipn_nat.nat_ptr;
 1977         if (in != NULL) {
 1978                 KMALLOCS(in, ipnat_t *, ipnn->ipn_ipnat.in_size);
 1979                 nat->nat_ptr = in;
 1980                 if (in == NULL) {
 1981                         IPFERROR(60038);
 1982                         error = ENOMEM;
 1983                         goto junkput;
 1984                 }
 1985                 bcopy((char *)&ipnn->ipn_ipnat, (char *)in,
 1986                       ipnn->ipn_ipnat.in_size);
 1987                 in->in_use = 1;
 1988                 in->in_flags |= IPN_DELETE;
 1989 
 1990                 ATOMIC_INC32(softn->ipf_nat_stats.ns_rules);
 1991 
 1992                 if (ipf_nat_resolverule(softc, in) != 0) {
 1993                         IPFERROR(60039);
 1994                         error = ESRCH;
 1995                         goto junkput;
 1996                 }
 1997         }
 1998 
 1999         /*
 2000          * Check that the NAT entry doesn't already exist in the kernel.
 2001          *
 2002          * For NAT_OUTBOUND, we're lookup for a duplicate MAP entry.  To do
 2003          * this, we check to see if the inbound combination of addresses and
 2004          * ports is already known.  Similar logic is applied for NAT_INBOUND.
 2005          *
 2006          */
 2007         bzero((char *)&fin, sizeof(fin));
 2008         fin.fin_v = nat->nat_v[0];
 2009         fin.fin_p = nat->nat_pr[0];
 2010         fin.fin_rev = nat->nat_rev;
 2011         fin.fin_ifp = nat->nat_ifps[0];
 2012         fin.fin_data[0] = ntohs(nat->nat_ndport);
 2013         fin.fin_data[1] = ntohs(nat->nat_nsport);
 2014 
 2015         switch (nat->nat_dir)
 2016         {
 2017         case NAT_OUTBOUND :
 2018         case NAT_DIVERTOUT :
 2019                 if (getlock) {
 2020                         READ_ENTER(&softc->ipf_nat);
 2021                 }
 2022 
 2023                 fin.fin_v = nat->nat_v[1];
 2024                 if (nat->nat_v[1] == 4) {
 2025                         n = ipf_nat_inlookup(&fin, nat->nat_flags, fin.fin_p,
 2026                                              nat->nat_ndstip, nat->nat_nsrcip);
 2027 #ifdef USE_INET6
 2028                 } else if (nat->nat_v[1] == 6) {
 2029                         n = ipf_nat6_inlookup(&fin, nat->nat_flags, fin.fin_p,
 2030                                               &nat->nat_ndst6.in6,
 2031                                               &nat->nat_nsrc6.in6);
 2032 #endif
 2033                 }
 2034 
 2035                 if (getlock) {
 2036                         RWLOCK_EXIT(&softc->ipf_nat);
 2037                 }
 2038                 if (n != NULL) {
 2039                         IPFERROR(60040);
 2040                         error = EEXIST;
 2041                         goto junkput;
 2042                 }
 2043                 break;
 2044 
 2045         case NAT_INBOUND :
 2046         case NAT_DIVERTIN :
 2047                 if (getlock) {
 2048                         READ_ENTER(&softc->ipf_nat);
 2049                 }
 2050 
 2051                 if (fin.fin_v == 4) {
 2052                         n = ipf_nat_outlookup(&fin, nat->nat_flags, fin.fin_p,
 2053                                               nat->nat_ndstip,
 2054                                               nat->nat_nsrcip);
 2055 #ifdef USE_INET6
 2056                 } else if (fin.fin_v == 6) {
 2057                         n = ipf_nat6_outlookup(&fin, nat->nat_flags, fin.fin_p,
 2058                                                &nat->nat_ndst6.in6,
 2059                                                &nat->nat_nsrc6.in6);
 2060 #endif
 2061                 }
 2062 
 2063                 if (getlock) {
 2064                         RWLOCK_EXIT(&softc->ipf_nat);
 2065                 }
 2066                 if (n != NULL) {
 2067                         IPFERROR(60041);
 2068                         error = EEXIST;
 2069                         goto junkput;
 2070                 }
 2071                 break;
 2072 
 2073         default :
 2074                 IPFERROR(60042);
 2075                 error = EINVAL;
 2076                 goto junkput;
 2077         }
 2078 
 2079         /*
 2080          * Restore ap_session_t structure.  Include the private data allocated
 2081          * if it was there.
 2082          */
 2083         aps = nat->nat_aps;
 2084         if (aps != NULL) {
 2085                 KMALLOC(aps, ap_session_t *);
 2086                 nat->nat_aps = aps;
 2087                 if (aps == NULL) {
 2088                         IPFERROR(60043);
 2089                         error = ENOMEM;
 2090                         goto junkput;
 2091                 }
 2092                 bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps));
 2093                 if (in != NULL)
 2094                         aps->aps_apr = in->in_apr;
 2095                 else
 2096                         aps->aps_apr = NULL;
 2097                 if (aps->aps_psiz != 0) {
 2098                         if (aps->aps_psiz > 81920) {
 2099                                 IPFERROR(60044);
 2100                                 error = ENOMEM;
 2101                                 goto junkput;
 2102                         }
 2103                         KMALLOCS(aps->aps_data, void *, aps->aps_psiz);
 2104                         if (aps->aps_data == NULL) {
 2105                                 IPFERROR(60045);
 2106                                 error = ENOMEM;
 2107                                 goto junkput;
 2108                         }
 2109                         bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data,
 2110                               aps->aps_psiz);
 2111                 } else {
 2112                         aps->aps_psiz = 0;
 2113                         aps->aps_data = NULL;
 2114                 }
 2115         }
 2116 
 2117         /*
 2118          * If there was a filtering rule associated with this entry then
 2119          * build up a new one.
 2120          */
 2121         fr = nat->nat_fr;
 2122         if (fr != NULL) {
 2123                 if ((nat->nat_flags & SI_NEWFR) != 0) {
 2124                         KMALLOC(fr, frentry_t *);
 2125                         nat->nat_fr = fr;
 2126                         if (fr == NULL) {
 2127                                 IPFERROR(60046);
 2128                                 error = ENOMEM;
 2129                                 goto junkput;
 2130                         }
 2131                         ipnn->ipn_nat.nat_fr = fr;
 2132                         fr->fr_ref = 1;
 2133                         (void) ipf_outobj(softc, data, ipnn, IPFOBJ_NATSAVE);
 2134                         bcopy((char *)&ipnn->ipn_fr, (char *)fr, sizeof(*fr));
 2135 
 2136                         fr->fr_ref = 1;
 2137                         fr->fr_dsize = 0;
 2138                         fr->fr_data = NULL;
 2139                         fr->fr_type = FR_T_NONE;
 2140 
 2141                         MUTEX_NUKE(&fr->fr_lock);
 2142                         MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock");
 2143                 } else {
 2144                         if (getlock) {
 2145                                 READ_ENTER(&softc->ipf_nat);
 2146                         }
 2147                         for (n = softn->ipf_nat_instances; n; n = n->nat_next)
 2148                                 if (n->nat_fr == fr)
 2149                                         break;
 2150 
 2151                         if (n != NULL) {
 2152                                 MUTEX_ENTER(&fr->fr_lock);
 2153                                 fr->fr_ref++;
 2154                                 MUTEX_EXIT(&fr->fr_lock);
 2155                         }
 2156                         if (getlock) {
 2157                                 RWLOCK_EXIT(&softc->ipf_nat);
 2158                         }
 2159 
 2160                         if (n == NULL) {
 2161                                 IPFERROR(60047);
 2162                                 error = ESRCH;
 2163                                 goto junkput;
 2164                         }
 2165                 }
 2166         }
 2167 
 2168         if (ipnn != &ipn) {
 2169                 KFREES(ipnn, ipn.ipn_dsize);
 2170                 ipnn = NULL;
 2171         }
 2172 
 2173         if (getlock) {
 2174                 WRITE_ENTER(&softc->ipf_nat);
 2175         }
 2176 
 2177         if (fin.fin_v == 4)
 2178                 error = ipf_nat_finalise(&fin, nat);
 2179 #ifdef USE_INET6
 2180         else
 2181                 error = ipf_nat6_finalise(&fin, nat);
 2182 #endif
 2183 
 2184         if (getlock) {
 2185                 RWLOCK_EXIT(&softc->ipf_nat);
 2186         }
 2187 
 2188         if (error == 0)
 2189                 return (0);
 2190 
 2191         IPFERROR(60048);
 2192         error = ENOMEM;
 2193 
 2194 junkput:
 2195         if (fr != NULL) {
 2196                 (void) ipf_derefrule(softc, &fr);
 2197         }
 2198 
 2199         if ((ipnn != NULL) && (ipnn != &ipn)) {
 2200                 KFREES(ipnn, ipn.ipn_dsize);
 2201         }
 2202         if (nat != NULL) {
 2203                 if (aps != NULL) {
 2204                         if (aps->aps_data != NULL) {
 2205                                 KFREES(aps->aps_data, aps->aps_psiz);
 2206                         }
 2207                         KFREE(aps);
 2208                 }
 2209                 if (in != NULL) {
 2210                         if (in->in_apr)
 2211                                 ipf_proxy_deref(in->in_apr);
 2212                         KFREES(in, in->in_size);
 2213                 }
 2214                 KFREE(nat);
 2215         }
 2216         return (error);
 2217 }
 2218 
 2219 
 2220 /* ------------------------------------------------------------------------ */
 2221 /* Function:    ipf_nat_delete                                              */
 2222 /* Returns:     Nil                                                         */
 2223 /* Parameters:  softc(I)   - pointer to soft context main structure         */
 2224 /*              nat(I)     - pointer to NAT structure to delete             */
 2225 /*              logtype(I) - type of LOG record to create before deleting   */
 2226 /* Write Lock:  ipf_nat                                                     */
 2227 /*                                                                          */
 2228 /* Delete a nat entry from the various lists and table.  If NAT logging is  */
 2229 /* enabled then generate a NAT log record for this event.                   */
 2230 /* ------------------------------------------------------------------------ */
 2231 void
 2232 ipf_nat_delete(ipf_main_softc_t *softc, struct nat *nat, int logtype)
 2233 {
 2234         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 2235         int madeorphan = 0, bkt, removed = 0;
 2236         nat_stat_side_t *nss;
 2237         struct ipnat *ipn;
 2238 
 2239         if (logtype != 0 && softn->ipf_nat_logging != 0)
 2240                 ipf_nat_log(softc, softn, nat, logtype);
 2241 
 2242         /*
 2243          * Take it as a general indication that all the pointers are set if
 2244          * nat_pnext is set.
 2245          */
 2246         if (nat->nat_pnext != NULL) {
 2247                 removed = 1;
 2248 
 2249                 bkt = nat->nat_hv[0] % softn->ipf_nat_table_sz;
 2250                 nss = &softn->ipf_nat_stats.ns_side[0];
 2251                 if (nss->ns_bucketlen[bkt] > 0)
 2252                         nss->ns_bucketlen[bkt]--;
 2253                 if (nss->ns_bucketlen[bkt] == 0) {
 2254                         nss->ns_inuse--;
 2255                 }
 2256 
 2257                 bkt = nat->nat_hv[1] % softn->ipf_nat_table_sz;
 2258                 nss = &softn->ipf_nat_stats.ns_side[1];
 2259                 if (nss->ns_bucketlen[bkt] > 0)
 2260                         nss->ns_bucketlen[bkt]--;
 2261                 if (nss->ns_bucketlen[bkt] == 0) {
 2262                         nss->ns_inuse--;
 2263                 }
 2264 
 2265                 *nat->nat_pnext = nat->nat_next;
 2266                 if (nat->nat_next != NULL) {
 2267                         nat->nat_next->nat_pnext = nat->nat_pnext;
 2268                         nat->nat_next = NULL;
 2269                 }
 2270                 nat->nat_pnext = NULL;
 2271 
 2272                 *nat->nat_phnext[0] = nat->nat_hnext[0];
 2273                 if (nat->nat_hnext[0] != NULL) {
 2274                         nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
 2275                         nat->nat_hnext[0] = NULL;
 2276                 }
 2277                 nat->nat_phnext[0] = NULL;
 2278 
 2279                 *nat->nat_phnext[1] = nat->nat_hnext[1];
 2280                 if (nat->nat_hnext[1] != NULL) {
 2281                         nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
 2282                         nat->nat_hnext[1] = NULL;
 2283                 }
 2284                 nat->nat_phnext[1] = NULL;
 2285 
 2286                 if ((nat->nat_flags & SI_WILDP) != 0) {
 2287                         ATOMIC_DEC32(softn->ipf_nat_stats.ns_wilds);
 2288                 }
 2289                 madeorphan = 1;
 2290         }
 2291 
 2292         if (nat->nat_me != NULL) {
 2293                 *nat->nat_me = NULL;
 2294                 nat->nat_me = NULL;
 2295                 nat->nat_ref--;
 2296                 ASSERT(nat->nat_ref >= 0);
 2297         }
 2298 
 2299         if (nat->nat_tqe.tqe_ifq != NULL) {
 2300                 /*
 2301                  * No call to ipf_freetimeoutqueue() is made here, they are
 2302                  * garbage collected in ipf_nat_expire().
 2303                  */
 2304                 (void) ipf_deletequeueentry(&nat->nat_tqe);
 2305         }
 2306 
 2307         if (nat->nat_sync) {
 2308                 ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync);
 2309                 nat->nat_sync = NULL;
 2310         }
 2311 
 2312         if (logtype == NL_EXPIRE)
 2313                 softn->ipf_nat_stats.ns_expire++;
 2314 
 2315         MUTEX_ENTER(&nat->nat_lock);
 2316         /*
 2317          * NL_DESTROY should only be passed in when we've got nat_ref >= 2.
 2318          * This happens when a nat'd packet is blocked and we want to throw
 2319          * away the NAT session.
 2320          */
 2321         if (logtype == NL_DESTROY) {
 2322                 if (nat->nat_ref > 2) {
 2323                         nat->nat_ref -= 2;
 2324                         MUTEX_EXIT(&nat->nat_lock);
 2325                         if (removed)
 2326                                 softn->ipf_nat_stats.ns_orphans++;
 2327                         return;
 2328                 }
 2329         } else if (nat->nat_ref > 1) {
 2330                 nat->nat_ref--;
 2331                 MUTEX_EXIT(&nat->nat_lock);
 2332                 if (madeorphan == 1)
 2333                         softn->ipf_nat_stats.ns_orphans++;
 2334                 return;
 2335         }
 2336         ASSERT(nat->nat_ref >= 0);
 2337         MUTEX_EXIT(&nat->nat_lock);
 2338 
 2339         nat->nat_ref = 0;
 2340 
 2341         if (madeorphan == 0)
 2342                 softn->ipf_nat_stats.ns_orphans--;
 2343 
 2344         /*
 2345          * At this point, nat_ref can be either 0 or -1
 2346          */
 2347         softn->ipf_nat_stats.ns_proto[nat->nat_pr[0]]--;
 2348 
 2349         if (nat->nat_fr != NULL) {
 2350                 (void) ipf_derefrule(softc, &nat->nat_fr);
 2351         }
 2352 
 2353         if (nat->nat_hm != NULL) {
 2354                 ipf_nat_hostmapdel(softc, &nat->nat_hm);
 2355         }
 2356 
 2357         /*
 2358          * If there is an active reference from the nat entry to its parent
 2359          * rule, decrement the rule's reference count and free it too if no
 2360          * longer being used.
 2361          */
 2362         ipn = nat->nat_ptr;
 2363         nat->nat_ptr = NULL;
 2364 
 2365         if (ipn != NULL) {
 2366                 ipn->in_space++;
 2367                 ipf_nat_rule_deref(softc, &ipn);
 2368         }
 2369 
 2370         if (nat->nat_aps != NULL) {
 2371                 ipf_proxy_free(softc, nat->nat_aps);
 2372                 nat->nat_aps = NULL;
 2373         }
 2374 
 2375         MUTEX_DESTROY(&nat->nat_lock);
 2376 
 2377         softn->ipf_nat_stats.ns_active--;
 2378 
 2379         /*
 2380          * If there's a fragment table entry too for this nat entry, then
 2381          * dereference that as well.  This is after nat_lock is released
 2382          * because of Tru64.
 2383          */
 2384         ipf_frag_natforget(softc, (void *)nat);
 2385 
 2386         KFREE(nat);
 2387 }
 2388 
 2389 
 2390 /* ------------------------------------------------------------------------ */
 2391 /* Function:    ipf_nat_flushtable                                          */
 2392 /* Returns:     int - number of NAT rules deleted                           */
 2393 /* Parameters:  softc(I) - pointer to soft context main structure           */
 2394 /*              softn(I) - pointer to NAT context structure                 */
 2395 /* Write Lock:  ipf_nat                                                     */
 2396 /*                                                                          */
 2397 /* Deletes all currently active NAT sessions.  In deleting each NAT entry a */
 2398 /* log record should be emitted in ipf_nat_delete() if NAT logging is       */
 2399 /* enabled.                                                                 */
 2400 /* ------------------------------------------------------------------------ */
 2401 /*
 2402  * nat_flushtable - clear the NAT table of all mapping entries.
 2403  */
 2404 static int
 2405 ipf_nat_flushtable(ipf_main_softc_t *softc, ipf_nat_softc_t *softn)
 2406 {
 2407         nat_t *nat;
 2408         int j = 0;
 2409 
 2410         /*
 2411          * ALL NAT mappings deleted, so lets just make the deletions
 2412          * quicker.
 2413          */
 2414         if (softn->ipf_nat_table[0] != NULL)
 2415                 bzero((char *)softn->ipf_nat_table[0],
 2416                       sizeof(softn->ipf_nat_table[0]) *
 2417                       softn->ipf_nat_table_sz);
 2418         if (softn->ipf_nat_table[1] != NULL)
 2419                 bzero((char *)softn->ipf_nat_table[1],
 2420                       sizeof(softn->ipf_nat_table[1]) *
 2421                       softn->ipf_nat_table_sz);
 2422 
 2423         while ((nat = softn->ipf_nat_instances) != NULL) {
 2424                 ipf_nat_delete(softc, nat, NL_FLUSH);
 2425                 j++;
 2426         }
 2427 
 2428         return (j);
 2429 }
 2430 
 2431 
 2432 /* ------------------------------------------------------------------------ */
 2433 /* Function:    ipf_nat_clearlist                                           */
 2434 /* Returns:     int - number of NAT/RDR rules deleted                       */
 2435 /* Parameters:  softc(I) - pointer to soft context main structure           */
 2436 /*              softn(I) - pointer to NAT context structure                 */
 2437 /*                                                                          */
 2438 /* Delete all rules in the current list of rules.  There is nothing elegant */
 2439 /* about this cleanup: simply free all entries on the list of rules and     */
 2440 /* clear out the tables used for hashed NAT rule lookups.                   */
 2441 /* ------------------------------------------------------------------------ */
 2442 static int
 2443 ipf_nat_clearlist(ipf_main_softc_t *softc, ipf_nat_softc_t *softn)
 2444 {
 2445         ipnat_t *n;
 2446         int i = 0;
 2447 
 2448         if (softn->ipf_nat_map_rules != NULL) {
 2449                 bzero((char *)softn->ipf_nat_map_rules,
 2450                       sizeof(*softn->ipf_nat_map_rules) *
 2451                       softn->ipf_nat_maprules_sz);
 2452         }
 2453         if (softn->ipf_nat_rdr_rules != NULL) {
 2454                 bzero((char *)softn->ipf_nat_rdr_rules,
 2455                       sizeof(*softn->ipf_nat_rdr_rules) *
 2456                       softn->ipf_nat_rdrrules_sz);
 2457         }
 2458 
 2459         while ((n = softn->ipf_nat_list) != NULL) {
 2460                 ipf_nat_delrule(softc, softn, n, 0);
 2461                 i++;
 2462         }
 2463 #if SOLARIS && !defined(INSTANCES)
 2464         pfil_delayed_copy = 1;
 2465 #endif
 2466         return (i);
 2467 }
 2468 
 2469 
 2470 /* ------------------------------------------------------------------------ */
 2471 /* Function:    ipf_nat_delrule                                             */
 2472 /* Returns:     Nil                                                         */
 2473 /* Parameters:  softc(I) - pointer to soft context main structure           */
 2474 /*              softn(I) - pointer to NAT context structure                 */
 2475 /*              np(I)    - pointer to NAT rule to delete                    */
 2476 /*              purge(I) - 1 == allow purge, 0 == prevent purge             */
 2477 /* Locks:       WRITE(ipf_nat)                                              */
 2478 /*                                                                          */
 2479 /* Preventing "purge" from occuring is allowed because when all of the NAT  */
 2480 /* rules are being removed, allowing the "purge" to walk through the list   */
 2481 /* of NAT sessions, possibly multiple times, would be a large performance   */
 2482 /* hit, on the order of O(N^2).                                             */
 2483 /* ------------------------------------------------------------------------ */
 2484 static void
 2485 ipf_nat_delrule(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, ipnat_t *np,
 2486         int purge)
 2487 {
 2488 
 2489         if (np->in_pnext != NULL) {
 2490                 *np->in_pnext = np->in_next;
 2491                 if (np->in_next != NULL)
 2492                         np->in_next->in_pnext = np->in_pnext;
 2493                 if (softn->ipf_nat_list_tail == &np->in_next)
 2494                         softn->ipf_nat_list_tail = np->in_pnext;
 2495         }
 2496 
 2497         if ((purge == 1) && ((np->in_flags & IPN_PURGE) != 0)) {
 2498                 nat_t *next;
 2499                 nat_t *nat;
 2500 
 2501                 for (next = softn->ipf_nat_instances; (nat = next) != NULL;) {
 2502                         next = nat->nat_next;
 2503                         if (nat->nat_ptr == np)
 2504                                 ipf_nat_delete(softc, nat, NL_PURGE);
 2505                 }
 2506         }
 2507 
 2508         if ((np->in_flags & IPN_DELETE) == 0) {
 2509                 if (np->in_redir & NAT_REDIRECT) {
 2510                         switch (np->in_v[0])
 2511                         {
 2512                         case 4 :
 2513                                 ipf_nat_delrdr(softn, np);
 2514                                 break;
 2515 #ifdef USE_INET6
 2516                         case 6 :
 2517                                 ipf_nat6_delrdr(softn, np);
 2518                                 break;
 2519 #endif
 2520                         }
 2521                 }
 2522                 if (np->in_redir & (NAT_MAPBLK|NAT_MAP)) {
 2523                         switch (np->in_v[0])
 2524                         {
 2525                         case 4 :
 2526                                 ipf_nat_delmap(softn, np);
 2527                                 break;
 2528 #ifdef USE_INET6
 2529                         case 6 :
 2530                                 ipf_nat6_delmap(softn, np);
 2531                                 break;
 2532 #endif
 2533                         }
 2534                 }
 2535         }
 2536 
 2537         np->in_flags |= IPN_DELETE;
 2538         ipf_nat_rule_deref(softc, &np);
 2539 }
 2540 
 2541 
 2542 /* ------------------------------------------------------------------------ */
 2543 /* Function:    ipf_nat_newmap                                              */
 2544 /* Returns:     int - -1 == error, 0 == success                             */
 2545 /* Parameters:  fin(I) - pointer to packet information                      */
 2546 /*              nat(I) - pointer to NAT entry                               */
 2547 /*              ni(I)  - pointer to structure with misc. information needed */
 2548 /*                       to create new NAT entry.                           */
 2549 /*                                                                          */
 2550 /* Given an empty NAT structure, populate it with new information about a   */
 2551 /* new NAT session, as defined by the matching NAT rule.                    */
 2552 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
 2553 /* to the new IP address for the translation.                               */
 2554 /* ------------------------------------------------------------------------ */
 2555 static int
 2556 ipf_nat_newmap(fr_info_t *fin, nat_t *nat, natinfo_t *ni)
 2557 {
 2558         ipf_main_softc_t *softc = fin->fin_main_soft;
 2559         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 2560         u_short st_port, dport, sport, port, sp, dp;
 2561         struct in_addr in, inb;
 2562         hostmap_t *hm;
 2563         u_32_t flags;
 2564         u_32_t st_ip;
 2565         ipnat_t *np;
 2566         nat_t *natl;
 2567         int l;
 2568 
 2569         /*
 2570          * If it's an outbound packet which doesn't match any existing
 2571          * record, then create a new port
 2572          */
 2573         l = 0;
 2574         hm = NULL;
 2575         np = ni->nai_np;
 2576         st_ip = np->in_snip;
 2577         st_port = np->in_spnext;
 2578         flags = nat->nat_flags;
 2579 
 2580         if (flags & IPN_ICMPQUERY) {
 2581                 sport = fin->fin_data[1];
 2582                 dport = 0;
 2583         } else {
 2584                 sport = htons(fin->fin_data[0]);
 2585                 dport = htons(fin->fin_data[1]);
 2586         }
 2587 
 2588         /*
 2589          * Do a loop until we either run out of entries to try or we find
 2590          * a NAT mapping that isn't currently being used.  This is done
 2591          * because the change to the source is not (usually) being fixed.
 2592          */
 2593         do {
 2594                 port = 0;
 2595                 in.s_addr = htonl(np->in_snip);
 2596                 if (l == 0) {
 2597                         /*
 2598                          * Check to see if there is an existing NAT
 2599                          * setup for this IP address pair.
 2600                          */
 2601                         hm = ipf_nat_hostmap(softn, np, fin->fin_src,
 2602                                              fin->fin_dst, in, 0);
 2603                         if (hm != NULL)
 2604                                 in.s_addr = hm->hm_nsrcip.s_addr;
 2605                 } else if ((l == 1) && (hm != NULL)) {
 2606                         ipf_nat_hostmapdel(softc, &hm);
 2607                 }
 2608                 in.s_addr = ntohl(in.s_addr);
 2609 
 2610                 nat->nat_hm = hm;
 2611 
 2612                 if ((np->in_nsrcmsk == 0xffffffff) && (np->in_spnext == 0)) {
 2613                         if (l > 0) {
 2614                                 NBUMPSIDEX(1, ns_exhausted, ns_exhausted_1);
 2615                                 DT4(ns_exhausted_1, fr_info_t *, fin, nat_t *, nat, natinfo_t *, ni, ipnat_t *, np);
 2616                                 return (-1);
 2617                         }
 2618                 }
 2619 
 2620                 if (np->in_redir == NAT_BIMAP &&
 2621                     np->in_osrcmsk == np->in_nsrcmsk) {
 2622                         /*
 2623                          * map the address block in a 1:1 fashion
 2624                          */
 2625                         in.s_addr = np->in_nsrcaddr;
 2626                         in.s_addr |= fin->fin_saddr & ~np->in_osrcmsk;
 2627                         in.s_addr = ntohl(in.s_addr);
 2628 
 2629                 } else if (np->in_redir & NAT_MAPBLK) {
 2630                         if ((l >= np->in_ppip) || ((l > 0) &&
 2631                              !(flags & IPN_TCPUDP))) {
 2632                                 NBUMPSIDEX(1, ns_exhausted, ns_exhausted_2);
 2633                                 DT4(ns_exhausted_2, fr_info_t *, fin, nat_t *, nat, natinfo_t *, ni, ipnat_t *, np);
 2634                                 return (-1);
 2635                         }
 2636                         /*
 2637                          * map-block - Calculate destination address.
 2638                          */
 2639                         in.s_addr = ntohl(fin->fin_saddr);
 2640                         in.s_addr &= ntohl(~np->in_osrcmsk);
 2641                         inb.s_addr = in.s_addr;
 2642                         in.s_addr /= np->in_ippip;
 2643                         in.s_addr &= ntohl(~np->in_nsrcmsk);
 2644                         in.s_addr += ntohl(np->in_nsrcaddr);
 2645                         /*
 2646                          * Calculate destination port.
 2647                          */
 2648                         if ((flags & IPN_TCPUDP) &&
 2649                             (np->in_ppip != 0)) {
 2650                                 port = ntohs(sport) + l;
 2651                                 port %= np->in_ppip;
 2652                                 port += np->in_ppip *
 2653                                         (inb.s_addr % np->in_ippip);
 2654                                 port += MAPBLK_MINPORT;
 2655                                 port = htons(port);
 2656                         }
 2657 
 2658                 } else if ((np->in_nsrcaddr == 0) &&
 2659                            (np->in_nsrcmsk == 0xffffffff)) {
 2660                         i6addr_t in6;
 2661 
 2662                         /*
 2663                          * 0/32 - use the interface's IP address.
 2664                          */
 2665                         if ((l > 0) ||
 2666                             ipf_ifpaddr(softc, 4, FRI_NORMAL, fin->fin_ifp,
 2667                                        &in6, NULL) == -1) {
 2668                                 NBUMPSIDEX(1, ns_new_ifpaddr, ns_new_ifpaddr_1);
 2669                                 DT4(ns_new_ifpaddr_1, fr_info_t *, fin, nat_t *, nat, natinfo_t *, ni, ipnat_t *, np);
 2670                                 return (-1);
 2671                         }
 2672                         in.s_addr = ntohl(in6.in4.s_addr);
 2673 
 2674                 } else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) {
 2675                         /*
 2676                          * 0/0 - use the original source address/port.
 2677                          */
 2678                         if (l > 0) {
 2679                                 NBUMPSIDEX(1, ns_exhausted, ns_exhausted_3);
 2680                                 DT4(ns_exhausted_3, fr_info_t *, fin, nat_t *, nat, natinfo_t *, ni, ipnat_t *, np);
 2681                                 return (-1);
 2682                         }
 2683                         in.s_addr = ntohl(fin->fin_saddr);
 2684 
 2685                 } else if ((np->in_nsrcmsk != 0xffffffff) &&
 2686                            (np->in_spnext == 0) && ((l > 0) || (hm == NULL)))
 2687                         np->in_snip++;
 2688 
 2689                 natl = NULL;
 2690 
 2691                 if ((flags & IPN_TCPUDP) &&
 2692                     ((np->in_redir & NAT_MAPBLK) == 0) &&
 2693                     (np->in_flags & IPN_AUTOPORTMAP)) {
 2694                         /*
 2695                          * "ports auto" (without map-block)
 2696                          */
 2697                         if ((l > 0) && (l % np->in_ppip == 0)) {
 2698                                 if ((l > np->in_ppip) &&
 2699                                     np->in_nsrcmsk != 0xffffffff)
 2700                                         np->in_snip++;
 2701                         }
 2702                         if (np->in_ppip != 0) {
 2703                                 port = ntohs(sport);
 2704                                 port += (l % np->in_ppip);
 2705                                 port %= np->in_ppip;
 2706                                 port += np->in_ppip *
 2707                                         (ntohl(fin->fin_saddr) %
 2708                                          np->in_ippip);
 2709                                 port += MAPBLK_MINPORT;
 2710                                 port = htons(port);
 2711                         }
 2712 
 2713                 } else if (((np->in_redir & NAT_MAPBLK) == 0) &&
 2714                            (flags & IPN_TCPUDPICMP) && (np->in_spnext != 0)) {
 2715                         /*
 2716                          * Standard port translation.  Select next port.
 2717                          */
 2718                         if (np->in_flags & IPN_SEQUENTIAL) {
 2719                                 port = np->in_spnext;
 2720                         } else {
 2721                                 port = ipf_random() % (np->in_spmax -
 2722                                                        np->in_spmin + 1);
 2723                                 port += np->in_spmin;
 2724                         }
 2725                         port = htons(port);
 2726                         np->in_spnext++;
 2727 
 2728                         if (np->in_spnext > np->in_spmax) {
 2729                                 np->in_spnext = np->in_spmin;
 2730                                 if (np->in_nsrcmsk != 0xffffffff)
 2731                                         np->in_snip++;
 2732                         }
 2733                 }
 2734 
 2735                 if (np->in_flags & IPN_SIPRANGE) {
 2736                         if (np->in_snip > ntohl(np->in_nsrcmsk))
 2737                                 np->in_snip = ntohl(np->in_nsrcaddr);
 2738                 } else {
 2739                         if ((np->in_nsrcmsk != 0xffffffff) &&
 2740                             ((np->in_snip + 1) & ntohl(np->in_nsrcmsk)) >
 2741                             ntohl(np->in_nsrcaddr))
 2742                                 np->in_snip = ntohl(np->in_nsrcaddr) + 1;
 2743                 }
 2744 
 2745                 if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY)))
 2746                         port = sport;
 2747 
 2748                 /*
 2749                  * Here we do a lookup of the connection as seen from
 2750                  * the outside.  If an IP# pair already exists, try
 2751                  * again.  So if you have A->B becomes C->B, you can
 2752                  * also have D->E become C->E but not D->B causing
 2753                  * another C->B.  Also take protocol and ports into
 2754                  * account when determining whether a pre-existing
 2755                  * NAT setup will cause an external conflict where
 2756                  * this is appropriate.
 2757                  */
 2758                 inb.s_addr = htonl(in.s_addr);
 2759                 sp = fin->fin_data[0];
 2760                 dp = fin->fin_data[1];
 2761                 fin->fin_data[0] = fin->fin_data[1];
 2762                 fin->fin_data[1] = ntohs(port);
 2763                 natl = ipf_nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
 2764                                         (u_int)fin->fin_p, fin->fin_dst, inb);
 2765                 fin->fin_data[0] = sp;
 2766                 fin->fin_data[1] = dp;
 2767 
 2768                 /*
 2769                  * Has the search wrapped around and come back to the
 2770                  * start ?
 2771                  */
 2772                 if ((natl != NULL) &&
 2773                     (np->in_spnext != 0) && (st_port == np->in_spnext) &&
 2774                     (np->in_snip != 0) && (st_ip == np->in_snip)) {
 2775                         NBUMPSIDED(1, ns_wrap);
 2776                         DT4(ns_wrap, fr_info_t *, fin, nat_t *, nat, natinfo_t *, ni, ipnat_t *, np);
 2777                         return (-1);
 2778                 }
 2779                 l++;
 2780         } while (natl != NULL);
 2781 
 2782         /* Setup the NAT table */
 2783         nat->nat_osrcip = fin->fin_src;
 2784         nat->nat_nsrcaddr = htonl(in.s_addr);
 2785         nat->nat_odstip = fin->fin_dst;
 2786         nat->nat_ndstip = fin->fin_dst;
 2787         if (nat->nat_hm == NULL)
 2788                 nat->nat_hm = ipf_nat_hostmap(softn, np, fin->fin_src,
 2789                                               fin->fin_dst, nat->nat_nsrcip,
 2790                                               0);
 2791 
 2792         if (flags & IPN_TCPUDP) {
 2793                 nat->nat_osport = sport;
 2794                 nat->nat_nsport = port; /* sport */
 2795                 nat->nat_odport = dport;
 2796                 nat->nat_ndport = dport;
 2797                 ((tcphdr_t *)fin->fin_dp)->th_sport = port;
 2798         } else if (flags & IPN_ICMPQUERY) {
 2799                 nat->nat_oicmpid = fin->fin_data[1];
 2800                 ((icmphdr_t *)fin->fin_dp)->icmp_id = port;
 2801                 nat->nat_nicmpid = port;
 2802         }
 2803         return (0);
 2804 }
 2805 
 2806 
 2807 /* ------------------------------------------------------------------------ */
 2808 /* Function:    ipf_nat_newrdr                                              */
 2809 /* Returns:     int - -1 == error, 0 == success (no move), 1 == success and */
 2810 /*                    allow rule to be moved if IPN_ROUNDR is set.          */
 2811 /* Parameters:  fin(I) - pointer to packet information                      */
 2812 /*              nat(I) - pointer to NAT entry                               */
 2813 /*              ni(I)  - pointer to structure with misc. information needed */
 2814 /*                       to create new NAT entry.                           */
 2815 /*                                                                          */
 2816 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
 2817 /* to the new IP address for the translation.                               */
 2818 /* ------------------------------------------------------------------------ */
 2819 static int
 2820 ipf_nat_newrdr(fr_info_t *fin, nat_t *nat, natinfo_t *ni)
 2821 {
 2822         ipf_main_softc_t *softc = fin->fin_main_soft;
 2823         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 2824         u_short nport, dport, sport;
 2825         struct in_addr in, inb;
 2826         u_short sp, dp;
 2827         hostmap_t *hm;
 2828         u_32_t flags;
 2829         ipnat_t *np;
 2830         nat_t *natl;
 2831         int move;
 2832 
 2833         move = 1;
 2834         hm = NULL;
 2835         in.s_addr = 0;
 2836         np = ni->nai_np;
 2837         flags = nat->nat_flags;
 2838 
 2839         if (flags & IPN_ICMPQUERY) {
 2840                 dport = fin->fin_data[1];
 2841                 sport = 0;
 2842         } else {
 2843                 sport = htons(fin->fin_data[0]);
 2844                 dport = htons(fin->fin_data[1]);
 2845         }
 2846 
 2847         /* TRACE sport, dport */
 2848 
 2849 
 2850         /*
 2851          * If the matching rule has IPN_STICKY set, then we want to have the
 2852          * same rule kick in as before.  Why would this happen?  If you have
 2853          * a collection of rdr rules with "round-robin sticky", the current
 2854          * packet might match a different one to the previous connection but
 2855          * we want the same destination to be used.
 2856          */
 2857         if (((np->in_flags & (IPN_ROUNDR|IPN_SPLIT)) != 0) &&
 2858             ((np->in_flags & IPN_STICKY) != 0)) {
 2859                 hm = ipf_nat_hostmap(softn, NULL, fin->fin_src, fin->fin_dst,
 2860                                      in, (u_32_t)dport);
 2861                 if (hm != NULL) {
 2862                         in.s_addr = ntohl(hm->hm_ndstip.s_addr);
 2863                         np = hm->hm_ipnat;
 2864                         ni->nai_np = np;
 2865                         move = 0;
 2866                         ipf_nat_hostmapdel(softc, &hm);
 2867                 }
 2868         }
 2869 
 2870         /*
 2871          * Otherwise, it's an inbound packet. Most likely, we don't
 2872          * want to rewrite source ports and source addresses. Instead,
 2873          * we want to rewrite to a fixed internal address and fixed
 2874          * internal port.
 2875          */
 2876         if (np->in_flags & IPN_SPLIT) {
 2877                 in.s_addr = np->in_dnip;
 2878                 inb.s_addr = htonl(in.s_addr);
 2879 
 2880                 if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) {
 2881                         hm = ipf_nat_hostmap(softn, NULL, fin->fin_src,
 2882                                              fin->fin_dst, inb, (u_32_t)dport);
 2883                         if (hm != NULL) {
 2884                                 in.s_addr = hm->hm_ndstip.s_addr;
 2885                                 move = 0;
 2886                         }
 2887                 }
 2888 
 2889                 if (hm == NULL || hm->hm_ref == 1) {
 2890                         if (np->in_ndstaddr == htonl(in.s_addr)) {
 2891                                 np->in_dnip = ntohl(np->in_ndstmsk);
 2892                                 move = 0;
 2893                         } else {
 2894                                 np->in_dnip = ntohl(np->in_ndstaddr);
 2895                         }
 2896                 }
 2897                 if (hm != NULL)
 2898                         ipf_nat_hostmapdel(softc, &hm);
 2899 
 2900         } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) {
 2901                 i6addr_t in6;
 2902 
 2903                 /*
 2904                  * 0/32 - use the interface's IP address.
 2905                  */
 2906                 if (ipf_ifpaddr(softc, 4, FRI_NORMAL, fin->fin_ifp,
 2907                                &in6, NULL) == -1) {
 2908                         NBUMPSIDEX(0, ns_new_ifpaddr, ns_new_ifpaddr_2);
 2909                         DT3(ns_new_ifpaddr_2, fr_info_t *, fin, nat_t *, nat, natinfo_t, ni);
 2910                         return (-1);
 2911                 }
 2912                 in.s_addr = ntohl(in6.in4.s_addr);
 2913 
 2914         } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk== 0)) {
 2915                 /*
 2916                  * 0/0 - use the original destination address/port.
 2917                  */
 2918                 in.s_addr = ntohl(fin->fin_daddr);
 2919 
 2920         } else if (np->in_redir == NAT_BIMAP &&
 2921                    np->in_ndstmsk == np->in_odstmsk) {
 2922                 /*
 2923                  * map the address block in a 1:1 fashion
 2924                  */
 2925                 in.s_addr = np->in_ndstaddr;
 2926                 in.s_addr |= fin->fin_daddr & ~np->in_ndstmsk;
 2927                 in.s_addr = ntohl(in.s_addr);
 2928         } else {
 2929                 in.s_addr = ntohl(np->in_ndstaddr);
 2930         }
 2931 
 2932         if ((np->in_dpnext == 0) || ((flags & NAT_NOTRULEPORT) != 0))
 2933                 nport = dport;
 2934         else {
 2935                 /*
 2936                  * Whilst not optimized for the case where
 2937                  * pmin == pmax, the gain is not significant.
 2938                  */
 2939                 if (((np->in_flags & IPN_FIXEDDPORT) == 0) &&
 2940                     (np->in_odport != np->in_dtop)) {
 2941                         nport = ntohs(dport) - np->in_odport + np->in_dpmax;
 2942                         nport = htons(nport);
 2943                 } else {
 2944                         nport = htons(np->in_dpnext);
 2945                         np->in_dpnext++;
 2946                         if (np->in_dpnext > np->in_dpmax)
 2947                                 np->in_dpnext = np->in_dpmin;
 2948                 }
 2949         }
 2950 
 2951         /*
 2952          * When the redirect-to address is set to 0.0.0.0, just
 2953          * assume a blank `forwarding' of the packet.  We don't
 2954          * setup any translation for this either.
 2955          */
 2956         if (in.s_addr == 0) {
 2957                 if (nport == dport) {
 2958                         NBUMPSIDED(0, ns_xlate_null);
 2959                         return (-1);
 2960                 }
 2961                 in.s_addr = ntohl(fin->fin_daddr);
 2962         }
 2963 
 2964         /*
 2965          * Check to see if this redirect mapping already exists and if
 2966         * it does, return "failure" (allowing it to be created will just
 2967          * cause one or both of these "connections" to stop working.)
 2968          */
 2969         inb.s_addr = htonl(in.s_addr);
 2970         sp = fin->fin_data[0];
 2971         dp = fin->fin_data[1];
 2972         fin->fin_data[1] = fin->fin_data[0];
 2973         fin->fin_data[0] = ntohs(nport);
 2974         natl = ipf_nat_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
 2975                              (u_int)fin->fin_p, inb, fin->fin_src);
 2976         fin->fin_data[0] = sp;
 2977         fin->fin_data[1] = dp;
 2978         if (natl != NULL) {
 2979                 DT2(ns_new_xlate_exists, fr_info_t *, fin, nat_t *, natl);
 2980                 NBUMPSIDE(0, ns_xlate_exists);
 2981                 return (-1);
 2982         }
 2983 
 2984         inb.s_addr = htonl(in.s_addr);
 2985         nat->nat_ndstaddr = htonl(in.s_addr);
 2986         nat->nat_odstip = fin->fin_dst;
 2987         nat->nat_nsrcip = fin->fin_src;
 2988         nat->nat_osrcip = fin->fin_src;
 2989         if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0))
 2990                 nat->nat_hm = ipf_nat_hostmap(softn, np, fin->fin_src,
 2991                                               fin->fin_dst, inb, (u_32_t)dport);
 2992 
 2993         if (flags & IPN_TCPUDP) {
 2994                 nat->nat_odport = dport;
 2995                 nat->nat_ndport = nport;
 2996                 nat->nat_osport = sport;
 2997                 nat->nat_nsport = sport;
 2998                 ((tcphdr_t *)fin->fin_dp)->th_dport = nport;
 2999         } else if (flags & IPN_ICMPQUERY) {
 3000                 nat->nat_oicmpid = fin->fin_data[1];
 3001                 ((icmphdr_t *)fin->fin_dp)->icmp_id = nport;
 3002                 nat->nat_nicmpid = nport;
 3003         }
 3004 
 3005         return (move);
 3006 }
 3007 
 3008 /* ------------------------------------------------------------------------ */
 3009 /* Function:    ipf_nat_add                                                 */
 3010 /* Returns:     nat_t* - NULL == failure to create new NAT structure,       */
 3011 /*                       else pointer to new NAT structure                  */
 3012 /* Parameters:  fin(I)       - pointer to packet information                */
 3013 /*              np(I)        - pointer to NAT rule                          */
 3014 /*              natsave(I)   - pointer to where to store NAT struct pointer */
 3015 /*              flags(I)     - flags describing the current packet          */
 3016 /*              direction(I) - direction of packet (in/out)                 */
 3017 /* Write Lock:  ipf_nat                                                     */
 3018 /*                                                                          */
 3019 /* Attempts to create a new NAT entry.  Does not actually change the packet */
 3020 /* in any way.                                                              */
 3021 /*                                                                          */
 3022 /* This function is in three main parts: (1) deal with creating a new NAT   */
 3023 /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with     */
 3024 /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */
 3025 /* and (3) building that structure and putting it into the NAT table(s).    */
 3026 /*                                                                          */
 3027 /* NOTE: natsave should NOT be used to point back to an ipstate_t struct    */
 3028 /*       as it can result in memory being corrupted.                        */
 3029 /* ------------------------------------------------------------------------ */
 3030 nat_t *
 3031 ipf_nat_add(fr_info_t *fin, ipnat_t *np, nat_t **natsave, u_int flags,
 3032         int direction)
 3033 {
 3034         ipf_main_softc_t *softc = fin->fin_main_soft;
 3035         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 3036         hostmap_t *hm = NULL;
 3037         nat_t *nat, *natl;
 3038         natstat_t *nsp;
 3039         u_int nflags;
 3040         natinfo_t ni;
 3041         int move;
 3042 
 3043         nsp = &softn->ipf_nat_stats;
 3044 
 3045         if ((nsp->ns_active * 100 / softn->ipf_nat_table_max) >
 3046             softn->ipf_nat_table_wm_high) {
 3047                 softn->ipf_nat_doflush = 1;
 3048         }
 3049 
 3050         if (nsp->ns_active >= softn->ipf_nat_table_max) {
 3051                 NBUMPSIDED(fin->fin_out, ns_table_max);
 3052                 DT2(ns_table_max, nat_stat_t *, nsp, ipf_nat_softc_t *, softn);
 3053                 return (NULL);
 3054         }
 3055 
 3056         move = 1;
 3057         nflags = np->in_flags & flags;
 3058         nflags &= NAT_FROMRULE;
 3059 
 3060         ni.nai_np = np;
 3061         ni.nai_dport = 0;
 3062         ni.nai_sport = 0;
 3063 
 3064         /* Give me a new nat */
 3065         KMALLOC(nat, nat_t *);
 3066         if (nat == NULL) {
 3067                 DT(ns_memfail);
 3068                 NBUMPSIDED(fin->fin_out, ns_memfail);
 3069                 /*
 3070                  * Try to automatically tune the max # of entries in the
 3071                  * table allowed to be less than what will cause kmem_alloc()
 3072                  * to fail and try to eliminate panics due to out of memory
 3073                  * conditions arising.
 3074                  */
 3075                 if ((softn->ipf_nat_table_max > softn->ipf_nat_table_sz) &&
 3076                     (nsp->ns_active > 100)) {
 3077                         softn->ipf_nat_table_max = nsp->ns_active - 100;
 3078                         printf("table_max reduced to %d\n",
 3079                                 softn->ipf_nat_table_max);
 3080                 }
 3081                 return (NULL);
 3082         }
 3083 
 3084         if (flags & IPN_ICMPQUERY) {
 3085                 /*
 3086                  * In the ICMP query NAT code, we translate the ICMP id fields
 3087                  * to make them unique. This is indepedent of the ICMP type
 3088                  * (e.g. in the unlikely event that a host sends an echo and
 3089                  * an tstamp request with the same id, both packets will have
 3090                  * their ip address/id field changed in the same way).
 3091                  */
 3092                 /* The icmp_id field is used by the sender to identify the
 3093                  * process making the icmp request. (the receiver justs
 3094                  * copies it back in its response). So, it closely matches
 3095                  * the concept of source port. We overlay sport, so we can
 3096                  * maximally reuse the existing code.
 3097                  */
 3098                 ni.nai_sport = fin->fin_data[1];
 3099                 ni.nai_dport = 0;
 3100         }
 3101 
 3102         bzero((char *)nat, sizeof(*nat));
 3103         nat->nat_flags = flags;
 3104         nat->nat_redir = np->in_redir;
 3105         nat->nat_dir = direction;
 3106         nat->nat_pr[0] = fin->fin_p;
 3107         nat->nat_pr[1] = fin->fin_p;
 3108 
 3109         /*
 3110          * Search the current table for a match and create a new mapping
 3111          * if there is none found.
 3112          */
 3113         if (np->in_redir & NAT_DIVERTUDP) {
 3114                 move = ipf_nat_newdivert(fin, nat, &ni);
 3115 
 3116         } else if (np->in_redir & NAT_REWRITE) {
 3117                 move = ipf_nat_newrewrite(fin, nat, &ni);
 3118 
 3119         } else if (direction == NAT_OUTBOUND) {
 3120                 /*
 3121                  * We can now arrange to call this for the same connection
 3122                  * because ipf_nat_new doesn't protect the code path into
 3123                  * this function.
 3124                  */
 3125                 natl = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p,
 3126                                      fin->fin_src, fin->fin_dst);
 3127                 if (natl != NULL) {
 3128                         KFREE(nat);
 3129                         nat = natl;
 3130                         goto done;
 3131                 }
 3132 
 3133                 move = ipf_nat_newmap(fin, nat, &ni);
 3134         } else {
 3135                 /*
 3136                  * NAT_INBOUND is used for redirects rules
 3137                  */
 3138                 natl = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p,
 3139                                         fin->fin_src, fin->fin_dst);
 3140                 if (natl != NULL) {
 3141                         KFREE(nat);
 3142                         nat = natl;
 3143                         goto done;
 3144                 }
 3145 
 3146                 move = ipf_nat_newrdr(fin, nat, &ni);
 3147         }
 3148         if (move == -1)
 3149                 goto badnat;
 3150 
 3151         np = ni.nai_np;
 3152 
 3153         nat->nat_mssclamp = np->in_mssclamp;
 3154         nat->nat_me = natsave;
 3155         nat->nat_fr = fin->fin_fr;
 3156         nat->nat_rev = fin->fin_rev;
 3157         nat->nat_ptr = np;
 3158         nat->nat_dlocal = np->in_dlocal;
 3159 
 3160         if ((np->in_apr != NULL) && ((nat->nat_flags & NAT_SLAVE) == 0)) {
 3161                 if (ipf_proxy_new(fin, nat) == -1) {
 3162                         NBUMPSIDED(fin->fin_out, ns_appr_fail);
 3163                         DT3(ns_appr_fail, fr_info_t *, fin, nat_t *, nat, ipnat_t *, np);
 3164                         goto badnat;
 3165                 }
 3166         }
 3167 
 3168         nat->nat_ifps[0] = np->in_ifps[0];
 3169         if (np->in_ifps[0] != NULL) {
 3170                 COPYIFNAME(np->in_v[0], np->in_ifps[0], nat->nat_ifnames[0]);
 3171         }
 3172 
 3173         nat->nat_ifps[1] = np->in_ifps[1];
 3174         if (np->in_ifps[1] != NULL) {
 3175                 COPYIFNAME(np->in_v[1], np->in_ifps[1], nat->nat_ifnames[1]);
 3176         }
 3177 
 3178         if (ipf_nat_finalise(fin, nat) == -1) {
 3179                 goto badnat;
 3180         }
 3181 
 3182         np->in_use++;
 3183 
 3184         if ((move == 1) && (np->in_flags & IPN_ROUNDR)) {
 3185                 if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_REDIRECT) {
 3186                         ipf_nat_delrdr(softn, np);
 3187                         ipf_nat_addrdr(softn, np);
 3188                 } else if ((np->in_redir & (NAT_REDIRECT|NAT_MAP)) == NAT_MAP) {
 3189                         ipf_nat_delmap(softn, np);
 3190                         ipf_nat_addmap(softn, np);
 3191                 }
 3192         }
 3193 
 3194         if (flags & SI_WILDP)
 3195                 nsp->ns_wilds++;
 3196         nsp->ns_proto[nat->nat_pr[0]]++;
 3197 
 3198         goto done;
 3199 badnat:
 3200         DT3(ns_badnatnew, fr_info_t *, fin, nat_t *, nat, ipnat_t *, np);
 3201         NBUMPSIDE(fin->fin_out, ns_badnatnew);
 3202         if ((hm = nat->nat_hm) != NULL)
 3203                 ipf_nat_hostmapdel(softc, &hm);
 3204         KFREE(nat);
 3205         nat = NULL;
 3206 done:
 3207         if (nat != NULL && np != NULL)
 3208                 np->in_hits++;
 3209         if (natsave != NULL)
 3210                 *natsave = nat;
 3211         return (nat);
 3212 }
 3213 
 3214 
 3215 /* ------------------------------------------------------------------------ */
 3216 /* Function:    ipf_nat_finalise                                            */
 3217 /* Returns:     int - 0 == sucess, -1 == failure                            */
 3218 /* Parameters:  fin(I) - pointer to packet information                      */
 3219 /*              nat(I) - pointer to NAT entry                               */
 3220 /* Write Lock:  ipf_nat                                                     */
 3221 /*                                                                          */
 3222 /* This is the tail end of constructing a new NAT entry and is the same     */
 3223 /* for both IPv4 and IPv6.                                                  */
 3224 /* ------------------------------------------------------------------------ */
 3225 /*ARGSUSED*/
 3226 static int
 3227 ipf_nat_finalise(fr_info_t *fin, nat_t *nat)
 3228 {
 3229         ipf_main_softc_t *softc = fin->fin_main_soft;
 3230         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 3231         u_32_t sum1, sum2, sumd;
 3232         frentry_t *fr;
 3233         u_32_t flags;
 3234 #if SOLARIS && defined(_KERNEL) && defined(ICK_M_CTL_MAGIC)
 3235         qpktinfo_t *qpi = fin->fin_qpi;
 3236 #endif
 3237 
 3238         flags = nat->nat_flags;
 3239 
 3240         switch (nat->nat_pr[0])
 3241         {
 3242         case IPPROTO_ICMP :
 3243                 sum1 = LONG_SUM(ntohs(nat->nat_oicmpid));
 3244                 sum2 = LONG_SUM(ntohs(nat->nat_nicmpid));
 3245                 CALC_SUMD(sum1, sum2, sumd);
 3246                 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
 3247 
 3248                 break;
 3249 
 3250         default :
 3251                 sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr) + \
 3252                                 ntohs(nat->nat_osport));
 3253                 sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr) + \
 3254                                 ntohs(nat->nat_nsport));
 3255                 CALC_SUMD(sum1, sum2, sumd);
 3256                 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
 3257 
 3258                 sum1 = LONG_SUM(ntohl(nat->nat_odstaddr) + \
 3259                                 ntohs(nat->nat_odport));
 3260                 sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr) + \
 3261                                 ntohs(nat->nat_ndport));
 3262                 CALC_SUMD(sum1, sum2, sumd);
 3263                 nat->nat_sumd[0] += (sumd & 0xffff) + (sumd >> 16);
 3264                 break;
 3265         }
 3266 
 3267         /*
 3268          * Compute the partial checksum, just in case.
 3269          * This is only ever placed into outbound packets so care needs
 3270          * to be taken over which pair of addresses are used.
 3271          */
 3272         if (nat->nat_dir == NAT_OUTBOUND) {
 3273                 sum1 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
 3274                 sum1 += LONG_SUM(ntohl(nat->nat_ndstaddr));
 3275         } else {
 3276                 sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr));
 3277                 sum1 += LONG_SUM(ntohl(nat->nat_odstaddr));
 3278         }
 3279         sum1 += nat->nat_pr[1];
 3280         nat->nat_sumd[1] = (sum1 & 0xffff) + (sum1 >> 16);
 3281 
 3282         sum1 = LONG_SUM(ntohl(nat->nat_osrcaddr));
 3283         sum2 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
 3284         CALC_SUMD(sum1, sum2, sumd);
 3285         nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
 3286 
 3287         sum1 = LONG_SUM(ntohl(nat->nat_odstaddr));
 3288         sum2 = LONG_SUM(ntohl(nat->nat_ndstaddr));
 3289         CALC_SUMD(sum1, sum2, sumd);
 3290         nat->nat_ipsumd += (sumd & 0xffff) + (sumd >> 16);
 3291 
 3292         nat->nat_v[0] = 4;
 3293         nat->nat_v[1] = 4;
 3294 
 3295         if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
 3296                 nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
 3297         }
 3298 
 3299         if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
 3300                 nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
 3301         }
 3302 
 3303         if ((nat->nat_flags & SI_CLONE) == 0)
 3304                 nat->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, nat);
 3305 
 3306         if (ipf_nat_insert(softc, softn, nat) == 0) {
 3307                 if (softn->ipf_nat_logging)
 3308                         ipf_nat_log(softc, softn, nat, NL_NEW);
 3309                 fr = nat->nat_fr;
 3310                 if (fr != NULL) {
 3311                         MUTEX_ENTER(&fr->fr_lock);
 3312                         fr->fr_ref++;
 3313                         MUTEX_EXIT(&fr->fr_lock);
 3314                 }
 3315                 return (0);
 3316         }
 3317 
 3318         NBUMPSIDED(fin->fin_out, ns_unfinalised);
 3319         DT2(ns_unfinalised, fr_info_t *, fin, nat_t *, nat);
 3320         /*
 3321          * nat_insert failed, so cleanup time...
 3322          */
 3323         if (nat->nat_sync != NULL)
 3324                 ipf_sync_del_nat(softc->ipf_sync_soft, nat->nat_sync);
 3325         return (-1);
 3326 }
 3327 
 3328 
 3329 /* ------------------------------------------------------------------------ */
 3330 /* Function:    ipf_nat_insert                                              */
 3331 /* Returns:     int - 0 == sucess, -1 == failure                            */
 3332 /* Parameters:  softc(I) - pointer to soft context main structure           */
 3333 /*              softn(I) - pointer to NAT context structure                 */
 3334 /*              nat(I) - pointer to NAT structure                           */
 3335 /* Write Lock:  ipf_nat                                                     */
 3336 /*                                                                          */
 3337 /* Insert a NAT entry into the hash tables for searching and add it to the  */
 3338 /* list of active NAT entries.  Adjust global counters when complete.       */
 3339 /* ------------------------------------------------------------------------ */
 3340 int
 3341 ipf_nat_insert(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, nat_t *nat)
 3342 {
 3343         u_int hv0, hv1;
 3344         u_int sp, dp;
 3345         ipnat_t *in;
 3346         int ret;
 3347 
 3348         /*
 3349         * Try and return an error as early as possible, so calculate the hash
 3350          * entry numbers first and then proceed.
 3351          */
 3352         if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) {
 3353                 if ((nat->nat_flags & IPN_TCPUDP) != 0) {
 3354                         sp = nat->nat_osport;
 3355                         dp = nat->nat_odport;
 3356                 } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
 3357                         sp = 0;
 3358                         dp = nat->nat_oicmpid;
 3359                 } else {
 3360                         sp = 0;
 3361                         dp = 0;
 3362                 }
 3363                 hv0 = NAT_HASH_FN(nat->nat_osrcaddr, sp, 0xffffffff);
 3364                 hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0 + dp, 0xffffffff);
 3365                 /*
 3366                  * TRACE nat_osrcaddr, nat_osport, nat_odstaddr,
 3367                  * nat_odport, hv0
 3368                  */
 3369 
 3370                 if ((nat->nat_flags & IPN_TCPUDP) != 0) {
 3371                         sp = nat->nat_nsport;
 3372                         dp = nat->nat_ndport;
 3373                 } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
 3374                         sp = 0;
 3375                         dp = nat->nat_nicmpid;
 3376                 } else {
 3377                         sp = 0;
 3378                         dp = 0;
 3379                 }
 3380                 hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, sp, 0xffffffff);
 3381                 hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1 + dp, 0xffffffff);
 3382                 /*
 3383                  * TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr,
 3384                  * nat_ndport, hv1
 3385                  */
 3386         } else {
 3387                 hv0 = NAT_HASH_FN(nat->nat_osrcaddr, 0, 0xffffffff);
 3388                 hv0 = NAT_HASH_FN(nat->nat_odstaddr, hv0, 0xffffffff);
 3389                 /* TRACE nat_osrcaddr, nat_odstaddr, hv0 */
 3390 
 3391                 hv1 = NAT_HASH_FN(nat->nat_nsrcaddr, 0, 0xffffffff);
 3392                 hv1 = NAT_HASH_FN(nat->nat_ndstaddr, hv1, 0xffffffff);
 3393                 /* TRACE nat_nsrcaddr, nat_ndstaddr, hv1 */
 3394         }
 3395 
 3396         nat->nat_hv[0] = hv0;
 3397         nat->nat_hv[1] = hv1;
 3398 
 3399         MUTEX_INIT(&nat->nat_lock, "nat entry lock");
 3400 
 3401         in = nat->nat_ptr;
 3402         nat->nat_ref = nat->nat_me ? 2 : 1;
 3403 
 3404         nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0';
 3405         nat->nat_ifps[0] = ipf_resolvenic(softc, nat->nat_ifnames[0], 4);
 3406 
 3407         if (nat->nat_ifnames[1][0] != '\0') {
 3408                 nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
 3409                 nat->nat_ifps[1] = ipf_resolvenic(softc,
 3410                                                   nat->nat_ifnames[1], 4);
 3411         } else if (in->in_ifnames[1] != -1) {
 3412                 char *name;
 3413 
 3414                 name = in->in_names + in->in_ifnames[1];
 3415                 if (name[1] != '\0' && name[0] != '-' && name[0] != '*') {
 3416                         (void) strncpy(nat->nat_ifnames[1],
 3417                                        nat->nat_ifnames[0], LIFNAMSIZ);
 3418                         nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
 3419                         nat->nat_ifps[1] = nat->nat_ifps[0];
 3420                 }
 3421         }
 3422         if ((nat->nat_ifps[0] != NULL) && (nat->nat_ifps[0] != (void *)-1)) {
 3423                 nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
 3424         }
 3425         if ((nat->nat_ifps[1] != NULL) && (nat->nat_ifps[1] != (void *)-1)) {
 3426                 nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
 3427         }
 3428 
 3429         ret = ipf_nat_hashtab_add(softc, softn, nat);
 3430         if (ret == -1)
 3431                 MUTEX_DESTROY(&nat->nat_lock);
 3432         return (ret);
 3433 }
 3434 
 3435 
 3436 /* ------------------------------------------------------------------------ */
 3437 /* Function:    ipf_nat_hashtab_add                                         */
 3438 /* Returns:     int - 0 == sucess, -1 == failure                            */
 3439 /* Parameters:  softc(I) - pointer to soft context main structure           */
 3440 /*              softn(I) - pointer to NAT context structure                 */
 3441 /*              nat(I) - pointer to NAT structure                           */
 3442 /*                                                                          */
 3443 /* Handle the insertion of a NAT entry into the table/list.                 */
 3444 /* ------------------------------------------------------------------------ */
 3445 int
 3446 ipf_nat_hashtab_add(ipf_main_softc_t *softc, ipf_nat_softc_t *softn,
 3447         nat_t *nat)
 3448 {
 3449         nat_t **natp;
 3450         u_int hv0;
 3451         u_int hv1;
 3452 
 3453         if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) {
 3454                 hv1 = nat->nat_hv[0] % softn->ipf_nat_table_sz;
 3455                 hv0 = nat->nat_hv[1] % softn->ipf_nat_table_sz;
 3456         } else {
 3457                 hv0 = nat->nat_hv[0] % softn->ipf_nat_table_sz;
 3458                 hv1 = nat->nat_hv[1] % softn->ipf_nat_table_sz;
 3459         }
 3460 
 3461         if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0] >=
 3462             softn->ipf_nat_maxbucket) {
 3463                 DT1(ns_bucket_max_0, int,
 3464                     softn->ipf_nat_stats.ns_side[0].ns_bucketlen[hv0]);
 3465                 NBUMPSIDE(0, ns_bucket_max);
 3466                 return (-1);
 3467         }
 3468 
 3469         if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1] >=
 3470             softn->ipf_nat_maxbucket) {
 3471                 DT1(ns_bucket_max_1, int,
 3472                     softn->ipf_nat_stats.ns_side[1].ns_bucketlen[hv1]);
 3473                 NBUMPSIDE(1, ns_bucket_max);
 3474                 return (-1);
 3475         }
 3476 
 3477         /*
 3478          * The ordering of operations in the list and hash table insertion
 3479          * is very important.  The last operation for each task should be
 3480          * to update the top of the list, after all the "nexts" have been
 3481          * done so that walking the list while it is being done does not
 3482          * find strange pointers.
 3483          *
 3484          * Global list of NAT instances
 3485          */
 3486         nat->nat_next = softn->ipf_nat_instances;
 3487         nat->nat_pnext = &softn->ipf_nat_instances;
 3488         if (softn->ipf_nat_instances)
 3489                 softn->ipf_nat_instances->nat_pnext = &nat->nat_next;
 3490         softn->ipf_nat_instances = nat;
 3491 
 3492         /*
 3493          * Inbound hash table.
 3494          */
 3495         natp = &softn->ipf_nat_table[0][hv0];
 3496         nat->nat_phnext[0] = natp;
 3497         nat->nat_hnext[0] = *natp;
 3498         if (*natp) {
 3499                 (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
 3500         } else {
 3501                 NBUMPSIDE(0, ns_inuse);
 3502         }
 3503         *natp = nat;
 3504         NBUMPSIDE(0, ns_bucketlen[hv0]);
 3505 
 3506         /*
 3507          * Outbound hash table.
 3508          */
 3509         natp = &softn->ipf_nat_table[1][hv1];
 3510         nat->nat_phnext[1] = natp;
 3511         nat->nat_hnext[1] = *natp;
 3512         if (*natp)
 3513                 (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
 3514         else {
 3515                 NBUMPSIDE(1, ns_inuse);
 3516         }
 3517         *natp = nat;
 3518         NBUMPSIDE(1, ns_bucketlen[hv1]);
 3519 
 3520         ipf_nat_setqueue(softc, softn, nat);
 3521 
 3522         if (nat->nat_dir & NAT_OUTBOUND) {
 3523                 NBUMPSIDE(1, ns_added);
 3524         } else {
 3525                 NBUMPSIDE(0, ns_added);
 3526         }
 3527         softn->ipf_nat_stats.ns_active++;
 3528         return (0);
 3529 }
 3530 
 3531 
 3532 /* ------------------------------------------------------------------------ */
 3533 /* Function:    ipf_nat_icmperrorlookup                                     */
 3534 /* Returns:     nat_t* - point to matching NAT structure                    */
 3535 /* Parameters:  fin(I) - pointer to packet information                      */
 3536 /*              dir(I) - direction of packet (in/out)                       */
 3537 /*                                                                          */
 3538 /* Check if the ICMP error message is related to an existing TCP, UDP or    */
 3539 /* ICMP query nat entry.  It is assumed that the packet is already of the   */
 3540 /* the required length.                                                     */
 3541 /* ------------------------------------------------------------------------ */
 3542 nat_t *
 3543 ipf_nat_icmperrorlookup(fr_info_t *fin, int dir)
 3544 {
 3545         ipf_main_softc_t *softc = fin->fin_main_soft;
 3546         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 3547         int flags = 0, type, minlen;
 3548         icmphdr_t *icmp, *orgicmp;
 3549         nat_stat_side_t *nside;
 3550         tcphdr_t *tcp = NULL;
 3551         u_short data[2];
 3552         nat_t *nat;
 3553         ip_t *oip;
 3554         u_int p;
 3555 
 3556         icmp = fin->fin_dp;
 3557         type = icmp->icmp_type;
 3558         nside = &softn->ipf_nat_stats.ns_side[fin->fin_out];
 3559         /*
 3560          * Does it at least have the return (basic) IP header ?
 3561          * Only a basic IP header (no options) should be with an ICMP error
 3562          * header.  Also, if it's not an error type, then return.
 3563          */
 3564         if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR)) {
 3565                 ATOMIC_INCL(nside->ns_icmp_basic);
 3566                 return (NULL);
 3567         }
 3568 
 3569         /*
 3570          * Check packet size
 3571          */
 3572         oip = (ip_t *)((char *)fin->fin_dp + 8);
 3573         minlen = IP_HL(oip) << 2;
 3574         if ((minlen < sizeof(ip_t)) ||
 3575             (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)) {
 3576                 ATOMIC_INCL(nside->ns_icmp_size);
 3577                 return (NULL);
 3578         }
 3579 
 3580         /*
 3581          * Is the buffer big enough for all of it ?  It's the size of the IP
 3582          * header claimed in the encapsulated part which is of concern.  It
 3583          * may be too big to be in this buffer but not so big that it's
 3584          * outside the ICMP packet, leading to TCP deref's causing problems.
 3585          * This is possible because we don't know how big oip_hl is when we
 3586          * do the pullup early in ipf_check() and thus can't gaurantee it is
 3587          * all here now.
 3588          */
 3589 #ifdef  ipf_nat_KERNEL
 3590         {
 3591         mb_t *m;
 3592 
 3593         m = fin->fin_m;
 3594 # if SOLARIS
 3595         if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
 3596             (char *)m->b_wptr) {
 3597                 ATOMIC_INCL(nside->ns_icmp_mbuf);
 3598                 return (NULL);
 3599         }
 3600 # else
 3601         if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
 3602             (char *)fin->fin_ip + M_LEN(m)) {
 3603                 ATOMIC_INCL(nside->ns_icmp_mbuf);
 3604                 return (NULL);
 3605         }
 3606 # endif
 3607         }
 3608 #endif
 3609 
 3610         if (fin->fin_daddr != oip->ip_src.s_addr) {
 3611                 ATOMIC_INCL(nside->ns_icmp_address);
 3612                 return (NULL);
 3613         }
 3614 
 3615         p = oip->ip_p;
 3616         if (p == IPPROTO_TCP)
 3617                 flags = IPN_TCP;
 3618         else if (p == IPPROTO_UDP)
 3619                 flags = IPN_UDP;
 3620         else if (p == IPPROTO_ICMP) {
 3621                 orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2));
 3622 
 3623                 /* see if this is related to an ICMP query */
 3624                 if (ipf_nat_icmpquerytype(orgicmp->icmp_type)) {
 3625                         data[0] = fin->fin_data[0];
 3626                         data[1] = fin->fin_data[1];
 3627                         fin->fin_data[0] = 0;
 3628                         fin->fin_data[1] = orgicmp->icmp_id;
 3629 
 3630                         flags = IPN_ICMPERR|IPN_ICMPQUERY;
 3631                         /*
 3632                          * NOTE : dir refers to the direction of the original
 3633                          *        ip packet. By definition the icmp error
 3634                          *        message flows in the opposite direction.
 3635                          */
 3636                         if (dir == NAT_INBOUND)
 3637                                 nat = ipf_nat_inlookup(fin, flags, p,
 3638                                                        oip->ip_dst,
 3639                                                        oip->ip_src);
 3640                         else
 3641                                 nat = ipf_nat_outlookup(fin, flags, p,
 3642                                                         oip->ip_dst,
 3643                                                         oip->ip_src);
 3644                         fin->fin_data[0] = data[0];
 3645                         fin->fin_data[1] = data[1];
 3646                         return (nat);
 3647                 }
 3648         }
 3649 
 3650         if (flags & IPN_TCPUDP) {
 3651                 minlen += 8;            /* + 64bits of data to get ports */
 3652                 /* TRACE (fin,minlen) */
 3653                 if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen) {
 3654                         ATOMIC_INCL(nside->ns_icmp_short);
 3655                         return (NULL);
 3656                 }
 3657 
 3658                 data[0] = fin->fin_data[0];
 3659                 data[1] = fin->fin_data[1];
 3660                 tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2));
 3661                 fin->fin_data[0] = ntohs(tcp->th_dport);
 3662                 fin->fin_data[1] = ntohs(tcp->th_sport);
 3663 
 3664                 if (dir == NAT_INBOUND) {
 3665                         nat = ipf_nat_inlookup(fin, flags, p, oip->ip_dst,
 3666                                                oip->ip_src);
 3667                 } else {
 3668                         nat = ipf_nat_outlookup(fin, flags, p, oip->ip_dst,
 3669                                             oip->ip_src);
 3670                 }
 3671                 fin->fin_data[0] = data[0];
 3672                 fin->fin_data[1] = data[1];
 3673                 return (nat);
 3674         }
 3675         if (dir == NAT_INBOUND)
 3676                 nat = ipf_nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
 3677         else
 3678                 nat = ipf_nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
 3679 
 3680         return (nat);
 3681 }
 3682 
 3683 
 3684 /* ------------------------------------------------------------------------ */
 3685 /* Function:    ipf_nat_icmperror                                           */
 3686 /* Returns:     nat_t* - point to matching NAT structure                    */
 3687 /* Parameters:  fin(I)    - pointer to packet information                   */
 3688 /*              nflags(I) - NAT flags for this packet                       */
 3689 /*              dir(I)    - direction of packet (in/out)                    */
 3690 /*                                                                          */
 3691 /* Fix up an ICMP packet which is an error message for an existing NAT      */
 3692 /* session.  This will correct both packet header data and checksums.       */
 3693 /*                                                                          */
 3694 /* This should *ONLY* be used for incoming ICMP error packets to make sure  */
 3695 /* a NAT'd ICMP packet gets correctly recognised.                           */
 3696 /* ------------------------------------------------------------------------ */
 3697 nat_t *
 3698 ipf_nat_icmperror(fr_info_t *fin, u_int *nflags, int dir)
 3699 {
 3700         ipf_main_softc_t *softc = fin->fin_main_soft;
 3701         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 3702         u_32_t sum1, sum2, sumd, sumd2;
 3703         struct in_addr a1, a2, a3, a4;
 3704         int flags, dlen, odst;
 3705         icmphdr_t *icmp;
 3706         u_short *csump;
 3707         tcphdr_t *tcp;
 3708         nat_t *nat;
 3709         ip_t *oip;
 3710         void *dp;
 3711 
 3712         if ((fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
 3713                 NBUMPSIDED(fin->fin_out, ns_icmp_short);
 3714                 return (NULL);
 3715         }
 3716 
 3717         /*
 3718         * ipf_nat_icmperrorlookup() will return NULL for `defective' packets.
 3719          */
 3720         if ((fin->fin_v != 4) || !(nat = ipf_nat_icmperrorlookup(fin, dir))) {
 3721                 NBUMPSIDED(fin->fin_out, ns_icmp_notfound);
 3722                 return (NULL);
 3723         }
 3724 
 3725         tcp = NULL;
 3726         csump = NULL;
 3727         flags = 0;
 3728         sumd2 = 0;
 3729         *nflags = IPN_ICMPERR;
 3730         icmp = fin->fin_dp;
 3731         oip = (ip_t *)&icmp->icmp_ip;
 3732         dp = (((char *)oip) + (IP_HL(oip) << 2));
 3733         if (oip->ip_p == IPPROTO_TCP) {
 3734                 tcp = (tcphdr_t *)dp;
 3735                 csump = (u_short *)&tcp->th_sum;
 3736                 flags = IPN_TCP;
 3737         } else if (oip->ip_p == IPPROTO_UDP) {
 3738                 udphdr_t *udp;
 3739 
 3740                 udp = (udphdr_t *)dp;
 3741                 tcp = (tcphdr_t *)dp;
 3742                 csump = (u_short *)&udp->uh_sum;
 3743                 flags = IPN_UDP;
 3744         } else if (oip->ip_p == IPPROTO_ICMP)
 3745                 flags = IPN_ICMPQUERY;
 3746         dlen = fin->fin_plen - ((char *)dp - (char *)fin->fin_ip);
 3747 
 3748         /*
 3749          * Need to adjust ICMP header to include the real IP#'s and
 3750          * port #'s.  Only apply a checksum change relative to the
 3751          * IP address change as it will be modified again in ipf_nat_checkout
 3752          * for both address and port.  Two checksum changes are
 3753          * necessary for the two header address changes.  Be careful
 3754          * to only modify the checksum once for the port # and twice
 3755          * for the IP#.
 3756          */
 3757 
 3758         /*
 3759          * Step 1
 3760          * Fix the IP addresses in the offending IP packet. You also need
 3761          * to adjust the IP header checksum of that offending IP packet.
 3762          *
 3763          * Normally, you would expect that the ICMP checksum of the
 3764          * ICMP error message needs to be adjusted as well for the
 3765          * IP address change in oip.
 3766          * However, this is a NOP, because the ICMP checksum is
 3767          * calculated over the complete ICMP packet, which includes the
 3768          * changed oip IP addresses and oip->ip_sum. However, these
 3769          * two changes cancel each other out (if the delta for
 3770          * the IP address is x, then the delta for ip_sum is minus x),
 3771          * so no change in the icmp_cksum is necessary.
 3772          *
 3773          * Inbound ICMP
 3774          * ------------
 3775          * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
 3776          * - response to outgoing packet (a,b)=>(c,b) (OIP_SRC=c,OIP_DST=b)
 3777          * - OIP_SRC(c)=nat_newsrcip,          OIP_DST(b)=nat_newdstip
 3778          *=> OIP_SRC(c)=nat_oldsrcip,          OIP_DST(b)=nat_olddstip
 3779          *
 3780          * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
 3781          * - response to outgoing packet (c,a)=>(b,a) (OIP_SRC=b,OIP_DST=a)
 3782          * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
 3783          *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
 3784          *
 3785          * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
 3786          * - response to outgoing packet (a,b)=>(c,d) (OIP_SRC=c,OIP_DST=d)
 3787          * - OIP_SRC(c)=nat_newsrcip,          OIP_DST(d)=nat_newdstip
 3788          *=> OIP_SRC(c)=nat_oldsrcip,          OIP_DST(d)=nat_olddstip
 3789          *
 3790          * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
 3791          * - response to outgoing packet (d,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
 3792          * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
 3793          *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
 3794          *
 3795          * Outbound ICMP
 3796          * -------------
 3797          * MAP rule, SRC=a,DST=b -> SRC=c,DST=b
 3798          * - response to incoming packet (b,c)=>(b,a) (OIP_SRC=b,OIP_DST=a)
 3799          * - OIP_SRC(b)=nat_olddstip,          OIP_DST(a)=nat_oldsrcip
 3800          *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
 3801          *
 3802          * RDR rule, SRC=a,DST=b -> SRC=a,DST=c
 3803          * - response to incoming packet (a,b)=>(a,c) (OIP_SRC=a,OIP_DST=c)
 3804          * - OIP_SRC(a)=nat_newsrcip,          OIP_DST(c)=nat_newdstip
 3805          *=> OIP_SRC(a)=nat_oldsrcip,          OIP_DST(c)=nat_olddstip
 3806          *
 3807          * REWRITE out rule, SRC=a,DST=b -> SRC=c,DST=d
 3808          * - response to incoming packet (d,c)=>(b,a) (OIP_SRC=c,OIP_DST=d)
 3809          * - OIP_SRC(c)=nat_olddstip,          OIP_DST(d)=nat_oldsrcip
 3810          *=> OIP_SRC(b)=nat_newdstip,          OIP_DST(a)=nat_newsrcip
 3811          *
 3812          * REWRITE in rule, SRC=a,DST=b -> SRC=c,DST=d
 3813          * - response to incoming packet (a,b)=>(c,d) (OIP_SRC=b,OIP_DST=a)
 3814          * - OIP_SRC(b)=nat_newsrcip,          OIP_DST(a)=nat_newdstip
 3815          *=> OIP_SRC(a)=nat_oldsrcip,          OIP_DST(c)=nat_olddstip
 3816          */
 3817 
 3818         if (((fin->fin_out == 0) && ((nat->nat_redir & NAT_MAP) != 0)) ||
 3819             ((fin->fin_out == 1) && ((nat->nat_redir & NAT_REDIRECT) != 0))) {
 3820                 a1.s_addr = ntohl(nat->nat_osrcaddr);
 3821                 a4.s_addr = ntohl(oip->ip_src.s_addr);
 3822                 a3.s_addr = ntohl(nat->nat_odstaddr);
 3823                 a2.s_addr = ntohl(oip->ip_dst.s_addr);
 3824                 oip->ip_src.s_addr = htonl(a1.s_addr);
 3825                 oip->ip_dst.s_addr = htonl(a3.s_addr);
 3826                 odst = 1;
 3827         } else {
 3828                 a1.s_addr = ntohl(nat->nat_ndstaddr);
 3829                 a2.s_addr = ntohl(oip->ip_dst.s_addr);
 3830                 a3.s_addr = ntohl(nat->nat_nsrcaddr);
 3831                 a4.s_addr = ntohl(oip->ip_src.s_addr);
 3832                 oip->ip_dst.s_addr = htonl(a3.s_addr);
 3833                 oip->ip_src.s_addr = htonl(a1.s_addr);
 3834                 odst = 0;
 3835         }
 3836         sum1 = 0;
 3837         sum2 = 0;
 3838         sumd = 0;
 3839         CALC_SUMD(a2.s_addr, a3.s_addr, sum1);
 3840         CALC_SUMD(a4.s_addr, a1.s_addr, sum2);
 3841         sumd = sum2 + sum1;
 3842         if (sumd != 0)
 3843                 ipf_fix_datacksum(&oip->ip_sum, sumd);
 3844 
 3845         sumd2 = sumd;
 3846         sum1 = 0;
 3847         sum2 = 0;
 3848 
 3849         /*
 3850          * Fix UDP pseudo header checksum to compensate for the
 3851          * IP address change.
 3852          */
 3853         if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) {
 3854                 u_32_t sum3, sum4, sumt;
 3855 
 3856                 /*
 3857                  * Step 2 :
 3858                  * For offending TCP/UDP IP packets, translate the ports as
 3859                  * well, based on the NAT specification. Of course such
 3860                  * a change may be reflected in the ICMP checksum as well.
 3861                  *
 3862                  * Since the port fields are part of the TCP/UDP checksum
 3863                  * of the offending IP packet, you need to adjust that checksum
 3864                  * as well... except that the change in the port numbers should
 3865                  * be offset by the checksum change.  However, the TCP/UDP
 3866                  * checksum will also need to change if there has been an
 3867                  * IP address change.
 3868                  */
 3869                 if (odst == 1) {
 3870                         sum1 = ntohs(nat->nat_osport);
 3871                         sum4 = ntohs(tcp->th_sport);
 3872                         sum3 = ntohs(nat->nat_odport);
 3873                         sum2 = ntohs(tcp->th_dport);
 3874 
 3875                         tcp->th_sport = htons(sum1);
 3876                         tcp->th_dport = htons(sum3);
 3877                 } else {
 3878                         sum1 = ntohs(nat->nat_ndport);
 3879                         sum2 = ntohs(tcp->th_dport);
 3880                         sum3 = ntohs(nat->nat_nsport);
 3881                         sum4 = ntohs(tcp->th_sport);
 3882 
 3883                         tcp->th_dport = htons(sum3);
 3884                         tcp->th_sport = htons(sum1);
 3885                 }
 3886                 CALC_SUMD(sum4, sum1, sumt);
 3887                 sumd += sumt;
 3888                 CALC_SUMD(sum2, sum3, sumt);
 3889                 sumd += sumt;
 3890 
 3891                 if (sumd != 0 || sumd2 != 0) {
 3892                         /*
 3893                          * At this point, sumd is the delta to apply to the
 3894                          * TCP/UDP header, given the changes in both the IP
 3895                          * address and the ports and sumd2 is the delta to
 3896                          * apply to the ICMP header, given the IP address
 3897                          * change delta that may need to be applied to the
 3898                          * TCP/UDP checksum instead.
 3899                          *
 3900                          * If we will both the IP and TCP/UDP checksums
 3901                          * then the ICMP checksum changes by the address
 3902                          * delta applied to the TCP/UDP checksum.  If we
 3903                          * do not change the TCP/UDP checksum them we
 3904                          * apply the delta in ports to the ICMP checksum.
 3905                          */
 3906                         if (oip->ip_p == IPPROTO_UDP) {
 3907                                 if ((dlen >= 8) && (*csump != 0)) {
 3908                                         ipf_fix_datacksum(csump, sumd);
 3909                                 } else {
 3910                                         CALC_SUMD(sum1, sum4, sumd2);
 3911                                         CALC_SUMD(sum3, sum2, sumt);
 3912                                         sumd2 += sumt;
 3913                                 }
 3914                         } else if (oip->ip_p == IPPROTO_TCP) {
 3915                                 if (dlen >= 18) {
 3916                                         ipf_fix_datacksum(csump, sumd);
 3917                                 } else {
 3918                                         CALC_SUMD(sum1, sum4, sumd2);
 3919                                         CALC_SUMD(sum3, sum2, sumt);
 3920                                         sumd2 += sumt;
 3921                                 }
 3922                         }
 3923                         if (sumd2 != 0) {
 3924                                 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
 3925                                 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
 3926                                 sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
 3927                                 ipf_fix_incksum(0, &icmp->icmp_cksum, sumd2, 0);
 3928                         }
 3929                 }
 3930         } else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) {
 3931                 icmphdr_t *orgicmp;
 3932 
 3933                 /*
 3934                  * XXX - what if this is bogus hl and we go off the end ?
 3935                  * In this case, ipf_nat_icmperrorlookup() will have
 3936                  * returned NULL.
 3937                  */
 3938                 orgicmp = (icmphdr_t *)dp;
 3939 
 3940                 if (odst == 1) {
 3941                         if (orgicmp->icmp_id != nat->nat_osport) {
 3942 
 3943                                 /*
 3944                                  * Fix ICMP checksum (of the offening ICMP
 3945                                  * query packet) to compensate the change
 3946                                  * in the ICMP id of the offending ICMP
 3947                                  * packet.
 3948                                  *
 3949                                  * Since you modify orgicmp->icmp_id with
 3950                                  * a delta (say x) and you compensate that
 3951                                  * in origicmp->icmp_cksum with a delta
 3952                                  * minus x, you don't have to adjust the
 3953                                  * overall icmp->icmp_cksum
 3954                                  */
 3955                                 sum1 = ntohs(orgicmp->icmp_id);
 3956                                 sum2 = ntohs(nat->nat_oicmpid);
 3957                                 CALC_SUMD(sum1, sum2, sumd);
 3958                                 orgicmp->icmp_id = nat->nat_oicmpid;
 3959                                 ipf_fix_datacksum(&orgicmp->icmp_cksum, sumd);
 3960                         }
 3961                 } /* nat_dir == NAT_INBOUND is impossible for icmp queries */
 3962         }
 3963         return (nat);
 3964 }
 3965 
 3966 
 3967 /*
 3968  *       MAP-IN    MAP-OUT   RDR-IN   RDR-OUT
 3969  * osrc    X       == src    == src      X
 3970  * odst    X       == dst    == dst      X
 3971  * nsrc  == dst      X         X      == dst
 3972  * ndst  == src      X         X      == src
 3973  * MAP = NAT_OUTBOUND, RDR = NAT_INBOUND
 3974  */
 3975 /*
 3976  * NB: these lookups don't lock access to the list, it assumed that it has
 3977  * already been done!
 3978  */
 3979 /* ------------------------------------------------------------------------ */
 3980 /* Function:    ipf_nat_inlookup                                            */
 3981 /* Returns:     nat_t* - NULL == no match,                                  */
 3982 /*                       else pointer to matching NAT entry                 */
 3983 /* Parameters:  fin(I)    - pointer to packet information                   */
 3984 /*              flags(I)  - NAT flags for this packet                       */
 3985 /*              p(I)      - protocol for this packet                        */
 3986 /*              src(I)    - source IP address                               */
 3987 /*              mapdst(I) - destination IP address                          */
 3988 /*                                                                          */
 3989 /* Lookup a nat entry based on the mapped destination ip address/port and   */
 3990 /* real source address/port.  We use this lookup when receiving a packet,   */
 3991 /* we're looking for a table entry, based on the destination address.       */
 3992 /*                                                                          */
 3993 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
 3994 /*                                                                          */
 3995 /* NOTE: IT IS ASSUMED THAT  IS ONLY HELD WITH A READ LOCK WHEN             */
 3996 /*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
 3997 /*                                                                          */
 3998 /* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
 3999 /*            the packet is of said protocol                                */
 4000 /* ------------------------------------------------------------------------ */
 4001 nat_t *
 4002 ipf_nat_inlookup(fr_info_t *fin, u_int flags, u_int p,
 4003         struct in_addr src , struct in_addr mapdst)
 4004 {
 4005         ipf_main_softc_t *softc = fin->fin_main_soft;
 4006         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 4007         u_short sport, dport;
 4008         grehdr_t *gre;
 4009         ipnat_t *ipn;
 4010         u_int sflags;
 4011         nat_t *nat;
 4012         int nflags;
 4013         u_32_t dst;
 4014         void *ifp;
 4015         u_int hv, rhv;
 4016 
 4017         ifp = fin->fin_ifp;
 4018         gre = NULL;
 4019         dst = mapdst.s_addr;
 4020         sflags = flags & NAT_TCPUDPICMP;
 4021 
 4022         switch (p)
 4023         {
 4024         case IPPROTO_TCP :
 4025         case IPPROTO_UDP :
 4026                 sport = htons(fin->fin_data[0]);
 4027                 dport = htons(fin->fin_data[1]);
 4028                 break;
 4029         case IPPROTO_ICMP :
 4030                 sport = 0;
 4031                 dport = fin->fin_data[1];
 4032                 break;
 4033         default :
 4034                 sport = 0;
 4035                 dport = 0;
 4036                 break;
 4037         }
 4038 
 4039 
 4040         if ((flags & SI_WILDP) != 0)
 4041                 goto find_in_wild_ports;
 4042 
 4043         rhv = NAT_HASH_FN(dst, dport, 0xffffffff);
 4044         rhv = NAT_HASH_FN(src.s_addr, rhv + sport, 0xffffffff);
 4045         hv = rhv % softn->ipf_nat_table_sz;
 4046         nat = softn->ipf_nat_table[1][hv];
 4047         /* TRACE dst, dport, src, sport, hv, nat */
 4048 
 4049         for (; nat; nat = nat->nat_hnext[1]) {
 4050                 if (nat->nat_ifps[0] != NULL) {
 4051                         if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
 4052                                 continue;
 4053                 }
 4054 
 4055                 if (nat->nat_pr[0] != p)
 4056                         continue;
 4057 
 4058                 switch (nat->nat_dir)
 4059                 {
 4060                 case NAT_INBOUND :
 4061                 case NAT_DIVERTIN :
 4062                         if (nat->nat_v[0] != 4)
 4063                                 continue;
 4064                         if (nat->nat_osrcaddr != src.s_addr ||
 4065                             nat->nat_odstaddr != dst)
 4066                                 continue;
 4067                         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
 4068                                 if (nat->nat_osport != sport)
 4069                                         continue;
 4070                                 if (nat->nat_odport != dport)
 4071                                         continue;
 4072 
 4073                         } else if (p == IPPROTO_ICMP) {
 4074                                 if (nat->nat_osport != dport) {
 4075                                         continue;
 4076                                 }
 4077                         }
 4078                         break;
 4079                 case NAT_DIVERTOUT :
 4080                         if (nat->nat_dlocal)
 4081                                 continue;
 4082                 case NAT_OUTBOUND :
 4083                         if (nat->nat_v[1] != 4)
 4084                                 continue;
 4085                         if (nat->nat_dlocal)
 4086                                 continue;
 4087                         if (nat->nat_dlocal)
 4088                                 continue;
 4089                         if (nat->nat_ndstaddr != src.s_addr ||
 4090                             nat->nat_nsrcaddr != dst)
 4091                                 continue;
 4092                         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
 4093                                 if (nat->nat_ndport != sport)
 4094                                         continue;
 4095                                 if (nat->nat_nsport != dport)
 4096                                         continue;
 4097 
 4098                         } else if (p == IPPROTO_ICMP) {
 4099                                 if (nat->nat_osport != dport) {
 4100                                         continue;
 4101                                 }
 4102                         }
 4103                         break;
 4104                 }
 4105 
 4106 
 4107                 if ((nat->nat_flags & IPN_TCPUDP) != 0) {
 4108                         ipn = nat->nat_ptr;
 4109                         if ((ipn != NULL) && (nat->nat_aps != NULL))
 4110                                 if (ipf_proxy_match(fin, nat) != 0)
 4111                                         continue;
 4112                 }
 4113                 if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
 4114                         nat->nat_ifps[0] = ifp;
 4115                         nat->nat_mtu[0] = GETIFMTU_4(ifp);
 4116                 }
 4117                 return (nat);
 4118         }
 4119 
 4120         /*
 4121          * So if we didn't find it but there are wildcard members in the hash
 4122          * table, go back and look for them.  We do this search and update here
 4123          * because it is modifying the NAT table and we want to do this only
 4124          * for the first packet that matches.  The exception, of course, is
 4125          * for "dummy" (FI_IGNORE) lookups.
 4126          */
 4127 find_in_wild_ports:
 4128         if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
 4129                 NBUMPSIDEX(0, ns_lookup_miss, ns_lookup_miss_0);
 4130                 return (NULL);
 4131         }
 4132         if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
 4133                 NBUMPSIDEX(0, ns_lookup_nowild, ns_lookup_nowild_0);
 4134                 return (NULL);
 4135         }
 4136 
 4137         RWLOCK_EXIT(&softc->ipf_nat);
 4138 
 4139         hv = NAT_HASH_FN(dst, 0, 0xffffffff);
 4140         hv = NAT_HASH_FN(src.s_addr, hv, softn->ipf_nat_table_sz);
 4141         WRITE_ENTER(&softc->ipf_nat);
 4142 
 4143         nat = softn->ipf_nat_table[1][hv];
 4144         /* TRACE dst, src, hv, nat */
 4145         for (; nat; nat = nat->nat_hnext[1]) {
 4146                 if (nat->nat_ifps[0] != NULL) {
 4147                         if ((ifp != NULL) && (ifp != nat->nat_ifps[0]))
 4148                                 continue;
 4149                 }
 4150 
 4151                 if (nat->nat_pr[0] != fin->fin_p)
 4152                         continue;
 4153 
 4154                 switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))
 4155                 {
 4156                 case NAT_INBOUND :
 4157                         if (nat->nat_v[0] != 4)
 4158                                 continue;
 4159                         if (nat->nat_osrcaddr != src.s_addr ||
 4160                             nat->nat_odstaddr != dst)
 4161                                 continue;
 4162                         break;
 4163                 case NAT_OUTBOUND :
 4164                         if (nat->nat_v[1] != 4)
 4165                                 continue;
 4166                         if (nat->nat_ndstaddr != src.s_addr ||
 4167                             nat->nat_nsrcaddr != dst)
 4168                                 continue;
 4169                         break;
 4170                 }
 4171 
 4172                 nflags = nat->nat_flags;
 4173                 if (!(nflags & (NAT_TCPUDP|SI_WILDP)))
 4174                         continue;
 4175 
 4176                 if (ipf_nat_wildok(nat, (int)sport, (int)dport, nflags,
 4177                                    NAT_INBOUND) == 1) {
 4178                         if ((fin->fin_flx & FI_IGNORE) != 0)
 4179                                 break;
 4180                         if ((nflags & SI_CLONE) != 0) {
 4181                                 nat = ipf_nat_clone(fin, nat);
 4182                                 if (nat == NULL)
 4183                                         break;
 4184                         } else {
 4185                                 MUTEX_ENTER(&softn->ipf_nat_new);
 4186                                 softn->ipf_nat_stats.ns_wilds--;
 4187                                 MUTEX_EXIT(&softn->ipf_nat_new);
 4188                         }
 4189 
 4190                         if (nat->nat_dir == NAT_INBOUND) {
 4191                                 if (nat->nat_osport == 0) {
 4192                                         nat->nat_osport = sport;
 4193                                         nat->nat_nsport = sport;
 4194                                 }
 4195                                 if (nat->nat_odport == 0) {
 4196                                         nat->nat_odport = dport;
 4197                                         nat->nat_ndport = dport;
 4198                                 }
 4199                         } else if (nat->nat_dir == NAT_OUTBOUND) {
 4200                                 if (nat->nat_osport == 0) {
 4201                                         nat->nat_osport = dport;
 4202                                         nat->nat_nsport = dport;
 4203                                 }
 4204                                 if (nat->nat_odport == 0) {
 4205                                         nat->nat_odport = sport;
 4206                                         nat->nat_ndport = sport;
 4207                                 }
 4208                         }
 4209                         if ((nat->nat_ifps[0] == NULL) && (ifp != NULL)) {
 4210                                 nat->nat_ifps[0] = ifp;
 4211                                 nat->nat_mtu[0] = GETIFMTU_4(ifp);
 4212                         }
 4213                         nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
 4214                         ipf_nat_tabmove(softn, nat);
 4215                         break;
 4216                 }
 4217         }
 4218 
 4219         MUTEX_DOWNGRADE(&softc->ipf_nat);
 4220 
 4221         if (nat == NULL) {
 4222                 NBUMPSIDE(0, ns_lookup_miss);
 4223         }
 4224         return (nat);
 4225 }
 4226 
 4227 
 4228 /* ------------------------------------------------------------------------ */
 4229 /* Function:    ipf_nat_tabmove                                             */
 4230 /* Returns:     Nil                                                         */
 4231 /* Parameters:  softn(I) - pointer to NAT context structure                 */
 4232 /*              nat(I)   - pointer to NAT structure                         */
 4233 /* Write Lock:  ipf_nat                                                     */
 4234 /*                                                                          */
 4235 /* This function is only called for TCP/UDP NAT table entries where the     */
 4236 /* original was placed in the table without hashing on the ports and we now */
 4237 /* want to include hashing on port numbers.                                 */
 4238 /* ------------------------------------------------------------------------ */
 4239 static void
 4240 ipf_nat_tabmove(ipf_nat_softc_t *softn, nat_t *nat)
 4241 {
 4242         u_int hv0, hv1, rhv0, rhv1;
 4243         natstat_t *nsp;
 4244         nat_t **natp;
 4245 
 4246         if (nat->nat_flags & SI_CLONE)
 4247                 return;
 4248 
 4249         nsp = &softn->ipf_nat_stats;
 4250         /*
 4251          * Remove the NAT entry from the old location
 4252          */
 4253         if (nat->nat_hnext[0])
 4254                 nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
 4255         *nat->nat_phnext[0] = nat->nat_hnext[0];
 4256         nsp->ns_side[0].ns_bucketlen[nat->nat_hv[0] %
 4257                                      softn->ipf_nat_table_sz]--;
 4258 
 4259         if (nat->nat_hnext[1])
 4260                 nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
 4261         *nat->nat_phnext[1] = nat->nat_hnext[1];
 4262         nsp->ns_side[1].ns_bucketlen[nat->nat_hv[1] %
 4263                                      softn->ipf_nat_table_sz]--;
 4264 
 4265         /*
 4266          * Add into the NAT table in the new position
 4267          */
 4268         rhv0 = NAT_HASH_FN(nat->nat_osrcaddr, nat->nat_osport, 0xffffffff);
 4269         rhv0 = NAT_HASH_FN(nat->nat_odstaddr, rhv0 + nat->nat_odport,
 4270                            0xffffffff);
 4271         rhv1 = NAT_HASH_FN(nat->nat_nsrcaddr, nat->nat_nsport, 0xffffffff);
 4272         rhv1 = NAT_HASH_FN(nat->nat_ndstaddr, rhv1 + nat->nat_ndport,
 4273                            0xffffffff);
 4274 
 4275         hv0 = rhv0 % softn->ipf_nat_table_sz;
 4276         hv1 = rhv1 % softn->ipf_nat_table_sz;
 4277 
 4278         if (nat->nat_dir == NAT_INBOUND || nat->nat_dir == NAT_DIVERTIN) {
 4279                 u_int swap;
 4280 
 4281                 swap = hv0;
 4282                 hv0 = hv1;
 4283                 hv1 = swap;
 4284         }
 4285 
 4286         /* TRACE nat_osrcaddr, nat_osport, nat_odstaddr, nat_odport, hv0 */
 4287         /* TRACE nat_nsrcaddr, nat_nsport, nat_ndstaddr, nat_ndport, hv1 */
 4288 
 4289         nat->nat_hv[0] = rhv0;
 4290         natp = &softn->ipf_nat_table[0][hv0];
 4291         if (*natp)
 4292                 (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
 4293         nat->nat_phnext[0] = natp;
 4294         nat->nat_hnext[0] = *natp;
 4295         *natp = nat;
 4296         nsp->ns_side[0].ns_bucketlen[hv0]++;
 4297 
 4298         nat->nat_hv[1] = rhv1;
 4299         natp = &softn->ipf_nat_table[1][hv1];
 4300         if (*natp)
 4301                 (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
 4302         nat->nat_phnext[1] = natp;
 4303         nat->nat_hnext[1] = *natp;
 4304         *natp = nat;
 4305         nsp->ns_side[1].ns_bucketlen[hv1]++;
 4306 }
 4307 
 4308 
 4309 /* ------------------------------------------------------------------------ */
 4310 /* Function:    ipf_nat_outlookup                                           */
 4311 /* Returns:     nat_t* - NULL == no match,                                  */
 4312 /*                       else pointer to matching NAT entry                 */
 4313 /* Parameters:  fin(I)   - pointer to packet information                    */
 4314 /*              flags(I) - NAT flags for this packet                        */
 4315 /*              p(I)     - protocol for this packet                         */
 4316 /*              src(I)   - source IP address                                */
 4317 /*              dst(I)   - destination IP address                           */
 4318 /*              rw(I)    - 1 == write lock on  held, 0 == read lock.        */
 4319 /*                                                                          */
 4320 /* Lookup a nat entry based on the source 'real' ip address/port and        */
 4321 /* destination address/port.  We use this lookup when sending a packet out, */
 4322 /* we're looking for a table entry, based on the source address.            */
 4323 /*                                                                          */
 4324 /* NOTE: THE PACKET BEING CHECKED (IF FOUND) HAS A MAPPING ALREADY.         */
 4325 /*                                                                          */
 4326 /* NOTE: IT IS ASSUMED THAT  IS ONLY HELD WITH A READ LOCK WHEN             */
 4327 /*       THIS FUNCTION IS CALLED WITH NAT_SEARCH SET IN nflags.             */
 4328 /*                                                                          */
 4329 /* flags   -> relevant are IPN_UDP/IPN_TCP/IPN_ICMPQUERY that indicate if   */
 4330 /*            the packet is of said protocol                                */
 4331 /* ------------------------------------------------------------------------ */
 4332 nat_t *
 4333 ipf_nat_outlookup(fr_info_t *fin, u_int flags, u_int p,
 4334         struct in_addr src , struct in_addr dst)
 4335 {
 4336         ipf_main_softc_t *softc = fin->fin_main_soft;
 4337         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 4338         u_short sport, dport;
 4339         u_int sflags;
 4340         ipnat_t *ipn;
 4341         nat_t *nat;
 4342         void *ifp;
 4343         u_int hv;
 4344 
 4345         ifp = fin->fin_ifp;
 4346         sflags = flags & IPN_TCPUDPICMP;
 4347 
 4348         switch (p)
 4349         {
 4350         case IPPROTO_TCP :
 4351         case IPPROTO_UDP :
 4352                 sport = htons(fin->fin_data[0]);
 4353                 dport = htons(fin->fin_data[1]);
 4354                 break;
 4355         case IPPROTO_ICMP :
 4356                 sport = 0;
 4357                 dport = fin->fin_data[1];
 4358                 break;
 4359         default :
 4360                 sport = 0;
 4361                 dport = 0;
 4362                 break;
 4363         }
 4364 
 4365         if ((flags & SI_WILDP) != 0)
 4366                 goto find_out_wild_ports;
 4367 
 4368         hv = NAT_HASH_FN(src.s_addr, sport, 0xffffffff);
 4369         hv = NAT_HASH_FN(dst.s_addr, hv + dport, softn->ipf_nat_table_sz);
 4370         nat = softn->ipf_nat_table[0][hv];
 4371 
 4372         /* TRACE src, sport, dst, dport, hv, nat */
 4373 
 4374         for (; nat; nat = nat->nat_hnext[0]) {
 4375                 if (nat->nat_ifps[1] != NULL) {
 4376                         if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
 4377                                 continue;
 4378                 }
 4379 
 4380                 if (nat->nat_pr[1] != p)
 4381                         continue;
 4382 
 4383                 switch (nat->nat_dir)
 4384                 {
 4385                 case NAT_INBOUND :
 4386                 case NAT_DIVERTIN :
 4387                         if (nat->nat_v[1] != 4)
 4388                                 continue;
 4389                         if (nat->nat_ndstaddr != src.s_addr ||
 4390                             nat->nat_nsrcaddr != dst.s_addr)
 4391                                 continue;
 4392 
 4393                         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
 4394                                 if (nat->nat_ndport != sport)
 4395                                         continue;
 4396                                 if (nat->nat_nsport != dport)
 4397                                         continue;
 4398 
 4399                         } else if (p == IPPROTO_ICMP) {
 4400                                 if (nat->nat_osport != dport) {
 4401                                         continue;
 4402                                 }
 4403                         }
 4404                         break;
 4405                 case NAT_OUTBOUND :
 4406                 case NAT_DIVERTOUT :
 4407                         if (nat->nat_v[0] != 4)
 4408                                 continue;
 4409                         if (nat->nat_osrcaddr != src.s_addr ||
 4410                             nat->nat_odstaddr != dst.s_addr)
 4411                                 continue;
 4412 
 4413                         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
 4414                                 if (nat->nat_odport != dport)
 4415                                         continue;
 4416                                 if (nat->nat_osport != sport)
 4417                                         continue;
 4418 
 4419                         } else if (p == IPPROTO_ICMP) {
 4420                                 if (nat->nat_osport != dport) {
 4421                                         continue;
 4422                                 }
 4423                         }
 4424                         break;
 4425                 }
 4426 
 4427                 ipn = nat->nat_ptr;
 4428                 if ((ipn != NULL) && (nat->nat_aps != NULL))
 4429                         if (ipf_proxy_match(fin, nat) != 0)
 4430                                 continue;
 4431 
 4432                 if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
 4433                         nat->nat_ifps[1] = ifp;
 4434                         nat->nat_mtu[1] = GETIFMTU_4(ifp);
 4435                 }
 4436                 return (nat);
 4437         }
 4438 
 4439         /*
 4440          * So if we didn't find it but there are wildcard members in the hash
 4441          * table, go back and look for them.  We do this search and update here
 4442          * because it is modifying the NAT table and we want to do this only
 4443          * for the first packet that matches.  The exception, of course, is
 4444          * for "dummy" (FI_IGNORE) lookups.
 4445          */
 4446 find_out_wild_ports:
 4447         if (!(flags & NAT_TCPUDP) || !(flags & NAT_SEARCH)) {
 4448                 NBUMPSIDEX(1, ns_lookup_miss, ns_lookup_miss_1);
 4449                 return (NULL);
 4450         }
 4451         if (softn->ipf_nat_stats.ns_wilds == 0 || (fin->fin_flx & FI_NOWILD)) {
 4452                 NBUMPSIDEX(1, ns_lookup_nowild, ns_lookup_nowild_1);
 4453                 return (NULL);
 4454         }
 4455 
 4456         RWLOCK_EXIT(&softc->ipf_nat);
 4457 
 4458         hv = NAT_HASH_FN(src.s_addr, 0, 0xffffffff);
 4459         hv = NAT_HASH_FN(dst.s_addr, hv, softn->ipf_nat_table_sz);
 4460 
 4461         WRITE_ENTER(&softc->ipf_nat);
 4462 
 4463         nat = softn->ipf_nat_table[0][hv];
 4464         for (; nat; nat = nat->nat_hnext[0]) {
 4465                 if (nat->nat_ifps[1] != NULL) {
 4466                         if ((ifp != NULL) && (ifp != nat->nat_ifps[1]))
 4467                                 continue;
 4468                 }
 4469 
 4470                 if (nat->nat_pr[1] != fin->fin_p)
 4471                         continue;
 4472 
 4473                 switch (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND))
 4474                 {
 4475                 case NAT_INBOUND :
 4476                         if (nat->nat_v[1] != 4)
 4477                                 continue;
 4478                         if (nat->nat_ndstaddr != src.s_addr ||
 4479                             nat->nat_nsrcaddr != dst.s_addr)
 4480                                 continue;
 4481                         break;
 4482                 case NAT_OUTBOUND :
 4483                         if (nat->nat_v[0] != 4)
 4484                                 continue;
 4485                         if (nat->nat_osrcaddr != src.s_addr ||
 4486                             nat->nat_odstaddr != dst.s_addr)
 4487                                 continue;
 4488                         break;
 4489                 }
 4490 
 4491                 if (!(nat->nat_flags & (NAT_TCPUDP|SI_WILDP)))
 4492                         continue;
 4493 
 4494                 if (ipf_nat_wildok(nat, (int)sport, (int)dport, nat->nat_flags,
 4495                                    NAT_OUTBOUND) == 1) {
 4496                         if ((fin->fin_flx & FI_IGNORE) != 0)
 4497                                 break;
 4498                         if ((nat->nat_flags & SI_CLONE) != 0) {
 4499                                 nat = ipf_nat_clone(fin, nat);
 4500                                 if (nat == NULL)
 4501                                         break;
 4502                         } else {
 4503                                 MUTEX_ENTER(&softn->ipf_nat_new);
 4504                                 softn->ipf_nat_stats.ns_wilds--;
 4505                                 MUTEX_EXIT(&softn->ipf_nat_new);
 4506                         }
 4507 
 4508                         if (nat->nat_dir == NAT_OUTBOUND) {
 4509                                 if (nat->nat_osport == 0) {
 4510                                         nat->nat_osport = sport;
 4511                                         nat->nat_nsport = sport;
 4512                                 }
 4513                                 if (nat->nat_odport == 0) {
 4514                                         nat->nat_odport = dport;
 4515                                         nat->nat_ndport = dport;
 4516                                 }
 4517                         } else if (nat->nat_dir == NAT_INBOUND) {
 4518                                 if (nat->nat_osport == 0) {
 4519                                         nat->nat_osport = dport;
 4520                                         nat->nat_nsport = dport;
 4521                                 }
 4522                                 if (nat->nat_odport == 0) {
 4523                                         nat->nat_odport = sport;
 4524                                         nat->nat_ndport = sport;
 4525                                 }
 4526                         }
 4527                         if ((nat->nat_ifps[1] == NULL) && (ifp != NULL)) {
 4528                                 nat->nat_ifps[1] = ifp;
 4529                                 nat->nat_mtu[1] = GETIFMTU_4(ifp);
 4530                         }
 4531                         nat->nat_flags &= ~(SI_W_DPORT|SI_W_SPORT);
 4532                         ipf_nat_tabmove(softn, nat);
 4533                         break;
 4534                 }
 4535         }
 4536 
 4537         MUTEX_DOWNGRADE(&softc->ipf_nat);
 4538 
 4539         if (nat == NULL) {
 4540                 NBUMPSIDE(1, ns_lookup_miss);
 4541         }
 4542         return (nat);
 4543 }
 4544 
 4545 
 4546 /* ------------------------------------------------------------------------ */
 4547 /* Function:    ipf_nat_lookupredir                                         */
 4548 /* Returns:     nat_t* - NULL == no match,                                  */
 4549 /*                       else pointer to matching NAT entry                 */
 4550 /* Parameters:  np(I) - pointer to description of packet to find NAT table  */
 4551 /*                      entry for.                                          */
 4552 /*                                                                          */
 4553 /* Lookup the NAT tables to search for a matching redirect                  */
 4554 /* The contents of natlookup_t should imitate those found in a packet that  */
 4555 /* would be translated - ie a packet coming in for RDR or going out for MAP.*/
 4556 /* We can do the lookup in one of two ways, imitating an inbound or         */
 4557 /* outbound  packet.  By default we assume outbound, unless IPN_IN is set.  */
 4558 /* For IN, the fields are set as follows:                                   */
 4559 /*     nl_real* = source information                                        */
 4560 /*     nl_out* = destination information (translated)                       */
 4561 /* For an out packet, the fields are set like this:                         */
 4562 /*     nl_in* = source information (untranslated)                           */
 4563 /*     nl_out* = destination information (translated)                       */
 4564 /* ------------------------------------------------------------------------ */
 4565 nat_t *
 4566 ipf_nat_lookupredir(natlookup_t *np)
 4567 {
 4568         fr_info_t fi;
 4569         nat_t *nat;
 4570 
 4571         bzero((char *)&fi, sizeof(fi));
 4572         if (np->nl_flags & IPN_IN) {
 4573                 fi.fin_data[0] = ntohs(np->nl_realport);
 4574                 fi.fin_data[1] = ntohs(np->nl_outport);
 4575         } else {
 4576                 fi.fin_data[0] = ntohs(np->nl_inport);
 4577                 fi.fin_data[1] = ntohs(np->nl_outport);
 4578         }
 4579         if (np->nl_flags & IPN_TCP)
 4580                 fi.fin_p = IPPROTO_TCP;
 4581         else if (np->nl_flags & IPN_UDP)
 4582                 fi.fin_p = IPPROTO_UDP;
 4583         else if (np->nl_flags & (IPN_ICMPERR|IPN_ICMPQUERY))
 4584                 fi.fin_p = IPPROTO_ICMP;
 4585 
 4586         /*
 4587          * We can do two sorts of lookups:
 4588          * - IPN_IN: we have the `real' and `out' address, look for `in'.
 4589          * - default: we have the `in' and `out' address, look for `real'.
 4590          */
 4591         if (np->nl_flags & IPN_IN) {
 4592                 if ((nat = ipf_nat_inlookup(&fi, np->nl_flags, fi.fin_p,
 4593                                             np->nl_realip, np->nl_outip))) {
 4594                         np->nl_inip = nat->nat_odstip;
 4595                         np->nl_inport = nat->nat_odport;
 4596                 }
 4597         } else {
 4598                 /*
 4599                  * If nl_inip is non null, this is a lookup based on the real
 4600                  * ip address. Else, we use the fake.
 4601                  */
 4602                 if ((nat = ipf_nat_outlookup(&fi, np->nl_flags, fi.fin_p,
 4603                                          np->nl_inip, np->nl_outip))) {
 4604 
 4605                         if ((np->nl_flags & IPN_FINDFORWARD) != 0) {
 4606                                 fr_info_t fin;
 4607                                 bzero((char *)&fin, sizeof(fin));
 4608                                 fin.fin_p = nat->nat_pr[0];
 4609                                 fin.fin_data[0] = ntohs(nat->nat_ndport);
 4610                                 fin.fin_data[1] = ntohs(nat->nat_nsport);
 4611                                 if (ipf_nat_inlookup(&fin, np->nl_flags,
 4612                                                      fin.fin_p, nat->nat_ndstip,
 4613                                                      nat->nat_nsrcip) != NULL) {
 4614                                         np->nl_flags &= ~IPN_FINDFORWARD;
 4615                                 }
 4616                         }
 4617 
 4618                         np->nl_realip = nat->nat_odstip;
 4619                         np->nl_realport = nat->nat_odport;
 4620                 }
 4621         }
 4622 
 4623         return (nat);
 4624 }
 4625 
 4626 
 4627 /* ------------------------------------------------------------------------ */
 4628 /* Function:    ipf_nat_match                                               */
 4629 /* Returns:     int - 0 == no match, 1 == match                             */
 4630 /* Parameters:  fin(I)   - pointer to packet information                    */
 4631 /*              np(I)    - pointer to NAT rule                              */
 4632 /*                                                                          */
 4633 /* Pull the matching of a packet against a NAT rule out of that complex     */
 4634 /* loop inside ipf_nat_checkin() and lay it out properly in its own function. */
 4635 /* ------------------------------------------------------------------------ */
 4636 static int
 4637 ipf_nat_match(fr_info_t *fin, ipnat_t *np)
 4638 {
 4639         ipf_main_softc_t *softc = fin->fin_main_soft;
 4640         frtuc_t *ft;
 4641         int match;
 4642 
 4643         match = 0;
 4644         switch (np->in_osrcatype)
 4645         {
 4646         case FRI_NORMAL :
 4647                 match = ((fin->fin_saddr & np->in_osrcmsk) != np->in_osrcaddr);
 4648                 break;
 4649         case FRI_LOOKUP :
 4650                 match = (*np->in_osrcfunc)(softc, np->in_osrcptr,
 4651                                            4, &fin->fin_saddr, fin->fin_plen);
 4652                 break;
 4653         }
 4654         match ^= ((np->in_flags & IPN_NOTSRC) != 0);
 4655         if (match)
 4656                 return (0);
 4657 
 4658         match = 0;
 4659         switch (np->in_odstatype)
 4660         {
 4661         case FRI_NORMAL :
 4662                 match = ((fin->fin_daddr & np->in_odstmsk) != np->in_odstaddr);
 4663                 break;
 4664         case FRI_LOOKUP :
 4665                 match = (*np->in_odstfunc)(softc, np->in_odstptr,
 4666                                            4, &fin->fin_daddr, fin->fin_plen);
 4667                 break;
 4668         }
 4669 
 4670         match ^= ((np->in_flags & IPN_NOTDST) != 0);
 4671         if (match)
 4672                 return (0);
 4673 
 4674         ft = &np->in_tuc;
 4675         if (!(fin->fin_flx & FI_TCPUDP) ||
 4676             (fin->fin_flx & (FI_SHORT|FI_FRAGBODY))) {
 4677                 if (ft->ftu_scmp || ft->ftu_dcmp)
 4678                         return (0);
 4679                 return (1);
 4680         }
 4681 
 4682         return (ipf_tcpudpchk(&fin->fin_fi, ft));
 4683 }
 4684 
 4685 
 4686 /* ------------------------------------------------------------------------ */
 4687 /* Function:    ipf_nat_update                                              */
 4688 /* Returns:     Nil                                                         */
 4689 /* Parameters:  fin(I) - pointer to packet information                      */
 4690 /*              nat(I) - pointer to NAT structure                           */
 4691 /*                                                                          */
 4692 /* Updates the lifetime of a NAT table entry for non-TCP packets.  Must be  */
 4693 /* called with fin_rev updated - i.e. after calling ipf_nat_proto().        */
 4694 /*                                                                          */
 4695 /* This *MUST* be called after ipf_nat_proto() as it expects fin_rev to     */
 4696 /* already be set.                                                          */
 4697 /* ------------------------------------------------------------------------ */
 4698 void
 4699 ipf_nat_update(fr_info_t *fin, nat_t *nat)
 4700 {
 4701         ipf_main_softc_t *softc = fin->fin_main_soft;
 4702         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 4703         ipftq_t *ifq, *ifq2;
 4704         ipftqent_t *tqe;
 4705         ipnat_t *np = nat->nat_ptr;
 4706 
 4707         tqe = &nat->nat_tqe;
 4708         ifq = tqe->tqe_ifq;
 4709 
 4710         /*
 4711          * We allow over-riding of NAT timeouts from NAT rules, even for
 4712          * TCP, however, if it is TCP and there is no rule timeout set,
 4713          * then do not update the timeout here.
 4714          */
 4715         if (np != NULL) {
 4716                 np->in_bytes[fin->fin_rev] += fin->fin_plen;
 4717                 ifq2 = np->in_tqehead[fin->fin_rev];
 4718         } else {
 4719                 ifq2 = NULL;
 4720         }
 4721 
 4722         if (nat->nat_pr[0] == IPPROTO_TCP && ifq2 == NULL) {
 4723                 (void) ipf_tcp_age(&nat->nat_tqe, fin, softn->ipf_nat_tcptq,
 4724                                    0, 2);
 4725         } else {
 4726                 if (ifq2 == NULL) {
 4727                         if (nat->nat_pr[0] == IPPROTO_UDP)
 4728                                 ifq2 = fin->fin_rev ? &softn->ipf_nat_udpacktq :
 4729                                                       &softn->ipf_nat_udptq;
 4730                         else if (nat->nat_pr[0] == IPPROTO_ICMP ||
 4731                                  nat->nat_pr[0] == IPPROTO_ICMPV6)
 4732                                 ifq2 = fin->fin_rev ? &softn->ipf_nat_icmpacktq:
 4733                                                       &softn->ipf_nat_icmptq;
 4734                         else
 4735                                 ifq2 = &softn->ipf_nat_iptq;
 4736                 }
 4737 
 4738                 ipf_movequeue(softc->ipf_ticks, tqe, ifq, ifq2);
 4739         }
 4740 }
 4741 
 4742 
 4743 /* ------------------------------------------------------------------------ */
 4744 /* Function:    ipf_nat_checkout                                            */
 4745 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
 4746 /*                     0 == no packet translation occurred,                 */
 4747 /*                     1 == packet was successfully translated.             */
 4748 /* Parameters:  fin(I)   - pointer to packet information                    */
 4749 /*              passp(I) - pointer to filtering result flags                */
 4750 /*                                                                          */
 4751 /* Check to see if an outcoming packet should be changed.  ICMP packets are */
 4752 /* first checked to see if they match an existing entry (if an error),      */
 4753 /* otherwise a search of the current NAT table is made.  If neither results */
 4754 /* in a match then a search for a matching NAT rule is made.  Create a new  */
 4755 /* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
 4756 /* packet header(s) as required.                                            */
 4757 /* ------------------------------------------------------------------------ */
 4758 int
 4759 ipf_nat_checkout(fr_info_t *fin, u_32_t *passp)
 4760 {
 4761         ipnat_t *np = NULL, *npnext;
 4762         struct ifnet *ifp, *sifp;
 4763         ipf_main_softc_t *softc;
 4764         ipf_nat_softc_t *softn;
 4765         icmphdr_t *icmp = NULL;
 4766         tcphdr_t *tcp = NULL;
 4767         int rval, natfailed;
 4768         u_int nflags = 0;
 4769         u_32_t ipa, iph;
 4770         int natadd = 1;
 4771         frentry_t *fr;
 4772         nat_t *nat;
 4773 
 4774         if (fin->fin_v == 6) {
 4775 #ifdef USE_INET6
 4776                 return (ipf_nat6_checkout(fin, passp));
 4777 #else
 4778                 return (0);
 4779 #endif
 4780         }
 4781 
 4782         softc = fin->fin_main_soft;
 4783         softn = softc->ipf_nat_soft;
 4784 
 4785         if (softn->ipf_nat_lock != 0)
 4786                 return (0);
 4787         if (softn->ipf_nat_stats.ns_rules == 0 &&
 4788             softn->ipf_nat_instances == NULL)
 4789                 return (0);
 4790 
 4791         natfailed = 0;
 4792         fr = fin->fin_fr;
 4793         sifp = fin->fin_ifp;
 4794         if (fr != NULL) {
 4795                 ifp = fr->fr_tifs[fin->fin_rev].fd_ptr;
 4796                 if ((ifp != NULL) && (ifp != (void *)-1))
 4797                         fin->fin_ifp = ifp;
 4798         }
 4799         ifp = fin->fin_ifp;
 4800 
 4801         if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
 4802                 switch (fin->fin_p)
 4803                 {
 4804                 case IPPROTO_TCP :
 4805                         nflags = IPN_TCP;
 4806                         break;
 4807                 case IPPROTO_UDP :
 4808                         nflags = IPN_UDP;
 4809                         break;
 4810                 case IPPROTO_ICMP :
 4811                         icmp = fin->fin_dp;
 4812 
 4813                         /*
 4814                          * This is an incoming packet, so the destination is
 4815                          * the icmp_id and the source port equals 0
 4816                          */
 4817                         if ((fin->fin_flx & FI_ICMPQUERY) != 0)
 4818                                 nflags = IPN_ICMPQUERY;
 4819                         break;
 4820                 default :
 4821                         break;
 4822                 }
 4823 
 4824                 if ((nflags & IPN_TCPUDP))
 4825                         tcp = fin->fin_dp;
 4826         }
 4827 
 4828         ipa = fin->fin_saddr;
 4829 
 4830         READ_ENTER(&softc->ipf_nat);
 4831 
 4832         if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) &&
 4833             (nat = ipf_nat_icmperror(fin, &nflags, NAT_OUTBOUND)))
 4834                 /*EMPTY*/;
 4835         else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
 4836                 natadd = 0;
 4837         else if ((nat = ipf_nat_outlookup(fin, nflags|NAT_SEARCH,
 4838                                       (u_int)fin->fin_p, fin->fin_src,
 4839                                       fin->fin_dst))) {
 4840                 nflags = nat->nat_flags;
 4841         } else if (fin->fin_off == 0) {
 4842                 u_32_t hv, msk, nmsk = 0;
 4843 
 4844                 /*
 4845                  * If there is no current entry in the nat table for this IP#,
 4846                  * create one for it (if there is a matching rule).
 4847                  */
 4848 maskloop:
 4849                 msk = softn->ipf_nat_map_active_masks[nmsk];
 4850                 iph = ipa & msk;
 4851                 hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_maprules_sz);
 4852 retry_roundrobin:
 4853                 for (np = softn->ipf_nat_map_rules[hv]; np; np = npnext) {
 4854                         npnext = np->in_mnext;
 4855                         if ((np->in_ifps[1] && (np->in_ifps[1] != ifp)))
 4856                                 continue;
 4857                         if (np->in_v[0] != 4)
 4858                                 continue;
 4859                         if (np->in_pr[1] && (np->in_pr[1] != fin->fin_p))
 4860                                 continue;
 4861                         if ((np->in_flags & IPN_RF) &&
 4862                             !(np->in_flags & nflags))
 4863                                 continue;
 4864                         if (np->in_flags & IPN_FILTER) {
 4865                                 switch (ipf_nat_match(fin, np))
 4866                                 {
 4867                                 case 0 :
 4868                                         continue;
 4869                                 case -1 :
 4870                                         rval = -3;
 4871                                         goto outmatchfail;
 4872                                 case 1 :
 4873                                 default :
 4874                                         break;
 4875                                 }
 4876                         } else if ((ipa & np->in_osrcmsk) != np->in_osrcaddr)
 4877                                 continue;
 4878 
 4879                         if ((fr != NULL) &&
 4880                             !ipf_matchtag(&np->in_tag, &fr->fr_nattag))
 4881                                 continue;
 4882 
 4883                         if (np->in_plabel != -1) {
 4884                                 if (((np->in_flags & IPN_FILTER) == 0) &&
 4885                                     (np->in_odport != fin->fin_data[1]))
 4886                                         continue;
 4887                                 if (ipf_proxy_ok(fin, tcp, np) == 0)
 4888                                         continue;
 4889                         }
 4890 
 4891                         if (np->in_flags & IPN_NO) {
 4892                                 np->in_hits++;
 4893                                 break;
 4894                         }
 4895                         MUTEX_ENTER(&softn->ipf_nat_new);
 4896                         /*
 4897                          * If we've matched a round-robin rule but it has
 4898                          * moved in the list since we got it, start over as
 4899                          * this is now no longer correct.
 4900                          */
 4901                         if (npnext != np->in_mnext) {
 4902                                 if ((np->in_flags & IPN_ROUNDR) != 0) {
 4903                                         MUTEX_EXIT(&softn->ipf_nat_new);
 4904                                         goto retry_roundrobin;
 4905                                 }
 4906                                 npnext = np->in_mnext;
 4907                         }
 4908 
 4909                         nat = ipf_nat_add(fin, np, NULL, nflags, NAT_OUTBOUND);
 4910                         MUTEX_EXIT(&softn->ipf_nat_new);
 4911                         if (nat != NULL) {
 4912                                 natfailed = 0;
 4913                                 break;
 4914                         }
 4915                         natfailed = -2;
 4916                 }
 4917                 if ((np == NULL) && (nmsk < softn->ipf_nat_map_max)) {
 4918                         nmsk++;
 4919                         goto maskloop;
 4920                 }
 4921         }
 4922 
 4923         if (nat != NULL) {
 4924                 rval = ipf_nat_out(fin, nat, natadd, nflags);
 4925                 if (rval == 1) {
 4926                         MUTEX_ENTER(&nat->nat_lock);
 4927                         ipf_nat_update(fin, nat);
 4928                         nat->nat_bytes[1] += fin->fin_plen;
 4929                         nat->nat_pkts[1]++;
 4930                         fin->fin_pktnum = nat->nat_pkts[1];
 4931                         MUTEX_EXIT(&nat->nat_lock);
 4932                 }
 4933         } else
 4934                 rval = natfailed;
 4935 outmatchfail:
 4936         RWLOCK_EXIT(&softc->ipf_nat);
 4937 
 4938         switch (rval)
 4939         {
 4940         case -3 :
 4941                 /* ipf_nat_match() failure */
 4942                 /* FALLTHROUGH */
 4943         case -2 :
 4944                 /* retry_roundrobin loop failure */
 4945                 /* FALLTHROUGH */
 4946         case -1 :
 4947                 /* proxy failure detected by ipf_nat_out() */
 4948                 if (passp != NULL) {
 4949                         DT2(frb_natv4out, fr_info_t *, fin, int, rval);
 4950                         NBUMPSIDED(1, ns_drop);
 4951                         *passp = FR_BLOCK;
 4952                         fin->fin_reason = FRB_NATV4;
 4953                 }
 4954                 fin->fin_flx |= FI_BADNAT;
 4955                 NBUMPSIDED(1, ns_badnat);
 4956                 rval = -1;      /* We only return -1 on error. */
 4957                 break;
 4958         case 0 :
 4959                 NBUMPSIDE(1, ns_ignored);
 4960                 break;
 4961         case 1 :
 4962                 NBUMPSIDE(1, ns_translated);
 4963                 break;
 4964         }
 4965         fin->fin_ifp = sifp;
 4966         return (rval);
 4967 }
 4968 
 4969 /* ------------------------------------------------------------------------ */
 4970 /* Function:    ipf_nat_out                                                 */
 4971 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
 4972 /*                     1 == packet was successfully translated.             */
 4973 /* Parameters:  fin(I)    - pointer to packet information                   */
 4974 /*              nat(I)    - pointer to NAT structure                        */
 4975 /*              natadd(I) - flag indicating if it is safe to add frag cache */
 4976 /*              nflags(I) - NAT flags set for this packet                   */
 4977 /*                                                                          */
 4978 /* Translate a packet coming "out" on an interface.                         */
 4979 /* ------------------------------------------------------------------------ */
 4980 int
 4981 ipf_nat_out(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags)
 4982 {
 4983         ipf_main_softc_t *softc = fin->fin_main_soft;
 4984         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 4985         icmphdr_t *icmp;
 4986         tcphdr_t *tcp;
 4987         ipnat_t *np;
 4988         int skip;
 4989         int i;
 4990 
 4991         tcp = NULL;
 4992         icmp = NULL;
 4993         np = nat->nat_ptr;
 4994 
 4995         if ((natadd != 0) && (fin->fin_flx & FI_FRAG) && (np != NULL))
 4996                 (void) ipf_frag_natnew(softc, fin, 0, nat);
 4997 
 4998         /*
 4999          * Fix up checksums, not by recalculating them, but
 5000          * simply computing adjustments.
 5001          * This is only done for STREAMS based IP implementations where the
 5002          * checksum has already been calculated by IP.  In all other cases,
 5003          * IPFilter is called before the checksum needs calculating so there
 5004          * is no call to modify whatever is in the header now.
 5005          */
 5006         if (nflags == IPN_ICMPERR) {
 5007                 u_32_t s1, s2, sumd, msumd;
 5008 
 5009                 s1 = LONG_SUM(ntohl(fin->fin_saddr));
 5010                 if (nat->nat_dir == NAT_OUTBOUND) {
 5011                         s2 = LONG_SUM(ntohl(nat->nat_nsrcaddr));
 5012                 } else {
 5013                         s2 = LONG_SUM(ntohl(nat->nat_odstaddr));
 5014                 }
 5015                 CALC_SUMD(s1, s2, sumd);
 5016                 msumd = sumd;
 5017 
 5018                 s1 = LONG_SUM(ntohl(fin->fin_daddr));
 5019                 if (nat->nat_dir == NAT_OUTBOUND) {
 5020                         s2 = LONG_SUM(ntohl(nat->nat_ndstaddr));
 5021                 } else {
 5022                         s2 = LONG_SUM(ntohl(nat->nat_osrcaddr));
 5023                 }
 5024                 CALC_SUMD(s1, s2, sumd);
 5025                 msumd += sumd;
 5026 
 5027                 ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, msumd, 0);
 5028         }
 5029 #if !defined(_KERNEL) || SOLARIS || \
 5030     defined(BRIDGE_IPF) || defined(__FreeBSD__)
 5031         else {
 5032                 /*
 5033                  * We always do this on FreeBSD because this code doesn't
 5034                  * exist in fastforward.
 5035                  */
 5036                 switch (nat->nat_dir)
 5037                 {
 5038                 case NAT_OUTBOUND :
 5039                         ipf_fix_outcksum(fin->fin_cksum & FI_CK_L4PART,
 5040                                          &fin->fin_ip->ip_sum,
 5041                                          nat->nat_ipsumd, 0);
 5042                         break;
 5043 
 5044                 case NAT_INBOUND :
 5045                         ipf_fix_incksum(fin->fin_cksum & FI_CK_L4PART,
 5046                                         &fin->fin_ip->ip_sum,
 5047                                         nat->nat_ipsumd, 0);
 5048                         break;
 5049 
 5050                 default :
 5051                         break;
 5052                 }
 5053         }
 5054 #endif
 5055 
 5056         /*
 5057          * Address assignment is after the checksum modification because
 5058          * we are using the address in the packet for determining the
 5059          * correct checksum offset (the ICMP error could be coming from
 5060          * anyone...)
 5061          */
 5062         switch (nat->nat_dir)
 5063         {
 5064         case NAT_OUTBOUND :
 5065                 fin->fin_ip->ip_src = nat->nat_nsrcip;
 5066                 fin->fin_saddr = nat->nat_nsrcaddr;
 5067                 fin->fin_ip->ip_dst = nat->nat_ndstip;
 5068                 fin->fin_daddr = nat->nat_ndstaddr;
 5069                 break;
 5070 
 5071         case NAT_INBOUND :
 5072                 fin->fin_ip->ip_src = nat->nat_odstip;
 5073                 fin->fin_saddr = nat->nat_ndstaddr;
 5074                 fin->fin_ip->ip_dst = nat->nat_osrcip;
 5075                 fin->fin_daddr = nat->nat_nsrcaddr;
 5076                 break;
 5077 
 5078         case NAT_DIVERTIN :
 5079             {
 5080                 mb_t *m;
 5081 
 5082                 skip = ipf_nat_decap(fin, nat);
 5083                 if (skip <= 0) {
 5084                         NBUMPSIDED(1, ns_decap_fail);
 5085                         return (-1);
 5086                 }
 5087 
 5088                 m = fin->fin_m;
 5089 
 5090 #if SOLARIS && defined(_KERNEL)
 5091                 m->b_rptr += skip;
 5092 #else
 5093                 m->m_data += skip;
 5094                 m->m_len -= skip;
 5095 
 5096 # ifdef M_PKTHDR
 5097                 if (m->m_flags & M_PKTHDR)
 5098                         m->m_pkthdr.len -= skip;
 5099 # endif
 5100 #endif
 5101 
 5102                 MUTEX_ENTER(&nat->nat_lock);
 5103                 ipf_nat_update(fin, nat);
 5104                 MUTEX_EXIT(&nat->nat_lock);
 5105                 fin->fin_flx |= FI_NATED;
 5106                 if (np != NULL && np->in_tag.ipt_num[0] != 0)
 5107                         fin->fin_nattag = &np->in_tag;
 5108                 return (1);
 5109                 /* NOTREACHED */
 5110             }
 5111 
 5112         case NAT_DIVERTOUT :
 5113             {
 5114                 u_32_t s1, s2, sumd;
 5115                 udphdr_t *uh;
 5116                 ip_t *ip;
 5117                 mb_t *m;
 5118 
 5119                 m = M_DUP(np->in_divmp);
 5120                 if (m == NULL) {
 5121                         NBUMPSIDED(1, ns_divert_dup);
 5122                         return (-1);
 5123                 }
 5124 
 5125                 ip = MTOD(m, ip_t *);
 5126                 ip_fillid(ip);
 5127                 s2 = ntohs(ip->ip_id);
 5128 
 5129                 s1 = ip->ip_len;
 5130                 ip->ip_len = ntohs(ip->ip_len);
 5131                 ip->ip_len += fin->fin_plen;
 5132                 ip->ip_len = htons(ip->ip_len);
 5133                 s2 += ntohs(ip->ip_len);
 5134                 CALC_SUMD(s1, s2, sumd);
 5135 
 5136                 uh = (udphdr_t *)(ip + 1);
 5137                 uh->uh_ulen += fin->fin_plen;
 5138                 uh->uh_ulen = htons(uh->uh_ulen);
 5139 #if !defined(_KERNEL) || SOLARIS || \
 5140     defined(BRIDGE_IPF) || defined(__FreeBSD__)
 5141                 ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0);
 5142 #endif
 5143 
 5144                 PREP_MB_T(fin, m);
 5145 
 5146                 fin->fin_src = ip->ip_src;
 5147                 fin->fin_dst = ip->ip_dst;
 5148                 fin->fin_ip = ip;
 5149                 fin->fin_plen += sizeof(ip_t) + 8;      /* UDP + IPv4 hdr */
 5150                 fin->fin_dlen += sizeof(ip_t) + 8;      /* UDP + IPv4 hdr */
 5151 
 5152                 nflags &= ~IPN_TCPUDPICMP;
 5153 
 5154                 break;
 5155             }
 5156 
 5157         default :
 5158                 break;
 5159         }
 5160 
 5161         if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
 5162                 u_short *csump;
 5163 
 5164                 if ((nat->nat_nsport != 0) && (nflags & IPN_TCPUDP)) {
 5165                         tcp = fin->fin_dp;
 5166 
 5167                         switch (nat->nat_dir)
 5168                         {
 5169                         case NAT_OUTBOUND :
 5170                                 tcp->th_sport = nat->nat_nsport;
 5171                                 fin->fin_data[0] = ntohs(nat->nat_nsport);
 5172                                 tcp->th_dport = nat->nat_ndport;
 5173                                 fin->fin_data[1] = ntohs(nat->nat_ndport);
 5174                                 break;
 5175 
 5176                         case NAT_INBOUND :
 5177                                 tcp->th_sport = nat->nat_odport;
 5178                                 fin->fin_data[0] = ntohs(nat->nat_odport);
 5179                                 tcp->th_dport = nat->nat_osport;
 5180                                 fin->fin_data[1] = ntohs(nat->nat_osport);
 5181                                 break;
 5182                         }
 5183                 }
 5184 
 5185                 if ((nat->nat_nsport != 0) && (nflags & IPN_ICMPQUERY)) {
 5186                         icmp = fin->fin_dp;
 5187                         icmp->icmp_id = nat->nat_nicmpid;
 5188                 }
 5189 
 5190                 csump = ipf_nat_proto(fin, nat, nflags);
 5191 
 5192                 /*
 5193                  * The above comments do not hold for layer 4 (or higher)
 5194                  * checksums...
 5195                  */
 5196                 if (csump != NULL) {
 5197                         if (nat->nat_dir == NAT_OUTBOUND)
 5198                                 ipf_fix_outcksum(fin->fin_cksum, csump,
 5199                                                  nat->nat_sumd[0],
 5200                                                  nat->nat_sumd[1] +
 5201                                                  fin->fin_dlen);
 5202                         else
 5203                                 ipf_fix_incksum(fin->fin_cksum, csump,
 5204                                                 nat->nat_sumd[0],
 5205                                                 nat->nat_sumd[1] +
 5206                                                 fin->fin_dlen);
 5207                 }
 5208         }
 5209 
 5210         ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
 5211         /* ------------------------------------------------------------- */
 5212         /* A few quick notes:                                            */
 5213         /*      Following are test conditions prior to calling the       */
 5214         /*      ipf_proxy_check routine.                                 */
 5215         /*                                                               */
 5216         /*      A NULL tcp indicates a non TCP/UDP packet.  When dealing */
 5217         /*      with a redirect rule, we attempt to match the packet's   */
 5218         /*      source port against in_dport, otherwise we'd compare the */
 5219         /*      packet's destination.                                    */
 5220         /* ------------------------------------------------------------- */
 5221         if ((np != NULL) && (np->in_apr != NULL)) {
 5222                 i = ipf_proxy_check(fin, nat);
 5223                 if (i == -1) {
 5224                         NBUMPSIDED(1, ns_ipf_proxy_fail);
 5225                 }
 5226         } else {
 5227                 i = 1;
 5228         }
 5229         fin->fin_flx |= FI_NATED;
 5230         return (i);
 5231 }
 5232 
 5233 
 5234 /* ------------------------------------------------------------------------ */
 5235 /* Function:    ipf_nat_checkin                                             */
 5236 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
 5237 /*                     0 == no packet translation occurred,                 */
 5238 /*                     1 == packet was successfully translated.             */
 5239 /* Parameters:  fin(I)   - pointer to packet information                    */
 5240 /*              passp(I) - pointer to filtering result flags                */
 5241 /*                                                                          */
 5242 /* Check to see if an incoming packet should be changed.  ICMP packets are  */
 5243 /* first checked to see if they match an existing entry (if an error),      */
 5244 /* otherwise a search of the current NAT table is made.  If neither results */
 5245 /* in a match then a search for a matching NAT rule is made.  Create a new  */
 5246 /* NAT entry if a we matched a NAT rule.  Lastly, actually change the       */
 5247 /* packet header(s) as required.                                            */
 5248 /* ------------------------------------------------------------------------ */
 5249 int
 5250 ipf_nat_checkin(fr_info_t *fin, u_32_t *passp)
 5251 {
 5252         ipf_main_softc_t *softc;
 5253         ipf_nat_softc_t *softn;
 5254         u_int nflags, natadd;
 5255         ipnat_t *np, *npnext;
 5256         int rval, natfailed;
 5257         struct ifnet *ifp;
 5258         struct in_addr in;
 5259         icmphdr_t *icmp;
 5260         tcphdr_t *tcp;
 5261         u_short dport;
 5262         nat_t *nat;
 5263         u_32_t iph;
 5264 
 5265         softc = fin->fin_main_soft;
 5266         softn = softc->ipf_nat_soft;
 5267 
 5268         if (softn->ipf_nat_lock != 0)
 5269                 return (0);
 5270         if (softn->ipf_nat_stats.ns_rules == 0 &&
 5271             softn->ipf_nat_instances == NULL)
 5272                 return (0);
 5273 
 5274         tcp = NULL;
 5275         icmp = NULL;
 5276         dport = 0;
 5277         natadd = 1;
 5278         nflags = 0;
 5279         natfailed = 0;
 5280         ifp = fin->fin_ifp;
 5281 
 5282         if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
 5283                 switch (fin->fin_p)
 5284                 {
 5285                 case IPPROTO_TCP :
 5286                         nflags = IPN_TCP;
 5287                         break;
 5288                 case IPPROTO_UDP :
 5289                         nflags = IPN_UDP;
 5290                         break;
 5291                 case IPPROTO_ICMP :
 5292                         icmp = fin->fin_dp;
 5293 
 5294                         /*
 5295                          * This is an incoming packet, so the destination is
 5296                          * the icmp_id and the source port equals 0
 5297                          */
 5298                         if ((fin->fin_flx & FI_ICMPQUERY) != 0) {
 5299                                 nflags = IPN_ICMPQUERY;
 5300                                 dport = icmp->icmp_id;
 5301                         } break;
 5302                 default :
 5303                         break;
 5304                 }
 5305 
 5306                 if ((nflags & IPN_TCPUDP)) {
 5307                         tcp = fin->fin_dp;
 5308                         dport = fin->fin_data[1];
 5309                 }
 5310         }
 5311 
 5312         in = fin->fin_dst;
 5313 
 5314         READ_ENTER(&softc->ipf_nat);
 5315 
 5316         if ((fin->fin_p == IPPROTO_ICMP) && !(nflags & IPN_ICMPQUERY) &&
 5317             (nat = ipf_nat_icmperror(fin, &nflags, NAT_INBOUND)))
 5318                 /*EMPTY*/;
 5319         else if ((fin->fin_flx & FI_FRAG) && (nat = ipf_frag_natknown(fin)))
 5320                 natadd = 0;
 5321         else if ((nat = ipf_nat_inlookup(fin, nflags|NAT_SEARCH,
 5322                                          (u_int)fin->fin_p,
 5323                                          fin->fin_src, in))) {
 5324                 nflags = nat->nat_flags;
 5325         } else if (fin->fin_off == 0) {
 5326                 u_32_t hv, msk, rmsk = 0;
 5327 
 5328                 /*
 5329                  * If there is no current entry in the nat table for this IP#,
 5330                  * create one for it (if there is a matching rule).
 5331                  */
 5332 maskloop:
 5333                 msk = softn->ipf_nat_rdr_active_masks[rmsk];
 5334                 iph = in.s_addr & msk;
 5335                 hv = NAT_HASH_FN(iph, 0, softn->ipf_nat_rdrrules_sz);
 5336 retry_roundrobin:
 5337                 /* TRACE (iph,msk,rmsk,hv,softn->ipf_nat_rdrrules_sz) */
 5338                 for (np = softn->ipf_nat_rdr_rules[hv]; np; np = npnext) {
 5339                         npnext = np->in_rnext;
 5340                         if (np->in_ifps[0] && (np->in_ifps[0] != ifp))
 5341                                 continue;
 5342                         if (np->in_v[0] != 4)
 5343                                 continue;
 5344                         if (np->in_pr[0] && (np->in_pr[0] != fin->fin_p))
 5345                                 continue;
 5346                         if ((np->in_flags & IPN_RF) && !(np->in_flags & nflags))
 5347                                 continue;
 5348                         if (np->in_flags & IPN_FILTER) {
 5349                                 switch (ipf_nat_match(fin, np))
 5350                                 {
 5351                                 case 0 :
 5352                                         continue;
 5353                                 case -1 :
 5354                                         rval = -3;
 5355                                         goto inmatchfail;
 5356                                 case 1 :
 5357                                 default :
 5358                                         break;
 5359                                 }
 5360                         } else {
 5361                                 if ((in.s_addr & np->in_odstmsk) !=
 5362                                     np->in_odstaddr)
 5363                                         continue;
 5364                                 if (np->in_odport &&
 5365                                     ((np->in_dtop < dport) ||
 5366                                      (dport < np->in_odport)))
 5367                                         continue;
 5368                         }
 5369 
 5370                         if (np->in_plabel != -1) {
 5371                                 if (!ipf_proxy_ok(fin, tcp, np)) {
 5372                                         continue;
 5373                                 }
 5374                         }
 5375 
 5376                         if (np->in_flags & IPN_NO) {
 5377                                 np->in_hits++;
 5378                                 break;
 5379                         }
 5380 
 5381                         MUTEX_ENTER(&softn->ipf_nat_new);
 5382                         /*
 5383                          * If we've matched a round-robin rule but it has
 5384                          * moved in the list since we got it, start over as
 5385                          * this is now no longer correct.
 5386                          */
 5387                         if (npnext != np->in_rnext) {
 5388                                 if ((np->in_flags & IPN_ROUNDR) != 0) {
 5389                                         MUTEX_EXIT(&softn->ipf_nat_new);
 5390                                         goto retry_roundrobin;
 5391                                 }
 5392                                 npnext = np->in_rnext;
 5393                         }
 5394 
 5395                         nat = ipf_nat_add(fin, np, NULL, nflags, NAT_INBOUND);
 5396                         MUTEX_EXIT(&softn->ipf_nat_new);
 5397                         if (nat != NULL) {
 5398                                 natfailed = 0;
 5399                                 break;
 5400                         }
 5401                         natfailed = -2;
 5402                 }
 5403                 if ((np == NULL) && (rmsk < softn->ipf_nat_rdr_max)) {
 5404                         rmsk++;
 5405                         goto maskloop;
 5406                 }
 5407         }
 5408 
 5409         if (nat != NULL) {
 5410                 rval = ipf_nat_in(fin, nat, natadd, nflags);
 5411                 if (rval == 1) {
 5412                         MUTEX_ENTER(&nat->nat_lock);
 5413                         ipf_nat_update(fin, nat);
 5414                         nat->nat_bytes[0] += fin->fin_plen;
 5415                         nat->nat_pkts[0]++;
 5416                         fin->fin_pktnum = nat->nat_pkts[0];
 5417                         MUTEX_EXIT(&nat->nat_lock);
 5418                 }
 5419         } else
 5420                 rval = natfailed;
 5421 inmatchfail:
 5422         RWLOCK_EXIT(&softc->ipf_nat);
 5423 
 5424         DT2(frb_natv4in, fr_info_t *, fin, int, rval);
 5425         switch (rval)
 5426         {
 5427         case -3 :
 5428                 /* ipf_nat_match() failure */
 5429                 /* FALLTHROUGH */
 5430         case -2 :
 5431                 /* retry_roundrobin loop failure */
 5432                 /* FALLTHROUGH */
 5433         case -1 :
 5434                 /* proxy failure detected by ipf_nat_in() */
 5435                 if (passp != NULL) {
 5436                         NBUMPSIDED(0, ns_drop);
 5437                         *passp = FR_BLOCK;
 5438                         fin->fin_reason = FRB_NATV4;
 5439                 }
 5440                 fin->fin_flx |= FI_BADNAT;
 5441                 NBUMPSIDED(0, ns_badnat);
 5442                 rval = -1;      /* We only return -1 on error. */
 5443                 break;
 5444         case 0 :
 5445                 NBUMPSIDE(0, ns_ignored);
 5446                 break;
 5447         case 1 :
 5448                 NBUMPSIDE(0, ns_translated);
 5449                 break;
 5450         }
 5451         return (rval);
 5452 }
 5453 
 5454 
 5455 /* ------------------------------------------------------------------------ */
 5456 /* Function:    ipf_nat_in                                                  */
 5457 /* Returns:     int - -1 == packet failed NAT checks so block it,           */
 5458 /*                     1 == packet was successfully translated.             */
 5459 /* Parameters:  fin(I)    - pointer to packet information                   */
 5460 /*              nat(I)    - pointer to NAT structure                        */
 5461 /*              natadd(I) - flag indicating if it is safe to add frag cache */
 5462 /*              nflags(I) - NAT flags set for this packet                   */
 5463 /* Locks Held:  ipf_nat(READ)                                               */
 5464 /*                                                                          */
 5465 /* Translate a packet coming "in" on an interface.                          */
 5466 /* ------------------------------------------------------------------------ */
 5467 int
 5468 ipf_nat_in(fr_info_t *fin, nat_t *nat, int natadd, u_32_t nflags)
 5469 {
 5470         ipf_main_softc_t *softc = fin->fin_main_soft;
 5471         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 5472         u_32_t sumd, ipsumd, sum1, sum2;
 5473         icmphdr_t *icmp;
 5474         tcphdr_t *tcp;
 5475         ipnat_t *np;
 5476         int skip;
 5477         int i;
 5478 
 5479         tcp = NULL;
 5480         np = nat->nat_ptr;
 5481         fin->fin_fr = nat->nat_fr;
 5482 
 5483         if (np != NULL) {
 5484                 if ((natadd != 0) && (fin->fin_flx & FI_FRAG))
 5485                         (void) ipf_frag_natnew(softc, fin, 0, nat);
 5486 
 5487         /* ------------------------------------------------------------- */
 5488         /* A few quick notes:                                            */
 5489         /*      Following are test conditions prior to calling the       */
 5490         /*      ipf_proxy_check routine.                                 */
 5491         /*                                                               */
 5492         /*      A NULL tcp indicates a non TCP/UDP packet.  When dealing */
 5493         /*      with a map rule, we attempt to match the packet's        */
 5494         /*      source port against in_dport, otherwise we'd compare the */
 5495         /*      packet's destination.                                    */
 5496         /* ------------------------------------------------------------- */
 5497                 if (np->in_apr != NULL) {
 5498                         i = ipf_proxy_check(fin, nat);
 5499                         if (i == -1) {
 5500                                 NBUMPSIDED(0, ns_ipf_proxy_fail);
 5501                                 return (-1);
 5502                         }
 5503                 }
 5504         }
 5505 
 5506         ipf_sync_update(softc, SMC_NAT, fin, nat->nat_sync);
 5507 
 5508         ipsumd = nat->nat_ipsumd;
 5509         /*
 5510          * Fix up checksums, not by recalculating them, but
 5511          * simply computing adjustments.
 5512          * Why only do this for some platforms on inbound packets ?
 5513          * Because for those that it is done, IP processing is yet to happen
 5514          * and so the IPv4 header checksum has not yet been evaluated.
 5515          * Perhaps it should always be done for the benefit of things like
 5516          * fast forwarding (so that it doesn't need to be recomputed) but with
 5517          * header checksum offloading, perhaps it is a moot point.
 5518          */
 5519 
 5520         switch (nat->nat_dir)
 5521         {
 5522         case NAT_INBOUND :
 5523                 if ((fin->fin_flx & FI_ICMPERR) == 0) {
 5524                         fin->fin_ip->ip_src = nat->nat_nsrcip;
 5525                         fin->fin_saddr = nat->nat_nsrcaddr;
 5526                 } else {
 5527                         sum1 = nat->nat_osrcaddr;
 5528                         sum2 = nat->nat_nsrcaddr;
 5529                         CALC_SUMD(sum1, sum2, sumd);
 5530                         ipsumd -= sumd;
 5531                 }
 5532                 fin->fin_ip->ip_dst = nat->nat_ndstip;
 5533                 fin->fin_daddr = nat->nat_ndstaddr;
 5534 #if !defined(_KERNEL) || SOLARIS
 5535                 ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, ipsumd, 0);
 5536 #endif
 5537                 break;
 5538 
 5539         case NAT_OUTBOUND :
 5540                 if ((fin->fin_flx & FI_ICMPERR) == 0) {
 5541                         fin->fin_ip->ip_src = nat->nat_odstip;
 5542                         fin->fin_saddr = nat->nat_odstaddr;
 5543                 } else {
 5544                         sum1 = nat->nat_odstaddr;
 5545                         sum2 = nat->nat_ndstaddr;
 5546                         CALC_SUMD(sum1, sum2, sumd);
 5547                         ipsumd -= sumd;
 5548                 }
 5549                 fin->fin_ip->ip_dst = nat->nat_osrcip;
 5550                 fin->fin_daddr = nat->nat_osrcaddr;
 5551 #if !defined(_KERNEL) || SOLARIS
 5552                 ipf_fix_incksum(0, &fin->fin_ip->ip_sum, ipsumd, 0);
 5553 #endif
 5554                 break;
 5555 
 5556         case NAT_DIVERTIN :
 5557             {
 5558                 udphdr_t *uh;
 5559                 ip_t *ip;
 5560                 mb_t *m;
 5561 
 5562                 m = M_DUP(np->in_divmp);
 5563                 if (m == NULL) {
 5564                         NBUMPSIDED(0, ns_divert_dup);
 5565                         return (-1);
 5566                 }
 5567 
 5568                 ip = MTOD(m, ip_t *);
 5569                 ip_fillid(ip);
 5570                 sum1 = ntohs(ip->ip_len);
 5571                 ip->ip_len = ntohs(ip->ip_len);
 5572                 ip->ip_len += fin->fin_plen;
 5573                 ip->ip_len = htons(ip->ip_len);
 5574 
 5575                 uh = (udphdr_t *)(ip + 1);
 5576                 uh->uh_ulen += fin->fin_plen;
 5577                 uh->uh_ulen = htons(uh->uh_ulen);
 5578 
 5579                 sum2 = ntohs(ip->ip_id) + ntohs(ip->ip_len);
 5580                 sum2 += ntohs(ip->ip_off) & IP_DF;
 5581                 CALC_SUMD(sum1, sum2, sumd);
 5582 
 5583 #if !defined(_KERNEL) || SOLARIS
 5584                 ipf_fix_outcksum(0, &ip->ip_sum, sumd, 0);
 5585 #endif
 5586                 PREP_MB_T(fin, m);
 5587 
 5588                 fin->fin_ip = ip;
 5589                 fin->fin_plen += sizeof(ip_t) + 8;      /* UDP + new IPv4 hdr */
 5590                 fin->fin_dlen += sizeof(ip_t) + 8;      /* UDP + old IPv4 hdr */
 5591 
 5592                 nflags &= ~IPN_TCPUDPICMP;
 5593 
 5594                 break;
 5595             }
 5596 
 5597         case NAT_DIVERTOUT :
 5598             {
 5599                 mb_t *m;
 5600 
 5601                 skip = ipf_nat_decap(fin, nat);
 5602                 if (skip <= 0) {
 5603                         NBUMPSIDED(0, ns_decap_fail);
 5604                         return (-1);
 5605                 }
 5606 
 5607                 m = fin->fin_m;
 5608 
 5609 #if SOLARIS && defined(_KERNEL)
 5610                 m->b_rptr += skip;
 5611 #else
 5612                 m->m_data += skip;
 5613                 m->m_len -= skip;
 5614 
 5615 # ifdef M_PKTHDR
 5616                 if (m->m_flags & M_PKTHDR)
 5617                         m->m_pkthdr.len -= skip;
 5618 # endif
 5619 #endif
 5620 
 5621                 ipf_nat_update(fin, nat);
 5622                 nflags &= ~IPN_TCPUDPICMP;
 5623                 fin->fin_flx |= FI_NATED;
 5624                 if (np != NULL && np->in_tag.ipt_num[0] != 0)
 5625                         fin->fin_nattag = &np->in_tag;
 5626                 return (1);
 5627                 /* NOTREACHED */
 5628             }
 5629         }
 5630         if (nflags & IPN_TCPUDP)
 5631                 tcp = fin->fin_dp;
 5632 
 5633         if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) {
 5634                 u_short *csump;
 5635 
 5636                 if ((nat->nat_odport != 0) && (nflags & IPN_TCPUDP)) {
 5637                         switch (nat->nat_dir)
 5638                         {
 5639                         case NAT_INBOUND :
 5640                                 tcp->th_sport = nat->nat_nsport;
 5641                                 fin->fin_data[0] = ntohs(nat->nat_nsport);
 5642                                 tcp->th_dport = nat->nat_ndport;
 5643                                 fin->fin_data[1] = ntohs(nat->nat_ndport);
 5644                                 break;
 5645 
 5646                         case NAT_OUTBOUND :
 5647                                 tcp->th_sport = nat->nat_odport;
 5648                                 fin->fin_data[0] = ntohs(nat->nat_odport);
 5649                                 tcp->th_dport = nat->nat_osport;
 5650                                 fin->fin_data[1] = ntohs(nat->nat_osport);
 5651                                 break;
 5652                         }
 5653                 }
 5654 
 5655 
 5656                 if ((nat->nat_odport != 0) && (nflags & IPN_ICMPQUERY)) {
 5657                         icmp = fin->fin_dp;
 5658 
 5659                         icmp->icmp_id = nat->nat_nicmpid;
 5660                 }
 5661 
 5662                 csump = ipf_nat_proto(fin, nat, nflags);
 5663 
 5664                 /*
 5665                  * The above comments do not hold for layer 4 (or higher)
 5666                  * checksums...
 5667                  */
 5668                 if (csump != NULL) {
 5669                         if (nat->nat_dir == NAT_OUTBOUND)
 5670                                 ipf_fix_incksum(0, csump, nat->nat_sumd[0], 0);
 5671                         else
 5672                                 ipf_fix_outcksum(0, csump, nat->nat_sumd[0], 0);
 5673                 }
 5674         }
 5675 
 5676         fin->fin_flx |= FI_NATED;
 5677         if (np != NULL && np->in_tag.ipt_num[0] != 0)
 5678                 fin->fin_nattag = &np->in_tag;
 5679         return (1);
 5680 }
 5681 
 5682 
 5683 /* ------------------------------------------------------------------------ */
 5684 /* Function:    ipf_nat_proto                                               */
 5685 /* Returns:     u_short* - pointer to transport header checksum to update,  */
 5686 /*                         NULL if the transport protocol is not recognised */
 5687 /*                         as needing a checksum update.                    */
 5688 /* Parameters:  fin(I)    - pointer to packet information                   */
 5689 /*              nat(I)    - pointer to NAT structure                        */
 5690 /*              nflags(I) - NAT flags set for this packet                   */
 5691 /*                                                                          */
 5692 /* Return the pointer to the checksum field for each protocol so understood.*/
 5693 /* If support for making other changes to a protocol header is required,    */
 5694 /* that is not strictly 'address' translation, such as clamping the MSS in  */
 5695 /* TCP down to a specific value, then do it from here.                      */
 5696 /* ------------------------------------------------------------------------ */
 5697 u_short *
 5698 ipf_nat_proto(fr_info_t *fin, nat_t *nat, u_int nflags)
 5699 {
 5700         icmphdr_t *icmp;
 5701         u_short *csump;
 5702         tcphdr_t *tcp;
 5703         udphdr_t *udp;
 5704 
 5705         csump = NULL;
 5706         if (fin->fin_out == 0) {
 5707                 fin->fin_rev = (nat->nat_dir & NAT_OUTBOUND);
 5708         } else {
 5709                 fin->fin_rev = ((nat->nat_dir & NAT_OUTBOUND) == 0);
 5710         }
 5711 
 5712         switch (fin->fin_p)
 5713         {
 5714         case IPPROTO_TCP :
 5715                 tcp = fin->fin_dp;
 5716 
 5717                 if ((nflags & IPN_TCP) != 0)
 5718                         csump = &tcp->th_sum;
 5719 
 5720                 /*
 5721                  * Do a MSS CLAMPING on a SYN packet,
 5722                  * only deal IPv4 for now.
 5723                  */
 5724                 if ((nat->nat_mssclamp != 0) && (tcp->th_flags & TH_SYN) != 0)
 5725                         ipf_nat_mssclamp(tcp, nat->nat_mssclamp, fin, csump);
 5726 
 5727                 break;
 5728 
 5729         case IPPROTO_UDP :
 5730                 udp = fin->fin_dp;
 5731 
 5732                 if ((nflags & IPN_UDP) != 0) {
 5733                         if (udp->uh_sum != 0)
 5734                                 csump = &udp->uh_sum;
 5735                 }
 5736                 break;
 5737 
 5738         case IPPROTO_ICMP :
 5739                 icmp = fin->fin_dp;
 5740 
 5741                 if ((nflags & IPN_ICMPQUERY) != 0) {
 5742                         if (icmp->icmp_cksum != 0)
 5743                                 csump = &icmp->icmp_cksum;
 5744                 }
 5745                 break;
 5746 
 5747 #ifdef USE_INET6
 5748         case IPPROTO_ICMPV6 :
 5749             {
 5750                 struct icmp6_hdr *icmp6 = (struct icmp6_hdr *)fin->fin_dp;
 5751 
 5752                 icmp6 = fin->fin_dp;
 5753 
 5754                 if ((nflags & IPN_ICMPQUERY) != 0) {
 5755                         if (icmp6->icmp6_cksum != 0)
 5756                                 csump = &icmp6->icmp6_cksum;
 5757                 }
 5758                 break;
 5759             }
 5760 #endif
 5761         }
 5762         return (csump);
 5763 }
 5764 
 5765 
 5766 /* ------------------------------------------------------------------------ */
 5767 /* Function:    ipf_nat_expire                                              */
 5768 /* Returns:     Nil                                                         */
 5769 /* Parameters:  softc(I) - pointer to soft context main structure           */
 5770 /*                                                                          */
 5771 /* Check all of the timeout queues for entries at the top which need to be  */
 5772 /* expired.                                                                 */
 5773 /* ------------------------------------------------------------------------ */
 5774 void
 5775 ipf_nat_expire(ipf_main_softc_t *softc)
 5776 {
 5777         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 5778         ipftq_t *ifq, *ifqnext;
 5779         ipftqent_t *tqe, *tqn;
 5780         int i;
 5781         SPL_INT(s);
 5782 
 5783         SPL_NET(s);
 5784         WRITE_ENTER(&softc->ipf_nat);
 5785         for (ifq = softn->ipf_nat_tcptq, i = 0; ifq != NULL;
 5786              ifq = ifq->ifq_next) {
 5787                 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) {
 5788                         if (tqe->tqe_die > softc->ipf_ticks)
 5789                                 break;
 5790                         tqn = tqe->tqe_next;
 5791                         ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE);
 5792                 }
 5793         }
 5794 
 5795         for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifq->ifq_next) {
 5796                 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); i++) {
 5797                         if (tqe->tqe_die > softc->ipf_ticks)
 5798                                 break;
 5799                         tqn = tqe->tqe_next;
 5800                         ipf_nat_delete(softc, tqe->tqe_parent, NL_EXPIRE);
 5801                 }
 5802         }
 5803 
 5804         for (ifq = softn->ipf_nat_utqe; ifq != NULL; ifq = ifqnext) {
 5805                 ifqnext = ifq->ifq_next;
 5806 
 5807                 if (((ifq->ifq_flags & IFQF_DELETE) != 0) &&
 5808                     (ifq->ifq_ref == 0)) {
 5809                         ipf_freetimeoutqueue(softc, ifq);
 5810                 }
 5811         }
 5812 
 5813         if (softn->ipf_nat_doflush != 0) {
 5814                 ipf_nat_extraflush(softc, softn, 2);
 5815                 softn->ipf_nat_doflush = 0;
 5816         }
 5817 
 5818         RWLOCK_EXIT(&softc->ipf_nat);
 5819         SPL_X(s);
 5820 }
 5821 
 5822 
 5823 /* ------------------------------------------------------------------------ */
 5824 /* Function:    ipf_nat_sync                                                */
 5825 /* Returns:     Nil                                                         */
 5826 /* Parameters:  softc(I) - pointer to soft context main structure           */
 5827 /*              ifp(I) - pointer to network interface                       */
 5828 /*                                                                          */
 5829 /* Walk through all of the currently active NAT sessions, looking for those */
 5830 /* which need to have their translated address updated.                     */
 5831 /* ------------------------------------------------------------------------ */
 5832 void
 5833 ipf_nat_sync(ipf_main_softc_t *softc, void *ifp)
 5834 {
 5835         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 5836         u_32_t sum1, sum2, sumd;
 5837         i6addr_t in;
 5838         ipnat_t *n;
 5839         nat_t *nat;
 5840         void *ifp2;
 5841         int idx;
 5842         SPL_INT(s);
 5843 
 5844         if (softc->ipf_running <= 0)
 5845                 return;
 5846 
 5847         /*
 5848          * Change IP addresses for NAT sessions for any protocol except TCP
 5849          * since it will break the TCP connection anyway.  The only rules
 5850          * which will get changed are those which are "map ... -> 0/32",
 5851          * where the rule specifies the address is taken from the interface.
 5852          */
 5853         SPL_NET(s);
 5854         WRITE_ENTER(&softc->ipf_nat);
 5855 
 5856         if (softc->ipf_running <= 0) {
 5857                 RWLOCK_EXIT(&softc->ipf_nat);
 5858                 return;
 5859         }
 5860 
 5861         for (nat = softn->ipf_nat_instances; nat; nat = nat->nat_next) {
 5862                 if ((nat->nat_flags & IPN_TCP) != 0)
 5863                         continue;
 5864 
 5865                 n = nat->nat_ptr;
 5866                 if (n != NULL) {
 5867                         if (n->in_v[1] == 4) {
 5868                                 if (n->in_redir & NAT_MAP) {
 5869                                         if ((n->in_nsrcaddr != 0) ||
 5870                                             (n->in_nsrcmsk != 0xffffffff))
 5871                                                 continue;
 5872                                 } else if (n->in_redir & NAT_REDIRECT) {
 5873                                         if ((n->in_ndstaddr != 0) ||
 5874                                             (n->in_ndstmsk != 0xffffffff))
 5875                                                 continue;
 5876                                 }
 5877                         }
 5878 #ifdef USE_INET6
 5879                         if (n->in_v[1] == 4) {
 5880                                 if (n->in_redir & NAT_MAP) {
 5881                                         if (!IP6_ISZERO(&n->in_nsrcaddr) ||
 5882                                             !IP6_ISONES(&n->in_nsrcmsk))
 5883                                                 continue;
 5884                                 } else if (n->in_redir & NAT_REDIRECT) {
 5885                                         if (!IP6_ISZERO(&n->in_ndstaddr) ||
 5886                                             !IP6_ISONES(&n->in_ndstmsk))
 5887                                                 continue;
 5888                                 }
 5889                         }
 5890 #endif
 5891                 }
 5892 
 5893                 if (((ifp == NULL) || (ifp == nat->nat_ifps[0]) ||
 5894                      (ifp == nat->nat_ifps[1]))) {
 5895                         nat->nat_ifps[0] = GETIFP(nat->nat_ifnames[0],
 5896                                                   nat->nat_v[0]);
 5897                         if ((nat->nat_ifps[0] != NULL) &&
 5898                             (nat->nat_ifps[0] != (void *)-1)) {
 5899                                 nat->nat_mtu[0] = GETIFMTU_4(nat->nat_ifps[0]);
 5900                         }
 5901                         if (nat->nat_ifnames[1][0] != '\0') {
 5902                                 nat->nat_ifps[1] = GETIFP(nat->nat_ifnames[1],
 5903                                                           nat->nat_v[1]);
 5904                         } else {
 5905                                 nat->nat_ifps[1] = nat->nat_ifps[0];
 5906                         }
 5907                         if ((nat->nat_ifps[1] != NULL) &&
 5908                             (nat->nat_ifps[1] != (void *)-1)) {
 5909                                 nat->nat_mtu[1] = GETIFMTU_4(nat->nat_ifps[1]);
 5910                         }
 5911                         ifp2 = nat->nat_ifps[0];
 5912                         if (ifp2 == NULL)
 5913                                 continue;
 5914 
 5915                         /*
 5916                          * Change the map-to address to be the same as the
 5917                          * new one.
 5918                          */
 5919                         sum1 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6);
 5920                         if (ipf_ifpaddr(softc, nat->nat_v[0], FRI_NORMAL, ifp2,
 5921                                        &in, NULL) != -1) {
 5922                                 if (nat->nat_v[0] == 4)
 5923                                         nat->nat_nsrcip = in.in4;
 5924                         }
 5925                         sum2 = NATFSUM(nat, nat->nat_v[1], nat_nsrc6);
 5926 
 5927                         if (sum1 == sum2)
 5928                                 continue;
 5929                         /*
 5930                          * Readjust the checksum adjustment to take into
 5931                          * account the new IP#.
 5932                          */
 5933                         CALC_SUMD(sum1, sum2, sumd);
 5934                         /* XXX - dont change for TCP when solaris does
 5935                          * hardware checksumming.
 5936                          */
 5937                         sumd += nat->nat_sumd[0];
 5938                         nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
 5939                         nat->nat_sumd[1] = nat->nat_sumd[0];
 5940                 }
 5941         }
 5942 
 5943         for (n = softn->ipf_nat_list; (n != NULL); n = n->in_next) {
 5944                 char *base = n->in_names;
 5945 
 5946                 if ((ifp == NULL) || (n->in_ifps[0] == ifp))
 5947                         n->in_ifps[0] = ipf_resolvenic(softc,
 5948                                                        base + n->in_ifnames[0],
 5949                                                        n->in_v[0]);
 5950                 if ((ifp == NULL) || (n->in_ifps[1] == ifp))
 5951                         n->in_ifps[1] = ipf_resolvenic(softc,
 5952                                                        base + n->in_ifnames[1],
 5953                                                        n->in_v[1]);
 5954 
 5955                 if (n->in_redir & NAT_REDIRECT)
 5956                         idx = 1;
 5957                 else
 5958                         idx = 0;
 5959 
 5960                 if (((ifp == NULL) || (n->in_ifps[idx] == ifp)) &&
 5961                     (n->in_ifps[idx] != NULL &&
 5962                      n->in_ifps[idx] != (void *)-1)) {
 5963 
 5964                         ipf_nat_nextaddrinit(softc, n->in_names, &n->in_osrc,
 5965                                              0, n->in_ifps[idx]);
 5966                         ipf_nat_nextaddrinit(softc, n->in_names, &n->in_odst,
 5967                                              0, n->in_ifps[idx]);
 5968                         ipf_nat_nextaddrinit(softc, n->in_names, &n->in_nsrc,
 5969                                              0, n->in_ifps[idx]);
 5970                         ipf_nat_nextaddrinit(softc, n->in_names, &n->in_ndst,
 5971                                              0, n->in_ifps[idx]);
 5972                 }
 5973         }
 5974         RWLOCK_EXIT(&softc->ipf_nat);
 5975         SPL_X(s);
 5976 }
 5977 
 5978 
 5979 /* ------------------------------------------------------------------------ */
 5980 /* Function:    ipf_nat_icmpquerytype                                       */
 5981 /* Returns:     int - 1 == success, 0 == failure                            */
 5982 /* Parameters:  icmptype(I) - ICMP type number                              */
 5983 /*                                                                          */
 5984 /* Tests to see if the ICMP type number passed is a query/response type or  */
 5985 /* not.                                                                     */
 5986 /* ------------------------------------------------------------------------ */
 5987 static int
 5988 ipf_nat_icmpquerytype(int icmptype)
 5989 {
 5990 
 5991         /*
 5992          * For the ICMP query NAT code, it is essential that both the query
 5993          * and the reply match on the NAT rule. Because the NAT structure
 5994          * does not keep track of the icmptype, and a single NAT structure
 5995          * is used for all icmp types with the same src, dest and id, we
 5996          * simply define the replies as queries as well. The funny thing is,
 5997          * altough it seems silly to call a reply a query, this is exactly
 5998          * as it is defined in the IPv4 specification
 5999          */
 6000         switch (icmptype)
 6001         {
 6002         case ICMP_ECHOREPLY:
 6003         case ICMP_ECHO:
 6004         /* route advertisement/solicitation is currently unsupported: */
 6005         /* it would require rewriting the ICMP data section          */
 6006         case ICMP_TSTAMP:
 6007         case ICMP_TSTAMPREPLY:
 6008         case ICMP_IREQ:
 6009         case ICMP_IREQREPLY:
 6010         case ICMP_MASKREQ:
 6011         case ICMP_MASKREPLY:
 6012                 return (1);
 6013         default:
 6014                 return (0);
 6015         }
 6016 }
 6017 
 6018 
 6019 /* ------------------------------------------------------------------------ */
 6020 /* Function:    nat_log                                                     */
 6021 /* Returns:     Nil                                                         */
 6022 /* Parameters:  softc(I) - pointer to soft context main structure           */
 6023 /*              softn(I) - pointer to NAT context structure                 */
 6024 /*              nat(I)    - pointer to NAT structure                        */
 6025 /*              action(I) - action related to NAT structure being performed */
 6026 /*                                                                          */
 6027 /* Creates a NAT log entry.                                                 */
 6028 /* ------------------------------------------------------------------------ */
 6029 void
 6030 ipf_nat_log(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, struct nat *nat,
 6031         u_int action)
 6032 {
 6033 #ifdef  IPFILTER_LOG
 6034         struct ipnat *np;
 6035         int rulen;
 6036         struct natlog natl;
 6037         void *items[1];
 6038         size_t sizes[1];
 6039         int types[1];
 6040 
 6041         bcopy((char *)&nat->nat_osrc6, (char *)&natl.nl_osrcip,
 6042               sizeof(natl.nl_osrcip));
 6043         bcopy((char *)&nat->nat_nsrc6, (char *)&natl.nl_nsrcip,
 6044               sizeof(natl.nl_nsrcip));
 6045         bcopy((char *)&nat->nat_odst6, (char *)&natl.nl_odstip,
 6046               sizeof(natl.nl_odstip));
 6047         bcopy((char *)&nat->nat_ndst6, (char *)&natl.nl_ndstip,
 6048               sizeof(natl.nl_ndstip));
 6049 
 6050         natl.nl_bytes[0] = nat->nat_bytes[0];
 6051         natl.nl_bytes[1] = nat->nat_bytes[1];
 6052         natl.nl_pkts[0] = nat->nat_pkts[0];
 6053         natl.nl_pkts[1] = nat->nat_pkts[1];
 6054         natl.nl_odstport = nat->nat_odport;
 6055         natl.nl_osrcport = nat->nat_osport;
 6056         natl.nl_nsrcport = nat->nat_nsport;
 6057         natl.nl_ndstport = nat->nat_ndport;
 6058         natl.nl_p[0] = nat->nat_pr[0];
 6059         natl.nl_p[1] = nat->nat_pr[1];
 6060         natl.nl_v[0] = nat->nat_v[0];
 6061         natl.nl_v[1] = nat->nat_v[1];
 6062         natl.nl_type = nat->nat_redir;
 6063         natl.nl_action = action;
 6064         natl.nl_rule = -1;
 6065 
 6066         bcopy(nat->nat_ifnames[0], natl.nl_ifnames[0],
 6067               sizeof(nat->nat_ifnames[0]));
 6068         bcopy(nat->nat_ifnames[1], natl.nl_ifnames[1],
 6069               sizeof(nat->nat_ifnames[1]));
 6070 
 6071         if (softc->ipf_large_nat && nat->nat_ptr != NULL) {
 6072                 for (rulen = 0, np = softn->ipf_nat_list; np != NULL;
 6073                      np = np->in_next, rulen++)
 6074                         if (np == nat->nat_ptr) {
 6075                                 natl.nl_rule = rulen;
 6076                                 break;
 6077                         }
 6078         }
 6079         items[0] = &natl;
 6080         sizes[0] = sizeof(natl);
 6081         types[0] = 0;
 6082 
 6083         (void) ipf_log_items(softc, IPL_LOGNAT, NULL, items, sizes, types, 1);
 6084 #endif
 6085 }
 6086 
 6087 
 6088 
 6089 
 6090 /* ------------------------------------------------------------------------ */
 6091 /* Function:    ipf_nat_rule_deref                                          */
 6092 /* Returns:     Nil                                                         */
 6093 /* Parameters:  softc(I) - pointer to soft context main structure           */
 6094 /*              inp(I)   - pointer to pointer to NAT rule                   */
 6095 /* Write Locks: ipf_nat                                                     */
 6096 /*                                                                          */
 6097 /* Dropping the refernce count for a rule means that whatever held the      */
 6098 /* pointer to this rule (*inp) is no longer interested in it and when the   */
 6099 /* reference count drops to zero, any resources allocated for the rule can  */
 6100 /* be released and the rule itself free'd.                                  */
 6101 /* ------------------------------------------------------------------------ */
 6102 void
 6103 ipf_nat_rule_deref(ipf_main_softc_t *softc, ipnat_t **inp)
 6104 {
 6105         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 6106         ipnat_t *n;
 6107 
 6108         n = *inp;
 6109         *inp = NULL;
 6110         n->in_use--;
 6111         if (n->in_use > 0)
 6112                 return;
 6113 
 6114         if (n->in_apr != NULL)
 6115                 ipf_proxy_deref(n->in_apr);
 6116 
 6117         ipf_nat_rule_fini(softc, n);
 6118 
 6119         if (n->in_redir & NAT_REDIRECT) {
 6120                 if ((n->in_flags & IPN_PROXYRULE) == 0) {
 6121                         ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_rdr);
 6122                 }
 6123         }
 6124         if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) {
 6125                 if ((n->in_flags & IPN_PROXYRULE) == 0) {
 6126                         ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules_map);
 6127                 }
 6128         }
 6129 
 6130         if (n->in_tqehead[0] != NULL) {
 6131                 if (ipf_deletetimeoutqueue(n->in_tqehead[0]) == 0) {
 6132                         ipf_freetimeoutqueue(softc, n->in_tqehead[0]);
 6133                 }
 6134         }
 6135 
 6136         if (n->in_tqehead[1] != NULL) {
 6137                 if (ipf_deletetimeoutqueue(n->in_tqehead[1]) == 0) {
 6138                         ipf_freetimeoutqueue(softc, n->in_tqehead[1]);
 6139                 }
 6140         }
 6141 
 6142         if ((n->in_flags & IPN_PROXYRULE) == 0) {
 6143                 ATOMIC_DEC32(softn->ipf_nat_stats.ns_rules);
 6144         }
 6145 
 6146         MUTEX_DESTROY(&n->in_lock);
 6147 
 6148         KFREES(n, n->in_size);
 6149 
 6150 #if SOLARIS && !defined(INSTANCES)
 6151         if (softn->ipf_nat_stats.ns_rules == 0)
 6152                 pfil_delayed_copy = 1;
 6153 #endif
 6154 }
 6155 
 6156 
 6157 /* ------------------------------------------------------------------------ */
 6158 /* Function:    ipf_nat_deref                                               */
 6159 /* Returns:     Nil                                                         */
 6160 /* Parameters:  softc(I) - pointer to soft context main structure           */
 6161 /*              natp(I)  - pointer to pointer to NAT table entry            */
 6162 /*                                                                          */
 6163 /* Decrement the reference counter for this NAT table entry and free it if  */
 6164 /* there are no more things using it.                                       */
 6165 /*                                                                          */
 6166 /* IF nat_ref == 1 when this function is called, then we have an orphan nat */
 6167 /* structure *because* it only gets called on paths _after_ nat_ref has been*/
 6168 /* incremented.  If nat_ref == 1 then we shouldn't decrement it here        */
 6169 /* because nat_delete() will do that and send nat_ref to -1.                */
 6170 /*                                                                          */
 6171 /* Holding the lock on nat_lock is required to serialise nat_delete() being */
 6172 /* called from a NAT flush ioctl with a deref happening because of a packet.*/
 6173 /* ------------------------------------------------------------------------ */
 6174 void
 6175 ipf_nat_deref(ipf_main_softc_t *softc, nat_t **natp)
 6176 {
 6177         nat_t *nat;
 6178 
 6179         nat = *natp;
 6180         *natp = NULL;
 6181 
 6182         MUTEX_ENTER(&nat->nat_lock);
 6183         if (nat->nat_ref > 1) {
 6184                 nat->nat_ref--;
 6185                 ASSERT(nat->nat_ref >= 0);
 6186                 MUTEX_EXIT(&nat->nat_lock);
 6187                 return;
 6188         }
 6189         MUTEX_EXIT(&nat->nat_lock);
 6190 
 6191         WRITE_ENTER(&softc->ipf_nat);
 6192         ipf_nat_delete(softc, nat, NL_EXPIRE);
 6193         RWLOCK_EXIT(&softc->ipf_nat);
 6194 }
 6195 
 6196 
 6197 /* ------------------------------------------------------------------------ */
 6198 /* Function:    ipf_nat_clone                                               */
 6199 /* Returns:     ipstate_t* - NULL == cloning failed,                        */
 6200 /*                           else pointer to new state structure            */
 6201 /* Parameters:  fin(I) - pointer to packet information                      */
 6202 /*              is(I)  - pointer to master state structure                  */
 6203 /* Write Lock:  ipf_nat                                                     */
 6204 /*                                                                          */
 6205 /* Create a "duplcate" state table entry from the master.                   */
 6206 /* ------------------------------------------------------------------------ */
 6207 nat_t *
 6208 ipf_nat_clone(fr_info_t *fin, nat_t *nat)
 6209 {
 6210         ipf_main_softc_t *softc = fin->fin_main_soft;
 6211         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 6212         frentry_t *fr;
 6213         nat_t *clone;
 6214         ipnat_t *np;
 6215 
 6216         KMALLOC(clone, nat_t *);
 6217         if (clone == NULL) {
 6218                 NBUMPSIDED(fin->fin_out, ns_clone_nomem);
 6219                 return (NULL);
 6220         }
 6221         bcopy((char *)nat, (char *)clone, sizeof(*clone));
 6222 
 6223         MUTEX_NUKE(&clone->nat_lock);
 6224 
 6225         clone->nat_rev = fin->fin_rev;
 6226         clone->nat_aps = NULL;
 6227         /*
 6228          * Initialize all these so that ipf_nat_delete() doesn't cause a crash.
 6229          */
 6230         clone->nat_tqe.tqe_pnext = NULL;
 6231         clone->nat_tqe.tqe_next = NULL;
 6232         clone->nat_tqe.tqe_ifq = NULL;
 6233         clone->nat_tqe.tqe_parent = clone;
 6234 
 6235         clone->nat_flags &= ~SI_CLONE;
 6236         clone->nat_flags |= SI_CLONED;
 6237 
 6238         if (clone->nat_hm)
 6239                 clone->nat_hm->hm_ref++;
 6240 
 6241         if (ipf_nat_insert(softc, softn, clone) == -1) {
 6242                 KFREE(clone);
 6243                 NBUMPSIDED(fin->fin_out, ns_insert_fail);
 6244                 return (NULL);
 6245         }
 6246 
 6247         np = clone->nat_ptr;
 6248         if (np != NULL) {
 6249                 if (softn->ipf_nat_logging)
 6250                         ipf_nat_log(softc, softn, clone, NL_CLONE);
 6251                 np->in_use++;
 6252         }
 6253         fr = clone->nat_fr;
 6254         if (fr != NULL) {
 6255                 MUTEX_ENTER(&fr->fr_lock);
 6256                 fr->fr_ref++;
 6257                 MUTEX_EXIT(&fr->fr_lock);
 6258         }
 6259 
 6260 
 6261         /*
 6262          * Because the clone is created outside the normal loop of things and
 6263          * TCP has special needs in terms of state, initialise the timeout
 6264          * state of the new NAT from here.
 6265          */
 6266         if (clone->nat_pr[0] == IPPROTO_TCP) {
 6267                 (void) ipf_tcp_age(&clone->nat_tqe, fin, softn->ipf_nat_tcptq,
 6268                                    clone->nat_flags, 2);
 6269         }
 6270         clone->nat_sync = ipf_sync_new(softc, SMC_NAT, fin, clone);
 6271         if (softn->ipf_nat_logging)
 6272                 ipf_nat_log(softc, softn, clone, NL_CLONE);
 6273         return (clone);
 6274 }
 6275 
 6276 
 6277 /* ------------------------------------------------------------------------ */
 6278 /* Function:   ipf_nat_wildok                                               */
 6279 /* Returns:    int - 1 == packet's ports match wildcards                    */
 6280 /*                   0 == packet's ports don't match wildcards              */
 6281 /* Parameters: nat(I)   - NAT entry                                         */
 6282 /*             sport(I) - source port                                       */
 6283 /*             dport(I) - destination port                                  */
 6284 /*             flags(I) - wildcard flags                                    */
 6285 /*             dir(I)   - packet direction                                  */
 6286 /*                                                                          */
 6287 /* Use NAT entry and packet direction to determine which combination of     */
 6288 /* wildcard flags should be used.                                           */
 6289 /* ------------------------------------------------------------------------ */
 6290 int
 6291 ipf_nat_wildok(nat_t *nat, int sport, int dport, int flags, int dir)
 6292 {
 6293         /*
 6294          * When called by       dir is set to
 6295          * nat_inlookup         NAT_INBOUND (0)
 6296          * nat_outlookup        NAT_OUTBOUND (1)
 6297          *
 6298          * We simply combine the packet's direction in dir with the original
 6299          * "intended" direction of that NAT entry in nat->nat_dir to decide
 6300          * which combination of wildcard flags to allow.
 6301          */
 6302         switch ((dir << 1) | (nat->nat_dir & (NAT_INBOUND|NAT_OUTBOUND)))
 6303         {
 6304         case 3: /* outbound packet / outbound entry */
 6305                 if (((nat->nat_osport == sport) ||
 6306                     (flags & SI_W_SPORT)) &&
 6307                     ((nat->nat_odport == dport) ||
 6308                     (flags & SI_W_DPORT)))
 6309                         return (1);
 6310                 break;
 6311         case 2: /* outbound packet / inbound entry */
 6312                 if (((nat->nat_osport == dport) ||
 6313                     (flags & SI_W_SPORT)) &&
 6314                     ((nat->nat_odport == sport) ||
 6315                     (flags & SI_W_DPORT)))
 6316                         return (1);
 6317                 break;
 6318         case 1: /* inbound packet / outbound entry */
 6319                 if (((nat->nat_osport == dport) ||
 6320                     (flags & SI_W_SPORT)) &&
 6321                     ((nat->nat_odport == sport) ||
 6322                     (flags & SI_W_DPORT)))
 6323                         return (1);
 6324                 break;
 6325         case 0: /* inbound packet / inbound entry */
 6326                 if (((nat->nat_osport == sport) ||
 6327                     (flags & SI_W_SPORT)) &&
 6328                     ((nat->nat_odport == dport) ||
 6329                     (flags & SI_W_DPORT)))
 6330                         return (1);
 6331                 break;
 6332         default:
 6333                 break;
 6334         }
 6335 
 6336         return (0);
 6337 }
 6338 
 6339 
 6340 /* ------------------------------------------------------------------------ */
 6341 /* Function:    nat_mssclamp                                                */
 6342 /* Returns:     Nil                                                         */
 6343 /* Parameters:  tcp(I)    - pointer to TCP header                           */
 6344 /*              maxmss(I) - value to clamp the TCP MSS to                   */
 6345 /*              fin(I)    - pointer to packet information                   */
 6346 /*              csump(I)  - pointer to TCP checksum                         */
 6347 /*                                                                          */
 6348 /* Check for MSS option and clamp it if necessary.  If found and changed,   */
 6349 /* then the TCP header checksum will be updated to reflect the change in    */
 6350 /* the MSS.                                                                 */
 6351 /* ------------------------------------------------------------------------ */
 6352 static void
 6353 ipf_nat_mssclamp(tcphdr_t *tcp, u_32_t maxmss, fr_info_t *fin, u_short *csump)
 6354 {
 6355         u_char *cp, *ep, opt;
 6356         int hlen, advance;
 6357         u_32_t mss, sumd;
 6358 
 6359         hlen = TCP_OFF(tcp) << 2;
 6360         if (hlen > sizeof(*tcp)) {
 6361                 cp = (u_char *)tcp + sizeof(*tcp);
 6362                 ep = (u_char *)tcp + hlen;
 6363 
 6364                 while (cp < ep) {
 6365                         opt = cp[0];
 6366                         if (opt == TCPOPT_EOL)
 6367                                 break;
 6368                         else if (opt == TCPOPT_NOP) {
 6369                                 cp++;
 6370                                 continue;
 6371                         }
 6372 
 6373                         if (cp + 1 >= ep)
 6374                                 break;
 6375                         advance = cp[1];
 6376                         if ((cp + advance > ep) || (advance <= 0))
 6377                                 break;
 6378                         switch (opt)
 6379                         {
 6380                         case TCPOPT_MAXSEG:
 6381                                 if (advance != 4)
 6382                                         break;
 6383                                 mss = cp[2] * 256 + cp[3];
 6384                                 if (mss > maxmss) {
 6385                                         cp[2] = maxmss / 256;
 6386                                         cp[3] = maxmss & 0xff;
 6387                                         CALC_SUMD(mss, maxmss, sumd);
 6388                                         ipf_fix_outcksum(0, csump, sumd, 0);
 6389                                 }
 6390                                 break;
 6391                         default:
 6392                                 /* ignore unknown options */
 6393                                 break;
 6394                         }
 6395 
 6396                         cp += advance;
 6397                 }
 6398         }
 6399 }
 6400 
 6401 
 6402 /* ------------------------------------------------------------------------ */
 6403 /* Function:    ipf_nat_setqueue                                            */
 6404 /* Returns:     Nil                                                         */
 6405 /* Parameters:  softc(I) - pointer to soft context main structure           */
 6406 /*              softn(I) - pointer to NAT context structure                 */
 6407 /*              nat(I)- pointer to NAT structure                            */
 6408 /* Locks:       ipf_nat (read or write)                                     */
 6409 /*                                                                          */
 6410 /* Put the NAT entry on its default queue entry, using rev as a helped in   */
 6411 /* determining which queue it should be placed on.                          */
 6412 /* ------------------------------------------------------------------------ */
 6413 void
 6414 ipf_nat_setqueue(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, nat_t *nat)
 6415 {
 6416         ipftq_t *oifq, *nifq;
 6417         int rev = nat->nat_rev;
 6418 
 6419         if (nat->nat_ptr != NULL)
 6420                 nifq = nat->nat_ptr->in_tqehead[rev];
 6421         else
 6422                 nifq = NULL;
 6423 
 6424         if (nifq == NULL) {
 6425                 switch (nat->nat_pr[0])
 6426                 {
 6427                 case IPPROTO_UDP :
 6428                         nifq = &softn->ipf_nat_udptq;
 6429                         break;
 6430                 case IPPROTO_ICMP :
 6431                         nifq = &softn->ipf_nat_icmptq;
 6432                         break;
 6433                 case IPPROTO_TCP :
 6434                         nifq = softn->ipf_nat_tcptq +
 6435                                nat->nat_tqe.tqe_state[rev];
 6436                         break;
 6437                 default :
 6438                         nifq = &softn->ipf_nat_iptq;
 6439                         break;
 6440                 }
 6441         }
 6442 
 6443         oifq = nat->nat_tqe.tqe_ifq;
 6444         /*
 6445          * If it's currently on a timeout queue, move it from one queue to
 6446          * another, else put it on the end of the newly determined queue.
 6447          */
 6448         if (oifq != NULL)
 6449                 ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq, nifq);
 6450         else
 6451                 ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe, nifq, nat);
 6452         return;
 6453 }
 6454 
 6455 
 6456 /* ------------------------------------------------------------------------ */
 6457 /* Function:    nat_getnext                                                 */
 6458 /* Returns:     int - 0 == ok, else error                                   */
 6459 /* Parameters:  softc(I) - pointer to soft context main structure           */
 6460 /*              t(I)   - pointer to ipftoken structure                      */
 6461 /*              itp(I) - pointer to ipfgeniter_t structure                  */
 6462 /*                                                                          */
 6463 /* Fetch the next nat/ipnat structure pointer from the linked list and      */
 6464 /* copy it out to the storage space pointed to by itp_data.  The next item  */
 6465 /* in the list to look at is put back in the ipftoken struture.             */
 6466 /* ------------------------------------------------------------------------ */
 6467 static int
 6468 ipf_nat_getnext(ipf_main_softc_t *softc, ipftoken_t *t, ipfgeniter_t *itp,
 6469         ipfobj_t *objp)
 6470 {
 6471         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 6472         hostmap_t *hm, *nexthm = NULL, zerohm;
 6473         ipnat_t *ipn, *nextipnat = NULL, zeroipn;
 6474         nat_t *nat, *nextnat = NULL, zeronat;
 6475         int error = 0;
 6476         void *nnext;
 6477 
 6478         if (itp->igi_nitems != 1) {
 6479                 IPFERROR(60075);
 6480                 return (ENOSPC);
 6481         }
 6482 
 6483         READ_ENTER(&softc->ipf_nat);
 6484 
 6485         switch (itp->igi_type)
 6486         {
 6487         case IPFGENITER_HOSTMAP :
 6488                 hm = t->ipt_data;
 6489                 if (hm == NULL) {
 6490                         nexthm = softn->ipf_hm_maplist;
 6491                 } else {
 6492                         nexthm = hm->hm_next;
 6493                 }
 6494                 if (nexthm != NULL) {
 6495                         ATOMIC_INC32(nexthm->hm_ref);
 6496                         t->ipt_data = nexthm;
 6497                 } else {
 6498                         bzero(&zerohm, sizeof(zerohm));
 6499                         nexthm = &zerohm;
 6500                         t->ipt_data = NULL;
 6501                 }
 6502                 nnext = nexthm->hm_next;
 6503                 break;
 6504 
 6505         case IPFGENITER_IPNAT :
 6506                 ipn = t->ipt_data;
 6507                 if (ipn == NULL) {
 6508                         nextipnat = softn->ipf_nat_list;
 6509                 } else {
 6510                         nextipnat = ipn->in_next;
 6511                 }
 6512                 if (nextipnat != NULL) {
 6513                         ATOMIC_INC32(nextipnat->in_use);
 6514                         t->ipt_data = nextipnat;
 6515                 } else {
 6516                         bzero(&zeroipn, sizeof(zeroipn));
 6517                         nextipnat = &zeroipn;
 6518                         t->ipt_data = NULL;
 6519                 }
 6520                 nnext = nextipnat->in_next;
 6521                 break;
 6522 
 6523         case IPFGENITER_NAT :
 6524                 nat = t->ipt_data;
 6525                 if (nat == NULL) {
 6526                         nextnat = softn->ipf_nat_instances;
 6527                 } else {
 6528                         nextnat = nat->nat_next;
 6529                 }
 6530                 if (nextnat != NULL) {
 6531                         MUTEX_ENTER(&nextnat->nat_lock);
 6532                         nextnat->nat_ref++;
 6533                         MUTEX_EXIT(&nextnat->nat_lock);
 6534                         t->ipt_data = nextnat;
 6535                 } else {
 6536                         bzero(&zeronat, sizeof(zeronat));
 6537                         nextnat = &zeronat;
 6538                         t->ipt_data = NULL;
 6539                 }
 6540                 nnext = nextnat->nat_next;
 6541                 break;
 6542 
 6543         default :
 6544                 RWLOCK_EXIT(&softc->ipf_nat);
 6545                 IPFERROR(60055);
 6546                 return (EINVAL);
 6547         }
 6548 
 6549         RWLOCK_EXIT(&softc->ipf_nat);
 6550 
 6551         objp->ipfo_ptr = itp->igi_data;
 6552 
 6553         switch (itp->igi_type)
 6554         {
 6555         case IPFGENITER_HOSTMAP :
 6556                 error = COPYOUT(nexthm, objp->ipfo_ptr, sizeof(*nexthm));
 6557                 if (error != 0) {
 6558                         IPFERROR(60049);
 6559                         error = EFAULT;
 6560                 }
 6561                 if (hm != NULL) {
 6562                         WRITE_ENTER(&softc->ipf_nat);
 6563                         ipf_nat_hostmapdel(softc, &hm);
 6564                         RWLOCK_EXIT(&softc->ipf_nat);
 6565                 }
 6566                 break;
 6567 
 6568         case IPFGENITER_IPNAT :
 6569                 objp->ipfo_size = nextipnat->in_size;
 6570                 objp->ipfo_type = IPFOBJ_IPNAT;
 6571                 error = ipf_outobjk(softc, objp, nextipnat);
 6572                 if (ipn != NULL) {
 6573                         WRITE_ENTER(&softc->ipf_nat);
 6574                         ipf_nat_rule_deref(softc, &ipn);
 6575                         RWLOCK_EXIT(&softc->ipf_nat);
 6576                 }
 6577                 break;
 6578 
 6579         case IPFGENITER_NAT :
 6580                 objp->ipfo_size = sizeof(nat_t);
 6581                 objp->ipfo_type = IPFOBJ_NAT;
 6582                 error = ipf_outobjk(softc, objp, nextnat);
 6583                 if (nat != NULL)
 6584                         ipf_nat_deref(softc, &nat);
 6585 
 6586                 break;
 6587         }
 6588 
 6589         if (nnext == NULL)
 6590                 ipf_token_mark_complete(t);
 6591 
 6592         return (error);
 6593 }
 6594 
 6595 
 6596 /* ------------------------------------------------------------------------ */
 6597 /* Function:    nat_extraflush                                              */
 6598 /* Returns:     int - 0 == success, -1 == failure                           */
 6599 /* Parameters:  softc(I) - pointer to soft context main structure           */
 6600 /*              softn(I) - pointer to NAT context structure                 */
 6601 /*              which(I) - how to flush the active NAT table                */
 6602 /* Write Locks: ipf_nat                                                     */
 6603 /*                                                                          */
 6604 /* Flush nat tables.  Three actions currently defined:                      */
 6605 /* which == 0 : flush all nat table entries                                 */
 6606 /* which == 1 : flush TCP connections which have started to close but are   */
 6607 /*            stuck for some reason.                                        */
 6608 /* which == 2 : flush TCP connections which have been idle for a long time, */
 6609 /*            starting at > 4 days idle and working back in successive half-*/
 6610 /*            days to at most 12 hours old.  If this fails to free enough   */
 6611 /*            slots then work backwards in half hour slots to 30 minutes.   */
 6612 /*            If that too fails, then work backwards in 30 second intervals */
 6613 /*            for the last 30 minutes to at worst 30 seconds idle.          */
 6614 /* ------------------------------------------------------------------------ */
 6615 static int
 6616 ipf_nat_extraflush(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, int which)
 6617 {
 6618         nat_t *nat, **natp;
 6619         ipftqent_t *tqn;
 6620         ipftq_t *ifq;
 6621         int removed;
 6622         SPL_INT(s);
 6623 
 6624         removed = 0;
 6625 
 6626         SPL_NET(s);
 6627         switch (which)
 6628         {
 6629         case 0 :
 6630                 softn->ipf_nat_stats.ns_flush_all++;
 6631                 /*
 6632                  * Style 0 flush removes everything...
 6633                  */
 6634                 for (natp = &softn->ipf_nat_instances;
 6635                      ((nat = *natp) != NULL); ) {
 6636                         ipf_nat_delete(softc, nat, NL_FLUSH);
 6637                         removed++;
 6638                 }
 6639                 break;
 6640 
 6641         case 1 :
 6642                 softn->ipf_nat_stats.ns_flush_closing++;
 6643                 /*
 6644                  * Since we're only interested in things that are closing,
 6645                  * we can start with the appropriate timeout queue.
 6646                  */
 6647                 for (ifq = softn->ipf_nat_tcptq + IPF_TCPS_CLOSE_WAIT;
 6648                      ifq != NULL; ifq = ifq->ifq_next) {
 6649 
 6650                         for (tqn = ifq->ifq_head; tqn != NULL; ) {
 6651                                 nat = tqn->tqe_parent;
 6652                                 tqn = tqn->tqe_next;
 6653                                 if (nat->nat_pr[0] != IPPROTO_TCP ||
 6654                                     nat->nat_pr[1] != IPPROTO_TCP)
 6655                                         break;
 6656                                 ipf_nat_delete(softc, nat, NL_EXPIRE);
 6657                                 removed++;
 6658                         }
 6659                 }
 6660 
 6661                 /*
 6662                  * Also need to look through the user defined queues.
 6663                  */
 6664                 for (ifq = softn->ipf_nat_utqe; ifq != NULL;
 6665                      ifq = ifq->ifq_next) {
 6666                         for (tqn = ifq->ifq_head; tqn != NULL; ) {
 6667                                 nat = tqn->tqe_parent;
 6668                                 tqn = tqn->tqe_next;
 6669                                 if (nat->nat_pr[0] != IPPROTO_TCP ||
 6670                                     nat->nat_pr[1] != IPPROTO_TCP)
 6671                                         continue;
 6672 
 6673                                 if ((nat->nat_tcpstate[0] >
 6674                                      IPF_TCPS_ESTABLISHED) &&
 6675                                     (nat->nat_tcpstate[1] >
 6676                                      IPF_TCPS_ESTABLISHED)) {
 6677                                         ipf_nat_delete(softc, nat, NL_EXPIRE);
 6678                                         removed++;
 6679                                 }
 6680                         }
 6681                 }
 6682                 break;
 6683 
 6684                 /*
 6685                  * Args 5-11 correspond to flushing those particular states
 6686                  * for TCP connections.
 6687                  */
 6688         case IPF_TCPS_CLOSE_WAIT :
 6689         case IPF_TCPS_FIN_WAIT_1 :
 6690         case IPF_TCPS_CLOSING :
 6691         case IPF_TCPS_LAST_ACK :
 6692         case IPF_TCPS_FIN_WAIT_2 :
 6693         case IPF_TCPS_TIME_WAIT :
 6694         case IPF_TCPS_CLOSED :
 6695                 softn->ipf_nat_stats.ns_flush_state++;
 6696                 tqn = softn->ipf_nat_tcptq[which].ifq_head;
 6697                 while (tqn != NULL) {
 6698                         nat = tqn->tqe_parent;
 6699                         tqn = tqn->tqe_next;
 6700                         ipf_nat_delete(softc, nat, NL_FLUSH);
 6701                         removed++;
 6702                 }
 6703                 break;
 6704 
 6705         default :
 6706                 if (which < 30)
 6707                         break;
 6708 
 6709                 softn->ipf_nat_stats.ns_flush_timeout++;
 6710                 /*
 6711                  * Take a large arbitrary number to mean the number of seconds
 6712                  * for which which consider to be the maximum value we'll allow
 6713                  * the expiration to be.
 6714                  */
 6715                 which = IPF_TTLVAL(which);
 6716                 for (natp = &softn->ipf_nat_instances;
 6717                      ((nat = *natp) != NULL); ) {
 6718                         if (softc->ipf_ticks - nat->nat_touched > which) {
 6719                                 ipf_nat_delete(softc, nat, NL_FLUSH);
 6720                                 removed++;
 6721                         } else
 6722                                 natp = &nat->nat_next;
 6723                 }
 6724                 break;
 6725         }
 6726 
 6727         if (which != 2) {
 6728                 SPL_X(s);
 6729                 return (removed);
 6730         }
 6731 
 6732         softn->ipf_nat_stats.ns_flush_queue++;
 6733 
 6734         /*
 6735          * Asked to remove inactive entries because the table is full, try
 6736          * again, 3 times, if first attempt failed with a different criteria
 6737          * each time.  The order tried in must be in decreasing age.
 6738          * Another alternative is to implement random drop and drop N entries
 6739          * at random until N have been freed up.
 6740          */
 6741         if (softc->ipf_ticks - softn->ipf_nat_last_force_flush >
 6742             IPF_TTLVAL(5)) {
 6743                 softn->ipf_nat_last_force_flush = softc->ipf_ticks;
 6744 
 6745                 removed = ipf_queueflush(softc, ipf_nat_flush_entry,
 6746                                          softn->ipf_nat_tcptq,
 6747                                          softn->ipf_nat_utqe,
 6748                                          &softn->ipf_nat_stats.ns_active,
 6749                                          softn->ipf_nat_table_sz,
 6750                                          softn->ipf_nat_table_wm_low);
 6751         }
 6752 
 6753         SPL_X(s);
 6754         return (removed);
 6755 }
 6756 
 6757 
 6758 /* ------------------------------------------------------------------------ */
 6759 /* Function:    ipf_nat_flush_entry                                         */
 6760 /* Returns:     0 - always succeeds                                         */
 6761 /* Parameters:  softc(I) - pointer to soft context main structure           */
 6762 /*              entry(I) - pointer to NAT entry                             */
 6763 /* Write Locks: ipf_nat                                                     */
 6764 /*                                                                          */
 6765 /* This function is a stepping stone between ipf_queueflush() and           */
 6766 /* nat_dlete().  It is used so we can provide a uniform interface via the   */
 6767 /* ipf_queueflush() function.  Since the nat_delete() function returns void */
 6768 /* we translate that to mean it always succeeds in deleting something.      */
 6769 /* ------------------------------------------------------------------------ */
 6770 static int
 6771 ipf_nat_flush_entry(ipf_main_softc_t *softc, void *entry)
 6772 {
 6773         ipf_nat_delete(softc, entry, NL_FLUSH);
 6774         return (0);
 6775 }
 6776 
 6777 
 6778 /* ------------------------------------------------------------------------ */
 6779 /* Function:    ipf_nat_iterator                                            */
 6780 /* Returns:     int - 0 == ok, else error                                   */
 6781 /* Parameters:  softc(I) - pointer to soft context main structure           */
 6782 /*              token(I) - pointer to ipftoken structure                    */
 6783 /*              itp(I)   - pointer to ipfgeniter_t structure                */
 6784 /*              obj(I)   - pointer to data description structure            */
 6785 /*                                                                          */
 6786 /* This function acts as a handler for the SIOCGENITER ioctls that use a    */
 6787 /* generic structure to iterate through a list.  There are three different  */
 6788 /* linked lists of NAT related information to go through: NAT rules, active */
 6789 /* NAT mappings and the NAT fragment cache.                                 */
 6790 /* ------------------------------------------------------------------------ */
 6791 static int
 6792 ipf_nat_iterator(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp,
 6793         ipfobj_t *obj)
 6794 {
 6795         int error;
 6796 
 6797         if (itp->igi_data == NULL) {
 6798                 IPFERROR(60052);
 6799                 return (EFAULT);
 6800         }
 6801 
 6802         switch (itp->igi_type)
 6803         {
 6804         case IPFGENITER_HOSTMAP :
 6805         case IPFGENITER_IPNAT :
 6806         case IPFGENITER_NAT :
 6807                 error = ipf_nat_getnext(softc, token, itp, obj);
 6808                 break;
 6809 
 6810         case IPFGENITER_NATFRAG :
 6811                 error = ipf_frag_nat_next(softc, token, itp);
 6812                 break;
 6813         default :
 6814                 IPFERROR(60053);
 6815                 error = EINVAL;
 6816                 break;
 6817         }
 6818 
 6819         return (error);
 6820 }
 6821 
 6822 
 6823 /* ------------------------------------------------------------------------ */
 6824 /* Function:    ipf_nat_setpending                                          */
 6825 /* Returns:     Nil                                                         */
 6826 /* Parameters:  softc(I) - pointer to soft context main structure           */
 6827 /*              nat(I)   - pointer to NAT structure                         */
 6828 /* Locks:       ipf_nat (read or write)                                     */
 6829 /*                                                                          */
 6830 /* Put the NAT entry on to the pending queue - this queue has a very short  */
 6831 /* lifetime where items are put that can't be deleted straight away because */
 6832 /* of locking issues but we want to delete them ASAP, anyway.  In calling   */
 6833 /* this function, it is assumed that the owner (if there is one, as shown   */
 6834 /* by nat_me) is no longer interested in it.                                */
 6835 /* ------------------------------------------------------------------------ */
 6836 void
 6837 ipf_nat_setpending(ipf_main_softc_t *softc, nat_t *nat)
 6838 {
 6839         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 6840         ipftq_t *oifq;
 6841 
 6842         oifq = nat->nat_tqe.tqe_ifq;
 6843         if (oifq != NULL)
 6844                 ipf_movequeue(softc->ipf_ticks, &nat->nat_tqe, oifq,
 6845                               &softn->ipf_nat_pending);
 6846         else
 6847                 ipf_queueappend(softc->ipf_ticks, &nat->nat_tqe,
 6848                                 &softn->ipf_nat_pending, nat);
 6849 
 6850         if (nat->nat_me != NULL) {
 6851                 *nat->nat_me = NULL;
 6852                 nat->nat_me = NULL;
 6853                 nat->nat_ref--;
 6854                 ASSERT(nat->nat_ref >= 0);
 6855         }
 6856 }
 6857 
 6858 
 6859 /* ------------------------------------------------------------------------ */
 6860 /* Function:    nat_newrewrite                                              */
 6861 /* Returns:     int - -1 == error, 0 == success (no move), 1 == success and */
 6862 /*                    allow rule to be moved if IPN_ROUNDR is set.          */
 6863 /* Parameters:  fin(I) - pointer to packet information                      */
 6864 /*              nat(I) - pointer to NAT entry                               */
 6865 /*              ni(I)  - pointer to structure with misc. information needed */
 6866 /*                       to create new NAT entry.                           */
 6867 /* Write Lock:  ipf_nat                                                     */
 6868 /*                                                                          */
 6869 /* This function is responsible for setting up an active NAT session where  */
 6870 /* we are changing both the source and destination parameters at the same   */
 6871 /* time.  The loop in here works differently to elsewhere - each iteration  */
 6872 /* is responsible for changing a single parameter that can be incremented.  */
 6873 /* So one pass may increase the source IP#, next source port, next dest. IP#*/
 6874 /* and the last destination port for a total of 4 iterations to try each.   */
 6875 /* This is done to try and exhaustively use the translation space available.*/
 6876 /* ------------------------------------------------------------------------ */
 6877 static int
 6878 ipf_nat_newrewrite(fr_info_t *fin, nat_t *nat, natinfo_t *nai)
 6879 {
 6880         int src_search = 1;
 6881         int dst_search = 1;
 6882         fr_info_t frnat;
 6883         u_32_t flags;
 6884         u_short swap;
 6885         ipnat_t *np;
 6886         nat_t *natl;
 6887         int l = 0;
 6888         int changed;
 6889 
 6890         natl = NULL;
 6891         changed = -1;
 6892         np = nai->nai_np;
 6893         flags = nat->nat_flags;
 6894         bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
 6895 
 6896         nat->nat_hm = NULL;
 6897 
 6898         do {
 6899                 changed = -1;
 6900                 /* TRACE (l, src_search, dst_search, np) */
 6901                 DT4(ipf_nat_rewrite_1, int, l, int, src_search, int, dst_search, ipnat_t *, np);
 6902 
 6903                 if ((src_search == 0) && (np->in_spnext == 0) &&
 6904                     (dst_search == 0) && (np->in_dpnext == 0)) {
 6905                         if (l > 0)
 6906                                 return (-1);
 6907                 }
 6908 
 6909                 /*
 6910                  * Find a new source address
 6911                  */
 6912                 if (ipf_nat_nextaddr(fin, &np->in_nsrc, &frnat.fin_saddr,
 6913                                      &frnat.fin_saddr) == -1) {
 6914                         return (-1);
 6915                 }
 6916 
 6917                 if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0xffffffff)) {
 6918                         src_search = 0;
 6919                         if (np->in_stepnext == 0)
 6920                                 np->in_stepnext = 1;
 6921 
 6922                 } else if ((np->in_nsrcaddr == 0) && (np->in_nsrcmsk == 0)) {
 6923                         src_search = 0;
 6924                         if (np->in_stepnext == 0)
 6925                                 np->in_stepnext = 1;
 6926 
 6927                 } else if (np->in_nsrcmsk == 0xffffffff) {
 6928                         src_search = 0;
 6929                         if (np->in_stepnext == 0)
 6930                                 np->in_stepnext = 1;
 6931 
 6932                 } else if (np->in_nsrcmsk != 0xffffffff) {
 6933                         if (np->in_stepnext == 0 && changed == -1) {
 6934                                 np->in_snip++;
 6935                                 np->in_stepnext++;
 6936                                 changed = 0;
 6937                         }
 6938                 }
 6939 
 6940                 if ((flags & IPN_TCPUDPICMP) != 0) {
 6941                         if (np->in_spnext != 0)
 6942                                 frnat.fin_data[0] = np->in_spnext;
 6943 
 6944                         /*
 6945                          * Standard port translation.  Select next port.
 6946                          */
 6947                         if ((flags & IPN_FIXEDSPORT) != 0) {
 6948                                 np->in_stepnext = 2;
 6949                         } else if ((np->in_stepnext == 1) &&
 6950                                    (changed == -1) && (natl != NULL)) {
 6951                                 np->in_spnext++;
 6952                                 np->in_stepnext++;
 6953                                 changed = 1;
 6954                                 if (np->in_spnext > np->in_spmax)
 6955                                         np->in_spnext = np->in_spmin;
 6956                         }
 6957                 } else {
 6958                         np->in_stepnext = 2;
 6959                 }
 6960                 np->in_stepnext &= 0x3;
 6961 
 6962                 /*
 6963                  * Find a new destination address
 6964                  */
 6965                 /* TRACE (fin, np, l, frnat) */
 6966                 DT4(ipf_nat_rewrite_2, frinfo_t *, fin, ipnat_t *, np, int, l, frinfo_t *, &frnat);
 6967 
 6968                 if (ipf_nat_nextaddr(fin, &np->in_ndst, &frnat.fin_daddr,
 6969                                      &frnat.fin_daddr) == -1)
 6970                         return (-1);
 6971                 if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0xffffffff)) {
 6972                         dst_search = 0;
 6973                         if (np->in_stepnext == 2)
 6974                                 np->in_stepnext = 3;
 6975 
 6976                 } else if ((np->in_ndstaddr == 0) && (np->in_ndstmsk == 0)) {
 6977                         dst_search = 0;
 6978                         if (np->in_stepnext == 2)
 6979                                 np->in_stepnext = 3;
 6980 
 6981                 } else if (np->in_ndstmsk == 0xffffffff) {
 6982                         dst_search = 0;
 6983                         if (np->in_stepnext == 2)
 6984                                 np->in_stepnext = 3;
 6985 
 6986                 } else if (np->in_ndstmsk != 0xffffffff) {
 6987                         if ((np->in_stepnext == 2) && (changed == -1) &&
 6988                             (natl != NULL)) {
 6989                                 changed = 2;
 6990                                 np->in_stepnext++;
 6991                                 np->in_dnip++;
 6992                         }
 6993                 }
 6994 
 6995                 if ((flags & IPN_TCPUDPICMP) != 0) {
 6996                         if (np->in_dpnext != 0)
 6997                                 frnat.fin_data[1] = np->in_dpnext;
 6998 
 6999                         /*
 7000                          * Standard port translation.  Select next port.
 7001                          */
 7002                         if ((flags & IPN_FIXEDDPORT) != 0) {
 7003                                 np->in_stepnext = 0;
 7004                         } else if (np->in_stepnext == 3 && changed == -1) {
 7005                                 np->in_dpnext++;
 7006                                 np->in_stepnext++;
 7007                                 changed = 3;
 7008                                 if (np->in_dpnext > np->in_dpmax)
 7009                                         np->in_dpnext = np->in_dpmin;
 7010                         }
 7011                 } else {
 7012                         if (np->in_stepnext == 3)
 7013                                 np->in_stepnext = 0;
 7014                 }
 7015 
 7016                 /* TRACE (frnat) */
 7017                 DT1(ipf_nat_rewrite_3, frinfo_t *, &frnat);
 7018 
 7019                 /*
 7020                  * Here we do a lookup of the connection as seen from
 7021                  * the outside.  If an IP# pair already exists, try
 7022                  * again.  So if you have A->B becomes C->B, you can
 7023                  * also have D->E become C->E but not D->B causing
 7024                  * another C->B.  Also take protocol and ports into
 7025                  * account when determining whether a pre-existing
 7026                  * NAT setup will cause an external conflict where
 7027                  * this is appropriate.
 7028                  *
 7029                  * fin_data[] is swapped around because we are doing a
 7030                  * lookup of the packet is if it were moving in the opposite
 7031                  * direction of the one we are working with now.
 7032                  */
 7033                 if (flags & IPN_TCPUDP) {
 7034                         swap = frnat.fin_data[0];
 7035                         frnat.fin_data[0] = frnat.fin_data[1];
 7036                         frnat.fin_data[1] = swap;
 7037                 }
 7038                 if (fin->fin_out == 1) {
 7039                         natl = ipf_nat_inlookup(&frnat,
 7040                                                 flags & ~(SI_WILDP|NAT_SEARCH),
 7041                                                 (u_int)frnat.fin_p,
 7042                                                 frnat.fin_dst, frnat.fin_src);
 7043 
 7044                 } else {
 7045                         natl = ipf_nat_outlookup(&frnat,
 7046                                                  flags & ~(SI_WILDP|NAT_SEARCH),
 7047                                                  (u_int)frnat.fin_p,
 7048                                                  frnat.fin_dst, frnat.fin_src);
 7049                 }
 7050                 if (flags & IPN_TCPUDP) {
 7051                         swap = frnat.fin_data[0];
 7052                         frnat.fin_data[0] = frnat.fin_data[1];
 7053                         frnat.fin_data[1] = swap;
 7054                 }
 7055 
 7056                 /* TRACE natl, in_stepnext, l */
 7057                 DT3(ipf_nat_rewrite_2, nat_t *, natl, ipnat_t *, np , int, l);
 7058 
 7059                 if ((natl != NULL) && (l > 8))  /* XXX 8 is arbitrary */
 7060                         return (-1);
 7061 
 7062                 np->in_stepnext &= 0x3;
 7063 
 7064                 l++;
 7065                 changed = -1;
 7066         } while (natl != NULL);
 7067 
 7068         nat->nat_osrcip = fin->fin_src;
 7069         nat->nat_odstip = fin->fin_dst;
 7070         nat->nat_nsrcip = frnat.fin_src;
 7071         nat->nat_ndstip = frnat.fin_dst;
 7072 
 7073         if ((flags & IPN_TCPUDP) != 0) {
 7074                 nat->nat_osport = htons(fin->fin_data[0]);
 7075                 nat->nat_odport = htons(fin->fin_data[1]);
 7076                 nat->nat_nsport = htons(frnat.fin_data[0]);
 7077                 nat->nat_ndport = htons(frnat.fin_data[1]);
 7078         } else if ((flags & IPN_ICMPQUERY) != 0) {
 7079                 nat->nat_oicmpid = fin->fin_data[1];
 7080                 nat->nat_nicmpid = frnat.fin_data[1];
 7081         }
 7082 
 7083         return (0);
 7084 }
 7085 
 7086 
 7087 /* ------------------------------------------------------------------------ */
 7088 /* Function:    nat_newdivert                                               */
 7089 /* Returns:     int - -1 == error, 0 == success                             */
 7090 /* Parameters:  fin(I) - pointer to packet information                      */
 7091 /*              nat(I) - pointer to NAT entry                               */
 7092 /*              ni(I)  - pointer to structure with misc. information needed */
 7093 /*                       to create new NAT entry.                           */
 7094 /* Write Lock:  ipf_nat                                                     */
 7095 /*                                                                          */
 7096 /* Create a new NAT  divert session as defined by the NAT rule.  This is    */
 7097 /* somewhat different to other NAT session creation routines because we     */
 7098 /* do not iterate through either port numbers or IP addresses, searching    */
 7099 /* for a unique mapping, however, a complimentary duplicate check is made.  */
 7100 /* ------------------------------------------------------------------------ */
 7101 static int
 7102 ipf_nat_newdivert(fr_info_t *fin, nat_t *nat, natinfo_t *nai)
 7103 {
 7104         ipf_main_softc_t *softc = fin->fin_main_soft;
 7105         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 7106         fr_info_t frnat;
 7107         ipnat_t *np;
 7108         nat_t *natl;
 7109         int p;
 7110 
 7111         np = nai->nai_np;
 7112         bcopy((char *)fin, (char *)&frnat, sizeof(*fin));
 7113 
 7114         nat->nat_pr[0] = 0;
 7115         nat->nat_osrcaddr = fin->fin_saddr;
 7116         nat->nat_odstaddr = fin->fin_daddr;
 7117         frnat.fin_saddr = htonl(np->in_snip);
 7118         frnat.fin_daddr = htonl(np->in_dnip);
 7119         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
 7120                 nat->nat_osport = htons(fin->fin_data[0]);
 7121                 nat->nat_odport = htons(fin->fin_data[1]);
 7122         } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
 7123                 nat->nat_oicmpid = fin->fin_data[1];
 7124         }
 7125 
 7126         if (np->in_redir & NAT_DIVERTUDP) {
 7127                 frnat.fin_data[0] = np->in_spnext;
 7128                 frnat.fin_data[1] = np->in_dpnext;
 7129                 frnat.fin_flx |= FI_TCPUDP;
 7130                 p = IPPROTO_UDP;
 7131         } else {
 7132                 frnat.fin_flx &= ~FI_TCPUDP;
 7133                 p = IPPROTO_IPIP;
 7134         }
 7135 
 7136         if (fin->fin_out == 1) {
 7137                 natl = ipf_nat_inlookup(&frnat, 0, p,
 7138                                         frnat.fin_dst, frnat.fin_src);
 7139 
 7140         } else {
 7141                 natl = ipf_nat_outlookup(&frnat, 0, p,
 7142                                          frnat.fin_dst, frnat.fin_src);
 7143         }
 7144 
 7145         if (natl != NULL) {
 7146                 NBUMPSIDED(fin->fin_out, ns_divert_exist);
 7147                 DT3(ns_divert_exist, fr_info_t *, fin, nat_t *, nat, natinfo_t, nai);
 7148                 return (-1);
 7149         }
 7150 
 7151         nat->nat_nsrcaddr = frnat.fin_saddr;
 7152         nat->nat_ndstaddr = frnat.fin_daddr;
 7153         if ((nat->nat_flags & IPN_TCPUDP) != 0) {
 7154                 nat->nat_nsport = htons(frnat.fin_data[0]);
 7155                 nat->nat_ndport = htons(frnat.fin_data[1]);
 7156         } else if ((nat->nat_flags & IPN_ICMPQUERY) != 0) {
 7157                 nat->nat_nicmpid = frnat.fin_data[1];
 7158         }
 7159 
 7160         nat->nat_pr[fin->fin_out] = fin->fin_p;
 7161         nat->nat_pr[1 - fin->fin_out] = p;
 7162 
 7163         if (np->in_redir & NAT_REDIRECT)
 7164                 nat->nat_dir = NAT_DIVERTIN;
 7165         else
 7166                 nat->nat_dir = NAT_DIVERTOUT;
 7167 
 7168         return (0);
 7169 }
 7170 
 7171 
 7172 /* ------------------------------------------------------------------------ */
 7173 /* Function:    nat_builddivertmp                                           */
 7174 /* Returns:     int - -1 == error, 0 == success                             */
 7175 /* Parameters:  softn(I) - pointer to NAT context structure                 */
 7176 /*              np(I)    - pointer to a NAT rule                            */
 7177 /*                                                                          */
 7178 /* For divert rules, a skeleton packet representing what will be prepended  */
 7179 /* to the real packet is created.  Even though we don't have the full       */
 7180 /* packet here, a checksum is calculated that we update later when we       */
 7181 /* fill in the final details.  At present a 0 checksum for UDP is being set */
 7182 /* here because it is expected that divert will be used for localhost.      */
 7183 /* ------------------------------------------------------------------------ */
 7184 static int
 7185 ipf_nat_builddivertmp(ipf_nat_softc_t *softn, ipnat_t *np)
 7186 {
 7187         udphdr_t *uh;
 7188         size_t len;
 7189         ip_t *ip;
 7190 
 7191         if ((np->in_redir & NAT_DIVERTUDP) != 0)
 7192                 len = sizeof(ip_t) + sizeof(udphdr_t);
 7193         else
 7194                 len = sizeof(ip_t);
 7195 
 7196         ALLOC_MB_T(np->in_divmp, len);
 7197         if (np->in_divmp == NULL) {
 7198                 NBUMPD(ipf_nat_stats, ns_divert_build);
 7199                 return (-1);
 7200         }
 7201 
 7202         /*
 7203          * First, the header to get the packet diverted to the new destination
 7204          */
 7205         ip = MTOD(np->in_divmp, ip_t *);
 7206         IP_V_A(ip, 4);
 7207         IP_HL_A(ip, 5);
 7208         ip->ip_tos = 0;
 7209         if ((np->in_redir & NAT_DIVERTUDP) != 0)
 7210                 ip->ip_p = IPPROTO_UDP;
 7211         else
 7212                 ip->ip_p = IPPROTO_IPIP;
 7213         ip->ip_ttl = 255;
 7214         ip->ip_off = 0;
 7215         ip->ip_sum = 0;
 7216         ip->ip_len = htons(len);
 7217         ip->ip_id = 0;
 7218         ip->ip_src.s_addr = htonl(np->in_snip);
 7219         ip->ip_dst.s_addr = htonl(np->in_dnip);
 7220         ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip));
 7221 
 7222         if (np->in_redir & NAT_DIVERTUDP) {
 7223                 uh = (udphdr_t *)(ip + 1);
 7224                 uh->uh_sum = 0;
 7225                 uh->uh_ulen = 8;
 7226                 uh->uh_sport = htons(np->in_spnext);
 7227                 uh->uh_dport = htons(np->in_dpnext);
 7228         }
 7229 
 7230         return (0);
 7231 }
 7232 
 7233 
 7234 #define MINDECAP        (sizeof(ip_t) + sizeof(udphdr_t) + sizeof(ip_t))
 7235 
 7236 /* ------------------------------------------------------------------------ */
 7237 /* Function:    nat_decap                                                   */
 7238 /* Returns:     int - -1 == error, 0 == success                             */
 7239 /* Parameters:  fin(I) - pointer to packet information                      */
 7240 /*              nat(I) - pointer to current NAT session                     */
 7241 /*                                                                          */
 7242 /* This function is responsible for undoing a packet's encapsulation in the */
 7243 /* reverse of an encap/divert rule.  After removing the outer encapsulation */
 7244 /* it is necessary to call ipf_makefrip() again so that the contents of 'fin'*/
 7245 /* match the "new" packet as it may still be used by IPFilter elsewhere.    */
 7246 /* We use "dir" here as the basis for some of the expectations about the    */
 7247 /* outer header.  If we return an error, the goal is to leave the original  */
 7248 /* packet information undisturbed - this falls short at the end where we'd  */
 7249 /* need to back a backup copy of "fin" - expensive.                         */
 7250 /* ------------------------------------------------------------------------ */
 7251 static int
 7252 ipf_nat_decap(fr_info_t *fin, nat_t *nat)
 7253 {
 7254         ipf_main_softc_t *softc = fin->fin_main_soft;
 7255         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 7256         char *hdr;
 7257         int hlen;
 7258         int skip;
 7259         mb_t *m;
 7260 
 7261         if ((fin->fin_flx & FI_ICMPERR) != 0) {
 7262                 /*
 7263                  * ICMP packets don't get decapsulated, instead what we need
 7264                  * to do is change the ICMP reply from including (in the data
 7265                  * portion for errors) the encapsulated packet that we sent
 7266                  * out to something that resembles the original packet prior
 7267                  * to encapsulation.  This isn't done here - all we're doing
 7268                  * here is changing the outer address to ensure that it gets
 7269                  * targetted back to the correct system.
 7270                  */
 7271 
 7272                 if (nat->nat_dir & NAT_OUTBOUND) {
 7273                         u_32_t sum1, sum2, sumd;
 7274 
 7275                         sum1 = ntohl(fin->fin_daddr);
 7276                         sum2 = ntohl(nat->nat_osrcaddr);
 7277                         CALC_SUMD(sum1, sum2, sumd);
 7278                         fin->fin_ip->ip_dst = nat->nat_osrcip;
 7279                         fin->fin_daddr = nat->nat_osrcaddr;
 7280 #if !defined(_KERNEL) || SOLARIS
 7281                         ipf_fix_outcksum(0, &fin->fin_ip->ip_sum, sumd, 0);
 7282 #endif
 7283                 }
 7284                 return (0);
 7285         }
 7286 
 7287         m = fin->fin_m;
 7288         skip = fin->fin_hlen;
 7289 
 7290         switch (nat->nat_dir)
 7291         {
 7292         case NAT_DIVERTIN :
 7293         case NAT_DIVERTOUT :
 7294                 if (fin->fin_plen < MINDECAP)
 7295                         return (-1);
 7296                 skip += sizeof(udphdr_t);
 7297                 break;
 7298 
 7299         case NAT_ENCAPIN :
 7300         case NAT_ENCAPOUT :
 7301                 if (fin->fin_plen < (skip + sizeof(ip_t)))
 7302                         return (-1);
 7303                 break;
 7304         default :
 7305                 return (-1);
 7306                 /* NOTREACHED */
 7307         }
 7308 
 7309         /*
 7310          * The aim here is to keep the original packet details in "fin" for
 7311          * as long as possible so that returning with an error is for the
 7312          * original packet and there is little undoing work to do.
 7313          */
 7314         if (M_LEN(m) < skip + sizeof(ip_t)) {
 7315                 if (ipf_pr_pullup(fin, skip + sizeof(ip_t)) == -1)
 7316                         return (-1);
 7317         }
 7318 
 7319         hdr = MTOD(fin->fin_m, char *);
 7320         fin->fin_ip = (ip_t *)(hdr + skip);
 7321         hlen = IP_HL(fin->fin_ip) << 2;
 7322 
 7323         if (ipf_pr_pullup(fin, skip + hlen) == -1) {
 7324                 NBUMPSIDED(fin->fin_out, ns_decap_pullup);
 7325                 return (-1);
 7326         }
 7327 
 7328         fin->fin_hlen = hlen;
 7329         fin->fin_dlen -= skip;
 7330         fin->fin_plen -= skip;
 7331         fin->fin_ipoff += skip;
 7332 
 7333         if (ipf_makefrip(hlen, (ip_t *)hdr, fin) == -1) {
 7334                 NBUMPSIDED(fin->fin_out, ns_decap_bad);
 7335                 return (-1);
 7336         }
 7337 
 7338         return (skip);
 7339 }
 7340 
 7341 
 7342 /* ------------------------------------------------------------------------ */
 7343 /* Function:    nat_nextaddr                                                */
 7344 /* Returns:     int - -1 == bad input (no new address),                     */
 7345 /*                     0 == success and dst has new address                 */
 7346 /* Parameters:  fin(I) - pointer to packet information                      */
 7347 /*              na(I)  - how to generate new address                        */
 7348 /*              old(I) - original address being replaced                    */
 7349 /*              dst(O) - where to put the new address                       */
 7350 /* Write Lock:  ipf_nat                                                     */
 7351 /*                                                                          */
 7352 /* This function uses the contents of the "na" structure, in combination    */
 7353 /* with "old" to produce a new address to store in "dst".  Not all of the   */
 7354 /* possible uses of "na" will result in a new address.                      */
 7355 /* ------------------------------------------------------------------------ */
 7356 static int
 7357 ipf_nat_nextaddr(fr_info_t *fin, nat_addr_t *na, u_32_t *old, u_32_t *dst)
 7358 {
 7359         ipf_main_softc_t *softc = fin->fin_main_soft;
 7360         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 7361         u_32_t amin, amax, new;
 7362         i6addr_t newip;
 7363         int error;
 7364 
 7365         new = 0;
 7366         amin = na->na_addr[0].in4.s_addr;
 7367 
 7368         switch (na->na_atype)
 7369         {
 7370         case FRI_RANGE :
 7371                 amax = na->na_addr[1].in4.s_addr;
 7372                 break;
 7373 
 7374         case FRI_NETMASKED :
 7375         case FRI_DYNAMIC :
 7376         case FRI_NORMAL :
 7377                 /*
 7378                  * Compute the maximum address by adding the inverse of the
 7379                  * netmask to the minimum address.
 7380                  */
 7381                 amax = ~na->na_addr[1].in4.s_addr;
 7382                 amax |= amin;
 7383                 break;
 7384 
 7385         case FRI_LOOKUP :
 7386                 break;
 7387 
 7388         case FRI_BROADCAST :
 7389         case FRI_PEERADDR :
 7390         case FRI_NETWORK :
 7391         default :
 7392                 DT4(ns_na_atype, fr_info_t *, fin, nat_addr_t *, na, u_32_t *, old, u_32_t *, new);
 7393                 return (-1);
 7394         }
 7395 
 7396         error = -1;
 7397 
 7398         if (na->na_atype == FRI_LOOKUP) {
 7399                 if (na->na_type == IPLT_DSTLIST) {
 7400                         error = ipf_dstlist_select_node(fin, na->na_ptr, dst,
 7401                                                         NULL);
 7402                 } else {
 7403                         NBUMPSIDE(fin->fin_out, ns_badnextaddr);
 7404                         DT4(ns_badnextaddr_1, fr_info_t *, fin, nat_addr_t *, na, u_32_t *, old, u_32_t *, new);
 7405                 }
 7406 
 7407         } else if (na->na_atype == IPLT_NONE) {
 7408                 /*
 7409                  * 0/0 as the new address means leave it alone.
 7410                  */
 7411                 if (na->na_addr[0].in4.s_addr == 0 &&
 7412                     na->na_addr[1].in4.s_addr == 0) {
 7413                         new = *old;
 7414 
 7415                 /*
 7416                  * 0/32 means get the interface's address
 7417                  */
 7418                 } else if (na->na_addr[0].in4.s_addr == 0 &&
 7419                            na->na_addr[1].in4.s_addr == 0xffffffff) {
 7420                         if (ipf_ifpaddr(softc, 4, na->na_atype,
 7421                                         fin->fin_ifp, &newip, NULL) == -1) {
 7422                                 NBUMPSIDED(fin->fin_out, ns_ifpaddrfail);
 7423                                 DT4(ns_ifpaddrfail, fr_info_t *, fin, nat_addr_t *, na, u_32_t *, old, u_32_t *, new);
 7424                                 return (-1);
 7425                         }
 7426                         new = newip.in4.s_addr;
 7427                 } else {
 7428                         new = htonl(na->na_nextip);
 7429                 }
 7430                 *dst = new;
 7431                 error = 0;
 7432 
 7433         } else {
 7434                 NBUMPSIDE(fin->fin_out, ns_badnextaddr);
 7435                 DT4(ns_badnextaddr_2, fr_info_t *, fin, nat_addr_t *, na, u_32_t *, old, u_32_t *, new);
 7436         }
 7437 
 7438         return (error);
 7439 }
 7440 
 7441 
 7442 /* ------------------------------------------------------------------------ */
 7443 /* Function:    nat_nextaddrinit                                            */
 7444 /* Returns:     int - 0 == success, else error number                       */
 7445 /* Parameters:  softc(I) - pointer to soft context main structure           */
 7446 /*              na(I)      - NAT address information for generating new addr*/
 7447 /*              initial(I) - flag indicating if it is the first call for    */
 7448 /*                           this "na" structure.                           */
 7449 /*              ifp(I)     - network interface to derive address            */
 7450 /*                           information from.                              */
 7451 /*                                                                          */
 7452 /* This function is expected to be called in two scenarious: when a new NAT */
 7453 /* rule is loaded into the kernel and when the list of NAT rules is sync'd  */
 7454 /* up with the valid network interfaces (possibly due to them changing.)    */
 7455 /* To distinguish between these, the "initial" parameter is used.  If it is */
 7456 /* 1 then this indicates the rule has just been reloaded and 0 for when we  */
 7457 /* are updating information.  This difference is important because in       */
 7458 /* instances where we are not updating address information associated with  */
 7459 /* a network interface, we don't want to disturb what the "next" address to */
 7460 /* come out of ipf_nat_nextaddr() will be.                                  */
 7461 /* ------------------------------------------------------------------------ */
 7462 static int
 7463 ipf_nat_nextaddrinit(ipf_main_softc_t *softc, char *base, nat_addr_t *na,
 7464         int initial, void *ifp)
 7465 {
 7466 
 7467         switch (na->na_atype)
 7468         {
 7469         case FRI_LOOKUP :
 7470                 if (na->na_subtype == 0) {
 7471                         na->na_ptr = ipf_lookup_res_num(softc, IPL_LOGNAT,
 7472                                                         na->na_type,
 7473                                                         na->na_num,
 7474                                                         &na->na_func);
 7475                 } else if (na->na_subtype == 1) {
 7476                         na->na_ptr = ipf_lookup_res_name(softc, IPL_LOGNAT,
 7477                                                          na->na_type,
 7478                                                          base + na->na_num,
 7479                                                          &na->na_func);
 7480                 }
 7481                 if (na->na_func == NULL) {
 7482                         IPFERROR(60060);
 7483                         return (ESRCH);
 7484                 }
 7485                 if (na->na_ptr == NULL) {
 7486                         IPFERROR(60056);
 7487                         return (ESRCH);
 7488                 }
 7489                 break;
 7490 
 7491         case FRI_DYNAMIC :
 7492         case FRI_BROADCAST :
 7493         case FRI_NETWORK :
 7494         case FRI_NETMASKED :
 7495         case FRI_PEERADDR :
 7496                 if (ifp != NULL)
 7497                         (void )ipf_ifpaddr(softc, 4, na->na_atype, ifp,
 7498                                            &na->na_addr[0], &na->na_addr[1]);
 7499                 break;
 7500 
 7501         case FRI_SPLIT :
 7502         case FRI_RANGE :
 7503                 if (initial)
 7504                         na->na_nextip = ntohl(na->na_addr[0].in4.s_addr);
 7505                 break;
 7506 
 7507         case FRI_NONE :
 7508                 na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr;
 7509                 return (0);
 7510 
 7511         case FRI_NORMAL :
 7512                 na->na_addr[0].in4.s_addr &= na->na_addr[1].in4.s_addr;
 7513                 break;
 7514 
 7515         default :
 7516                 IPFERROR(60054);
 7517                 return (EINVAL);
 7518         }
 7519 
 7520         if (initial && (na->na_atype == FRI_NORMAL)) {
 7521                 if (na->na_addr[0].in4.s_addr == 0) {
 7522                         if ((na->na_addr[1].in4.s_addr == 0xffffffff) ||
 7523                             (na->na_addr[1].in4.s_addr == 0)) {
 7524                                 return (0);
 7525                         }
 7526                 }
 7527 
 7528                 if (na->na_addr[1].in4.s_addr == 0xffffffff) {
 7529                         na->na_nextip = ntohl(na->na_addr[0].in4.s_addr);
 7530                 } else {
 7531                         na->na_nextip = ntohl(na->na_addr[0].in4.s_addr) + 1;
 7532                 }
 7533         }
 7534 
 7535         return (0);
 7536 }
 7537 
 7538 
 7539 /* ------------------------------------------------------------------------ */
 7540 /* Function:    ipf_nat_matchflush                                          */
 7541 /* Returns:     int - -1 == error, 0 == success                             */
 7542 /* Parameters:  softc(I) - pointer to soft context main structure           */
 7543 /*              softn(I) - pointer to NAT context structure                 */
 7544 /*              nat(I)   - pointer to current NAT session                   */
 7545 /*                                                                          */
 7546 /* ------------------------------------------------------------------------ */
 7547 static int
 7548 ipf_nat_matchflush(ipf_main_softc_t *softc, ipf_nat_softc_t *softn,
 7549         caddr_t data)
 7550 {
 7551         int *array, flushed, error;
 7552         nat_t *nat, *natnext;
 7553         ipfobj_t obj;
 7554 
 7555         error = ipf_matcharray_load(softc, data, &obj, &array);
 7556         if (error != 0)
 7557                 return (error);
 7558 
 7559         flushed = 0;
 7560 
 7561         for (nat = softn->ipf_nat_instances; nat != NULL; nat = natnext) {
 7562                 natnext = nat->nat_next;
 7563                 if (ipf_nat_matcharray(nat, array, softc->ipf_ticks) == 0) {
 7564                         ipf_nat_delete(softc, nat, NL_FLUSH);
 7565                         flushed++;
 7566                 }
 7567         }
 7568 
 7569         obj.ipfo_retval = flushed;
 7570         error = BCOPYOUT(&obj, data, sizeof(obj));
 7571 
 7572         KFREES(array, array[0] * sizeof(*array));
 7573 
 7574         return (error);
 7575 }
 7576 
 7577 
 7578 /* ------------------------------------------------------------------------ */
 7579 /* Function:    ipf_nat_matcharray                                          */
 7580 /* Returns:     int - -1 == error, 0 == success                             */
 7581 /* Parameters:  fin(I) - pointer to packet information                      */
 7582 /*              nat(I) - pointer to current NAT session                     */
 7583 /*                                                                          */
 7584 /* ------------------------------------------------------------------------ */
 7585 static int
 7586 ipf_nat_matcharray(nat_t *nat, int *array, u_long ticks)
 7587 {
 7588         int i, n, *x, e, p;
 7589 
 7590         e = 0;
 7591         n = array[0];
 7592         x = array + 1;
 7593 
 7594         for (; n > 0; x += 3 + x[2]) {
 7595                 if (x[0] == IPF_EXP_END)
 7596                         break;
 7597                 e = 0;
 7598 
 7599                 n -= x[2] + 3;
 7600                 if (n < 0)
 7601                         break;
 7602 
 7603                 p = x[0] >> 16;
 7604                 if (p != 0 && p != nat->nat_pr[1])
 7605                         break;
 7606 
 7607                 switch (x[0])
 7608                 {
 7609                 case IPF_EXP_IP_PR :
 7610                         for (i = 0; !e && i < x[2]; i++) {
 7611                                 e |= (nat->nat_pr[1] == x[i + 3]);
 7612                         }
 7613                         break;
 7614 
 7615                 case IPF_EXP_IP_SRCADDR :
 7616                         if (nat->nat_v[0] == 4) {
 7617                                 for (i = 0; !e && i < x[2]; i++) {
 7618                                         e |= ((nat->nat_osrcaddr & x[i + 4]) ==
 7619                                               x[i + 3]);
 7620                                 }
 7621                         }
 7622                         if (nat->nat_v[1] == 4) {
 7623                                 for (i = 0; !e && i < x[2]; i++) {
 7624                                         e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
 7625                                               x[i + 3]);
 7626                                 }
 7627                         }
 7628                         break;
 7629 
 7630                 case IPF_EXP_IP_DSTADDR :
 7631                         if (nat->nat_v[0] == 4) {
 7632                                 for (i = 0; !e && i < x[2]; i++) {
 7633                                         e |= ((nat->nat_odstaddr & x[i + 4]) ==
 7634                                               x[i + 3]);
 7635                                 }
 7636                         }
 7637                         if (nat->nat_v[1] == 4) {
 7638                                 for (i = 0; !e && i < x[2]; i++) {
 7639                                         e |= ((nat->nat_ndstaddr & x[i + 4]) ==
 7640                                               x[i + 3]);
 7641                                 }
 7642                         }
 7643                         break;
 7644 
 7645                 case IPF_EXP_IP_ADDR :
 7646                         for (i = 0; !e && i < x[2]; i++) {
 7647                                 if (nat->nat_v[0] == 4) {
 7648                                         e |= ((nat->nat_osrcaddr & x[i + 4]) ==
 7649                                               x[i + 3]);
 7650                                 }
 7651                                 if (nat->nat_v[1] == 4) {
 7652                                         e |= ((nat->nat_nsrcaddr & x[i + 4]) ==
 7653                                               x[i + 3]);
 7654                                 }
 7655                                 if (nat->nat_v[0] == 4) {
 7656                                         e |= ((nat->nat_odstaddr & x[i + 4]) ==
 7657                                               x[i + 3]);
 7658                                 }
 7659                                 if (nat->nat_v[1] == 4) {
 7660                                         e |= ((nat->nat_ndstaddr & x[i + 4]) ==
 7661                                               x[i + 3]);
 7662                                 }
 7663                         }
 7664                         break;
 7665 
 7666 #ifdef USE_INET6
 7667                 case IPF_EXP_IP6_SRCADDR :
 7668                         if (nat->nat_v[0] == 6) {
 7669                                 for (i = 0; !e && i < x[3]; i++) {
 7670                                         e |= IP6_MASKEQ(&nat->nat_osrc6,
 7671                                                         x + i + 7, x + i + 3);
 7672                                 }
 7673                         }
 7674                         if (nat->nat_v[1] == 6) {
 7675                                 for (i = 0; !e && i < x[3]; i++) {
 7676                                         e |= IP6_MASKEQ(&nat->nat_nsrc6,
 7677                                                         x + i + 7, x + i + 3);
 7678                                 }
 7679                         }
 7680                         break;
 7681 
 7682                 case IPF_EXP_IP6_DSTADDR :
 7683                         if (nat->nat_v[0] == 6) {
 7684                                 for (i = 0; !e && i < x[3]; i++) {
 7685                                         e |= IP6_MASKEQ(&nat->nat_odst6,
 7686                                                         x + i + 7,
 7687                                                         x + i + 3);
 7688                                 }
 7689                         }
 7690                         if (nat->nat_v[1] == 6) {
 7691                                 for (i = 0; !e && i < x[3]; i++) {
 7692                                         e |= IP6_MASKEQ(&nat->nat_ndst6,
 7693                                                         x + i + 7,
 7694                                                         x + i + 3);
 7695                                 }
 7696                         }
 7697                         break;
 7698 
 7699                 case IPF_EXP_IP6_ADDR :
 7700                         for (i = 0; !e && i < x[3]; i++) {
 7701                                 if (nat->nat_v[0] == 6) {
 7702                                         e |= IP6_MASKEQ(&nat->nat_osrc6,
 7703                                                         x + i + 7,
 7704                                                         x + i + 3);
 7705                                 }
 7706                                 if (nat->nat_v[0] == 6) {
 7707                                         e |= IP6_MASKEQ(&nat->nat_odst6,
 7708                                                         x + i + 7,
 7709                                                         x + i + 3);
 7710                                 }
 7711                                 if (nat->nat_v[1] == 6) {
 7712                                         e |= IP6_MASKEQ(&nat->nat_nsrc6,
 7713                                                         x + i + 7,
 7714                                                         x + i + 3);
 7715                                 }
 7716                                 if (nat->nat_v[1] == 6) {
 7717                                         e |= IP6_MASKEQ(&nat->nat_ndst6,
 7718                                                         x + i + 7,
 7719                                                         x + i + 3);
 7720                                 }
 7721                         }
 7722                         break;
 7723 #endif
 7724 
 7725                 case IPF_EXP_UDP_PORT :
 7726                 case IPF_EXP_TCP_PORT :
 7727                         for (i = 0; !e && i < x[2]; i++) {
 7728                                 e |= (nat->nat_nsport == x[i + 3]) ||
 7729                                      (nat->nat_ndport == x[i + 3]);
 7730                         }
 7731                         break;
 7732 
 7733                 case IPF_EXP_UDP_SPORT :
 7734                 case IPF_EXP_TCP_SPORT :
 7735                         for (i = 0; !e && i < x[2]; i++) {
 7736                                 e |= (nat->nat_nsport == x[i + 3]);
 7737                         }
 7738                         break;
 7739 
 7740                 case IPF_EXP_UDP_DPORT :
 7741                 case IPF_EXP_TCP_DPORT :
 7742                         for (i = 0; !e && i < x[2]; i++) {
 7743                                 e |= (nat->nat_ndport == x[i + 3]);
 7744                         }
 7745                         break;
 7746 
 7747                 case IPF_EXP_TCP_STATE :
 7748                         for (i = 0; !e && i < x[2]; i++) {
 7749                                 e |= (nat->nat_tcpstate[0] == x[i + 3]) ||
 7750                                      (nat->nat_tcpstate[1] == x[i + 3]);
 7751                         }
 7752                         break;
 7753 
 7754                 case IPF_EXP_IDLE_GT :
 7755                         e |= (ticks - nat->nat_touched > x[3]);
 7756                         break;
 7757                 }
 7758                 e ^= x[1];
 7759 
 7760                 if (!e)
 7761                         break;
 7762         }
 7763 
 7764         return (e);
 7765 }
 7766 
 7767 
 7768 /* ------------------------------------------------------------------------ */
 7769 /* Function:    ipf_nat_gettable                                            */
 7770 /* Returns:     int     - 0 = success, else error                           */
 7771 /* Parameters:  softc(I) - pointer to soft context main structure           */
 7772 /*              softn(I) - pointer to NAT context structure                 */
 7773 /*              data(I)  - pointer to ioctl data                            */
 7774 /*                                                                          */
 7775 /* This function handles ioctl requests for tables of nat information.      */
 7776 /* At present the only table it deals with is the hash bucket statistics.   */
 7777 /* ------------------------------------------------------------------------ */
 7778 static int
 7779 ipf_nat_gettable(ipf_main_softc_t *softc, ipf_nat_softc_t *softn, char *data)
 7780 {
 7781         ipftable_t table;
 7782         int error;
 7783 
 7784         error = ipf_inobj(softc, data, NULL, &table, IPFOBJ_GTABLE);
 7785         if (error != 0)
 7786                 return (error);
 7787 
 7788         switch (table.ita_type)
 7789         {
 7790         case IPFTABLE_BUCKETS_NATIN :
 7791                 error = COPYOUT(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
 7792                                 table.ita_table,
 7793                                 softn->ipf_nat_table_sz * sizeof(u_int));
 7794                 break;
 7795 
 7796         case IPFTABLE_BUCKETS_NATOUT :
 7797                 error = COPYOUT(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
 7798                                 table.ita_table,
 7799                                 softn->ipf_nat_table_sz * sizeof(u_int));
 7800                 break;
 7801 
 7802         default :
 7803                 IPFERROR(60058);
 7804                 return (EINVAL);
 7805         }
 7806 
 7807         if (error != 0) {
 7808                 IPFERROR(60059);
 7809                 error = EFAULT;
 7810         }
 7811         return (error);
 7812 }
 7813 
 7814 
 7815 /* ------------------------------------------------------------------------ */
 7816 /* Function:    ipf_nat_settimeout                                          */
 7817 /* Returns:     int  - 0 = success, else failure                            */
 7818 /* Parameters:  softc(I) - pointer to soft context main structure           */
 7819 /*              t(I) - pointer to tunable                                   */
 7820 /*              p(I) - pointer to new tuning data                           */
 7821 /*                                                                          */
 7822 /* Apply the timeout change to the NAT timeout queues.                      */
 7823 /* ------------------------------------------------------------------------ */
 7824 int
 7825 ipf_nat_settimeout(struct ipf_main_softc_s *softc, ipftuneable_t *t,
 7826         ipftuneval_t *p)
 7827 {
 7828         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 7829 
 7830         if (!strncmp(t->ipft_name, "tcp_", 4))
 7831                 return (ipf_settimeout_tcp(t, p, softn->ipf_nat_tcptq));
 7832 
 7833         if (!strcmp(t->ipft_name, "udp_timeout")) {
 7834                 ipf_apply_timeout(&softn->ipf_nat_udptq, p->ipftu_int);
 7835         } else if (!strcmp(t->ipft_name, "udp_ack_timeout")) {
 7836                 ipf_apply_timeout(&softn->ipf_nat_udpacktq, p->ipftu_int);
 7837         } else if (!strcmp(t->ipft_name, "icmp_timeout")) {
 7838                 ipf_apply_timeout(&softn->ipf_nat_icmptq, p->ipftu_int);
 7839         } else if (!strcmp(t->ipft_name, "icmp_ack_timeout")) {
 7840                 ipf_apply_timeout(&softn->ipf_nat_icmpacktq, p->ipftu_int);
 7841         } else if (!strcmp(t->ipft_name, "ip_timeout")) {
 7842                 ipf_apply_timeout(&softn->ipf_nat_iptq, p->ipftu_int);
 7843         } else {
 7844                 IPFERROR(60062);
 7845                 return (ESRCH);
 7846         }
 7847         return (0);
 7848 }
 7849 
 7850 
 7851 /* ------------------------------------------------------------------------ */
 7852 /* Function:    ipf_nat_rehash                                              */
 7853 /* Returns:     int  - 0 = success, else failure                            */
 7854 /* Parameters:  softc(I) - pointer to soft context main structure           */
 7855 /*              t(I) - pointer to tunable                                   */
 7856 /*              p(I) - pointer to new tuning data                           */
 7857 /*                                                                          */
 7858 /* To change the size of the basic NAT table, we need to first allocate the */
 7859 /* new tables (lest it fails and we've got nowhere to store all of the NAT  */
 7860 /* sessions currently active) and then walk through the entire list and     */
 7861 /* insert them into the table.  There are two tables here: an inbound one   */
 7862 /* and an outbound one.  Each NAT entry goes into each table once.          */
 7863 /* ------------------------------------------------------------------------ */
 7864 int
 7865 ipf_nat_rehash(ipf_main_softc_t *softc, ipftuneable_t *t, ipftuneval_t *p)
 7866 {
 7867         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 7868         nat_t **newtab[2], *nat, **natp;
 7869         u_int *bucketlens[2];
 7870         u_int maxbucket;
 7871         u_int newsize;
 7872         int error;
 7873         u_int hv;
 7874         int i;
 7875 
 7876         newsize = p->ipftu_int;
 7877         /*
 7878          * In case there is nothing to do...
 7879          */
 7880         if (newsize == softn->ipf_nat_table_sz)
 7881                 return (0);
 7882 
 7883         newtab[0] = NULL;
 7884         newtab[1] = NULL;
 7885         bucketlens[0] = NULL;
 7886         bucketlens[1] = NULL;
 7887         /*
 7888          * 4 tables depend on the NAT table size: the inbound looking table,
 7889          * the outbound lookup table and the hash chain length for each.
 7890          */
 7891         KMALLOCS(newtab[0], nat_t **, newsize * sizeof(nat_t *));
 7892         if (newtab[0] == NULL) {
 7893                 error = 60063;
 7894                 goto badrehash;
 7895         }
 7896 
 7897         KMALLOCS(newtab[1], nat_t **, newsize * sizeof(nat_t *));
 7898         if (newtab[1] == NULL) {
 7899                 error = 60064;
 7900                 goto badrehash;
 7901         }
 7902 
 7903         KMALLOCS(bucketlens[0], u_int *, newsize * sizeof(u_int));
 7904         if (bucketlens[0] == NULL) {
 7905                 error = 60065;
 7906                 goto badrehash;
 7907         }
 7908 
 7909         KMALLOCS(bucketlens[1], u_int *, newsize * sizeof(u_int));
 7910         if (bucketlens[1] == NULL) {
 7911                 error = 60066;
 7912                 goto badrehash;
 7913         }
 7914 
 7915         /*
 7916          * Recalculate the maximum length based on the new size.
 7917          */
 7918         for (maxbucket = 0, i = newsize; i > 0; i >>= 1)
 7919                 maxbucket++;
 7920         maxbucket *= 2;
 7921 
 7922         bzero((char *)newtab[0], newsize * sizeof(nat_t *));
 7923         bzero((char *)newtab[1], newsize * sizeof(nat_t *));
 7924         bzero((char *)bucketlens[0], newsize * sizeof(u_int));
 7925         bzero((char *)bucketlens[1], newsize * sizeof(u_int));
 7926 
 7927         WRITE_ENTER(&softc->ipf_nat);
 7928 
 7929         if (softn->ipf_nat_table[0] != NULL) {
 7930                 KFREES(softn->ipf_nat_table[0],
 7931                        softn->ipf_nat_table_sz *
 7932                        sizeof(*softn->ipf_nat_table[0]));
 7933         }
 7934         softn->ipf_nat_table[0] = newtab[0];
 7935 
 7936         if (softn->ipf_nat_table[1] != NULL) {
 7937                 KFREES(softn->ipf_nat_table[1],
 7938                        softn->ipf_nat_table_sz *
 7939                        sizeof(*softn->ipf_nat_table[1]));
 7940         }
 7941         softn->ipf_nat_table[1] = newtab[1];
 7942 
 7943         if (softn->ipf_nat_stats.ns_side[0].ns_bucketlen != NULL) {
 7944                 KFREES(softn->ipf_nat_stats.ns_side[0].ns_bucketlen,
 7945                        softn->ipf_nat_table_sz * sizeof(u_int));
 7946         }
 7947         softn->ipf_nat_stats.ns_side[0].ns_bucketlen = bucketlens[0];
 7948 
 7949         if (softn->ipf_nat_stats.ns_side[1].ns_bucketlen != NULL) {
 7950                 KFREES(softn->ipf_nat_stats.ns_side[1].ns_bucketlen,
 7951                        softn->ipf_nat_table_sz * sizeof(u_int));
 7952         }
 7953         softn->ipf_nat_stats.ns_side[1].ns_bucketlen = bucketlens[1];
 7954 
 7955 #ifdef USE_INET6
 7956         if (softn->ipf_nat_stats.ns_side6[0].ns_bucketlen != NULL) {
 7957                 KFREES(softn->ipf_nat_stats.ns_side6[0].ns_bucketlen,
 7958                        softn->ipf_nat_table_sz * sizeof(u_int));
 7959         }
 7960         softn->ipf_nat_stats.ns_side6[0].ns_bucketlen = bucketlens[0];
 7961 
 7962         if (softn->ipf_nat_stats.ns_side6[1].ns_bucketlen != NULL) {
 7963                 KFREES(softn->ipf_nat_stats.ns_side6[1].ns_bucketlen,
 7964                        softn->ipf_nat_table_sz * sizeof(u_int));
 7965         }
 7966         softn->ipf_nat_stats.ns_side6[1].ns_bucketlen = bucketlens[1];
 7967 #endif
 7968 
 7969         softn->ipf_nat_maxbucket = maxbucket;
 7970         softn->ipf_nat_table_sz = newsize;
 7971         /*
 7972          * Walk through the entire list of NAT table entries and put them
 7973          * in the new NAT table, somewhere.  Because we have a new table,
 7974          * we need to restart the counter of how many chains are in use.
 7975          */
 7976         softn->ipf_nat_stats.ns_side[0].ns_inuse = 0;
 7977         softn->ipf_nat_stats.ns_side[1].ns_inuse = 0;
 7978 #ifdef USE_INET6
 7979         softn->ipf_nat_stats.ns_side6[0].ns_inuse = 0;
 7980         softn->ipf_nat_stats.ns_side6[1].ns_inuse = 0;
 7981 #endif
 7982 
 7983         for (nat = softn->ipf_nat_instances; nat != NULL; nat = nat->nat_next) {
 7984                 nat->nat_hnext[0] = NULL;
 7985                 nat->nat_phnext[0] = NULL;
 7986                 hv = nat->nat_hv[0] % softn->ipf_nat_table_sz;
 7987 
 7988                 natp = &softn->ipf_nat_table[0][hv];
 7989                 if (*natp) {
 7990                         (*natp)->nat_phnext[0] = &nat->nat_hnext[0];
 7991                 } else {
 7992                         NBUMPSIDE(0, ns_inuse);
 7993                 }
 7994                 nat->nat_phnext[0] = natp;
 7995                 nat->nat_hnext[0] = *natp;
 7996                 *natp = nat;
 7997                 NBUMPSIDE(0, ns_bucketlen[hv]);
 7998 
 7999                 nat->nat_hnext[1] = NULL;
 8000                 nat->nat_phnext[1] = NULL;
 8001                 hv = nat->nat_hv[1] % softn->ipf_nat_table_sz;
 8002 
 8003                 natp = &softn->ipf_nat_table[1][hv];
 8004                 if (*natp) {
 8005                         (*natp)->nat_phnext[1] = &nat->nat_hnext[1];
 8006                 } else {
 8007                         NBUMPSIDE(1, ns_inuse);
 8008                 }
 8009                 nat->nat_phnext[1] = natp;
 8010                 nat->nat_hnext[1] = *natp;
 8011                 *natp = nat;
 8012                 NBUMPSIDE(1, ns_bucketlen[hv]);
 8013         }
 8014         RWLOCK_EXIT(&softc->ipf_nat);
 8015 
 8016         return (0);
 8017 
 8018 badrehash:
 8019         if (bucketlens[1] != NULL) {
 8020                 KFREES(bucketlens[0], newsize * sizeof(u_int));
 8021         }
 8022         if (bucketlens[0] != NULL) {
 8023                 KFREES(bucketlens[0], newsize * sizeof(u_int));
 8024         }
 8025         if (newtab[0] != NULL) {
 8026                 KFREES(newtab[0], newsize * sizeof(nat_t *));
 8027         }
 8028         if (newtab[1] != NULL) {
 8029                 KFREES(newtab[1], newsize * sizeof(nat_t *));
 8030         }
 8031         IPFERROR(error);
 8032         return (ENOMEM);
 8033 }
 8034 
 8035 
 8036 /* ------------------------------------------------------------------------ */
 8037 /* Function:    ipf_nat_rehash_rules                                        */
 8038 /* Returns:     int  - 0 = success, else failure                            */
 8039 /* Parameters:  softc(I) - pointer to soft context main structure           */
 8040 /*              t(I) - pointer to tunable                                   */
 8041 /*              p(I) - pointer to new tuning data                           */
 8042 /*                                                                          */
 8043 /* All of the NAT rules hang off of a hash table that is searched with a    */
 8044 /* hash on address after the netmask is applied.  There is a different table*/
 8045 /* for both inbound rules (rdr) and outbound (map.)  The resizing will only */
 8046 /* affect one of these two tables.                                          */
 8047 /* ------------------------------------------------------------------------ */
 8048 int
 8049 ipf_nat_rehash_rules(ipf_main_softc_t *softc, ipftuneable_t *t,
 8050         ipftuneval_t *p)
 8051 {
 8052         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 8053         ipnat_t **newtab, *np, ***old, **npp;
 8054         u_int newsize;
 8055         u_int mask;
 8056         u_int hv;
 8057 
 8058         newsize = p->ipftu_int;
 8059         /*
 8060          * In case there is nothing to do...
 8061          */
 8062         if (newsize == *t->ipft_pint)
 8063                 return (0);
 8064 
 8065         /*
 8066          * All inbound rules have the NAT_REDIRECT bit set in in_redir and
 8067          * all outbound rules have either NAT_MAP or MAT_MAPBLK set.
 8068          * This if statement allows for some more generic code to be below,
 8069          * rather than two huge gobs of code that almost do the same thing.
 8070          */
 8071         if (t->ipft_pint == &softn->ipf_nat_rdrrules_sz) {
 8072                 old = &softn->ipf_nat_rdr_rules;
 8073                 mask = NAT_REDIRECT;
 8074         } else {
 8075                 old = &softn->ipf_nat_map_rules;
 8076                 mask = NAT_MAP|NAT_MAPBLK;
 8077         }
 8078 
 8079         KMALLOCS(newtab, ipnat_t **, newsize * sizeof(ipnat_t *));
 8080         if (newtab == NULL) {
 8081                 IPFERROR(60067);
 8082                 return (ENOMEM);
 8083         }
 8084 
 8085         bzero((char *)newtab, newsize * sizeof(ipnat_t *));
 8086 
 8087         WRITE_ENTER(&softc->ipf_nat);
 8088 
 8089         if (*old != NULL) {
 8090                 KFREES(*old, *t->ipft_pint * sizeof(ipnat_t **));
 8091         }
 8092         *old = newtab;
 8093         *t->ipft_pint = newsize;
 8094 
 8095         for (np = softn->ipf_nat_list; np != NULL; np = np->in_next) {
 8096                 if ((np->in_redir & mask) == 0)
 8097                         continue;
 8098 
 8099                 if (np->in_redir & NAT_REDIRECT) {
 8100                         np->in_rnext = NULL;
 8101                         hv = np->in_hv[0] % newsize;
 8102                         for (npp = newtab + hv; *npp != NULL; )
 8103                                 npp = &(*npp)->in_rnext;
 8104                         np->in_prnext = npp;
 8105                         *npp = np;
 8106                 }
 8107                 if (np->in_redir & NAT_MAP) {
 8108                         np->in_mnext = NULL;
 8109                         hv = np->in_hv[1] % newsize;
 8110                         for (npp = newtab + hv; *npp != NULL; )
 8111                                 npp = &(*npp)->in_mnext;
 8112                         np->in_pmnext = npp;
 8113                         *npp = np;
 8114                 }
 8115 
 8116         }
 8117         RWLOCK_EXIT(&softc->ipf_nat);
 8118 
 8119         return (0);
 8120 }
 8121 
 8122 
 8123 /* ------------------------------------------------------------------------ */
 8124 /* Function:    ipf_nat_hostmap_rehash                                      */
 8125 /* Returns:     int  - 0 = success, else failure                            */
 8126 /* Parameters:  softc(I) - pointer to soft context main structure           */
 8127 /*              t(I) - pointer to tunable                                   */
 8128 /*              p(I) - pointer to new tuning data                           */
 8129 /*                                                                          */
 8130 /* Allocate and populate a new hash table that will contain a reference to  */
 8131 /* all of the active IP# translations currently in place.                   */
 8132 /* ------------------------------------------------------------------------ */
 8133 int
 8134 ipf_nat_hostmap_rehash(ipf_main_softc_t *softc, ipftuneable_t *t,
 8135         ipftuneval_t *p)
 8136 {
 8137         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 8138         hostmap_t *hm, **newtab;
 8139         u_int newsize;
 8140         u_int hv;
 8141 
 8142         newsize = p->ipftu_int;
 8143         /*
 8144          * In case there is nothing to do...
 8145          */
 8146         if (newsize == *t->ipft_pint)
 8147                 return (0);
 8148 
 8149         KMALLOCS(newtab, hostmap_t **, newsize * sizeof(hostmap_t *));
 8150         if (newtab == NULL) {
 8151                 IPFERROR(60068);
 8152                 return (ENOMEM);
 8153         }
 8154 
 8155         bzero((char *)newtab, newsize * sizeof(hostmap_t *));
 8156 
 8157         WRITE_ENTER(&softc->ipf_nat);
 8158         if (softn->ipf_hm_maptable != NULL) {
 8159                 KFREES(softn->ipf_hm_maptable,
 8160                        softn->ipf_nat_hostmap_sz * sizeof(hostmap_t *));
 8161         }
 8162         softn->ipf_hm_maptable = newtab;
 8163         softn->ipf_nat_hostmap_sz = newsize;
 8164 
 8165         for (hm = softn->ipf_hm_maplist; hm != NULL; hm = hm->hm_next) {
 8166                 hv = hm->hm_hv % softn->ipf_nat_hostmap_sz;
 8167                 hm->hm_hnext = softn->ipf_hm_maptable[hv];
 8168                 hm->hm_phnext = softn->ipf_hm_maptable + hv;
 8169                 if (softn->ipf_hm_maptable[hv] != NULL)
 8170                         softn->ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext;
 8171                 softn->ipf_hm_maptable[hv] = hm;
 8172         }
 8173         RWLOCK_EXIT(&softc->ipf_nat);
 8174 
 8175         return (0);
 8176 }
 8177 
 8178 
 8179 /* ------------------------------------------------------------------------ */
 8180 /* Function:    ipf_nat_add_tq                                              */
 8181 /* Parameters:  softc(I) - pointer to soft context main structure           */
 8182 /*                                                                          */
 8183 /* ------------------------------------------------------------------------ */
 8184 ipftq_t *
 8185 ipf_nat_add_tq(ipf_main_softc_t *softc, int ttl)
 8186 {
 8187         ipf_nat_softc_t *softs = softc->ipf_nat_soft;
 8188 
 8189         return (ipf_addtimeoutqueue(softc, &softs->ipf_nat_utqe, ttl));
 8190 }
 8191 
 8192 /* ------------------------------------------------------------------------ */
 8193 /* Function:    ipf_nat_uncreate                                            */
 8194 /* Returns:     Nil                                                         */
 8195 /* Parameters:  fin(I) - pointer to packet information                      */
 8196 /*                                                                          */
 8197 /* This function is used to remove a NAT entry from the NAT table when we   */
 8198 /* decide that the create was actually in error. It is thus assumed that    */
 8199 /* fin_flx will have both FI_NATED and FI_NATNEW set. Because we're dealing */
 8200 /* with the translated packet (not the original), we have to reverse the    */
 8201 /* lookup. Although doing the lookup is expensive (relatively speaking), it */
 8202 /* is not anticipated that this will be a frequent occurance for normal     */
 8203 /* traffic patterns.                                                        */
 8204 /* ------------------------------------------------------------------------ */
 8205 void
 8206 ipf_nat_uncreate(fr_info_t *fin)
 8207 {
 8208         ipf_main_softc_t *softc = fin->fin_main_soft;
 8209         ipf_nat_softc_t *softn = softc->ipf_nat_soft;
 8210         int nflags;
 8211         nat_t *nat;
 8212 
 8213         switch (fin->fin_p)
 8214         {
 8215         case IPPROTO_TCP :
 8216                 nflags = IPN_TCP;
 8217                 break;
 8218         case IPPROTO_UDP :
 8219                 nflags = IPN_UDP;
 8220                 break;
 8221         default :
 8222                 nflags = 0;
 8223                 break;
 8224         }
 8225 
 8226         WRITE_ENTER(&softc->ipf_nat);
 8227 
 8228         if (fin->fin_out == 0) {
 8229                 nat = ipf_nat_outlookup(fin, nflags, (u_int)fin->fin_p,
 8230                                         fin->fin_dst, fin->fin_src);
 8231         } else {
 8232                 nat = ipf_nat_inlookup(fin, nflags, (u_int)fin->fin_p,
 8233                                        fin->fin_src, fin->fin_dst);
 8234         }
 8235 
 8236         if (nat != NULL) {
 8237                 NBUMPSIDE(fin->fin_out, ns_uncreate[0]);
 8238                 ipf_nat_delete(softc, nat, NL_DESTROY);
 8239         } else {
 8240                 NBUMPSIDE(fin->fin_out, ns_uncreate[1]);
 8241         }
 8242 
 8243         RWLOCK_EXIT(&softc->ipf_nat);
 8244 }
 8245 
 8246 
 8247 /* ------------------------------------------------------------------------ */
 8248 /* Function:    ipf_nat_cmp_rules                                           */
 8249 /* Returns:     int   - 0 == success, else rules do not match.              */
 8250 /* Parameters:  n1(I) - first rule to compare                               */
 8251 /*              n2(I) - first rule to compare                               */
 8252 /*                                                                          */
 8253 /* Compare two rules using pointers to each rule. A straight bcmp will not  */
 8254 /* work as some fields (such as in_dst, in_pkts) actually do change once    */
 8255 /* the rule has been loaded into the kernel. Whilst this function returns   */
 8256 /* various non-zero returns, they're strictly to aid in debugging. Use of   */
 8257 /* this function should simply care if the result is zero or not.           */
 8258 /* ------------------------------------------------------------------------ */
 8259 static int
 8260 ipf_nat_cmp_rules(ipnat_t *n1, ipnat_t *n2)
 8261 {
 8262         if (n1->in_size != n2->in_size)
 8263                 return (1);
 8264 
 8265         if (bcmp((char *)&n1->in_v, (char *)&n2->in_v,
 8266                  offsetof(ipnat_t, in_ndst) - offsetof(ipnat_t, in_v)) != 0)
 8267                 return (2);
 8268 
 8269         if (bcmp((char *)&n1->in_tuc, (char *)&n2->in_tuc,
 8270                  n1->in_size - offsetof(ipnat_t, in_tuc)) != 0)
 8271                 return (3);
 8272         if (n1->in_ndst.na_atype != n2->in_ndst.na_atype)
 8273                 return (5);
 8274         if (n1->in_ndst.na_function != n2->in_ndst.na_function)
 8275                 return (6);
 8276         if (bcmp((char *)&n1->in_ndst.na_addr, (char *)&n2->in_ndst.na_addr,
 8277                  sizeof(n1->in_ndst.na_addr)))
 8278                 return (7);
 8279         if (n1->in_nsrc.na_atype != n2->in_nsrc.na_atype)
 8280                 return (8);
 8281         if (n1->in_nsrc.na_function != n2->in_nsrc.na_function)
 8282                 return (9);
 8283         if (bcmp((char *)&n1->in_nsrc.na_addr, (char *)&n2->in_nsrc.na_addr,
 8284                  sizeof(n1->in_nsrc.na_addr)))
 8285                 return (10);
 8286         if (n1->in_odst.na_atype != n2->in_odst.na_atype)
 8287                 return (11);
 8288         if (n1->in_odst.na_function != n2->in_odst.na_function)
 8289                 return (12);
 8290         if (bcmp((char *)&n1->in_odst.na_addr, (char *)&n2->in_odst.na_addr,
 8291                  sizeof(n1->in_odst.na_addr)))
 8292                 return (13);
 8293         if (n1->in_osrc.na_atype != n2->in_osrc.na_atype)
 8294                 return (14);
 8295         if (n1->in_osrc.na_function != n2->in_osrc.na_function)
 8296                 return (15);
 8297         if (bcmp((char *)&n1->in_osrc.na_addr, (char *)&n2->in_osrc.na_addr,
 8298                  sizeof(n1->in_osrc.na_addr)))
 8299                 return (16);
 8300         return (0);
 8301 }
 8302 
 8303 
 8304 /* ------------------------------------------------------------------------ */
 8305 /* Function:    ipf_nat_rule_init                                           */
 8306 /* Returns:     int   - 0 == success, else rules do not match.              */
 8307 /* Parameters:  softc(I) - pointer to soft context main structure           */
 8308 /*              softn(I) - pointer to NAT context structure                 */
 8309 /*              n(I)     - first rule to compare                            */
 8310 /*                                                                          */
 8311 /* ------------------------------------------------------------------------ */
 8312 static int
 8313 ipf_nat_rule_init(ipf_main_softc_t *softc, ipf_nat_softc_t *softn,
 8314         ipnat_t *n)
 8315 {
 8316         int error = 0;
 8317 
 8318         if ((n->in_flags & IPN_SIPRANGE) != 0)
 8319                 n->in_nsrcatype = FRI_RANGE;
 8320 
 8321         if ((n->in_flags & IPN_DIPRANGE) != 0)
 8322                 n->in_ndstatype = FRI_RANGE;
 8323 
 8324         if ((n->in_flags & IPN_SPLIT) != 0)
 8325                 n->in_ndstatype = FRI_SPLIT;
 8326 
 8327         if ((n->in_redir & (NAT_MAP|NAT_REWRITE|NAT_DIVERTUDP)) != 0)
 8328                 n->in_spnext = n->in_spmin;
 8329 
 8330         if ((n->in_redir & (NAT_REWRITE|NAT_DIVERTUDP)) != 0) {
 8331                 n->in_dpnext = n->in_dpmin;
 8332         } else if (n->in_redir == NAT_REDIRECT) {
 8333                 n->in_dpnext = n->in_dpmin;
 8334         }
 8335 
 8336         n->in_stepnext = 0;
 8337 
 8338         switch (n->in_v[0])
 8339         {
 8340         case 4 :
 8341                 error = ipf_nat_ruleaddrinit(softc, softn, n);
 8342                 if (error != 0)
 8343                         return (error);
 8344                 break;
 8345 #ifdef USE_INET6
 8346         case 6 :
 8347                 error = ipf_nat6_ruleaddrinit(softc, softn, n);
 8348                 if (error != 0)
 8349                         return (error);
 8350                 break;
 8351 #endif
 8352         default :
 8353                 break;
 8354         }
 8355 
 8356         if (n->in_redir == (NAT_DIVERTUDP|NAT_MAP)) {
 8357                 /*
 8358                  * Prerecord whether or not the destination of the divert
 8359                  * is local or not to the interface the packet is going
 8360                  * to be sent out.
 8361                  */
 8362                 n->in_dlocal = ipf_deliverlocal(softc, n->in_v[1],
 8363                                                 n->in_ifps[1], &n->in_ndstip6);
 8364         }
 8365 
 8366         return (error);
 8367 }
 8368 
 8369 
 8370 /* ------------------------------------------------------------------------ */
 8371 /* Function:    ipf_nat_rule_fini                                           */
 8372 /* Returns:     int   - 0 == success, else rules do not match.              */
 8373 /* Parameters:  softc(I) - pointer to soft context main structure           */
 8374 /*              n(I)     - rule to work on                                  */
 8375 /*                                                                          */
 8376 /* This function is used to release any objects that were referenced during */
 8377 /* the rule initialisation. This is useful both when free'ing the rule and  */
 8378 /* when handling ioctls that need to initialise these fields but not        */
 8379 /* actually use them after the ioctl processing has finished.               */
 8380 /* ------------------------------------------------------------------------ */
 8381 static void
 8382 ipf_nat_rule_fini(ipf_main_softc_t *softc, ipnat_t *n)
 8383 {
 8384         if (n->in_odst.na_atype == FRI_LOOKUP && n->in_odst.na_ptr != NULL)
 8385                 ipf_lookup_deref(softc, n->in_odst.na_type, n->in_odst.na_ptr);
 8386 
 8387         if (n->in_osrc.na_atype == FRI_LOOKUP && n->in_osrc.na_ptr != NULL)
 8388                 ipf_lookup_deref(softc, n->in_osrc.na_type, n->in_osrc.na_ptr);
 8389 
 8390         if (n->in_ndst.na_atype == FRI_LOOKUP && n->in_ndst.na_ptr != NULL)
 8391                 ipf_lookup_deref(softc, n->in_ndst.na_type, n->in_ndst.na_ptr);
 8392 
 8393         if (n->in_nsrc.na_atype == FRI_LOOKUP && n->in_nsrc.na_ptr != NULL)
 8394                 ipf_lookup_deref(softc, n->in_nsrc.na_type, n->in_nsrc.na_ptr);
 8395 
 8396         if (n->in_divmp != NULL)
 8397                 FREE_MB_T(n->in_divmp);
 8398 }

Cache object: 86353a539b052a66d2e362de1c665c3f


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