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