1*5b28f239Srillig /* $NetBSD: ip_proxy.c,v 1.8 2024/09/08 09:36:51 rillig Exp $ */ 2c2aa585cSchristos 3c2aa585cSchristos /* 4c2aa585cSchristos * Copyright (C) 2012 by Darren Reed. 5c2aa585cSchristos * 6c2aa585cSchristos * See the IPFILTER.LICENCE file for details on licencing. 7c2aa585cSchristos */ 8c2aa585cSchristos #if defined(KERNEL) || defined(_KERNEL) 9c2aa585cSchristos # undef KERNEL 10c2aa585cSchristos # undef _KERNEL 11c2aa585cSchristos # define KERNEL 1 12c2aa585cSchristos # define _KERNEL 1 13c2aa585cSchristos #endif 14c2aa585cSchristos #include <sys/errno.h> 15c2aa585cSchristos #include <sys/types.h> 16c2aa585cSchristos #include <sys/param.h> 17c2aa585cSchristos #include <sys/time.h> 18c2aa585cSchristos #include <sys/file.h> 19c2aa585cSchristos #if !defined(AIX) 20c2aa585cSchristos # include <sys/fcntl.h> 21c2aa585cSchristos #endif 22c2aa585cSchristos #if !defined(_KERNEL) && !defined(__KERNEL__) 23c2aa585cSchristos # include <stdio.h> 24c2aa585cSchristos # include <string.h> 25c2aa585cSchristos # include <stdlib.h> 26c2aa585cSchristos # include <ctype.h> 27c2aa585cSchristos # define _KERNEL 28c2aa585cSchristos # ifdef __OpenBSD__ 29c2aa585cSchristos struct file; 30c2aa585cSchristos # endif 31c2aa585cSchristos # include <sys/uio.h> 32c2aa585cSchristos # undef _KERNEL 33c2aa585cSchristos #endif 34c2aa585cSchristos #if !defined(linux) 35c2aa585cSchristos # include <sys/protosw.h> 36c2aa585cSchristos #endif 37c2aa585cSchristos #include <sys/socket.h> 38c2aa585cSchristos #if defined(_KERNEL) 39c2aa585cSchristos # if !defined(__NetBSD__) && !defined(sun) && !defined(__osf__) && \ 40c2aa585cSchristos !defined(__OpenBSD__) && !defined(__hpux) && !defined(__sgi) && \ 41c2aa585cSchristos !defined(AIX) 42c2aa585cSchristos # include <sys/ctype.h> 43c2aa585cSchristos # endif 44c2aa585cSchristos # include <sys/systm.h> 45c2aa585cSchristos # if !defined(__SVR4) && !defined(__svr4__) 46c2aa585cSchristos # include <sys/mbuf.h> 47c2aa585cSchristos # endif 48c2aa585cSchristos #endif 49c2aa585cSchristos #if defined(_KERNEL) && (__FreeBSD_version >= 220000) 50c2aa585cSchristos # include <sys/filio.h> 51c2aa585cSchristos # include <sys/fcntl.h> 52c2aa585cSchristos #else 53c2aa585cSchristos # include <sys/ioctl.h> 54c2aa585cSchristos #endif 55c2aa585cSchristos #if defined(__SVR4) || defined(__svr4__) 56c2aa585cSchristos # include <sys/byteorder.h> 57c2aa585cSchristos # ifdef _KERNEL 58c2aa585cSchristos # include <sys/dditypes.h> 59c2aa585cSchristos # endif 60c2aa585cSchristos # include <sys/stream.h> 61c2aa585cSchristos # include <sys/kmem.h> 62c2aa585cSchristos #endif 63c2aa585cSchristos #if __FreeBSD__ > 2 64c2aa585cSchristos # include <sys/queue.h> 65c2aa585cSchristos #endif 66c2aa585cSchristos #include <net/if.h> 67c2aa585cSchristos #ifdef sun 68c2aa585cSchristos # include <net/af.h> 69c2aa585cSchristos #endif 70c2aa585cSchristos #include <netinet/in.h> 71c2aa585cSchristos #include <netinet/in_systm.h> 72c2aa585cSchristos #include <netinet/ip.h> 73c2aa585cSchristos #ifndef linux 74c2aa585cSchristos # include <netinet/ip_var.h> 75c2aa585cSchristos #endif 76c2aa585cSchristos #include <netinet/tcp.h> 77c2aa585cSchristos #include <netinet/udp.h> 78c2aa585cSchristos #include <netinet/ip_icmp.h> 79c2aa585cSchristos #include "netinet/ip_compat.h" 80c2aa585cSchristos #include "netinet/ip_fil.h" 81c2aa585cSchristos #include "netinet/ip_nat.h" 82c2aa585cSchristos #include "netinet/ip_state.h" 83c2aa585cSchristos #include "netinet/ip_proxy.h" 84c2aa585cSchristos #if (__FreeBSD_version >= 300000) 85c2aa585cSchristos # include <sys/malloc.h> 86c2aa585cSchristos #endif 87c2aa585cSchristos 88c2aa585cSchristos /* END OF INCLUDES */ 89c2aa585cSchristos 900c6adecaSchristos #include "netinet/ip_dns_pxy.c" 91c2aa585cSchristos #include "netinet/ip_ftp_pxy.c" 92c2aa585cSchristos #include "netinet/ip_tftp_pxy.c" 93c2aa585cSchristos #include "netinet/ip_rcmd_pxy.c" 94c2aa585cSchristos #include "netinet/ip_pptp_pxy.c" 95c2aa585cSchristos #if defined(_KERNEL) 96c2aa585cSchristos # include "netinet/ip_irc_pxy.c" 97c2aa585cSchristos # include "netinet/ip_raudio_pxy.c" 98c2aa585cSchristos # include "netinet/ip_netbios_pxy.c" 99c2aa585cSchristos #endif 100c2aa585cSchristos #include "netinet/ip_ipsec_pxy.c" 101c2aa585cSchristos #include "netinet/ip_rpcb_pxy.c" 102c2aa585cSchristos 103c2aa585cSchristos #if !defined(lint) 1040c6adecaSchristos #if defined(__NetBSD__) 1050c6adecaSchristos #include <sys/cdefs.h> 106*5b28f239Srillig __KERNEL_RCSID(0, "$NetBSD: ip_proxy.c,v 1.8 2024/09/08 09:36:51 rillig Exp $"); 1070c6adecaSchristos #else 10813885a66Sdarrenr static const char rcsid[] = "@(#)Id: ip_proxy.c,v 1.1.1.2 2012/07/22 13:45:33 darrenr Exp"; 1090c6adecaSchristos #endif 110c2aa585cSchristos #endif 111c2aa585cSchristos 112c2aa585cSchristos #define AP_SESS_SIZE 53 113c2aa585cSchristos 1140c6adecaSchristos static int ipf_proxy_fixseqack(fr_info_t *, ip_t *, ap_session_t *, int ); 1150c6adecaSchristos static aproxy_t *ipf_proxy_create_clone(ipf_main_softc_t *, aproxy_t *); 116c2aa585cSchristos 117c2aa585cSchristos typedef struct ipf_proxy_softc_s { 118c2aa585cSchristos int ips_proxy_debug; 119c2aa585cSchristos int ips_proxy_session_size; 120c2aa585cSchristos ap_session_t **ips_sess_tab; 121c2aa585cSchristos ap_session_t *ips_sess_list; 122c2aa585cSchristos aproxy_t *ips_proxies; 123c2aa585cSchristos int ips_init_run; 124c2aa585cSchristos ipftuneable_t *ipf_proxy_tune; 125c2aa585cSchristos } ipf_proxy_softc_t; 126c2aa585cSchristos 127af97d7beSmaxv static const ipftuneable_t ipf_proxy_tuneables[] = { 128c2aa585cSchristos { { (void *)offsetof(ipf_proxy_softc_t, ips_proxy_debug) }, 12913885a66Sdarrenr "proxy_debug", 0, 0x1f, 130c2aa585cSchristos stsizeof(ipf_proxy_softc_t, ips_proxy_debug), 131c2aa585cSchristos 0, NULL, NULL }, 132c2aa585cSchristos { { NULL }, NULL, 0, 0, 133c2aa585cSchristos 0, 134c2aa585cSchristos 0, NULL, NULL} 135c2aa585cSchristos }; 136c2aa585cSchristos 137c2aa585cSchristos static aproxy_t *ap_proxylist = NULL; 138c2aa585cSchristos static aproxy_t ips_proxies[] = { 139c2aa585cSchristos #ifdef IPF_FTP_PROXY 140c2aa585cSchristos { NULL, NULL, "ftp", (char)IPPROTO_TCP, 0, 0, 0, 141c2aa585cSchristos ipf_p_ftp_main_load, ipf_p_ftp_main_unload, 142c2aa585cSchristos ipf_p_ftp_soft_create, ipf_p_ftp_soft_destroy, 143c2aa585cSchristos NULL, NULL, 144c2aa585cSchristos ipf_p_ftp_new, ipf_p_ftp_del, ipf_p_ftp_in, ipf_p_ftp_out, NULL, 145c2aa585cSchristos NULL, NULL, NULL, NULL }, 146c2aa585cSchristos #endif 147c2aa585cSchristos #ifdef IPF_TFTP_PROXY 14813885a66Sdarrenr { NULL, NULL, "tftp", (char)IPPROTO_UDP, 0, 0, 0, 149c2aa585cSchristos ipf_p_tftp_main_load, ipf_p_tftp_main_unload, 15013885a66Sdarrenr ipf_p_tftp_soft_create, ipf_p_tftp_soft_destroy, 151c2aa585cSchristos NULL, NULL, 15213885a66Sdarrenr ipf_p_tftp_new, ipf_p_tftp_del, 15313885a66Sdarrenr ipf_p_tftp_in, ipf_p_tftp_out, NULL, 154c2aa585cSchristos NULL, NULL, NULL, NULL }, 155c2aa585cSchristos #endif 156c2aa585cSchristos #ifdef IPF_IRC_PROXY 157c2aa585cSchristos { NULL, NULL, "irc", (char)IPPROTO_TCP, 0, 0, 0, 158c2aa585cSchristos ipf_p_irc_main_load, ipf_p_irc_main_unload, 159c2aa585cSchristos NULL, NULL, 160c2aa585cSchristos NULL, NULL, 161c2aa585cSchristos ipf_p_irc_new, NULL, NULL, ipf_p_irc_out, NULL, 162c2aa585cSchristos NULL, NULL, NULL, NULL }, 163c2aa585cSchristos #endif 164c2aa585cSchristos #ifdef IPF_RCMD_PROXY 165c2aa585cSchristos { NULL, NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, 0, 166c2aa585cSchristos ipf_p_rcmd_main_load, ipf_p_rcmd_main_unload, 167c2aa585cSchristos NULL, NULL, 168c2aa585cSchristos NULL, NULL, 169c2aa585cSchristos ipf_p_rcmd_new, ipf_p_rcmd_del, 170c2aa585cSchristos ipf_p_rcmd_in, ipf_p_rcmd_out, NULL, 171c2aa585cSchristos NULL, NULL, NULL, NULL }, 172c2aa585cSchristos #endif 173c2aa585cSchristos #ifdef IPF_RAUDIO_PROXY 174c2aa585cSchristos { NULL, NULL, "raudio", (char)IPPROTO_TCP, 0, 0, 0, 175c2aa585cSchristos ipf_p_raudio_main_load, ipf_p_raudio_main_unload, 176c2aa585cSchristos NULL, NULL, 177c2aa585cSchristos NULL, NULL, 178c2aa585cSchristos ipf_p_raudio_new, NULL, ipf_p_raudio_in, ipf_p_raudio_out, NULL, 179c2aa585cSchristos NULL, NULL, NULL, NULL }, 180c2aa585cSchristos #endif 181c2aa585cSchristos #ifdef IPF_MSNRPC_PROXY 182c2aa585cSchristos { NULL, NULL, "msnrpc", (char)IPPROTO_TCP, 0, 0, 0, 183c2aa585cSchristos ipf_p_msnrpc_init, ipf_p_msnrpc_fini, 184c2aa585cSchristos NULL, NULL, 185c2aa585cSchristos NULL, NULL, 186c2aa585cSchristos ipf_p_msnrpc_new, NULL, ipf_p_msnrpc_in, ipf_p_msnrpc_out, NULL, 187c2aa585cSchristos NULL, NULL, NULL, NULL }, 188c2aa585cSchristos #endif 189c2aa585cSchristos #ifdef IPF_NETBIOS_PROXY 190c2aa585cSchristos { NULL, NULL, "netbios", (char)IPPROTO_UDP, 0, 0, 0, 191c2aa585cSchristos ipf_p_netbios_main_load, ipf_p_netbios_main_unload, 192c2aa585cSchristos NULL, NULL, 193c2aa585cSchristos NULL, NULL, 194c2aa585cSchristos NULL, NULL, NULL, ipf_p_netbios_out, NULL, 195c2aa585cSchristos NULL, NULL, NULL, NULL }, 196c2aa585cSchristos #endif 197c2aa585cSchristos #ifdef IPF_IPSEC_PROXY 198c2aa585cSchristos { NULL, NULL, "ipsec", (char)IPPROTO_UDP, 0, 0, 0, 199c2aa585cSchristos NULL, NULL, 200c2aa585cSchristos ipf_p_ipsec_soft_create, ipf_p_ipsec_soft_destroy, 201c2aa585cSchristos ipf_p_ipsec_soft_init, ipf_p_ipsec_soft_fini, 202c2aa585cSchristos ipf_p_ipsec_new, ipf_p_ipsec_del, 203c2aa585cSchristos ipf_p_ipsec_inout, ipf_p_ipsec_inout, ipf_p_ipsec_match, 204c2aa585cSchristos NULL, NULL, NULL, NULL }, 205c2aa585cSchristos #endif 206c2aa585cSchristos #ifdef IPF_DNS_PROXY 207c2aa585cSchristos { NULL, NULL, "dns", (char)IPPROTO_UDP, 0, 0, 0, 208c2aa585cSchristos NULL, NULL, 209c2aa585cSchristos ipf_p_dns_soft_create, ipf_p_dns_soft_destroy, 210c2aa585cSchristos NULL, NULL, 211c2aa585cSchristos ipf_p_dns_new, ipf_p_ipsec_del, 212c2aa585cSchristos ipf_p_dns_inout, ipf_p_dns_inout, ipf_p_dns_match, 213c2aa585cSchristos ipf_p_dns_ctl, NULL, NULL, NULL }, 214c2aa585cSchristos #endif 215c2aa585cSchristos #ifdef IPF_PPTP_PROXY 216c2aa585cSchristos { NULL, NULL, "pptp", (char)IPPROTO_TCP, 0, 0, 0, 217c2aa585cSchristos ipf_p_pptp_main_load, ipf_p_pptp_main_unload, 218c2aa585cSchristos NULL, NULL, 219c2aa585cSchristos NULL, NULL, 220c2aa585cSchristos ipf_p_pptp_new, ipf_p_pptp_del, 221c2aa585cSchristos ipf_p_pptp_inout, ipf_p_pptp_inout, NULL, 222c2aa585cSchristos NULL, NULL, NULL, NULL }, 223c2aa585cSchristos #endif 2240c6adecaSchristos #ifdef IPF_H323_PROXY 2250c6adecaSchristos { NULL, NULL, "h323", (char)IPPROTO_TCP, 0, 0, 0, 2260c6adecaSchristos ipf_p_h323_main_load, ipf_p_h323_main_unload, 2270c6adecaSchristos NULL, NULL, 2280c6adecaSchristos NULL, NULL, 2290c6adecaSchristos ipf_p_h323_new, ipf_p_h323_del, 2300c6adecaSchristos ipf_p_h323_in, NULL, NULL, 2310c6adecaSchristos NULL, NULL, NULL, NULL }, 2320c6adecaSchristos { NULL, NULL, "h245", (char)IPPROTO_TCP, 0, 0, 0, NULL, NULL, 2330c6adecaSchristos NULL, NULL, 2340c6adecaSchristos NULL, NULL, 2350c6adecaSchristos ipf_p_h245_new, NULL, 2360c6adecaSchristos NULL, ipf_p_h245_out, NULL, 2370c6adecaSchristos NULL, NULL, NULL, NULL }, 2380c6adecaSchristos #endif 239c2aa585cSchristos #ifdef IPF_RPCB_PROXY 240c2aa585cSchristos # ifndef _KERNEL 241c2aa585cSchristos { NULL, NULL, "rpcbt", (char)IPPROTO_TCP, 0, 0, 0, 242c2aa585cSchristos NULL, NULL, 243c2aa585cSchristos NULL, NULL, 244c2aa585cSchristos NULL, NULL, 245c2aa585cSchristos ipf_p_rpcb_new, ipf_p_rpcb_del, 246c2aa585cSchristos ipf_p_rpcb_in, ipf_p_rpcb_out, NULL, 247c2aa585cSchristos NULL, NULL, NULL, NULL }, 248c2aa585cSchristos # endif 249c2aa585cSchristos { NULL, NULL, "rpcbu", (char)IPPROTO_UDP, 0, 0, 0, 250c2aa585cSchristos ipf_p_rpcb_main_load, ipf_p_rpcb_main_unload, 251c2aa585cSchristos NULL, NULL, 252c2aa585cSchristos NULL, NULL, 253c2aa585cSchristos ipf_p_rpcb_new, ipf_p_rpcb_del, 254c2aa585cSchristos ipf_p_rpcb_in, ipf_p_rpcb_out, NULL, 255c2aa585cSchristos NULL, NULL, NULL, NULL }, 256c2aa585cSchristos #endif 257c2aa585cSchristos { NULL, NULL, "", '\0', 0, 0, 0, 258c2aa585cSchristos NULL, NULL, 259c2aa585cSchristos NULL, NULL, 260c2aa585cSchristos NULL, NULL, 261c2aa585cSchristos NULL, NULL, 262c2aa585cSchristos NULL, NULL, NULL, 263c2aa585cSchristos NULL, NULL, NULL, NULL } 264c2aa585cSchristos }; 265c2aa585cSchristos 266c2aa585cSchristos 267c2aa585cSchristos /* ------------------------------------------------------------------------ */ 26813885a66Sdarrenr /* Function: ipf_proxy_main_load */ 26913885a66Sdarrenr /* Returns: int - 0 == success, else failure. */ 27013885a66Sdarrenr /* Parameters: Nil */ 271c2aa585cSchristos /* */ 272c2aa585cSchristos /* Initialise hook for kernel application proxies. */ 273c2aa585cSchristos /* Call the initialise routine for all the compiled in kernel proxies. */ 274c2aa585cSchristos /* ------------------------------------------------------------------------ */ 275c2aa585cSchristos int 2760c6adecaSchristos ipf_proxy_main_load(void) 277c2aa585cSchristos { 278c2aa585cSchristos aproxy_t *ap; 279c2aa585cSchristos 280c2aa585cSchristos for (ap = ips_proxies; ap->apr_p; ap++) { 281c2aa585cSchristos if (ap->apr_load != NULL) 282c2aa585cSchristos (*ap->apr_load)(); 283c2aa585cSchristos } 284c2aa585cSchristos return 0; 285c2aa585cSchristos } 286c2aa585cSchristos 287c2aa585cSchristos 288c2aa585cSchristos /* ------------------------------------------------------------------------ */ 28913885a66Sdarrenr /* Function: ipf_proxy_main_unload */ 29013885a66Sdarrenr /* Returns: int - 0 == success, else failure. */ 291c2aa585cSchristos /* Parameters: Nil */ 292c2aa585cSchristos /* */ 293c2aa585cSchristos /* Unload hook for kernel application proxies. */ 294c2aa585cSchristos /* Call the finialise routine for all the compiled in kernel proxies. */ 295c2aa585cSchristos /* ------------------------------------------------------------------------ */ 296c2aa585cSchristos int 2970c6adecaSchristos ipf_proxy_main_unload(void) 298c2aa585cSchristos { 299c2aa585cSchristos aproxy_t *ap; 300c2aa585cSchristos 301c2aa585cSchristos for (ap = ips_proxies; ap->apr_p; ap++) 302c2aa585cSchristos if (ap->apr_unload != NULL) 303c2aa585cSchristos (*ap->apr_unload)(); 304c2aa585cSchristos for (ap = ap_proxylist; ap; ap = ap->apr_next) 305c2aa585cSchristos if (ap->apr_unload != NULL) 306c2aa585cSchristos (*ap->apr_unload)(); 307c2aa585cSchristos 308c2aa585cSchristos return 0; 309c2aa585cSchristos } 310c2aa585cSchristos 311c2aa585cSchristos 31213885a66Sdarrenr /* ------------------------------------------------------------------------ */ 31313885a66Sdarrenr /* Function: ipf_proxy_soft_create */ 31413885a66Sdarrenr /* Returns: void * - */ 31513885a66Sdarrenr /* Parameters: softc(I) - pointer to soft context main structure */ 31613885a66Sdarrenr /* */ 31713885a66Sdarrenr /* Build the structure to hold all of the run time data to support proxies. */ 31813885a66Sdarrenr /* ------------------------------------------------------------------------ */ 319c2aa585cSchristos void * 3200c6adecaSchristos ipf_proxy_soft_create(ipf_main_softc_t *softc) 321c2aa585cSchristos { 322c2aa585cSchristos ipf_proxy_softc_t *softp; 323c2aa585cSchristos aproxy_t *last; 324c2aa585cSchristos aproxy_t *apn; 325c2aa585cSchristos aproxy_t *ap; 326c2aa585cSchristos 327c2aa585cSchristos KMALLOC(softp, ipf_proxy_softc_t *); 328c2aa585cSchristos if (softp == NULL) 329c2aa585cSchristos return softp; 330c2aa585cSchristos 331c2aa585cSchristos bzero((char *)softp, sizeof(*softp)); 332c2aa585cSchristos 333c2aa585cSchristos #if defined(_KERNEL) 334c2aa585cSchristos softp->ips_proxy_debug = 0; 335c2aa585cSchristos #else 336c2aa585cSchristos softp->ips_proxy_debug = 2; 337c2aa585cSchristos #endif 338c2aa585cSchristos softp->ips_proxy_session_size = AP_SESS_SIZE; 339c2aa585cSchristos 340c2aa585cSchristos softp->ipf_proxy_tune = ipf_tune_array_copy(softp, 341c2aa585cSchristos sizeof(ipf_proxy_tuneables), 342c2aa585cSchristos ipf_proxy_tuneables); 343c2aa585cSchristos if (softp->ipf_proxy_tune == NULL) { 344c2aa585cSchristos ipf_proxy_soft_destroy(softc, softp); 345c2aa585cSchristos return NULL; 346c2aa585cSchristos } 347c2aa585cSchristos if (ipf_tune_array_link(softc, softp->ipf_proxy_tune) == -1) { 348c2aa585cSchristos ipf_proxy_soft_destroy(softc, softp); 349c2aa585cSchristos return NULL; 350c2aa585cSchristos } 351c2aa585cSchristos 352c2aa585cSchristos last = NULL; 353c2aa585cSchristos for (ap = ips_proxies; ap->apr_p; ap++) { 354c2aa585cSchristos apn = ipf_proxy_create_clone(softc, ap); 355c2aa585cSchristos if (apn == NULL) 356c2aa585cSchristos goto failed; 357c2aa585cSchristos if (last != NULL) 358c2aa585cSchristos last->apr_next = apn; 359c2aa585cSchristos else 360c2aa585cSchristos softp->ips_proxies = apn; 361c2aa585cSchristos last = apn; 362c2aa585cSchristos } 363c2aa585cSchristos for (ap = ips_proxies; ap != NULL; ap = ap->apr_next) { 364c2aa585cSchristos apn = ipf_proxy_create_clone(softc, ap); 365c2aa585cSchristos if (apn == NULL) 366c2aa585cSchristos goto failed; 367c2aa585cSchristos if (last != NULL) 368c2aa585cSchristos last->apr_next = apn; 369c2aa585cSchristos else 370c2aa585cSchristos softp->ips_proxies = apn; 371c2aa585cSchristos last = apn; 372c2aa585cSchristos } 373c2aa585cSchristos 374c2aa585cSchristos return softp; 375c2aa585cSchristos failed: 376c2aa585cSchristos ipf_proxy_soft_destroy(softc, softp); 377c2aa585cSchristos return NULL; 378c2aa585cSchristos } 379c2aa585cSchristos 380c2aa585cSchristos 38113885a66Sdarrenr /* ------------------------------------------------------------------------ */ 38213885a66Sdarrenr /* Function: ipf_proxy_soft_create */ 38313885a66Sdarrenr /* Returns: void * - */ 38413885a66Sdarrenr /* Parameters: softc(I) - pointer to soft context main structure */ 38513885a66Sdarrenr /* orig(I) - pointer to proxy definition to copy */ 38613885a66Sdarrenr /* */ 38713885a66Sdarrenr /* This function clones a proxy definition given by orig and returns a */ 38813885a66Sdarrenr /* a pointer to that copy. */ 38913885a66Sdarrenr /* ------------------------------------------------------------------------ */ 390c2aa585cSchristos static aproxy_t * 3910c6adecaSchristos ipf_proxy_create_clone(ipf_main_softc_t *softc, aproxy_t *orig) 392c2aa585cSchristos { 393c2aa585cSchristos aproxy_t *apn; 394c2aa585cSchristos 395c2aa585cSchristos KMALLOC(apn, aproxy_t *); 396c2aa585cSchristos if (apn == NULL) 397c2aa585cSchristos return NULL; 398c2aa585cSchristos 399c2aa585cSchristos bcopy((char *)orig, (char *)apn, sizeof(*apn)); 400c2aa585cSchristos apn->apr_next = NULL; 401c2aa585cSchristos apn->apr_soft = NULL; 402c2aa585cSchristos 403c2aa585cSchristos if (apn->apr_create != NULL) { 404c2aa585cSchristos apn->apr_soft = (*apn->apr_create)(softc); 405c2aa585cSchristos if (apn->apr_soft == NULL) { 406c2aa585cSchristos KFREE(apn); 407c2aa585cSchristos return NULL; 408c2aa585cSchristos } 409c2aa585cSchristos } 410c2aa585cSchristos 411c2aa585cSchristos apn->apr_parent = orig; 412c2aa585cSchristos orig->apr_clones++; 413c2aa585cSchristos 414c2aa585cSchristos return apn; 415c2aa585cSchristos } 416c2aa585cSchristos 417c2aa585cSchristos 41813885a66Sdarrenr /* ------------------------------------------------------------------------ */ 41913885a66Sdarrenr /* Function: ipf_proxy_soft_create */ 42013885a66Sdarrenr /* Returns: int - 0 == success, else failure. */ 42113885a66Sdarrenr /* Parameters: softc(I) - pointer to soft context main structure */ 42213885a66Sdarrenr /* arg(I) - pointer to proxy contect data */ 42313885a66Sdarrenr /* */ 42413885a66Sdarrenr /* Initialise the proxy context and walk through each of the proxies and */ 42513885a66Sdarrenr /* call its initialisation function. This allows for proxies to do any */ 42613885a66Sdarrenr /* local setup prior to actual use. */ 42713885a66Sdarrenr /* ------------------------------------------------------------------------ */ 428c2aa585cSchristos int 4290c6adecaSchristos ipf_proxy_soft_init(ipf_main_softc_t *softc, void *arg) 430c2aa585cSchristos { 431c2aa585cSchristos ipf_proxy_softc_t *softp; 432c2aa585cSchristos aproxy_t *ap; 433c2aa585cSchristos u_int size; 434c2aa585cSchristos int err; 435c2aa585cSchristos 436c2aa585cSchristos softp = arg; 437c2aa585cSchristos size = softp->ips_proxy_session_size * sizeof(ap_session_t *); 438c2aa585cSchristos 439c2aa585cSchristos KMALLOCS(softp->ips_sess_tab, ap_session_t **, size); 440c2aa585cSchristos 441c2aa585cSchristos if (softp->ips_sess_tab == NULL) 442c2aa585cSchristos return -1; 443c2aa585cSchristos 444c2aa585cSchristos bzero(softp->ips_sess_tab, size); 445c2aa585cSchristos 446c2aa585cSchristos for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next) { 447c2aa585cSchristos if (ap->apr_init != NULL) { 448c2aa585cSchristos err = (*ap->apr_init)(softc, ap->apr_soft); 449c2aa585cSchristos if (err != 0) 450c2aa585cSchristos return -2; 451c2aa585cSchristos } 452c2aa585cSchristos } 453c2aa585cSchristos softp->ips_init_run = 1; 454c2aa585cSchristos 455c2aa585cSchristos return 0; 456c2aa585cSchristos } 457c2aa585cSchristos 458c2aa585cSchristos 45913885a66Sdarrenr /* ------------------------------------------------------------------------ */ 46013885a66Sdarrenr /* Function: ipf_proxy_soft_create */ 46113885a66Sdarrenr /* Returns: int - 0 == success, else failure. */ 46213885a66Sdarrenr /* Parameters: softc(I) - pointer to soft context main structure */ 46313885a66Sdarrenr /* arg(I) - pointer to proxy contect data */ 46413885a66Sdarrenr /* */ 46513885a66Sdarrenr /* This function should always succeed. It is responsible for ensuring that */ 46613885a66Sdarrenr /* the proxy context can be safely called when ipf_proxy_soft_destroy is */ 46713885a66Sdarrenr /* called and suring all of the proxies have similarly been instructed. */ 46813885a66Sdarrenr /* ------------------------------------------------------------------------ */ 469c2aa585cSchristos int 4700c6adecaSchristos ipf_proxy_soft_fini(ipf_main_softc_t *softc, void *arg) 471c2aa585cSchristos { 472c2aa585cSchristos ipf_proxy_softc_t *softp = arg; 473c2aa585cSchristos aproxy_t *ap; 474c2aa585cSchristos 475c2aa585cSchristos for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next) { 476c2aa585cSchristos if (ap->apr_fini != NULL) { 477c2aa585cSchristos (*ap->apr_fini)(softc, ap->apr_soft); 478c2aa585cSchristos } 479c2aa585cSchristos } 480c2aa585cSchristos 481c2aa585cSchristos if (softp->ips_sess_tab != NULL) { 482c2aa585cSchristos KFREES(softp->ips_sess_tab, 483c2aa585cSchristos softp->ips_proxy_session_size * sizeof(ap_session_t *)); 484c2aa585cSchristos softp->ips_sess_tab = NULL; 485c2aa585cSchristos } 486c2aa585cSchristos softp->ips_init_run = 0; 487c2aa585cSchristos 488c2aa585cSchristos return 0; 489c2aa585cSchristos } 490c2aa585cSchristos 491c2aa585cSchristos 49213885a66Sdarrenr /* ------------------------------------------------------------------------ */ 49313885a66Sdarrenr /* Function: ipf_proxy_soft_destroy */ 49413885a66Sdarrenr /* Returns: Nil */ 49513885a66Sdarrenr /* Parameters: softc(I) - pointer to soft context main structure */ 49613885a66Sdarrenr /* arg(I) - pointer to proxy contect data */ 49713885a66Sdarrenr /* */ 49813885a66Sdarrenr /* Free up all of the local data structures allocated during creation. */ 49913885a66Sdarrenr /* ------------------------------------------------------------------------ */ 500c2aa585cSchristos void 5010c6adecaSchristos ipf_proxy_soft_destroy(ipf_main_softc_t *softc, void *arg) 502c2aa585cSchristos { 503c2aa585cSchristos ipf_proxy_softc_t *softp = arg; 504c2aa585cSchristos aproxy_t *ap; 505c2aa585cSchristos 506c2aa585cSchristos while ((ap = softp->ips_proxies) != NULL) { 507c2aa585cSchristos softp->ips_proxies = ap->apr_next; 508c2aa585cSchristos if (ap->apr_destroy != NULL) 509c2aa585cSchristos (*ap->apr_destroy)(softc, ap->apr_soft); 510c2aa585cSchristos ap->apr_parent->apr_clones--; 511c2aa585cSchristos KFREE(ap); 512c2aa585cSchristos } 513c2aa585cSchristos 514c2aa585cSchristos if (softp->ipf_proxy_tune != NULL) { 515c2aa585cSchristos ipf_tune_array_unlink(softc, softp->ipf_proxy_tune); 516c2aa585cSchristos KFREES(softp->ipf_proxy_tune, sizeof(ipf_proxy_tuneables)); 517c2aa585cSchristos softp->ipf_proxy_tune = NULL; 518c2aa585cSchristos } 519c2aa585cSchristos 520c2aa585cSchristos KFREE(softp); 521c2aa585cSchristos } 522c2aa585cSchristos 523c2aa585cSchristos 524c2aa585cSchristos /* ------------------------------------------------------------------------ */ 525c2aa585cSchristos /* Function: ipf_proxy_flush */ 526c2aa585cSchristos /* Returns: Nil */ 52713885a66Sdarrenr /* Parameters: arg(I) - pointer to proxy contect data */ 52813885a66Sdarrenr /* how(I) - indicates the type of flush operation */ 529c2aa585cSchristos /* */ 53013885a66Sdarrenr /* Walk through all of the proxies and pass on the flush command as either */ 53113885a66Sdarrenr /* a flush or a clear. */ 532c2aa585cSchristos /* ------------------------------------------------------------------------ */ 533c2aa585cSchristos void 5340c6adecaSchristos ipf_proxy_flush(void *arg, int how) 535c2aa585cSchristos { 536c2aa585cSchristos ipf_proxy_softc_t *softp = arg; 537c2aa585cSchristos aproxy_t *ap; 538c2aa585cSchristos 539c2aa585cSchristos switch (how) 540c2aa585cSchristos { 541c2aa585cSchristos case 0 : 542c2aa585cSchristos for (ap = softp->ips_proxies; ap; ap = ap->apr_next) 543c2aa585cSchristos if (ap->apr_flush != NULL) 544c2aa585cSchristos (*ap->apr_flush)(ap, how); 545c2aa585cSchristos break; 546c2aa585cSchristos case 1 : 547c2aa585cSchristos for (ap = softp->ips_proxies; ap; ap = ap->apr_next) 548c2aa585cSchristos if (ap->apr_clear != NULL) 549c2aa585cSchristos (*ap->apr_clear)(ap); 550c2aa585cSchristos break; 551c2aa585cSchristos default : 552c2aa585cSchristos break; 553c2aa585cSchristos } 554c2aa585cSchristos } 555c2aa585cSchristos 556c2aa585cSchristos 557c2aa585cSchristos /* ------------------------------------------------------------------------ */ 558c2aa585cSchristos /* Function: ipf_proxy_add */ 55913885a66Sdarrenr /* Returns: int - 0 == success, else failure. */ 560c2aa585cSchristos /* Parameters: ap(I) - pointer to proxy structure */ 561c2aa585cSchristos /* */ 562c2aa585cSchristos /* Dynamically add a new kernel proxy. Ensure that it is unique in the */ 563c2aa585cSchristos /* collection compiled in and dynamically added. */ 564c2aa585cSchristos /* ------------------------------------------------------------------------ */ 565c2aa585cSchristos int 5660c6adecaSchristos ipf_proxy_add(void *arg, aproxy_t *ap) 567c2aa585cSchristos { 568c2aa585cSchristos ipf_proxy_softc_t *softp = arg; 569c2aa585cSchristos 570c2aa585cSchristos aproxy_t *a; 571c2aa585cSchristos 572c2aa585cSchristos for (a = ips_proxies; a->apr_p; a++) 573c2aa585cSchristos if ((a->apr_p == ap->apr_p) && 574c2aa585cSchristos !strncmp(a->apr_label, ap->apr_label, 575c2aa585cSchristos sizeof(ap->apr_label))) { 57613885a66Sdarrenr if (softp->ips_proxy_debug & 0x01) 577c2aa585cSchristos printf("ipf_proxy_add: %s/%d present (B)\n", 578c2aa585cSchristos a->apr_label, a->apr_p); 579c2aa585cSchristos return -1; 580c2aa585cSchristos } 581c2aa585cSchristos 582c2aa585cSchristos for (a = ap_proxylist; (a != NULL); a = a->apr_next) 583c2aa585cSchristos if ((a->apr_p == ap->apr_p) && 584c2aa585cSchristos !strncmp(a->apr_label, ap->apr_label, 585c2aa585cSchristos sizeof(ap->apr_label))) { 58613885a66Sdarrenr if (softp->ips_proxy_debug & 0x01) 587c2aa585cSchristos printf("ipf_proxy_add: %s/%d present (D)\n", 588c2aa585cSchristos a->apr_label, a->apr_p); 589c2aa585cSchristos return -1; 590c2aa585cSchristos } 591c2aa585cSchristos ap->apr_next = ap_proxylist; 592c2aa585cSchristos ap_proxylist = ap; 593c2aa585cSchristos if (ap->apr_load != NULL) 594c2aa585cSchristos (*ap->apr_load)(); 595c2aa585cSchristos return 0; 596c2aa585cSchristos } 597c2aa585cSchristos 598c2aa585cSchristos 599c2aa585cSchristos /* ------------------------------------------------------------------------ */ 600c2aa585cSchristos /* Function: ipf_proxy_ctl */ 601c2aa585cSchristos /* Returns: int - 0 == success, else error */ 60213885a66Sdarrenr /* Parameters: softc(I) - pointer to soft context main structure */ 60313885a66Sdarrenr /* arg(I) - pointer to proxy context */ 60413885a66Sdarrenr /* ctl(I) - pointer to proxy control structure */ 605c2aa585cSchristos /* */ 606c2aa585cSchristos /* Check to see if the proxy this control request has come through for */ 607c2aa585cSchristos /* exists, and if it does and it has a control function then invoke that */ 608c2aa585cSchristos /* control function. */ 609c2aa585cSchristos /* ------------------------------------------------------------------------ */ 610c2aa585cSchristos int 6110c6adecaSchristos ipf_proxy_ctl(ipf_main_softc_t *softc, void *arg, ap_ctl_t *ctl) 612c2aa585cSchristos { 613c2aa585cSchristos ipf_proxy_softc_t *softp = arg; 614c2aa585cSchristos aproxy_t *a; 615c2aa585cSchristos int error; 616c2aa585cSchristos 617c2aa585cSchristos a = ipf_proxy_lookup(arg, ctl->apc_p, ctl->apc_label); 618c2aa585cSchristos if (a == NULL) { 61913885a66Sdarrenr if (softp->ips_proxy_debug & 0x01) 620c2aa585cSchristos printf("ipf_proxy_ctl: can't find %s/%d\n", 621c2aa585cSchristos ctl->apc_label, ctl->apc_p); 622c2aa585cSchristos IPFERROR(80001); 623c2aa585cSchristos error = ESRCH; 624c2aa585cSchristos } else if (a->apr_ctl == NULL) { 62513885a66Sdarrenr if (softp->ips_proxy_debug & 0x01) 626c2aa585cSchristos printf("ipf_proxy_ctl: no ctl function for %s/%d\n", 627c2aa585cSchristos ctl->apc_label, ctl->apc_p); 628c2aa585cSchristos IPFERROR(80002); 629c2aa585cSchristos error = ENXIO; 630c2aa585cSchristos } else { 631c2aa585cSchristos error = (*a->apr_ctl)(softc, a->apr_soft, ctl); 63213885a66Sdarrenr if ((error != 0) && (softp->ips_proxy_debug & 0x02)) 633c2aa585cSchristos printf("ipf_proxy_ctl: %s/%d ctl error %d\n", 634c2aa585cSchristos a->apr_label, a->apr_p, error); 635c2aa585cSchristos } 636c2aa585cSchristos return error; 637c2aa585cSchristos } 638c2aa585cSchristos 639c2aa585cSchristos 640c2aa585cSchristos /* ------------------------------------------------------------------------ */ 641c2aa585cSchristos /* Function: ipf_proxy_del */ 64213885a66Sdarrenr /* Returns: int - 0 == success, else failure. */ 643c2aa585cSchristos /* Parameters: ap(I) - pointer to proxy structure */ 644c2aa585cSchristos /* */ 645c2aa585cSchristos /* Delete a proxy that has been added dynamically from those available. */ 646c2aa585cSchristos /* If it is in use, return 1 (do not destroy NOW), not in use 0 or -1 */ 647c2aa585cSchristos /* if it cannot be matched. */ 648c2aa585cSchristos /* ------------------------------------------------------------------------ */ 649c2aa585cSchristos int 6500c6adecaSchristos ipf_proxy_del(aproxy_t *ap) 651c2aa585cSchristos { 652c2aa585cSchristos aproxy_t *a, **app; 653c2aa585cSchristos 654c2aa585cSchristos for (app = &ap_proxylist; ((a = *app) != NULL); app = &a->apr_next) { 655c2aa585cSchristos if (a == ap) { 656c2aa585cSchristos a->apr_flags |= APR_DELETE; 657c2aa585cSchristos if (ap->apr_ref == 0 && ap->apr_clones == 0) { 658c2aa585cSchristos *app = a->apr_next; 659c2aa585cSchristos return 0; 660c2aa585cSchristos } 661c2aa585cSchristos return 1; 662c2aa585cSchristos } 663c2aa585cSchristos } 664c2aa585cSchristos 665c2aa585cSchristos return -1; 666c2aa585cSchristos } 667c2aa585cSchristos 668c2aa585cSchristos 669c2aa585cSchristos /* ------------------------------------------------------------------------ */ 670c2aa585cSchristos /* Function: ipf_proxy_ok */ 671c2aa585cSchristos /* Returns: int - 1 == good match else not. */ 672c2aa585cSchristos /* Parameters: fin(I) - pointer to packet information */ 67313885a66Sdarrenr /* tcp(I) - pointer to TCP/UDP header */ 674c2aa585cSchristos /* nat(I) - pointer to current NAT session */ 675c2aa585cSchristos /* */ 67613885a66Sdarrenr /* This function extends the NAT matching to ensure that a packet that has */ 67713885a66Sdarrenr /* arrived matches the proxy information attached to the NAT rule. Notably, */ 67813885a66Sdarrenr /* if the proxy is scheduled to be deleted then packets will not match the */ 67913885a66Sdarrenr /* rule even if the rule is still active. */ 680c2aa585cSchristos /* ------------------------------------------------------------------------ */ 681c2aa585cSchristos int 68213885a66Sdarrenr ipf_proxy_ok(fr_info_t *fin, tcphdr_t *tcp, ipnat_t *np) 683c2aa585cSchristos { 68413885a66Sdarrenr aproxy_t *apr = np->in_apr; 68513885a66Sdarrenr u_short dport = np->in_odport; 686c2aa585cSchristos 687c2aa585cSchristos if ((apr == NULL) || (apr->apr_flags & APR_DELETE) || 688c2aa585cSchristos (fin->fin_p != apr->apr_p)) 689c2aa585cSchristos return 0; 690c2aa585cSchristos if ((tcp == NULL) && dport) 691c2aa585cSchristos return 0; 692c2aa585cSchristos return 1; 693c2aa585cSchristos } 694c2aa585cSchristos 695c2aa585cSchristos 696c2aa585cSchristos /* ------------------------------------------------------------------------ */ 697c2aa585cSchristos /* Function: ipf_proxy_ioctl */ 698c2aa585cSchristos /* Returns: int - 0 == success, else error */ 69913885a66Sdarrenr /* Parameters: softc(I) - pointer to soft context main structure */ 70013885a66Sdarrenr /* data(I) - pointer to ioctl data */ 70113885a66Sdarrenr /* cmd(I) - ioctl command */ 70213885a66Sdarrenr /* mode(I) - mode bits for device */ 70313885a66Sdarrenr /* ctx(I) - pointer to context information */ 704c2aa585cSchristos /* */ 705c2aa585cSchristos /* ------------------------------------------------------------------------ */ 706c2aa585cSchristos int 7070c6adecaSchristos ipf_proxy_ioctl(ipf_main_softc_t *softc, void *data, ioctlcmd_t cmd, int mode, 7080c6adecaSchristos void *ctx) 709c2aa585cSchristos { 710c2aa585cSchristos ap_ctl_t ctl; 7110c6adecaSchristos void *ptr; 712c2aa585cSchristos int error; 713c2aa585cSchristos 714c2aa585cSchristos mode = mode; /* LINT */ 715c2aa585cSchristos 716c2aa585cSchristos switch (cmd) 717c2aa585cSchristos { 718c2aa585cSchristos case SIOCPROXY : 719c2aa585cSchristos error = ipf_inobj(softc, data, NULL, &ctl, IPFOBJ_PROXYCTL); 720c2aa585cSchristos if (error != 0) { 721c2aa585cSchristos return error; 722c2aa585cSchristos } 723c2aa585cSchristos ptr = NULL; 724c2aa585cSchristos 725c2aa585cSchristos if (ctl.apc_dsize > 0) { 7260c6adecaSchristos KMALLOCS(ptr, void *, ctl.apc_dsize); 727c2aa585cSchristos if (ptr == NULL) { 728c2aa585cSchristos IPFERROR(80003); 729c2aa585cSchristos error = ENOMEM; 730c2aa585cSchristos } else { 731c2aa585cSchristos error = copyinptr(softc, ctl.apc_data, ptr, 732c2aa585cSchristos ctl.apc_dsize); 733c2aa585cSchristos if (error == 0) 734c2aa585cSchristos ctl.apc_data = ptr; 735c2aa585cSchristos } 736c2aa585cSchristos } else { 737c2aa585cSchristos ctl.apc_data = NULL; 738c2aa585cSchristos error = 0; 739c2aa585cSchristos } 740c2aa585cSchristos 741c2aa585cSchristos if (error == 0) 74213885a66Sdarrenr error = ipf_proxy_ctl(softc, softc->ipf_proxy_soft, 74313885a66Sdarrenr &ctl); 744c2aa585cSchristos 745c2aa585cSchristos if ((error != 0) && (ptr != NULL)) { 746c2aa585cSchristos KFREES(ptr, ctl.apc_dsize); 747c2aa585cSchristos } 748c2aa585cSchristos break; 749c2aa585cSchristos 750c2aa585cSchristos default : 751c2aa585cSchristos IPFERROR(80004); 752c2aa585cSchristos error = EINVAL; 753c2aa585cSchristos } 754c2aa585cSchristos return error; 755c2aa585cSchristos } 756c2aa585cSchristos 757c2aa585cSchristos 758c2aa585cSchristos /* ------------------------------------------------------------------------ */ 759c2aa585cSchristos /* Function: ipf_proxy_match */ 76013885a66Sdarrenr /* Returns: int - 0 == success, else error */ 761c2aa585cSchristos /* Parameters: fin(I) - pointer to packet information */ 762c2aa585cSchristos /* nat(I) - pointer to current NAT session */ 763c2aa585cSchristos /* */ 764c2aa585cSchristos /* If a proxy has a match function, call that to do extended packet */ 76513885a66Sdarrenr /* matching. Whilst other parts of the NAT code are rather lenient when it */ 76613885a66Sdarrenr /* comes to the quality of the packet that it will transform, the proxy */ 76713885a66Sdarrenr /* matching is not because they need to work with data, not just headers. */ 768c2aa585cSchristos /* ------------------------------------------------------------------------ */ 769c2aa585cSchristos int 7700c6adecaSchristos ipf_proxy_match(fr_info_t *fin, nat_t *nat) 771c2aa585cSchristos { 772c2aa585cSchristos ipf_main_softc_t *softc = fin->fin_main_soft; 773c2aa585cSchristos ipf_proxy_softc_t *softp = softc->ipf_proxy_soft; 774c2aa585cSchristos aproxy_t *apr; 775c2aa585cSchristos ipnat_t *ipn; 776c2aa585cSchristos int result; 777c2aa585cSchristos 778c2aa585cSchristos ipn = nat->nat_ptr; 77913885a66Sdarrenr if (softp->ips_proxy_debug & 0x04) 780c2aa585cSchristos printf("ipf_proxy_match(%lx,%lx) aps %lx ptr %lx\n", 781c2aa585cSchristos (u_long)fin, (u_long)nat, (u_long)nat->nat_aps, 782c2aa585cSchristos (u_long)ipn); 783c2aa585cSchristos 784c2aa585cSchristos if ((fin->fin_flx & (FI_SHORT|FI_BAD)) != 0) { 78513885a66Sdarrenr if (softp->ips_proxy_debug & 0x08) 786c2aa585cSchristos printf("ipf_proxy_match: flx 0x%x (BAD|SHORT)\n", 787c2aa585cSchristos fin->fin_flx); 788c2aa585cSchristos return -1; 789c2aa585cSchristos } 790c2aa585cSchristos 791c2aa585cSchristos apr = ipn->in_apr; 792c2aa585cSchristos if ((apr == NULL) || (apr->apr_flags & APR_DELETE)) { 79313885a66Sdarrenr if (softp->ips_proxy_debug & 0x08) 794c2aa585cSchristos printf("ipf_proxy_match:apr %lx apr_flags 0x%x\n", 795c2aa585cSchristos (u_long)apr, apr ? apr->apr_flags : 0); 796c2aa585cSchristos return -1; 797c2aa585cSchristos } 798c2aa585cSchristos 799c2aa585cSchristos if (apr->apr_match != NULL) { 800c2aa585cSchristos result = (*apr->apr_match)(fin, nat->nat_aps, nat); 801c2aa585cSchristos if (result != 0) { 80213885a66Sdarrenr if (softp->ips_proxy_debug & 0x08) 803c2aa585cSchristos printf("ipf_proxy_match: result %d\n", result); 804c2aa585cSchristos return -1; 805c2aa585cSchristos } 806c2aa585cSchristos } 807c2aa585cSchristos return 0; 808c2aa585cSchristos } 809c2aa585cSchristos 810c2aa585cSchristos 811c2aa585cSchristos /* ------------------------------------------------------------------------ */ 812c2aa585cSchristos /* Function: ipf_proxy_new */ 81313885a66Sdarrenr /* Returns: int - 0 == success, else error */ 814c2aa585cSchristos /* Parameters: fin(I) - pointer to packet information */ 815c2aa585cSchristos /* nat(I) - pointer to current NAT session */ 816c2aa585cSchristos /* */ 817c2aa585cSchristos /* Allocate a new application proxy structure and fill it in with the */ 818c2aa585cSchristos /* relevant details. call the init function once complete, prior to */ 819c2aa585cSchristos /* returning. */ 820c2aa585cSchristos /* ------------------------------------------------------------------------ */ 821c2aa585cSchristos int 8220c6adecaSchristos ipf_proxy_new(fr_info_t *fin, nat_t *nat) 823c2aa585cSchristos { 824c2aa585cSchristos ipf_main_softc_t *softc = fin->fin_main_soft; 825c2aa585cSchristos ipf_proxy_softc_t *softp = softc->ipf_proxy_soft; 826c2aa585cSchristos register ap_session_t *aps; 827c2aa585cSchristos aproxy_t *apr; 828c2aa585cSchristos 82913885a66Sdarrenr if (softp->ips_proxy_debug & 0x04) 830c2aa585cSchristos printf("ipf_proxy_new(%lx,%lx) \n", (u_long)fin, (u_long)nat); 831c2aa585cSchristos 832c2aa585cSchristos if ((nat->nat_ptr == NULL) || (nat->nat_aps != NULL)) { 83313885a66Sdarrenr if (softp->ips_proxy_debug & 0x08) 834c2aa585cSchristos printf("ipf_proxy_new: nat_ptr %lx nat_aps %lx\n", 835c2aa585cSchristos (u_long)nat->nat_ptr, (u_long)nat->nat_aps); 836c2aa585cSchristos return -1; 837c2aa585cSchristos } 838c2aa585cSchristos 839c2aa585cSchristos apr = nat->nat_ptr->in_apr; 840c2aa585cSchristos 841c2aa585cSchristos if ((apr->apr_flags & APR_DELETE) || 842c2aa585cSchristos (fin->fin_p != apr->apr_p)) { 84313885a66Sdarrenr if (softp->ips_proxy_debug & 0x08) 844c2aa585cSchristos printf("ipf_proxy_new: apr_flags 0x%x p %d/%d\n", 845c2aa585cSchristos apr->apr_flags, fin->fin_p, apr->apr_p); 846c2aa585cSchristos return -1; 847c2aa585cSchristos } 848c2aa585cSchristos 849c2aa585cSchristos KMALLOC(aps, ap_session_t *); 850c2aa585cSchristos if (!aps) { 85113885a66Sdarrenr if (softp->ips_proxy_debug & 0x08) 852c2aa585cSchristos printf("ipf_proxy_new: malloc failed (%lu)\n", 853c2aa585cSchristos (u_long)sizeof(ap_session_t)); 854c2aa585cSchristos return -1; 855c2aa585cSchristos } 856c2aa585cSchristos 857c2aa585cSchristos bzero((char *)aps, sizeof(*aps)); 858c2aa585cSchristos aps->aps_data = NULL; 859c2aa585cSchristos aps->aps_apr = apr; 860c2aa585cSchristos aps->aps_psiz = 0; 861c2aa585cSchristos if (apr->apr_new != NULL) 862c2aa585cSchristos if ((*apr->apr_new)(apr->apr_soft, fin, aps, nat) == -1) { 863c2aa585cSchristos if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) { 864c2aa585cSchristos KFREES(aps->aps_data, aps->aps_psiz); 865c2aa585cSchristos } 866c2aa585cSchristos KFREE(aps); 86713885a66Sdarrenr if (softp->ips_proxy_debug & 0x08) 868c2aa585cSchristos printf("ipf_proxy_new: new(%lx) failed\n", 869c2aa585cSchristos (u_long)apr->apr_new); 870c2aa585cSchristos return -1; 871c2aa585cSchristos } 872c2aa585cSchristos aps->aps_nat = nat; 873c2aa585cSchristos aps->aps_next = softp->ips_sess_list; 874c2aa585cSchristos softp->ips_sess_list = aps; 875c2aa585cSchristos nat->nat_aps = aps; 876c2aa585cSchristos 877c2aa585cSchristos return 0; 878c2aa585cSchristos } 879c2aa585cSchristos 880c2aa585cSchristos 881c2aa585cSchristos /* ------------------------------------------------------------------------ */ 882c2aa585cSchristos /* Function: ipf_proxy_check */ 883c2aa585cSchristos /* Returns: int - -1 == error, 0 == success */ 884c2aa585cSchristos /* Parameters: fin(I) - pointer to packet information */ 885c2aa585cSchristos /* nat(I) - pointer to current NAT session */ 886c2aa585cSchristos /* */ 887c2aa585cSchristos /* Check to see if a packet should be passed through an active proxy */ 888c2aa585cSchristos /* routine if one has been setup for it. We don't need to check the */ 889c2aa585cSchristos /* checksum here if IPFILTER_CKSUM is defined because if it is, a failed */ 890c2aa585cSchristos /* check causes FI_BAD to be set. */ 891c2aa585cSchristos /* ------------------------------------------------------------------------ */ 892c2aa585cSchristos int 8930c6adecaSchristos ipf_proxy_check(fr_info_t *fin, nat_t *nat) 894c2aa585cSchristos { 895c2aa585cSchristos ipf_main_softc_t *softc = fin->fin_main_soft; 896c2aa585cSchristos ipf_proxy_softc_t *softp = softc->ipf_proxy_soft; 89713885a66Sdarrenr #if SOLARIS && defined(_KERNEL) && defined(ICK_VALID) 898c2aa585cSchristos mb_t *m; 899c2aa585cSchristos #endif 900c2aa585cSchristos tcphdr_t *tcp = NULL; 901c2aa585cSchristos udphdr_t *udp = NULL; 902c2aa585cSchristos ap_session_t *aps; 903c2aa585cSchristos aproxy_t *apr; 90413885a66Sdarrenr short adjlen; 90513885a66Sdarrenr int dosum; 906c2aa585cSchristos ip_t *ip; 907c2aa585cSchristos short rv; 908c2aa585cSchristos int err; 909c2aa585cSchristos #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) 910c2aa585cSchristos u_32_t s1, s2, sd; 911c2aa585cSchristos #endif 912c2aa585cSchristos 913c2aa585cSchristos if (fin->fin_flx & FI_BAD) { 91413885a66Sdarrenr if (softp->ips_proxy_debug & 0x08) 91513885a66Sdarrenr printf("ipf_proxy_check: flx 0x%x (BAD)\n", 91613885a66Sdarrenr fin->fin_flx); 917c2aa585cSchristos return -1; 918c2aa585cSchristos } 919c2aa585cSchristos 920c2aa585cSchristos #ifndef IPFILTER_CKSUM 921c2aa585cSchristos if ((fin->fin_out == 0) && (ipf_checkl4sum(fin) == -1)) { 92213885a66Sdarrenr if (softp->ips_proxy_debug & 0x08) 923c2aa585cSchristos printf("ipf_proxy_check: l4 checksum failure %d\n", 924c2aa585cSchristos fin->fin_p); 925c2aa585cSchristos if (fin->fin_p == IPPROTO_TCP) 926c2aa585cSchristos softc->ipf_stats[fin->fin_out].fr_tcpbad++; 927c2aa585cSchristos return -1; 928c2aa585cSchristos } 929c2aa585cSchristos #endif 930c2aa585cSchristos 931c2aa585cSchristos aps = nat->nat_aps; 932c2aa585cSchristos if (aps != NULL) { 933c2aa585cSchristos /* 934c2aa585cSchristos * If there is data in this packet to be proxied then try and 935c2aa585cSchristos * get it all into the one buffer, else drop it. 936c2aa585cSchristos */ 937c2aa585cSchristos #if defined(MENTAT) || defined(HAVE_M_PULLDOWN) 938c2aa585cSchristos if ((fin->fin_dlen > 0) && !(fin->fin_flx & FI_COALESCE)) 939c2aa585cSchristos if (ipf_coalesce(fin) == -1) { 94013885a66Sdarrenr if (softp->ips_proxy_debug & 0x08) 94113885a66Sdarrenr printf("ipf_proxy_check: %s %x\n", 94213885a66Sdarrenr "coalesce failed", fin->fin_flx); 943c2aa585cSchristos return -1; 944c2aa585cSchristos } 945c2aa585cSchristos #endif 946c2aa585cSchristos ip = fin->fin_ip; 94713885a66Sdarrenr if (fin->fin_cksum > FI_CK_SUMOK) 94813885a66Sdarrenr dosum = 0; 94913885a66Sdarrenr else 95013885a66Sdarrenr dosum = 1; 951c2aa585cSchristos 952c2aa585cSchristos switch (fin->fin_p) 953c2aa585cSchristos { 954c2aa585cSchristos case IPPROTO_TCP : 955c2aa585cSchristos tcp = (tcphdr_t *)fin->fin_dp; 95613885a66Sdarrenr #if SOLARIS && defined(_KERNEL) && defined(ICK_VALID) 957c2aa585cSchristos m = fin->fin_qfm; 958c2aa585cSchristos if (dohwcksum && (m->b_ick_flag == ICK_VALID)) 959c2aa585cSchristos dosum = 0; 960c2aa585cSchristos #endif 961c2aa585cSchristos break; 962c2aa585cSchristos case IPPROTO_UDP : 963c2aa585cSchristos udp = (udphdr_t *)fin->fin_dp; 964c2aa585cSchristos break; 965c2aa585cSchristos default : 966c2aa585cSchristos break; 967c2aa585cSchristos } 968c2aa585cSchristos 969c2aa585cSchristos apr = aps->aps_apr; 970c2aa585cSchristos err = 0; 971c2aa585cSchristos if (fin->fin_out != 0) { 972c2aa585cSchristos if (apr->apr_outpkt != NULL) 97313885a66Sdarrenr err = (*apr->apr_outpkt)(apr->apr_soft, fin, 97413885a66Sdarrenr aps, nat); 975c2aa585cSchristos } else { 976c2aa585cSchristos if (apr->apr_inpkt != NULL) 97713885a66Sdarrenr err = (*apr->apr_inpkt)(apr->apr_soft, fin, 97813885a66Sdarrenr aps, nat); 979c2aa585cSchristos } 980c2aa585cSchristos 981c2aa585cSchristos rv = APR_EXIT(err); 98213885a66Sdarrenr if (((softp->ips_proxy_debug & 0x08) && (rv != 0)) || 98313885a66Sdarrenr (softp->ips_proxy_debug & 0x04)) 984c2aa585cSchristos printf("ipf_proxy_check: out %d err %x rv %d\n", 985c2aa585cSchristos fin->fin_out, err, rv); 986c2aa585cSchristos if (rv == 1) 987c2aa585cSchristos return -1; 988c2aa585cSchristos 989c2aa585cSchristos if (rv == 2) { 99013885a66Sdarrenr ipf_proxy_deref(apr); 991c2aa585cSchristos nat->nat_aps = NULL; 992c2aa585cSchristos return -1; 993c2aa585cSchristos } 994c2aa585cSchristos 995c2aa585cSchristos /* 996c2aa585cSchristos * If err != 0 then the data size of the packet has changed 997c2aa585cSchristos * so we need to recalculate the header checksums for the 998c2aa585cSchristos * packet. 999c2aa585cSchristos */ 100013885a66Sdarrenr adjlen = APR_INC(err); 1001c2aa585cSchristos #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) 1002c2aa585cSchristos s1 = LONG_SUM(fin->fin_plen - adjlen); 1003c2aa585cSchristos s2 = LONG_SUM(fin->fin_plen); 1004c2aa585cSchristos CALC_SUMD(s1, s2, sd); 100513885a66Sdarrenr if ((err != 0) && (fin->fin_cksum < FI_CK_L4PART) && 100613885a66Sdarrenr fin->fin_v == 4) 100713885a66Sdarrenr ipf_fix_outcksum(0, &ip->ip_sum, sd, 0); 1008c2aa585cSchristos #endif 100913885a66Sdarrenr if (fin->fin_flx & FI_DOCKSUM) 101013885a66Sdarrenr dosum = 1; 1011c2aa585cSchristos 10120c6adecaSchristos #ifdef INET 1013c2aa585cSchristos /* 1014c2aa585cSchristos * For TCP packets, we may need to adjust the sequence and 1015c2aa585cSchristos * acknowledgement numbers to reflect changes in size of the 1016c2aa585cSchristos * data stream. 1017c2aa585cSchristos * 1018c2aa585cSchristos * For both TCP and UDP, recalculate the layer 4 checksum, 1019c2aa585cSchristos * regardless, as we can't tell (here) if data has been 1020c2aa585cSchristos * changed or not. 1021c2aa585cSchristos */ 1022c2aa585cSchristos if (tcp != NULL) { 102313885a66Sdarrenr err = ipf_proxy_fixseqack(fin, ip, aps, adjlen); 102413885a66Sdarrenr if (fin->fin_cksum == FI_CK_L4PART) { 102513885a66Sdarrenr u_short sum = ntohs(tcp->th_sum); 102613885a66Sdarrenr sum += adjlen; 102713885a66Sdarrenr tcp->th_sum = htons(sum); 102813885a66Sdarrenr } else if (fin->fin_cksum < FI_CK_L4PART) { 1029c2aa585cSchristos tcp->th_sum = fr_cksum(fin, ip, 1030c2aa585cSchristos IPPROTO_TCP, tcp); 103113885a66Sdarrenr } 1032c2aa585cSchristos } else if ((udp != NULL) && (udp->uh_sum != 0)) { 103313885a66Sdarrenr if (fin->fin_cksum == FI_CK_L4PART) { 103413885a66Sdarrenr u_short sum = ntohs(udp->uh_sum); 103513885a66Sdarrenr sum += adjlen; 103613885a66Sdarrenr udp->uh_sum = htons(sum); 103713885a66Sdarrenr } else if (dosum) { 1038c2aa585cSchristos udp->uh_sum = fr_cksum(fin, ip, 1039c2aa585cSchristos IPPROTO_UDP, udp); 1040c2aa585cSchristos } 104113885a66Sdarrenr } 10420c6adecaSchristos #endif 1043c2aa585cSchristos aps->aps_bytes += fin->fin_plen; 1044c2aa585cSchristos aps->aps_pkts++; 1045c2aa585cSchristos return 1; 1046c2aa585cSchristos } 1047c2aa585cSchristos return 0; 1048c2aa585cSchristos } 1049c2aa585cSchristos 1050c2aa585cSchristos 1051c2aa585cSchristos /* ------------------------------------------------------------------------ */ 1052c2aa585cSchristos /* Function: ipf_proxy_lookup */ 1053c2aa585cSchristos /* Returns: int - -1 == error, 0 == success */ 105413885a66Sdarrenr /* Parameters: arg(I) - pointer to proxy context information */ 105513885a66Sdarrenr /* pr(I) - protocol number for proxy */ 105613885a66Sdarrenr /* name(I) - proxy name */ 1057c2aa585cSchristos /* */ 1058*5b28f239Srillig /* Search for a proxy by the protocol it is being used with and its name. */ 1059c2aa585cSchristos /* ------------------------------------------------------------------------ */ 1060c2aa585cSchristos aproxy_t * 10610c6adecaSchristos ipf_proxy_lookup(void *arg, u_int pr, char *name) 1062c2aa585cSchristos { 1063c2aa585cSchristos ipf_proxy_softc_t *softp = arg; 1064c2aa585cSchristos aproxy_t *ap; 1065c2aa585cSchristos 106613885a66Sdarrenr if (softp->ips_proxy_debug & 0x04) 1067c2aa585cSchristos printf("ipf_proxy_lookup(%d,%s)\n", pr, name); 1068c2aa585cSchristos 1069c2aa585cSchristos for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next) 1070c2aa585cSchristos if ((ap->apr_p == pr) && 1071c2aa585cSchristos !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) { 1072c2aa585cSchristos ap->apr_ref++; 1073c2aa585cSchristos return ap; 1074c2aa585cSchristos } 1075c2aa585cSchristos 107613885a66Sdarrenr if (softp->ips_proxy_debug & 0x08) 1077c2aa585cSchristos printf("ipf_proxy_lookup: failed for %d/%s\n", pr, name); 1078c2aa585cSchristos return NULL; 1079c2aa585cSchristos } 1080c2aa585cSchristos 1081c2aa585cSchristos 1082c2aa585cSchristos /* ------------------------------------------------------------------------ */ 108313885a66Sdarrenr /* Function: ipf_proxy_deref */ 1084c2aa585cSchristos /* Returns: Nil */ 1085c2aa585cSchristos /* Parameters: ap(I) - pointer to proxy structure */ 1086c2aa585cSchristos /* */ 108713885a66Sdarrenr /* Drop the reference counter associated with the proxy. */ 1088c2aa585cSchristos /* ------------------------------------------------------------------------ */ 1089c2aa585cSchristos void 109013885a66Sdarrenr ipf_proxy_deref(aproxy_t *ap) 1091c2aa585cSchristos { 1092c2aa585cSchristos ap->apr_ref--; 1093c2aa585cSchristos } 1094c2aa585cSchristos 1095c2aa585cSchristos 1096c2aa585cSchristos /* ------------------------------------------------------------------------ */ 109713885a66Sdarrenr /* Function: ipf_proxy_free */ 1098c2aa585cSchristos /* Returns: Nil */ 109913885a66Sdarrenr /* Parameters: softc(I) - pointer to soft context main structure */ 110013885a66Sdarrenr /* aps(I) - pointer to current proxy session */ 1101c2aa585cSchristos /* Locks Held: ipf_nat_new, ipf_nat(W) */ 110213885a66Sdarrenr /* */ 110313885a66Sdarrenr /* Free up proxy session information allocated to be used with a NAT */ 110413885a66Sdarrenr /* session. */ 1105c2aa585cSchristos /* ------------------------------------------------------------------------ */ 1106c2aa585cSchristos void 110713885a66Sdarrenr ipf_proxy_free(ipf_main_softc_t *softc, ap_session_t *aps) 1108c2aa585cSchristos { 110913885a66Sdarrenr ipf_proxy_softc_t *softp = softc->ipf_proxy_soft; 1110c2aa585cSchristos ap_session_t *a, **ap; 1111c2aa585cSchristos aproxy_t *apr; 1112c2aa585cSchristos 1113c2aa585cSchristos if (!aps) 1114c2aa585cSchristos return; 1115c2aa585cSchristos 1116c2aa585cSchristos for (ap = &softp->ips_sess_list; ((a = *ap) != NULL); ap = &a->aps_next) 1117c2aa585cSchristos if (a == aps) { 1118c2aa585cSchristos *ap = a->aps_next; 1119c2aa585cSchristos break; 1120c2aa585cSchristos } 1121c2aa585cSchristos 1122c2aa585cSchristos apr = aps->aps_apr; 1123c2aa585cSchristos if ((apr != NULL) && (apr->apr_del != NULL)) 1124c2aa585cSchristos (*apr->apr_del)(softc, aps); 1125c2aa585cSchristos 1126c2aa585cSchristos if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) 1127c2aa585cSchristos KFREES(aps->aps_data, aps->aps_psiz); 1128c2aa585cSchristos KFREE(aps); 1129c2aa585cSchristos } 1130c2aa585cSchristos 1131c2aa585cSchristos 1132c2aa585cSchristos /* ------------------------------------------------------------------------ */ 1133c2aa585cSchristos /* Function: ipf_proxy_fixseqack */ 1134c2aa585cSchristos /* Returns: int - 2 if TCP ack/seq is changed, else 0 */ 1135c2aa585cSchristos /* Parameters: fin(I) - pointer to packet information */ 113613885a66Sdarrenr /* ip(I) - pointer to IP header */ 1137c2aa585cSchristos /* nat(I) - pointer to current NAT session */ 113813885a66Sdarrenr /* inc(I) - delta to apply to TCP sequence numbering */ 1139c2aa585cSchristos /* */ 114013885a66Sdarrenr /* Adjust the TCP sequence/acknowledge numbers in the TCP header based on */ 114113885a66Sdarrenr /* whether or not the new header is past the point at which an adjustment */ 114213885a66Sdarrenr /* occurred. This might happen because of (say) an FTP string being changed */ 114313885a66Sdarrenr /* and the new string being a different length to the old. */ 1144c2aa585cSchristos /* ------------------------------------------------------------------------ */ 1145c2aa585cSchristos static int 11460c6adecaSchristos ipf_proxy_fixseqack(fr_info_t *fin, ip_t *ip, ap_session_t *aps, int inc) 1147c2aa585cSchristos { 1148c2aa585cSchristos ipf_main_softc_t *softc = fin->fin_main_soft; 1149c2aa585cSchristos ipf_proxy_softc_t *softp = softc->ipf_proxy_soft; 1150c2aa585cSchristos int sel, ch = 0, out, nlen; 1151c2aa585cSchristos u_32_t seq1, seq2; 1152c2aa585cSchristos tcphdr_t *tcp; 1153c2aa585cSchristos short inc2; 1154c2aa585cSchristos 1155c2aa585cSchristos tcp = (tcphdr_t *)fin->fin_dp; 1156c2aa585cSchristos out = fin->fin_out; 1157c2aa585cSchristos /* 1158c2aa585cSchristos * ip_len has already been adjusted by 'inc'. 1159c2aa585cSchristos */ 116013885a66Sdarrenr nlen = fin->fin_dlen; 116113885a66Sdarrenr nlen -= (TCP_OFF(tcp) << 2); 1162c2aa585cSchristos 1163c2aa585cSchristos inc2 = inc; 1164c2aa585cSchristos inc = (int)inc2; 1165c2aa585cSchristos 1166c2aa585cSchristos if (out != 0) { 1167c2aa585cSchristos seq1 = (u_32_t)ntohl(tcp->th_seq); 1168c2aa585cSchristos sel = aps->aps_sel[out]; 1169c2aa585cSchristos 1170c2aa585cSchristos /* switch to other set ? */ 1171c2aa585cSchristos if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) && 1172c2aa585cSchristos (seq1 > aps->aps_seqmin[!sel])) { 117313885a66Sdarrenr if (softp->ips_proxy_debug & 0x10) 1174c2aa585cSchristos printf("proxy out switch set seq %d -> %d %x > %x\n", 1175c2aa585cSchristos sel, !sel, seq1, 1176c2aa585cSchristos aps->aps_seqmin[!sel]); 1177c2aa585cSchristos sel = aps->aps_sel[out] = !sel; 1178c2aa585cSchristos } 1179c2aa585cSchristos 1180c2aa585cSchristos if (aps->aps_seqoff[sel]) { 1181c2aa585cSchristos seq2 = aps->aps_seqmin[sel] - aps->aps_seqoff[sel]; 1182c2aa585cSchristos if (seq1 > seq2) { 1183c2aa585cSchristos seq2 = aps->aps_seqoff[sel]; 1184c2aa585cSchristos seq1 += seq2; 1185c2aa585cSchristos tcp->th_seq = htonl(seq1); 1186c2aa585cSchristos ch = 1; 1187c2aa585cSchristos } 1188c2aa585cSchristos } 1189c2aa585cSchristos 1190c2aa585cSchristos if (inc && (seq1 > aps->aps_seqmin[!sel])) { 1191c2aa585cSchristos aps->aps_seqmin[sel] = seq1 + nlen - 1; 1192c2aa585cSchristos aps->aps_seqoff[sel] = aps->aps_seqoff[sel] + inc; 119313885a66Sdarrenr if (softp->ips_proxy_debug & 0x10) 1194c2aa585cSchristos printf("proxy seq set %d at %x to %d + %d\n", 1195c2aa585cSchristos sel, aps->aps_seqmin[sel], 1196c2aa585cSchristos aps->aps_seqoff[sel], inc); 1197c2aa585cSchristos } 1198c2aa585cSchristos 1199c2aa585cSchristos /***/ 1200c2aa585cSchristos 1201c2aa585cSchristos seq1 = ntohl(tcp->th_ack); 1202c2aa585cSchristos sel = aps->aps_sel[1 - out]; 1203c2aa585cSchristos 1204c2aa585cSchristos /* switch to other set ? */ 1205c2aa585cSchristos if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) && 1206c2aa585cSchristos (seq1 > aps->aps_ackmin[!sel])) { 120713885a66Sdarrenr if (softp->ips_proxy_debug & 0x10) 1208c2aa585cSchristos printf("proxy out switch set ack %d -> %d %x > %x\n", 1209c2aa585cSchristos sel, !sel, seq1, 1210c2aa585cSchristos aps->aps_ackmin[!sel]); 1211c2aa585cSchristos sel = aps->aps_sel[1 - out] = !sel; 1212c2aa585cSchristos } 1213c2aa585cSchristos 1214c2aa585cSchristos if (aps->aps_ackoff[sel] && (seq1 > aps->aps_ackmin[sel])) { 1215c2aa585cSchristos seq2 = aps->aps_ackoff[sel]; 1216c2aa585cSchristos tcp->th_ack = htonl(seq1 - seq2); 1217c2aa585cSchristos ch = 1; 1218c2aa585cSchristos } 1219c2aa585cSchristos } else { 1220c2aa585cSchristos seq1 = ntohl(tcp->th_seq); 1221c2aa585cSchristos sel = aps->aps_sel[out]; 1222c2aa585cSchristos 1223c2aa585cSchristos /* switch to other set ? */ 1224c2aa585cSchristos if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) && 1225c2aa585cSchristos (seq1 > aps->aps_ackmin[!sel])) { 122613885a66Sdarrenr if (softp->ips_proxy_debug & 0x10) 1227c2aa585cSchristos printf("proxy in switch set ack %d -> %d %x > %x\n", 1228c2aa585cSchristos sel, !sel, seq1, aps->aps_ackmin[!sel]); 1229c2aa585cSchristos sel = aps->aps_sel[out] = !sel; 1230c2aa585cSchristos } 1231c2aa585cSchristos 1232c2aa585cSchristos if (aps->aps_ackoff[sel]) { 1233c2aa585cSchristos seq2 = aps->aps_ackmin[sel] - aps->aps_ackoff[sel]; 1234c2aa585cSchristos if (seq1 > seq2) { 1235c2aa585cSchristos seq2 = aps->aps_ackoff[sel]; 1236c2aa585cSchristos seq1 += seq2; 1237c2aa585cSchristos tcp->th_seq = htonl(seq1); 1238c2aa585cSchristos ch = 1; 1239c2aa585cSchristos } 1240c2aa585cSchristos } 1241c2aa585cSchristos 1242c2aa585cSchristos if (inc && (seq1 > aps->aps_ackmin[!sel])) { 1243c2aa585cSchristos aps->aps_ackmin[!sel] = seq1 + nlen - 1; 1244c2aa585cSchristos aps->aps_ackoff[!sel] = aps->aps_ackoff[sel] + inc; 1245c2aa585cSchristos 124613885a66Sdarrenr if (softp->ips_proxy_debug & 0x10) 1247c2aa585cSchristos printf("proxy ack set %d at %x to %d + %d\n", 1248c2aa585cSchristos !sel, aps->aps_seqmin[!sel], 1249c2aa585cSchristos aps->aps_seqoff[sel], inc); 1250c2aa585cSchristos } 1251c2aa585cSchristos 1252c2aa585cSchristos /***/ 1253c2aa585cSchristos 1254c2aa585cSchristos seq1 = ntohl(tcp->th_ack); 1255c2aa585cSchristos sel = aps->aps_sel[1 - out]; 1256c2aa585cSchristos 1257c2aa585cSchristos /* switch to other set ? */ 1258c2aa585cSchristos if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) && 1259c2aa585cSchristos (seq1 > aps->aps_seqmin[!sel])) { 126013885a66Sdarrenr if (softp->ips_proxy_debug & 0x10) 1261c2aa585cSchristos printf("proxy in switch set seq %d -> %d %x > %x\n", 1262c2aa585cSchristos sel, !sel, seq1, aps->aps_seqmin[!sel]); 1263c2aa585cSchristos sel = aps->aps_sel[1 - out] = !sel; 1264c2aa585cSchristos } 1265c2aa585cSchristos 1266c2aa585cSchristos if (aps->aps_seqoff[sel] != 0) { 126713885a66Sdarrenr if (softp->ips_proxy_debug & 0x10) 1268c2aa585cSchristos printf("sel %d seqoff %d seq1 %x seqmin %x\n", 1269c2aa585cSchristos sel, aps->aps_seqoff[sel], seq1, 1270c2aa585cSchristos aps->aps_seqmin[sel]); 1271c2aa585cSchristos if (seq1 > aps->aps_seqmin[sel]) { 1272c2aa585cSchristos seq2 = aps->aps_seqoff[sel]; 1273c2aa585cSchristos tcp->th_ack = htonl(seq1 - seq2); 1274c2aa585cSchristos ch = 1; 1275c2aa585cSchristos } 1276c2aa585cSchristos } 1277c2aa585cSchristos } 1278c2aa585cSchristos 127913885a66Sdarrenr if (softp->ips_proxy_debug & 0x10) 128013885a66Sdarrenr printf("ipf_proxy_fixseqack: seq %u ack %u\n", 1281c2aa585cSchristos (u_32_t)ntohl(tcp->th_seq), (u_32_t)ntohl(tcp->th_ack)); 1282c2aa585cSchristos return ch ? 2 : 0; 1283c2aa585cSchristos } 128413885a66Sdarrenr 128513885a66Sdarrenr 128613885a66Sdarrenr /* ------------------------------------------------------------------------ */ 128713885a66Sdarrenr /* Function: ipf_proxy_rule_rev */ 128813885a66Sdarrenr /* Returns: ipnat_t * - NULL = failure, else pointer to new rule */ 128913885a66Sdarrenr /* Parameters: nat(I) - pointer to NAT session to create rule from */ 129013885a66Sdarrenr /* */ 129113885a66Sdarrenr /* This function creates a NAT rule that is based upon the reverse packet */ 129213885a66Sdarrenr /* flow associated with this NAT session. Thus if this NAT session was */ 129313885a66Sdarrenr /* created with a map rule then this function will create a rdr rule. */ 129413885a66Sdarrenr /* Only address fields and network interfaces are assigned in this function */ 129513885a66Sdarrenr /* and the address fields are formed such that an exact is required. If the */ 129613885a66Sdarrenr /* original rule had a netmask, that is not replicated here not is it */ 129713885a66Sdarrenr /* desired. The ultimate goal here is to create a NAT rule to support a NAT */ 129813885a66Sdarrenr /* session being created that does not have a user configured rule. The */ 129913885a66Sdarrenr /* classic example is supporting the FTP proxy, where a data channel needs */ 130013885a66Sdarrenr /* to be setup, based on the addresses used for the control connection. In */ 130113885a66Sdarrenr /* that case, this function is used to handle creating NAT rules to support */ 130213885a66Sdarrenr /* data connections with the PORT and EPRT commands. */ 130313885a66Sdarrenr /* ------------------------------------------------------------------------ */ 130413885a66Sdarrenr ipnat_t * 130572926482Sdarrenr ipf_proxy_rule_rev(nat_t *nat) 130613885a66Sdarrenr { 130713885a66Sdarrenr ipnat_t *old; 130813885a66Sdarrenr ipnat_t *ipn; 130913885a66Sdarrenr int size; 131013885a66Sdarrenr 131113885a66Sdarrenr old = nat->nat_ptr; 131213885a66Sdarrenr size = old->in_size; 131313885a66Sdarrenr 131413885a66Sdarrenr KMALLOCS(ipn, ipnat_t *, size); 131513885a66Sdarrenr if (ipn == NULL) 131613885a66Sdarrenr return NULL; 131713885a66Sdarrenr 131813885a66Sdarrenr bzero((char *)ipn, size); 131913885a66Sdarrenr 132013885a66Sdarrenr ipn->in_use = 1; 132113885a66Sdarrenr ipn->in_hits = 1; 132213885a66Sdarrenr ipn->in_ippip = 1; 132313885a66Sdarrenr ipn->in_apr = NULL; 132413885a66Sdarrenr ipn->in_size = size; 132513885a66Sdarrenr ipn->in_pr[0] = old->in_pr[1]; 132613885a66Sdarrenr ipn->in_pr[1] = old->in_pr[0]; 132713885a66Sdarrenr ipn->in_v[0] = old->in_v[1]; 132813885a66Sdarrenr ipn->in_v[1] = old->in_v[0]; 132913885a66Sdarrenr ipn->in_ifps[0] = old->in_ifps[1]; 133013885a66Sdarrenr ipn->in_ifps[1] = old->in_ifps[0]; 133113885a66Sdarrenr ipn->in_flags = (old->in_flags | IPN_PROXYRULE); 133213885a66Sdarrenr 133313885a66Sdarrenr ipn->in_nsrcip6 = nat->nat_odst6; 133413885a66Sdarrenr ipn->in_osrcip6 = nat->nat_ndst6; 133513885a66Sdarrenr 133613885a66Sdarrenr if ((old->in_redir & NAT_REDIRECT) != 0) { 133713885a66Sdarrenr ipn->in_redir = NAT_MAP; 133813885a66Sdarrenr if (ipn->in_v[0] == 4) { 133913885a66Sdarrenr ipn->in_snip = ntohl(nat->nat_odstaddr); 134013885a66Sdarrenr ipn->in_dnip = ntohl(nat->nat_nsrcaddr); 134113885a66Sdarrenr } else { 134213885a66Sdarrenr #ifdef USE_INET6 134313885a66Sdarrenr ipn->in_snip6 = nat->nat_odst6; 134413885a66Sdarrenr ipn->in_dnip6 = nat->nat_nsrc6; 134513885a66Sdarrenr #endif 134613885a66Sdarrenr } 134713885a66Sdarrenr ipn->in_ndstip6 = nat->nat_nsrc6; 134813885a66Sdarrenr ipn->in_odstip6 = nat->nat_osrc6; 134913885a66Sdarrenr } else { 135013885a66Sdarrenr ipn->in_redir = NAT_REDIRECT; 135113885a66Sdarrenr if (ipn->in_v[0] == 4) { 135213885a66Sdarrenr ipn->in_snip = ntohl(nat->nat_odstaddr); 135313885a66Sdarrenr ipn->in_dnip = ntohl(nat->nat_osrcaddr); 135413885a66Sdarrenr } else { 135513885a66Sdarrenr #ifdef USE_INET6 135613885a66Sdarrenr ipn->in_snip6 = nat->nat_odst6; 135713885a66Sdarrenr ipn->in_dnip6 = nat->nat_osrc6; 135813885a66Sdarrenr #endif 135913885a66Sdarrenr } 136013885a66Sdarrenr ipn->in_ndstip6 = nat->nat_osrc6; 136113885a66Sdarrenr ipn->in_odstip6 = nat->nat_nsrc6; 136213885a66Sdarrenr } 136313885a66Sdarrenr 136413885a66Sdarrenr IP6_SETONES(&ipn->in_osrcmsk6); 136513885a66Sdarrenr IP6_SETONES(&ipn->in_nsrcmsk6); 136613885a66Sdarrenr IP6_SETONES(&ipn->in_odstmsk6); 136713885a66Sdarrenr IP6_SETONES(&ipn->in_ndstmsk6); 136813885a66Sdarrenr 136913885a66Sdarrenr ipn->in_namelen = old->in_namelen; 137013885a66Sdarrenr ipn->in_ifnames[0] = old->in_ifnames[1]; 137113885a66Sdarrenr ipn->in_ifnames[1] = old->in_ifnames[0]; 137213885a66Sdarrenr bcopy(old->in_names, ipn->in_names, ipn->in_namelen); 137313885a66Sdarrenr MUTEX_INIT(&ipn->in_lock, "ipnat rev rule lock"); 137413885a66Sdarrenr 137513885a66Sdarrenr return ipn; 137613885a66Sdarrenr } 137713885a66Sdarrenr 137813885a66Sdarrenr 137913885a66Sdarrenr /* ------------------------------------------------------------------------ */ 138013885a66Sdarrenr /* Function: ipf_proxy_rule_fwd */ 138113885a66Sdarrenr /* Returns: ipnat_t * - NULL = failure, else pointer to new rule */ 138213885a66Sdarrenr /* Parameters: nat(I) - pointer to NAT session to create rule from */ 138313885a66Sdarrenr /* */ 138413885a66Sdarrenr /* The purpose and rationale of this function is much the same as the above */ 138513885a66Sdarrenr /* function, ipf_proxy_rule_rev, except that a rule is created that matches */ 138613885a66Sdarrenr /* the same direction as that of the existing NAT session. Thus if this NAT */ 138713885a66Sdarrenr /* session was created with a map rule then this function will also create */ 138813885a66Sdarrenr /* a data structure to represent a map rule. Whereas ipf_proxy_rule_rev is */ 138913885a66Sdarrenr /* used to support PORT/EPRT, this function supports PASV/EPSV. */ 139013885a66Sdarrenr /* ------------------------------------------------------------------------ */ 139113885a66Sdarrenr ipnat_t * 139272926482Sdarrenr ipf_proxy_rule_fwd(nat_t *nat) 139313885a66Sdarrenr { 139413885a66Sdarrenr ipnat_t *old; 139513885a66Sdarrenr ipnat_t *ipn; 139613885a66Sdarrenr int size; 139713885a66Sdarrenr 139813885a66Sdarrenr old = nat->nat_ptr; 139913885a66Sdarrenr size = old->in_size; 140013885a66Sdarrenr 140113885a66Sdarrenr KMALLOCS(ipn, ipnat_t *, size); 140213885a66Sdarrenr if (ipn == NULL) 140313885a66Sdarrenr return NULL; 140413885a66Sdarrenr 140513885a66Sdarrenr bzero((char *)ipn, size); 140613885a66Sdarrenr 140713885a66Sdarrenr ipn->in_use = 1; 140813885a66Sdarrenr ipn->in_hits = 1; 140913885a66Sdarrenr ipn->in_ippip = 1; 141013885a66Sdarrenr ipn->in_apr = NULL; 141113885a66Sdarrenr ipn->in_size = size; 141213885a66Sdarrenr ipn->in_pr[0] = old->in_pr[0]; 141313885a66Sdarrenr ipn->in_pr[1] = old->in_pr[1]; 141413885a66Sdarrenr ipn->in_v[0] = old->in_v[0]; 141513885a66Sdarrenr ipn->in_v[1] = old->in_v[1]; 141613885a66Sdarrenr ipn->in_ifps[0] = nat->nat_ifps[0]; 141713885a66Sdarrenr ipn->in_ifps[1] = nat->nat_ifps[1]; 141813885a66Sdarrenr ipn->in_flags = (old->in_flags | IPN_PROXYRULE); 141913885a66Sdarrenr 142013885a66Sdarrenr ipn->in_nsrcip6 = nat->nat_nsrc6; 142113885a66Sdarrenr ipn->in_osrcip6 = nat->nat_osrc6; 142213885a66Sdarrenr ipn->in_ndstip6 = nat->nat_ndst6; 142313885a66Sdarrenr ipn->in_odstip6 = nat->nat_odst6; 142413885a66Sdarrenr ipn->in_redir = old->in_redir; 142513885a66Sdarrenr 142613885a66Sdarrenr if (ipn->in_v[0] == 4) { 142713885a66Sdarrenr ipn->in_snip = ntohl(nat->nat_nsrcaddr); 142813885a66Sdarrenr ipn->in_dnip = ntohl(nat->nat_ndstaddr); 142913885a66Sdarrenr } else { 143013885a66Sdarrenr #ifdef USE_INET6 143113885a66Sdarrenr ipn->in_snip6 = nat->nat_nsrc6; 143213885a66Sdarrenr ipn->in_dnip6 = nat->nat_ndst6; 143313885a66Sdarrenr #endif 143413885a66Sdarrenr } 143513885a66Sdarrenr 143613885a66Sdarrenr IP6_SETONES(&ipn->in_osrcmsk6); 143713885a66Sdarrenr IP6_SETONES(&ipn->in_nsrcmsk6); 143813885a66Sdarrenr IP6_SETONES(&ipn->in_odstmsk6); 143913885a66Sdarrenr IP6_SETONES(&ipn->in_ndstmsk6); 144013885a66Sdarrenr 144113885a66Sdarrenr ipn->in_namelen = old->in_namelen; 144213885a66Sdarrenr ipn->in_ifnames[0] = old->in_ifnames[0]; 144313885a66Sdarrenr ipn->in_ifnames[1] = old->in_ifnames[1]; 144413885a66Sdarrenr bcopy(old->in_names, ipn->in_names, ipn->in_namelen); 144513885a66Sdarrenr MUTEX_INIT(&ipn->in_lock, "ipnat fwd rule lock"); 144613885a66Sdarrenr 144713885a66Sdarrenr return ipn; 144813885a66Sdarrenr } 1449