1 2 /* 3 * Copyright (C) 2012 by Darren Reed. 4 * 5 * See the IPFILTER.LICENCE file for details on licencing. 6 * 7 * Simple FTP transparent proxy for in-kernel use. For use with the NAT 8 * code. 9 * Id: ip_ftp_pxy.c,v 2.88.2.19 2006/04/01 10:14:53 darrenr Exp $ 10 */ 11 12 #define IPF_FTP_PROXY 13 14 #define IPF_MINPORTLEN 18 15 #define IPF_MINEPRTLEN 20 16 #define IPF_MAXPORTLEN 30 17 #define IPF_MIN227LEN 39 18 #define IPF_MAX227LEN 51 19 #define IPF_MIN229LEN 47 20 #define IPF_MAX229LEN 51 21 22 #define FTPXY_GO 0 23 #define FTPXY_INIT 1 24 #define FTPXY_USER_1 2 25 #define FTPXY_USOK_1 3 26 #define FTPXY_PASS_1 4 27 #define FTPXY_PAOK_1 5 28 #define FTPXY_AUTH_1 6 29 #define FTPXY_AUOK_1 7 30 #define FTPXY_ADAT_1 8 31 #define FTPXY_ADOK_1 9 32 #define FTPXY_ACCT_1 10 33 #define FTPXY_ACOK_1 11 34 #define FTPXY_USER_2 12 35 #define FTPXY_USOK_2 13 36 #define FTPXY_PASS_2 14 37 #define FTPXY_PAOK_2 15 38 39 #define FTPXY_JUNK_OK 0 40 #define FTPXY_JUNK_BAD 1 /* Ignore all commands for this connection */ 41 #define FTPXY_JUNK_EOL 2 /* consume the rest of this line only */ 42 #define FTPXY_JUNK_CONT 3 /* Saerching for next numeric */ 43 44 /* 45 * Values for FTP commands. Numerics cover 0-999 46 */ 47 #define FTPXY_C_PASV 1000 48 #define FTPXY_C_PORT 1001 49 #define FTPXY_C_EPSV 1002 50 #define FTPXY_C_EPRT 1003 51 52 53 typedef struct ipf_ftp_softc_s { 54 int ipf_p_ftp_pasvonly; 55 /* Do not require logins before transfers */ 56 int ipf_p_ftp_insecure; 57 int ipf_p_ftp_pasvrdr; 58 /* PASV must be last command prior to 227 */ 59 int ipf_p_ftp_forcepasv; 60 int ipf_p_ftp_debug; 61 int ipf_p_ftp_single_xfer; 62 void *ipf_p_ftp_tune; 63 } ipf_ftp_softc_t; 64 65 66 void ipf_p_ftp_main_load(void); 67 void ipf_p_ftp_main_unload(void); 68 void *ipf_p_ftp_soft_create(ipf_main_softc_t *); 69 void ipf_p_ftp_soft_destroy(ipf_main_softc_t *, void *); 70 71 int ipf_p_ftp_client(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 72 ftpinfo_t *, int); 73 int ipf_p_ftp_complete(char *, size_t); 74 int ipf_p_ftp_in(void *, fr_info_t *, ap_session_t *, nat_t *); 75 int ipf_p_ftp_new(void *, fr_info_t *, ap_session_t *, nat_t *); 76 void ipf_p_ftp_del(ipf_main_softc_t *, ap_session_t *); 77 int ipf_p_ftp_out(void *, fr_info_t *, ap_session_t *, nat_t *); 78 int ipf_p_ftp_pasv(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 79 ftpinfo_t *, int); 80 int ipf_p_ftp_epsv(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 81 ftpinfo_t *, int); 82 int ipf_p_ftp_port(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 83 ftpinfo_t *, int); 84 int ipf_p_ftp_process(ipf_ftp_softc_t *, fr_info_t *, nat_t *, 85 ftpinfo_t *, int); 86 int ipf_p_ftp_server(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 87 ftpinfo_t *, int); 88 int ipf_p_ftp_valid(ipf_ftp_softc_t *, ftpinfo_t *, int, char *, size_t); 89 int ipf_p_ftp_server_valid(ipf_ftp_softc_t *, ftpside_t *, char *, 90 size_t); 91 int ipf_p_ftp_client_valid(ipf_ftp_softc_t *, ftpside_t *, char *, 92 size_t); 93 u_short ipf_p_ftp_atoi(char **); 94 int ipf_p_ftp_pasvreply(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 95 ftpinfo_t *, u_int, char *, char *); 96 int ipf_p_ftp_eprt(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 97 ftpinfo_t *, int); 98 int ipf_p_ftp_eprt4(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 99 ftpinfo_t *, int); 100 int ipf_p_ftp_eprt6(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 101 ftpinfo_t *, int); 102 int ipf_p_ftp_addport(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 103 ftpinfo_t *, int, int, int); 104 void ipf_p_ftp_setpending(ipf_main_softc_t *, ftpinfo_t *); 105 106 /* 107 * Debug levels 108 */ 109 #define DEBUG_SECURITY 0x01 110 #define DEBUG_ERROR 0x02 111 #define DEBUG_INFO 0x04 112 #define DEBUG_PARSE_ERR 0x08 113 #define DEBUG_PARSE_INFO 0x10 114 #define DEBUG_PARSE 0x20 115 116 static int ipf_p_ftp_proxy_init = 0; 117 static frentry_t ftppxyfr; 118 static ipftuneable_t ipf_ftp_tuneables[] = { 119 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_debug) }, 120 "ftp_debug", 0, 0x7f, 121 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_debug), 122 0, NULL, NULL }, 123 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_pasvonly) }, 124 "ftp_pasvonly", 0, 1, 125 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_pasvonly), 126 0, NULL, NULL }, 127 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_insecure) }, 128 "ftp_insecure", 0, 1, 129 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_insecure), 130 0, NULL, NULL }, 131 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_pasvrdr) }, 132 "ftp_pasvrdr", 0, 1, 133 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_pasvrdr), 134 0, NULL, NULL }, 135 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_forcepasv) }, 136 "ftp_forcepasv", 0, 1, 137 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_forcepasv), 138 0, NULL, NULL }, 139 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_single_xfer) }, 140 "ftp_single_xfer", 0, 1, 141 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_single_xfer), 142 0, NULL, NULL }, 143 { { NULL }, NULL, 0, 0, 0, 0, NULL, NULL } 144 }; 145 146 147 void 148 ipf_p_ftp_main_load(void) 149 { 150 bzero((char *)&ftppxyfr, sizeof(ftppxyfr)); 151 ftppxyfr.fr_ref = 1; 152 ftppxyfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 153 154 MUTEX_INIT(&ftppxyfr.fr_lock, "FTP Proxy Mutex"); 155 ipf_p_ftp_proxy_init = 1; 156 } 157 158 159 void 160 ipf_p_ftp_main_unload(void) 161 { 162 163 if (ipf_p_ftp_proxy_init == 1) { 164 MUTEX_DESTROY(&ftppxyfr.fr_lock); 165 ipf_p_ftp_proxy_init = 0; 166 } 167 } 168 169 170 /* 171 * Initialize local structures. 172 */ 173 void * 174 ipf_p_ftp_soft_create(ipf_main_softc_t *softc) 175 { 176 ipf_ftp_softc_t *softf; 177 178 KMALLOC(softf, ipf_ftp_softc_t *); 179 if (softf == NULL) 180 return (NULL); 181 182 bzero((char *)softf, sizeof(*softf)); 183 #if defined(_KERNEL) 184 softf->ipf_p_ftp_debug = 0; 185 #else 186 softf->ipf_p_ftp_debug = DEBUG_PARSE_ERR; 187 #endif 188 softf->ipf_p_ftp_forcepasv = 1; 189 190 softf->ipf_p_ftp_tune = ipf_tune_array_copy(softf, 191 sizeof(ipf_ftp_tuneables), 192 ipf_ftp_tuneables); 193 if (softf->ipf_p_ftp_tune == NULL) { 194 ipf_p_ftp_soft_destroy(softc, softf); 195 return (NULL); 196 } 197 if (ipf_tune_array_link(softc, softf->ipf_p_ftp_tune) == -1) { 198 ipf_p_ftp_soft_destroy(softc, softf); 199 return (NULL); 200 } 201 202 return (softf); 203 } 204 205 206 void 207 ipf_p_ftp_soft_destroy(ipf_main_softc_t *softc, void *arg) 208 { 209 ipf_ftp_softc_t *softf = arg; 210 211 if (softf->ipf_p_ftp_tune != NULL) { 212 ipf_tune_array_unlink(softc, softf->ipf_p_ftp_tune); 213 KFREES(softf->ipf_p_ftp_tune, sizeof(ipf_ftp_tuneables)); 214 softf->ipf_p_ftp_tune = NULL; 215 } 216 217 KFREE(softf); 218 } 219 220 221 int 222 ipf_p_ftp_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) 223 { 224 ftpinfo_t *ftp; 225 ftpside_t *f; 226 227 KMALLOC(ftp, ftpinfo_t *); 228 if (ftp == NULL) 229 return (-1); 230 231 nat = nat; /* LINT */ 232 233 aps->aps_data = ftp; 234 aps->aps_psiz = sizeof(ftpinfo_t); 235 aps->aps_sport = htons(fin->fin_sport); 236 aps->aps_dport = htons(fin->fin_dport); 237 238 bzero((char *)ftp, sizeof(*ftp)); 239 f = &ftp->ftp_side[0]; 240 f->ftps_rptr = f->ftps_buf; 241 f->ftps_wptr = f->ftps_buf; 242 f = &ftp->ftp_side[1]; 243 f->ftps_rptr = f->ftps_buf; 244 f->ftps_wptr = f->ftps_buf; 245 ftp->ftp_passok = FTPXY_INIT; 246 ftp->ftp_incok = 0; 247 return (0); 248 } 249 250 251 void 252 ipf_p_ftp_setpending(ipf_main_softc_t *softc, ftpinfo_t *ftp) 253 { 254 if (ftp->ftp_pendnat != NULL) 255 ipf_nat_setpending(softc, ftp->ftp_pendnat); 256 257 if (ftp->ftp_pendstate != NULL) { 258 READ_ENTER(&softc->ipf_state); 259 ipf_state_setpending(softc, ftp->ftp_pendstate); 260 RWLOCK_EXIT(&softc->ipf_state); 261 } 262 } 263 264 265 void 266 ipf_p_ftp_del(ipf_main_softc_t *softc, ap_session_t *aps) 267 { 268 ftpinfo_t *ftp; 269 270 ftp = aps->aps_data; 271 if (ftp != NULL) 272 ipf_p_ftp_setpending(softc, ftp); 273 } 274 275 276 int 277 ipf_p_ftp_port(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat, 278 ftpinfo_t *ftp, int dlen) 279 { 280 char newbuf[IPF_FTPBUFSZ], *s; 281 u_int a1, a2, a3, a4; 282 u_short a5, a6, sp; 283 size_t nlen, olen; 284 tcphdr_t *tcp; 285 int inc, off; 286 ftpside_t *f; 287 mb_t *m; 288 289 m = fin->fin_m; 290 f = &ftp->ftp_side[0]; 291 tcp = (tcphdr_t *)fin->fin_dp; 292 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 293 294 /* 295 * Check for client sending out PORT message. 296 */ 297 if (dlen < IPF_MINPORTLEN) { 298 DT3(ftp_PORT_error_dlen, nat_t *, nat, ftpside_t *, f, 299 u_int, dlen); 300 if (softf->ipf_p_ftp_debug & DEBUG_PARSE) 301 printf("ipf_p_ftp_port:dlen(%d) < IPF_MINPORTLEN\n", 302 dlen); 303 return (0); 304 } 305 /* 306 * Skip the PORT command + space 307 */ 308 s = f->ftps_rptr + 5; 309 /* 310 * Pick out the address components, two at a time. 311 */ 312 a1 = ipf_p_ftp_atoi(&s); 313 if (s == NULL) { 314 DT2(ftp_PORT_error_atoi_1, nat_t *, nat, ftpside_t *, f); 315 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 316 printf("ipf_p_ftp_port:ipf_p_ftp_atoi(%d) failed\n", 1); 317 return (0); 318 } 319 a2 = ipf_p_ftp_atoi(&s); 320 if (s == NULL) { 321 DT2(ftp_PORT_error_atoi_2, nat_t *, nat, ftpside_t *, f); 322 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 323 printf("ipf_p_ftp_port:ipf_p_ftp_atoi(%d) failed\n", 2); 324 return (0); 325 } 326 327 /* 328 * Check that IP address in the PORT/PASV reply is the same as the 329 * sender of the command - prevents using PORT for port scanning. 330 */ 331 a1 <<= 16; 332 a1 |= a2; 333 if (((nat->nat_dir == NAT_OUTBOUND) && 334 (a1 != ntohl(nat->nat_osrcaddr))) || 335 ((nat->nat_dir == NAT_INBOUND) && 336 (a1 != ntohl(nat->nat_nsrcaddr)))) { 337 DT3(ftp_PORT_error_address, nat_t *, nat, ftpside_t *, f, 338 u_int, a1); 339 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) 340 printf("ipf_p_ftp_port:%s != nat->nat_inip\n", "a1"); 341 return (APR_ERR(1)); 342 } 343 344 a5 = ipf_p_ftp_atoi(&s); 345 if (s == NULL) { 346 DT2(ftp_PORT_error_atoi_3, nat_t *, nat, ftpside_t *, f); 347 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 348 printf("ipf_p_ftp_port:ipf_p_ftp_atoi(%d) failed\n", 3); 349 return (0); 350 } 351 if (*s == ')') 352 s++; 353 354 /* 355 * check for CR-LF at the end. 356 */ 357 if (*s == '\n') 358 s--; 359 if ((*s != '\r') || (*(s + 1) != '\n')) { 360 DT2(ftp_PORT_error_no_crlf, nat_t *, nat, ftpside_t *, f); 361 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 362 printf("ipf_p_ftp_port:missing %s\n", "cr-lf"); 363 return (0); 364 } 365 s += 2; 366 a6 = a5 & 0xff; 367 368 /* 369 * Calculate the source port. Verification of > 1024 is in 370 * ipf_p_ftp_addport. 371 */ 372 a5 >>= 8; 373 a5 &= 0xff; 374 sp = a5 << 8 | a6; 375 376 /* 377 * Calculate new address parts for PORT command 378 */ 379 if (nat->nat_dir == NAT_INBOUND) 380 a1 = ntohl(nat->nat_ndstaddr); 381 else 382 a1 = ntohl(ip->ip_src.s_addr); 383 a1 = ntohl(ip->ip_src.s_addr); 384 a2 = (a1 >> 16) & 0xff; 385 a3 = (a1 >> 8) & 0xff; 386 a4 = a1 & 0xff; 387 a1 >>= 24; 388 olen = s - f->ftps_rptr; 389 (void) snprintf(newbuf, sizeof(newbuf), "%s %u,%u,%u,%u,%u,%u\r\n", 390 "PORT", a1, a2, a3, a4, a5, a6); 391 392 nlen = strlen(newbuf); 393 inc = nlen - olen; 394 if ((inc + fin->fin_plen) > 65535) { 395 DT3(ftp_PORT_error_inc, nat_t *, nat, ftpside_t *, f, 396 int, inc); 397 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) 398 printf("ipf_p_ftp_port:inc(%d) + ip->ip_len > 65535\n", 399 inc); 400 return (0); 401 } 402 403 #if !defined(_KERNEL) 404 M_ADJ(m, inc); 405 #else 406 /* 407 * m_adj takes care of pkthdr.len, if required and treats inc<0 to 408 * mean remove -len bytes from the end of the packet. 409 * The mbuf chain will be extended if necessary by m_copyback(). 410 */ 411 if (inc < 0) 412 M_ADJ(m, inc); 413 #endif /* !defined(_KERNEL) */ 414 COPYBACK(m, off, nlen, newbuf); 415 fin->fin_flx |= FI_DOCKSUM; 416 417 if (inc != 0) { 418 fin->fin_plen += inc; 419 ip->ip_len = htons(fin->fin_plen); 420 fin->fin_dlen += inc; 421 } 422 423 f->ftps_cmd = FTPXY_C_PORT; 424 return (ipf_p_ftp_addport(softf, fin, ip, nat, ftp, dlen, sp, inc)); 425 } 426 427 428 int 429 ipf_p_ftp_addport(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat, 430 ftpinfo_t *ftp, int dlen, int nport, int inc) 431 { 432 tcphdr_t tcph, *tcp2 = &tcph; 433 ipf_main_softc_t *softc; 434 ipf_nat_softc_t *softn; 435 int direction; 436 fr_info_t fi; 437 ipnat_t *ipn; 438 nat_t *nat2; 439 u_short sp; 440 int flags; 441 442 softc = fin->fin_main_soft; 443 softn = softc->ipf_nat_soft; 444 445 if ((ftp->ftp_pendnat != NULL) || (ftp->ftp_pendstate != NULL)) { 446 if (softf->ipf_p_ftp_single_xfer != 0) { 447 DT2(ftp_PORT_error_add_active, nat_t *, nat, 448 ftpinfo_t *, ftp); 449 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) 450 printf("ipf_p_ftp_addport:xfer active %p/%p\n", 451 ftp->ftp_pendnat, ftp->ftp_pendstate); 452 return (0); 453 } 454 ipf_p_ftp_setpending(softc, ftp); 455 } 456 457 /* 458 * Add skeleton NAT entry for connection which will come back the 459 * other way. 460 */ 461 sp = nport; 462 /* 463 * Don't allow the PORT command to specify a port < 1024 due to 464 * security risks. 465 */ 466 if (sp < 1024) { 467 DT3(ftp_PORT_error_port, nat_t *, nat, ftpinfo_t *, ftp, 468 u_int, sp); 469 if (softf->ipf_p_ftp_debug & DEBUG_SECURITY) 470 printf("ipf_p_ftp_addport:sp(%d) < 1024\n", sp); 471 return (0); 472 } 473 /* 474 * The server may not make the connection back from port 20, but 475 * it is the most likely so use it here to check for a conflicting 476 * mapping. 477 */ 478 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 479 fi.fin_flx |= FI_IGNORE; 480 fi.fin_data[0] = sp; 481 fi.fin_data[1] = fin->fin_data[1] - 1; 482 fi.fin_src6 = nat->nat_ndst6; 483 fi.fin_dst6 = nat->nat_nsrc6; 484 485 #ifndef USE_INET6 486 if (nat->nat_v[0] == 6) 487 return (APR_INC(inc)); 488 #endif 489 490 /* 491 * If an existing entry already exists, use it instead. 492 */ 493 #ifdef USE_INET6 494 if (nat->nat_v[0] == 6) { 495 if (nat->nat_dir == NAT_OUTBOUND) { 496 nat2 = ipf_nat6_outlookup(&fi, IPN_TCP|NAT_SEARCH, 497 nat->nat_pr[1], 498 &nat->nat_osrc6.in6, 499 &nat->nat_odst6.in6); 500 } else { 501 nat2 = ipf_nat6_inlookup(&fi, IPN_TCP|NAT_SEARCH, 502 nat->nat_pr[0], 503 &nat->nat_odst6.in6, 504 &nat->nat_osrc6.in6); 505 } 506 } else 507 #endif 508 { 509 if (nat->nat_dir == NAT_OUTBOUND) { 510 nat2 = ipf_nat_outlookup(&fi, IPN_TCP|NAT_SEARCH, 511 nat->nat_pr[1], 512 nat->nat_osrcip, 513 nat->nat_odstip); 514 } else { 515 nat2 = ipf_nat_inlookup(&fi, IPN_TCP|NAT_SEARCH, 516 nat->nat_pr[0], 517 nat->nat_odstip, 518 nat->nat_osrcip); 519 } 520 } 521 if (nat2 != NULL) 522 return (APR_INC(inc)); 523 524 /* 525 * An existing entry doesn't exist. Let's make one. 526 */ 527 ipn = ipf_proxy_rule_rev(nat); 528 if (ipn == NULL) 529 return (APR_ERR(1)); 530 ipn->in_use = 0; 531 532 fi.fin_fr = &ftppxyfr; 533 fi.fin_dp = (char *)tcp2; 534 fi.fin_dlen = sizeof(*tcp2); 535 fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); 536 fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; 537 fi.fin_data[1] = sp; 538 fi.fin_data[0] = 0; 539 540 bzero((char *)tcp2, sizeof(*tcp2)); 541 tcp2->th_sport = 0; 542 tcp2->th_dport = htons(sp); 543 544 tcp2->th_win = htons(8192); 545 TCP_OFF_A(tcp2, 5); 546 tcp2->th_flags = TH_SYN; 547 548 if (nat->nat_dir == NAT_INBOUND) { 549 fi.fin_out = 1; 550 direction = NAT_OUTBOUND; 551 } else { 552 fi.fin_out = 0; 553 direction = NAT_INBOUND; 554 } 555 flags = SI_W_SPORT|NAT_SLAVE|IPN_TCP; 556 557 MUTEX_ENTER(&softn->ipf_nat_new); 558 #ifdef USE_INET6 559 if (nat->nat_v[0] == 6) 560 nat2 = ipf_nat6_add(&fi, ipn, &ftp->ftp_pendnat, flags, 561 direction); 562 else 563 #endif 564 nat2 = ipf_nat_add(&fi, ipn, &ftp->ftp_pendnat, flags, 565 direction); 566 MUTEX_EXIT(&softn->ipf_nat_new); 567 568 if (nat2 == NULL) { 569 KFREES(ipn, ipn->in_size); 570 return (APR_ERR(1)); 571 } 572 573 (void) ipf_nat_proto(&fi, nat2, IPN_TCP); 574 MUTEX_ENTER(&nat2->nat_lock); 575 ipf_nat_update(&fi, nat2); 576 MUTEX_EXIT(&nat2->nat_lock); 577 fi.fin_ifp = NULL; 578 if (nat2->nat_dir == NAT_INBOUND) 579 fi.fin_dst6 = nat->nat_osrc6; 580 if (ipf_state_add(softc, &fi, (ipstate_t **)&ftp->ftp_pendstate, 581 SI_W_SPORT) != 0) 582 ipf_nat_setpending(softc, nat2); 583 584 return (APR_INC(inc)); 585 } 586 587 588 int 589 ipf_p_ftp_client(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, 590 nat_t *nat, ftpinfo_t *ftp, int dlen) 591 { 592 char *rptr, *wptr, cmd[6], c; 593 ftpside_t *f; 594 int inc, i; 595 596 inc = 0; 597 f = &ftp->ftp_side[0]; 598 rptr = f->ftps_rptr; 599 wptr = f->ftps_wptr; 600 601 for (i = 0; (i < 5) && (i < dlen); i++) { 602 c = rptr[i]; 603 if (ISALPHA(c)) { 604 cmd[i] = TOUPPER(c); 605 } else { 606 cmd[i] = c; 607 } 608 } 609 cmd[i] = '\0'; 610 611 ftp->ftp_incok = 0; 612 DT2(ftp_client_command, char [], cmd, int, ftp->ftp_passok); 613 if (!strncmp(cmd, "USER ", 5) || !strncmp(cmd, "XAUT ", 5)) { 614 if (ftp->ftp_passok == FTPXY_ADOK_1 || 615 ftp->ftp_passok == FTPXY_AUOK_1) { 616 ftp->ftp_passok = FTPXY_USER_2; 617 ftp->ftp_incok = 1; 618 } else { 619 ftp->ftp_passok = FTPXY_USER_1; 620 ftp->ftp_incok = 1; 621 } 622 } else if (!strncmp(cmd, "AUTH ", 5)) { 623 ftp->ftp_passok = FTPXY_AUTH_1; 624 ftp->ftp_incok = 1; 625 } else if (!strncmp(cmd, "PASS ", 5)) { 626 if (ftp->ftp_passok == FTPXY_USOK_1) { 627 ftp->ftp_passok = FTPXY_PASS_1; 628 ftp->ftp_incok = 1; 629 } else if (ftp->ftp_passok == FTPXY_USOK_2) { 630 ftp->ftp_passok = FTPXY_PASS_2; 631 ftp->ftp_incok = 1; 632 } 633 } else if ((ftp->ftp_passok == FTPXY_AUOK_1) && 634 !strncmp(cmd, "ADAT ", 5)) { 635 ftp->ftp_passok = FTPXY_ADAT_1; 636 ftp->ftp_incok = 1; 637 } else if ((ftp->ftp_passok == FTPXY_PAOK_1 || 638 ftp->ftp_passok == FTPXY_PAOK_2) && 639 !strncmp(cmd, "ACCT ", 5)) { 640 ftp->ftp_passok = FTPXY_ACCT_1; 641 ftp->ftp_incok = 1; 642 } else if ((ftp->ftp_passok == FTPXY_GO) && 643 !softf->ipf_p_ftp_pasvonly && 644 !strncmp(cmd, "PORT ", 5)) { 645 inc = ipf_p_ftp_port(softf, fin, ip, nat, ftp, dlen); 646 } else if ((ftp->ftp_passok == FTPXY_GO) && 647 !softf->ipf_p_ftp_pasvonly && 648 !strncmp(cmd, "EPRT ", 5)) { 649 inc = ipf_p_ftp_eprt(softf, fin, ip, nat, ftp, dlen); 650 } else if (softf->ipf_p_ftp_insecure && 651 !softf->ipf_p_ftp_pasvonly && 652 !strncmp(cmd, "PORT ", 5)) { 653 inc = ipf_p_ftp_port(softf, fin, ip, nat, ftp, dlen); 654 } 655 if (softf->ipf_p_ftp_debug & DEBUG_PARSE) 656 printf("ipf_p_ftp_client: cmd[%s] passok %d incok %d inc %d\n", 657 cmd, ftp->ftp_passok, ftp->ftp_incok, inc); 658 659 DT2(ftp_client_passok, char *, cmd, int, ftp->ftp_passok); 660 while ((*rptr++ != '\n') && (rptr < wptr)) 661 ; 662 f->ftps_rptr = rptr; 663 return (inc); 664 } 665 666 667 int 668 ipf_p_ftp_pasv(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat, 669 ftpinfo_t *ftp, int dlen) 670 { 671 u_int a1, a2, a3, a4, data_ip; 672 char newbuf[IPF_FTPBUFSZ]; 673 const char *brackets[2]; 674 u_short a5, a6; 675 ftpside_t *f; 676 char *s; 677 678 if ((softf->ipf_p_ftp_forcepasv != 0) && 679 (ftp->ftp_side[0].ftps_cmd != FTPXY_C_PASV)) { 680 DT2(ftp_PASV_error_state, nat_t *, nat, ftpinfo_t *, ftp); 681 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) 682 printf("ipf_p_ftp_pasv:ftps_cmd(%d) != FTPXY_C_PASV\n", 683 ftp->ftp_side[0].ftps_cmd); 684 return (0); 685 } 686 687 f = &ftp->ftp_side[1]; 688 689 #define PASV_REPLEN 24 690 /* 691 * Check for PASV reply message. 692 */ 693 if (dlen < IPF_MIN227LEN) { 694 DT3(ftp_PASV_error_short, nat_t *, nat, ftpinfo_t *, ftp, 695 int, dlen); 696 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) 697 printf("ipf_p_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n", 698 dlen); 699 return (0); 700 } else if (strncmp(f->ftps_rptr, 701 "227 Entering Passive Mod", PASV_REPLEN)) { 702 DT2(ftp_PASV_error_string, nat_t *, nat, ftpinfo_t *, ftp); 703 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 704 printf("ipf_p_ftp_pasv:%d reply wrong\n", 227); 705 return (0); 706 } 707 708 brackets[0] = ""; 709 brackets[1] = ""; 710 /* 711 * Skip the PASV reply + space 712 */ 713 s = f->ftps_rptr + PASV_REPLEN; 714 while (*s && !ISDIGIT(*s)) { 715 if (*s == '(') { 716 brackets[0] = "("; 717 brackets[1] = ")"; 718 } 719 s++; 720 } 721 722 /* 723 * Pick out the address components, two at a time. 724 */ 725 a1 = ipf_p_ftp_atoi(&s); 726 if (s == NULL) { 727 DT2(ftp_PASV_error_atoi_1, nat_t *, nat, ftpside_t *, f); 728 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 729 printf("ipf_p_ftp_pasv:ipf_p_ftp_atoi(%d) failed\n", 1); 730 return (0); 731 } 732 a2 = ipf_p_ftp_atoi(&s); 733 if (s == NULL) { 734 DT2(ftp_PASV_error_atoi_2, nat_t *, nat, ftpside_t *, f); 735 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 736 printf("ipf_p_ftp_pasv:ipf_p_ftp_atoi(%d) failed\n", 2); 737 return (0); 738 } 739 740 /* 741 * check that IP address in the PASV reply is the same as the 742 * sender of the command - prevents using PASV for port scanning. 743 */ 744 a1 <<= 16; 745 a1 |= a2; 746 747 if (((nat->nat_dir == NAT_INBOUND) && 748 (a1 != ntohl(nat->nat_ndstaddr))) || 749 ((nat->nat_dir == NAT_OUTBOUND) && 750 (a1 != ntohl(nat->nat_odstaddr)))) { 751 DT3(ftp_PASV_error_address, nat_t *, nat, ftpside_t *, f, 752 u_int, a1); 753 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) 754 printf("ipf_p_ftp_pasv:%s != nat->nat_oip\n", "a1"); 755 return (0); 756 } 757 758 a5 = ipf_p_ftp_atoi(&s); 759 if (s == NULL) { 760 DT2(ftp_PASV_error_atoi_3, nat_t *, nat, ftpside_t *, f); 761 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 762 printf("ipf_p_ftp_pasv:ipf_p_ftp_atoi(%d) failed\n", 3); 763 return (0); 764 } 765 766 if (*s == ')') 767 s++; 768 if (*s == '.') 769 s++; 770 if (*s == '\n') 771 s--; 772 /* 773 * check for CR-LF at the end. 774 */ 775 if ((*s != '\r') || (*(s + 1) != '\n')) { 776 DT(pasv_missing_crlf); 777 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 778 printf("ipf_p_ftp_pasv:missing %s", "cr-lf\n"); 779 return (0); 780 } 781 s += 2; 782 783 a6 = a5 & 0xff; 784 a5 >>= 8; 785 /* 786 * Calculate new address parts for 227 reply 787 */ 788 if (nat->nat_dir == NAT_INBOUND) { 789 data_ip = nat->nat_odstaddr; 790 a1 = ntohl(data_ip); 791 } else 792 data_ip = htonl(a1); 793 794 a2 = (a1 >> 16) & 0xff; 795 a3 = (a1 >> 8) & 0xff; 796 a4 = a1 & 0xff; 797 a1 >>= 24; 798 799 (void) snprintf(newbuf, sizeof(newbuf), "%s %s%u,%u,%u,%u,%u,%u%s\r\n", 800 "227 Entering Passive Mode", brackets[0], a1, a2, a3, a4, 801 a5, a6, brackets[1]); 802 return (ipf_p_ftp_pasvreply(softf, fin, ip, nat, ftp, (a5 << 8 | a6), 803 newbuf, s)); 804 } 805 806 int 807 ipf_p_ftp_pasvreply(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, 808 nat_t *nat, ftpinfo_t *ftp, u_int port, char *newmsg, char *s) 809 { 810 int inc, off, nflags; 811 tcphdr_t *tcp, tcph, *tcp2; 812 ipf_main_softc_t *softc; 813 ipf_nat_softc_t *softn; 814 size_t nlen, olen; 815 #ifdef USE_INET6 816 ip6_t *ip6; 817 #endif 818 ipnat_t *ipn; 819 fr_info_t fi; 820 ftpside_t *f; 821 nat_t *nat2; 822 mb_t *m; 823 824 softc = fin->fin_main_soft; 825 softn = softc->ipf_nat_soft; 826 827 if ((ftp->ftp_pendnat != NULL) || (ftp->ftp_pendstate != NULL)) 828 ipf_p_ftp_setpending(softc, ftp); 829 830 m = fin->fin_m; 831 tcp = (tcphdr_t *)fin->fin_dp; 832 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 833 834 tcp2 = &tcph; 835 inc = 0; 836 837 f = &ftp->ftp_side[1]; 838 olen = s - f->ftps_rptr; 839 nlen = strlen(newmsg); 840 inc = nlen - olen; 841 if ((inc + fin->fin_plen) > 65535) { 842 DT3(ftp_PASV_error_inc, nat_t *, nat, ftpside_t *, f, 843 int, inc); 844 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) 845 printf("ipf_p_ftp_pasv:inc(%d) + ip->ip_len > 65535\n", 846 inc); 847 return (0); 848 } 849 850 ipn = ipf_proxy_rule_fwd(nat); 851 if (ipn == NULL) 852 return (APR_ERR(1)); 853 ipn->in_use = 0; 854 855 /* 856 * Add skeleton NAT entry for connection which will come back the 857 * other way. 858 */ 859 bzero((char *)tcp2, sizeof(*tcp2)); 860 bcopy((char *)fin, (char *)&fi, sizeof(fi)); 861 fi.fin_flx |= FI_IGNORE; 862 fi.fin_data[0] = 0; 863 fi.fin_data[1] = port; 864 nflags = IPN_TCP|SI_W_SPORT; 865 866 fi.fin_fr = &ftppxyfr; 867 fi.fin_dp = (char *)tcp2; 868 fi.fin_out = 1 - fin->fin_out; 869 fi.fin_dlen = sizeof(*tcp2); 870 fi.fin_src6 = nat->nat_osrc6; 871 fi.fin_dst6 = nat->nat_odst6; 872 fi.fin_plen = fi.fin_hlen + sizeof(*tcp); 873 fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; 874 875 TCP_OFF_A(tcp2, 5); 876 tcp2->th_flags = TH_SYN; 877 tcp2->th_win = htons(8192); 878 tcp2->th_dport = htons(port); 879 880 MUTEX_ENTER(&softn->ipf_nat_new); 881 #ifdef USE_INET6 882 if (nat->nat_v[0] == 6) 883 nat2 = ipf_nat6_add(&fi, ipn, &ftp->ftp_pendnat, 884 nflags, nat->nat_dir); 885 else 886 #endif 887 nat2 = ipf_nat_add(&fi, ipn, &ftp->ftp_pendnat, 888 nflags, nat->nat_dir); 889 MUTEX_EXIT(&softn->ipf_nat_new); 890 891 if (nat2 == NULL) { 892 KFREES(ipn, ipn->in_size); 893 return (APR_ERR(1)); 894 } 895 896 (void) ipf_nat_proto(&fi, nat2, IPN_TCP); 897 MUTEX_ENTER(&nat2->nat_lock); 898 ipf_nat_update(&fi, nat2); 899 MUTEX_EXIT(&nat2->nat_lock); 900 fi.fin_ifp = NULL; 901 if (nat->nat_dir == NAT_INBOUND) { 902 #ifdef USE_INET6 903 if (nat->nat_v[0] == 6) 904 fi.fin_dst6 = nat->nat_ndst6; 905 else 906 #endif 907 fi.fin_daddr = nat->nat_ndstaddr; 908 } 909 if (ipf_state_add(softc, &fi, (ipstate_t **)&ftp->ftp_pendstate, 910 SI_W_SPORT) != 0) 911 ipf_nat_setpending(softc, nat2); 912 913 #if !defined(_KERNEL) 914 M_ADJ(m, inc); 915 #else 916 /* 917 * m_adj takes care of pkthdr.len, if required and treats inc<0 to 918 * mean remove -len bytes from the end of the packet. 919 * The mbuf chain will be extended if necessary by m_copyback(). 920 */ 921 if (inc < 0) 922 M_ADJ(m, inc); 923 #endif /* !defined(_KERNEL) */ 924 COPYBACK(m, off, nlen, newmsg); 925 fin->fin_flx |= FI_DOCKSUM; 926 927 if (inc != 0) { 928 fin->fin_plen += inc; 929 fin->fin_dlen += inc; 930 #ifdef USE_INET6 931 if (nat->nat_v[0] == 6) { 932 ip6 = (ip6_t *)fin->fin_ip; 933 u_short len = ntohs(ip6->ip6_plen) + inc; 934 ip6->ip6_plen = htons(len); 935 } else 936 #endif 937 ip->ip_len = htons(fin->fin_plen); 938 } 939 940 return (APR_INC(inc)); 941 } 942 943 944 int 945 ipf_p_ftp_server(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat, 946 ftpinfo_t *ftp, int dlen) 947 { 948 char *rptr, *wptr; 949 ftpside_t *f; 950 int inc; 951 952 inc = 0; 953 f = &ftp->ftp_side[1]; 954 rptr = f->ftps_rptr; 955 wptr = f->ftps_wptr; 956 957 DT2(ftp_server_response, char *, rptr, int, ftp->ftp_passok); 958 if (*rptr == ' ') 959 goto server_cmd_ok; 960 if (!ISDIGIT(*rptr) || !ISDIGIT(*(rptr + 1)) || !ISDIGIT(*(rptr + 2))) 961 return (0); 962 if (softf->ipf_p_ftp_debug & DEBUG_PARSE) 963 printf("ipf_p_ftp_server_1: cmd[%4.4s] passok %d\n", 964 rptr, ftp->ftp_passok); 965 if (ftp->ftp_passok == FTPXY_GO) { 966 if (!strncmp(rptr, "227 ", 4)) 967 inc = ipf_p_ftp_pasv(softf, fin, ip, nat, ftp, dlen); 968 else if (!strncmp(rptr, "229 ", 4)) 969 inc = ipf_p_ftp_epsv(softf, fin, ip, nat, ftp, dlen); 970 else if (strncmp(rptr, "200", 3)) { 971 /* 972 * 200 is returned for a successful command. 973 */ 974 ; 975 } 976 } else if (softf->ipf_p_ftp_insecure && !strncmp(rptr, "227 ", 4)) { 977 inc = ipf_p_ftp_pasv(softf, fin, ip, nat, ftp, dlen); 978 } else if (softf->ipf_p_ftp_insecure && !strncmp(rptr, "229 ", 4)) { 979 inc = ipf_p_ftp_epsv(softf, fin, ip, nat, ftp, dlen); 980 } else if (*rptr == '5' || *rptr == '4') 981 ftp->ftp_passok = FTPXY_INIT; 982 else if (ftp->ftp_incok) { 983 if (*rptr == '3') { 984 if (ftp->ftp_passok == FTPXY_ACCT_1) 985 ftp->ftp_passok = FTPXY_GO; 986 else 987 ftp->ftp_passok++; 988 } else if (*rptr == '2') { 989 switch (ftp->ftp_passok) 990 { 991 case FTPXY_USER_1 : 992 case FTPXY_USER_2 : 993 case FTPXY_PASS_1 : 994 case FTPXY_PASS_2 : 995 case FTPXY_ACCT_1 : 996 ftp->ftp_passok = FTPXY_GO; 997 break; 998 default : 999 ftp->ftp_passok += 3; 1000 break; 1001 } 1002 } 1003 } 1004 ftp->ftp_incok = 0; 1005 server_cmd_ok: 1006 if (softf->ipf_p_ftp_debug & DEBUG_PARSE) 1007 printf("ipf_p_ftp_server_2: cmd[%4.4s] passok %d\n", 1008 rptr, ftp->ftp_passok); 1009 DT3(ftp_server_passok, char *,rptr, int, ftp->ftp_incok, 1010 int, ftp->ftp_passok); 1011 1012 while ((*rptr++ != '\n') && (rptr < wptr)) 1013 ; 1014 f->ftps_rptr = rptr; 1015 return (inc); 1016 } 1017 1018 1019 /* 1020 * 0 FTPXY_JUNK_OK 1021 * 1 FTPXY_JUNK_BAD 1022 * 2 FTPXY_JUNK_EOL 1023 * 3 FTPXY_JUNK_CONT 1024 * 1025 * Look to see if the buffer starts with something which we recognise as 1026 * being the correct syntax for the FTP protocol. 1027 */ 1028 int 1029 ipf_p_ftp_client_valid(ipf_ftp_softc_t *softf, ftpside_t *ftps, char *buf, 1030 size_t len) 1031 { 1032 register char *s, c, pc; 1033 register size_t i = len; 1034 char cmd[5]; 1035 1036 s = buf; 1037 1038 if (ftps->ftps_junk == FTPXY_JUNK_BAD) 1039 return (FTPXY_JUNK_BAD); 1040 1041 if (i < 5) { 1042 DT1(client_valid, int, i); 1043 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) 1044 printf("ipf_p_ftp_client_valid:i(%d) < 5\n", (int)i); 1045 return (2); 1046 } 1047 1048 i--; 1049 c = *s++; 1050 1051 if (ISALPHA(c)) { 1052 cmd[0] = TOUPPER(c); 1053 c = *s++; 1054 i--; 1055 if (ISALPHA(c)) { 1056 cmd[1] = TOUPPER(c); 1057 c = *s++; 1058 i--; 1059 if (ISALPHA(c)) { 1060 cmd[2] = TOUPPER(c); 1061 c = *s++; 1062 i--; 1063 if (ISALPHA(c)) { 1064 cmd[3] = TOUPPER(c); 1065 c = *s++; 1066 i--; 1067 if ((c != ' ') && (c != '\r')) 1068 goto bad_client_command; 1069 } else if ((c != ' ') && (c != '\r')) 1070 goto bad_client_command; 1071 } else 1072 goto bad_client_command; 1073 } else 1074 goto bad_client_command; 1075 } else { 1076 bad_client_command: 1077 DT4(client_junk, int, len, int, i, int, c, char *, buf); 1078 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 1079 printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*.*s]\n", 1080 "ipf_p_ftp_client_valid", 1081 ftps->ftps_junk, (int)len, (int)i, c, 1082 (int)len, (int)len, buf); 1083 return (FTPXY_JUNK_BAD); 1084 } 1085 1086 for (; i; i--) { 1087 pc = c; 1088 c = *s++; 1089 if ((pc == '\r') && (c == '\n')) { 1090 cmd[4] = '\0'; 1091 if (!strcmp(cmd, "PASV")) { 1092 ftps->ftps_cmd = FTPXY_C_PASV; 1093 } else if (!strcmp(cmd, "EPSV")) { 1094 ftps->ftps_cmd = FTPXY_C_EPSV; 1095 } else { 1096 ftps->ftps_cmd = 0; 1097 } 1098 return (0); 1099 } 1100 } 1101 #if !defined(_KERNEL) 1102 printf("ipf_p_ftp_client_valid:junk after cmd[%*.*s]\n", 1103 (int)len, (int)len, buf); 1104 #endif 1105 return (FTPXY_JUNK_EOL); 1106 } 1107 1108 1109 int 1110 ipf_p_ftp_server_valid(ipf_ftp_softc_t *softf, ftpside_t *ftps, char *buf, 1111 size_t len) 1112 { 1113 register char *s, c, pc; 1114 register size_t i = len; 1115 int cmd; 1116 1117 s = buf; 1118 cmd = 0; 1119 1120 if (ftps->ftps_junk == FTPXY_JUNK_BAD) 1121 return (FTPXY_JUNK_BAD); 1122 1123 if (i < 5) { 1124 DT1(server_valid, int, i); 1125 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 1126 printf("ipf_p_ftp_servert_valid:i(%d) < 5\n", (int)i); 1127 return (2); 1128 } 1129 1130 c = *s++; 1131 i--; 1132 if (c == ' ') { 1133 cmd = -1; 1134 goto search_eol; 1135 } 1136 1137 if (ISDIGIT(c)) { 1138 cmd = (c - '0') * 100; 1139 c = *s++; 1140 i--; 1141 if (ISDIGIT(c)) { 1142 cmd += (c - '0') * 10; 1143 c = *s++; 1144 i--; 1145 if (ISDIGIT(c)) { 1146 cmd += (c - '0'); 1147 c = *s++; 1148 i--; 1149 if ((c != '-') && (c != ' ')) 1150 goto bad_server_command; 1151 if (c == '-') 1152 return (FTPXY_JUNK_CONT); 1153 } else 1154 goto bad_server_command; 1155 } else 1156 goto bad_server_command; 1157 } else { 1158 bad_server_command: 1159 DT4(server_junk, int len, buf, int, i, int, c, char *, buf); 1160 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_INFO) 1161 printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*.*s]\n", 1162 "ipf_p_ftp_server_valid", 1163 ftps->ftps_junk, (int)len, (int)i, 1164 c, (int)len, (int)len, buf); 1165 if (ftps->ftps_junk == FTPXY_JUNK_CONT) 1166 return (FTPXY_JUNK_CONT); 1167 return (FTPXY_JUNK_BAD); 1168 } 1169 search_eol: 1170 for (; i; i--) { 1171 pc = c; 1172 c = *s++; 1173 if ((pc == '\r') && (c == '\n')) { 1174 if (cmd == -1) { 1175 if (ftps->ftps_junk == FTPXY_JUNK_CONT) 1176 return (FTPXY_JUNK_CONT); 1177 } else { 1178 ftps->ftps_cmd = cmd; 1179 } 1180 return (FTPXY_JUNK_OK); 1181 } 1182 } 1183 1184 DT2(junk_eol, int, len, char *, buf); 1185 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_INFO) 1186 printf("ipf_p_ftp_server_valid:junk after cmd[%*.*s]\n", 1187 (int)len, (int)len, buf); 1188 return (FTPXY_JUNK_EOL); 1189 } 1190 1191 1192 int 1193 ipf_p_ftp_valid(ipf_ftp_softc_t *softf, ftpinfo_t *ftp, int side, char *buf, 1194 size_t len) 1195 { 1196 ftpside_t *ftps; 1197 1198 ftps = &ftp->ftp_side[side]; 1199 1200 if (side == 0) 1201 return (ipf_p_ftp_client_valid(softf, ftps, buf, len)); 1202 else 1203 return (ipf_p_ftp_server_valid(softf, ftps, buf, len)); 1204 } 1205 1206 1207 /* 1208 * For map rules, the following applies: 1209 * rv == 0 for outbound processing, 1210 * rv == 1 for inbound processing. 1211 * For rdr rules, the following applies: 1212 * rv == 0 for inbound processing, 1213 * rv == 1 for outbound processing. 1214 */ 1215 int 1216 ipf_p_ftp_process(ipf_ftp_softc_t *softf, fr_info_t *fin, nat_t *nat, 1217 ftpinfo_t *ftp, int rv) 1218 { 1219 int mlen, len, off, inc, i, sel, sel2, ok, ackoff, seqoff, retry; 1220 char *rptr, *wptr, *s; 1221 u_32_t thseq, thack; 1222 ap_session_t *aps; 1223 ftpside_t *f, *t; 1224 tcphdr_t *tcp; 1225 ip_t *ip; 1226 mb_t *m; 1227 1228 m = fin->fin_m; 1229 ip = fin->fin_ip; 1230 tcp = (tcphdr_t *)fin->fin_dp; 1231 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 1232 1233 f = &ftp->ftp_side[rv]; 1234 t = &ftp->ftp_side[1 - rv]; 1235 thseq = ntohl(tcp->th_seq); 1236 thack = ntohl(tcp->th_ack); 1237 mlen = MSGDSIZE(m) - off; 1238 1239 DT3(process_debug, tcphdr_t *, tcp, int, off, int, mlen); 1240 if (softf->ipf_p_ftp_debug & DEBUG_INFO) 1241 printf("ipf_p_ftp_process: %d:%d,%d, mlen %d flags %x\n", 1242 fin->fin_out, fin->fin_sport, fin->fin_dport, 1243 mlen, tcp->th_flags); 1244 1245 if ((mlen == 0) && ((tcp->th_flags & TH_OPENING) == TH_OPENING)) { 1246 f->ftps_seq[0] = thseq + 1; 1247 t->ftps_seq[0] = thack; 1248 return (0); 1249 } else if (mlen < 0) { 1250 return (0); 1251 } 1252 1253 aps = nat->nat_aps; 1254 1255 sel = aps->aps_sel[1 - rv]; 1256 sel2 = aps->aps_sel[rv]; 1257 if (rv == 1) { 1258 seqoff = aps->aps_seqoff[sel]; 1259 if (aps->aps_seqmin[sel] > seqoff + thseq) 1260 seqoff = aps->aps_seqoff[!sel]; 1261 ackoff = aps->aps_ackoff[sel2]; 1262 if (aps->aps_ackmin[sel2] > ackoff + thack) 1263 ackoff = aps->aps_ackoff[!sel2]; 1264 } else { 1265 seqoff = aps->aps_ackoff[sel]; 1266 if (softf->ipf_p_ftp_debug & DEBUG_INFO) 1267 printf("seqoff %d thseq %x ackmin %x\n", seqoff, thseq, 1268 aps->aps_ackmin[sel]); 1269 if (aps->aps_ackmin[sel] > seqoff + thseq) 1270 seqoff = aps->aps_ackoff[!sel]; 1271 1272 ackoff = aps->aps_seqoff[sel2]; 1273 if (softf->ipf_p_ftp_debug & DEBUG_INFO) 1274 printf("ackoff %d thack %x seqmin %x\n", ackoff, thack, 1275 aps->aps_seqmin[sel2]); 1276 if (ackoff > 0) { 1277 if (aps->aps_seqmin[sel2] > ackoff + thack) 1278 ackoff = aps->aps_seqoff[!sel2]; 1279 } else { 1280 if (aps->aps_seqmin[sel2] > thack) 1281 ackoff = aps->aps_seqoff[!sel2]; 1282 } 1283 } 1284 if (softf->ipf_p_ftp_debug & DEBUG_INFO) { 1285 printf("%s: %x seq %x/%d ack %x/%d len %d/%d off %d\n", 1286 rv ? "IN" : "OUT", tcp->th_flags, thseq, seqoff, 1287 thack, ackoff, mlen, fin->fin_plen, off); 1288 printf("sel %d seqmin %x/%x offset %d/%d\n", sel, 1289 aps->aps_seqmin[sel], aps->aps_seqmin[sel2], 1290 aps->aps_seqoff[sel], aps->aps_seqoff[sel2]); 1291 printf("sel %d ackmin %x/%x offset %d/%d\n", sel2, 1292 aps->aps_ackmin[sel], aps->aps_ackmin[sel2], 1293 aps->aps_ackoff[sel], aps->aps_ackoff[sel2]); 1294 } 1295 1296 /* 1297 * XXX - Ideally, this packet should get dropped because we now know 1298 * that it is out of order (and there is no real danger in doing so 1299 * apart from causing packets to go through here ordered). 1300 */ 1301 if (softf->ipf_p_ftp_debug & DEBUG_INFO) { 1302 printf("rv %d t:seq[0] %x seq[1] %x %d/%d\n", 1303 rv, t->ftps_seq[0], t->ftps_seq[1], seqoff, ackoff); 1304 } 1305 1306 ok = 0; 1307 if (t->ftps_seq[0] == 0) { 1308 t->ftps_seq[0] = thack; 1309 ok = 1; 1310 } else { 1311 if (ackoff == 0) { 1312 if (t->ftps_seq[0] == thack) 1313 ok = 1; 1314 else if (t->ftps_seq[1] == thack) { 1315 t->ftps_seq[0] = thack; 1316 ok = 1; 1317 } 1318 } else { 1319 if (t->ftps_seq[0] + ackoff == thack) { 1320 t->ftps_seq[0] = thack; 1321 ok = 1; 1322 } else if (t->ftps_seq[0] == thack + ackoff) { 1323 t->ftps_seq[0] = thack + ackoff; 1324 ok = 1; 1325 } else if (t->ftps_seq[1] + ackoff == thack) { 1326 t->ftps_seq[0] = thack; 1327 ok = 1; 1328 } else if (t->ftps_seq[1] == thack + ackoff) { 1329 t->ftps_seq[0] = thack + ackoff; 1330 ok = 1; 1331 } 1332 } 1333 } 1334 1335 if (softf->ipf_p_ftp_debug & DEBUG_INFO) { 1336 if (!ok) 1337 printf("%s ok\n", "not"); 1338 } 1339 1340 if (!mlen) { 1341 if (t->ftps_seq[0] + ackoff != thack && 1342 t->ftps_seq[1] + ackoff != thack) { 1343 DT3(thack, ftpside_t *t, t, int, ackoff, u_32_t, thack); 1344 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) { 1345 printf("%s:seq[0](%u) + (%d) != (%u)\n", 1346 "ipf_p_ftp_process", t->ftps_seq[0], 1347 ackoff, thack); 1348 printf("%s:seq[1](%u) + (%d) != (%u)\n", 1349 "ipf_p_ftp_process", t->ftps_seq[1], 1350 ackoff, thack); 1351 } 1352 return (APR_ERR(1)); 1353 } 1354 1355 if (softf->ipf_p_ftp_debug & DEBUG_PARSE) { 1356 printf("ipf_p_ftp_process:f:seq[0] %x seq[1] %x\n", 1357 f->ftps_seq[0], f->ftps_seq[1]); 1358 } 1359 1360 if (tcp->th_flags & TH_FIN) { 1361 if (thseq == f->ftps_seq[1]) { 1362 f->ftps_seq[0] = f->ftps_seq[1] - seqoff; 1363 f->ftps_seq[1] = thseq + 1 - seqoff; 1364 } else { 1365 DT2(thseq, ftpside_t *t, t, u_32_t, thseq); 1366 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) { 1367 printf("FIN: thseq %x seqoff %d ftps_seq %x\n", 1368 thseq, seqoff, f->ftps_seq[0]); 1369 } 1370 return (APR_ERR(1)); 1371 } 1372 } 1373 f->ftps_len = 0; 1374 return (0); 1375 } 1376 1377 ok = 0; 1378 if ((thseq == f->ftps_seq[0]) || (thseq == f->ftps_seq[1])) { 1379 ok = 1; 1380 /* 1381 * Retransmitted data packet. 1382 */ 1383 } else if ((thseq + mlen == f->ftps_seq[0]) || 1384 (thseq + mlen == f->ftps_seq[1])) { 1385 ok = 1; 1386 } 1387 1388 if (ok == 0) { 1389 DT3(ok_0, ftpside_t *, f, u_32_t, thseq, int, mlen); 1390 inc = thseq - f->ftps_seq[0]; 1391 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) { 1392 printf("inc %d sel %d rv %d\n", inc, sel, rv); 1393 printf("th_seq %x ftps_seq %x/%x\n", 1394 thseq, f->ftps_seq[0], f->ftps_seq[1]); 1395 printf("ackmin %x ackoff %d\n", aps->aps_ackmin[sel], 1396 aps->aps_ackoff[sel]); 1397 printf("seqmin %x seqoff %d\n", aps->aps_seqmin[sel], 1398 aps->aps_seqoff[sel]); 1399 } 1400 1401 return (APR_ERR(1)); 1402 } 1403 1404 inc = 0; 1405 rptr = f->ftps_rptr; 1406 wptr = f->ftps_wptr; 1407 f->ftps_seq[0] = thseq; 1408 f->ftps_seq[1] = f->ftps_seq[0] + mlen; 1409 f->ftps_len = mlen; 1410 1411 while (mlen > 0) { 1412 len = MIN(mlen, sizeof(f->ftps_buf) - (wptr - rptr)); 1413 if (len == 0) 1414 break; 1415 COPYDATA(m, off, len, wptr); 1416 mlen -= len; 1417 off += len; 1418 wptr += len; 1419 1420 whilemore: 1421 if (softf->ipf_p_ftp_debug & DEBUG_PARSE) 1422 printf("%s:len %d/%d off %d wptr %lx junk %d [%*.*s]\n", 1423 "ipf_p_ftp_process", 1424 len, mlen, off, (u_long)wptr, f->ftps_junk, 1425 len, len, rptr); 1426 1427 f->ftps_wptr = wptr; 1428 if (f->ftps_junk != FTPXY_JUNK_OK) { 1429 i = f->ftps_junk; 1430 f->ftps_junk = ipf_p_ftp_valid(softf, ftp, rv, rptr, 1431 wptr - rptr); 1432 DT2(junk_transit, int, i, int, f->ftps_junk); 1433 1434 if (softf->ipf_p_ftp_debug & DEBUG_PARSE) 1435 printf("%s:junk %d -> %d\n", 1436 "ipf_p_ftp_process", i, f->ftps_junk); 1437 1438 if (f->ftps_junk == FTPXY_JUNK_BAD) { 1439 DT(buffer_full); 1440 if (wptr - rptr == sizeof(f->ftps_buf)) { 1441 if (softf->ipf_p_ftp_debug & 1442 DEBUG_PARSE_INFO) 1443 printf("%s:full buffer\n", 1444 "ipf_p_ftp_process"); 1445 f->ftps_rptr = f->ftps_buf; 1446 f->ftps_wptr = f->ftps_buf; 1447 rptr = f->ftps_rptr; 1448 wptr = f->ftps_wptr; 1449 continue; 1450 } 1451 } 1452 } 1453 1454 while ((f->ftps_junk == FTPXY_JUNK_OK) && (wptr > rptr)) { 1455 len = wptr - rptr; 1456 f->ftps_junk = ipf_p_ftp_valid(softf, ftp, rv, 1457 rptr, len); 1458 DT5(junk_ftp_valid, int, len, int, rv, u_long, rptr, 1459 u_long, wptr, int, f->ftps_junk); 1460 1461 if (softf->ipf_p_ftp_debug & DEBUG_PARSE) { 1462 printf("%s=%d len %d rv %d ptr %lx/%lx ", 1463 "ipf_p_ftp_valid", 1464 f->ftps_junk, len, rv, (u_long)rptr, 1465 (u_long)wptr); 1466 printf("buf [%*.*s]\n", len, len, rptr); 1467 } 1468 1469 if (f->ftps_junk == FTPXY_JUNK_OK) { 1470 f->ftps_cmds++; 1471 f->ftps_rptr = rptr; 1472 if (rv) 1473 inc += ipf_p_ftp_server(softf, fin, ip, 1474 nat, ftp, len); 1475 else 1476 inc += ipf_p_ftp_client(softf, fin, ip, 1477 nat, ftp, len); 1478 rptr = f->ftps_rptr; 1479 wptr = f->ftps_wptr; 1480 } 1481 } 1482 1483 /* 1484 * Off to a bad start so lets just forget about using the 1485 * ftp proxy for this connection. 1486 */ 1487 if ((f->ftps_cmds == 0) && (f->ftps_junk == FTPXY_JUNK_BAD)) { 1488 /* f->ftps_seq[1] += inc; */ 1489 1490 DT(ftp_junk_cmd); 1491 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) 1492 printf("%s:cmds == 0 junk == 1\n", 1493 "ipf_p_ftp_process"); 1494 return (APR_ERR(2)); 1495 } 1496 1497 retry = 0; 1498 if ((f->ftps_junk != FTPXY_JUNK_OK) && (rptr < wptr)) { 1499 for (s = rptr; s < wptr; s++) { 1500 if ((*s == '\r') && (s + 1 < wptr) && 1501 (*(s + 1) == '\n')) { 1502 rptr = s + 2; 1503 retry = 1; 1504 if (f->ftps_junk != FTPXY_JUNK_CONT) 1505 f->ftps_junk = FTPXY_JUNK_OK; 1506 break; 1507 } 1508 } 1509 } 1510 1511 if (rptr == wptr) { 1512 rptr = wptr = f->ftps_buf; 1513 } else { 1514 /* 1515 * Compact the buffer back to the start. The junk 1516 * flag should already be set and because we're not 1517 * throwing away any data, it is preserved from its 1518 * current state. 1519 */ 1520 if (rptr > f->ftps_buf) { 1521 bcopy(rptr, f->ftps_buf, wptr - rptr); 1522 wptr -= rptr - f->ftps_buf; 1523 rptr = f->ftps_buf; 1524 } 1525 } 1526 f->ftps_rptr = rptr; 1527 f->ftps_wptr = wptr; 1528 if (retry) 1529 goto whilemore; 1530 } 1531 1532 /* f->ftps_seq[1] += inc; */ 1533 if (tcp->th_flags & TH_FIN) 1534 f->ftps_seq[1]++; 1535 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_INFO) { 1536 mlen = MSGDSIZE(m); 1537 mlen -= off; 1538 printf("ftps_seq[1] = %x inc %d len %d\n", 1539 f->ftps_seq[1], inc, mlen); 1540 } 1541 1542 f->ftps_rptr = rptr; 1543 f->ftps_wptr = wptr; 1544 return (APR_INC(inc)); 1545 } 1546 1547 1548 int 1549 ipf_p_ftp_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) 1550 { 1551 ipf_ftp_softc_t *softf = arg; 1552 ftpinfo_t *ftp; 1553 int rev; 1554 1555 ftp = aps->aps_data; 1556 if (ftp == NULL) 1557 return (0); 1558 1559 rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; 1560 if (ftp->ftp_side[1 - rev].ftps_ifp == NULL) 1561 ftp->ftp_side[1 - rev].ftps_ifp = fin->fin_ifp; 1562 1563 return (ipf_p_ftp_process(softf, fin, nat, ftp, rev)); 1564 } 1565 1566 1567 int 1568 ipf_p_ftp_in(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) 1569 { 1570 ipf_ftp_softc_t *softf = arg; 1571 ftpinfo_t *ftp; 1572 int rev; 1573 1574 ftp = aps->aps_data; 1575 if (ftp == NULL) 1576 return (0); 1577 1578 rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; 1579 if (ftp->ftp_side[rev].ftps_ifp == NULL) 1580 ftp->ftp_side[rev].ftps_ifp = fin->fin_ifp; 1581 1582 return (ipf_p_ftp_process(softf, fin, nat, ftp, 1 - rev)); 1583 } 1584 1585 1586 /* 1587 * ipf_p_ftp_atoi - implement a version of atoi which processes numbers in 1588 * pairs separated by commas (which are expected to be in the range 0 - 255), 1589 * returning a 16 bit number combining either side of the , as the MSB and 1590 * LSB. 1591 */ 1592 u_short 1593 ipf_p_ftp_atoi(char **ptr) 1594 { 1595 register char *s = *ptr, c; 1596 register u_char i = 0, j = 0; 1597 1598 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1599 i *= 10; 1600 i += c - '0'; 1601 } 1602 if (c != ',') { 1603 *ptr = NULL; 1604 return (0); 1605 } 1606 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1607 j *= 10; 1608 j += c - '0'; 1609 } 1610 *ptr = s; 1611 i &= 0xff; 1612 j &= 0xff; 1613 return (i << 8) | j; 1614 } 1615 1616 1617 int 1618 ipf_p_ftp_eprt(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat, 1619 ftpinfo_t *ftp, int dlen) 1620 { 1621 ftpside_t *f; 1622 1623 /* 1624 * Check for client sending out EPRT message. 1625 */ 1626 if (dlen < IPF_MINEPRTLEN) { 1627 DT1(epert_dlen, int, dlen); 1628 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 1629 printf("ipf_p_ftp_eprt:dlen(%d) < IPF_MINEPRTLEN\n", 1630 dlen); 1631 return (0); 1632 } 1633 1634 /* 1635 * Parse the EPRT command. Format is: 1636 * "EPRT |1|1.2.3.4|2000|" for IPv4 and 1637 * "EPRT |2|ef00::1:2|2000|" for IPv6 1638 */ 1639 f = &ftp->ftp_side[0]; 1640 if (f->ftps_rptr[5] != '|') 1641 return (0); 1642 if (f->ftps_rptr[5] == f->ftps_rptr[7]) { 1643 if (f->ftps_rptr[6] == '1' && nat->nat_v[0] == 4) 1644 return (ipf_p_ftp_eprt4(softf, fin, ip, nat, ftp, dlen)); 1645 #ifdef USE_INET6 1646 if (f->ftps_rptr[6] == '2' && nat->nat_v[0] == 6) 1647 return (ipf_p_ftp_eprt6(softf, fin, ip, nat, ftp, dlen)); 1648 #endif 1649 } 1650 return (0); 1651 } 1652 1653 1654 int 1655 ipf_p_ftp_eprt4(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat, 1656 ftpinfo_t *ftp, int dlen) 1657 { 1658 int a1, a2, a3, a4, port, olen, nlen, inc, off; 1659 char newbuf[IPF_FTPBUFSZ]; 1660 char *s, c, delim; 1661 u_32_t addr, i; 1662 tcphdr_t *tcp; 1663 ftpside_t *f; 1664 mb_t *m; 1665 1666 m = fin->fin_m; 1667 tcp = (tcphdr_t *)fin->fin_dp; 1668 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 1669 f = &ftp->ftp_side[0]; 1670 delim = f->ftps_rptr[5]; 1671 s = f->ftps_rptr + 8; 1672 1673 /* 1674 * get the IP address. 1675 */ 1676 i = 0; 1677 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1678 i *= 10; 1679 i += c - '0'; 1680 } 1681 if (i > 255) 1682 return (0); 1683 if (c != '.') 1684 return (0); 1685 addr = (i << 24); 1686 1687 i = 0; 1688 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1689 i *= 10; 1690 i += c - '0'; 1691 } 1692 if (i > 255) 1693 return (0); 1694 if (c != '.') 1695 return (0); 1696 addr |= (addr << 16); 1697 1698 i = 0; 1699 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1700 i *= 10; 1701 i += c - '0'; 1702 } 1703 if (i > 255) 1704 return (0); 1705 if (c != '.') 1706 return (0); 1707 addr |= (addr << 8); 1708 1709 i = 0; 1710 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1711 i *= 10; 1712 i += c - '0'; 1713 } 1714 if (i > 255) 1715 return (0); 1716 if (c != delim) 1717 return (0); 1718 addr |= addr; 1719 1720 /* 1721 * Get the port number 1722 */ 1723 i = 0; 1724 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1725 i *= 10; 1726 i += c - '0'; 1727 } 1728 if (i > 65535) 1729 return (0); 1730 if (c != delim) 1731 return (0); 1732 port = i; 1733 1734 /* 1735 * Check for CR-LF at the end of the command string. 1736 */ 1737 if ((*s != '\r') || (*(s + 1) != '\n')) { 1738 DT(eprt4_no_crlf); 1739 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 1740 printf("ipf_p_ftp_eprt4:missing %s\n", "cr-lf"); 1741 return (0); 1742 } 1743 s += 2; 1744 1745 /* 1746 * Calculate new address parts for PORT command 1747 */ 1748 if (nat->nat_dir == NAT_INBOUND) 1749 a1 = ntohl(nat->nat_odstaddr); 1750 else 1751 a1 = ntohl(ip->ip_src.s_addr); 1752 a2 = (a1 >> 16) & 0xff; 1753 a3 = (a1 >> 8) & 0xff; 1754 a4 = a1 & 0xff; 1755 a1 >>= 24; 1756 olen = s - f->ftps_rptr; 1757 /* DO NOT change this to snprintf! */ 1758 /* 1759 * While we could force the use of | as a delimiter here, it makes 1760 * sense to preserve whatever character is being used by the systems 1761 * involved in the communication. 1762 */ 1763 (void) snprintf(newbuf, sizeof(newbuf), "%s %c1%c%u.%u.%u.%u%c%u%c\r\n", 1764 "EPRT", delim, delim, a1, a2, a3, a4, delim, port, 1765 delim); 1766 1767 nlen = strlen(newbuf); 1768 inc = nlen - olen; 1769 if ((inc + fin->fin_plen) > 65535) { 1770 DT2(eprt4_len, int, inc, int, fin->fin_plen); 1771 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) 1772 printf("ipf_p_ftp_eprt4:inc(%d) + ip->ip_len > 65535\n", 1773 inc); 1774 return (0); 1775 } 1776 1777 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 1778 #if !defined(_KERNEL) 1779 M_ADJ(m, inc); 1780 #else 1781 if (inc < 0) 1782 M_ADJ(m, inc); 1783 #endif 1784 /* the mbuf chain will be extended if necessary by m_copyback() */ 1785 COPYBACK(m, off, nlen, newbuf); 1786 fin->fin_flx |= FI_DOCKSUM; 1787 1788 if (inc != 0) { 1789 fin->fin_plen += inc; 1790 ip->ip_len = htons(fin->fin_plen); 1791 fin->fin_dlen += inc; 1792 } 1793 1794 f->ftps_cmd = FTPXY_C_EPRT; 1795 return (ipf_p_ftp_addport(softf, fin, ip, nat, ftp, dlen, port, inc)); 1796 } 1797 1798 1799 int 1800 ipf_p_ftp_epsv(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat, 1801 ftpinfo_t *ftp, int dlen) 1802 { 1803 char newbuf[IPF_FTPBUFSZ]; 1804 u_short ap = 0; 1805 ftpside_t *f; 1806 char *s; 1807 1808 if ((softf->ipf_p_ftp_forcepasv != 0) && 1809 (ftp->ftp_side[0].ftps_cmd != FTPXY_C_EPSV)) { 1810 DT1(epsv_cmd, int, ftp->ftp_side[0].ftps_cmd); 1811 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 1812 printf("ipf_p_ftp_epsv:ftps_cmd(%d) != FTPXY_C_EPSV\n", 1813 ftp->ftp_side[0].ftps_cmd); 1814 return (0); 1815 } 1816 f = &ftp->ftp_side[1]; 1817 1818 #define EPSV_REPLEN 33 1819 /* 1820 * Check for EPSV reply message. 1821 */ 1822 if (dlen < IPF_MIN229LEN) { 1823 return (0); 1824 } else if (strncmp(f->ftps_rptr, 1825 "229 Entering Extended Passive Mode", EPSV_REPLEN)) { 1826 return (0); 1827 } 1828 1829 /* 1830 * Skip the EPSV command + space 1831 */ 1832 s = f->ftps_rptr + 33; 1833 while (*s && !ISDIGIT(*s)) 1834 s++; 1835 1836 /* 1837 * As per RFC 2428, there are no addres components in the EPSV 1838 * response. So we'll go straight to getting the port. 1839 */ 1840 while (*s && ISDIGIT(*s)) { 1841 ap *= 10; 1842 ap += *s++ - '0'; 1843 } 1844 1845 if (*s == '|') 1846 s++; 1847 if (*s == ')') 1848 s++; 1849 if (*s == '\n') 1850 s--; 1851 /* 1852 * check for CR-LF at the end. 1853 */ 1854 if ((*s != '\r') || (*(s + 1) != '\n')) { 1855 return (0); 1856 } 1857 s += 2; 1858 1859 (void) snprintf(newbuf, sizeof(newbuf), "%s (|||%u|)\r\n", 1860 "229 Entering Extended Passive Mode", ap); 1861 1862 return (ipf_p_ftp_pasvreply(softf, fin, ip, nat, ftp, (u_int)ap, 1863 newbuf, s)); 1864 } 1865 1866 #ifdef USE_INET6 1867 int 1868 ipf_p_ftp_eprt6(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat, 1869 ftpinfo_t *ftp, int dlen) 1870 { 1871 int port, olen, nlen, inc, off, left, i; 1872 char newbuf[IPF_FTPBUFSZ]; 1873 char *s, c; 1874 i6addr_t addr, *a6; 1875 tcphdr_t *tcp; 1876 ip6_t *ip6; 1877 char delim; 1878 u_short whole; 1879 u_short part; 1880 ftpside_t *f; 1881 u_short *t; 1882 int fwd; 1883 mb_t *m; 1884 u_32_t a; 1885 1886 m = fin->fin_m; 1887 ip6 = (ip6_t *)ip; 1888 f = &ftp->ftp_side[0]; 1889 s = f->ftps_rptr + 8; 1890 f = &ftp->ftp_side[0]; 1891 delim = f->ftps_rptr[5]; 1892 tcp = (tcphdr_t *)fin->fin_dp; 1893 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 1894 1895 addr.i6[0] = 0; 1896 addr.i6[1] = 0; 1897 addr.i6[2] = 0; 1898 addr.i6[3] = 0; 1899 /* 1900 * Parse an IPv6 address. 1901 * Go forward until either :: or | is found. If :: is found, 1902 * reverse direction. Direction change is performed to ease 1903 * parsing an unknown number of 0s in the middle. 1904 */ 1905 whole = 0; 1906 t = (u_short *)&addr; 1907 fwd = 1; 1908 for (part = 0; (c = *s) != '\0'; ) { 1909 if (c == delim) { 1910 *t = htons((u_short)whole); 1911 break; 1912 } 1913 if (c == ':') { 1914 *t = part; 1915 if (fwd) { 1916 *t = htons((u_short)whole); 1917 t++; 1918 } else { 1919 *t = htons((u_short)(whole >> 16)); 1920 t--; 1921 } 1922 whole = 0; 1923 if (fwd == 1 && s[1] == ':') { 1924 while (*s && *s != '|') 1925 s++; 1926 if ((c = *s) != delim) 1927 break; 1928 t = (u_short *)&addr.i6[3]; 1929 t++; 1930 fwd = 0; 1931 } else if (fwd == 0 && s[-1] == ':') { 1932 break; 1933 } 1934 } else { 1935 if (c >= '0' && c <= '9') { 1936 c -= '0'; 1937 } else if (c >= 'a' && c <= 'f') { 1938 c -= 'a' + 10; 1939 } else if (c >= 'A' && c <= 'F') { 1940 c -= 'A' + 10; 1941 } 1942 if (fwd) { 1943 whole <<= 8; 1944 whole |= c; 1945 } else { 1946 whole >>= 8; 1947 whole |= ((u_32_t)c) << 24; 1948 } 1949 } 1950 if (fwd) 1951 s++; 1952 else 1953 s--; 1954 } 1955 if (c != ':' && c != delim) 1956 return (0); 1957 1958 while (*s != '|') 1959 s++; 1960 s++; 1961 1962 /* 1963 * Get the port number 1964 */ 1965 i = 0; 1966 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1967 i *= 10; 1968 i += c - '0'; 1969 } 1970 if (i > 65535) 1971 return (0); 1972 if (c != delim) 1973 return (0); 1974 port = (u_short)(i & 0xffff); 1975 1976 /* 1977 * Check for CR-LF at the end of the command string. 1978 */ 1979 if ((*s != '\r') || (*(s + 1) != '\n')) { 1980 DT(eprt6_no_crlf); 1981 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 1982 printf("ipf_p_ftp_eprt6:missing %s\n", "cr-lf"); 1983 return (0); 1984 } 1985 s += 2; 1986 1987 /* 1988 * Calculate new address parts for PORT command 1989 */ 1990 a6 = (i6addr_t *)&ip6->ip6_src; 1991 olen = s - f->ftps_rptr; 1992 /* DO NOT change this to snprintf! */ 1993 /* 1994 * While we could force the use of | as a delimiter here, it makes 1995 * sense to preserve whatever character is being used by the systems 1996 * involved in the communication. 1997 */ 1998 s = newbuf; 1999 left = sizeof(newbuf); 2000 (void) snprintf(s, left, "EPRT %c2%c", delim, delim); 2001 s += strlen(s); 2002 a = ntohl(a6->i6[0]); 2003 snprintf(s, left, "%x:%x:", a >> 16, a & 0xffff); 2004 left -= strlen(s); 2005 s += strlen(s); 2006 a = ntohl(a6->i6[1]); 2007 snprintf(s, left, "%x:%x:", a >> 16, a & 0xffff); 2008 left -= strlen(s); 2009 s += strlen(s); 2010 a = ntohl(a6->i6[2]); 2011 snprintf(s, left,"%x:%x:", a >> 16, a & 0xffff); 2012 left -= strlen(s); 2013 s += strlen(s); 2014 a = ntohl(a6->i6[3]); 2015 snprintf(s, left, "%x:%x", a >> 16, a & 0xffff); 2016 left -= strlen(s); 2017 s += strlen(s); 2018 snprintf(s, left, "|%d|\r\n", port); 2019 nlen = strlen(newbuf); 2020 inc = nlen - olen; 2021 if ((inc + fin->fin_plen) > 65535) { 2022 DT2(eprt6_len, int, inc, int, fin->fin_plen); 2023 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) 2024 printf("ipf_p_ftp_eprt6:inc(%d) + ip->ip_len > 65535\n", 2025 inc); 2026 return (0); 2027 } 2028 2029 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 2030 #if !defined(_KERNEL) 2031 M_ADJ(m, inc); 2032 #else 2033 if (inc < 0) 2034 M_ADJ(m, inc); 2035 #endif 2036 /* the mbuf chain will be extended if necessary by m_copyback() */ 2037 COPYBACK(m, off, nlen, newbuf); 2038 fin->fin_flx |= FI_DOCKSUM; 2039 2040 if (inc != 0) { 2041 fin->fin_plen += inc; 2042 ip6->ip6_plen = htons(fin->fin_plen - fin->fin_hlen); 2043 fin->fin_dlen += inc; 2044 } 2045 2046 f->ftps_cmd = FTPXY_C_EPRT; 2047 return (ipf_p_ftp_addport(softf, fin, ip, nat, ftp, dlen, port, inc)); 2048 } 2049 #endif 2050