ip_proxy.c revision 98004
153642Sguido/*
292685Sdarrenr * Copyright (C) 1997-2002 by Darren Reed.
353642Sguido *
480482Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
553642Sguido */
653642Sguido
753642Sguido#if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL)
853642Sguido# define	_KERNEL
953642Sguido#endif
1053642Sguido
1192685Sdarrenr#ifdef __sgi
1292685Sdarrenr# include <sys/ptimers.h>
1392685Sdarrenr#endif
1453642Sguido#include <sys/errno.h>
1553642Sguido#include <sys/types.h>
1653642Sguido#include <sys/param.h>
1753642Sguido#include <sys/time.h>
1853642Sguido#include <sys/file.h>
1953642Sguido#if !defined(__FreeBSD_version)
2053642Sguido# include <sys/ioctl.h>
2153642Sguido#endif
2253642Sguido#include <sys/fcntl.h>
2353642Sguido#if !defined(_KERNEL) && !defined(KERNEL)
2453642Sguido# include <stdio.h>
2553642Sguido# include <string.h>
2653642Sguido# include <stdlib.h>
2753642Sguido#endif
2853642Sguido#ifndef	linux
2953642Sguido# include <sys/protosw.h>
3053642Sguido#endif
3153642Sguido#include <sys/socket.h>
3253642Sguido#if defined(_KERNEL)
3353642Sguido# if !defined(linux)
3453642Sguido#  include <sys/systm.h>
3553642Sguido# else
3653642Sguido#  include <linux/string.h>
3753642Sguido# endif
3853642Sguido#endif
3953642Sguido#if !defined(__SVR4) && !defined(__svr4__)
4053642Sguido# ifndef linux
4153642Sguido#  include <sys/mbuf.h>
4253642Sguido# endif
4353642Sguido#else
4453642Sguido# include <sys/byteorder.h>
4553642Sguido# ifdef _KERNEL
4653642Sguido#  include <sys/dditypes.h>
4753642Sguido# endif
4853642Sguido# include <sys/stream.h>
4953642Sguido# include <sys/kmem.h>
5053642Sguido#endif
5153642Sguido#if __FreeBSD__ > 2
5253642Sguido# include <sys/queue.h>
5353642Sguido#endif
5453642Sguido#include <net/if.h>
5553642Sguido#ifdef sun
5653642Sguido# include <net/af.h>
5753642Sguido#endif
5853642Sguido#include <net/route.h>
5953642Sguido#include <netinet/in.h>
6053642Sguido#include <netinet/in_systm.h>
6153642Sguido#include <netinet/ip.h>
6253642Sguido#ifndef linux
6353642Sguido# include <netinet/ip_var.h>
6453642Sguido#endif
6553642Sguido#include <netinet/tcp.h>
6653642Sguido#include <netinet/udp.h>
6753642Sguido#include <netinet/ip_icmp.h>
6853642Sguido#include "netinet/ip_compat.h"
6953642Sguido#include <netinet/tcpip.h>
7053642Sguido#include "netinet/ip_fil.h"
7153642Sguido#include "netinet/ip_nat.h"
7253642Sguido#include "netinet/ip_state.h"
7392685Sdarrenr#include "netinet/ip_proxy.h"
7453642Sguido#if (__FreeBSD_version >= 300000)
7553642Sguido# include <sys/malloc.h>
7653642Sguido#endif
7753642Sguido
7880482Sdarrenr#if !defined(lint)
7980482Sdarrenr/* static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.9.2.6 2001/07/15 22:06:15 darrenr Exp $"; */
8080482Sdarrenrstatic const char rcsid[] = "@(#)$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_proxy.c 98004 2002-06-07 08:56:30Z darrenr $";
8180482Sdarrenr#endif
8253642Sguido
8392685Sdarrenr#if defined(_KERNEL) && (SOLARIS || defined(__sgi))
8492685Sdarrenrextern  KRWLOCK_T       ipf_nat, ipf_state;
8592685Sdarrenr#endif
8680482Sdarrenr
8753642Sguido#ifndef MIN
8853642Sguido#define MIN(a,b)        (((a)<(b))?(a):(b))
8953642Sguido#endif
9053642Sguido
9153642Sguidostatic int appr_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int ));
9253642Sguido
9353642Sguido
9453642Sguido#define	AP_SESS_SIZE	53
9553642Sguido
9695563Sdarrenr#include "netinet/ip_ftp_pxy.c"
9792685Sdarrenr#if defined(_KERNEL)
9853642Sguido#include "netinet/ip_rcmd_pxy.c"
9953642Sguido#include "netinet/ip_raudio_pxy.c"
10092685Sdarrenr#include "netinet/ip_netbios_pxy.c"
10193224Sru#include "netinet/ip_ipsec_pxy.c"
10253642Sguido#endif
10353642Sguido
10453642Sguidoap_session_t	*ap_sess_tab[AP_SESS_SIZE];
10553642Sguidoap_session_t	*ap_sess_list = NULL;
10660855Sdarrenraproxy_t	*ap_proxylist = NULL;
10753642Sguidoaproxy_t	ap_proxies[] = {
10853642Sguido#ifdef	IPF_FTP_PROXY
10960855Sdarrenr	{ NULL, "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, NULL,
11092685Sdarrenr	  ippr_ftp_new, NULL, ippr_ftp_in, ippr_ftp_out, NULL },
11153642Sguido#endif
11253642Sguido#ifdef	IPF_RCMD_PROXY
11360855Sdarrenr	{ NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, ippr_rcmd_init, NULL,
11492685Sdarrenr	  ippr_rcmd_new, NULL, NULL, ippr_rcmd_out, NULL },
11553642Sguido#endif
11653642Sguido#ifdef	IPF_RAUDIO_PROXY
11760855Sdarrenr	{ NULL, "raudio", (char)IPPROTO_TCP, 0, 0, ippr_raudio_init, NULL,
11892685Sdarrenr	  ippr_raudio_new, NULL, ippr_raudio_in, ippr_raudio_out, NULL },
11953642Sguido#endif
12092685Sdarrenr#ifdef IPF_IPSEC_PROXY
12192685Sdarrenr	{ NULL, "ipsec", (char)IPPROTO_UDP, 0, 0, ippr_ipsec_init, NULL,
12292685Sdarrenr	  ippr_ipsec_new, ippr_ipsec_del, NULL, ippr_ipsec_out,
12392685Sdarrenr	  ippr_ipsec_match },
12492685Sdarrenr#endif
12592685Sdarrenr#ifdef	IPF_NETBIOS_PROXY
12698004Sdarrenr	{ NULL, "netbios", (char)IPPROTO_UDP, 0, 0, ippr_netbios_init, NULL,
12792685Sdarrenr	  NULL, NULL, NULL, ippr_netbios_out, NULL },
12892685Sdarrenr#endif
12992685Sdarrenr#ifdef  IPF_H323_PROXY
13092685Sdarrenr    { NULL, "h323", (char)IPPROTO_TCP, 0, 0, ippr_h323_init, NULL,
13192685Sdarrenr 	  ippr_h323_new, ippr_h323_del, ippr_h323_in, ippr_h323_out, NULL },
13292685Sdarrenr    { NULL, "h245", (char)IPPROTO_TCP, 0, 0, ippr_h245_init, NULL,
13392685Sdarrenr 	  ippr_h245_new, NULL, NULL, ippr_h245_out, NULL },
13492685Sdarrenr#endif
13592685Sdarrenr	{ NULL, "", '\0', 0, 0, NULL, NULL, NULL }
13653642Sguido};
13753642Sguido
13853642Sguido
13992685Sdarrenr/*
14092685Sdarrenr * Dynamically add a new kernel proxy.  Ensure that it is unique in the
14192685Sdarrenr * collection compiled in and dynamically added.
14292685Sdarrenr */
14360855Sdarrenrint appr_add(ap)
14460855Sdarrenraproxy_t *ap;
14560855Sdarrenr{
14660855Sdarrenr	aproxy_t *a;
14760855Sdarrenr
14860855Sdarrenr	for (a = ap_proxies; a->apr_p; a++)
14960855Sdarrenr		if ((a->apr_p == ap->apr_p) &&
15060855Sdarrenr		    !strncmp(a->apr_label, ap->apr_label,
15160855Sdarrenr			     sizeof(ap->apr_label)))
15260855Sdarrenr			return -1;
15360855Sdarrenr
15492685Sdarrenr	for (a = ap_proxylist; a && a->apr_p; a = a->apr_next)
15560855Sdarrenr		if ((a->apr_p == ap->apr_p) &&
15660855Sdarrenr		    !strncmp(a->apr_label, ap->apr_label,
15760855Sdarrenr			     sizeof(ap->apr_label)))
15860855Sdarrenr			return -1;
15960855Sdarrenr	ap->apr_next = ap_proxylist;
16060855Sdarrenr	ap_proxylist = ap;
16160855Sdarrenr	return (*ap->apr_init)();
16260855Sdarrenr}
16360855Sdarrenr
16460855Sdarrenr
16592685Sdarrenr/*
16692685Sdarrenr * Delete a proxy that has been added dynamically from those available.
16792685Sdarrenr * If it is in use, return 1 (do not destroy NOW), not in use 0 or -1
16892685Sdarrenr * if it cannot be matched.
16992685Sdarrenr */
17060855Sdarrenrint appr_del(ap)
17160855Sdarrenraproxy_t *ap;
17260855Sdarrenr{
17360855Sdarrenr	aproxy_t *a, **app;
17460855Sdarrenr
17560855Sdarrenr	for (app = &ap_proxylist; (a = *app); app = &a->apr_next)
17660855Sdarrenr		if (a == ap) {
17792685Sdarrenr			a->apr_flags |= APR_DELETE;
17892685Sdarrenr			*app = a->apr_next;
17960855Sdarrenr			if (ap->apr_ref != 0)
18060855Sdarrenr				return 1;
18160855Sdarrenr			return 0;
18260855Sdarrenr		}
18360855Sdarrenr	return -1;
18460855Sdarrenr}
18560855Sdarrenr
18660855Sdarrenr
18792685Sdarrenr/*
18892685Sdarrenr * Return 1 if the packet is a good match against a proxy, else 0.
18992685Sdarrenr */
19053642Sguidoint appr_ok(ip, tcp, nat)
19153642Sguidoip_t *ip;
19253642Sguidotcphdr_t *tcp;
19353642Sguidoipnat_t *nat;
19453642Sguido{
19553642Sguido	aproxy_t *apr = nat->in_apr;
19653642Sguido	u_short dport = nat->in_dport;
19753642Sguido
19892685Sdarrenr	if ((apr == NULL) || (apr->apr_flags & APR_DELETE) ||
19953642Sguido	    (ip->ip_p != apr->apr_p))
20053642Sguido		return 0;
20192685Sdarrenr	if (((tcp != NULL) && (tcp->th_dport != dport)) || (!tcp && dport))
20253642Sguido		return 0;
20353642Sguido	return 1;
20453642Sguido}
20553642Sguido
20653642Sguido
20753642Sguido/*
20892685Sdarrenr * If a proxy has a match function, call that to do extended packet
20992685Sdarrenr * matching.
21092685Sdarrenr */
21192685Sdarrenrint appr_match(fin, nat)
21292685Sdarrenrfr_info_t *fin;
21392685Sdarrenrnat_t *nat;
21492685Sdarrenr{
21592685Sdarrenr	aproxy_t *apr;
21692685Sdarrenr	ipnat_t *ipn;
21792685Sdarrenr
21892685Sdarrenr	ipn = nat->nat_ptr;
21992685Sdarrenr	if (ipn == NULL)
22092685Sdarrenr		return -1;
22192685Sdarrenr	apr = ipn->in_apr;
22292685Sdarrenr	if ((apr == NULL) || (apr->apr_flags & APR_DELETE) ||
22392685Sdarrenr	    (nat->nat_aps == NULL))
22492685Sdarrenr		return -1;
22592685Sdarrenr	if (apr->apr_match != NULL)
22692685Sdarrenr		if ((*apr->apr_match)(fin, nat->nat_aps, nat) != 0)
22792685Sdarrenr			return -1;
22892685Sdarrenr	return 0;
22992685Sdarrenr}
23092685Sdarrenr
23192685Sdarrenr
23292685Sdarrenr/*
23353642Sguido * Allocate a new application proxy structure and fill it in with the
23453642Sguido * relevant details.  call the init function once complete, prior to
23553642Sguido * returning.
23653642Sguido */
23792685Sdarrenrint appr_new(fin, ip, nat)
23892685Sdarrenrfr_info_t *fin;
23953642Sguidoip_t *ip;
24053642Sguidonat_t *nat;
24153642Sguido{
24253642Sguido	register ap_session_t *aps;
24392685Sdarrenr	aproxy_t *apr;
24453642Sguido
24592685Sdarrenr	if ((nat->nat_ptr == NULL) || (nat->nat_aps != NULL))
24692685Sdarrenr		return -1;
24792685Sdarrenr
24892685Sdarrenr	apr = nat->nat_ptr->in_apr;
24992685Sdarrenr
25053642Sguido	if (!apr || (apr->apr_flags & APR_DELETE) || (ip->ip_p != apr->apr_p))
25192685Sdarrenr		return -1;
25253642Sguido
25353642Sguido	KMALLOC(aps, ap_session_t *);
25453642Sguido	if (!aps)
25592685Sdarrenr		return -1;
25653642Sguido	bzero((char *)aps, sizeof(*aps));
25753642Sguido	aps->aps_p = ip->ip_p;
25853642Sguido	aps->aps_data = NULL;
25953642Sguido	aps->aps_apr = apr;
26053642Sguido	aps->aps_psiz = 0;
26160855Sdarrenr	if (apr->apr_new != NULL)
26260855Sdarrenr		if ((*apr->apr_new)(fin, ip, aps, nat) == -1) {
26392685Sdarrenr			if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) {
26492685Sdarrenr				KFREES(aps->aps_data, aps->aps_psiz);
26592685Sdarrenr			}
26660855Sdarrenr			KFREE(aps);
26792685Sdarrenr			return -1;
26860855Sdarrenr		}
26960855Sdarrenr	aps->aps_nat = nat;
27060855Sdarrenr	aps->aps_next = ap_sess_list;
27153642Sguido	ap_sess_list = aps;
27292685Sdarrenr	nat->nat_aps = aps;
27392685Sdarrenr
27492685Sdarrenr	return 0;
27553642Sguido}
27653642Sguido
27753642Sguido
27853642Sguido/*
27953642Sguido * check to see if a packet should be passed through an active proxy routine
28053642Sguido * if one has been setup for it.
28153642Sguido */
28253642Sguidoint appr_check(ip, fin, nat)
28353642Sguidoip_t *ip;
28453642Sguidofr_info_t *fin;
28553642Sguidonat_t *nat;
28653642Sguido{
28780482Sdarrenr#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
28880482Sdarrenr	mb_t *m = fin->fin_qfm;
28980482Sdarrenr	int dosum = 1;
29080482Sdarrenr#endif
29180482Sdarrenr	tcphdr_t *tcp = NULL;
29253642Sguido	ap_session_t *aps;
29353642Sguido	aproxy_t *apr;
29453642Sguido	u_32_t sum;
29560855Sdarrenr	short rv;
29653642Sguido	int err;
29753642Sguido
29853642Sguido	aps = nat->nat_aps;
29953642Sguido	if ((aps != NULL) && (aps->aps_p == ip->ip_p)) {
30053642Sguido		if (ip->ip_p == IPPROTO_TCP) {
30153642Sguido			tcp = (tcphdr_t *)fin->fin_dp;
30253642Sguido			/*
30353642Sguido			 * verify that the checksum is correct.  If not, then
30453642Sguido			 * don't do anything with this packet.
30553642Sguido			 */
30680482Sdarrenr#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
30780482Sdarrenr			if (dohwcksum && (m->b_ick_flag == ICK_VALID)) {
30880482Sdarrenr				sum = tcp->th_sum;
30980482Sdarrenr				dosum = 0;
31080482Sdarrenr			}
31180482Sdarrenr			if (dosum)
31280482Sdarrenr				sum = fr_tcpsum(fin->fin_qfm, ip, tcp);
31353642Sguido#else
31453642Sguido			sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp);
31553642Sguido#endif
31653642Sguido			if (sum != tcp->th_sum) {
31753642Sguido				frstats[fin->fin_out].fr_tcpbad++;
31853642Sguido				return -1;
31953642Sguido			}
32053642Sguido		}
32153642Sguido
32253642Sguido		apr = aps->aps_apr;
32353642Sguido		err = 0;
32453642Sguido		if (fin->fin_out != 0) {
32553642Sguido			if (apr->apr_outpkt != NULL)
32653642Sguido				err = (*apr->apr_outpkt)(fin, ip, aps, nat);
32753642Sguido		} else {
32853642Sguido			if (apr->apr_inpkt != NULL)
32953642Sguido				err = (*apr->apr_inpkt)(fin, ip, aps, nat);
33053642Sguido		}
33153642Sguido
33260855Sdarrenr		rv = APR_EXIT(err);
33392685Sdarrenr		if (rv == 1)
33492685Sdarrenr			return -1;
33592685Sdarrenr		if (rv == 2) {
33692685Sdarrenr			appr_free(apr);
33792685Sdarrenr			nat->nat_aps = NULL;
33892685Sdarrenr			return -1;
33992685Sdarrenr		}
34060855Sdarrenr
34153642Sguido		if (tcp != NULL) {
34260855Sdarrenr			err = appr_fixseqack(fin, ip, aps, APR_INC(err));
34380482Sdarrenr#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
34480482Sdarrenr			if (dosum)
34580482Sdarrenr				tcp->th_sum = fr_tcpsum(fin->fin_qfm, ip, tcp);
34653642Sguido#else
34753642Sguido			tcp->th_sum = fr_tcpsum(*(mb_t **)fin->fin_mp, ip, tcp);
34853642Sguido#endif
34953642Sguido		}
35053642Sguido		aps->aps_bytes += ip->ip_len;
35153642Sguido		aps->aps_pkts++;
35260855Sdarrenr		return 1;
35353642Sguido	}
35460855Sdarrenr	return 0;
35553642Sguido}
35653642Sguido
35753642Sguido
35892685Sdarrenr/*
35992685Sdarrenr * Search for an proxy by the protocol it is being used with and its name.
36092685Sdarrenr */
36192685Sdarrenraproxy_t *appr_lookup(pr, name)
36253642Sguidou_int pr;
36353642Sguidochar *name;
36453642Sguido{
36553642Sguido	aproxy_t *ap;
36653642Sguido
36753642Sguido	for (ap = ap_proxies; ap->apr_p; ap++)
36853642Sguido		if ((ap->apr_p == pr) &&
36953642Sguido		    !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) {
37053642Sguido			ap->apr_ref++;
37153642Sguido			return ap;
37253642Sguido		}
37360855Sdarrenr
37460855Sdarrenr	for (ap = ap_proxylist; ap; ap = ap->apr_next)
37560855Sdarrenr		if ((ap->apr_p == pr) &&
37660855Sdarrenr		    !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) {
37760855Sdarrenr			ap->apr_ref++;
37860855Sdarrenr			return ap;
37960855Sdarrenr		}
38053642Sguido	return NULL;
38153642Sguido}
38253642Sguido
38353642Sguido
38453642Sguidovoid appr_free(ap)
38553642Sguidoaproxy_t *ap;
38653642Sguido{
38753642Sguido	ap->apr_ref--;
38853642Sguido}
38953642Sguido
39053642Sguido
39153642Sguidovoid aps_free(aps)
39253642Sguidoap_session_t *aps;
39353642Sguido{
39453642Sguido	ap_session_t *a, **ap;
39592685Sdarrenr	aproxy_t *apr;
39653642Sguido
39753642Sguido	if (!aps)
39853642Sguido		return;
39953642Sguido
40053642Sguido	for (ap = &ap_sess_list; (a = *ap); ap = &a->aps_next)
40153642Sguido		if (a == aps) {
40253642Sguido			*ap = a->aps_next;
40353642Sguido			break;
40453642Sguido		}
40553642Sguido
40692685Sdarrenr	apr = aps->aps_apr;
40792685Sdarrenr	if ((apr != NULL) && (apr->apr_del != NULL))
40892685Sdarrenr		(*apr->apr_del)(aps);
40992685Sdarrenr
41060855Sdarrenr	if ((aps->aps_data != NULL) && (aps->aps_psiz != 0))
41160855Sdarrenr		KFREES(aps->aps_data, aps->aps_psiz);
41260855Sdarrenr	KFREE(aps);
41353642Sguido}
41453642Sguido
41553642Sguido
41653642Sguidostatic int appr_fixseqack(fin, ip, aps, inc)
41753642Sguidofr_info_t *fin;
41853642Sguidoip_t *ip;
41953642Sguidoap_session_t *aps;
42053642Sguidoint inc;
42153642Sguido{
42253642Sguido	int sel, ch = 0, out, nlen;
42353642Sguido	u_32_t seq1, seq2;
42453642Sguido	tcphdr_t *tcp;
42598004Sdarrenr	short inc2;
42653642Sguido
42753642Sguido	tcp = (tcphdr_t *)fin->fin_dp;
42853642Sguido	out = fin->fin_out;
42953642Sguido	nlen = ip->ip_len;
43053642Sguido	nlen -= (ip->ip_hl << 2) + (tcp->th_off << 2);
43198004Sdarrenr	inc2 = inc;
43298004Sdarrenr	inc = (int)inc2;
43353642Sguido
43453642Sguido	if (out != 0) {
43553642Sguido		seq1 = (u_32_t)ntohl(tcp->th_seq);
43653642Sguido		sel = aps->aps_sel[out];
43753642Sguido
43853642Sguido		/* switch to other set ? */
43953642Sguido		if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) &&
44053642Sguido		    (seq1 > aps->aps_seqmin[!sel]))
44153642Sguido			sel = aps->aps_sel[out] = !sel;
44253642Sguido
44353642Sguido		if (aps->aps_seqoff[sel]) {
44453642Sguido			seq2 = aps->aps_seqmin[sel] - aps->aps_seqoff[sel];
44553642Sguido			if (seq1 > seq2) {
44653642Sguido				seq2 = aps->aps_seqoff[sel];
44753642Sguido				seq1 += seq2;
44853642Sguido				tcp->th_seq = htonl(seq1);
44953642Sguido				ch = 1;
45053642Sguido			}
45153642Sguido		}
45253642Sguido
45353642Sguido		if (inc && (seq1 > aps->aps_seqmin[!sel])) {
45453642Sguido			aps->aps_seqmin[!sel] = seq1 + nlen - 1;
45553642Sguido			aps->aps_seqoff[!sel] = aps->aps_seqoff[sel] + inc;
45653642Sguido		}
45753642Sguido
45853642Sguido		/***/
45953642Sguido
46053642Sguido		seq1 = ntohl(tcp->th_ack);
46153642Sguido		sel = aps->aps_sel[1 - out];
46253642Sguido
46353642Sguido		/* switch to other set ? */
46453642Sguido		if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) &&
46553642Sguido		    (seq1 > aps->aps_ackmin[!sel]))
46653642Sguido			sel = aps->aps_sel[1 - out] = !sel;
46753642Sguido
46853642Sguido		if (aps->aps_ackoff[sel] && (seq1 > aps->aps_ackmin[sel])) {
46953642Sguido			seq2 = aps->aps_ackoff[sel];
47053642Sguido			tcp->th_ack = htonl(seq1 - seq2);
47153642Sguido			ch = 1;
47253642Sguido		}
47353642Sguido	} else {
47453642Sguido		seq1 = ntohl(tcp->th_seq);
47553642Sguido		sel = aps->aps_sel[out];
47653642Sguido
47753642Sguido		/* switch to other set ? */
47853642Sguido		if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) &&
47953642Sguido		    (seq1 > aps->aps_ackmin[!sel]))
48053642Sguido			sel = aps->aps_sel[out] = !sel;
48153642Sguido
48253642Sguido		if (aps->aps_ackoff[sel]) {
48353642Sguido			seq2 = aps->aps_ackmin[sel] -
48453642Sguido			       aps->aps_ackoff[sel];
48553642Sguido			if (seq1 > seq2) {
48653642Sguido				seq2 = aps->aps_ackoff[sel];
48753642Sguido				seq1 += seq2;
48853642Sguido				tcp->th_seq = htonl(seq1);
48953642Sguido				ch = 1;
49053642Sguido			}
49153642Sguido		}
49253642Sguido
49353642Sguido		if (inc && (seq1 > aps->aps_ackmin[!sel])) {
49453642Sguido			aps->aps_ackmin[!sel] = seq1 + nlen - 1;
49553642Sguido			aps->aps_ackoff[!sel] = aps->aps_ackoff[sel] + inc;
49653642Sguido		}
49753642Sguido
49853642Sguido		/***/
49953642Sguido
50053642Sguido		seq1 = ntohl(tcp->th_ack);
50153642Sguido		sel = aps->aps_sel[1 - out];
50253642Sguido
50353642Sguido		/* switch to other set ? */
50453642Sguido		if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) &&
50553642Sguido		    (seq1 > aps->aps_seqmin[!sel]))
50653642Sguido			sel = aps->aps_sel[1 - out] = !sel;
50753642Sguido
50853642Sguido		if (aps->aps_seqoff[sel] && (seq1 > aps->aps_seqmin[sel])) {
50953642Sguido			seq2 = aps->aps_seqoff[sel];
51053642Sguido			tcp->th_ack = htonl(seq1 - seq2);
51153642Sguido			ch = 1;
51253642Sguido		}
51353642Sguido	}
51453642Sguido	return ch ? 2 : 0;
51553642Sguido}
51653642Sguido
51753642Sguido
51892685Sdarrenr/*
51992685Sdarrenr * Initialise hook for kernel application proxies.
52092685Sdarrenr * Call the initialise routine for all the compiled in kernel proxies.
52192685Sdarrenr */
52253642Sguidoint appr_init()
52353642Sguido{
52453642Sguido	aproxy_t *ap;
52553642Sguido	int err = 0;
52653642Sguido
52753642Sguido	for (ap = ap_proxies; ap->apr_p; ap++) {
52853642Sguido		err = (*ap->apr_init)();
52953642Sguido		if (err != 0)
53053642Sguido			break;
53153642Sguido	}
53253642Sguido	return err;
53353642Sguido}
53460855Sdarrenr
53560855Sdarrenr
53692685Sdarrenr/*
53792685Sdarrenr * Unload hook for kernel application proxies.
53892685Sdarrenr * Call the finialise routine for all the compiled in kernel proxies.
53992685Sdarrenr */
54060855Sdarrenrvoid appr_unload()
54160855Sdarrenr{
54260855Sdarrenr	aproxy_t *ap;
54360855Sdarrenr
54460855Sdarrenr	for (ap = ap_proxies; ap->apr_p; ap++)
54560855Sdarrenr		if (ap->apr_fini)
54660855Sdarrenr			(*ap->apr_fini)();
54760855Sdarrenr	for (ap = ap_proxylist; ap; ap = ap->apr_next)
54860855Sdarrenr		if (ap->apr_fini)
54960855Sdarrenr			(*ap->apr_fini)();
55060855Sdarrenr}
551