Home | History | Annotate | Download | only in ipf
      1      0    stevel /*
      2   6295  an207044  * Copyright (C) 1995-2004 by Darren Reed.
      3      0    stevel  *
      4      0    stevel  * See the IPFILTER.LICENCE file for details on licencing.
      5      0    stevel  *
      6   8624    Darren  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
      7      0    stevel  * Use is subject to license terms.
      8      0    stevel  */
      9      0    stevel 
     10      0    stevel #if defined(KERNEL) || defined(_KERNEL)
     11      0    stevel # undef KERNEL
     12      0    stevel # undef _KERNEL
     13      0    stevel # define        KERNEL	1
     14      0    stevel # define        _KERNEL	1
     15      0    stevel #endif
     16      0    stevel #include <sys/errno.h>
     17      0    stevel #include <sys/types.h>
     18      0    stevel #include <sys/param.h>
     19      0    stevel #include <sys/time.h>
     20      0    stevel #include <sys/file.h>
     21      0    stevel #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
     22      0    stevel     defined(_KERNEL)
     23      0    stevel # include "opt_ipfilter_log.h"
     24      0    stevel #endif
     25      0    stevel #if !defined(_KERNEL)
     26      0    stevel # include <stdio.h>
     27      0    stevel # include <string.h>
     28      0    stevel # include <stdlib.h>
     29      0    stevel # define _KERNEL
     30      0    stevel # ifdef __OpenBSD__
     31      0    stevel struct file;
     32      0    stevel # endif
     33      0    stevel # include <sys/uio.h>
     34      0    stevel # undef _KERNEL
     35      0    stevel #endif
     36      0    stevel #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
     37      0    stevel # include <sys/filio.h>
     38      0    stevel # include <sys/fcntl.h>
     39      0    stevel #else
     40      0    stevel # include <sys/ioctl.h>
     41      0    stevel #endif
     42   2393  yz155240 #if !defined(AIX)
     43   2393  yz155240 # include <sys/fcntl.h>
     44   2393  yz155240 #endif
     45   2393  yz155240 #if !defined(linux)
     46   2393  yz155240 # include <sys/protosw.h>
     47   2393  yz155240 #endif
     48      0    stevel #include <sys/socket.h>
     49      0    stevel #if defined(_KERNEL)
     50      0    stevel # include <sys/systm.h>
     51      0    stevel # if !defined(__SVR4) && !defined(__svr4__)
     52      0    stevel #  include <sys/mbuf.h>
     53      0    stevel # endif
     54      0    stevel #endif
     55      0    stevel #if defined(__SVR4) || defined(__svr4__)
     56      0    stevel # include <sys/filio.h>
     57      0    stevel # include <sys/byteorder.h>
     58      0    stevel # ifdef _KERNEL
     59      0    stevel #  include <sys/dditypes.h>
     60      0    stevel # endif
     61      0    stevel # include <sys/stream.h>
     62      0    stevel # include <sys/kmem.h>
     63      0    stevel #endif
     64      0    stevel #if __FreeBSD_version >= 300000
     65      0    stevel # include <sys/queue.h>
     66      0    stevel #endif
     67      0    stevel #include <net/if.h>
     68      0    stevel #if __FreeBSD_version >= 300000
     69      0    stevel # include <net/if_var.h>
     70      0    stevel # if defined(_KERNEL) && !defined(IPFILTER_LKM)
     71      0    stevel #  include "opt_ipfilter.h"
     72      0    stevel # endif
     73      0    stevel #endif
     74      0    stevel #ifdef sun
     75      0    stevel # include <net/af.h>
     76      0    stevel #endif
     77      0    stevel #include <net/route.h>
     78      0    stevel #include <netinet/in.h>
     79      0    stevel #include <netinet/in_systm.h>
     80      0    stevel #include <netinet/ip.h>
     81      0    stevel 
     82      0    stevel #ifdef RFC1825
     83      0    stevel # include <vpn/md5.h>
     84      0    stevel # include <vpn/ipsec.h>
     85      0    stevel extern struct ifnet vpnif;
     86      0    stevel #endif
     87      0    stevel 
     88   2393  yz155240 #if !defined(linux)
     89   2393  yz155240 # include <netinet/ip_var.h>
     90   2393  yz155240 #endif
     91      0    stevel #include <netinet/tcp.h>
     92      0    stevel #include <netinet/udp.h>
     93      0    stevel #include <netinet/ip_icmp.h>
     94   2393  yz155240 #include "netinet/ip_compat.h"
     95      0    stevel #include <netinet/tcpip.h>
     96      0    stevel #include "netinet/ip_fil.h"
     97      0    stevel #include "netinet/ip_nat.h"
     98      0    stevel #include "netinet/ip_frag.h"
     99      0    stevel #include "netinet/ip_state.h"
    100      0    stevel #include "netinet/ip_proxy.h"
    101   3448  dh155122 #include "netinet/ipf_stack.h"
    102      0    stevel #ifdef	IPFILTER_SYNC
    103      0    stevel #include "netinet/ip_sync.h"
    104      0    stevel #endif
    105      0    stevel #if (__FreeBSD_version >= 300000)
    106      0    stevel # include <sys/malloc.h>
    107      0    stevel #endif
    108   2393  yz155240 /* END OF INCLUDES */
    109   2393  yz155240 
    110      0    stevel #undef	SOCKADDR_IN
    111      0    stevel #define	SOCKADDR_IN	struct sockaddr_in
    112      0    stevel 
    113      0    stevel #if !defined(lint)
    114      0    stevel static const char sccsid[] = "@(#)ip_nat.c	1.11 6/5/96 (C) 1995 Darren Reed";
    115   2393  yz155240 static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.195.2.42 2005/08/11 19:51:36 darrenr Exp $";
    116      0    stevel #endif
    117      0    stevel 
    118      0    stevel 
    119      0    stevel /* ======================================================================== */
    120      0    stevel /* How the NAT is organised and works.                                      */
    121      0    stevel /*                                                                          */
    122      0    stevel /* Inside (interface y) NAT       Outside (interface x)                     */
    123      0    stevel /* -------------------- -+- -------------------------------------           */
    124      0    stevel /* Packet going          |   out, processsed by fr_checknatout() for x      */
    125      0    stevel /* ------------>         |   ------------>                                  */
    126      0    stevel /* src=10.1.1.1          |   src=192.1.1.1                                  */
    127      0    stevel /*                       |                                                  */
    128      0    stevel /*                       |   in, processed by fr_checknatin() for x         */
    129      0    stevel /* <------------         |   <------------                                  */
    130      0    stevel /* dst=10.1.1.1          |   dst=192.1.1.1                                  */
    131      0    stevel /* -------------------- -+- -------------------------------------           */
    132      0    stevel /* fr_checknatout() - changes ip_src and if required, sport                 */
    133      0    stevel /*             - creates a new mapping, if required.                        */
    134      0    stevel /* fr_checknatin()  - changes ip_dst and if required, dport                 */
    135      0    stevel /*                                                                          */
    136      0    stevel /* In the NAT table, internal source is recorded as "in" and externally     */
    137      0    stevel /* seen as "out".                                                           */
    138      0    stevel /* ======================================================================== */
    139      0    stevel 
    140   3448  dh155122 
    141   3448  dh155122 static	int	nat_clearlist __P((ipf_stack_t *));
    142   3448  dh155122 static	void	nat_addnat __P((struct ipnat *, ipf_stack_t *));
    143   3448  dh155122 static	void	nat_addrdr __P((struct ipnat *, ipf_stack_t *));
    144   3448  dh155122 static	int	fr_natgetent __P((caddr_t, ipf_stack_t *));
    145   3448  dh155122 static	int	fr_natgetsz __P((caddr_t, ipf_stack_t *));
    146   3448  dh155122 static	int	fr_natputent __P((caddr_t, int, ipf_stack_t *));
    147   3448  dh155122 static	void	nat_tabmove __P((nat_t *, ipf_stack_t *));
    148      0    stevel static	int	nat_match __P((fr_info_t *, ipnat_t *));
    149      0    stevel static	INLINE	int nat_newmap __P((fr_info_t *, nat_t *, natinfo_t *));
    150      0    stevel static	INLINE	int nat_newrdr __P((fr_info_t *, nat_t *, natinfo_t *));
    151      0    stevel static	hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr,
    152   3448  dh155122 				    struct in_addr, struct in_addr, u_32_t,
    153   3448  dh155122 				    ipf_stack_t *));
    154      0    stevel static	INLINE	int nat_icmpquerytype4 __P((int));
    155   7176  yx160601 static	int	nat_ruleaddrinit __P((ipnat_t *));
    156   7176  yx160601 static	int	nat_siocaddnat __P((ipnat_t *, ipnat_t **, int, ipf_stack_t *));
    157   7176  yx160601 static	void	nat_siocdelnat __P((ipnat_t *, ipnat_t **, int, ipf_stack_t *));
    158   3448  dh155122 static	INLINE	int nat_icmperrortype4 __P((int));
    159      0    stevel static	INLINE	int nat_finalise __P((fr_info_t *, nat_t *, natinfo_t *,
    160      0    stevel 				      tcphdr_t *, nat_t **, int));
    161   4380  jojemann static	INLINE	int nat_resolverule __P((ipnat_t *, ipf_stack_t *));
    162   2958  dr146992 static	void	nat_mssclamp __P((tcphdr_t *, u_32_t, u_short *));
    163   3448  dh155122 static	int	nat_getnext __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *));
    164   3448  dh155122 static	int	nat_iterator __P((ipftoken_t *, ipfgeniter_t *, ipf_stack_t *));
    165   8170      John static	int	nat_flushtable __P((int, ipf_stack_t *));
    166      0    stevel 
    167   6253  an207044 #define NAT_HAS_L4_CHANGED(n)	\
    168   6295  an207044  	(((n)->nat_flags & (IPN_TCPUDPICMP)) && \
    169   6295  an207044  	(n)->nat_inport != (n)->nat_outport)
    170   8170      John 
    171      0    stevel 
    172      0    stevel /* ------------------------------------------------------------------------ */
    173      0    stevel /* Function:    fr_natinit                                                  */
    174      0    stevel /* Returns:     int - 0 == success, -1 == failure                           */
    175      0    stevel /* Parameters:  Nil                                                         */
    176      0    stevel /*                                                                          */
    177      0    stevel /* Initialise all of the NAT locks, tables and other structures.            */
    178      0    stevel /* ------------------------------------------------------------------------ */
    179   3448  dh155122 int fr_natinit(ifs)
    180   3448  dh155122 ipf_stack_t *ifs;
    181      0    stevel {
    182      0    stevel 	int i;
    183      0    stevel 
    184   3448  dh155122 	KMALLOCS(ifs->ifs_nat_table[0], nat_t **,
    185   3448  dh155122 		 sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz);
    186   3448  dh155122 	if (ifs->ifs_nat_table[0] != NULL)
    187   3448  dh155122 		bzero((char *)ifs->ifs_nat_table[0],
    188   3448  dh155122 		      ifs->ifs_ipf_nattable_sz * sizeof(nat_t *));
    189      0    stevel 	else
    190      0    stevel 		return -1;
    191      0    stevel 
    192   3448  dh155122 	KMALLOCS(ifs->ifs_nat_table[1], nat_t **,
    193   3448  dh155122 		 sizeof(nat_t *) * ifs->ifs_ipf_nattable_sz);
    194   3448  dh155122 	if (ifs->ifs_nat_table[1] != NULL)
    195   3448  dh155122 		bzero((char *)ifs->ifs_nat_table[1],
    196   3448  dh155122 		      ifs->ifs_ipf_nattable_sz * sizeof(nat_t *));
    197      0    stevel 	else
    198   2393  yz155240 		return -2;
    199      0    stevel 
    200   3448  dh155122 	KMALLOCS(ifs->ifs_nat_rules, ipnat_t **,
    201   3448  dh155122 		 sizeof(ipnat_t *) * ifs->ifs_ipf_natrules_sz);
    202   3448  dh155122 	if (ifs->ifs_nat_rules != NULL)
    203   3448  dh155122 		bzero((char *)ifs->ifs_nat_rules,
    204   3448  dh155122 		      ifs->ifs_ipf_natrules_sz * sizeof(ipnat_t *));
    205      0    stevel 	else
    206   2393  yz155240 		return -3;
    207      0    stevel 
    208   3448  dh155122 	KMALLOCS(ifs->ifs_rdr_rules, ipnat_t **,
    209   3448  dh155122 		 sizeof(ipnat_t *) * ifs->ifs_ipf_rdrrules_sz);
    210   3448  dh155122 	if (ifs->ifs_rdr_rules != NULL)
    211   3448  dh155122 		bzero((char *)ifs->ifs_rdr_rules,
    212   3448  dh155122 		      ifs->ifs_ipf_rdrrules_sz * sizeof(ipnat_t *));
    213      0    stevel 	else
    214   2393  yz155240 		return -4;
    215      0    stevel 
    216   3448  dh155122 	KMALLOCS(ifs->ifs_maptable, hostmap_t **,
    217   3448  dh155122 		 sizeof(hostmap_t *) * ifs->ifs_ipf_hostmap_sz);
    218   3448  dh155122 	if (ifs->ifs_maptable != NULL)
    219   3448  dh155122 		bzero((char *)ifs->ifs_maptable,
    220   3448  dh155122 		      sizeof(hostmap_t *) * ifs->ifs_ipf_hostmap_sz);
    221      0    stevel 	else
    222   2393  yz155240 		return -5;
    223      0    stevel 
    224   3448  dh155122 	ifs->ifs_ipf_hm_maplist = NULL;
    225   3448  dh155122 
    226   3448  dh155122 	KMALLOCS(ifs->ifs_nat_stats.ns_bucketlen[0], u_long *,
    227   3448  dh155122 		 ifs->ifs_ipf_nattable_sz * sizeof(u_long));
    228   3448  dh155122 	if (ifs->ifs_nat_stats.ns_bucketlen[0] == NULL)
    229   3448  dh155122 		return -1;
    230   3448  dh155122 	bzero((char *)ifs->ifs_nat_stats.ns_bucketlen[0],
    231   3448  dh155122 	      ifs->ifs_ipf_nattable_sz * sizeof(u_long));
    232   3448  dh155122 
    233   3448  dh155122 	KMALLOCS(ifs->ifs_nat_stats.ns_bucketlen[1], u_long *,
    234   3448  dh155122 		 ifs->ifs_ipf_nattable_sz * sizeof(u_long));
    235   3448  dh155122 	if (ifs->ifs_nat_stats.ns_bucketlen[1] == NULL)
    236   3448  dh155122 		return -1;
    237   3448  dh155122 	bzero((char *)ifs->ifs_nat_stats.ns_bucketlen[1],
    238   3448  dh155122 	      ifs->ifs_ipf_nattable_sz * sizeof(u_long));
    239   3448  dh155122 
    240   3448  dh155122 	if (ifs->ifs_fr_nat_maxbucket == 0) {
    241   3448  dh155122 		for (i = ifs->ifs_ipf_nattable_sz; i > 0; i >>= 1)
    242   3448  dh155122 			ifs->ifs_fr_nat_maxbucket++;
    243   3448  dh155122 		ifs->ifs_fr_nat_maxbucket *= 2;
    244   3448  dh155122 	}
    245   3448  dh155122 
    246   3448  dh155122 	fr_sttab_init(ifs->ifs_nat_tqb, ifs);
    247      0    stevel 	/*
    248      0    stevel 	 * Increase this because we may have "keep state" following this too
    249      0    stevel 	 * and packet storms can occur if this is removed too quickly.
    250      0    stevel 	 */
    251   3448  dh155122 	ifs->ifs_nat_tqb[IPF_TCPS_CLOSED].ifq_ttl = ifs->ifs_fr_tcplastack;
    252   3448  dh155122 	ifs->ifs_nat_tqb[IPF_TCP_NSTATES - 1].ifq_next = &ifs->ifs_nat_udptq;
    253   3448  dh155122 	ifs->ifs_nat_udptq.ifq_ttl = ifs->ifs_fr_defnatage;
    254   3448  dh155122 	ifs->ifs_nat_udptq.ifq_ref = 1;
    255   3448  dh155122 	ifs->ifs_nat_udptq.ifq_head = NULL;
    256   3448  dh155122 	ifs->ifs_nat_udptq.ifq_tail = &ifs->ifs_nat_udptq.ifq_head;
    257   3448  dh155122 	MUTEX_INIT(&ifs->ifs_nat_udptq.ifq_lock, "nat ipftq udp tab");
    258   3448  dh155122 	ifs->ifs_nat_udptq.ifq_next = &ifs->ifs_nat_icmptq;
    259   3448  dh155122 	ifs->ifs_nat_icmptq.ifq_ttl = ifs->ifs_fr_defnaticmpage;
    260   3448  dh155122 	ifs->ifs_nat_icmptq.ifq_ref = 1;
    261   3448  dh155122 	ifs->ifs_nat_icmptq.ifq_head = NULL;
    262   3448  dh155122 	ifs->ifs_nat_icmptq.ifq_tail = &ifs->ifs_nat_icmptq.ifq_head;
    263   3448  dh155122 	MUTEX_INIT(&ifs->ifs_nat_icmptq.ifq_lock, "nat icmp ipftq tab");
    264   3448  dh155122 	ifs->ifs_nat_icmptq.ifq_next = &ifs->ifs_nat_iptq;
    265   3448  dh155122 	ifs->ifs_nat_iptq.ifq_ttl = ifs->ifs_fr_defnatipage;
    266   3448  dh155122 	ifs->ifs_nat_iptq.ifq_ref = 1;
    267   3448  dh155122 	ifs->ifs_nat_iptq.ifq_head = NULL;
    268   3448  dh155122 	ifs->ifs_nat_iptq.ifq_tail = &ifs->ifs_nat_iptq.ifq_head;
    269   3448  dh155122 	MUTEX_INIT(&ifs->ifs_nat_iptq.ifq_lock, "nat ip ipftq tab");
    270   3448  dh155122 	ifs->ifs_nat_iptq.ifq_next = NULL;
    271      0    stevel 
    272      0    stevel 	for (i = 0; i < IPF_TCP_NSTATES; i++) {
    273   3448  dh155122 		if (ifs->ifs_nat_tqb[i].ifq_ttl < ifs->ifs_fr_defnaticmpage)
    274   3448  dh155122 			ifs->ifs_nat_tqb[i].ifq_ttl = ifs->ifs_fr_defnaticmpage;
    275      0    stevel #ifdef LARGE_NAT
    276   3448  dh155122 		else if (ifs->ifs_nat_tqb[i].ifq_ttl > ifs->ifs_fr_defnatage)
    277   3448  dh155122 			ifs->ifs_nat_tqb[i].ifq_ttl = ifs->ifs_fr_defnatage;
    278      0    stevel #endif
    279      0    stevel 	}
    280      0    stevel 
    281      0    stevel 	/*
    282      0    stevel 	 * Increase this because we may have "keep state" following
    283      0    stevel 	 * this too and packet storms can occur if this is removed
    284      0    stevel 	 * too quickly.
    285      0    stevel 	 */
    286   3448  dh155122 	ifs->ifs_nat_tqb[IPF_TCPS_CLOSED].ifq_ttl =
    287   3448  dh155122 	    ifs->ifs_nat_tqb[IPF_TCPS_LAST_ACK].ifq_ttl;
    288   3448  dh155122 
    289   3448  dh155122 	RWLOCK_INIT(&ifs->ifs_ipf_nat, "ipf IP NAT rwlock");
    290   3448  dh155122 	RWLOCK_INIT(&ifs->ifs_ipf_natfrag, "ipf IP NAT-Frag rwlock");
    291   3448  dh155122 	MUTEX_INIT(&ifs->ifs_ipf_nat_new, "ipf nat new mutex");
    292   3448  dh155122 	MUTEX_INIT(&ifs->ifs_ipf_natio, "ipf nat io mutex");
    293   3448  dh155122 
    294   3448  dh155122 	ifs->ifs_fr_nat_init = 1;
    295   8170      John 	ifs->ifs_nat_last_force_flush = ifs->ifs_fr_ticks;
    296      0    stevel 	return 0;
    297      0    stevel }
    298      0    stevel 
    299      0    stevel 
    300      0    stevel /* ------------------------------------------------------------------------ */
    301      0    stevel /* Function:    nat_addrdr                                                  */
    302      0    stevel /* Returns:     Nil                                                         */
    303      0    stevel /* Parameters:  n(I) - pointer to NAT rule to add                           */
    304      0    stevel /*                                                                          */
    305      0    stevel /* Adds a redirect rule to the hash table of redirect rules and the list of */
    306      0    stevel /* loaded NAT rules.  Updates the bitmask indicating which netmasks are in  */
    307      0    stevel /* use by redirect rules.                                                   */
    308      0    stevel /* ------------------------------------------------------------------------ */
    309   3448  dh155122 static void nat_addrdr(n, ifs)
    310      0    stevel ipnat_t *n;
    311   3448  dh155122 ipf_stack_t *ifs;
    312      0    stevel {
    313      0    stevel 	ipnat_t **np;
    314      0    stevel 	u_32_t j;
    315      0    stevel 	u_int hv;
    316      0    stevel 	int k;
    317      0    stevel 
    318      0    stevel 	k = count4bits(n->in_outmsk);
    319      0    stevel 	if ((k >= 0) && (k != 32))
    320   3448  dh155122 		ifs->ifs_rdr_masks |= 1 << k;
    321      0    stevel 	j = (n->in_outip & n->in_outmsk);
    322   3448  dh155122 	hv = NAT_HASH_FN(j, 0, ifs->ifs_ipf_rdrrules_sz);
    323   3448  dh155122 	np = ifs->ifs_rdr_rules + hv;
    324      0    stevel 	while (*np != NULL)
    325      0    stevel 		np = &(*np)->in_rnext;
    326      0    stevel 	n->in_rnext = NULL;
    327      0    stevel 	n->in_prnext = np;
    328   2393  yz155240 	n->in_hv = hv;
    329      0    stevel 	*np = n;
    330      0    stevel }
    331      0    stevel 
    332      0    stevel 
    333      0    stevel /* ------------------------------------------------------------------------ */
    334      0    stevel /* Function:    nat_addnat                                                  */
    335      0    stevel /* Returns:     Nil                                                         */
    336      0    stevel /* Parameters:  n(I) - pointer to NAT rule to add                           */
    337      0    stevel /*                                                                          */
    338      0    stevel /* Adds a NAT map rule to the hash table of rules and the list of  loaded   */
    339      0    stevel /* NAT rules.  Updates the bitmask indicating which netmasks are in use by  */
    340      0    stevel /* redirect rules.                                                          */
    341      0    stevel /* ------------------------------------------------------------------------ */
    342   3448  dh155122 static void nat_addnat(n, ifs)
    343      0    stevel ipnat_t *n;
    344   3448  dh155122 ipf_stack_t *ifs;
    345      0    stevel {
    346      0    stevel 	ipnat_t **np;
    347      0    stevel 	u_32_t j;
    348      0    stevel 	u_int hv;
    349      0    stevel 	int k;
    350      0    stevel 
    351      0    stevel 	k = count4bits(n->in_inmsk);
    352      0    stevel 	if ((k >= 0) && (k != 32))
    353   3448  dh155122 		ifs->ifs_nat_masks |= 1 << k;
    354      0    stevel 	j = (n->in_inip & n->in_inmsk);
    355   3448  dh155122 	hv = NAT_HASH_FN(j, 0, ifs->ifs_ipf_natrules_sz);
    356   3448  dh155122 	np = ifs->ifs_nat_rules + hv;
    357      0    stevel 	while (*np != NULL)
    358      0    stevel 		np = &(*np)->in_mnext;
    359      0    stevel 	n->in_mnext = NULL;
    360      0    stevel 	n->in_pmnext = np;
    361   2393  yz155240 	n->in_hv = hv;
    362      0    stevel 	*np = n;
    363      0    stevel }
    364      0    stevel 
    365      0    stevel 
    366      0    stevel /* ------------------------------------------------------------------------ */
    367      0    stevel /* Function:    nat_delrdr                                                  */
    368      0    stevel /* Returns:     Nil                                                         */
    369      0    stevel /* Parameters:  n(I) - pointer to NAT rule to delete                        */
    370      0    stevel /*                                                                          */
    371      0    stevel /* Removes a redirect rule from the hash table of redirect rules.           */
    372      0    stevel /* ------------------------------------------------------------------------ */
    373   7176  yx160601 void nat_delrdr(n)
    374      0    stevel ipnat_t *n;
    375      0    stevel {
    376      0    stevel 	if (n->in_rnext)
    377      0    stevel 		n->in_rnext->in_prnext = n->in_prnext;
    378      0    stevel 	*n->in_prnext = n->in_rnext;
    379      0    stevel }
    380      0    stevel 
    381      0    stevel 
    382      0    stevel /* ------------------------------------------------------------------------ */
    383      0    stevel /* Function:    nat_delnat                                                  */
    384      0    stevel /* Returns:     Nil                                                         */
    385      0    stevel /* Parameters:  n(I) - pointer to NAT rule to delete                        */
    386      0    stevel /*                                                                          */
    387      0    stevel /* Removes a NAT map rule from the hash table of NAT map rules.             */
    388      0    stevel /* ------------------------------------------------------------------------ */
    389   7176  yx160601 void nat_delnat(n)
    390      0    stevel ipnat_t *n;
    391      0    stevel {
    392      0    stevel 	if (n->in_mnext != NULL)
    393      0    stevel 		n->in_mnext->in_pmnext = n->in_pmnext;
    394      0    stevel 	*n->in_pmnext = n->in_mnext;
    395      0    stevel }
    396      0    stevel 
    397      0    stevel 
    398      0    stevel /* ------------------------------------------------------------------------ */
    399      0    stevel /* Function:    nat_hostmap                                                 */
    400      0    stevel /* Returns:     struct hostmap* - NULL if no hostmap could be created,      */
    401      0    stevel /*                                else a pointer to the hostmapping to use  */
    402      0    stevel /* Parameters:  np(I)   - pointer to NAT rule                               */
    403      0    stevel /*              real(I) - real IP address                                   */
    404      0    stevel /*              map(I)  - mapped IP address                                 */
    405      0    stevel /*              port(I) - destination port number                           */
    406      0    stevel /* Write Locks: ipf_nat                                                     */
    407      0    stevel /*                                                                          */
    408      0    stevel /* Check if an ip address has already been allocated for a given mapping    */
    409      0    stevel /* that is not doing port based translation.  If is not yet allocated, then */
    410   2393  yz155240 /* create a new entry if a non-NULL NAT rule pointer has been supplied.     */
    411      0    stevel /* ------------------------------------------------------------------------ */
    412   3448  dh155122 static struct hostmap *nat_hostmap(np, src, dst, map, port, ifs)
    413      0    stevel ipnat_t *np;
    414      0    stevel struct in_addr src;
    415      0    stevel struct in_addr dst;
    416      0    stevel struct in_addr map;
    417      0    stevel u_32_t port;
    418   3448  dh155122 ipf_stack_t *ifs;
    419      0    stevel {
    420      0    stevel 	hostmap_t *hm;
    421      0    stevel 	u_int hv;
    422      0    stevel 
    423      0    stevel 	hv = (src.s_addr ^ dst.s_addr);
    424      0    stevel 	hv += src.s_addr;
    425      0    stevel 	hv += dst.s_addr;
    426      0    stevel 	hv %= HOSTMAP_SIZE;
    427   3448  dh155122 	for (hm = ifs->ifs_maptable[hv]; hm; hm = hm->hm_next)
    428      0    stevel 		if ((hm->hm_srcip.s_addr == src.s_addr) &&
    429      0    stevel 		    (hm->hm_dstip.s_addr == dst.s_addr) &&
    430      0    stevel 		    ((np == NULL) || (np == hm->hm_ipnat)) &&
    431      0    stevel 		    ((port == 0) || (port == hm->hm_port))) {
    432      0    stevel 			hm->hm_ref++;
    433      0    stevel 			return hm;
    434      0    stevel 		}
    435      0    stevel 
    436      0    stevel 	if (np == NULL)
    437      0    stevel 		return NULL;
    438      0    stevel 
    439      0    stevel 	KMALLOC(hm, hostmap_t *);
    440      0    stevel 	if (hm) {
    441   3448  dh155122 		hm->hm_hnext = ifs->ifs_ipf_hm_maplist;
    442   3448  dh155122 		hm->hm_phnext = &ifs->ifs_ipf_hm_maplist;
    443   3448  dh155122 		if (ifs->ifs_ipf_hm_maplist != NULL)
    444   3448  dh155122 			ifs->ifs_ipf_hm_maplist->hm_phnext = &hm->hm_hnext;
    445   3448  dh155122 		ifs->ifs_ipf_hm_maplist = hm;
    446   3448  dh155122 
    447   3448  dh155122 		hm->hm_next = ifs->ifs_maptable[hv];
    448   3448  dh155122 		hm->hm_pnext = ifs->ifs_maptable + hv;
    449   3448  dh155122 		if (ifs->ifs_maptable[hv] != NULL)
    450   3448  dh155122 			ifs->ifs_maptable[hv]->hm_pnext = &hm->hm_next;
    451   3448  dh155122 		ifs->ifs_maptable[hv] = hm;
    452      0    stevel 		hm->hm_ipnat = np;
    453      0    stevel 		hm->hm_srcip = src;
    454      0    stevel 		hm->hm_dstip = dst;
    455      0    stevel 		hm->hm_mapip = map;
    456      0    stevel 		hm->hm_ref = 1;
    457      0    stevel 		hm->hm_port = port;
    458   7176  yx160601 		hm->hm_v = 4;
    459      0    stevel 	}
    460      0    stevel 	return hm;
    461      0    stevel }
    462      0    stevel 
    463      0    stevel 
    464      0    stevel /* ------------------------------------------------------------------------ */
    465   5417  jojemann /* Function:    fr_hostmapdel                                              */
    466   5417  jojemann /* Returns:     Nil                                                         */
    467   5417  jojemann /* Parameters:  hmp(I) - pointer to pointer to hostmap structure            */
    468      0    stevel /* Write Locks: ipf_nat                                                     */
    469      0    stevel /*                                                                          */
    470      0    stevel /* Decrement the references to this hostmap structure by one.  If this      */
    471      0    stevel /* reaches zero then remove it and free it.                                 */
    472      0    stevel /* ------------------------------------------------------------------------ */
    473   5417  jojemann void fr_hostmapdel(hmp)
    474   5417  jojemann struct hostmap **hmp;
    475   5417  jojemann {
    476   5417  jojemann 	struct hostmap *hm;
    477   5417  jojemann 
    478   5417  jojemann 	hm = *hmp;
    479   5417  jojemann 	*hmp = NULL;
    480   5417  jojemann 
    481      0    stevel 	hm->hm_ref--;
    482      0    stevel 	if (hm->hm_ref == 0) {
    483      0    stevel 		if (hm->hm_next)
    484      0    stevel 			hm->hm_next->hm_pnext = hm->hm_pnext;
    485      0    stevel 		*hm->hm_pnext = hm->hm_next;
    486   3448  dh155122 		if (hm->hm_hnext)
    487   3448  dh155122 			hm->hm_hnext->hm_phnext = hm->hm_phnext;
    488   3448  dh155122 		*hm->hm_phnext = hm->hm_hnext;
    489      0    stevel 		KFREE(hm);
    490      0    stevel 	}
    491      0    stevel }
    492      0    stevel 
    493      0    stevel 
    494      0    stevel /* ------------------------------------------------------------------------ */
    495      0    stevel /* Function:    fix_outcksum                                                */
    496      0    stevel /* Returns:     Nil                                                         */
    497   2958  dr146992 /* Parameters:  sp(I)  - location of 16bit checksum to update               */
    498      0    stevel /*              n((I)  - amount to adjust checksum by                       */
    499      0    stevel /*                                                                          */
    500      0    stevel /* Adjusts the 16bit checksum by "n" for packets going out.                 */
    501      0    stevel /* ------------------------------------------------------------------------ */
    502   2958  dr146992 void fix_outcksum(sp, n)
    503      0    stevel u_short *sp;
    504      0    stevel u_32_t n;
    505      0    stevel {
    506      0    stevel 	u_short sumshort;
    507      0    stevel 	u_32_t sum1;
    508      0    stevel 
    509      0    stevel 	if (n == 0)
    510      0    stevel 		return;
    511      0    stevel 
    512      0    stevel 	sum1 = (~ntohs(*sp)) & 0xffff;
    513      0    stevel 	sum1 += (n);
    514      0    stevel 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
    515      0    stevel 	/* Again */
    516      0    stevel 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
    517      0    stevel 	sumshort = ~(u_short)sum1;
    518      0    stevel 	*(sp) = htons(sumshort);
    519      0    stevel }
    520      0    stevel 
    521      0    stevel 
    522      0    stevel /* ------------------------------------------------------------------------ */
    523      0    stevel /* Function:    fix_incksum                                                 */
    524      0    stevel /* Returns:     Nil                                                         */
    525   2958  dr146992 /* Parameters:  sp(I)  - location of 16bit checksum to update               */
    526      0    stevel /*              n((I)  - amount to adjust checksum by                       */
    527      0    stevel /*                                                                          */
    528      0    stevel /* Adjusts the 16bit checksum by "n" for packets going in.                  */
    529      0    stevel /* ------------------------------------------------------------------------ */
    530   2958  dr146992 void fix_incksum(sp, n)
    531      0    stevel u_short *sp;
    532      0    stevel u_32_t n;
    533      0    stevel {
    534      0    stevel 	u_short sumshort;
    535      0    stevel 	u_32_t sum1;
    536      0    stevel 
    537      0    stevel 	if (n == 0)
    538      0    stevel 		return;
    539      0    stevel 
    540      0    stevel 	sum1 = (~ntohs(*sp)) & 0xffff;
    541      0    stevel 	sum1 += ~(n) & 0xffff;
    542      0    stevel 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
    543      0    stevel 	/* Again */
    544      0    stevel 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
    545      0    stevel 	sumshort = ~(u_short)sum1;
    546      0    stevel 	*(sp) = htons(sumshort);
    547      0    stevel }
    548      0    stevel 
    549      0    stevel 
    550      0    stevel /* ------------------------------------------------------------------------ */
    551      0    stevel /* Function:    fix_datacksum                                               */
    552      0    stevel /* Returns:     Nil                                                         */
    553      0    stevel /* Parameters:  sp(I)  - location of 16bit checksum to update               */
    554      0    stevel /*              n((I)  - amount to adjust checksum by                       */
    555      0    stevel /*                                                                          */
    556      0    stevel /* Fix_datacksum is used *only* for the adjustments of checksums in the     */
    557      0    stevel /* data section of an IP packet.                                            */
    558      0    stevel /*                                                                          */
    559      0    stevel /* The only situation in which you need to do this is when NAT'ing an       */
    560      0    stevel /* ICMP error message. Such a message, contains in its body the IP header   */
    561      0    stevel /* of the original IP packet, that causes the error.                        */
    562      0    stevel /*                                                                          */
    563      0    stevel /* You can't use fix_incksum or fix_outcksum in that case, because for the  */
    564      0    stevel /* kernel the data section of the ICMP error is just data, and no special   */
    565      0    stevel /* processing like hardware cksum or ntohs processing have been done by the */
    566      0    stevel /* kernel on the data section.                                              */
    567      0    stevel /* ------------------------------------------------------------------------ */
    568      0    stevel void fix_datacksum(sp, n)
    569      0    stevel u_short *sp;
    570      0    stevel u_32_t n;
    571      0    stevel {
    572      0    stevel 	u_short sumshort;
    573      0    stevel 	u_32_t sum1;
    574      0    stevel 
    575      0    stevel 	if (n == 0)
    576      0    stevel 		return;
    577      0    stevel 
    578      0    stevel 	sum1 = (~ntohs(*sp)) & 0xffff;
    579      0    stevel 	sum1 += (n);
    580      0    stevel 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
    581      0    stevel 	/* Again */
    582      0    stevel 	sum1 = (sum1 >> 16) + (sum1 & 0xffff);
    583      0    stevel 	sumshort = ~(u_short)sum1;
    584      0    stevel 	*(sp) = htons(sumshort);
    585      0    stevel }
    586      0    stevel 
    587      0    stevel 
    588      0    stevel /* ------------------------------------------------------------------------ */
    589      0    stevel /* Function:    fr_nat_ioctl                                                */
    590      0    stevel /* Returns:     int - 0 == success, != 0 == failure                         */
    591      0    stevel /* Parameters:  data(I) - pointer to ioctl data                             */
    592      0    stevel /*              cmd(I)  - ioctl command integer                             */
    593      0    stevel /*              mode(I) - file mode bits used with open                     */
    594   8170      John /*              uid(I)  - uid of caller                                     */
    595   8170      John /*              ctx(I)  - pointer to give the uid context                   */
    596   8170      John /*              ifs     - ipf stack instance                                */
    597      0    stevel /*                                                                          */
    598      0    stevel /* Processes an ioctl call made to operate on the IP Filter NAT device.     */
    599      0    stevel /* ------------------------------------------------------------------------ */
    600   3448  dh155122 int fr_nat_ioctl(data, cmd, mode, uid, ctx, ifs)
    601   2393  yz155240 ioctlcmd_t cmd;
    602      0    stevel caddr_t data;
    603   3448  dh155122 int mode, uid;
    604   3448  dh155122 void *ctx;
    605   3448  dh155122 ipf_stack_t *ifs;
    606      0    stevel {
    607      0    stevel 	ipnat_t *nat, *nt, *n = NULL, **np = NULL;
    608      0    stevel 	int error = 0, ret, arg, getlock;
    609      0    stevel 	ipnat_t natd;
    610      0    stevel 
    611      0    stevel #if (BSD >= 199306) && defined(_KERNEL)
    612      0    stevel 	if ((securelevel >= 2) && (mode & FWRITE))
    613      0    stevel 		return EPERM;
    614      0    stevel #endif
    615      0    stevel 
    616      0    stevel #if defined(__osf__) && defined(_KERNEL)
    617      0    stevel 	getlock = 0;
    618      0    stevel #else
    619      0    stevel 	getlock = (mode & NAT_LOCKHELD) ? 0 : 1;
    620      0    stevel #endif
    621      0    stevel 
    622      0    stevel 	nat = NULL;     /* XXX gcc -Wuninitialized */
    623   2393  yz155240 	if (cmd == (ioctlcmd_t)SIOCADNAT) {
    624      0    stevel 		KMALLOC(nt, ipnat_t *);
    625      0    stevel 	} else {
    626      0    stevel 		nt = NULL;
    627      0    stevel 	}
    628      0    stevel 
    629   2393  yz155240 	if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) {
    630      0    stevel 		if (mode & NAT_SYSSPACE) {
    631      0    stevel 			bcopy(data, (char *)&natd, sizeof(natd));
    632      0    stevel 			error = 0;
    633      0    stevel 		} else {
    634      0    stevel 			error = fr_inobj(data, &natd, IPFOBJ_IPNAT);
    635      0    stevel 		}
    636      0    stevel 
    637      0    stevel 	}
    638      0    stevel 
    639      0    stevel 	if (error != 0)
    640      0    stevel 		goto done;
    641      0    stevel 
    642      0    stevel 	/*
    643      0    stevel 	 * For add/delete, look to see if the NAT entry is already present
    644      0    stevel 	 */
    645   2393  yz155240 	if ((cmd == (ioctlcmd_t)SIOCADNAT) || (cmd == (ioctlcmd_t)SIOCRMNAT)) {
    646      0    stevel 		nat = &natd;
    647   2393  yz155240 		if (nat->in_v == 0)	/* For backward compat. */
    648   2393  yz155240 			nat->in_v = 4;
    649      0    stevel 		nat->in_flags &= IPN_USERFLAGS;
    650      0    stevel 		if ((nat->in_redir & NAT_MAPBLK) == 0) {
    651      0    stevel 			if ((nat->in_flags & IPN_SPLIT) == 0)
    652      0    stevel 				nat->in_inip &= nat->in_inmsk;
    653      0    stevel 			if ((nat->in_flags & IPN_IPRANGE) == 0)
    654      0    stevel 				nat->in_outip &= nat->in_outmsk;
    655      0    stevel 		}
    656   3448  dh155122 		MUTEX_ENTER(&ifs->ifs_ipf_natio);
    657   3448  dh155122 		for (np = &ifs->ifs_nat_list; ((n = *np) != NULL);
    658   3448  dh155122 		     np = &n->in_next)
    659   5828  jojemann 			if (bcmp((char *)&nat->in_flags, (char *)&n->in_flags,
    660   5828  jojemann 			    IPN_CMPSIZ) == 0) {
    661   5828  jojemann 				if (nat->in_redir == NAT_REDIRECT &&
    662   5828  jojemann 				    nat->in_pnext != n->in_pnext)
    663   5828  jojemann 					continue;
    664   5828  jojemann 				break;
    665   5828  jojemann 			}
    666      0    stevel 	}
    667      0    stevel 
    668      0    stevel 	switch (cmd)
    669      0    stevel 	{
    670   3448  dh155122 	case SIOCGENITER :
    671   3448  dh155122 	    {
    672   3448  dh155122 		ipfgeniter_t iter;
    673   3448  dh155122 		ipftoken_t *token;
    674   3448  dh155122 
    675   3448  dh155122 		error = fr_inobj(data, &iter, IPFOBJ_GENITER);
    676   3448  dh155122 		if (error != 0)
    677   3448  dh155122 			break;
    678   3448  dh155122 
    679   3448  dh155122 		token = ipf_findtoken(iter.igi_type, uid, ctx, ifs);
    680   3448  dh155122 		if (token != NULL)
    681   3448  dh155122 			error  = nat_iterator(token, &iter, ifs);
    682   3448  dh155122 		else
    683   3448  dh155122 			error = ESRCH;
    684   3448  dh155122 		RWLOCK_EXIT(&ifs->ifs_ipf_tokens);
    685   3448  dh155122 		break;
    686   3448  dh155122 	    }
    687      0    stevel #ifdef  IPFILTER_LOG
    688      0    stevel 	case SIOCIPFFB :
    689      0    stevel 	{
    690      0    stevel 		int tmp;
    691      0    stevel 
    692      0    stevel 		if (!(mode & FWRITE))
    693      0    stevel 			error = EPERM;
    694      0    stevel 		else {
    695   3448  dh155122 			tmp = ipflog_clear(IPL_LOGNAT, ifs);
    696   7433      John 			error = BCOPYOUT((char *)&tmp, (char *)data,
    697   7433      John 					sizeof(tmp));
    698   7433      John 			if (error != 0)
    699   7433      John 				error = EFAULT;
    700      0    stevel 		}
    701      0    stevel 		break;
    702      0    stevel 	}
    703      0    stevel 	case SIOCSETLG :
    704   7433      John 		if (!(mode & FWRITE)) {
    705   7433      John 			error = EPERM;
    706   7433      John 		} else {
    707   7433      John 			error = BCOPYIN((char *)data,
    708   7433      John 					(char *)&ifs->ifs_nat_logging,
    709   7433      John 					sizeof(ifs->ifs_nat_logging));
    710   7433      John 			if (error != 0)
    711   7433      John 				error = EFAULT;
    712   7433      John 		}
    713   7433      John 		break;
    714   7433      John 	case SIOCGETLG :
    715   7433      John 		error = BCOPYOUT((char *)&ifs->ifs_nat_logging, (char *)data,
    716   3448  dh155122 				sizeof(ifs->ifs_nat_logging));
    717   7433      John 		if (error != 0)
    718   7433      John 			error = EFAULT;
    719      0    stevel 		break;
    720      0    stevel 	case FIONREAD :
    721   3448  dh155122 		arg = ifs->ifs_iplused[IPL_LOGNAT];
    722   7433      John 		error = BCOPYOUT(&arg, data, sizeof(arg));
    723   7433      John 		if (error != 0)
    724   7433      John 			error = EFAULT;
    725      0    stevel 		break;
    726      0    stevel #endif
    727      0    stevel 	case SIOCADNAT :
    728      0    stevel 		if (!(mode & FWRITE)) {
    729      0    stevel 			error = EPERM;
    730      0    stevel 		} else if (n != NULL) {
    731      0    stevel 			error = EEXIST;
    732      0    stevel 		} else if (nt == NULL) {
    733      0    stevel 			error = ENOMEM;
    734      0    stevel 		}
    735      0    stevel 		if (error != 0) {
    736   3448  dh155122 			MUTEX_EXIT(&ifs->ifs_ipf_natio);
    737      0    stevel 			break;
    738      0    stevel 		}
    739      0    stevel 		bcopy((char *)nat, (char *)nt, sizeof(*n));
    740   3448  dh155122 		error = nat_siocaddnat(nt, np, getlock, ifs);
    741   3448  dh155122 		MUTEX_EXIT(&ifs->ifs_ipf_natio);
    742      0    stevel 		if (error == 0)
    743      0    stevel 			nt = NULL;
    744      0    stevel 		break;
    745      0    stevel 	case SIOCRMNAT :
    746      0    stevel 		if (!(mode & FWRITE)) {
    747      0    stevel 			error = EPERM;
    748      0    stevel 			n = NULL;
    749      0    stevel 		} else if (n == NULL) {
    750      0    stevel 			error = ESRCH;
    751      0    stevel 		}
    752      0    stevel 
    753      0    stevel 		if (error != 0) {
    754   3448  dh155122 			MUTEX_EXIT(&ifs->ifs_ipf_natio);
    755   3448  dh155122 			break;
    756   3448  dh155122 		}
    757   3448  dh155122 		nat_siocdelnat(n, np, getlock, ifs);
    758   3448  dh155122 
    759   3448  dh155122 		MUTEX_EXIT(&ifs->ifs_ipf_natio);
    760      0    stevel 		n = NULL;
    761      0    stevel 		break;
    762      0    stevel 	case SIOCGNATS :
    763   3448  dh155122 		ifs->ifs_nat_stats.ns_table[0] = ifs->ifs_nat_table[0];
    764   3448  dh155122 		ifs->ifs_nat_stats.ns_table[1] = ifs->ifs_nat_table[1];
    765   3448  dh155122 		ifs->ifs_nat_stats.ns_list = ifs->ifs_nat_list;
    766   3448  dh155122 		ifs->ifs_nat_stats.ns_maptable = ifs->ifs_maptable;
    767   3448  dh155122 		ifs->ifs_nat_stats.ns_maplist = ifs->ifs_ipf_hm_maplist;
    768   3448  dh155122 		ifs->ifs_nat_stats.ns_nattab_max = ifs->ifs_ipf_nattable_max;
    769   3448  dh155122 		ifs->ifs_nat_stats.ns_nattab_sz = ifs->ifs_ipf_nattable_sz;
    770   3448  dh155122 		ifs->ifs_nat_stats.ns_rultab_sz = ifs->ifs_ipf_natrules_sz;
    771   3448  dh155122 		ifs->ifs_nat_stats.ns_rdrtab_sz = ifs->ifs_ipf_rdrrules_sz;
    772   3448  dh155122 		ifs->ifs_nat_stats.ns_hostmap_sz = ifs->ifs_ipf_hostmap_sz;
    773   3448  dh155122 		ifs->ifs_nat_stats.ns_instances = ifs->ifs_nat_instances;
    774   3448  dh155122 		ifs->ifs_nat_stats.ns_apslist = ifs->ifs_ap_sess_list;
    775   3448  dh155122 		error = fr_outobj(data, &ifs->ifs_nat_stats, IPFOBJ_NATSTAT);
    776      0    stevel 		break;
    777      0    stevel 	case SIOCGNATL :
    778      0    stevel 	    {
    779      0    stevel 		natlookup_t nl;
    780      0    stevel 
    781      0    stevel 		if (getlock) {
    782   3448  dh155122 			READ_ENTER(&ifs->ifs_ipf_nat);
    783      0    stevel 		}
    784      0    stevel 		error = fr_inobj(data, &nl, IPFOBJ_NATLOOKUP);
    785   7176  yx160601 		if (nl.nl_v != 6)
    786   7176  yx160601 			nl.nl_v = 4;
    787    680  dr146992 		if (error == 0) {
    788   7176  yx160601 			void *ptr;
    789   7176  yx160601 
    790   7176  yx160601 			switch (nl.nl_v)
    791   7176  yx160601 			{
    792   7176  yx160601 			case 4:
    793   7176  yx160601 				ptr = nat_lookupredir(&nl, ifs);
    794   7176  yx160601 				break;
    795   7176  yx160601 #ifdef	USE_INET6
    796   7176  yx160601 			case 6:
    797   7176  yx160601 				ptr = nat6_lookupredir(&nl, ifs);
    798   7176  yx160601 				break;
    799   7176  yx160601 #endif
    800   7176  yx160601 			default:
    801   7176  yx160601 				ptr = NULL;
    802   7176  yx160601 				break;
    803   7176  yx160601 			}
    804   7176  yx160601 
    805   7176  yx160601 			if (ptr != NULL) {
    806    680  dr146992 				error = fr_outobj(data, &nl, IPFOBJ_NATLOOKUP);
    807   2393  yz155240 			} else {
    808    680  dr146992 				error = ESRCH;
    809   2393  yz155240 			}
    810    680  dr146992 		}
    811      0    stevel 		if (getlock) {
    812   3448  dh155122 			RWLOCK_EXIT(&ifs->ifs_ipf_nat);
    813      0    stevel 		}
    814      0    stevel 		break;
    815      0    stevel 	    }
    816      0    stevel 	case SIOCIPFFL :	/* old SIOCFLNAT & SIOCCNATL */
    817      0    stevel 		if (!(mode & FWRITE)) {
    818      0    stevel 			error = EPERM;
    819      0    stevel 			break;
    820      0    stevel 		}
    821      0    stevel 		if (getlock) {
    822   3448  dh155122 			WRITE_ENTER(&ifs->ifs_ipf_nat);
    823      0    stevel 		}
    824   7433      John 		error = BCOPYIN(data, &arg, sizeof(arg));
    825   7433      John 		if (error != 0) {
    826   7433      John 			error = EFAULT;
    827   7433      John 		} else {
    828   8170      John 			if (arg == FLUSH_LIST)
    829   7433      John 				ret = nat_clearlist(ifs);
    830   8170      John 			else if (VALID_TABLE_FLUSH_OPT(arg))
    831   8170      John 				ret = nat_flushtable(arg, ifs);
    832   7433      John 			else
    833   7433      John 				error = EINVAL;
    834   7433      John 		}
    835      0    stevel 		if (getlock) {
    836   3448  dh155122 			RWLOCK_EXIT(&ifs->ifs_ipf_nat);
    837      0    stevel 		}
    838      0    stevel 		if (error == 0) {
    839   7433      John 			error = BCOPYOUT(&ret, data, sizeof(ret));
    840   7433      John 			if (error != 0)
    841   7433      John 				error = EFAULT;
    842      0    stevel 		}
    843      0    stevel 		break;
    844      0    stevel 	case SIOCPROXY :
    845   3448  dh155122 		error = appr_ioctl(data, cmd, mode, ifs);
    846      0    stevel 		break;
    847      0    stevel 	case SIOCSTLCK :
    848   2393  yz155240 		if (!(mode & FWRITE)) {
    849   2393  yz155240 			error = EPERM;
    850   2393  yz155240 		} else {
    851   7433      John 			error = fr_lock(data, &ifs->ifs_fr_nat_lock);
    852   2393  yz155240 		}
    853      0    stevel 		break;
    854      0    stevel 	case SIOCSTPUT :
    855   2761  jojemann 		if ((mode & FWRITE) != 0) {
    856   3448  dh155122 			error = fr_natputent(data, getlock, ifs);
    857   1143  jojemann 		} else {
    858      0    stevel 			error = EACCES;
    859   1143  jojemann 		}
    860      0    stevel 		break;
    861      0    stevel 	case SIOCSTGSZ :
    862   3448  dh155122 		if (ifs->ifs_fr_nat_lock) {
    863      0    stevel 			if (getlock) {
    864   3448  dh155122 				READ_ENTER(&ifs->ifs_ipf_nat);
    865   3448  dh155122 			}
    866   3448  dh155122 			error = fr_natgetsz(data, ifs);
    867      0    stevel 			if (getlock) {
    868   3448  dh155122 				RWLOCK_EXIT(&ifs->ifs_ipf_nat);
    869      0    stevel 			}
    870      0    stevel 		} else
    871      0    stevel 			error = EACCES;
    872      0    stevel 		break;
    873      0    stevel 	case SIOCSTGET :
    874   3448  dh155122 		if (ifs->ifs_fr_nat_lock) {
    875      0    stevel 			if (getlock) {
    876   3448  dh155122 				READ_ENTER(&ifs->ifs_ipf_nat);
    877   3448  dh155122 			}
    878   3448  dh155122 			error = fr_natgetent(data, ifs);
    879      0    stevel 			if (getlock) {
    880   3448  dh155122 				RWLOCK_EXIT(&ifs->ifs_ipf_nat);
    881      0    stevel 			}
    882      0    stevel 		} else
    883      0    stevel 			error = EACCES;
    884   3448  dh155122 		break;
    885   3448  dh155122 	case SIOCIPFDELTOK :
    886   7433      John 		error = BCOPYIN((caddr_t)data, (caddr_t)&arg, sizeof(arg));
    887   7433      John 		if (error != 0) {
    888   7433      John 			error = EFAULT;
    889   7433      John 		} else {
    890   7433      John 			error = ipf_deltoken(arg, uid, ctx, ifs);
    891   7433      John 		}
    892      0    stevel 		break;
    893      0    stevel 	default :
    894      0    stevel 		error = EINVAL;
    895      0    stevel 		break;
    896      0    stevel 	}
    897      0    stevel done:
    898      0    stevel 	if (nt)
    899      0    stevel 		KFREE(nt);
    900      0    stevel 	return error;
    901      0    stevel }
    902      0    stevel 
    903      0    stevel 
    904      0    stevel /* ------------------------------------------------------------------------ */
    905      0    stevel /* Function:    nat_siocaddnat                                              */
    906      0    stevel /* Returns:     int - 0 == success, != 0 == failure                         */
    907      0    stevel /* Parameters:  n(I)       - pointer to new NAT rule                        */
    908      0    stevel /*              np(I)      - pointer to where to insert new NAT rule        */
    909      0    stevel /*              getlock(I) - flag indicating if lock on ipf_nat is held     */
    910      0    stevel /* Mutex Locks: ipf_natio                                                   */
    911      0    stevel /*                                                                          */
    912      0    stevel /* Handle SIOCADNAT.  Resolve and calculate details inside the NAT rule     */
    913      0    stevel /* from information passed to the kernel, then add it  to the appropriate   */
    914      0    stevel /* NAT rule table(s).                                                       */
    915      0    stevel /* ------------------------------------------------------------------------ */
    916   3448  dh155122 static int nat_siocaddnat(n, np, getlock, ifs)
    917      0    stevel ipnat_t *n, **np;
    918      0    stevel int getlock;
    919   3448  dh155122 ipf_stack_t *ifs;
    920      0    stevel {
    921      0    stevel 	int error = 0, i, j;
    922      0    stevel 
    923   4380  jojemann 	if (nat_resolverule(n, ifs) != 0)
    924   4380  jojemann 		return ENOENT;
    925   2393  yz155240 
    926   2393  yz155240 	if ((n->in_age[0] == 0) && (n->in_age[1] != 0))
    927   2393  yz155240 		return EINVAL;
    928      0    stevel 
    929      0    stevel 	n->in_use = 0;
    930      0    stevel 	if (n->in_redir & NAT_MAPBLK)
    931      0    stevel 		n->in_space = USABLE_PORTS * ~ntohl(n->in_outmsk);
    932      0    stevel 	else if (n->in_flags & IPN_AUTOPORTMAP)
    933      0    stevel 		n->in_space = USABLE_PORTS * ~ntohl(n->in_inmsk);
    934      0    stevel 	else if (n->in_flags & IPN_IPRANGE)
    935      0    stevel 		n->in_space = ntohl(n->in_outmsk) - ntohl(n->in_outip);
    936      0    stevel 	else if (n->in_flags & IPN_SPLIT)
    937      0    stevel 		n->in_space = 2;
    938   2393  yz155240 	else if (n->in_outmsk != 0)
    939      0    stevel 		n->in_space = ~ntohl(n->in_outmsk);
    940   2393  yz155240 	else
    941   2393  yz155240 		n->in_space = 1;
    942   8624    Darren 	if (n->in_flags & NAT_TCPUDPICMPQ) {
    943   8624    Darren 		if (ntohs(n->in_pmax) < ntohs(n->in_pmin))
    944   8624    Darren 			return EINVAL;
    945   8624    Darren 	}
    946   2393  yz155240 
    947      0    stevel 	/*
    948      0    stevel 	 * Calculate the number of valid IP addresses in the output
    949      0    stevel 	 * mapping range.  In all cases, the range is inclusive of
    950      0    stevel 	 * the start and ending IP addresses.
    951      0    stevel 	 * If to a CIDR address, lose 2: broadcast + network address
    952      0    stevel 	 *                               (so subtract 1)
    953      0    stevel 	 * If to a range, add one.
    954      0    stevel 	 * If to a single IP address, set to 1.
    955      0    stevel 	 */
    956      0    stevel 	if (n->in_space) {
    957      0    stevel 		if ((n->in_flags & IPN_IPRANGE) != 0)
    958      0    stevel 			n->in_space += 1;
    959      0    stevel 		else
    960      0    stevel 			n->in_space -= 1;
    961      0    stevel 	} else
    962      0    stevel 		n->in_space = 1;
    963   2393  yz155240 
    964   7176  yx160601 #ifdef	USE_INET6
    965   7176  yx160601 	if (n->in_v == 6 && (n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0 &&
    966   7176  yx160601 	    !IP6_ISONES(&n->in_out[1]) && !IP6_ISZERO(&n->in_out[1]))
    967   7176  yx160601 		IP6_ADD(&n->in_out[0], 1, &n->in_next6)
    968   7176  yx160601 	else if (n->in_v == 6 &&
    969   7176  yx160601 	    (n->in_flags & IPN_SPLIT) && (n->in_redir & NAT_REDIRECT))
    970   7176  yx160601 		n->in_next6 = n->in_in[0];
    971   7176  yx160601 	else if (n->in_v == 6)
    972   7176  yx160601 		n->in_next6 = n->in_out[0];
    973   7176  yx160601 	else
    974   7176  yx160601 #endif
    975      0    stevel 	if ((n->in_outmsk != 0xffffffff) && (n->in_outmsk != 0) &&
    976      0    stevel 	    ((n->in_flags & (IPN_IPRANGE|IPN_SPLIT)) == 0))
    977      0    stevel 		n->in_nip = ntohl(n->in_outip) + 1;
    978      0    stevel 	else if ((n->in_flags & IPN_SPLIT) &&
    979      0    stevel 		 (n->in_redir & NAT_REDIRECT))
    980      0    stevel 		n->in_nip = ntohl(n->in_inip);
    981      0    stevel 	else
    982      0    stevel 		n->in_nip = ntohl(n->in_outip);
    983   7176  yx160601 
    984      0    stevel 	if (n->in_redir & NAT_MAP) {
    985      0    stevel 		n->in_pnext = ntohs(n->in_pmin);
    986      0    stevel 		/*
    987      0    stevel 		 * Multiply by the number of ports made available.
    988      0    stevel 		 */
    989      0    stevel 		if (ntohs(n->in_pmax) >= ntohs(n->in_pmin)) {
    990      0    stevel 			n->in_space *= (ntohs(n->in_pmax) -
    991      0    stevel 					ntohs(n->in_pmin) + 1);
    992      0    stevel 			/*
    993      0    stevel 			 * Because two different sources can map to
    994      0    stevel 			 * different destinations but use the same
    995      0    stevel 			 * local IP#/port #.
    996      0    stevel 			 * If the result is smaller than in_space, then
    997      0    stevel 			 * we may have wrapped around 32bits.
    998      0    stevel 			 */
    999      0    stevel 			i = n->in_inmsk;
   1000      0    stevel 			if ((i != 0) && (i != 0xffffffff)) {
   1001      0    stevel 				j = n->in_space * (~ntohl(i) + 1);
   1002      0    stevel 				if (j >= n->in_space)
   1003      0    stevel 					n->in_space = j;
   1004      0    stevel 				else
   1005      0    stevel 					n->in_space = 0xffffffff;
   1006      0    stevel 			}
   1007      0    stevel 		}
   1008      0    stevel 		/*
   1009      0    stevel 		 * If no protocol is specified, multiple by 256 to allow for
   1010      0    stevel 		 * at least one IP:IP mapping per protocol.
   1011      0    stevel 		 */
   1012      0    stevel 		if ((n->in_flags & IPN_TCPUDPICMP) == 0) {
   1013      0    stevel 				j = n->in_space * 256;
   1014      0    stevel 				if (j >= n->in_space)
   1015      0    stevel 					n->in_space = j;
   1016      0    stevel 				else
   1017      0    stevel 					n->in_space = 0xffffffff;
   1018      0    stevel 		}
   1019      0    stevel 	}
   1020   2393  yz155240 
   1021      0    stevel 	/* Otherwise, these fields are preset */
   1022      0    stevel 
   1023      0    stevel 	if (getlock) {
   1024   3448  dh155122 		WRITE_ENTER(&ifs->ifs_ipf_nat);
   1025      0    stevel 	}
   1026      0    stevel 	n->in_next = NULL;
   1027      0    stevel 	*np = n;
   1028      0    stevel 
   1029      0    stevel 	if (n->in_age[0] != 0)
   1030   3448  dh155122 	    n->in_tqehead[0] = fr_addtimeoutqueue(&ifs->ifs_nat_utqe,
   1031   3448  dh155122 						  n->in_age[0], ifs);
   1032      0    stevel 
   1033      0    stevel 	if (n->in_age[1] != 0)
   1034   3448  dh155122 	    n->in_tqehead[1] = fr_addtimeoutqueue(&ifs->ifs_nat_utqe,
   1035   3448  dh155122 						  n->in_age[1], ifs);
   1036      0    stevel 
   1037      0    stevel 	if (n->in_redir & NAT_REDIRECT) {
   1038      0    stevel 		n->in_flags &= ~IPN_NOTDST;
   1039   7176  yx160601 		switch (n->in_v)
   1040   7176  yx160601 		{
   1041   7176  yx160601 		case 4 :
   1042   7176  yx160601 			nat_addrdr(n, ifs);
   1043   7176  yx160601 			break;
   1044   7176  yx160601 #ifdef	USE_INET6
   1045   7176  yx160601 		case 6 :
   1046   7176  yx160601 			nat6_addrdr(n, ifs);
   1047   7176  yx160601 			break;
   1048   7176  yx160601 #endif
   1049   7176  yx160601 		default :
   1050   7176  yx160601 			break;
   1051   7176  yx160601 		}
   1052      0    stevel 	}
   1053      0    stevel 	if (n->in_redir & (NAT_MAP|NAT_MAPBLK)) {
   1054      0    stevel 		n->in_flags &= ~IPN_NOTSRC;
   1055   7176  yx160601 		switch (n->in_v)
   1056   7176  yx160601 		{
   1057   7176  yx160601 		case 4 :
   1058   7176  yx160601 			nat_addnat(n, ifs);
   1059   7176  yx160601 			break;
   1060   7176  yx160601 #ifdef	USE_INET6
   1061   7176  yx160601 		case 6 :
   1062   7176  yx160601 			nat6_addnat(n, ifs);
   1063   7176  yx160601 			break;
   1064   7176  yx160601 #endif
   1065   7176  yx160601 		default :
   1066   7176  yx160601 			break;
   1067   7176  yx160601 		}
   1068      0    stevel 	}
   1069      0    stevel 	n = NULL;
   1070   3448  dh155122 	ifs->ifs_nat_stats.ns_rules++;
   1071   3448  dh155122 	if (getlock) {
   1072   3448  dh155122 		RWLOCK_EXIT(&ifs->ifs_ipf_nat);			/* WRITE */
   1073      0    stevel 	}
   1074      0    stevel 
   1075      0    stevel 	return error;
   1076      0    stevel }
   1077      0    stevel 
   1078      0    stevel 
   1079      0    stevel /* ------------------------------------------------------------------------ */
   1080      0    stevel /* Function:    nat_resolvrule                                              */
   1081   4380  jojemann /* Returns:     int - 0 == success, -1 == failure                           */
   1082      0    stevel /* Parameters:  n(I)  - pointer to NAT rule                                 */
   1083      0    stevel /*                                                                          */
   1084   4380  jojemann /* Resolve some of the details inside the NAT rule.  Includes resolving	    */
   1085   4380  jojemann /* any specified interfaces and proxy labels, and determines whether or not */
   1086   4380  jojemann /* all proxy labels are correctly specified.				    */
   1087   4380  jojemann /*									    */
   1088   4380  jojemann /* Called by nat_siocaddnat() (SIOCADNAT) and fr_natputent (SIOCSTPUT).     */
   1089   4380  jojemann /* ------------------------------------------------------------------------ */
   1090   4380  jojemann static int nat_resolverule(n, ifs)
   1091   2393  yz155240 ipnat_t *n;
   1092   3448  dh155122 ipf_stack_t *ifs;
   1093   2393  yz155240 {
   1094   2393  yz155240 	n->in_ifnames[0][LIFNAMSIZ - 1] = '\0';
   1095   7176  yx160601 	n->in_ifps[0] = fr_resolvenic(n->in_ifnames[0], n->in_v, ifs);
   1096   2393  yz155240 
   1097   2393  yz155240 	n->in_ifnames[1][LIFNAMSIZ - 1] = '\0';
   1098      0    stevel 	if (n->in_ifnames[1][0] == '\0') {
   1099      0    stevel 		(void) strncpy(n->in_ifnames[1], n->in_ifnames[0], LIFNAMSIZ);
   1100      0    stevel 		n->in_ifps[1] = n->in_ifps[0];
   1101      0    stevel 	} else {
   1102   7176  yx160601 		n->in_ifps[1] = fr_resolvenic(n->in_ifnames[1], n->in_v, ifs);
   1103      0    stevel 	}
   1104      0    stevel 
   1105      0    stevel 	if (n->in_plabel[0] != '\0') {
   1106   3448  dh155122 		n->in_apr = appr_lookup(n->in_p, n->in_plabel, ifs);
   1107   4380  jojemann 		if (n->in_apr == NULL)
   1108   4380  jojemann 			return -1;
   1109   4380  jojemann 	}
   1110   4380  jojemann 	return 0;
   1111      0    stevel }
   1112      0    stevel 
   1113      0    stevel 
   1114      0    stevel /* ------------------------------------------------------------------------ */
   1115      0    stevel /* Function:    nat_siocdelnat                                              */
   1116      0    stevel /* Returns:     int - 0 == success, != 0 == failure                         */
   1117      0    stevel /* Parameters:  n(I)       - pointer to new NAT rule                        */
   1118      0    stevel /*              np(I)      - pointer to where to insert new NAT rule        */
   1119      0    stevel /*              getlock(I) - flag indicating if lock on ipf_nat is held     */
   1120      0    stevel /* Mutex Locks: ipf_natio                                                   */
   1121      0    stevel /*                                                                          */
   1122      0    stevel /* Handle SIOCADNAT.  Resolve and calculate details inside the NAT rule     */
   1123      0    stevel /* from information passed to the kernel, then add it  to the appropriate   */
   1124      0    stevel /* NAT rule table(s).                                                       */
   1125      0    stevel /* ------------------------------------------------------------------------ */
   1126   3448  dh155122 static void nat_siocdelnat(n, np, getlock, ifs)
   1127      0    stevel ipnat_t *n, **np;
   1128      0    stevel int getlock;
   1129   3448  dh155122 ipf_stack_t *ifs;
   1130   3448  dh155122 {
   1131   7176  yx160601 	int i;
   1132   7176  yx160601 
   1133   3448  dh155122 	if (getlock) {
   1134   3448  dh155122 		WRITE_ENTER(&ifs->ifs_ipf_nat);
   1135      0    stevel 	}
   1136      0    stevel 	if (n->in_redir & NAT_REDIRECT)
   1137      0    stevel 		nat_delrdr(n);
   1138      0    stevel 	if (n->in_redir & (NAT_MAPBLK|NAT_MAP))
   1139      0    stevel 		nat_delnat(n);
   1140   3448  dh155122 	if (ifs->ifs_nat_list == NULL) {
   1141   3448  dh155122 		ifs->ifs_nat_masks = 0;
   1142   3448  dh155122 		ifs->ifs_rdr_masks = 0;
   1143   7176  yx160601 		for (i = 0; i < 4; i++) {
   1144   7176  yx160601 			ifs->ifs_nat6_masks[i] = 0;
   1145   7176  yx160601 			ifs->ifs_rdr6_masks[i] = 0;
   1146   7176  yx160601 		}
   1147      0    stevel 	}
   1148      0    stevel 
   1149   2393  yz155240 	if (n->in_tqehead[0] != NULL) {
   1150   2393  yz155240 		if (fr_deletetimeoutqueue(n->in_tqehead[0]) == 0) {
   1151   4817  an207044 			fr_freetimeoutqueue(n->in_tqehead[0], ifs);
   1152   2393  yz155240 		}
   1153   2393  yz155240 	}
   1154   2393  yz155240 
   1155   2393  yz155240 	if (n->in_tqehead[1] != NULL) {
   1156   2393  yz155240 		if (fr_deletetimeoutqueue(n->in_tqehead[1]) == 0) {
   1157   3448  dh155122 			fr_freetimeoutqueue(n->in_tqehead[1], ifs);
   1158   2393  yz155240 		}
   1159   2393  yz155240 	}
   1160      0    stevel 
   1161      0    stevel 	*np = n->in_next;
   1162      0    stevel 
   1163      0    stevel 	if (n->in_use == 0) {
   1164      0    stevel 		if (n->in_apr)
   1165      0    stevel 			appr_free(n->in_apr);
   1166      0    stevel 		KFREE(n);
   1167   3448  dh155122 		ifs->ifs_nat_stats.ns_rules--;
   1168      0    stevel 	} else {
   1169      0    stevel 		n->in_flags |= IPN_DELETE;
   1170      0    stevel 		n->in_next = NULL;
   1171      0    stevel 	}
   1172      0    stevel 	if (getlock) {
   1173   3448  dh155122 		RWLOCK_EXIT(&ifs->ifs_ipf_nat);			/* READ/WRITE */
   1174      0    stevel 	}
   1175      0    stevel }
   1176      0    stevel 
   1177      0    stevel 
   1178      0    stevel /* ------------------------------------------------------------------------ */
   1179      0    stevel /* Function:    fr_natgetsz                                                 */
   1180      0    stevel /* Returns:     int - 0 == success, != 0 is the error value.                */
   1181      0    stevel /* Parameters:  data(I) - pointer to natget structure with kernel pointer   */
   1182      0    stevel /*                        get the size of.                                  */
   1183      0    stevel /*                                                                          */
   1184      0    stevel /* Handle SIOCSTGSZ.                                                        */
   1185      0    stevel /* Return the size of the nat list entry to be copied back to user space.   */
   1186      0    stevel /* The size of the entry is stored in the ng_sz field and the enture natget */
   1187      0    stevel /* structure is copied back to the user.                                    */
   1188      0    stevel /* ------------------------------------------------------------------------ */
   1189   3448  dh155122 static int fr_natgetsz(data, ifs)
   1190      0    stevel caddr_t data;
   1191   3448  dh155122 ipf_stack_t *ifs;
   1192      0    stevel {
   1193      0    stevel 	ap_session_t *aps;
   1194      0    stevel 	nat_t *nat, *n;
   1195      0    stevel 	natget_t ng;
   1196   7433      John 	int err;
   1197   7433      John 
   1198   7433      John 	err = BCOPYIN(data, &ng, sizeof(ng));
   1199   7433      John 	if (err != 0)
   1200   7433      John 		return EFAULT;
   1201      0    stevel 
   1202      0    stevel 	nat = ng.ng_ptr;
   1203      0    stevel 	if (!nat) {
   1204   3448  dh155122 		nat = ifs->ifs_nat_instances;
   1205      0    stevel 		ng.ng_sz = 0;
   1206      0    stevel 		/*
   1207      0    stevel 		 * Empty list so the size returned is 0.  Simple.
   1208      0    stevel 		 */
   1209      0    stevel 		if (nat == NULL) {
   1210   7433      John 			err = BCOPYOUT(&ng, data, sizeof(ng));
   1211   7433      John 			if (err != 0) {
   1212   7433      John 				return EFAULT;
   1213   7433      John 			} else {
   1214   7433      John 				return 0;
   1215   7433      John 			}
   1216      0    stevel 		}
   1217      0    stevel 	} else {
   1218      0    stevel 		/*
   1219      0    stevel 		 * Make sure the pointer we're copying from exists in the
   1220      0    stevel 		 * current list of entries.  Security precaution to prevent
   1221      0    stevel 		 * copying of random kernel data.
   1222      0    stevel 		 */
   1223   3448  dh155122 		for (n = ifs->ifs_nat_instances; n; n = n->nat_next)
   1224      0    stevel 			if (n == nat)
   1225      0    stevel 				break;
   1226      0    stevel 		if (!n)
   1227      0    stevel 			return ESRCH;
   1228      0    stevel 	}
   1229      0    stevel 
   1230      0    stevel 	/*
   1231      0    stevel 	 * Incluse any space required for proxy data structures.
   1232      0    stevel 	 */
   1233      0    stevel 	ng.ng_sz = sizeof(nat_save_t);
   1234      0    stevel 	aps = nat->nat_aps;
   1235   2393  yz155240 	if (aps != NULL) {
   1236   2393  yz155240 		ng.ng_sz += sizeof(ap_session_t) - 4;
   1237   2393  yz155240 		if (aps->aps_data != 0)
   1238   2393  yz155240 			ng.ng_sz += aps->aps_psiz;
   1239   2393  yz155240 	}
   1240   2393  yz155240 
   1241   7433      John 	err = BCOPYOUT(&ng, data, sizeof(ng));
   1242   7433      John 	if (err != 0)
   1243   7433      John 		return EFAULT;
   1244      0    stevel 	return 0;
   1245      0    stevel }
   1246      0    stevel 
   1247      0    stevel 
   1248      0    stevel /* ------------------------------------------------------------------------ */
   1249      0    stevel /* Function:    fr_natgetent                                                */
   1250      0    stevel /* Returns:     int - 0 == success, != 0 is the error value.                */
   1251      0    stevel /* Parameters:  data(I) - pointer to natget structure with kernel pointer   */
   1252      0    stevel /*                        to NAT structure to copy out.                     */
   1253      0    stevel /*                                                                          */
   1254      0    stevel /* Handle SIOCSTGET.                                                        */
   1255      0    stevel /* Copies out NAT entry to user space.  Any additional data held for a      */
   1256      0    stevel /* proxy is also copied, as to is the NAT rule which was responsible for it */
   1257      0    stevel /* ------------------------------------------------------------------------ */
   1258   3448  dh155122 static int fr_natgetent(data, ifs)
   1259      0    stevel caddr_t data;
   1260   3448  dh155122 ipf_stack_t *ifs;
   1261      0    stevel {
   1262   2393  yz155240 	int error, outsize;
   1263      0    stevel 	ap_session_t *aps;
   1264   2393  yz155240 	nat_save_t *ipn, ipns;
   1265      0    stevel 	nat_t *n, *nat;
   1266   2393  yz155240 
   1267   2393  yz155240 	error = fr_inobj(data, &ipns, IPFOBJ_NATSAVE);
   1268      0    stevel 	if (error != 0)
   1269      0    stevel 		return error;
   1270      0    stevel 
   1271   2393  yz155240 	if ((ipns.ipn_dsize < sizeof(ipns)) || (ipns.ipn_dsize > 81920))
   1272   2393  yz155240 		return EINVAL;
   1273   2393  yz155240 
   1274   2393  yz155240 	KMALLOCS(ipn, nat_save_t *, ipns.ipn_dsize);
   1275   2393  yz155240 	if (ipn == NULL)
   1276   2393  yz155240 		return ENOMEM;
   1277   2393  yz155240 
   1278   2393  yz155240 	ipn->ipn_dsize = ipns.ipn_dsize;
   1279   2393  yz155240 	nat = ipns.ipn_next;
   1280      0    stevel 	if (nat == NULL) {
   1281   3448  dh155122 		nat = ifs->ifs_nat_instances;
   1282      0    stevel 		if (nat == NULL) {
   1283   3448  dh155122 			if (ifs->ifs_nat_instances == NULL)
   1284   2393  yz155240 				error = ENOENT;
   1285   2393  yz155240 			goto finished;
   1286      0    stevel 		}
   1287      0    stevel 	} else {
   1288      0    stevel 		/*
   1289      0    stevel 		 * Make sure the pointer we're copying from exists in the
   1290      0    stevel 		 * current list of entries.  Security precaution to prevent
   1291      0    stevel 		 * copying of random kernel data.
   1292      0    stevel 		 */
   1293   3448  dh155122 		for (n = ifs->ifs_nat_instances; n; n = n->nat_next)
   1294      0    stevel 			if (n == nat)
   1295      0    stevel 				break;
   1296   2393  yz155240 		if (n == NULL) {
   1297   2393  yz155240 			error = ESRCH;
   1298   2393  yz155240 			goto finished;
   1299   2393  yz155240 		}
   1300   2393  yz155240 	}
   1301   2393  yz155240 	ipn->ipn_next = nat->nat_next;
   1302   2393  yz155240 
   1303   2393  yz155240 	/*
   1304   2393  yz155240 	 * Copy the NAT structure.
   1305   2393  yz155240 	 */
   1306   2393  yz155240 	bcopy((char *)nat, &ipn->ipn_nat, sizeof(*nat));
   1307      0    stevel 
   1308      0    stevel 	/*
   1309      0    stevel 	 * If we have a pointer to the NAT rule it belongs to, save that too.
   1310      0    stevel 	 */
   1311   2393  yz155240 	if (nat->nat_ptr != NULL)
   1312   2393  yz155240 		bcopy((char *)nat->nat_ptr, (char *)&ipn->ipn_ipnat,
   1313   2393  yz155240 		      sizeof(ipn->ipn_ipnat));
   1314      0    stevel 
   1315      0    stevel 	/*
   1316      0    stevel 	 * If we also know the NAT entry has an associated filter rule,
   1317      0    stevel 	 * save that too.
   1318      0    stevel 	 */
   1319   2393  yz155240 	if (nat->nat_fr != NULL)
   1320   2393  yz155240 		bcopy((char *)nat->nat_fr, (char *)&ipn->ipn_fr,
   1321   2393  yz155240 		      sizeof(ipn->ipn_fr));
   1322      0    stevel 
   1323      0    stevel 	/*
   1324      0    stevel 	 * Last but not least, if there is an application proxy session set
   1325      0    stevel 	 * up for this NAT entry, then copy that out too, including any
   1326      0    stevel 	 * private data saved along side it by the proxy.
   1327      0    stevel 	 */
   1328      0    stevel 	aps = nat->nat_aps;
   1329   2393  yz155240 	outsize = ipn->ipn_dsize - sizeof(*ipn) + sizeof(ipn->ipn_data);
   1330      0    stevel 	if (aps != NULL) {
   1331   2393  yz155240 		char *s;
   1332   2393  yz155240 
   1333   2393  yz155240 		if (outsize < sizeof(*aps)) {
   1334   2393  yz155240 			error = ENOBUFS;
   1335   2393  yz155240 			goto finished;
   1336   2393  yz155240 		}
   1337   2393  yz155240 
   1338   2393  yz155240 		s = ipn->ipn_data;
   1339   2393  yz155240 		bcopy((char *)aps, s, sizeof(*aps));
   1340   2393  yz155240 		s += sizeof(*aps);
   1341   2393  yz155240 		outsize -= sizeof(*aps);
   1342   2393  yz155240 		if ((aps->aps_data != NULL) && (outsize >= aps->aps_psiz))
   1343   2393  yz155240 			bcopy(aps->aps_data, s, aps->aps_psiz);
   1344   2393  yz155240 		else
   1345   2393  yz155240 			error = ENOBUFS;
   1346   2393  yz155240 	}
   1347   2393  yz155240 	if (error == 0) {
   1348   2393  yz155240 		error = fr_outobjsz(data, ipn, IPFOBJ_NATSAVE, ipns.ipn_dsize);
   1349   2393  yz155240 	}
   1350   2393  yz155240 
   1351   2393  yz155240 finished:
   1352   2393  yz155240 	if (ipn != NULL) {
   1353   2393  yz155240 		KFREES(ipn, ipns.ipn_dsize);
   1354      0    stevel 	}
   1355      0    stevel 	return error;
   1356      0    stevel }
   1357      0    stevel 
   1358   6253  an207044 /* ------------------------------------------------------------------------ */
   1359   6253  an207044 /* Function:    nat_calc_chksum_diffs					    */
   1360   6253  an207044 /* Returns:     void							    */
   1361   6253  an207044 /* Parameters:  nat	-	pointer to NAT table entry		    */
   1362   6253  an207044 /*                                                                          */
   1363   6253  an207044 /* Function calculates chksum deltas for IP header (nat_ipsumd) and TCP/UDP */
   1364   6253  an207044 /* headers (nat_sumd). The things for L4 (UDP/TCP) get complicated when     */
   1365   6253  an207044 /* we are dealing with partial chksum offload. For these cases we need to   */
   1366   6253  an207044 /* compute a 'partial chksum delta'. The 'partial chksum delta'is stored    */
   1367   6253  an207044 /* into nat_sumd[1], while ordinary chksum delta for TCP/UDP is in 	    */
   1368   6253  an207044 /* nat_sumd[0]. 							    */
   1369   6253  an207044 /*									    */
   1370   6253  an207044 /* The function accepts initialized NAT table entry and computes the deltas */
   1371   6253  an207044 /* from nat_inip/nat_outip members. The function is called right before	    */
   1372   6253  an207044 /* the new entry is inserted into the table.				    */
   1373   6253  an207044 /*									    */
   1374   6253  an207044 /* The ipsumd (IP hedaer chksum delta adjustment) is computed as a chksum   */
   1375   6253  an207044 /* of delta between original and new IP addresses.			    */
   1376   6253  an207044 /*									    */
   1377   6253  an207044 /* the nat_sumd[0] (TCP/UDP header chksum delta adjustment) is computed as  */
   1378   6253  an207044 /* a chkusm of delta between original an new IP addrress:port tupples.	    */
   1379   6253  an207044 /*									    */
   1380   6253  an207044 /* Some facts about chksum, we should remember:				    */
   1381   6253  an207044 /*	IP header chksum covers IP header only				    */
   1382   6253  an207044 /*									    */
   1383   6253  an207044 /*	TCP/UDP chksum covers data payload and so called pseudo header	    */
   1384   6253  an207044 /*		SRC, DST IP address					    */
   1385   6253  an207044 /*		SRC, DST Port						    */
   1386   6253  an207044 /*		length of payload					    */
   1387   6253  an207044 /*									    */
   1388   6253  an207044 /* The partial chksum delta (nat_sumd[1] is used to adjust db_ckusm16	    */
   1389   6253  an207044 /* member of dblk_t structure. The db_ckusm16 member is not part of 	    */
   1390   6253  an207044 /* IP/UDP/TCP header it is 16 bit value computed by NIC driver with partial */
   1391   6253  an207044 /* chksum offload capacbility for every inbound packet. The db_cksum16 is   */
   1392   6253  an207044 /* stored along with other IP packet data in dblk_t structure and used in   */
   1393   6253  an207044 /* for IP/UDP/TCP chksum validation later in ip.c. 			    */
   1394   6253  an207044 /*									    */
   1395   6253  an207044 /* The partial chksum delta (adjustment, nat_sumd[1]) is computed as chksum */
   1396   6253  an207044 /* of delta between new and orig address. NOTE: the order of operands for   */
   1397   6253  an207044 /* partial delta operation is swapped compared to computing the IP/TCP/UDP  */
   1398   6253  an207044 /* header adjustment. It is by design see (IP_CKSUM_RECV() macro in ip.c).  */
   1399   6253  an207044 /*									    */
   1400   6253  an207044 /* ------------------------------------------------------------------------ */
   1401   7176  yx160601 void nat_calc_chksum_diffs(nat)
   1402   6253  an207044 nat_t *nat;
   1403   6253  an207044 {
   1404   6253  an207044 	u_32_t	sum_orig = 0;
   1405   6253  an207044 	u_32_t	sum_changed = 0;
   1406   6253  an207044 	u_32_t	sumd;
   1407   6253  an207044 	u_32_t	ipsum_orig = 0;
   1408   6253  an207044 	u_32_t	ipsum_changed = 0;
   1409   6253  an207044 
   1410   7176  yx160601 	if (nat->nat_v != 4 && nat->nat_v != 6)
   1411   7176  yx160601 		return;
   1412   7176  yx160601 
   1413   6253  an207044 	/*
   1414   6253  an207044 	 * the switch calculates operands for CALC_SUMD(),
   1415   6253  an207044 	 * which will compute the partial chksum delta.
   1416   6253  an207044 	 */
   1417   6253  an207044 	switch (nat->nat_dir)
   1418   6253  an207044 	{
   1419   6253  an207044 	case NAT_INBOUND:
   1420   6253  an207044 		/*
   1421   6253  an207044 		 * we are dealing with RDR rule (DST address gets
   1422   6253  an207044 		 * modified on packet from client)
   1423   6253  an207044 		 */
   1424   7176  yx160601 		if (nat->nat_v == 4) {
   1425   7176  yx160601 			sum_changed = LONG_SUM(ntohl(nat->nat_inip.s_addr));
   1426   7176  yx160601 			sum_orig = LONG_SUM(ntohl(nat->nat_outip.s_addr));
   1427   7176  yx160601 		} else {
   1428   7176  yx160601 			sum_changed = LONG_SUM6(&nat->nat_inip6);
   1429   7176  yx160601 			sum_orig = LONG_SUM6(&nat->nat_outip6);
   1430   7176  yx160601 		}
   1431   6253  an207044 		break;
   1432   6253  an207044 	case NAT_OUTBOUND:
   1433   6253  an207044 		/*
   1434   6253  an207044 		 * we are dealing with MAP rule (SRC address gets
   1435   6253  an207044 		 * modified on packet from client)
   1436   6253  an207044 		 */
   1437   7176  yx160601 		if (nat->nat_v == 4) {
   1438   7176  yx160601 			sum_changed = LONG_SUM(ntohl(nat->nat_outip.s_addr));
   1439   7176  yx160601 			sum_orig = LONG_SUM(ntohl(nat->nat_inip.s_addr));
   1440   7176  yx160601 		} else {
   1441   7176  yx160601 			sum_changed = LONG_SUM6(&nat->nat_outip6);
   1442   7176  yx160601 			sum_orig = LONG_SUM6(&nat->nat_inip6);
   1443   7176  yx160601 		}
   1444   6253  an207044 		break;
   1445   6253  an207044 	default: ;
   1446   6253  an207044 		break;
   1447   6253  an207044 	}
   1448   6253  an207044 
   1449   6253  an207044 	/*
   1450   6253  an207044 	 * we also preserve CALC_SUMD() operands here, for IP chksum delta
   1451   6253  an207044 	 * calculation, which happens at the end of function.
   1452   6253  an207044 	 */
   1453   6253  an207044 	ipsum_changed = sum_changed;
   1454   6253  an207044 	ipsum_orig = sum_orig;
   1455   6253  an207044 	/*
   1456   6253  an207044 	 * NOTE: the order of operands for partial chksum adjustment
   1457   6253  an207044 	 * computation has to be swapped!
   1458   6253  an207044 	 */
   1459   6253  an207044 	CALC_SUMD(sum_changed, sum_orig, sumd);
   1460   6253  an207044 	nat->nat_sumd[1] = (sumd & 0xffff) + (sumd >> 16);
   1461   6253  an207044 
   1462   6295  an207044 	if (nat->nat_flags & (IPN_TCPUDP | IPN_ICMPQUERY)) {
   1463   6253  an207044 
   1464   6253  an207044 		/*
   1465   6253  an207044 		 * switch calculates operands for CALC_SUMD(), which will
   1466   6253  an207044 		 * compute the full chksum delta.
   1467   6253  an207044 		 */
   1468   6253  an207044 		switch (nat->nat_dir)
   1469   6253  an207044 		{
   1470   6253  an207044 		case NAT_INBOUND:
   1471   7176  yx160601 			if (nat->nat_v == 4) {
   1472   7176  yx160601 				sum_changed = LONG_SUM(
   1473   7176  yx160601 				    ntohl(nat->nat_inip.s_addr) +
   1474   7176  yx160601 				    ntohs(nat->nat_inport));
   1475   7176  yx160601 				sum_orig = LONG_SUM(
   1476   7176  yx160601 				    ntohl(nat->nat_outip.s_addr) +
   1477   7176  yx160601 				    ntohs(nat->nat_outport));
   1478   7176  yx160601 			} else {
   1479   7176  yx160601 				sum_changed = LONG_SUM6(&nat->nat_inip6) +
   1480   7176  yx160601 				    ntohs(nat->nat_inport);
   1481   7176  yx160601 				sum_orig = LONG_SUM6(&nat->nat_outip6) +
   1482   7176  yx160601 				    ntohs(nat->nat_outport);
   1483   7176  yx160601 			}
   1484   6253  an207044 			break;
   1485   6253  an207044 		case NAT_OUTBOUND:
   1486   7176  yx160601 			if (nat->nat_v == 4) {
   1487   7176  yx160601 				sum_changed = LONG_SUM(
   1488   7176  yx160601 				    ntohl(nat->nat_outip.s_addr) +
   1489   7176  yx160601 				    ntohs(nat->nat_outport));
   1490   7176  yx160601 				sum_orig = LONG_SUM(
   1491   7176  yx160601 				    ntohl(nat->nat_inip.s_addr) +
   1492   7176  yx160601 				    ntohs(nat->nat_inport));
   1493   7176  yx160601 			} else {
   1494   7176  yx160601 				sum_changed = LONG_SUM6(&nat->nat_outip6) +
   1495   7176  yx160601 				    ntohs(nat->nat_outport);
   1496   7176  yx160601 				sum_orig = LONG_SUM6(&nat->nat_inip6) +
   1497   7176  yx160601 				    ntohs(nat->nat_inport);
   1498   7176  yx160601 			}
   1499   6253  an207044 			break;
   1500   6253  an207044 		default: ;
   1501   6253  an207044 			break;
   1502   6253  an207044 		}
   1503   6253  an207044 
   1504   6253  an207044 		CALC_SUMD(sum_orig, sum_changed, sumd);
   1505   6253  an207044 		nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
   1506   6295  an207044 
   1507   6295  an207044 		if (!(nat->nat_flags & IPN_TCPUDP)) {
   1508   6295  an207044 			/*
   1509   6295  an207044 			 * partial HW chksum offload works for TCP/UDP headers only,
   1510   6295  an207044 			 * so we need to enforce full chksum adjustment for ICMP
   1511   6295  an207044 			 */
   1512   6295  an207044 			nat->nat_sumd[1] = nat->nat_sumd[0];
   1513   6295  an207044 		}
   1514   6253  an207044 	}
   1515   6253  an207044 	else
   1516   6253  an207044 		nat->nat_sumd[0] = nat->nat_sumd[1];
   1517   6253  an207044 
   1518   6253  an207044 	/*
   1519   6253  an207044 	 * we may reuse the already computed nat_sumd[0] for IP header chksum
   1520   6253  an207044 	 * adjustment in case the L4 (TCP/UDP header) is not changed by NAT.
   1521   6253  an207044 	 */
   1522   7176  yx160601 	if (nat->nat_v == 4) {
   1523   7176  yx160601 		if (NAT_HAS_L4_CHANGED(nat)) {
   1524   7176  yx160601 			/*
   1525   7176  yx160601 			 * bad luck, NAT changes also the L4 header, use IP
   1526   7176  yx160601 			 * addresses to compute chksum adjustment for IP header.
   1527   7176  yx160601 			 */
   1528   7176  yx160601 			CALC_SUMD(ipsum_orig, ipsum_changed, sumd);
   1529   7176  yx160601 			nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
   1530   7176  yx160601 		} else {
   1531   7176  yx160601 			/*
   1532   7176  yx160601 			 * the NAT does not change L4 hdr -> reuse chksum
   1533   7176  yx160601 			 * adjustment for IP hdr.
   1534   7176  yx160601 			 */
   1535   7176  yx160601 			nat->nat_ipsumd = nat->nat_sumd[0];
   1536   7176  yx160601 
   1537   7176  yx160601 			/*
   1538   7176  yx160601 			 * if L4 header does not use chksum - zero out deltas
   1539   7176  yx160601 			 */
   1540   7176  yx160601 			if (!(nat->nat_flags & IPN_TCPUDP)) {
   1541   7176  yx160601 				nat->nat_sumd[0] = 0;
   1542   7176  yx160601 				nat->nat_sumd[1] = 0;
   1543   7176  yx160601 			}
   1544   6295  an207044 		}
   1545   6253  an207044 	}
   1546   6253  an207044 
   1547   6253  an207044 	return;
   1548   6253  an207044 }
   1549      0    stevel 
   1550      0    stevel /* ------------------------------------------------------------------------ */
   1551      0    stevel /* Function:    fr_natputent                                                */
   1552      0    stevel /* Returns:     int - 0 == success, != 0 is the error value.                */
   1553   8170      John /* Parameters:  data(I)    - pointer to natget structure with NAT           */
   1554   8170      John /*                           structure information to load into the kernel  */
   1555   2393  yz155240 /*              getlock(I) - flag indicating whether or not a write lock    */
   1556   2393  yz155240 /*                           on ipf_nat is already held.                    */
   1557   8170      John /*              ifs        - ipf stack instance                             */
   1558      0    stevel /*                                                                          */
   1559      0    stevel /* Handle SIOCSTPUT.                                                        */
   1560      0    stevel /* Loads a NAT table entry from user space, including a NAT rule, proxy and */
   1561      0    stevel /* firewall rule data structures, if pointers to them indicate so.          */
   1562      0    stevel /* ------------------------------------------------------------------------ */
   1563   3448  dh155122 static int fr_natputent(data, getlock, ifs)
   1564      0    stevel caddr_t data;
   1565   1143  jojemann int getlock;
   1566   3448  dh155122 ipf_stack_t *ifs;
   1567      0    stevel {
   1568      0    stevel 	nat_save_t ipn, *ipnn;
   1569      0    stevel 	ap_session_t *aps;
   1570      0    stevel 	nat_t *n, *nat;
   1571      0    stevel 	frentry_t *fr;
   1572    429  dr146992 	fr_info_t fin;
   1573      0    stevel 	ipnat_t *in;
   1574      0    stevel 	int error;
   1575      0    stevel 
   1576      0    stevel 	error = fr_inobj(data, &ipn, IPFOBJ_NATSAVE);
   1577      0    stevel 	if (error != 0)
   1578      0    stevel 		return error;
   1579   4817  an207044 
   1580   4817  an207044 	/*
   1581   8170      John 	 * Trigger automatic call to nat_flushtable() if the
   1582   4817  an207044 	 * table has reached capcity specified by hi watermark.
   1583   4817  an207044 	 */
   1584   8170      John 	if (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_level_hi)
   1585   4817  an207044 		ifs->ifs_nat_doflush = 1;
   1586      0    stevel 
   1587   2393  yz155240 	/*
   1588   7432      John 	 * If automatic flushing did not do its job, and the table
   1589   7432      John 	 * has filled up, don't try to create a new entry.
   1590   7432      John 	 */
   1591   7432      John 	if (ifs->ifs_nat_stats.ns_inuse >= ifs->ifs_ipf_nattable_max) {
   1592   7432      John 		ifs->ifs_nat_stats.ns_memfail++;
   1593   7432      John 		return ENOMEM;
   1594   7432      John 	}
   1595   7432      John 
   1596   7432      John 	/*
   1597   2393  yz155240 	 * Initialise early because of code at junkput label.
   1598   2393  yz155240 	 */
   1599   2393  yz155240 	in = NULL;
   1600   2393  yz155240 	aps = NULL;
   1601      0    stevel 	nat = NULL;
   1602   2393  yz155240 	ipnn = NULL;
   1603   2393  yz155240 
   1604   2393  yz155240 	/*
   1605   2393  yz155240 	 * New entry, copy in the rest of the NAT entry if it's size is more
   1606   2393  yz155240 	 * than just the nat_t structure.
   1607   2393  yz155240 	 */
   1608   2393  yz155240 	fr = NULL;
   1609   2393  yz155240 	if (ipn.ipn_dsize > sizeof(ipn)) {
   1610   2393  yz155240 		if (ipn.ipn_dsize > 81920) {
   1611   2393  yz155240 			error = ENOMEM;
   1612   2393  yz155240 			goto junkput;
   1613   2393  yz155240 		}
   1614   2393  yz155240 
   1615   2393  yz155240 		KMALLOCS(ipnn, nat_save_t *, ipn.ipn_dsize);
   1616      0    stevel 		if (ipnn == NULL)
   1617      0    stevel 			return ENOMEM;
   1618      0    stevel 
   1619   2393  yz155240 		error = fr_inobjsz(data, ipnn, IPFOBJ_NATSAVE, ipn.ipn_dsize);
   1620      0    stevel 		if (error != 0) {
   1621      0    stevel 			error = EFAULT;
   1622      0    stevel 			goto junkput;
   1623      0    stevel 		}
   1624      0    stevel 	} else
   1625   2393  yz155240 		ipnn = &ipn;
   1626      0    stevel 
   1627      0    stevel 	KMALLOC(nat, nat_t *);
   1628      0    stevel 	if (nat == NULL) {
   1629      0    stevel 		error = ENOMEM;
   1630      0    stevel 		goto junkput;
   1631      0    stevel 	}
   1632      0    stevel 
   1633   2393  yz155240 	bcopy((char *)&ipnn->ipn_nat, (char *)nat, sizeof(*nat));
   1634      0    stevel 	/*
   1635      0    stevel 	 * Initialize all these so that nat_delete() doesn't cause a crash.
   1636      0    stevel 	 */
   1637   2393  yz155240 	bzero((char *)nat, offsetof(struct nat, nat_tqe));
   1638   2393  yz155240 	nat->nat_tqe.tqe_pnext = NULL;
   1639   2393  yz155240 	nat->nat_tqe.tqe_next = NULL;
   1640   2393  yz155240 	nat->nat_tqe.tqe_ifq = NULL;
   1641   2393  yz155240 	nat->nat_tqe.tqe_parent = nat;
   1642      0    stevel 
   1643      0    stevel 	/*
   1644      0    stevel 	 * Restore the rule associated with this nat session
   1645      0    stevel 	 */
   1646   2393  yz155240 	in = ipnn->ipn_nat.nat_ptr;
   1647      0    stevel 	if (in != NULL) {
   1648      0    stevel 		KMALLOC(in, ipnat_t *);
   1649   2393  yz155240 		nat->nat_ptr = in;
   1650      0    stevel 		if (in == NULL) {
   1651      0    stevel 			error = ENOMEM;
   1652      0    stevel 			goto junkput;
   1653      0    stevel 		}
   1654   2393  yz155240 		bzero((char *)in, offsetof(struct ipnat, in_next6));
   1655   2393  yz155240 		bcopy((char *)&ipnn->ipn_ipnat, (char *)in, sizeof(*in));
   1656      0    stevel 		in->in_use = 1;
   1657      0    stevel 		in->in_flags |= IPN_DELETE;
   1658   2393  yz155240 
   1659   3448  dh155122 		ATOMIC_INC(ifs->ifs_nat_stats.ns_rules);
   1660   3448  dh155122 
   1661   4380  jojemann 		if (nat_resolverule(in, ifs) != 0) {
   1662   4380  jojemann 			error = ESRCH;
   1663   4380  jojemann 			goto junkput;
   1664   4380  jojemann 		}
   1665    429  dr146992 	}
   1666    429  dr146992 
   1667    429  dr146992 	/*
   1668    429  dr146992 	 * Check that the NAT entry doesn't already exist in the kernel.
   1669    429  dr146992 	 */
   1670   7176  yx160601 	if (nat->nat_v != 6)
   1671   7176  yx160601 		nat->nat_v = 4;
   1672    429  dr146992 	bzero((char *)&fin, sizeof(fin));
   1673    429  dr146992 	fin.fin_p = nat->nat_p;
   1674   4414  jojemann 	fin.fin_ifs = ifs;
   1675    429  dr146992 	if (nat->nat_dir == NAT_OUTBOUND) {
   1676    429  dr146992 		fin.fin_data[0] = ntohs(nat->nat_oport);
   1677    429  dr146992 		fin.fin_data[1] = ntohs(nat->nat_outport);
   1678   2508  yz155240 		fin.fin_ifp = nat->nat_ifps[0];
   1679   1143  jojemann 		if (getlock) {
   1680   3448  dh155122 			READ_ENTER(&ifs->ifs_ipf_nat);
   1681   1143  jojemann 		}
   1682   7176  yx160601 
   1683   7176  yx160601 		switch (nat->nat_v)
   1684   7176  yx160601 		{
   1685   7176  yx160601 		case 4:
   1686   7176  yx160601 			fin.fin_v = nat->nat_v;
   1687   7176  yx160601 			n = nat_inlookup(&fin, nat->nat_flags, fin.fin_p,
   1688   7176  yx160601 			    nat->nat_oip, nat->nat_outip);
   1689   7176  yx160601 			break;
   1690   7176  yx160601 #ifdef USE_INET6
   1691   7176  yx160601 		case 6:
   1692   7176  yx160601 			n = nat6_inlookup(&fin, nat->nat_flags, fin.fin_p,
   1693   7176  yx160601 			    &nat->nat_oip6.in6, &nat->nat_outip6.in6);
   1694   7176  yx160601 			break;
   1695   7176  yx160601 #endif
   1696   7176  yx160601 		default:
   1697   7176  yx160601 			n = NULL;
   1698   7176  yx160601 			break;
   1699   7176  yx160601 		}
   1700   7176  yx160601 
   1701   1143  jojemann 		if (getlock) {
   1702   3448  dh155122 			RWLOCK_EXIT(&ifs->ifs_ipf_nat);
   1703   1143  jojemann 		}
   1704   1143  jojemann 		if (n != NULL) {
   1705    429  dr146992 			error = EEXIST;
   1706    429  dr146992 			goto junkput;
   1707    429  dr146992 		}
   1708    429  dr146992 	} else if (nat->nat_dir == NAT_INBOUND) {
   1709   1364  jojemann 		fin.fin_data[0] = ntohs(nat->nat_inport);
   1710    429  dr146992 		fin.fin_data[1] = ntohs(nat->nat_oport);
   1711   2508  yz155240 		fin.fin_ifp = nat->nat_ifps[1];
   1712   1143  jojemann 		if (getlock) {
   1713   3448  dh155122 			READ_ENTER(&ifs->ifs_ipf_nat);
   1714   1143  jojemann 		}
   1715   7176  yx160601 
   1716   7176  yx160601 		switch (nat->nat_v)
   1717   7176  yx160601 		{
   1718   7176  yx160601 		case 4:
   1719   7176  yx160601 			n = nat_outlookup(&fin, nat->nat_flags, fin.fin_p,
   1720   7176  yx160601 			    nat->nat_inip, nat->nat_oip);
   1721   7176  yx160601 			break;
   1722   7176  yx160601 #ifdef USE_INET6
   1723   7176  yx160601 		case 6:
   1724   7176  yx160601 			n = nat6_outlookup(&fin, nat->nat_flags, fin.fin_p,
   1725   7176  yx160601 			    &nat->nat_inip6.in6, &nat->nat_oip6.in6);
   1726   7176  yx160601 			break;
   1727   7176  yx160601 #endif
   1728   7176  yx160601 		default:
   1729   7176  yx160601 			n = NULL;
   1730   7176  yx160601 			break;
   1731   7176  yx160601 		}
   1732   7176  yx160601 
   1733   1143  jojemann 		if (getlock) {
   1734   3448  dh155122 			RWLOCK_EXIT(&ifs->ifs_ipf_nat);
   1735   1143  jojemann 		}
   1736   1143  jojemann 		if (n != NULL) {
   1737    429  dr146992 			error = EEXIST;
   1738    429  dr146992 			goto junkput;
   1739    429  dr146992 		}
   1740    429  dr146992 	} else {
   1741    429  dr146992 		error = EINVAL;
   1742    429  dr146992 		goto junkput;
   1743      0    stevel 	}
   1744      0    stevel 
   1745      0    stevel 	/*
   1746      0    stevel 	 * Restore ap_session_t structure.  Include the private data allocated
   1747      0    stevel 	 * if it was there.
   1748      0    stevel 	 */
   1749   2393  yz155240 	aps = nat->nat_aps;
   1750      0    stevel 	if (aps != NULL) {
   1751      0    stevel 		KMALLOC(aps, ap_session_t *);
   1752   2393  yz155240 		nat->nat_aps = aps;
   1753      0    stevel 		if (aps == NULL) {
   1754      0    stevel 			error = ENOMEM;
   1755      0    stevel 			goto junkput;
   1756      0    stevel 		}
   1757      0    stevel 		bcopy(ipnn->ipn_data, (char *)aps, sizeof(*aps));
   1758   2393  yz155240 		if (in != NULL)
   1759      0    stevel 			aps->aps_apr = in->in_apr;
   1760   2393  yz155240 		else
   1761   2393  yz155240 			aps->aps_apr = NULL;
   1762      0    stevel 		if (aps->aps_psiz != 0) {
   1763   2393  yz155240 			if (aps->aps_psiz > 81920) {
   1764   2393  yz155240 				error = ENOMEM;
   1765   2393  yz155240 				goto junkput;
   1766   2393  yz155240 			}
   1767      0    stevel 			KMALLOCS(aps->aps_data, void *, aps->aps_psiz);
   1768      0    stevel 			if (aps->aps_data == NULL) {
   1769      0    stevel 				error = ENOMEM;
   1770      0    stevel 				goto junkput;
   1771      0    stevel 			}
   1772      0    stevel 			bcopy(ipnn->ipn_data + sizeof(*aps), aps->aps_data,
   1773      0    stevel 			      aps->aps_psiz);
   1774      0    stevel 		} else {
   1775      0    stevel 			aps->aps_psiz = 0;
   1776      0    stevel 			aps->aps_data = NULL;
   1777      0    stevel 		}
   1778      0    stevel 	}
   1779      0    stevel 
   1780      0    stevel 	/*
   1781      0    stevel 	 * If there was a filtering rule associated with this entry then
   1782      0    stevel 	 * build up a new one.
   1783      0    stevel 	 */
   1784   2393  yz155240 	fr = nat->nat_fr;
   1785      0    stevel 	if (fr != NULL) {
   1786   2393  yz155240 		if ((nat->nat_flags & SI_NEWFR) != 0) {
   1787      0    stevel 			KMALLOC(fr, frentry_t *);
   1788      0    stevel 			nat->nat_fr = fr;
   1789      0    stevel 			if (fr == NULL) {
   1790      0    stevel 				error = ENOMEM;
   1791      0    stevel 				goto junkput;
   1792      0    stevel 			}
   1793   2393  yz155240 			ipnn->ipn_nat.nat_fr = fr;
   1794   2393  yz155240 			(void) fr_outobj(data, ipnn, IPFOBJ_NATSAVE);
   1795   2393  yz155240 			bcopy((char *)&ipnn->ipn_fr, (char *)fr, sizeof(*fr));
   1796   4380  jojemann 
   1797   4380  jojemann 			fr->fr_ref = 1;
   1798   4380  jojemann 			fr->fr_dsize = 0;
   1799   4380  jojemann 			fr->fr_data = NULL;
   1800   4380  jojemann 			fr->fr_type = FR_T_NONE;
   1801   4380  jojemann 
   1802      0    stevel 			MUTEX_NUKE(&fr->fr_lock);
   1803      0    stevel 			MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock");
   1804   2393  yz155240 		} else {
   1805   4380  jojemann 			if (getlock) {
   1806   4380  jojemann 				READ_ENTER(&ifs->ifs_ipf_nat);
   1807   4380  jojemann 			}
   1808   3448  dh155122 			for (n = ifs->ifs_nat_instances; n; n = n->nat_next)
   1809      0    stevel 				if (n->nat_fr == fr)
   1810      0    stevel 					break;
   1811   2393  yz155240 
   1812   1143  jojemann 			if (n != NULL) {
   1813   1143  jojemann 				MUTEX_ENTER(&fr->fr_lock);
   1814   1143  jojemann 				fr->fr_ref++;
   1815   1143  jojemann 				MUTEX_EXIT(&fr->fr_lock);
   1816   1143  jojemann 			}
   1817   4380  jojemann 			if (getlock) {
   1818   4380  jojemann 				RWLOCK_EXIT(&ifs->ifs_ipf_nat);
   1819   4380  jojemann 			}
   1820      0    stevel 			if (!n) {
   1821      0    stevel 				error = ESRCH;
   1822      0    stevel 				goto junkput;
   1823      0    stevel 			}
   1824      0    stevel 		}
   1825      0    stevel 	}
   1826      0    stevel 
   1827   2393  yz155240 	if (ipnn != &ipn) {
   1828   2393  yz155240 		KFREES(ipnn, ipn.ipn_dsize);
   1829   2393  yz155240 		ipnn = NULL;
   1830   2393  yz155240 	}
   1831   6253  an207044 
   1832   6253  an207044 	nat_calc_chksum_diffs(nat);
   1833   2393  yz155240 
   1834   2393  yz155240 	if (getlock) {
   1835   3448  dh155122 		WRITE_ENTER(&ifs->ifs_ipf_nat);
   1836   3448  dh155122 	}
   1837   7176  yx160601 
   1838   7176  yx160601 	nat_calc_chksum_diffs(nat);
   1839   7176  yx160601 
   1840   7176  yx160601 	switch (nat->nat_v)
   1841   7176  yx160601 	{
   1842   7176  yx160601 	case 4 :
   1843   7176  yx160601 		error = nat_insert(nat, nat->nat_rev, ifs);
   1844   7176  yx160601 		break;
   1845   7176  yx160601 #ifdef USE_INET6
   1846   7176  yx160601 	case 6 :
   1847   7176  yx160601 		error = nat6_insert(nat, nat->nat_rev, ifs);
   1848   7176  yx160601 		break;
   1849   7176  yx160601 #endif
   1850   7176  yx160601 	default :
   1851   7176  yx160601 		break;
   1852   7176  yx160601 	}
   1853   7176  yx160601 
   1854   2393  yz155240 	if ((error == 0) && (aps != NULL)) {
   1855   3448  dh155122 		aps->aps_next = ifs->ifs_ap_sess_list;
   1856   3448  dh155122 		ifs->ifs_ap_sess_list = aps;
   1857   3448  dh155122 	}
   1858   3448  dh155122 	if (getlock) {
   1859   3448  dh155122 		RWLOCK_EXIT(&ifs->ifs_ipf_nat);
   1860   1143  jojemann 	}
   1861   2393  yz155240 
   1862   2393  yz155240 	if (error == 0)
   1863   2393  yz155240 		return 0;
   1864   2393  yz155240 
   1865    263  jojemann 	error = ENOMEM;
   1866    263  jojemann 
   1867      0    stevel junkput:
   1868   2393  yz155240 	if (fr != NULL)
   1869   3448  dh155122 		(void) fr_derefrule(&fr, ifs);
   1870   2393  yz155240 
   1871   2393  yz155240 	if ((ipnn != NULL) && (ipnn != &ipn)) {
   1872   2393  yz155240 		KFREES(ipnn, ipn.ipn_dsize);
   1873    263  jojemann 	}
   1874    263  jojemann 	if (nat != NULL) {
   1875    263  jojemann 		if (aps != NULL) {
   1876    263  jojemann 			if (aps->aps_data != NULL) {
   1877    263  jojemann 				KFREES(aps->aps_data, aps->aps_psiz);
   1878    263  jojemann 			}
   1879    263  jojemann 			KFREE(aps);
   1880    263  jojemann 		}
   1881    263  jojemann 		if (in != NULL) {
   1882    263  jojemann 			if (in->in_apr)
   1883    263  jojemann 				appr_free(in->in_apr);
   1884    263  jojemann 			KFREE(in);
   1885    263  jojemann 		}
   1886    263  jojemann 		KFREE(nat);
   1887    263  jojemann 	}
   1888   2393  yz155240 	return error;
   1889      0    stevel }
   1890      0    stevel 
   1891      0    stevel 
   1892      0    stevel /* ------------------------------------------------------------------------ */
   1893      0    stevel /* Function:    nat_delete                                                  */
   1894   8170      John /* Returns:     int	- 0 if entry deleted. Otherwise, ref count on entry */
   1895   8170      John /* Parameters:  nat	- pointer to the NAT entry to delete		    */
   1896   8170      John /*		logtype	- type of LOG record to create before deleting	    */
   1897   8170      John /*		ifs	- ipf stack instance				    */
   1898      0    stevel /* Write Lock:  ipf_nat                                                     */
   1899      0    stevel /*                                                                          */
   1900      0    stevel /* Delete a nat entry from the various lists and table.  If NAT logging is  */
   1901      0    stevel /* enabled then generate a NAT log record for this event.                   */
   1902      0    stevel /* ------------------------------------------------------------------------ */
   1903   8170      John int nat_delete(nat, logtype, ifs)
   1904      0    stevel struct nat *nat;
   1905      0    stevel int logtype;
   1906   3448  dh155122 ipf_stack_t *ifs;
   1907      0    stevel {
   1908      0    stevel 	struct ipnat *ipn;
   1909   7432      John 	int removed = 0;
   1910      0    stevel 
   1911   3448  dh155122 	if (logtype != 0 && ifs->ifs_nat_logging != 0)
   1912   3448  dh155122 		nat_log(nat, logtype, ifs);
   1913   3448  dh155122 
   1914      0    stevel 	/*
   1915   7432      John 	 * Start by removing the entry from the hash table of nat entries
   1916   7432      John 	 * so it will not be "used" again.
   1917   7432      John 	 *
   1918   7432      John 	 * It will remain in the "list" of nat entries until all references
   1919   7432      John 	 * have been accounted for.
   1920   7432      John 	 */
   1921   7432      John 	if ((nat->nat_phnext[0] != NULL) && (nat->nat_phnext[1] != NULL)) {
   1922   7432      John 		removed = 1;
   1923   7432      John 
   1924   3448  dh155122 		ifs->ifs_nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--;
   1925   3448  dh155122 		ifs->ifs_nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--;
   1926      0    stevel 
   1927   7432      John 		*nat->nat_phnext[0] = nat->nat_hnext[0];
   1928   7432      John 		if (nat->nat_hnext[0] != NULL) {
   1929   7432      John 			nat->nat_hnext[0]->nat_phnext[0] = nat->nat_phnext[0];
   1930   7432      John 			nat->nat_hnext[0] = NULL;
   1931   7432      John 		}
   1932   7432      John 		nat->nat_phnext[0] = NULL;
   1933   7432      John 
   1934   7432      John 		*nat->nat_phnext[1] = nat->nat_hnext[1];
   1935   7432      John 		if (nat->nat_hnext[1] != NULL) {
   1936   7432      John 			nat->nat_hnext[1]->nat_phnext[1] = nat->nat_phnext[1];
   1937   7432      John 			nat->nat_hnext[1] = NULL;
   1938   7432      John 		}
   1939   7432      John 		nat->nat_phnext[1] = NULL;
   1940   7432      John 
   1941   7432      John 		if ((nat->nat_flags & SI_WILDP) != 0)
   1942   7432      John 			ifs->ifs_nat_stats.ns_wilds--;
   1943   7432      John 	}
   1944   7432      John 
   1945   7432      John 	/*
   1946   7432      John 	 * Next, remove it from the timeout queue it is in.
   1947   7432      John 	 */
   1948   7432      John 	fr_deletequeueentry(&nat->nat_tqe);
   1949   7432      John 
   1950   7432      John 	if (nat->nat_me != NULL) {
   1951   7432      John 		*nat->nat_me = NULL;
   1952   7432      John 		nat->nat_me = NULL;
   1953   7432      John 	}
   1954   7432      John 
   1955   7432      John 	MUTEX_ENTER(&nat->nat_lock);
   1956   8624    Darren  	if (nat->nat_ref > 1) {
   1957   7432      John 		nat->nat_ref--;
   1958   7432      John 		MUTEX_EXIT(&nat->nat_lock);
   1959   7432      John  		if (removed)
   1960   7432      John  			ifs->ifs_nat_stats.ns_orphans++;
   1961   8170      John 		return (nat->nat_ref);
   1962   7432      John 	}
   1963   7432      John 	MUTEX_EXIT(&nat->nat_lock);
   1964   7432      John 
   1965   7432      John 	nat->nat_ref = 0;
   1966   7432      John 
   1967   7432      John 	/*
   1968   7432      John 	 * If entry had already been removed,
   1969   7432      John 	 * it means we're cleaning up an orphan.
   1970   7432      John 	 */
   1971   7432      John  	if (!removed)
   1972   7432      John  		ifs->ifs_nat_stats.ns_orphans--;
   1973   7432      John 
   1974   7432      John #ifdef	IPFILTER_SYNC
   1975   7432      John 	if (nat->nat_sync)
   1976   7432      John 		ipfsync_del(nat->nat_sync);
   1977   7432      John #endif
   1978   7432      John 
   1979   7432      John 	/*
   1980   7432      John 	 * Now remove it from master list of nat table entries
   1981   7432      John 	 */
   1982   7432      John 	if (nat->nat_pnext != NULL) {
   1983      0    stevel 		*nat->nat_pnext = nat->nat_next;
   1984      0    stevel 		if (nat->nat_next != NULL) {
   1985      0    stevel 			nat->nat_next->nat_pnext = nat->nat_pnext;
   1986      0    stevel 			nat->nat_next = NULL;
   1987      0    stevel 		}
   1988      0    stevel 		nat->nat_pnext = NULL;
   1989   7432      John 	}
   1990   8170      John 
   1991      0    stevel 	if (nat->nat_fr != NULL)
   1992   3448  dh155122 		(void)fr_derefrule(&nat->nat_fr, ifs);
   1993      0    stevel 
   1994      0    stevel 	if (nat->nat_hm != NULL)
   1995   5417  jojemann 		fr_hostmapdel(&nat->nat_hm);
   1996      0    stevel 
   1997      0    stevel 	/*
   1998      0    stevel 	 * If there is an active reference from the nat entry to its parent
   1999      0    stevel 	 * rule, decrement the rule's reference count and free it too if no
   2000      0    stevel 	 * longer being used.
   2001      0    stevel 	 */
   2002      0    stevel 	ipn = nat->nat_ptr;
   2003      0    stevel 	if (ipn != NULL) {
   2004      0    stevel 		ipn->in_space++;
   2005      0    stevel 		ipn->in_use--;
   2006      0    stevel 		if (ipn->in_use == 0 && (ipn->in_flags & IPN_DELETE)) {
   2007      0    stevel 			if (ipn->in_apr)
   2008      0    stevel 				appr_free(ipn->in_apr);
   2009      0    stevel 			KFREE(ipn);
   2010   3448  dh155122 			ifs->ifs_nat_stats.ns_rules--;
   2011      0    stevel 		}
   2012      0    stevel 	}
   2013      0    stevel 
   2014      0    stevel 	MUTEX_DESTROY(&nat->nat_lock);
   2015      0    stevel 
   2016   3448  dh155122 	aps_free(nat->nat_aps, ifs);
   2017   3448  dh155122 	ifs->ifs_nat_stats.ns_inuse--;
   2018      0    stevel 
   2019      0    stevel 	/*
   2020      0    stevel 	 * If there's a fragment table entry too for this nat entry, then
   2021      0    stevel 	 * dereference that as well.  This is after nat_lock is released
   2022      0    stevel 	 * because of Tru64.
   2023      0    stevel 	 */
   2024   3448  dh155122 	fr_forgetnat((void *)nat, ifs);
   2025      0    stevel 
   2026      0    stevel 	KFREE(nat);
   2027   8170      John 
   2028   8170      John 	return (0);
   2029      0    stevel }
   2030      0    stevel 
   2031      0    stevel 
   2032      0    stevel /* ------------------------------------------------------------------------ */
   2033      0    stevel /* Function:    nat_clearlist                                               */
   2034      0    stevel /* Returns:     int - number of NAT/RDR rules deleted                       */
   2035      0    stevel /* Parameters:  Nil                                                         */
   2036      0    stevel /*                                                                          */
   2037      0    stevel /* Delete all rules in the current list of rules.  There is nothing elegant */
   2038      0    stevel /* about this cleanup: simply free all entries on the list of rules and     */
   2039      0    stevel /* clear out the tables used for hashed NAT rule lookups.                   */
   2040      0    stevel /* ------------------------------------------------------------------------ */
   2041   3448  dh155122 static int nat_clearlist(ifs)
   2042   3448  dh155122 ipf_stack_t *ifs;
   2043   3448  dh155122 {
   2044   3448  dh155122 	ipnat_t *n, **np = &ifs->ifs_nat_list;
   2045      0    stevel 	int i = 0;
   2046      0    stevel 
   2047   3448  dh155122 	if (ifs->ifs_nat_rules != NULL)
   2048   3448  dh155122 		bzero((char *)ifs->ifs_nat_rules,
   2049   3448  dh155122 		      sizeof(*ifs->ifs_nat_rules) * ifs->ifs_ipf_natrules_sz);
   2050   3448  dh155122 	if (ifs->ifs_rdr_rules != NULL)
   2051   3448  dh155122 		bzero((char *)ifs->ifs_rdr_rules,
   2052   3448  dh155122 		      sizeof(*ifs->ifs_rdr_rules) * ifs->ifs_ipf_rdrrules_sz);
   2053      0    stevel 
   2054      0    stevel 	while ((n = *np) != NULL) {
   2055      0    stevel 		*np = n->in_next;
   2056      0    stevel 		if (n->in_use == 0) {
   2057      0    stevel 			if (n->in_apr != NULL)
   2058      0    stevel 				appr_free(n->in_apr);
   2059      0    stevel 			KFREE(n);
   2060   3448  dh155122 			ifs->ifs_nat_stats.ns_rules--;
   2061      0    stevel 		} else {
   2062      0    stevel 			n->in_flags |= IPN_DELETE;
   2063      0    stevel 			n->in_next = NULL;
   2064      0    stevel 		}
   2065      0    stevel 		i++;
   2066      0    stevel 	}
   2067   3448  dh155122 	ifs->ifs_nat_masks = 0;
   2068   3448  dh155122 	ifs->ifs_rdr_masks = 0;
   2069   7176  yx160601 	for (i = 0; i < 4; i++) {
   2070   7176  yx160601 		ifs->ifs_nat6_masks[i] = 0;
   2071   7176  yx160601 		ifs->ifs_rdr6_masks[i] = 0;
   2072   7176  yx160601 	}
   2073      0    stevel 	return i;
   2074      0    stevel }
   2075      0    stevel 
   2076      0    stevel 
   2077      0    stevel /* ------------------------------------------------------------------------ */
   2078      0    stevel /* Function:    nat_newmap                                                  */
   2079      0    stevel /* Returns:     int - -1 == error, 0 == success                             */
   2080      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
   2081      0    stevel /*              nat(I) - pointer to NAT entry                               */
   2082      0    stevel /*              ni(I)  - pointer to structure with misc. information needed */
   2083      0    stevel /*                       to create new NAT entry.                           */
   2084      0    stevel /*                                                                          */
   2085      0    stevel /* Given an empty NAT structure, populate it with new information about a   */
   2086      0    stevel /* new NAT session, as defined by the matching NAT rule.                    */
   2087   2393  yz155240 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
   2088   2393  yz155240 /* to the new IP address for the translation.                               */
   2089      0    stevel /* ------------------------------------------------------------------------ */
   2090      0    stevel static INLINE int nat_newmap(fin, nat, ni)
   2091      0    stevel fr_info_t *fin;
   2092      0    stevel nat_t *nat;
   2093      0    stevel natinfo_t *ni;
   2094      0    stevel {
   2095      0    stevel 	u_short st_port, dport, sport, port, sp, dp;
   2096      0    stevel 	struct in_addr in, inb;
   2097      0    stevel 	hostmap_t *hm;
   2098      0    stevel 	u_32_t flags;
   2099      0    stevel 	u_32_t st_ip;
   2100      0    stevel 	ipnat_t *np;
   2101      0    stevel 	nat_t *natl;
   2102      0    stevel 	int l;
   2103   3448  dh155122 	ipf_stack_t *ifs = fin->fin_ifs;
   2104      0    stevel 
   2105      0    stevel 	/*
   2106      0    stevel 	 * If it's an outbound packet which doesn't match any existing
   2107      0    stevel 	 * record, then create a new port
   2108      0    stevel 	 */
   2109      0    stevel 	l = 0;
   2110      0    stevel 	hm = NULL;
   2111      0    stevel 	np = ni->nai_np;
   2112      0    stevel 	st_ip = np->in_nip;
   2113      0    stevel 	st_port = np->in_pnext;
   2114      0    stevel 	flags = ni->nai_flags;
   2115      0    stevel 	sport = ni->nai_sport;
   2116      0    stevel 	dport = ni->nai_dport;
   2117      0    stevel 
   2118      0    stevel 	/*
   2119      0    stevel 	 * Do a loop until we either run out of entries to try or we find
   2120      0    stevel 	 * a NAT mapping that isn't currently being used.  This is done
   2121      0    stevel 	 * because the change to the source is not (usually) being fixed.
   2122      0    stevel 	 */
   2123      0    stevel 	do {
   2124      0    stevel 		port = 0;
   2125      0    stevel 		in.s_addr = htonl(np->in_nip);
   2126      0    stevel 		if (l == 0) {
   2127      0    stevel 			/*
   2128      0    stevel 			 * Check to see if there is an existing NAT
   2129      0    stevel 			 * setup for this IP address pair.
   2130      0    stevel 			 */
   2131      0    stevel 			hm = nat_hostmap(np, fin->fin_src, fin->fin_dst,
   2132   3448  dh155122 					 in, 0, ifs);
   2133      0    stevel 			if (hm != NULL)
   2134      0    stevel 				in.s_addr = hm->hm_mapip.s_addr;
   2135      0    stevel 		} else if ((l == 1) && (hm != NULL)) {
   2136   5417  jojemann 			fr_hostmapdel(&hm);
   2137      0    stevel 		}
   2138      0    stevel 		in.s_addr = ntohl(in.s_addr);
   2139      0    stevel 
   2140      0    stevel 		nat->nat_hm = hm;
   2141      0    stevel 
   2142      0    stevel 		if ((np->in_outmsk == 0xffffffff) && (np->in_pnext == 0)) {
   2143      0    stevel 			if (l > 0)
   2144      0    stevel 				return -1;
   2145      0    stevel 		}
   2146      0    stevel 
   2147      0    stevel 		if (np->in_redir == NAT_BIMAP &&
   2148      0    stevel 		    np->in_inmsk == np->in_outmsk) {
   2149      0    stevel 			/*
   2150      0    stevel 			 * map the address block in a 1:1 fashion
   2151      0    stevel 			 */
   2152      0    stevel 			in.s_addr = np->in_outip;
   2153      0    stevel 			in.s_addr |= fin->fin_saddr & ~np->in_inmsk;
   2154      0    stevel 			in.s_addr = ntohl(in.s_addr);
   2155      0    stevel 
   2156      0    stevel 		} else if (np->in_redir & NAT_MAPBLK) {
   2157      0    stevel 			if ((l >= np->in_ppip) || ((l > 0) &&
   2158      0    stevel 			     !(flags & IPN_TCPUDP)))
   2159      0    stevel 				return -1;
   2160      0    stevel 			/*
   2161      0    stevel 			 * map-block - Calculate destination address.
   2162      0    stevel 			 */
   2163      0    stevel 			in.s_addr = ntohl(fin->fin_saddr);
   2164      0    stevel 			in.s_addr &= ntohl(~np->in_inmsk);
   2165      0    stevel 			inb.s_addr = in.s_addr;
   2166      0    stevel 			in.s_addr /= np->in_ippip;
   2167      0    stevel 			in.s_addr &= ntohl(~np->in_outmsk);
   2168      0    stevel 			in.s_addr += ntohl(np->in_outip);
   2169      0    stevel 			/*
   2170      0    stevel 			 * Calculate destination port.
   2171      0    stevel 			 */
   2172      0    stevel 			if ((flags & IPN_TCPUDP) &&
   2173      0    stevel 			    (np->in_ppip != 0)) {
   2174      0    stevel 				port = ntohs(sport) + l;
   2175      0    stevel 				port %= np->in_ppip;
   2176      0    stevel 				port += np->in_ppip *
   2177      0    stevel 					(inb.s_addr % np->in_ippip);
   2178      0    stevel 				port += MAPBLK_MINPORT;
   2179      0    stevel 				port = htons(port);
   2180      0    stevel 			}
   2181      0    stevel 
   2182      0    stevel 		} else if ((np->in_outip == 0) &&
   2183      0    stevel 			   (np->in_outmsk == 0xffffffff)) {
   2184      0    stevel 			/*
   2185      0    stevel 			 * 0/32 - use the interface's IP address.
   2186      0    stevel 			 */
   2187      0    stevel 			if ((l > 0) ||
   2188      0    stevel 			    fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp,
   2189   3448  dh155122 				       &in, NULL, fin->fin_ifs) == -1)
   2190      0    stevel 				return -1;
   2191      0    stevel 			in.s_addr = ntohl(in.s_addr);
   2192      0    stevel 
   2193      0    stevel 		} else if ((np->in_outip == 0) && (np->in_outmsk == 0)) {
   2194      0    stevel 			/*
   2195      0    stevel 			 * 0/0 - use the original source address/port.
   2196      0    stevel 			 */
   2197      0    stevel 			if (l > 0)
   2198      0    stevel 				return -1;
   2199      0    stevel 			in.s_addr = ntohl(fin->fin_saddr);
   2200      0    stevel 
   2201      0    stevel 		} else if ((np->in_outmsk != 0xffffffff) &&
   2202      0    stevel 			   (np->in_pnext == 0) && ((l > 0) || (hm == NULL)))
   2203      0    stevel 			np->in_nip++;
   2204      0    stevel 
   2205      0    stevel 		natl = NULL;
   2206      0    stevel 
   2207      0    stevel 		if ((flags & IPN_TCPUDP) &&
   2208      0    stevel 		    ((np->in_redir & NAT_MAPBLK) == 0) &&
   2209      0    stevel 		    (np->in_flags & IPN_AUTOPORTMAP)) {
   2210      0    stevel 			/*
   2211      0    stevel 			 * "ports auto" (without map-block)
   2212      0    stevel 			 */
   2213      0    stevel 			if ((l > 0) && (l % np->in_ppip == 0)) {
   2214      0    stevel 				if (l > np->in_space) {
   2215      0    stevel 					return -1;
   2216      0    stevel 				} else if ((l > np->in_ppip) &&
   2217      0    stevel 					   np->in_outmsk != 0xffffffff)
   2218      0    stevel 					np->in_nip++;
   2219      0    stevel 			}
   2220      0    stevel 			if (np->in_ppip != 0) {
   2221      0    stevel 				port = ntohs(sport);
   2222      0    stevel 				port += (l % np->in_ppip);
   2223      0    stevel 				port %= np->in_ppip;
   2224      0    stevel 				port += np->in_ppip *
   2225      0    stevel 					(ntohl(fin->fin_saddr) %
   2226      0    stevel 					 np->in_ippip);
   2227      0    stevel 				port += MAPBLK_MINPORT;
   2228      0    stevel 				port = htons(port);
   2229      0    stevel 			}
   2230      0    stevel 
   2231      0    stevel 		} else if (((np->in_redir & NAT_MAPBLK) == 0) &&
   2232      0    stevel 			   (flags & IPN_TCPUDPICMP) && (np->in_pnext != 0)) {
   2233      0    stevel 			/*
   2234      0    stevel 			 * Standard port translation.  Select next port.
   2235      0    stevel 			 */
   2236   7259  dr146992 			if (np->in_flags & IPN_SEQUENTIAL) {
   2237   7259  dr146992 				port = np->in_pnext;
   2238   7259  dr146992 			} else {
   2239   7259  dr146992 				port = ipf_random() % (ntohs(np->in_pmax) -
   2240   8624    Darren 						       ntohs(np->in_pmin) + 1);
   2241   7259  dr146992 				port += ntohs(np->in_pmin);
   2242   7259  dr146992 			}
   2243   7259  dr146992 			port = htons(port);
   2244   7259  dr146992 			np->in_pnext++;
   2245      0    stevel 
   2246      0    stevel 			if (np->in_pnext > ntohs(np->in_pmax)) {
   2247      0    stevel 				np->in_pnext = ntohs(np->in_pmin);
   2248      0    stevel 				if (np->in_outmsk != 0xffffffff)
   2249      0    stevel 					np->in_nip++;
   2250      0    stevel 			}
   2251      0    stevel 		}
   2252      0    stevel 
   2253      0    stevel 		if (np->in_flags & IPN_IPRANGE) {
   2254      0    stevel 			if (np->in_nip > ntohl(np->in_outmsk))
   2255      0    stevel 				np->in_nip = ntohl(np->in_outip);
   2256      0    stevel 		} else {
   2257      0    stevel 			if ((np->in_outmsk != 0xffffffff) &&
   2258      0    stevel 			    ((np->in_nip + 1) & ntohl(np->in_outmsk)) >
   2259      0    stevel 			    ntohl(np->in_outip))
   2260      0    stevel 				np->in_nip = ntohl(np->in_outip) + 1;
   2261      0    stevel 		}
   2262      0    stevel 
   2263      0    stevel 		if ((port == 0) && (flags & (IPN_TCPUDPICMP|IPN_ICMPQUERY)))
   2264      0    stevel 			port = sport;
   2265      0    stevel 
   2266      0    stevel 		/*
   2267      0    stevel 		 * Here we do a lookup of the connection as seen from
   2268      0    stevel 		 * the outside.  If an IP# pair already exists, try
   2269      0    stevel 		 * again.  So if you have A->B becomes C->B, you can
   2270      0    stevel 		 * also have D->E become C->E but not D->B causing
   2271      0    stevel 		 * another C->B.  Also take protocol and ports into
   2272      0    stevel 		 * account when determining whether a pre-existing
   2273      0    stevel 		 * NAT setup will cause an external conflict where
   2274      0    stevel 		 * this is appropriate.
   2275      0    stevel 		 */
   2276      0    stevel 		inb.s_addr = htonl(in.s_addr);
   2277      0    stevel 		sp = fin->fin_data[0];
   2278      0    stevel 		dp = fin->fin_data[1];
   2279      0    stevel 		fin->fin_data[0] = fin->fin_data[1];
   2280      0    stevel 		fin->fin_data[1] = htons(port);
   2281      0    stevel 		natl = nat_inlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
   2282      0    stevel 				    (u_int)fin->fin_p, fin->fin_dst, inb);
   2283      0    stevel 		fin->fin_data[0] = sp;
   2284      0    stevel 		fin->fin_data[1] = dp;
   2285      0    stevel 
   2286      0    stevel 		/*
   2287      0    stevel 		 * Has the search wrapped around and come back to the
   2288      0    stevel 		 * start ?
   2289      0    stevel 		 */
   2290      0    stevel 		if ((natl != NULL) &&
   2291      0    stevel 		    (np->in_pnext != 0) && (st_port == np->in_pnext) &&
   2292      0    stevel 		    (np->in_nip != 0) && (st_ip == np->in_nip))
   2293      0    stevel 			return -1;
   2294      0    stevel 		l++;
   2295      0    stevel 	} while (natl != NULL);
   2296      0    stevel 
   2297      0    stevel 	if (np->in_space > 0)
   2298      0    stevel 		np->in_space--;
   2299      0    stevel 
   2300      0    stevel 	/* Setup the NAT table */
   2301      0    stevel 	nat->nat_inip = fin->fin_src;
   2302      0    stevel 	nat->nat_outip.s_addr = htonl(in.s_addr);
   2303      0    stevel 	nat->nat_oip = fin->fin_dst;
   2304      0    stevel 	if (nat->nat_hm == NULL)
   2305      0    stevel 		nat->nat_hm = nat_hostmap(np, fin->fin_src, fin->fin_dst,
   2306   3448  dh155122 					  nat->nat_outip, 0, ifs);
   2307      0    stevel 
   2308   2393  yz155240 	if (flags & IPN_TCPUDP) {
   2309      0    stevel 		nat->nat_inport = sport;
   2310      0    stevel 		nat->nat_outport = port;	/* sport */
   2311      0    stevel 		nat->nat_oport = dport;
   2312      0    stevel 		((tcphdr_t *)fin->fin_dp)->th_sport = port;
   2313   2393  yz155240 	} else if (flags & IPN_ICMPQUERY) {
   2314      0    stevel 		((icmphdr_t *)fin->fin_dp)->icmp_id = port;
   2315   2393  yz155240 		nat->nat_inport = port;
   2316   2393  yz155240 		nat->nat_outport = port;
   2317   2393  yz155240 	}
   2318   2393  yz155240 
   2319   2393  yz155240 	ni->nai_ip.s_addr = in.s_addr;
   2320      0    stevel 	ni->nai_port = port;
   2321      0    stevel 	ni->nai_nport = dport;
   2322      0    stevel 	return 0;
   2323      0    stevel }
   2324      0    stevel 
   2325      0    stevel 
   2326      0    stevel /* ------------------------------------------------------------------------ */
   2327      0    stevel /* Function:    nat_newrdr                                                  */
   2328      0    stevel /* Returns:     int - -1 == error, 0 == success (no move), 1 == success and */
   2329      0    stevel /*                    allow rule to be moved if IPN_ROUNDR is set.          */
   2330      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
   2331      0    stevel /*              nat(I) - pointer to NAT entry                               */
   2332      0    stevel /*              ni(I)  - pointer to structure with misc. information needed */
   2333      0    stevel /*                       to create new NAT entry.                           */
   2334      0    stevel /*                                                                          */
   2335   2393  yz155240 /* ni.nai_ip is passed in uninitialised and must be set, in host byte order,*/
   2336   2393  yz155240 /* to the new IP address for the translation.                               */
   2337      0    stevel /* ------------------------------------------------------------------------ */
   2338      0    stevel static INLINE int nat_newrdr(fin, nat, ni)
   2339      0    stevel fr_info_t *fin;
   2340      0    stevel nat_t *nat;
   2341      0    stevel natinfo_t *ni;
   2342      0    stevel {
   2343      0    stevel 	u_short nport, dport, sport;
   2344   5828  jojemann 	struct in_addr in, inb;
   2345   5828  jojemann 	u_short sp, dp;
   2346      0    stevel 	hostmap_t *hm;
   2347      0    stevel 	u_32_t flags;
   2348      0    stevel 	ipnat_t *np;
   2349   5828  jojemann 	nat_t *natl;
   2350      0    stevel 	int move;
   2351   3448  dh155122 	ipf_stack_t *ifs = fin->fin_ifs;
   2352      0    stevel 
   2353      0    stevel 	move = 1;
   2354      0    stevel 	hm = NULL;
   2355   2393  yz155240 	in.s_addr = 0;
   2356      0    stevel 	np = ni->nai_np;
   2357      0    stevel 	flags = ni->nai_flags;
   2358      0    stevel 	sport = ni->nai_sport;
   2359      0    stevel 	dport = ni->nai_dport;
   2360      0    stevel 
   2361      0    stevel 	/*
   2362      0    stevel 	 * If the matching rule has IPN_STICKY set, then we want to have the
   2363      0    stevel 	 * same rule kick in as before.  Why would this happen?  If you have
   2364      0    stevel 	 * a collection of rdr rules with "round-robin sticky", the current
   2365      0    stevel 	 * packet might match a different one to the previous connection but
   2366      0    stevel 	 * we want the same destination to be used.
   2367      0    stevel 	 */
   2368      0    stevel 	if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) ==
   2369      0    stevel 	    (IPN_ROUNDR|IPN_STICKY)) {
   2370      0    stevel 		hm = nat_hostmap(NULL, fin->fin_src, fin->fin_dst, in,
   2371   3448  dh155122 				 (u_32_t)dport, ifs);
   2372      0    stevel 		if (hm != NULL) {
   2373   2393  yz155240 			in.s_addr = ntohl(hm->hm_mapip.s_addr);
   2374      0    stevel 			np = hm->hm_ipnat;
   2375      0    stevel 			ni->nai_np = np;
   2376      0    stevel 			move = 0;
   2377      0    stevel 		}
   2378      0    stevel 	}
   2379      0    stevel 
   2380      0    stevel 	/*
   2381      0    stevel 	 * Otherwise, it's an inbound packet. Most likely, we don't
   2382      0    stevel 	 * want to rewrite source ports and source addresses. Instead,
   2383      0    stevel 	 * we want to rewrite to a fixed internal address and fixed
   2384      0    stevel 	 * internal port.
   2385      0    stevel 	 */
   2386      0    stevel 	if (np->in_flags & IPN_SPLIT) {
   2387      0    stevel 		in.s_addr = np->in_nip;
   2388      0    stevel 
   2389      0    stevel 		if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) {
   2390      0    stevel 			hm = nat_hostmap(np, fin->fin_src, fin->fin_dst,
   2391   3448  dh155122 					 in, (u_32_t)dport, ifs);
   2392      0    stevel 			if (hm != NULL) {
   2393      0    stevel 				in.s_addr = hm->hm_mapip.s_addr;
   2394      0    stevel 				move = 0;
   2395      0    stevel 			}
   2396      0    stevel 		}
   2397      0    stevel 
   2398      0    stevel 		if (hm == NULL || hm->hm_ref == 1) {
   2399      0    stevel 			if (np->in_inip == htonl(in.s_addr)) {
   2400      0    stevel 				np->in_nip = ntohl(np->in_inmsk);
   2401      0    stevel 				move = 0;
   2402      0    stevel 			} else {
   2403      0    stevel 				np->in_nip = ntohl(np->in_inip);
   2404      0    stevel 			}
   2405      0    stevel 		}
   2406      0    stevel 
   2407      0    stevel 	} else if ((np->in_inip == 0) && (np->in_inmsk == 0xffffffff)) {
   2408      0    stevel 		/*
   2409      0    stevel 		 * 0/32 - use the interface's IP address.
   2410      0    stevel 		 */
   2411   3448  dh155122 		if (fr_ifpaddr(4, FRI_NORMAL, fin->fin_ifp, &in, NULL,
   2412   3448  dh155122 			   fin->fin_ifs) == -1)
   2413      0    stevel 			return -1;
   2414      0    stevel 		in.s_addr = ntohl(in.s_addr);
   2415      0    stevel 
   2416      0    stevel 	} else if ((np->in_inip == 0) && (np->in_inmsk== 0)) {
   2417      0    stevel 		/*
   2418      0    stevel 		 * 0/0 - use the original destination address/port.
   2419      0    stevel 		 */
   2420      0    stevel 		in.s_addr = ntohl(fin->fin_daddr);
   2421      0    stevel 
   2422      0    stevel 	} else if (np->in_redir == NAT_BIMAP &&
   2423      0    stevel 		   np->in_inmsk == np->in_outmsk) {
   2424      0    stevel 		/*
   2425      0    stevel 		 * map the address block in a 1:1 fashion
   2426      0    stevel 		 */
   2427   2393  yz155240 		in.s_addr = np->in_inip;
   2428   2393  yz155240 		in.s_addr |= fin->fin_daddr & ~np->in_inmsk;
   2429   2393  yz155240 		in.s_addr = ntohl(in.s_addr);
   2430      0    stevel 	} else {
   2431      0    stevel 		in.s_addr = ntohl(np->in_inip);
   2432      0    stevel 	}
   2433      0    stevel 
   2434      0    stevel 	if ((np->in_pnext == 0) || ((flags & NAT_NOTRULEPORT) != 0))
   2435      0    stevel 		nport = dport;
   2436      0    stevel 	else {
   2437      0    stevel 		/*
   2438      0    stevel 		 * Whilst not optimized for the case where
   2439      0    stevel 		 * pmin == pmax, the gain is not significant.
   2440      0    stevel 		 */
   2441   2393  yz155240 		if (((np->in_flags & IPN_FIXEDDPORT) == 0) &&
   2442   2393  yz155240 		    (np->in_pmin != np->in_pmax)) {
   2443      0    stevel 			nport = ntohs(dport) - ntohs(np->in_pmin) +
   2444      0    stevel 				ntohs(np->in_pnext);
   2445      0    stevel 			nport = htons(nport);
   2446      0    stevel 		} else
   2447      0    stevel 			nport = np->in_pnext;
   2448      0    stevel 	}
   2449      0    stevel 
   2450      0    stevel 	/*
   2451      0    stevel 	 * When the redirect-to address is set to 0.0.0.0, just
   2452      0    stevel 	 * assume a blank `forwarding' of the packet.  We don't
   2453      0    stevel 	 * setup any translation for this either.
   2454      0    stevel 	 */
   2455      0    stevel 	if (in.s_addr == 0) {
   2456      0    stevel 		if (nport == dport)
   2457      0    stevel 			return -1;
   2458      0    stevel 		in.s_addr = ntohl(fin->fin_daddr);
   2459      0    stevel 	}
   2460   5828  jojemann 
   2461   5828  jojemann 	/*
   2462   5828  jojemann 	 * Check to see if this redirect mapping already exists and if
   2463   5828  jojemann 	 * it does, return "failure" (allowing it to be created will just
   2464   5828  jojemann 	 * cause one or both of these "connections" to stop working.)
   2465   5828  jojemann 	 */
   2466   5828  jojemann 	inb.s_addr = htonl(in.s_addr);
   2467   5828  jojemann 	sp = fin->fin_data[0];
   2468   5828  jojemann 	dp = fin->fin_data[1];
   2469   5828  jojemann 	fin->fin_data[1] = fin->fin_data[0];
   2470   5828  jojemann 	fin->fin_data[0] = ntohs(nport);
   2471   5828  jojemann 	natl = nat_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH),
   2472   5828  jojemann 		    (u_int)fin->fin_p, inb, fin->fin_src);
   2473   5828  jojemann 	fin->fin_data[0] = sp;
   2474   5828  jojemann 	fin->fin_data[1] = dp;
   2475   5828  jojemann 	if (natl != NULL)
   2476   5828  jojemann 		return (-1);
   2477      0    stevel 
   2478      0    stevel 	nat->nat_inip.s_addr = htonl(in.s_addr);
   2479      0    stevel 	nat->nat_outip = fin->fin_dst;
   2480      0    stevel 	nat->nat_oip = fin->fin_src;
   2481      0    stevel 
   2482   2393  yz155240 	ni->nai_ip.s_addr = in.s_addr;
   2483      0    stevel 	ni->nai_nport = nport;
   2484      0    stevel 	ni->nai_port = sport;
   2485      0    stevel 
   2486      0    stevel 	if (flags & IPN_TCPUDP) {
   2487      0    stevel 		nat->nat_inport = nport;
   2488      0    stevel 		nat->nat_outport = dport;
   2489      0    stevel 		nat->nat_oport = sport;
   2490      0    stevel 		((tcphdr_t *)fin->fin_dp)->th_dport = nport;
   2491      0    stevel 	} else if (flags & IPN_ICMPQUERY) {
   2492      0    stevel 		((icmphdr_t *)fin->fin_dp)->icmp_id = nport;
   2493   2393  yz155240 		nat->nat_inport = nport;
   2494   2393  yz155240 		nat->nat_outport = nport;
   2495      0    stevel 	}
   2496      0    stevel 
   2497      0    stevel 	return move;
   2498      0    stevel }
   2499      0    stevel 
   2500      0    stevel /* ------------------------------------------------------------------------ */
   2501      0    stevel /* Function:    nat_new                                                     */
   2502      0    stevel /* Returns:     nat_t* - NULL == failure to create new NAT structure,       */
   2503      0    stevel /*                       else pointer to new NAT structure                  */
   2504      0    stevel /* Parameters:  fin(I)       - pointer to packet information                */
   2505      0    stevel /*              np(I)        - pointer to NAT rule                          */
   2506      0    stevel /*              natsave(I)   - pointer to where to store NAT struct pointer */
   2507      0    stevel /*              flags(I)     - flags describing the current packet          */
   2508      0    stevel /*              direction(I) - direction of packet (in/out)                 */
   2509      0    stevel /* Write Lock:  ipf_nat                                                     */
   2510      0    stevel /*                                                                          */
   2511      0    stevel /* Attempts to create a new NAT entry.  Does not actually change the packet */
   2512      0    stevel /* in any way.                                                              */
   2513      0    stevel /*                                                                          */
   2514      0    stevel /* This fucntion is in three main parts: (1) deal with creating a new NAT   */
   2515      0    stevel /* structure for a "MAP" rule (outgoing NAT translation); (2) deal with     */
   2516      0    stevel /* creating a new NAT structure for a "RDR" rule (incoming NAT translation) */
   2517      0    stevel /* and (3) building that structure and putting it into the NAT table(s).    */
   2518      0    stevel /* ------------------------------------------------------------------------ */
   2519      0    stevel nat_t *nat_new(fin, np, natsave, flags, direction)
   2520      0    stevel fr_info_t *fin;
   2521      0    stevel ipnat_t *np;
   2522      0    stevel nat_t **natsave;
   2523      0    stevel u_int flags;
   2524      0    stevel int direction;
   2525      0    stevel {
   2526      0    stevel 	tcphdr_t *tcp = NULL;
   2527      0    stevel 	hostmap_t *hm = NULL;
   2528      0    stevel 	nat_t *nat, *natl;
   2529      0    stevel 	u_int nflags;
   2530      0    stevel 	natinfo_t ni;
   2531      0    stevel 	int move;
   2532   3448  dh155122 	ipf_stack_t *ifs = fin->fin_ifs;
   2533   4817  an207044 
   2534   4817  an207044 	/*
   2535   8170      John 	 * Trigger automatic call to nat_flushtable() if the
   2536   4817  an207044 	 * table has reached capcity specified by hi watermark.
   2537   4817  an207044 	 */
   2538   8170      John 	if (NAT_TAB_WATER_LEVEL(ifs) > ifs->ifs_nat_flush_level_hi)
   2539   4817  an207044 		ifs->ifs_nat_doflush = 1;
   2540   3448  dh155122 
   2541   7432      John 	/*
   2542   7432      John 	 * If automatic flushing did not do its job, and the table
   2543   7432      John 	 * has filled up, don't try to create a new entry.
   2544   7432      John 	 */
   2545   3448  dh155122 	if (ifs->ifs_nat_stats.ns_inuse >= ifs->ifs_ipf_nattable_max) {
   2546   3448  dh155122 		ifs->ifs_nat_stats.ns_memfail++;
   2547   2393  yz155240 		return NULL;
   2548   2393  yz155240 	}
   2549      0    stevel 
   2550      0    stevel 	move = 1;
   2551      0    stevel 	nflags = np->in_flags & flags;
   2552      0    stevel 	nflags &= NAT_FROMRULE;
   2553      0    stevel 
   2554      0    stevel 	ni.nai_np = np;
   2555      0    stevel 	ni.nai_nflags = nflags;
   2556      0    stevel 	ni.nai_flags = flags;
   2557      0    stevel 
   2558      0    stevel 	/* Give me a new nat */
   2559      0    stevel 	KMALLOC(nat, nat_t *);
   2560      0    stevel 	if (nat == NULL) {
   2561   3448  dh155122 		ifs->ifs_nat_stats.ns_memfail++;
   2562   2393  yz155240 		/*
   2563   2393  yz155240 		 * Try to automatically tune the max # of entries in the
   2564   2393  yz155240 		 * table allowed to be less than what will cause kmem_alloc()
   2565   2393  yz155240 		 * to fail and try to eliminate panics due to out of memory
   2566   2393  yz155240 		 * conditions arising.
   2567   2393  yz155240 		 */
   2568   3448  dh155122 		if (ifs->ifs_ipf_nattable_max > ifs->ifs_ipf_nattable_sz) {
   2569   3448  dh155122 			ifs->ifs_ipf_nattable_max = ifs->ifs_nat_stats.ns_inuse - 100;
   2570   2393  yz155240 			printf("ipf_nattable_max reduced to %d\n",
   2571   3448  dh155122 				ifs->ifs_ipf_nattable_max);
   2572   2393  yz155240 		}
   2573      0    stevel 		return NULL;
   2574      0    stevel 	}
   2575      0    stevel 
   2576      0    stevel 	if (flags & IPN_TCPUDP) {
   2577      0    stevel 		tcp = fin->fin_dp;
   2578      0    stevel 		ni.nai_sport = htons(fin->fin_sport);
   2579      0    stevel 		ni.nai_dport = htons(fin->fin_dport);
   2580      0    stevel 	} else if (flags & IPN_ICMPQUERY) {
   2581      0    stevel 		/*
   2582      0    stevel 		 * In the ICMP query NAT code, we translate the ICMP id fields
   2583   2393  yz155240 		 * to make them unique. This is indepedent of the ICMP type
   2584   2393  yz155240 		 * (e.g. in the unlikely event that a host sends an echo and
   2585   2393  yz155240 		 * an tstamp request with the same id, both packets will have
   2586      0    stevel 		 * their ip address/id field changed in the same way).
   2587      0    stevel 		 */
   2588      0    stevel 		/* The icmp_id field is used by the sender to identify the
   2589   2393  yz155240 		 * process making the icmp request. (the receiver justs
   2590   2393  yz155240 		 * copies it back in its response). So, it closely matches
   2591   2393  yz155240 		 * the concept of source port. We overlay sport, so we can
   2592      0    stevel 		 * maximally reuse the existing code.
   2593      0    stevel 		 */
   2594      0    stevel 		ni.nai_sport = ((icmphdr_t *)fin->fin_dp)->icmp_id;
   2595      0    stevel 		ni.nai_dport = ni.nai_sport;
   2596      0    stevel 	}
   2597      0    stevel 
   2598      0    stevel 	bzero((char *)nat, sizeof(*nat));
   2599      0    stevel 	nat->nat_flags = flags;
   2600   3448  dh155122 	nat->nat_redir = np->in_redir;
   2601      0    stevel 
   2602   2393  yz155240 	if ((flags & NAT_SLAVE) == 0) {
   2603   3448  dh155122 		MUTEX_ENTER(&ifs->ifs_ipf_nat_new);
   2604   2393  yz155240 	}
   2605      0    stevel 
   2606      0    stevel 	/*
   2607      0    stevel 	 * Search the current table for a match.
   2608      0    stevel 	 */
   2609      0    stevel 	if (direction == NAT_OUTBOUND) {
   2610      0    stevel 		/*
   2611      0    stevel 		 * We can now arrange to call this for the same connection
   2612      0    stevel 		 * because ipf_nat_new doesn't protect the code path into
   2613      0    stevel 		 * this function.
   2614      0    stevel 		 */
   2615      0    stevel 		natl = nat_outlookup(fin, nflags, (u_int)fin->fin_p,
   2616      0    stevel 				     fin->fin_src, fin->fin_dst);
   2617      0    stevel 		if (natl != NULL) {
   2618   4380  jojemann 			KFREE(nat);
   2619   2393  yz155240 			nat = natl;
   2620   2393  yz155240 			goto done;
   2621      0    stevel 		}
   2622      0    stevel 
   2623      0    stevel 		move = nat_newmap(fin, nat, &ni);
   2624   2393  yz155240 		if (move == -1)
   2625      0    stevel 			goto badnat;
   2626      0    stevel 
   2627      0    stevel 		np = ni.nai_np;
   2628      0    stevel 	} else {
   2629   2393  yz155240 		/*
   2630      0    stevel 		 * NAT_INBOUND is used only for redirects rules
   2631      0    stevel 		 */
   2632      0    stevel 		natl = nat_inlookup(fin, nflags, (u_int)fin->fin_p,
   2633      0    stevel 				    fin->fin_src, fin->fin_dst);
   2634      0    stevel 		if (natl != NULL) {
   2635   4380  jojemann 			KFREE(nat);
   2636   2393  yz155240 			nat = natl;
   2637   2393  yz155240 			goto done;
   2638      0    stevel 		}
   2639      0    stevel 
   2640      0    stevel 		move = nat_newrdr(fin, nat, &ni);
   2641   2393  yz155240 		if (move == -1)
   2642      0    stevel 			goto badnat;
   2643      0    stevel 
   2644      0    stevel 		np = ni.nai_np;
   2645   6256  an207044 	}
   2646      0    stevel 
   2647      0    stevel 	if ((move == 1) && (np->in_flags & IPN_ROUNDR)) {
   2648      0    stevel 		if (np->in_redir == NAT_REDIRECT) {
   2649      0    stevel 			nat_delrdr(np);
   2650   3448  dh155122 			nat_addrdr(np, ifs);
   2651      0    stevel 		} else if (np->in_redir == NAT_MAP) {
   2652      0    stevel 			nat_delnat(np);
   2653   3448  dh155122 			nat_addnat(np, ifs);
   2654      0    stevel 		}
   2655      0    stevel 	}
   2656      0    stevel 
   2657      0    stevel 	if (nat_finalise(fin, nat, &ni, tcp, natsave, direction) == -1) {
   2658   2393  yz155240 		goto badnat;
   2659      0    stevel 	}
   2660   6253  an207044 
   2661   6253  an207044 	nat_calc_chksum_diffs(nat);
   2662   6253  an207044 
   2663      0    stevel 	if (flags & SI_WILDP)
   2664   3448  dh155122 		ifs->ifs_nat_stats.ns_wilds++;
   2665   7432      John 	fin->fin_flx |= FI_NEWNAT;
   2666   2393  yz155240 	goto done;
   2667      0    stevel badnat:
   2668   3448  dh155122 	ifs->ifs_nat_stats.ns_badnat++;
   2669      0    stevel 	if ((hm = nat->nat_hm) != NULL)
   2670   5417  jojemann 		fr_hostmapdel(&hm);
   2671      0    stevel 	KFREE(nat);
   2672   2393  yz155240 	nat = NULL;
   2673   2393  yz155240 done:
   2674   2393  yz155240 	if ((flags & NAT_SLAVE) == 0) {
   2675   3448  dh155122 		MUTEX_EXIT(&ifs->ifs_ipf_nat_new);
   2676   2393  yz155240 	}
   2677   2393  yz155240 	return nat;
   2678      0    stevel }
   2679      0    stevel 
   2680      0    stevel 
   2681      0    stevel /* ------------------------------------------------------------------------ */
   2682      0    stevel /* Function:    nat_finalise                                                */
   2683      0    stevel /* Returns:     int - 0 == sucess, -1 == failure                            */
   2684      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
   2685      0    stevel /*              nat(I) - pointer to NAT entry                               */
   2686      0    stevel /*              ni(I)  - pointer to structure with misc. information needed */
   2687      0    stevel /*                       to create new NAT entry.                           */
   2688      0    stevel /* Write Lock:  ipf_nat                                                     */
   2689      0    stevel /*                                                                          */
   2690      0    stevel /* This is the tail end of constructing a new NAT entry and is the same     */
   2691      0    stevel /* for both IPv4 and IPv6.                                                  */
   2692      0    stevel /* ------------------------------------------------------------------------ */
   2693      0    stevel /*ARGSUSED*/
   2694      0    stevel static INLINE int nat_finalise(fin, nat, ni, tcp, natsave, direction)
   2695      0    stevel fr_info_t *fin;
   2696      0    stevel nat_t *nat;
   2697      0    stevel natinfo_t *ni;
   2698      0    stevel tcphdr_t *tcp;
   2699      0    stevel nat_t **natsave;
   2700      0    stevel int direction;
   2701      0    stevel {
   2702      0    stevel 	frentry_t *fr;
   2703      0    stevel 	ipnat_t *np;
   2704   3448  dh155122 	ipf_stack_t *ifs = fin->fin_ifs;
   2705      0    stevel 
   2706      0    stevel 	np = ni->nai_np;
   2707      0    stevel 
   2708   2958  dr146992 	COPYIFNAME(fin->fin_ifp, nat->nat_ifnames[0], fin->fin_v);
   2709   2958  dr146992 
   2710   2146  jojemann #ifdef	IPFILTER_SYNC
   2711   2146  jojemann 	if ((nat->nat_flags & SI_CLONE) == 0)
   2712   2146  jojemann 		nat->nat_sync = ipfsync_new(SMC_NAT, fin, nat);
   2713      0    stevel #endif
   2714      0    stevel 
   2715      0    stevel 	nat->nat_me = natsave;
   2716      0    stevel 	nat->nat_dir = direction;
   2717   2508  yz155240 	nat->nat_ifps[0] = np->in_ifps[0];
   2718   2508  yz155240 	nat->nat_ifps[1] = np->in_ifps[1];
   2719      0    stevel 	nat->nat_ptr = np;
   2720      0    stevel 	nat->nat_p = fin->fin_p;
   2721   7176  yx160601 	nat->nat_v = fin->fin_v;
   2722      0    stevel 	nat->nat_mssclamp = np->in_mssclamp;
   2723      0    stevel 	fr = fin->fin_fr;
   2724      0    stevel 	nat->nat_fr = fr;
   2725      0    stevel 
   2726      0    stevel 	if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0))
   2727      0    stevel 		if (appr_new(fin, nat) == -1)
   2728      0    stevel 			return -1;
   2729      0    stevel 
   2730   3448  dh155122 	if (nat_insert(nat, fin->fin_rev, ifs) == 0) {
   2731   3448  dh155122 		if (ifs->ifs_nat_logging)
   2732   3448  dh155122 			nat_log(nat, (u_int)np->in_redir, ifs);
   2733      0    stevel 		np->in_use++;
   2734      0    stevel 		if (fr != NULL) {
   2735      0    stevel 			MUTEX_ENTER(&fr->fr_lock);
   2736      0    stevel 			fr->fr_ref++;
   2737      0    stevel 			MUTEX_EXIT(&fr->fr_lock);
   2738      0    stevel 		}
   2739      0    stevel 		return 0;
   2740      0    stevel 	}
   2741      0    stevel 
   2742      0    stevel 	/*
   2743      0    stevel 	 * nat_insert failed, so cleanup time...
   2744      0    stevel 	 */
   2745      0    stevel 	return -1;
   2746      0    stevel }
   2747      0    stevel 
   2748      0    stevel 
   2749      0    stevel /* ------------------------------------------------------------------------ */
   2750   2393  yz155240 /* Function:   nat_insert                                                   */
   2751   2393  yz155240 /* Returns:    int - 0 == sucess, -1 == failure                             */
   2752   2393  yz155240 /* Parameters: nat(I) - pointer to NAT structure                            */
   2753   2393  yz155240 /*             rev(I) - flag indicating forward/reverse direction of packet */
   2754   2393  yz155240 /* Write Lock: ipf_nat                                                      */
   2755      0    stevel /*                                                                          */
   2756      0    stevel /* Insert a NAT entry into the hash tables for searching and add it to the  */
   2757      0    stevel /* list of active NAT entries.  Adjust global counters when complete.       */
   2758      0    stevel /* ------------------------------------------------------------------------ */
   2759   3448  dh155122 int	nat_insert(nat, rev, ifs)
   2760      0    stevel nat_t	*nat;
   2761   2393  yz155240 int	rev;
   2762   3448  dh155122 ipf_stack_t *ifs;
   2763   2393  yz155240 {
   2764      0    stevel 	u_int hv1, hv2;
   2765      0    stevel 	nat_t **natp;
   2766      0    stevel 
   2767      0    stevel 	/*
   2768      0    stevel 	 * Try and return an error as early as possible, so calculate the hash
   2769      0    stevel 	 * entry numbers first and then proceed.
   2770      0    stevel 	 */
   2771      0    stevel 	if ((nat->nat_flags & (SI_W_SPORT|SI_W_DPORT)) == 0) {
   2772      0    stevel 		hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, nat->nat_inport,
   2773      0    stevel 				  0xffffffff);
   2774      0    stevel 		hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1 + nat->nat_oport,
   2775   3448  dh155122 				  ifs->ifs_ipf_nattable_sz);
   2776      0    stevel 		hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, nat->nat_outport,
   2777      0    stevel 				  0xffffffff);
   2778      0    stevel 		hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2 + nat->nat_oport,
   2779   3448  dh155122 				  ifs->ifs_ipf_nattable_sz);
   2780      0    stevel 	} else {
   2781      0    stevel 		hv1 = NAT_HASH_FN(nat->nat_inip.s_addr, 0, 0xffffffff);
   2782   3448  dh155122 		hv1 = NAT_HASH_FN(nat->nat_oip.s_addr, hv1,
   2783   3448  dh155122 				  ifs->ifs_ipf_nattable_sz);
   2784      0    stevel 		hv2 = NAT_HASH_FN(nat->nat_outip.s_addr, 0, 0xffffffff);
   2785   3448  dh155122 		hv2 = NAT_HASH_FN(nat->nat_oip.s_addr, hv2,
   2786   3448  dh155122 				  ifs->ifs_ipf_nattable_sz);
   2787   3448  dh155122 	}
   2788   3448  dh155122 
   2789   3448  dh155122 	if (ifs->ifs_nat_stats.ns_bucketlen[0][hv1] >= ifs->ifs_fr_nat_maxbucket ||
   2790   3448  dh155122 	    ifs->ifs_nat_stats.ns_bucketlen[1][hv2] >= ifs->ifs_fr_nat_maxbucket) {
   2791      0    stevel 		return -1;
   2792   2393  yz155240 	}
   2793      0    stevel 
   2794      0    stevel 	nat->nat_hv[0] = hv1;
   2795      0    stevel 	nat->nat_hv[1] = hv2;
   2796      0    stevel 
   2797      0    stevel 	MUTEX_INIT(&nat->nat_lock, "nat entry lock");
   2798      0    stevel 
   2799   2393  yz155240 	nat->nat_rev = rev;
   2800      0    stevel 	nat->nat_ref = 1;
   2801      0    stevel 	nat->nat_bytes[0] = 0;
   2802      0    stevel 	nat->nat_pkts[0] = 0;
   2803      0    stevel 	nat->nat_bytes[1] = 0;
   2804      0    stevel 	nat->nat_pkts[1] = 0;
   2805   2393  yz155240 
   2806   2393  yz155240 	nat->nat_ifnames[0][LIFNAMSIZ - 1] = '\0';
   2807   3448  dh155122 	nat->nat_ifps[0] = fr_resolvenic(nat->nat_ifnames[0], 4, ifs);
   2808   2393  yz155240 
   2809   2393  yz155240 	if (nat->nat_ifnames[1][0] !='\0') {
   2810   2393  yz155240 		nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
   2811   3448  dh155122 		nat->nat_ifps[1] = fr_resolvenic(nat->nat_ifnames[1], 4, ifs);
   2812      0    stevel 	} else {
   2813   2146  jojemann 		(void) strncpy(nat->nat_ifnames[1], nat->nat_ifnames[0],
   2814   2393  yz155240 			       LIFNAMSIZ);
   2815   2393  yz155240 		nat->nat_ifnames[1][LIFNAMSIZ - 1] = '\0';
   2816      0    stevel 		nat->nat_ifps[1] = nat->nat_ifps[0];
   2817      0    stevel 	}
   2818      0    stevel 
   2819   3448  dh155122 	nat->nat_next = ifs->ifs_nat_instances;
   2820   3448  dh155122 	nat->nat_pnext = &ifs->ifs_nat_instances;
   2821   3448  dh155122 	if (ifs->ifs_nat_instances)
   2822   3448  dh155122 		ifs->ifs_nat_instances->nat_pnext = &nat->nat_next;
   2823   3448  dh155122 	ifs->ifs_nat_instances = nat;
   2824   3448  dh155122 
   2825   3448  dh155122 	natp = &ifs->ifs_nat_table[0][hv1];
   2826      0    stevel 	if (*natp)
   2827      0    stevel 		(*natp)->nat_phnext[0] = &nat->nat_hnext[0];
   2828      0    stevel 	nat->nat_phnext[0] = natp;
   2829      0    stevel 	nat->nat_hnext[0] = *natp;
   2830      0    stevel 	*natp = nat;
   2831   3448  dh155122 	ifs->ifs_nat_stats.ns_bucketlen[0][hv1]++;
   2832   3448  dh155122 
   2833   3448  dh155122 	natp = &ifs->ifs_nat_table[1][hv2];
   2834      0    stevel 	if (*natp)
   2835      0    stevel 		(*natp)->nat_phnext[1] = &nat->nat_hnext[1];
   2836      0    stevel 	nat->nat_phnext[1] = natp;
   2837      0    stevel 	nat->nat_hnext[1] = *natp;
   2838      0    stevel 	*natp = nat;
   2839   3448  dh155122 	ifs->ifs_nat_stats.ns_bucketlen[1][hv2]++;
   2840   3448  dh155122 
   2841   3448  dh155122 	fr_setnatqueue(nat, rev, ifs);
   2842   3448  dh155122 
   2843   3448  dh155122 	ifs->ifs_nat_stats.ns_added++;
   2844   3448  dh155122 	ifs->ifs_nat_stats.ns_inuse++;
   2845      0    stevel 	return 0;
   2846      0    stevel }
   2847      0    stevel 
   2848      0    stevel 
   2849      0    stevel /* ------------------------------------------------------------------------ */
   2850      0    stevel /* Function:    nat_icmperrorlookup                                         */
   2851      0    stevel /* Returns:     nat_t* - point to matching NAT structure                    */
   2852      0    stevel /* Parameters:  fin(I) - pointer to packet information                      */
   2853      0    stevel /*              dir(I) - direction of packet (in/out)                       */
   2854      0    stevel /*                                                                          */
   2855      0    stevel /* Check if the ICMP error message is related to an existing TCP, UDP or    */
   2856   2393  yz155240 /* ICMP query nat entry.  It is assumed that the packet is already of the   */
   2857   2393  yz155240 /* the required length.                                                     */
   2858      0    stevel /* ------------------------------------------------------------------------ */
   2859      0    stevel nat_t *nat_icmperrorlookup(fin, dir)
   2860      0    stevel fr_info_t *fin;
   2861      0    stevel int dir;
   2862      0    stevel {
   2863   2393  yz155240 	int flags = 0, minlen;
   2864   2393  yz155240 	icmphdr_t *orgicmp;
   2865      0    stevel 	tcphdr_t *tcp = NULL;
   2866   2393  yz155240 	u_short data[2];
   2867   2393  yz155240 	nat_t *nat;
   2868      0    stevel 	ip_t *oip;
   2869      0    stevel 	u_int p;
   2870      0    stevel 
   2871      0    stevel 	/*
   2872      0    stevel 	 * Does it at least have the return (basic) IP header ?
   2873      0    stevel 	 * Only a basic IP header (no options) should be with an ICMP error
   2874   2393  yz155240 	 * header.  Also, if it's not an error type, then return.
   2875   2393  yz155240 	 */
   2876   2393  yz155240 	if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR))
   2877   2393  yz155240 		return NULL;
   2878   2393  yz155240 
   2879   2393  yz155240 	/*
   2880   2393  yz155240 	 * Check packet size
   2881      0    stevel 	 */
   2882      0    stevel 	oip = (ip_t *)((char *)fin->fin_dp + 8);
   2883      0    stevel 	minlen = IP_HL(oip) << 2;
   2884   2393  yz155240 	if ((minlen < sizeof(ip_t)) ||
   2885   2393  yz155240 	    (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen))
   2886      0    stevel 		return NULL;
   2887      0    stevel 	/*
   2888      0    stevel 	 * Is the buffer big enough for all of it ?  It's the size of the IP
   2889      0    stevel 	 * header claimed in the encapsulated part which is of concern.  It
   2890      0    stevel 	 * may be too big to be in this buffer but not so big that it's
   2891      0    stevel 	 * outside the ICMP packet, leading to TCP deref's causing problems.
   2892      0    stevel 	 * This is possible because we don't know how big oip_hl is when we
   2893      0    stevel 	 * do the pullup early in fr_check() and thus can't gaurantee it is
   2894      0    stevel 	 * all here now.
   2895      0    stevel 	 */
   2896      0    stevel #ifdef  _KERNEL
   2897      0    stevel 	{
   2898      0    stevel 	mb_t *m;
   2899      0    stevel 
   2900      0    stevel 	m = fin->fin_m;
   2901      0    stevel # if defined(MENTAT)
   2902      0    stevel 	if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr)
   2903      0    stevel 		return NULL;
   2904   2393  yz155240 # else
   2905      0    stevel 	if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
   2906      0    stevel 	    (char *)fin->fin_ip + M_LEN(m))
   2907   2393  yz155240 		return NULL;
   2908   2393  yz155240 # endif
   2909   2393  yz155240 	}
   2910   2393  yz155240 #endif
   2911   2393  yz155240 
   2912   2393  yz155240 	if (fin->fin_daddr != oip->ip_src.s_addr)
   2913   2393  yz155240 		return NULL;
   2914   2393  yz155240 
   2915      0    stevel 	p = oip->ip_p;
   2916      0    stevel 	if (p == IPPROTO_TCP)
   2917      0    stevel 		flags = IPN_TCP;
   2918      0    stevel 	else if (p == IPPROTO_UDP)
   2919      0    stevel 		flags = IPN_UDP;
   2920      0    stevel 	else if (p == IPPROTO_ICMP) {
   2921      0    stevel 		orgicmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2));
   2922      0    stevel 
   2923      0    stevel 		/* see if this is related to an ICMP query */
   2924      0    stevel 		if (nat_icmpquerytype4(orgicmp->icmp_type)) {
   2925   2393  yz155240 			data[0] = fin->fin_data[0];
   2926   2393  yz155240 			data[1] = fin->fin_data[1];
   2927   2393  yz155240 			fin->fin_data[0] = 0;
   2928   2393  yz155240 			fin->fin_data[1] = orgicmp->icmp_id;
   2929   2393  yz155240 
   2930   2393  yz155240 			flags = IPN_ICMPERR|IPN_ICMPQUERY;
   2931      0    stevel 			/*
   2932      0    stevel 			 * NOTE : dir refers to the direction of the original
   2933      0    stevel 			 *        ip packet. By definition the icmp error
   2934      0    stevel 			 *        message flows in the opposite direction.
   2935      0    stevel 			 */
   2936      0    stevel 			if (dir == NAT_INBOUND)
   2937   2393  yz155240 				nat = nat_inlookup(fin, flags, p, oip->ip_dst,
   2938   2393  yz155240 						   oip->ip_src);
   2939   2393  yz155240 			else
   2940   2393  yz155240 				nat = nat_outlookup(fin, flags, p, oip->ip_dst,
   2941      0    stevel 						    oip->ip_src);
   2942   2393  yz155240 			fin->fin_data[0] = data[0];
   2943   2393  yz155240 			fin->fin_data[1] = data[1];
   2944   2393  yz155240 			return nat;
   2945      0    stevel 		}
   2946      0    stevel 	}
   2947      0    stevel 
   2948      0    stevel 	if (flags & IPN_TCPUDP) {
   2949      0    stevel 		minlen += 8;		/* + 64bits of data to get ports */
   2950      0    stevel 		if (fin->fin_plen < ICMPERR_IPICMPHLEN + minlen)
   2951      0    stevel 			return NULL;
   2952      0    stevel 
   2953      0    stevel 		data[0] = fin->fin_data[0];
   2954      0    stevel 		data[1] = fin->fin_data[1];
   2955      0    stevel 		tcp = (tcphdr_t *)((char *)oip + (IP_HL(oip) << 2));
   2956      0    stevel 		fin->fin_data[0] = ntohs(tcp->th_dport);
   2957      0    stevel 		fin->fin_data[1] = ntohs(tcp->th_sport);
   2958      0    stevel 
   2959      0    stevel 		if (dir == NAT_INBOUND) {
   2960      0    stevel 			nat = nat_inlookup(fin, flags, p, oip->ip_dst,
   2961      0    stevel 					   oip->ip_src);
   2962      0    stevel 		} else {
   2963      0    stevel 			nat = nat_outlookup(fin, flags, p, oip->ip_dst,
   2964      0    stevel 					    oip->ip_src);
   2965      0    stevel 		}
   2966      0    stevel 		fin->fin_data[0] = data[0];
   2967      0    stevel 		fin->fin_data[1] = data[1];
   2968      0    stevel 		return nat;
   2969      0    stevel 	}
   2970      0    stevel 	if (dir == NAT_INBOUND)
   2971      0    stevel 		return nat_inlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
   2972      0    stevel 	else
   2973      0    stevel 		return nat_outlookup(fin, 0, p, oip->ip_dst, oip->ip_src);
   2974      0    stevel }
   2975      0    stevel 
   2976      0    stevel 
   2977      0    stevel /* ------------------------------------------------------------------------ */
   2978      0    stevel /* Function:    nat_icmperror                                               */
   2979      0    stevel /* Returns:     nat_t* - point to matching NAT structure                    */
   2980      0    stevel /* Parameters:  fin(I)    - pointer to packet information                   */
   2981      0