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