mirror of
https://git.FreeBSD.org/ports.git
synced 2025-01-03 06:04:53 +00:00
a0c6cf9fc4
- provide more OPTIONS, including (untested) support for pf(4) - integrate the follow-XFF-patch from devel.squid-cache.org (submitted by Michael Ranner), this should improve interaction with dansguardian - use id 100 for the squid pseudo user instead of choosing the first free id greater than 3127, a behaviour introduced with PORTVERSION 2.5.4_6. Provide a 'changeuser' target to make migration from a high id to id 100 possible (requested by Kris Kennaway) - don't let the port CONFLICT with itself (criticized by Oliver Eikemeier) - provide rcNG support in squid.sh only on systems with /etc/rc.subr PR: ports/64061 Submitted by: Thomas-Martin Seck (maintainer)
413 lines
14 KiB
Diff
413 lines
14 KiB
Diff
! This is a reduced part of the original follow-XFF patchset from
|
|
! devel.squid-cache.org for use with the FreeBSD squid-2.5 port.
|
|
Index: src/acl.c
|
|
--- src/acl.c 13 May 2003 02:14:12 -0000 1.43.2.16
|
|
+++ src/acl.c 23 Nov 2003 14:20:12 -0000
|
|
@@ -2001,6 +2001,11 @@
|
|
cbdataLock(A);
|
|
if (request != NULL) {
|
|
checklist->request = requestLink(request);
|
|
+#if FOLLOW_X_FORWARDED_FOR
|
|
+ if (Config.onoff.acl_uses_indirect_client) {
|
|
+ checklist->src_addr = request->indirect_client_addr;
|
|
+ } else
|
|
+#endif /* FOLLOW_X_FORWARDED_FOR */
|
|
checklist->src_addr = request->client_addr;
|
|
checklist->my_addr = request->my_addr;
|
|
checklist->my_port = request->my_port;
|
|
Index: src/cf.data.pre
|
|
--- src/cf.data.pre 7 Nov 2003 03:14:30 -0000 1.49.2.46
|
|
+++ src/cf.data.pre 23 Nov 2003 14:20:17 -0000
|
|
@@ -2065,6 +2065,92 @@
|
|
NOCOMMENT_END
|
|
DOC_END
|
|
|
|
+NAME: follow_x_forwarded_for
|
|
+TYPE: acl_access
|
|
+IFDEF: FOLLOW_X_FORWARDED_FOR
|
|
+LOC: Config.accessList.followXFF
|
|
+DEFAULT: none
|
|
+DEFAULT_IF_NONE: deny all
|
|
+DOC_START
|
|
+ Allowing or Denying the X-Forwarded-For header to be followed to
|
|
+ find the original source of a request.
|
|
+
|
|
+ Requests may pass through a chain of several other proxies
|
|
+ before reaching us. The X-Forwarded-For header will contain a
|
|
+ comma-separated list of the IP addresses in the chain, with the
|
|
+ rightmost address being the most recent.
|
|
+
|
|
+ If a request reaches us from a source that is allowed by this
|
|
+ configuration item, then we consult the X-Forwarded-For header
|
|
+ to see where that host received the request from. If the
|
|
+ X-Forwarded-For header contains multiple addresses, and if
|
|
+ acl_uses_indirect_client is on, then we continue backtracking
|
|
+ until we reach an address for which we are not allowed to
|
|
+ follow the X-Forwarded-For header, or until we reach the first
|
|
+ address in the list. (If acl_uses_indirect_client is off, then
|
|
+ it's impossible to backtrack through more than one level of
|
|
+ X-Forwarded-For addresses.)
|
|
+
|
|
+ The end result of this process is an IP address that we will
|
|
+ refer to as the indirect client address. This address may
|
|
+ be treated as the client address for access control, delay
|
|
+ pools and logging, depending on the acl_uses_indirect_client,
|
|
+ delay_pool_uses_indirect_client and log_uses_indirect_client
|
|
+ options.
|
|
+
|
|
+ SECURITY CONSIDERATIONS:
|
|
+
|
|
+ Any host for which we follow the X-Forwarded-For header
|
|
+ can place incorrect information in the header, and Squid
|
|
+ will use the incorrect information as if it were the
|
|
+ source address of the request. This may enable remote
|
|
+ hosts to bypass any access control restrictions that are
|
|
+ based on the client's source addresses.
|
|
+
|
|
+ For example:
|
|
+
|
|
+ acl localhost src 127.0.0.1
|
|
+ acl my_other_proxy srcdomain .proxy.example.com
|
|
+ follow_x_forwarded_for allow localhost
|
|
+ follow_x_forwarded_for allow my_other_proxy
|
|
+DOC_END
|
|
+
|
|
+NAME: acl_uses_indirect_client
|
|
+COMMENT: on|off
|
|
+TYPE: onoff
|
|
+IFDEF: FOLLOW_X_FORWARDED_FOR
|
|
+DEFAULT: on
|
|
+LOC: Config.onoff.acl_uses_indirect_client
|
|
+DOC_START
|
|
+ Controls whether the indirect client address
|
|
+ (see follow_x_forwarded_for) is used instead of the
|
|
+ direct client address in acl matching.
|
|
+DOC_END
|
|
+
|
|
+NAME: delay_pool_uses_indirect_client
|
|
+COMMENT: on|off
|
|
+TYPE: onoff
|
|
+IFDEF: FOLLOW_X_FORWARDED_FOR && DELAY_POOLS
|
|
+DEFAULT: on
|
|
+LOC: Config.onoff.delay_pool_uses_indirect_client
|
|
+DOC_START
|
|
+ Controls whether the indirect client address
|
|
+ (see follow_x_forwarded_for) is used instead of the
|
|
+ direct client address in delay pools.
|
|
+DOC_END
|
|
+
|
|
+NAME: log_uses_indirect_client
|
|
+COMMENT: on|off
|
|
+TYPE: onoff
|
|
+IFDEF: FOLLOW_X_FORWARDED_FOR
|
|
+DEFAULT: on
|
|
+LOC: Config.onoff.log_uses_indirect_client
|
|
+DOC_START
|
|
+ Controls whether the indirect client address
|
|
+ (see follow_x_forwarded_for) is used instead of the
|
|
+ direct client address in the access log.
|
|
+DOC_END
|
|
+
|
|
NAME: http_access
|
|
TYPE: acl_access
|
|
LOC: Config.accessList.http
|
|
Index: src/client_side.c
|
|
--- src/client_side.c 2 Sep 2003 02:13:45 -0000 1.47.2.39
|
|
+++ src/client_side.c 23 Nov 2003 14:20:22 -0000
|
|
@@ -109,6 +109,11 @@
|
|
#if USE_IDENT
|
|
static IDCB clientIdentDone;
|
|
#endif
|
|
+#if FOLLOW_X_FORWARDED_FOR
|
|
+static void clientFollowXForwardedForStart(void *data);
|
|
+static void clientFollowXForwardedForNext(void *data);
|
|
+static void clientFollowXForwardedForDone(int answer, void *data);
|
|
+#endif /* FOLLOW_X_FORWARDED_FOR */
|
|
static int clientOnlyIfCached(clientHttpRequest * http);
|
|
static STCB clientSendMoreData;
|
|
static STCB clientCacheHit;
|
|
@@ -177,10 +182,179 @@
|
|
return ch;
|
|
}
|
|
|
|
+#if FOLLOW_X_FORWARDED_FOR
|
|
+/*
|
|
+ * clientFollowXForwardedForStart() copies the X-Forwarded-For
|
|
+ * header into x_forwarded_for_iterator and passes control to
|
|
+ * clientFollowXForwardedForNext().
|
|
+ *
|
|
+ * clientFollowXForwardedForNext() checks the indirect_client_addr
|
|
+ * against the followXFF ACL and passes the result to
|
|
+ * clientFollowXForwardedForDone().
|
|
+ *
|
|
+ * clientFollowXForwardedForDone() either grabs the next address
|
|
+ * from the tail of x_forwarded_for_iterator and loops back to
|
|
+ * clientFollowXForwardedForNext(), or cleans up and passes control to
|
|
+ * clientAccessCheck().
|
|
+ */
|
|
+
|
|
+static void
|
|
+clientFollowXForwardedForStart(void *data)
|
|
+{
|
|
+ clientHttpRequest *http = data;
|
|
+ request_t *request = http->request;
|
|
+ if (Config.accessList.followXFF
|
|
+ && httpHeaderHas(&request->header, HDR_X_FORWARDED_FOR))
|
|
+ {
|
|
+ request->x_forwarded_for_iterator = httpHeaderGetList(
|
|
+ &request->header, HDR_X_FORWARDED_FOR);
|
|
+ debug(33, 5) ("clientFollowXForwardedForStart: indirect_client_addr=%s XFF='%s'\n",
|
|
+ inet_ntoa(request->indirect_client_addr),
|
|
+ strBuf(request->x_forwarded_for_iterator));
|
|
+ clientFollowXForwardedForNext(http);
|
|
+ } else {
|
|
+ /* not configured to follow X-Forwarded-For, or nothing to follow */
|
|
+ debug(33, 5) ("clientFollowXForwardedForStart: nothing to do\n");
|
|
+ clientFollowXForwardedForDone(-1, http);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+clientFollowXForwardedForNext(void *data)
|
|
+{
|
|
+ clientHttpRequest *http = data;
|
|
+ request_t *request = http->request;
|
|
+ debug(33, 5) ("clientFollowXForwardedForNext: indirect_client_addr=%s XFF='%s'\n",
|
|
+ inet_ntoa(request->indirect_client_addr),
|
|
+ strBuf(request->x_forwarded_for_iterator));
|
|
+ if (strLen(request->x_forwarded_for_iterator) != 0) {
|
|
+ /* check the acl to see whether to believe the X-Forwarded-For header */
|
|
+ http->acl_checklist = clientAclChecklistCreate(
|
|
+ Config.accessList.followXFF, http);
|
|
+ aclNBCheck(http->acl_checklist, clientFollowXForwardedForDone, http);
|
|
+ } else {
|
|
+ /* nothing left to follow */
|
|
+ debug(33, 5) ("clientFollowXForwardedForNext: nothing more to do\n");
|
|
+ clientFollowXForwardedForDone(-1, http);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+clientFollowXForwardedForDone(int answer, void *data)
|
|
+{
|
|
+ clientHttpRequest *http = data;
|
|
+ request_t *request = http->request;
|
|
+ /*
|
|
+ * answer should be be ACCESS_ALLOWED or ACCESS_DENIED if we are
|
|
+ * called as a result of ACL checks, or -1 if we are called when
|
|
+ * there's nothing left to do.
|
|
+ */
|
|
+ if (answer == ACCESS_ALLOWED) {
|
|
+ /*
|
|
+ * The IP address currently in request->indirect_client_addr
|
|
+ * is trusted to use X-Forwarded-For. Remove the last
|
|
+ * comma-delimited element from x_forwarded_for_iterator and use
|
|
+ * it to to replace indirect_client_addr, then repeat the cycle.
|
|
+ */
|
|
+ const char *p;
|
|
+ const char *asciiaddr;
|
|
+ int l;
|
|
+ struct in_addr addr;
|
|
+ debug(33, 5) ("clientFollowXForwardedForDone: indirect_client_addr=%s is trusted\n",
|
|
+ inet_ntoa(request->indirect_client_addr));
|
|
+ p = strBuf(request->x_forwarded_for_iterator);
|
|
+ l = strLen(request->x_forwarded_for_iterator);
|
|
+
|
|
+ /*
|
|
+ * XXX x_forwarded_for_iterator should really be a list of
|
|
+ * IP addresses, but it's a String instead. We have to
|
|
+ * walk backwards through the String, biting off the last
|
|
+ * comma-delimited part each time. As long as the data is in
|
|
+ * a String, we should probably implement and use a variant of
|
|
+ * strListGetItem() that walks backwards instead of forwards
|
|
+ * through a comma-separated list. But we don't even do that;
|
|
+ * we just do the work in-line here.
|
|
+ */
|
|
+ /* skip trailing space and commas */
|
|
+ while (l > 0 && (p[l-1] == ',' || xisspace(p[l-1])))
|
|
+ l--;
|
|
+ strCut(request->x_forwarded_for_iterator, l);
|
|
+ /* look for start of last item in list */
|
|
+ while (l > 0 && ! (p[l-1] == ',' || xisspace(p[l-1])))
|
|
+ l--;
|
|
+ asciiaddr = p+l;
|
|
+ if (inet_aton(asciiaddr, &addr) == 0) {
|
|
+ /* the address is not well formed; do not use it */
|
|
+ debug(33, 3) ("clientFollowXForwardedForDone: malformed address '%s'\n",
|
|
+ asciiaddr);
|
|
+ goto done;
|
|
+ }
|
|
+ debug(33, 3) ("clientFollowXForwardedForDone: changing indirect_client_addr from %s to '%s'\n",
|
|
+ inet_ntoa(request->indirect_client_addr),
|
|
+ asciiaddr);
|
|
+ request->indirect_client_addr = addr;
|
|
+ strCut(request->x_forwarded_for_iterator, l);
|
|
+ if (! Config.onoff.acl_uses_indirect_client) {
|
|
+ /*
|
|
+ * If acl_uses_indirect_client is off, then it's impossible
|
|
+ * to follow more than one level of X-Forwarded-For.
|
|
+ */
|
|
+ goto done;
|
|
+ }
|
|
+ clientFollowXForwardedForNext(http);
|
|
+ return;
|
|
+ } else if (answer == ACCESS_DENIED) {
|
|
+ debug(33, 5) ("clientFollowXForwardedForDone: indirect_client_addr=%s not trusted\n",
|
|
+ inet_ntoa(request->indirect_client_addr));
|
|
+ } else {
|
|
+ debug(33, 5) ("clientFollowXForwardedForDone: indirect_client_addr=%s nothing more to do\n",
|
|
+ inet_ntoa(request->indirect_client_addr));
|
|
+ }
|
|
+done:
|
|
+ /* clean up, and pass control to clientAccessCheck */
|
|
+ debug(33, 6) ("clientFollowXForwardedForDone: cleanup\n");
|
|
+ if (Config.onoff.log_uses_indirect_client) {
|
|
+ /*
|
|
+ * Ensure that the access log shows the indirect client
|
|
+ * instead of the direct client.
|
|
+ */
|
|
+ ConnStateData *conn = http->conn;
|
|
+ conn->log_addr = request->indirect_client_addr;
|
|
+ conn->log_addr.s_addr &= Config.Addrs.client_netmask.s_addr;
|
|
+ debug(33, 3) ("clientFollowXForwardedForDone: setting log_addr=%s\n",
|
|
+ inet_ntoa(conn->log_addr));
|
|
+ }
|
|
+ stringClean(&request->x_forwarded_for_iterator);
|
|
+ request->flags.done_follow_x_forwarded_for = 1;
|
|
+ http->acl_checklist = NULL; /* XXX do we need to aclChecklistFree() ? */
|
|
+ clientAccessCheck(http);
|
|
+}
|
|
+#endif /* FOLLOW_X_FORWARDED_FOR */
|
|
+
|
|
void
|
|
clientAccessCheck(void *data)
|
|
{
|
|
clientHttpRequest *http = data;
|
|
+#if FOLLOW_X_FORWARDED_FOR
|
|
+ if (! http->request->flags.done_follow_x_forwarded_for
|
|
+ && httpHeaderHas(&http->request->header, HDR_X_FORWARDED_FOR))
|
|
+ {
|
|
+ /*
|
|
+ * There's an X-ForwardedFor header and we haven't yet tried
|
|
+ * to follow it to find the indirect_client_addr. Follow it now.
|
|
+ * clientFollowXForwardedForDone() will eventually pass control
|
|
+ * back to us.
|
|
+ *
|
|
+ * XXX perhaps our caller should have called
|
|
+ * clientFollowXForwardedForStart instead. Then we wouldn't
|
|
+ * need to do this little dance transferring control over
|
|
+ * there and then back here, and we wouldn't need the
|
|
+ * done_follow_x_forwarded_for flag.
|
|
+ */
|
|
+ clientFollowXForwardedForStart(data);
|
|
+ return;
|
|
+ }
|
|
+#endif /* FOLLOW_X_FORWARDED_FOR */
|
|
if (checkAccelOnly(http)) {
|
|
/* deny proxy requests in accel_only mode */
|
|
debug(33, 1) ("clientAccessCheck: proxy request denied in accel_only mode\n");
|
|
@@ -325,6 +499,9 @@
|
|
new_request->http_ver = old_request->http_ver;
|
|
httpHeaderAppend(&new_request->header, &old_request->header);
|
|
new_request->client_addr = old_request->client_addr;
|
|
+#if FOLLOW_X_FORWARDED_FOR
|
|
+ new_request->indirect_client_addr = old_request->indirect_client_addr;
|
|
+#endif /* FOLLOW_X_FORWARDED_FOR */
|
|
new_request->my_addr = old_request->my_addr;
|
|
new_request->my_port = old_request->my_port;
|
|
new_request->flags.redirected = 1;
|
|
@@ -3051,6 +3228,9 @@
|
|
safe_free(http->log_uri);
|
|
http->log_uri = xstrdup(urlCanonicalClean(request));
|
|
request->client_addr = conn->peer.sin_addr;
|
|
+#if FOLLOW_X_FORWARDED_FOR
|
|
+ request->indirect_client_addr = request->client_addr;
|
|
+#endif /* FOLLOW_X_FORWARDED_FOR */
|
|
request->my_addr = conn->me.sin_addr;
|
|
request->my_port = ntohs(conn->me.sin_port);
|
|
request->http_ver = http->http_ver;
|
|
Index: src/delay_pools.c
|
|
--- src/delay_pools.c 19 Jun 2003 02:13:57 -0000 1.5.54.6
|
|
+++ src/delay_pools.c 23 Nov 2003 14:20:23 -0000
|
|
@@ -318,6 +318,11 @@
|
|
r = http->request;
|
|
|
|
memset(&ch, '\0', sizeof(ch));
|
|
+#if FOLLOW_X_FORWARDED_FOR
|
|
+ if (Config.onoff.delay_pool_uses_indirect_client) {
|
|
+ ch.src_addr = r->indirect_client_addr;
|
|
+ } else
|
|
+#endif /* FOLLOW_X_FORWARDED_FOR */
|
|
ch.src_addr = r->client_addr;
|
|
ch.my_addr = r->my_addr;
|
|
ch.my_port = r->my_port;
|
|
Index: src/structs.h
|
|
*** src/structs.h.orig Thu Feb 26 20:32:47 2004
|
|
--- src/structs.h Thu Feb 26 20:34:51 2004
|
|
***************
|
|
*** 594,599 ****
|
|
--- 594,604 ----
|
|
int pipeline_prefetch;
|
|
int request_entities;
|
|
int detect_broken_server_pconns;
|
|
+ #if FOLLOW_X_FORWARDED_FOR
|
|
+ int acl_uses_indirect_client;
|
|
+ int delay_pool_uses_indirect_client;
|
|
+ int log_uses_indirect_client;
|
|
+ #endif /* FOLLOW_X_FORWARDED_FOR */
|
|
} onoff;
|
|
acl *aclList;
|
|
struct {
|
|
***************
|
|
*** 615,620 ****
|
|
--- 620,628 ----
|
|
acl_access *reply;
|
|
acl_address *outgoing_address;
|
|
acl_tos *outgoing_tos;
|
|
+ #if FOLLOW_X_FORWARDED_FOR
|
|
+ acl_access *followXFF;
|
|
+ #endif /* FOLLOW_X_FORWARDED_FOR */
|
|
} accessList;
|
|
acl_deny_info_list *denyInfoList;
|
|
struct _authConfig {
|
|
***************
|
|
*** 1611,1616 ****
|
|
--- 1619,1629 ----
|
|
unsigned int internal:1;
|
|
unsigned int body_sent:1;
|
|
unsigned int reset_tcp:1;
|
|
+ #if FOLLOW_X_FORWARDED_FOR
|
|
+ /* XXX this flag could be eliminated;
|
|
+ * see comments in clientAccessCheck */
|
|
+ unsigned int done_follow_x_forwarded_for;
|
|
+ #endif /* FOLLOW_X_FORWARDED_FOR */
|
|
};
|
|
|
|
struct _link_list {
|
|
***************
|
|
*** 1657,1662 ****
|
|
--- 1670,1678 ----
|
|
int max_forwards;
|
|
/* these in_addr's could probably be sockaddr_in's */
|
|
struct in_addr client_addr;
|
|
+ #if FOLLOW_X_FORWARDED_FOR
|
|
+ struct in_addr indirect_client_addr; /* after following X-Forwarded-For */
|
|
+ #endif /* FOLLOW_X_FORWARDED_FOR */
|
|
struct in_addr my_addr;
|
|
unsigned short my_port;
|
|
HttpHeader header;
|
|
***************
|
|
*** 1667,1672 ****
|
|
--- 1683,1693 ----
|
|
char *peer_login; /* Configured peer login:password */
|
|
time_t lastmod; /* Used on refreshes */
|
|
const char *vary_headers; /* Used when varying entities are detected. Changes how the store key is calculated */
|
|
+ #if FOLLOW_X_FORWARDED_FOR
|
|
+ /* XXX a list of IP addresses would be a better data structure
|
|
+ * than this String */
|
|
+ String x_forwarded_for_iterator;
|
|
+ #endif /* FOLLOW_X_FORWARDED_FOR */
|
|
};
|
|
|
|
struct _cachemgr_passwd {
|