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