Home | History | Annotate | Line # | Download | only in netinet
ip_proxy.c revision 1.2
      1  1.2  christos /*	$NetBSD: ip_proxy.c,v 1.2 2012/03/23 20:39:50 christos 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.2  christos __KERNEL_RCSID(0, "$NetBSD: ip_proxy.c,v 1.2 2012/03/23 20:39:50 christos Exp $");
    109  1.2  christos #else
    110  1.2  christos static const char rcsid[] = "@(#)Id: ip_proxy.c,v 2.102.2.7 2012/01/29 05:30:36 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.1  christos 		"ips_proxy_debug",	0,	10,
    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.1  christos 	{ NULL, NULL, "tftp", (char)IPPROTO_TCP, 0, 0, 0,
    151  1.1  christos 	  ipf_p_tftp_main_load, ipf_p_tftp_main_unload,
    152  1.1  christos 	  NULL, NULL,
    153  1.1  christos 	  NULL, NULL,
    154  1.1  christos 	  ipf_p_tftp_new, NULL, 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.1  christos /* Function:    ipf_proxy_init                                              */
    270  1.1  christos /* Returns:     int - -1 == error, 0 == success                             */
    271  1.1  christos /* Parameters:  fin(I) - pointer to packet information                      */
    272  1.1  christos /*              nat(I) - pointer to current NAT session                     */
    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.1  christos /* Function:    ipf_proxy_unload                                            */
    292  1.1  christos /* Returns:     Nil                                                         */
    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.1  christos void *
    315  1.2  christos ipf_proxy_soft_create(ipf_main_softc_t *softc)
    316  1.1  christos {
    317  1.1  christos 	ipf_proxy_softc_t *softp;
    318  1.1  christos 	aproxy_t *last;
    319  1.1  christos 	aproxy_t *apn;
    320  1.1  christos 	aproxy_t *ap;
    321  1.1  christos 
    322  1.1  christos 	KMALLOC(softp, ipf_proxy_softc_t *);
    323  1.1  christos 	if (softp == NULL)
    324  1.1  christos 		return softp;
    325  1.1  christos 
    326  1.1  christos 	bzero((char *)softp, sizeof(*softp));
    327  1.1  christos 
    328  1.1  christos #if defined(_KERNEL)
    329  1.1  christos 	softp->ips_proxy_debug = 0;
    330  1.1  christos #else
    331  1.1  christos 	softp->ips_proxy_debug = 2;
    332  1.1  christos #endif
    333  1.1  christos 	softp->ips_proxy_session_size = AP_SESS_SIZE;
    334  1.1  christos 
    335  1.1  christos 	softp->ipf_proxy_tune = ipf_tune_array_copy(softp,
    336  1.1  christos 						    sizeof(ipf_proxy_tuneables),
    337  1.1  christos 						    ipf_proxy_tuneables);
    338  1.1  christos 	if (softp->ipf_proxy_tune == NULL) {
    339  1.1  christos 		ipf_proxy_soft_destroy(softc, softp);
    340  1.1  christos 		return NULL;
    341  1.1  christos 	}
    342  1.1  christos 	if (ipf_tune_array_link(softc, softp->ipf_proxy_tune) == -1) {
    343  1.1  christos 		ipf_proxy_soft_destroy(softc, softp);
    344  1.1  christos 		return NULL;
    345  1.1  christos 	}
    346  1.1  christos 
    347  1.1  christos 	last = NULL;
    348  1.1  christos 	for (ap = ips_proxies; ap->apr_p; ap++) {
    349  1.1  christos 		apn = ipf_proxy_create_clone(softc, ap);
    350  1.1  christos 		if (apn == NULL)
    351  1.1  christos 			goto failed;
    352  1.1  christos 		if (last != NULL)
    353  1.1  christos 			last->apr_next = apn;
    354  1.1  christos 		else
    355  1.1  christos 			softp->ips_proxies = apn;
    356  1.1  christos 		last = apn;
    357  1.1  christos 	}
    358  1.1  christos 	for (ap = ips_proxies; ap != NULL; ap = ap->apr_next) {
    359  1.1  christos 		apn = ipf_proxy_create_clone(softc, ap);
    360  1.1  christos 		if (apn == NULL)
    361  1.1  christos 			goto failed;
    362  1.1  christos 		if (last != NULL)
    363  1.1  christos 			last->apr_next = apn;
    364  1.1  christos 		else
    365  1.1  christos 			softp->ips_proxies = apn;
    366  1.1  christos 		last = apn;
    367  1.1  christos 	}
    368  1.1  christos 
    369  1.1  christos 	return softp;
    370  1.1  christos failed:
    371  1.1  christos 	ipf_proxy_soft_destroy(softc, softp);
    372  1.1  christos 	return NULL;
    373  1.1  christos }
    374  1.1  christos 
    375  1.1  christos 
    376  1.1  christos static aproxy_t *
    377  1.2  christos ipf_proxy_create_clone(ipf_main_softc_t *softc, aproxy_t *orig)
    378  1.1  christos {
    379  1.1  christos 	aproxy_t *apn;
    380  1.1  christos 
    381  1.1  christos 	KMALLOC(apn, aproxy_t *);
    382  1.1  christos 	if (apn == NULL)
    383  1.1  christos 		return NULL;
    384  1.1  christos 
    385  1.1  christos 	bcopy((char *)orig, (char *)apn, sizeof(*apn));
    386  1.1  christos 	apn->apr_next = NULL;
    387  1.1  christos 	apn->apr_soft = NULL;
    388  1.1  christos 
    389  1.1  christos 	if (apn->apr_create != NULL) {
    390  1.1  christos 		apn->apr_soft = (*apn->apr_create)(softc);
    391  1.1  christos 		if (apn->apr_soft == NULL) {
    392  1.1  christos 			KFREE(apn);
    393  1.1  christos 			return NULL;
    394  1.1  christos 		}
    395  1.1  christos 	}
    396  1.1  christos 
    397  1.1  christos 	apn->apr_parent = orig;
    398  1.1  christos 	orig->apr_clones++;
    399  1.1  christos 
    400  1.1  christos 	return apn;
    401  1.1  christos }
    402  1.1  christos 
    403  1.1  christos 
    404  1.1  christos int
    405  1.2  christos ipf_proxy_soft_init(ipf_main_softc_t *softc, void *arg)
    406  1.1  christos {
    407  1.1  christos 	ipf_proxy_softc_t *softp;
    408  1.1  christos 	aproxy_t *ap;
    409  1.1  christos 	u_int size;
    410  1.1  christos 	int err;
    411  1.1  christos 
    412  1.1  christos 	softp = arg;
    413  1.1  christos 	size = softp->ips_proxy_session_size * sizeof(ap_session_t *);
    414  1.1  christos 
    415  1.1  christos 	KMALLOCS(softp->ips_sess_tab, ap_session_t **, size);
    416  1.1  christos 
    417  1.1  christos 	if (softp->ips_sess_tab == NULL)
    418  1.1  christos 		return -1;
    419  1.1  christos 
    420  1.1  christos 	bzero(softp->ips_sess_tab, size);
    421  1.1  christos 
    422  1.1  christos 	for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next) {
    423  1.1  christos 		if (ap->apr_init != NULL) {
    424  1.1  christos 			err = (*ap->apr_init)(softc, ap->apr_soft);
    425  1.1  christos 			if (err != 0)
    426  1.1  christos 				return -2;
    427  1.1  christos 		}
    428  1.1  christos 	}
    429  1.1  christos 	softp->ips_init_run = 1;
    430  1.1  christos 
    431  1.1  christos 	return 0;
    432  1.1  christos }
    433  1.1  christos 
    434  1.1  christos 
    435  1.1  christos int
    436  1.2  christos ipf_proxy_soft_fini(ipf_main_softc_t *softc, void *arg)
    437  1.1  christos {
    438  1.1  christos 	ipf_proxy_softc_t *softp = arg;
    439  1.1  christos 	aproxy_t *ap;
    440  1.1  christos 
    441  1.1  christos 	for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next) {
    442  1.1  christos 		if (ap->apr_fini != NULL) {
    443  1.1  christos 			(*ap->apr_fini)(softc, ap->apr_soft);
    444  1.1  christos 		}
    445  1.1  christos 	}
    446  1.1  christos 
    447  1.1  christos 	if (softp->ips_sess_tab != NULL) {
    448  1.1  christos 		KFREES(softp->ips_sess_tab,
    449  1.1  christos 		       softp->ips_proxy_session_size * sizeof(ap_session_t *));
    450  1.1  christos 		softp->ips_sess_tab = NULL;
    451  1.1  christos 	}
    452  1.1  christos 	softp->ips_init_run = 0;
    453  1.1  christos 
    454  1.1  christos 	return 0;
    455  1.1  christos }
    456  1.1  christos 
    457  1.1  christos 
    458  1.1  christos void
    459  1.2  christos ipf_proxy_soft_destroy(ipf_main_softc_t *softc, void *arg)
    460  1.1  christos {
    461  1.1  christos 	ipf_proxy_softc_t *softp = arg;
    462  1.1  christos 	aproxy_t *ap;
    463  1.1  christos 
    464  1.1  christos 	while ((ap = softp->ips_proxies) != NULL) {
    465  1.1  christos 		softp->ips_proxies = ap->apr_next;
    466  1.1  christos 		if (ap->apr_destroy != NULL)
    467  1.1  christos 			(*ap->apr_destroy)(softc, ap->apr_soft);
    468  1.1  christos 		ap->apr_parent->apr_clones--;
    469  1.1  christos 		KFREE(ap);
    470  1.1  christos 	}
    471  1.1  christos 
    472  1.1  christos 	if (softp->ipf_proxy_tune != NULL) {
    473  1.1  christos                 ipf_tune_array_unlink(softc, softp->ipf_proxy_tune);
    474  1.1  christos                 KFREES(softp->ipf_proxy_tune, sizeof(ipf_proxy_tuneables));
    475  1.1  christos                 softp->ipf_proxy_tune = NULL;
    476  1.1  christos 	}
    477  1.1  christos 
    478  1.1  christos 	KFREE(softp);
    479  1.1  christos }
    480  1.1  christos 
    481  1.1  christos 
    482  1.1  christos /* ------------------------------------------------------------------------ */
    483  1.1  christos /* Function:    ipf_proxy_flush                                             */
    484  1.1  christos /* Returns:     Nil                                                         */
    485  1.1  christos /* Parameters:  fin(I) - pointer to packet information                      */
    486  1.1  christos /*              nat(I) - pointer to current NAT session                     */
    487  1.1  christos /*                                                                          */
    488  1.1  christos /* ------------------------------------------------------------------------ */
    489  1.1  christos void
    490  1.2  christos ipf_proxy_flush(void *arg, int how)
    491  1.1  christos {
    492  1.1  christos 	ipf_proxy_softc_t *softp = arg;
    493  1.1  christos 	aproxy_t *ap;
    494  1.1  christos 
    495  1.1  christos 	switch (how)
    496  1.1  christos 	{
    497  1.1  christos 	case 0 :
    498  1.1  christos 		for (ap = softp->ips_proxies; ap; ap = ap->apr_next)
    499  1.1  christos 			if (ap->apr_flush != NULL)
    500  1.1  christos 				(*ap->apr_flush)(ap, how);
    501  1.1  christos 		break;
    502  1.1  christos 	case 1 :
    503  1.1  christos 		for (ap = softp->ips_proxies; ap; ap = ap->apr_next)
    504  1.1  christos 			if (ap->apr_clear != NULL)
    505  1.1  christos 				(*ap->apr_clear)(ap);
    506  1.1  christos 		break;
    507  1.1  christos 	default :
    508  1.1  christos 		break;
    509  1.1  christos 	}
    510  1.1  christos }
    511  1.1  christos 
    512  1.1  christos 
    513  1.1  christos /* ------------------------------------------------------------------------ */
    514  1.1  christos /* Function:    ipf_proxy_add                                               */
    515  1.1  christos /* Returns:     int - -1 == error, 0 == success                             */
    516  1.1  christos /* Parameters:  ap(I) - pointer to proxy structure                          */
    517  1.1  christos /*                                                                          */
    518  1.1  christos /* Dynamically add a new kernel proxy.  Ensure that it is unique in the     */
    519  1.1  christos /* collection compiled in and dynamically added.                            */
    520  1.1  christos /* ------------------------------------------------------------------------ */
    521  1.1  christos int
    522  1.2  christos ipf_proxy_add(void *arg, aproxy_t *ap)
    523  1.1  christos {
    524  1.1  christos 	ipf_proxy_softc_t *softp = arg;
    525  1.1  christos 
    526  1.1  christos 	aproxy_t *a;
    527  1.1  christos 
    528  1.1  christos 	for (a = ips_proxies; a->apr_p; a++)
    529  1.1  christos 		if ((a->apr_p == ap->apr_p) &&
    530  1.1  christos 		    !strncmp(a->apr_label, ap->apr_label,
    531  1.1  christos 			     sizeof(ap->apr_label))) {
    532  1.1  christos 			if (softp->ips_proxy_debug > 1)
    533  1.1  christos 				printf("ipf_proxy_add: %s/%d present (B)\n",
    534  1.1  christos 				       a->apr_label, a->apr_p);
    535  1.1  christos 			return -1;
    536  1.1  christos 		}
    537  1.1  christos 
    538  1.1  christos 	for (a = ap_proxylist; (a != NULL); a = a->apr_next)
    539  1.1  christos 		if ((a->apr_p == ap->apr_p) &&
    540  1.1  christos 		    !strncmp(a->apr_label, ap->apr_label,
    541  1.1  christos 			     sizeof(ap->apr_label))) {
    542  1.1  christos 			if (softp->ips_proxy_debug > 1)
    543  1.1  christos 				printf("ipf_proxy_add: %s/%d present (D)\n",
    544  1.1  christos 				       a->apr_label, a->apr_p);
    545  1.1  christos 			return -1;
    546  1.1  christos 		}
    547  1.1  christos 	ap->apr_next = ap_proxylist;
    548  1.1  christos 	ap_proxylist = ap;
    549  1.1  christos 	if (ap->apr_load != NULL)
    550  1.1  christos 		(*ap->apr_load)();
    551  1.1  christos 	return 0;
    552  1.1  christos }
    553  1.1  christos 
    554  1.1  christos 
    555  1.1  christos /* ------------------------------------------------------------------------ */
    556  1.1  christos /* Function:    ipf_proxy_ctl                                               */
    557  1.1  christos /* Returns:     int - 0 == success, else error                              */
    558  1.1  christos /* Parameters:  ctl(I) - pointer to proxy control structure                 */
    559  1.1  christos /*                                                                          */
    560  1.1  christos /* Check to see if the proxy this control request has come through for      */
    561  1.1  christos /* exists, and if it does and it has a control function then invoke that    */
    562  1.1  christos /* control function.                                                        */
    563  1.1  christos /* ------------------------------------------------------------------------ */
    564  1.1  christos int
    565  1.2  christos ipf_proxy_ctl(ipf_main_softc_t *softc, void *arg, ap_ctl_t *ctl)
    566  1.1  christos {
    567  1.1  christos 	ipf_proxy_softc_t *softp = arg;
    568  1.1  christos 	aproxy_t *a;
    569  1.1  christos 	int error;
    570  1.1  christos 
    571  1.1  christos 	a = ipf_proxy_lookup(arg, ctl->apc_p, ctl->apc_label);
    572  1.1  christos 	if (a == NULL) {
    573  1.1  christos 		if (softp->ips_proxy_debug > 1)
    574  1.1  christos 			printf("ipf_proxy_ctl: can't find %s/%d\n",
    575  1.1  christos 				ctl->apc_label, ctl->apc_p);
    576  1.1  christos 		IPFERROR(80001);
    577  1.1  christos 		error = ESRCH;
    578  1.1  christos 	} else if (a->apr_ctl == NULL) {
    579  1.1  christos 		if (softp->ips_proxy_debug > 1)
    580  1.1  christos 			printf("ipf_proxy_ctl: no ctl function for %s/%d\n",
    581  1.1  christos 				ctl->apc_label, ctl->apc_p);
    582  1.1  christos 		IPFERROR(80002);
    583  1.1  christos 		error = ENXIO;
    584  1.1  christos 	} else {
    585  1.1  christos 		error = (*a->apr_ctl)(softc, a->apr_soft, ctl);
    586  1.1  christos 		if ((error != 0) && (softp->ips_proxy_debug > 1))
    587  1.1  christos 			printf("ipf_proxy_ctl: %s/%d ctl error %d\n",
    588  1.1  christos 				a->apr_label, a->apr_p, error);
    589  1.1  christos 	}
    590  1.1  christos 	return error;
    591  1.1  christos }
    592  1.1  christos 
    593  1.1  christos 
    594  1.1  christos /* ------------------------------------------------------------------------ */
    595  1.1  christos /* Function:    ipf_proxy_del                                               */
    596  1.1  christos /* Returns:     int - -1 == error, 0 == success                             */
    597  1.1  christos /* Parameters:  ap(I) - pointer to proxy structure                          */
    598  1.1  christos /*                                                                          */
    599  1.1  christos /* Delete a proxy that has been added dynamically from those available.     */
    600  1.1  christos /* If it is in use, return 1 (do not destroy NOW), not in use 0 or -1       */
    601  1.1  christos /* if it cannot be matched.                                                 */
    602  1.1  christos /* ------------------------------------------------------------------------ */
    603  1.1  christos int
    604  1.2  christos ipf_proxy_del(aproxy_t *ap)
    605  1.1  christos {
    606  1.1  christos 	aproxy_t *a, **app;
    607  1.1  christos 
    608  1.1  christos 	for (app = &ap_proxylist; ((a = *app) != NULL); app = &a->apr_next) {
    609  1.1  christos 		if (a == ap) {
    610  1.1  christos 			a->apr_flags |= APR_DELETE;
    611  1.1  christos 			if (ap->apr_ref == 0 && ap->apr_clones == 0) {
    612  1.1  christos 				*app = a->apr_next;
    613  1.1  christos 				return 0;
    614  1.1  christos 			}
    615  1.1  christos 			return 1;
    616  1.1  christos 		}
    617  1.1  christos 	}
    618  1.1  christos 
    619  1.1  christos 	return -1;
    620  1.1  christos }
    621  1.1  christos 
    622  1.1  christos 
    623  1.1  christos /* ------------------------------------------------------------------------ */
    624  1.1  christos /* Function:    ipf_proxy_ok                                                */
    625  1.1  christos /* Returns:     int - 1 == good match else not.                             */
    626  1.1  christos /* Parameters:  fin(I) - pointer to packet information                      */
    627  1.1  christos /*              nat(I) - pointer to current NAT session                     */
    628  1.1  christos /*                                                                          */
    629  1.1  christos /* ------------------------------------------------------------------------ */
    630  1.1  christos int
    631  1.2  christos ipf_proxy_ok(fr_info_t *fin, tcphdr_t *tcp, ipnat_t *nat)
    632  1.1  christos {
    633  1.1  christos 	aproxy_t *apr = nat->in_apr;
    634  1.1  christos 	u_short dport = nat->in_odport;
    635  1.1  christos 
    636  1.1  christos 	if ((apr == NULL) || (apr->apr_flags & APR_DELETE) ||
    637  1.1  christos 	    (fin->fin_p != apr->apr_p))
    638  1.1  christos 		return 0;
    639  1.1  christos 	if ((tcp == NULL) && dport)
    640  1.1  christos 		return 0;
    641  1.1  christos 	return 1;
    642  1.1  christos }
    643  1.1  christos 
    644  1.1  christos 
    645  1.1  christos /* ------------------------------------------------------------------------ */
    646  1.1  christos /* Function:    ipf_proxy_ioctl                                             */
    647  1.1  christos /* Returns:     int - 0 == success, else error                              */
    648  1.1  christos /* Parameters:  fin(I) - pointer to packet information                      */
    649  1.1  christos /*              nat(I) - pointer to current NAT session                     */
    650  1.1  christos /*                                                                          */
    651  1.1  christos /* ------------------------------------------------------------------------ */
    652  1.1  christos int
    653  1.2  christos ipf_proxy_ioctl(ipf_main_softc_t *softc, void *data, ioctlcmd_t cmd, int mode,
    654  1.2  christos     void *ctx)
    655  1.1  christos {
    656  1.1  christos 	ap_ctl_t ctl;
    657  1.2  christos 	void *ptr;
    658  1.1  christos 	int error;
    659  1.1  christos 
    660  1.1  christos 	mode = mode;	/* LINT */
    661  1.1  christos 
    662  1.1  christos 	switch (cmd)
    663  1.1  christos 	{
    664  1.1  christos 	case SIOCPROXY :
    665  1.1  christos 		error = ipf_inobj(softc, data, NULL, &ctl, IPFOBJ_PROXYCTL);
    666  1.1  christos 		if (error != 0) {
    667  1.1  christos 			return error;
    668  1.1  christos 		}
    669  1.1  christos 		ptr = NULL;
    670  1.1  christos 
    671  1.1  christos 		if (ctl.apc_dsize > 0) {
    672  1.2  christos 			KMALLOCS(ptr, void *, ctl.apc_dsize);
    673  1.1  christos 			if (ptr == NULL) {
    674  1.1  christos 				IPFERROR(80003);
    675  1.1  christos 				error = ENOMEM;
    676  1.1  christos 			} else {
    677  1.1  christos 				error = copyinptr(softc, ctl.apc_data, ptr,
    678  1.1  christos 						  ctl.apc_dsize);
    679  1.1  christos 				if (error == 0)
    680  1.1  christos 					ctl.apc_data = ptr;
    681  1.1  christos 			}
    682  1.1  christos 		} else {
    683  1.1  christos 			ctl.apc_data = NULL;
    684  1.1  christos 			error = 0;
    685  1.1  christos 		}
    686  1.1  christos 
    687  1.1  christos 		if (error == 0)
    688  1.1  christos 			error = ipf_proxy_ctl(softc, softc->ipf_proxy_soft, &ctl);
    689  1.1  christos 
    690  1.1  christos 		if ((error != 0) && (ptr != NULL)) {
    691  1.1  christos 			KFREES(ptr, ctl.apc_dsize);
    692  1.1  christos 		}
    693  1.1  christos 		break;
    694  1.1  christos 
    695  1.1  christos 	default :
    696  1.1  christos 		IPFERROR(80004);
    697  1.1  christos 		error = EINVAL;
    698  1.1  christos 	}
    699  1.1  christos 	return error;
    700  1.1  christos }
    701  1.1  christos 
    702  1.1  christos 
    703  1.1  christos /* ------------------------------------------------------------------------ */
    704  1.1  christos /* Function:    ipf_proxy_match                                             */
    705  1.1  christos /* Returns:     int - -1 == error, 0 == success                             */
    706  1.1  christos /* Parameters:  fin(I) - pointer to packet information                      */
    707  1.1  christos /*              nat(I) - pointer to current NAT session                     */
    708  1.1  christos /*                                                                          */
    709  1.1  christos /* If a proxy has a match function, call that to do extended packet         */
    710  1.1  christos /* matching.                                                                */
    711  1.1  christos /* ------------------------------------------------------------------------ */
    712  1.1  christos int
    713  1.2  christos ipf_proxy_match(fr_info_t *fin, nat_t *nat)
    714  1.1  christos {
    715  1.1  christos 	ipf_main_softc_t *softc = fin->fin_main_soft;
    716  1.1  christos 	ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
    717  1.1  christos 	aproxy_t *apr;
    718  1.1  christos 	ipnat_t *ipn;
    719  1.1  christos 	int result;
    720  1.1  christos 
    721  1.1  christos 	ipn = nat->nat_ptr;
    722  1.1  christos 	if (softp->ips_proxy_debug > 8)
    723  1.1  christos 		printf("ipf_proxy_match(%lx,%lx) aps %lx ptr %lx\n",
    724  1.1  christos 			(u_long)fin, (u_long)nat, (u_long)nat->nat_aps,
    725  1.1  christos 			(u_long)ipn);
    726  1.1  christos 
    727  1.1  christos 	if ((fin->fin_flx & (FI_SHORT|FI_BAD)) != 0) {
    728  1.1  christos 		if (softp->ips_proxy_debug > 0)
    729  1.1  christos 			printf("ipf_proxy_match: flx 0x%x (BAD|SHORT)\n",
    730  1.1  christos 				fin->fin_flx);
    731  1.1  christos 		return -1;
    732  1.1  christos 	}
    733  1.1  christos 
    734  1.1  christos 	apr = ipn->in_apr;
    735  1.1  christos 	if ((apr == NULL) || (apr->apr_flags & APR_DELETE)) {
    736  1.1  christos 		if (softp->ips_proxy_debug > 0)
    737  1.1  christos 			printf("ipf_proxy_match:apr %lx apr_flags 0x%x\n",
    738  1.1  christos 				(u_long)apr, apr ? apr->apr_flags : 0);
    739  1.1  christos 		return -1;
    740  1.1  christos 	}
    741  1.1  christos 
    742  1.1  christos 	if (apr->apr_match != NULL) {
    743  1.1  christos 		result = (*apr->apr_match)(fin, nat->nat_aps, nat);
    744  1.1  christos 		if (result != 0) {
    745  1.1  christos 			if (softp->ips_proxy_debug > 4)
    746  1.1  christos 				printf("ipf_proxy_match: result %d\n", result);
    747  1.1  christos 			return -1;
    748  1.1  christos 		}
    749  1.1  christos 	}
    750  1.1  christos 	return 0;
    751  1.1  christos }
    752  1.1  christos 
    753  1.1  christos 
    754  1.1  christos /* ------------------------------------------------------------------------ */
    755  1.1  christos /* Function:    ipf_proxy_new                                               */
    756  1.1  christos /* Returns:     int - -1 == error, 0 == success                             */
    757  1.1  christos /* Parameters:  fin(I) - pointer to packet information                      */
    758  1.1  christos /*              nat(I) - pointer to current NAT session                     */
    759  1.1  christos /*                                                                          */
    760  1.1  christos /* Allocate a new application proxy structure and fill it in with the       */
    761  1.1  christos /* relevant details.  call the init function once complete, prior to        */
    762  1.1  christos /* returning.                                                               */
    763  1.1  christos /* ------------------------------------------------------------------------ */
    764  1.1  christos int
    765  1.2  christos ipf_proxy_new(fr_info_t *fin, nat_t *nat)
    766  1.1  christos {
    767  1.1  christos 	ipf_main_softc_t *softc = fin->fin_main_soft;
    768  1.1  christos 	ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
    769  1.1  christos 	register ap_session_t *aps;
    770  1.1  christos 	aproxy_t *apr;
    771  1.1  christos 
    772  1.1  christos 	if (softp->ips_proxy_debug > 8)
    773  1.1  christos 		printf("ipf_proxy_new(%lx,%lx) \n", (u_long)fin, (u_long)nat);
    774  1.1  christos 
    775  1.1  christos 	if ((nat->nat_ptr == NULL) || (nat->nat_aps != NULL)) {
    776  1.1  christos 		if (softp->ips_proxy_debug > 0)
    777  1.1  christos 			printf("ipf_proxy_new: nat_ptr %lx nat_aps %lx\n",
    778  1.1  christos 				(u_long)nat->nat_ptr, (u_long)nat->nat_aps);
    779  1.1  christos 		return -1;
    780  1.1  christos 	}
    781  1.1  christos 
    782  1.1  christos 	apr = nat->nat_ptr->in_apr;
    783  1.1  christos 
    784  1.1  christos 	if ((apr->apr_flags & APR_DELETE) ||
    785  1.1  christos 	    (fin->fin_p != apr->apr_p)) {
    786  1.1  christos 		if (softp->ips_proxy_debug > 2)
    787  1.1  christos 			printf("ipf_proxy_new: apr_flags 0x%x p %d/%d\n",
    788  1.1  christos 				apr->apr_flags, fin->fin_p, apr->apr_p);
    789  1.1  christos 		return -1;
    790  1.1  christos 	}
    791  1.1  christos 
    792  1.1  christos 	KMALLOC(aps, ap_session_t *);
    793  1.1  christos 	if (!aps) {
    794  1.1  christos 		if (softp->ips_proxy_debug > 0)
    795  1.1  christos 			printf("ipf_proxy_new: malloc failed (%lu)\n",
    796  1.1  christos 				(u_long)sizeof(ap_session_t));
    797  1.1  christos 		return -1;
    798  1.1  christos 	}
    799  1.1  christos 
    800  1.1  christos 	bzero((char *)aps, sizeof(*aps));
    801  1.1  christos 	aps->aps_data = NULL;
    802  1.1  christos 	aps->aps_apr = apr;
    803  1.1  christos 	aps->aps_psiz = 0;
    804  1.1  christos 	if (apr->apr_new != NULL)
    805  1.1  christos 		if ((*apr->apr_new)(apr->apr_soft, fin, aps, nat) == -1) {
    806  1.1  christos 			if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) {
    807  1.1  christos 				KFREES(aps->aps_data, aps->aps_psiz);
    808  1.1  christos 			}
    809  1.1  christos 			KFREE(aps);
    810  1.1  christos 			if (softp->ips_proxy_debug > 2)
    811  1.1  christos 				printf("ipf_proxy_new: new(%lx) failed\n",
    812  1.1  christos 					(u_long)apr->apr_new);
    813  1.1  christos 			return -1;
    814  1.1  christos 		}
    815  1.1  christos 	aps->aps_nat = nat;
    816  1.1  christos 	aps->aps_next = softp->ips_sess_list;
    817  1.1  christos 	softp->ips_sess_list = aps;
    818  1.1  christos 	nat->nat_aps = aps;
    819  1.1  christos 
    820  1.1  christos 	return 0;
    821  1.1  christos }
    822  1.1  christos 
    823  1.1  christos 
    824  1.1  christos /* ------------------------------------------------------------------------ */
    825  1.1  christos /* Function:    ipf_proxy_check                                             */
    826  1.1  christos /* Returns:     int - -1 == error, 0 == success                             */
    827  1.1  christos /* Parameters:  fin(I) - pointer to packet information                      */
    828  1.1  christos /*              nat(I) - pointer to current NAT session                     */
    829  1.1  christos /*                                                                          */
    830  1.1  christos /* Check to see if a packet should be passed through an active proxy        */
    831  1.1  christos /* routine if one has been setup for it.  We don't need to check the        */
    832  1.1  christos /* checksum here if IPFILTER_CKSUM is defined because if it is, a failed    */
    833  1.1  christos /* check causes FI_BAD to be set.                                           */
    834  1.1  christos /* ------------------------------------------------------------------------ */
    835  1.1  christos int
    836  1.2  christos ipf_proxy_check(fr_info_t *fin, nat_t *nat)
    837  1.1  christos {
    838  1.1  christos 	ipf_main_softc_t *softc = fin->fin_main_soft;
    839  1.1  christos 	ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
    840  1.1  christos #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
    841  1.1  christos # if defined(ICK_VALID)
    842  1.1  christos 	mb_t *m;
    843  1.1  christos # endif
    844  1.1  christos 	int dosum = 1;
    845  1.1  christos #endif
    846  1.1  christos 	tcphdr_t *tcp = NULL;
    847  1.1  christos 	udphdr_t *udp = NULL;
    848  1.1  christos 	ap_session_t *aps;
    849  1.1  christos 	aproxy_t *apr;
    850  1.1  christos 	ip_t *ip;
    851  1.1  christos 	short rv;
    852  1.1  christos 	int err;
    853  1.1  christos #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi)
    854  1.1  christos 	u_32_t s1, s2, sd;
    855  1.1  christos #endif
    856  1.1  christos 
    857  1.1  christos 	if (fin->fin_flx & FI_BAD) {
    858  1.1  christos 		if (softp->ips_proxy_debug > 0)
    859  1.1  christos 			printf("ipf_proxy_check: flx 0x%x (BAD)\n", fin->fin_flx);
    860  1.1  christos 		return -1;
    861  1.1  christos 	}
    862  1.1  christos 
    863  1.1  christos #ifndef IPFILTER_CKSUM
    864  1.1  christos 	if ((fin->fin_out == 0) && (ipf_checkl4sum(fin) == -1)) {
    865  1.1  christos 		if (softp->ips_proxy_debug > 0)
    866  1.1  christos 			printf("ipf_proxy_check: l4 checksum failure %d\n",
    867  1.1  christos 				fin->fin_p);
    868  1.1  christos 		if (fin->fin_p == IPPROTO_TCP)
    869  1.1  christos 			softc->ipf_stats[fin->fin_out].fr_tcpbad++;
    870  1.1  christos 		return -1;
    871  1.1  christos 	}
    872  1.1  christos #endif
    873  1.1  christos 
    874  1.1  christos 	aps = nat->nat_aps;
    875  1.1  christos 	if (aps != NULL) {
    876  1.1  christos 		/*
    877  1.1  christos 		 * If there is data in this packet to be proxied then try and
    878  1.1  christos 		 * get it all into the one buffer, else drop it.
    879  1.1  christos 		 */
    880  1.1  christos #if defined(MENTAT) || defined(HAVE_M_PULLDOWN)
    881  1.1  christos 		if ((fin->fin_dlen > 0) && !(fin->fin_flx & FI_COALESCE))
    882  1.1  christos 			if (ipf_coalesce(fin) == -1) {
    883  1.1  christos 				if (softp->ips_proxy_debug > 0)
    884  1.1  christos 					printf("ipf_proxy_check: coalesce failed %x\n", fin->fin_flx);
    885  1.1  christos 				return -1;
    886  1.1  christos 			}
    887  1.1  christos #endif
    888  1.1  christos 		ip = fin->fin_ip;
    889  1.1  christos 
    890  1.1  christos 		switch (fin->fin_p)
    891  1.1  christos 		{
    892  1.1  christos 		case IPPROTO_TCP :
    893  1.1  christos 			tcp = (tcphdr_t *)fin->fin_dp;
    894  1.1  christos 
    895  1.1  christos #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID)
    896  1.1  christos 			m = fin->fin_qfm;
    897  1.1  christos 			if (dohwcksum && (m->b_ick_flag == ICK_VALID))
    898  1.1  christos 				dosum = 0;
    899  1.1  christos #endif
    900  1.1  christos 			/*
    901  1.1  christos 			 * Don't bother the proxy with these...or in fact,
    902  1.1  christos 			 * should we free up proxy stuff when seen?
    903  1.1  christos 			 */
    904  1.1  christos 			if ((fin->fin_tcpf & TH_RST) != 0)
    905  1.1  christos 				break;
    906  1.1  christos 			/*FALLTHROUGH*/
    907  1.1  christos 		case IPPROTO_UDP :
    908  1.1  christos 			udp = (udphdr_t *)fin->fin_dp;
    909  1.1  christos 			break;
    910  1.1  christos 		default :
    911  1.1  christos 			break;
    912  1.1  christos 		}
    913  1.1  christos 
    914  1.1  christos 		apr = aps->aps_apr;
    915  1.1  christos 		err = 0;
    916  1.1  christos 		if (fin->fin_out != 0) {
    917  1.1  christos 			if (apr->apr_outpkt != NULL)
    918  1.1  christos 				err = (*apr->apr_outpkt)(apr->apr_soft, fin, aps, nat);
    919  1.1  christos 		} else {
    920  1.1  christos 			if (apr->apr_inpkt != NULL)
    921  1.1  christos 				err = (*apr->apr_inpkt)(apr->apr_soft, fin, aps, nat);
    922  1.1  christos 		}
    923  1.1  christos 
    924  1.1  christos 		rv = APR_EXIT(err);
    925  1.1  christos 		if (((softp->ips_proxy_debug > 0) && (rv != 0)) ||
    926  1.1  christos 		    (softp->ips_proxy_debug > 8))
    927  1.1  christos 			printf("ipf_proxy_check: out %d err %x rv %d\n",
    928  1.1  christos 				fin->fin_out, err, rv);
    929  1.1  christos 		if (rv == 1)
    930  1.1  christos 			return -1;
    931  1.1  christos 
    932  1.1  christos 		if (rv == 2) {
    933  1.1  christos 			ipf_proxy_free(apr);
    934  1.1  christos 			nat->nat_aps = NULL;
    935  1.1  christos 			return -1;
    936  1.1  christos 		}
    937  1.1  christos 
    938  1.1  christos 		/*
    939  1.1  christos 		 * If err != 0 then the data size of the packet has changed
    940  1.1  christos 		 * so we need to recalculate the header checksums for the
    941  1.1  christos 		 * packet.
    942  1.1  christos 		 */
    943  1.1  christos #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi)
    944  1.1  christos 		if (err != 0) {
    945  1.1  christos 			short adjlen = err & 0xffff;
    946  1.1  christos 
    947  1.1  christos 			s1 = LONG_SUM(fin->fin_plen - adjlen);
    948  1.1  christos 			s2 = LONG_SUM(fin->fin_plen);
    949  1.1  christos 			CALC_SUMD(s1, s2, sd);
    950  1.1  christos 			ipf_fix_outcksum(fin, &ip->ip_sum, sd);
    951  1.1  christos 		}
    952  1.1  christos #endif
    953  1.1  christos 
    954  1.2  christos #ifdef INET
    955  1.1  christos 		/*
    956  1.1  christos 		 * For TCP packets, we may need to adjust the sequence and
    957  1.1  christos 		 * acknowledgement numbers to reflect changes in size of the
    958  1.1  christos 		 * data stream.
    959  1.1  christos 		 *
    960  1.1  christos 		 * For both TCP and UDP, recalculate the layer 4 checksum,
    961  1.1  christos 		 * regardless, as we can't tell (here) if data has been
    962  1.1  christos 		 * changed or not.
    963  1.1  christos 		 */
    964  1.1  christos 		if (tcp != NULL) {
    965  1.1  christos 			err = ipf_proxy_fixseqack(fin, ip, aps, APR_INC(err));
    966  1.1  christos #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
    967  1.1  christos 			if (dosum)
    968  1.1  christos #endif
    969  1.1  christos 				tcp->th_sum = fr_cksum(fin, ip,
    970  1.1  christos 						       IPPROTO_TCP, tcp);
    971  1.1  christos 		} else if ((udp != NULL) && (udp->uh_sum != 0)) {
    972  1.1  christos #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
    973  1.1  christos 			if (dosum)
    974  1.1  christos #endif
    975  1.1  christos 				udp->uh_sum = fr_cksum(fin, ip,
    976  1.1  christos 						       IPPROTO_UDP, udp);
    977  1.1  christos 		}
    978  1.2  christos #endif
    979  1.1  christos 		aps->aps_bytes += fin->fin_plen;
    980  1.1  christos 		aps->aps_pkts++;
    981  1.1  christos 		return 1;
    982  1.1  christos 	}
    983  1.1  christos 	return 0;
    984  1.1  christos }
    985  1.1  christos 
    986  1.1  christos 
    987  1.1  christos /* ------------------------------------------------------------------------ */
    988  1.1  christos /* Function:    ipf_proxy_lookup                                            */
    989  1.1  christos /* Returns:     int - -1 == error, 0 == success                             */
    990  1.1  christos /* Parameters:  fin(I) - pointer to packet information                      */
    991  1.1  christos /*              nat(I) - pointer to current NAT session                     */
    992  1.1  christos /*                                                                          */
    993  1.1  christos /* Search for an proxy by the protocol it is being used with and its name.  */
    994  1.1  christos /* ------------------------------------------------------------------------ */
    995  1.1  christos aproxy_t *
    996  1.2  christos ipf_proxy_lookup(void *arg, u_int pr, char *name)
    997  1.1  christos {
    998  1.1  christos 	ipf_proxy_softc_t *softp = arg;
    999  1.1  christos 	aproxy_t *ap;
   1000  1.1  christos 
   1001  1.1  christos 	if (softp->ips_proxy_debug > 8)
   1002  1.1  christos 		printf("ipf_proxy_lookup(%d,%s)\n", pr, name);
   1003  1.1  christos 
   1004  1.1  christos 	for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next)
   1005  1.1  christos 		if ((ap->apr_p == pr) &&
   1006  1.1  christos 		    !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) {
   1007  1.1  christos 			ap->apr_ref++;
   1008  1.1  christos 			return ap;
   1009  1.1  christos 		}
   1010  1.1  christos 
   1011  1.1  christos 	if (softp->ips_proxy_debug > 2)
   1012  1.1  christos 		printf("ipf_proxy_lookup: failed for %d/%s\n", pr, name);
   1013  1.1  christos 	return NULL;
   1014  1.1  christos }
   1015  1.1  christos 
   1016  1.1  christos 
   1017  1.1  christos /* ------------------------------------------------------------------------ */
   1018  1.1  christos /* Function:    ipf_proxy_free                                              */
   1019  1.1  christos /* Returns:     Nil                                                         */
   1020  1.1  christos /* Parameters:  ap(I) - pointer to proxy structure                          */
   1021  1.1  christos /*                                                                          */
   1022  1.1  christos /* ------------------------------------------------------------------------ */
   1023  1.1  christos void
   1024  1.2  christos ipf_proxy_free(aproxy_t *ap)
   1025  1.1  christos {
   1026  1.1  christos 	ap->apr_ref--;
   1027  1.1  christos }
   1028  1.1  christos 
   1029  1.1  christos 
   1030  1.1  christos /* ------------------------------------------------------------------------ */
   1031  1.1  christos /* Function:    aps_free                                                    */
   1032  1.1  christos /* Returns:     Nil                                                         */
   1033  1.1  christos /* Parameters:  fin(I) - pointer to packet information                      */
   1034  1.1  christos /*              nat(I) - pointer to current NAT session                     */
   1035  1.1  christos /*                                                                          */
   1036  1.1  christos /* Locks Held:  ipf_nat_new, ipf_nat(W)                                     */
   1037  1.1  christos /* ------------------------------------------------------------------------ */
   1038  1.1  christos void
   1039  1.2  christos aps_free(ipf_main_softc_t *softc, void *arg, ap_session_t *aps)
   1040  1.1  christos {
   1041  1.1  christos 	ipf_proxy_softc_t *softp = arg;
   1042  1.1  christos 	ap_session_t *a, **ap;
   1043  1.1  christos 	aproxy_t *apr;
   1044  1.1  christos 
   1045  1.1  christos 	if (!aps)
   1046  1.1  christos 		return;
   1047  1.1  christos 
   1048  1.1  christos 	for (ap = &softp->ips_sess_list; ((a = *ap) != NULL); ap = &a->aps_next)
   1049  1.1  christos 		if (a == aps) {
   1050  1.1  christos 			*ap = a->aps_next;
   1051  1.1  christos 			break;
   1052  1.1  christos 		}
   1053  1.1  christos 
   1054  1.1  christos 	apr = aps->aps_apr;
   1055  1.1  christos 	if ((apr != NULL) && (apr->apr_del != NULL))
   1056  1.1  christos 		(*apr->apr_del)(softc, aps);
   1057  1.1  christos 
   1058  1.1  christos 	if ((aps->aps_data != NULL) && (aps->aps_psiz != 0))
   1059  1.1  christos 		KFREES(aps->aps_data, aps->aps_psiz);
   1060  1.1  christos 	KFREE(aps);
   1061  1.1  christos }
   1062  1.1  christos 
   1063  1.1  christos 
   1064  1.1  christos /* ------------------------------------------------------------------------ */
   1065  1.1  christos /* Function:    ipf_proxy_fixseqack                                         */
   1066  1.1  christos /* Returns:     int -  2 if TCP ack/seq is changed, else 0                  */
   1067  1.1  christos /* Parameters:  fin(I) - pointer to packet information                      */
   1068  1.1  christos /*              nat(I) - pointer to current NAT session                     */
   1069  1.1  christos /*                                                                          */
   1070  1.1  christos /* ------------------------------------------------------------------------ */
   1071  1.1  christos static int
   1072  1.2  christos ipf_proxy_fixseqack(fr_info_t *fin, ip_t *ip, ap_session_t *aps, int inc)
   1073  1.1  christos {
   1074  1.1  christos 	ipf_main_softc_t *softc = fin->fin_main_soft;
   1075  1.1  christos 	ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
   1076  1.1  christos 	int sel, ch = 0, out, nlen;
   1077  1.1  christos 	u_32_t seq1, seq2;
   1078  1.1  christos 	tcphdr_t *tcp;
   1079  1.1  christos 	short inc2;
   1080  1.1  christos 
   1081  1.1  christos 	tcp = (tcphdr_t *)fin->fin_dp;
   1082  1.1  christos 	out = fin->fin_out;
   1083  1.1  christos 	/*
   1084  1.1  christos 	 * ip_len has already been adjusted by 'inc'.
   1085  1.1  christos 	 */
   1086  1.1  christos 	nlen = fin->fin_plen;
   1087  1.1  christos 	nlen -= (IP_HL(ip) << 2) + (TCP_OFF(tcp) << 2);
   1088  1.1  christos 
   1089  1.1  christos 	inc2 = inc;
   1090  1.1  christos 	inc = (int)inc2;
   1091  1.1  christos 
   1092  1.1  christos 	if (out != 0) {
   1093  1.1  christos 		seq1 = (u_32_t)ntohl(tcp->th_seq);
   1094  1.1  christos 		sel = aps->aps_sel[out];
   1095  1.1  christos 
   1096  1.1  christos 		/* switch to other set ? */
   1097  1.1  christos 		if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) &&
   1098  1.1  christos 		    (seq1 > aps->aps_seqmin[!sel])) {
   1099  1.1  christos 			if (softp->ips_proxy_debug > 7)
   1100  1.1  christos 				printf("proxy out switch set seq %d -> %d %x > %x\n",
   1101  1.1  christos 					sel, !sel, seq1,
   1102  1.1  christos 					aps->aps_seqmin[!sel]);
   1103  1.1  christos 			sel = aps->aps_sel[out] = !sel;
   1104  1.1  christos 		}
   1105  1.1  christos 
   1106  1.1  christos 		if (aps->aps_seqoff[sel]) {
   1107  1.1  christos 			seq2 = aps->aps_seqmin[sel] - aps->aps_seqoff[sel];
   1108  1.1  christos 			if (seq1 > seq2) {
   1109  1.1  christos 				seq2 = aps->aps_seqoff[sel];
   1110  1.1  christos 				seq1 += seq2;
   1111  1.1  christos 				tcp->th_seq = htonl(seq1);
   1112  1.1  christos 				ch = 1;
   1113  1.1  christos 			}
   1114  1.1  christos 		}
   1115  1.1  christos 
   1116  1.1  christos 		if (inc && (seq1 > aps->aps_seqmin[!sel])) {
   1117  1.1  christos 			aps->aps_seqmin[sel] = seq1 + nlen - 1;
   1118  1.1  christos 			aps->aps_seqoff[sel] = aps->aps_seqoff[sel] + inc;
   1119  1.1  christos 			if (softp->ips_proxy_debug > 7)
   1120  1.1  christos 				printf("proxy seq set %d at %x to %d + %d\n",
   1121  1.1  christos 					sel, aps->aps_seqmin[sel],
   1122  1.1  christos 					aps->aps_seqoff[sel], inc);
   1123  1.1  christos 		}
   1124  1.1  christos 
   1125  1.1  christos 		/***/
   1126  1.1  christos 
   1127  1.1  christos 		seq1 = ntohl(tcp->th_ack);
   1128  1.1  christos 		sel = aps->aps_sel[1 - out];
   1129  1.1  christos 
   1130  1.1  christos 		/* switch to other set ? */
   1131  1.1  christos 		if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) &&
   1132  1.1  christos 		    (seq1 > aps->aps_ackmin[!sel])) {
   1133  1.1  christos 			if (softp->ips_proxy_debug > 7)
   1134  1.1  christos 				printf("proxy out switch set ack %d -> %d %x > %x\n",
   1135  1.1  christos 					sel, !sel, seq1,
   1136  1.1  christos 					aps->aps_ackmin[!sel]);
   1137  1.1  christos 			sel = aps->aps_sel[1 - out] = !sel;
   1138  1.1  christos 		}
   1139  1.1  christos 
   1140  1.1  christos 		if (aps->aps_ackoff[sel] && (seq1 > aps->aps_ackmin[sel])) {
   1141  1.1  christos 			seq2 = aps->aps_ackoff[sel];
   1142  1.1  christos 			tcp->th_ack = htonl(seq1 - seq2);
   1143  1.1  christos 			ch = 1;
   1144  1.1  christos 		}
   1145  1.1  christos 	} else {
   1146  1.1  christos 		seq1 = ntohl(tcp->th_seq);
   1147  1.1  christos 		sel = aps->aps_sel[out];
   1148  1.1  christos 
   1149  1.1  christos 		/* switch to other set ? */
   1150  1.1  christos 		if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) &&
   1151  1.1  christos 		    (seq1 > aps->aps_ackmin[!sel])) {
   1152  1.1  christos 			if (softp->ips_proxy_debug > 7)
   1153  1.1  christos 				printf("proxy in switch set ack %d -> %d %x > %x\n",
   1154  1.1  christos 					sel, !sel, seq1, aps->aps_ackmin[!sel]);
   1155  1.1  christos 			sel = aps->aps_sel[out] = !sel;
   1156  1.1  christos 		}
   1157  1.1  christos 
   1158  1.1  christos 		if (aps->aps_ackoff[sel]) {
   1159  1.1  christos 			seq2 = aps->aps_ackmin[sel] - aps->aps_ackoff[sel];
   1160  1.1  christos 			if (seq1 > seq2) {
   1161  1.1  christos 				seq2 = aps->aps_ackoff[sel];
   1162  1.1  christos 				seq1 += seq2;
   1163  1.1  christos 				tcp->th_seq = htonl(seq1);
   1164  1.1  christos 				ch = 1;
   1165  1.1  christos 			}
   1166  1.1  christos 		}
   1167  1.1  christos 
   1168  1.1  christos 		if (inc && (seq1 > aps->aps_ackmin[!sel])) {
   1169  1.1  christos 			aps->aps_ackmin[!sel] = seq1 + nlen - 1;
   1170  1.1  christos 			aps->aps_ackoff[!sel] = aps->aps_ackoff[sel] + inc;
   1171  1.1  christos 
   1172  1.1  christos 			if (softp->ips_proxy_debug > 7)
   1173  1.1  christos 				printf("proxy ack set %d at %x to %d + %d\n",
   1174  1.1  christos 					!sel, aps->aps_seqmin[!sel],
   1175  1.1  christos 					aps->aps_seqoff[sel], inc);
   1176  1.1  christos 		}
   1177  1.1  christos 
   1178  1.1  christos 		/***/
   1179  1.1  christos 
   1180  1.1  christos 		seq1 = ntohl(tcp->th_ack);
   1181  1.1  christos 		sel = aps->aps_sel[1 - out];
   1182  1.1  christos 
   1183  1.1  christos 		/* switch to other set ? */
   1184  1.1  christos 		if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) &&
   1185  1.1  christos 		    (seq1 > aps->aps_seqmin[!sel])) {
   1186  1.1  christos 			if (softp->ips_proxy_debug > 7)
   1187  1.1  christos 				printf("proxy in switch set seq %d -> %d %x > %x\n",
   1188  1.1  christos 					sel, !sel, seq1, aps->aps_seqmin[!sel]);
   1189  1.1  christos 			sel = aps->aps_sel[1 - out] = !sel;
   1190  1.1  christos 		}
   1191  1.1  christos 
   1192  1.1  christos 		if (aps->aps_seqoff[sel] != 0) {
   1193  1.1  christos 			if (softp->ips_proxy_debug > 7)
   1194  1.1  christos 				printf("sel %d seqoff %d seq1 %x seqmin %x\n",
   1195  1.1  christos 					sel, aps->aps_seqoff[sel], seq1,
   1196  1.1  christos 					aps->aps_seqmin[sel]);
   1197  1.1  christos 			if (seq1 > aps->aps_seqmin[sel]) {
   1198  1.1  christos 				seq2 = aps->aps_seqoff[sel];
   1199  1.1  christos 				tcp->th_ack = htonl(seq1 - seq2);
   1200  1.1  christos 				ch = 1;
   1201  1.1  christos 			}
   1202  1.1  christos 		}
   1203  1.1  christos 	}
   1204  1.1  christos 
   1205  1.1  christos 	if (softp->ips_proxy_debug > 8)
   1206  1.1  christos 		printf("ipf_proxy_fixseqack: seq %x ack %x\n",
   1207  1.1  christos 			(u_32_t)ntohl(tcp->th_seq), (u_32_t)ntohl(tcp->th_ack));
   1208  1.1  christos 	return ch ? 2 : 0;
   1209  1.1  christos }
   1210