/*
- * $Id: IPInterception.cc,v 1.4 2003/01/23 00:37:13 robertc Exp $
+ * $Id: IPInterception.cc,v 1.5 2003/02/21 19:53:01 hno Exp $
*
* DEBUG: section 89 NAT / IP Interception
* AUTHOR: Robert Collins
#include <linux/netfilter_ipv4.h>
#endif
-void
-rewriteURIwithInterceptedDetails(char const *originalURL, char *uriBuffer, size_t bufferLength, int fd, struct sockaddr_in me, struct sockaddr_in peer, int vport)
-{
#if IPF_TRANSPARENT
+int
+clientNatLookup(int fd, struct sockaddr_in me, struct sockaddr_in peer, struct sockaddr_in *dst)
+{
struct natlookup natLookup;
static int natfd = -1;
static int siocgnatl_cmd = SIOCGNATL & 0xff;
int x;
-#endif
-#if PF_TRANSPARENT
- struct pfioc_natlook nl;
- static int pffd = -1;
-#endif
-#if LINUX_NETFILTER
- size_t sock_sz = sizeof(me);
-#endif
-#if IPF_TRANSPARENT
+
natLookup.nl_inport = me.sin_port;
natLookup.nl_outport = peer.sin_port;
natLookup.nl_inip = me.sin_addr;
errno = save_errno;
}
if (natfd < 0) {
- debug(89, 1) ("rewriteURIwithInterceptedDetails: NAT open failed: %s\n",
+ debug(50, 1) ("parseHttpRequest: NAT open failed: %s\n",
xstrerror());
- cbdataFree(context);
- xfree(inbuf);
- return rewriteURIwithInterceptedDetailsAbort(conn, "error:nat-open-failed");
+ return -1;
}
- /*
+ /*
* IP-Filter changed the type for SIOCGNATL between
* 3.3 and 3.4. It also changed the cmd value for
* SIOCGNATL, so at least we can detect it. We could
}
if (x < 0) {
if (errno != ESRCH) {
- debug(89, 1) ("rewriteURIwithInterceptedDetails: NAT lookup failed: ioctl(SIOCGNATL)\n");
+ debug(50, 1) ("parseHttpRequest: NAT lookup failed: ioctl(SIOCGNATL)\n");
close(natfd);
natfd = -1;
- cbdataFree(context);
- xfree(inbuf);
- return rewriteURIwithInterceptedDetailsAbort(conn,
- "error:nat-lookup-failed");
- } else
- snprintf(uriBuffer, bufferLength, "http://%s:%d%s",
- inet_ntoa(me.sin_addr), vport, originalURL);
+ }
+ return -1;
} else {
- if (vport_mode)
- vport = ntohs(natLookup.nl_realport);
- snprintf(uriBuffer, bufferLength, "http://%s:%d%s",
- inet_ntoa(natLookup.nl_realip), vport, originalURL);
+ if (me.sin_addr.s_addr != natLookup.nl_realip.s_addr)
+ dst->sin_family = AF_INET;
+ dst->sin_port = natLookup.nl_realport;
+ dst->sin_addr = natLookup.nl_realip;
+ return 0;
+ } else {
+ return -1;
+ }
}
+}
+#elif LINUX_NETFILTER
+int
+clientNatLookup(int fd, struct sockaddr_in me, struct sockaddr_in peer, struct sockaddr_in *dst)
+{
+ size_t sock_sz = sizeof(*dst);
+ memcpy(dst, &me, sizeof(*dst));
+ if (getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, dst, &sock_sz) != 0)
+ return -1;
+
+ debug(33, 5) ("clientNatLookup: addr = %s", inet_ntoa(dst->sin_addr));
+ if (me.sin_addr.s_addr != dst->sin_addr.s_addr)
+ return 0;
+ else
+ return -1;
+}
#elif PF_TRANSPARENT
+int
+clientNatLookup(int fd, struct sockaddr_in me, struct sockaddr_in peer, struct sockaddr_in *dst)
+{
+ struct pfioc_natlook nl;
+ static int pffd = -1;
if (pffd < 0)
pffd = open("/dev/pf", O_RDWR);
if (pffd < 0) {
- debug(89, 1) ("rewriteURIwithInterceptedDetails: PF open failed: %s\n",
+ debug(50, 1) ("parseHttpRequest: PF open failed: %s\n",
xstrerror());
- cbdataFree(context);
- xfree(inbuf);
- return rewriteURIwithInterceptedDetailsAbort(conn, "error:pf-open-failed");
+ return -1;
}
+ memset(dst, 0, sizeof(*dst));
memset(&nl, 0, sizeof(struct pfioc_natlook));
nl.saddr.v4.s_addr = peer.sin_addr.s_addr;
nl.sport = peer.sin_port;
nl.direction = PF_OUT;
if (ioctl(pffd, DIOCNATLOOK, &nl)) {
if (errno != ENOENT) {
- debug(89, 1) ("rewriteURIwithInterceptedDetails: PF lookup failed: ioctl(DIOCNATLOOK)\n");
+ debug(50, 1) ("parseHttpRequest: PF lookup failed: ioctl(DIOCNATLOOK)\n");
close(pffd);
pffd = -1;
- cbdataFree(context);
- xfree(inbuf);
- return rewriteURIwithInterceptedDetailsAbort(conn,
- "error:pf-lookup-failed");
- } else
- snprintf(uriBuffer, bufferLength, "http://%s:%d%s",
- inet_ntoa(me.sin_addr), vport, originalURL);
- } else
- snprintf(uriBuffer, bufferLength, "http://%s:%d%s",
- inet_ntoa(nl.rdaddr.v4), ntohs(nl.rdport), originalURL);
+ }
+ return -1;
+ } else {
+ int natted = me.sin_addr.s_addr != nt.rdaddr.v4.s_addr;
+ dst->sin_family = AF_INET;
+ dst->sin_port = nl.rdport;
+ dst->sin_addr = nl.rdaddr.v4;
+ if (natted)
+ return 0;
+ else
+ return -1;
+ }
+}
#else
-#if LINUX_NETFILTER
- /* If the call fails the address structure will be unchanged */
- getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, &me, &sock_sz);
- debug(89, 5) ("rewriteURIwithInterceptedDetails: addr = %s",
- inet_ntoa(me.sin_addr));
- if (vport_mode)
- vport = (int) ntohs(me.sin_port);
-#endif
- snprintf(uriBuffer, bufferLength, "http://%s:%d%s",
- inet_ntoa(me.sin_addr), vport, originalURL);
-#endif
+int
+clientNatLookup(int fd, struct sockaddr_in me, struct sockaddr_in peer, struct sockaddr_in *dst)
+{
+ debug(33, 1) ("WARNING: transparent proxying not supported\n");
+ return -1;
}
+#endif
+
/*
- * $Id: cache_cf.cc,v 1.432 2003/02/17 08:39:43 robertc Exp $
+ * $Id: cache_cf.cc,v 1.433 2003/02/21 19:53:01 hno Exp $
*
* DEBUG: section 3 Configuration File Parsing
* AUTHOR: Harvest Derived
static void parse_denyinfo(acl_deny_info_list ** var);
static void dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var);
static void free_denyinfo(acl_deny_info_list ** var);
+#if CURRENTLY_UNUSED
static void parse_sockaddr_in_list(sockaddr_in_list **);
static void dump_sockaddr_in_list(StoreEntry *, const char *, const sockaddr_in_list *);
static void free_sockaddr_in_list(sockaddr_in_list **);
-#if 0
static int check_null_sockaddr_in_list(const sockaddr_in_list *);
+#endif /* CURRENTLY_UNUSED */
+static void parse_http_port_list(http_port_list **);
+static void dump_http_port_list(StoreEntry *, const char *, const http_port_list *);
+static void free_http_port_list(http_port_list **);
+#if UNUSED_CODE
+static int check_null_http_port_list(const http_port_list *);
#endif
#if USE_SSL
static void parse_https_port_list(https_port_list **);
static void
configDoConfigure(void)
{
- LOCAL_ARRAY(char, buf, BUFSIZ);
memset(&Config2, '\0', sizeof(SquidConfig2));
/* init memory as early as possible */
memConfigure();
wordlistDestroy(&Config.Program.redirect);
}
}
- if (Config.Accel.host) {
- snprintf(buf, BUFSIZ, "http://%s:%d", Config.Accel.host, Config.Accel.port);
- Config2.Accel.prefix = xstrdup(buf);
- Config2.Accel.on = 1;
- }
if (Config.appendDomain)
if (*Config.appendDomain != '.')
fatal("append_domain must begin with a '.'");
if (Config.errHtmlText == NULL)
Config.errHtmlText = xstrdup(null_string);
storeConfigure();
- if (Config2.Accel.on && !strcmp(Config.Accel.host, "virtual")) {
- vhost_mode = 1;
- if (Config.Accel.port == 0)
- vport_mode = 1;
- }
snprintf(ThisCache, sizeof(ThisCache), "%s (%s)",
uniqueHostname(),
full_appname_string);
return PEER_SIBLING;
}
+#if CURRENTLY_UNUSED
+/* This code was previously used by http_port. Left as it really should
+ * be used by icp_port and htcp_port
+ */
void
parse_sockaddr_in_list_token(sockaddr_in_list ** head, char *token)
{
}
}
-#if 0
static int
check_null_sockaddr_in_list(const sockaddr_in_list * s)
{
return NULL == s;
}
-#endif
+#endif /* CURRENTLY_UNUSED */
-#if USE_SSL
static void
-parse_https_port_list(https_port_list ** head)
+parse_http_port_specification(http_port_list * s, char *token)
{
- char *token;
- char *t;
- char *host;
+ char *host = NULL;
const struct hostent *hp;
- unsigned short port;
- https_port_list *s;
- token = strtok(NULL, w_space);
- if (!token)
- self_destruct();
- host = NULL;
- port = 0;
+ unsigned short port = 0;
+ char *t;
if ((t = strchr(token, ':'))) {
/* host:port */
host = token;
*t = '\0';
- port = (unsigned short) xatoi(t + 1);
+ port = (unsigned short) atoi(t + 1);
if (0 == port)
self_destruct();
- } else if ((port = xatoi(token)) > 0) {
+ } else if ((port = atoi(token)) > 0) {
/* port */
} else {
self_destruct();
}
- s = (https_port_list *)xcalloc(1, sizeof(*s));
s->s.sin_port = htons(port);
if (NULL == host)
s->s.sin_addr = any_addr;
else if (1 == safe_inet_addr(host, &s->s.sin_addr))
(void) 0;
- else if ((hp = gethostbyname(host))) /* dont use ipcache */
+ else if ((hp = gethostbyname(host))) {
+ /* dont use ipcache */
s->s.sin_addr = inaddrFromHostent(hp);
- else
+ s->defaultsite = xstrdup(host);
+ } else
+ self_destruct();
+}
+
+static void
+parse_http_port_option(http_port_list * s, char *token)
+{
+ if (strncmp(token, "defaultsite=", 12) == 0) {
+ safe_free(s->defaultsite);
+ s->defaultsite = xstrdup(token + 12);
+ s->accel = 1;
+ } else if (strncmp(token, "name=", 5) == 0) {
+ safe_free(s->name);
+ s->name = xstrdup(token + 5);
+ } else if (strcmp(token, "transparent") == 0) {
+ s->transparent = 1;
+ } else if (strcmp(token, "vhost") == 0) {
+ s->vhost = 1;
+ s->accel = 1;
+ } else if (strcmp(token, "vport") == 0) {
+ s->vport = -1;
+ s->accel = 1;
+ } else if (strncmp(token, "vport=", 6) == 0) {
+ s->vport = atoi(token + 6);
+ s->accel = 1;
+ } else if (strncmp(token, "protocol=", 9) == 0) {
+ s->protocol = xstrdup(token + 9);
+ s->accel = 1;
+ } else if (strcmp(token, "accel") == 0) {
+ s->accel = 1;
+ } else {
+ self_destruct();
+ }
+}
+
+static void
+free_generic_http_port_data(http_port_list * s)
+{
+ safe_free(s->name);
+ safe_free(s->defaultsite);
+}
+
+static void
+cbdataFree_http_port(void *data)
+{
+ free_generic_http_port_data((http_port_list *)data);
+}
+
+
+static http_port_list *
+create_http_port(char *portspec)
+{
+ CBDATA_TYPE(http_port_list);
+ CBDATA_INIT_TYPE_FREECB(http_port_list, cbdataFree_http_port);
+
+ http_port_list *s = cbdataAlloc(http_port_list);
+ s->protocol = xstrdup("http");
+ parse_http_port_specification(s, portspec);
+ return s;
+}
+
+void
+add_http_port(char *portspec)
+{
+ http_port_list *s = create_http_port(portspec);
+ s->next = Config.Sockaddr.http;
+ Config.Sockaddr.http = s;
+}
+
+static void
+parse_http_port_list(http_port_list ** head)
+{
+ char *token = strtok(NULL, w_space);
+ if (!token)
self_destruct();
+ http_port_list *s = create_http_port(token);
+ /* parse options ... */
+ while ((token = strtok(NULL, w_space))) {
+ parse_http_port_option(s, token);
+ }
+ while (*head)
+ head = &(*head)->next;
+ *head = s;
+}
+
+static void
+dump_generic_http_port(StoreEntry * e, const char *n, const http_port_list * s)
+{
+ storeAppendPrintf(e, "%s %s:%d",
+ n,
+ inet_ntoa(s->s.sin_addr),
+ ntohs(s->s.sin_port));
+ if (s->defaultsite)
+ storeAppendPrintf(e, " defaultsite=%s", s->defaultsite);
+ if (s->transparent)
+ storeAppendPrintf(e, " transparent");
+ if (s->vhost)
+ storeAppendPrintf(e, " vhost");
+ if (s->vport)
+ storeAppendPrintf(e, " vport");
+}
+static void
+dump_http_port_list(StoreEntry * e, const char *n, const http_port_list * s)
+{
+ while (s) {
+ dump_generic_http_port(e, n, s);
+ storeAppendPrintf(e, "\n");
+ s = s->next;
+ }
+}
+
+static void
+free_http_port_list(http_port_list ** head)
+{
+ http_port_list *s;
+ while ((s = *head) != NULL) {
+ *head = s->next;
+ cbdataFree(s);
+ }
+}
+
+#if UNUSED_CODE
+static int
+check_null_http_port_list(const http_port_list * s)
+{
+ return NULL == s;
+}
+#endif
+
+#if USE_SSL
+static void
+cbdataFree_https_port(void *data)
+{
+ https_port_list *s = (https_port_list *)data;
+ free_generic_http_port_data(&s->http);
+ safe_free(s->cert);
+ safe_free(s->key);
+}
+
+static void
+parse_https_port_list(https_port_list ** head)
+{
+ CBDATA_TYPE(https_port_list);
+ char *token;
+ https_port_list *s;
+ CBDATA_INIT_TYPE_FREECB(https_port_list, cbdataFree_https_port);
+ token = strtok(NULL, w_space);
+ if (!token)
+ self_destruct();
+ s = cbdataAlloc(https_port_list);
+ s->http.protocol = xstrdup("https");
+ parse_http_port_specification(&s->http, token);
/* parse options ... */
while ((token = strtok(NULL, w_space))) {
if (strncmp(token, "cert=", 5) == 0) {
safe_free(s->sslflags);
s->sslflags = xstrdup(token + 9);
} else {
- self_destruct();
+ parse_http_port_option(&s->http, token);
}
}
- while (*head)
- head = &(*head)->next;
s->sslContext = sslCreateServerContext(s->cert, s->key, s->version, s->cipher, s->options, s->sslflags, s->clientca, s->cafile, s->capath);
if (!s->sslContext)
self_destruct();
+ while (*head)
+ head = (https_port_list **)&(*head)->http.next;
*head = s;
}
dump_https_port_list(StoreEntry * e, const char *n, const https_port_list * s)
{
while (s) {
- storeAppendPrintf(e, "%s %s:%d",
- n,
- inet_ntoa(s->s.sin_addr),
- ntohs(s->s.sin_port));
+ dump_generic_http_port(e, n, &s->http);
if (s->cert)
storeAppendPrintf(e, " cert=%s", s->cert);
if (s->key)
if (s->sslflags)
storeAppendPrintf(e, " sslflags=%s", s->sslflags);
storeAppendPrintf(e, "\n");
- s = s->next;
+ s = (https_port_list *) s->http.next;
}
}
{
https_port_list *s;
while ((s = *head) != NULL) {
- *head = s->next;
- safe_free(s->cert);
- safe_free(s->key);
- safe_free(s);
+ *head = (https_port_list *) s->http.next;
+ cbdataFree(s);
}
}
void
configFreeMemory(void)
{
- safe_free(Config2.Accel.prefix);
free_all();
}
/*
- * $Id: client_side.cc,v 1.622 2003/02/20 00:13:04 hno Exp $
+ * $Id: client_side.cc,v 1.623 2003/02/21 19:53:01 hno Exp $
*
* DEBUG: section 33 Client-side Routines
* AUTHOR: Duane Wessels
static void ClientSocketContextPushDeferredIfNeeded(ClientSocketContext * deferredRequest, ConnStateData * conn);
static void clientUpdateSocketStats(log_type logType, size_t size);
-static ClientSocketContext *clientCheckRequestLineIsParseable(char *inbuf, size_t req_sz, ConnStateData * conn);
static ClientSocketContext *clientParseRequestMethod(char *inbuf, method_t * method_p, ConnStateData * conn);
static char *skipLeadingSpace(char *aString);
static char *findTrailingHTTPVersion(char *uriAndHTTPVersion);
+#if UNUSED_CODE
static void trimTrailingSpaces(char *aString, size_t len);
-static ClientSocketContext *parseURIandHTTPVersion(char **url_p, http_version_t * http_ver_p, ConnStateData * conn);
+#endif
+static ClientSocketContext *parseURIandHTTPVersion(char **url_p, http_version_t * http_ver_p, ConnStateData * conn, char *http_version_str);
static void setLogUri(clientHttpRequest * http, char const *uri);
-static void prepareInternalUrl(clientHttpRequest * http, char *url);
-static void prepareForwardProxyUrl(clientHttpRequest * http, char *url);
-static void prepareAcceleratedUrl(clientHttpRequest * http, char *url, char *req_hdr);
static int connGetAvailableBufferLength(ConnStateData const *conn);
static void connMakeSpaceAvailable(ConnStateData * conn);
static void connAddContextToQueue(ConnStateData * conn, ClientSocketContext * context);
static void connNoteUseOfBuffer(ConnStateData * conn, size_t byteCount);
static int connKeepReadingIncompleteRequest(ConnStateData * conn);
static void connCancelIncompleteRequests(ConnStateData * conn);
-static ConnStateData *connStateCreate(struct sockaddr_in *peer, struct sockaddr_in *me, int fd);
+static ConnStateData *connStateCreate(struct sockaddr_in *peer, struct sockaddr_in *me, int fd, http_port_list *port);
static int connAreAllContextsForThisConnection(ConnStateData * connState);
static void connFreeAllContexts(ConnStateData * connState);
return context;
}
-ClientSocketContext *
-clientCheckRequestLineIsParseable(char *inbuf, size_t req_sz, ConnStateData * conn)
-{
- if (strlen(inbuf) != req_sz) {
- debug(33, 1) ("clientCheckRequestLineIsParseable: Requestheader contains NULL characters\n");
- return parseHttpRequestAbort(conn, "error:invalid-request");
- }
- return NULL;
-}
-
ClientSocketContext *
clientParseRequestMethod(char *inbuf, method_t * method_p, ConnStateData * conn)
{
char *mstr = NULL;
if ((mstr = strtok(inbuf, "\t ")) == NULL) {
debug(33, 1) ("clientParseRequestMethod: Can't get request method\n");
- return parseHttpRequestAbort(conn, "error:invalid-request-method");
+ return parseHttpRequestAbort(conn, "error:invalid-request");
}
*method_p = urlParseMethod(mstr);
if (*method_p == METHOD_NONE) {
return result;
}
-char *
+static char *
findTrailingHTTPVersion(char *uriAndHTTPVersion)
{
- char *token = uriAndHTTPVersion + strlen(uriAndHTTPVersion);
- assert(*token == '\0');
- while (token > uriAndHTTPVersion) {
- --token;
- if (xisspace(*token) && !strncmp(token + 1, "HTTP/", 5))
- return token + 1;
+ char *token;
+
+ for (token = strchr(uriAndHTTPVersion, '\n'); token > uriAndHTTPVersion; token--) {
+ if (*token == '\n' || *token == '\r')
+ continue;
+ if (xisspace(*token)) {
+ if (strncasecmp(token + 1, "HTTP/", 5) == 0)
+ return token + 1;
+ else
+ break;
+ }
}
- return uriAndHTTPVersion;
+ return NULL;
}
+#if UNUSED_CODE
void
trimTrailingSpaces(char *aString, size_t len)
{
while (endPointer > aString && xisspace(*endPointer))
*(endPointer--) = '\0';
}
+#endif
-ClientSocketContext *
+static ClientSocketContext *
parseURIandHTTPVersion(char **url_p, http_version_t * http_ver_p,
- ConnStateData * conn)
+ ConnStateData * conn, char *http_version_str)
{
char *url;
- char *token;
- /* look for URL+HTTP/x.x */
+ char *t;
+ /* look for URL (strtok initiated by clientParseRequestMethod) */
if ((url = strtok(NULL, "\n")) == NULL) {
debug(33, 1) ("parseHttpRequest: Missing URL\n");
return parseHttpRequestAbort(conn, "error:missing-url");
}
url = skipLeadingSpace(url);
- token = findTrailingHTTPVersion(url);
- trimTrailingSpaces(url, token - url - 1);
+ if (!*url || (http_version_str && http_version_str <= url+1)) {
+ debug(33, 1) ("parseHttpRequest: Missing URL\n");
+ return parseHttpRequestAbort(conn, "error:missing-url");
+ }
+ /* Terminate URL just before HTTP version (or at end of line) */
+ if (http_version_str)
+ http_version_str[-1] = '\0';
+ else {
+ t = url + strlen(url) - 1;
+ while (t > url && *t == '\r')
+ *t-- = '\0';
+ }
debug(33, 5) ("parseHttpRequest: URI is '%s'\n", url);
*url_p = url;
- if (token == NULL) {
- debug(33, 3) ("parseHttpRequest: Missing HTTP identifier\n");
-#if RELAXED_HTTP_PARSER
- httpBuildVersion(http_ver_p, 0, 9); /* wild guess */
-#else
- return parseHttpRequestAbort(conn, "error:missing-http-ident");
-#endif
- } else {
- if (sscanf(token + 5, "%d.%d", &http_ver_p->major,
+ if (http_version_str) {
+ if (sscanf(http_version_str + 5, "%d.%d", &http_ver_p->major,
&http_ver_p->minor) != 2) {
debug(33, 3) ("parseHttpRequest: Invalid HTTP identifier.\n");
return parseHttpRequestAbort(conn, "error:invalid-http-ident");
}
debug(33, 6) ("parseHttpRequest: Client HTTP version %d.%d.\n",
http_ver_p->major, http_ver_p->minor);
+ } else {
+ httpBuildVersion(http_ver_p, 0, 9); /* wild guess */
}
return NULL;
}
/* Utility function to perform part of request parsing */
static ClientSocketContext *
-clientParseHttpRequestLine(char *inbuf, size_t req_sz, ConnStateData * conn,
- method_t * method_p, char **url_p, http_version_t * http_ver_p)
+clientParseHttpRequestLine(char *reqline, ConnStateData * conn,
+ method_t * method_p, char **url_p, http_version_t * http_ver_p, char * http_version_str)
{
ClientSocketContext *result = NULL;
- if ((result = clientCheckRequestLineIsParseable(inbuf, req_sz, conn))
- || (result = clientParseRequestMethod(inbuf, method_p, conn))
- || (result = parseURIandHTTPVersion(url_p, http_ver_p, conn)))
+ /* XXX: This sequence relies on strtok() */
+ if ((result = clientParseRequestMethod(reqline, method_p, conn))
+ || (result = parseURIandHTTPVersion(url_p, http_ver_p, conn, http_version_str)))
return result;
return NULL;
http->log_uri = xstrndup(rfc1738_escape_unescaped(uri), MAX_URL);
}
-void
-prepareInternalUrl(clientHttpRequest * http, char *url)
-{
- http->uri = xstrdup(internalLocalUri(NULL, url));
- http->flags.internal = 1;
- http->flags.accel = 1;
-}
+static void
+prepareAcceleratedURL(ConnStateData * conn, clientHttpRequest *http, char *url, const char *req_hdr) {
+ int vhost = conn->port->vhost;
+ int vport = conn->port->vport;
+ char *host;
-void
-prepareForwardProxyUrl(clientHttpRequest * http, char *url)
-{
- size_t url_sz;
- /* URL may be rewritten later, so make extra room */
- url_sz = strlen(url) + Config.appendDomainLen + 5;
- http->uri = (char *)xcalloc(url_sz, 1);
- strcpy(http->uri, url);
- http->flags.accel = 0;
-}
+ http->flags.accel = 1;
-void
-prepareAcceleratedUrl(clientHttpRequest * http, char *url, char *req_hdr)
-{
- size_t url_sz;
- char *t;
- /* prepend the accel prefix */
- if (opt_accel_uses_host && (t = mime_get_header(req_hdr, "Host"))) {
- int vport;
- char *q;
- const char *protocol_name = "http";
- if (vport_mode)
- vport = (int) ntohs(http->conn->me.sin_port);
- else
- vport = (int) Config.Accel.port;
- /* If a Host: header was specified, use it to build the URL
- * instead of the one in the Config file. */
- /*
- * XXX Use of the Host: header here opens a potential
- * security hole. There are no checks that the Host: value
- * corresponds to one of your servers. It might, for example,
- * refer to www.playboy.com. The 'dst' and/or 'dst_domain' ACL
- * types should be used to prevent httpd-accelerators
- * handling requests for non-local servers */
- strtok(t, " /;@");
- if ((q = strchr(t, ':'))) {
- *q++ = '\0';
- if (vport_mode)
- vport = atoi(q);
- }
- url_sz = strlen(url) + 32 + Config.appendDomainLen + strlen(t);
- http->uri = (char *)xcalloc(url_sz, 1);
+ /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
-#if SSL_FORWARDING_NOT_YET_DONE
- if (Config.Sockaddr.https->s.sin_port == http->conn->me.sin_port) {
- protocol_name = "https";
- vport = ntohs(http->conn->me.sin_port);
- }
+ if (*url != '/') {
+ if (conn->port->vhost)
+ return; /* already in good shape */
+ /* else we need to ignore the host name */
+ url = strstr(url, "//");
+#if SHOULD_REJECT_UNKNOWN_URLS
+ if (!url)
+ return parseHttpRequestAbort(conn, "error:invalid-request");
#endif
+ if (url)
+ url = strchr(url + 2, '/');
+ if (!url)
+ url = (char *) "/";
+ }
+
+ if (internalCheck(url)) {
+ /* prepend our name & port */
+ http->uri = xstrdup(internalLocalUri(NULL, url));
+ http->flags.internal = 1;
+ } else if (vhost && (host = mime_get_header(req_hdr, "Host")) != NULL) {
+ int url_sz = strlen(url) + 32 + Config.appendDomainLen +
+ strlen(host);
+ http->uri = (char *)xcalloc(url_sz, 1);
+ snprintf(http->uri, url_sz, "%s://%s%s",
+ conn->port->protocol, host, url);
+ debug(33, 5) ("ACCEL VHOST REWRITE: '%s'\n", http->uri);
+ } else if (conn->port->defaultsite) {
+ int url_sz = strlen(url) + 32 + Config.appendDomainLen +
+ strlen(conn->port->defaultsite);
+ http->uri = (char *)xcalloc(url_sz, 1);
+ snprintf(http->uri, url_sz, "%s://%s%s",
+ conn->port->protocol, conn->port->defaultsite, url);
+ debug(33, 5) ("ACCEL DEFAULTSITE REWRITE: '%s'\n", http->uri);
+ } else if (vport == -1) {
+ /* Put the local socket IP address as the hostname. */
+ int url_sz = strlen(url) + 32 + Config.appendDomainLen;
+ http->uri = (char *)xcalloc(url_sz, 1);
+ snprintf(http->uri, url_sz, "%s://%s:%d%s",
+ http->conn->port->protocol,
+ inet_ntoa(http->conn->me.sin_addr),
+ ntohs(http->conn->me.sin_port), url);
+ debug(33, 5) ("ACCEL VPORT REWRITE: '%s'\n", http->uri);
+ } else if (vport > 0) {
+ /* Put the local socket IP address as the hostname, but static port */
+ int url_sz = strlen(url) + 32 + Config.appendDomainLen;
+ http->uri = (char *)xcalloc(url_sz, 1);
snprintf(http->uri, url_sz, "%s://%s:%d%s",
- protocol_name, t, vport, url);
- } else if (vhost_mode) {
- int vport;
- /* Put the local socket IP address as the hostname */
- url_sz = strlen(url) + 32 + Config.appendDomainLen;
+ http->conn->port->protocol,
+ inet_ntoa(http->conn->me.sin_addr),
+ vport, url);
+ debug(33, 5) ("ACCEL VPORT REWRITE: '%s'\n", http->uri);
+ }
+}
+
+static void
+prepareTransparentURL(ConnStateData * conn, clientHttpRequest *http, char *url, const char *req_hdr) {
+ char *host;
+
+ http->flags.accel = 1;
+
+ if (*url != '/')
+ return; /* already in good shape */
+
+ /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
+
+ if (internalCheck(url)) {
+ /* prepend our name & port */
+ http->uri = xstrdup(internalLocalUri(NULL, url));
+ http->flags.internal = 1;
+ } else if ((host = mime_get_header(req_hdr, "Host")) != NULL) {
+ int url_sz = strlen(url) + 32 + Config.appendDomainLen +
+ strlen(host);
http->uri = (char *)xcalloc(url_sz, 1);
- if (vport_mode)
- vport = (int) ntohs(http->conn->me.sin_port);
- else
- vport = (int) Config.Accel.port;
- rewriteURIwithInterceptedDetails(url, http->uri, url_sz, http->conn->fd,
- http->conn->me, http->conn->peer, vport);
- debug(33, 5) ("VHOST REWRITE: '%s'\n", http->uri);
+ snprintf(http->uri, url_sz, "%s://%s%s",
+ conn->port->protocol, host, url);
+ debug(33, 5) ("TRANSPARENT HOST REWRITE: '%s'\n", http->uri);
} else {
- url_sz = strlen(Config2.Accel.prefix) + strlen(url) +
- Config.appendDomainLen + 1;
+ /* Put the local socket IP address as the hostname. */
+ int url_sz = strlen(url) + 32 + Config.appendDomainLen;
http->uri = (char *)xcalloc(url_sz, 1);
- snprintf(http->uri, url_sz, "%s%s", Config2.Accel.prefix, url);
+ snprintf(http->uri, url_sz, "%s://%s:%d%s",
+ http->conn->port->protocol,
+ inet_ntoa(http->conn->me.sin_addr),
+ ntohs(http->conn->me.sin_port), url);
+ debug(33, 5) ("TRANSPARENT REWRITE: '%s'\n", http->uri);
}
- http->flags.accel = 1;
}
/*
char *inbuf = NULL;
char *url = NULL;
char *req_hdr = NULL;
+ char *t;
http_version_t http_ver;
char *end;
size_t header_sz; /* size of headers, not including first line */
clientHttpRequest *http;
ClientSocketContext *result;
StoreIOBuffer tempBuffer;
+ char *http_version;
/* pre-set these values to make aborting simpler */
*prefix_p = NULL;
*method_p = METHOD_NONE;
- if ((req_sz = headersEnd(conn->in.buf, conn->in.notYetUsed)) == 0) {
- debug(33, 5) ("Incomplete request, waiting for end of headers\n");
+ /* Read the HTTP message. HTTP/0.9 is detected by the absence of a HTTP signature */
+ if ((t = (char *)memchr(conn->in.buf, '\n', conn->in.notYetUsed)) == NULL) {
+ debug(33, 5) ("Incomplete request, waiting for end of request line\n");
return NULL;
}
+ *req_line_sz_p = t - conn->in.buf + 1;
+ http_version = findTrailingHTTPVersion(conn->in.buf);
+ if (http_version) {
+ if ((req_sz = headersEnd(conn->in.buf, conn->in.notYetUsed)) == 0) {
+ debug(33, 5) ("Incomplete request, waiting for end of headers\n");
+ return NULL;
+ }
+ } else {
+ debug(33, 3) ("parseHttpRequest: Missing HTTP identifier\n");
+ req_sz = t - conn->in.buf + 1; /* HTTP/0.9 requests */
+ }
+
assert(req_sz <= conn->in.notYetUsed);
/* Use memcpy, not strdup! */
inbuf = (char *)xmalloc(req_sz + 1);
xmemcpy(inbuf, conn->in.buf, req_sz);
*(inbuf + req_sz) = '\0';
+ /* and adjust http_version to point into the new copy */
+ if (http_version)
+ http_version = inbuf + (http_version - conn->in.buf);
+
+ /* Barf on NULL characters in the headers */
+ if (strlen(inbuf) != req_sz) {
+ debug(33, 1) ("parseHttpRequest: Requestheader contains NULL characters\n");
+#if TRY_TO_IGNORE_THIS
+ return parseHttpRequestAbort(conn, "error:invalid-request");
+#endif
+ }
/* Is there a legitimate first line to the headers ? */
- if ((result =
- clientParseHttpRequestLine(inbuf, req_sz, conn, method_p, &url,
- &http_ver))) {
+ if ((result = clientParseHttpRequestLine(inbuf, conn, method_p, &url,
+ &http_ver, http_version))) {
/* something wrong, abort */
xfree(inbuf);
return result;
* Process headers after request line
* TODO: Use httpRequestParse here.
*/
- req_hdr = strtok(NULL, null_string);
- header_sz = req_sz - (req_hdr - inbuf);
- if (0 == header_sz) {
- debug(33, 3) ("parseHttpRequest: header_sz == 0\n");
- xfree(inbuf);
- return NULL;
- }
- assert(header_sz > 0);
+ req_hdr = inbuf + *req_line_sz_p;
+ header_sz = req_sz - *req_line_sz_p;
debug(33, 3) ("parseHttpRequest: req_hdr = {%s}\n", req_hdr);
end = req_hdr + header_sz;
debug(33, 3) ("parseHttpRequest: end = {%s}\n", end);
prefix_sz = end - inbuf;
- *req_line_sz_p = req_hdr - inbuf;
debug(33, 3) ("parseHttpRequest: prefix_sz = %d, req_line_sz = %d\n",
(int) prefix_sz, (int) *req_line_sz_p);
assert(prefix_sz <= conn->in.notYetUsed);
*(*prefix_p + prefix_sz) = '\0';
dlinkAdd(http, &http->active, &ClientActiveRequests);
- /* XXX this function is still way to long. here is a natural point for further simplification */
-
debug(33, 5) ("parseHttpRequest: Request Header is\n%s\n",
(*prefix_p) + *req_line_sz_p);
+
#if THIS_VIOLATES_HTTP_SPECS_ON_URL_TRANSFORMATION
if ((t = strchr(url, '#'))) /* remove HTML anchors */
*t = '\0';
#endif
- if (internalCheck(url))
- prepareInternalUrl(http, url);
- else if (Config2.Accel.on && *url == '/')
- prepareAcceleratedUrl(http, url, req_hdr);
- else
- prepareForwardProxyUrl(http, url);
+ /* Rewrite the URL in transparent or accelerator mode */
+ if (conn->transparent) {
+ prepareTransparentURL(conn, http, url, req_hdr);
+ } else if (conn->port->accel) {
+ prepareAcceleratedURL(conn, http, url, req_hdr);
+ }
+
+ if (!http->uri) {
+ /* No special rewrites have been applied above, use the
+ * requested url. may be rewritten later, so make extra room */
+ int url_sz = strlen(url) + Config.appendDomainLen + 5;
+ http->uri = (char *)xcalloc(url_sz, 1);
+ strcpy(http->uri, url);
+ }
+
setLogUri(http, http->uri);
debug(33, 5) ("parseHttpRequest: Complete request received\n");
xfree(inbuf);
result->flags.parsed_ok = 1;
return result;
+
}
static int
/* compile headers */
/* we should skip request line! */
if (!httpRequestParseHeader(request, prefix + req_line_sz))
- debug(33, 1) ("Failed to parse request headers: %s\n%s\n",
+ if (http->http_ver.major >= 1)
+ debug(33, 1) ("Failed to parse request headers: %s\n%s\n",
http->uri, prefix);
/* continue anyway? */
conn->body.buf = NULL;
conn->body.bufsize = 0;
/* Remember that we have touched the body, not restartable */
- if (request != NULL)
+ if (request != NULL) {
request->flags.body_sent = 1;
+ conn->body.request = NULL;
+ }
/* Invoke callback function */
callback(buf, size, cbdata);
- if (request != NULL)
+ if (request != NULL) {
requestUnlink(request); /* Linked in clientReadBody */
+ }
debug(33, 2) ("clientProcessBody: end fd=%d size=%lu body_size=%lu in.notYetUsed=%lu cb=%p req=%p\n",
conn->fd, (unsigned long int)size, (unsigned long int) conn->body.size_left,
(unsigned long) conn->in.notYetUsed, callback, request);
}
ConnStateData *
-connStateCreate(struct sockaddr_in *peer, struct sockaddr_in *me, int fd)
+connStateCreate(struct sockaddr_in *peer, struct sockaddr_in *me, int fd, http_port_list *port)
{
ConnStateData *result = cbdataAlloc(ConnStateData);
result->peer = *peer;
result->me = *me;
result->fd = fd;
result->in.buf = (char *)memAllocBuf(CLIENT_REQ_BUF_SZ, &result->in.allocatedSize);
+ result->port = cbdataReference(port);
+ if (port->transparent) {
+ struct sockaddr_in dst;
+ if (clientNatLookup(fd, *me, *peer, &dst) == 0) {
+ result->me = dst; /* XXX This should be moved to another field */
+ result->transparent = 1;
+ }
+ }
result->flags.readMoreRequests = 1;
return result;
}
httpAccept(int sock, int newfd, ConnectionDetail *details,
comm_err_t flag, int xerrno, void *data)
{
- int *N = &incoming_sockets_accepted;
+ http_port_list *s = (http_port_list *)data;
ConnStateData *connState = NULL;
if (flag == COMM_ERR_CLOSING) {
}
/* kick off another one for later */
- comm_accept(sock, httpAccept, NULL);
+ comm_accept(sock, httpAccept, data);
/* XXX we're not considering httpAcceptDefer yet! */
}
debug(33, 4) ("httpAccept: FD %d: accepted\n", newfd);
- connState = connStateCreate(&details->peer, &details->me, newfd);
+ fd_note(newfd, "client http connect");
+ connState = connStateCreate(&details->peer, &details->me, newfd, s);
+ connState->port = cbdataReference(s);
comm_add_close_handler(newfd, connStateFree, connState);
if (Config.onoff.log_fqdn)
fqdncache_gethostbyaddr(details->peer.sin_addr, FQDN_LOOKUP_IF_MISS);
clientReadSomeData(connState);
commSetDefer(newfd, clientReadDefer, connState);
clientdbEstablished(details->peer.sin_addr, 1);
- assert(N);
- (*N)++;
+ incoming_sockets_accepted++;
}
#if USE_SSL
clientReadSomeData(conn);
}
-struct _https_port_data {
- SSL_CTX *sslContext;
-};
-typedef struct _https_port_data https_port_data;
-CBDATA_TYPE(https_port_data);
-
/* handle a new HTTPS connection */
static void
httpsAccept(int sock, int newfd, ConnectionDetail *details,
comm_err_t flag, int xerrno, void *data)
{
- int *N = &incoming_sockets_accepted;
- https_port_data *https_port = (https_port_data *)data;
- SSL_CTX *sslContext = https_port->sslContext;
+ https_port_list *s = (https_port_list *)data;
+ SSL_CTX *sslContext = s->sslContext;
ConnStateData *connState = NULL;
SSL *ssl;
int ssl_error;
fd_table[newfd].read_method = &ssl_read_method;
fd_table[newfd].write_method = &ssl_write_method;
debug(50, 5) ("httpsAccept: FD %d accepted, starting SSL negotiation.\n", newfd);
+ fd_note(newfd, "client https connect");
- connState = connStateCreate(&details->peer, &details->me, newfd);
- /* XXX account connState->in.buf */
+ connState = connStateCreate(&details->peer, &details->me, newfd, (http_port_list *)s);
+ connState->port = (http_port_list *)cbdataReference(s);
comm_add_close_handler(newfd, connStateFree, connState);
if (Config.onoff.log_fqdn)
fqdncache_gethostbyaddr(details->peer.sin_addr, FQDN_LOOKUP_IF_MISS);
commSetSelect(newfd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
commSetDefer(newfd, clientReadDefer, connState);
clientdbEstablished(details->peer.sin_addr, 1);
- (*N)++;
+ incoming_sockets_accepted++;
}
#endif /* USE_SSL */
static void
clientHttpConnectionsOpen(void)
{
- sockaddr_in_list *s;
+ http_port_list *s;
int fd;
for (s = Config.Sockaddr.http; s; s = s->next) {
if (MAXHTTPPORTS == NHttpSockets) {
if (fd < 0)
continue;
comm_listen(fd);
- comm_accept(fd, httpAccept, NULL);
+ comm_accept(fd, httpAccept, s);
/*
* We need to set a defer handler here so that we don't
* peg the CPU with select() when we hit the FD limit.
clientHttpsConnectionsOpen(void)
{
https_port_list *s;
- https_port_data *https_port;
int fd;
- for (s = Config.Sockaddr.https; s; s = s->next) {
+ for (s = Config.Sockaddr.https; s; s = (https_port_list *)s->http.next) {
if (MAXHTTPPORTS == NHttpSockets) {
debug(1, 1) ("WARNING: You have too many 'https_port' lines.\n");
debug(1, 1) (" The limit is %d\n", MAXHTTPPORTS);
enter_suid();
fd = comm_open(SOCK_STREAM,
0,
- s->s.sin_addr,
- ntohs(s->s.sin_port), COMM_NONBLOCKING, "HTTPS Socket");
+ s->http.s.sin_addr,
+ ntohs(s->http.s.sin_port), COMM_NONBLOCKING, "HTTPS Socket");
leave_suid();
if (fd < 0)
continue;
- CBDATA_INIT_TYPE(https_port_data);
- https_port = cbdataAlloc(https_port_data);
- https_port->sslContext = s->sslContext;
comm_listen(fd);
- comm_accept(fd, httpsAccept, https_port);
+ comm_accept(fd, httpsAccept, s);
commSetDefer(fd, httpAcceptDefer, NULL);
debug(1, 1) ("Accepting HTTPS connections at %s, port %d, FD %d.\n",
- inet_ntoa(s->s.sin_addr), (int) ntohs(s->s.sin_port), fd);
+ inet_ntoa(s->http.s.sin_addr), (int) ntohs(s->http.s.sin_port), fd);
HttpSockets[NHttpSockets++] = fd;
}
}