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