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