xref: /illumos-gate/usr/src/uts/common/inet/ipf/ip_proxy.c (revision b6c3f786)
1 /*
2  * Copyright (C) 1997-2003 by Darren Reed.
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  *
6  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
7  * Use is subject to license terms.
8  */
9 
10 #pragma ident	"%Z%%M%	%I%	%E% SMI"
11 
12 #if defined(KERNEL) || defined(_KERNEL)
13 # undef KERNEL
14 # undef _KERNEL
15 # define        KERNEL	1
16 # define        _KERNEL	1
17 #endif
18 #include <sys/errno.h>
19 #include <sys/types.h>
20 #include <sys/param.h>
21 #include <sys/time.h>
22 #include <sys/file.h>
23 #if !defined(AIX)
24 # include <sys/fcntl.h>
25 #endif
26 #if !defined(_KERNEL) && !defined(__KERNEL__)
27 # include <stdio.h>
28 # include <string.h>
29 # include <stdlib.h>
30 # include <ctype.h>
31 # define _KERNEL
32 # ifdef __OpenBSD__
33 struct file;
34 # endif
35 # include <sys/uio.h>
36 # undef _KERNEL
37 #endif
38 #if !defined(linux)
39 # include <sys/protosw.h>
40 #endif
41 #include <sys/socket.h>
42 #if defined(_KERNEL)
43 # if !defined(__NetBSD__) && !defined(sun) && !defined(__osf__) && \
44      !defined(__OpenBSD__) && !defined(__hpux) && !defined(__sgi) && \
45      !defined(AIX)
46 #  include <sys/ctype.h>
47 # endif
48 # include <sys/systm.h>
49 # if !defined(__SVR4) && !defined(__svr4__)
50 #  include <sys/mbuf.h>
51 # endif
52 #endif
53 #if defined(_KERNEL) && (__FreeBSD_version >= 220000)
54 # include <sys/filio.h>
55 # include <sys/fcntl.h>
56 # if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM)
57 #  include "opt_ipfilter.h"
58 # endif
59 #else
60 # include <sys/ioctl.h>
61 #endif
62 #if defined(__SVR4) || defined(__svr4__)
63 # include <sys/byteorder.h>
64 # ifdef _KERNEL
65 #  include <sys/dditypes.h>
66 #  include <sys/strsubr.h>
67 # endif
68 # include <sys/stream.h>
69 # include <sys/kmem.h>
70 # include <sys/pattr.h>
71 #endif
72 #if __FreeBSD__ > 2
73 # include <sys/queue.h>
74 #endif
75 #include <net/if.h>
76 #ifdef sun
77 # include <net/af.h>
78 #endif
79 #include <net/route.h>
80 #include <netinet/in.h>
81 #include <netinet/in_systm.h>
82 #include <netinet/ip.h>
83 #ifndef linux
84 # include <netinet/ip_var.h>
85 #endif
86 #include <netinet/tcp.h>
87 #include <netinet/udp.h>
88 #include <netinet/ip_icmp.h>
89 #include "netinet/ip_compat.h"
90 #include <netinet/tcpip.h>
91 #include "netinet/ipf_stack.h"
92 #include "netinet/ip_fil.h"
93 #include "netinet/ip_nat.h"
94 #include "netinet/ip_state.h"
95 #include "netinet/ip_proxy.h"
96 #if (__FreeBSD_version >= 300000)
97 # include <sys/malloc.h>
98 #endif
99 
100 #include "netinet/ip_ftp_pxy.c"
101 #include "netinet/ip_rcmd_pxy.c"
102 # include "netinet/ip_pptp_pxy.c"
103 #if defined(_KERNEL)
104 # include "netinet/ip_irc_pxy.c"
105 # include "netinet/ip_raudio_pxy.c"
106 # include "netinet/ip_h323_pxy.c"
107 # include "netinet/ip_netbios_pxy.c"
108 #endif
109 #include "netinet/ip_ipsec_pxy.c"
110 #include "netinet/ip_rpcb_pxy.c"
111 
112 /* END OF INCLUDES */
113 
114 #if !defined(lint)
115 static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.62.2.14 2005/06/18 02:41:33 darrenr Exp $";
116 #endif
117 
118 static int appr_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int ));
119 
120 #define	AP_SESS_SIZE	53
121 
122 #if defined(_KERNEL)
123 int		ipf_proxy_debug = 0;
124 #else
125 int		ipf_proxy_debug = 2;
126 #endif
127 
128 static aproxy_t	lcl_ap_proxies[] = {
129 #ifdef	IPF_FTP_PROXY
130 	{ NULL, "ftp", (char)IPPROTO_TCP, 0, 0, NULL, ippr_ftp_init, ippr_ftp_fini,
131 	  ippr_ftp_new, NULL, ippr_ftp_in, ippr_ftp_out, NULL },
132 #endif
133 #ifdef	IPF_IRC_PROXY
134 	{ NULL, "irc", (char)IPPROTO_TCP, 0, 0, NULL, ippr_irc_init, ippr_irc_fini,
135 	  ippr_irc_new, NULL, NULL, ippr_irc_out, NULL, NULL },
136 #endif
137 #ifdef	IPF_RCMD_PROXY
138 	{ NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, NULL, ippr_rcmd_init, ippr_rcmd_fini,
139 	  ippr_rcmd_new, NULL, ippr_rcmd_in, ippr_rcmd_out, NULL, NULL },
140 #endif
141 #ifdef	IPF_RAUDIO_PROXY
142 	{ NULL, "raudio", (char)IPPROTO_TCP, 0, 0, NULL, ippr_raudio_init, ippr_raudio_fini,
143 	  ippr_raudio_new, NULL, ippr_raudio_in, ippr_raudio_out, NULL, NULL },
144 #endif
145 #ifdef	IPF_MSNRPC_PROXY
146 	{ NULL, "msnrpc", (char)IPPROTO_TCP, 0, 0, NULL, ippr_msnrpc_init, ippr_msnrpc_fini,
147 	  ippr_msnrpc_new, NULL, ippr_msnrpc_in, ippr_msnrpc_out, NULL, NULL },
148 #endif
149 #ifdef	IPF_NETBIOS_PROXY
150 	{ NULL, "netbios", (char)IPPROTO_UDP, 0, 0, NULL, ippr_netbios_init, ippr_netbios_fini,
151 	  NULL, NULL, NULL, ippr_netbios_out, NULL, NULL },
152 #endif
153 #ifdef	IPF_IPSEC_PROXY
154 	{ NULL, "ipsec", (char)IPPROTO_UDP, 0, 0, NULL,
155 	  ippr_ipsec_init, ippr_ipsec_fini, ippr_ipsec_new, ippr_ipsec_del,
156 	  ippr_ipsec_inout, ippr_ipsec_inout, ippr_ipsec_match, NULL },
157 #endif
158 #ifdef	IPF_PPTP_PROXY
159 	{ NULL, "pptp", (char)IPPROTO_TCP, 0, 0, NULL,
160 	  ippr_pptp_init, ippr_pptp_fini, ippr_pptp_new, ippr_pptp_del,
161 	  ippr_pptp_inout, ippr_pptp_inout, NULL, NULL },
162 #endif
163 #ifdef  IPF_H323_PROXY
164 	{ NULL, "h323", (char)IPPROTO_TCP, 0, 0, NULL, ippr_h323_init, ippr_h323_fini,
165 	  ippr_h323_new, ippr_h323_del, ippr_h323_in, NULL, NULL },
166 	{ NULL, "h245", (char)IPPROTO_TCP, 0, 0, NULL, NULL, NULL,
167 	  ippr_h245_new, NULL, NULL, ippr_h245_out, NULL },
168 #endif
169 #ifdef	IPF_RPCB_PROXY
170 # if 0
171 	{ NULL, "rpcbt", (char)IPPROTO_TCP, 0, 0, NULL,
172 	  ippr_rpcb_init, ippr_rpcb_fini, ippr_rpcb_new, ippr_rpcb_del,
173 	  ippr_rpcb_in, ippr_rpcb_out, NULL, NULL },
174 # endif
175 	{ NULL, "rpcbu", (char)IPPROTO_UDP, 0, 0, NULL,
176 	  ippr_rpcb_init, ippr_rpcb_fini, ippr_rpcb_new, ippr_rpcb_del,
177 	  ippr_rpcb_in, ippr_rpcb_out, NULL, NULL },
178 #endif
179 	{ NULL, "", '\0', 0, 0, NULL, NULL, NULL, NULL, NULL }
180 };
181 
182 /*
183  * Dynamically add a new kernel proxy.  Ensure that it is unique in the
184  * collection compiled in and dynamically added.
185  */
186 int appr_add(ap, ifs)
187 aproxy_t *ap;
188 ipf_stack_t *ifs;
189 {
190 	aproxy_t *a;
191 
192 	for (a = ifs->ifs_ap_proxies; a->apr_p; a++)
193 		if ((a->apr_p == ap->apr_p) &&
194 		    !strncmp(a->apr_label, ap->apr_label,
195 			     sizeof(ap->apr_label))) {
196 			if (ipf_proxy_debug > 1)
197 				printf("appr_add: %s/%d already present (B)\n",
198 				       a->apr_label, a->apr_p);
199 			return -1;
200 		}
201 
202 	for (a = ifs->ifs_ap_proxylist; a->apr_p; a = a->apr_next)
203 		if ((a->apr_p == ap->apr_p) &&
204 		    !strncmp(a->apr_label, ap->apr_label,
205 			     sizeof(ap->apr_label))) {
206 			if (ipf_proxy_debug > 1)
207 				printf("appr_add: %s/%d already present (D)\n",
208 				       a->apr_label, a->apr_p);
209 			return -1;
210 		}
211 	ap->apr_next = ifs->ifs_ap_proxylist;
212 	ifs->ifs_ap_proxylist = ap;
213 	if (ap->apr_init != NULL)
214 		return (*ap->apr_init)(&ap->apr_private, ifs);
215 
216 	return 0;
217 }
218 
219 
220 /*
221  * Check to see if the proxy this control request has come through for
222  * exists, and if it does and it has a control function then invoke that
223  * control function.
224  */
225 int appr_ctl(ctl, ifs)
226 ap_ctl_t *ctl;
227 ipf_stack_t *ifs;
228 {
229 	aproxy_t *a;
230 	int error;
231 
232 	a = appr_lookup(ctl->apc_p, ctl->apc_label, ifs);
233 	if (a == NULL) {
234 		if (ipf_proxy_debug > 1)
235 			printf("appr_ctl: can't find %s/%d\n",
236 				ctl->apc_label, ctl->apc_p);
237 		error = ESRCH;
238 	} else if (a->apr_ctl == NULL) {
239 		if (ipf_proxy_debug > 1)
240 			printf("appr_ctl: no ctl function for %s/%d\n",
241 				ctl->apc_label, ctl->apc_p);
242 		error = ENXIO;
243 	} else {
244 		error = (*a->apr_ctl)(a, ctl, a->apr_private);
245 		if ((error != 0) && (ipf_proxy_debug > 1))
246 			printf("appr_ctl: %s/%d ctl error %d\n",
247 				a->apr_label, a->apr_p, error);
248 	}
249 	return error;
250 }
251 
252 
253 /*
254  * Delete a proxy that has been added dynamically from those available.
255  * If it is in use, return 1 (do not destroy NOW), not in use 0 or -1
256  * if it cannot be matched.
257  */
258 int appr_del(ap, ifs)
259 aproxy_t *ap;
260 ipf_stack_t *ifs;
261 {
262 	aproxy_t *a, **app;
263 
264 	for (app = &ifs->ifs_ap_proxylist; ((a = *app) != NULL);
265 	     app = &a->apr_next)
266 		if (a == ap) {
267 			a->apr_flags |= APR_DELETE;
268 			*app = a->apr_next;
269 			if (ap->apr_ref != 0) {
270 				if (ipf_proxy_debug > 2)
271 					printf("appr_del: orphaning %s/%d\n",
272 						ap->apr_label, ap->apr_p);
273 				return 1;
274 			}
275 			return 0;
276 		}
277 	if (ipf_proxy_debug > 1)
278 		printf("appr_del: proxy %lx not found\n", (u_long)ap);
279 	return -1;
280 }
281 
282 
283 /*
284  * Return 1 if the packet is a good match against a proxy, else 0.
285  */
286 int appr_ok(fin, tcp, nat)
287 fr_info_t *fin;
288 tcphdr_t *tcp;
289 ipnat_t *nat;
290 {
291 	aproxy_t *apr = nat->in_apr;
292 	u_short dport = nat->in_dport;
293 
294 	if ((apr == NULL) || (apr->apr_flags & APR_DELETE) ||
295 	    (fin->fin_p != apr->apr_p))
296 		return 0;
297 	if ((tcp == NULL) && dport)
298 		return 0;
299 	return 1;
300 }
301 
302 
303 int appr_ioctl(data, cmd, mode, ifs)
304 caddr_t data;
305 ioctlcmd_t cmd;
306 int mode;
307 ipf_stack_t *ifs;
308 {
309 	ap_ctl_t ctl;
310 	caddr_t ptr;
311 	int error;
312 
313 	mode = mode;	/* LINT */
314 
315 	switch (cmd)
316 	{
317 	case SIOCPROXY :
318 		(void) BCOPYIN(data, &ctl, sizeof(ctl));
319 		ptr = NULL;
320 
321 		if (ctl.apc_dsize > 0) {
322 			KMALLOCS(ptr, caddr_t, ctl.apc_dsize);
323 			if (ptr == NULL)
324 				error = ENOMEM;
325 			else {
326 				error = copyinptr(ctl.apc_data, ptr,
327 						  ctl.apc_dsize);
328 				if (error == 0)
329 					ctl.apc_data = ptr;
330 			}
331 		} else {
332 			ctl.apc_data = NULL;
333 			error = 0;
334 		}
335 
336 		if (error == 0)
337 			error = appr_ctl(&ctl, ifs);
338 
339 		if ((ctl.apc_dsize > 0) && (ptr != NULL) &&
340 		    (ctl.apc_data == ptr)) {
341 			KFREES(ptr, ctl.apc_dsize);
342 		}
343 		break;
344 
345 	default :
346 		error = EINVAL;
347 	}
348 	return error;
349 }
350 
351 
352 /*
353  * If a proxy has a match function, call that to do extended packet
354  * matching.
355  */
356 int appr_match(fin, nat)
357 fr_info_t *fin;
358 nat_t *nat;
359 {
360 	aproxy_t *apr;
361 	ipnat_t *ipn;
362 	int result;
363 
364 	ipn = nat->nat_ptr;
365 	if (ipf_proxy_debug > 8)
366 		printf("appr_match(%lx,%lx) aps %lx ptr %lx\n",
367 			(u_long)fin, (u_long)nat, (u_long)nat->nat_aps,
368 			(u_long)ipn);
369 
370 	if ((fin->fin_flx & (FI_SHORT|FI_BAD)) != 0) {
371 		if (ipf_proxy_debug > 0)
372 			printf("appr_match: flx 0x%x (BAD|SHORT)\n",
373 				fin->fin_flx);
374 		return -1;
375 	}
376 
377 	apr = ipn->in_apr;
378 	if ((apr == NULL) || (apr->apr_flags & APR_DELETE)) {
379 		if (ipf_proxy_debug > 0)
380 			printf("appr_match:apr %lx apr_flags 0x%x\n",
381 				(u_long)apr, apr ? apr->apr_flags : 0);
382 		return -1;
383 	}
384 
385 	if (apr->apr_match != NULL) {
386 		result = (*apr->apr_match)(fin, nat->nat_aps, nat, apr->apr_private);
387 		if (result != 0) {
388 			if (ipf_proxy_debug > 4)
389 				printf("appr_match: result %d\n", result);
390 			return -1;
391 		}
392 	}
393 	return 0;
394 }
395 
396 
397 /*
398  * Allocate a new application proxy structure and fill it in with the
399  * relevant details.  call the init function once complete, prior to
400  * returning.
401  */
402 int appr_new(fin, nat)
403 fr_info_t *fin;
404 nat_t *nat;
405 {
406 	register ap_session_t *aps;
407 	aproxy_t *apr;
408 	ipf_stack_t *ifs = fin->fin_ifs;
409 
410 	if (ipf_proxy_debug > 8)
411 		printf("appr_new(%lx,%lx) \n", (u_long)fin, (u_long)nat);
412 
413 	if ((nat->nat_ptr == NULL) || (nat->nat_aps != NULL)) {
414 		if (ipf_proxy_debug > 0)
415 			printf("appr_new: nat_ptr %lx nat_aps %lx\n",
416 				(u_long)nat->nat_ptr, (u_long)nat->nat_aps);
417 		return -1;
418 	}
419 
420 	apr = nat->nat_ptr->in_apr;
421 
422 	if ((apr->apr_flags & APR_DELETE) ||
423 	    (fin->fin_p != apr->apr_p)) {
424 		if (ipf_proxy_debug > 2)
425 			printf("appr_new: apr_flags 0x%x p %d/%d\n",
426 				apr->apr_flags, fin->fin_p, apr->apr_p);
427 		return -1;
428 	}
429 
430 	KMALLOC(aps, ap_session_t *);
431 	if (!aps) {
432 		if (ipf_proxy_debug > 0)
433 			printf("appr_new: malloc failed (%lu)\n",
434 				(u_long)sizeof(ap_session_t));
435 		return -1;
436 	}
437 
438 	bzero((char *)aps, sizeof(*aps));
439 	aps->aps_p = fin->fin_p;
440 	aps->aps_data = NULL;
441 	aps->aps_apr = apr;
442 	aps->aps_psiz = 0;
443 	if (apr->apr_new != NULL)
444 		if ((*apr->apr_new)(fin, aps, nat, apr->apr_private) == -1) {
445 			if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) {
446 				KFREES(aps->aps_data, aps->aps_psiz);
447 			}
448 			KFREE(aps);
449 			if (ipf_proxy_debug > 2)
450 				printf("appr_new: new(%lx) failed\n",
451 					(u_long)apr->apr_new);
452 			return -1;
453 		}
454 	aps->aps_nat = nat;
455 	aps->aps_next = ifs->ifs_ap_sess_list;
456 	ifs->ifs_ap_sess_list = aps;
457 	nat->nat_aps = aps;
458 
459 	return 0;
460 }
461 
462 
463 /*
464  * Check to see if a packet should be passed through an active proxy routine
465  * if one has been setup for it.  We don't need to check the checksum here if
466  * IPFILTER_CKSUM is defined because if it is, a failed check causes FI_BAD
467  * to be set.
468  */
469 int appr_check(fin, nat)
470 fr_info_t *fin;
471 nat_t *nat;
472 {
473 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID)
474 	mb_t *m;
475 	int dosum = 1;
476 #endif
477 	tcphdr_t *tcp = NULL;
478 	udphdr_t *udp = NULL;
479 	void *tcpudp = NULL;
480 	u_short *csump;
481 	ap_session_t *aps;
482 	aproxy_t *apr;
483 	ip_t *ip;
484 	short rv;
485 	int err;
486 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi)
487 	u_32_t s1, s2, sd;
488 #endif
489 	ipf_stack_t *ifs = fin->fin_ifs;
490 
491 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
492 	net_data_t net_data_p;
493 	if (fin->fin_v == 4)
494 		net_data_p = ifs->ifs_ipf_ipv4;
495 	else
496 		net_data_p = ifs->ifs_ipf_ipv6;
497 #endif
498 
499 	if (fin->fin_flx & FI_BAD) {
500 		if (ipf_proxy_debug > 0)
501 			printf("appr_check: flx 0x%x (BAD)\n", fin->fin_flx);
502 		return -1;
503 	}
504 
505 #ifndef IPFILTER_CKSUM
506 	if ((fin->fin_out == 0) && (fr_checkl4sum(fin) == -1)) {
507 		if (ipf_proxy_debug > 0)
508 			printf("appr_check: l4 checksum failure %d\n",
509 				fin->fin_p);
510 		if (fin->fin_p == IPPROTO_TCP)
511 			ifs->ifs_frstats[fin->fin_out].fr_tcpbad++;
512 		return -1;
513 	}
514 #endif
515 
516 	aps = nat->nat_aps;
517 	if ((aps != NULL) && (aps->aps_p == fin->fin_p)) {
518 		/*
519 		 * If there is data in this packet to be proxied then try and
520 		 * get it all into the one buffer, else drop it.
521 		 */
522 #if defined(MENTAT) || defined(HAVE_M_PULLDOWN)
523 		if ((fin->fin_dlen > 0) && !(fin->fin_flx & FI_COALESCE))
524 			if (fr_coalesce(fin) == -1) {
525 				if (ipf_proxy_debug > 0)
526 					printf("appr_check: fr_coalesce failed %x\n", fin->fin_flx);
527 				return -1;
528 			}
529 #endif
530 		ip = fin->fin_ip;
531 
532 		switch (fin->fin_p)
533 		{
534 		case IPPROTO_TCP :
535 			tcp = (tcphdr_t *)fin->fin_dp;
536 
537 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID)
538 			m = fin->fin_qfm;
539 			if (dohwcksum && (m->b_ick_flag == ICK_VALID))
540 				dosum = 0;
541 #endif
542 			/*
543 			 * Don't bother the proxy with these...or in fact,
544 			 * should we free up proxy stuff when seen?
545 			 */
546 			if ((fin->fin_tcpf & TH_RST) != 0)
547 				break;
548 			/*FALLTHROUGH*/
549 		case IPPROTO_UDP :
550 			udp = (udphdr_t *)fin->fin_dp;
551 			break;
552 		default :
553 			break;
554 		}
555 
556 		apr = aps->aps_apr;
557 		err = 0;
558 		if (fin->fin_out != 0) {
559 			if (apr->apr_outpkt != NULL)
560 				err = (*apr->apr_outpkt)(fin, aps, nat, apr->apr_private);
561 		} else {
562 			if (apr->apr_inpkt != NULL)
563 				err = (*apr->apr_inpkt)(fin, aps, nat, apr->apr_private);
564 		}
565 
566 		rv = APR_EXIT(err);
567 		if (((ipf_proxy_debug > 0) && (rv != 0)) ||
568 		    (ipf_proxy_debug > 8))
569 			printf("appr_check: out %d err %x rv %d\n",
570 				fin->fin_out, err, rv);
571 		if (rv == 1)
572 			return -1;
573 
574 		if (rv == 2) {
575 			appr_free(apr);
576 			nat->nat_aps = NULL;
577 			return -1;
578 		}
579 
580 		/*
581 		 * If err != 0 then the data size of the packet has changed
582 		 * so we need to recalculate the header checksums for the
583 		 * packet.
584 		 * inbound packets always need to be adjusted.
585 		 */
586 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi)
587 		if (err != 0) {
588 			short adjlen = err & 0xffff;
589 
590 			s1 = LONG_SUM(ip->ip_len - adjlen);
591 			s2 = LONG_SUM(ip->ip_len);
592 			CALC_SUMD(s1, s2, sd);
593 			sd = (sd & 0xffff) + (sd >> 16);
594 			if (!fin->fin_out ||
595 			    !NET_IS_HCK_L3_FULL(net_data_p, fin->fin_m))
596 				fix_outcksum(&ip->ip_sum, sd);
597 		}
598 #endif
599 
600 		/*
601 		 * For TCP packets, we may need to adjust the sequence and
602 		 * acknowledgement numbers to reflect changes in size of the
603 		 * data stream.
604 		 *
605 		 * For both TCP and UDP, recalculate the layer 4 checksum in
606 		 * software checksum case, as we can't tell if data has been
607 		 * changed or not.
608 		 */
609 		if (tcp != NULL) {
610 			tcpudp = tcp;
611 			csump = &tcp->th_sum;
612 			(void) appr_fixseqack(fin, ip, aps, APR_INC(err));
613 		} else if (udp != NULL) {
614 			tcpudp = udp;
615 			csump = &udp->uh_sum;
616 		}
617 
618 		if (tcpudp) {
619 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(MENTAT)
620 			if (!fin->fin_out) {
621 				/*
622 				 * We are incapable of adjusting partial hcksum
623 				 * result for inbound packets here, as the
624 				 * partial hcksum calculation range might not
625 				 * cover the whole payload, and the payload data
626 				 * might be changed by proxy.
627 				 */
628 				DB_CKSUMFLAGS(fin->fin_m) &= ~HCK_PARTIALCKSUM;
629 
630 				/* Inbound packets always need recalculation. */
631 				*csump = fr_cksum(fin->fin_qfm, ip,
632 						  fin->fin_p, tcpudp);
633 			} else if (NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) {
634 				if (err != 0) {
635 					DB_CKSUMEND(fin->fin_m) += (short)err;
636 					fix_incksum(csump, sd);
637 				}
638 			} else if (!NET_IS_HCK_L4_FULL(net_data_p, fin->fin_m))
639 				*csump = fr_cksum(fin->fin_qfm, ip,
640 						  fin->fin_p, tcpudp);
641 #else
642 			*csump = fr_cksum(fin->fin_m, ip, fin->fin_p, tcpudp);
643 #endif
644 		}
645 		aps->aps_bytes += fin->fin_plen;
646 		aps->aps_pkts++;
647 		return 1;
648 	}
649 	return 0;
650 }
651 
652 
653 /*
654  * Search for an proxy by the protocol it is being used with and its name.
655  */
656 aproxy_t *appr_lookup(pr, name, ifs)
657 u_int pr;
658 char *name;
659 ipf_stack_t *ifs;
660 {
661 	aproxy_t *ap;
662 
663 	if (ipf_proxy_debug > 8)
664 		printf("appr_lookup(%d,%s)\n", pr, name);
665 
666 	for (ap = ifs->ifs_ap_proxies; ap->apr_p; ap++)
667 		if ((ap->apr_p == pr) &&
668 		    !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) {
669 			ap->apr_ref++;
670 			return ap;
671 		}
672 
673 	for (ap = ifs->ifs_ap_proxylist; ap; ap = ap->apr_next)
674 		if ((ap->apr_p == pr) &&
675 		    !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) {
676 			ap->apr_ref++;
677 			return ap;
678 		}
679 	if (ipf_proxy_debug > 2)
680 		printf("appr_lookup: failed for %d/%s\n", pr, name);
681 	return NULL;
682 }
683 
684 
685 void appr_free(ap)
686 aproxy_t *ap;
687 {
688 	ap->apr_ref--;
689 }
690 
691 
692 void aps_free(aps, ifs)
693 ap_session_t *aps;
694 ipf_stack_t *ifs;
695 {
696 	ap_session_t *a, **ap;
697 	aproxy_t *apr;
698 
699 	if (!aps)
700 		return;
701 
702 	for (ap = &ifs->ifs_ap_sess_list; ((a = *ap) != NULL); ap = &a->aps_next)
703 		if (a == aps) {
704 			*ap = a->aps_next;
705 			break;
706 		}
707 
708 	apr = aps->aps_apr;
709 	if ((apr != NULL) && (apr->apr_del != NULL))
710 		(*apr->apr_del)(aps, apr->apr_private, ifs);
711 
712 	if ((aps->aps_data != NULL) && (aps->aps_psiz != 0))
713 		KFREES(aps->aps_data, aps->aps_psiz);
714 	KFREE(aps);
715 }
716 
717 
718 /*
719  * returns 2 if ack or seq number in TCP header is changed, returns 0 otherwise
720  */
721 static int appr_fixseqack(fin, ip, aps, inc)
722 fr_info_t *fin;
723 ip_t *ip;
724 ap_session_t *aps;
725 int inc;
726 {
727 	int sel, ch = 0, out, nlen;
728 	u_32_t seq1, seq2;
729 	tcphdr_t *tcp;
730 	short inc2;
731 
732 	tcp = (tcphdr_t *)fin->fin_dp;
733 	out = fin->fin_out;
734 	/*
735 	 * ip_len has already been adjusted by 'inc'.
736 	 */
737 	nlen = ip->ip_len;
738 	nlen -= (IP_HL(ip) << 2) + (TCP_OFF(tcp) << 2);
739 
740 	inc2 = inc;
741 	inc = (int)inc2;
742 
743 	if (out != 0) {
744 		seq1 = (u_32_t)ntohl(tcp->th_seq);
745 		sel = aps->aps_sel[out];
746 
747 		/* switch to other set ? */
748 		if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) &&
749 		    (seq1 > aps->aps_seqmin[!sel])) {
750 			if (ipf_proxy_debug > 7)
751 				printf("proxy out switch set seq %d -> %d %x > %x\n",
752 					sel, !sel, seq1,
753 					aps->aps_seqmin[!sel]);
754 			sel = aps->aps_sel[out] = !sel;
755 		}
756 
757 		if (aps->aps_seqoff[sel]) {
758 			seq2 = aps->aps_seqmin[sel] - aps->aps_seqoff[sel];
759 			if (seq1 > seq2) {
760 				seq2 = aps->aps_seqoff[sel];
761 				seq1 += seq2;
762 				tcp->th_seq = htonl(seq1);
763 				ch = 1;
764 			}
765 		}
766 
767 		if (inc && (seq1 > aps->aps_seqmin[!sel])) {
768 			aps->aps_seqmin[sel] = seq1 + nlen - 1;
769 			aps->aps_seqoff[sel] = aps->aps_seqoff[sel] + inc;
770 			if (ipf_proxy_debug > 7)
771 				printf("proxy seq set %d at %x to %d + %d\n",
772 					sel, aps->aps_seqmin[sel],
773 					aps->aps_seqoff[sel], inc);
774 		}
775 
776 		/***/
777 
778 		seq1 = ntohl(tcp->th_ack);
779 		sel = aps->aps_sel[1 - out];
780 
781 		/* switch to other set ? */
782 		if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) &&
783 		    (seq1 > aps->aps_ackmin[!sel])) {
784 			if (ipf_proxy_debug > 7)
785 				printf("proxy out switch set ack %d -> %d %x > %x\n",
786 					sel, !sel, seq1,
787 					aps->aps_ackmin[!sel]);
788 			sel = aps->aps_sel[1 - out] = !sel;
789 		}
790 
791 		if (aps->aps_ackoff[sel] && (seq1 > aps->aps_ackmin[sel])) {
792 			seq2 = aps->aps_ackoff[sel];
793 			tcp->th_ack = htonl(seq1 - seq2);
794 			ch = 1;
795 		}
796 	} else {
797 		seq1 = ntohl(tcp->th_seq);
798 		sel = aps->aps_sel[out];
799 
800 		/* switch to other set ? */
801 		if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) &&
802 		    (seq1 > aps->aps_ackmin[!sel])) {
803 			if (ipf_proxy_debug > 7)
804 				printf("proxy in switch set ack %d -> %d %x > %x\n",
805 					sel, !sel, seq1, aps->aps_ackmin[!sel]);
806 			sel = aps->aps_sel[out] = !sel;
807 		}
808 
809 		if (aps->aps_ackoff[sel]) {
810 			seq2 = aps->aps_ackmin[sel] - aps->aps_ackoff[sel];
811 			if (seq1 > seq2) {
812 				seq2 = aps->aps_ackoff[sel];
813 				seq1 += seq2;
814 				tcp->th_seq = htonl(seq1);
815 				ch = 1;
816 			}
817 		}
818 
819 		if (inc && (seq1 > aps->aps_ackmin[!sel])) {
820 			aps->aps_ackmin[!sel] = seq1 + nlen - 1;
821 			aps->aps_ackoff[!sel] = aps->aps_ackoff[sel] + inc;
822 
823 			if (ipf_proxy_debug > 7)
824 				printf("proxy ack set %d at %x to %d + %d\n",
825 					!sel, aps->aps_seqmin[!sel],
826 					aps->aps_seqoff[sel], inc);
827 		}
828 
829 		/***/
830 
831 		seq1 = ntohl(tcp->th_ack);
832 		sel = aps->aps_sel[1 - out];
833 
834 		/* switch to other set ? */
835 		if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) &&
836 		    (seq1 > aps->aps_seqmin[!sel])) {
837 			if (ipf_proxy_debug > 7)
838 				printf("proxy in switch set seq %d -> %d %x > %x\n",
839 					sel, !sel, seq1, aps->aps_seqmin[!sel]);
840 			sel = aps->aps_sel[1 - out] = !sel;
841 		}
842 
843 		if (aps->aps_seqoff[sel] != 0) {
844 			if (ipf_proxy_debug > 7)
845 				printf("sel %d seqoff %d seq1 %x seqmin %x\n",
846 					sel, aps->aps_seqoff[sel], seq1,
847 					aps->aps_seqmin[sel]);
848 			if (seq1 > aps->aps_seqmin[sel]) {
849 				seq2 = aps->aps_seqoff[sel];
850 				tcp->th_ack = htonl(seq1 - seq2);
851 				ch = 1;
852 			}
853 		}
854 	}
855 
856 	if (ipf_proxy_debug > 8)
857 		printf("appr_fixseqack: seq %x ack %x\n",
858 			ntohl(tcp->th_seq), ntohl(tcp->th_ack));
859 	return ch ? 2 : 0;
860 }
861 
862 
863 /*
864  * Initialise hook for kernel application proxies.
865  * Call the initialise routine for all the compiled in kernel proxies.
866  */
867 int appr_init(ifs)
868 ipf_stack_t *ifs;
869 {
870 	aproxy_t *ap;
871 	int err =  0;
872 
873 	/* Since the refcnt is used we make a copy of lcl_ap_proxies */
874 	KMALLOCS(ifs->ifs_ap_proxies, aproxy_t *, sizeof (lcl_ap_proxies));
875 	bcopy(lcl_ap_proxies, ifs->ifs_ap_proxies, sizeof (lcl_ap_proxies));
876 
877 	for (ap = ifs->ifs_ap_proxies; ap->apr_p; ap++) {
878 		if (ap->apr_init != NULL) {
879 			err = (*ap->apr_init)(&ap->apr_private, ifs);
880 			if (err != 0)
881 				break;
882 		}
883 	}
884 	return 0;
885 }
886 
887 
888 /*
889  * Unload hook for kernel application proxies.
890  * Call the finialise routine for all the compiled in kernel proxies.
891  */
892 void appr_unload(ifs)
893 ipf_stack_t *ifs;
894 {
895 	aproxy_t *ap;
896 	if(ifs->ifs_ap_proxies == NULL)
897 		return;
898 
899 	for (ap = ifs->ifs_ap_proxies; ap->apr_p; ap++)
900 		if (ap->apr_fini != NULL)
901 			(*ap->apr_fini)(&ap->apr_private, ifs);
902 	for (ap = ifs->ifs_ap_proxylist; ap; ap = ap->apr_next)
903 		if (ap->apr_fini != NULL)
904 			(*ap->apr_fini)(&ap->apr_private, ifs);
905 
906 	KFREES(ifs->ifs_ap_proxies, sizeof (lcl_ap_proxies));
907 	ifs->ifs_ap_proxies = NULL;
908 }
909