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