1 /* 2 * Copyright (C) 1997-2003 by Darren Reed 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * $Id: ip_ftp_pxy.c,v 2.88.2.15 2005/03/19 19:38:10 darrenr Exp $ 7 * 8 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 9 * Use is subject to license terms. 10 * 11 * Simple FTP transparent proxy for in-kernel use. For use with the NAT 12 * code. 13 */ 14 15 #pragma ident "%Z%%M% %I% %E% SMI" 16 17 18 #define IPF_FTP_PROXY 19 20 #define IPF_MINPORTLEN 18 21 #define IPF_MAXPORTLEN 30 22 #define IPF_MIN227LEN 39 23 #define IPF_MAX227LEN 51 24 #define IPF_MIN229LEN 47 25 #define IPF_MAX229LEN 51 26 27 #define FTPXY_GO 0 28 #define FTPXY_INIT 1 29 #define FTPXY_USER_1 2 30 #define FTPXY_USOK_1 3 31 #define FTPXY_PASS_1 4 32 #define FTPXY_PAOK_1 5 33 #define FTPXY_AUTH_1 6 34 #define FTPXY_AUOK_1 7 35 #define FTPXY_ADAT_1 8 36 #define FTPXY_ADOK_1 9 37 #define FTPXY_ACCT_1 10 38 #define FTPXY_ACOK_1 11 39 #define FTPXY_USER_2 12 40 #define FTPXY_USOK_2 13 41 #define FTPXY_PASS_2 14 42 #define FTPXY_PAOK_2 15 43 44 /* 45 * Values for FTP commands. Numerics cover 0-999 46 */ 47 #define FTPXY_C_PASV 1000 48 49 int ippr_ftp_client __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); 50 int ippr_ftp_complete __P((char *, size_t)); 51 int ippr_ftp_in __P((fr_info_t *, ap_session_t *, nat_t *)); 52 int ippr_ftp_init __P((void)); 53 void ippr_ftp_fini __P((void)); 54 int ippr_ftp_new __P((fr_info_t *, ap_session_t *, nat_t *)); 55 int ippr_ftp_out __P((fr_info_t *, ap_session_t *, nat_t *)); 56 int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); 57 int ippr_ftp_epsv __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); 58 int ippr_ftp_port __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); 59 int ippr_ftp_process __P((fr_info_t *, nat_t *, ftpinfo_t *, int)); 60 int ippr_ftp_server __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); 61 int ippr_ftp_valid __P((ftpinfo_t *, int, char *, size_t)); 62 int ippr_ftp_server_valid __P((ftpside_t *, char *, size_t)); 63 int ippr_ftp_client_valid __P((ftpside_t *, char *, size_t)); 64 u_short ippr_ftp_atoi __P((char **)); 65 int ippr_ftp_pasvreply __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, 66 u_int, char *, char *, u_int)); 67 68 69 int ftp_proxy_init = 0; 70 int ippr_ftp_pasvonly = 0; 71 int ippr_ftp_insecure = 0; /* Do not require logins before transfers */ 72 int ippr_ftp_pasvrdr = 0; 73 int ippr_ftp_forcepasv = 0; /* PASV must be last command prior to 227 */ 74 #if defined(_KERNEL) 75 int ippr_ftp_debug = 0; 76 #else 77 int ippr_ftp_debug = 2; 78 #endif 79 /* 80 * 1 - security 81 * 2 - errors 82 * 3 - error debugging 83 * 4 - parsing errors 84 * 5 - parsing info 85 * 6 - parsing debug 86 */ 87 88 static frentry_t ftppxyfr; 89 static ipftuneable_t ftptune = { 90 { &ippr_ftp_debug }, 91 "ippr_ftp_debug", 92 0, 93 10, 94 sizeof(ippr_ftp_debug), 95 0, 96 NULL 97 }; 98 99 100 /* 101 * Initialize local structures. 102 */ 103 int ippr_ftp_init() 104 { 105 bzero((char *)&ftppxyfr, sizeof(ftppxyfr)); 106 ftppxyfr.fr_ref = 1; 107 ftppxyfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 108 MUTEX_INIT(&ftppxyfr.fr_lock, "FTP Proxy Mutex"); 109 ftp_proxy_init = 1; 110 (void) fr_addipftune(&ftptune); 111 112 return 0; 113 } 114 115 116 void ippr_ftp_fini() 117 { 118 (void) fr_delipftune(&ftptune); 119 120 if (ftp_proxy_init == 1) { 121 MUTEX_DESTROY(&ftppxyfr.fr_lock); 122 ftp_proxy_init = 0; 123 } 124 } 125 126 127 int ippr_ftp_new(fin, aps, nat) 128 fr_info_t *fin; 129 ap_session_t *aps; 130 nat_t *nat; 131 { 132 ftpinfo_t *ftp; 133 ftpside_t *f; 134 135 KMALLOC(ftp, ftpinfo_t *); 136 if (ftp == NULL) 137 return -1; 138 139 fin = fin; /* LINT */ 140 nat = nat; /* LINT */ 141 142 aps->aps_data = ftp; 143 aps->aps_psiz = sizeof(ftpinfo_t); 144 145 bzero((char *)ftp, sizeof(*ftp)); 146 f = &ftp->ftp_side[0]; 147 f->ftps_rptr = f->ftps_buf; 148 f->ftps_wptr = f->ftps_buf; 149 f = &ftp->ftp_side[1]; 150 f->ftps_rptr = f->ftps_buf; 151 f->ftps_wptr = f->ftps_buf; 152 ftp->ftp_passok = FTPXY_INIT; 153 ftp->ftp_incok = 0; 154 return 0; 155 } 156 157 158 int ippr_ftp_port(fin, ip, nat, f, dlen) 159 fr_info_t *fin; 160 ip_t *ip; 161 nat_t *nat; 162 ftpside_t *f; 163 int dlen; 164 { 165 tcphdr_t *tcp, tcph, *tcp2 = &tcph; 166 char newbuf[IPF_FTPBUFSZ], *s; 167 struct in_addr swip, swip2; 168 u_int a1, a2, a3, a4; 169 int inc, off, flags; 170 u_short a5, a6, sp; 171 size_t nlen, olen; 172 fr_info_t fi; 173 nat_t *nat2; 174 mb_t *m; 175 176 m = fin->fin_m; 177 tcp = (tcphdr_t *)fin->fin_dp; 178 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 179 180 /* 181 * Check for client sending out PORT message. 182 */ 183 if (dlen < IPF_MINPORTLEN) { 184 if (ippr_ftp_debug > 1) 185 printf("ippr_ftp_port:dlen(%d) < IPF_MINPORTLEN\n", 186 dlen); 187 return 0; 188 } 189 /* 190 * Skip the PORT command + space 191 */ 192 s = f->ftps_rptr + 5; 193 /* 194 * Pick out the address components, two at a time. 195 */ 196 a1 = ippr_ftp_atoi(&s); 197 if (s == NULL) { 198 if (ippr_ftp_debug > 1) 199 printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 1); 200 return 0; 201 } 202 a2 = ippr_ftp_atoi(&s); 203 if (s == NULL) { 204 if (ippr_ftp_debug > 1) 205 printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 2); 206 return 0; 207 } 208 209 /* 210 * Check that IP address in the PORT/PASV reply is the same as the 211 * sender of the command - prevents using PORT for port scanning. 212 */ 213 a1 <<= 16; 214 a1 |= a2; 215 if (((nat->nat_dir == NAT_OUTBOUND) && 216 (a1 != ntohl(nat->nat_inip.s_addr))) || 217 ((nat->nat_dir == NAT_INBOUND) && 218 (a1 != ntohl(nat->nat_oip.s_addr)))) { 219 if (ippr_ftp_debug > 0) 220 printf("ippr_ftp_port:%s != nat->nat_inip\n", "a1"); 221 return APR_ERR(1); 222 } 223 224 a5 = ippr_ftp_atoi(&s); 225 if (s == NULL) { 226 if (ippr_ftp_debug > 1) 227 printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 3); 228 return 0; 229 } 230 if (*s == ')') 231 s++; 232 233 /* 234 * check for CR-LF at the end. 235 */ 236 if (*s == '\n') 237 s--; 238 if ((*s == '\r') && (*(s + 1) == '\n')) { 239 s += 2; 240 a6 = a5 & 0xff; 241 } else { 242 if (ippr_ftp_debug > 1) 243 printf("ippr_ftp_port:missing %s\n", "cr-lf"); 244 return 0; 245 } 246 247 a5 >>= 8; 248 a5 &= 0xff; 249 sp = a5 << 8 | a6; 250 /* 251 * Don't allow the PORT command to specify a port < 1024 due to 252 * security crap. 253 */ 254 if (sp < 1024) { 255 if (ippr_ftp_debug > 0) 256 printf("ippr_ftp_port:sp(%d) < 1024\n", sp); 257 return 0; 258 } 259 /* 260 * Calculate new address parts for PORT command 261 */ 262 if (nat->nat_dir == NAT_INBOUND) 263 a1 = ntohl(nat->nat_oip.s_addr); 264 else 265 a1 = ntohl(ip->ip_src.s_addr); 266 a2 = (a1 >> 16) & 0xff; 267 a3 = (a1 >> 8) & 0xff; 268 a4 = a1 & 0xff; 269 a1 >>= 24; 270 olen = s - f->ftps_rptr; 271 /* DO NOT change this to snprintf! */ 272 #if defined(SNPRINTF) && defined(_KERNEL) 273 (void) SNPRINTF(newbuf, sizeof(newbuf), "%s %u,%u,%u,%u,%u,%u\r\n", 274 "PORT", a1, a2, a3, a4, a5, a6); 275 #else 276 (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", 277 "PORT", a1, a2, a3, a4, a5, a6); 278 #endif 279 280 nlen = strlen(newbuf); 281 inc = nlen - olen; 282 if ((inc + ip->ip_len) > 65535) { 283 if (ippr_ftp_debug > 0) 284 printf("ippr_ftp_port:inc(%d) + ip->ip_len > 65535\n", 285 inc); 286 return 0; 287 } 288 289 #if !defined(_KERNEL) 290 bcopy(newbuf, MTOD(m, char *) + off, nlen); 291 #else 292 # if defined(MENTAT) 293 if (inc < 0) 294 (void)adjmsg(m, inc); 295 # else /* defined(MENTAT) */ 296 /* 297 * m_adj takes care of pkthdr.len, if required and treats inc<0 to 298 * mean remove -len bytes from the end of the packet. 299 * The mbuf chain will be extended if necessary by m_copyback(). 300 */ 301 if (inc < 0) 302 m_adj(m, inc); 303 # endif /* defined(MENTAT) */ 304 #endif /* !defined(_KERNEL) */ 305 COPYBACK(m, off, nlen, newbuf); 306 307 if (inc != 0) { 308 ip->ip_len += inc; 309 fin->fin_dlen += inc; 310 fin->fin_plen += inc; 311 } 312 313 /* 314 * The server may not make the connection back from port 20, but 315 * it is the most likely so use it here to check for a conflicting 316 * mapping. 317 */ 318 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 319 fi.fin_state = NULL; 320 fi.fin_nat = NULL; 321 fi.fin_flx |= FI_IGNORE; 322 fi.fin_data[0] = sp; 323 fi.fin_data[1] = fin->fin_data[1] - 1; 324 /* 325 * Add skeleton NAT entry for connection which will come back the 326 * other way. 327 */ 328 if (nat->nat_dir == NAT_OUTBOUND) 329 nat2 = nat_outlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, 330 nat->nat_inip, nat->nat_oip); 331 else 332 nat2 = nat_inlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, 333 nat->nat_inip, nat->nat_oip); 334 if (nat2 == NULL) { 335 int slen; 336 337 slen = ip->ip_len; 338 ip->ip_len = fin->fin_hlen + sizeof(*tcp2); 339 bzero((char *)tcp2, sizeof(*tcp2)); 340 tcp2->th_win = htons(8192); 341 tcp2->th_sport = htons(sp); 342 TCP_OFF_A(tcp2, 5); 343 tcp2->th_flags = TH_SYN; 344 tcp2->th_dport = 0; /* XXX - don't specify remote port */ 345 fi.fin_data[1] = 0; 346 fi.fin_dlen = sizeof(*tcp2); 347 fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); 348 fi.fin_dp = (char *)tcp2; 349 fi.fin_fr = &ftppxyfr; 350 fi.fin_out = nat->nat_dir; 351 fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; 352 swip = ip->ip_src; 353 swip2 = ip->ip_dst; 354 if (nat->nat_dir == NAT_OUTBOUND) { 355 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; 356 ip->ip_src = nat->nat_inip; 357 } else if (nat->nat_dir == NAT_INBOUND) { 358 fi.fin_fi.fi_saddr = nat->nat_oip.s_addr; 359 ip->ip_src = nat->nat_oip; 360 } 361 362 flags = NAT_SLAVE|IPN_TCP|SI_W_DPORT; 363 if (nat->nat_dir == NAT_INBOUND) 364 flags |= NAT_NOTRULEPORT; 365 nat2 = nat_new(&fi, nat->nat_ptr, NULL, flags, nat->nat_dir); 366 367 if (nat2 != NULL) { 368 (void) nat_proto(&fi, nat2, IPN_TCP); 369 nat_update(&fi, nat2, nat->nat_ptr); 370 fi.fin_ifp = NULL; 371 if (nat->nat_dir == NAT_INBOUND) { 372 fi.fin_fi.fi_daddr = nat->nat_inip.s_addr; 373 ip->ip_dst = nat->nat_inip; 374 } 375 (void) fr_addstate(&fi, &nat2->nat_state, SI_W_DPORT); 376 if (fi.fin_state != NULL) 377 fr_statederef(&fi, (ipstate_t **)&fi.fin_state); 378 } 379 ip->ip_len = slen; 380 ip->ip_src = swip; 381 ip->ip_dst = swip2; 382 } else { 383 ipstate_t *is; 384 385 nat_update(&fi, nat2, nat->nat_ptr); 386 READ_ENTER(&ipf_state); 387 is = nat2->nat_state; 388 if (is != NULL) { 389 MUTEX_ENTER(&is->is_lock); 390 (void)fr_tcp_age(&is->is_sti, &fi, ips_tqtqb, 391 is->is_flags); 392 MUTEX_EXIT(&is->is_lock); 393 } 394 RWLOCK_EXIT(&ipf_state); 395 } 396 return APR_INC(inc); 397 } 398 399 400 int ippr_ftp_client(fin, ip, nat, ftp, dlen) 401 fr_info_t *fin; 402 nat_t *nat; 403 ftpinfo_t *ftp; 404 ip_t *ip; 405 int dlen; 406 { 407 char *rptr, *wptr, cmd[6], c; 408 ftpside_t *f; 409 int inc, i; 410 411 inc = 0; 412 f = &ftp->ftp_side[0]; 413 rptr = f->ftps_rptr; 414 wptr = f->ftps_wptr; 415 416 for (i = 0; (i < 5) && (i < dlen); i++) { 417 c = rptr[i]; 418 if (ISALPHA(c)) { 419 cmd[i] = TOUPPER(c); 420 } else { 421 cmd[i] = c; 422 } 423 } 424 cmd[i] = '\0'; 425 426 ftp->ftp_incok = 0; 427 if (!strncmp(cmd, "USER ", 5) || !strncmp(cmd, "XAUT ", 5)) { 428 if (ftp->ftp_passok == FTPXY_ADOK_1 || 429 ftp->ftp_passok == FTPXY_AUOK_1) { 430 ftp->ftp_passok = FTPXY_USER_2; 431 ftp->ftp_incok = 1; 432 } else { 433 ftp->ftp_passok = FTPXY_USER_1; 434 ftp->ftp_incok = 1; 435 } 436 } else if (!strncmp(cmd, "AUTH ", 5)) { 437 ftp->ftp_passok = FTPXY_AUTH_1; 438 ftp->ftp_incok = 1; 439 } else if (!strncmp(cmd, "PASS ", 5)) { 440 if (ftp->ftp_passok == FTPXY_USOK_1) { 441 ftp->ftp_passok = FTPXY_PASS_1; 442 ftp->ftp_incok = 1; 443 } else if (ftp->ftp_passok == FTPXY_USOK_2) { 444 ftp->ftp_passok = FTPXY_PASS_2; 445 ftp->ftp_incok = 1; 446 } 447 } else if ((ftp->ftp_passok == FTPXY_AUOK_1) && 448 !strncmp(cmd, "ADAT ", 5)) { 449 ftp->ftp_passok = FTPXY_ADAT_1; 450 ftp->ftp_incok = 1; 451 } else if ((ftp->ftp_passok == FTPXY_PAOK_1 || 452 ftp->ftp_passok == FTPXY_PAOK_2) && 453 !strncmp(cmd, "ACCT ", 5)) { 454 ftp->ftp_passok = FTPXY_ACCT_1; 455 ftp->ftp_incok = 1; 456 } else if ((ftp->ftp_passok == FTPXY_GO) && !ippr_ftp_pasvonly && 457 !strncmp(cmd, "PORT ", 5)) { 458 inc = ippr_ftp_port(fin, ip, nat, f, dlen); 459 } else if (ippr_ftp_insecure && !ippr_ftp_pasvonly && 460 !strncmp(cmd, "PORT ", 5)) { 461 inc = ippr_ftp_port(fin, ip, nat, f, dlen); 462 } 463 464 while ((*rptr++ != '\n') && (rptr < wptr)) 465 ; 466 f->ftps_rptr = rptr; 467 return inc; 468 } 469 470 471 int ippr_ftp_pasv(fin, ip, nat, ftp, dlen) 472 fr_info_t *fin; 473 ip_t *ip; 474 nat_t *nat; 475 ftpinfo_t *ftp; 476 int dlen; 477 { 478 u_int a1, a2, a3, a4, data_ip; 479 char newbuf[IPF_FTPBUFSZ]; 480 char *s, *brackets[2]; 481 u_short a5, a6; 482 ftpside_t *f; 483 484 if (ippr_ftp_forcepasv != 0 && 485 ftp->ftp_side[0].ftps_cmds != FTPXY_C_PASV) { 486 if (ippr_ftp_debug > 0) 487 printf("ippr_ftp_pasv:ftps_cmds(%d) != FTPXY_C_PASV\n", 488 ftp->ftp_side[0].ftps_cmds); 489 return 0; 490 } 491 492 f = &ftp->ftp_side[1]; 493 494 #define PASV_REPLEN 24 495 /* 496 * Check for PASV reply message. 497 */ 498 if (dlen < IPF_MIN227LEN) { 499 if (ippr_ftp_debug > 1) 500 printf("ippr_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n", 501 dlen); 502 return 0; 503 } else if (strncmp(f->ftps_rptr, 504 "227 Entering Passive Mod", PASV_REPLEN)) { 505 if (ippr_ftp_debug > 0) 506 printf("ippr_ftp_pasv:%d reply wrong\n", 227); 507 return 0; 508 } 509 510 brackets[0] = ""; 511 brackets[1] = ""; 512 /* 513 * Skip the PASV reply + space 514 */ 515 s = f->ftps_rptr + PASV_REPLEN; 516 while (*s && !ISDIGIT(*s)) { 517 if (*s == '(') { 518 brackets[0] = "("; 519 brackets[1] = ")"; 520 } 521 s++; 522 } 523 524 /* 525 * Pick out the address components, two at a time. 526 */ 527 a1 = ippr_ftp_atoi(&s); 528 if (s == NULL) { 529 if (ippr_ftp_debug > 1) 530 printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 1); 531 return 0; 532 } 533 a2 = ippr_ftp_atoi(&s); 534 if (s == NULL) { 535 if (ippr_ftp_debug > 1) 536 printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 2); 537 return 0; 538 } 539 540 /* 541 * check that IP address in the PASV reply is the same as the 542 * sender of the command - prevents using PASV for port scanning. 543 */ 544 a1 <<= 16; 545 a1 |= a2; 546 547 if (((nat->nat_dir == NAT_INBOUND) && 548 (a1 != ntohl(nat->nat_inip.s_addr))) || 549 ((nat->nat_dir == NAT_OUTBOUND) && 550 (a1 != ntohl(nat->nat_oip.s_addr)))) { 551 if (ippr_ftp_debug > 0) 552 printf("ippr_ftp_pasv:%s != nat->nat_oip\n", "a1"); 553 return 0; 554 } 555 556 a5 = ippr_ftp_atoi(&s); 557 if (s == NULL) { 558 if (ippr_ftp_debug > 1) 559 printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 3); 560 return 0; 561 } 562 563 if (*s == ')') 564 s++; 565 if (*s == '.') 566 s++; 567 if (*s == '\n') 568 s--; 569 /* 570 * check for CR-LF at the end. 571 */ 572 if ((*s == '\r') && (*(s + 1) == '\n')) { 573 s += 2; 574 } else { 575 if (ippr_ftp_debug > 1) 576 printf("ippr_ftp_pasv:missing %s", "cr-lf\n"); 577 return 0; 578 } 579 580 a6 = a5 & 0xff; 581 a5 >>= 8; 582 /* 583 * Calculate new address parts for 227 reply 584 */ 585 if (nat->nat_dir == NAT_INBOUND) { 586 data_ip = nat->nat_outip.s_addr; 587 a1 = ntohl(data_ip); 588 } else 589 data_ip = htonl(a1); 590 591 a2 = (a1 >> 16) & 0xff; 592 a3 = (a1 >> 8) & 0xff; 593 a4 = a1 & 0xff; 594 a1 >>= 24; 595 596 #if defined(SNPRINTF) && defined(_KERNEL) 597 (void) SNPRINTF(newbuf, sizeof(newbuf), "%s %s%u,%u,%u,%u,%u,%u%s\r\n", 598 "227 Entering Passive Mode", brackets[0], a1, a2, a3, a4, 599 a5, a6, brackets[1]); 600 #else 601 (void) sprintf(newbuf, "%s %s%u,%u,%u,%u,%u,%u%s\r\n", 602 "227 Entering Passive Mode", brackets[0], a1, a2, a3, a4, 603 a5, a6, brackets[1]); 604 #endif 605 return ippr_ftp_pasvreply(fin, ip, nat, f, (a5 << 8 | a6), 606 newbuf, s, data_ip); 607 } 608 609 int ippr_ftp_pasvreply(fin, ip, nat, f, port, newmsg, s, data_ip) 610 fr_info_t *fin; 611 ip_t *ip; 612 nat_t *nat; 613 ftpside_t *f; 614 u_int port; 615 char *newmsg; 616 char *s; 617 u_int data_ip; 618 { 619 int inc, off, nflags, sflags; 620 tcphdr_t *tcp, tcph, *tcp2; 621 struct in_addr swip, swip2; 622 struct in_addr data_addr; 623 size_t nlen, olen; 624 fr_info_t fi; 625 nat_t *nat2; 626 mb_t *m; 627 628 m = fin->fin_m; 629 tcp = (tcphdr_t *)fin->fin_dp; 630 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 631 632 data_addr.s_addr = data_ip; 633 tcp2 = &tcph; 634 inc = 0; 635 636 637 olen = s - f->ftps_rptr; 638 nlen = strlen(newmsg); 639 inc = nlen - olen; 640 if ((inc + ip->ip_len) > 65535) { 641 if (ippr_ftp_debug > 0) 642 printf("ippr_ftp_pasv:inc(%d) + ip->ip_len > 65535\n", 643 inc); 644 return 0; 645 } 646 647 #if !defined(_KERNEL) 648 bcopy(newmsg, MTOD(m, char *) + off, nlen); 649 #else 650 # if defined(MENTAT) 651 if (inc < 0) 652 (void)adjmsg(m, inc); 653 # else /* defined(MENTAT) */ 654 /* 655 * m_adj takes care of pkthdr.len, if required and treats inc<0 to 656 * mean remove -len bytes from the end of the packet. 657 * The mbuf chain will be extended if necessary by m_copyback(). 658 */ 659 if (inc < 0) 660 m_adj(m, inc); 661 # endif /* defined(MENTAT) */ 662 #endif /* !defined(_KERNEL) */ 663 COPYBACK(m, off, nlen, newmsg); 664 665 if (inc != 0) { 666 ip->ip_len += inc; 667 fin->fin_dlen += inc; 668 fin->fin_plen += inc; 669 } 670 671 /* 672 * Add skeleton NAT entry for connection which will come back the 673 * other way. 674 */ 675 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 676 fi.fin_state = NULL; 677 fi.fin_nat = NULL; 678 fi.fin_flx |= FI_IGNORE; 679 fi.fin_data[0] = 0; 680 fi.fin_data[1] = port; 681 nflags = IPN_TCP|SI_W_SPORT; 682 if (ippr_ftp_pasvrdr && f->ftps_ifp) 683 nflags |= SI_W_DPORT; 684 if (nat->nat_dir == NAT_OUTBOUND) 685 nat2 = nat_outlookup(&fi, nflags|NAT_SEARCH, 686 nat->nat_p, nat->nat_inip, nat->nat_oip); 687 else 688 nat2 = nat_inlookup(&fi, nflags|NAT_SEARCH, 689 nat->nat_p, nat->nat_inip, nat->nat_oip); 690 if (nat2 == NULL) { 691 int slen; 692 693 slen = ip->ip_len; 694 ip->ip_len = fin->fin_hlen + sizeof(*tcp2); 695 bzero((char *)tcp2, sizeof(*tcp2)); 696 tcp2->th_win = htons(8192); 697 tcp2->th_sport = 0; /* XXX - fake it for nat_new */ 698 TCP_OFF_A(tcp2, 5); 699 tcp2->th_flags = TH_SYN; 700 fi.fin_data[1] = port; 701 fi.fin_dlen = sizeof(*tcp2); 702 tcp2->th_dport = htons(port); 703 fi.fin_data[0] = 0; 704 fi.fin_dp = (char *)tcp2; 705 fi.fin_plen = fi.fin_hlen + sizeof(*tcp); 706 fi.fin_fr = &ftppxyfr; 707 fi.fin_out = nat->nat_dir; 708 fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; 709 swip = ip->ip_src; 710 swip2 = ip->ip_dst; 711 if (nat->nat_dir == NAT_OUTBOUND) { 712 fi.fin_fi.fi_daddr = data_addr.s_addr; 713 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; 714 ip->ip_dst = data_addr; 715 ip->ip_src = nat->nat_inip; 716 } else if (nat->nat_dir == NAT_INBOUND) { 717 fi.fin_fi.fi_saddr = nat->nat_oip.s_addr; 718 fi.fin_fi.fi_daddr = nat->nat_outip.s_addr; 719 ip->ip_src = nat->nat_oip; 720 ip->ip_dst = nat->nat_outip; 721 } 722 723 sflags = nflags; 724 nflags |= NAT_SLAVE; 725 if (nat->nat_dir == NAT_INBOUND) 726 nflags |= NAT_NOTRULEPORT; 727 nat2 = nat_new(&fi, nat->nat_ptr, NULL, nflags, nat->nat_dir); 728 if (nat2 != NULL) { 729 (void) nat_proto(&fi, nat2, IPN_TCP); 730 nat_update(&fi, nat2, nat->nat_ptr); 731 fi.fin_ifp = NULL; 732 if (nat->nat_dir == NAT_INBOUND) { 733 fi.fin_fi.fi_daddr = nat->nat_inip.s_addr; 734 ip->ip_dst = nat->nat_inip; 735 } 736 (void) fr_addstate(&fi, &nat2->nat_state, sflags); 737 if (fi.fin_state != NULL) 738 fr_statederef(&fi, (ipstate_t **)&fi.fin_state); 739 } 740 741 ip->ip_len = slen; 742 ip->ip_src = swip; 743 ip->ip_dst = swip2; 744 } else { 745 ipstate_t *is; 746 747 nat_update(&fi, nat2, nat->nat_ptr); 748 READ_ENTER(&ipf_state); 749 is = nat2->nat_state; 750 if (is != NULL) { 751 MUTEX_ENTER(&is->is_lock); 752 (void)fr_tcp_age(&is->is_sti, &fi, ips_tqtqb, 753 is->is_flags); 754 MUTEX_EXIT(&is->is_lock); 755 } 756 RWLOCK_EXIT(&ipf_state); 757 } 758 return inc; 759 } 760 761 762 int ippr_ftp_server(fin, ip, nat, ftp, dlen) 763 fr_info_t *fin; 764 ip_t *ip; 765 nat_t *nat; 766 ftpinfo_t *ftp; 767 int dlen; 768 { 769 char *rptr, *wptr; 770 ftpside_t *f; 771 int inc; 772 773 inc = 0; 774 f = &ftp->ftp_side[1]; 775 rptr = f->ftps_rptr; 776 wptr = f->ftps_wptr; 777 778 if (*rptr == ' ') 779 goto server_cmd_ok; 780 if (!ISDIGIT(*rptr) || !ISDIGIT(*(rptr + 1)) || !ISDIGIT(*(rptr + 2))) 781 return 0; 782 if (ftp->ftp_passok == FTPXY_GO) { 783 if (!strncmp(rptr, "227 ", 4)) 784 inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen); 785 else if (!strncmp(rptr, "229 ", 4)) 786 inc = ippr_ftp_epsv(fin, ip, nat, f, dlen); 787 } else if (ippr_ftp_insecure && !strncmp(rptr, "227 ", 4)) { 788 inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen); 789 } else if (ippr_ftp_insecure && !strncmp(rptr, "229 ", 4)) { 790 inc = ippr_ftp_epsv(fin, ip, nat, f, dlen); 791 } else if (*rptr == '5' || *rptr == '4') 792 ftp->ftp_passok = FTPXY_INIT; 793 else if (ftp->ftp_incok) { 794 if (*rptr == '3') { 795 if (ftp->ftp_passok == FTPXY_ACCT_1) 796 ftp->ftp_passok = FTPXY_GO; 797 else 798 ftp->ftp_passok++; 799 } else if (*rptr == '2') { 800 switch (ftp->ftp_passok) 801 { 802 case FTPXY_USER_1 : 803 case FTPXY_USER_2 : 804 case FTPXY_PASS_1 : 805 case FTPXY_PASS_2 : 806 case FTPXY_ACCT_1 : 807 ftp->ftp_passok = FTPXY_GO; 808 break; 809 default : 810 ftp->ftp_passok += 3; 811 break; 812 } 813 } 814 } 815 server_cmd_ok: 816 ftp->ftp_incok = 0; 817 818 while ((*rptr++ != '\n') && (rptr < wptr)) 819 ; 820 f->ftps_rptr = rptr; 821 return inc; 822 } 823 824 825 /* 826 * Look to see if the buffer starts with something which we recognise as 827 * being the correct syntax for the FTP protocol. 828 */ 829 int ippr_ftp_client_valid(ftps, buf, len) 830 ftpside_t *ftps; 831 char *buf; 832 size_t len; 833 { 834 register char *s, c, pc; 835 register size_t i = len; 836 char cmd[5]; 837 838 s = buf; 839 840 if (ftps->ftps_junk == 1) 841 return 1; 842 843 if (i < 5) { 844 if (ippr_ftp_debug > 3) 845 printf("ippr_ftp_client_valid:i(%d) < 5\n", (int)i); 846 return 2; 847 } 848 849 i--; 850 c = *s++; 851 852 if (ISALPHA(c)) { 853 cmd[0] = TOUPPER(c); 854 c = *s++; 855 i--; 856 if (ISALPHA(c)) { 857 cmd[1] = TOUPPER(c); 858 c = *s++; 859 i--; 860 if (ISALPHA(c)) { 861 cmd[2] = TOUPPER(c); 862 c = *s++; 863 i--; 864 if (ISALPHA(c)) { 865 cmd[3] = TOUPPER(c); 866 c = *s++; 867 i--; 868 if ((c != ' ') && (c != '\r')) 869 goto bad_client_command; 870 } else if ((c != ' ') && (c != '\r')) 871 goto bad_client_command; 872 } else 873 goto bad_client_command; 874 } else 875 goto bad_client_command; 876 } else { 877 bad_client_command: 878 if (ippr_ftp_debug > 3) 879 printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*s]\n", 880 "ippr_ftp_client_valid", 881 ftps->ftps_junk, (int)len, (int)i, c, 882 (int)len, buf); 883 return 1; 884 } 885 886 for (; i; i--) { 887 pc = c; 888 c = *s++; 889 if ((pc == '\r') && (c == '\n')) { 890 cmd[4] = '\0'; 891 if (!strcmp(cmd, "PASV")) 892 ftps->ftps_cmds = FTPXY_C_PASV; 893 else 894 ftps->ftps_cmds = 0; 895 return 0; 896 } 897 } 898 #if !defined(_KERNEL) 899 printf("ippr_ftp_client_valid:junk after cmd[%*.*s]\n", 900 (int)len, (int)len, buf); 901 #endif 902 return 2; 903 } 904 905 906 int ippr_ftp_server_valid(ftps, buf, len) 907 ftpside_t *ftps; 908 char *buf; 909 size_t len; 910 { 911 register char *s, c, pc; 912 register size_t i = len; 913 int cmd; 914 915 s = buf; 916 cmd = 0; 917 918 if (ftps->ftps_junk == 1) 919 return 1; 920 921 if (i < 5) { 922 if (ippr_ftp_debug > 3) 923 printf("ippr_ftp_servert_valid:i(%d) < 5\n", (int)i); 924 return 2; 925 } 926 927 c = *s++; 928 i--; 929 if (c == ' ') 930 goto search_eol; 931 932 if (ISDIGIT(c)) { 933 cmd = (c - '0') * 100; 934 c = *s++; 935 i--; 936 if (ISDIGIT(c)) { 937 cmd += (c - '0') * 10; 938 c = *s++; 939 i--; 940 if (ISDIGIT(c)) { 941 cmd += (c - '0'); 942 c = *s++; 943 i--; 944 if ((c != '-') && (c != ' ')) 945 goto bad_server_command; 946 } else 947 goto bad_server_command; 948 } else 949 goto bad_server_command; 950 } else { 951 bad_server_command: 952 if (ippr_ftp_debug > 3) 953 printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*s]\n", 954 "ippr_ftp_server_valid", 955 ftps->ftps_junk, (int)len, (int)i, 956 c, (int)len, buf); 957 return 1; 958 } 959 search_eol: 960 for (; i; i--) { 961 pc = c; 962 c = *s++; 963 if ((pc == '\r') && (c == '\n')) { 964 ftps->ftps_cmds = cmd; 965 return 0; 966 } 967 } 968 if (ippr_ftp_debug > 3) 969 printf("ippr_ftp_server_valid:junk after cmd[%*s]\n", 970 (int)len, buf); 971 return 2; 972 } 973 974 975 int ippr_ftp_valid(ftp, side, buf, len) 976 ftpinfo_t *ftp; 977 int side; 978 char *buf; 979 size_t len; 980 { 981 ftpside_t *ftps; 982 int ret; 983 984 ftps = &ftp->ftp_side[side]; 985 986 if (side == 0) 987 ret = ippr_ftp_client_valid(ftps, buf, len); 988 else 989 ret = ippr_ftp_server_valid(ftps, buf, len); 990 return ret; 991 } 992 993 994 /* 995 * For map rules, the following applies: 996 * rv == 0 for outbound processing, 997 * rv == 1 for inbound processing. 998 * For rdr rules, the following applies: 999 * rv == 0 for inbound processing, 1000 * rv == 1 for outbound processing. 1001 */ 1002 int ippr_ftp_process(fin, nat, ftp, rv) 1003 fr_info_t *fin; 1004 nat_t *nat; 1005 ftpinfo_t *ftp; 1006 int rv; 1007 { 1008 int mlen, len, off, inc, i, sel, sel2, ok, ackoff, seqoff; 1009 char *rptr, *wptr, *s; 1010 u_32_t thseq, thack; 1011 ap_session_t *aps; 1012 ftpside_t *f, *t; 1013 tcphdr_t *tcp; 1014 ip_t *ip; 1015 mb_t *m; 1016 1017 m = fin->fin_m; 1018 ip = fin->fin_ip; 1019 tcp = (tcphdr_t *)fin->fin_dp; 1020 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 1021 1022 f = &ftp->ftp_side[rv]; 1023 t = &ftp->ftp_side[1 - rv]; 1024 thseq = ntohl(tcp->th_seq); 1025 thack = ntohl(tcp->th_ack); 1026 1027 #ifdef __sgi 1028 mlen = fin->fin_plen - off; 1029 #else 1030 mlen = MSGDSIZE(m) - off; 1031 #endif 1032 if (ippr_ftp_debug > 4) 1033 printf("ippr_ftp_process: mlen %d\n", mlen); 1034 1035 if (mlen <= 0) { 1036 if ((tcp->th_flags & TH_OPENING) == TH_OPENING) { 1037 f->ftps_seq[0] = thseq + 1; 1038 t->ftps_seq[0] = thack; 1039 } 1040 return 0; 1041 } 1042 aps = nat->nat_aps; 1043 1044 sel = aps->aps_sel[1 - rv]; 1045 sel2 = aps->aps_sel[rv]; 1046 if (rv == 0) { 1047 seqoff = aps->aps_seqoff[sel]; 1048 if (aps->aps_seqmin[sel] > seqoff + thseq) 1049 seqoff = aps->aps_seqoff[!sel]; 1050 ackoff = aps->aps_ackoff[sel2]; 1051 if (aps->aps_ackmin[sel2] > ackoff + thack) 1052 ackoff = aps->aps_ackoff[!sel2]; 1053 } else { 1054 seqoff = aps->aps_ackoff[sel]; 1055 if (ippr_ftp_debug > 2) 1056 printf("seqoff %d thseq %x ackmin %x\n", seqoff, thseq, 1057 aps->aps_ackmin[sel]); 1058 if (aps->aps_ackmin[sel] > seqoff + thseq) 1059 seqoff = aps->aps_ackoff[!sel]; 1060 1061 ackoff = aps->aps_seqoff[sel2]; 1062 if (ippr_ftp_debug > 2) 1063 printf("ackoff %d thack %x seqmin %x\n", ackoff, thack, 1064 aps->aps_seqmin[sel2]); 1065 if (ackoff > 0) { 1066 if (aps->aps_seqmin[sel2] > ackoff + thack) 1067 ackoff = aps->aps_seqoff[!sel2]; 1068 } else { 1069 if (aps->aps_seqmin[sel2] > thack) 1070 ackoff = aps->aps_seqoff[!sel2]; 1071 } 1072 } 1073 if (ippr_ftp_debug > 2) { 1074 printf("%s: %x seq %x/%d ack %x/%d len %d/%d off %d\n", 1075 rv ? "IN" : "OUT", tcp->th_flags, thseq, seqoff, 1076 thack, ackoff, mlen, fin->fin_plen, off); 1077 printf("sel %d seqmin %x/%x offset %d/%d\n", sel, 1078 aps->aps_seqmin[sel], aps->aps_seqmin[sel2], 1079 aps->aps_seqoff[sel], aps->aps_seqoff[sel2]); 1080 printf("sel %d ackmin %x/%x offset %d/%d\n", sel2, 1081 aps->aps_ackmin[sel], aps->aps_ackmin[sel2], 1082 aps->aps_ackoff[sel], aps->aps_ackoff[sel2]); 1083 } 1084 1085 /* 1086 * XXX - Ideally, this packet should get dropped because we now know 1087 * that it is out of order (and there is no real danger in doing so 1088 * apart from causing packets to go through here ordered). 1089 */ 1090 if (ippr_ftp_debug > 2) { 1091 printf("rv %d t:seq[0] %x seq[1] %x %d/%d\n", 1092 rv, t->ftps_seq[0], t->ftps_seq[1], seqoff, ackoff); 1093 } 1094 1095 ok = 0; 1096 if (t->ftps_seq[0] == 0) { 1097 t->ftps_seq[0] = thack; 1098 ok = 1; 1099 } else { 1100 if (ackoff == 0) { 1101 if (t->ftps_seq[0] == thack) 1102 ok = 1; 1103 else if (t->ftps_seq[1] == thack) { 1104 t->ftps_seq[0] = thack; 1105 ok = 1; 1106 } 1107 } else { 1108 if (t->ftps_seq[0] + ackoff == thack) 1109 ok = 1; 1110 else if (t->ftps_seq[0] == thack + ackoff) 1111 ok = 1; 1112 else if (t->ftps_seq[1] + ackoff == thack) { 1113 t->ftps_seq[0] = thack - ackoff; 1114 ok = 1; 1115 } else if (t->ftps_seq[1] == thack + ackoff) { 1116 t->ftps_seq[0] = thack - ackoff; 1117 ok = 1; 1118 } 1119 } 1120 } 1121 1122 if (ippr_ftp_debug > 2) { 1123 if (!ok) 1124 printf("%s ok\n", "not"); 1125 } 1126 1127 if (!mlen) { 1128 if (t->ftps_seq[0] + ackoff != thack) { 1129 if (ippr_ftp_debug > 1) { 1130 printf("%s:seq[0](%x) + (%x) != (%x)\n", 1131 "ippr_ftp_process", t->ftps_seq[0], 1132 ackoff, thack); 1133 } 1134 return APR_ERR(1); 1135 } 1136 1137 if (ippr_ftp_debug > 2) { 1138 printf("ippr_ftp_process:f:seq[0] %x seq[1] %x\n", 1139 f->ftps_seq[0], f->ftps_seq[1]); 1140 } 1141 1142 if (tcp->th_flags & TH_FIN) { 1143 if (thseq == f->ftps_seq[1]) { 1144 f->ftps_seq[0] = f->ftps_seq[1] - seqoff; 1145 f->ftps_seq[1] = thseq + 1 - seqoff; 1146 } else { 1147 if (ippr_ftp_debug > 1) { 1148 printf("FIN: thseq %x seqoff %d ftps_seq %x\n", 1149 thseq, seqoff, f->ftps_seq[0]); 1150 } 1151 return APR_ERR(1); 1152 } 1153 } 1154 f->ftps_len = 0; 1155 return 0; 1156 } 1157 1158 ok = 0; 1159 if ((thseq == f->ftps_seq[0]) || (thseq == f->ftps_seq[1])) { 1160 ok = 1; 1161 /* 1162 * Retransmitted data packet. 1163 */ 1164 } else if ((thseq + mlen == f->ftps_seq[0]) || 1165 (thseq + mlen == f->ftps_seq[1])) { 1166 ok = 1; 1167 } 1168 1169 if (ok == 0) { 1170 inc = thseq - f->ftps_seq[0]; 1171 if (ippr_ftp_debug > 1) { 1172 printf("inc %d sel %d rv %d\n", inc, sel, rv); 1173 printf("th_seq %x ftps_seq %x/%x\n", 1174 thseq, f->ftps_seq[0], f->ftps_seq[1]); 1175 printf("ackmin %x ackoff %d\n", aps->aps_ackmin[sel], 1176 aps->aps_ackoff[sel]); 1177 printf("seqmin %x seqoff %d\n", aps->aps_seqmin[sel], 1178 aps->aps_seqoff[sel]); 1179 } 1180 1181 return APR_ERR(1); 1182 } 1183 1184 inc = 0; 1185 rptr = f->ftps_rptr; 1186 wptr = f->ftps_wptr; 1187 f->ftps_seq[0] = thseq; 1188 f->ftps_seq[1] = f->ftps_seq[0] + mlen; 1189 f->ftps_len = mlen; 1190 1191 while (mlen > 0) { 1192 len = MIN(mlen, sizeof(f->ftps_buf) - (wptr - rptr)); 1193 COPYDATA(m, off, len, wptr); 1194 mlen -= len; 1195 off += len; 1196 wptr += len; 1197 1198 if (ippr_ftp_debug > 3) 1199 printf("%s:len %d/%d off %d wptr %lx junk %d [%*s]\n", 1200 "ippr_ftp_process", 1201 len, mlen, off, (u_long)wptr, f->ftps_junk, 1202 len, rptr); 1203 1204 f->ftps_wptr = wptr; 1205 if (f->ftps_junk != 0) { 1206 i = f->ftps_junk; 1207 f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, 1208 wptr - rptr); 1209 1210 if (ippr_ftp_debug > 5) 1211 printf("%s:junk %d -> %d\n", 1212 "ippr_ftp_process", i, f->ftps_junk); 1213 1214 if (f->ftps_junk != 0) { 1215 if (wptr - rptr == sizeof(f->ftps_buf)) { 1216 if (ippr_ftp_debug > 4) 1217 printf("%s:full buffer\n", 1218 "ippr_ftp_process"); 1219 f->ftps_rptr = f->ftps_buf; 1220 f->ftps_wptr = f->ftps_buf; 1221 rptr = f->ftps_rptr; 1222 wptr = f->ftps_wptr; 1223 /* 1224 * Because we throw away data here that 1225 * we would otherwise parse, set the 1226 * junk flag to indicate just ignore 1227 * any data upto the next CRLF. 1228 */ 1229 f->ftps_junk = 1; 1230 continue; 1231 } 1232 } 1233 } 1234 1235 while ((f->ftps_junk == 0) && (wptr > rptr)) { 1236 len = wptr - rptr; 1237 f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, len); 1238 1239 if (ippr_ftp_debug > 3) { 1240 printf("%s=%d len %d rv %d ptr %lx/%lx ", 1241 "ippr_ftp_valid", 1242 f->ftps_junk, len, rv, (u_long)rptr, 1243 (u_long)wptr); 1244 printf("buf [%*s]\n", len, rptr); 1245 } 1246 1247 if (f->ftps_junk == 0) { 1248 f->ftps_rptr = rptr; 1249 if (rv) 1250 inc += ippr_ftp_server(fin, ip, nat, 1251 ftp, len); 1252 else 1253 inc += ippr_ftp_client(fin, ip, nat, 1254 ftp, len); 1255 rptr = f->ftps_rptr; 1256 wptr = f->ftps_wptr; 1257 } 1258 } 1259 1260 /* 1261 * Off to a bad start so lets just forget about using the 1262 * ftp proxy for this connection. 1263 */ 1264 if ((f->ftps_cmds == 0) && (f->ftps_junk == 1)) { 1265 /* f->ftps_seq[1] += inc; */ 1266 1267 if (ippr_ftp_debug > 1) 1268 printf("%s:cmds == 0 junk == 1\n", 1269 "ippr_ftp_process"); 1270 return APR_ERR(2); 1271 } 1272 1273 if ((f->ftps_junk != 0) && (rptr < wptr)) { 1274 for (s = rptr; s < wptr; s++) { 1275 if ((*s == '\r') && (s + 1 < wptr) && 1276 (*(s + 1) == '\n')) { 1277 rptr = s + 2; 1278 f->ftps_junk = 0; 1279 break; 1280 } 1281 } 1282 } 1283 1284 if (rptr == wptr) { 1285 rptr = wptr = f->ftps_buf; 1286 } else { 1287 /* 1288 * Compact the buffer back to the start. The junk 1289 * flag should already be set and because we're not 1290 * throwing away any data, it is preserved from its 1291 * current state. 1292 */ 1293 if (rptr > f->ftps_buf) { 1294 bcopy(rptr, f->ftps_buf, len); 1295 wptr -= rptr - f->ftps_buf; 1296 rptr = f->ftps_buf; 1297 } 1298 } 1299 f->ftps_rptr = rptr; 1300 f->ftps_wptr = wptr; 1301 } 1302 1303 /* f->ftps_seq[1] += inc; */ 1304 if (tcp->th_flags & TH_FIN) 1305 f->ftps_seq[1]++; 1306 if (ippr_ftp_debug > 3) { 1307 #ifdef __sgi 1308 mlen = fin->fin_plen; 1309 #else 1310 mlen = MSGDSIZE(m); 1311 #endif 1312 mlen -= off; 1313 printf("ftps_seq[1] = %x inc %d len %d\n", 1314 f->ftps_seq[1], inc, mlen); 1315 } 1316 1317 f->ftps_rptr = rptr; 1318 f->ftps_wptr = wptr; 1319 return APR_INC(inc); 1320 } 1321 1322 1323 int ippr_ftp_out(fin, aps, nat) 1324 fr_info_t *fin; 1325 ap_session_t *aps; 1326 nat_t *nat; 1327 { 1328 ftpinfo_t *ftp; 1329 int rev; 1330 1331 ftp = aps->aps_data; 1332 if (ftp == NULL) 1333 return 0; 1334 1335 rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; 1336 if (ftp->ftp_side[1 - rev].ftps_ifp == NULL) 1337 ftp->ftp_side[1 - rev].ftps_ifp = fin->fin_ifp; 1338 1339 return ippr_ftp_process(fin, nat, ftp, rev); 1340 } 1341 1342 1343 int ippr_ftp_in(fin, aps, nat) 1344 fr_info_t *fin; 1345 ap_session_t *aps; 1346 nat_t *nat; 1347 { 1348 ftpinfo_t *ftp; 1349 int rev; 1350 1351 ftp = aps->aps_data; 1352 if (ftp == NULL) 1353 return 0; 1354 1355 rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; 1356 if (ftp->ftp_side[rev].ftps_ifp == NULL) 1357 ftp->ftp_side[rev].ftps_ifp = fin->fin_ifp; 1358 1359 return ippr_ftp_process(fin, nat, ftp, 1 - rev); 1360 } 1361 1362 1363 /* 1364 * ippr_ftp_atoi - implement a version of atoi which processes numbers in 1365 * pairs separated by commas (which are expected to be in the range 0 - 255), 1366 * returning a 16 bit number combining either side of the , as the MSB and 1367 * LSB. 1368 */ 1369 u_short ippr_ftp_atoi(ptr) 1370 char **ptr; 1371 { 1372 register char *s = *ptr, c; 1373 register u_char i = 0, j = 0; 1374 1375 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1376 i *= 10; 1377 i += c - '0'; 1378 } 1379 if (c != ',') { 1380 *ptr = NULL; 1381 return 0; 1382 } 1383 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1384 j *= 10; 1385 j += c - '0'; 1386 } 1387 *ptr = s; 1388 i &= 0xff; 1389 j &= 0xff; 1390 return (i << 8) | j; 1391 } 1392 1393 1394 int ippr_ftp_epsv(fin, ip, nat, f, dlen) 1395 fr_info_t *fin; 1396 ip_t *ip; 1397 nat_t *nat; 1398 ftpside_t *f; 1399 int dlen; 1400 { 1401 char newbuf[IPF_FTPBUFSZ]; 1402 char *s; 1403 u_short ap = 0; 1404 1405 #define EPSV_REPLEN 33 1406 /* 1407 * Check for EPSV reply message. 1408 */ 1409 if (dlen < IPF_MIN229LEN) 1410 return (0); 1411 else if (strncmp(f->ftps_rptr, 1412 "229 Entering Extended Passive Mode", EPSV_REPLEN)) 1413 return (0); 1414 1415 /* 1416 * Skip the EPSV command + space 1417 */ 1418 s = f->ftps_rptr + 33; 1419 while (*s && !ISDIGIT(*s)) 1420 s++; 1421 1422 /* 1423 * As per RFC 2428, there are no addres components in the EPSV 1424 * response. So we'll go straight to getting the port. 1425 */ 1426 while (*s && ISDIGIT(*s)) { 1427 ap *= 10; 1428 ap += *s++ - '0'; 1429 } 1430 1431 if (!s) 1432 return 0; 1433 1434 if (*s == '|') 1435 s++; 1436 if (*s == ')') 1437 s++; 1438 if (*s == '\n') 1439 s--; 1440 /* 1441 * check for CR-LF at the end. 1442 */ 1443 if ((*s == '\r') && (*(s + 1) == '\n')) { 1444 s += 2; 1445 } else 1446 return 0; 1447 1448 #if defined(SNPRINTF) && defined(_KERNEL) 1449 (void) SNPRINTF(newbuf, sizeof(newbuf), "%s (|||%u|)\r\n", 1450 "229 Entering Extended Passive Mode", ap); 1451 #else 1452 (void) sprintf(newbuf, "%s (|||%u|)\r\n", 1453 "229 Entering Extended Passive Mode", ap); 1454 #endif 1455 1456 return ippr_ftp_pasvreply(fin, ip, nat, f, (u_int)ap, newbuf, s, 1457 ip->ip_src.s_addr); 1458 } 1459