summaryrefslogtreecommitdiff
path: root/APACHE_1_3_42/src/modules/proxy/proxy_connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'APACHE_1_3_42/src/modules/proxy/proxy_connect.c')
-rw-r--r--APACHE_1_3_42/src/modules/proxy/proxy_connect.c257
1 files changed, 257 insertions, 0 deletions
diff --git a/APACHE_1_3_42/src/modules/proxy/proxy_connect.c b/APACHE_1_3_42/src/modules/proxy/proxy_connect.c
new file mode 100644
index 0000000000..d316fd9196
--- /dev/null
+++ b/APACHE_1_3_42/src/modules/proxy/proxy_connect.c
@@ -0,0 +1,257 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* CONNECT method for Apache proxy */
+
+#include "mod_proxy.h"
+#include "http_log.h"
+#include "http_main.h"
+
+#ifdef HAVE_BSTRING_H
+#include <bstring.h> /* for IRIX, FD_SET calls bzero() */
+#endif
+
+/*
+ * This handles Netscape CONNECT method secure proxy requests.
+ * A connection is opened to the specified host and data is
+ * passed through between the WWW site and the browser.
+ *
+ * This code is based on the INTERNET-DRAFT document
+ * "Tunneling SSL Through a WWW Proxy" currently at
+ * http://www.mcom.com/newsref/std/tunneling_ssl.html.
+ *
+ * If proxyhost and proxyport are set, we send a CONNECT to
+ * the specified proxy..
+ *
+ * FIXME: this is bad, because it does its own socket I/O
+ * instead of using the I/O in buff.c. However,
+ * the I/O in buff.c blocks on reads, and because
+ * this function doesn't know how much data will
+ * be sent either way (or when) it can't use blocking
+ * I/O. This may be very implementation-specific
+ * (to Linux). Any suggestions?
+ * FIXME: this doesn't log the number of bytes sent, but
+ * that may be okay, since the data is supposed to
+ * be transparent. In fact, this doesn't log at all
+ * yet. 8^)
+ * FIXME: doesn't check any headers initally sent from the
+ * client.
+ * FIXME: should allow authentication, but hopefully the
+ * generic proxy authentication is good enough.
+ * FIXME: no check for r->assbackwards, whatever that is.
+ */
+
+static int allowed_port(proxy_server_conf *conf, int port)
+{
+ int i;
+ int *list = (int *)conf->allowed_connect_ports->elts;
+
+ for (i = 0; i < conf->allowed_connect_ports->nelts; i++) {
+ if (port == list[i])
+ return 1;
+ }
+ return 0;
+}
+
+
+int ap_proxy_connect_handler(request_rec *r, cache_req *c, char *url,
+ const char *proxyhost, int proxyport)
+{
+ struct sockaddr_in server;
+ struct in_addr destaddr;
+ struct hostent server_hp;
+ const char *host, *err;
+ char *p;
+ int port, sock;
+ char buffer[HUGE_STRING_LEN];
+ int nbytes, i, j;
+ fd_set fds;
+
+ void *sconf = r->server->module_config;
+ proxy_server_conf *conf =
+ (proxy_server_conf *)ap_get_module_config(sconf, &proxy_module);
+ struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;
+
+ memset(&server, '\0', sizeof(server));
+ server.sin_family = AF_INET;
+
+ /* Break the URL into host:port pairs */
+
+ host = url;
+ p = strchr(url, ':');
+ if (p == NULL)
+ port = DEFAULT_HTTPS_PORT;
+ else {
+ port = atoi(p + 1);
+ *p = '\0';
+ }
+
+/* check if ProxyBlock directive on this host */
+ destaddr.s_addr = ap_inet_addr(host);
+ for (i = 0; i < conf->noproxies->nelts; i++) {
+ if ((npent[i].name != NULL && strstr(host, npent[i].name) != NULL)
+ || destaddr.s_addr == npent[i].addr.s_addr
+ || npent[i].name[0] == '*')
+ return ap_proxyerror(r, HTTP_FORBIDDEN,
+ "Connect to remote machine blocked");
+ }
+
+ /* Check if it is an allowed port */
+ if (conf->allowed_connect_ports->nelts == 0) {
+ /* Default setting if not overridden by AllowCONNECT */
+ switch (port) {
+ case DEFAULT_HTTPS_PORT:
+ case DEFAULT_SNEWS_PORT:
+ break;
+ default:
+ return HTTP_FORBIDDEN;
+ }
+ }
+ else if (!allowed_port(conf, port))
+ return HTTP_FORBIDDEN;
+
+ if (proxyhost) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server,
+ "CONNECT to remote proxy %s on port %d", proxyhost, proxyport);
+ }
+ else {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server,
+ "CONNECT to %s on port %d", host, port);
+ }
+
+ /* Nasty cast to work around broken terniary expressions on MSVC */
+ server.sin_port = htons((unsigned short)(proxyport ? proxyport : port));
+ err = ap_proxy_host2addr(proxyhost ? proxyhost : host, &server_hp);
+
+ if (err != NULL)
+ return ap_proxyerror(r,
+ proxyhost ? HTTP_BAD_GATEWAY : HTTP_INTERNAL_SERVER_ERROR, err);
+
+ sock = ap_psocket_ex(r->pool, PF_INET, SOCK_STREAM, IPPROTO_TCP, 1);
+ if (sock == -1) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, r, "proxy: error creating socket");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+#ifdef CHECK_FD_SETSIZE
+ if (sock >= FD_SETSIZE) {
+ ap_log_error(APLOG_MARK, APLOG_NOERRNO | APLOG_WARNING, NULL,
+ "proxy_connect_handler: filedescriptor (%u) "
+ "larger than FD_SETSIZE (%u) "
+ "found, you probably need to rebuild Apache with a "
+ "larger FD_SETSIZE", sock, FD_SETSIZE);
+ ap_pclosesocket(r->pool, sock);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+#endif
+
+ j = 0;
+ while (server_hp.h_addr_list[j] != NULL) {
+ memcpy(&server.sin_addr, server_hp.h_addr_list[j],
+ sizeof(struct in_addr));
+ i = ap_proxy_doconnect(sock, &server, r);
+ if (i == 0)
+ break;
+ j++;
+ }
+ if (i == -1) {
+ ap_pclosesocket(r->pool, sock);
+ return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR, ap_pstrcat(r->pool,
+ "Could not connect to remote machine:<br>", strerror(errno), NULL));
+ }
+
+ /*
+ * If we are connecting through a remote proxy, we need to pass the
+ * CONNECT request on to it.
+ */
+ if (proxyport) {
+ /*
+ * FIXME: We should not be calling write() directly, but we currently
+ * have no alternative. Error checking ignored. Also, we force a
+ * HTTP/1.0 request to keep things simple.
+ */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server,
+ "Sending the CONNECT request to the remote proxy");
+ ap_snprintf(buffer, sizeof(buffer), "CONNECT %s HTTP/1.0" CRLF, r->uri);
+ send(sock, buffer, strlen(buffer), 0);
+ ap_snprintf(buffer, sizeof(buffer),
+ "Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
+ send(sock, buffer, strlen(buffer), 0);
+ }
+ else {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server,
+ "Returning 200 OK Status");
+ ap_rvputs(r, "HTTP/1.0 200 Connection established" CRLF, NULL);
+ ap_rvputs(r, "Proxy-agent: ", ap_get_server_version(), CRLF CRLF, NULL);
+ ap_bflush(r->connection->client);
+ }
+
+ while (1) { /* Infinite loop until error (one side closes
+ * the connection) */
+ FD_ZERO(&fds);
+ FD_SET(sock, &fds);
+ FD_SET(ap_bfileno(r->connection->client, B_WR), &fds);
+
+ ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server,
+ "Going to sleep (select)");
+ i = ap_select((ap_bfileno(r->connection->client, B_WR) > sock ?
+ ap_bfileno(r->connection->client, B_WR) + 1 :
+ sock + 1), &fds, NULL, NULL, NULL);
+ ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server,
+ "Woke from select(), i=%d", i);
+
+ if (i) {
+ if (FD_ISSET(sock, &fds)) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server,
+ "sock was set");
+ if ((nbytes = recv(sock, buffer, HUGE_STRING_LEN, 0)) != 0) {
+ if (nbytes == -1)
+ break;
+ if (send(ap_bfileno(r->connection->client, B_WR), buffer,
+ nbytes, 0) == EOF)
+ break;
+ ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO,
+ r->server, "Wrote %d bytes to client", nbytes);
+ }
+ else
+ break;
+ }
+ else if (FD_ISSET(ap_bfileno(r->connection->client, B_WR), &fds)) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO, r->server,
+ "client->fd was set");
+ if ((nbytes = recv(ap_bfileno(r->connection->client, B_WR),
+ buffer, HUGE_STRING_LEN, 0)) != 0) {
+ if (nbytes == -1)
+ break;
+ if (send(sock, buffer, nbytes, 0) == EOF)
+ break;
+ ap_log_error(APLOG_MARK, APLOG_DEBUG | APLOG_NOERRNO,
+ r->server, "Wrote %d bytes to server", nbytes);
+ }
+ else
+ break;
+ }
+ else
+ break; /* Must be done waiting */
+ }
+ else
+ break;
+ }
+
+ ap_pclosesocket(r->pool, sock);
+
+ return OK;
+}