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