chuck 96/12/24 09:23:26
Modified: src/modules/proxy proxy_ftp.c Log: Add PASV to FTP proxy. Make default MIME type text/plain, so folks get their READMEs OK. Merry Christmas. Revision Changes Path 1.4 +146 -48 apache/src/modules/proxy/proxy_ftp.c Index: proxy_ftp.c =================================================================== RCS file: /export/home/cvs/apache/src/modules/proxy/proxy_ftp.c,v retrieving revision 1.3 retrieving revision 1.4 diff -C3 -r1.3 -r1.4 *** proxy_ftp.c 1996/10/20 23:59:02 1.3 --- proxy_ftp.c 1996/12/24 17:23:24 1.4 *************** *** 326,346 **** * Handles direct access of ftp:// URLs * Original (Non-PASV) version from * Troy Morrison <[EMAIL PROTECTED]> */ int proxy_ftp_handler(request_rec *r, struct cache_req *c, char *url) { char *host, *path, *p, *user, *password, *parms; const char *err; ! int port, userlen, passlen, i, len, sock, dsock, csd, rc, nocache; struct sockaddr_in server; struct hdr_entry *hdr; array_header *resp_hdrs; ! BUFF *f, *cache, *data; pool *pool=r->pool; const int one=1; const long int zero=0L; /* This appears to fix a bug(?) that generates an "Address family not supported by protocol" error in proxy_doconnect() later (along with making sure server.sin_family = AF_INET - cdm) */ --- 326,358 ---- * Handles direct access of ftp:// URLs * Original (Non-PASV) version from * Troy Morrison <[EMAIL PROTECTED]> + * PASV added by Chuck */ int proxy_ftp_handler(request_rec *r, struct cache_req *c, char *url) { char *host, *path, *p, *user, *password, *parms; const char *err; ! int port, userlen, passlen, i, len, sock, dsock, rc, nocache; ! int csd = 0; struct sockaddr_in server; struct hdr_entry *hdr; array_header *resp_hdrs; ! BUFF *f, *cache; ! BUFF *data = NULL; pool *pool=r->pool; const int one=1; const long int zero=0L; + /* stuff for PASV mode */ + unsigned int presult, h0, h1, h2, h3, p0, p1; + unsigned int paddr; + unsigned short pport; + struct sockaddr_in data_addr; + int pasvmode = 0; + char pasv[64]; + char *pstr; + /* This appears to fix a bug(?) that generates an "Address family not supported by protocol" error in proxy_doconnect() later (along with making sure server.sin_family = AF_INET - cdm) */ *************** *** 519,574 **** else if (i == 504) parms[0] = '\0'; } ! /* set up data connection */ ! len = sizeof(struct sockaddr_in); ! if (getsockname(sock, (struct sockaddr *)&server, &len) < 0) ! { ! proxy_log_uerror("getsockname", NULL, ! "proxy: error getting socket address", r->server); ! pclosef(pool, sock); ! return SERVER_ERROR; ! } ! dsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (dsock == -1) ! { ! proxy_log_uerror("socket", NULL, "proxy: error creating socket", r->server); pclosef(pool, sock); ! return SERVER_ERROR; } note_cleanups_for_fd(pool, dsock); ! if (setsockopt(dsock, SOL_SOCKET, SO_REUSEADDR, (const char *)&one, ! sizeof(int)) == -1) { proxy_log_uerror("setsockopt", NULL, ! "proxy: error setting reuseaddr option", r->server); pclosef(pool, dsock); pclosef(pool, sock); return SERVER_ERROR; } ! if (bind(dsock, (struct sockaddr *)&server, sizeof(struct sockaddr_in)) == ! -1) ! { ! char buff[22]; ! sprintf(buff, "%s:%d", inet_ntoa(server.sin_addr), server.sin_port); ! proxy_log_uerror("bind", buff, ! "proxy: error binding to ftp data socket", r->server); ! pclosef(pool, sock); pclosef(pool, dsock); } - listen(dsock, 2); /* only need a short queue */ /* set request */ len = decodeenc(path); /* TM - if len == 0 then it must be a directory (you can't RETR nothing) */ ! if(len==0) parms="d"; ! else { bputs("SIZE ", f); bwrite(f, path, len); --- 531,665 ---- else if (i == 504) parms[0] = '\0'; } ! /* try to set up PASV data connection first */ dsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (dsock == -1) ! { ! proxy_log_uerror("socket", NULL, "proxy: error creating PASV socket", r->server); pclosef(pool, sock); ! return SERVER_ERROR; } note_cleanups_for_fd(pool, dsock); ! if (setsockopt(dsock, SOL_SOCKET, SO_DEBUG, (const char *)&one, ! sizeof (int)) == -1) { proxy_log_uerror("setsockopt", NULL, ! "proxy: error setting PASV debug option", r->server); pclosef(pool, dsock); pclosef(pool, sock); return SERVER_ERROR; } ! bputs("PASV\015\012", f); ! bflush(f); ! Explain0("FTP: PASV command issued"); ! /* possible results: 227, 421, 500, 501, 502, 530 */ ! i = bgets(pasv, sizeof(pasv), f); ! if (i == -1) ! { ! proxy_log_uerror("command", NULL, "PASV: control connection is toast", ! r->server); pclosef(pool, dsock); + pclosef(pool, sock); + return SERVER_ERROR; + } else + { + pasv[i-1] = '\0'; + pstr = strtok(pasv, " "); /* separate result code */ + if (pstr != NULL) + { + presult = atoi(pstr); + pstr = strtok(NULL, "("); /* separate address & port params */ + if (pstr != NULL) + pstr = strtok(NULL, ")"); + } + else + presult = atoi(pasv); + + Explain1("FTP: returned status %d", presult); + + if (presult == 227 && pstr != NULL && (sscanf(pstr, + "%d,%d,%d,%d,%d,%d", &h3, &h2, &h1, &h0, &p1, &p0) == 6)) + { + /* pardon the parens, but it makes gcc happy */ + paddr = (((((h3 << 8) + h2) << 8) + h1) << 8) + h0; + pport = (p1 << 8) + p0; + Explain5("FTP: contacting host %d.%d.%d.%d:%d", + h3, h2, h1, h0, pport); + data_addr.sin_family = AF_INET; + data_addr.sin_addr.s_addr = htonl(paddr); + data_addr.sin_port = htons(pport); + i = proxy_doconnect(dsock, &data_addr, r); + + if (i == -1) + return proxyerror(r, "Could not connect to remote machine"); + else + { + data = bcreate(pool, B_RDWR); + bpushfd(data, dsock, dsock); + pasvmode = 1; + } + } else + pclosef(pool, dsock); /* and try the regular way */ + } + + if (!pasvmode) /* set up data connection */ + { + len = sizeof(struct sockaddr_in); + if (getsockname(sock, (struct sockaddr *)&server, &len) < 0) + { + proxy_log_uerror("getsockname", NULL, + "proxy: error getting socket address", r->server); + pclosef(pool, sock); + return SERVER_ERROR; + } + + dsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (dsock == -1) + { + proxy_log_uerror("socket", NULL, "proxy: error creating socket", + r->server); + pclosef(pool, sock); + return SERVER_ERROR; + } + note_cleanups_for_fd(pool, dsock); + + if (setsockopt(dsock, SOL_SOCKET, SO_REUSEADDR, (const char *)&one, + sizeof(int)) == -1) + { + proxy_log_uerror("setsockopt", NULL, + "proxy: error setting reuseaddr option", r->server); + pclosef(pool, dsock); + pclosef(pool, sock); + return SERVER_ERROR; + } + + if (bind(dsock, (struct sockaddr *)&server, + sizeof(struct sockaddr_in)) == -1) + { + char buff[22]; + + sprintf(buff, "%s:%d", inet_ntoa(server.sin_addr), server.sin_port); + proxy_log_uerror("bind", buff, + "proxy: error binding to ftp data socket", r->server); + pclosef(pool, sock); + pclosef(pool, dsock); + } + listen(dsock, 2); /* only need a short queue */ } /* set request */ len = decodeenc(path); /* TM - if len == 0 then it must be a directory (you can't RETR nothing) */ ! if(len==0) ! { ! parms="d"; ! } else { bputs("SIZE ", f); bwrite(f, path, len); *************** *** 656,662 **** proxy_add_header(resp_hdrs, "Content-Type", r->content_type, HDR_REP); Explain1("FTP: Content-Type set to %s",r->content_type); ! } } i = proxy_cache_update(c, resp_hdrs, "FTP", nocache); if (i != DECLINED) --- 747,756 ---- proxy_add_header(resp_hdrs, "Content-Type", r->content_type, HDR_REP); Explain1("FTP: Content-Type set to %s",r->content_type); ! } else ! { ! proxy_add_header(resp_hdrs, "Content-Type", "text/plain", HDR_REP); ! } } i = proxy_cache_update(c, resp_hdrs, "FTP", nocache); if (i != DECLINED) *************** *** 667,690 **** } cache = c->fp; ! /* wait for connection */ ! hard_timeout ("proxy ftp data connect", r); ! len = sizeof(struct sockaddr_in); ! do csd = accept(dsock, (struct sockaddr *)&server, &len); ! while (csd == -1 && errno == EINTR); /* SHUDDER on SOCKS - cdm */ ! if (csd == -1) { ! proxy_log_uerror("accept", NULL, ! "proxy: failed to accept data connection", r->server); ! pclosef(pool, dsock); ! pclosef(pool, sock); ! proxy_cache_error(c); ! return BAD_GATEWAY; } - note_cleanups_for_fd(pool, csd); - data = bcreate(pool, B_RDWR); - bpushfd(data, csd, -1); - kill_timeout(r); hard_timeout ("proxy receive", r); /* send response */ --- 761,786 ---- } cache = c->fp; ! if (!pasvmode) /* wait for connection */ { ! hard_timeout ("proxy ftp data connect", r); ! len = sizeof(struct sockaddr_in); ! do csd = accept(dsock, (struct sockaddr *)&server, &len); ! while (csd == -1 && errno == EINTR); ! if (csd == -1) ! { ! proxy_log_uerror("accept", NULL, ! "proxy: failed to accept data connection", r->server); ! pclosef(pool, dsock); ! pclosef(pool, sock); ! proxy_cache_error(c); ! return BAD_GATEWAY; ! } ! note_cleanups_for_fd(pool, csd); ! data = bcreate(pool, B_RDWR); ! bpushfd(data, csd, -1); ! kill_timeout(r); } hard_timeout ("proxy receive", r); /* send response */ *************** *** 731,737 **** /* abort the transfer */ bputs("ABOR\015\012", f); bflush(f); ! pclosef(pool, csd); Explain0("FTP: ABOR"); /* responses: 225, 226, 421, 500, 501, 502 */ i = ftp_getrc(f); --- 827,834 ---- /* abort the transfer */ bputs("ABOR\015\012", f); bflush(f); ! if (!pasvmode) ! pclosef(pool, csd); Explain0("FTP: ABOR"); /* responses: 225, 226, 421, 500, 501, 502 */ i = ftp_getrc(f); *************** *** 746,752 **** Explain0("FTP: QUIT"); /* responses: 221, 500 */ ! pclosef(pool, csd); pclosef(pool, dsock); pclosef(pool, sock); --- 843,850 ---- Explain0("FTP: QUIT"); /* responses: 221, 500 */ ! if (!pasvmode) ! pclosef(pool, csd); pclosef(pool, dsock); pclosef(pool, sock);