[BACK]Return to ip_nat.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / external / bsd / ipf / netinet

Annotation of src/sys/external/bsd/ipf/netinet/ip_nat.c, Revision 1.6.2.1

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

CVSweb <webmaster@jp.NetBSD.org>