2 * Simple FTP transparent proxy for in-kernel use. For use with the NAT
4 * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c,v 1.17.2.5 2003/03/01 03:55:54 darrenr Exp $
5 * $DragonFly: src/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c,v 1.2 2003/06/17 04:28:20 dillon Exp $
7 #if SOLARIS && defined(_KERNEL)
8 extern kmutex_t ipf_rw;
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')
19 #define IPF_MINPORTLEN 18
20 #define IPF_MAXPORTLEN 30
21 #define IPF_MIN227LEN 39
22 #define IPF_MAX227LEN 51
23 #define IPF_FTPBUFSZ 96 /* This *MUST* be >= 53! */
27 #define FTPXY_USER_1 2
28 #define FTPXY_USOK_1 3
29 #define FTPXY_PASS_1 4
30 #define FTPXY_PAOK_1 5
31 #define FTPXY_AUTH_1 6
32 #define FTPXY_AUOK_1 7
33 #define FTPXY_ADAT_1 8
34 #define FTPXY_ADOK_1 9
35 #define FTPXY_ACCT_1 10
36 #define FTPXY_ACOK_1 11
37 #define FTPXY_USER_2 12
38 #define FTPXY_USOK_2 13
39 #define FTPXY_PASS_2 14
40 #define FTPXY_PAOK_2 15
43 * Values for FTP commands. Numerics cover 0-999
45 #define FTPXY_C_PASV 1000
47 int ippr_ftp_client __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int));
48 int ippr_ftp_complete __P((char *, size_t));
49 int ippr_ftp_in __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *));
50 int ippr_ftp_init __P((void));
51 int ippr_ftp_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *));
52 int ippr_ftp_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *));
53 int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int));
54 int ippr_ftp_port __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int));
55 int ippr_ftp_process __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int));
56 int ippr_ftp_server __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int));
57 int ippr_ftp_valid __P((ftpinfo_t *, int, char *, size_t));
58 int ippr_ftp_server_valid __P((ftpside_t *, char *, size_t));
59 int ippr_ftp_client_valid __P((ftpside_t *, char *, size_t));
60 u_short ippr_ftp_atoi __P((char **));
62 static frentry_t ftppxyfr;
63 int ippr_ftp_pasvonly = 0;
64 int ippr_ftp_insecure = 0;
65 int ippr_ftp_forcepasv = 0;
69 * Initialize local structures.
73 bzero((char *)&ftppxyfr, sizeof(ftppxyfr));
75 ftppxyfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
80 int ippr_ftp_new(fin, ip, aps, nat)
89 KMALLOC(ftp, ftpinfo_t *);
93 aps->aps_psiz = sizeof(ftpinfo_t);
95 bzero((char *)ftp, sizeof(*ftp));
96 f = &ftp->ftp_side[0];
97 f->ftps_rptr = f->ftps_buf;
98 f->ftps_wptr = f->ftps_buf;
99 f = &ftp->ftp_side[1];
100 f->ftps_rptr = f->ftps_buf;
101 f->ftps_wptr = f->ftps_buf;
102 ftp->ftp_passok = FTPXY_INIT;
107 int ippr_ftp_port(fin, ip, nat, f, dlen)
114 tcphdr_t *tcp, tcph, *tcp2 = &tcph;
115 char newbuf[IPF_FTPBUFSZ], *s;
116 u_int a1, a2, a3, a4;
128 tcp = (tcphdr_t *)fin->fin_dp;
130 * Check for client sending out PORT message.
132 if (dlen < IPF_MINPORTLEN) {
133 #if !defined(_KERNEL) && !defined(KERNEL)
135 "ippr_ftp_port:dlen(%d) < IPF_MINPORTLEN\n", dlen);
139 off = fin->fin_hlen + (tcp->th_off << 2);
141 * Skip the PORT command + space
143 s = f->ftps_rptr + 5;
145 * Pick out the address components, two at a time.
147 a1 = ippr_ftp_atoi(&s);
149 #if !defined(_KERNEL) && !defined(KERNEL)
150 fprintf(stdout, "ippr_ftp_port:ippr_ftp_atoi(1) failed\n");
154 a2 = ippr_ftp_atoi(&s);
156 #if !defined(_KERNEL) && !defined(KERNEL)
157 fprintf(stdout, "ippr_ftp_port:ippr_ftp_atoi(2) failed\n");
162 * check that IP address in the PORT/PASV reply is the same as the
163 * sender of the command - prevents using PORT for port scanning.
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");
174 a5 = ippr_ftp_atoi(&s);
176 #if !defined(_KERNEL) && !defined(KERNEL)
177 fprintf(stdout, "ippr_ftp_port:ippr_ftp_atoi(3) failed\n");
185 * check for CR-LF at the end.
189 if ((*s == '\r') && (*(s + 1) == '\n')) {
193 #if !defined(_KERNEL) && !defined(KERNEL)
194 fprintf(stdout, "ippr_ftp_port:missing cr-lf\n");
201 * Calculate new address parts for PORT command
203 a1 = ntohl(ip->ip_src.s_addr);
204 a2 = (a1 >> 16) & 0xff;
205 a3 = (a1 >> 8) & 0xff;
208 olen = s - f->ftps_rptr;
209 /* DO NOT change this to snprintf! */
210 (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n",
211 "PORT", a1, a2, a3, a4, a5, a6);
213 nlen = strlen(newbuf);
215 if ((inc + ip->ip_len) > 65535) {
216 #if !defined(_KERNEL) && !defined(KERNEL)
218 "ippr_ftp_port:inc(%d) + ip->ip_len > 65535\n", inc);
223 #if !defined(_KERNEL)
224 m = *((mb_t **)fin->fin_mp);
225 bcopy(newbuf, (char *)m + off, nlen);
229 for (m1 = m; m1->b_cont; m1 = m1->b_cont)
231 if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) {
234 /* alloc enough to keep same trailer space for lower driver */
235 nm = allocb(nlen, BPRI_MED);
236 PANIC((!nm),("ippr_ftp_out: allocb failed"));
238 nm->b_band = m1->b_band;
242 PANIC((m1->b_wptr < m1->b_rptr),
243 ("ippr_ftp_out: cannot handle fragmented data block"));
247 if (m1->b_datap->db_struiolim == m1->b_wptr)
248 m1->b_datap->db_struiolim += inc;
249 m1->b_datap->db_struioflag &= ~STRUIO_IP;
252 copyin_mblk(m, off, nlen, newbuf);
254 m = *((mb_t **)fin->fin_mp);
257 /* the mbuf chain will be extended if necessary by m_copyback() */
258 m_copyback(m, off, nlen, newbuf);
260 if (!(m->m_flags & M_PKTHDR))
261 m->m_pkthdr.len += inc;
266 #if (SOLARIS || defined(__sgi)) && defined(_KERNEL)
267 register u_32_t sum1, sum2;
270 sum2 = ip->ip_len + inc;
272 /* Because ~1 == -2, We really need ~1 == -1 */
276 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
278 fix_outcksum(fin, &ip->ip_sum, sum2);
284 * Add skeleton NAT entry for connection which will come back the
289 * Don't allow the PORT command to specify a port < 1024 due to
293 #if !defined(_KERNEL) && !defined(KERNEL)
294 fprintf(stdout, "ippr_ftp_port:sp(%d) < 1024\n", sp);
300 * The server may not make the connection back from port 20, but
301 * it is the most likely so use it here to check for a conflicting
304 bcopy((char *)fin, (char *)&fi, sizeof(fi));
306 fi.fin_data[1] = fin->fin_data[1] - 1;
307 ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip,
313 ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
314 bzero((char *)tcp2, sizeof(*tcp2));
315 tcp2->th_win = htons(8192);
316 tcp2->th_sport = htons(sp);
318 tcp2->th_flags = TH_SYN;
319 tcp2->th_dport = 0; /* XXX - don't specify remote port */
321 fi.fin_dlen = sizeof(*tcp2);
322 fi.fin_dp = (char *)tcp2;
323 fi.fin_fr = &ftppxyfr;
326 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
327 ip->ip_src = nat->nat_inip;
328 ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_DPORT,
331 ipn->nat_age = fr_defnatage;
332 (void) fr_addstate(ip, &fi, NULL,
333 FI_W_DPORT|FI_IGNOREPKT);
342 int ippr_ftp_client(fin, ip, nat, ftp, dlen)
349 char *rptr, *wptr, cmd[6], c;
354 f = &ftp->ftp_side[0];
358 for (i = 0; (i < 5) && (i < dlen); i++) {
369 if (!strncmp(cmd, "USER ", 5) || !strncmp(cmd, "XAUT ", 5)) {
370 if (ftp->ftp_passok == FTPXY_ADOK_1 ||
371 ftp->ftp_passok == FTPXY_AUOK_1) {
372 ftp->ftp_passok = FTPXY_USER_2;
375 ftp->ftp_passok = FTPXY_USER_1;
378 } else if (!strncmp(cmd, "AUTH ", 5)) {
379 ftp->ftp_passok = FTPXY_AUTH_1;
381 } else if (!strncmp(cmd, "PASS ", 5)) {
382 if (ftp->ftp_passok == FTPXY_USOK_1) {
383 ftp->ftp_passok = FTPXY_PASS_1;
385 } else if (ftp->ftp_passok == FTPXY_USOK_2) {
386 ftp->ftp_passok = FTPXY_PASS_2;
389 } else if ((ftp->ftp_passok == FTPXY_AUOK_1) &&
390 !strncmp(cmd, "ADAT ", 5)) {
391 ftp->ftp_passok = FTPXY_ADAT_1;
393 } else if ((ftp->ftp_passok == FTPXY_PAOK_1 ||
394 ftp->ftp_passok == FTPXY_PAOK_2) &&
395 !strncmp(cmd, "ACCT ", 5)) {
396 ftp->ftp_passok = FTPXY_ACCT_1;
398 } else if ((ftp->ftp_passok == FTPXY_GO) && !ippr_ftp_pasvonly &&
399 !strncmp(cmd, "PORT ", 5)) {
400 inc = ippr_ftp_port(fin, ip, nat, f, dlen);
401 } else if (ippr_ftp_insecure && !ippr_ftp_pasvonly &&
402 !strncmp(cmd, "PORT ", 5)) {
403 inc = ippr_ftp_port(fin, ip, nat, f, dlen);
406 while ((*rptr++ != '\n') && (rptr < wptr))
413 int ippr_ftp_pasv(fin, ip, nat, ftp, dlen)
420 tcphdr_t *tcp, tcph, *tcp2 = &tcph;
421 struct in_addr swip, swip2;
422 u_int a1, a2, a3, a4;
430 if (ippr_ftp_forcepasv != 0 &&
431 ftp->ftp_side[0].ftps_cmds != FTPXY_C_PASV) {
432 #if !defined(_KERNEL) && !defined(KERNEL)
434 "ippr_ftp_pasv:ftps_cmds(%d) != FTPXY_C_PASV\n",
435 ftp->ftp_side[0].ftps_cmds);
440 f = &ftp->ftp_side[1];
442 #define PASV_REPLEN 24
444 * Check for PASV reply message.
446 if (dlen < IPF_MIN227LEN) {
447 #if !defined(_KERNEL) && !defined(KERNEL)
449 "ippr_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n", dlen);
452 } else if (strncmp(f->ftps_rptr,
453 "227 Entering Passive Mod", PASV_REPLEN)) {
454 #if !defined(_KERNEL) && !defined(KERNEL)
455 fprintf(stdout, "ippr_ftp_pasv:227 reply wrong\n");
460 tcp = (tcphdr_t *)fin->fin_dp;
463 * Skip the PASV reply + space
465 s = f->ftps_rptr + PASV_REPLEN;
466 while (*s && !isdigit(*s))
469 * Pick out the address components, two at a time.
471 a1 = ippr_ftp_atoi(&s);
473 #if !defined(_KERNEL) && !defined(KERNEL)
474 fprintf(stdout, "ippr_ftp_pasv:ippr_ftp_atoi(1) failed\n");
478 a2 = ippr_ftp_atoi(&s);
480 #if !defined(_KERNEL) && !defined(KERNEL)
481 fprintf(stdout, "ippr_ftp_pasv:ippr_ftp_atoi(2) failed\n");
487 * check that IP address in the PORT/PASV reply is the same as the
488 * sender of the command - prevents using PORT for port scanning.
492 if (a1 != ntohl(nat->nat_oip.s_addr)) {
493 #if !defined(_KERNEL) && !defined(KERNEL)
494 fprintf(stdout, "ippr_ftp_pasv:a1 != nat->nat_oip\n");
499 a5 = ippr_ftp_atoi(&s);
501 #if !defined(_KERNEL) && !defined(KERNEL)
502 fprintf(stdout, "ippr_ftp_pasv:ippr_ftp_atoi(3) failed\n");
514 * check for CR-LF at the end.
516 if ((*s == '\r') && (*(s + 1) == '\n')) {
520 #if !defined(_KERNEL) && !defined(KERNEL)
521 fprintf(stdout, "ippr_ftp_pasv:missing cr-lf\n");
527 * Calculate new address parts for 227 reply
529 a1 = ntohl(ip->ip_src.s_addr);
530 a2 = (a1 >> 16) & 0xff;
531 a3 = (a1 >> 8) & 0xff;
536 olen = s - f->ftps_rptr;
537 (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n",
538 "227 Entering Passive Mode", a1, a2, a3, a4, a5, a6);
539 nlen = strlen(newbuf);
541 if ((inc + ip->ip_len) > 65535)
544 #if !defined(_KERNEL)
545 m = *((mb_t **)fin->fin_mp);
546 m_copyback(m, off, nlen, newbuf);
550 for (m1 = m; m1->b_cont; m1 = m1->b_cont)
552 if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) {
555 /* alloc enough to keep same trailer space for lower driver */
556 nm = allocb(nlen, BPRI_MED);
557 PANIC((!nm),("ippr_ftp_out: allocb failed"));
559 nm->b_band = m1->b_band;
563 PANIC((m1->b_wptr < m1->b_rptr),
564 ("ippr_ftp_out: cannot handle fragmented data block"));
570 /*copyin_mblk(m, off, nlen, newbuf);*/
572 m = *((mb_t **)fin->fin_mp);
575 /* the mbuf chain will be extended if necessary by m_copyback() */
576 /*m_copyback(m, off, nlen, newbuf);*/
577 # endif /* SOLARIS */
580 #if (SOLARIS || defined(__sgi)) && defined(_KERNEL)
581 register u_32_t sum1, sum2;
584 sum2 = ip->ip_len + inc;
586 /* Because ~1 == -2, We really need ~1 == -1 */
590 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
592 fix_outcksum(fin, &ip->ip_sum, sum2);
593 #endif /* SOLARIS || defined(__sgi) */
599 * Add skeleton NAT entry for connection which will come back the
602 bcopy((char *)fin, (char *)&fi, sizeof(fi));
604 dp = htons(fin->fin_data[1] - 1);
605 fi.fin_data[1] = ntohs(dp);
606 ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip,
612 ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
613 bzero((char *)tcp2, sizeof(*tcp2));
614 tcp2->th_win = htons(8192);
615 tcp2->th_sport = 0; /* XXX - fake it for nat_new */
617 tcp2->th_flags = TH_SYN;
618 fi.fin_data[1] = a5 << 8 | a6;
619 fi.fin_dlen = sizeof(*tcp2);
620 tcp2->th_dport = htons(fi.fin_data[1]);
622 fi.fin_dp = (char *)tcp2;
623 fi.fin_fr = &ftppxyfr;
627 fi.fin_fi.fi_daddr = ip->ip_src.s_addr;
628 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
629 ip->ip_dst = ip->ip_src;
630 ip->ip_src = nat->nat_inip;
631 ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_SPORT,
634 ipn->nat_age = fr_defnatage;
635 (void) fr_addstate(ip, &fi, NULL,
636 FI_W_SPORT|FI_IGNOREPKT);
646 int ippr_ftp_server(fin, ip, nat, ftp, dlen)
658 f = &ftp->ftp_side[1];
662 if (!isdigit(*rptr) || !isdigit(*(rptr + 1)) || !isdigit(*(rptr + 2)))
664 if (ftp->ftp_passok == FTPXY_GO) {
665 if (!strncmp(rptr, "227 ", 4))
666 inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen);
667 } else if (ippr_ftp_insecure && !strncmp(rptr, "227 ", 4)) {
668 inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen);
669 } else if (*rptr == '5' || *rptr == '4')
670 ftp->ftp_passok = FTPXY_INIT;
671 else if (ftp->ftp_incok) {
673 if (ftp->ftp_passok == FTPXY_ACCT_1)
674 ftp->ftp_passok = FTPXY_GO;
677 } else if (*rptr == '2') {
678 switch (ftp->ftp_passok)
685 ftp->ftp_passok = FTPXY_GO;
688 ftp->ftp_passok += 3;
695 while ((*rptr++ != '\n') && (rptr < wptr))
703 * Look to see if the buffer starts with something which we recognise as
704 * being the correct syntax for the FTP protocol.
706 int ippr_ftp_client_valid(ftps, buf, len)
712 register size_t i = len;
716 #if !defined(_KERNEL) && !defined(KERNEL)
717 fprintf(stdout, "ippr_ftp_client_valid:i(%d) < 5\n", i);
741 if ((c != ' ') && (c != '\r'))
742 goto bad_client_command;
743 } else if ((c != ' ') && (c != '\r'))
744 goto bad_client_command;
746 goto bad_client_command;
748 goto bad_client_command;
751 #if !defined(_KERNEL) && !defined(KERNEL)
753 "ippr_ftp_client_valid:bad cmd:len %d i %d c 0x%x\n",
763 if (!strcmp(cmd, "PASV"))
764 ftps->ftps_cmds = FTPXY_C_PASV;
770 #if !defined(_KERNEL) && !defined(KERNEL)
771 fprintf(stdout, "ippr_ftp_client_valid:junk after cmd[%s]\n", buf);
777 int ippr_ftp_server_valid(ftps, buf, len)
783 register size_t i = len;
794 cmd = (c - '0') * 100;
798 cmd += (c - '0') * 10;
805 if ((c != '-') && (c != ' '))
806 goto bad_server_command;
808 goto bad_server_command;
810 goto bad_server_command;
813 #if !defined(_KERNEL) && !defined(KERNEL)
815 "ippr_ftp_server_valid:bad cmd:len %d i %d c 0x%x\n",
824 ftps->ftps_cmds = cmd;
828 #if !defined(_KERNEL) && !defined(KERNEL)
829 fprintf(stdout, "ippr_ftp_server_valid:junk after cmd[%s]\n", buf);
835 int ippr_ftp_valid(ftp, side, buf, len)
844 ftps = &ftp->ftp_side[side];
847 ret = ippr_ftp_client_valid(ftps, buf, len);
849 ret = ippr_ftp_server_valid(ftps, buf, len);
855 * rv == 0 for outbound processing,
856 * rv == 1 for inbound processing.
858 int ippr_ftp_process(fin, ip, nat, ftp, rv)
865 int mlen, len, off, inc, i, sel, sel2, ok, ackoff, seqoff;
873 tcp = (tcphdr_t *)fin->fin_dp;
874 off = fin->fin_hlen + (tcp->th_off << 2);
875 #if SOLARIS && defined(_KERNEL)
878 m = *((mb_t **)fin->fin_mp);
887 mlen = mbufchainlen(m);
893 t = &ftp->ftp_side[1 - rv];
894 f = &ftp->ftp_side[rv];
895 thseq = ntohl(tcp->th_seq);
896 thack = ntohl(tcp->th_ack);
898 sel = aps->aps_sel[1 - rv];
899 sel2 = aps->aps_sel[rv];
901 seqoff = aps->aps_seqoff[sel];
902 if (aps->aps_seqmin[sel] > seqoff + thseq)
903 seqoff = aps->aps_seqoff[!sel];
904 ackoff = aps->aps_ackoff[sel2];
905 if (aps->aps_ackmin[sel2] > ackoff + thack)
906 ackoff = aps->aps_ackoff[!sel2];
909 printf("seqoff %d thseq %x ackmin %x\n", seqoff, thseq,
910 aps->aps_ackmin[sel]);
912 seqoff = aps->aps_ackoff[sel];
913 if (aps->aps_ackmin[sel] > seqoff + thseq)
914 seqoff = aps->aps_ackoff[!sel];
917 printf("ackoff %d thack %x seqmin %x\n", ackoff, thack,
918 aps->aps_seqmin[sel2]);
920 ackoff = aps->aps_seqoff[sel2];
922 if (aps->aps_seqmin[sel2] > ackoff + thack)
923 ackoff = aps->aps_seqoff[!sel2];
925 if (aps->aps_seqmin[sel2] > thack)
926 ackoff = aps->aps_seqoff[!sel2];
930 printf("%s: %x seq %x/%d ack %x/%d len %d\n", rv ? "IN" : "OUT",
931 tcp->th_flags, thseq, seqoff, thack, ackoff, mlen);
932 printf("sel %d seqmin %x/%x offset %d/%d\n", sel,
933 aps->aps_seqmin[sel], aps->aps_seqmin[sel2],
934 aps->aps_seqoff[sel], aps->aps_seqoff[sel2]);
935 printf("sel %d ackmin %x/%x offset %d/%d\n", sel2,
936 aps->aps_ackmin[sel], aps->aps_ackmin[sel2],
937 aps->aps_ackoff[sel], aps->aps_ackoff[sel2]);
941 * XXX - Ideally, this packet should get dropped because we now know
942 * that it is out of order (and there is no real danger in doing so
943 * apart from causing packets to go through here ordered).
946 printf("rv %d t:seq[0] %x seq[1] %x %d/%d\n",
947 rv, t->ftps_seq[0], t->ftps_seq[1], seqoff, ackoff);
951 if (t->ftps_seq[0] == 0) {
952 t->ftps_seq[0] = thack;
956 if (t->ftps_seq[0] == thack)
958 else if (t->ftps_seq[1] == thack) {
959 t->ftps_seq[0] = thack;
963 if (t->ftps_seq[0] + ackoff == thack)
965 else if (t->ftps_seq[0] == thack + ackoff)
967 else if (t->ftps_seq[1] + ackoff == thack) {
968 t->ftps_seq[0] = thack - ackoff;
970 } else if (t->ftps_seq[1] == thack + ackoff) {
971 t->ftps_seq[0] = thack - ackoff;
983 if (t->ftps_seq[0] + ackoff != thack) {
984 #if !defined(_KERNEL) && !defined(KERNEL)
986 "ippr_ftp_process:seq[0](%x) + ackoff(%x) != thack(%x)\n",
987 t->ftps_seq[0], ackoff, thack);
993 printf("f:seq[0] %x seq[1] %x\n", f->ftps_seq[0], f->ftps_seq[1]);
995 if (tcp->th_flags & TH_FIN) {
996 if (thseq == f->ftps_seq[1]) {
997 f->ftps_seq[0] = f->ftps_seq[1] - seqoff;
998 f->ftps_seq[1] = thseq + 1 - seqoff;
1000 #if PROXY_DEBUG || (!defined(_KERNEL) && !defined(KERNEL))
1001 printf("FIN: thseq %x seqoff %d ftps_seq %x\n",
1002 thseq, seqoff, f->ftps_seq[0]);
1012 if ((thseq == f->ftps_seq[0]) || (thseq == f->ftps_seq[1])) {
1015 * Retransmitted data packet.
1017 } else if ((thseq + mlen == f->ftps_seq[0]) ||
1018 (thseq + mlen == f->ftps_seq[1])) {
1023 inc = thseq - f->ftps_seq[0];
1024 #if PROXY_DEBUG || (!defined(_KERNEL) && !defined(KERNEL))
1025 printf("inc %d sel %d rv %d\n", inc, sel, rv);
1026 printf("th_seq %x ftps_seq %x/%x\n", thseq, f->ftps_seq[0],
1028 printf("ackmin %x ackoff %d\n", aps->aps_ackmin[sel],
1029 aps->aps_ackoff[sel]);
1030 printf("seqmin %x seqoff %d\n", aps->aps_seqmin[sel],
1031 aps->aps_seqoff[sel]);
1038 rptr = f->ftps_rptr;
1039 wptr = f->ftps_wptr;
1040 f->ftps_seq[0] = thseq;
1041 f->ftps_seq[1] = f->ftps_seq[0] + mlen;
1045 len = MIN(mlen, FTP_BUFSZ / 2);
1047 #if !defined(_KERNEL)
1048 bcopy((char *)m + off, wptr, len);
1051 copyout_mblk(m, off, len, wptr);
1053 m_copydata(m, off, len, wptr);
1059 f->ftps_wptr = wptr;
1060 if (f->ftps_junk == 2)
1061 f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr,
1064 while ((f->ftps_junk == 0) && (wptr > rptr)) {
1065 f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr,
1067 if (f->ftps_junk == 0) {
1070 f->ftps_rptr = rptr;
1072 inc += ippr_ftp_server(fin, ip, nat,
1075 inc += ippr_ftp_client(fin, ip, nat,
1077 rptr = f->ftps_rptr;
1078 wptr = f->ftps_wptr;
1083 * Off to a bad start so lets just forget about using the
1084 * ftp proxy for this connection.
1086 if ((f->ftps_cmds == 0) && (f->ftps_junk == 1)) {
1087 /* f->ftps_seq[1] += inc; */
1088 #if !defined(_KERNEL) && !defined(KERNEL)
1090 "ippr_ftp_process:cmds == 0 junk == 1\n");
1095 while ((f->ftps_junk == 1) && (rptr < wptr)) {
1096 while ((rptr < wptr) && (*rptr != '\r'))
1099 if (*rptr == '\r') {
1100 if (rptr + 1 < wptr) {
1101 if (*(rptr + 1) == '\n') {
1110 f->ftps_rptr = rptr;
1113 rptr = wptr = f->ftps_buf;
1115 if ((wptr > f->ftps_buf + FTP_BUFSZ / 2)) {
1117 if ((rptr == f->ftps_buf) ||
1118 (wptr - rptr > FTP_BUFSZ / 2)) {
1120 rptr = wptr = f->ftps_buf;
1122 bcopy(rptr, f->ftps_buf, i);
1123 wptr = f->ftps_buf + i;
1127 f->ftps_rptr = rptr;
1128 f->ftps_wptr = wptr;
1132 /* f->ftps_seq[1] += inc; */
1133 if (tcp->th_flags & TH_FIN)
1142 mlen = mbufchainlen(m);
1146 printf("ftps_seq[1] = %x inc %d len %d\n", f->ftps_seq[1], inc, mlen);
1149 f->ftps_rptr = rptr;
1150 f->ftps_wptr = wptr;
1151 return APR_INC(inc);
1155 int ippr_ftp_out(fin, ip, aps, nat)
1163 ftp = aps->aps_data;
1166 return ippr_ftp_process(fin, ip, nat, ftp, 0);
1170 int ippr_ftp_in(fin, ip, aps, nat)
1178 ftp = aps->aps_data;
1181 return ippr_ftp_process(fin, ip, nat, ftp, 1);
1186 * ippr_ftp_atoi - implement a version of atoi which processes numbers in
1187 * pairs separated by commas (which are expected to be in the range 0 - 255),
1188 * returning a 16 bit number combining either side of the , as the MSB and
1191 u_short ippr_ftp_atoi(ptr)
1194 register char *s = *ptr, c;
1195 register u_char i = 0, j = 0;
1197 while ((c = *s++) && isdigit(c)) {
1205 while ((c = *s++) && isdigit(c)) {
1212 return (i << 8) | j;