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.7 2006/12/23 00:27:02 swildner Exp $
7 #if SOLARIS && defined(_KERNEL)
8 extern kmutex_t ipf_rw;
12 #define kprintf printf
15 #define isdigit(x) ((x) >= '0' && (x) <= '9')
16 #define isupper(x) (((unsigned)(x) >= 'A') && ((unsigned)(x) <= 'Z'))
17 #define islower(x) (((unsigned)(x) >= 'a') && ((unsigned)(x) <= 'z'))
18 #define isalpha(x) (isupper(x) || islower(x))
19 #define toupper(x) (isupper(x) ? (x) : (x) - 'a' + 'A')
23 #define IPF_MINPORTLEN 18
24 #define IPF_MAXPORTLEN 30
25 #define IPF_MIN227LEN 39
26 #define IPF_MAX227LEN 51
27 #define IPF_FTPBUFSZ 96 /* This *MUST* be >= 53! */
31 #define FTPXY_USER_1 2
32 #define FTPXY_USOK_1 3
33 #define FTPXY_PASS_1 4
34 #define FTPXY_PAOK_1 5
35 #define FTPXY_AUTH_1 6
36 #define FTPXY_AUOK_1 7
37 #define FTPXY_ADAT_1 8
38 #define FTPXY_ADOK_1 9
39 #define FTPXY_ACCT_1 10
40 #define FTPXY_ACOK_1 11
41 #define FTPXY_USER_2 12
42 #define FTPXY_USOK_2 13
43 #define FTPXY_PASS_2 14
44 #define FTPXY_PAOK_2 15
47 * Values for FTP commands. Numerics cover 0-999
49 #define FTPXY_C_PASV 1000
51 int ippr_ftp_client (fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int);
52 int ippr_ftp_complete (char *, size_t);
53 int ippr_ftp_in (fr_info_t *, ip_t *, ap_session_t *, nat_t *);
54 int ippr_ftp_init (void);
55 int ippr_ftp_new (fr_info_t *, ip_t *, ap_session_t *, nat_t *);
56 int ippr_ftp_out (fr_info_t *, ip_t *, ap_session_t *, nat_t *);
57 int ippr_ftp_pasv (fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int);
58 int ippr_ftp_port (fr_info_t *, ip_t *, nat_t *, ftpside_t *, int);
59 int ippr_ftp_process (fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int);
60 int ippr_ftp_server (fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int);
61 int ippr_ftp_valid (ftpinfo_t *, int, char *, size_t);
62 int ippr_ftp_server_valid (ftpside_t *, char *, size_t);
63 int ippr_ftp_client_valid (ftpside_t *, char *, size_t);
64 u_short ippr_ftp_atoi (char **);
66 static frentry_t ftppxyfr;
67 int ippr_ftp_pasvonly = 0;
68 int ippr_ftp_insecure = 0;
69 int ippr_ftp_forcepasv = 0;
73 * Initialize local structures.
77 bzero((char *)&ftppxyfr, sizeof(ftppxyfr));
79 ftppxyfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
84 int ippr_ftp_new(fin, ip, aps, nat)
93 KMALLOC(ftp, ftpinfo_t *);
97 aps->aps_psiz = sizeof(ftpinfo_t);
99 bzero((char *)ftp, sizeof(*ftp));
100 f = &ftp->ftp_side[0];
101 f->ftps_rptr = f->ftps_buf;
102 f->ftps_wptr = f->ftps_buf;
103 f = &ftp->ftp_side[1];
104 f->ftps_rptr = f->ftps_buf;
105 f->ftps_wptr = f->ftps_buf;
106 ftp->ftp_passok = FTPXY_INIT;
111 int ippr_ftp_port(fin, ip, nat, f, dlen)
118 tcphdr_t *tcp, tcph, *tcp2 = &tcph;
119 char newbuf[IPF_FTPBUFSZ], *s;
120 u_int a1, a2, a3, a4;
128 #if SOLARIS && defined(_KERNEL)
132 tcp = (tcphdr_t *)fin->fin_dp;
134 * Check for client sending out PORT message.
136 if (dlen < IPF_MINPORTLEN) {
137 #if !defined(_KERNEL) && !defined(KERNEL)
139 "ippr_ftp_port:dlen(%d) < IPF_MINPORTLEN\n", dlen);
143 off = fin->fin_hlen + (tcp->th_off << 2);
145 * Skip the PORT command + space
147 s = f->ftps_rptr + 5;
149 * Pick out the address components, two at a time.
151 a1 = ippr_ftp_atoi(&s);
153 #if !defined(_KERNEL) && !defined(KERNEL)
154 fprintf(stdout, "ippr_ftp_port:ippr_ftp_atoi(1) failed\n");
158 a2 = ippr_ftp_atoi(&s);
160 #if !defined(_KERNEL) && !defined(KERNEL)
161 fprintf(stdout, "ippr_ftp_port:ippr_ftp_atoi(2) failed\n");
166 * check that IP address in the PORT/PASV reply is the same as the
167 * sender of the command - prevents using PORT for port scanning.
171 if (a1 != ntohl(nat->nat_inip.s_addr)) {
172 #if !defined(_KERNEL) && !defined(KERNEL)
173 fprintf(stdout, "ippr_ftp_port:a1 != nat->nat_inip\n");
178 a5 = ippr_ftp_atoi(&s);
180 #if !defined(_KERNEL) && !defined(KERNEL)
181 fprintf(stdout, "ippr_ftp_port:ippr_ftp_atoi(3) failed\n");
189 * check for CR-LF at the end.
193 if ((*s == '\r') && (*(s + 1) == '\n')) {
197 #if !defined(_KERNEL) && !defined(KERNEL)
198 fprintf(stdout, "ippr_ftp_port:missing cr-lf\n");
205 * Calculate new address parts for PORT command
207 a1 = ntohl(ip->ip_src.s_addr);
208 a2 = (a1 >> 16) & 0xff;
209 a3 = (a1 >> 8) & 0xff;
212 olen = s - f->ftps_rptr;
213 /* DO NOT change this to snprintf! */
214 #if defined(OpenBSD) && (200311 >= 200311)
215 (void) snprintf(newbuf, sizeof(newbuf), "%s %u,%u,%u,%u,%u,%u\r\n",
216 "PORT", a1, a2, a3, a4, a5, a6);
218 (void) ksprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n",
219 "PORT", a1, a2, a3, a4, a5, a6);
222 nlen = strlen(newbuf);
224 if ((inc + ip->ip_len) > 65535) {
225 #if !defined(_KERNEL) && !defined(KERNEL)
227 "ippr_ftp_port:inc(%d) + ip->ip_len > 65535\n", inc);
232 #if !defined(_KERNEL)
234 bcopy(newbuf, (char *)m + off, nlen);
238 for (m1 = m; m1->b_cont; m1 = m1->b_cont)
240 if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) {
243 /* alloc enough to keep same trailer space for lower driver */
244 nm = allocb(nlen, BPRI_MED);
245 PANIC((!nm),("ippr_ftp_out: allocb failed"));
247 nm->b_band = m1->b_band;
251 PANIC((m1->b_wptr < m1->b_rptr),
252 ("ippr_ftp_out: cannot handle fragmented data block"));
256 if (m1->b_datap->db_struiolim == m1->b_wptr)
257 m1->b_datap->db_struiolim += inc;
258 m1->b_datap->db_struioflag &= ~STRUIO_IP;
261 copyin_mblk(m, off, nlen, newbuf);
266 /* the mbuf chain will be extended if necessary by m_copyback() */
267 m_copyback(m, off, nlen, newbuf);
269 if (!(m->m_flags & M_PKTHDR))
270 m->m_pkthdr.len += inc;
275 #if ((SOLARIS || defined(__sgi)) && defined(_KERNEL)) || !defined(_KERNEL)
279 sum2 = ip->ip_len + inc;
281 /* Because ~1 == -2, We really need ~1 == -1 */
285 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
287 fix_outcksum(fin, &ip->ip_sum, sum2);
293 * Add skeleton NAT entry for connection which will come back the
298 * Don't allow the PORT command to specify a port < 1024 due to
302 #if !defined(_KERNEL) && !defined(KERNEL)
303 fprintf(stdout, "ippr_ftp_port:sp(%d) < 1024\n", sp);
309 * The server may not make the connection back from port 20, but
310 * it is the most likely so use it here to check for a conflicting
313 bcopy((char *)fin, (char *)&fi, sizeof(fi));
315 fi.fin_data[1] = fin->fin_data[1] - 1;
316 ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip,
322 ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
323 bzero((char *)tcp2, sizeof(*tcp2));
324 tcp2->th_win = htons(8192);
325 tcp2->th_sport = htons(sp);
327 tcp2->th_flags = TH_SYN;
328 tcp2->th_dport = 0; /* XXX - don't specify remote port */
330 fi.fin_dlen = sizeof(*tcp2);
331 fi.fin_dp = (char *)tcp2;
332 fi.fin_fr = &ftppxyfr;
335 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
336 ip->ip_src = nat->nat_inip;
337 ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_DPORT,
340 ipn->nat_age = fr_defnatage;
341 (void) fr_addstate(ip, &fi, NULL,
342 FI_W_DPORT|FI_IGNOREPKT);
351 int ippr_ftp_client(fin, ip, nat, ftp, dlen)
358 char *rptr, *wptr, cmd[6], c;
363 f = &ftp->ftp_side[0];
367 for (i = 0; (i < 5) && (i < dlen); i++) {
378 if (!strncmp(cmd, "USER ", 5) || !strncmp(cmd, "XAUT ", 5)) {
379 if (ftp->ftp_passok == FTPXY_ADOK_1 ||
380 ftp->ftp_passok == FTPXY_AUOK_1) {
381 ftp->ftp_passok = FTPXY_USER_2;
384 ftp->ftp_passok = FTPXY_USER_1;
387 } else if (!strncmp(cmd, "AUTH ", 5)) {
388 ftp->ftp_passok = FTPXY_AUTH_1;
390 } else if (!strncmp(cmd, "PASS ", 5)) {
391 if (ftp->ftp_passok == FTPXY_USOK_1) {
392 ftp->ftp_passok = FTPXY_PASS_1;
394 } else if (ftp->ftp_passok == FTPXY_USOK_2) {
395 ftp->ftp_passok = FTPXY_PASS_2;
398 } else if ((ftp->ftp_passok == FTPXY_AUOK_1) &&
399 !strncmp(cmd, "ADAT ", 5)) {
400 ftp->ftp_passok = FTPXY_ADAT_1;
402 } else if ((ftp->ftp_passok == FTPXY_PAOK_1 ||
403 ftp->ftp_passok == FTPXY_PAOK_2) &&
404 !strncmp(cmd, "ACCT ", 5)) {
405 ftp->ftp_passok = FTPXY_ACCT_1;
407 } else if ((ftp->ftp_passok == FTPXY_GO) && !ippr_ftp_pasvonly &&
408 !strncmp(cmd, "PORT ", 5)) {
409 inc = ippr_ftp_port(fin, ip, nat, f, dlen);
410 } else if (ippr_ftp_insecure && !ippr_ftp_pasvonly &&
411 !strncmp(cmd, "PORT ", 5)) {
412 inc = ippr_ftp_port(fin, ip, nat, f, dlen);
415 while ((*rptr++ != '\n') && (rptr < wptr))
422 int ippr_ftp_pasv(fin, ip, nat, ftp, dlen)
429 tcphdr_t *tcp, tcph, *tcp2 = &tcph;
430 struct in_addr swip, swip2;
431 u_int a1, a2, a3, a4;
439 if (ippr_ftp_forcepasv != 0 &&
440 ftp->ftp_side[0].ftps_cmds != FTPXY_C_PASV) {
441 #if !defined(_KERNEL) && !defined(KERNEL)
443 "ippr_ftp_pasv:ftps_cmds(%d) != FTPXY_C_PASV\n",
444 ftp->ftp_side[0].ftps_cmds);
449 f = &ftp->ftp_side[1];
451 #define PASV_REPLEN 24
453 * Check for PASV reply message.
455 if (dlen < IPF_MIN227LEN) {
456 #if !defined(_KERNEL) && !defined(KERNEL)
458 "ippr_ftp_pasv:dlen(%d) < IPF_MIN227LEN\n", dlen);
461 } else if (strncmp(f->ftps_rptr,
462 "227 Entering Passive Mod", PASV_REPLEN)) {
463 #if !defined(_KERNEL) && !defined(KERNEL)
464 fprintf(stdout, "ippr_ftp_pasv:227 reply wrong\n");
469 tcp = (tcphdr_t *)fin->fin_dp;
472 * Skip the PASV reply + space
474 s = f->ftps_rptr + PASV_REPLEN;
475 while (*s && !isdigit(*s))
478 * Pick out the address components, two at a time.
480 a1 = ippr_ftp_atoi(&s);
482 #if !defined(_KERNEL) && !defined(KERNEL)
483 fprintf(stdout, "ippr_ftp_pasv:ippr_ftp_atoi(1) failed\n");
487 a2 = ippr_ftp_atoi(&s);
489 #if !defined(_KERNEL) && !defined(KERNEL)
490 fprintf(stdout, "ippr_ftp_pasv:ippr_ftp_atoi(2) failed\n");
496 * check that IP address in the PORT/PASV reply is the same as the
497 * sender of the command - prevents using PORT for port scanning.
501 if (a1 != ntohl(nat->nat_oip.s_addr)) {
502 #if !defined(_KERNEL) && !defined(KERNEL)
503 fprintf(stdout, "ippr_ftp_pasv:a1 != nat->nat_oip\n");
508 a5 = ippr_ftp_atoi(&s);
510 #if !defined(_KERNEL) && !defined(KERNEL)
511 fprintf(stdout, "ippr_ftp_pasv:ippr_ftp_atoi(3) failed\n");
523 * check for CR-LF at the end.
525 if ((*s == '\r') && (*(s + 1) == '\n')) {
529 #if !defined(_KERNEL) && !defined(KERNEL)
530 fprintf(stdout, "ippr_ftp_pasv:missing cr-lf\n");
536 * Calculate new address parts for 227 reply
538 a1 = ntohl(ip->ip_src.s_addr);
539 a2 = (a1 >> 16) & 0xff;
540 a3 = (a1 >> 8) & 0xff;
545 olen = s - f->ftps_rptr;
546 (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n",
547 "227 Entering Passive Mode", a1, a2, a3, a4, a5, a6);
548 nlen = strlen(newbuf);
550 if ((inc + ip->ip_len) > 65535)
553 #if !defined(_KERNEL)
555 m_copyback(m, off, nlen, newbuf);
559 for (m1 = m; m1->b_cont; m1 = m1->b_cont)
561 if ((inc > 0) && (m1->b_datap->db_lim - m1->b_wptr < inc)) {
564 /* alloc enough to keep same trailer space for lower driver */
565 nm = allocb(nlen, BPRI_MED);
566 PANIC((!nm),("ippr_ftp_out: allocb failed"));
568 nm->b_band = m1->b_band;
572 PANIC((m1->b_wptr < m1->b_rptr),
573 ("ippr_ftp_out: cannot handle fragmented data block"));
579 /*copyin_mblk(m, off, nlen, newbuf);*/
584 /* the mbuf chain will be extended if necessary by m_copyback() */
585 /*m_copyback(m, off, nlen, newbuf);*/
586 # endif /* SOLARIS */
589 #if ((SOLARIS || defined(__sgi)) && defined(_KERNEL)) || !defined(_KERNEL)
593 sum2 = ip->ip_len + inc;
595 /* Because ~1 == -2, We really need ~1 == -1 */
599 sum2 = (sum2 & 0xffff) + (sum2 >> 16);
601 fix_outcksum(fin, &ip->ip_sum, sum2);
602 #endif /* SOLARIS || defined(__sgi) */
608 * Add skeleton NAT entry for connection which will come back the
611 bcopy((char *)fin, (char *)&fi, sizeof(fi));
613 dp = htons(fin->fin_data[1] - 1);
614 fi.fin_data[1] = ntohs(dp);
615 ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip,
621 ip->ip_len = fin->fin_hlen + sizeof(*tcp2);
622 bzero((char *)tcp2, sizeof(*tcp2));
623 tcp2->th_win = htons(8192);
624 tcp2->th_sport = 0; /* XXX - fake it for nat_new */
626 tcp2->th_flags = TH_SYN;
627 fi.fin_data[1] = a5 << 8 | a6;
628 fi.fin_dlen = sizeof(*tcp2);
629 tcp2->th_dport = htons(fi.fin_data[1]);
631 fi.fin_dp = (char *)tcp2;
632 fi.fin_fr = &ftppxyfr;
636 fi.fin_fi.fi_daddr = ip->ip_src.s_addr;
637 fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
638 ip->ip_dst = ip->ip_src;
639 ip->ip_src = nat->nat_inip;
640 ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_SPORT,
643 ipn->nat_age = fr_defnatage;
644 (void) fr_addstate(ip, &fi, NULL,
645 FI_W_SPORT|FI_IGNOREPKT);
655 int ippr_ftp_server(fin, ip, nat, ftp, dlen)
667 f = &ftp->ftp_side[1];
671 if (!isdigit(*rptr) || !isdigit(*(rptr + 1)) || !isdigit(*(rptr + 2)))
673 if (ftp->ftp_passok == FTPXY_GO) {
674 if (!strncmp(rptr, "227 ", 4))
675 inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen);
676 } else if (ippr_ftp_insecure && !strncmp(rptr, "227 ", 4)) {
677 inc = ippr_ftp_pasv(fin, ip, nat, ftp, dlen);
678 } else if (*rptr == '5' || *rptr == '4')
679 ftp->ftp_passok = FTPXY_INIT;
680 else if (ftp->ftp_incok) {
682 if (ftp->ftp_passok == FTPXY_ACCT_1)
683 ftp->ftp_passok = FTPXY_GO;
686 } else if (*rptr == '2') {
687 switch (ftp->ftp_passok)
694 ftp->ftp_passok = FTPXY_GO;
697 ftp->ftp_passok += 3;
704 while ((*rptr++ != '\n') && (rptr < wptr))
712 * Look to see if the buffer starts with something which we recognise as
713 * being the correct syntax for the FTP protocol.
715 int ippr_ftp_client_valid(ftps, buf, len)
725 #if !defined(_KERNEL) && !defined(KERNEL)
726 fprintf(stdout, "ippr_ftp_client_valid:i(%lu) < 5\n",
751 if ((c != ' ') && (c != '\r'))
752 goto bad_client_command;
753 } else if ((c != ' ') && (c != '\r'))
754 goto bad_client_command;
756 goto bad_client_command;
758 goto bad_client_command;
761 #if !defined(_KERNEL) && !defined(KERNEL)
763 "ippr_ftp_client_valid:bad cmd:len %lu i %lu c 0x%x\n",
764 (u_long)i, (u_long)len, c);
773 if (!strcmp(cmd, "PASV"))
774 ftps->ftps_cmds = FTPXY_C_PASV;
780 #if !defined(_KERNEL) && !defined(KERNEL)
781 fprintf(stdout, "ippr_ftp_client_valid:junk after cmd[%s]\n", buf);
787 int ippr_ftp_server_valid(ftps, buf, len)
804 cmd = (c - '0') * 100;
808 cmd += (c - '0') * 10;
815 if ((c != '-') && (c != ' '))
816 goto bad_server_command;
818 goto bad_server_command;
820 goto bad_server_command;
823 #if !defined(_KERNEL) && !defined(KERNEL)
825 "ippr_ftp_server_valid:bad cmd:len %lu i %lu c 0x%x\n",
826 (u_long)i, (u_long)len, c);
834 ftps->ftps_cmds = cmd;
838 #if !defined(_KERNEL) && !defined(KERNEL)
839 fprintf(stdout, "ippr_ftp_server_valid:junk after cmd[%s]\n", buf);
845 int ippr_ftp_valid(ftp, side, buf, len)
854 ftps = &ftp->ftp_side[side];
857 ret = ippr_ftp_client_valid(ftps, buf, len);
859 ret = ippr_ftp_server_valid(ftps, buf, len);
865 * rv == 0 for outbound processing,
866 * rv == 1 for inbound processing.
868 int ippr_ftp_process(fin, ip, nat, ftp, rv)
875 int mlen, len, off, inc, i, sel, sel2, ok, ackoff, seqoff;
883 tcp = (tcphdr_t *)fin->fin_dp;
884 off = fin->fin_hlen + (tcp->th_off << 2);
885 #if SOLARIS && defined(_KERNEL)
897 mlen = mbufchainlen(m);
903 t = &ftp->ftp_side[1 - rv];
904 f = &ftp->ftp_side[rv];
905 thseq = ntohl(tcp->th_seq);
906 thack = ntohl(tcp->th_ack);
908 sel = aps->aps_sel[1 - rv];
909 sel2 = aps->aps_sel[rv];
911 seqoff = aps->aps_seqoff[sel];
912 if (aps->aps_seqmin[sel] > seqoff + thseq)
913 seqoff = aps->aps_seqoff[!sel];
914 ackoff = aps->aps_ackoff[sel2];
915 if (aps->aps_ackmin[sel2] > ackoff + thack)
916 ackoff = aps->aps_ackoff[!sel2];
919 kprintf("seqoff %d thseq %x ackmin %x\n", seqoff, thseq,
920 aps->aps_ackmin[sel]);
922 seqoff = aps->aps_ackoff[sel];
923 if (aps->aps_ackmin[sel] > seqoff + thseq)
924 seqoff = aps->aps_ackoff[!sel];
927 kprintf("ackoff %d thack %x seqmin %x\n", ackoff, thack,
928 aps->aps_seqmin[sel2]);
930 ackoff = aps->aps_seqoff[sel2];
932 if (aps->aps_seqmin[sel2] > ackoff + thack)
933 ackoff = aps->aps_seqoff[!sel2];
935 if (aps->aps_seqmin[sel2] > thack)
936 ackoff = aps->aps_seqoff[!sel2];
940 kprintf("%s: %x seq %x/%d ack %x/%d len %d\n", rv ? "IN" : "OUT",
941 tcp->th_flags, thseq, seqoff, thack, ackoff, mlen);
942 kprintf("sel %d seqmin %x/%x offset %d/%d\n", sel,
943 aps->aps_seqmin[sel], aps->aps_seqmin[sel2],
944 aps->aps_seqoff[sel], aps->aps_seqoff[sel2]);
945 kprintf("sel %d ackmin %x/%x offset %d/%d\n", sel2,
946 aps->aps_ackmin[sel], aps->aps_ackmin[sel2],
947 aps->aps_ackoff[sel], aps->aps_ackoff[sel2]);
951 * XXX - Ideally, this packet should get dropped because we now know
952 * that it is out of order (and there is no real danger in doing so
953 * apart from causing packets to go through here ordered).
956 kprintf("rv %d t:seq[0] %x seq[1] %x %d/%d\n",
957 rv, t->ftps_seq[0], t->ftps_seq[1], seqoff, ackoff);
961 if (t->ftps_seq[0] == 0) {
962 t->ftps_seq[0] = thack;
966 if (t->ftps_seq[0] == thack)
968 else if (t->ftps_seq[1] == thack) {
969 t->ftps_seq[0] = thack;
973 if (t->ftps_seq[0] + ackoff == thack)
975 else if (t->ftps_seq[0] == thack + ackoff)
977 else if (t->ftps_seq[1] + ackoff == thack) {
978 t->ftps_seq[0] = thack - ackoff;
980 } else if (t->ftps_seq[1] == thack + ackoff) {
981 t->ftps_seq[0] = thack - ackoff;
993 if (t->ftps_seq[0] + ackoff != thack) {
994 #if !defined(_KERNEL) && !defined(KERNEL)
996 "ippr_ftp_process:seq[0](%x) + ackoff(%x) != thack(%x)\n",
997 t->ftps_seq[0], ackoff, thack);
1003 kprintf("f:seq[0] %x seq[1] %x\n", f->ftps_seq[0], f->ftps_seq[1]);
1005 if (tcp->th_flags & TH_FIN) {
1006 if (thseq == f->ftps_seq[1]) {
1007 f->ftps_seq[0] = f->ftps_seq[1] - seqoff;
1008 f->ftps_seq[1] = thseq + 1 - seqoff;
1010 #if PROXY_DEBUG || (!defined(_KERNEL) && !defined(KERNEL))
1011 kprintf("FIN: thseq %x seqoff %d ftps_seq %x\n",
1012 thseq, seqoff, f->ftps_seq[0]);
1022 if ((thseq == f->ftps_seq[0]) || (thseq == f->ftps_seq[1])) {
1025 * Retransmitted data packet.
1027 } else if ((thseq + mlen == f->ftps_seq[0]) ||
1028 (thseq + mlen == f->ftps_seq[1])) {
1033 inc = thseq - f->ftps_seq[0];
1034 #if PROXY_DEBUG || (!defined(_KERNEL) && !defined(KERNEL))
1035 kprintf("inc %d sel %d rv %d\n", inc, sel, rv);
1036 kprintf("th_seq %x ftps_seq %x/%x\n", thseq, f->ftps_seq[0],
1038 kprintf("ackmin %x ackoff %d\n", (u_int)aps->aps_ackmin[sel],
1039 aps->aps_ackoff[sel]);
1040 kprintf("seqmin %x seqoff %d\n", (u_int)aps->aps_seqmin[sel],
1041 aps->aps_seqoff[sel]);
1048 rptr = f->ftps_rptr;
1049 wptr = f->ftps_wptr;
1050 f->ftps_seq[0] = thseq;
1051 f->ftps_seq[1] = f->ftps_seq[0] + mlen;
1055 len = MIN(mlen, FTP_BUFSZ / 2);
1057 #if !defined(_KERNEL)
1058 bcopy((char *)m + off, wptr, len);
1061 copyout_mblk(m, off, len, wptr);
1063 m_copydata(m, off, len, wptr);
1069 f->ftps_wptr = wptr;
1070 if (f->ftps_junk == 2)
1071 f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr,
1074 while ((f->ftps_junk == 0) && (wptr > rptr)) {
1075 f->ftps_junk = ippr_ftp_valid(ftp, rv, rptr,
1077 if (f->ftps_junk == 0) {
1080 f->ftps_rptr = rptr;
1082 inc += ippr_ftp_server(fin, ip, nat,
1085 inc += ippr_ftp_client(fin, ip, nat,
1087 rptr = f->ftps_rptr;
1088 wptr = f->ftps_wptr;
1093 * Off to a bad start so lets just forget about using the
1094 * ftp proxy for this connection.
1096 if ((f->ftps_cmds == 0) && (f->ftps_junk == 1)) {
1097 /* f->ftps_seq[1] += inc; */
1098 #if !defined(_KERNEL) && !defined(KERNEL)
1100 "ippr_ftp_process:cmds == 0 junk == 1\n");
1105 while ((f->ftps_junk == 1) && (rptr < wptr)) {
1106 while ((rptr < wptr) && (*rptr != '\r'))
1109 if (*rptr == '\r') {
1110 if (rptr + 1 < wptr) {
1111 if (*(rptr + 1) == '\n') {
1120 f->ftps_rptr = rptr;
1123 rptr = wptr = f->ftps_buf;
1125 if ((wptr > f->ftps_buf + FTP_BUFSZ / 2)) {
1127 if ((rptr == f->ftps_buf) ||
1128 (wptr - rptr > FTP_BUFSZ / 2)) {
1130 rptr = wptr = f->ftps_buf;
1132 bcopy(rptr, f->ftps_buf, i);
1133 wptr = f->ftps_buf + i;
1137 f->ftps_rptr = rptr;
1138 f->ftps_wptr = wptr;
1142 /* f->ftps_seq[1] += inc; */
1143 if (tcp->th_flags & TH_FIN)
1152 mlen = mbufchainlen(m);
1156 kprintf("ftps_seq[1] = %x inc %d len %d\n", f->ftps_seq[1], inc, mlen);
1159 f->ftps_rptr = rptr;
1160 f->ftps_wptr = wptr;
1161 return APR_INC(inc);
1165 int ippr_ftp_out(fin, ip, aps, nat)
1173 ftp = aps->aps_data;
1176 return ippr_ftp_process(fin, ip, nat, ftp, 0);
1180 int ippr_ftp_in(fin, ip, aps, nat)
1188 ftp = aps->aps_data;
1191 return ippr_ftp_process(fin, ip, nat, ftp, 1);
1196 * ippr_ftp_atoi - implement a version of atoi which processes numbers in
1197 * pairs separated by commas (which are expected to be in the range 0 - 255),
1198 * returning a 16 bit number combining either side of the , as the MSB and
1201 u_short ippr_ftp_atoi(ptr)
1205 u_char i = 0, j = 0;
1207 while ((c = *s++) && isdigit(c)) {
1215 while ((c = *s++) && isdigit(c)) {
1222 return (i << 8) | j;