Home | History | Annotate | Line # | Download | only in netinet
      1  1.8    rillig /*	$NetBSD: ip_proxy.c,v 1.8 2024/09/08 09:36:51 rillig Exp $	*/
      2  1.1  christos 
      3  1.1  christos /*
      4  1.1  christos  * Copyright (C) 2012 by Darren Reed.
      5  1.1  christos  *
      6  1.1  christos  * See the IPFILTER.LICENCE file for details on licencing.
      7  1.1  christos  */
      8  1.1  christos #if defined(KERNEL) || defined(_KERNEL)
      9  1.1  christos # undef KERNEL
     10  1.1  christos # undef _KERNEL
     11  1.1  christos # 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(AIX)
     20  1.1  christos # include <sys/fcntl.h>
     21  1.1  christos #endif
     22  1.1  christos #if !defined(_KERNEL) && !defined(__KERNEL__)
     23  1.1  christos # include <stdio.h>
     24  1.1  christos # include <string.h>
     25  1.1  christos # include <stdlib.h>
     26  1.1  christos # include <ctype.h>
     27  1.1  christos # define _KERNEL
     28  1.1  christos # ifdef __OpenBSD__
     29  1.1  christos struct file;
     30  1.1  christos # endif
     31  1.1  christos # include <sys/uio.h>
     32  1.1  christos # undef _KERNEL
     33  1.1  christos #endif
     34  1.1  christos #if !defined(linux)
     35  1.1  christos # include <sys/protosw.h>
     36  1.1  christos #endif
     37  1.1  christos #include <sys/socket.h>
     38  1.1  christos #if defined(_KERNEL)
     39  1.1  christos # if !defined(__NetBSD__) && !defined(sun) && !defined(__osf__) && \
     40  1.1  christos      !defined(__OpenBSD__) && !defined(__hpux) && !defined(__sgi) && \
     41  1.1  christos      !defined(AIX)
     42  1.1  christos #  include <sys/ctype.h>
     43  1.1  christos # endif
     44  1.1  christos # include <sys/systm.h>
     45  1.1  christos # if !defined(__SVR4) && !defined(__svr4__)
     46  1.1  christos #  include <sys/mbuf.h>
     47  1.1  christos # endif
     48  1.1  christos #endif
     49  1.1  christos #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
     50  1.1  christos # include <sys/filio.h>
     51  1.1  christos # include <sys/fcntl.h>
     52  1.1  christos #else
     53  1.1  christos # include <sys/ioctl.h>
     54  1.1  christos #endif
     55  1.1  christos #if defined(__SVR4) || defined(__svr4__)
     56  1.1  christos # include <sys/byteorder.h>
     57  1.1  christos # ifdef _KERNEL
     58  1.1  christos #  include <sys/dditypes.h>
     59  1.1  christos # endif
     60  1.1  christos # include <sys/stream.h>
     61  1.1  christos # include <sys/kmem.h>
     62  1.1  christos #endif
     63  1.1  christos #if __FreeBSD__ > 2
     64  1.1  christos # include <sys/queue.h>
     65  1.1  christos #endif
     66  1.1  christos #include <net/if.h>
     67  1.1  christos #ifdef sun
     68  1.1  christos # include <net/af.h>
     69  1.1  christos #endif
     70  1.1  christos #include <netinet/in.h>
     71  1.1  christos #include <netinet/in_systm.h>
     72  1.1  christos #include <netinet/ip.h>
     73  1.1  christos #ifndef linux
     74  1.1  christos # include <netinet/ip_var.h>
     75  1.1  christos #endif
     76  1.1  christos #include <netinet/tcp.h>
     77  1.1  christos #include <netinet/udp.h>
     78  1.1  christos #include <netinet/ip_icmp.h>
     79  1.1  christos #include "netinet/ip_compat.h"
     80  1.1  christos #include "netinet/ip_fil.h"
     81  1.1  christos #include "netinet/ip_nat.h"
     82  1.1  christos #include "netinet/ip_state.h"
     83  1.1  christos #include "netinet/ip_proxy.h"
     84  1.1  christos #if (__FreeBSD_version >= 300000)
     85  1.1  christos # include <sys/malloc.h>
     86  1.1  christos #endif
     87  1.1  christos 
     88  1.1  christos /* END OF INCLUDES */
     89  1.1  christos 
     90  1.2  christos #include "netinet/ip_dns_pxy.c"
     91  1.1  christos #include "netinet/ip_ftp_pxy.c"
     92  1.1  christos #include "netinet/ip_tftp_pxy.c"
     93  1.1  christos #include "netinet/ip_rcmd_pxy.c"
     94  1.1  christos #include "netinet/ip_pptp_pxy.c"
     95  1.1  christos #if defined(_KERNEL)
     96  1.1  christos # include "netinet/ip_irc_pxy.c"
     97  1.1  christos # include "netinet/ip_raudio_pxy.c"
     98  1.1  christos # include "netinet/ip_netbios_pxy.c"
     99  1.1  christos #endif
    100  1.1  christos #include "netinet/ip_ipsec_pxy.c"
    101  1.1  christos #include "netinet/ip_rpcb_pxy.c"
    102  1.1  christos 
    103  1.1  christos #if !defined(lint)
    104  1.2  christos #if defined(__NetBSD__)
    105  1.2  christos #include <sys/cdefs.h>
    106  1.8    rillig __KERNEL_RCSID(0, "$NetBSD: ip_proxy.c,v 1.8 2024/09/08 09:36:51 rillig Exp $");
    107  1.2  christos #else
    108  1.3   darrenr static const char rcsid[] = "@(#)Id: ip_proxy.c,v 1.1.1.2 2012/07/22 13:45:33 darrenr Exp";
    109  1.2  christos #endif
    110  1.1  christos #endif
    111  1.1  christos 
    112  1.1  christos #define	AP_SESS_SIZE	53
    113  1.1  christos 
    114  1.2  christos static int ipf_proxy_fixseqack(fr_info_t *, ip_t *, ap_session_t *, int );
    115  1.2  christos static aproxy_t *ipf_proxy_create_clone(ipf_main_softc_t *, aproxy_t *);
    116  1.1  christos 
    117  1.1  christos typedef struct ipf_proxy_softc_s {
    118  1.1  christos 	int		ips_proxy_debug;
    119  1.1  christos 	int		ips_proxy_session_size;
    120  1.1  christos 	ap_session_t	**ips_sess_tab;
    121  1.1  christos 	ap_session_t	*ips_sess_list;
    122  1.1  christos 	aproxy_t	*ips_proxies;
    123  1.1  christos 	int		ips_init_run;
    124  1.1  christos 	ipftuneable_t	*ipf_proxy_tune;
    125  1.1  christos } ipf_proxy_softc_t;
    126  1.1  christos 
    127  1.7      maxv static const ipftuneable_t ipf_proxy_tuneables[] = {
    128  1.1  christos 	{ { (void *)offsetof(ipf_proxy_softc_t, ips_proxy_debug) },
    129  1.3   darrenr 		"proxy_debug",	0,	0x1f,
    130  1.1  christos 		stsizeof(ipf_proxy_softc_t, ips_proxy_debug),
    131  1.1  christos 		0,	NULL,	NULL },
    132  1.1  christos 	{ { NULL },		NULL,			0,	0,
    133  1.1  christos 		0,
    134  1.1  christos 		0,	NULL,	NULL}
    135  1.1  christos };
    136  1.1  christos 
    137  1.1  christos static	aproxy_t	*ap_proxylist = NULL;
    138  1.1  christos static	aproxy_t	ips_proxies[] = {
    139  1.1  christos #ifdef	IPF_FTP_PROXY
    140  1.1  christos 	{ NULL, NULL, "ftp", (char)IPPROTO_TCP, 0, 0, 0,
    141  1.1  christos 	  ipf_p_ftp_main_load, ipf_p_ftp_main_unload,
    142  1.1  christos 	  ipf_p_ftp_soft_create, ipf_p_ftp_soft_destroy,
    143  1.1  christos 	  NULL, NULL,
    144  1.1  christos 	  ipf_p_ftp_new, ipf_p_ftp_del, ipf_p_ftp_in, ipf_p_ftp_out, NULL,
    145  1.1  christos 	  NULL, NULL, NULL, NULL },
    146  1.1  christos #endif
    147  1.1  christos #ifdef	IPF_TFTP_PROXY
    148  1.3   darrenr 	{ NULL, NULL, "tftp", (char)IPPROTO_UDP, 0, 0, 0,
    149  1.1  christos 	  ipf_p_tftp_main_load, ipf_p_tftp_main_unload,
    150  1.3   darrenr 	  ipf_p_tftp_soft_create, ipf_p_tftp_soft_destroy,
    151  1.1  christos 	  NULL, NULL,
    152  1.3   darrenr 	  ipf_p_tftp_new, ipf_p_tftp_del,
    153  1.3   darrenr 	  ipf_p_tftp_in, ipf_p_tftp_out, NULL,
    154  1.1  christos 	  NULL, NULL, NULL, NULL },
    155  1.1  christos #endif
    156  1.1  christos #ifdef	IPF_IRC_PROXY
    157  1.1  christos 	{ NULL, NULL, "irc", (char)IPPROTO_TCP, 0, 0, 0,
    158  1.1  christos 	  ipf_p_irc_main_load, ipf_p_irc_main_unload,
    159  1.1  christos 	  NULL, NULL,
    160  1.1  christos 	  NULL, NULL,
    161  1.1  christos 	  ipf_p_irc_new, NULL, NULL, ipf_p_irc_out, NULL,
    162  1.1  christos 	  NULL, NULL, NULL, NULL },
    163  1.1  christos #endif
    164  1.1  christos #ifdef	IPF_RCMD_PROXY
    165  1.1  christos 	{ NULL, NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, 0,
    166  1.1  christos 	  ipf_p_rcmd_main_load, ipf_p_rcmd_main_unload,
    167  1.1  christos 	  NULL, NULL,
    168  1.1  christos 	  NULL, NULL,
    169  1.1  christos 	  ipf_p_rcmd_new, ipf_p_rcmd_del,
    170  1.1  christos 	  ipf_p_rcmd_in, ipf_p_rcmd_out, NULL,
    171  1.1  christos 	  NULL, NULL, NULL, NULL },
    172  1.1  christos #endif
    173  1.1  christos #ifdef	IPF_RAUDIO_PROXY
    174  1.1  christos 	{ NULL, NULL, "raudio", (char)IPPROTO_TCP, 0, 0, 0,
    175  1.1  christos 	  ipf_p_raudio_main_load, ipf_p_raudio_main_unload,
    176  1.1  christos 	  NULL, NULL,
    177  1.1  christos 	  NULL, NULL,
    178  1.1  christos 	  ipf_p_raudio_new, NULL, ipf_p_raudio_in, ipf_p_raudio_out, NULL,
    179  1.1  christos 	  NULL, NULL, NULL, NULL },
    180  1.1  christos #endif
    181  1.1  christos #ifdef	IPF_MSNRPC_PROXY
    182  1.1  christos 	{ NULL, NULL, "msnrpc", (char)IPPROTO_TCP, 0, 0, 0,
    183  1.1  christos 	  ipf_p_msnrpc_init, ipf_p_msnrpc_fini,
    184  1.1  christos 	  NULL, NULL,
    185  1.1  christos 	  NULL, NULL,
    186  1.1  christos 	  ipf_p_msnrpc_new, NULL, ipf_p_msnrpc_in, ipf_p_msnrpc_out, NULL,
    187  1.1  christos 	  NULL, NULL, NULL, NULL },
    188  1.1  christos #endif
    189  1.1  christos #ifdef	IPF_NETBIOS_PROXY
    190  1.1  christos 	{ NULL, NULL, "netbios", (char)IPPROTO_UDP, 0, 0, 0,
    191  1.1  christos 	  ipf_p_netbios_main_load, ipf_p_netbios_main_unload,
    192  1.1  christos 	  NULL, NULL,
    193  1.1  christos 	  NULL, NULL,
    194  1.1  christos 	  NULL, NULL, NULL, ipf_p_netbios_out, NULL,
    195  1.1  christos 	  NULL, NULL, NULL, NULL },
    196  1.1  christos #endif
    197  1.1  christos #ifdef	IPF_IPSEC_PROXY
    198  1.1  christos 	{ NULL, NULL, "ipsec", (char)IPPROTO_UDP, 0, 0, 0,
    199  1.1  christos 	  NULL, NULL,
    200  1.1  christos 	  ipf_p_ipsec_soft_create, ipf_p_ipsec_soft_destroy,
    201  1.1  christos 	  ipf_p_ipsec_soft_init, ipf_p_ipsec_soft_fini,
    202  1.1  christos 	  ipf_p_ipsec_new, ipf_p_ipsec_del,
    203  1.1  christos 	  ipf_p_ipsec_inout, ipf_p_ipsec_inout, ipf_p_ipsec_match,
    204  1.1  christos 	  NULL, NULL, NULL, NULL },
    205  1.1  christos #endif
    206  1.1  christos #ifdef	IPF_DNS_PROXY
    207  1.1  christos 	{ NULL, NULL, "dns", (char)IPPROTO_UDP, 0, 0, 0,
    208  1.1  christos 	  NULL, NULL,
    209  1.1  christos 	  ipf_p_dns_soft_create, ipf_p_dns_soft_destroy,
    210  1.1  christos 	  NULL, NULL,
    211  1.1  christos 	  ipf_p_dns_new, ipf_p_ipsec_del,
    212  1.1  christos 	  ipf_p_dns_inout, ipf_p_dns_inout, ipf_p_dns_match,
    213  1.1  christos 	  ipf_p_dns_ctl, NULL, NULL, NULL },
    214  1.1  christos #endif
    215  1.1  christos #ifdef	IPF_PPTP_PROXY
    216  1.1  christos 	{ NULL, NULL, "pptp", (char)IPPROTO_TCP, 0, 0, 0,
    217  1.1  christos 	  ipf_p_pptp_main_load, ipf_p_pptp_main_unload,
    218  1.1  christos 	  NULL, NULL,
    219  1.1  christos 	  NULL, NULL,
    220  1.1  christos 	  ipf_p_pptp_new, ipf_p_pptp_del,
    221  1.1  christos 	  ipf_p_pptp_inout, ipf_p_pptp_inout, NULL,
    222  1.1  christos 	  NULL, NULL, NULL, NULL },
    223  1.1  christos #endif
    224  1.2  christos #ifdef  IPF_H323_PROXY
    225  1.2  christos 	{ NULL, NULL, "h323", (char)IPPROTO_TCP, 0, 0, 0,
    226  1.2  christos 	  ipf_p_h323_main_load, ipf_p_h323_main_unload,
    227  1.2  christos 	  NULL, NULL,
    228  1.2  christos 	  NULL, NULL,
    229  1.2  christos 	  ipf_p_h323_new, ipf_p_h323_del,
    230  1.2  christos 	  ipf_p_h323_in, NULL, NULL,
    231  1.2  christos 	  NULL, NULL, NULL, NULL },
    232  1.2  christos 	{ NULL, NULL, "h245", (char)IPPROTO_TCP, 0, 0, 0, NULL, NULL,
    233  1.2  christos 	  NULL, NULL,
    234  1.2  christos 	  NULL, NULL,
    235  1.2  christos 	  ipf_p_h245_new, NULL,
    236  1.2  christos 	  NULL, ipf_p_h245_out, NULL,
    237  1.2  christos 	  NULL, NULL, NULL, NULL },
    238  1.2  christos #endif
    239  1.1  christos #ifdef	IPF_RPCB_PROXY
    240  1.1  christos # ifndef _KERNEL
    241  1.1  christos 	{ NULL, NULL, "rpcbt", (char)IPPROTO_TCP, 0, 0, 0,
    242  1.1  christos 	  NULL, NULL,
    243  1.1  christos 	  NULL, NULL,
    244  1.1  christos 	  NULL, NULL,
    245  1.1  christos 	  ipf_p_rpcb_new, ipf_p_rpcb_del,
    246  1.1  christos 	  ipf_p_rpcb_in, ipf_p_rpcb_out, NULL,
    247  1.1  christos 	  NULL, NULL, NULL, NULL },
    248  1.1  christos # endif
    249  1.1  christos 	{ NULL, NULL, "rpcbu", (char)IPPROTO_UDP, 0, 0, 0,
    250  1.1  christos 	  ipf_p_rpcb_main_load, ipf_p_rpcb_main_unload,
    251  1.1  christos 	  NULL, NULL,
    252  1.1  christos 	  NULL, NULL,
    253  1.1  christos 	  ipf_p_rpcb_new, ipf_p_rpcb_del,
    254  1.1  christos 	  ipf_p_rpcb_in, ipf_p_rpcb_out, NULL,
    255  1.1  christos 	  NULL, NULL, NULL, NULL },
    256  1.1  christos #endif
    257  1.1  christos 	{ NULL, NULL, "", '\0', 0, 0, 0,
    258  1.1  christos 	  NULL, NULL,
    259  1.1  christos 	  NULL, NULL,
    260  1.1  christos 	  NULL, NULL,
    261  1.1  christos 	  NULL, NULL,
    262  1.1  christos 	  NULL, NULL, NULL,
    263  1.1  christos 	  NULL, NULL, NULL, NULL }
    264  1.1  christos };
    265  1.1  christos 
    266  1.1  christos 
    267  1.1  christos /* ------------------------------------------------------------------------ */
    268  1.3   darrenr /* Function:    ipf_proxy_main_load                                         */
    269  1.3   darrenr /* Returns:     int    - 0 == success, else failure.                        */
    270  1.3   darrenr /* Parameters:  Nil                                                         */
    271  1.1  christos /*                                                                          */
    272  1.1  christos /* Initialise hook for kernel application proxies.                          */
    273  1.1  christos /* Call the initialise routine for all the compiled in kernel proxies.      */
    274  1.1  christos /* ------------------------------------------------------------------------ */
    275  1.1  christos int
    276  1.2  christos ipf_proxy_main_load(void)
    277  1.1  christos {
    278  1.1  christos 	aproxy_t *ap;
    279  1.1  christos 
    280  1.1  christos 	for (ap = ips_proxies; ap->apr_p; ap++) {
    281  1.1  christos 		if (ap->apr_load != NULL)
    282  1.1  christos 			(*ap->apr_load)();
    283  1.1  christos 	}
    284  1.1  christos 	return 0;
    285  1.1  christos }
    286  1.1  christos 
    287  1.1  christos 
    288  1.1  christos /* ------------------------------------------------------------------------ */
    289  1.3   darrenr /* Function:    ipf_proxy_main_unload                                       */
    290  1.3   darrenr /* Returns:     int - 0 == success, else failure.                           */
    291  1.1  christos /* Parameters:  Nil                                                         */
    292  1.1  christos /*                                                                          */
    293  1.1  christos /* Unload hook for kernel application proxies.                              */
    294  1.1  christos /* Call the finialise routine for all the compiled in kernel proxies.       */
    295  1.1  christos /* ------------------------------------------------------------------------ */
    296  1.1  christos int
    297  1.2  christos ipf_proxy_main_unload(void)
    298  1.1  christos {
    299  1.1  christos 	aproxy_t *ap;
    300  1.1  christos 
    301  1.1  christos 	for (ap = ips_proxies; ap->apr_p; ap++)
    302  1.1  christos 		if (ap->apr_unload != NULL)
    303  1.1  christos 			(*ap->apr_unload)();
    304  1.1  christos 	for (ap = ap_proxylist; ap; ap = ap->apr_next)
    305  1.1  christos 		if (ap->apr_unload != NULL)
    306  1.1  christos 			(*ap->apr_unload)();
    307  1.1  christos 
    308  1.1  christos 	return 0;
    309  1.1  christos }
    310  1.1  christos 
    311  1.1  christos 
    312  1.3   darrenr /* ------------------------------------------------------------------------ */
    313  1.3   darrenr /* Function:    ipf_proxy_soft_create                                       */
    314  1.3   darrenr /* Returns:     void *   -                                                  */
    315  1.3   darrenr /* Parameters:  softc(I) - pointer to soft context main structure           */
    316  1.3   darrenr /*                                                                          */
    317  1.3   darrenr /* Build the structure to hold all of the run time data to support proxies. */
    318  1.3   darrenr /* ------------------------------------------------------------------------ */
    319  1.1  christos void *
    320  1.2  christos ipf_proxy_soft_create(ipf_main_softc_t *softc)
    321  1.1  christos {
    322  1.1  christos 	ipf_proxy_softc_t *softp;
    323  1.1  christos 	aproxy_t *last;
    324  1.1  christos 	aproxy_t *apn;
    325  1.1  christos 	aproxy_t *ap;
    326  1.1  christos 
    327  1.1  christos 	KMALLOC(softp, ipf_proxy_softc_t *);
    328  1.1  christos 	if (softp == NULL)
    329  1.1  christos 		return softp;
    330  1.1  christos 
    331  1.1  christos 	bzero((char *)softp, sizeof(*softp));
    332  1.1  christos 
    333  1.1  christos #if defined(_KERNEL)
    334  1.1  christos 	softp->ips_proxy_debug = 0;
    335  1.1  christos #else
    336  1.1  christos 	softp->ips_proxy_debug = 2;
    337  1.1  christos #endif
    338  1.1  christos 	softp->ips_proxy_session_size = AP_SESS_SIZE;
    339  1.1  christos 
    340  1.1  christos 	softp->ipf_proxy_tune = ipf_tune_array_copy(softp,
    341  1.1  christos 						    sizeof(ipf_proxy_tuneables),
    342  1.1  christos 						    ipf_proxy_tuneables);
    343  1.1  christos 	if (softp->ipf_proxy_tune == NULL) {
    344  1.1  christos 		ipf_proxy_soft_destroy(softc, softp);
    345  1.1  christos 		return NULL;
    346  1.1  christos 	}
    347  1.1  christos 	if (ipf_tune_array_link(softc, softp->ipf_proxy_tune) == -1) {
    348  1.1  christos 		ipf_proxy_soft_destroy(softc, softp);
    349  1.1  christos 		return NULL;
    350  1.1  christos 	}
    351  1.1  christos 
    352  1.1  christos 	last = NULL;
    353  1.1  christos 	for (ap = ips_proxies; ap->apr_p; ap++) {
    354  1.1  christos 		apn = ipf_proxy_create_clone(softc, ap);
    355  1.1  christos 		if (apn == NULL)
    356  1.1  christos 			goto failed;
    357  1.1  christos 		if (last != NULL)
    358  1.1  christos 			last->apr_next = apn;
    359  1.1  christos 		else
    360  1.1  christos 			softp->ips_proxies = apn;
    361  1.1  christos 		last = apn;
    362  1.1  christos 	}
    363  1.1  christos 	for (ap = ips_proxies; ap != NULL; ap = ap->apr_next) {
    364  1.1  christos 		apn = ipf_proxy_create_clone(softc, ap);
    365  1.1  christos 		if (apn == NULL)
    366  1.1  christos 			goto failed;
    367  1.1  christos 		if (last != NULL)
    368  1.1  christos 			last->apr_next = apn;
    369  1.1  christos 		else
    370  1.1  christos 			softp->ips_proxies = apn;
    371  1.1  christos 		last = apn;
    372  1.1  christos 	}
    373  1.1  christos 
    374  1.1  christos 	return softp;
    375  1.1  christos failed:
    376  1.1  christos 	ipf_proxy_soft_destroy(softc, softp);
    377  1.1  christos 	return NULL;
    378  1.1  christos }
    379  1.1  christos 
    380  1.1  christos 
    381  1.3   darrenr /* ------------------------------------------------------------------------ */
    382  1.3   darrenr /* Function:    ipf_proxy_soft_create                                       */
    383  1.3   darrenr /* Returns:     void *   -                                                  */
    384  1.3   darrenr /* Parameters:  softc(I) - pointer to soft context main structure           */
    385  1.3   darrenr /*              orig(I)  - pointer to proxy definition to copy              */
    386  1.3   darrenr /*                                                                          */
    387  1.3   darrenr /* This function clones a proxy definition given by orig and returns a      */
    388  1.3   darrenr /* a pointer to that copy.                                                  */
    389  1.3   darrenr /* ------------------------------------------------------------------------ */
    390  1.1  christos static aproxy_t *
    391  1.2  christos ipf_proxy_create_clone(ipf_main_softc_t *softc, aproxy_t *orig)
    392  1.1  christos {
    393  1.1  christos 	aproxy_t *apn;
    394  1.1  christos 
    395  1.1  christos 	KMALLOC(apn, aproxy_t *);
    396  1.1  christos 	if (apn == NULL)
    397  1.1  christos 		return NULL;
    398  1.1  christos 
    399  1.1  christos 	bcopy((char *)orig, (char *)apn, sizeof(*apn));
    400  1.1  christos 	apn->apr_next = NULL;
    401  1.1  christos 	apn->apr_soft = NULL;
    402  1.1  christos 
    403  1.1  christos 	if (apn->apr_create != NULL) {
    404  1.1  christos 		apn->apr_soft = (*apn->apr_create)(softc);
    405  1.1  christos 		if (apn->apr_soft == NULL) {
    406  1.1  christos 			KFREE(apn);
    407  1.1  christos 			return NULL;
    408  1.1  christos 		}
    409  1.1  christos 	}
    410  1.1  christos 
    411  1.1  christos 	apn->apr_parent = orig;
    412  1.1  christos 	orig->apr_clones++;
    413  1.1  christos 
    414  1.1  christos 	return apn;
    415  1.1  christos }
    416  1.1  christos 
    417  1.1  christos 
    418  1.3   darrenr /* ------------------------------------------------------------------------ */
    419  1.3   darrenr /* Function:    ipf_proxy_soft_create                                       */
    420  1.3   darrenr /* Returns:     int      - 0 == success, else failure.                      */
    421  1.3   darrenr /* Parameters:  softc(I) - pointer to soft context main structure           */
    422  1.3   darrenr /*              arg(I)   - pointer to proxy contect data                    */
    423  1.3   darrenr /*                                                                          */
    424  1.3   darrenr /* Initialise the proxy context and walk through each of the proxies and    */
    425  1.3   darrenr /* call its initialisation function. This allows for proxies to do any      */
    426  1.3   darrenr /* local setup prior to actual use.                                         */
    427  1.3   darrenr /* ------------------------------------------------------------------------ */
    428  1.1  christos int
    429  1.2  christos ipf_proxy_soft_init(ipf_main_softc_t *softc, void *arg)
    430  1.1  christos {
    431  1.1  christos 	ipf_proxy_softc_t *softp;
    432  1.1  christos 	aproxy_t *ap;
    433  1.1  christos 	u_int size;
    434  1.1  christos 	int err;
    435  1.1  christos 
    436  1.1  christos 	softp = arg;
    437  1.1  christos 	size = softp->ips_proxy_session_size * sizeof(ap_session_t *);
    438  1.1  christos 
    439  1.1  christos 	KMALLOCS(softp->ips_sess_tab, ap_session_t **, size);
    440  1.1  christos 
    441  1.1  christos 	if (softp->ips_sess_tab == NULL)
    442  1.1  christos 		return -1;
    443  1.1  christos 
    444  1.1  christos 	bzero(softp->ips_sess_tab, size);
    445  1.1  christos 
    446  1.1  christos 	for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next) {
    447  1.1  christos 		if (ap->apr_init != NULL) {
    448  1.1  christos 			err = (*ap->apr_init)(softc, ap->apr_soft);
    449  1.1  christos 			if (err != 0)
    450  1.1  christos 				return -2;
    451  1.1  christos 		}
    452  1.1  christos 	}
    453  1.1  christos 	softp->ips_init_run = 1;
    454  1.1  christos 
    455  1.1  christos 	return 0;
    456  1.1  christos }
    457  1.1  christos 
    458  1.1  christos 
    459  1.3   darrenr /* ------------------------------------------------------------------------ */
    460  1.3   darrenr /* Function:    ipf_proxy_soft_create                                       */
    461  1.3   darrenr /* Returns:     int      - 0 == success, else failure.                      */
    462  1.3   darrenr /* Parameters:  softc(I) - pointer to soft context main structure           */
    463  1.3   darrenr /*              arg(I)   - pointer to proxy contect data                    */
    464  1.3   darrenr /*                                                                          */
    465  1.3   darrenr /* This function should always succeed. It is responsible for ensuring that */
    466  1.3   darrenr /* the proxy context can be safely called when ipf_proxy_soft_destroy is    */
    467  1.3   darrenr /* called and suring all of the proxies have similarly been instructed.     */
    468  1.3   darrenr /* ------------------------------------------------------------------------ */
    469  1.1  christos int
    470  1.2  christos ipf_proxy_soft_fini(ipf_main_softc_t *softc, void *arg)
    471  1.1  christos {
    472  1.1  christos 	ipf_proxy_softc_t *softp = arg;
    473  1.1  christos 	aproxy_t *ap;
    474  1.1  christos 
    475  1.1  christos 	for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next) {
    476  1.1  christos 		if (ap->apr_fini != NULL) {
    477  1.1  christos 			(*ap->apr_fini)(softc, ap->apr_soft);
    478  1.1  christos 		}
    479  1.1  christos 	}
    480  1.1  christos 
    481  1.1  christos 	if (softp->ips_sess_tab != NULL) {
    482  1.1  christos 		KFREES(softp->ips_sess_tab,
    483  1.1  christos 		       softp->ips_proxy_session_size * sizeof(ap_session_t *));
    484  1.1  christos 		softp->ips_sess_tab = NULL;
    485  1.1  christos 	}
    486  1.1  christos 	softp->ips_init_run = 0;
    487  1.1  christos 
    488  1.1  christos 	return 0;
    489  1.1  christos }
    490  1.1  christos 
    491  1.1  christos 
    492  1.3   darrenr /* ------------------------------------------------------------------------ */
    493  1.3   darrenr /* Function:    ipf_proxy_soft_destroy                                      */
    494  1.3   darrenr /* Returns:     Nil                                                         */
    495  1.3   darrenr /* Parameters:  softc(I) - pointer to soft context main structure           */
    496  1.3   darrenr /*              arg(I)   - pointer to proxy contect data                    */
    497  1.3   darrenr /*                                                                          */
    498  1.3   darrenr /* Free up all of the local data structures allocated during creation.      */
    499  1.3   darrenr /* ------------------------------------------------------------------------ */
    500  1.1  christos void
    501  1.2  christos ipf_proxy_soft_destroy(ipf_main_softc_t *softc, void *arg)
    502  1.1  christos {
    503  1.1  christos 	ipf_proxy_softc_t *softp = arg;
    504  1.1  christos 	aproxy_t *ap;
    505  1.1  christos 
    506  1.1  christos 	while ((ap = softp->ips_proxies) != NULL) {
    507  1.1  christos 		softp->ips_proxies = ap->apr_next;
    508  1.1  christos 		if (ap->apr_destroy != NULL)
    509  1.1  christos 			(*ap->apr_destroy)(softc, ap->apr_soft);
    510  1.1  christos 		ap->apr_parent->apr_clones--;
    511  1.1  christos 		KFREE(ap);
    512  1.1  christos 	}
    513  1.1  christos 
    514  1.1  christos 	if (softp->ipf_proxy_tune != NULL) {
    515  1.1  christos                 ipf_tune_array_unlink(softc, softp->ipf_proxy_tune);
    516  1.1  christos                 KFREES(softp->ipf_proxy_tune, sizeof(ipf_proxy_tuneables));
    517  1.1  christos                 softp->ipf_proxy_tune = NULL;
    518  1.1  christos 	}
    519  1.1  christos 
    520  1.1  christos 	KFREE(softp);
    521  1.1  christos }
    522  1.1  christos 
    523  1.1  christos 
    524  1.1  christos /* ------------------------------------------------------------------------ */
    525  1.1  christos /* Function:    ipf_proxy_flush                                             */
    526  1.1  christos /* Returns:     Nil                                                         */
    527  1.3   darrenr /* Parameters:  arg(I)   - pointer to proxy contect data                    */
    528  1.3   darrenr /*              how(I)   - indicates the type of flush operation            */
    529  1.1  christos /*                                                                          */
    530  1.3   darrenr /* Walk through all of the proxies and pass on the flush command as either  */
    531  1.3   darrenr /* a flush or a clear.                                                      */
    532  1.1  christos /* ------------------------------------------------------------------------ */
    533  1.1  christos void
    534  1.2  christos ipf_proxy_flush(void *arg, int how)
    535  1.1  christos {
    536  1.1  christos 	ipf_proxy_softc_t *softp = arg;
    537  1.1  christos 	aproxy_t *ap;
    538  1.1  christos 
    539  1.1  christos 	switch (how)
    540  1.1  christos 	{
    541  1.1  christos 	case 0 :
    542  1.1  christos 		for (ap = softp->ips_proxies; ap; ap = ap->apr_next)
    543  1.1  christos 			if (ap->apr_flush != NULL)
    544  1.1  christos 				(*ap->apr_flush)(ap, how);
    545  1.1  christos 		break;
    546  1.1  christos 	case 1 :
    547  1.1  christos 		for (ap = softp->ips_proxies; ap; ap = ap->apr_next)
    548  1.1  christos 			if (ap->apr_clear != NULL)
    549  1.1  christos 				(*ap->apr_clear)(ap);
    550  1.1  christos 		break;
    551  1.1  christos 	default :
    552  1.1  christos 		break;
    553  1.1  christos 	}
    554  1.1  christos }
    555  1.1  christos 
    556  1.1  christos 
    557  1.1  christos /* ------------------------------------------------------------------------ */
    558  1.1  christos /* Function:    ipf_proxy_add                                               */
    559  1.3   darrenr /* Returns:     int   - 0 == success, else failure.                         */
    560  1.1  christos /* Parameters:  ap(I) - pointer to proxy structure                          */
    561  1.1  christos /*                                                                          */
    562  1.1  christos /* Dynamically add a new kernel proxy.  Ensure that it is unique in the     */
    563  1.1  christos /* collection compiled in and dynamically added.                            */
    564  1.1  christos /* ------------------------------------------------------------------------ */
    565  1.1  christos int
    566  1.2  christos ipf_proxy_add(void *arg, aproxy_t *ap)
    567  1.1  christos {
    568  1.1  christos 	ipf_proxy_softc_t *softp = arg;
    569  1.1  christos 
    570  1.1  christos 	aproxy_t *a;
    571  1.1  christos 
    572  1.1  christos 	for (a = ips_proxies; a->apr_p; a++)
    573  1.1  christos 		if ((a->apr_p == ap->apr_p) &&
    574  1.1  christos 		    !strncmp(a->apr_label, ap->apr_label,
    575  1.1  christos 			     sizeof(ap->apr_label))) {
    576  1.3   darrenr 			if (softp->ips_proxy_debug & 0x01)
    577  1.1  christos 				printf("ipf_proxy_add: %s/%d present (B)\n",
    578  1.1  christos 				       a->apr_label, a->apr_p);
    579  1.1  christos 			return -1;
    580  1.1  christos 		}
    581  1.1  christos 
    582  1.1  christos 	for (a = ap_proxylist; (a != NULL); a = a->apr_next)
    583  1.1  christos 		if ((a->apr_p == ap->apr_p) &&
    584  1.1  christos 		    !strncmp(a->apr_label, ap->apr_label,
    585  1.1  christos 			     sizeof(ap->apr_label))) {
    586  1.3   darrenr 			if (softp->ips_proxy_debug & 0x01)
    587  1.1  christos 				printf("ipf_proxy_add: %s/%d present (D)\n",
    588  1.1  christos 				       a->apr_label, a->apr_p);
    589  1.1  christos 			return -1;
    590  1.1  christos 		}
    591  1.1  christos 	ap->apr_next = ap_proxylist;
    592  1.1  christos 	ap_proxylist = ap;
    593  1.1  christos 	if (ap->apr_load != NULL)
    594  1.1  christos 		(*ap->apr_load)();
    595  1.1  christos 	return 0;
    596  1.1  christos }
    597  1.1  christos 
    598  1.1  christos 
    599  1.1  christos /* ------------------------------------------------------------------------ */
    600  1.1  christos /* Function:    ipf_proxy_ctl                                               */
    601  1.3   darrenr /* Returns:     int    - 0 == success, else error                           */
    602  1.3   darrenr /* Parameters:  softc(I) - pointer to soft context main structure           */
    603  1.3   darrenr /*              arg(I)   - pointer to proxy context                         */
    604  1.3   darrenr /*              ctl(I)   - pointer to proxy control structure               */
    605  1.1  christos /*                                                                          */
    606  1.1  christos /* Check to see if the proxy this control request has come through for      */
    607  1.1  christos /* exists, and if it does and it has a control function then invoke that    */
    608  1.1  christos /* control function.                                                        */
    609  1.1  christos /* ------------------------------------------------------------------------ */
    610  1.1  christos int
    611  1.2  christos ipf_proxy_ctl(ipf_main_softc_t *softc, void *arg, ap_ctl_t *ctl)
    612  1.1  christos {
    613  1.1  christos 	ipf_proxy_softc_t *softp = arg;
    614  1.1  christos 	aproxy_t *a;
    615  1.1  christos 	int error;
    616  1.1  christos 
    617  1.1  christos 	a = ipf_proxy_lookup(arg, ctl->apc_p, ctl->apc_label);
    618  1.1  christos 	if (a == NULL) {
    619  1.3   darrenr 		if (softp->ips_proxy_debug & 0x01)
    620  1.1  christos 			printf("ipf_proxy_ctl: can't find %s/%d\n",
    621  1.1  christos 				ctl->apc_label, ctl->apc_p);
    622  1.1  christos 		IPFERROR(80001);
    623  1.1  christos 		error = ESRCH;
    624  1.1  christos 	} else if (a->apr_ctl == NULL) {
    625  1.3   darrenr 		if (softp->ips_proxy_debug & 0x01)
    626  1.1  christos 			printf("ipf_proxy_ctl: no ctl function for %s/%d\n",
    627  1.1  christos 				ctl->apc_label, ctl->apc_p);
    628  1.1  christos 		IPFERROR(80002);
    629  1.1  christos 		error = ENXIO;
    630  1.1  christos 	} else {
    631  1.1  christos 		error = (*a->apr_ctl)(softc, a->apr_soft, ctl);
    632  1.3   darrenr 		if ((error != 0) && (softp->ips_proxy_debug & 0x02))
    633  1.1  christos 			printf("ipf_proxy_ctl: %s/%d ctl error %d\n",
    634  1.1  christos 				a->apr_label, a->apr_p, error);
    635  1.1  christos 	}
    636  1.1  christos 	return error;
    637  1.1  christos }
    638  1.1  christos 
    639  1.1  christos 
    640  1.1  christos /* ------------------------------------------------------------------------ */
    641  1.1  christos /* Function:    ipf_proxy_del                                               */
    642  1.3   darrenr /* Returns:     int   - 0 == success, else failure.                         */
    643  1.1  christos /* Parameters:  ap(I) - pointer to proxy structure                          */
    644  1.1  christos /*                                                                          */
    645  1.1  christos /* Delete a proxy that has been added dynamically from those available.     */
    646  1.1  christos /* If it is in use, return 1 (do not destroy NOW), not in use 0 or -1       */
    647  1.1  christos /* if it cannot be matched.                                                 */
    648  1.1  christos /* ------------------------------------------------------------------------ */
    649  1.1  christos int
    650  1.2  christos ipf_proxy_del(aproxy_t *ap)
    651  1.1  christos {
    652  1.1  christos 	aproxy_t *a, **app;
    653  1.1  christos 
    654  1.1  christos 	for (app = &ap_proxylist; ((a = *app) != NULL); app = &a->apr_next) {
    655  1.1  christos 		if (a == ap) {
    656  1.1  christos 			a->apr_flags |= APR_DELETE;
    657  1.1  christos 			if (ap->apr_ref == 0 && ap->apr_clones == 0) {
    658  1.1  christos 				*app = a->apr_next;
    659  1.1  christos 				return 0;
    660  1.1  christos 			}
    661  1.1  christos 			return 1;
    662  1.1  christos 		}
    663  1.1  christos 	}
    664  1.1  christos 
    665  1.1  christos 	return -1;
    666  1.1  christos }
    667  1.1  christos 
    668  1.1  christos 
    669  1.1  christos /* ------------------------------------------------------------------------ */
    670  1.1  christos /* Function:    ipf_proxy_ok                                                */
    671  1.3   darrenr /* Returns:     int    - 1 == good match else not.                          */
    672  1.1  christos /* Parameters:  fin(I) - pointer to packet information                      */
    673  1.3   darrenr /*              tcp(I) - pointer to TCP/UDP header                          */
    674  1.1  christos /*              nat(I) - pointer to current NAT session                     */
    675  1.1  christos /*                                                                          */
    676  1.3   darrenr /* This function extends the NAT matching to ensure that a packet that has  */
    677  1.3   darrenr /* arrived matches the proxy information attached to the NAT rule. Notably, */
    678  1.3   darrenr /* if the proxy is scheduled to be deleted then packets will not match the  */
    679  1.3   darrenr /* rule even if the rule is still active.                                   */
    680  1.1  christos /* ------------------------------------------------------------------------ */
    681  1.1  christos int
    682  1.3   darrenr ipf_proxy_ok(fr_info_t *fin, tcphdr_t *tcp, ipnat_t *np)
    683  1.1  christos {
    684  1.3   darrenr 	aproxy_t *apr = np->in_apr;
    685  1.3   darrenr 	u_short dport = np->in_odport;
    686  1.1  christos 
    687  1.1  christos 	if ((apr == NULL) || (apr->apr_flags & APR_DELETE) ||
    688  1.1  christos 	    (fin->fin_p != apr->apr_p))
    689  1.1  christos 		return 0;
    690  1.1  christos 	if ((tcp == NULL) && dport)
    691  1.1  christos 		return 0;
    692  1.1  christos 	return 1;
    693  1.1  christos }
    694  1.1  christos 
    695  1.1  christos 
    696  1.1  christos /* ------------------------------------------------------------------------ */
    697  1.1  christos /* Function:    ipf_proxy_ioctl                                             */
    698  1.3   darrenr /* Returns:     int    - 0 == success, else error                           */
    699  1.3   darrenr /* Parameters:  softc(I) - pointer to soft context main structure           */
    700  1.3   darrenr /*              data(I)  - pointer to ioctl data                            */
    701  1.3   darrenr /*              cmd(I)   - ioctl command                                    */
    702  1.3   darrenr /*              mode(I)  - mode bits for device                             */
    703  1.3   darrenr /*              ctx(I)   - pointer to context information                   */
    704  1.1  christos /*                                                                          */
    705  1.1  christos /* ------------------------------------------------------------------------ */
    706  1.1  christos int
    707  1.2  christos ipf_proxy_ioctl(ipf_main_softc_t *softc, void *data, ioctlcmd_t cmd, int mode,
    708  1.2  christos     void *ctx)
    709  1.1  christos {
    710  1.1  christos 	ap_ctl_t ctl;
    711  1.2  christos 	void *ptr;
    712  1.1  christos 	int error;
    713  1.1  christos 
    714  1.1  christos 	mode = mode;	/* LINT */
    715  1.1  christos 
    716  1.1  christos 	switch (cmd)
    717  1.1  christos 	{
    718  1.1  christos 	case SIOCPROXY :
    719  1.1  christos 		error = ipf_inobj(softc, data, NULL, &ctl, IPFOBJ_PROXYCTL);
    720  1.1  christos 		if (error != 0) {
    721  1.1  christos 			return error;
    722  1.1  christos 		}
    723  1.1  christos 		ptr = NULL;
    724  1.1  christos 
    725  1.1  christos 		if (ctl.apc_dsize > 0) {
    726  1.2  christos 			KMALLOCS(ptr, void *, ctl.apc_dsize);
    727  1.1  christos 			if (ptr == NULL) {
    728  1.1  christos 				IPFERROR(80003);
    729  1.1  christos 				error = ENOMEM;
    730  1.1  christos 			} else {
    731  1.1  christos 				error = copyinptr(softc, ctl.apc_data, ptr,
    732  1.1  christos 						  ctl.apc_dsize);
    733  1.1  christos 				if (error == 0)
    734  1.1  christos 					ctl.apc_data = ptr;
    735  1.1  christos 			}
    736  1.1  christos 		} else {
    737  1.1  christos 			ctl.apc_data = NULL;
    738  1.1  christos 			error = 0;
    739  1.1  christos 		}
    740  1.1  christos 
    741  1.1  christos 		if (error == 0)
    742  1.3   darrenr 			error = ipf_proxy_ctl(softc, softc->ipf_proxy_soft,
    743  1.3   darrenr 					      &ctl);
    744  1.1  christos 
    745  1.1  christos 		if ((error != 0) && (ptr != NULL)) {
    746  1.1  christos 			KFREES(ptr, ctl.apc_dsize);
    747  1.1  christos 		}
    748  1.1  christos 		break;
    749  1.1  christos 
    750  1.1  christos 	default :
    751  1.1  christos 		IPFERROR(80004);
    752  1.1  christos 		error = EINVAL;
    753  1.1  christos 	}
    754  1.1  christos 	return error;
    755  1.1  christos }
    756  1.1  christos 
    757  1.1  christos 
    758  1.1  christos /* ------------------------------------------------------------------------ */
    759  1.1  christos /* Function:    ipf_proxy_match                                             */
    760  1.3   darrenr /* Returns:     int    - 0 == success, else error                           */
    761  1.1  christos /* Parameters:  fin(I) - pointer to packet information                      */
    762  1.1  christos /*              nat(I) - pointer to current NAT session                     */
    763  1.1  christos /*                                                                          */
    764  1.1  christos /* If a proxy has a match function, call that to do extended packet         */
    765  1.3   darrenr /* matching. Whilst other parts of the NAT code are rather lenient when it  */
    766  1.3   darrenr /* comes to the quality of the packet that it will transform, the proxy     */
    767  1.3   darrenr /* matching is not because they need to work with data, not just headers.   */
    768  1.1  christos /* ------------------------------------------------------------------------ */
    769  1.1  christos int
    770  1.2  christos ipf_proxy_match(fr_info_t *fin, nat_t *nat)
    771  1.1  christos {
    772  1.1  christos 	ipf_main_softc_t *softc = fin->fin_main_soft;
    773  1.1  christos 	ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
    774  1.1  christos 	aproxy_t *apr;
    775  1.1  christos 	ipnat_t *ipn;
    776  1.1  christos 	int result;
    777  1.1  christos 
    778  1.1  christos 	ipn = nat->nat_ptr;
    779  1.3   darrenr 	if (softp->ips_proxy_debug & 0x04)
    780  1.1  christos 		printf("ipf_proxy_match(%lx,%lx) aps %lx ptr %lx\n",
    781  1.1  christos 			(u_long)fin, (u_long)nat, (u_long)nat->nat_aps,
    782  1.1  christos 			(u_long)ipn);
    783  1.1  christos 
    784  1.1  christos 	if ((fin->fin_flx & (FI_SHORT|FI_BAD)) != 0) {
    785  1.3   darrenr 		if (softp->ips_proxy_debug & 0x08)
    786  1.1  christos 			printf("ipf_proxy_match: flx 0x%x (BAD|SHORT)\n",
    787  1.1  christos 				fin->fin_flx);
    788  1.1  christos 		return -1;
    789  1.1  christos 	}
    790  1.1  christos 
    791  1.1  christos 	apr = ipn->in_apr;
    792  1.1  christos 	if ((apr == NULL) || (apr->apr_flags & APR_DELETE)) {
    793  1.3   darrenr 		if (softp->ips_proxy_debug & 0x08)
    794  1.1  christos 			printf("ipf_proxy_match:apr %lx apr_flags 0x%x\n",
    795  1.1  christos 				(u_long)apr, apr ? apr->apr_flags : 0);
    796  1.1  christos 		return -1;
    797  1.1  christos 	}
    798  1.1  christos 
    799  1.1  christos 	if (apr->apr_match != NULL) {
    800  1.1  christos 		result = (*apr->apr_match)(fin, nat->nat_aps, nat);
    801  1.1  christos 		if (result != 0) {
    802  1.3   darrenr 			if (softp->ips_proxy_debug & 0x08)
    803  1.1  christos 				printf("ipf_proxy_match: result %d\n", result);
    804  1.1  christos 			return -1;
    805  1.1  christos 		}
    806  1.1  christos 	}
    807  1.1  christos 	return 0;
    808  1.1  christos }
    809  1.1  christos 
    810  1.1  christos 
    811  1.1  christos /* ------------------------------------------------------------------------ */
    812  1.1  christos /* Function:    ipf_proxy_new                                               */
    813  1.3   darrenr /* Returns:     int    - 0 == success, else error                           */
    814  1.1  christos /* Parameters:  fin(I) - pointer to packet information                      */
    815  1.1  christos /*              nat(I) - pointer to current NAT session                     */
    816  1.1  christos /*                                                                          */
    817  1.1  christos /* Allocate a new application proxy structure and fill it in with the       */
    818  1.1  christos /* relevant details.  call the init function once complete, prior to        */
    819  1.1  christos /* returning.                                                               */
    820  1.1  christos /* ------------------------------------------------------------------------ */
    821  1.1  christos int
    822  1.2  christos ipf_proxy_new(fr_info_t *fin, nat_t *nat)
    823  1.1  christos {
    824  1.1  christos 	ipf_main_softc_t *softc = fin->fin_main_soft;
    825  1.1  christos 	ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
    826  1.1  christos 	register ap_session_t *aps;
    827  1.1  christos 	aproxy_t *apr;
    828  1.1  christos 
    829  1.3   darrenr 	if (softp->ips_proxy_debug & 0x04)
    830  1.1  christos 		printf("ipf_proxy_new(%lx,%lx) \n", (u_long)fin, (u_long)nat);
    831  1.1  christos 
    832  1.1  christos 	if ((nat->nat_ptr == NULL) || (nat->nat_aps != NULL)) {
    833  1.3   darrenr 		if (softp->ips_proxy_debug & 0x08)
    834  1.1  christos 			printf("ipf_proxy_new: nat_ptr %lx nat_aps %lx\n",
    835  1.1  christos 				(u_long)nat->nat_ptr, (u_long)nat->nat_aps);
    836  1.1  christos 		return -1;
    837  1.1  christos 	}
    838  1.1  christos 
    839  1.1  christos 	apr = nat->nat_ptr->in_apr;
    840  1.1  christos 
    841  1.1  christos 	if ((apr->apr_flags & APR_DELETE) ||
    842  1.1  christos 	    (fin->fin_p != apr->apr_p)) {
    843  1.3   darrenr 		if (softp->ips_proxy_debug & 0x08)
    844  1.1  christos 			printf("ipf_proxy_new: apr_flags 0x%x p %d/%d\n",
    845  1.1  christos 				apr->apr_flags, fin->fin_p, apr->apr_p);
    846  1.1  christos 		return -1;
    847  1.1  christos 	}
    848  1.1  christos 
    849  1.1  christos 	KMALLOC(aps, ap_session_t *);
    850  1.1  christos 	if (!aps) {
    851  1.3   darrenr 		if (softp->ips_proxy_debug & 0x08)
    852  1.1  christos 			printf("ipf_proxy_new: malloc failed (%lu)\n",
    853  1.1  christos 				(u_long)sizeof(ap_session_t));
    854  1.1  christos 		return -1;
    855  1.1  christos 	}
    856  1.1  christos 
    857  1.1  christos 	bzero((char *)aps, sizeof(*aps));
    858  1.1  christos 	aps->aps_data = NULL;
    859  1.1  christos 	aps->aps_apr = apr;
    860  1.1  christos 	aps->aps_psiz = 0;
    861  1.1  christos 	if (apr->apr_new != NULL)
    862  1.1  christos 		if ((*apr->apr_new)(apr->apr_soft, fin, aps, nat) == -1) {
    863  1.1  christos 			if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) {
    864  1.1  christos 				KFREES(aps->aps_data, aps->aps_psiz);
    865  1.1  christos 			}
    866  1.1  christos 			KFREE(aps);
    867  1.3   darrenr 			if (softp->ips_proxy_debug & 0x08)
    868  1.1  christos 				printf("ipf_proxy_new: new(%lx) failed\n",
    869  1.1  christos 					(u_long)apr->apr_new);
    870  1.1  christos 			return -1;
    871  1.1  christos 		}
    872  1.1  christos 	aps->aps_nat = nat;
    873  1.1  christos 	aps->aps_next = softp->ips_sess_list;
    874  1.1  christos 	softp->ips_sess_list = aps;
    875  1.1  christos 	nat->nat_aps = aps;
    876  1.1  christos 
    877  1.1  christos 	return 0;
    878  1.1  christos }
    879  1.1  christos 
    880  1.1  christos 
    881  1.1  christos /* ------------------------------------------------------------------------ */
    882  1.1  christos /* Function:    ipf_proxy_check                                             */
    883  1.1  christos /* Returns:     int - -1 == error, 0 == success                             */
    884  1.1  christos /* Parameters:  fin(I) - pointer to packet information                      */
    885  1.1  christos /*              nat(I) - pointer to current NAT session                     */
    886  1.1  christos /*                                                                          */
    887  1.1  christos /* Check to see if a packet should be passed through an active proxy        */
    888  1.1  christos /* routine if one has been setup for it.  We don't need to check the        */
    889  1.1  christos /* checksum here if IPFILTER_CKSUM is defined because if it is, a failed    */
    890  1.1  christos /* check causes FI_BAD to be set.                                           */
    891  1.1  christos /* ------------------------------------------------------------------------ */
    892  1.1  christos int
    893  1.2  christos ipf_proxy_check(fr_info_t *fin, nat_t *nat)
    894  1.1  christos {
    895  1.1  christos 	ipf_main_softc_t *softc = fin->fin_main_soft;
    896  1.1  christos 	ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
    897  1.3   darrenr #if SOLARIS && defined(_KERNEL) && defined(ICK_VALID)
    898  1.1  christos 	mb_t *m;
    899  1.1  christos #endif
    900  1.1  christos 	tcphdr_t *tcp = NULL;
    901  1.1  christos 	udphdr_t *udp = NULL;
    902  1.1  christos 	ap_session_t *aps;
    903  1.1  christos 	aproxy_t *apr;
    904  1.3   darrenr 	short adjlen;
    905  1.3   darrenr 	int dosum;
    906  1.1  christos 	ip_t *ip;
    907  1.1  christos 	short rv;
    908  1.1  christos 	int err;
    909  1.1  christos #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi)
    910  1.1  christos 	u_32_t s1, s2, sd;
    911  1.1  christos #endif
    912  1.1  christos 
    913  1.1  christos 	if (fin->fin_flx & FI_BAD) {
    914  1.3   darrenr 		if (softp->ips_proxy_debug & 0x08)
    915  1.3   darrenr 			printf("ipf_proxy_check: flx 0x%x (BAD)\n",
    916  1.3   darrenr 			       fin->fin_flx);
    917  1.1  christos 		return -1;
    918  1.1  christos 	}
    919  1.1  christos 
    920  1.1  christos #ifndef IPFILTER_CKSUM
    921  1.1  christos 	if ((fin->fin_out == 0) && (ipf_checkl4sum(fin) == -1)) {
    922  1.3   darrenr 		if (softp->ips_proxy_debug & 0x08)
    923  1.1  christos 			printf("ipf_proxy_check: l4 checksum failure %d\n",
    924  1.1  christos 				fin->fin_p);
    925  1.1  christos 		if (fin->fin_p == IPPROTO_TCP)
    926  1.1  christos 			softc->ipf_stats[fin->fin_out].fr_tcpbad++;
    927  1.1  christos 		return -1;
    928  1.1  christos 	}
    929  1.1  christos #endif
    930  1.1  christos 
    931  1.1  christos 	aps = nat->nat_aps;
    932  1.1  christos 	if (aps != NULL) {
    933  1.1  christos 		/*
    934  1.1  christos 		 * If there is data in this packet to be proxied then try and
    935  1.1  christos 		 * get it all into the one buffer, else drop it.
    936  1.1  christos 		 */
    937  1.1  christos #if defined(MENTAT) || defined(HAVE_M_PULLDOWN)
    938  1.1  christos 		if ((fin->fin_dlen > 0) && !(fin->fin_flx & FI_COALESCE))
    939  1.1  christos 			if (ipf_coalesce(fin) == -1) {
    940  1.3   darrenr 				if (softp->ips_proxy_debug & 0x08)
    941  1.3   darrenr 					printf("ipf_proxy_check: %s %x\n",
    942  1.3   darrenr 					       "coalesce failed", fin->fin_flx);
    943  1.1  christos 				return -1;
    944  1.1  christos 			}
    945  1.1  christos #endif
    946  1.1  christos 		ip = fin->fin_ip;
    947  1.3   darrenr 		if (fin->fin_cksum > FI_CK_SUMOK)
    948  1.3   darrenr 			dosum = 0;
    949  1.3   darrenr 		else
    950  1.3   darrenr 			dosum = 1;
    951  1.1  christos 
    952  1.1  christos 		switch (fin->fin_p)
    953  1.1  christos 		{
    954  1.1  christos 		case IPPROTO_TCP :
    955  1.1  christos 			tcp = (tcphdr_t *)fin->fin_dp;
    956  1.3   darrenr #if SOLARIS && defined(_KERNEL) && defined(ICK_VALID)
    957  1.1  christos 			m = fin->fin_qfm;
    958  1.1  christos 			if (dohwcksum && (m->b_ick_flag == ICK_VALID))
    959  1.1  christos 				dosum = 0;
    960  1.1  christos #endif
    961  1.3   darrenr 			break;
    962  1.1  christos 		case IPPROTO_UDP :
    963  1.1  christos 			udp = (udphdr_t *)fin->fin_dp;
    964  1.1  christos 			break;
    965  1.1  christos 		default :
    966  1.1  christos 			break;
    967  1.1  christos 		}
    968  1.1  christos 
    969  1.1  christos 		apr = aps->aps_apr;
    970  1.1  christos 		err = 0;
    971  1.1  christos 		if (fin->fin_out != 0) {
    972  1.1  christos 			if (apr->apr_outpkt != NULL)
    973  1.3   darrenr 				err = (*apr->apr_outpkt)(apr->apr_soft, fin,
    974  1.3   darrenr 							 aps, nat);
    975  1.1  christos 		} else {
    976  1.1  christos 			if (apr->apr_inpkt != NULL)
    977  1.3   darrenr 				err = (*apr->apr_inpkt)(apr->apr_soft, fin,
    978  1.3   darrenr 							aps, nat);
    979  1.1  christos 		}
    980  1.1  christos 
    981  1.1  christos 		rv = APR_EXIT(err);
    982  1.3   darrenr 		if (((softp->ips_proxy_debug & 0x08) && (rv != 0)) ||
    983  1.3   darrenr 		    (softp->ips_proxy_debug & 0x04))
    984  1.1  christos 			printf("ipf_proxy_check: out %d err %x rv %d\n",
    985  1.1  christos 				fin->fin_out, err, rv);
    986  1.1  christos 		if (rv == 1)
    987  1.1  christos 			return -1;
    988  1.1  christos 
    989  1.1  christos 		if (rv == 2) {
    990  1.3   darrenr 			ipf_proxy_deref(apr);
    991  1.1  christos 			nat->nat_aps = NULL;
    992  1.1  christos 			return -1;
    993  1.1  christos 		}
    994  1.1  christos 
    995  1.1  christos 		/*
    996  1.1  christos 		 * If err != 0 then the data size of the packet has changed
    997  1.1  christos 		 * so we need to recalculate the header checksums for the
    998  1.1  christos 		 * packet.
    999  1.1  christos 		 */
   1000  1.3   darrenr 		adjlen = APR_INC(err);
   1001  1.1  christos #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi)
   1002  1.3   darrenr 		s1 = LONG_SUM(fin->fin_plen - adjlen);
   1003  1.3   darrenr 		s2 = LONG_SUM(fin->fin_plen);
   1004  1.3   darrenr 		CALC_SUMD(s1, s2, sd);
   1005  1.3   darrenr 		if ((err != 0) && (fin->fin_cksum < FI_CK_L4PART) &&
   1006  1.3   darrenr 		    fin->fin_v == 4)
   1007  1.3   darrenr 			ipf_fix_outcksum(0, &ip->ip_sum, sd, 0);
   1008  1.1  christos #endif
   1009  1.3   darrenr 		if (fin->fin_flx & FI_DOCKSUM)
   1010  1.3   darrenr 			dosum = 1;
   1011  1.1  christos 
   1012  1.2  christos #ifdef INET
   1013  1.1  christos 		/*
   1014  1.1  christos 		 * For TCP packets, we may need to adjust the sequence and
   1015  1.1  christos 		 * acknowledgement numbers to reflect changes in size of the
   1016  1.1  christos 		 * data stream.
   1017  1.1  christos 		 *
   1018  1.1  christos 		 * For both TCP and UDP, recalculate the layer 4 checksum,
   1019  1.1  christos 		 * regardless, as we can't tell (here) if data has been
   1020  1.1  christos 		 * changed or not.
   1021  1.1  christos 		 */
   1022  1.1  christos 		if (tcp != NULL) {
   1023  1.3   darrenr 			err = ipf_proxy_fixseqack(fin, ip, aps, adjlen);
   1024  1.3   darrenr 			if (fin->fin_cksum == FI_CK_L4PART) {
   1025  1.3   darrenr 				u_short sum = ntohs(tcp->th_sum);
   1026  1.3   darrenr 				sum += adjlen;
   1027  1.3   darrenr 				tcp->th_sum = htons(sum);
   1028  1.3   darrenr 			} else if (fin->fin_cksum < FI_CK_L4PART) {
   1029  1.1  christos 				tcp->th_sum = fr_cksum(fin, ip,
   1030  1.1  christos 						       IPPROTO_TCP, tcp);
   1031  1.3   darrenr 			}
   1032  1.1  christos 		} else if ((udp != NULL) && (udp->uh_sum != 0)) {
   1033  1.3   darrenr 			if (fin->fin_cksum == FI_CK_L4PART) {
   1034  1.3   darrenr 				u_short sum = ntohs(udp->uh_sum);
   1035  1.3   darrenr 				sum += adjlen;
   1036  1.3   darrenr 				udp->uh_sum = htons(sum);
   1037  1.3   darrenr 			} else if (dosum) {
   1038  1.1  christos 				udp->uh_sum = fr_cksum(fin, ip,
   1039  1.1  christos 						       IPPROTO_UDP, udp);
   1040  1.3   darrenr 			}
   1041  1.1  christos 		}
   1042  1.2  christos #endif
   1043  1.1  christos 		aps->aps_bytes += fin->fin_plen;
   1044  1.1  christos 		aps->aps_pkts++;
   1045  1.1  christos 		return 1;
   1046  1.1  christos 	}
   1047  1.1  christos 	return 0;
   1048  1.1  christos }
   1049  1.1  christos 
   1050  1.1  christos 
   1051  1.1  christos /* ------------------------------------------------------------------------ */
   1052  1.1  christos /* Function:    ipf_proxy_lookup                                            */
   1053  1.1  christos /* Returns:     int - -1 == error, 0 == success                             */
   1054  1.3   darrenr /* Parameters:  arg(I)  - pointer to proxy context information              */
   1055  1.3   darrenr /*              pr(I)   - protocol number for proxy                         */
   1056  1.3   darrenr /*              name(I) - proxy name                                        */
   1057  1.1  christos /*                                                                          */
   1058  1.8    rillig /* Search for a proxy by the protocol it is being used with and its name.   */
   1059  1.1  christos /* ------------------------------------------------------------------------ */
   1060  1.1  christos aproxy_t *
   1061  1.2  christos ipf_proxy_lookup(void *arg, u_int pr, char *name)
   1062  1.1  christos {
   1063  1.1  christos 	ipf_proxy_softc_t *softp = arg;
   1064  1.1  christos 	aproxy_t *ap;
   1065  1.1  christos 
   1066  1.3   darrenr 	if (softp->ips_proxy_debug & 0x04)
   1067  1.1  christos 		printf("ipf_proxy_lookup(%d,%s)\n", pr, name);
   1068  1.1  christos 
   1069  1.1  christos 	for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next)
   1070  1.1  christos 		if ((ap->apr_p == pr) &&
   1071  1.1  christos 		    !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) {
   1072  1.1  christos 			ap->apr_ref++;
   1073  1.1  christos 			return ap;
   1074  1.1  christos 		}
   1075  1.1  christos 
   1076  1.3   darrenr 	if (softp->ips_proxy_debug & 0x08)
   1077  1.1  christos 		printf("ipf_proxy_lookup: failed for %d/%s\n", pr, name);
   1078  1.1  christos 	return NULL;
   1079  1.1  christos }
   1080  1.1  christos 
   1081  1.1  christos 
   1082  1.1  christos /* ------------------------------------------------------------------------ */
   1083  1.3   darrenr /* Function:    ipf_proxy_deref                                             */
   1084  1.1  christos /* Returns:     Nil                                                         */
   1085  1.1  christos /* Parameters:  ap(I) - pointer to proxy structure                          */
   1086  1.1  christos /*                                                                          */
   1087  1.3   darrenr /* Drop the reference counter associated with the proxy.                    */
   1088  1.1  christos /* ------------------------------------------------------------------------ */
   1089  1.1  christos void
   1090  1.3   darrenr ipf_proxy_deref(aproxy_t *ap)
   1091  1.1  christos {
   1092  1.1  christos 	ap->apr_ref--;
   1093  1.1  christos }
   1094  1.1  christos 
   1095  1.1  christos 
   1096  1.1  christos /* ------------------------------------------------------------------------ */
   1097  1.3   darrenr /* Function:    ipf_proxy_free                                              */
   1098  1.1  christos /* Returns:     Nil                                                         */
   1099  1.3   darrenr /* Parameters:  softc(I) - pointer to soft context main structure           */
   1100  1.3   darrenr /*              aps(I)   - pointer to current proxy session                 */
   1101  1.3   darrenr /* Locks Held:  ipf_nat_new, ipf_nat(W)                                     */
   1102  1.1  christos /*                                                                          */
   1103  1.3   darrenr /* Free up proxy session information allocated to be used with a NAT        */
   1104  1.3   darrenr /* session.                                                                 */
   1105  1.1  christos /* ------------------------------------------------------------------------ */
   1106  1.1  christos void
   1107  1.3   darrenr ipf_proxy_free(ipf_main_softc_t *softc, ap_session_t *aps)
   1108  1.1  christos {
   1109  1.3   darrenr 	ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
   1110  1.1  christos 	ap_session_t *a, **ap;
   1111  1.1  christos 	aproxy_t *apr;
   1112  1.1  christos 
   1113  1.1  christos 	if (!aps)
   1114  1.1  christos 		return;
   1115  1.1  christos 
   1116  1.1  christos 	for (ap = &softp->ips_sess_list; ((a = *ap) != NULL); ap = &a->aps_next)
   1117  1.1  christos 		if (a == aps) {
   1118  1.1  christos 			*ap = a->aps_next;
   1119  1.1  christos 			break;
   1120  1.1  christos 		}
   1121  1.1  christos 
   1122  1.1  christos 	apr = aps->aps_apr;
   1123  1.1  christos 	if ((apr != NULL) && (apr->apr_del != NULL))
   1124  1.1  christos 		(*apr->apr_del)(softc, aps);
   1125  1.1  christos 
   1126  1.1  christos 	if ((aps->aps_data != NULL) && (aps->aps_psiz != 0))
   1127  1.1  christos 		KFREES(aps->aps_data, aps->aps_psiz);
   1128  1.1  christos 	KFREE(aps);
   1129  1.1  christos }
   1130  1.1  christos 
   1131  1.1  christos 
   1132  1.1  christos /* ------------------------------------------------------------------------ */
   1133  1.1  christos /* Function:    ipf_proxy_fixseqack                                         */
   1134  1.3   darrenr /* Returns:     int    - 2 if TCP ack/seq is changed, else 0                */
   1135  1.1  christos /* Parameters:  fin(I) - pointer to packet information                      */
   1136  1.3   darrenr /*              ip(I)  - pointer to IP header                               */
   1137  1.1  christos /*              nat(I) - pointer to current NAT session                     */
   1138  1.3   darrenr /*              inc(I) - delta to apply to TCP sequence numbering           */
   1139  1.1  christos /*                                                                          */
   1140  1.3   darrenr /* Adjust the TCP sequence/acknowledge numbers in the TCP header based on   */
   1141  1.3   darrenr /* whether or not the new header is past the point at which an adjustment   */
   1142  1.3   darrenr /* occurred. This might happen because of (say) an FTP string being changed */
   1143  1.3   darrenr /* and the new string being a different length to the old.                  */
   1144  1.1  christos /* ------------------------------------------------------------------------ */
   1145  1.1  christos static int
   1146  1.2  christos ipf_proxy_fixseqack(fr_info_t *fin, ip_t *ip, ap_session_t *aps, int inc)
   1147  1.1  christos {
   1148  1.1  christos 	ipf_main_softc_t *softc = fin->fin_main_soft;
   1149  1.1  christos 	ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
   1150  1.1  christos 	int sel, ch = 0, out, nlen;
   1151  1.1  christos 	u_32_t seq1, seq2;
   1152  1.1  christos 	tcphdr_t *tcp;
   1153  1.1  christos 	short inc2;
   1154  1.1  christos 
   1155  1.1  christos 	tcp = (tcphdr_t *)fin->fin_dp;
   1156  1.1  christos 	out = fin->fin_out;
   1157  1.1  christos 	/*
   1158  1.1  christos 	 * ip_len has already been adjusted by 'inc'.
   1159  1.1  christos 	 */
   1160  1.3   darrenr 	nlen = fin->fin_dlen;
   1161  1.3   darrenr 	nlen -= (TCP_OFF(tcp) << 2);
   1162  1.1  christos 
   1163  1.1  christos 	inc2 = inc;
   1164  1.1  christos 	inc = (int)inc2;
   1165  1.1  christos 
   1166  1.1  christos 	if (out != 0) {
   1167  1.1  christos 		seq1 = (u_32_t)ntohl(tcp->th_seq);
   1168  1.1  christos 		sel = aps->aps_sel[out];
   1169  1.1  christos 
   1170  1.1  christos 		/* switch to other set ? */
   1171  1.1  christos 		if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) &&
   1172  1.1  christos 		    (seq1 > aps->aps_seqmin[!sel])) {
   1173  1.3   darrenr 			if (softp->ips_proxy_debug & 0x10)
   1174  1.1  christos 				printf("proxy out switch set seq %d -> %d %x > %x\n",
   1175  1.1  christos 					sel, !sel, seq1,
   1176  1.1  christos 					aps->aps_seqmin[!sel]);
   1177  1.1  christos 			sel = aps->aps_sel[out] = !sel;
   1178  1.1  christos 		}
   1179  1.1  christos 
   1180  1.1  christos 		if (aps->aps_seqoff[sel]) {
   1181  1.1  christos 			seq2 = aps->aps_seqmin[sel] - aps->aps_seqoff[sel];
   1182  1.1  christos 			if (seq1 > seq2) {
   1183  1.1  christos 				seq2 = aps->aps_seqoff[sel];
   1184  1.1  christos 				seq1 += seq2;
   1185  1.1  christos 				tcp->th_seq = htonl(seq1);
   1186  1.1  christos 				ch = 1;
   1187  1.1  christos 			}
   1188  1.1  christos 		}
   1189  1.1  christos 
   1190  1.1  christos 		if (inc && (seq1 > aps->aps_seqmin[!sel])) {
   1191  1.1  christos 			aps->aps_seqmin[sel] = seq1 + nlen - 1;
   1192  1.1  christos 			aps->aps_seqoff[sel] = aps->aps_seqoff[sel] + inc;
   1193  1.3   darrenr 			if (softp->ips_proxy_debug & 0x10)
   1194  1.1  christos 				printf("proxy seq set %d at %x to %d + %d\n",
   1195  1.1  christos 					sel, aps->aps_seqmin[sel],
   1196  1.1  christos 					aps->aps_seqoff[sel], inc);
   1197  1.1  christos 		}
   1198  1.1  christos 
   1199  1.1  christos 		/***/
   1200  1.1  christos 
   1201  1.1  christos 		seq1 = ntohl(tcp->th_ack);
   1202  1.1  christos 		sel = aps->aps_sel[1 - out];
   1203  1.1  christos 
   1204  1.1  christos 		/* switch to other set ? */
   1205  1.1  christos 		if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) &&
   1206  1.1  christos 		    (seq1 > aps->aps_ackmin[!sel])) {
   1207  1.3   darrenr 			if (softp->ips_proxy_debug & 0x10)
   1208  1.1  christos 				printf("proxy out switch set ack %d -> %d %x > %x\n",
   1209  1.1  christos 					sel, !sel, seq1,
   1210  1.1  christos 					aps->aps_ackmin[!sel]);
   1211  1.1  christos 			sel = aps->aps_sel[1 - out] = !sel;
   1212  1.1  christos 		}
   1213  1.1  christos 
   1214  1.1  christos 		if (aps->aps_ackoff[sel] && (seq1 > aps->aps_ackmin[sel])) {
   1215  1.1  christos 			seq2 = aps->aps_ackoff[sel];
   1216  1.1  christos 			tcp->th_ack = htonl(seq1 - seq2);
   1217  1.1  christos 			ch = 1;
   1218  1.1  christos 		}
   1219  1.1  christos 	} else {
   1220  1.1  christos 		seq1 = ntohl(tcp->th_seq);
   1221  1.1  christos 		sel = aps->aps_sel[out];
   1222  1.1  christos 
   1223  1.1  christos 		/* switch to other set ? */
   1224  1.1  christos 		if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) &&
   1225  1.1  christos 		    (seq1 > aps->aps_ackmin[!sel])) {
   1226  1.3   darrenr 			if (softp->ips_proxy_debug & 0x10)
   1227  1.1  christos 				printf("proxy in switch set ack %d -> %d %x > %x\n",
   1228  1.1  christos 					sel, !sel, seq1, aps->aps_ackmin[!sel]);
   1229  1.1  christos 			sel = aps->aps_sel[out] = !sel;
   1230  1.1  christos 		}
   1231  1.1  christos 
   1232  1.1  christos 		if (aps->aps_ackoff[sel]) {
   1233  1.1  christos 			seq2 = aps->aps_ackmin[sel] - aps->aps_ackoff[sel];
   1234  1.1  christos 			if (seq1 > seq2) {
   1235  1.1  christos 				seq2 = aps->aps_ackoff[sel];
   1236  1.1  christos 				seq1 += seq2;
   1237  1.1  christos 				tcp->th_seq = htonl(seq1);
   1238  1.1  christos 				ch = 1;
   1239  1.1  christos 			}
   1240  1.1  christos 		}
   1241  1.1  christos 
   1242  1.1  christos 		if (inc && (seq1 > aps->aps_ackmin[!sel])) {
   1243  1.1  christos 			aps->aps_ackmin[!sel] = seq1 + nlen - 1;
   1244  1.1  christos 			aps->aps_ackoff[!sel] = aps->aps_ackoff[sel] + inc;
   1245  1.1  christos 
   1246  1.3   darrenr 			if (softp->ips_proxy_debug & 0x10)
   1247  1.1  christos 				printf("proxy ack set %d at %x to %d + %d\n",
   1248  1.1  christos 					!sel, aps->aps_seqmin[!sel],
   1249  1.1  christos 					aps->aps_seqoff[sel], inc);
   1250  1.1  christos 		}
   1251  1.1  christos 
   1252  1.1  christos 		/***/
   1253  1.1  christos 
   1254  1.1  christos 		seq1 = ntohl(tcp->th_ack);
   1255  1.1  christos 		sel = aps->aps_sel[1 - out];
   1256  1.1  christos 
   1257  1.1  christos 		/* switch to other set ? */
   1258  1.1  christos 		if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) &&
   1259  1.1  christos 		    (seq1 > aps->aps_seqmin[!sel])) {
   1260  1.3   darrenr 			if (softp->ips_proxy_debug & 0x10)
   1261  1.1  christos 				printf("proxy in switch set seq %d -> %d %x > %x\n",
   1262  1.1  christos 					sel, !sel, seq1, aps->aps_seqmin[!sel]);
   1263  1.1  christos 			sel = aps->aps_sel[1 - out] = !sel;
   1264  1.1  christos 		}
   1265  1.1  christos 
   1266  1.1  christos 		if (aps->aps_seqoff[sel] != 0) {
   1267  1.3   darrenr 			if (softp->ips_proxy_debug & 0x10)
   1268  1.1  christos 				printf("sel %d seqoff %d seq1 %x seqmin %x\n",
   1269  1.1  christos 					sel, aps->aps_seqoff[sel], seq1,
   1270  1.1  christos 					aps->aps_seqmin[sel]);
   1271  1.1  christos 			if (seq1 > aps->aps_seqmin[sel]) {
   1272  1.1  christos 				seq2 = aps->aps_seqoff[sel];
   1273  1.1  christos 				tcp->th_ack = htonl(seq1 - seq2);
   1274  1.1  christos 				ch = 1;
   1275  1.1  christos 			}
   1276  1.1  christos 		}
   1277  1.1  christos 	}
   1278  1.1  christos 
   1279  1.3   darrenr 	if (softp->ips_proxy_debug & 0x10)
   1280  1.3   darrenr 		printf("ipf_proxy_fixseqack: seq %u ack %u\n",
   1281  1.1  christos 			(u_32_t)ntohl(tcp->th_seq), (u_32_t)ntohl(tcp->th_ack));
   1282  1.1  christos 	return ch ? 2 : 0;
   1283  1.1  christos }
   1284  1.3   darrenr 
   1285  1.3   darrenr 
   1286  1.3   darrenr /* ------------------------------------------------------------------------ */
   1287  1.3   darrenr /* Function:    ipf_proxy_rule_rev                                          */
   1288  1.3   darrenr /* Returns:     ipnat_t * - NULL = failure, else pointer to new rule        */
   1289  1.3   darrenr /* Parameters:  nat(I) - pointer to NAT session to create rule from         */
   1290  1.3   darrenr /*                                                                          */
   1291  1.3   darrenr /* This function creates a NAT rule that is based upon the reverse packet   */
   1292  1.3   darrenr /* flow associated with this NAT session. Thus if this NAT session was      */
   1293  1.3   darrenr /* created with a map rule then this function will create a rdr rule.       */
   1294  1.3   darrenr /* Only address fields and network interfaces are assigned in this function */
   1295  1.3   darrenr /* and the address fields are formed such that an exact is required. If the */
   1296  1.3   darrenr /* original rule had a netmask, that is not replicated here not is it       */
   1297  1.3   darrenr /* desired. The ultimate goal here is to create a NAT rule to support a NAT */
   1298  1.3   darrenr /* session being created that does not have a user configured rule. The     */
   1299  1.3   darrenr /* classic example is supporting the FTP proxy, where a data channel needs  */
   1300  1.3   darrenr /* to be setup, based on the addresses used for the control connection. In  */
   1301  1.3   darrenr /* that case, this function is used to handle creating NAT rules to support */
   1302  1.3   darrenr /* data connections with the PORT and EPRT commands.                        */
   1303  1.3   darrenr /* ------------------------------------------------------------------------ */
   1304  1.3   darrenr ipnat_t *
   1305  1.5   darrenr ipf_proxy_rule_rev(nat_t *nat)
   1306  1.3   darrenr {
   1307  1.3   darrenr 	ipnat_t *old;
   1308  1.3   darrenr 	ipnat_t *ipn;
   1309  1.3   darrenr 	int size;
   1310  1.3   darrenr 
   1311  1.3   darrenr 	old = nat->nat_ptr;
   1312  1.3   darrenr 	size = old->in_size;
   1313  1.3   darrenr 
   1314  1.3   darrenr 	KMALLOCS(ipn, ipnat_t *, size);
   1315  1.3   darrenr 	if (ipn == NULL)
   1316  1.3   darrenr 		return NULL;
   1317  1.3   darrenr 
   1318  1.3   darrenr 	bzero((char *)ipn, size);
   1319  1.3   darrenr 
   1320  1.3   darrenr 	ipn->in_use = 1;
   1321  1.3   darrenr 	ipn->in_hits = 1;
   1322  1.3   darrenr 	ipn->in_ippip = 1;
   1323  1.3   darrenr 	ipn->in_apr = NULL;
   1324  1.3   darrenr 	ipn->in_size = size;
   1325  1.3   darrenr 	ipn->in_pr[0] = old->in_pr[1];
   1326  1.3   darrenr 	ipn->in_pr[1] = old->in_pr[0];
   1327  1.3   darrenr 	ipn->in_v[0] = old->in_v[1];
   1328  1.3   darrenr 	ipn->in_v[1] = old->in_v[0];
   1329  1.3   darrenr 	ipn->in_ifps[0] = old->in_ifps[1];
   1330  1.3   darrenr 	ipn->in_ifps[1] = old->in_ifps[0];
   1331  1.3   darrenr 	ipn->in_flags = (old->in_flags | IPN_PROXYRULE);
   1332  1.3   darrenr 
   1333  1.3   darrenr 	ipn->in_nsrcip6 = nat->nat_odst6;
   1334  1.3   darrenr 	ipn->in_osrcip6 = nat->nat_ndst6;
   1335  1.3   darrenr 
   1336  1.3   darrenr 	if ((old->in_redir & NAT_REDIRECT) != 0) {
   1337  1.3   darrenr 		ipn->in_redir = NAT_MAP;
   1338  1.3   darrenr 		if (ipn->in_v[0] == 4) {
   1339  1.3   darrenr 			ipn->in_snip = ntohl(nat->nat_odstaddr);
   1340  1.3   darrenr 			ipn->in_dnip = ntohl(nat->nat_nsrcaddr);
   1341  1.3   darrenr 		} else {
   1342  1.3   darrenr #ifdef USE_INET6
   1343  1.3   darrenr 			ipn->in_snip6 = nat->nat_odst6;
   1344  1.3   darrenr 			ipn->in_dnip6 = nat->nat_nsrc6;
   1345  1.3   darrenr #endif
   1346  1.3   darrenr 		}
   1347  1.3   darrenr 		ipn->in_ndstip6 = nat->nat_nsrc6;
   1348  1.3   darrenr 		ipn->in_odstip6 = nat->nat_osrc6;
   1349  1.3   darrenr 	} else {
   1350  1.3   darrenr 		ipn->in_redir = NAT_REDIRECT;
   1351  1.3   darrenr 		if (ipn->in_v[0] == 4) {
   1352  1.3   darrenr 			ipn->in_snip = ntohl(nat->nat_odstaddr);
   1353  1.3   darrenr 			ipn->in_dnip = ntohl(nat->nat_osrcaddr);
   1354  1.3   darrenr 		} else {
   1355  1.3   darrenr #ifdef USE_INET6
   1356  1.3   darrenr 			ipn->in_snip6 = nat->nat_odst6;
   1357  1.3   darrenr 			ipn->in_dnip6 = nat->nat_osrc6;
   1358  1.3   darrenr #endif
   1359  1.3   darrenr 		}
   1360  1.3   darrenr 		ipn->in_ndstip6 = nat->nat_osrc6;
   1361  1.3   darrenr 		ipn->in_odstip6 = nat->nat_nsrc6;
   1362  1.3   darrenr 	}
   1363  1.3   darrenr 
   1364  1.3   darrenr 	IP6_SETONES(&ipn->in_osrcmsk6);
   1365  1.3   darrenr 	IP6_SETONES(&ipn->in_nsrcmsk6);
   1366  1.3   darrenr 	IP6_SETONES(&ipn->in_odstmsk6);
   1367  1.3   darrenr 	IP6_SETONES(&ipn->in_ndstmsk6);
   1368  1.3   darrenr 
   1369  1.3   darrenr 	ipn->in_namelen = old->in_namelen;
   1370  1.3   darrenr 	ipn->in_ifnames[0] = old->in_ifnames[1];
   1371  1.3   darrenr 	ipn->in_ifnames[1] = old->in_ifnames[0];
   1372  1.3   darrenr 	bcopy(old->in_names, ipn->in_names, ipn->in_namelen);
   1373  1.3   darrenr 	MUTEX_INIT(&ipn->in_lock, "ipnat rev rule lock");
   1374  1.3   darrenr 
   1375  1.3   darrenr 	return ipn;
   1376  1.3   darrenr }
   1377  1.3   darrenr 
   1378  1.3   darrenr 
   1379  1.3   darrenr /* ------------------------------------------------------------------------ */
   1380  1.3   darrenr /* Function:    ipf_proxy_rule_fwd                                          */
   1381  1.3   darrenr /* Returns:     ipnat_t * - NULL = failure, else pointer to new rule        */
   1382  1.3   darrenr /* Parameters:  nat(I) - pointer to NAT session to create rule from         */
   1383  1.3   darrenr /*                                                                          */
   1384  1.3   darrenr /* The purpose and rationale of this function is much the same as the above */
   1385  1.3   darrenr /* function, ipf_proxy_rule_rev, except that a rule is created that matches */
   1386  1.3   darrenr /* the same direction as that of the existing NAT session. Thus if this NAT */
   1387  1.3   darrenr /* session was created with a map rule then this function will also create  */
   1388  1.3   darrenr /* a data structure to represent a map rule. Whereas ipf_proxy_rule_rev is  */
   1389  1.3   darrenr /* used to support PORT/EPRT, this function supports PASV/EPSV.             */
   1390  1.3   darrenr /* ------------------------------------------------------------------------ */
   1391  1.3   darrenr ipnat_t *
   1392  1.5   darrenr ipf_proxy_rule_fwd(nat_t *nat)
   1393  1.3   darrenr {
   1394  1.3   darrenr 	ipnat_t *old;
   1395  1.3   darrenr 	ipnat_t *ipn;
   1396  1.3   darrenr 	int size;
   1397  1.3   darrenr 
   1398  1.3   darrenr 	old = nat->nat_ptr;
   1399  1.3   darrenr 	size = old->in_size;
   1400  1.3   darrenr 
   1401  1.3   darrenr 	KMALLOCS(ipn, ipnat_t *, size);
   1402  1.3   darrenr 	if (ipn == NULL)
   1403  1.3   darrenr 		return NULL;
   1404  1.3   darrenr 
   1405  1.3   darrenr 	bzero((char *)ipn, size);
   1406  1.3   darrenr 
   1407  1.3   darrenr 	ipn->in_use = 1;
   1408  1.3   darrenr 	ipn->in_hits = 1;
   1409  1.3   darrenr 	ipn->in_ippip = 1;
   1410  1.3   darrenr 	ipn->in_apr = NULL;
   1411  1.3   darrenr 	ipn->in_size = size;
   1412  1.3   darrenr 	ipn->in_pr[0] = old->in_pr[0];
   1413  1.3   darrenr 	ipn->in_pr[1] = old->in_pr[1];
   1414  1.3   darrenr 	ipn->in_v[0] = old->in_v[0];
   1415  1.3   darrenr 	ipn->in_v[1] = old->in_v[1];
   1416  1.3   darrenr 	ipn->in_ifps[0] = nat->nat_ifps[0];
   1417  1.3   darrenr 	ipn->in_ifps[1] = nat->nat_ifps[1];
   1418  1.3   darrenr 	ipn->in_flags = (old->in_flags | IPN_PROXYRULE);
   1419  1.3   darrenr 
   1420  1.3   darrenr 	ipn->in_nsrcip6 = nat->nat_nsrc6;
   1421  1.3   darrenr 	ipn->in_osrcip6 = nat->nat_osrc6;
   1422  1.3   darrenr 	ipn->in_ndstip6 = nat->nat_ndst6;
   1423  1.3   darrenr 	ipn->in_odstip6 = nat->nat_odst6;
   1424  1.3   darrenr 	ipn->in_redir = old->in_redir;
   1425  1.3   darrenr 
   1426  1.3   darrenr 	if (ipn->in_v[0] == 4) {
   1427  1.3   darrenr 		ipn->in_snip = ntohl(nat->nat_nsrcaddr);
   1428  1.3   darrenr 		ipn->in_dnip = ntohl(nat->nat_ndstaddr);
   1429  1.3   darrenr 	} else {
   1430  1.3   darrenr #ifdef USE_INET6
   1431  1.3   darrenr 		ipn->in_snip6 = nat->nat_nsrc6;
   1432  1.3   darrenr 		ipn->in_dnip6 = nat->nat_ndst6;
   1433  1.3   darrenr #endif
   1434  1.3   darrenr 	}
   1435  1.3   darrenr 
   1436  1.3   darrenr 	IP6_SETONES(&ipn->in_osrcmsk6);
   1437  1.3   darrenr 	IP6_SETONES(&ipn->in_nsrcmsk6);
   1438  1.3   darrenr 	IP6_SETONES(&ipn->in_odstmsk6);
   1439  1.3   darrenr 	IP6_SETONES(&ipn->in_ndstmsk6);
   1440  1.3   darrenr 
   1441  1.3   darrenr 	ipn->in_namelen = old->in_namelen;
   1442  1.3   darrenr 	ipn->in_ifnames[0] = old->in_ifnames[0];
   1443  1.3   darrenr 	ipn->in_ifnames[1] = old->in_ifnames[1];
   1444  1.3   darrenr 	bcopy(old->in_names, ipn->in_names, ipn->in_namelen);
   1445  1.3   darrenr 	MUTEX_INIT(&ipn->in_lock, "ipnat fwd rule lock");
   1446  1.3   darrenr 
   1447  1.3   darrenr 	return ipn;
   1448  1.3   darrenr }
   1449