ip_proxy.c revision 1.2 1 /* $NetBSD: ip_proxy.c,v 1.2 2012/03/23 20:39:50 christos Exp $ */
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__
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 #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__ > 2
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_dns_pxy.c"
92 #include "netinet/ip_ftp_pxy.c"
93 #include "netinet/ip_tftp_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_h323_pxy.c"
100 # include "netinet/ip_netbios_pxy.c"
101 #endif
102 #include "netinet/ip_ipsec_pxy.c"
103 #include "netinet/ip_rpcb_pxy.c"
104
105 #if !defined(lint)
106 #if defined(__NetBSD__)
107 #include <sys/cdefs.h>
108 __KERNEL_RCSID(0, "$NetBSD: ip_proxy.c,v 1.2 2012/03/23 20:39:50 christos Exp $");
109 #else
110 static const char rcsid[] = "@(#)Id: ip_proxy.c,v 2.102.2.7 2012/01/29 05:30:36 darrenr Exp";
111 #endif
112 #endif
113
114 #define AP_SESS_SIZE 53
115
116 static int ipf_proxy_fixseqack(fr_info_t *, ip_t *, ap_session_t *, int );
117 static aproxy_t *ipf_proxy_create_clone(ipf_main_softc_t *, aproxy_t *);
118
119 typedef struct ipf_proxy_softc_s {
120 int ips_proxy_debug;
121 int ips_proxy_session_size;
122 ap_session_t **ips_sess_tab;
123 ap_session_t *ips_sess_list;
124 aproxy_t *ips_proxies;
125 int ips_init_run;
126 ipftuneable_t *ipf_proxy_tune;
127 } ipf_proxy_softc_t;
128
129 static ipftuneable_t ipf_proxy_tuneables[] = {
130 { { (void *)offsetof(ipf_proxy_softc_t, ips_proxy_debug) },
131 "ips_proxy_debug", 0, 10,
132 stsizeof(ipf_proxy_softc_t, ips_proxy_debug),
133 0, NULL, NULL },
134 { { NULL }, NULL, 0, 0,
135 0,
136 0, NULL, NULL}
137 };
138
139 static aproxy_t *ap_proxylist = NULL;
140 static aproxy_t ips_proxies[] = {
141 #ifdef IPF_FTP_PROXY
142 { NULL, NULL, "ftp", (char)IPPROTO_TCP, 0, 0, 0,
143 ipf_p_ftp_main_load, ipf_p_ftp_main_unload,
144 ipf_p_ftp_soft_create, ipf_p_ftp_soft_destroy,
145 NULL, NULL,
146 ipf_p_ftp_new, ipf_p_ftp_del, ipf_p_ftp_in, ipf_p_ftp_out, NULL,
147 NULL, NULL, NULL, NULL },
148 #endif
149 #ifdef IPF_TFTP_PROXY
150 { NULL, NULL, "tftp", (char)IPPROTO_TCP, 0, 0, 0,
151 ipf_p_tftp_main_load, ipf_p_tftp_main_unload,
152 NULL, NULL,
153 NULL, NULL,
154 ipf_p_tftp_new, NULL, ipf_p_tftp_in, ipf_p_tftp_out, NULL,
155 NULL, NULL, NULL, NULL },
156 #endif
157 #ifdef IPF_IRC_PROXY
158 { NULL, NULL, "irc", (char)IPPROTO_TCP, 0, 0, 0,
159 ipf_p_irc_main_load, ipf_p_irc_main_unload,
160 NULL, NULL,
161 NULL, NULL,
162 ipf_p_irc_new, NULL, NULL, ipf_p_irc_out, NULL,
163 NULL, NULL, NULL, NULL },
164 #endif
165 #ifdef IPF_RCMD_PROXY
166 { NULL, NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, 0,
167 ipf_p_rcmd_main_load, ipf_p_rcmd_main_unload,
168 NULL, NULL,
169 NULL, NULL,
170 ipf_p_rcmd_new, ipf_p_rcmd_del,
171 ipf_p_rcmd_in, ipf_p_rcmd_out, NULL,
172 NULL, NULL, NULL, NULL },
173 #endif
174 #ifdef IPF_RAUDIO_PROXY
175 { NULL, NULL, "raudio", (char)IPPROTO_TCP, 0, 0, 0,
176 ipf_p_raudio_main_load, ipf_p_raudio_main_unload,
177 NULL, NULL,
178 NULL, NULL,
179 ipf_p_raudio_new, NULL, ipf_p_raudio_in, ipf_p_raudio_out, NULL,
180 NULL, NULL, NULL, NULL },
181 #endif
182 #ifdef IPF_MSNRPC_PROXY
183 { NULL, NULL, "msnrpc", (char)IPPROTO_TCP, 0, 0, 0,
184 ipf_p_msnrpc_init, ipf_p_msnrpc_fini,
185 NULL, NULL,
186 NULL, NULL,
187 ipf_p_msnrpc_new, NULL, ipf_p_msnrpc_in, ipf_p_msnrpc_out, NULL,
188 NULL, NULL, NULL, NULL },
189 #endif
190 #ifdef IPF_NETBIOS_PROXY
191 { NULL, NULL, "netbios", (char)IPPROTO_UDP, 0, 0, 0,
192 ipf_p_netbios_main_load, ipf_p_netbios_main_unload,
193 NULL, NULL,
194 NULL, NULL,
195 NULL, NULL, NULL, ipf_p_netbios_out, NULL,
196 NULL, NULL, NULL, NULL },
197 #endif
198 #ifdef IPF_IPSEC_PROXY
199 { NULL, NULL, "ipsec", (char)IPPROTO_UDP, 0, 0, 0,
200 NULL, NULL,
201 ipf_p_ipsec_soft_create, ipf_p_ipsec_soft_destroy,
202 ipf_p_ipsec_soft_init, ipf_p_ipsec_soft_fini,
203 ipf_p_ipsec_new, ipf_p_ipsec_del,
204 ipf_p_ipsec_inout, ipf_p_ipsec_inout, ipf_p_ipsec_match,
205 NULL, NULL, NULL, NULL },
206 #endif
207 #ifdef IPF_DNS_PROXY
208 { NULL, NULL, "dns", (char)IPPROTO_UDP, 0, 0, 0,
209 NULL, NULL,
210 ipf_p_dns_soft_create, ipf_p_dns_soft_destroy,
211 NULL, NULL,
212 ipf_p_dns_new, ipf_p_ipsec_del,
213 ipf_p_dns_inout, ipf_p_dns_inout, ipf_p_dns_match,
214 ipf_p_dns_ctl, NULL, NULL, NULL },
215 #endif
216 #ifdef IPF_PPTP_PROXY
217 { NULL, NULL, "pptp", (char)IPPROTO_TCP, 0, 0, 0,
218 ipf_p_pptp_main_load, ipf_p_pptp_main_unload,
219 NULL, NULL,
220 NULL, NULL,
221 ipf_p_pptp_new, ipf_p_pptp_del,
222 ipf_p_pptp_inout, ipf_p_pptp_inout, NULL,
223 NULL, NULL, NULL, NULL },
224 #endif
225 #ifdef IPF_H323_PROXY
226 { NULL, NULL, "h323", (char)IPPROTO_TCP, 0, 0, 0,
227 ipf_p_h323_main_load, ipf_p_h323_main_unload,
228 NULL, NULL,
229 NULL, NULL,
230 ipf_p_h323_new, ipf_p_h323_del,
231 ipf_p_h323_in, NULL, NULL,
232 NULL, NULL, NULL, NULL },
233 { NULL, NULL, "h245", (char)IPPROTO_TCP, 0, 0, 0, NULL, NULL,
234 NULL, NULL,
235 NULL, NULL,
236 ipf_p_h245_new, NULL,
237 NULL, ipf_p_h245_out, NULL,
238 NULL, NULL, NULL, NULL },
239 #endif
240 #ifdef IPF_RPCB_PROXY
241 # ifndef _KERNEL
242 { NULL, NULL, "rpcbt", (char)IPPROTO_TCP, 0, 0, 0,
243 NULL, NULL,
244 NULL, NULL,
245 NULL, NULL,
246 ipf_p_rpcb_new, ipf_p_rpcb_del,
247 ipf_p_rpcb_in, ipf_p_rpcb_out, NULL,
248 NULL, NULL, NULL, NULL },
249 # endif
250 { NULL, NULL, "rpcbu", (char)IPPROTO_UDP, 0, 0, 0,
251 ipf_p_rpcb_main_load, ipf_p_rpcb_main_unload,
252 NULL, NULL,
253 NULL, NULL,
254 ipf_p_rpcb_new, ipf_p_rpcb_del,
255 ipf_p_rpcb_in, ipf_p_rpcb_out, NULL,
256 NULL, NULL, NULL, NULL },
257 #endif
258 { NULL, NULL, "", '\0', 0, 0, 0,
259 NULL, NULL,
260 NULL, NULL,
261 NULL, NULL,
262 NULL, NULL,
263 NULL, NULL, NULL,
264 NULL, NULL, NULL, NULL }
265 };
266
267
268 /* ------------------------------------------------------------------------ */
269 /* Function: ipf_proxy_init */
270 /* Returns: int - -1 == error, 0 == success */
271 /* Parameters: fin(I) - pointer to packet information */
272 /* nat(I) - pointer to current NAT session */
273 /* */
274 /* Initialise hook for kernel application proxies. */
275 /* Call the initialise routine for all the compiled in kernel proxies. */
276 /* ------------------------------------------------------------------------ */
277 int
278 ipf_proxy_main_load(void)
279 {
280 aproxy_t *ap;
281
282 for (ap = ips_proxies; ap->apr_p; ap++) {
283 if (ap->apr_load != NULL)
284 (*ap->apr_load)();
285 }
286 return 0;
287 }
288
289
290 /* ------------------------------------------------------------------------ */
291 /* Function: ipf_proxy_unload */
292 /* Returns: Nil */
293 /* Parameters: Nil */
294 /* */
295 /* Unload hook for kernel application proxies. */
296 /* Call the finialise routine for all the compiled in kernel proxies. */
297 /* ------------------------------------------------------------------------ */
298 int
299 ipf_proxy_main_unload(void)
300 {
301 aproxy_t *ap;
302
303 for (ap = ips_proxies; ap->apr_p; ap++)
304 if (ap->apr_unload != NULL)
305 (*ap->apr_unload)();
306 for (ap = ap_proxylist; ap; ap = ap->apr_next)
307 if (ap->apr_unload != NULL)
308 (*ap->apr_unload)();
309
310 return 0;
311 }
312
313
314 void *
315 ipf_proxy_soft_create(ipf_main_softc_t *softc)
316 {
317 ipf_proxy_softc_t *softp;
318 aproxy_t *last;
319 aproxy_t *apn;
320 aproxy_t *ap;
321
322 KMALLOC(softp, ipf_proxy_softc_t *);
323 if (softp == NULL)
324 return softp;
325
326 bzero((char *)softp, sizeof(*softp));
327
328 #if defined(_KERNEL)
329 softp->ips_proxy_debug = 0;
330 #else
331 softp->ips_proxy_debug = 2;
332 #endif
333 softp->ips_proxy_session_size = AP_SESS_SIZE;
334
335 softp->ipf_proxy_tune = ipf_tune_array_copy(softp,
336 sizeof(ipf_proxy_tuneables),
337 ipf_proxy_tuneables);
338 if (softp->ipf_proxy_tune == NULL) {
339 ipf_proxy_soft_destroy(softc, softp);
340 return NULL;
341 }
342 if (ipf_tune_array_link(softc, softp->ipf_proxy_tune) == -1) {
343 ipf_proxy_soft_destroy(softc, softp);
344 return NULL;
345 }
346
347 last = NULL;
348 for (ap = ips_proxies; ap->apr_p; ap++) {
349 apn = ipf_proxy_create_clone(softc, ap);
350 if (apn == NULL)
351 goto failed;
352 if (last != NULL)
353 last->apr_next = apn;
354 else
355 softp->ips_proxies = apn;
356 last = apn;
357 }
358 for (ap = ips_proxies; ap != NULL; ap = ap->apr_next) {
359 apn = ipf_proxy_create_clone(softc, ap);
360 if (apn == NULL)
361 goto failed;
362 if (last != NULL)
363 last->apr_next = apn;
364 else
365 softp->ips_proxies = apn;
366 last = apn;
367 }
368
369 return softp;
370 failed:
371 ipf_proxy_soft_destroy(softc, softp);
372 return NULL;
373 }
374
375
376 static aproxy_t *
377 ipf_proxy_create_clone(ipf_main_softc_t *softc, aproxy_t *orig)
378 {
379 aproxy_t *apn;
380
381 KMALLOC(apn, aproxy_t *);
382 if (apn == NULL)
383 return NULL;
384
385 bcopy((char *)orig, (char *)apn, sizeof(*apn));
386 apn->apr_next = NULL;
387 apn->apr_soft = NULL;
388
389 if (apn->apr_create != NULL) {
390 apn->apr_soft = (*apn->apr_create)(softc);
391 if (apn->apr_soft == NULL) {
392 KFREE(apn);
393 return NULL;
394 }
395 }
396
397 apn->apr_parent = orig;
398 orig->apr_clones++;
399
400 return apn;
401 }
402
403
404 int
405 ipf_proxy_soft_init(ipf_main_softc_t *softc, void *arg)
406 {
407 ipf_proxy_softc_t *softp;
408 aproxy_t *ap;
409 u_int size;
410 int err;
411
412 softp = arg;
413 size = softp->ips_proxy_session_size * sizeof(ap_session_t *);
414
415 KMALLOCS(softp->ips_sess_tab, ap_session_t **, size);
416
417 if (softp->ips_sess_tab == NULL)
418 return -1;
419
420 bzero(softp->ips_sess_tab, size);
421
422 for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next) {
423 if (ap->apr_init != NULL) {
424 err = (*ap->apr_init)(softc, ap->apr_soft);
425 if (err != 0)
426 return -2;
427 }
428 }
429 softp->ips_init_run = 1;
430
431 return 0;
432 }
433
434
435 int
436 ipf_proxy_soft_fini(ipf_main_softc_t *softc, void *arg)
437 {
438 ipf_proxy_softc_t *softp = arg;
439 aproxy_t *ap;
440
441 for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next) {
442 if (ap->apr_fini != NULL) {
443 (*ap->apr_fini)(softc, ap->apr_soft);
444 }
445 }
446
447 if (softp->ips_sess_tab != NULL) {
448 KFREES(softp->ips_sess_tab,
449 softp->ips_proxy_session_size * sizeof(ap_session_t *));
450 softp->ips_sess_tab = NULL;
451 }
452 softp->ips_init_run = 0;
453
454 return 0;
455 }
456
457
458 void
459 ipf_proxy_soft_destroy(ipf_main_softc_t *softc, void *arg)
460 {
461 ipf_proxy_softc_t *softp = arg;
462 aproxy_t *ap;
463
464 while ((ap = softp->ips_proxies) != NULL) {
465 softp->ips_proxies = ap->apr_next;
466 if (ap->apr_destroy != NULL)
467 (*ap->apr_destroy)(softc, ap->apr_soft);
468 ap->apr_parent->apr_clones--;
469 KFREE(ap);
470 }
471
472 if (softp->ipf_proxy_tune != NULL) {
473 ipf_tune_array_unlink(softc, softp->ipf_proxy_tune);
474 KFREES(softp->ipf_proxy_tune, sizeof(ipf_proxy_tuneables));
475 softp->ipf_proxy_tune = NULL;
476 }
477
478 KFREE(softp);
479 }
480
481
482 /* ------------------------------------------------------------------------ */
483 /* Function: ipf_proxy_flush */
484 /* Returns: Nil */
485 /* Parameters: fin(I) - pointer to packet information */
486 /* nat(I) - pointer to current NAT session */
487 /* */
488 /* ------------------------------------------------------------------------ */
489 void
490 ipf_proxy_flush(void *arg, int how)
491 {
492 ipf_proxy_softc_t *softp = arg;
493 aproxy_t *ap;
494
495 switch (how)
496 {
497 case 0 :
498 for (ap = softp->ips_proxies; ap; ap = ap->apr_next)
499 if (ap->apr_flush != NULL)
500 (*ap->apr_flush)(ap, how);
501 break;
502 case 1 :
503 for (ap = softp->ips_proxies; ap; ap = ap->apr_next)
504 if (ap->apr_clear != NULL)
505 (*ap->apr_clear)(ap);
506 break;
507 default :
508 break;
509 }
510 }
511
512
513 /* ------------------------------------------------------------------------ */
514 /* Function: ipf_proxy_add */
515 /* Returns: int - -1 == error, 0 == success */
516 /* Parameters: ap(I) - pointer to proxy structure */
517 /* */
518 /* Dynamically add a new kernel proxy. Ensure that it is unique in the */
519 /* collection compiled in and dynamically added. */
520 /* ------------------------------------------------------------------------ */
521 int
522 ipf_proxy_add(void *arg, aproxy_t *ap)
523 {
524 ipf_proxy_softc_t *softp = arg;
525
526 aproxy_t *a;
527
528 for (a = ips_proxies; a->apr_p; a++)
529 if ((a->apr_p == ap->apr_p) &&
530 !strncmp(a->apr_label, ap->apr_label,
531 sizeof(ap->apr_label))) {
532 if (softp->ips_proxy_debug > 1)
533 printf("ipf_proxy_add: %s/%d present (B)\n",
534 a->apr_label, a->apr_p);
535 return -1;
536 }
537
538 for (a = ap_proxylist; (a != NULL); a = a->apr_next)
539 if ((a->apr_p == ap->apr_p) &&
540 !strncmp(a->apr_label, ap->apr_label,
541 sizeof(ap->apr_label))) {
542 if (softp->ips_proxy_debug > 1)
543 printf("ipf_proxy_add: %s/%d present (D)\n",
544 a->apr_label, a->apr_p);
545 return -1;
546 }
547 ap->apr_next = ap_proxylist;
548 ap_proxylist = ap;
549 if (ap->apr_load != NULL)
550 (*ap->apr_load)();
551 return 0;
552 }
553
554
555 /* ------------------------------------------------------------------------ */
556 /* Function: ipf_proxy_ctl */
557 /* Returns: int - 0 == success, else error */
558 /* Parameters: ctl(I) - pointer to proxy control structure */
559 /* */
560 /* Check to see if the proxy this control request has come through for */
561 /* exists, and if it does and it has a control function then invoke that */
562 /* control function. */
563 /* ------------------------------------------------------------------------ */
564 int
565 ipf_proxy_ctl(ipf_main_softc_t *softc, void *arg, ap_ctl_t *ctl)
566 {
567 ipf_proxy_softc_t *softp = arg;
568 aproxy_t *a;
569 int error;
570
571 a = ipf_proxy_lookup(arg, ctl->apc_p, ctl->apc_label);
572 if (a == NULL) {
573 if (softp->ips_proxy_debug > 1)
574 printf("ipf_proxy_ctl: can't find %s/%d\n",
575 ctl->apc_label, ctl->apc_p);
576 IPFERROR(80001);
577 error = ESRCH;
578 } else if (a->apr_ctl == NULL) {
579 if (softp->ips_proxy_debug > 1)
580 printf("ipf_proxy_ctl: no ctl function for %s/%d\n",
581 ctl->apc_label, ctl->apc_p);
582 IPFERROR(80002);
583 error = ENXIO;
584 } else {
585 error = (*a->apr_ctl)(softc, a->apr_soft, ctl);
586 if ((error != 0) && (softp->ips_proxy_debug > 1))
587 printf("ipf_proxy_ctl: %s/%d ctl error %d\n",
588 a->apr_label, a->apr_p, error);
589 }
590 return error;
591 }
592
593
594 /* ------------------------------------------------------------------------ */
595 /* Function: ipf_proxy_del */
596 /* Returns: int - -1 == error, 0 == success */
597 /* Parameters: ap(I) - pointer to proxy structure */
598 /* */
599 /* Delete a proxy that has been added dynamically from those available. */
600 /* If it is in use, return 1 (do not destroy NOW), not in use 0 or -1 */
601 /* if it cannot be matched. */
602 /* ------------------------------------------------------------------------ */
603 int
604 ipf_proxy_del(aproxy_t *ap)
605 {
606 aproxy_t *a, **app;
607
608 for (app = &ap_proxylist; ((a = *app) != NULL); app = &a->apr_next) {
609 if (a == ap) {
610 a->apr_flags |= APR_DELETE;
611 if (ap->apr_ref == 0 && ap->apr_clones == 0) {
612 *app = a->apr_next;
613 return 0;
614 }
615 return 1;
616 }
617 }
618
619 return -1;
620 }
621
622
623 /* ------------------------------------------------------------------------ */
624 /* Function: ipf_proxy_ok */
625 /* Returns: int - 1 == good match else not. */
626 /* Parameters: fin(I) - pointer to packet information */
627 /* nat(I) - pointer to current NAT session */
628 /* */
629 /* ------------------------------------------------------------------------ */
630 int
631 ipf_proxy_ok(fr_info_t *fin, tcphdr_t *tcp, ipnat_t *nat)
632 {
633 aproxy_t *apr = nat->in_apr;
634 u_short dport = nat->in_odport;
635
636 if ((apr == NULL) || (apr->apr_flags & APR_DELETE) ||
637 (fin->fin_p != apr->apr_p))
638 return 0;
639 if ((tcp == NULL) && dport)
640 return 0;
641 return 1;
642 }
643
644
645 /* ------------------------------------------------------------------------ */
646 /* Function: ipf_proxy_ioctl */
647 /* Returns: int - 0 == success, else error */
648 /* Parameters: fin(I) - pointer to packet information */
649 /* nat(I) - pointer to current NAT session */
650 /* */
651 /* ------------------------------------------------------------------------ */
652 int
653 ipf_proxy_ioctl(ipf_main_softc_t *softc, void *data, ioctlcmd_t cmd, int mode,
654 void *ctx)
655 {
656 ap_ctl_t ctl;
657 void *ptr;
658 int error;
659
660 mode = mode; /* LINT */
661
662 switch (cmd)
663 {
664 case SIOCPROXY :
665 error = ipf_inobj(softc, data, NULL, &ctl, IPFOBJ_PROXYCTL);
666 if (error != 0) {
667 return error;
668 }
669 ptr = NULL;
670
671 if (ctl.apc_dsize > 0) {
672 KMALLOCS(ptr, void *, ctl.apc_dsize);
673 if (ptr == NULL) {
674 IPFERROR(80003);
675 error = ENOMEM;
676 } else {
677 error = copyinptr(softc, ctl.apc_data, ptr,
678 ctl.apc_dsize);
679 if (error == 0)
680 ctl.apc_data = ptr;
681 }
682 } else {
683 ctl.apc_data = NULL;
684 error = 0;
685 }
686
687 if (error == 0)
688 error = ipf_proxy_ctl(softc, softc->ipf_proxy_soft, &ctl);
689
690 if ((error != 0) && (ptr != NULL)) {
691 KFREES(ptr, ctl.apc_dsize);
692 }
693 break;
694
695 default :
696 IPFERROR(80004);
697 error = EINVAL;
698 }
699 return error;
700 }
701
702
703 /* ------------------------------------------------------------------------ */
704 /* Function: ipf_proxy_match */
705 /* Returns: int - -1 == error, 0 == success */
706 /* Parameters: fin(I) - pointer to packet information */
707 /* nat(I) - pointer to current NAT session */
708 /* */
709 /* If a proxy has a match function, call that to do extended packet */
710 /* matching. */
711 /* ------------------------------------------------------------------------ */
712 int
713 ipf_proxy_match(fr_info_t *fin, nat_t *nat)
714 {
715 ipf_main_softc_t *softc = fin->fin_main_soft;
716 ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
717 aproxy_t *apr;
718 ipnat_t *ipn;
719 int result;
720
721 ipn = nat->nat_ptr;
722 if (softp->ips_proxy_debug > 8)
723 printf("ipf_proxy_match(%lx,%lx) aps %lx ptr %lx\n",
724 (u_long)fin, (u_long)nat, (u_long)nat->nat_aps,
725 (u_long)ipn);
726
727 if ((fin->fin_flx & (FI_SHORT|FI_BAD)) != 0) {
728 if (softp->ips_proxy_debug > 0)
729 printf("ipf_proxy_match: flx 0x%x (BAD|SHORT)\n",
730 fin->fin_flx);
731 return -1;
732 }
733
734 apr = ipn->in_apr;
735 if ((apr == NULL) || (apr->apr_flags & APR_DELETE)) {
736 if (softp->ips_proxy_debug > 0)
737 printf("ipf_proxy_match:apr %lx apr_flags 0x%x\n",
738 (u_long)apr, apr ? apr->apr_flags : 0);
739 return -1;
740 }
741
742 if (apr->apr_match != NULL) {
743 result = (*apr->apr_match)(fin, nat->nat_aps, nat);
744 if (result != 0) {
745 if (softp->ips_proxy_debug > 4)
746 printf("ipf_proxy_match: result %d\n", result);
747 return -1;
748 }
749 }
750 return 0;
751 }
752
753
754 /* ------------------------------------------------------------------------ */
755 /* Function: ipf_proxy_new */
756 /* Returns: int - -1 == error, 0 == success */
757 /* Parameters: fin(I) - pointer to packet information */
758 /* nat(I) - pointer to current NAT session */
759 /* */
760 /* Allocate a new application proxy structure and fill it in with the */
761 /* relevant details. call the init function once complete, prior to */
762 /* returning. */
763 /* ------------------------------------------------------------------------ */
764 int
765 ipf_proxy_new(fr_info_t *fin, nat_t *nat)
766 {
767 ipf_main_softc_t *softc = fin->fin_main_soft;
768 ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
769 register ap_session_t *aps;
770 aproxy_t *apr;
771
772 if (softp->ips_proxy_debug > 8)
773 printf("ipf_proxy_new(%lx,%lx) \n", (u_long)fin, (u_long)nat);
774
775 if ((nat->nat_ptr == NULL) || (nat->nat_aps != NULL)) {
776 if (softp->ips_proxy_debug > 0)
777 printf("ipf_proxy_new: nat_ptr %lx nat_aps %lx\n",
778 (u_long)nat->nat_ptr, (u_long)nat->nat_aps);
779 return -1;
780 }
781
782 apr = nat->nat_ptr->in_apr;
783
784 if ((apr->apr_flags & APR_DELETE) ||
785 (fin->fin_p != apr->apr_p)) {
786 if (softp->ips_proxy_debug > 2)
787 printf("ipf_proxy_new: apr_flags 0x%x p %d/%d\n",
788 apr->apr_flags, fin->fin_p, apr->apr_p);
789 return -1;
790 }
791
792 KMALLOC(aps, ap_session_t *);
793 if (!aps) {
794 if (softp->ips_proxy_debug > 0)
795 printf("ipf_proxy_new: malloc failed (%lu)\n",
796 (u_long)sizeof(ap_session_t));
797 return -1;
798 }
799
800 bzero((char *)aps, sizeof(*aps));
801 aps->aps_data = NULL;
802 aps->aps_apr = apr;
803 aps->aps_psiz = 0;
804 if (apr->apr_new != NULL)
805 if ((*apr->apr_new)(apr->apr_soft, fin, aps, nat) == -1) {
806 if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) {
807 KFREES(aps->aps_data, aps->aps_psiz);
808 }
809 KFREE(aps);
810 if (softp->ips_proxy_debug > 2)
811 printf("ipf_proxy_new: new(%lx) failed\n",
812 (u_long)apr->apr_new);
813 return -1;
814 }
815 aps->aps_nat = nat;
816 aps->aps_next = softp->ips_sess_list;
817 softp->ips_sess_list = aps;
818 nat->nat_aps = aps;
819
820 return 0;
821 }
822
823
824 /* ------------------------------------------------------------------------ */
825 /* Function: ipf_proxy_check */
826 /* Returns: int - -1 == error, 0 == success */
827 /* Parameters: fin(I) - pointer to packet information */
828 /* nat(I) - pointer to current NAT session */
829 /* */
830 /* Check to see if a packet should be passed through an active proxy */
831 /* routine if one has been setup for it. We don't need to check the */
832 /* checksum here if IPFILTER_CKSUM is defined because if it is, a failed */
833 /* check causes FI_BAD to be set. */
834 /* ------------------------------------------------------------------------ */
835 int
836 ipf_proxy_check(fr_info_t *fin, nat_t *nat)
837 {
838 ipf_main_softc_t *softc = fin->fin_main_soft;
839 ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
840 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
841 # if defined(ICK_VALID)
842 mb_t *m;
843 # endif
844 int dosum = 1;
845 #endif
846 tcphdr_t *tcp = NULL;
847 udphdr_t *udp = NULL;
848 ap_session_t *aps;
849 aproxy_t *apr;
850 ip_t *ip;
851 short rv;
852 int err;
853 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi)
854 u_32_t s1, s2, sd;
855 #endif
856
857 if (fin->fin_flx & FI_BAD) {
858 if (softp->ips_proxy_debug > 0)
859 printf("ipf_proxy_check: flx 0x%x (BAD)\n", fin->fin_flx);
860 return -1;
861 }
862
863 #ifndef IPFILTER_CKSUM
864 if ((fin->fin_out == 0) && (ipf_checkl4sum(fin) == -1)) {
865 if (softp->ips_proxy_debug > 0)
866 printf("ipf_proxy_check: l4 checksum failure %d\n",
867 fin->fin_p);
868 if (fin->fin_p == IPPROTO_TCP)
869 softc->ipf_stats[fin->fin_out].fr_tcpbad++;
870 return -1;
871 }
872 #endif
873
874 aps = nat->nat_aps;
875 if (aps != NULL) {
876 /*
877 * If there is data in this packet to be proxied then try and
878 * get it all into the one buffer, else drop it.
879 */
880 #if defined(MENTAT) || defined(HAVE_M_PULLDOWN)
881 if ((fin->fin_dlen > 0) && !(fin->fin_flx & FI_COALESCE))
882 if (ipf_coalesce(fin) == -1) {
883 if (softp->ips_proxy_debug > 0)
884 printf("ipf_proxy_check: coalesce failed %x\n", fin->fin_flx);
885 return -1;
886 }
887 #endif
888 ip = fin->fin_ip;
889
890 switch (fin->fin_p)
891 {
892 case IPPROTO_TCP :
893 tcp = (tcphdr_t *)fin->fin_dp;
894
895 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID)
896 m = fin->fin_qfm;
897 if (dohwcksum && (m->b_ick_flag == ICK_VALID))
898 dosum = 0;
899 #endif
900 /*
901 * Don't bother the proxy with these...or in fact,
902 * should we free up proxy stuff when seen?
903 */
904 if ((fin->fin_tcpf & TH_RST) != 0)
905 break;
906 /*FALLTHROUGH*/
907 case IPPROTO_UDP :
908 udp = (udphdr_t *)fin->fin_dp;
909 break;
910 default :
911 break;
912 }
913
914 apr = aps->aps_apr;
915 err = 0;
916 if (fin->fin_out != 0) {
917 if (apr->apr_outpkt != NULL)
918 err = (*apr->apr_outpkt)(apr->apr_soft, fin, aps, nat);
919 } else {
920 if (apr->apr_inpkt != NULL)
921 err = (*apr->apr_inpkt)(apr->apr_soft, fin, aps, nat);
922 }
923
924 rv = APR_EXIT(err);
925 if (((softp->ips_proxy_debug > 0) && (rv != 0)) ||
926 (softp->ips_proxy_debug > 8))
927 printf("ipf_proxy_check: out %d err %x rv %d\n",
928 fin->fin_out, err, rv);
929 if (rv == 1)
930 return -1;
931
932 if (rv == 2) {
933 ipf_proxy_free(apr);
934 nat->nat_aps = NULL;
935 return -1;
936 }
937
938 /*
939 * If err != 0 then the data size of the packet has changed
940 * so we need to recalculate the header checksums for the
941 * packet.
942 */
943 #if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi)
944 if (err != 0) {
945 short adjlen = err & 0xffff;
946
947 s1 = LONG_SUM(fin->fin_plen - adjlen);
948 s2 = LONG_SUM(fin->fin_plen);
949 CALC_SUMD(s1, s2, sd);
950 ipf_fix_outcksum(fin, &ip->ip_sum, sd);
951 }
952 #endif
953
954 #ifdef INET
955 /*
956 * For TCP packets, we may need to adjust the sequence and
957 * acknowledgement numbers to reflect changes in size of the
958 * data stream.
959 *
960 * For both TCP and UDP, recalculate the layer 4 checksum,
961 * regardless, as we can't tell (here) if data has been
962 * changed or not.
963 */
964 if (tcp != NULL) {
965 err = ipf_proxy_fixseqack(fin, ip, aps, APR_INC(err));
966 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
967 if (dosum)
968 #endif
969 tcp->th_sum = fr_cksum(fin, ip,
970 IPPROTO_TCP, tcp);
971 } else if ((udp != NULL) && (udp->uh_sum != 0)) {
972 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6)
973 if (dosum)
974 #endif
975 udp->uh_sum = fr_cksum(fin, ip,
976 IPPROTO_UDP, udp);
977 }
978 #endif
979 aps->aps_bytes += fin->fin_plen;
980 aps->aps_pkts++;
981 return 1;
982 }
983 return 0;
984 }
985
986
987 /* ------------------------------------------------------------------------ */
988 /* Function: ipf_proxy_lookup */
989 /* Returns: int - -1 == error, 0 == success */
990 /* Parameters: fin(I) - pointer to packet information */
991 /* nat(I) - pointer to current NAT session */
992 /* */
993 /* Search for an proxy by the protocol it is being used with and its name. */
994 /* ------------------------------------------------------------------------ */
995 aproxy_t *
996 ipf_proxy_lookup(void *arg, u_int pr, char *name)
997 {
998 ipf_proxy_softc_t *softp = arg;
999 aproxy_t *ap;
1000
1001 if (softp->ips_proxy_debug > 8)
1002 printf("ipf_proxy_lookup(%d,%s)\n", pr, name);
1003
1004 for (ap = softp->ips_proxies; ap != NULL; ap = ap->apr_next)
1005 if ((ap->apr_p == pr) &&
1006 !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) {
1007 ap->apr_ref++;
1008 return ap;
1009 }
1010
1011 if (softp->ips_proxy_debug > 2)
1012 printf("ipf_proxy_lookup: failed for %d/%s\n", pr, name);
1013 return NULL;
1014 }
1015
1016
1017 /* ------------------------------------------------------------------------ */
1018 /* Function: ipf_proxy_free */
1019 /* Returns: Nil */
1020 /* Parameters: ap(I) - pointer to proxy structure */
1021 /* */
1022 /* ------------------------------------------------------------------------ */
1023 void
1024 ipf_proxy_free(aproxy_t *ap)
1025 {
1026 ap->apr_ref--;
1027 }
1028
1029
1030 /* ------------------------------------------------------------------------ */
1031 /* Function: aps_free */
1032 /* Returns: Nil */
1033 /* Parameters: fin(I) - pointer to packet information */
1034 /* nat(I) - pointer to current NAT session */
1035 /* */
1036 /* Locks Held: ipf_nat_new, ipf_nat(W) */
1037 /* ------------------------------------------------------------------------ */
1038 void
1039 aps_free(ipf_main_softc_t *softc, void *arg, ap_session_t *aps)
1040 {
1041 ipf_proxy_softc_t *softp = arg;
1042 ap_session_t *a, **ap;
1043 aproxy_t *apr;
1044
1045 if (!aps)
1046 return;
1047
1048 for (ap = &softp->ips_sess_list; ((a = *ap) != NULL); ap = &a->aps_next)
1049 if (a == aps) {
1050 *ap = a->aps_next;
1051 break;
1052 }
1053
1054 apr = aps->aps_apr;
1055 if ((apr != NULL) && (apr->apr_del != NULL))
1056 (*apr->apr_del)(softc, aps);
1057
1058 if ((aps->aps_data != NULL) && (aps->aps_psiz != 0))
1059 KFREES(aps->aps_data, aps->aps_psiz);
1060 KFREE(aps);
1061 }
1062
1063
1064 /* ------------------------------------------------------------------------ */
1065 /* Function: ipf_proxy_fixseqack */
1066 /* Returns: int - 2 if TCP ack/seq is changed, else 0 */
1067 /* Parameters: fin(I) - pointer to packet information */
1068 /* nat(I) - pointer to current NAT session */
1069 /* */
1070 /* ------------------------------------------------------------------------ */
1071 static int
1072 ipf_proxy_fixseqack(fr_info_t *fin, ip_t *ip, ap_session_t *aps, int inc)
1073 {
1074 ipf_main_softc_t *softc = fin->fin_main_soft;
1075 ipf_proxy_softc_t *softp = softc->ipf_proxy_soft;
1076 int sel, ch = 0, out, nlen;
1077 u_32_t seq1, seq2;
1078 tcphdr_t *tcp;
1079 short inc2;
1080
1081 tcp = (tcphdr_t *)fin->fin_dp;
1082 out = fin->fin_out;
1083 /*
1084 * ip_len has already been adjusted by 'inc'.
1085 */
1086 nlen = fin->fin_plen;
1087 nlen -= (IP_HL(ip) << 2) + (TCP_OFF(tcp) << 2);
1088
1089 inc2 = inc;
1090 inc = (int)inc2;
1091
1092 if (out != 0) {
1093 seq1 = (u_32_t)ntohl(tcp->th_seq);
1094 sel = aps->aps_sel[out];
1095
1096 /* switch to other set ? */
1097 if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) &&
1098 (seq1 > aps->aps_seqmin[!sel])) {
1099 if (softp->ips_proxy_debug > 7)
1100 printf("proxy out switch set seq %d -> %d %x > %x\n",
1101 sel, !sel, seq1,
1102 aps->aps_seqmin[!sel]);
1103 sel = aps->aps_sel[out] = !sel;
1104 }
1105
1106 if (aps->aps_seqoff[sel]) {
1107 seq2 = aps->aps_seqmin[sel] - aps->aps_seqoff[sel];
1108 if (seq1 > seq2) {
1109 seq2 = aps->aps_seqoff[sel];
1110 seq1 += seq2;
1111 tcp->th_seq = htonl(seq1);
1112 ch = 1;
1113 }
1114 }
1115
1116 if (inc && (seq1 > aps->aps_seqmin[!sel])) {
1117 aps->aps_seqmin[sel] = seq1 + nlen - 1;
1118 aps->aps_seqoff[sel] = aps->aps_seqoff[sel] + inc;
1119 if (softp->ips_proxy_debug > 7)
1120 printf("proxy seq set %d at %x to %d + %d\n",
1121 sel, aps->aps_seqmin[sel],
1122 aps->aps_seqoff[sel], inc);
1123 }
1124
1125 /***/
1126
1127 seq1 = ntohl(tcp->th_ack);
1128 sel = aps->aps_sel[1 - out];
1129
1130 /* switch to other set ? */
1131 if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) &&
1132 (seq1 > aps->aps_ackmin[!sel])) {
1133 if (softp->ips_proxy_debug > 7)
1134 printf("proxy out switch set ack %d -> %d %x > %x\n",
1135 sel, !sel, seq1,
1136 aps->aps_ackmin[!sel]);
1137 sel = aps->aps_sel[1 - out] = !sel;
1138 }
1139
1140 if (aps->aps_ackoff[sel] && (seq1 > aps->aps_ackmin[sel])) {
1141 seq2 = aps->aps_ackoff[sel];
1142 tcp->th_ack = htonl(seq1 - seq2);
1143 ch = 1;
1144 }
1145 } else {
1146 seq1 = ntohl(tcp->th_seq);
1147 sel = aps->aps_sel[out];
1148
1149 /* switch to other set ? */
1150 if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) &&
1151 (seq1 > aps->aps_ackmin[!sel])) {
1152 if (softp->ips_proxy_debug > 7)
1153 printf("proxy in switch set ack %d -> %d %x > %x\n",
1154 sel, !sel, seq1, aps->aps_ackmin[!sel]);
1155 sel = aps->aps_sel[out] = !sel;
1156 }
1157
1158 if (aps->aps_ackoff[sel]) {
1159 seq2 = aps->aps_ackmin[sel] - aps->aps_ackoff[sel];
1160 if (seq1 > seq2) {
1161 seq2 = aps->aps_ackoff[sel];
1162 seq1 += seq2;
1163 tcp->th_seq = htonl(seq1);
1164 ch = 1;
1165 }
1166 }
1167
1168 if (inc && (seq1 > aps->aps_ackmin[!sel])) {
1169 aps->aps_ackmin[!sel] = seq1 + nlen - 1;
1170 aps->aps_ackoff[!sel] = aps->aps_ackoff[sel] + inc;
1171
1172 if (softp->ips_proxy_debug > 7)
1173 printf("proxy ack set %d at %x to %d + %d\n",
1174 !sel, aps->aps_seqmin[!sel],
1175 aps->aps_seqoff[sel], inc);
1176 }
1177
1178 /***/
1179
1180 seq1 = ntohl(tcp->th_ack);
1181 sel = aps->aps_sel[1 - out];
1182
1183 /* switch to other set ? */
1184 if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) &&
1185 (seq1 > aps->aps_seqmin[!sel])) {
1186 if (softp->ips_proxy_debug > 7)
1187 printf("proxy in switch set seq %d -> %d %x > %x\n",
1188 sel, !sel, seq1, aps->aps_seqmin[!sel]);
1189 sel = aps->aps_sel[1 - out] = !sel;
1190 }
1191
1192 if (aps->aps_seqoff[sel] != 0) {
1193 if (softp->ips_proxy_debug > 7)
1194 printf("sel %d seqoff %d seq1 %x seqmin %x\n",
1195 sel, aps->aps_seqoff[sel], seq1,
1196 aps->aps_seqmin[sel]);
1197 if (seq1 > aps->aps_seqmin[sel]) {
1198 seq2 = aps->aps_seqoff[sel];
1199 tcp->th_ack = htonl(seq1 - seq2);
1200 ch = 1;
1201 }
1202 }
1203 }
1204
1205 if (softp->ips_proxy_debug > 8)
1206 printf("ipf_proxy_fixseqack: seq %x ack %x\n",
1207 (u_32_t)ntohl(tcp->th_seq), (u_32_t)ntohl(tcp->th_ack));
1208 return ch ? 2 : 0;
1209 }
1210