ip_ftp_pxy.c revision 72006
1/* 2 * Simple FTP transparent proxy for in-kernel use. For use with the NAT 3 * code. 4 * 5 * $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c 72006 2001-02-04 14:26:56Z darrenr $ 6 */ 7#if SOLARIS && defined(_KERNEL) 8extern kmutex_t ipf_rw; 9#endif 10 11#define isdigit(x) ((x) >= '0' && (x) <= '9') 12#define isupper(x) (((unsigned)(x) >= 'A') && ((unsigned)(x) <= 'Z')) 13#define islower(x) (((unsigned)(x) >= 'a') && ((unsigned)(x) <= 'z')) 14#define isalpha(x) (isupper(x) || islower(x)) 15#define toupper(x) (isupper(x) ? (x) : (x) - 'a' + 'A') 16 17#define IPF_FTP_PROXY 18 19#define IPF_MINPORTLEN 18 20#define IPF_MAXPORTLEN 30 21#define IPF_MIN227LEN 39 22#define IPF_MAX227LEN 51 23#define IPF_FTPBUFSZ 96 /* This *MUST* be >= 53! */ 24 25 26int ippr_ftp_client __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); 27int ippr_ftp_complete __P((char *, size_t)); 28int ippr_ftp_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); 29int ippr_ftp_init __P((void)); 30int ippr_ftp_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); 31int ippr_ftp_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *)); 32int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); 33int ippr_ftp_port __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); 34int ippr_ftp_process __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); 35int ippr_ftp_server __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); 36int ippr_ftp_valid __P((char *, size_t)); 37u_short ippr_ftp_atoi __P((char **)); 38 39static frentry_t natfr; 40int ippr_ftp_pasvonly = 0; 41int ippr_ftp_insecure = 0; 42 43 44/* 45 * Initialize local structures. 46 */ 47int ippr_ftp_init() 48{ 49 bzero((char *)&natfr, sizeof(natfr)); 50 natfr.fr_ref = 1; 51 natfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 52 return 0; 53} 54 55 56int ippr_ftp_new(fin, ip, aps, nat) 57fr_info_t *fin; 58ip_t *ip; 59ap_session_t *aps; 60nat_t *nat; 61{ 62 ftpinfo_t *ftp; 63 ftpside_t *f; 64 65 KMALLOC(ftp, ftpinfo_t *); 66 if (ftp == NULL) 67 return -1; 68 aps->aps_data = ftp; 69 aps->aps_psiz = sizeof(ftpinfo_t); 70 71 bzero((char *)ftp, sizeof(*ftp)); 72 f = &ftp->ftp_side[0]; 73 f->ftps_rptr = f->ftps_buf; 74 f->ftps_wptr = f->ftps_buf; 75 f = &ftp->ftp_side[1]; 76 f->ftps_rptr = f->ftps_buf; 77 f->ftps_wptr = f->ftps_buf; 78 return 0; 79} 80 81 82int ippr_ftp_port(fin, ip, nat, f, dlen) 83fr_info_t *fin; 84ip_t *ip; 85nat_t *nat; 86ftpside_t *f; 87int dlen; 88{ 89 tcphdr_t *tcp, tcph, *tcp2 = &tcph; 90 char newbuf[IPF_FTPBUFSZ], *s; 91 u_short a5, a6, sp, dp; 92 u_int a1, a2, a3, a4; 93 struct in_addr swip; 94 size_t nlen, olen; 95 fr_info_t fi; 96 int inc, off; 97 nat_t *ipn; 98 mb_t *m; 99#if SOLARIS 100 mb_t *m1; 101#endif 102 103 tcp = (tcphdr_t *)fin->fin_dp; 104 /* 105 * Check for client sending out PORT message. 106 */ 107 if (dlen < IPF_MINPORTLEN) 108 return 0; 109 off = fin->fin_hlen + (tcp->th_off << 2); 110 /* 111 * Skip the PORT command + space 112 */ 113 s = f->ftps_rptr + 5; 114 /* 115 * Pick out the address components, two at a time. 116 */ 117 a1 = ippr_ftp_atoi(&s); 118 if (!s) 119 return 0; 120 a2 = ippr_ftp_atoi(&s); 121 if (!s) 122 return 0; 123 /* 124 * check that IP address in the PORT/PASV reply is the same as the 125 * sender of the command - prevents using PORT for port scanning. 126 */ 127 a1 <<= 16; 128 a1 |= a2; 129 if (a1 != ntohl(nat->nat_inip.s_addr)) 130 return 0; 131 132 a5 = ippr_ftp_atoi(&s); 133 if (!s) 134 return 0; 135 if (*s == ')') 136 s++; 137 138 /* 139 * check for CR-LF at the end. 140 */ 141 if (*s == '\n') 142 s--; 143 if ((*s == '\r') && (*(s + 1) == '\n')) { 144 s += 2; 145 a6 = a5 & 0xff; 146 } else 147 return 0; 148 a5 >>= 8; 149 a5 &= 0xff; 150 /* 151 * Calculate new address parts for PORT command 152 */ 153 a1 = ntohl(ip->ip_src.s_addr); 154 a2 = (a1 >> 16) & 0xff; 155 a3 = (a1 >> 8) & 0xff; 156 a4 = a1 & 0xff; 157 a1 >>= 24; 158 olen = s - f->ftps_rptr; 159 /* DO NOT change this to sprintf! */ 160 (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", 161 "PORT", a1, a2, a3, a4, a5, a6); 162 163 nlen = strlen(newbuf); 164 inc = nlen - olen; 165 if ((inc + ip->ip_len) > 65535) 166 return 0; 167 168#if SOLARIS 169 m = fin->fin_qfm; 170 for (m1 = m; m1->b_cont; m1 = m1->b_cont) 171 ; 172 if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) { 173 mblk_t *nm; 174 175 /* alloc enough to keep same trailer space for lower driver */ 176 nm = allocb(nlen, BPRI_MED); 177 PANIC((!nm),("ippr_ftp_out: allocb failed")); 178 179 nm->b_band = m1->b_band; 180 nm->b_wptr += nlen; 181 182 m1->b_wptr -= olen; 183 PANIC((m1->b_wptr < m1->b_rptr), 184 ("ippr_ftp_out: cannot handle fragmented data block")); 185 186 linkb(m1, nm); 187 } else { 188 if (m1->b_datap->db_struiolim == m1->b_wptr) 189 m1->b_datap->db_struiolim += inc; 190 m1->b_datap->db_struioflag &= ~STRUIO_IP; 191 m1->b_wptr += inc; 192 } 193 copyin_mblk(m, off, nlen, newbuf); 194#else 195 m = *((mb_t **)fin->fin_mp); 196 if (inc < 0) 197 m_adj(m, inc); 198 /* the mbuf chain will be extended if necessary by m_copyback() */ 199 m_copyback(m, off, nlen, newbuf); 200# ifdef M_PKTHDR 201 if (!(m->m_flags & M_PKTHDR)) 202 m->m_pkthdr.len += inc; 203# endif 204#endif 205 if (inc != 0) { 206#if SOLARIS || defined(__sgi) 207 register u_32_t sum1, sum2; 208 209 sum1 = ip->ip_len; 210 sum2 = ip->ip_len + inc; 211 212 /* Because ~1 == -2, We really need ~1 == -1 */ 213 if (sum1 > sum2) 214 sum2--; 215 sum2 -= sum1; 216 sum2 = (sum2 & 0xffff) + (sum2 >> 16); 217 218 fix_outcksum(&ip->ip_sum, sum2); 219#endif 220 ip->ip_len += inc; 221 } 222 223 /* 224 * Add skeleton NAT entry for connection which will come back the 225 * other way. 226 */ 227 sp = htons(a5 << 8 | a6); 228 /* 229 * Don't allow the PORT command to specify a port < 1024 due to 230 * security crap. 231 */ 232 if (ntohs(sp) < 1024) 233 return 0; 234 /* 235 * The server may not make the connection back from port 20, but 236 * it is the most likely so use it here to check for a conflicting 237 * mapping. 238 */ 239 dp = htons(fin->fin_data[1] - 1); 240 ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_p, nat->nat_inip, 241 ip->ip_dst, (dp << 16) | sp, 0); 242 if (ipn == NULL) { 243 int slen; 244 245 slen = ip->ip_len; 246 ip->ip_len = fin->fin_hlen + sizeof(*tcp2); 247 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 248 bzero((char *)tcp2, sizeof(*tcp2)); 249 tcp2->th_win = htons(8192); 250 tcp2->th_sport = sp; 251 tcp2->th_off = 5; 252 tcp2->th_dport = 0; /* XXX - don't specify remote port */ 253 fi.fin_data[0] = ntohs(sp); 254 fi.fin_data[1] = 0; 255 fi.fin_dlen = sizeof(*tcp2); 256 fi.fin_dp = (char *)tcp2; 257 fi.fin_fr = &natfr; 258 swip = ip->ip_src; 259 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; 260 ip->ip_src = nat->nat_inip; 261 ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_TCP|FI_W_DPORT, 262 NAT_OUTBOUND); 263 if (ipn != NULL) { 264 ipn->nat_age = fr_defnatage; 265 (void) fr_addstate(ip, &fi, FI_W_DPORT); 266 } 267 ip->ip_len = slen; 268 ip->ip_src = swip; 269 } 270 return APR_INC(inc); 271} 272 273 274int ippr_ftp_client(fin, ip, nat, ftp, dlen) 275fr_info_t *fin; 276nat_t *nat; 277ftpinfo_t *ftp; 278ip_t *ip; 279int dlen; 280{ 281 char *rptr, *wptr, cmd[6], c; 282 ftpside_t *f; 283 int inc, i; 284 285 inc = 0; 286 f = &ftp->ftp_side[0]; 287 rptr = f->ftps_rptr; 288 wptr = f->ftps_wptr; 289 290 for (i = 0; (i < 5) && (i < dlen); i++) { 291 c = rptr[i]; 292 if (isalpha(c)) { 293 cmd[i] = toupper(c); 294 } else { 295 cmd[i] = c; 296 } 297 } 298 cmd[i] = '\0'; 299 300 if ((ftp->ftp_passok == 0) && !strncmp(cmd, "USER ", 5)) 301 ftp->ftp_passok = 1; 302 else if ((ftp->ftp_passok == 2) && !strncmp(cmd, "PASS ", 5)) 303 ftp->ftp_passok = 3; 304 else if ((ftp->ftp_passok == 4) && !ippr_ftp_pasvonly && 305 !strncmp(cmd, "PORT ", 5)) { 306 inc = ippr_ftp_port(fin, ip, nat, f, dlen); 307 } else if (ippr_ftp_insecure && !ippr_ftp_pasvonly && 308 !strncmp(cmd, "PORT ", 5)) { 309 inc = ippr_ftp_port(fin, ip, nat, f, dlen); 310 } 311 312 while ((*rptr++ != '\n') && (rptr < wptr)) 313 ; 314 f->ftps_rptr = rptr; 315 return inc; 316} 317 318 319int ippr_ftp_pasv(fin, ip, nat, f, dlen) 320fr_info_t *fin; 321ip_t *ip; 322nat_t *nat; 323ftpside_t *f; 324int dlen; 325{ 326 tcphdr_t *tcp, tcph, *tcp2 = &tcph; 327 struct in_addr swip, swip2; 328 u_short a5, a6, sp, dp; 329 u_int a1, a2, a3, a4; 330 fr_info_t fi; 331 nat_t *ipn; 332 int inc; 333 char *s; 334 335 /* 336 * Check for PASV reply message. 337 */ 338 if (dlen < IPF_MIN227LEN) 339 return 0; 340 else if (strncmp(f->ftps_rptr, "227 Entering Passive Mode", 25)) 341 return 0; 342 343 tcp = (tcphdr_t *)fin->fin_dp; 344 345 /* 346 * Skip the PORT command + space 347 */ 348 s = f->ftps_rptr + 25; 349 while (*s && !isdigit(*s)) 350 s++; 351 /* 352 * Pick out the address components, two at a time. 353 */ 354 a1 = ippr_ftp_atoi(&s); 355 if (!s) 356 return 0; 357 a2 = ippr_ftp_atoi(&s); 358 if (!s) 359 return 0; 360 361 /* 362 * check that IP address in the PORT/PASV reply is the same as the 363 * sender of the command - prevents using PORT for port scanning. 364 */ 365 a1 <<= 16; 366 a1 |= a2; 367 if (a1 != ntohl(nat->nat_oip.s_addr)) 368 return 0; 369 370 a5 = ippr_ftp_atoi(&s); 371 if (!s) 372 return 0; 373 374 if (*s == ')') 375 s++; 376 if (*s == '\n') 377 s--; 378 /* 379 * check for CR-LF at the end. 380 */ 381 if ((*s == '\r') && (*(s + 1) == '\n')) { 382 s += 2; 383 a6 = a5 & 0xff; 384 } else 385 return 0; 386 a5 >>= 8; 387 /* 388 * Calculate new address parts for 227 reply 389 */ 390 a1 = ntohl(ip->ip_src.s_addr); 391 a2 = (a1 >> 16) & 0xff; 392 a3 = (a1 >> 8) & 0xff; 393 a4 = a1 & 0xff; 394 a1 >>= 24; 395 inc = 0; 396#if 0 397 olen = s - f->ftps_rptr; 398 (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", 399 "227 Entering Passive Mode", a1, a2, a3, a4, a5, a6); 400 nlen = strlen(newbuf); 401 inc = nlen - olen; 402 if ((inc + ip->ip_len) > 65535) 403 return 0; 404 405#if SOLARIS 406 m = fin->fin_qfm; 407 for (m1 = m; m1->b_cont; m1 = m1->b_cont) 408 ; 409 if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) { 410 mblk_t *nm; 411 412 /* alloc enough to keep same trailer space for lower driver */ 413 nm = allocb(nlen, BPRI_MED); 414 PANIC((!nm),("ippr_ftp_out: allocb failed")); 415 416 nm->b_band = m1->b_band; 417 nm->b_wptr += nlen; 418 419 m1->b_wptr -= olen; 420 PANIC((m1->b_wptr < m1->b_rptr), 421 ("ippr_ftp_out: cannot handle fragmented data block")); 422 423 linkb(m1, nm); 424 } else { 425 m1->b_wptr += inc; 426 } 427 /*copyin_mblk(m, off, nlen, newbuf);*/ 428#else /* SOLARIS */ 429 m = *((mb_t **)fin->fin_mp); 430 if (inc < 0) 431 m_adj(m, inc); 432 /* the mbuf chain will be extended if necessary by m_copyback() */ 433 /*m_copyback(m, off, nlen, newbuf);*/ 434#endif /* SOLARIS */ 435 if (inc != 0) { 436#if SOLARIS || defined(__sgi) 437 register u_32_t sum1, sum2; 438 439 sum1 = ip->ip_len; 440 sum2 = ip->ip_len + inc; 441 442 /* Because ~1 == -2, We really need ~1 == -1 */ 443 if (sum1 > sum2) 444 sum2--; 445 sum2 -= sum1; 446 sum2 = (sum2 & 0xffff) + (sum2 >> 16); 447 448 fix_outcksum(&ip->ip_sum, sum2); 449#endif /* SOLARIS || defined(__sgi) */ 450 ip->ip_len += inc; 451 } 452#endif /* 0 */ 453 454 /* 455 * Add skeleton NAT entry for connection which will come back the 456 * other way. 457 */ 458 sp = 0; 459 dp = htons(fin->fin_data[1] - 1); 460 ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_p, nat->nat_inip, 461 ip->ip_dst, (dp << 16) | sp, 0); 462 if (ipn == NULL) { 463 int slen; 464 465 slen = ip->ip_len; 466 ip->ip_len = fin->fin_hlen + sizeof(*tcp2); 467 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 468 bzero((char *)tcp2, sizeof(*tcp2)); 469 tcp2->th_win = htons(8192); 470 tcp2->th_sport = 0; /* XXX - fake it for nat_new */ 471 tcp2->th_off = 5; 472 fi.fin_data[1] = a5 << 8 | a6; 473 fi.fin_dlen = sizeof(*tcp2); 474 tcp2->th_dport = htons(fi.fin_data[1]); 475 fi.fin_data[0] = 0; 476 fi.fin_dp = (char *)tcp2; 477 fi.fin_fr = &natfr; 478 swip = ip->ip_src; 479 swip2 = ip->ip_dst; 480 fi.fin_fi.fi_daddr = ip->ip_src.s_addr; 481 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; 482 ip->ip_dst = ip->ip_src; 483 ip->ip_src = nat->nat_inip; 484 ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_TCP|FI_W_SPORT, 485 NAT_OUTBOUND); 486 if (ipn != NULL) { 487 ipn->nat_age = fr_defnatage; 488 (void) fr_addstate(ip, &fi, FI_W_SPORT); 489 } 490 ip->ip_len = slen; 491 ip->ip_src = swip; 492 ip->ip_dst = swip2; 493 } 494 return inc; 495} 496 497 498int ippr_ftp_server(fin, ip, nat, ftp, dlen) 499fr_info_t *fin; 500ip_t *ip; 501nat_t *nat; 502ftpinfo_t *ftp; 503int dlen; 504{ 505 char *rptr, *wptr; 506 ftpside_t *f; 507 int inc; 508 509 inc = 0; 510 f = &ftp->ftp_side[1]; 511 rptr = f->ftps_rptr; 512 wptr = f->ftps_wptr; 513 514 if ((ftp->ftp_passok == 1) && !strncmp(rptr, "331", 3)) 515 ftp->ftp_passok = 2; 516 else if ((ftp->ftp_passok == 3) && !strncmp(rptr, "230", 3)) 517 ftp->ftp_passok = 4; 518 else if ((ftp->ftp_passok == 3) && !strncmp(rptr, "530", 3)) 519 ftp->ftp_passok = 0; 520 else if ((ftp->ftp_passok == 4) && !strncmp(rptr, "227 ", 4)) { 521 inc = ippr_ftp_pasv(fin, ip, nat, f, dlen); 522 } else if (ippr_ftp_insecure && !strncmp(rptr, "227 ", 4)) { 523 inc = ippr_ftp_pasv(fin, ip, nat, f, dlen); 524 } 525 while ((*rptr++ != '\n') && (rptr < wptr)) 526 ; 527 f->ftps_rptr = rptr; 528 return inc; 529} 530 531 532/* 533 * Look to see if the buffer starts with something which we recognise as 534 * being the correct syntax for the FTP protocol. 535 */ 536int ippr_ftp_valid(buf, len) 537char *buf; 538size_t len; 539{ 540 register char *s, c; 541 register size_t i = len; 542 543 if (i < 5) 544 return 2; 545 s = buf; 546 c = *s++; 547 i--; 548 549 if (isdigit(c)) { 550 c = *s++; 551 i--; 552 if (isdigit(c)) { 553 c = *s++; 554 i--; 555 if (isdigit(c)) { 556 c = *s++; 557 i--; 558 if ((c != '-') && (c != ' ')) 559 return 1; 560 } else 561 return 1; 562 } else 563 return 1; 564 } else if (isalpha(c)) { 565 c = *s++; 566 i--; 567 if (isalpha(c)) { 568 c = *s++; 569 i--; 570 if (isalpha(c)) { 571 c = *s++; 572 i--; 573 if (isalpha(c)) { 574 c = *s++; 575 i--; 576 if ((c != ' ') && (c != '\r')) 577 return 1; 578 } else if ((c != ' ') && (c != '\r')) 579 return 1; 580 } else 581 return 1; 582 } else 583 return 1; 584 } else 585 return 1; 586 for (; i; i--) { 587 c = *s++; 588 if (c == '\n') 589 return 0; 590 } 591 return 2; 592} 593 594 595int ippr_ftp_process(fin, ip, nat, ftp, rv) 596fr_info_t *fin; 597ip_t *ip; 598nat_t *nat; 599ftpinfo_t *ftp; 600int rv; 601{ 602 int mlen, len, off, inc, i, sel; 603 char *rptr, *wptr; 604 ftpside_t *f, *t; 605 tcphdr_t *tcp; 606 mb_t *m; 607 608 tcp = (tcphdr_t *)fin->fin_dp; 609 off = fin->fin_hlen + (tcp->th_off << 2); 610 611#if SOLARIS 612 m = fin->fin_qfm; 613#else 614 m = *((mb_t **)fin->fin_mp); 615#endif 616 617#if SOLARIS 618 mlen = msgdsize(m) - off; 619#else 620 mlen = mbufchainlen(m) - off; 621#endif 622 623 t = &ftp->ftp_side[1 - rv]; 624 f = &ftp->ftp_side[rv]; 625 if (!mlen) { 626 if (!t->ftps_seq || 627 (int)ntohl(tcp->th_ack) - (int)t->ftps_seq > 0) 628 t->ftps_seq = ntohl(tcp->th_ack); 629 f->ftps_len = 0; 630 return 0; 631 } 632 633 inc = 0; 634 rptr = f->ftps_rptr; 635 wptr = f->ftps_wptr; 636 637 sel = nat->nat_aps->aps_sel[1 - rv]; 638 if (rv) 639 i = nat->nat_aps->aps_ackoff[sel]; 640 else 641 i = nat->nat_aps->aps_seqoff[sel]; 642 /* 643 * XXX - Ideally, this packet should get dropped because we now know 644 * that it is out of order (and there is no real danger in doing so 645 * apart from causing packets to go through here ordered). 646 */ 647 if (f->ftps_len + f->ftps_seq == ntohl(tcp->th_seq)) 648 f->ftps_seq = ntohl(tcp->th_seq); 649 else if (ntohl(tcp->th_seq) + i != f->ftps_seq) { 650 return APR_ERR(-1); 651 } 652 f->ftps_len = mlen; 653 654 while (mlen > 0) { 655 len = MIN(mlen, FTP_BUFSZ / 2); 656 657#if SOLARIS 658 copyout_mblk(m, off, len, wptr); 659#else 660 m_copydata(m, off, len, wptr); 661#endif 662 mlen -= len; 663 off += len; 664 wptr += len; 665 f->ftps_wptr = wptr; 666 if (f->ftps_junk == 2) 667 f->ftps_junk = ippr_ftp_valid(rptr, wptr - rptr); 668 669 while ((f->ftps_junk == 0) && (wptr > rptr)) { 670 f->ftps_junk = ippr_ftp_valid(rptr, wptr - rptr); 671 if (f->ftps_junk == 0) { 672 len = wptr - rptr; 673 f->ftps_rptr = rptr; 674 if (rv) 675 inc += ippr_ftp_server(fin, ip, nat, 676 ftp, len); 677 else 678 inc += ippr_ftp_client(fin, ip, nat, 679 ftp, len); 680 rptr = f->ftps_rptr; 681 } 682 } 683 684 while ((f->ftps_junk == 1) && (rptr < wptr)) { 685 while ((rptr < wptr) && (*rptr != '\r')) 686 rptr++; 687 688 if (*rptr == '\r') { 689 if (rptr + 1 < wptr) { 690 if (*(rptr + 1) == '\n') { 691 rptr += 2; 692 f->ftps_junk = 0; 693 } else 694 rptr++; 695 } else 696 break; 697 } 698 } 699 f->ftps_rptr = rptr; 700 701 if (rptr == wptr) { 702 rptr = wptr = f->ftps_buf; 703 } else { 704 if ((wptr > f->ftps_buf + FTP_BUFSZ / 2)) { 705 i = wptr - rptr; 706 if ((rptr == f->ftps_buf) || 707 (wptr - rptr > FTP_BUFSZ / 2)) { 708 f->ftps_junk = 1; 709 rptr = wptr = f->ftps_buf; 710 } else { 711 bcopy(rptr, f->ftps_buf, i); 712 wptr = f->ftps_buf + i; 713 rptr = f->ftps_buf; 714 } 715 } 716 f->ftps_rptr = rptr; 717 f->ftps_wptr = wptr; 718 } 719 } 720 721 t->ftps_seq = ntohl(tcp->th_ack); 722 f->ftps_rptr = rptr; 723 f->ftps_wptr = wptr; 724 return APR_INC(inc); 725} 726 727 728int ippr_ftp_out(fin, ip, aps, nat) 729fr_info_t *fin; 730ip_t *ip; 731ap_session_t *aps; 732nat_t *nat; 733{ 734 ftpinfo_t *ftp; 735 736 ftp = aps->aps_data; 737 if (ftp == NULL) 738 return 0; 739 return ippr_ftp_process(fin, ip, nat, ftp, 0); 740} 741 742 743int ippr_ftp_in(fin, ip, aps, nat) 744fr_info_t *fin; 745ip_t *ip; 746ap_session_t *aps; 747nat_t *nat; 748{ 749 ftpinfo_t *ftp; 750 751 ftp = aps->aps_data; 752 if (ftp == NULL) 753 return 0; 754 return ippr_ftp_process(fin, ip, nat, ftp, 1); 755} 756 757 758/* 759 * ippr_ftp_atoi - implement a version of atoi which processes numbers in 760 * pairs separated by commas (which are expected to be in the range 0 - 255), 761 * returning a 16 bit number combining either side of the , as the MSB and 762 * LSB. 763 */ 764u_short ippr_ftp_atoi(ptr) 765char **ptr; 766{ 767 register char *s = *ptr, c; 768 register u_char i = 0, j = 0; 769 770 while ((c = *s++) && isdigit(c)) { 771 i *= 10; 772 i += c - '0'; 773 } 774 if (c != ',') { 775 *ptr = NULL; 776 return 0; 777 } 778 while ((c = *s++) && isdigit(c)) { 779 j *= 10; 780 j += c - '0'; 781 } 782 *ptr = s; 783 i &= 0xff; 784 j &= 0xff; 785 return (i << 8) | j; 786} 787