1 /* $NetBSD: ip_ftp_pxy.c,v 1.7 2018/06/03 10:37:23 maxv Exp $ */ 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 * Id: ip_ftp_pxy.c,v 1.1.1.2 2012/07/22 13:45:18 darrenr Exp 12 */ 13 14 #include <sys/cdefs.h> 15 __KERNEL_RCSID(1, "$NetBSD: ip_ftp_pxy.c,v 1.7 2018/06/03 10:37:23 maxv Exp $"); 16 17 #define IPF_FTP_PROXY 18 19 #define IPF_MINPORTLEN 18 20 #define IPF_MINEPRTLEN 20 21 #define IPF_MAXPORTLEN 30 22 #define IPF_MIN227LEN 39 23 #define IPF_MAX227LEN 51 24 #define IPF_MIN229LEN 47 25 #define IPF_MAX229LEN 51 26 27 #define FTPXY_GO 0 28 #define FTPXY_INIT 1 29 #define FTPXY_USER_1 2 30 #define FTPXY_USOK_1 3 31 #define FTPXY_PASS_1 4 32 #define FTPXY_PAOK_1 5 33 #define FTPXY_AUTH_1 6 34 #define FTPXY_AUOK_1 7 35 #define FTPXY_ADAT_1 8 36 #define FTPXY_ADOK_1 9 37 #define FTPXY_ACCT_1 10 38 #define FTPXY_ACOK_1 11 39 #define FTPXY_USER_2 12 40 #define FTPXY_USOK_2 13 41 #define FTPXY_PASS_2 14 42 #define FTPXY_PAOK_2 15 43 44 #define FTPXY_JUNK_OK 0 45 #define FTPXY_JUNK_BAD 1 /* Ignore all commands for this connection */ 46 #define FTPXY_JUNK_EOL 2 /* consume the rest of this line only */ 47 #define FTPXY_JUNK_CONT 3 /* Saerching for next numeric */ 48 49 /* 50 * Values for FTP commands. Numerics cover 0-999 51 */ 52 #define FTPXY_C_PASV 1000 53 #define FTPXY_C_PORT 1001 54 #define FTPXY_C_EPSV 1002 55 #define FTPXY_C_EPRT 1003 56 57 58 typedef struct ipf_ftp_softc_s { 59 int ipf_p_ftp_pasvonly; 60 /* Do not require logins before transfers */ 61 int ipf_p_ftp_insecure; 62 int ipf_p_ftp_pasvrdr; 63 /* PASV must be last command prior to 227 */ 64 int ipf_p_ftp_forcepasv; 65 int ipf_p_ftp_debug; 66 int ipf_p_ftp_single_xfer; 67 void *ipf_p_ftp_tune; 68 } ipf_ftp_softc_t; 69 70 71 void ipf_p_ftp_main_load(void); 72 void ipf_p_ftp_main_unload(void); 73 void *ipf_p_ftp_soft_create(ipf_main_softc_t *); 74 void ipf_p_ftp_soft_destroy(ipf_main_softc_t *, void *); 75 76 int ipf_p_ftp_client(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 77 ftpinfo_t *, int); 78 int ipf_p_ftp_complete(char *, size_t); 79 int ipf_p_ftp_in(void *, fr_info_t *, ap_session_t *, nat_t *); 80 int ipf_p_ftp_new(void *, fr_info_t *, ap_session_t *, nat_t *); 81 void ipf_p_ftp_del(ipf_main_softc_t *, ap_session_t *); 82 int ipf_p_ftp_out(void *, fr_info_t *, ap_session_t *, nat_t *); 83 int ipf_p_ftp_pasv(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 84 ftpinfo_t *, int); 85 int ipf_p_ftp_epsv(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 86 ftpinfo_t *, int); 87 int ipf_p_ftp_port(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 88 ftpinfo_t *, int); 89 int ipf_p_ftp_process(ipf_ftp_softc_t *, fr_info_t *, nat_t *, 90 ftpinfo_t *, int); 91 int ipf_p_ftp_server(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 92 ftpinfo_t *, int); 93 int ipf_p_ftp_valid(ipf_ftp_softc_t *, ftpinfo_t *, int, char *, size_t); 94 int ipf_p_ftp_server_valid(ipf_ftp_softc_t *, ftpside_t *, char *, 95 size_t); 96 int ipf_p_ftp_client_valid(ipf_ftp_softc_t *, ftpside_t *, char *, 97 size_t); 98 u_short ipf_p_ftp_atoi(char **); 99 int ipf_p_ftp_pasvreply(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 100 ftpinfo_t *, u_int, char *, char *); 101 int ipf_p_ftp_eprt(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 102 ftpinfo_t *, int); 103 int ipf_p_ftp_eprt4(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 104 ftpinfo_t *, int); 105 int ipf_p_ftp_eprt6(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 106 ftpinfo_t *, int); 107 int ipf_p_ftp_addport(ipf_ftp_softc_t *, fr_info_t *, ip_t *, nat_t *, 108 ftpinfo_t *, int, int, int); 109 void ipf_p_ftp_setpending(ipf_main_softc_t *, ftpinfo_t *); 110 111 /* 112 * Debug levels 113 */ 114 #define DEBUG_SECURITY 0x01 115 #define DEBUG_ERROR 0x02 116 #define DEBUG_INFO 0x04 117 #define DEBUG_PARSE_ERR 0x08 118 #define DEBUG_PARSE_INFO 0x10 119 #define DEBUG_PARSE 0x20 120 121 static int ipf_p_ftp_proxy_init = 0; 122 static frentry_t ftppxyfr; 123 static const ipftuneable_t ipf_ftp_tuneables[] = { 124 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_debug) }, 125 "ftp_debug", 0, 0x7f, 126 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_debug), 127 0, NULL, NULL }, 128 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_pasvonly) }, 129 "ftp_pasvonly", 0, 1, 130 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_pasvonly), 131 0, NULL, NULL }, 132 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_insecure) }, 133 "ftp_insecure", 0, 1, 134 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_insecure), 135 0, NULL, NULL }, 136 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_pasvrdr) }, 137 "ftp_pasvrdr", 0, 1, 138 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_pasvrdr), 139 0, NULL, NULL }, 140 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_forcepasv) }, 141 "ftp_forcepasv", 0, 1, 142 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_forcepasv), 143 0, NULL, NULL }, 144 { { (void *)offsetof(ipf_ftp_softc_t, ipf_p_ftp_single_xfer) }, 145 "ftp_single_xfer", 0, 1, 146 stsizeof(ipf_ftp_softc_t, ipf_p_ftp_single_xfer), 147 0, NULL, NULL }, 148 { { NULL }, NULL, 0, 0, 0, 0, NULL, NULL } 149 }; 150 151 152 void 153 ipf_p_ftp_main_load(void) 154 { 155 bzero((char *)&ftppxyfr, sizeof(ftppxyfr)); 156 ftppxyfr.fr_ref = 1; 157 ftppxyfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; 158 159 MUTEX_INIT(&ftppxyfr.fr_lock, "FTP Proxy Mutex"); 160 ipf_p_ftp_proxy_init = 1; 161 } 162 163 164 void 165 ipf_p_ftp_main_unload(void) 166 { 167 168 if (ipf_p_ftp_proxy_init == 1) { 169 MUTEX_DESTROY(&ftppxyfr.fr_lock); 170 ipf_p_ftp_proxy_init = 0; 171 } 172 } 173 174 175 /* 176 * Initialize local structures. 177 */ 178 void * 179 ipf_p_ftp_soft_create(ipf_main_softc_t *softc) 180 { 181 ipf_ftp_softc_t *softf; 182 183 KMALLOC(softf, ipf_ftp_softc_t *); 184 if (softf == NULL) 185 return NULL; 186 187 bzero((char *)softf, sizeof(*softf)); 188 #if defined(_KERNEL) 189 softf->ipf_p_ftp_debug = 0; 190 #else 191 softf->ipf_p_ftp_debug = DEBUG_PARSE_ERR; 192 #endif 193 softf->ipf_p_ftp_forcepasv = 1; 194 195 softf->ipf_p_ftp_tune = ipf_tune_array_copy(softf, 196 sizeof(ipf_ftp_tuneables), 197 ipf_ftp_tuneables); 198 if (softf->ipf_p_ftp_tune == NULL) { 199 ipf_p_ftp_soft_destroy(softc, softf); 200 return NULL; 201 } 202 if (ipf_tune_array_link(softc, softf->ipf_p_ftp_tune) == -1) { 203 ipf_p_ftp_soft_destroy(softc, softf); 204 return NULL; 205 } 206 207 return softf; 208 } 209 210 211 void 212 ipf_p_ftp_soft_destroy(ipf_main_softc_t *softc, void *arg) 213 { 214 ipf_ftp_softc_t *softf = arg; 215 216 if (softf->ipf_p_ftp_tune != NULL) { 217 ipf_tune_array_unlink(softc, softf->ipf_p_ftp_tune); 218 KFREES(softf->ipf_p_ftp_tune, sizeof(ipf_ftp_tuneables)); 219 softf->ipf_p_ftp_tune = NULL; 220 } 221 222 KFREE(softf); 223 } 224 225 226 int 227 ipf_p_ftp_new(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) 228 { 229 ftpinfo_t *ftp; 230 ftpside_t *f; 231 232 KMALLOC(ftp, ftpinfo_t *); 233 if (ftp == NULL) 234 return -1; 235 236 nat = nat; /* LINT */ 237 238 aps->aps_data = ftp; 239 aps->aps_psiz = sizeof(ftpinfo_t); 240 aps->aps_sport = htons(fin->fin_sport); 241 aps->aps_dport = htons(fin->fin_dport); 242 243 bzero((char *)ftp, sizeof(*ftp)); 244 f = &ftp->ftp_side[0]; 245 f->ftps_rptr = f->ftps_buf; 246 f->ftps_wptr = f->ftps_buf; 247 f = &ftp->ftp_side[1]; 248 f->ftps_rptr = f->ftps_buf; 249 f->ftps_wptr = f->ftps_buf; 250 ftp->ftp_passok = FTPXY_INIT; 251 ftp->ftp_incok = 0; 252 return 0; 253 } 254 255 256 void 257 ipf_p_ftp_setpending(ipf_main_softc_t *softc, ftpinfo_t *ftp) 258 { 259 if (ftp->ftp_pendnat != NULL) 260 ipf_nat_setpending(softc, ftp->ftp_pendnat); 261 262 if (ftp->ftp_pendstate != NULL) { 263 READ_ENTER(&softc->ipf_state); 264 ipf_state_setpending(softc, ftp->ftp_pendstate); 265 RWLOCK_EXIT(&softc->ipf_state); 266 } 267 } 268 269 270 void 271 ipf_p_ftp_del(ipf_main_softc_t *softc, 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 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 if (nat->nat_v[0] == 6) { 491 #ifndef USE_INET6 492 return APR_INC(inc); 493 #endif 494 } 495 496 /* 497 * Add skeleton NAT entry for connection which will come back the 498 * other way. 499 */ 500 #ifdef USE_INET6 501 if (nat->nat_v[0] == 6) { 502 if (nat->nat_dir == NAT_OUTBOUND) { 503 nat2 = ipf_nat6_outlookup(&fi, IPN_TCP|NAT_SEARCH, 504 nat->nat_pr[1], 505 &nat->nat_osrc6.in6, 506 &nat->nat_odst6.in6); 507 } else { 508 nat2 = ipf_nat6_inlookup(&fi, IPN_TCP|NAT_SEARCH, 509 nat->nat_pr[0], 510 &nat->nat_odst6.in6, 511 &nat->nat_osrc6.in6); 512 } 513 } else 514 #endif 515 { 516 if (nat->nat_dir == NAT_OUTBOUND) { 517 nat2 = ipf_nat_outlookup(&fi, IPN_TCP|NAT_SEARCH, 518 nat->nat_pr[1], 519 nat->nat_osrcip, 520 nat->nat_odstip); 521 } else { 522 nat2 = ipf_nat_inlookup(&fi, IPN_TCP|NAT_SEARCH, 523 nat->nat_pr[0], 524 nat->nat_odstip, 525 nat->nat_osrcip); 526 } 527 } 528 if (nat2 != NULL) 529 return APR_INC(inc); 530 531 ipn = ipf_proxy_rule_rev(nat); 532 if (ipn == NULL) 533 return APR_ERR(1); 534 ipn->in_use = 0; 535 536 fi.fin_fr = &ftppxyfr; 537 fi.fin_dp = (char *)tcp2; 538 fi.fin_dlen = sizeof(*tcp2); 539 fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); 540 fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; 541 fi.fin_data[1] = sp; 542 fi.fin_data[0] = 0; 543 544 bzero((char *)tcp2, sizeof(*tcp2)); 545 tcp2->th_sport = 0; 546 tcp2->th_dport = htons(sp); 547 548 tcp2->th_win = htons(8192); 549 TCP_OFF_A(tcp2, 5); 550 tcp2->th_flags = TH_SYN; 551 552 if (nat->nat_dir == NAT_INBOUND) { 553 fi.fin_out = 1; 554 direction = NAT_OUTBOUND; 555 } else { 556 fi.fin_out = 0; 557 direction = NAT_INBOUND; 558 } 559 flags = SI_W_SPORT|NAT_SLAVE|IPN_TCP; 560 561 MUTEX_ENTER(&softn->ipf_nat_new); 562 if (nat->nat_v[0] == 6) { 563 #ifdef USE_INET6 564 nat2 = ipf_nat6_add(&fi, ipn, &ftp->ftp_pendnat, flags, 565 direction); 566 #endif 567 } else { 568 nat2 = ipf_nat_add(&fi, ipn, &ftp->ftp_pendnat, flags, 569 direction); 570 } 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, nat_t *nat, 595 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 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 = NULL; 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 if (nat->nat_v[0] == 6) { 887 #ifdef USE_INET6 888 nat2 = ipf_nat6_add(&fi, ipn, &ftp->ftp_pendnat, 889 nflags, nat->nat_dir); 890 #endif 891 } else { 892 nat2 = ipf_nat_add(&fi, ipn, &ftp->ftp_pendnat, 893 nflags, nat->nat_dir); 894 } 895 MUTEX_EXIT(&softn->ipf_nat_new); 896 897 if (nat2 == NULL) { 898 KFREES(ipn, ipn->in_size); 899 return APR_ERR(1); 900 } 901 902 (void) ipf_nat_proto(&fi, nat2, IPN_TCP); 903 MUTEX_ENTER(&nat2->nat_lock); 904 ipf_nat_update(&fi, nat2); 905 MUTEX_EXIT(&nat2->nat_lock); 906 fi.fin_ifp = NULL; 907 if (nat->nat_dir == NAT_INBOUND) { 908 if (nat->nat_v[0] == 6) { 909 #ifdef USE_INET6 910 fi.fin_dst6 = nat->nat_ndst6; 911 #endif 912 } else { 913 fi.fin_daddr = nat->nat_ndstaddr; 914 } 915 } 916 if (ipf_state_add(softc, &fi, (ipstate_t **)&ftp->ftp_pendstate, 917 SI_W_SPORT) != 0) 918 ipf_nat_setpending(softc, nat2); 919 920 #if !defined(_KERNEL) 921 M_ADJ(m, inc); 922 #else 923 /* 924 * m_adj takes care of pkthdr.len, if required and treats inc<0 to 925 * mean remove -len bytes from the end of the packet. 926 * The mbuf chain will be extended if necessary by m_copyback(). 927 */ 928 if (inc < 0) 929 M_ADJ(m, inc); 930 #endif /* !defined(_KERNEL) */ 931 COPYBACK(m, off, nlen, newmsg); 932 fin->fin_flx |= FI_DOCKSUM; 933 934 if (inc != 0) { 935 fin->fin_plen += inc; 936 fin->fin_dlen += inc; 937 if (nat->nat_v[0] == 6) { 938 #ifdef USE_INET6 939 ip6 = (ip6_t *)fin->fin_ip; 940 u_short len = ntohs(ip6->ip6_plen) + inc; 941 ip6->ip6_plen = htons(len); 942 #endif 943 } else { 944 ip->ip_len = htons(fin->fin_plen); 945 } 946 } 947 948 return APR_INC(inc); 949 } 950 951 952 int 953 ipf_p_ftp_server(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat, 954 ftpinfo_t *ftp, int dlen) 955 { 956 char *rptr, *wptr; 957 ftpside_t *f; 958 int inc; 959 960 inc = 0; 961 f = &ftp->ftp_side[1]; 962 rptr = f->ftps_rptr; 963 wptr = f->ftps_wptr; 964 965 DT2(ftp_server_response, char *, rptr, int, ftp->ftp_passok); 966 if (*rptr == ' ') 967 goto server_cmd_ok; 968 if (!ISDIGIT(*rptr) || !ISDIGIT(*(rptr + 1)) || !ISDIGIT(*(rptr + 2))) 969 return 0; 970 if (softf->ipf_p_ftp_debug & DEBUG_PARSE) 971 printf("ipf_p_ftp_server_1: cmd[%4.4s] passok %d\n", 972 rptr, ftp->ftp_passok); 973 if (ftp->ftp_passok == FTPXY_GO) { 974 if (!strncmp(rptr, "227 ", 4)) 975 inc = ipf_p_ftp_pasv(softf, fin, ip, nat, ftp, dlen); 976 else if (!strncmp(rptr, "229 ", 4)) 977 inc = ipf_p_ftp_epsv(softf, fin, ip, nat, ftp, dlen); 978 else if (strncmp(rptr, "200", 3)) { 979 /* 980 * 200 is returned for a successful command. 981 */ 982 ; 983 } 984 } else if (softf->ipf_p_ftp_insecure && !strncmp(rptr, "227 ", 4)) { 985 inc = ipf_p_ftp_pasv(softf, fin, ip, nat, ftp, dlen); 986 } else if (softf->ipf_p_ftp_insecure && !strncmp(rptr, "229 ", 4)) { 987 inc = ipf_p_ftp_epsv(softf, fin, ip, nat, ftp, dlen); 988 } else if (*rptr == '5' || *rptr == '4') 989 ftp->ftp_passok = FTPXY_INIT; 990 else if (ftp->ftp_incok) { 991 if (*rptr == '3') { 992 if (ftp->ftp_passok == FTPXY_ACCT_1) 993 ftp->ftp_passok = FTPXY_GO; 994 else 995 ftp->ftp_passok++; 996 } else if (*rptr == '2') { 997 switch (ftp->ftp_passok) 998 { 999 case FTPXY_USER_1 : 1000 case FTPXY_USER_2 : 1001 case FTPXY_PASS_1 : 1002 case FTPXY_PASS_2 : 1003 case FTPXY_ACCT_1 : 1004 ftp->ftp_passok = FTPXY_GO; 1005 break; 1006 default : 1007 ftp->ftp_passok += 3; 1008 break; 1009 } 1010 } 1011 } 1012 ftp->ftp_incok = 0; 1013 server_cmd_ok: 1014 if (softf->ipf_p_ftp_debug & DEBUG_PARSE) 1015 printf("ipf_p_ftp_server_2: cmd[%4.4s] passok %d\n", 1016 rptr, ftp->ftp_passok); 1017 DT3(ftp_server_passok, char *,rptr, int, ftp->ftp_incok, 1018 int, ftp->ftp_passok); 1019 1020 while ((*rptr++ != '\n') && (rptr < wptr)) 1021 ; 1022 f->ftps_rptr = rptr; 1023 return inc; 1024 } 1025 1026 1027 /* 1028 * 0 FTPXY_JUNK_OK 1029 * 1 FTPXY_JUNK_BAD 1030 * 2 FTPXY_JUNK_EOL 1031 * 3 FTPXY_JUNK_CONT 1032 * 1033 * Look to see if the buffer starts with something which we recognise as 1034 * being the correct syntax for the FTP protocol. 1035 */ 1036 int 1037 ipf_p_ftp_client_valid(ipf_ftp_softc_t *softf, ftpside_t *ftps, char *buf, 1038 size_t len) 1039 { 1040 register char *s, c, pc; 1041 register size_t i = len; 1042 char cmd[5]; 1043 1044 s = buf; 1045 1046 if (ftps->ftps_junk == FTPXY_JUNK_BAD) 1047 return FTPXY_JUNK_BAD; 1048 1049 if (i < 5) { 1050 DT1(client_valid, int, i); 1051 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) 1052 printf("ipf_p_ftp_client_valid:i(%d) < 5\n", (int)i); 1053 return 2; 1054 } 1055 1056 i--; 1057 c = *s++; 1058 1059 if (ISALPHA(c)) { 1060 cmd[0] = TOUPPER(c); 1061 c = *s++; 1062 i--; 1063 if (ISALPHA(c)) { 1064 cmd[1] = TOUPPER(c); 1065 c = *s++; 1066 i--; 1067 if (ISALPHA(c)) { 1068 cmd[2] = TOUPPER(c); 1069 c = *s++; 1070 i--; 1071 if (ISALPHA(c)) { 1072 cmd[3] = TOUPPER(c); 1073 c = *s++; 1074 i--; 1075 if ((c != ' ') && (c != '\r')) 1076 goto bad_client_command; 1077 } else if ((c != ' ') && (c != '\r')) 1078 goto bad_client_command; 1079 } else 1080 goto bad_client_command; 1081 } else 1082 goto bad_client_command; 1083 } else { 1084 bad_client_command: 1085 DT4(client_junk, int, len, int, i, int, c, char *, buf); 1086 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 1087 printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*.*s]\n", 1088 "ipf_p_ftp_client_valid", 1089 ftps->ftps_junk, (int)len, (int)i, c, 1090 (int)len, (int)len, buf); 1091 return FTPXY_JUNK_BAD; 1092 } 1093 1094 for (; i; i--) { 1095 pc = c; 1096 c = *s++; 1097 if ((pc == '\r') && (c == '\n')) { 1098 cmd[4] = '\0'; 1099 if (!strcmp(cmd, "PASV")) { 1100 ftps->ftps_cmd = FTPXY_C_PASV; 1101 } else if (!strcmp(cmd, "EPSV")) { 1102 ftps->ftps_cmd = FTPXY_C_EPSV; 1103 } else { 1104 ftps->ftps_cmd = 0; 1105 } 1106 return 0; 1107 } 1108 } 1109 #if !defined(_KERNEL) 1110 printf("ipf_p_ftp_client_valid:junk after cmd[%*.*s]\n", 1111 (int)len, (int)len, buf); 1112 #endif 1113 return FTPXY_JUNK_EOL; 1114 } 1115 1116 1117 int 1118 ipf_p_ftp_server_valid(ipf_ftp_softc_t *softf, ftpside_t *ftps, char *buf, 1119 size_t len) 1120 { 1121 register char *s, c, pc; 1122 register size_t i = len; 1123 int cmd; 1124 1125 s = buf; 1126 cmd = 0; 1127 1128 if (ftps->ftps_junk == FTPXY_JUNK_BAD) 1129 return FTPXY_JUNK_BAD; 1130 1131 if (i < 5) { 1132 DT1(server_valid, int, i); 1133 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 1134 printf("ipf_p_ftp_servert_valid:i(%d) < 5\n", (int)i); 1135 return 2; 1136 } 1137 1138 c = *s++; 1139 i--; 1140 if (c == ' ') { 1141 cmd = -1; 1142 goto search_eol; 1143 } 1144 1145 if (ISDIGIT(c)) { 1146 cmd = (c - '0') * 100; 1147 c = *s++; 1148 i--; 1149 if (ISDIGIT(c)) { 1150 cmd += (c - '0') * 10; 1151 c = *s++; 1152 i--; 1153 if (ISDIGIT(c)) { 1154 cmd += (c - '0'); 1155 c = *s++; 1156 i--; 1157 if ((c != '-') && (c != ' ')) 1158 goto bad_server_command; 1159 if (c == '-') 1160 return FTPXY_JUNK_CONT; 1161 } else 1162 goto bad_server_command; 1163 } else 1164 goto bad_server_command; 1165 } else { 1166 bad_server_command: 1167 DT4(server_junk, int len, buf, int, i, int, c, char *, buf); 1168 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_INFO) 1169 printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*.*s]\n", 1170 "ipf_p_ftp_server_valid", 1171 ftps->ftps_junk, (int)len, (int)i, 1172 c, (int)len, (int)len, buf); 1173 if (ftps->ftps_junk == FTPXY_JUNK_CONT) 1174 return FTPXY_JUNK_CONT; 1175 return FTPXY_JUNK_BAD; 1176 } 1177 search_eol: 1178 for (; i; i--) { 1179 pc = c; 1180 c = *s++; 1181 if ((pc == '\r') && (c == '\n')) { 1182 if (cmd == -1) { 1183 if (ftps->ftps_junk == FTPXY_JUNK_CONT) 1184 return FTPXY_JUNK_CONT; 1185 } else { 1186 ftps->ftps_cmd = cmd; 1187 } 1188 return FTPXY_JUNK_OK; 1189 } 1190 } 1191 1192 DT2(junk_eol, int, len, char *, buf); 1193 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_INFO) 1194 printf("ipf_p_ftp_server_valid:junk after cmd[%*.*s]\n", 1195 (int)len, (int)len, buf); 1196 return FTPXY_JUNK_EOL; 1197 } 1198 1199 1200 int 1201 ipf_p_ftp_valid(ipf_ftp_softc_t *softf, ftpinfo_t *ftp, int side, char *buf, 1202 size_t len) 1203 { 1204 ftpside_t *ftps; 1205 int ret; 1206 1207 ftps = &ftp->ftp_side[side]; 1208 1209 if (side == 0) 1210 ret = ipf_p_ftp_client_valid(softf, ftps, buf, len); 1211 else 1212 ret = ipf_p_ftp_server_valid(softf, ftps, buf, len); 1213 return ret; 1214 } 1215 1216 1217 /* 1218 * For map rules, the following applies: 1219 * rv == 0 for outbound processing, 1220 * rv == 1 for inbound processing. 1221 * For rdr rules, the following applies: 1222 * rv == 0 for inbound processing, 1223 * rv == 1 for outbound processing. 1224 */ 1225 int 1226 ipf_p_ftp_process(ipf_ftp_softc_t *softf, fr_info_t *fin, nat_t *nat, 1227 ftpinfo_t *ftp, int rv) 1228 { 1229 int mlen, len, off, inc, i, sel, sel2, ok, ackoff, seqoff, retry; 1230 char *rptr, *wptr, *s; 1231 u_32_t thseq, thack; 1232 ap_session_t *aps; 1233 ftpside_t *f, *t; 1234 tcphdr_t *tcp; 1235 ip_t *ip; 1236 mb_t *m; 1237 1238 m = fin->fin_m; 1239 ip = fin->fin_ip; 1240 tcp = (tcphdr_t *)fin->fin_dp; 1241 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 1242 1243 f = &ftp->ftp_side[rv]; 1244 t = &ftp->ftp_side[1 - rv]; 1245 thseq = ntohl(tcp->th_seq); 1246 thack = ntohl(tcp->th_ack); 1247 #ifdef __sgi 1248 mlen = fin->fin_plen - off; 1249 #else 1250 mlen = MSGDSIZE(m) - off; 1251 #endif 1252 1253 DT3(process_debug, tcphdr_t *, tcp, int, off, int, mlen); 1254 if (softf->ipf_p_ftp_debug & DEBUG_INFO) 1255 printf("ipf_p_ftp_process: %d:%d,%d, mlen %d flags %x\n", 1256 fin->fin_out, fin->fin_sport, fin->fin_dport, 1257 mlen, tcp->th_flags); 1258 1259 if ((mlen == 0) && ((tcp->th_flags & TH_OPENING) == TH_OPENING)) { 1260 f->ftps_seq[0] = thseq + 1; 1261 t->ftps_seq[0] = thack; 1262 return 0; 1263 } else if (mlen < 0) { 1264 return 0; 1265 } 1266 1267 aps = nat->nat_aps; 1268 1269 sel = aps->aps_sel[1 - rv]; 1270 sel2 = aps->aps_sel[rv]; 1271 if (rv == 1) { 1272 seqoff = aps->aps_seqoff[sel]; 1273 if (aps->aps_seqmin[sel] > seqoff + thseq) 1274 seqoff = aps->aps_seqoff[!sel]; 1275 ackoff = aps->aps_ackoff[sel2]; 1276 if (aps->aps_ackmin[sel2] > ackoff + thack) 1277 ackoff = aps->aps_ackoff[!sel2]; 1278 } else { 1279 seqoff = aps->aps_ackoff[sel]; 1280 if (softf->ipf_p_ftp_debug & DEBUG_INFO) 1281 printf("seqoff %d thseq %x ackmin %x\n", seqoff, thseq, 1282 aps->aps_ackmin[sel]); 1283 if (aps->aps_ackmin[sel] > seqoff + thseq) 1284 seqoff = aps->aps_ackoff[!sel]; 1285 1286 ackoff = aps->aps_seqoff[sel2]; 1287 if (softf->ipf_p_ftp_debug & DEBUG_INFO) 1288 printf("ackoff %d thack %x seqmin %x\n", ackoff, thack, 1289 aps->aps_seqmin[sel2]); 1290 if (ackoff > 0) { 1291 if (aps->aps_seqmin[sel2] > ackoff + thack) 1292 ackoff = aps->aps_seqoff[!sel2]; 1293 } else { 1294 if (aps->aps_seqmin[sel2] > thack) 1295 ackoff = aps->aps_seqoff[!sel2]; 1296 } 1297 } 1298 if (softf->ipf_p_ftp_debug & DEBUG_INFO) { 1299 printf("%s: %x seq %x/%d ack %x/%d len %d/%d off %d\n", 1300 rv ? "IN" : "OUT", tcp->th_flags, thseq, seqoff, 1301 thack, ackoff, mlen, fin->fin_plen, off); 1302 printf("sel %d seqmin %x/%x offset %d/%d\n", sel, 1303 aps->aps_seqmin[sel], aps->aps_seqmin[sel2], 1304 aps->aps_seqoff[sel], aps->aps_seqoff[sel2]); 1305 printf("sel %d ackmin %x/%x offset %d/%d\n", sel2, 1306 aps->aps_ackmin[sel], aps->aps_ackmin[sel2], 1307 aps->aps_ackoff[sel], aps->aps_ackoff[sel2]); 1308 } 1309 1310 /* 1311 * XXX - Ideally, this packet should get dropped because we now know 1312 * that it is out of order (and there is no real danger in doing so 1313 * apart from causing packets to go through here ordered). 1314 */ 1315 if (softf->ipf_p_ftp_debug & DEBUG_INFO) { 1316 printf("rv %d t:seq[0] %x seq[1] %x %d/%d\n", 1317 rv, t->ftps_seq[0], t->ftps_seq[1], seqoff, ackoff); 1318 } 1319 1320 ok = 0; 1321 if (t->ftps_seq[0] == 0) { 1322 t->ftps_seq[0] = thack; 1323 ok = 1; 1324 } else { 1325 if (ackoff == 0) { 1326 if (t->ftps_seq[0] == thack) 1327 ok = 1; 1328 else if (t->ftps_seq[1] == thack) { 1329 t->ftps_seq[0] = thack; 1330 ok = 1; 1331 } 1332 } else { 1333 if (t->ftps_seq[0] + ackoff == thack) { 1334 t->ftps_seq[0] = thack; 1335 ok = 1; 1336 } else if (t->ftps_seq[0] == thack + ackoff) { 1337 t->ftps_seq[0] = thack + ackoff; 1338 ok = 1; 1339 } else if (t->ftps_seq[1] + ackoff == thack) { 1340 t->ftps_seq[0] = thack; 1341 ok = 1; 1342 } else if (t->ftps_seq[1] == thack + ackoff) { 1343 t->ftps_seq[0] = thack + ackoff; 1344 ok = 1; 1345 } 1346 } 1347 } 1348 1349 if (softf->ipf_p_ftp_debug & DEBUG_INFO) { 1350 if (!ok) 1351 printf("%s ok\n", "not"); 1352 } 1353 1354 if (!mlen) { 1355 if (t->ftps_seq[0] + ackoff != thack && 1356 t->ftps_seq[1] + ackoff != thack) { 1357 DT3(thack, ftpside_t *t, t, int, ackoff, u_32_t, thack); 1358 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) { 1359 printf("%s:seq[0](%u) + (%d) != (%u)\n", 1360 "ipf_p_ftp_process", t->ftps_seq[0], 1361 ackoff, thack); 1362 printf("%s:seq[0](%u) + (%d) != (%u)\n", 1363 "ipf_p_ftp_process", t->ftps_seq[1], 1364 ackoff, thack); 1365 } 1366 return APR_ERR(1); 1367 } 1368 1369 if (softf->ipf_p_ftp_debug & DEBUG_PARSE) { 1370 printf("ipf_p_ftp_process:f:seq[0] %x seq[1] %x\n", 1371 f->ftps_seq[0], f->ftps_seq[1]); 1372 } 1373 1374 if (tcp->th_flags & TH_FIN) { 1375 if (thseq == f->ftps_seq[1]) { 1376 f->ftps_seq[0] = f->ftps_seq[1] - seqoff; 1377 f->ftps_seq[1] = thseq + 1 - seqoff; 1378 } else { 1379 DT2(thseq, ftpside_t *t, t, u_32_t, thseq); 1380 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) { 1381 printf("FIN: thseq %x seqoff %d ftps_seq %x\n", 1382 thseq, seqoff, f->ftps_seq[0]); 1383 } 1384 return APR_ERR(1); 1385 } 1386 } 1387 f->ftps_len = 0; 1388 return 0; 1389 } 1390 1391 ok = 0; 1392 if ((thseq == f->ftps_seq[0]) || (thseq == f->ftps_seq[1])) { 1393 ok = 1; 1394 /* 1395 * Retransmitted data packet. 1396 */ 1397 } else if ((thseq + mlen == f->ftps_seq[0]) || 1398 (thseq + mlen == f->ftps_seq[1])) { 1399 ok = 1; 1400 } 1401 1402 if (ok == 0) { 1403 DT3(ok_0, ftpside_t *, f, u_32_t, thseq, int, mlen); 1404 inc = thseq - f->ftps_seq[0]; 1405 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) { 1406 printf("inc %d sel %d rv %d\n", inc, sel, rv); 1407 printf("th_seq %x ftps_seq %x/%x\n", 1408 thseq, f->ftps_seq[0], f->ftps_seq[1]); 1409 printf("ackmin %x ackoff %d\n", aps->aps_ackmin[sel], 1410 aps->aps_ackoff[sel]); 1411 printf("seqmin %x seqoff %d\n", aps->aps_seqmin[sel], 1412 aps->aps_seqoff[sel]); 1413 } 1414 1415 return APR_ERR(1); 1416 } 1417 1418 inc = 0; 1419 rptr = f->ftps_rptr; 1420 wptr = f->ftps_wptr; 1421 f->ftps_seq[0] = thseq; 1422 f->ftps_seq[1] = f->ftps_seq[0] + mlen; 1423 f->ftps_len = mlen; 1424 1425 while (mlen > 0) { 1426 len = MIN(mlen, sizeof(f->ftps_buf) - (wptr - rptr)); 1427 if (len == 0) 1428 break; 1429 COPYDATA(m, off, len, wptr); 1430 mlen -= len; 1431 off += len; 1432 wptr += len; 1433 1434 whilemore: 1435 if (softf->ipf_p_ftp_debug & DEBUG_PARSE) 1436 printf("%s:len %d/%d off %d wptr %lx junk %d [%*.*s]\n", 1437 "ipf_p_ftp_process", 1438 len, mlen, off, (u_long)wptr, f->ftps_junk, 1439 len, len, rptr); 1440 1441 f->ftps_wptr = wptr; 1442 if (f->ftps_junk != FTPXY_JUNK_OK) { 1443 i = f->ftps_junk; 1444 f->ftps_junk = ipf_p_ftp_valid(softf, ftp, rv, rptr, 1445 wptr - rptr); 1446 DT2(junk_transit, int, i, int, f->ftps_junk); 1447 1448 if (softf->ipf_p_ftp_debug & DEBUG_PARSE) 1449 printf("%s:junk %d -> %d\n", 1450 "ipf_p_ftp_process", i, f->ftps_junk); 1451 1452 if (f->ftps_junk == FTPXY_JUNK_BAD) { 1453 DT(buffer_full); 1454 if (wptr - rptr == sizeof(f->ftps_buf)) { 1455 if (softf->ipf_p_ftp_debug & 1456 DEBUG_PARSE_INFO) 1457 printf("%s:full buffer\n", 1458 "ipf_p_ftp_process"); 1459 f->ftps_rptr = f->ftps_buf; 1460 f->ftps_wptr = f->ftps_buf; 1461 rptr = f->ftps_rptr; 1462 wptr = f->ftps_wptr; 1463 continue; 1464 } 1465 } 1466 } 1467 1468 while ((f->ftps_junk == FTPXY_JUNK_OK) && (wptr > rptr)) { 1469 len = wptr - rptr; 1470 f->ftps_junk = ipf_p_ftp_valid(softf, ftp, rv, 1471 rptr, len); 1472 1473 if (softf->ipf_p_ftp_debug & DEBUG_PARSE) { 1474 printf("%s=%d len %d rv %d ptr %lx/%lx ", 1475 "ipf_p_ftp_valid", 1476 f->ftps_junk, len, rv, (u_long)rptr, 1477 (u_long)wptr); 1478 printf("buf [%*.*s]\n", len, len, rptr); 1479 } 1480 1481 if (f->ftps_junk == FTPXY_JUNK_OK) { 1482 f->ftps_cmds++; 1483 f->ftps_rptr = rptr; 1484 if (rv) 1485 inc += ipf_p_ftp_server(softf, fin, ip, 1486 nat, ftp, len); 1487 else 1488 inc += ipf_p_ftp_client(softf, fin, ip, 1489 nat, ftp, len); 1490 rptr = f->ftps_rptr; 1491 wptr = f->ftps_wptr; 1492 } 1493 } 1494 1495 /* 1496 * Off to a bad start so lets just forget about using the 1497 * ftp proxy for this connection. 1498 */ 1499 if ((f->ftps_cmds == 0) && (f->ftps_junk == FTPXY_JUNK_BAD)) { 1500 /* f->ftps_seq[1] += inc; */ 1501 1502 DT(ftp_junk_cmd); 1503 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) 1504 printf("%s:cmds == 0 junk == 1\n", 1505 "ipf_p_ftp_process"); 1506 return APR_ERR(2); 1507 } 1508 1509 retry = 0; 1510 if ((f->ftps_junk != FTPXY_JUNK_OK) && (rptr < wptr)) { 1511 for (s = rptr; s < wptr; s++) { 1512 if ((*s == '\r') && (s + 1 < wptr) && 1513 (*(s + 1) == '\n')) { 1514 rptr = s + 2; 1515 retry = 1; 1516 if (f->ftps_junk != FTPXY_JUNK_CONT) 1517 f->ftps_junk = FTPXY_JUNK_OK; 1518 break; 1519 } 1520 } 1521 } 1522 1523 if (rptr == wptr) { 1524 rptr = wptr = f->ftps_buf; 1525 } else { 1526 /* 1527 * Compact the buffer back to the start. The junk 1528 * flag should already be set and because we're not 1529 * throwing away any data, it is preserved from its 1530 * current state. 1531 */ 1532 if (rptr > f->ftps_buf) { 1533 bcopy(rptr, f->ftps_buf, wptr - rptr); 1534 wptr -= rptr - f->ftps_buf; 1535 rptr = f->ftps_buf; 1536 } 1537 } 1538 f->ftps_rptr = rptr; 1539 f->ftps_wptr = wptr; 1540 if (retry) 1541 goto whilemore; 1542 } 1543 1544 /* f->ftps_seq[1] += inc; */ 1545 if (tcp->th_flags & TH_FIN) 1546 f->ftps_seq[1]++; 1547 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_INFO) { 1548 #ifdef __sgi 1549 mlen = fin->fin_plen; 1550 #else 1551 mlen = MSGDSIZE(m); 1552 #endif 1553 mlen -= off; 1554 printf("ftps_seq[1] = %x inc %d len %d\n", 1555 f->ftps_seq[1], inc, mlen); 1556 } 1557 1558 f->ftps_rptr = rptr; 1559 f->ftps_wptr = wptr; 1560 return APR_INC(inc); 1561 } 1562 1563 1564 int 1565 ipf_p_ftp_out(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) 1566 { 1567 ipf_ftp_softc_t *softf = arg; 1568 ftpinfo_t *ftp; 1569 int rev; 1570 1571 ftp = aps->aps_data; 1572 if (ftp == NULL) 1573 return 0; 1574 1575 rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; 1576 if (ftp->ftp_side[1 - rev].ftps_ifp == NULL) 1577 ftp->ftp_side[1 - rev].ftps_ifp = fin->fin_ifp; 1578 1579 return ipf_p_ftp_process(softf, fin, nat, ftp, rev); 1580 } 1581 1582 1583 int 1584 ipf_p_ftp_in(void *arg, fr_info_t *fin, ap_session_t *aps, nat_t *nat) 1585 { 1586 ipf_ftp_softc_t *softf = arg; 1587 ftpinfo_t *ftp; 1588 int rev; 1589 1590 ftp = aps->aps_data; 1591 if (ftp == NULL) 1592 return 0; 1593 1594 rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; 1595 if (ftp->ftp_side[rev].ftps_ifp == NULL) 1596 ftp->ftp_side[rev].ftps_ifp = fin->fin_ifp; 1597 1598 return ipf_p_ftp_process(softf, fin, nat, ftp, 1 - rev); 1599 } 1600 1601 1602 /* 1603 * ipf_p_ftp_atoi - implement a version of atoi which processes numbers in 1604 * pairs separated by commas (which are expected to be in the range 0 - 255), 1605 * returning a 16 bit number combining either side of the , as the MSB and 1606 * LSB. 1607 */ 1608 u_short 1609 ipf_p_ftp_atoi(char **ptr) 1610 { 1611 register char *s = *ptr, c; 1612 register u_char i = 0, j = 0; 1613 1614 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1615 i *= 10; 1616 i += c - '0'; 1617 } 1618 if (c != ',') { 1619 *ptr = NULL; 1620 return 0; 1621 } 1622 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1623 j *= 10; 1624 j += c - '0'; 1625 } 1626 *ptr = s; 1627 i &= 0xff; 1628 j &= 0xff; 1629 return (i << 8) | j; 1630 } 1631 1632 1633 int 1634 ipf_p_ftp_eprt(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat, 1635 ftpinfo_t *ftp, int dlen) 1636 { 1637 ftpside_t *f; 1638 1639 /* 1640 * Check for client sending out EPRT message. 1641 */ 1642 if (dlen < IPF_MINEPRTLEN) { 1643 DT1(epert_dlen, int, dlen); 1644 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 1645 printf("ipf_p_ftp_eprt:dlen(%d) < IPF_MINEPRTLEN\n", 1646 dlen); 1647 return 0; 1648 } 1649 1650 /* 1651 * Parse the EPRT command. Format is: 1652 * "EPRT |1|1.2.3.4|2000|" for IPv4 and 1653 * "EPRT |2|ef00::1:2|2000|" for IPv6 1654 */ 1655 f = &ftp->ftp_side[0]; 1656 if (f->ftps_rptr[5] != '|') 1657 return 0; 1658 if (f->ftps_rptr[5] == f->ftps_rptr[7]) { 1659 if (f->ftps_rptr[6] == '1' && nat->nat_v[0] == 4) 1660 return ipf_p_ftp_eprt4(softf, fin, ip, nat, ftp, dlen); 1661 #ifdef USE_INET6 1662 if (f->ftps_rptr[6] == '2' && nat->nat_v[0] == 6) 1663 return ipf_p_ftp_eprt6(softf, fin, ip, nat, ftp, dlen); 1664 #endif 1665 } 1666 return 0; 1667 } 1668 1669 1670 int 1671 ipf_p_ftp_eprt4(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat, 1672 ftpinfo_t *ftp, int dlen) 1673 { 1674 int a1, a2, a3, a4, port, olen, nlen, inc, off; 1675 char newbuf[IPF_FTPBUFSZ]; 1676 char *s, c, delim; 1677 u_32_t addr, i; 1678 tcphdr_t *tcp; 1679 ftpside_t *f; 1680 mb_t *m; 1681 1682 m = fin->fin_m; 1683 tcp = (tcphdr_t *)fin->fin_dp; 1684 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 1685 f = &ftp->ftp_side[0]; 1686 delim = f->ftps_rptr[5]; 1687 s = f->ftps_rptr + 8; 1688 1689 /* 1690 * get the IP address. 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 = (i << 24); 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 << 16); 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 != '.') 1722 return 0; 1723 addr |= (addr << 8); 1724 1725 i = 0; 1726 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1727 i *= 10; 1728 i += c - '0'; 1729 } 1730 if (i > 255) 1731 return 0; 1732 if (c != delim) 1733 return 0; 1734 addr |= addr; 1735 1736 /* 1737 * Get the port number 1738 */ 1739 i = 0; 1740 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1741 i *= 10; 1742 i += c - '0'; 1743 } 1744 if (i > 65535) 1745 return 0; 1746 if (c != delim) 1747 return 0; 1748 port = i; 1749 1750 /* 1751 * Check for CR-LF at the end of the command string. 1752 */ 1753 if ((*s != '\r') || (*(s + 1) != '\n')) { 1754 DT(eprt4_no_crlf); 1755 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 1756 printf("ipf_p_ftp_eprt4:missing %s\n", "cr-lf"); 1757 return 0; 1758 } 1759 s += 2; 1760 1761 /* 1762 * Calculate new address parts for PORT command 1763 */ 1764 if (nat->nat_dir == NAT_INBOUND) 1765 a1 = ntohl(nat->nat_odstaddr); 1766 else 1767 a1 = ntohl(ip->ip_src.s_addr); 1768 a2 = (a1 >> 16) & 0xff; 1769 a3 = (a1 >> 8) & 0xff; 1770 a4 = a1 & 0xff; 1771 a1 >>= 24; 1772 olen = s - f->ftps_rptr; 1773 /* 1774 * While we could force the use of | as a delimiter here, it makes 1775 * sense to preserve whatever character is being used by the systems 1776 * involved in the communication. 1777 */ 1778 snprintf(newbuf, sizeof(newbuf), "%s %c1%c%u.%u.%u.%u%c%u%c\r\n", 1779 "EPRT", delim, delim, a1, a2, a3, a4, delim, port, delim); 1780 1781 nlen = strlen(newbuf); 1782 inc = nlen - olen; 1783 if ((inc + fin->fin_plen) > 65535) { 1784 DT2(eprt4_len, int, inc, int, fin->fin_plen); 1785 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) 1786 printf("ipf_p_ftp_eprt4:inc(%d) + ip->ip_len > 65535\n", 1787 inc); 1788 return 0; 1789 } 1790 1791 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 1792 #if !defined(_KERNEL) 1793 M_ADJ(m, inc); 1794 #else 1795 if (inc < 0) 1796 M_ADJ(m, inc); 1797 #endif 1798 /* the mbuf chain will be extended if necessary by m_copyback() */ 1799 COPYBACK(m, off, nlen, newbuf); 1800 fin->fin_flx |= FI_DOCKSUM; 1801 1802 if (inc != 0) { 1803 fin->fin_plen += inc; 1804 ip->ip_len = htons(fin->fin_plen); 1805 fin->fin_dlen += inc; 1806 } 1807 1808 f->ftps_cmd = FTPXY_C_EPRT; 1809 return ipf_p_ftp_addport(softf, fin, ip, nat, ftp, dlen, port, inc); 1810 } 1811 1812 1813 int 1814 ipf_p_ftp_epsv(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, nat_t *nat, 1815 ftpinfo_t *ftp, int dlen) 1816 { 1817 char newbuf[IPF_FTPBUFSZ]; 1818 u_short ap = 0; 1819 ftpside_t *f; 1820 char *s; 1821 1822 if ((softf->ipf_p_ftp_forcepasv != 0) && 1823 (ftp->ftp_side[0].ftps_cmd != FTPXY_C_EPSV)) { 1824 DT1(epsv_cmd, int, ftp->ftp_side[0].ftps_cmd); 1825 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 1826 printf("ipf_p_ftp_epsv:ftps_cmd(%d) != FTPXY_C_EPSV\n", 1827 ftp->ftp_side[0].ftps_cmd); 1828 return 0; 1829 } 1830 f = &ftp->ftp_side[1]; 1831 1832 #define EPSV_REPLEN 33 1833 /* 1834 * Check for EPSV reply message. 1835 */ 1836 if (dlen < IPF_MIN229LEN) { 1837 return (0); 1838 } else if (strncmp(f->ftps_rptr, 1839 "229 Entering Extended Passive Mode", EPSV_REPLEN)) { 1840 return (0); 1841 } 1842 1843 /* 1844 * Skip the EPSV command + space 1845 */ 1846 s = f->ftps_rptr + 33; 1847 while (*s && !ISDIGIT(*s)) 1848 s++; 1849 1850 /* 1851 * As per RFC 2428, there are no addres components in the EPSV 1852 * response. So we'll go straight to getting the port. 1853 */ 1854 while (*s && ISDIGIT(*s)) { 1855 ap *= 10; 1856 ap += *s++ - '0'; 1857 } 1858 1859 if (!s) { 1860 return 0; 1861 } 1862 1863 if (*s == '|') 1864 s++; 1865 if (*s == ')') 1866 s++; 1867 if (*s == '\n') 1868 s--; 1869 /* 1870 * check for CR-LF at the end. 1871 */ 1872 if ((*s != '\r') || (*(s + 1) != '\n')) { 1873 return 0; 1874 } 1875 s += 2; 1876 1877 snprintf(newbuf, sizeof(newbuf), "%s (|||%u|)\r\n", 1878 "229 Entering Extended Passive Mode", ap); 1879 1880 return ipf_p_ftp_pasvreply(softf, fin, ip, nat, ftp, (u_int)ap, 1881 newbuf, s); 1882 } 1883 1884 #ifdef USE_INET6 1885 int 1886 ipf_p_ftp_eprt6(ipf_ftp_softc_t *softf, fr_info_t *fin, ip_t *ip, 1887 nat_t *nat, ftpinfo_t *ftp, int dlen) 1888 { 1889 int port, olen, nlen, inc, off, left, i; 1890 char newbuf[IPF_FTPBUFSZ]; 1891 char *s, c; 1892 i6addr_t addr, *a6; 1893 tcphdr_t *tcp; 1894 ip6_t *ip6; 1895 char delim; 1896 u_short whole; 1897 u_short part; 1898 ftpside_t *f; 1899 u_short *t; 1900 int fwd; 1901 mb_t *m; 1902 u_32_t a; 1903 1904 m = fin->fin_m; 1905 ip6 = (ip6_t *)ip; 1906 f = &ftp->ftp_side[0]; 1907 s = f->ftps_rptr + 8; 1908 f = &ftp->ftp_side[0]; 1909 delim = f->ftps_rptr[5]; 1910 tcp = (tcphdr_t *)fin->fin_dp; 1911 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 1912 1913 addr.i6[0] = 0; 1914 addr.i6[1] = 0; 1915 addr.i6[2] = 0; 1916 addr.i6[3] = 0; 1917 /* 1918 * Parse an IPv6 address. 1919 * Go forward until either :: or | is found. If :: is found, 1920 * reverse direction. Direction change is performed to ease 1921 * parsing an unknown number of 0s in the middle. 1922 */ 1923 whole = 0; 1924 t = (u_short *)&addr; 1925 fwd = 1; 1926 for (part = 0; (c = *s) != '\0'; ) { 1927 if (c == delim) { 1928 *t = htons((u_short)whole); 1929 break; 1930 } 1931 if (c == ':') { 1932 *t = part; 1933 if (fwd) { 1934 *t = htons((u_short)whole); 1935 t++; 1936 } else { 1937 *t = htons((u_short)(whole >> 16)); 1938 t--; 1939 } 1940 whole = 0; 1941 if (fwd == 1 && s[1] == ':') { 1942 while (*s && *s != '|') 1943 s++; 1944 if ((c = *s) != delim) 1945 break; 1946 t = (u_short *)&addr.i6[3]; 1947 t++; 1948 fwd = 0; 1949 } else if (fwd == 0 && s[-1] == ':') { 1950 break; 1951 } 1952 } else { 1953 if (c >= '0' && c <= '9') { 1954 c -= '0'; 1955 } else if (c >= 'a' && c <= 'f') { 1956 c -= 'a' + 10; 1957 } else if (c >= 'A' && c <= 'F') { 1958 c -= 'A' + 10; 1959 } 1960 if (fwd) { 1961 whole <<= 8; 1962 whole |= c; 1963 } else { 1964 whole >>= 8; 1965 whole |= ((u_32_t)c) << 24; 1966 } 1967 } 1968 if (fwd) 1969 s++; 1970 else 1971 s--; 1972 } 1973 if (c != ':' && c != delim) 1974 return 0; 1975 1976 while (*s != '|') 1977 s++; 1978 s++; 1979 1980 /* 1981 * Get the port number 1982 */ 1983 i = 0; 1984 while (((c = *s++) != '\0') && ISDIGIT(c)) { 1985 i *= 10; 1986 i += c - '0'; 1987 } 1988 if (i > 65535) 1989 return 0; 1990 if (c != delim) 1991 return 0; 1992 port = (u_short)(i & 0xffff); 1993 1994 /* 1995 * Check for CR-LF at the end of the command string. 1996 */ 1997 if ((*s != '\r') || (*(s + 1) != '\n')) { 1998 DT(eprt6_no_crlf); 1999 if (softf->ipf_p_ftp_debug & DEBUG_PARSE_ERR) 2000 printf("ipf_p_ftp_eprt6:missing %s\n", "cr-lf"); 2001 return 0; 2002 } 2003 s += 2; 2004 2005 /* 2006 * Calculate new address parts for PORT command 2007 */ 2008 a6 = (i6addr_t *)&ip6->ip6_src; 2009 olen = s - f->ftps_rptr; 2010 /* DO NOT change this to snprintf! */ 2011 /* 2012 * While we could force the use of | as a delimiter here, it makes 2013 * sense to preserve whatever character is being used by the systems 2014 * involved in the communication. 2015 */ 2016 s = newbuf; 2017 left = sizeof(newbuf); 2018 snprintf(newbuf, left, "EPRT %c2%c", delim, delim); 2019 left -= strlen(s) + 1; 2020 s += strlen(s); 2021 a = ntohl(a6->i6[0]); 2022 snprintf(s, left, "%x:%x:", a >> 16, a & 0xffff); 2023 left -= strlen(s); 2024 s += strlen(s); 2025 a = ntohl(a6->i6[1]); 2026 snprintf(s, left, "%x:%x:", a >> 16, a & 0xffff); 2027 left -= strlen(s); 2028 s += strlen(s); 2029 a = ntohl(a6->i6[2]); 2030 snprintf(s, left, "%x:%x:", a >> 16, a & 0xffff); 2031 left -= strlen(s); 2032 s += strlen(s); 2033 a = ntohl(a6->i6[3]); 2034 snprintf(s, left, "%x:%x", a >> 16, a & 0xffff); 2035 left -= strlen(s); 2036 s += strlen(s); 2037 snprintf(s, left, "|%d|\r\n", port); 2038 nlen = strlen(newbuf); 2039 inc = nlen - olen; 2040 if ((inc + fin->fin_plen) > 65535) { 2041 DT2(eprt6_len, int, inc, int, fin->fin_plen); 2042 if (softf->ipf_p_ftp_debug & DEBUG_ERROR) 2043 printf("ipf_p_ftp_eprt6:inc(%d) + ip->ip_len > 65535\n", 2044 inc); 2045 return 0; 2046 } 2047 2048 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 2049 #if !defined(_KERNEL) 2050 M_ADJ(m, inc); 2051 #else 2052 if (inc < 0) 2053 M_ADJ(m, inc); 2054 #endif 2055 /* the mbuf chain will be extended if necessary by m_copyback() */ 2056 COPYBACK(m, off, nlen, newbuf); 2057 fin->fin_flx |= FI_DOCKSUM; 2058 2059 if (inc != 0) { 2060 fin->fin_plen += inc; 2061 ip6->ip6_plen = htons(fin->fin_plen - fin->fin_hlen); 2062 fin->fin_dlen += inc; 2063 } 2064 2065 f->ftps_cmd = FTPXY_C_EPRT; 2066 return ipf_p_ftp_addport(softf, fin, ip, nat, ftp, dlen, port, inc); 2067 } 2068 #endif /* USE_INET6 */ 2069