1/* $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c 145522 2005-04-25 18:43:14Z darrenr $ */ 2 |
3/*
|
4 * Copyright (C) 1997-2003 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 *
|
5 * $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c 130886 2004-06-21 22:46:36Z darrenr $
|
11 * $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c 145522 2005-04-25 18:43:14Z darrenr $ 12 * Id: ip_ftp_pxy.c,v 2.88.2.15 2005/03/19 19:38:10 darrenr Exp |
13 */
|
7#if SOLARIS && defined(_KERNEL)
8extern kmutex_t ipf_rw;
9#endif
|
14
|
11#define isdigit(x) ((x) >= '0' && (x) <= '9')
12#define isupper(x) (((unsigned)(x) >= 'A') && ((unsigned)(x) <= 'Z'))
13#define islower(x) (((unsigned)(x) >= 'a') && ((unsigned)(x) <= 'z'))
14#define isalpha(x) (isupper(x) || islower(x))
15#define toupper(x) (isupper(x) ? (x) : (x) - 'a' + 'A')
16
|
15#define IPF_FTP_PROXY 16 17#define IPF_MINPORTLEN 18 18#define IPF_MAXPORTLEN 30 19#define IPF_MIN227LEN 39 20#define IPF_MAX227LEN 51
|
23#define IPF_FTPBUFSZ 96 /* This *MUST* be >= 53! */
|
21#define IPF_MIN229LEN 47 22#define IPF_MAX229LEN 51 |
23 24#define FTPXY_GO 0 25#define FTPXY_INIT 1 26#define FTPXY_USER_1 2 27#define FTPXY_USOK_1 3 28#define FTPXY_PASS_1 4 29#define FTPXY_PAOK_1 5 30#define FTPXY_AUTH_1 6 31#define FTPXY_AUOK_1 7 32#define FTPXY_ADAT_1 8 33#define FTPXY_ADOK_1 9 34#define FTPXY_ACCT_1 10 35#define FTPXY_ACOK_1 11 36#define FTPXY_USER_2 12 37#define FTPXY_USOK_2 13 38#define FTPXY_PASS_2 14 39#define FTPXY_PAOK_2 15 40 41/* 42 * Values for FTP commands. Numerics cover 0-999 43 */ 44#define FTPXY_C_PASV 1000 45 46int ippr_ftp_client __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); 47int ippr_ftp_complete __P((char *, size_t));
|
49int ippr_ftp_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *));
|
48int ippr_ftp_in __P((fr_info_t *, ap_session_t *, nat_t *)); |
49int ippr_ftp_init __P((void));
|
51int ippr_ftp_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *));
52int ippr_ftp_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *));
|
50void ippr_ftp_fini __P((void)); 51int ippr_ftp_new __P((fr_info_t *, ap_session_t *, nat_t *)); 52int ippr_ftp_out __P((fr_info_t *, ap_session_t *, nat_t *)); |
53int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int));
|
54int ippr_ftp_epsv __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); |
55int ippr_ftp_port __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int));
|
55int ippr_ftp_process __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int));
|
56int ippr_ftp_process __P((fr_info_t *, nat_t *, ftpinfo_t *, int)); |
57int ippr_ftp_server __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); 58int ippr_ftp_valid __P((ftpinfo_t *, int, char *, size_t)); 59int ippr_ftp_server_valid __P((ftpside_t *, char *, size_t)); 60int ippr_ftp_client_valid __P((ftpside_t *, char *, size_t)); 61u_short ippr_ftp_atoi __P((char **));
|
62int ippr_ftp_pasvreply __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, 63 u_int, char *, char *, u_int)); |
64
|
62static frentry_t ftppxyfr;
|
65 66int ftp_proxy_init = 0; |
67int ippr_ftp_pasvonly = 0;
|
64int ippr_ftp_insecure = 0;
65int ippr_ftp_forcepasv = 0;
|
68int ippr_ftp_insecure = 0; /* Do not require logins before transfers */ 69int ippr_ftp_pasvrdr = 0; 70int ippr_ftp_forcepasv = 0; /* PASV must be last command prior to 227 */ 71#if defined(_KERNEL) 72int ippr_ftp_debug = 0; 73#else 74int ippr_ftp_debug = 2; 75#endif 76/* 77 * 1 - security 78 * 2 - errors 79 * 3 - error debugging 80 * 4 - parsing errors 81 * 5 - parsing info 82 * 6 - parsing debug 83 */ |
84
|
85static frentry_t ftppxyfr; 86static ipftuneable_t ftptune = { 87 { &ippr_ftp_debug }, 88 "ippr_ftp_debug", 89 0, 90 10, 91 sizeof(ippr_ftp_debug), 92 0, 93 NULL 94}; |
95
|
96 |
97/* 98 * Initialize local structures. 99 */ 100int ippr_ftp_init() 101{ 102 bzero((char *)&ftppxyfr, sizeof(ftppxyfr)); 103 ftppxyfr.fr_ref = 1; 104 ftppxyfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
|
105 MUTEX_INIT(&ftppxyfr.fr_lock, "FTP Proxy Mutex"); 106 ftp_proxy_init = 1; 107 (void) fr_addipftune(&ftptune); 108 |
109 return 0; 110} 111 112
|
80int ippr_ftp_new(fin, ip, aps, nat)
|
113void ippr_ftp_fini() 114{ 115 (void) fr_delipftune(&ftptune); 116 117 if (ftp_proxy_init == 1) { 118 MUTEX_DESTROY(&ftppxyfr.fr_lock); 119 ftp_proxy_init = 0; 120 } 121} 122 123 124int ippr_ftp_new(fin, aps, nat) |
125fr_info_t *fin;
|
82ip_t *ip;
|
126ap_session_t *aps; 127nat_t *nat; 128{ 129 ftpinfo_t *ftp; 130 ftpside_t *f; 131 132 KMALLOC(ftp, ftpinfo_t *); 133 if (ftp == NULL) 134 return -1;
|
135 136 fin = fin; /* LINT */ 137 nat = nat; /* LINT */ 138 |
139 aps->aps_data = ftp; 140 aps->aps_psiz = sizeof(ftpinfo_t); 141 142 bzero((char *)ftp, sizeof(*ftp)); 143 f = &ftp->ftp_side[0]; 144 f->ftps_rptr = f->ftps_buf; 145 f->ftps_wptr = f->ftps_buf; 146 f = &ftp->ftp_side[1]; 147 f->ftps_rptr = f->ftps_buf; 148 f->ftps_wptr = f->ftps_buf; 149 ftp->ftp_passok = FTPXY_INIT;
|
150 ftp->ftp_incok = 0; |
151 return 0; 152} 153 154 155int ippr_ftp_port(fin, ip, nat, f, dlen) 156fr_info_t *fin; 157ip_t *ip; 158nat_t *nat; 159ftpside_t *f; 160int dlen; 161{ 162 tcphdr_t *tcp, tcph, *tcp2 = &tcph; 163 char newbuf[IPF_FTPBUFSZ], *s;
|
164 struct in_addr swip, swip2; |
165 u_int a1, a2, a3, a4;
|
117 struct in_addr swip;
|
166 int inc, off, flags; |
167 u_short a5, a6, sp; 168 size_t nlen, olen; 169 fr_info_t fi;
|
121 int inc, off;
122 nat_t *ipn;
|
170 nat_t *nat2; |
171 mb_t *m;
|
124#if SOLARIS && defined(_KERNEL)
125 mb_t *m1;
126#endif
|
172
|
173 m = fin->fin_m; |
174 tcp = (tcphdr_t *)fin->fin_dp;
|
175 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; 176 |
177 /* 178 * Check for client sending out PORT message. 179 */ 180 if (dlen < IPF_MINPORTLEN) {
|
133#if !defined(_KERNEL) && !defined(KERNEL)
134 fprintf(stdout,
135 "ippr_ftp_port:dlen(%d) < IPF_MINPORTLEN\n", dlen);
136#endif
|
181 if (ippr_ftp_debug > 1) 182 printf("ippr_ftp_port:dlen(%d) < IPF_MINPORTLEN\n", 183 dlen); |
184 return 0; 185 }
|
139 off = fin->fin_hlen + (tcp->th_off << 2);
|
186 /* 187 * Skip the PORT command + space 188 */ 189 s = f->ftps_rptr + 5; 190 /* 191 * Pick out the address components, two at a time. 192 */ 193 a1 = ippr_ftp_atoi(&s); 194 if (s == NULL) {
|
149#if !defined(_KERNEL) && !defined(KERNEL)
150 fprintf(stdout, "ippr_ftp_port:ippr_ftp_atoi(1) failed\n");
151#endif
|
195 if (ippr_ftp_debug > 1) 196 printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 1); |
197 return 0; 198 } 199 a2 = ippr_ftp_atoi(&s); 200 if (s == NULL) {
|
156#if !defined(_KERNEL) && !defined(KERNEL)
157 fprintf(stdout, "ippr_ftp_port:ippr_ftp_atoi(2) failed\n");
158#endif
|
201 if (ippr_ftp_debug > 1) 202 printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 2); |
203 return 0; 204 }
|
205 |
206 /*
|
162 * check that IP address in the PORT/PASV reply is the same as the
|
207 * Check that IP address in the PORT/PASV reply is the same as the |
208 * sender of the command - prevents using PORT for port scanning. 209 */ 210 a1 <<= 16; 211 a1 |= a2;
|
167 if (a1 != ntohl(nat->nat_inip.s_addr)) {
168#if !defined(_KERNEL) && !defined(KERNEL)
169 fprintf(stdout, "ippr_ftp_port:a1 != nat->nat_inip\n");
170#endif
171 return 0;
|
212 if (((nat->nat_dir == NAT_OUTBOUND) && 213 (a1 != ntohl(nat->nat_inip.s_addr))) || 214 ((nat->nat_dir == NAT_INBOUND) && 215 (a1 != ntohl(nat->nat_oip.s_addr)))) { 216 if (ippr_ftp_debug > 0) 217 printf("ippr_ftp_port:%s != nat->nat_inip\n", "a1"); 218 return APR_ERR(1); |
219 } 220 221 a5 = ippr_ftp_atoi(&s); 222 if (s == NULL) {
|
176#if !defined(_KERNEL) && !defined(KERNEL)
177 fprintf(stdout, "ippr_ftp_port:ippr_ftp_atoi(3) failed\n");
178#endif
|
223 if (ippr_ftp_debug > 1) 224 printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 3); |
225 return 0; 226 } 227 if (*s == ')') 228 s++; 229 230 /* 231 * check for CR-LF at the end. 232 */ 233 if (*s == '\n') 234 s--; 235 if ((*s == '\r') && (*(s + 1) == '\n')) { 236 s += 2; 237 a6 = a5 & 0xff; 238 } else {
|
193#if !defined(_KERNEL) && !defined(KERNEL)
194 fprintf(stdout, "ippr_ftp_port:missing cr-lf\n");
195#endif
|
239 if (ippr_ftp_debug > 1) 240 printf("ippr_ftp_port:missing %s\n", "cr-lf"); |
241 return 0; 242 }
|
243 |
244 a5 >>= 8; 245 a5 &= 0xff;
|
246 sp = a5 << 8 | a6; |
247 /*
|
248 * Don't allow the PORT command to specify a port < 1024 due to 249 * security crap. 250 */ 251 if (sp < 1024) { 252 if (ippr_ftp_debug > 0) 253 printf("ippr_ftp_port:sp(%d) < 1024\n", sp); 254 return 0; 255 } 256 /* |
257 * Calculate new address parts for PORT command 258 */
|
203 a1 = ntohl(ip->ip_src.s_addr);
|
259 if (nat->nat_dir == NAT_INBOUND) 260 a1 = ntohl(nat->nat_oip.s_addr); 261 else 262 a1 = ntohl(ip->ip_src.s_addr); |
263 a2 = (a1 >> 16) & 0xff; 264 a3 = (a1 >> 8) & 0xff; 265 a4 = a1 & 0xff; 266 a1 >>= 24; 267 olen = s - f->ftps_rptr; 268 /* DO NOT change this to snprintf! */
|
210#if defined(OpenBSD) && (200311 >= 200311)
211 (void) snprintf(newbuf, sizeof(newbuf), "%s %u,%u,%u,%u,%u,%u\r\n",
212 "PORT", a1, a2, a3, a4, a5, a6);
|
269#if defined(SNPRINTF) && defined(_KERNEL) 270 SNPRINTF(newbuf, sizeof(newbuf), "%s %u,%u,%u,%u,%u,%u\r\n", 271 "PORT", a1, a2, a3, a4, a5, a6); |
272#else 273 (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", 274 "PORT", a1, a2, a3, a4, a5, a6); 275#endif 276 277 nlen = strlen(newbuf); 278 inc = nlen - olen; 279 if ((inc + ip->ip_len) > 65535) {
|
221#if !defined(_KERNEL) && !defined(KERNEL)
222 fprintf(stdout,
223 "ippr_ftp_port:inc(%d) + ip->ip_len > 65535\n", inc);
224#endif
|
280 if (ippr_ftp_debug > 0) 281 printf("ippr_ftp_port:inc(%d) + ip->ip_len > 65535\n", 282 inc); |
283 return 0; 284 } 285 286#if !defined(_KERNEL)
|
229 m = *fin->fin_mp;
230 bcopy(newbuf, (char *)m + off, nlen);
|
287 bcopy(newbuf, MTOD(m, char *) + off, nlen); |
288#else
|
232# if SOLARIS
233 m = fin->fin_qfm;
234 for (m1 = m; m1->b_cont; m1 = m1->b_cont)
235 ;
236 if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) {
237 mblk_t *nm;
238
239 /* alloc enough to keep same trailer space for lower driver */
240 nm = allocb(nlen, BPRI_MED);
241 PANIC((!nm),("ippr_ftp_out: allocb failed"));
242
243 nm->b_band = m1->b_band;
244 nm->b_wptr += nlen;
245
246 m1->b_wptr -= olen;
247 PANIC((m1->b_wptr < m1->b_rptr),
248 ("ippr_ftp_out: cannot handle fragmented data block"));
249
250 linkb(m1, nm);
251 } else {
252 if (m1->b_datap->db_struiolim == m1->b_wptr)
253 m1->b_datap->db_struiolim += inc;
254 m1->b_datap->db_struioflag &= ~STRUIO_IP;
255 m1->b_wptr += inc;
256 }
257 copyin_mblk(m, off, nlen, newbuf);
258# else
259 m = *fin->fin_mp;
|
289# if defined(MENTAT) |
290 if (inc < 0)
|
291 (void)adjmsg(m, inc); 292# else /* defined(MENTAT) */ 293 /* 294 * m_adj takes care of pkthdr.len, if required and treats inc<0 to 295 * mean remove -len bytes from the end of the packet. 296 * The mbuf chain will be extended if necessary by m_copyback(). 297 */ 298 if (inc < 0) |
299 m_adj(m, inc);
|
262 /* the mbuf chain will be extended if necessary by m_copyback() */
263 m_copyback(m, off, nlen, newbuf);
264# ifdef M_PKTHDR
265 if (!(m->m_flags & M_PKTHDR))
266 m->m_pkthdr.len += inc;
267# endif
268# endif
269#endif
270 if (inc != 0) {
271#if ((SOLARIS || defined(__sgi)) && defined(_KERNEL)) || !defined(_KERNEL)
272 register u_32_t sum1, sum2;
|
300# endif /* defined(MENTAT) */ 301#endif /* !defined(_KERNEL) */ 302 COPYBACK(m, off, nlen, newbuf); |
303
|
274 sum1 = ip->ip_len;
275 sum2 = ip->ip_len + inc;
276
277 /* Because ~1 == -2, We really need ~1 == -1 */
278 if (sum1 > sum2)
279 sum2--;
280 sum2 -= sum1;
281 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
282
283 fix_outcksum(fin, &ip->ip_sum, sum2);
284#endif
|
304 if (inc != 0) { |
305 ip->ip_len += inc;
|
306 fin->fin_dlen += inc; 307 fin->fin_plen += inc; |
308 } 309 310 /*
|
289 * Add skeleton NAT entry for connection which will come back the
290 * other way.
291 */
292 sp = (a5 << 8 | a6);
293 /*
294 * Don't allow the PORT command to specify a port < 1024 due to
295 * security crap.
296 */
297 if (sp < 1024) {
298#if !defined(_KERNEL) && !defined(KERNEL)
299 fprintf(stdout, "ippr_ftp_port:sp(%d) < 1024\n", sp);
300#endif
301 return 0;
302 }
303
304 /*
|
311 * The server may not make the connection back from port 20, but 312 * it is the most likely so use it here to check for a conflicting 313 * mapping. 314 */ 315 bcopy((char *)fin, (char *)&fi, sizeof(fi));
|
316 fi.fin_state = NULL; 317 fi.fin_nat = NULL; 318 fi.fin_flx |= FI_IGNORE; |
319 fi.fin_data[0] = sp; 320 fi.fin_data[1] = fin->fin_data[1] - 1;
|
312 ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip,
313 ip->ip_dst, 0);
314 if (ipn == NULL) {
|
321 /* 322 * Add skeleton NAT entry for connection which will come back the 323 * other way. 324 */ 325 if (nat->nat_dir == NAT_OUTBOUND) 326 nat2 = nat_outlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, 327 nat->nat_inip, nat->nat_oip); 328 else 329 nat2 = nat_inlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p, 330 nat->nat_inip, nat->nat_oip); 331 if (nat2 == NULL) { |
332 int slen; 333 334 slen = ip->ip_len; 335 ip->ip_len = fin->fin_hlen + sizeof(*tcp2); 336 bzero((char *)tcp2, sizeof(*tcp2)); 337 tcp2->th_win = htons(8192); 338 tcp2->th_sport = htons(sp);
|
322 tcp2->th_off = 5;
|
339 TCP_OFF_A(tcp2, 5); |
340 tcp2->th_flags = TH_SYN; 341 tcp2->th_dport = 0; /* XXX - don't specify remote port */ 342 fi.fin_data[1] = 0; 343 fi.fin_dlen = sizeof(*tcp2);
|
344 fi.fin_plen = fi.fin_hlen + sizeof(*tcp2); |
345 fi.fin_dp = (char *)tcp2; 346 fi.fin_fr = &ftppxyfr;
|
329 fi.fin_out = 1;
|
347 fi.fin_out = nat->nat_dir; 348 fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; |
349 swip = ip->ip_src;
|
331 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
332 ip->ip_src = nat->nat_inip;
333 ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_DPORT,
334 NAT_OUTBOUND);
335 if (ipn != NULL) {
336 ipn->nat_age = fr_defnatage;
337 (void) fr_addstate(ip, &fi, NULL,
338 FI_W_DPORT|FI_IGNOREPKT);
|
350 swip2 = ip->ip_dst; 351 if (nat->nat_dir == NAT_OUTBOUND) { 352 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; 353 ip->ip_src = nat->nat_inip; 354 } else if (nat->nat_dir == NAT_INBOUND) { 355 fi.fin_fi.fi_saddr = nat->nat_oip.s_addr; 356 ip->ip_src = nat->nat_oip; |
357 }
|
358 359 flags = NAT_SLAVE|IPN_TCP|SI_W_DPORT; 360 if (nat->nat_dir == NAT_INBOUND) 361 flags |= NAT_NOTRULEPORT; 362 nat2 = nat_new(&fi, nat->nat_ptr, NULL, flags, nat->nat_dir); 363 364 if (nat2 != NULL) { 365 (void) nat_proto(&fi, nat2, IPN_TCP); 366 nat_update(&fi, nat2, nat->nat_ptr); 367 fi.fin_ifp = NULL; 368 if (nat->nat_dir == NAT_INBOUND) { 369 fi.fin_fi.fi_daddr = nat->nat_inip.s_addr; 370 ip->ip_dst = nat->nat_inip; 371 } 372 (void) fr_addstate(&fi, &nat2->nat_state, SI_W_DPORT); 373 if (fi.fin_state != NULL) 374 fr_statederef(&fi, (ipstate_t **)&fi.fin_state); 375 } |
376 ip->ip_len = slen; 377 ip->ip_src = swip;
|
378 ip->ip_dst = swip2; 379 } else { 380 ipstate_t *is; 381 382 nat_update(&fi, nat2, nat->nat_ptr); 383 READ_ENTER(&ipf_state); 384 is = nat2->nat_state; 385 if (is != NULL) { 386 MUTEX_ENTER(&is->is_lock); 387 (void)fr_tcp_age(&is->is_sti, &fi, ips_tqtqb, 388 is->is_flags); 389 MUTEX_EXIT(&is->is_lock); 390 } 391 RWLOCK_EXIT(&ipf_state); |
392 }
|
343 return inc;
|
393 return APR_INC(inc); |
394} 395 396 397int ippr_ftp_client(fin, ip, nat, ftp, dlen) 398fr_info_t *fin; 399nat_t *nat; 400ftpinfo_t *ftp; 401ip_t *ip; 402int dlen; 403{ 404 char *rptr, *wptr, cmd[6], c; 405 ftpside_t *f; 406 int inc, i; 407 408 inc = 0; 409 f = &ftp->ftp_side[0]; 410 rptr = f->ftps_rptr; 411 wptr = f->ftps_wptr; 412 413 for (i = 0; (i < 5) && (i < dlen); i++) { 414 c = rptr[i];
|
365 if (isalpha(c)) {
366 cmd[i] = toupper(c);
|
415 if (ISALPHA(c)) { 416 cmd[i] = TOUPPER(c); |
417 } else { 418 cmd[i] = c; 419 } 420 } 421 cmd[i] = '\0'; 422 423 ftp->ftp_incok = 0; 424 if (!strncmp(cmd, "USER ", 5) || !strncmp(cmd, "XAUT ", 5)) { 425 if (ftp->ftp_passok == FTPXY_ADOK_1 || 426 ftp->ftp_passok == FTPXY_AUOK_1) { 427 ftp->ftp_passok = FTPXY_USER_2; 428 ftp->ftp_incok = 1; 429 } else { 430 ftp->ftp_passok = FTPXY_USER_1; 431 ftp->ftp_incok = 1; 432 } 433 } else if (!strncmp(cmd, "AUTH ", 5)) { 434 ftp->ftp_passok = FTPXY_AUTH_1; 435 ftp->ftp_incok = 1; 436 } else if (!strncmp(cmd, "PASS ", 5)) { 437 if (ftp->ftp_passok == FTPXY_USOK_1) { 438 ftp->ftp_passok = FTPXY_PASS_1; 439 ftp->ftp_incok = 1; 440 } else if (ftp->ftp_passok == FTPXY_USOK_2) { 441 ftp->ftp_passok = FTPXY_PASS_2; 442 ftp->ftp_incok = 1; 443 } 444 } else if ((ftp->ftp_passok == FTPXY_AUOK_1) && 445 !strncmp(cmd, "ADAT ", 5)) { 446 ftp->ftp_passok = FTPXY_ADAT_1; 447 ftp->ftp_incok = 1; 448 } else if ((ftp->ftp_passok == FTPXY_PAOK_1 || 449 ftp->ftp_passok == FTPXY_PAOK_2) && 450 !strncmp(cmd, "ACCT ", 5)) { 451 ftp->ftp_passok = FTPXY_ACCT_1; 452 ftp->ftp_incok = 1; 453 } else if ((ftp->ftp_passok == FTPXY_GO) && !ippr_ftp_pasvonly && 454 !strncmp(cmd, "PORT ", 5)) { 455 inc = ippr_ftp_port(fin, ip, nat, f, dlen); 456 } else if (ippr_ftp_insecure && !ippr_ftp_pasvonly && 457 !strncmp(cmd, "PORT ", 5)) { 458 inc = ippr_ftp_port(fin, ip, nat, f, dlen); 459 } 460 461 while ((*rptr++ != '\n') && (rptr < wptr)) 462 ; 463 f->ftps_rptr = rptr; 464 return inc; 465} 466 467 468int ippr_ftp_pasv(fin, ip, nat, ftp, dlen) 469fr_info_t *fin; 470ip_t *ip; 471nat_t *nat; 472ftpinfo_t *ftp; 473int dlen; 474{
|
425 tcphdr_t *tcp, tcph, *tcp2 = &tcph;
426 struct in_addr swip, swip2;
427 u_int a1, a2, a3, a4;
428 u_short a5, a6, dp;
429 fr_info_t fi;
|
475 u_int a1, a2, a3, a4, data_ip; 476 char newbuf[IPF_FTPBUFSZ]; 477 char *s, *brackets[2]; 478 u_short a5, a6; |
479 ftpside_t *f;
|
431 nat_t *ipn;
432 int inc;
433 char *s;
|
480 481 if (ippr_ftp_forcepasv != 0 && 482 ftp->ftp_side[0].ftps_cmds != FTPXY_C_PASV) {
|
437#if !defined(_KERNEL) && !defined(KERNEL)
438 fprintf(stdout,
439 "ippr_ftp_pasv:ftps_cmds(%d) != FTPXY_C_PASV\n",
440 ftp->ftp_side[0].ftps_cmds);
441#endif
|
483 if (ippr_ftp_debug > 0) 484 printf("ippr_ftp_pasv:ftps_cmds(%d) != FTPXY_C_PASV\n", 485 ftp->ftp_side[0].ftps_cmds); |
486 return 0; 487 } 488 489 f = &ftp->ftp_side[1]; 490 491#define PASV_REPLEN 24 492 /* 493 * Check for PASV reply message. 494 */ 495 if (dlen < IPF_MIN227LEN) {
|
452#if !defined(_KERNEL) && !defined(KERNEL)
453 fprintf(stdout,
454 "ippr_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n", dlen);
455#endif
|
496 if (ippr_ftp_debug > 1) 497 printf("ippr_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n", 498 dlen); |
499 return 0; 500 } else if (strncmp(f->ftps_rptr, 501 "227 Entering Passive Mod", PASV_REPLEN)) {
|
459#if !defined(_KERNEL) && !defined(KERNEL)
460 fprintf(stdout, "ippr_ftp_pasv:227 reply wrong\n");
461#endif
|
502 if (ippr_ftp_debug > 0) 503 printf("ippr_ftp_pasv:%d reply wrong\n", 227); |
504 return 0; 505 } 506
|
465 tcp = (tcphdr_t *)fin->fin_dp;
466
|
507 brackets[0] = ""; 508 brackets[1] = ""; |
509 /* 510 * Skip the PASV reply + space 511 */ 512 s = f->ftps_rptr + PASV_REPLEN;
|
471 while (*s && !isdigit(*s))
|
513 while (*s && !ISDIGIT(*s)) { 514 if (*s == '(') { 515 brackets[0] = "("; 516 brackets[1] = ")"; 517 } |
518 s++;
|
519 } 520 |
521 /* 522 * Pick out the address components, two at a time. 523 */ 524 a1 = ippr_ftp_atoi(&s); 525 if (s == NULL) {
|
478#if !defined(_KERNEL) && !defined(KERNEL)
479 fprintf(stdout, "ippr_ftp_pasv:ippr_ftp_atoi(1) failed\n");
480#endif
|
526 if (ippr_ftp_debug > 1) 527 printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 1); |
528 return 0; 529 } 530 a2 = ippr_ftp_atoi(&s); 531 if (s == NULL) {
|
485#if !defined(_KERNEL) && !defined(KERNEL)
486 fprintf(stdout, "ippr_ftp_pasv:ippr_ftp_atoi(2) failed\n");
487#endif
|
532 if (ippr_ftp_debug > 1) 533 printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 2); |
534 return 0; 535 } 536 537 /*
|
492 * check that IP address in the PORT/PASV reply is the same as the
493 * sender of the command - prevents using PORT for port scanning.
|
538 * check that IP address in the PASV reply is the same as the 539 * sender of the command - prevents using PASV for port scanning. |
540 */ 541 a1 <<= 16; 542 a1 |= a2;
|
497 if (a1 != ntohl(nat->nat_oip.s_addr)) {
498#if !defined(_KERNEL) && !defined(KERNEL)
499 fprintf(stdout, "ippr_ftp_pasv:a1 != nat->nat_oip\n");
500#endif
|
543 544 if (((nat->nat_dir == NAT_INBOUND) && 545 (a1 != ntohl(nat->nat_inip.s_addr))) || 546 ((nat->nat_dir == NAT_OUTBOUND) && 547 (a1 != ntohl(nat->nat_oip.s_addr)))) { 548 if (ippr_ftp_debug > 0) 549 printf("ippr_ftp_pasv:%s != nat->nat_oip\n", "a1"); |
550 return 0; 551 } 552 553 a5 = ippr_ftp_atoi(&s); 554 if (s == NULL) {
|
506#if !defined(_KERNEL) && !defined(KERNEL)
507 fprintf(stdout, "ippr_ftp_pasv:ippr_ftp_atoi(3) failed\n");
508#endif
|
555 if (ippr_ftp_debug > 1) 556 printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 3); |
557 return 0; 558 } 559 560 if (*s == ')') 561 s++; 562 if (*s == '.') 563 s++; 564 if (*s == '\n') 565 s--; 566 /* 567 * check for CR-LF at the end. 568 */ 569 if ((*s == '\r') && (*(s + 1) == '\n')) { 570 s += 2;
|
523 a6 = a5 & 0xff;
|
571 } else {
|
525#if !defined(_KERNEL) && !defined(KERNEL)
526 fprintf(stdout, "ippr_ftp_pasv:missing cr-lf\n");
527#endif
|
572 if (ippr_ftp_debug > 1) 573 printf("ippr_ftp_pasv:missing %s", "cr-lf\n"); |
574 return 0; 575 }
|
576 577 a6 = a5 & 0xff; |
578 a5 >>= 8; 579 /* 580 * Calculate new address parts for 227 reply 581 */
|
534 a1 = ntohl(ip->ip_src.s_addr);
|
582 if (nat->nat_dir == NAT_INBOUND) { 583 data_ip = nat->nat_outip.s_addr; 584 a1 = ntohl(data_ip); 585 } else 586 data_ip = htonl(a1); 587 |
588 a2 = (a1 >> 16) & 0xff; 589 a3 = (a1 >> 8) & 0xff; 590 a4 = a1 & 0xff; 591 a1 >>= 24;
|
539 inc = 0;
540#if 0
541 olen = s - f->ftps_rptr;
542 (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n",
543 "227 Entering Passive Mode", a1, a2, a3, a4, a5, a6);
544 nlen = strlen(newbuf);
545 inc = nlen - olen;
546 if ((inc + ip->ip_len) > 65535)
547 return 0;
|
592
|
549#if !defined(_KERNEL)
550 m = *fin->fin_mp;
551 m_copyback(m, off, nlen, newbuf);
|
593#if defined(SNPRINTF) && defined(_KERNEL) 594 SNPRINTF(newbuf, sizeof(newbuf), "%s %s%u,%u,%u,%u,%u,%u%s\r\n", 595 "227 Entering Passive Mode", brackets[0], a1, a2, a3, a4, 596 a5, a6, brackets[1]); |
597#else
|
553# if SOLARIS
554 m = fin->fin_qfm;
555 for (m1 = m; m1->b_cont; m1 = m1->b_cont)
556 ;
557 if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) {
558 mblk_t *nm;
|
598 (void) sprintf(newbuf, "%s %s%u,%u,%u,%u,%u,%u%s\r\n", 599 "227 Entering Passive Mode", brackets[0], a1, a2, a3, a4, 600 a5, a6, brackets[1]); 601#endif 602 return ippr_ftp_pasvreply(fin, ip, nat, f, (a5 << 8 | a6), 603 newbuf, s, data_ip); 604} |
605
|
560 /* alloc enough to keep same trailer space for lower driver */
561 nm = allocb(nlen, BPRI_MED);
562 PANIC((!nm),("ippr_ftp_out: allocb failed"));
|
606int ippr_ftp_pasvreply(fin, ip, nat, f, port, newmsg, s, data_ip) 607fr_info_t *fin; 608ip_t *ip; 609nat_t *nat; 610ftpside_t *f; 611u_int port; 612char *newmsg; 613char *s; 614u_int data_ip; 615{ 616 int inc, off, nflags, sflags; 617 tcphdr_t *tcp, tcph, *tcp2; 618 struct in_addr swip, swip2; 619 struct in_addr data_addr; 620 size_t nlen, olen; 621 fr_info_t fi; 622 nat_t *nat2; 623 mb_t *m; |
624
|
564 nm->b_band = m1->b_band;
565 nm->b_wptr += nlen;
|
625 m = fin->fin_m; 626 tcp = (tcphdr_t *)fin->fin_dp; 627 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; |
628
|
567 m1->b_wptr -= olen;
568 PANIC((m1->b_wptr < m1->b_rptr),
569 ("ippr_ftp_out: cannot handle fragmented data block"));
|
629 data_addr.s_addr = data_ip; 630 tcp2 = &tcph; 631 inc = 0; |
632
|
571 linkb(m1, nm);
572 } else {
573 m1->b_wptr += inc;
|
633 634 olen = s - f->ftps_rptr; 635 nlen = strlen(newmsg); 636 inc = nlen - olen; 637 if ((inc + ip->ip_len) > 65535) { 638 if (ippr_ftp_debug > 0) 639 printf("ippr_ftp_pasv:inc(%d) + ip->ip_len > 65535\n", 640 inc); 641 return 0; |
642 }
|
575 /*copyin_mblk(m, off, nlen, newbuf);*/
576# else /* SOLARIS */
577 m = *fin->fin_mp;
|
643 644#if !defined(_KERNEL) 645 bcopy(newmsg, MTOD(m, char *) + off, nlen); 646#else 647# if defined(MENTAT) |
648 if (inc < 0)
|
649 (void)adjmsg(m, inc); 650# else /* defined(MENTAT) */ 651 /* 652 * m_adj takes care of pkthdr.len, if required and treats inc<0 to 653 * mean remove -len bytes from the end of the packet. 654 * The mbuf chain will be extended if necessary by m_copyback(). 655 */ 656 if (inc < 0) |
657 m_adj(m, inc);
|
580 /* the mbuf chain will be extended if necessary by m_copyback() */
581 /*m_copyback(m, off, nlen, newbuf);*/
582# endif /* SOLARIS */
583#endif /* _KERNEL */
584 if (inc != 0) {
585#if ((SOLARIS || defined(__sgi)) && defined(_KERNEL)) || !defined(_KERNEL)
586 register u_32_t sum1, sum2;
|
658# endif /* defined(MENTAT) */ 659#endif /* !defined(_KERNEL) */ 660 COPYBACK(m, off, nlen, newmsg); |
661
|
588 sum1 = ip->ip_len;
589 sum2 = ip->ip_len + inc;
590
591 /* Because ~1 == -2, We really need ~1 == -1 */
592 if (sum1 > sum2)
593 sum2--;
594 sum2 -= sum1;
595 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
596
597 fix_outcksum(fin, &ip->ip_sum, sum2);
598#endif /* SOLARIS || defined(__sgi) */
|
662 if (inc != 0) { |
663 ip->ip_len += inc;
|
664 fin->fin_dlen += inc; 665 fin->fin_plen += inc; |
666 }
|
601#endif /* 0 */
|
667 668 /* 669 * Add skeleton NAT entry for connection which will come back the 670 * other way. 671 */ 672 bcopy((char *)fin, (char *)&fi, sizeof(fi));
|
673 fi.fin_state = NULL; 674 fi.fin_nat = NULL; 675 fi.fin_flx |= FI_IGNORE; |
676 fi.fin_data[0] = 0;
|
609 dp = htons(fin->fin_data[1] - 1);
610 fi.fin_data[1] = ntohs(dp);
611 ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip,
612 ip->ip_dst, 0);
613 if (ipn == NULL) {
|
677 fi.fin_data[1] = port; 678 nflags = IPN_TCP|SI_W_SPORT; 679 if (ippr_ftp_pasvrdr && f->ftps_ifp) 680 nflags |= SI_W_DPORT; 681 if (nat->nat_dir == NAT_OUTBOUND) 682 nat2 = nat_outlookup(&fi, nflags|NAT_SEARCH, 683 nat->nat_p, nat->nat_inip, nat->nat_oip); 684 else 685 nat2 = nat_inlookup(&fi, nflags|NAT_SEARCH, 686 nat->nat_p, nat->nat_inip, nat->nat_oip); 687 if (nat2 == NULL) { |
688 int slen; 689 690 slen = ip->ip_len; 691 ip->ip_len = fin->fin_hlen + sizeof(*tcp2); 692 bzero((char *)tcp2, sizeof(*tcp2)); 693 tcp2->th_win = htons(8192); 694 tcp2->th_sport = 0; /* XXX - fake it for nat_new */
|
621 tcp2->th_off = 5;
|
695 TCP_OFF_A(tcp2, 5); |
696 tcp2->th_flags = TH_SYN;
|
623 fi.fin_data[1] = a5 << 8 | a6;
|
697 fi.fin_data[1] = port; |
698 fi.fin_dlen = sizeof(*tcp2);
|
625 tcp2->th_dport = htons(fi.fin_data[1]);
|
699 tcp2->th_dport = htons(port); |
700 fi.fin_data[0] = 0; 701 fi.fin_dp = (char *)tcp2;
|
702 fi.fin_plen = fi.fin_hlen + sizeof(*tcp); |
703 fi.fin_fr = &ftppxyfr;
|
629 fi.fin_out = 1;
|
704 fi.fin_out = nat->nat_dir; 705 fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE; |
706 swip = ip->ip_src; 707 swip2 = ip->ip_dst;
|
632 fi.fin_fi.fi_daddr = ip->ip_src.s_addr;
633 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
634 ip->ip_dst = ip->ip_src;
635 ip->ip_src = nat->nat_inip;
636 ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_SPORT,
637 NAT_OUTBOUND);
638 if (ipn != NULL) {
639 ipn->nat_age = fr_defnatage;
640 (void) fr_addstate(ip, &fi, NULL,
641 FI_W_SPORT|FI_IGNOREPKT);
|
708 if (nat->nat_dir == NAT_OUTBOUND) { 709 fi.fin_fi.fi_daddr = data_addr.s_addr; 710 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; 711 ip->ip_dst = data_addr; 712 ip->ip_src = nat->nat_inip; 713 } else if (nat->nat_dir == NAT_INBOUND) { 714 fi.fin_fi.fi_saddr = nat->nat_oip.s_addr; 715 fi.fin_fi.fi_daddr = nat->nat_outip.s_addr; 716 ip->ip_src = nat->nat_oip; 717 ip->ip_dst = nat->nat_outip; |
718 }
|
719 720 sflags = nflags; 721 nflags |= NAT_SLAVE; 722 if (nat->nat_dir == NAT_INBOUND) 723 nflags |= NAT_NOTRULEPORT; 724 nat2 = nat_new(&fi, nat->nat_ptr, NULL, nflags, nat->nat_dir); 725 if (nat2 != NULL) { 726 (void) nat_proto(&fi, nat2, IPN_TCP); 727 nat_update(&fi, nat2, nat->nat_ptr); 728 fi.fin_ifp = NULL; 729 if (nat->nat_dir == NAT_INBOUND) { 730 fi.fin_fi.fi_daddr = nat->nat_inip.s_addr; 731 ip->ip_dst = nat->nat_inip; 732 } 733 (void) fr_addstate(&fi, &nat2->nat_state, sflags); 734 if (fi.fin_state != NULL) 735 fr_statederef(&fi, (ipstate_t **)&fi.fin_state); 736 } 737 |
738 ip->ip_len = slen; 739 ip->ip_src = swip; 740 ip->ip_dst = swip2;
|
741 } else { 742 ipstate_t *is; 743 744 nat_update(&fi, nat2, nat->nat_ptr); 745 READ_ENTER(&ipf_state); 746 is = nat2->nat_state; 747 if (is != NULL) { 748 MUTEX_ENTER(&is->is_lock); 749 (void)fr_tcp_age(&is->is_sti, &fi, ips_tqtqb, 750 is->is_flags); 751 MUTEX_EXIT(&is->is_lock); 752 } 753 RWLOCK_EXIT(&ipf_state); |
754 } 755 return inc; 756} 757 758 759int ippr_ftp_server(fin, ip, nat, ftp, dlen) 760fr_info_t *fin; 761ip_t *ip; 762nat_t *nat; 763ftpinfo_t *ftp; 764int dlen; 765{ 766 char *rptr, *wptr; 767 ftpside_t *f; 768 int inc; 769 770 inc = 0; 771 f = &ftp->ftp_side[1]; 772 rptr = f->ftps_rptr; 773 wptr = f->ftps_wptr; 774
|
667 if (!isdigit(*rptr) || !isdigit(*(rptr + 1)) || !isdigit(*(rptr + 2)))
|
775 if (*rptr == ' ') 776 goto server_cmd_ok; 777 if (!ISDIGIT(*rptr) || !ISDIGIT(*(rptr + 1)) || !ISDIGIT(*(rptr + 2))) |
778 return 0; 779 if (ftp->ftp_passok == FTPXY_GO) { 780 if (!strncmp(rptr, "227 ", 4)) 781 inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen);
|
782 else if (!strncmp(rptr, "229 ", 4)) 783 inc = ippr_ftp_epsv(fin, ip, nat, f, dlen); |
784 } else if (ippr_ftp_insecure && !strncmp(rptr, "227 ", 4)) { 785 inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen);
|
786 } else if (ippr_ftp_insecure && !strncmp(rptr, "229 ", 4)) { 787 inc = ippr_ftp_epsv(fin, ip, nat, f, dlen); |
788 } else if (*rptr == '5' || *rptr == '4') 789 ftp->ftp_passok = FTPXY_INIT; 790 else if (ftp->ftp_incok) { 791 if (*rptr == '3') { 792 if (ftp->ftp_passok == FTPXY_ACCT_1) 793 ftp->ftp_passok = FTPXY_GO; 794 else 795 ftp->ftp_passok++; 796 } else if (*rptr == '2') { 797 switch (ftp->ftp_passok) 798 { 799 case FTPXY_USER_1 : 800 case FTPXY_USER_2 : 801 case FTPXY_PASS_1 : 802 case FTPXY_PASS_2 : 803 case FTPXY_ACCT_1 : 804 ftp->ftp_passok = FTPXY_GO; 805 break; 806 default : 807 ftp->ftp_passok += 3; 808 break; 809 } 810 } 811 }
|
812server_cmd_ok: |
813 ftp->ftp_incok = 0; 814 815 while ((*rptr++ != '\n') && (rptr < wptr)) 816 ; 817 f->ftps_rptr = rptr; 818 return inc; 819} 820 821 822/* 823 * Look to see if the buffer starts with something which we recognise as 824 * being the correct syntax for the FTP protocol. 825 */ 826int ippr_ftp_client_valid(ftps, buf, len) 827ftpside_t *ftps; 828char *buf; 829size_t len; 830{
|
716 register char *s, c;
|
831 register char *s, c, pc; |
832 register size_t i = len; 833 char cmd[5]; 834
|
835 s = buf; 836 837 if (ftps->ftps_junk == 1) 838 return 1; 839 |
840 if (i < 5) {
|
721#if !defined(_KERNEL) && !defined(KERNEL)
722 fprintf(stdout, "ippr_ftp_client_valid:i(%lu) < 5\n",
723 (u_long)i);
724#endif
|
841 if (ippr_ftp_debug > 3) 842 printf("ippr_ftp_client_valid:i(%d) < 5\n", (int)i); |
843 return 2; 844 }
|
727 s = buf;
728 c = *s++;
|
845 |
846 i--;
|
847 c = *s++; |
848
|
731 if (isalpha(c)) {
732 cmd[0] = toupper(c);
|
849 if (ISALPHA(c)) { 850 cmd[0] = TOUPPER(c); |
851 c = *s++; 852 i--;
|
735 if (isalpha(c)) {
736 cmd[1] = toupper(c);
|
853 if (ISALPHA(c)) { 854 cmd[1] = TOUPPER(c); |
855 c = *s++; 856 i--;
|
739 if (isalpha(c)) {
740 cmd[2] = toupper(c);
|
857 if (ISALPHA(c)) { 858 cmd[2] = TOUPPER(c); |
859 c = *s++; 860 i--;
|
743 if (isalpha(c)) {
744 cmd[3] = toupper(c);
|
861 if (ISALPHA(c)) { 862 cmd[3] = TOUPPER(c); |
863 c = *s++; 864 i--; 865 if ((c != ' ') && (c != '\r')) 866 goto bad_client_command; 867 } else if ((c != ' ') && (c != '\r')) 868 goto bad_client_command; 869 } else 870 goto bad_client_command; 871 } else 872 goto bad_client_command; 873 } else { 874bad_client_command:
|
757#if !defined(_KERNEL) && !defined(KERNEL)
758 fprintf(stdout,
759 "ippr_ftp_client_valid:bad cmd:len %lu i %lu c 0x%x\n",
760 (u_long)i, (u_long)len, c);
761#endif
|
875 if (ippr_ftp_debug > 3) 876 printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*.*s]\n", 877 "ippr_ftp_client_valid", 878 ftps->ftps_junk, (int)len, (int)i, c, 879 (int)len, (int)len, buf); |
880 return 1; 881 } 882 883 for (; i; i--) {
|
884 pc = c; |
885 c = *s++;
|
767 if (c == '\n') {
|
886 if ((pc == '\r') && (c == '\n')) { |
887 cmd[4] = '\0'; 888 if (!strcmp(cmd, "PASV")) 889 ftps->ftps_cmds = FTPXY_C_PASV; 890 else 891 ftps->ftps_cmds = 0; 892 return 0; 893 } 894 }
|
776#if !defined(_KERNEL) && !defined(KERNEL)
777 fprintf(stdout, "ippr_ftp_client_valid:junk after cmd[%s]\n", buf);
|
895#if !defined(_KERNEL) 896 printf("ippr_ftp_client_valid:junk after cmd[%*.*s]\n", 897 (int)len, (int)len, buf); |
898#endif 899 return 2; 900} 901 902 903int ippr_ftp_server_valid(ftps, buf, len) 904ftpside_t *ftps; 905char *buf; 906size_t len; 907{
|
788 register char *s, c;
|
908 register char *s, c, pc; |
909 register size_t i = len; 910 int cmd; 911
|
792 if (i < 5)
793 return 2;
|
912 s = buf;
|
795 c = *s++;
|
913 cmd = 0;
|
914 915 if (ftps->ftps_junk == 1) 916 return 1; 917 918 if (i < 5) { 919 if (ippr_ftp_debug > 3) 920 printf("ippr_ftp_servert_valid:i(%d) < 5\n", (int)i); 921 return 2; 922 } 923 924 c = *s++; |
925 i--;
|
926 if (c == ' ') 927 goto search_eol; |
928
|
799 if (isdigit(c)) {
|
929 if (ISDIGIT(c)) { |
930 cmd = (c - '0') * 100; 931 c = *s++; 932 i--;
|
803 if (isdigit(c)) {
|
933 if (ISDIGIT(c)) { |
934 cmd += (c - '0') * 10; 935 c = *s++; 936 i--;
|
807 if (isdigit(c)) {
|
937 if (ISDIGIT(c)) { |
938 cmd += (c - '0'); 939 c = *s++; 940 i--; 941 if ((c != '-') && (c != ' ')) 942 goto bad_server_command; 943 } else 944 goto bad_server_command; 945 } else 946 goto bad_server_command; 947 } else { 948bad_server_command:
|
819#if !defined(_KERNEL) && !defined(KERNEL)
820 fprintf(stdout,
821 "ippr_ftp_server_valid:bad cmd:len %lu i %lu c 0x%x\n",
822 (u_long)i, (u_long)len, c);
823#endif
|
949 if (ippr_ftp_debug > 3) 950 printf("%s:bad:junk %d len %d/%d c 0x%x buf [%*.*s]\n", 951 "ippr_ftp_server_valid", 952 ftps->ftps_junk, (int)len, (int)i, 953 c, (int)len, (int)len, buf); |
954 return 1; 955 }
|
826
|
956search_eol: |
957 for (; i; i--) {
|
958 pc = c; |
959 c = *s++;
|
829 if (c == '\n') {
|
960 if ((pc == '\r') && (c == '\n')) { |
961 ftps->ftps_cmds = cmd; 962 return 0; 963 } 964 }
|
834#if !defined(_KERNEL) && !defined(KERNEL)
835 fprintf(stdout, "ippr_ftp_server_valid:junk after cmd[%s]\n", buf);
836#endif
|
965 if (ippr_ftp_debug > 3) 966 printf("ippr_ftp_server_valid:junk after cmd[%*.*s]\n", 967 (int)len, (int)len, buf); |
968 return 2; 969} 970 971 972int ippr_ftp_valid(ftp, side, buf, len) 973ftpinfo_t *ftp; 974int side; 975char *buf; 976size_t len; 977{ 978 ftpside_t *ftps; 979 int ret; 980 981 ftps = &ftp->ftp_side[side]; 982 983 if (side == 0) 984 ret = ippr_ftp_client_valid(ftps, buf, len); 985 else 986 ret = ippr_ftp_server_valid(ftps, buf, len); 987 return ret; 988} 989 990 991/*
|
992 * For map rules, the following applies: |
993 * rv == 0 for outbound processing, 994 * rv == 1 for inbound processing.
|
995 * For rdr rules, the following applies: 996 * rv == 0 for inbound processing, 997 * rv == 1 for outbound processing. |
998 */
|
864int ippr_ftp_process(fin, ip, nat, ftp, rv)
|
999int ippr_ftp_process(fin, nat, ftp, rv) |
1000fr_info_t *fin;
|
866ip_t *ip;
|
1001nat_t *nat; 1002ftpinfo_t *ftp; 1003int rv; 1004{ 1005 int mlen, len, off, inc, i, sel, sel2, ok, ackoff, seqoff;
|
1006 char *rptr, *wptr, *s; |
1007 u_32_t thseq, thack;
|
873 char *rptr, *wptr;
|
1008 ap_session_t *aps; 1009 ftpside_t *f, *t; 1010 tcphdr_t *tcp;
|
1011 ip_t *ip; |
1012 mb_t *m; 1013
|
1014 m = fin->fin_m; 1015 ip = fin->fin_ip; |
1016 tcp = (tcphdr_t *)fin->fin_dp;
|
880 off = fin->fin_hlen + (tcp->th_off << 2);
881#if SOLARIS && defined(_KERNEL)
882 m = fin->fin_qfm;
883#else
884 m = *fin->fin_mp;
885#endif
|
1017 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff; |
1018
|
887#ifndef _KERNEL
888 mlen = mbuflen(m);
|
1019 f = &ftp->ftp_side[rv]; 1020 t = &ftp->ftp_side[1 - rv]; 1021 thseq = ntohl(tcp->th_seq); 1022 thack = ntohl(tcp->th_ack); 1023 1024#ifdef __sgi 1025 mlen = fin->fin_plen - off; |
1026#else
|
890# if SOLARIS
891 mlen = msgdsize(m);
892# else
893 mlen = mbufchainlen(m);
894# endif
|
1027 mlen = MSGDSIZE(m) - off; |
1028#endif
|
896 mlen -= off;
|
1029 if (ippr_ftp_debug > 4) 1030 printf("ippr_ftp_process: mlen %d\n", mlen); |
1031
|
1032 if (mlen <= 0) { 1033 if ((tcp->th_flags & TH_OPENING) == TH_OPENING) { 1034 f->ftps_seq[0] = thseq + 1; 1035 t->ftps_seq[0] = thack; 1036 } 1037 return 0; 1038 } |
1039 aps = nat->nat_aps;
|
899 t = &ftp->ftp_side[1 - rv];
900 f = &ftp->ftp_side[rv];
901 thseq = ntohl(tcp->th_seq);
902 thack = ntohl(tcp->th_ack);
|
1040 1041 sel = aps->aps_sel[1 - rv]; 1042 sel2 = aps->aps_sel[rv]; 1043 if (rv == 0) { 1044 seqoff = aps->aps_seqoff[sel]; 1045 if (aps->aps_seqmin[sel] > seqoff + thseq) 1046 seqoff = aps->aps_seqoff[!sel]; 1047 ackoff = aps->aps_ackoff[sel2]; 1048 if (aps->aps_ackmin[sel2] > ackoff + thack) 1049 ackoff = aps->aps_ackoff[!sel2]; 1050 } else {
|
914#if PROXY_DEBUG
915 printf("seqoff %d thseq %x ackmin %x\n", seqoff, thseq,
916 aps->aps_ackmin[sel]);
917#endif
|
1051 seqoff = aps->aps_ackoff[sel];
|
1052 if (ippr_ftp_debug > 2) 1053 printf("seqoff %d thseq %x ackmin %x\n", seqoff, thseq, 1054 aps->aps_ackmin[sel]); |
1055 if (aps->aps_ackmin[sel] > seqoff + thseq) 1056 seqoff = aps->aps_ackoff[!sel]; 1057
|
922#if PROXY_DEBUG
923 printf("ackoff %d thack %x seqmin %x\n", ackoff, thack,
924 aps->aps_seqmin[sel2]);
925#endif
|
1058 ackoff = aps->aps_seqoff[sel2];
|
1059 if (ippr_ftp_debug > 2) 1060 printf("ackoff %d thack %x seqmin %x\n", ackoff, thack, 1061 aps->aps_seqmin[sel2]); |
1062 if (ackoff > 0) { 1063 if (aps->aps_seqmin[sel2] > ackoff + thack) 1064 ackoff = aps->aps_seqoff[!sel2]; 1065 } else { 1066 if (aps->aps_seqmin[sel2] > thack) 1067 ackoff = aps->aps_seqoff[!sel2]; 1068 } 1069 }
|
935#if PROXY_DEBUG
936 printf("%s: %x seq %x/%d ack %x/%d len %d\n", rv ? "IN" : "OUT",
937 tcp->th_flags, thseq, seqoff, thack, ackoff, mlen);
938 printf("sel %d seqmin %x/%x offset %d/%d\n", sel,
939 aps->aps_seqmin[sel], aps->aps_seqmin[sel2],
940 aps->aps_seqoff[sel], aps->aps_seqoff[sel2]);
941 printf("sel %d ackmin %x/%x offset %d/%d\n", sel2,
942 aps->aps_ackmin[sel], aps->aps_ackmin[sel2],
943 aps->aps_ackoff[sel], aps->aps_ackoff[sel2]);
944#endif
|
1070 if (ippr_ftp_debug > 2) { 1071 printf("%s: %x seq %x/%d ack %x/%d len %d/%d off %d\n", 1072 rv ? "IN" : "OUT", tcp->th_flags, thseq, seqoff, 1073 thack, ackoff, mlen, fin->fin_plen, off); 1074 printf("sel %d seqmin %x/%x offset %d/%d\n", sel, 1075 aps->aps_seqmin[sel], aps->aps_seqmin[sel2], 1076 aps->aps_seqoff[sel], aps->aps_seqoff[sel2]); 1077 printf("sel %d ackmin %x/%x offset %d/%d\n", sel2, 1078 aps->aps_ackmin[sel], aps->aps_ackmin[sel2], 1079 aps->aps_ackoff[sel], aps->aps_ackoff[sel2]); 1080 } |
1081 1082 /* 1083 * XXX - Ideally, this packet should get dropped because we now know 1084 * that it is out of order (and there is no real danger in doing so 1085 * apart from causing packets to go through here ordered). 1086 */
|
951#if PROXY_DEBUG
952 printf("rv %d t:seq[0] %x seq[1] %x %d/%d\n",
953 rv, t->ftps_seq[0], t->ftps_seq[1], seqoff, ackoff);
954#endif
|
1087 if (ippr_ftp_debug > 2) { 1088 printf("rv %d t:seq[0] %x seq[1] %x %d/%d\n", 1089 rv, t->ftps_seq[0], t->ftps_seq[1], seqoff, ackoff); 1090 } |
1091 1092 ok = 0; 1093 if (t->ftps_seq[0] == 0) { 1094 t->ftps_seq[0] = thack; 1095 ok = 1; 1096 } else { 1097 if (ackoff == 0) { 1098 if (t->ftps_seq[0] == thack) 1099 ok = 1; 1100 else if (t->ftps_seq[1] == thack) { 1101 t->ftps_seq[0] = thack; 1102 ok = 1; 1103 } 1104 } else { 1105 if (t->ftps_seq[0] + ackoff == thack) 1106 ok = 1; 1107 else if (t->ftps_seq[0] == thack + ackoff) 1108 ok = 1; 1109 else if (t->ftps_seq[1] + ackoff == thack) { 1110 t->ftps_seq[0] = thack - ackoff; 1111 ok = 1; 1112 } else if (t->ftps_seq[1] == thack + ackoff) { 1113 t->ftps_seq[0] = thack - ackoff; 1114 ok = 1; 1115 } 1116 } 1117 } 1118
|
983#if PROXY_DEBUG
984 if (!ok)
985 printf("not ok\n");
986#endif
|
1119 if (ippr_ftp_debug > 2) { 1120 if (!ok) 1121 printf("%s ok\n", "not"); 1122 } |
1123 1124 if (!mlen) { 1125 if (t->ftps_seq[0] + ackoff != thack) {
|
990#if !defined(_KERNEL) && !defined(KERNEL)
991 fprintf(stdout,
992 "ippr_ftp_process:seq[0](%x) + ackoff(%x) != thack(%x)\n",
993 t->ftps_seq[0], ackoff, thack);
994#endif
|
1126 if (ippr_ftp_debug > 1) { 1127 printf("%s:seq[0](%x) + (%x) != (%x)\n", 1128 "ippr_ftp_process", t->ftps_seq[0], 1129 ackoff, thack); 1130 } |
1131 return APR_ERR(1); 1132 } 1133
|
998#if PROXY_DEBUG
999 printf("f:seq[0] %x seq[1] %x\n", f->ftps_seq[0], f->ftps_seq[1]);
1000#endif
|
1134 if (ippr_ftp_debug > 2) { 1135 printf("ippr_ftp_process:f:seq[0] %x seq[1] %x\n", 1136 f->ftps_seq[0], f->ftps_seq[1]); 1137 } 1138 |
1139 if (tcp->th_flags & TH_FIN) { 1140 if (thseq == f->ftps_seq[1]) { 1141 f->ftps_seq[0] = f->ftps_seq[1] - seqoff; 1142 f->ftps_seq[1] = thseq + 1 - seqoff; 1143 } else {
|
1006#if PROXY_DEBUG || (!defined(_KERNEL) && !defined(KERNEL))
1007 printf("FIN: thseq %x seqoff %d ftps_seq %x\n",
1008 thseq, seqoff, f->ftps_seq[0]);
1009#endif
|
1144 if (ippr_ftp_debug > 1) { 1145 printf("FIN: thseq %x seqoff %d ftps_seq %x\n", 1146 thseq, seqoff, f->ftps_seq[0]); 1147 } |
1148 return APR_ERR(1); 1149 } 1150 } 1151 f->ftps_len = 0; 1152 return 0; 1153 } 1154 1155 ok = 0; 1156 if ((thseq == f->ftps_seq[0]) || (thseq == f->ftps_seq[1])) { 1157 ok = 1; 1158 /* 1159 * Retransmitted data packet. 1160 */ 1161 } else if ((thseq + mlen == f->ftps_seq[0]) || 1162 (thseq + mlen == f->ftps_seq[1])) { 1163 ok = 1; 1164 } 1165 1166 if (ok == 0) { 1167 inc = thseq - f->ftps_seq[0];
|
1030#if PROXY_DEBUG || (!defined(_KERNEL) && !defined(KERNEL))
1031 printf("inc %d sel %d rv %d\n", inc, sel, rv);
1032 printf("th_seq %x ftps_seq %x/%x\n", thseq, f->ftps_seq[0],
1033 f->ftps_seq[1]);
1034 printf("ackmin %x ackoff %d\n", (u_int)aps->aps_ackmin[sel],
1035 aps->aps_ackoff[sel]);
1036 printf("seqmin %x seqoff %d\n", (u_int)aps->aps_seqmin[sel],
1037 aps->aps_seqoff[sel]);
1038#endif
|
1168 if (ippr_ftp_debug > 1) { 1169 printf("inc %d sel %d rv %d\n", inc, sel, rv); 1170 printf("th_seq %x ftps_seq %x/%x\n", 1171 thseq, f->ftps_seq[0], f->ftps_seq[1]); 1172 printf("ackmin %x ackoff %d\n", aps->aps_ackmin[sel], 1173 aps->aps_ackoff[sel]); 1174 printf("seqmin %x seqoff %d\n", aps->aps_seqmin[sel], 1175 aps->aps_seqoff[sel]); 1176 } |
1177 1178 return APR_ERR(1); 1179 } 1180 1181 inc = 0; 1182 rptr = f->ftps_rptr; 1183 wptr = f->ftps_wptr; 1184 f->ftps_seq[0] = thseq; 1185 f->ftps_seq[1] = f->ftps_seq[0] + mlen; 1186 f->ftps_len = mlen; 1187 1188 while (mlen > 0) {
|
1051 len = MIN(mlen, FTP_BUFSZ / 2);
1052
1053#if !defined(_KERNEL)
1054 bcopy((char *)m + off, wptr, len);
1055#else
1056# if SOLARIS
1057 copyout_mblk(m, off, len, wptr);
1058# else
1059 m_copydata(m, off, len, wptr);
1060# endif
1061#endif
|
1189 len = MIN(mlen, sizeof(f->ftps_buf) - (wptr - rptr)); 1190 COPYDATA(m, off, len, wptr); |
1191 mlen -= len; 1192 off += len; 1193 wptr += len;
|
1194 1195 if (ippr_ftp_debug > 3) 1196 printf("%s:len %d/%d off %d wptr %lx junk %d [%*.*s]\n", 1197 "ippr_ftp_process", 1198 len, mlen, off, (u_long)wptr, f->ftps_junk, 1199 len, len, rptr); 1200 |
1201 f->ftps_wptr = wptr;
|
1066 if (f->ftps_junk == 2)
|
1202 if (f->ftps_junk != 0) { 1203 i = f->ftps_junk; |
1204 f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, 1205 wptr - rptr); 1206
|
1207 if (ippr_ftp_debug > 5) 1208 printf("%s:junk %d -> %d\n", 1209 "ippr_ftp_process", i, f->ftps_junk); 1210 1211 if (f->ftps_junk != 0) { 1212 if (wptr - rptr == sizeof(f->ftps_buf)) { 1213 if (ippr_ftp_debug > 4) 1214 printf("%s:full buffer\n", 1215 "ippr_ftp_process"); 1216 f->ftps_rptr = f->ftps_buf; 1217 f->ftps_wptr = f->ftps_buf; 1218 rptr = f->ftps_rptr; 1219 wptr = f->ftps_wptr; 1220 /* 1221 * Because we throw away data here that 1222 * we would otherwise parse, set the 1223 * junk flag to indicate just ignore 1224 * any data upto the next CRLF. 1225 */ 1226 f->ftps_junk = 1; 1227 continue; 1228 } 1229 } 1230 } 1231 |
1232 while ((f->ftps_junk == 0) && (wptr > rptr)) {
|
1071 f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr,
1072 wptr - rptr);
|
1233 len = wptr - rptr; 1234 f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr, len); 1235 1236 if (ippr_ftp_debug > 3) { 1237 printf("%s=%d len %d rv %d ptr %lx/%lx ", 1238 "ippr_ftp_valid", 1239 f->ftps_junk, len, rv, (u_long)rptr, 1240 (u_long)wptr); 1241 printf("buf [%*.*s]\n", len, len, rptr); 1242 } 1243 |
1244 if (f->ftps_junk == 0) {
|
1074 f->ftps_cmds++;
1075 len = wptr - rptr;
|
1245 f->ftps_rptr = rptr; 1246 if (rv) 1247 inc += ippr_ftp_server(fin, ip, nat, 1248 ftp, len); 1249 else 1250 inc += ippr_ftp_client(fin, ip, nat, 1251 ftp, len); 1252 rptr = f->ftps_rptr; 1253 wptr = f->ftps_wptr; 1254 } 1255 } 1256 1257 /* 1258 * Off to a bad start so lets just forget about using the 1259 * ftp proxy for this connection. 1260 */ 1261 if ((f->ftps_cmds == 0) && (f->ftps_junk == 1)) { 1262 /* f->ftps_seq[1] += inc; */
|
1094#if !defined(_KERNEL) && !defined(KERNEL)
1095 fprintf(stdout,
1096 "ippr_ftp_process:cmds == 0 junk == 1\n");
1097#endif
|
1263 1264 if (ippr_ftp_debug > 1) 1265 printf("%s:cmds == 0 junk == 1\n", 1266 "ippr_ftp_process"); |
1267 return APR_ERR(2); 1268 } 1269
|
1101 while ((f->ftps_junk == 1) && (rptr < wptr)) {
1102 while ((rptr < wptr) && (*rptr != '\r'))
1103 rptr++;
1104
1105 if (*rptr == '\r') {
1106 if (rptr + 1 < wptr) {
1107 if (*(rptr + 1) == '\n') {
1108 rptr += 2;
1109 f->ftps_junk = 0;
1110 } else
1111 rptr++;
1112 } else
|
1270 if ((f->ftps_junk != 0) && (rptr < wptr)) { 1271 for (s = rptr; s < wptr; s++) { 1272 if ((*s == '\r') && (s + 1 < wptr) && 1273 (*(s + 1) == '\n')) { 1274 rptr = s + 2; 1275 f->ftps_junk = 0; |
1276 break;
|
1277 } |
1278 } 1279 }
|
1116 f->ftps_rptr = rptr;
|
1280 1281 if (rptr == wptr) { 1282 rptr = wptr = f->ftps_buf; 1283 } else {
|
1121 if ((wptr > f->ftps_buf + FTP_BUFSZ / 2)) {
1122 i = wptr - rptr;
1123 if ((rptr == f->ftps_buf) ||
1124 (wptr - rptr > FTP_BUFSZ / 2)) {
1125 f->ftps_junk = 1;
1126 rptr = wptr = f->ftps_buf;
1127 } else {
1128 bcopy(rptr, f->ftps_buf, i);
1129 wptr = f->ftps_buf + i;
1130 rptr = f->ftps_buf;
1131 }
|
1284 /* 1285 * Compact the buffer back to the start. The junk 1286 * flag should already be set and because we're not 1287 * throwing away any data, it is preserved from its 1288 * current state. 1289 */ 1290 if (rptr > f->ftps_buf) { 1291 bcopy(rptr, f->ftps_buf, len); 1292 wptr -= rptr - f->ftps_buf; 1293 rptr = f->ftps_buf; |
1294 }
|
1133 f->ftps_rptr = rptr;
1134 f->ftps_wptr = wptr;
|
1295 }
|
1296 f->ftps_rptr = rptr; 1297 f->ftps_wptr = wptr; |
1298 } 1299 1300 /* f->ftps_seq[1] += inc; */ 1301 if (tcp->th_flags & TH_FIN) 1302 f->ftps_seq[1]++;
|
1141#if PROXY_DEBUG
1142# ifndef _KERNEL
1143 mlen = mbuflen(m);
1144# else
1145# if SOLARIS
1146 mlen = msgdsize(m);
1147# else
1148 mlen = mbufchainlen(m);
1149# endif
1150# endif
1151 mlen -= off;
1152 printf("ftps_seq[1] = %x inc %d len %d\n", f->ftps_seq[1], inc, mlen);
|
1303 if (ippr_ftp_debug > 3) { 1304#ifdef __sgi 1305 mlen = fin->fin_plen; 1306#else 1307 mlen = MSGDSIZE(m); |
1308#endif
|
1309 mlen -= off; 1310 printf("ftps_seq[1] = %x inc %d len %d\n", 1311 f->ftps_seq[1], inc, mlen); 1312 } |
1313 1314 f->ftps_rptr = rptr; 1315 f->ftps_wptr = wptr; 1316 return APR_INC(inc); 1317} 1318 1319
|
1161int ippr_ftp_out(fin, ip, aps, nat)
|
1320int ippr_ftp_out(fin, aps, nat) |
1321fr_info_t *fin;
|
1163ip_t *ip;
|
1322ap_session_t *aps; 1323nat_t *nat; 1324{ 1325 ftpinfo_t *ftp;
|
1326 int rev; |
1327 1328 ftp = aps->aps_data; 1329 if (ftp == NULL) 1330 return 0;
|
1172 return ippr_ftp_process(fin, ip, nat, ftp, 0);
|
1331 1332 rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; 1333 if (ftp->ftp_side[1 - rev].ftps_ifp == NULL) 1334 ftp->ftp_side[1 - rev].ftps_ifp = fin->fin_ifp; 1335 1336 return ippr_ftp_process(fin, nat, ftp, rev); |
1337} 1338 1339
|
1176int ippr_ftp_in(fin, ip, aps, nat)
|
1340int ippr_ftp_in(fin, aps, nat) |
1341fr_info_t *fin;
|
1178ip_t *ip;
|
1342ap_session_t *aps; 1343nat_t *nat; 1344{ 1345 ftpinfo_t *ftp;
|
1346 int rev; |
1347 1348 ftp = aps->aps_data; 1349 if (ftp == NULL) 1350 return 0;
|
1187 return ippr_ftp_process(fin, ip, nat, ftp, 1);
|
1351 1352 rev = (nat->nat_dir == NAT_OUTBOUND) ? 0 : 1; 1353 if (ftp->ftp_side[rev].ftps_ifp == NULL) 1354 ftp->ftp_side[rev].ftps_ifp = fin->fin_ifp; 1355 1356 return ippr_ftp_process(fin, nat, ftp, 1 - rev); |
1357} 1358 1359 1360/* 1361 * ippr_ftp_atoi - implement a version of atoi which processes numbers in 1362 * pairs separated by commas (which are expected to be in the range 0 - 255), 1363 * returning a 16 bit number combining either side of the , as the MSB and 1364 * LSB. 1365 */ 1366u_short ippr_ftp_atoi(ptr) 1367char **ptr; 1368{ 1369 register char *s = *ptr, c; 1370 register u_char i = 0, j = 0; 1371
|
1203 while ((c = *s++) && isdigit(c)) {
|
1372 while (((c = *s++) != '\0') && ISDIGIT(c)) { |
1373 i *= 10; 1374 i += c - '0'; 1375 } 1376 if (c != ',') { 1377 *ptr = NULL; 1378 return 0; 1379 }
|
1211 while ((c = *s++) && isdigit(c)) {
|
1380 while (((c = *s++) != '\0') && ISDIGIT(c)) { |
1381 j *= 10; 1382 j += c - '0'; 1383 } 1384 *ptr = s; 1385 i &= 0xff; 1386 j &= 0xff; 1387 return (i << 8) | j; 1388}
|
1389 1390 1391int ippr_ftp_epsv(fin, ip, nat, f, dlen) 1392fr_info_t *fin; 1393ip_t *ip; 1394nat_t *nat; 1395ftpside_t *f; 1396int dlen; 1397{ 1398 char newbuf[IPF_FTPBUFSZ]; 1399 char *s; 1400 u_short ap = 0; 1401 1402#define EPSV_REPLEN 33 1403 /* 1404 * Check for EPSV reply message. 1405 */ 1406 if (dlen < IPF_MIN229LEN) 1407 return (0); 1408 else if (strncmp(f->ftps_rptr, 1409 "229 Entering Extended Passive Mode", EPSV_REPLEN)) 1410 return (0); 1411 1412 /* 1413 * Skip the EPSV command + space 1414 */ 1415 s = f->ftps_rptr + 33; 1416 while (*s && !ISDIGIT(*s)) 1417 s++; 1418 1419 /* 1420 * As per RFC 2428, there are no addres components in the EPSV 1421 * response. So we'll go straight to getting the port. 1422 */ 1423 while (*s && ISDIGIT(*s)) { 1424 ap *= 10; 1425 ap += *s++ - '0'; 1426 } 1427 1428 if (!s) 1429 return 0; 1430 1431 if (*s == '|') 1432 s++; 1433 if (*s == ')') 1434 s++; 1435 if (*s == '\n') 1436 s--; 1437 /* 1438 * check for CR-LF at the end. 1439 */ 1440 if ((*s == '\r') && (*(s + 1) == '\n')) { 1441 s += 2; 1442 } else 1443 return 0; 1444 1445#if defined(SNPRINTF) && defined(_KERNEL) 1446 SNPRINTF(newbuf, sizeof(newbuf), "%s (|||%u|)\r\n", 1447 "229 Entering Extended Passive Mode", ap); 1448#else 1449 (void) sprintf(newbuf, "%s (|||%u|)\r\n", 1450 "229 Entering Extended Passive Mode", ap); 1451#endif 1452 1453 return ippr_ftp_pasvreply(fin, ip, nat, f, (u_int)ap, newbuf, s, 1454 ip->ip_src.s_addr); 1455} |
|