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