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