xref: /netbsd-src/sys/external/bsd/ipf/netinet/ip_proxy.c (revision 5b28f239895d55856221c590945769250e289f5f)
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