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