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