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