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