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