1/* $NetBSD: ip_proxy.c,v 1.19 2009/08/19 08:36:11 darrenr Exp $ */ 2 3/* 4 * Copyright (C) 1997-2003 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__ 29struct 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# if (__FreeBSD_version >= 300000) && !defined(IPFILTER_LKM) 53# include "opt_ipfilter.h" 54# endif 55#else 56# include <sys/ioctl.h> 57#endif 58#if defined(__SVR4) || defined(__svr4__) 59# include <sys/byteorder.h> 60# ifdef _KERNEL 61# include <sys/dditypes.h> 62# endif 63# include <sys/stream.h> 64# include <sys/kmem.h> 65#endif 66#if __FreeBSD__ > 2 67# include <sys/queue.h> 68#endif 69#include <net/if.h> 70#ifdef sun 71# include <net/af.h> 72#endif 73#include <netinet/in.h> 74#include <netinet/in_systm.h> 75#include <netinet/ip.h> 76#ifndef linux 77# include <netinet/ip_var.h> 78#endif 79#include <netinet/tcp.h> 80#include <netinet/udp.h> 81#include <netinet/ip_icmp.h> 82#include "netinet/ip_compat.h" 83#include <netinet/tcpip.h> 84#include "netinet/ip_fil.h" 85#include "netinet/ip_nat.h" 86#include "netinet/ip_state.h" 87#include "netinet/ip_proxy.h" 88#if (__FreeBSD_version >= 300000) 89# include <sys/malloc.h> 90#endif 91 92/* END OF INCLUDES */ 93 94#include "netinet/ip_ftp_pxy.c" 95#include "netinet/ip_rcmd_pxy.c" 96# include "netinet/ip_pptp_pxy.c" 97#if defined(_KERNEL) 98# include "netinet/ip_irc_pxy.c" 99# include "netinet/ip_raudio_pxy.c" 100# include "netinet/ip_h323_pxy.c" 101# include "netinet/ip_netbios_pxy.c" 102#endif 103#include "netinet/ip_ipsec_pxy.c" 104#include "netinet/ip_rpcb_pxy.c" 105 106#if !defined(lint) 107#if defined(__NetBSD__) 108#include <sys/cdefs.h> 109__KERNEL_RCSID(0, "$NetBSD: ip_proxy.c,v 1.19 2009/08/19 08:36:11 darrenr Exp $"); 110#else 111static const char rcsid[] = "@(#)Id: ip_proxy.c,v 2.62.2.23 2009/07/22 01:41:14 darrenr Exp"; 112#endif 113#endif 114 115#ifdef INET 116static int 117appr_fixseqack(fr_info_t *, ip_t *, ap_session_t *, int ); 118#endif 119 120#define AP_SESS_SIZE 53 121 122#if defined(_KERNEL) 123int ipf_proxy_debug = 0; 124#else 125int ipf_proxy_debug = 2; 126#endif 127ap_session_t *ap_sess_tab[AP_SESS_SIZE]; 128ap_session_t *ap_sess_list = NULL; 129aproxy_t *ap_proxylist = NULL; 130aproxy_t ap_proxies[] = { 131#ifdef IPF_FTP_PROXY 132 { NULL, "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, ippr_ftp_fini, 133 ippr_ftp_new, NULL, ippr_ftp_in, ippr_ftp_out, NULL, NULL }, 134#endif 135#ifdef IPF_IRC_PROXY 136 { NULL, "irc", (char)IPPROTO_TCP, 0, 0, ippr_irc_init, ippr_irc_fini, 137 ippr_irc_new, NULL, NULL, ippr_irc_out, NULL, NULL }, 138#endif 139#ifdef IPF_RCMD_PROXY 140 { NULL, "rcmd", (char)IPPROTO_TCP, 0, 0, ippr_rcmd_init, ippr_rcmd_fini, 141 ippr_rcmd_new, NULL, ippr_rcmd_in, ippr_rcmd_out, NULL, NULL }, 142#endif 143#ifdef IPF_RAUDIO_PROXY 144 { NULL, "raudio", (char)IPPROTO_TCP, 0, 0, ippr_raudio_init, ippr_raudio_fini, 145 ippr_raudio_new, NULL, ippr_raudio_in, ippr_raudio_out, NULL, NULL }, 146#endif 147#ifdef IPF_MSNRPC_PROXY 148 { NULL, "msnrpc", (char)IPPROTO_TCP, 0, 0, ippr_msnrpc_init, ippr_msnrpc_fini, 149 ippr_msnrpc_new, NULL, ippr_msnrpc_in, ippr_msnrpc_out, NULL, NULL }, 150#endif 151#ifdef IPF_NETBIOS_PROXY 152 { NULL, "netbios", (char)IPPROTO_UDP, 0, 0, ippr_netbios_init, ippr_netbios_fini, 153 NULL, NULL, NULL, ippr_netbios_out, NULL, NULL }, 154#endif 155#ifdef IPF_IPSEC_PROXY 156 { NULL, "ipsec", (char)IPPROTO_UDP, 0, 0, 157 ippr_ipsec_init, ippr_ipsec_fini, ippr_ipsec_new, ippr_ipsec_del, 158 ippr_ipsec_inout, ippr_ipsec_inout, ippr_ipsec_match, NULL }, 159#endif 160#ifdef IPF_PPTP_PROXY 161 { NULL, "pptp", (char)IPPROTO_TCP, 0, 0, 162 ippr_pptp_init, ippr_pptp_fini, ippr_pptp_new, ippr_pptp_del, 163 ippr_pptp_inout, ippr_pptp_inout, NULL, NULL }, 164#endif 165#ifdef IPF_H323_PROXY 166 { NULL, "h323", (char)IPPROTO_TCP, 0, 0, ippr_h323_init, ippr_h323_fini, 167 ippr_h323_new, ippr_h323_del, ippr_h323_in, NULL, NULL, NULL }, 168 { NULL, "h245", (char)IPPROTO_TCP, 0, 0, NULL, NULL, 169 ippr_h245_new, NULL, NULL, ippr_h245_out, NULL, NULL }, 170#endif 171#ifdef IPF_RPCB_PROXY 172# if 0 173 { NULL, "rpcbt", (char)IPPROTO_TCP, 0, 0, 174 ippr_rpcb_init, ippr_rpcb_fini, ippr_rpcb_new, ippr_rpcb_del, 175 ippr_rpcb_in, ippr_rpcb_out, NULL, NULL }, 176# endif 177 { NULL, "rpcbu", (char)IPPROTO_UDP, 0, 0, 178 ippr_rpcb_init, ippr_rpcb_fini, ippr_rpcb_new, ippr_rpcb_del, 179 ippr_rpcb_in, ippr_rpcb_out, NULL, NULL }, 180#endif 181 { NULL, "", '\0', 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } 182}; 183 184/* 185 * Dynamically add a new kernel proxy. Ensure that it is unique in the 186 * collection compiled in and dynamically added. 187 */ 188int 189appr_add(aproxy_t *ap) 190{ 191 aproxy_t *a; 192 193 for (a = ap_proxies; a->apr_p; a++) 194 if ((a->apr_p == ap->apr_p) && 195 !strncmp(a->apr_label, ap->apr_label, 196 sizeof(ap->apr_label))) { 197 if (ipf_proxy_debug > 1) 198 printf("appr_add: %s/%d already present (B)\n", 199 a->apr_label, a->apr_p); 200 return -1; 201 } 202 203 for (a = ap_proxylist; (a != NULL); a = a->apr_next) 204 if ((a->apr_p == ap->apr_p) && 205 !strncmp(a->apr_label, ap->apr_label, 206 sizeof(ap->apr_label))) { 207 if (ipf_proxy_debug > 1) 208 printf("appr_add: %s/%d already present (D)\n", 209 a->apr_label, a->apr_p); 210 return -1; 211 } 212 ap->apr_next = ap_proxylist; 213 ap_proxylist = ap; 214 if (ap->apr_init != NULL) 215 return (*ap->apr_init)(); 216 return 0; 217} 218 219 220/* 221 * Check to see if the proxy this control request has come through for 222 * exists, and if it does and it has a control function then invoke that 223 * control function. 224 */ 225int 226appr_ctl(ap_ctl_t *ctl) 227{ 228 aproxy_t *a; 229 int error; 230 231 a = appr_lookup(ctl->apc_p, ctl->apc_label); 232 if (a == NULL) { 233 if (ipf_proxy_debug > 1) 234 printf("appr_ctl: can't find %s/%d\n", 235 ctl->apc_label, ctl->apc_p); 236 error = ESRCH; 237 } else if (a->apr_ctl == NULL) { 238 if (ipf_proxy_debug > 1) 239 printf("appr_ctl: no ctl function for %s/%d\n", 240 ctl->apc_label, ctl->apc_p); 241 error = ENXIO; 242 } else { 243 error = (*a->apr_ctl)(a, ctl); 244 if ((error != 0) && (ipf_proxy_debug > 1)) 245 printf("appr_ctl: %s/%d ctl error %d\n", 246 a->apr_label, a->apr_p, error); 247 } 248 return error; 249} 250 251 252/* 253 * Delete a proxy that has been added dynamically from those available. 254 * If it is in use, return 1 (do not destroy NOW), not in use 0 or -1 255 * if it cannot be matched. 256 */ 257int 258appr_del(aproxy_t *ap) 259{ 260 aproxy_t *a, **app; 261 262 for (app = &ap_proxylist; ((a = *app) != NULL); app = &a->apr_next) 263 if (a == ap) { 264 a->apr_flags |= APR_DELETE; 265 *app = a->apr_next; 266 if (ap->apr_ref != 0) { 267 if (ipf_proxy_debug > 2) 268 printf("appr_del: orphaning %s/%d\n", 269 ap->apr_label, ap->apr_p); 270 return 1; 271 } 272 return 0; 273 } 274 if (ipf_proxy_debug > 1) 275 printf("appr_del: proxy %lx not found\n", (u_long)ap); 276 return -1; 277} 278 279 280/* 281 * Return 1 if the packet is a good match against a proxy, else 0. 282 */ 283int 284appr_ok(fr_info_t *fin, tcphdr_t *tcp, ipnat_t *nat) 285{ 286 aproxy_t *apr = nat->in_apr; 287 u_short dport = nat->in_dport; 288 289 if ((apr == NULL) || (apr->apr_flags & APR_DELETE) || 290 (fin->fin_p != apr->apr_p)) 291 return 0; 292 if ((tcp == NULL) && dport) 293 return 0; 294 return 1; 295} 296 297 298int 299appr_ioctl(void * data, ioctlcmd_t cmd, int mode, void *ctx) 300{ 301 ap_ctl_t ctl; 302 void *ptr; 303 int error; 304 305 mode = mode; /* LINT */ 306 307 switch (cmd) 308 { 309 case SIOCPROXY : 310 error = BCOPYIN(data, &ctl, sizeof(ctl)); 311 if (error != 0) 312 return EFAULT; 313 ptr = NULL; 314 315 if (ctl.apc_dsize > 0) { 316 KMALLOCS(ptr, void *, ctl.apc_dsize); 317 if (ptr == NULL) 318 error = ENOMEM; 319 else { 320 error = copyinptr(ctl.apc_data, ptr, 321 ctl.apc_dsize); 322 if (error == 0) 323 ctl.apc_data = ptr; 324 } 325 } else { 326 ctl.apc_data = NULL; 327 error = 0; 328 } 329 330 if (error == 0) 331 error = appr_ctl(&ctl); 332 333 if (ptr != NULL) { 334 KFREES(ptr, ctl.apc_dsize); 335 } 336 break; 337 338 default : 339 error = EINVAL; 340 } 341 return error; 342} 343 344 345/* 346 * If a proxy has a match function, call that to do extended packet 347 * matching. 348 */ 349int 350appr_match(fr_info_t *fin, nat_t *nat) 351{ 352 aproxy_t *apr; 353 ipnat_t *ipn; 354 int result; 355 356 ipn = nat->nat_ptr; 357 if (ipf_proxy_debug > 8) 358 printf("appr_match(%lx,%lx) aps %lx ptr %lx\n", 359 (u_long)fin, (u_long)nat, (u_long)nat->nat_aps, 360 (u_long)ipn); 361 362 if ((fin->fin_flx & (FI_SHORT|FI_BAD)) != 0) { 363 if (ipf_proxy_debug > 0) 364 printf("appr_match: flx 0x%x (BAD|SHORT)\n", 365 fin->fin_flx); 366 return -1; 367 } 368 369 apr = ipn->in_apr; 370 if ((apr == NULL) || (apr->apr_flags & APR_DELETE)) { 371 if (ipf_proxy_debug > 0) 372 printf("appr_match:apr %lx apr_flags 0x%x\n", 373 (u_long)apr, apr ? apr->apr_flags : 0); 374 return -1; 375 } 376 377 if (apr->apr_match != NULL) { 378 result = (*apr->apr_match)(fin, nat->nat_aps, nat); 379 if (result != 0) { 380 if (ipf_proxy_debug > 4) 381 printf("appr_match: result %d\n", result); 382 return -1; 383 } 384 } 385 return 0; 386} 387 388 389/* 390 * Allocate a new application proxy structure and fill it in with the 391 * relevant details. call the init function once complete, prior to 392 * returning. 393 */ 394int 395appr_new(fr_info_t *fin, nat_t *nat) 396{ 397 register ap_session_t *aps; 398 aproxy_t *apr; 399 400 if (ipf_proxy_debug > 8) 401 printf("appr_new(%lx,%lx) \n", (u_long)fin, (u_long)nat); 402 403 if ((nat->nat_ptr == NULL) || (nat->nat_aps != NULL)) { 404 if (ipf_proxy_debug > 0) 405 printf("appr_new: nat_ptr %lx nat_aps %lx\n", 406 (u_long)nat->nat_ptr, (u_long)nat->nat_aps); 407 return -1; 408 } 409 410 apr = nat->nat_ptr->in_apr; 411 412 if ((apr->apr_flags & APR_DELETE) || 413 (fin->fin_p != apr->apr_p)) { 414 if (ipf_proxy_debug > 2) 415 printf("appr_new: apr_flags 0x%x p %d/%d\n", 416 apr->apr_flags, fin->fin_p, apr->apr_p); 417 return -1; 418 } 419 420 KMALLOC(aps, ap_session_t *); 421 if (!aps) { 422 if (ipf_proxy_debug > 0) 423 printf("appr_new: malloc failed (%lu)\n", 424 (u_long)sizeof(ap_session_t)); 425 return -1; 426 } 427 428 bzero((char *)aps, sizeof(*aps)); 429 aps->aps_p = fin->fin_p; 430 aps->aps_data = NULL; 431 aps->aps_apr = apr; 432 aps->aps_psiz = 0; 433 if (apr->apr_new != NULL) 434 if ((*apr->apr_new)(fin, aps, nat) == -1) { 435 if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) { 436 KFREES(aps->aps_data, aps->aps_psiz); 437 } 438 KFREE(aps); 439 if (ipf_proxy_debug > 2) 440 printf("appr_new: new(%lx) failed\n", 441 (u_long)apr->apr_new); 442 return -1; 443 } 444 aps->aps_nat = nat; 445 aps->aps_next = ap_sess_list; 446 ap_sess_list = aps; 447 nat->nat_aps = aps; 448 449 return 0; 450} 451 452 453/* 454 * Check to see if a packet should be passed through an active proxy routine 455 * if one has been setup for it. We don't need to check the checksum here if 456 * IPFILTER_CKSUM is defined because if it is, a failed check causes FI_BAD 457 * to be set. 458 */ 459int 460appr_check(fr_info_t *fin, nat_t *nat) 461{ 462#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 463# if defined(ICK_VALID) 464 mb_t *m; 465# endif 466 int dosum = 1; 467#endif 468 tcphdr_t *tcp = NULL; 469 udphdr_t *udp = NULL; 470 ap_session_t *aps; 471 aproxy_t *apr; 472 ip_t *ip; 473 short rv; 474 int err; 475#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) 476 u_32_t s1, s2, sd; 477#endif 478 479 if (fin->fin_flx & FI_BAD) { 480 if (ipf_proxy_debug > 0) 481 printf("appr_check: flx 0x%x (BAD)\n", fin->fin_flx); 482 return -1; 483 } 484 485#ifndef IPFILTER_CKSUM 486 if ((fin->fin_out == 0) && (fr_checkl4sum(fin) == -1)) { 487 if (ipf_proxy_debug > 0) 488 printf("appr_check: l4 checksum failure %d\n", 489 fin->fin_p); 490 if (fin->fin_p == IPPROTO_TCP) 491 frstats[fin->fin_out].fr_tcpbad++; 492 return -1; 493 } 494#endif 495 496 aps = nat->nat_aps; 497 if ((aps != NULL) && (aps->aps_p == fin->fin_p)) { 498 /* 499 * If there is data in this packet to be proxied then try and 500 * get it all into the one buffer, else drop it. 501 */ 502#if defined(MENTAT) || defined(HAVE_M_PULLDOWN) 503 if ((fin->fin_dlen > 0) && !(fin->fin_flx & FI_COALESCE)) 504 if (fr_coalesce(fin) == -1) { 505 if (ipf_proxy_debug > 0) 506 printf("appr_check: fr_coalesce failed %x\n", fin->fin_flx); 507 return -1; 508 } 509#endif 510 ip = fin->fin_ip; 511 512 switch (fin->fin_p) 513 { 514 case IPPROTO_TCP : 515 tcp = (tcphdr_t *)fin->fin_dp; 516 517#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID) 518 m = fin->fin_qfm; 519 if (dohwcksum && (m->b_ick_flag == ICK_VALID)) 520 dosum = 0; 521#endif 522 /* 523 * Don't bother the proxy with these...or in fact, 524 * should we free up proxy stuff when seen? 525 */ 526 if ((fin->fin_tcpf & TH_RST) != 0) 527 break; 528 /*FALLTHROUGH*/ 529 case IPPROTO_UDP : 530 udp = (udphdr_t *)fin->fin_dp; 531 break; 532 default : 533 break; 534 } 535 536 apr = aps->aps_apr; 537 err = 0; 538 if (fin->fin_out != 0) { 539 if (apr->apr_outpkt != NULL) 540 err = (*apr->apr_outpkt)(fin, aps, nat); 541 } else { 542 if (apr->apr_inpkt != NULL) 543 err = (*apr->apr_inpkt)(fin, aps, nat); 544 } 545 546 rv = APR_EXIT(err); 547 if (((ipf_proxy_debug > 0) && (rv != 0)) || 548 (ipf_proxy_debug > 8)) 549 printf("appr_check: out %d err %x rv %d\n", 550 fin->fin_out, err, rv); 551 if (rv == 1) 552 return -1; 553 554 if (rv == 2) { 555 appr_free(apr); 556 nat->nat_aps = NULL; 557 return -1; 558 } 559 560 /* 561 * If err != 0 then the data size of the packet has changed 562 * so we need to recalculate the header checksums for the 563 * packet. 564 */ 565#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) 566 if (err != 0) { 567 short adjlen = err & 0xffff; 568 569 s1 = LONG_SUM(fin->fin_plen - adjlen); 570 s2 = LONG_SUM(fin->fin_plen); 571 CALC_SUMD(s1, s2, sd); 572 fix_outcksum(fin, &ip->ip_sum, sd); 573 } 574#endif 575 576#ifdef INET 577 /* 578 * For TCP packets, we may need to adjust the sequence and 579 * acknowledgement numbers to reflect changes in size of the 580 * data stream. 581 * 582 * For both TCP and UDP, recalculate the layer 4 checksum, 583 * regardless, as we can't tell (here) if data has been 584 * changed or not. 585 */ 586 if (tcp != NULL) { 587 err = appr_fixseqack(fin, ip, aps, APR_INC(err)); 588#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 589 if (dosum) 590 tcp->th_sum = fr_cksum(fin->fin_qfm, ip, 591 IPPROTO_TCP, tcp, 592 fin->fin_plen); 593#else 594 tcp->th_sum = fr_cksum(fin->fin_m, ip, 595 IPPROTO_TCP, tcp, 596 fin->fin_plen); 597#endif 598 } else if ((udp != NULL) && (udp->uh_sum != 0)) { 599#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 600 if (dosum) 601 udp->uh_sum = fr_cksum(fin->fin_qfm, ip, 602 IPPROTO_UDP, udp, 603 fin->fin_plen); 604#else 605 udp->uh_sum = fr_cksum(fin->fin_m, ip, 606 IPPROTO_UDP, udp, 607 fin->fin_plen); 608#endif 609 } 610#endif 611 aps->aps_bytes += fin->fin_plen; 612 aps->aps_pkts++; 613 return 1; 614 } 615 return 0; 616} 617 618 619/* 620 * Search for an proxy by the protocol it is being used with and its name. 621 */ 622aproxy_t * 623appr_lookup(u_int pr, char *name) 624{ 625 aproxy_t *ap; 626 627 if (ipf_proxy_debug > 8) 628 printf("appr_lookup(%d,%s)\n", pr, name); 629 630 for (ap = ap_proxies; ap->apr_p; ap++) 631 if ((ap->apr_p == pr) && 632 !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) { 633 ap->apr_ref++; 634 return ap; 635 } 636 637 for (ap = ap_proxylist; ap; ap = ap->apr_next) 638 if ((ap->apr_p == pr) && 639 !strncmp(name, ap->apr_label, sizeof(ap->apr_label))) { 640 ap->apr_ref++; 641 return ap; 642 } 643 if (ipf_proxy_debug > 2) 644 printf("appr_lookup: failed for %d/%s\n", pr, name); 645 return NULL; 646} 647 648 649void 650appr_free(aproxy_t *ap) 651{ 652 ap->apr_ref--; 653} 654 655 656void 657aps_free(ap_session_t *aps) 658{ 659 ap_session_t *a, **ap; 660 aproxy_t *apr; 661 662 if (!aps) 663 return; 664 665 for (ap = &ap_sess_list; ((a = *ap) != NULL); ap = &a->aps_next) 666 if (a == aps) { 667 *ap = a->aps_next; 668 break; 669 } 670 671 apr = aps->aps_apr; 672 if ((apr != NULL) && (apr->apr_del != NULL)) 673 (*apr->apr_del)(aps); 674 675 if ((aps->aps_data != NULL) && (aps->aps_psiz != 0)) 676 KFREES(aps->aps_data, aps->aps_psiz); 677 KFREE(aps); 678} 679 680 681#ifdef INET 682/* 683 * returns 2 if ack or seq number in TCP header is changed, returns 0 otherwise 684 */ 685static int 686appr_fixseqack(fr_info_t *fin, ip_t *ip, ap_session_t *aps, int inc) 687{ 688 int sel, ch = 0, out, nlen; 689 u_32_t seq1, seq2; 690 tcphdr_t *tcp; 691 short inc2; 692 693 tcp = (tcphdr_t *)fin->fin_dp; 694 out = fin->fin_out; 695 /* 696 * fin->fin_plen has already been adjusted by 'inc'. 697 */ 698 nlen = fin->fin_plen; 699 nlen -= (IP_HL(ip) << 2) + (TCP_OFF(tcp) << 2); 700 701 inc2 = inc; 702 inc = (int)inc2; 703 704 if (out != 0) { 705 seq1 = (u_32_t)ntohl(tcp->th_seq); 706 sel = aps->aps_sel[out]; 707 708 /* switch to other set ? */ 709 if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) && 710 (seq1 > aps->aps_seqmin[!sel])) { 711 if (ipf_proxy_debug > 7) 712 printf("proxy out switch set seq %d -> %d %x > %x\n", 713 sel, !sel, seq1, 714 aps->aps_seqmin[!sel]); 715 sel = aps->aps_sel[out] = !sel; 716 } 717 718 if (aps->aps_seqoff[sel]) { 719 seq2 = aps->aps_seqmin[sel] - aps->aps_seqoff[sel]; 720 if (seq1 > seq2) { 721 seq2 = aps->aps_seqoff[sel]; 722 seq1 += seq2; 723 tcp->th_seq = htonl(seq1); 724 ch = 1; 725 } 726 } 727 728 if (inc && (seq1 > aps->aps_seqmin[!sel])) { 729 aps->aps_seqmin[sel] = seq1 + nlen - 1; 730 aps->aps_seqoff[sel] = aps->aps_seqoff[sel] + inc; 731 if (ipf_proxy_debug > 7) 732 printf("proxy seq set %d at %x to %d + %d\n", 733 sel, aps->aps_seqmin[sel], 734 aps->aps_seqoff[sel], inc); 735 } 736 737 /***/ 738 739 seq1 = ntohl(tcp->th_ack); 740 sel = aps->aps_sel[1 - out]; 741 742 /* switch to other set ? */ 743 if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) && 744 (seq1 > aps->aps_ackmin[!sel])) { 745 if (ipf_proxy_debug > 7) 746 printf("proxy out switch set ack %d -> %d %x > %x\n", 747 sel, !sel, seq1, 748 aps->aps_ackmin[!sel]); 749 sel = aps->aps_sel[1 - out] = !sel; 750 } 751 752 if (aps->aps_ackoff[sel] && (seq1 > aps->aps_ackmin[sel])) { 753 seq2 = aps->aps_ackoff[sel]; 754 tcp->th_ack = htonl(seq1 - seq2); 755 ch = 1; 756 } 757 } else { 758 seq1 = ntohl(tcp->th_seq); 759 sel = aps->aps_sel[out]; 760 761 /* switch to other set ? */ 762 if ((aps->aps_ackmin[!sel] > aps->aps_ackmin[sel]) && 763 (seq1 > aps->aps_ackmin[!sel])) { 764 if (ipf_proxy_debug > 7) 765 printf("proxy in switch set ack %d -> %d %x > %x\n", 766 sel, !sel, seq1, aps->aps_ackmin[!sel]); 767 sel = aps->aps_sel[out] = !sel; 768 } 769 770 if (aps->aps_ackoff[sel]) { 771 seq2 = aps->aps_ackmin[sel] - aps->aps_ackoff[sel]; 772 if (seq1 > seq2) { 773 seq2 = aps->aps_ackoff[sel]; 774 seq1 += seq2; 775 tcp->th_seq = htonl(seq1); 776 ch = 1; 777 } 778 } 779 780 if (inc && (seq1 > aps->aps_ackmin[!sel])) { 781 aps->aps_ackmin[!sel] = seq1 + nlen - 1; 782 aps->aps_ackoff[!sel] = aps->aps_ackoff[sel] + inc; 783 784 if (ipf_proxy_debug > 7) 785 printf("proxy ack set %d at %x to %d + %d\n", 786 !sel, aps->aps_seqmin[!sel], 787 aps->aps_seqoff[sel], inc); 788 } 789 790 /***/ 791 792 seq1 = ntohl(tcp->th_ack); 793 sel = aps->aps_sel[1 - out]; 794 795 /* switch to other set ? */ 796 if ((aps->aps_seqmin[!sel] > aps->aps_seqmin[sel]) && 797 (seq1 > aps->aps_seqmin[!sel])) { 798 if (ipf_proxy_debug > 7) 799 printf("proxy in switch set seq %d -> %d %x > %x\n", 800 sel, !sel, seq1, aps->aps_seqmin[!sel]); 801 sel = aps->aps_sel[1 - out] = !sel; 802 } 803 804 if (aps->aps_seqoff[sel] != 0) { 805 if (ipf_proxy_debug > 7) 806 printf("sel %d seqoff %d seq1 %x seqmin %x\n", 807 sel, aps->aps_seqoff[sel], seq1, 808 aps->aps_seqmin[sel]); 809 if (seq1 > aps->aps_seqmin[sel]) { 810 seq2 = aps->aps_seqoff[sel]; 811 tcp->th_ack = htonl(seq1 - seq2); 812 ch = 1; 813 } 814 } 815 } 816 817 if (ipf_proxy_debug > 8) 818 printf("appr_fixseqack: seq %x ack %x\n", 819 (u_32_t)ntohl(tcp->th_seq), (u_32_t)ntohl(tcp->th_ack)); 820 return ch ? 2 : 0; 821} 822#endif 823 824 825/* 826 * Initialise hook for kernel application proxies. 827 * Call the initialise routine for all the compiled in kernel proxies. 828 */ 829int 830appr_init(void) 831{ 832 aproxy_t *ap; 833 int err = 0; 834 835 for (ap = ap_proxies; ap->apr_p; ap++) { 836 if (ap->apr_init != NULL) { 837 err = (*ap->apr_init)(); 838 if (err != 0) 839 break; 840 } 841 } 842 return err; 843} 844 845 846/* 847 * Unload hook for kernel application proxies. 848 * Call the finialise routine for all the compiled in kernel proxies. 849 */ 850void 851appr_unload(void) 852{ 853 aproxy_t *ap; 854 855 for (ap = ap_proxies; ap->apr_p; ap++) 856 if (ap->apr_fini != NULL) 857 (*ap->apr_fini)(); 858 for (ap = ap_proxylist; ap; ap = ap->apr_next) 859 if (ap->apr_fini != NULL) 860 (*ap->apr_fini)(); 861} 862