diff options
Diffstat (limited to 'sys/contrib/ipfilter/netinet/ip_ftp_pxy.c')
-rw-r--r-- | sys/contrib/ipfilter/netinet/ip_ftp_pxy.c | 148 |
1 files changed, 101 insertions, 47 deletions
diff --git a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c index d5eac9c..ce673d9 100644 --- a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c @@ -49,10 +49,12 @@ int ippr_ftp_pasv __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); int ippr_ftp_port __P((fr_info_t *, ip_t *, nat_t *, ftpside_t *, int)); int ippr_ftp_process __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); int ippr_ftp_server __P((fr_info_t *, ip_t *, nat_t *, ftpinfo_t *, int)); -int ippr_ftp_valid __P((char *, size_t)); +int ippr_ftp_valid __P((int, char *, size_t)); +int ippr_ftp_server_valid __P((char *, size_t)); +int ippr_ftp_client_valid __P((char *, size_t)); u_short ippr_ftp_atoi __P((char **)); -static frentry_t natfr; +static frentry_t ftppxyfr; int ippr_ftp_pasvonly = 0; int ippr_ftp_insecure = 0; @@ -62,9 +64,9 @@ int ippr_ftp_insecure = 0; */ int ippr_ftp_init() { - bzero((char *)&natfr, sizeof(natfr)); - natfr.fr_ref = 1; - natfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; + bzero((char *)&ftppxyfr, sizeof(ftppxyfr)); + ftppxyfr.fr_ref = 1; + ftppxyfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE; return 0; } @@ -105,9 +107,9 @@ int dlen; { tcphdr_t *tcp, tcph, *tcp2 = &tcph; char newbuf[IPF_FTPBUFSZ], *s; - u_short a5, a6, sp, dp; u_int a1, a2, a3, a4; struct in_addr swip; + u_short a5, a6, sp; size_t nlen, olen; fr_info_t fi; int inc, off; @@ -173,7 +175,7 @@ int dlen; a4 = a1 & 0xff; a1 >>= 24; olen = s - f->ftps_rptr; - /* DO NOT change this to sprintf! */ + /* DO NOT change this to snprintf! */ (void) sprintf(newbuf, "%s %u,%u,%u,%u,%u,%u\r\n", "PORT", a1, a2, a3, a4, a5, a6); @@ -241,46 +243,47 @@ int dlen; * Add skeleton NAT entry for connection which will come back the * other way. */ - sp = htons(a5 << 8 | a6); + sp = (a5 << 8 | a6); /* * Don't allow the PORT command to specify a port < 1024 due to * security crap. */ - if (ntohs(sp) < 1024) + if (sp < 1024) return 0; /* * The server may not make the connection back from port 20, but * it is the most likely so use it here to check for a conflicting * mapping. */ - dp = htons(fin->fin_data[1] - 1); - ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_p, nat->nat_inip, - ip->ip_dst, (dp << 16) | sp, 0); + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + fi.fin_data[0] = sp; + fi.fin_data[1] = fin->fin_data[1] - 1; + ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip, + ip->ip_dst, 0); if (ipn == NULL) { int slen; slen = ip->ip_len; ip->ip_len = fin->fin_hlen + sizeof(*tcp2); - bcopy((char *)fin, (char *)&fi, sizeof(fi)); bzero((char *)tcp2, sizeof(*tcp2)); tcp2->th_win = htons(8192); - tcp2->th_sport = sp; + tcp2->th_sport = htons(sp); tcp2->th_off = 5; tcp2->th_dport = 0; /* XXX - don't specify remote port */ - fi.fin_data[0] = ntohs(sp); fi.fin_data[1] = 0; fi.fin_dlen = sizeof(*tcp2); fi.fin_dp = (char *)tcp2; - fi.fin_fr = &natfr; + fi.fin_fr = &ftppxyfr; fi.fin_out = 1; swip = ip->ip_src; fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; ip->ip_src = nat->nat_inip; - ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_TCP|FI_W_DPORT, + ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_DPORT, NAT_OUTBOUND); if (ipn != NULL) { ipn->nat_age = fr_defnatage; - (void) fr_addstate(ip, &fi, FI_W_DPORT); + (void) fr_addstate(ip, &fi, NULL, + FI_W_DPORT|FI_IGNOREPKT); } ip->ip_len = slen; ip->ip_src = swip; @@ -340,7 +343,8 @@ int dlen; !strncmp(cmd, "ADAT ", 5)) { ftp->ftp_passok = FTPXY_ADAT_1; ftp->ftp_incok = 1; - } else if ((ftp->ftp_passok == FTPXY_PAOK_2) && + } else if ((ftp->ftp_passok == FTPXY_PAOK_1 || + ftp->ftp_passok == FTPXY_PAOK_2) && !strncmp(cmd, "ACCT ", 5)) { ftp->ftp_passok = FTPXY_ACCT_1; ftp->ftp_incok = 1; @@ -368,8 +372,8 @@ int dlen; { tcphdr_t *tcp, tcph, *tcp2 = &tcph; struct in_addr swip, swip2; - u_short a5, a6, sp, dp; u_int a1, a2, a3, a4; + u_short a5, a6, dp; fr_info_t fi; nat_t *ipn; int inc; @@ -501,26 +505,27 @@ int dlen; * Add skeleton NAT entry for connection which will come back the * other way. */ - sp = 0; + bcopy((char *)fin, (char *)&fi, sizeof(fi)); + fi.fin_data[0] = 0; dp = htons(fin->fin_data[1] - 1); - ipn = nat_outlookup(fin->fin_ifp, IPN_TCP, nat->nat_p, nat->nat_inip, - ip->ip_dst, (dp << 16) | sp, 0); + fi.fin_data[1] = ntohs(dp); + ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip, + ip->ip_dst, 0); if (ipn == NULL) { int slen; slen = ip->ip_len; ip->ip_len = fin->fin_hlen + sizeof(*tcp2); - bcopy((char *)fin, (char *)&fi, sizeof(fi)); bzero((char *)tcp2, sizeof(*tcp2)); tcp2->th_win = htons(8192); tcp2->th_sport = 0; /* XXX - fake it for nat_new */ tcp2->th_off = 5; - fi.fin_data[0] = a5 << 8 | a6; + fi.fin_data[1] = a5 << 8 | a6; fi.fin_dlen = sizeof(*tcp2); - tcp2->th_dport = htons(fi.fin_data[0]); - fi.fin_data[1] = 0; + tcp2->th_dport = htons(fi.fin_data[1]); + fi.fin_data[0] = 0; fi.fin_dp = (char *)tcp2; - fi.fin_fr = &natfr; + fi.fin_fr = &ftppxyfr; fi.fin_out = 1; swip = ip->ip_src; swip2 = ip->ip_dst; @@ -528,11 +533,12 @@ int dlen; fi.fin_fi.fi_saddr = nat->nat_inip.s_addr; ip->ip_dst = ip->ip_src; ip->ip_src = nat->nat_inip; - ipn = nat_new(nat->nat_ptr, ip, &fi, IPN_TCP|FI_W_SPORT, + ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_SPORT, NAT_OUTBOUND); if (ipn != NULL) { ipn->nat_age = fr_defnatage; - (void) fr_addstate(ip, &fi, FI_W_SPORT); + (void) fr_addstate(ip, &fi, NULL, + FI_W_SPORT|FI_IGNOREPKT); } ip->ip_len = slen; ip->ip_src = swip; @@ -601,7 +607,7 @@ int dlen; * Look to see if the buffer starts with something which we recognise as * being the correct syntax for the FTP protocol. */ -int ippr_ftp_valid(buf, len) +int ippr_ftp_client_valid(buf, len) char *buf; size_t len; { @@ -614,36 +620,60 @@ size_t len; c = *s++; i--; - if (isdigit(c)) { + if (isalpha(c)) { c = *s++; i--; - if (isdigit(c)) { + if (isalpha(c)) { c = *s++; i--; - if (isdigit(c)) { + if (isalpha(c)) { c = *s++; i--; - if ((c != '-') && (c != ' ')) + if (isalpha(c)) { + c = *s++; + i--; + if ((c != ' ') && (c != '\r')) + return 1; + } else if ((c != ' ') && (c != '\r')) return 1; } else return 1; } else return 1; - } else if (isalpha(c)) { + } else + return 1; + for (; i; i--) { + c = *s++; + if (c == '\n') + return 0; + } + return 2; +} + + +int ippr_ftp_server_valid(buf, len) +char *buf; +size_t len; +{ + register char *s, c; + register size_t i = len; + + if (i < 5) + return 2; + s = buf; + c = *s++; + i--; + + if (isdigit(c)) { c = *s++; i--; - if (isalpha(c)) { + if (isdigit(c)) { c = *s++; i--; - if (isalpha(c)) { + if (isdigit(c)) { c = *s++; i--; - if (isalpha(c)) { - c = *s++; - i--; - if ((c != ' ') && (c != '\r')) - return 1; - } else if ((c != ' ') && (c != '\r')) + if ((c != '-') && (c != ' ')) return 1; } else return 1; @@ -660,6 +690,21 @@ size_t len; } +int ippr_ftp_valid(side, buf, len) +int side; +char *buf; +size_t len; +{ + int ret; + + if (side == 0) + ret = ippr_ftp_client_valid(buf, len); + else + ret = ippr_ftp_server_valid(buf, len); + return ret; +} + + int ippr_ftp_process(fin, ip, nat, ftp, rv) fr_info_t *fin; ip_t *ip; @@ -715,7 +760,7 @@ int rv; if (f->ftps_len + f->ftps_seq == ntohl(tcp->th_seq)) f->ftps_seq = ntohl(tcp->th_seq); else if (ntohl(tcp->th_seq) + i != f->ftps_seq) { - return APR_ERR(-1); + return APR_ERR(1); } f->ftps_len = mlen; @@ -732,11 +777,12 @@ int rv; wptr += len; f->ftps_wptr = wptr; if (f->ftps_junk == 2) - f->ftps_junk = ippr_ftp_valid(rptr, wptr - rptr); + f->ftps_junk = ippr_ftp_valid(rv, rptr, wptr - rptr); while ((f->ftps_junk == 0) && (wptr > rptr)) { - f->ftps_junk = ippr_ftp_valid(rptr, wptr - rptr); + f->ftps_junk = ippr_ftp_valid(rv, rptr, wptr - rptr); if (f->ftps_junk == 0) { + f->ftps_cmds++; len = wptr - rptr; f->ftps_rptr = rptr; if (rv) @@ -746,9 +792,17 @@ int rv; inc += ippr_ftp_client(fin, ip, nat, ftp, len); rptr = f->ftps_rptr; + wptr = f->ftps_wptr; } } + /* + * Off to a bad start so lets just forget about using the + * ftp proxy for this connection. + */ + if ((f->ftps_cmds == 0) && (f->ftps_junk == 1)) + return APR_ERR(2); + while ((f->ftps_junk == 1) && (rptr < wptr)) { while ((rptr < wptr) && (*rptr != '\r')) rptr++; |