Deleted Added
sdiff udiff text old ( 130886 ) new ( 145522 )
full compact
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 *
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 */
14
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
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));
48int ippr_ftp_in __P((fr_info_t *, ap_session_t *, nat_t *));
49int ippr_ftp_init __P((void));
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));
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
65
66int ftp_proxy_init = 0;
67int ippr_ftp_pasvonly = 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
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;
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;
166 int inc, off, flags;
167 u_short a5, a6, sp;
168 size_t nlen, olen;
169 fr_info_t fi;
170 nat_t *nat2;
171 mb_t *m;
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) {
181 if (ippr_ftp_debug > 1)
182 printf("ippr_ftp_port:dlen(%d) < IPF_MINPORTLEN\n",
183 dlen);
184 return 0;
185 }
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) {
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) {
201 if (ippr_ftp_debug > 1)
202 printf("ippr_ftp_port:ippr_ftp_atoi(%d) failed\n", 2);
203 return 0;
204 }
205
206 /*
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;
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) {
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 {
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 */
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! */
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) {
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)
287 bcopy(newbuf, MTOD(m, char *) + off, nlen);
288#else
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);
300# endif /* defined(MENTAT) */
301#endif /* !defined(_KERNEL) */
302 COPYBACK(m, off, nlen, newbuf);
303
304 if (inc != 0) {
305 ip->ip_len += inc;
306 fin->fin_dlen += inc;
307 fin->fin_plen += inc;
308 }
309
310 /*
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;
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);
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;
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;
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 }
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];
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{
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;
480
481 if (ippr_ftp_forcepasv != 0 &&
482 ftp->ftp_side[0].ftps_cmds != FTPXY_C_PASV) {
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) {
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)) {
502 if (ippr_ftp_debug > 0)
503 printf("ippr_ftp_pasv:%d reply wrong\n", 227);
504 return 0;
505 }
506
507 brackets[0] = "";
508 brackets[1] = "";
509 /*
510 * Skip the PASV reply + space
511 */
512 s = f->ftps_rptr + PASV_REPLEN;
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) {
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) {
532 if (ippr_ftp_debug > 1)
533 printf("ippr_ftp_pasv:ippr_ftp_atoi(%d) failed\n", 2);
534 return 0;
535 }
536
537 /*
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;
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) {
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;
571 } else {
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 */
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;
592
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
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
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
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
629 data_addr.s_addr = data_ip;
630 tcp2 = &tcph;
631 inc = 0;
632
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 }
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);
658# endif /* defined(MENTAT) */
659#endif /* !defined(_KERNEL) */
660 COPYBACK(m, off, nlen, newmsg);
661
662 if (inc != 0) {
663 ip->ip_len += inc;
664 fin->fin_dlen += inc;
665 fin->fin_plen += inc;
666 }
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;
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 */
695 TCP_OFF_A(tcp2, 5);
696 tcp2->th_flags = TH_SYN;
697 fi.fin_data[1] = port;
698 fi.fin_dlen = sizeof(*tcp2);
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;
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;
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
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{
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) {
841 if (ippr_ftp_debug > 3)
842 printf("ippr_ftp_client_valid:i(%d) < 5\n", (int)i);
843 return 2;
844 }
845
846 i--;
847 c = *s++;
848
849 if (ISALPHA(c)) {
850 cmd[0] = TOUPPER(c);
851 c = *s++;
852 i--;
853 if (ISALPHA(c)) {
854 cmd[1] = TOUPPER(c);
855 c = *s++;
856 i--;
857 if (ISALPHA(c)) {
858 cmd[2] = TOUPPER(c);
859 c = *s++;
860 i--;
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:
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++;
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 }
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{
908 register char *s, c, pc;
909 register size_t i = len;
910 int cmd;
911
912 s = buf;
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
929 if (ISDIGIT(c)) {
930 cmd = (c - '0') * 100;
931 c = *s++;
932 i--;
933 if (ISDIGIT(c)) {
934 cmd += (c - '0') * 10;
935 c = *s++;
936 i--;
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:
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 }
956search_eol:
957 for (; i; i--) {
958 pc = c;
959 c = *s++;
960 if ((pc == '\r') && (c == '\n')) {
961 ftps->ftps_cmds = cmd;
962 return 0;
963 }
964 }
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 */
999int ippr_ftp_process(fin, nat, ftp, rv)
1000fr_info_t *fin;
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;
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;
1017 off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
1018
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
1027 mlen = MSGDSIZE(m) - off;
1028#endif
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;
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 {
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
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 }
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 */
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
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) {
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
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 {
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];
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) {
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;
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)) {
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) {
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; */
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
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 }
1280
1281 if (rptr == wptr) {
1282 rptr = wptr = f->ftps_buf;
1283 } else {
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 }
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]++;
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
1320int ippr_ftp_out(fin, aps, nat)
1321fr_info_t *fin;
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;
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
1340int ippr_ftp_in(fin, aps, nat)
1341fr_info_t *fin;
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;
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
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 }
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}