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.6 2004/07/04 09:24:39 darrenr Exp $
5 * $DragonFly: src/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c,v 1.5 2004/07/28 00:22:37 hmp 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 (fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int);
48 int ippr_ftp_complete (char *, size_t);
49 int ippr_ftp_in (fr_info_t *, ip_t *, ap_session_t *, nat_t *);
50 int ippr_ftp_init (void);
51 int ippr_ftp_new (fr_info_t *, ip_t *, ap_session_t *, nat_t *);
52 int ippr_ftp_out (fr_info_t *, ip_t *, ap_session_t *, nat_t *);
53 int ippr_ftp_pasv (fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int);
54 int ippr_ftp_port (fr_info_t *, ip_t *, nat_t *, ftpside_t *, int);
55 int ippr_ftp_process (fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int);
56 int ippr_ftp_server (fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int);
57 int ippr_ftp_valid (ftpinfo_t *, int, char *, size_t);
58 int ippr_ftp_server_valid (ftpside_t *, char *, size_t);
59 int ippr_ftp_client_valid (ftpside_t *, char *, size_t);
60 u_short ippr_ftp_atoi (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;
124 #if SOLARIS && defined(_KERNEL)
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 #if defined(OpenBSD) && (200311 >= 200311)
211 (void) snprintf(newbuf, sizeof(newbuf), "%s %u,%u,%u,%u,%u,%u\r\n",
212 "PORT", a1, a2, a3, a4, a5, a6);
214 (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n",
215 "PORT", a1, a2, a3, a4, a5, a6);
218 nlen = strlen(newbuf);
220 if ((inc + ip->ip_len) > 65535) {
221 #if !defined(_KERNEL) && !defined(KERNEL)
223 "ippr_ftp_port:inc(%d) + ip->ip_len > 65535\n", inc);
228 #if !defined(_KERNEL)
230 bcopy(newbuf, (char *)m + off, nlen);
234 for (m1 = m; m1->b_cont; m1 = m1->b_cont)
236 if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) {
239 /* alloc enough to keep same trailer space for lower driver */
240 nm = allocb(nlen, BPRI_MED);
241 PANIC((!nm),("ippr_ftp_out: allocb failed"));
243 nm->b_band = m1->b_band;
247 PANIC((m1->b_wptr < m1->b_rptr),
248 ("ippr_ftp_out: cannot handle fragmented data block"));
252 if (m1->b_datap->db_struiolim == m1->b_wptr)
253 m1->b_datap->db_struiolim += inc;
254 m1->b_datap->db_struioflag &= ~STRUIO_IP;
257 copyin_mblk(m, off, nlen, newbuf);
262 /* the mbuf chain will be extended if necessary by m_copyback() */
263 m_copyback(m, off, nlen, newbuf);
265 if (!(m->m_flags & M_PKTHDR))
266 m->m_pkthdr.len += inc;
271 #if ((SOLARIS || defined(__sgi)) && defined(_KERNEL)) || !defined(_KERNEL)
275 sum2 = ip->ip_len + inc;
277 /* Because ~1 == -2, We really need ~1 == -1 */
281 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
283 fix_outcksum(fin, &ip->ip_sum, sum2);
289 * Add skeleton NAT entry for connection which will come back the
294 * Don't allow the PORT command to specify a port < 1024 due to
298 #if !defined(_KERNEL) && !defined(KERNEL)
299 fprintf(stdout, "ippr_ftp_port:sp(%d) < 1024\n", sp);
305 * The server may not make the connection back from port 20, but
306 * it is the most likely so use it here to check for a conflicting
309 bcopy((char *)fin, (char *)&fi, sizeof(fi));
311 fi.fin_data[1] = fin->fin_data[1] - 1;
312 ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip,
318 ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
319 bzero((char *)tcp2, sizeof(*tcp2));
320 tcp2->th_win = htons(8192);
321 tcp2->th_sport = htons(sp);
323 tcp2->th_flags = TH_SYN;
324 tcp2->th_dport = 0; /* XXX - don't specify remote port */
326 fi.fin_dlen = sizeof(*tcp2);
327 fi.fin_dp = (char *)tcp2;
328 fi.fin_fr = &ftppxyfr;
331 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
332 ip->ip_src = nat->nat_inip;
333 ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_DPORT,
336 ipn->nat_age = fr_defnatage;
337 (void) fr_addstate(ip, &fi, NULL,
338 FI_W_DPORT|FI_IGNOREPKT);
347 int ippr_ftp_client(fin, ip, nat, ftp, dlen)
354 char *rptr, *wptr, cmd[6], c;
359 f = &ftp->ftp_side[0];
363 for (i = 0; (i < 5) && (i < dlen); i++) {
374 if (!strncmp(cmd, "USER ", 5) || !strncmp(cmd, "XAUT ", 5)) {
375 if (ftp->ftp_passok == FTPXY_ADOK_1 ||
376 ftp->ftp_passok == FTPXY_AUOK_1) {
377 ftp->ftp_passok = FTPXY_USER_2;
380 ftp->ftp_passok = FTPXY_USER_1;
383 } else if (!strncmp(cmd, "AUTH ", 5)) {
384 ftp->ftp_passok = FTPXY_AUTH_1;
386 } else if (!strncmp(cmd, "PASS ", 5)) {
387 if (ftp->ftp_passok == FTPXY_USOK_1) {
388 ftp->ftp_passok = FTPXY_PASS_1;
390 } else if (ftp->ftp_passok == FTPXY_USOK_2) {
391 ftp->ftp_passok = FTPXY_PASS_2;
394 } else if ((ftp->ftp_passok == FTPXY_AUOK_1) &&
395 !strncmp(cmd, "ADAT ", 5)) {
396 ftp->ftp_passok = FTPXY_ADAT_1;
398 } else if ((ftp->ftp_passok == FTPXY_PAOK_1 ||
399 ftp->ftp_passok == FTPXY_PAOK_2) &&
400 !strncmp(cmd, "ACCT ", 5)) {
401 ftp->ftp_passok = FTPXY_ACCT_1;
403 } else if ((ftp->ftp_passok == FTPXY_GO) && !ippr_ftp_pasvonly &&
404 !strncmp(cmd, "PORT ", 5)) {
405 inc = ippr_ftp_port(fin, ip, nat, f, dlen);
406 } else if (ippr_ftp_insecure && !ippr_ftp_pasvonly &&
407 !strncmp(cmd, "PORT ", 5)) {
408 inc = ippr_ftp_port(fin, ip, nat, f, dlen);
411 while ((*rptr++ != '\n') && (rptr < wptr))
418 int ippr_ftp_pasv(fin, ip, nat, ftp, dlen)
425 tcphdr_t *tcp, tcph, *tcp2 = &tcph;
426 struct in_addr swip, swip2;
427 u_int a1, a2, a3, a4;
435 if (ippr_ftp_forcepasv != 0 &&
436 ftp->ftp_side[0].ftps_cmds != FTPXY_C_PASV) {
437 #if !defined(_KERNEL) && !defined(KERNEL)
439 "ippr_ftp_pasv:ftps_cmds(%d) != FTPXY_C_PASV\n",
440 ftp->ftp_side[0].ftps_cmds);
445 f = &ftp->ftp_side[1];
447 #define PASV_REPLEN 24
449 * Check for PASV reply message.
451 if (dlen < IPF_MIN227LEN) {
452 #if !defined(_KERNEL) && !defined(KERNEL)
454 "ippr_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n", dlen);
457 } else if (strncmp(f->ftps_rptr,
458 "227 Entering Passive Mod", PASV_REPLEN)) {
459 #if !defined(_KERNEL) && !defined(KERNEL)
460 fprintf(stdout, "ippr_ftp_pasv:227 reply wrong\n");
465 tcp = (tcphdr_t *)fin->fin_dp;
468 * Skip the PASV reply + space
470 s = f->ftps_rptr + PASV_REPLEN;
471 while (*s && !isdigit(*s))
474 * Pick out the address components, two at a time.
476 a1 = ippr_ftp_atoi(&s);
478 #if !defined(_KERNEL) && !defined(KERNEL)
479 fprintf(stdout, "ippr_ftp_pasv:ippr_ftp_atoi(1) failed\n");
483 a2 = ippr_ftp_atoi(&s);
485 #if !defined(_KERNEL) && !defined(KERNEL)
486 fprintf(stdout, "ippr_ftp_pasv:ippr_ftp_atoi(2) failed\n");
492 * check that IP address in the PORT/PASV reply is the same as the
493 * sender of the command - prevents using PORT for port scanning.
497 if (a1 != ntohl(nat->nat_oip.s_addr)) {
498 #if !defined(_KERNEL) && !defined(KERNEL)
499 fprintf(stdout, "ippr_ftp_pasv:a1 != nat->nat_oip\n");
504 a5 = ippr_ftp_atoi(&s);
506 #if !defined(_KERNEL) && !defined(KERNEL)
507 fprintf(stdout, "ippr_ftp_pasv:ippr_ftp_atoi(3) failed\n");
519 * check for CR-LF at the end.
521 if ((*s == '\r') && (*(s + 1) == '\n')) {
525 #if !defined(_KERNEL) && !defined(KERNEL)
526 fprintf(stdout, "ippr_ftp_pasv:missing cr-lf\n");
532 * Calculate new address parts for 227 reply
534 a1 = ntohl(ip->ip_src.s_addr);
535 a2 = (a1 >> 16) & 0xff;
536 a3 = (a1 >> 8) & 0xff;
541 olen = s - f->ftps_rptr;
542 (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n",
543 "227 Entering Passive Mode", a1, a2, a3, a4, a5, a6);
544 nlen = strlen(newbuf);
546 if ((inc + ip->ip_len) > 65535)
549 #if !defined(_KERNEL)
551 m_copyback(m, off, nlen, newbuf);
555 for (m1 = m; m1->b_cont; m1 = m1->b_cont)
557 if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) {
560 /* alloc enough to keep same trailer space for lower driver */
561 nm = allocb(nlen, BPRI_MED);
562 PANIC((!nm),("ippr_ftp_out: allocb failed"));
564 nm->b_band = m1->b_band;
568 PANIC((m1->b_wptr < m1->b_rptr),
569 ("ippr_ftp_out: cannot handle fragmented data block"));
575 /*copyin_mblk(m, off, nlen, newbuf);*/
580 /* the mbuf chain will be extended if necessary by m_copyback() */
581 /*m_copyback(m, off, nlen, newbuf);*/
582 # endif /* SOLARIS */
585 #if ((SOLARIS || defined(__sgi)) && defined(_KERNEL)) || !defined(_KERNEL)
589 sum2 = ip->ip_len + inc;
591 /* Because ~1 == -2, We really need ~1 == -1 */
595 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
597 fix_outcksum(fin, &ip->ip_sum, sum2);
598 #endif /* SOLARIS || defined(__sgi) */
604 * Add skeleton NAT entry for connection which will come back the
607 bcopy((char *)fin, (char *)&fi, sizeof(fi));
609 dp = htons(fin->fin_data[1] - 1);
610 fi.fin_data[1] = ntohs(dp);
611 ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip,
617 ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
618 bzero((char *)tcp2, sizeof(*tcp2));
619 tcp2->th_win = htons(8192);
620 tcp2->th_sport = 0; /* XXX - fake it for nat_new */
622 tcp2->th_flags = TH_SYN;
623 fi.fin_data[1] = a5 << 8 | a6;
624 fi.fin_dlen = sizeof(*tcp2);
625 tcp2->th_dport = htons(fi.fin_data[1]);
627 fi.fin_dp = (char *)tcp2;
628 fi.fin_fr = &ftppxyfr;
632 fi.fin_fi.fi_daddr = ip->ip_src.s_addr;
633 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
634 ip->ip_dst = ip->ip_src;
635 ip->ip_src = nat->nat_inip;
636 ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_SPORT,
639 ipn->nat_age = fr_defnatage;
640 (void) fr_addstate(ip, &fi, NULL,
641 FI_W_SPORT|FI_IGNOREPKT);
651 int ippr_ftp_server(fin, ip, nat, ftp, dlen)
663 f = &ftp->ftp_side[1];
667 if (!isdigit(*rptr) || !isdigit(*(rptr + 1)) || !isdigit(*(rptr + 2)))
669 if (ftp->ftp_passok == FTPXY_GO) {
670 if (!strncmp(rptr, "227 ", 4))
671 inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen);
672 } else if (ippr_ftp_insecure && !strncmp(rptr, "227 ", 4)) {
673 inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen);
674 } else if (*rptr == '5' || *rptr == '4')
675 ftp->ftp_passok = FTPXY_INIT;
676 else if (ftp->ftp_incok) {
678 if (ftp->ftp_passok == FTPXY_ACCT_1)
679 ftp->ftp_passok = FTPXY_GO;
682 } else if (*rptr == '2') {
683 switch (ftp->ftp_passok)
690 ftp->ftp_passok = FTPXY_GO;
693 ftp->ftp_passok += 3;
700 while ((*rptr++ != '\n') && (rptr < wptr))
708 * Look to see if the buffer starts with something which we recognise as
709 * being the correct syntax for the FTP protocol.
711 int ippr_ftp_client_valid(ftps, buf, len)
721 #if !defined(_KERNEL) && !defined(KERNEL)
722 fprintf(stdout, "ippr_ftp_client_valid:i(%lu) < 5\n",
747 if ((c != ' ') && (c != '\r'))
748 goto bad_client_command;
749 } else if ((c != ' ') && (c != '\r'))
750 goto bad_client_command;
752 goto bad_client_command;
754 goto bad_client_command;
757 #if !defined(_KERNEL) && !defined(KERNEL)
759 "ippr_ftp_client_valid:bad cmd:len %lu i %lu c 0x%x\n",
760 (u_long)i, (u_long)len, c);
769 if (!strcmp(cmd, "PASV"))
770 ftps->ftps_cmds = FTPXY_C_PASV;
776 #if !defined(_KERNEL) && !defined(KERNEL)
777 fprintf(stdout, "ippr_ftp_client_valid:junk after cmd[%s]\n", buf);
783 int ippr_ftp_server_valid(ftps, buf, len)
800 cmd = (c - '0') * 100;
804 cmd += (c - '0') * 10;
811 if ((c != '-') && (c != ' '))
812 goto bad_server_command;
814 goto bad_server_command;
816 goto bad_server_command;
819 #if !defined(_KERNEL) && !defined(KERNEL)
821 "ippr_ftp_server_valid:bad cmd:len %lu i %lu c 0x%x\n",
822 (u_long)i, (u_long)len, c);
830 ftps->ftps_cmds = cmd;
834 #if !defined(_KERNEL) && !defined(KERNEL)
835 fprintf(stdout, "ippr_ftp_server_valid:junk after cmd[%s]\n", buf);
841 int ippr_ftp_valid(ftp, side, buf, len)
850 ftps = &ftp->ftp_side[side];
853 ret = ippr_ftp_client_valid(ftps, buf, len);
855 ret = ippr_ftp_server_valid(ftps, buf, len);
861 * rv == 0 for outbound processing,
862 * rv == 1 for inbound processing.
864 int ippr_ftp_process(fin, ip, nat, ftp, rv)
871 int mlen, len, off, inc, i, sel, sel2, ok, ackoff, seqoff;
879 tcp = (tcphdr_t *)fin->fin_dp;
880 off = fin->fin_hlen + (tcp->th_off << 2);
881 #if SOLARIS && defined(_KERNEL)
893 mlen = mbufchainlen(m);
899 t = &ftp->ftp_side[1 - rv];
900 f = &ftp->ftp_side[rv];
901 thseq = ntohl(tcp->th_seq);
902 thack = ntohl(tcp->th_ack);
904 sel = aps->aps_sel[1 - rv];
905 sel2 = aps->aps_sel[rv];
907 seqoff = aps->aps_seqoff[sel];
908 if (aps->aps_seqmin[sel] > seqoff + thseq)
909 seqoff = aps->aps_seqoff[!sel];
910 ackoff = aps->aps_ackoff[sel2];
911 if (aps->aps_ackmin[sel2] > ackoff + thack)
912 ackoff = aps->aps_ackoff[!sel2];
915 printf("seqoff %d thseq %x ackmin %x\n", seqoff, thseq,
916 aps->aps_ackmin[sel]);
918 seqoff = aps->aps_ackoff[sel];
919 if (aps->aps_ackmin[sel] > seqoff + thseq)
920 seqoff = aps->aps_ackoff[!sel];
923 printf("ackoff %d thack %x seqmin %x\n", ackoff, thack,
924 aps->aps_seqmin[sel2]);
926 ackoff = aps->aps_seqoff[sel2];
928 if (aps->aps_seqmin[sel2] > ackoff + thack)
929 ackoff = aps->aps_seqoff[!sel2];
931 if (aps->aps_seqmin[sel2] > thack)
932 ackoff = aps->aps_seqoff[!sel2];
936 printf("%s: %x seq %x/%d ack %x/%d len %d\n", rv ? "IN" : "OUT",
937 tcp->th_flags, thseq, seqoff, thack, ackoff, mlen);
938 printf("sel %d seqmin %x/%x offset %d/%d\n", sel,
939 aps->aps_seqmin[sel], aps->aps_seqmin[sel2],
940 aps->aps_seqoff[sel], aps->aps_seqoff[sel2]);
941 printf("sel %d ackmin %x/%x offset %d/%d\n", sel2,
942 aps->aps_ackmin[sel], aps->aps_ackmin[sel2],
943 aps->aps_ackoff[sel], aps->aps_ackoff[sel2]);
947 * XXX - Ideally, this packet should get dropped because we now know
948 * that it is out of order (and there is no real danger in doing so
949 * apart from causing packets to go through here ordered).
952 printf("rv %d t:seq[0] %x seq[1] %x %d/%d\n",
953 rv, t->ftps_seq[0], t->ftps_seq[1], seqoff, ackoff);
957 if (t->ftps_seq[0] == 0) {
958 t->ftps_seq[0] = thack;
962 if (t->ftps_seq[0] == thack)
964 else if (t->ftps_seq[1] == thack) {
965 t->ftps_seq[0] = thack;
969 if (t->ftps_seq[0] + ackoff == thack)
971 else if (t->ftps_seq[0] == thack + ackoff)
973 else if (t->ftps_seq[1] + ackoff == thack) {
974 t->ftps_seq[0] = thack - ackoff;
976 } else if (t->ftps_seq[1] == thack + ackoff) {
977 t->ftps_seq[0] = thack - ackoff;
989 if (t->ftps_seq[0] + ackoff != thack) {
990 #if !defined(_KERNEL) && !defined(KERNEL)
992 "ippr_ftp_process:seq[0](%x) + ackoff(%x) != thack(%x)\n",
993 t->ftps_seq[0], ackoff, thack);
999 printf("f:seq[0] %x seq[1] %x\n", f->ftps_seq[0], f->ftps_seq[1]);
1001 if (tcp->th_flags & TH_FIN) {
1002 if (thseq == f->ftps_seq[1]) {
1003 f->ftps_seq[0] = f->ftps_seq[1] - seqoff;
1004 f->ftps_seq[1] = thseq + 1 - seqoff;
1006 #if PROXY_DEBUG || (!defined(_KERNEL) && !defined(KERNEL))
1007 printf("FIN: thseq %x seqoff %d ftps_seq %x\n",
1008 thseq, seqoff, f->ftps_seq[0]);
1018 if ((thseq == f->ftps_seq[0]) || (thseq == f->ftps_seq[1])) {
1021 * Retransmitted data packet.
1023 } else if ((thseq + mlen == f->ftps_seq[0]) ||
1024 (thseq + mlen == f->ftps_seq[1])) {
1029 inc = thseq - f->ftps_seq[0];
1030 #if PROXY_DEBUG || (!defined(_KERNEL) && !defined(KERNEL))
1031 printf("inc %d sel %d rv %d\n", inc, sel, rv);
1032 printf("th_seq %x ftps_seq %x/%x\n", thseq, f->ftps_seq[0],
1034 printf("ackmin %x ackoff %d\n", (u_int)aps->aps_ackmin[sel],
1035 aps->aps_ackoff[sel]);
1036 printf("seqmin %x seqoff %d\n", (u_int)aps->aps_seqmin[sel],
1037 aps->aps_seqoff[sel]);
1044 rptr = f->ftps_rptr;
1045 wptr = f->ftps_wptr;
1046 f->ftps_seq[0] = thseq;
1047 f->ftps_seq[1] = f->ftps_seq[0] + mlen;
1051 len = MIN(mlen, FTP_BUFSZ / 2);
1053 #if !defined(_KERNEL)
1054 bcopy((char *)m + off, wptr, len);
1057 copyout_mblk(m, off, len, wptr);
1059 m_copydata(m, off, len, wptr);
1065 f->ftps_wptr = wptr;
1066 if (f->ftps_junk == 2)
1067 f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr,
1070 while ((f->ftps_junk == 0) && (wptr > rptr)) {
1071 f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr,
1073 if (f->ftps_junk == 0) {
1076 f->ftps_rptr = rptr;
1078 inc += ippr_ftp_server(fin, ip, nat,
1081 inc += ippr_ftp_client(fin, ip, nat,
1083 rptr = f->ftps_rptr;
1084 wptr = f->ftps_wptr;
1089 * Off to a bad start so lets just forget about using the
1090 * ftp proxy for this connection.
1092 if ((f->ftps_cmds == 0) && (f->ftps_junk == 1)) {
1093 /* f->ftps_seq[1] += inc; */
1094 #if !defined(_KERNEL) && !defined(KERNEL)
1096 "ippr_ftp_process:cmds == 0 junk == 1\n");
1101 while ((f->ftps_junk == 1) && (rptr < wptr)) {
1102 while ((rptr < wptr) && (*rptr != '\r'))
1105 if (*rptr == '\r') {
1106 if (rptr + 1 < wptr) {
1107 if (*(rptr + 1) == '\n') {
1116 f->ftps_rptr = rptr;
1119 rptr = wptr = f->ftps_buf;
1121 if ((wptr > f->ftps_buf + FTP_BUFSZ / 2)) {
1123 if ((rptr == f->ftps_buf) ||
1124 (wptr - rptr > FTP_BUFSZ / 2)) {
1126 rptr = wptr = f->ftps_buf;
1128 bcopy(rptr, f->ftps_buf, i);
1129 wptr = f->ftps_buf + i;
1133 f->ftps_rptr = rptr;
1134 f->ftps_wptr = wptr;
1138 /* f->ftps_seq[1] += inc; */
1139 if (tcp->th_flags & TH_FIN)
1148 mlen = mbufchainlen(m);
1152 printf("ftps_seq[1] = %x inc %d len %d\n", f->ftps_seq[1], inc, mlen);
1155 f->ftps_rptr = rptr;
1156 f->ftps_wptr = wptr;
1157 return APR_INC(inc);
1161 int ippr_ftp_out(fin, ip, aps, nat)
1169 ftp = aps->aps_data;
1172 return ippr_ftp_process(fin, ip, nat, ftp, 0);
1176 int ippr_ftp_in(fin, ip, aps, nat)
1184 ftp = aps->aps_data;
1187 return ippr_ftp_process(fin, ip, nat, ftp, 1);
1192 * ippr_ftp_atoi - implement a version of atoi which processes numbers in
1193 * pairs separated by commas (which are expected to be in the range 0 - 255),
1194 * returning a 16 bit number combining either side of the , as the MSB and
1197 u_short ippr_ftp_atoi(ptr)
1201 u_char i = 0, j = 0;
1203 while ((c = *s++) && isdigit(c)) {
1211 while ((c = *s++) && isdigit(c)) {
1218 return (i << 8) | j;