dnl Configuration input file for Squid
dnl
-dnl $Id: configure.in,v 1.449 2007/04/12 23:51:55 wessels Exp $
+dnl $Id: configure.in,v 1.450 2007/04/15 14:46:11 serassio Exp $
dnl
dnl
dnl
AC_CONFIG_AUX_DIR(cfgaux)
AC_CONFIG_SRCDIR([src/main.cc])
AM_INIT_AUTOMAKE([tar-ustar])
-AC_REVISION($Revision: 1.449 $)dnl
+AC_REVISION($Revision: 1.450 $)dnl
AC_PREFIX_DEFAULT(/usr/local/squid)
AM_MAINTAINER_MODE
esac
fi
+dnl Enable Linux transparent proxy support
+AC_ARG_ENABLE(linux-tproxy,
+[ --enable-linux-tproxy
+ Enable real Transparent Proxy support for Netfilter TPROXY.],
+[ if test "$enableval" = "yes" ; then
+ echo "Linux Netfilter/TPROXY enabled"
+ AC_DEFINE(LINUX_TPROXY, 1, [Enable real Transparent Proxy support for Netfilter TPROXY.])
+ LINUX_TPROXY="yes"
+ if test -z "$LINUX_NETFILTER"; then
+ echo "Linux-Netfilter Transparent Proxy automatically enabled"
+ LINUX_NETFILTER="yes"
+ fi
+ fi
+])
+
AM_CONDITIONAL(MAKE_LEAKFINDER, false)
dnl Enable Leak Finding Functions
AC_ARG_ENABLE(leakfinder,
db_185.h
)
-AC_CHECK_HEADERS(linux/netfilter_ipv4.h,,,
+AC_CHECK_HEADERS(
+ linux/netfilter_ipv4.h \
+ linux/netfilter_ipv4/ip_tproxy.h \
+,,,
SQUID_DEFAULT_INCLUDES
#if HAVE_LIMITS_H
#include <limits.h>
sleep 10
fi
+dnl Linux Netfilter/TPROXY support requires some specific header files
+dnl Shamelessly copied from shamelessly copied from above
+if test "$LINUX_TPROXY" ; then
+ AC_MSG_CHECKING(if TPROXY header files are installed)
+ # hold on to your hats...
+ if test "$ac_cv_header_linux_netfilter_ipv4_ip_tproxy_h" = "yes" && test "$LINUX_NETFILTER" = "yes"; then
+ LINUX_TPROXY="yes"
+ AC_DEFINE(LINUX_TPROXY, 1, [Enable real Transparent Proxy support for Netfilter TPROXY.])
+ else
+ LINUX_TPROXY="no"
+ AC_DEFINE(LINUX_TPROXY, 0, [Enable real Transparent Proxy support for Netfilter TPROXY.])
+ fi
+ AC_MSG_RESULT($LINUX_TPROXY)
+fi
+if test "$LINUX_TPROXY" = "no" && test "$LINUX_NETFILTER" = "yes"; then
+ echo "WARNING: Cannot find TPROXY headers, you need to install the"
+ echo "tproxy package from:"
+ echo " - lynx http://www.balabit.com/downloads/tproxy/"
+ sleep 10
+fi
+
if test -z "$USE_GNUREGEX" ; then
case "$host" in
*-sun-solaris2.[[0-4]])
/* Define to 1 if you have the <linux/netfilter_ipv4.h> header file. */
#undef HAVE_LINUX_NETFILTER_IPV4_H
+/* Define to 1 if you have the <linux/netfilter_ipv4/ip_tproxy.h> header file. */
+#undef HAVE_LINUX_NETFILTER_IPV4_IP_TPROXY_H
+
/* long is defined in system headers */
#undef HAVE_LONG
/* Enable support for Transparent Proxy on Linux (Netfilter) systems */
#undef LINUX_NETFILTER
+/* Enable real Transparent Proxy support for Netfilter TPROXY. */
+#undef LINUX_TPROXY
+
/* If we need to declare sys_errlist[] as external */
#undef NEED_SYS_ERRLIST
{
const ICAPServiceRep &s = service();
// TODO: check whether NULL domain is appropriate here
- connection = icapPconnPool->pop(s.host.buf(), s.port, NULL);
+ connection = icapPconnPool->pop(s.host.buf(), s.port, NULL, NULL);
if (connection >= 0) {
debugs(93,3, HERE << "reused pconn FD " << connection);
if (reuseConnection) {
debugs(93,3, HERE << "pushing pconn" << status());
commSetTimeout(connection, -1, NULL, NULL);
- icapPconnPool->push(connection, theService->host.buf(), theService->port, NULL);
+ icapPconnPool->push(connection, theService->host.buf(), theService->port, NULL, NULL);
} else {
debugs(93,3, HERE << "closing pconn" << status());
// comm_close will clear timeout
/*
- * $Id: cache_cf.cc,v 1.507 2007/04/11 22:57:34 wessels Exp $
+ * $Id: cache_cf.cc,v 1.508 2007/04/15 14:46:12 serassio Exp $
*
* DEBUG: section 3 Configuration File Parsing
* AUTHOR: Harvest Derived
s->disable_pmtu_discovery = DISABLE_PMTU_ALWAYS;
else
self_destruct();
+
+#if LINUX_TPROXY
+
+ } else if (strcmp(token, "tproxy") == 0) {
+ s->tproxy = 1;
+ need_linux_tproxy = 1;
+#endif
+
} else {
self_destruct();
}
#
-# $Id: cf.data.pre,v 1.431 2007/04/07 09:35:38 serassio Exp $
+# $Id: cf.data.pre,v 1.432 2007/04/15 14:46:13 serassio Exp $
#
#
# SQUID Web Proxy Cache http://www.squid-cache.org/
protocol= Protocol to reconstruct accelerated requests with.
Defaults to http
+ tproxy Support Linux TPROXY for spoofing
+ outgoing connections using the client
+ IP address.
+
disable-pmtu-discovery=
Control Path-MTU discovery usage:
off lets OS decide on what to do (default).
/*
- * $Id: client_side.cc,v 1.745 2007/04/06 04:50:05 rousskov Exp $
+ * $Id: client_side.cc,v 1.746 2007/04/15 14:46:15 serassio Exp $
*
* DEBUG: section 33 Client-side Routines
* AUTHOR: Duane Wessels
http->al.reply = HTTPMSGLOCK(rep);
context->sendStartOfMessage(rep, recievedData);
}
+
PROF_stop(clientSocketRecipient);
}
ClientSocketContext::initiateClose(const char *reason)
{
debugs(33, 5, HERE << "initiateClose: closing for " << reason);
+
if (http != NULL) {
ConnStateData::Pointer conn = http->getConn();
debugs(33, 2, HERE << "avoiding double-closing " << conn);
return;
}
-
+
/*
* XXX We assume the reply fits in the TCP transmit
* window. If not the connection may stall while sending
* this may be an issue.
*/
conn->startClosing(reason);
+
return;
}
}
assert (this->fd() == fd);
/* Bail out quickly on COMM_ERR_CLOSING - close handlers will tidy up */
+
if (errflag == COMM_ERR_CLOSING)
return;
/* Attempt to parse the first line; this'll define the method, url, version and header begin */
r = HttpParserParseReqLine(hp);
+
if (r == 0) {
debug(33, 5) ("Incomplete request, waiting for end of request line\n");
- return NULL;
+ return NULL;
}
+
if (r == -1) {
return parseHttpRequestAbort(conn, "error:invalid-request");
}
+
/* Request line is valid here .. */
*http_ver = HttpVersion(hp->v_maj, hp->v_min);
/* We know the whole request is in hp->buf now */
assert(req_sz <= (size_t) hp->bufsiz);
+
/* Will the following be true with HTTP/0.9 requests? probably not .. */
/* So the rest of the code will need to deal with '0'-byte headers (ie, none, so don't try parsing em) */
assert(req_sz > 0);
+
hp->hdr_end = req_sz - 1;
+
hp->hdr_start = hp->req_end + 1;
/* Enforce max_request_size */
/* Set method_p */
*method_p = HttpRequestMethod(&hp->buf[hp->m_start], &hp->buf[hp->m_end]);
+
if (*method_p == METHOD_NONE) {
- /* XXX need a way to say "this many character length string" */
+ /* XXX need a way to say "this many character length string" */
debug(33, 1) ("clientParseRequestMethod: Unsupported method in request '%s'\n", hp->buf);
- /* XXX where's the method set for this error? */
+ /* XXX where's the method set for this error? */
return parseHttpRequestAbort(conn, "error:unsupported-request-method");
}
* below needs to be modified to not expect a mutable nul-terminated string.
*/
url = (char *)xmalloc(hp->u_end - hp->u_start + 16);
+
memcpy(url, hp->buf + hp->u_start, hp->u_end - hp->u_start + 1);
+
url[hp->u_end - hp->u_start + 1] = '\0';
/*
*/
/* XXX this code should be modified to take a const char * later! */
req_hdr = (char *) hp->buf + hp->req_end + 1;
+
debug(33, 3) ("parseHttpRequest: req_hdr = {%s}\n", req_hdr);
+
end = (char *) hp->buf + hp->hdr_end;
+
debug(33, 3) ("parseHttpRequest: end = {%s}\n", end);
if (strstr(req_hdr, "\r\r\n")) {
debug(33, 1) ("WARNING: suspicious HTTP request contains double CR\n");
- xfree(url);
+ xfree(url);
return parseHttpRequestAbort(conn, "error:double-CR");
}
assert(context->http->out.offset == 0);
context->pullData();
conn->flags.readMoreRequests = false;
- goto finish;
+ goto finish;
}
if ((request = HttpRequest::CreateFromUrlAndMethod(http->uri, method)) == NULL) {
assert(context->http->out.offset == 0);
context->pullData();
conn->flags.readMoreRequests = false;
- goto finish;
+ goto finish;
}
/* compile headers */
assert(context->http->out.offset == 0);
context->pullData();
conn->flags.readMoreRequests = false;
- goto finish;
+ goto finish;
}
request->flags.accelerated = http->flags.accel;
request->flags.transparent = http->flags.transparent;
+#if LINUX_TPROXY
+
+ request->flags.tproxy = conn->port->tproxy;
+#endif
+
if (internalCheck(request->urlpath.buf())) {
if (internalHostnameIs(request->host) &&
request->port == getMyPort()) {
assert(context->http->out.offset == 0);
context->pullData();
conn->flags.readMoreRequests = false;
- goto finish;
+ goto finish;
}
assert(context->http->out.offset == 0);
context->pullData();
conn->flags.readMoreRequests = false;
- goto finish;
+ goto finish;
}
http->request = HTTPMSGLOCK(request);
clientSetKeepaliveFlag(http);
/* Do we expect a request-body? */
+
if (request->content_length > 0) {
request->body_pipe = conn->expectRequestBody(request->content_length);
notedUseOfBuffer = true;
conn->handleRequestBodyData();
+
if (!request->body_pipe->exhausted())
conn->readSomeData();
ConnStateData::bodySizeLeft()
{
// XXX: this logic will not work for chunked requests with unknown sizes
+
if (bodyPipe != NULL)
return bodyPipe->unproducedSize();
while (conn->in.notYetUsed > 0 && conn->bodySizeLeft() == 0) {
connStripBufferWhitespace (conn);
- /* Don't try to parse if the buffer is empty */
- if (conn->in.notYetUsed == 0)
- break;
+ /* Don't try to parse if the buffer is empty */
+
+ if (conn->in.notYetUsed == 0)
+ break;
/* Limit the number of concurrent requests to 2 */
/* Terminate the string */
conn->in.buf[conn->in.notYetUsed] = '\0';
- /* Begin the parsing */
- HttpParserInit(&hp, conn->in.buf, conn->in.notYetUsed);
+ /* Begin the parsing */
+ HttpParserInit(&hp, conn->in.buf, conn->in.notYetUsed);
/* Process request */
- PROF_start(parseHttpRequest);
+ PROF_start(parseHttpRequest);
+
context = parseHttpRequest(conn, &hp, &method, &http_ver);
- PROF_stop(parseHttpRequest);
+
+ PROF_stop(parseHttpRequest);
/* partial or incomplete request */
if (!context) {
continue; /* while offset > 0 && conn->bodySizeLeft() == 0 */
}
} /* while offset > 0 && conn->bodySizeLeft() == 0 */
+
/* XXX where to 'finish' the parsing pass? */
return parsed_req;
xmemmove(current_buf, buf, size);
in.notYetUsed += size;
+
in.buf[in.notYetUsed] = '\0'; /* Terminate the string */
// if we are reading a body, stuff data into the body pipe
return closing_;
}
-// Called by ClientSocketContext to give the connection a chance to read
+// Called by ClientSocketContext to give the connection a chance to read
// the entire body before closing the socket.
void
ConnStateData::startClosing(const char *reason)
/*
- * $Id: forward.cc,v 1.155 2007/04/12 14:07:10 rousskov Exp $
+ * $Id: forward.cc,v 1.156 2007/04/15 14:46:16 serassio Exp $
*
* DEBUG: section 17 Request Forwarding
* AUTHOR: Duane Wessels
#include "SquidTime.h"
#include "Store.h"
+#if LINUX_TPROXY
+#include <linux/netfilter_ipv4/ip_tproxy.h>
+#endif
+
static PSC fwdStartCompleteWrapper;
static PF fwdServerClosedWrapper;
#if USE_SSL
}
// Called once, right after object creation, when it is safe to set self
-void FwdState::start(Pointer aSelf) {
+void FwdState::start(Pointer aSelf)
+{
// Protect ourselves from being destroyed when the only Server pointing
// to us is gone (while we expect to talk to more Servers later).
// Once we set self, we are responsible for clearing it when we do not
storeRegisterAbort(entry, FwdState::abort, this);
peerSelect(request, entry, fwdStartCompleteWrapper, this);
- // TODO: set self _after_ the peer is selected because we do not need
+ // TODO: set self _after_ the peer is selected because we do not need
// self until we start talking to some Server.
}
void
FwdState::completed()
{
- if (flags.forward_completed == 1) {
- debugs(17, 1, HERE << "FwdState::completed called on a completed request! Bad!");
- return;
- }
- flags.forward_completed = 1;
+ if (flags.forward_completed == 1) {
+ debugs(17, 1, HERE << "FwdState::completed called on a completed request! Bad!");
+ return;
+ }
+
+ flags.forward_completed = 1;
#if URL_CHECKSUM_DEBUG
FwdState::~FwdState()
{
debugs(17, 3, HERE << "FwdState destructor starting");
+
if (! flags.forward_completed)
- completed();
+ completed();
serversFree(&servers);
debug(17, 3) ("fwdStateFree: closing FD %d\n", fd);
comm_close(fd);
}
+
debugs(17, 3, HERE << "FwdState destructor done");
}
default:
FwdState::Pointer fwd = new FwdState(client_fd, entry, request);
+#if LINUX_TPROXY
+ /* If we need to transparently proxy the request
+ * then we need the client source address and port */
+ fwd->src.sin_family = AF_INET;
+ fwd->src.sin_addr = request->client_addr;
+ fwd->src.sin_port = request->client_port;
+#endif
+
fwd->start(fwd);
return;
}
debug(17, 3) ("fwdComplete: not re-forwarding status %d\n",
entry->getReply()->sline.status);
EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
- entry->complete();
- if (server_fd < 0)
- completed();
+ entry->complete();
+
+ if (server_fd < 0)
+ completed();
+
self = NULL; // refcounted
}
}
const char *domain = NULL;
int ctimeout;
int ftimeout = Config.Timeout.forward - (squid_curtime - start_t);
+#if LINUX_TPROXY
+
+ struct in_tproxy itp;
+#endif
struct IN_ADDR outgoing;
unsigned short tos;
+
+ struct IN_ADDR *client_addr = NULL;
assert(fs);
assert(server_fd == -1);
debug(17, 3) ("fwdConnectStart: %s\n", url);
ctimeout = Config.Timeout.connect;
}
+#if LINUX_TPROXY
+ if (request->flags.tproxy)
+ client_addr = &request->client_addr;
+
+#endif
+
if (ftimeout < 0)
ftimeout = 5;
if (ftimeout < ctimeout)
ctimeout = ftimeout;
- if ((fd = fwdPconnPool->pop(host, port, domain)) >= 0) {
+ if ((fd = fwdPconnPool->pop(host, port, domain, client_addr)) >= 0) {
if (checkRetriable()) {
debug(17, 3) ("fwdConnectStart: reusing pconn FD %d\n", fd);
server_fd = fd;
commSetTimeout(fd, ctimeout, fwdConnectTimeoutWrapper, this);
- if (fs->_peer)
+ if (fs->_peer) {
hierarchyNote(&request->hier, fs->code, fs->_peer->host);
- else
+ } else {
+#if LINUX_TPROXY
+
+ if (request->flags.tproxy) {
+ itp.v.addr.faddr.s_addr = src.sin_addr.s_addr;
+ itp.v.addr.fport = 0;
+
+ /* If these syscalls fail then we just fallback to connecting
+ * normally by simply ignoring the errors...
+ */
+ itp.op = TPROXY_ASSIGN;
+
+ if (setsockopt(fd, SOL_IP, IP_TPROXY, &itp, sizeof(itp)) == -1) {
+ debug(20, 1) ("tproxy ip=%s,0x%x,port=%d ERROR ASSIGN\n",
+ inet_ntoa(itp.v.addr.faddr),
+ itp.v.addr.faddr.s_addr,
+ itp.v.addr.fport);
+ request->flags.tproxy = 0;
+ } else {
+ itp.op = TPROXY_FLAGS;
+ itp.v.flags = ITP_CONNECT;
+
+ if (setsockopt(fd, SOL_IP, IP_TPROXY, &itp, sizeof(itp)) == -1) {
+ debug(20, 1) ("tproxy ip=%x,port=%d ERROR CONNECT\n",
+ itp.v.addr.faddr.s_addr,
+ itp.v.addr.fport);
+ request->flags.tproxy = 0;
+ }
+ }
+ }
+
+#endif
hierarchyNote(&request->hier, fs->code, request->host);
+ }
commConnectStart(fd, host, port, fwdConnectDoneWrapper, this);
}
break;
case PROTO_WAIS: /* Not implemented */
+
default:
debug(17, 1) ("fwdDispatch: Cannot retrieve '%s'\n",
storeUrl(entry));
}
void
-FwdState::pconnPush(int fd, const char *host, int port, const char *domain)
+
+FwdState::pconnPush(int fd, const char *host, int port, const char *domain, struct IN_ADDR *client_addr)
{
- fwdPconnPool->push(fd, host, port, domain);
+ fwdPconnPool->push(fd, host, port, domain, client_addr);
}
void
bool checkRetry();
bool checkRetriable();
void dispatch();
- void pconnPush(int fd, const char *host, int port, const char *domain);
+ void pconnPush(int fd, const char *host, int port, const char *domain, struct IN_ADDR *client_addr);
bool dontRetry() { return flags.dont_retry; }
}
flags;
+#if LINUX_NETFILTER
+ struct sockaddr_in src;
+#endif
};
/*
- * $Id: globals.h,v 1.139 2006/09/13 18:55:10 serassio Exp $
+ * $Id: globals.h,v 1.140 2007/04/15 14:46:16 serassio Exp $
*
*
* SQUID Web Proxy Cache http://www.squid-cache.org/
extern const char *external_acl_message; /* NULL */
extern int opt_send_signal; /* -1 */
extern int opt_no_daemon; /* 0 */
+#if LINUX_TPROXY
+ extern int need_linux_tproxy; /* 0 */
+#endif
+
#ifdef __cplusplus
}
/*
- * $Id: http.cc,v 1.512 2007/04/06 12:15:51 serassio Exp $
+ * $Id: http.cc,v 1.513 2007/04/15 14:46:16 serassio Exp $
*
* DEBUG: section 11 Hypertext Transfer Protocol (HTTP)
* AUTHOR: Harvest Derived
#endif
HttpStateData::HttpStateData(FwdState *theFwdState) : ServerStateData(theFwdState),
- header_bytes_read(0), reply_bytes_read(0)
+ header_bytes_read(0), reply_bytes_read(0)
{
debugs(11,5,HERE << "HttpStateData " << this << " created");
ignoreCacheControl = false;
}
int
-HttpStateData::dataDescriptor() const {
+HttpStateData::dataDescriptor() const
+{
return fd;
}
*/
if (!refreshIsCachable(entry)) {
- debug(22, 3) ("refreshIsCachable() returned non-cacheable..\n");
+ debug(22, 3) ("refreshIsCachable() returned non-cacheable..\n");
return 0;
- }
+ }
/* don't cache objects from peers w/o LMT, Date, or Expires */
/* check that is it enough to check headers @?@ */
#if HEADERS_LOG
headersLog(1, 0, request->method, getReply());
+
#endif
ctx_exit(ctx);
/* If we haven't seen the end of reply headers, we are not done */
debug(11,5)("persistentConnStatus: flags.headers_parsed=%d\n", flags.headers_parsed);
+
if (!flags.headers_parsed)
return INCOMPLETE_MSG;
const int clen = reply->bodySize(request->method);
+
debug(11,5)("persistentConnStatus: clen=%d\n", clen);
/* If the body size is unknown we must wait for EOF */
// if (entry->mem_obj->endOffset() < reply->content_length + reply->hdr_sz)
const int body_bytes_read = reply_bytes_read - header_bytes_read;
debugs(11,5, "persistentConnStatus: body_bytes_read=" <<
- body_bytes_read << " content_length=" << reply->content_length);
+ body_bytes_read << " content_length=" << reply->content_length);
if (body_bytes_read < reply->content_length)
return INCOMPLETE_MSG;
* definately at EOF, so we want to process the reply
* headers.
*/
- PROF_start(HttpStateData_processReplyHeader);
+ PROF_start(HttpStateData_processReplyHeader);
processReplyHeader();
- PROF_stop(HttpStateData_processReplyHeader);
- }
- else if (getReply()->sline.status == HTTP_INVALID_HEADER && HttpVersion(0,9) != getReply()->sline.version) {
+ PROF_stop(HttpStateData_processReplyHeader);
+ } else if (getReply()->sline.status == HTTP_INVALID_HEADER && HttpVersion(0,9) != getReply()->sline.version) {
fwd->fail(errorCon(ERR_INVALID_RESP, HTTP_BAD_GATEWAY, fwd->request));
flags.do_next_read = 0;
} else {
}
} else {
if (!flags.headers_parsed) {
- PROF_start(HttpStateData_processReplyHeader);
+ PROF_start(HttpStateData_processReplyHeader);
processReplyHeader();
- PROF_stop(HttpStateData_processReplyHeader);
+ PROF_stop(HttpStateData_processReplyHeader);
if (flags.headers_parsed) {
bool fail = reply == NULL;
int len = readBuf->contentSize();
#if ICAP_CLIENT
+
if (virginBodyDestination != NULL) {
const size_t putSize = virginBodyDestination->putMoreData(data, len);
readBuf->consume(putSize);
return;
}
+
// Even if we are done with sending the virgin body to ICAP, we may still
// be waiting for adapted headers. We need them before writing to store.
if (adaptedHeadSource != NULL) {
debugs(11,5, HERE << "need adapted head from " << adaptedHeadSource);
return;
}
+
#endif
entry->write (StoreIOBuffer(len, currentOffset, (char*)data));
+
readBuf->consume(len);
+
currentOffset += len;
}
void
HttpStateData::processReplyBody()
{
+
+ struct IN_ADDR *client_addr = NULL;
+
if (!flags.headers_parsed) {
flags.do_next_read = 1;
maybeReadVirginBody();
#if ICAP_CLIENT
if (icapAccessCheckPending)
return;
+
#endif
/*
comm_remove_close_handler(fd, httpStateFree, this);
fwd->unregister(fd);
+#if LINUX_TPROXY
+
+ if (orig_request->flags.tproxy)
+ client_addr = &orig_request->client_addr;
+
+#endif
if (_peer) {
if (_peer->options.originserver)
- fwd->pconnPush(fd, _peer->name, orig_request->port, orig_request->host);
+ fwd->pconnPush(fd, _peer->name, orig_request->port, orig_request->host, client_addr);
else
- fwd->pconnPush(fd, _peer->name, _peer->http_port, NULL);
+ fwd->pconnPush(fd, _peer->name, _peer->http_port, NULL, client_addr);
} else {
- fwd->pconnPush(fd, request->host, request->port, NULL);
+ fwd->pconnPush(fd, request->host, request->port, NULL, client_addr);
}
fd = -1;
#if RE_ENABLE_THIS_IF_NEEDED_OR_DELETE
// This code is not broken, but is probably not needed because we
// probably can read more than will fit into the BodyPipe buffer.
+
if (virginBodyDestination != NULL) {
/*
* BodyPipe buffer has a finite size limit. We
if (icap_space < read_sz)
read_sz = icap_space;
}
+
#endif
#endif
debugs(11,9, HERE << (flags.do_next_read ? "may" : "wont") <<
- " read up to " << read_sz << " bytes from FD " << fd);
+ " read up to " << read_sz << " bytes from FD " << fd);
/*
* why <2? Because delayAwareRead() won't actually read if
HttpStateData::closeServer()
{
debugs(11,5, HERE << "closing HTTP server FD " << fd << " this " << this);
+
if (fd >= 0) {
fwd->unregister(fd);
comm_remove_close_handler(fd, httpStateFree, this);
if (orig_request->body_pipe != NULL) {
requestBodySource = orig_request->body_pipe;
+
if (!requestBodySource->setConsumerIfNotLate(this)) {
debugs(32,3, HERE << "aborting on partially consumed body");
requestBodySource = NULL;
return false;
}
+
requestSender = HttpStateData::sentRequestBodyWrapper;
debugs(32,3, HERE << "expecting request body on pipe " << requestBodySource);
} else {
}
assert(requestBodySource != NULL);
+
if (requestBodySource->buf().hasContent()) {
// XXX: why does not this trigger a debug message on every request?
+
if (flags.headers_parsed && !flags.abuse_detected) {
flags.abuse_detected = 1;
debug(11, 1) ("http handleMoreRequestBodyAvailable: Likely proxy abuse detected '%s' -> '%s'\n",
{
if (size > 0)
kb_incr(&statCounter.server.http.kbytes_out, size);
+
ServerStateData::sentRequestBody(fd, size, errflag);
}
{
debugs(11,5, HERE << "aborting transaction for " << reason <<
"; FD " << fd << ", this " << this);
+
if (fd >= 0)
comm_close(fd);
else
/*
- * $Id: main.cc,v 1.444 2007/04/13 23:12:31 wessels Exp $
+ * $Id: main.cc,v 1.445 2007/04/15 14:46:17 serassio Exp $
*
* DEBUG: section 1 Startup and Main Loop
* AUTHOR: Harvest Derived
SignalDispatcher::dispatch()
{
PROF_start(SignalDispatcher_dispatch);
+
if (do_reconfigure) {
mainReconfigure();
do_reconfigure = 0;
break;
case 'k':
+
if ((int) strlen(optarg) < 1)
usage();
case 'm':
if (optarg) {
#if MALLOC_DBG
- malloc_debug_level = atoi(optarg);
+ malloc_debug_level = atoi(optarg);
#else
- fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
+ fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
#endif
} else {
static void
setEffectiveUser(void)
{
+ keepCapabilities();
leave_suid(); /* Run as non privilegied user */
#ifdef _SQUID_OS2_
storeDigestRegisterWithCacheManager(manager);
StoreFileSystem::RegisterAllFsWithCacheManager(manager);
storeRegisterWithCacheManager(manager);
- storeLogRegisterWithCacheManager(manager);
+ storeLogRegisterWithCacheManager(manager);
#if DEBUGSTRINGS
StringRegistry::Instance().registerWithCacheManager(manager);
serverConnectionsOpen();
neighbors_init();
+
neighborsRegisterWithCacheManager(manager);
if (Config.chroot_dir)
unlinkdClose(); /* after sync/flush */
#endif
+
storeDirWriteCleanLogs(0);
PrintRusage();
dumpMallocStats();
/*
- * $Id: pconn.cc,v 1.47 2006/09/03 21:05:20 hno Exp $
+ * $Id: pconn.cc,v 1.48 2007/04/15 14:46:17 serassio Exp $
*
* DEBUG: section 48 Persistent Connections
* AUTHOR: Duane Wessels
/* ========== PconnPool PRIVATE FUNCTIONS ============================================ */
const char *
-PconnPool::key(const char *host, u_short port, const char *domain)
+
+PconnPool::key(const char *host, u_short port, const char *domain, struct IN_ADDR *client_address)
{
LOCAL_ARRAY(char, buf, SQUIDHOSTNAMELEN * 2 + 10);
- if (domain)
+ if (domain && client_address)
+ snprintf(buf, SQUIDHOSTNAMELEN * 2 + 10, "%s:%d-%s/%s", host, (int) port, inet_ntoa(*client_address), domain);
+ else if (domain && (!client_address))
snprintf(buf, SQUIDHOSTNAMELEN * 2 + 10, "%s:%d/%s", host, (int) port, domain);
+ else if ((!domain) && client_address)
+ snprintf(buf, SQUIDHOSTNAMELEN * 2 + 10, "%s:%d-%s", host, (int) port, inet_ntoa(*client_address));
else
snprintf(buf, SQUIDHOSTNAMELEN * 2 + 10, "%s:%d", host, (int) port);
}
void
-PconnPool::push(int fd, const char *host, u_short port, const char *domain)
+
+PconnPool::push(int fd, const char *host, u_short port, const char *domain, struct IN_ADDR *client_address)
{
IdleConnList *list;
const char *aKey;
LOCAL_ARRAY(char, desc, FD_DESC_SZ);
- if (fdUsageHigh()) {
+ if (fdUsageHigh())
+ {
debug(48, 3) ("PconnPool::push: Not many unused FDs\n");
comm_close(fd);
return;
- } else if (shutting_down) {
+ } else if (shutting_down)
+ {
comm_close(fd);
return;
}
- aKey = key(host, port, domain);
+ aKey = key(host, port, domain, client_address);
list = (IdleConnList *) hash_lookup(table, aKey);
- if (list == NULL) {
+ if (list == NULL)
+ {
list = new IdleConnList(aKey, this);
debug(48, 3) ("pconnNew: adding %s\n", hashKeyStr(&list->hash));
hash_join(table, &list->hash);
* return a pconn fd for host:port, or -1 if none are available
*/
int
-PconnPool::pop(const char *host, u_short port, const char *domain)
+
+PconnPool::pop(const char *host, u_short port, const char *domain, struct IN_ADDR *client_address)
{
IdleConnList *list;
- const char * aKey = key(host, port, domain);
+ const char * aKey = key(host, port, domain, client_address);
list = (IdleConnList *)hash_lookup(table, aKey);
if (list == NULL)
int fd = list->findUseableFD();
- if (fd >= 0) {
+ if (fd >= 0)
+ {
list->clearHandlers(fd);
list->removeFD(fd); /* might delete list */
}
PconnPool(const char *);
void moduleInit();
- void push(int fd, const char *host, u_short port, const char *domain);
- int pop(const char *host, u_short port, const char *domain);
+ void push(int fd, const char *host, u_short port, const char *domain, struct IN_ADDR *client_address);
+ int pop(const char *host, u_short port, const char *domain, struct IN_ADDR *client_address);
void count(int uses);
void dumpHist(StoreEntry *e);
void unlinkList(IdleConnList *list) const;
private:
- static const char *key(const char *host, u_short port, const char *domain);
+ static const char *key(const char *host, u_short port, const char *domain, struct IN_ADDR *client_address);
int hist[PCONN_HIST_SZ];
hash_table *table;
/*
- * $Id: protos.h,v 1.539 2007/04/13 23:12:31 wessels Exp $
+ * $Id: protos.h,v 1.540 2007/04/15 14:46:17 serassio Exp $
*
*
* SQUID Web Proxy Cache http://www.squid-cache.org/
SQUIDCEXTERN double dpercent(double, double);
SQUIDCEXTERN void squid_signal(int sig, SIGHDLR *, int flags);
SQUIDCEXTERN pid_t readPidFile(void);
+SQUIDCEXTERN void keepCapabilities(void);
SQUIDCEXTERN struct IN_ADDR inaddrFromHostent(const struct hostent *hp);
SQUIDCEXTERN int intAverage(int, int, int, int);
/*
- * $Id: structs.h,v 1.553 2007/04/07 09:35:38 serassio Exp $
+ * $Id: structs.h,v 1.554 2007/04/15 14:46:17 serassio Exp $
*
*
* SQUID Web Proxy Cache http://www.squid-cache.org/
int vport; /* virtual port support, -1 for dynamic, >0 static*/
int disable_pmtu_discovery;
+#if LINUX_TPROXY
+unsigned int tproxy:
+ 1; /* spoof client ip using tproxy */
+#endif
};
#if HTTP_VIOLATIONS
nocache_hack = 0;
#endif
+#if LINUX_TPROXY
+ tproxy = 0;
+#endif
}
unsigned int transparent:
1;
+#if LINUX_TPROXY
+unsigned int tproxy:
+ 1; /* spoof client ip using tproxy */
+#endif
unsigned int internal:
1;
/*
- * $Id: tools.cc,v 1.272 2006/11/04 17:10:43 hno Exp $
+ * $Id: tools.cc,v 1.273 2007/04/15 14:46:17 serassio Exp $
*
* DEBUG: section 21 Misc Functions
* AUTHOR: Harvest Derived
#include "wordlist.h"
#include "SquidTime.h"
+#if LINUX_TPROXY
+#undef _POSIX_SOURCE
+/* Ugly glue to get around linux header madness colliding with glibc */
+#define _LINUX_TYPES_H
+#define _LINUX_FS_H
+typedef uint32_t __u32;
+#include <sys/capability.h>
+#endif
+
#if HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif
if (setuid(Config2.effectiveUserID) < 0)
debug(50, 0) ("ALERT: setuid: %s\n", xstrerror());
+#endif
+#if LINUX_TPROXY
+
+ if (need_linux_tproxy) {
+ cap_user_header_t head = (cap_user_header_t) xcalloc(1, sizeof(cap_user_header_t));
+ cap_user_data_t cap = (cap_user_data_t) xcalloc(1, sizeof(cap_user_data_t));
+
+ head->version = _LINUX_CAPABILITY_VERSION;
+ head->pid = 0;
+ cap->inheritable = cap->permitted = cap->effective = (1 << CAP_NET_ADMIN) + (1 << CAP_NET_BIND_SERVICE) + (1 << CAP_NET_BROADCAST);
+
+ if (capset(head, cap) != 0) {
+ xfree(head);
+ xfree(cap);
+ fatal("Error giving up capabilities");
+ }
+
+ xfree(head);
+ xfree(cap);
+ }
+
#endif
#if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
/* Set Linux DUMPABLE flag */
if (quoted)
mb->append("\"", 1);
}
+
+void
+keepCapabilities(void)
+{
+#if LINUX_TPROXY
+
+ if (need_linux_tproxy) {
+ if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
+ debug(1, 1) ("Error - tproxy support requires capability setting which has failed. Continuing without tproxy support\n");
+ }
+ }
+
+#endif
+}