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