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);