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