--------------------- PatchSet 2876 Date: 2001/08/26 20:02:40 Author: hno Branch: hno-emara Tag: (none) Log: Initial commit. Basically rproxy+external_acl Members: acconfig.h:1.10->1.10.4.1 configure.in:1.24->1.24.4.1 include/cache_snmp.h:1.2->1.2.92.1 src/HttpHeader.c:1.6->1.6.30.1 src/HttpRequest.c:1.7->1.7.26.1 src/Makefile.in:1.14->1.14.4.1 src/acl.c:1.33->1.33.4.1 src/cache_cf.c:1.33->1.33.4.1 src/cf.data.pre:1.32->1.32.4.1 src/client_side.c:1.34->1.34.4.1 src/enums.h:1.22->1.22.6.1 src/errormap.c:1.1->1.1.18.1 src/errorpage.c:1.13->1.13.14.1 src/external_acl.c:1.1->1.1.12.1 src/forward.c:1.12->1.12.38.1 src/globals.h:1.11->1.11.4.1 src/http.c:1.14->1.14.12.1 src/icp_v2.c:1.5->1.5.16.1 src/locrewrite.c:1.1->1.1.24.1 src/main.c:1.25->1.25.4.1 src/mib.txt:1.3->1.3.92.1 src/neighbors.c:1.12->1.12.12.1 src/peer_monitor.c:1.1->1.1.18.1 src/peer_select.c:1.9->1.9.26.1 src/peer_userhash.c:1.1->1.1.18.1 src/protos.h:1.32->1.32.4.1 src/redirect.c:1.7->1.7.44.1 src/snmp_agent.c:1.6->1.6.56.1 src/snmp_core.c:1.7->1.7.12.1 src/ssl_support.c:1.3->1.3.16.1 src/store_key_md5.c:1.6->1.6.26.1 src/structs.h:1.38->1.38.6.1 src/typedefs.h:1.23->1.23.6.1 Index: squid/acconfig.h =================================================================== RCS file: /cvsroot/squid-sf//squid/Attic/acconfig.h,v retrieving revision 1.10 retrieving revision 1.10.4.1 diff -u -r1.10 -r1.10.4.1 --- squid/acconfig.h 24 Aug 2001 15:44:04 -0000 1.10 +++ squid/acconfig.h 26 Aug 2001 20:02:40 -0000 1.10.4.1 @@ -23,7 +23,7 @@ #ifndef __CONFIGURE_H__ #define __CONFIGURE_H__ @TOP@ -/* $Id: acconfig.h,v 1.10 2001/08/24 15:44:04 squidadm Exp $ */ +/* $Id: acconfig.h,v 1.10.4.1 2001/08/26 20:02:40 hno Exp $ */ /********************************* * START OF CONFIGURABLE OPTIONS * @@ -327,6 +327,11 @@ */ #undef X_ACCELERATOR_VARY +/* + * Enable authentication support in accelerators + */ +#undef AUTH_ON_ACCELERATION + @BOTTOM@ #endif /* __CONFIGURE_H__ */ Index: squid/configure.in =================================================================== RCS file: /cvsroot/squid-sf//squid/configure.in,v retrieving revision 1.24 retrieving revision 1.24.4.1 diff -u -r1.24 -r1.24.4.1 --- squid/configure.in 24 Aug 2001 15:44:04 -0000 1.24 +++ squid/configure.in 26 Aug 2001 20:02:40 -0000 1.24.4.1 @@ -3,13 +3,13 @@ dnl dnl Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9) dnl -dnl $Id: configure.in,v 1.24 2001/08/24 15:44:04 squidadm Exp $ +dnl $Id: configure.in,v 1.24.4.1 2001/08/26 20:02:40 hno Exp $ dnl dnl dnl AC_INIT(src/main.c) AC_CONFIG_HEADER(include/autoconf.h) -AC_REVISION($Revision: 1.24 $)dnl +AC_REVISION($Revision: 1.24.4.1 $)dnl AC_PREFIX_DEFAULT(/usr/local/squid) AC_CONFIG_AUX_DIR(cfgaux) @@ -582,6 +582,15 @@ fi ]) +AC_ARG_ENABLE(auth-on-acceleration, +[ --enable-auth-on-acceleration + Enable authentication in accelerators], +[ if test "$enableval" = "yes" ; then + echo "AUTH_ON_ACCELERATION enabled" + AC_DEFINE(AUTH_ON_ACCELERATION) + fi +]) + dnl Select Error language AC_ARG_ENABLE(err-language, [ --enable-err-language=lang Index: squid/include/cache_snmp.h =================================================================== RCS file: /cvsroot/squid-sf//squid/include/cache_snmp.h,v retrieving revision 1.2 retrieving revision 1.2.92.1 diff -u -r1.2 -r1.2.92.1 --- squid/include/cache_snmp.h 23 Oct 2000 15:04:18 -0000 1.2 +++ squid/include/cache_snmp.h 26 Aug 2001 20:02:40 -0000 1.2.92.1 @@ -1,5 +1,5 @@ /* - * $Id: cache_snmp.h,v 1.2 2000/10/23 15:04:18 hno Exp $ + * $Id: cache_snmp.h,v 1.2.92.1 2001/08/26 20:02:40 hno Exp $ */ #ifdef SQUID_SNMP @@ -122,6 +122,8 @@ MESH_PTBL_IGN, MESH_PTBL_KEEPAL_S, MESH_PTBL_KEEPAL_R, + MESH_PTBL_INDEX, + MESH_PTBL_HOST, MESH_PTBL_END }; Index: squid/src/HttpHeader.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/HttpHeader.c,v retrieving revision 1.6 retrieving revision 1.6.30.1 diff -u -r1.6 -r1.6.30.1 --- squid/src/HttpHeader.c 14 Apr 2001 00:31:01 -0000 1.6 +++ squid/src/HttpHeader.c 26 Aug 2001 20:02:40 -0000 1.6.30.1 @@ -1,6 +1,6 @@ /* - * $Id: HttpHeader.c,v 1.6 2001/04/14 00:31:01 squidadm Exp $ + * $Id: HttpHeader.c,v 1.6.30.1 2001/08/26 20:02:40 hno Exp $ * * DEBUG: section 55 HTTP Header * AUTHOR: Alex Rousskov @@ -128,6 +128,8 @@ #if X_ACCELERATOR_VARY {"X-Accelerator-Vary", HDR_X_ACCELERATOR_VARY, ftStr}, #endif + {"X-Error-URL", HDR_X_ERROR_URL, ftStr}, + {"X-Error-Status", HDR_X_ERROR_STATUS, ftInt}, {"Other:", HDR_OTHER, ftStr} /* ':' will not allow matches */ }; static HttpHeaderFieldInfo *Headers = NULL; Index: squid/src/HttpRequest.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/HttpRequest.c,v retrieving revision 1.7 retrieving revision 1.7.26.1 diff -u -r1.7 -r1.7.26.1 --- squid/src/HttpRequest.c 14 Apr 2001 00:31:01 -0000 1.7 +++ squid/src/HttpRequest.c 26 Aug 2001 20:02:40 -0000 1.7.26.1 @@ -1,6 +1,6 @@ /* - * $Id: HttpRequest.c,v 1.7 2001/04/14 00:31:01 squidadm Exp $ + * $Id: HttpRequest.c,v 1.7.26.1 2001/08/26 20:02:40 hno Exp $ * * DEBUG: section 73 HTTP Request * AUTHOR: Duane Wessels @@ -61,6 +61,7 @@ authenticateAuthUserRequestUnlock(req->auth_user_request); safe_free(req->canonical); safe_free(req->vary_headers); + safe_free(req->urlgroup); stringClean(&req->urlpath); httpHeaderClean(&req->header); if (req->cache_control) Index: squid/src/Makefile.in =================================================================== RCS file: /cvsroot/squid-sf//squid/src/Attic/Makefile.in,v retrieving revision 1.14 retrieving revision 1.14.4.1 diff -u -r1.14 -r1.14.4.1 --- squid/src/Makefile.in 24 Aug 2001 15:43:57 -0000 1.14 +++ squid/src/Makefile.in 26 Aug 2001 20:02:40 -0000 1.14.4.1 @@ -1,7 +1,7 @@ # # Makefile for the Squid Object Cache server # -# $Id: Makefile.in,v 1.14 2001/08/24 15:43:57 squidadm Exp $ +# $Id: Makefile.in,v 1.14.4.1 2001/08/26 20:02:40 hno Exp $ # # Uncomment and customize the following to suit your needs: # @@ -114,6 +114,8 @@ errorpage.o \ ETag.o \ event.o \ + errormap.o \ + external_acl.o \ fd.o \ filemap.o \ forward.o \ @@ -142,6 +144,7 @@ ipc.o \ ipcache.o \ @LEAKFINDER_OBJS@ \ + locrewrite.o \ logfile.o \ main.o \ mem.o \ @@ -154,7 +157,9 @@ Packer.o \ pconn.o \ peer_digest.o \ + peer_monitor.o \ peer_select.o \ + peer_userhash.o \ redirect.o \ referer.o \ refresh.o \ Index: squid/src/acl.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/acl.c,v retrieving revision 1.33 retrieving revision 1.33.4.1 diff -u -r1.33 -r1.33.4.1 --- squid/src/acl.c 22 Aug 2001 21:15:46 -0000 1.33 +++ squid/src/acl.c 26 Aug 2001 20:02:40 -0000 1.33.4.1 @@ -1,6 +1,6 @@ /* - * $Id: acl.c,v 1.33 2001/08/22 21:15:46 squidadm Exp $ + * $Id: acl.c,v 1.33.4.1 2001/08/26 20:02:40 hno Exp $ * * DEBUG: section 28 Access Control * AUTHOR: Duane Wessels @@ -43,9 +43,7 @@ static void aclParseUserList(void **current); static void aclParseIpList(void *curlist); static void aclParseIntlist(void *curlist); -#if SQUID_SNMP static void aclParseWordList(void *curlist); -#endif static void aclParseProtoList(void *curlist); static void aclParseMethodList(void *curlist); static void aclParseTimeSpec(void *curlist); @@ -64,9 +62,7 @@ static int aclMatchIp(void *dataptr, struct in_addr c); static int aclMatchDomainList(void *dataptr, const char *); static int aclMatchIntegerRange(intrange * data, int i); -#if SQUID_SNMP static int aclMatchWordList(wordlist *, const char *); -#endif static void aclParseUserMaxIP(void *data); static void aclDestroyUserMaxIP(void *data); static wordlist *aclDumpUserMaxIP(void *data); @@ -82,6 +78,7 @@ static IPH aclLookupDstIPforASNDone; static FQDNH aclLookupSrcFQDNDone; static FQDNH aclLookupDstFQDNDone; +static EAH aclLookupExternalDone; static wordlist *aclDumpIpList(void *); static wordlist *aclDumpDomainList(void *data); static wordlist *aclDumpTimeSpecList(acl_time_data *); @@ -226,6 +223,10 @@ return ACL_REP_MIME_TYPE; if (!strcmp(s, "max_user_ip")) return ACL_MAX_USER_IP; + if (!strcmp(s, "urlgroup")) + return ACL_URLGROUP; + if (!strcmp(s, "external")) + return ACL_EXTERNAL; return ACL_NONE; } @@ -296,6 +297,10 @@ return "rep_mime_type"; if (type == ACL_MAX_USER_IP) return "max_user_ip"; + if (type == ACL_URLGROUP) + return "urlgroup"; + if (type == ACL_EXTERNAL) + return "external"; return "ERROR"; } @@ -646,7 +651,6 @@ } } -#if SQUID_SNMP static void aclParseWordList(void *curlist) { @@ -654,7 +658,6 @@ while ((t = strtokFile())) wordlistAdd(curlist, t); } -#endif static void aclParseUserList(void **current) @@ -850,6 +853,12 @@ aclParseArpList(&A->data); break; #endif + case ACL_URLGROUP: + aclParseWordList(&A->data); + break; + case ACL_EXTERNAL: + aclParseExternal(&A->data); + break; case ACL_NONE: case ACL_ENUM_MAX: fatal("Bad ACL type"); @@ -1388,7 +1397,6 @@ return data->weekbits & (1 << tm.tm_wday) ? 1 : 0; } -#if SQUID_SNMP static int aclMatchWordList(wordlist * w, const char *word) { @@ -1401,7 +1409,6 @@ } return 0; } -#endif static int aclMatchAcl(acl * ae, aclCheck_t * checklist) @@ -1686,6 +1693,13 @@ header = ""; return aclMatchRegex(ae->data, header); /* NOTREACHED */ + case ACL_URLGROUP: + if (!checklist->request->urlgroup) + return 0; + return aclMatchWordList(ae->data, checklist->request->urlgroup); + break; + case ACL_EXTERNAL: + return aclMatchExternal(ae->data, checklist); case ACL_NONE: case ACL_ENUM_MAX: break; @@ -1805,6 +1819,11 @@ } } #endif + else if (checklist->state[ACL_EXTERNAL] == ACL_LOOKUP_NEEDED) { + acl *acl = aclFindByName(AclMatchedName); + externalAclLookup(checklist, acl->data, aclLookupExternalDone, checklist); + return; + } /* * We are done with this _acl_access entry. Either the request * is allowed, denied, requires authentication, or we move on to @@ -1933,6 +1952,14 @@ aclCheck(checklist); } +static void +aclLookupExternalDone(int result, void *data) +{ + aclCheck_t *checklist = data; + checklist->state[ACL_EXTERNAL] = ACL_LOOKUP_DONE; + aclCheck(checklist); +} + aclCheck_t * aclChecklistCreate(const acl_access * A, request_t * request, const char *ident) { @@ -2085,6 +2112,12 @@ case ACL_MY_PORT: aclDestroyIntRange(a->data); break; + case ACL_URLGROUP: + wordlistDestroy((wordlist **) & a->data); + break; + case ACL_EXTERNAL: + aclDestroyExternal(&a->data); + break; case ACL_NONE: case ACL_ENUM_MAX: debug(28, 1) ("aclDestroyAcls: no case for ACL type %d\n", a->type); @@ -2431,6 +2464,10 @@ case ACL_SRC_ARP: return aclDumpArpList(a->data); #endif + case ACL_URLGROUP: + return wordlistDup(a->data); + case ACL_EXTERNAL: + return aclDumpExternal(a->data); case ACL_NONE: case ACL_ENUM_MAX: break; Index: squid/src/cache_cf.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/cache_cf.c,v retrieving revision 1.33 retrieving revision 1.33.4.1 diff -u -r1.33 -r1.33.4.1 --- squid/src/cache_cf.c 24 Aug 2001 05:54:05 -0000 1.33 +++ squid/src/cache_cf.c 26 Aug 2001 20:02:40 -0000 1.33.4.1 @@ -1,6 +1,6 @@ /* - * $Id: cache_cf.c,v 1.33 2001/08/24 05:54:05 squidadm Exp $ + * $Id: cache_cf.c,v 1.33.4.1 2001/08/26 20:02:40 hno Exp $ * * DEBUG: section 3 Configuration File Parsing * AUTHOR: Harvest Derived @@ -93,10 +93,16 @@ 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 **); 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 **); +static int check_null_http_port_list(const http_port_list *); #if USE_SSL static void parse_https_port_list(https_port_list **); static void dump_https_port_list(StoreEntry *, const char *, const https_port_list *); @@ -281,7 +287,6 @@ static void configDoConfigure(void) { - LOCAL_ARRAY(char, buf, BUFSIZ); memset(&Config2, '\0', sizeof(SquidConfig2)); /* init memory as early as possible */ memConfigure(); @@ -305,16 +310,17 @@ if (Config.dnsChildren < 1) fatal("No dnsservers allocated"); #endif - if (Config.Program.redirect) { - if (Config.redirectChildren < 1) { - Config.redirectChildren = 0; - wordlistDestroy(&Config.Program.redirect); + if (Config.Program.url_rewrite.command) { + if (Config.Program.url_rewrite.children < 1) { + Config.Program.url_rewrite.children = 0; + wordlistDestroy(&Config.Program.url_rewrite.command); } } - 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.Program.location_rewrite.command) { + if (Config.Program.location_rewrite.children < 1) { + Config.Program.location_rewrite.children = 0; + wordlistDestroy(&Config.Program.location_rewrite.command); + } } if (Config.appendDomain) if (*Config.appendDomain != '.') @@ -322,13 +328,6 @@ 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; - } - if (Config.Sockaddr.http == NULL) - fatal("No http_port specified!"); snprintf(ThisCache, sizeof(ThisCache), "%s:%d (%s)", uniqueHostname(), (int) ntohs(Config.Sockaddr.http->s.sin_port), @@ -364,8 +363,10 @@ #if USE_UNLINKD requirePathnameExists("unlinkd_program", Config.Program.unlinkd); #endif - if (Config.Program.redirect) - requirePathnameExists("redirect_program", Config.Program.redirect->key); + if (Config.Program.url_rewrite.command) + requirePathnameExists("url_rewrite_program", Config.Program.url_rewrite.command->key); + if (Config.Program.location_rewrite.command) + requirePathnameExists("location_rewrite_program", Config.Program.location_rewrite.command->key); requirePathnameExists("Icon Directory", Config.icons.directory); requirePathnameExists("Error Directory", Config.errorDirectory); #if HTTP_VIOLATIONS @@ -1266,7 +1267,7 @@ d->domain); } if (p->access) { - snprintf(xname, 128, "cache_peer_access %s", p->host); + snprintf(xname, 128, "cache_peer_access %s", p->name); dump_acl_access(entry, xname, p->access); } for (t = p->typelist; t; t = t->next) { @@ -1290,9 +1291,11 @@ p->icp.port = CACHE_ICP_PORT; p->weight = 1; p->stats.logged_state = PEER_ALIVE; + p->monitor.state = PEER_ALIVE; if ((token = strtok(NULL, w_space)) == NULL) self_destruct(); p->host = xstrdup(token); + p->name = xstrdup(token); if ((token = strtok(NULL, w_space)) == NULL) self_destruct(); p->type = parseNeighborType(token); @@ -1323,6 +1326,8 @@ p->options.default_parent = 1; } else if (!strcasecmp(token, "round-robin")) { p->options.roundrobin = 1; + } else if (!strcasecmp(token, "userhash")) { + p->options.userhash = 1; #if USE_HTCP } else if (!strcasecmp(token, "htcp")) { p->options.htcp = 1; @@ -1353,11 +1358,40 @@ p->options.allow_miss = 1; } else if (!strcasecmp(token, "max-conn=")) { p->max_conn = atoi(token + 9); + } else if (!strcasecmp(token, "originserver")) { + p->options.originserver = 1; + } else if (!strncasecmp(token, "name=", 5)) { + safe_free(p->name); + if (token[5]) + p->name = xstrdup(token + 5); + } else if (!strncasecmp(token, "monitorurl=", 11)) { + safe_free(p->monitor.url); + if (token[11]) + p->monitor.url = xstrdup(token + 11); + } else if (!strncasecmp(token, "monitorsize=", 12)) { + p->monitor.min = atoi(token + 12); + p->monitor.max = -1; + if (strchr(token + 12, ',')) + token = strchr(token + 12, ','); + else + token = strchr(token + 12, '-'); + if (token) + p->monitor.max = atoi(token + 1); + } else if (!strncasecmp(token, "monitorinterval=", 16)) { + p->monitor.interval = atoi(token + 16); + } else if (!strncasecmp(token, "monitortimeout=", 15)) { + p->monitor.timeout = atoi(token + 15); + } else if (!strncasecmp(token, "forceddomain=", 13)) { + safe_free(p->domain); + if (token[13]) + p->domain = xstrdup(token + 13); } else { debug(3, 0) ("parse_peer: token='%s'\n", token); self_destruct(); } } + if (peerFindByName(p->name)) + fatalf("ERROR: cache_peer %s specified twice\n", p->name); if (p->weight < 1) p->weight = 1; p->icp.version = ICP_VERSION_CURRENT; @@ -2074,6 +2108,62 @@ storeAppendPrintf(entry, "\n"); } +static void +parse_errormap(errormap **head) +{ + errormap *m = xcalloc(1, sizeof(*m)); + char *url = strtok(NULL, w_space); + char *token; + struct error_map_entry **tail = &m->map; + if (!url) + self_destruct(); + m->url = xstrdup(url); + while ((token = strtok(NULL, w_space))) { + struct error_map_entry *e = xcalloc(1, sizeof (*e)); + e->value = xstrdup(token); + e->status = atoi(token); + if (!e->status) + e->status = -errorPageId(token); + if (!e->status) + debug(15, 0) ("WARNING: Unknown errormap code: %s\n", token); + *tail = e; + tail = &e->next; + } + while (*head) + head = &(*head)->next; + *head = m; +} + +static void +dump_errormap(StoreEntry * entry, const char *name, errormap * map) +{ + while(map) { + struct error_map_entry *me; + storeAppendPrintf(entry, "%s %s", + name, map->url); + for (me = map->map; me; me = me->next) + storeAppendPrintf(entry, " %s", me->value); + storeAppendPrintf(entry, "\n"); + map = map->next; + } +} + +static void +free_errormap(errormap **head) +{ + while (*head) { + errormap *map = *head; + *head = map->next; + while(map->map) { + struct error_map_entry *me = map->map; + map->map = me->next; + safe_free(me->value); + safe_free(me); + } + safe_free(map->url); + safe_free(map); + } +} #include "cf_parser.h" @@ -2094,6 +2184,10 @@ 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 + */ static void parse_sockaddr_in_list(sockaddr_in_list ** head) { @@ -2161,22 +2255,15 @@ { return NULL == s; } +#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; @@ -2189,16 +2276,146 @@ } else { self_destruct(); } - s = 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); + } 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; + } else if (strcmp(token, "vport") == 0) { + s->vport = ntohs(s->s.sin_port); + } else if (strncmp(token, "vport=", 6) == 0) { + s->vport = atoi(token + 6); + } else if (strncmp(token, "urlgroup=", 9) == 0) { + s->urlgroup = xstrdup(token + 9); + } else if (strncmp(token, "protocol=", 9) == 0) { + s->protocol = xstrdup(token + 9); + } 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(data); +} + + +static void +parse_http_port_list(http_port_list ** head) +{ + CBDATA_TYPE(http_port_list); + char *token; + http_port_list *s; + CBDATA_INIT_TYPE_FREECB(http_port_list, cbdataFree_http_port); + token = strtok(NULL, w_space); + if (!token) + self_destruct(); + s = cbdataAlloc(http_port_list); + s->protocol = xstrdup("http"); + parse_http_port_specification(s, 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); + } +} + +static int +check_null_http_port_list(const http_port_list * s) +{ + return NULL == s; +} + +#if USE_SSL +static void +cbdataFree_https_port(void *data) +{ + https_port_list *s = 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) { @@ -2208,11 +2425,11 @@ safe_free(s->key); s->key = xstrdup(token + 4); } else { - self_destruct(); + parse_http_port_option(&s->http, token); } } while (*head) - head = &(*head)->next; + head = (https_port_list **) (&(*head)->http.next); *head = s; } @@ -2220,13 +2437,13 @@ dump_https_port_list(StoreEntry * e, const char *n, const https_port_list * s) { while (s) { - storeAppendPrintf(e, "%s %s:%d cert=\"%s\" key=\"%s\"\n", - n, - inet_ntoa(s->s.sin_addr), - ntohs(s->s.sin_port), - s->cert, - s->key); - s = s->next; + dump_generic_http_port(e, n, &s->http); + if (s->cert) + storeAppendPrintf(e, " cert=\"%s\"", s->cert); + if (s->key) + storeAppendPrintf(e, " key=\"%s\"", s->key); + storeAppendPrintf(e, "\n"); + s = (https_port_list *) s->http.next; } } @@ -2235,10 +2452,8 @@ { 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); } } @@ -2255,7 +2470,6 @@ void configFreeMemory(void) { - safe_free(Config2.Accel.prefix); free_all(); } @@ -2267,3 +2481,4 @@ if (stat(path, &sb) < 0) fatalf("%s: %s", path, xstrerror()); } + Index: squid/src/cf.data.pre =================================================================== RCS file: /cvsroot/squid-sf//squid/src/cf.data.pre,v retrieving revision 1.32 retrieving revision 1.32.4.1 diff -u -r1.32 -r1.32.4.1 --- squid/src/cf.data.pre 22 Aug 2001 21:15:46 -0000 1.32 +++ squid/src/cf.data.pre 26 Aug 2001 20:02:40 -0000 1.32.4.1 @@ -1,6 +1,6 @@ # -# $Id: cf.data.pre,v 1.32 2001/08/22 21:15:46 squidadm Exp $ +# $Id: cf.data.pre,v 1.32.4.1 2001/08/26 20:02:40 hno Exp $ # # # SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -54,14 +54,14 @@ COMMENT_END NAME: http_port ascii_port -TYPE: sockaddr_in_list +TYPE: http_port_list DEFAULT: none DEFAULT_IF_NONE: 3128 LOC: Config.Sockaddr.http DOC_START - Usage: port - hostname:port - 1.2.3.4:port + Usage: port [options] + hostname:port [options] + 1.2.3.4:port [options] The socket addresses where Squid will listen for HTTP client requests. You may specify multiple socket addresses. @@ -82,6 +82,19 @@ address, however. You may specify multiple socket addresses on multiple lines. + + options are: + transparent Support for transparent proxies + vhost Accelerator using Host directive + vport Accelerator with IP virtual host support + vport= As above, but uses specified port number + rather than the http_port number. + defaultsite= Main web site name for accelerators. + urlgroup= Default urlgroup to mark requests + with (see also acl urlgroup and + url_rewrite_program) + protocol= Protocol to reconstruct accelerated + requests with. Defaults to http. DOC_END NAME: https_port @@ -90,7 +103,7 @@ DEFAULT: none LOC: Config.Sockaddr.https DOC_START - Usage: [ip:]port cert=certificate.pem [key=key.pem] + Usage: [ip:]port cert=certificate.pem [key=key.pem] [options] The socket address where Squid will listen for HTTPS client requests. @@ -103,7 +116,18 @@ combined certificate and key file. You may specify multiple socket addresses on multiple lines, - each with their own SSL certificate. + each with their own SSL certificate and/or options. + + Options: + defaultsite= The name of the https site presented + on this port. + urlgroup= Default urlgroup to mark requests + with (see also acl urlgroup and + url_rewrite_program) + protocol= Protocol to reconstruct accelerated + requests with. Defaults to https. + [the other options from http_port are also available + but does not make much sense for use in https_port] DOC_END NAME: ssl_version @@ -268,6 +292,16 @@ digest-url=url allow-miss max-conn + originserver + userhash + sourcehash + name=xxx + monitorurl=url + monitorsize=sizespec + monitorinterval=seconds + monitortimeout=seconds + group=name + forceddomain=name use 'proxy-only' to specify that objects fetched from this cache should not be saved locally. @@ -352,9 +386,45 @@ requests from peer by denying cache_peer_access if the source is a peer) + 'originserver' causes this parent peer to be contacted as + a origin server. Meant to be used in accelerator setups. + + use 'userhash' to load-balance amongs a set of parents + based on the client proxy_auth or ident username. + use 'max-conn' to limit the amount of connections Squid may open to this peer. + use 'sourcehash' to load-balanse amongs a set of parents + based on the client source ip. + + use 'name=xxx' if you have multiple peers on the same + host but different ports. This name can then be used to + differentiate the peers in cache_peer_access and similar + directives. + + use 'monitorurl=url' to have periodically request a given + URL from the peer, and only concider the peer as alive + if this monitoring is successful (default none) + + use 'monitorsize=min[-max]' to limit the size range of + 'monitorurl' replies considered valid. Defaults to 0 to + accept any size replies as valid. + + use 'monitorinterval=seconds' to change frequency of + how often the peer is monitored with 'monitorurl' + (default 300 for a 5 minute interval). If set to 0 + then monitoring is disabled even if a URL is defined. + + use 'monitortimeout=seconds' to change the timeout of + 'monitorurl'. Defaults to 'monitorinterval'. + + use 'forceddomain=name' to forcibly set the Host header + of requests forwarded to this peer. Useful in accelerator + setups where the server (peer) expects a certain domain + name and using redirectors to feed this domainname + is not feasible. + NOTE: non-ICP neighbors must be specified as 'parent'. DOC_END @@ -1154,22 +1224,36 @@ DOC_END -NAME: redirect_program +NAME: url_rewrite_program redirect_program TYPE: wordlist -LOC: Config.Program.redirect +LOC: Config.Program.url_rewrite.command DEFAULT: none DOC_START - Specify the location of the executable for the URL redirector. + Specify the location of the executable for the URL rewriter. Since they can perform almost any function there isn't one included. - See the FAQ (section 15) for information on how to write one. - By default, a redirector is not used. -DOC_END + For each requested URL rewriter will receive on line with the format + + URL client_ip "/" fqdn user method urlgroup -NAME: redirect_children + And the rewriter may return a rewritten URL. The other components of + the request line does not need to be returned (ignored if they are). + + The rewriter can also indicate that a client-side redirect should + be performed to the new URL. This is done by prefixing the returned + URL with "301:" (moved permanently) or 302: (moved temporarily). + + It can also return a "urlgroup" that can subsequently be matched + in cache_peer_access and similar ACL driven rules. An urlgroup is + returned by prefixing the returned url with "!urlgroup!" + + By default, a URL rewriter is not used. +DOC_END + +NAME: url_rewrite_children redirect_children TYPE: int DEFAULT: 5 -LOC: Config.redirectChildren +LOC: Config.Program.url_rewrite.children DOC_START The number of redirector processes to spawn. If you start too few Squid will have to wait for them to process a backlog of @@ -1177,26 +1261,70 @@ and other system resources. DOC_END -NAME: redirect_rewrites_host_header +NAME: url_rewrite_host_header redirect_rewrites_host_header TYPE: onoff DEFAULT: on LOC: Config.onoff.redir_rewrites_host DOC_START - By default Squid rewrites any Host: header in redirected + By default Squid rewrites any Host: header in rewritten requests. If you are running a accelerator then this may - not be a wanted effect of a redirector. + not be a wanted effect of your URL rewriting. + WARNING: Entries are cached on the result of the URL rewriting + process, so be careful if you have domain-virtual hosts. DOC_END -NAME: redirector_access +NAME: url_rewrite_access redirector_access TYPE: acl_access DEFAULT: none -LOC: Config.accessList.redirector +LOC: Config.accessList.url_rewrite DOC_START If defined, this access list specifies which requests are sent to the redirector processes. By default all requests are sent. DOC_END +NAME: location_rewrite_program +TYPE: wordlist +LOC: Config.Program.location_rewrite.command +DEFAULT: none +DOC_START + Specify the location of the executable for the Location rewriter, + used to rewrite server generated redirects. Usually used in + conjunction with a url_rewrite_program + + For each Location header received the location rewriter will receive + one line with the format: + + location URL requested URL urlgroup + + And the rewriter may return a rewritten URL. The other components of + the request line does not need to be returned (ignored if they are). + + By default, a Location rewriter is not used. +DOC_END + +NAME: location_rewrite_children +TYPE: int +DEFAULT: 5 +LOC: Config.Program.location_rewrite.children +DOC_START + The number of location rewriting processes to spawn. If you start + too few Squid will have to wait for them to process a backlog of + URLs, slowing it down. If you start too many they will use RAM + and other system resources. +DOC_END + +NAME: location_rewrite_access +TYPE: acl_access +DEFAULT: none +LOC: Config.accessList.location_rewrite +DOC_START + If defined, this access list specifies which requests are + sent to the location rewriting processes. By default all Location + headers are sent. +DOC_END + + NAME: auth_param TYPE: authparam LOC: Config.authConfig @@ -1406,6 +1534,57 @@ See also the acl max_user_ip. DOC_END +NAME: external_acl_ttl +TYPE: time_t +LOC: Config.externalAclTTL +DEFAULT: 1 hour +DOC_START + Time to cache external ACL lookups + + Can be specified multiple times, and applies to any following + external_acl_class specifications. +DOC_END + +NAME: external_acl_children +TYPE: int +DEFAULT: 5 +LOC: Config.externalAclChildren +DOC_START + The number of processes spawn to service external acl lookups. + + Can be specified multiple times, and applies to any following + external_acl_class specifications. +DOC_END + +NAME: external_acl_class +TYPE: externalAclHelper +LOC: Config.externalAclHelperList +DEFAULT: none +DOC_START + This option defines external acl classes using a helper program + to look up the status + + external_acl_class name [FORMAT..] /path/to/helper [helper arguments..] + + The helper receives lines per the FORMAT specification, and returns + OK or ERR indicating the validity of the request. + + FORMAT specifications + + %LOGIN Authenticated user login name + %IDENT Ident user name + %SRC Client IP + %DST Requested host + %PROTO Requested protocol + %PORT Requested port + %METHOD Request method + %{Header} HTTP request header + + In addition, any string specified in the referencing acl will also be + included in the helper request line, after the specified formats + +DOC_END + COMMENT_START OPTIONS FOR TUNING THE CACHE ----------------------------------------------------------------------------- @@ -1895,6 +2074,9 @@ # multiple address's if they are going through proxy farms, # so a limit of 1 may cause user problems. + acl acl_name external class_name [arguments...] + # external ACL lookup via a helper class defined by the + # external_acl_class directive. acl aclname req_mime_type mime-type1 ... # regex match agains the mime type of the request generated @@ -1911,6 +2093,8 @@ # effect in rules that affect the reply data stream such as # http_reply_access. + acl urlgroup group1 ... + # match against the urlgroup as indicated by redirectors Examples: acl myexample dst_as 1241 @@ -1979,6 +2163,17 @@ NOCOMMENT_END DOC_END +NAME: http_access2 +TYPE: acl_access +LOC: Config.accessList.http2 +DEFAULT: none +DOC_START + Allowing or Denying access based on defined access lists + + Identical to http_access, but runs after redirectors. If not set + then only http_access is used. +DOC_END + NAME: http_reply_access TYPE: acl_access LOC: Config.accessList.reply @@ -2269,88 +2464,6 @@ DOC_END COMMENT_START - HTTPD-ACCELERATOR OPTIONS - ----------------------------------------------------------------------------- -COMMENT_END - -NAME: httpd_accel_host -TYPE: string -LOC: Config.Accel.host -DEFAULT: none -DOC_NONE - -NAME: httpd_accel_port -TYPE: ushort -LOC: Config.Accel.port -DEFAULT: 80 -DOC_START - If you want to run Squid as an httpd accelerator, define the - host name and port number where the real HTTP server is. - - If you want virtual host support then specify the hostname - as "virtual". - - If you want virtual port support then specify the port as "0". - - NOTE: enabling httpd_accel_host disables proxy-caching and - ICP. If you want these features enabled also, then set - the 'httpd_accel_with_proxy' option. -DOC_END - -NAME: httpd_accel_single_host -COMMENT: on|off -TYPE: onoff -LOC: Config.Accel.single_host -DEFAULT: off -DOC_START - If you are running Squid as a accelerator and have a single backend - server then set this to on. This causes Squid to forward the request - to this server irregardles of what any redirectors or Host headers - says. - - Leave this at off if you have multiple backend servers, and use a - redirector (or host table or private DNS) to map the requests to the - appropriate backend servers. Note that the mapping needs to be a - 1-1 mapping between requested and backend (from redirector) domain - names or caching will fail, as cacing is performed using the - URL returned from the redirector. - - See also redirect_rewrites_host_header. -DOC_END - -NAME: httpd_accel_with_proxy -COMMENT: on|off -TYPE: onoff -DEFAULT: off -LOC: Config.onoff.accel_with_proxy -DOC_START - If you want to use Squid as both a local httpd accelerator - and as a proxy, change this to 'on'. Note however that your - proxy users may have trouble to reach the accelerated domains - unless their browsers are configured not to use this proxy for - those domains (for example via the no_proxy browser configuration - setting) -DOC_END - -NAME: httpd_accel_uses_host_header -COMMENT: on|off -TYPE: onoff -DEFAULT: off -LOC: opt_accel_uses_host -DOC_START - HTTP/1.1 requests include a Host: header which is basically the - hostname from the URL. Squid can be an accelerator for - different HTTP servers by looking at this header. However, - Squid does NOT check the value of the Host header, so it opens - a big security hole. We recommend that this option remain - disabled unless you are sure of what you are doing. - - However, you will need to enable this option if you run Squid - as a transparent proxy. Otherwise, virtual servers which - require the Host: header will not be properly cached. -DOC_END - -COMMENT_START MISCELLANEOUS ----------------------------------------------------------------------------- COMMENT_END @@ -2412,6 +2525,45 @@ the default buffer size. DOC_END +NAME: error_map +TYPE: errormap +LOC: Config.errorMapList +DEFAULT: none +DOC_START + Map errors to custom messages + + error_map message_url http_status ... + + http_status ... is a list of HTTP status codes or Squid error + messages. + + Use in accelerators to substitute the error messages returned + by servers with other custom errors. + + error_map http://your.server/error/404.shtml 404 + + Requests for error messages is a GET request for the configured + URL with the following special headers + + X-Error-Status: The received HTTP status code (i.e. 404) + X-Request-URI: The requested URI where the error occurred + + In Addition the following headers are forwarded from the client + request: + + User-Agent, Cookie, X-Forwarded-For, Via, Authorization, + Accept, Referer + + And the following headers from the server reply: + + Server, Via, Location, Content-Location + + The reply returned to the client will carry the original HTTP + headers from the real error message, but with the reply body + of the configured error message. + +DOC_END + NAME: err_html_text TYPE: eol LOC: Config.errHtmlText @@ -2427,7 +2579,6 @@ insert a %L tag in the error template file. DOC_END - NAME: deny_info TYPE: denyinfo LOC: Config.denyInfoList @@ -2487,6 +2638,16 @@ reduced memory thrashing in your malloc library. DOC_END +NAME: via +COMMENT: on|off +TYPE: onoff +DEFAULT: on +LOC: Config.onoff.via +DOC_START + If set (default), Squid will include a Via header in requests and + replies. +DOC_END + NAME: forwarded_for COMMENT: on|off TYPE: onoff @@ -2504,6 +2665,7 @@ X-Forwarded-For: unknown DOC_END + NAME: log_icp_queries COMMENT: on|off TYPE: onoff Index: squid/src/client_side.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/client_side.c,v retrieving revision 1.34 retrieving revision 1.34.4.1 diff -u -r1.34 -r1.34.4.1 --- squid/src/client_side.c 24 Aug 2001 15:43:57 -0000 1.34 +++ squid/src/client_side.c 26 Aug 2001 20:02:41 -0000 1.34.4.1 @@ -1,6 +1,6 @@ /* - * $Id: client_side.c,v 1.34 2001/08/24 15:43:57 squidadm Exp $ + * $Id: client_side.c,v 1.34.4.1 2001/08/26 20:02:41 hno Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Duane Wessels @@ -95,12 +95,12 @@ static void clientCheckNoCacheDone(int answer, void *data); static STCB clientHandleIMSReply; static int clientGetsOldEntry(StoreEntry * new, StoreEntry * old, request_t * request); -static int checkAccelOnly(clientHttpRequest *); #if USE_IDENT static IDCB clientIdentDone; #endif static int clientOnlyIfCached(clientHttpRequest * http); static STCB clientSendMoreData; +static STCB clientSendMoreHeaderData; static STCB clientCacheHit; static void clientSetKeepaliveFlag(clientHttpRequest *); static void clientPackRangeHdr(const HttpReply * rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb); @@ -117,22 +117,8 @@ static int clientReplyBodyTooLarge(HttpReply *, int clen); static int clientRequestBodyTooLarge(int clen); static void clientProcessBody(ConnStateData * conn); - -static int -checkAccelOnly(clientHttpRequest * http) -{ - /* return TRUE if someone makes a proxy request to us and - * we are in httpd-accel only mode */ - if (!Config2.Accel.on) - return 0; - if (Config.onoff.accel_with_proxy) - return 0; - if (http->request->protocol == PROTO_CACHEOBJ) - return 0; - if (http->flags.accel) - return 0; - return 1; -} +static void clientAccessCheckDone2(int answer, void *data); +static void clientAccessCheck2(void *data); #if USE_IDENT static void @@ -168,16 +154,22 @@ clientAccessCheck(void *data) { clientHttpRequest *http = data; - if (checkAccelOnly(http)) { - /* deny proxy requests in accel_only mode */ - debug(33, 1) ("clientAccessCheck: proxy request denied in accel_only mode\n"); - clientAccessCheckDone(ACCESS_DENIED, http); - return; - } http->acl_checklist = clientAclChecklistCreate(Config.accessList.http, http); aclNBCheck(http->acl_checklist, clientAccessCheckDone, http); } +static void +clientAccessCheck2(void *data) +{ + clientHttpRequest *http = data; + if (Config.accessList.http2 && !http->redirect.status) { + http->acl_checklist = clientAclChecklistCreate(Config.accessList.http2, http); + aclNBCheck(http->acl_checklist, clientAccessCheckDone2, http); + } else { + clientCheckNoCache(http); + } +} + /* * returns true if client specified that the object must come from the cache * without contacting origin server @@ -207,7 +199,7 @@ delaySetStoreClient(h->sc, delayClient(h)); #endif storeClientCopy(h->sc, e, 0, 0, CLIENT_SOCK_SZ, - memAllocate(MEM_CLIENT_SOCK_BUF), clientSendMoreData, h); + memAllocate(MEM_CLIENT_SOCK_BUF), clientSendMoreHeaderData, h); return e; } @@ -278,22 +270,97 @@ } static void +clientAccessCheckDone2(int answer, void *data) +{ + clientHttpRequest *http = data; + err_type page_id; + http_status status; + ErrorState *err = NULL; + char *proxy_auth_msg = NULL; + debug(33, 2) ("The request %s %s is %s, because it matched '%s'\n", + RequestMethodStr[http->request->method], http->uri, + answer == ACCESS_ALLOWED ? "ALLOWED" : "DENIED", + AclMatchedName ? AclMatchedName : "NO ACL's"); + proxy_auth_msg = authenticateAuthUserRequestMessage(http->conn->auth_user_request ? http->conn->auth_user_request : http->request->auth_user_request); + http->acl_checklist = NULL; + if (answer == ACCESS_ALLOWED) { + clientCheckNoCache(http); + } else { + debug(33, 5) ("Access Denied: %s\n", http->uri); + debug(33, 5) ("AclMatchedName = %s\n", + AclMatchedName ? AclMatchedName : ""); + debug(33, 5) ("Proxy Auth Message = %s\n", + proxy_auth_msg ? proxy_auth_msg : ""); + /* + * NOTE: get page_id here, based on AclMatchedName because + * if USE_DELAY_POOLS is enabled, then AclMatchedName gets + * clobbered in the clientCreateStoreEntry() call + * just below. Pedro Ribeiro + */ + page_id = aclGetDenyInfoPage(&Config.denyInfoList, AclMatchedName); + http->log_type = LOG_TCP_DENIED; + http->entry = clientCreateStoreEntry(http, http->request->method, + null_request_flags); + if (answer == ACCESS_REQ_PROXY_AUTH || aclIsProxyAuth(AclMatchedName)) { + if (!http->flags.accel) { + /* Proxy authorisation needed */ + status = HTTP_PROXY_AUTHENTICATION_REQUIRED; + } else { + /* WWW authorisation needed */ + status = HTTP_UNAUTHORIZED; + } + if (page_id == ERR_NONE) + page_id = ERR_CACHE_ACCESS_DENIED; + } else { + status = HTTP_FORBIDDEN; + if (page_id == ERR_NONE) + page_id = ERR_ACCESS_DENIED; + } + err = errorCon(page_id, status); + err->request = requestLink(http->request); + err->src_addr = http->conn->peer.sin_addr; + if (http->conn->auth_user_request) + err->auth_user_request = http->conn->auth_user_request; + else if (http->request->auth_user_request) + err->auth_user_request = http->request->auth_user_request; + /* lock for the error state */ + if (err->auth_user_request) + authenticateAuthUserRequestLock(err->auth_user_request); + err->callback_data = NULL; + errorAppendEntry(http->entry, err); + } +} + +static void clientRedirectDone(void *data, char *result) { clientHttpRequest *http = data; request_t *new_request = NULL; request_t *old_request = http->request; + const char *urlgroup = http->conn->port->urlgroup; debug(33, 5) ("clientRedirectDone: '%s' result=%s\n", http->uri, result ? result : "NULL"); assert(http->redirect_state == REDIRECT_PENDING); http->redirect_state = REDIRECT_DONE; if (result) { - http_status status = (http_status) atoi(result); + http_status status; + if (*result == '!') { + char *t; + if ((t = strchr(result + 1, '!')) != NULL) { + urlgroup = result + 1; + *t++ = '\0'; + result = t; + } else { + debug(33, 1) ("clientRedirectDone: bad input: %s\n", result); + } + } + status = (http_status) atoi(result); if (status == HTTP_MOVED_PERMANENTLY || status == HTTP_MOVED_TEMPORARILY) { - char *t = result; + char *t; if ((t = strchr(result, ':')) != NULL) { http->redirect.status = status; http->redirect.location = xstrdup(t + 1); + /* urlParse below will fail, setting new_request to NULL... */ } else { debug(33, 1) ("clientRedirectDone: bad input: %s\n", result); } @@ -309,6 +376,7 @@ new_request->client_addr = old_request->client_addr; new_request->my_addr = old_request->my_addr; new_request->my_port = old_request->my_port; + memcpy(&new_request->flags, &old_request->flags, sizeof(new_request->flags)); new_request->flags.redirected = 1; if (old_request->auth_user_request) { new_request->auth_user_request = old_request->auth_user_request; @@ -319,16 +387,22 @@ old_request->body_connection = NULL; } new_request->content_length = old_request->content_length; - new_request->flags.proxy_keepalive = old_request->flags.proxy_keepalive; - requestUnlink(old_request); + http->orig_request = old_request; http->request = requestLink(new_request); - } + } else { + /* Don't mess with urlgroup on internal request */ + if (old_request->flags.internal) + urlgroup = NULL; + } + safe_free(http->request->urlgroup); /* only paranoia. should not happen */ + if (urlgroup && *urlgroup) + http->request->urlgroup = xstrdup(urlgroup); clientInterpretRequestHeaders(http); #if HEADERS_LOG headersLog(0, 1, request->method, request); #endif fd_note(http->conn->fd, http->uri); - clientCheckNoCache(http); + clientAccessCheck2(http); } static void @@ -542,10 +616,10 @@ http->out.offset, CLIENT_SOCK_SZ, buf, - clientSendMoreData, + clientSendMoreHeaderData, http); } else { - clientSendMoreData(data, buf, size); + clientSendMoreHeaderData(data, buf, size); } } @@ -832,6 +906,9 @@ storeUnlockObject(e); } requestUnlink(http->request); + http->request = NULL; + requestUnlink(http->orig_request); + http->orig_request = NULL; assert(http != http->next); assert(http->conn->chr != NULL); /* Unlink us from the clients request list */ @@ -1350,6 +1427,18 @@ debug(33, 3) ("clientBuildReplyHeader: can't keep-alive, unknown body size\n"); request->flags.proxy_keepalive = 0; } + /* Append Via */ + { + LOCAL_ARRAY(char, bbuf, MAX_URL+32); + String strVia = httpHeaderGetList(hdr, HDR_VIA); + snprintf(bbuf, sizeof(bbuf), "%d.%d %s", + rep->sline.version.major, + rep->sline.version.minor, ThisCache); + strListAdd(&strVia, bbuf, ','); + httpHeaderDelById(hdr, HDR_VIA); + httpHeaderPutStr(hdr, HDR_VIA, strBuf(strVia)); + stringClean(&strVia); + } /* Signal keep-alive if needed */ httpHeaderPutStr(hdr, http->flags.accel ? HDR_CONNECTION : HDR_PROXY_CONNECTION, @@ -1498,7 +1587,7 @@ } if (checkNegativeHit(e)) { http->log_type = LOG_TCP_NEGATIVE_HIT; - clientSendMoreData(data, buf, size); + clientSendMoreHeaderData(data, buf, size); } else if (r->method == METHOD_HEAD) { /* * RFC 2068 seems to indicate there is no "conditional HEAD" @@ -1507,7 +1596,7 @@ */ if (e->mem_status == IN_MEMORY) http->log_type = LOG_TCP_MEM_HIT; - clientSendMoreData(data, buf, size); + clientSendMoreHeaderData(data, buf, size); } else if (refreshCheckHTTP(e, r) && !http->flags.internal) { debug(33, 5) ("clientCacheHit: in refreshCheck() block\n"); /* @@ -1563,7 +1652,7 @@ clientProcessMiss(http); } else if (modifiedSince(e, http->request)) { http->log_type = LOG_TCP_IMS_HIT; - clientSendMoreData(data, buf, size); + clientSendMoreHeaderData(data, buf, size); } else { time_t timestamp = e->timestamp; MemBuf mb = httpPacked304Reply(e->mem_obj->reply); @@ -1592,7 +1681,7 @@ http->log_type = LOG_TCP_MEM_HIT; else if (Config.onoff.offline) http->log_type = LOG_TCP_OFFLINE_HIT; - clientSendMoreData(data, buf, size); + clientSendMoreHeaderData(data, buf, size); } } @@ -1810,14 +1899,34 @@ } } +typedef struct { + clientHttpRequest *http; + char *buf; + ssize_t size; + const char *body_buf; + ssize_t body_size; + HttpReply *rep; +} clientCheckHeaderStateData; + +CBDATA_TYPE(clientCheckHeaderStateData); + +static void clientHttpLocationRewriteCheck(clientCheckHeaderStateData * state); +static void clientHttpLocationRewriteCheckDone(int answer, void *data); +static void clientHttpLocationRewrite(clientCheckHeaderStateData * state); +static void clientHttpLocationRewriteDone(void *data, char *reply); +static void clientHttpReplyAccessCheck(clientCheckHeaderStateData * state); +static void clientHttpReplyAccessCheckDone(int answer, void *data); +static void clientCheckErrorMap(clientCheckHeaderStateData * state); +static void clientCheckHeaderDone(clientCheckHeaderStateData * state); /* * accepts chunk of a http message in buf, parses prefix, filters headers and * such, writes processed message to the client's socket */ static void -clientSendMoreData(void *data, char *buf, ssize_t size) +clientSendMoreHeaderData(void *data, char *buf, ssize_t size) { + clientCheckHeaderStateData *state; clientHttpRequest *http = data; StoreEntry *entry = http->entry; ConnStateData *conn = http->conn; @@ -1825,18 +1934,16 @@ HttpReply *rep = NULL; const char *body_buf = buf; ssize_t body_size = size; - MemBuf mb; - ssize_t check_size = 0; - debug(33, 5) ("clientSendMoreData: %s, %d bytes\n", http->uri, (int) size); + debug(33, 5) ("clientSendMoreHeaderData: %s, %d bytes\n", http->uri, (int) size); assert(size <= CLIENT_SOCK_SZ); assert(http->request != NULL); dlinkDelete(&http->active, &ClientActiveRequests); dlinkAdd(http, &http->active, &ClientActiveRequests); - debug(33, 5) ("clientSendMoreData: FD %d '%s', out.offset=%d \n", + debug(33, 5) ("clientSendMoreHeaderData: FD %d '%s', out.offset=%d \n", fd, storeUrl(entry), (int) http->out.offset); if (conn->chr != http) { /* there is another object in progress, defer this one */ - debug(33, 1) ("clientSendMoreData: Deferring %s\n", storeUrl(entry)); + debug(33, 1) ("clientSendMoreHeaderData: Deferring %s\n", storeUrl(entry)); memFree(buf, MEM_CLIENT_SOCK_BUF); return; } else if (entry && EBIT_TEST(entry->flags, ENTRY_ABORTED)) { @@ -1855,7 +1962,7 @@ memFree(buf, MEM_CLIENT_SOCK_BUF); return; } - if (http->out.offset == 0) { + assert(http->out.offset == 0); if (Config.onoff.log_mime_hdrs) { size_t k; if ((k = headersEnd(buf, size))) { @@ -1865,9 +1972,25 @@ } } rep = clientBuildReply(http, buf, size); - if (rep) { - aclCheck_t *ch; - int rv; + if (!rep) { + if (size < CLIENT_SOCK_SZ && entry->store_status == STORE_PENDING) { + /* wait for more to arrive */ + storeClientCopy(http->sc, entry, + http->out.offset + size, + http->out.offset, + CLIENT_SOCK_SZ, + buf, + clientSendMoreHeaderData, + http); + return; + } else { + debug(33, 1) ("clientSendMoreHeaderData: %s could not find end of header\n", http->uri); + /* call clientWriteComplete so the client socket gets closed */ + clientWriteComplete(fd, NULL, 0, COMM_OK, http); + memFree(buf, MEM_CLIENT_SOCK_BUF); + return; + } + } httpReplyBodyBuildSize(http->request, rep, &Config.ReplyBodySize); if (clientReplyBodyTooLarge(rep, rep->content_length)) { ErrorState *err = errorCon(ERR_TOO_BIG, HTTP_FORBIDDEN); @@ -1882,19 +2005,158 @@ return; } body_size = size - rep->hdr_sz; - assert(body_size >= 0); body_buf = buf + rep->hdr_sz; + assert(body_size >= 0); http->range_iter.prefix_size = rep->hdr_sz; - debug(33, 3) ("clientSendMoreData: Appending %d bytes after %d bytes of headers\n", + debug(33, 3) ("clientSendMoreHeaderData: Appending %d bytes after %d bytes of headers\n", body_size, rep->hdr_sz); - ch = aclChecklistCreate(Config.accessList.reply, http->request, NULL); - ch->reply = rep; - rv = aclCheckFast(Config.accessList.reply, ch); + CBDATA_INIT_TYPE(clientCheckHeaderStateData); + state = cbdataAlloc(clientCheckHeaderStateData); + state->http = http; + cbdataLock(http); + state->rep = rep; + state->buf = buf; + state->size = size; + state->body_buf = body_buf; + state->body_size = body_size; + clientHttpLocationRewriteCheck(state); +} + +static void +clientHttpLocationRewriteCheck(clientCheckHeaderStateData * state) +{ + HttpReply *rep = state->rep; + aclCheck_t *ch; + if (!cbdataValid(state->http)) { + /* oops.. */ + clientCheckHeaderDone(state); + return; + } + if (!Config.Program.location_rewrite.command || !httpHeaderHas(&rep->header, HDR_LOCATION)) { + clientHttpLocationRewriteDone(state, NULL); + return; + } + if (Config.accessList.location_rewrite) { + ch = clientAclChecklistCreate(Config.accessList.location_rewrite, state->http); + ch->reply = state->rep; + aclNBCheck(ch, clientHttpLocationRewriteCheckDone, state); + } else { + clientHttpLocationRewriteCheckDone(ACCESS_ALLOWED, state); + } +} + +static void +clientHttpLocationRewriteCheckDone(int answer, void *data) +{ + clientCheckHeaderStateData *state = data; + if (!cbdataValid(state->http)) { + /* oops.. */ + clientCheckHeaderDone(state); + return; + } + if (answer == ACCESS_ALLOWED) { + clientHttpLocationRewrite(state); + } else { + clientHttpLocationRewriteDone(state, NULL); + } +} + +static void +clientHttpLocationRewrite(clientCheckHeaderStateData * state) +{ + HttpReply *rep = state->rep; + if (!cbdataValid(state->http)) { + /* oops.. */ + clientCheckHeaderDone(state); + return; + } + if (!httpHeaderHas(&rep->header, HDR_LOCATION)) + clientHttpLocationRewriteDone(state, NULL); + else + locationRewriteStart(rep, state->http, clientHttpLocationRewriteDone, state); +} + +static void +clientHttpLocationRewriteDone(void *data, char *reply) +{ + clientCheckHeaderStateData *state = data; + clientHttpRequest *http = state->http; + HttpReply *rep = state->rep; + ConnStateData *conn = http->conn; + if (!cbdataValid(http)) { + /* oops.. */ + clientCheckHeaderDone(state); + return; + } + if (reply && *reply) { + httpHeaderDelById(&rep->header, HDR_LOCATION); + if (*reply == '/') { + /* We have to restore the URL as sent by the client */ + request_t *req = http->orig_request ? http->orig_request : http->request; + const char *proto = conn->port->protocol; + const char *host = httpHeaderGetStr(&req->header, HDR_HOST); + int url_sz; + char *url; + if (!host) + host = req->host; + url_sz = strlen(proto) + 3 + strlen(host) + strlen(reply) + 1; + url = xcalloc(1, url_sz); + snprintf(url, url_sz, "%s://%s%s", proto, host, reply); + httpHeaderPutStrf(&rep->header, HDR_LOCATION, url); + safe_free(url); + } else { + httpHeaderPutStrf(&rep->header, HDR_LOCATION, reply); + } + } + clientHttpReplyAccessCheck(state); +} + +static void +clientHttpReplyAccessCheck(clientCheckHeaderStateData * state) +{ + aclCheck_t *ch; + if (!cbdataValid(state->http)) { + /* oops.. */ + clientCheckHeaderDone(state); + return; + } + if (Config.accessList.reply) { + ch = clientAclChecklistCreate(Config.accessList.reply, state->http); + ch->reply = state->rep; + aclNBCheck(ch, clientHttpReplyAccessCheckDone, state); + } else { + clientHttpReplyAccessCheckDone(ACCESS_ALLOWED, state); + } +} + +/* Handle error mapping. + * + * 1. Look up if there is a error map for the request + * 2. Start requesting the error URL + * 3. When headers are received, create a new reply structure and copy + * over the relevant headers (start with the headers from the original + * reply, and copy over Content-Length) + * 4. Make the new reply the current one + * 5. Detatch from the previous reply + * 6. Go to clientCheckHeaderDone, as if nothing had happened, but now + * fetching from the new reply. + */ +static void +clientHttpReplyAccessCheckDone(int answer, void *data) +{ + clientCheckHeaderStateData *state = data; + clientHttpRequest *http = state->http; + HttpReply *rep = state->rep; + if (!cbdataValid(state->http)) { + /* oops.. */ + clientCheckHeaderDone(state); + return; + } debug(33, 2) ("The reply for %s %s is %s, because it matched '%s'\n", RequestMethodStr[http->request->method], http->uri, - rv ? "ALLOWED" : "DENIED", + answer ? "ALLOWED" : "DENIED", AclMatchedName ? AclMatchedName : "NO ACL's"); - if (!rv && rep->sline.status != HTTP_FORBIDDEN + if (answer != ACCESS_ALLOWED && rep->sline.status != HTTP_FORBIDDEN && !clientAlwaysAllowResponse(rep->sline.status)) { /* the if above is slightly broken, but there is no way * to tell if this is a squid generated error page, or one from @@ -1911,34 +2173,156 @@ httpReplyDestroy(rep); return; } - aclChecklistFree(ch); - } else if (size < CLIENT_SOCK_SZ && entry->store_status == STORE_PENDING) { - /* wait for more to arrive */ - storeClientCopy(http->sc, entry, - http->out.offset + size, - http->out.offset, - CLIENT_SOCK_SZ, - buf, - clientSendMoreData, - http); + clientCheckErrorMap(state); +} + +static void +clientCheckErrorMapDone(StoreEntry *e, int body_offset, ssize_t content_length, void *data) +{ + clientCheckHeaderStateData * state = data; + if (!cbdataValid(state->http)) { + /* oops.. */ + clientCheckHeaderDone(state); return; } + if (e) { + clientHttpRequest *http = state->http; + /* Get rid of the old request entry */ + storeUnregister(http->sc, http->entry, http); + storeUnlockObject(http->entry); + /* Attach ourselves to the new request entry */ + http->entry = e; + storeLockObject(e); + http->sc = storeClientListAdd(http->entry, http); + /* Adjust the header size */ + state->rep->hdr_sz = body_offset; + /* Clean up any old body content */ + httpBodyClean(&state->rep->body); + state->body_buf = NULL; + state->body_size = 0; + /* And finally, adjust content-length to the new value */ + httpHeaderDelById(&state->rep->header, HDR_CONTENT_LENGTH); + if (content_length >= 0) { + httpHeaderPutInt(&state->rep->header, HDR_CONTENT_LENGTH, content_length); + } + } + clientCheckHeaderDone(state); +} +static void +clientCheckErrorMap(clientCheckHeaderStateData * state) +{ + clientHttpRequest *http = state->http; + HttpReply *rep = state->rep; + if (!cbdataValid(http)) { + /* oops.. */ + clientCheckHeaderDone(state); + return; + } + if (rep->sline.status < 100 || rep->sline.status >= 400) { + request_t *request = http->orig_request ? http->orig_request : http->request; + if (errorMapStart(Config.errorMapList, request, rep, NULL, clientCheckErrorMapDone, state)) + return; + } + clientCheckHeaderDone(state); +} + +static void +clientCheckHeaderDone(clientCheckHeaderStateData * state) +{ + char *buf = state->buf; + const char *body_buf = state->body_buf; + ssize_t body_size = state->body_size; + HttpReply *rep = state->rep; + clientHttpRequest *http = state->http; + MemBuf mb; + cbdataFree(state); + if (!cbdataValid(http)) + goto aborted; /* reset range iterator */ http->range_iter.pos = HttpHdrRangeInitPos; - } else if (!http->request->range) { - /* Avoid copying to MemBuf for non-range requests */ - /* Note, if we're here, then 'rep' is known to be NULL */ + if (http->request->method == METHOD_HEAD) { + /* do not forward body for HEAD replies */ + body_size = 0; + http->flags.done_copying = 1; + } + /* init mb; put status line and headers */ + mb = httpReplyPack(rep); + http->out.offset += rep->hdr_sz; +#if HEADERS_LOG + headersLog(0, 0, http->request->method, rep); +#endif + httpReplyDestroy(rep); + rep = NULL; + /* append body if any */ + if (http->request->range) { + /* Only GET requests should have ranges */ + assert(http->request->method == METHOD_GET); + /* clientPackMoreRanges() updates http->out.offset */ + /* force the end of the transfer if we are done */ + if (!clientPackMoreRanges(http, body_buf, body_size, &mb)) + http->flags.done_copying = 1; + } else if (body_buf && body_size) { http->out.offset += body_size; + memBufAppend(&mb, body_buf, body_size); + } + /* write */ + comm_write_mbuf(http->conn->fd, mb, clientWriteComplete, http); + /* clean up */ + aborted: + memFree(buf, MEM_CLIENT_SOCK_BUF); + cbdataUnlock(http); + http = NULL; +} + + +/* + * accepts chunk of a http message in buf, parses prefix, filters headers and + * such, writes processed message to the client's socket + */ +static void +clientSendMoreData(void *data, char *buf, ssize_t size) +{ + clientHttpRequest *http = data; + StoreEntry *entry = http->entry; + ConnStateData *conn = http->conn; + int fd = conn->fd; + MemBuf mb; + debug(33, 5) ("clientSendMoreData: %s, %d bytes\n", http->uri, (int) size); + assert(size <= CLIENT_SOCK_SZ); + assert(http->request != NULL); + dlinkDelete(&http->active, &ClientActiveRequests); + dlinkAdd(http, &http->active, &ClientActiveRequests); + debug(33, 5) ("clientSendMoreData: FD %d '%s', out.offset=%d \n", + fd, storeUrl(entry), (int) http->out.offset); + if (conn->chr != http) { + /* there is another object in progress, defer this one */ + debug(33, 1) ("clientSendMoreData: Deferring %s\n", storeUrl(entry)); + memFree(buf, MEM_CLIENT_SOCK_BUF); + return; + } else if (entry && EBIT_TEST(entry->flags, ENTRY_ABORTED)) { + /* call clientWriteComplete so the client socket gets closed */ + clientWriteComplete(fd, NULL, 0, COMM_OK, http); + memFree(buf, MEM_CLIENT_SOCK_BUF); + return; + } else if (size < 0) { + /* call clientWriteComplete so the client socket gets closed */ + clientWriteComplete(fd, NULL, 0, COMM_OK, http); + memFree(buf, MEM_CLIENT_SOCK_BUF); + return; + } else if (size == 0) { + /* call clientWriteComplete so the client socket gets closed */ + clientWriteComplete(fd, NULL, 0, COMM_OK, http); + memFree(buf, MEM_CLIENT_SOCK_BUF); + return; + } + if (!http->request->range) { + /* Avoid copying to MemBuf for non-range requests */ + http->out.offset += size; comm_write(fd, buf, size, clientWriteBodyComplete, http, NULL); /* NULL because clientWriteBodyComplete frees it */ return; } if (http->request->method == METHOD_HEAD) { - if (rep) { - /* do not forward body for HEAD replies */ - body_size = 0; - http->flags.done_copying = 1; - } else { /* * If we are here, then store_status == STORE_OK and it * seems we have a HEAD repsponse which is missing the @@ -1949,37 +2333,19 @@ */ http->flags.done_copying = 1; } - } - /* write headers and/or body if any */ - assert(rep || (body_buf && body_size)); /* init mb; put status line and headers if any */ - if (rep) { - mb = httpReplyPack(rep); - http->out.offset += rep->hdr_sz; - check_size += rep->hdr_sz; -#if HEADERS_LOG - headersLog(0, 0, http->request->method, rep); -#endif - httpReplyDestroy(rep); - rep = NULL; - } else { memBufDefInit(&mb); - } - /* append body if any */ if (http->request->range) { /* Only GET requests should have ranges */ assert(http->request->method == METHOD_GET); /* clientPackMoreRanges() updates http->out.offset */ /* force the end of the transfer if we are done */ - if (!clientPackMoreRanges(http, body_buf, body_size, &mb)) + if (!clientPackMoreRanges(http, buf, size, &mb)) http->flags.done_copying = 1; - } else if (body_buf && body_size) { - http->out.offset += body_size; - check_size += body_size; - memBufAppend(&mb, body_buf, body_size); + } else { + http->out.offset += size; + memBufAppend(&mb, buf, size); } - if (!http->request->range && http->request->method == METHOD_GET) - assert(check_size == size); /* write */ comm_write_mbuf(fd, mb, clientWriteComplete, http); /* if we don't do it, who will? */ @@ -2050,7 +2416,7 @@ http->out.offset, CLIENT_SOCK_SZ, memAllocate(MEM_CLIENT_SOCK_BUF), - clientSendMoreData, + clientSendMoreHeaderData, http); } } @@ -2425,15 +2791,6 @@ size_t req_sz; method_t method; clientHttpRequest *http = NULL; -#if IPF_TRANSPARENT - struct natlookup natLookup; - static int natfd = -1; - static int siocgnatl_cmd = SIOCGNATL & 0xff; - int x; -#endif -#if LINUX_NETFILTER - size_t sock_sz = sizeof(conn->me); -#endif if ((req_sz = headersEnd(conn->in.buf, conn->in.offset)) == 0) { debug(33, 5) ("Incomplete request, waiting for end of headers\n"); @@ -2544,123 +2901,53 @@ *t = '\0'; /* handle internal objects */ + if (*url == '/') { + int vhost = conn->port->vhost || conn->port->transparent; + int vport = conn->port->vport || conn->port->transparent; if (internalCheck(url)) { /* prepend our name & port */ http->uri = xstrdup(internalLocalUri(NULL, url)); http->flags.internal = 1; http->flags.accel = 1; - } - /* see if we running in Config2.Accel.on, if so got to convert it to URL */ - else if (Config2.Accel.on && *url == '/') { - /* prepend the accel prefix */ - if (opt_accel_uses_host && (t = mime_get_header(req_hdr, "Host"))) { - int vport; - char *q; - 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); - } + debug(33, 5) ("INTERNAL REWRITE: '%s'\n", http->uri); + } else if (vhost && (t = mime_get_header(req_hdr, "Host"))) { url_sz = strlen(url) + 32 + Config.appendDomainLen + strlen(t); http->uri = xcalloc(url_sz, 1); - -#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); - } -#endif - 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; + snprintf(http->uri, url_sz, "%s://%s%s", + conn->port->protocol, t, url); + debug(33, 5) ("VHOST REWRITE: '%s'\n", http->uri); + } else if (conn->port->defaultsite) { + url_sz = strlen(url) + 32 + Config.appendDomainLen + + strlen(conn->port->defaultsite); http->uri = xcalloc(url_sz, 1); - if (vport_mode) - vport = (int) ntohs(http->conn->me.sin_port); - else - vport = (int) Config.Accel.port; -#if IPF_TRANSPARENT - natLookup.nl_inport = http->conn->me.sin_port; - natLookup.nl_outport = http->conn->peer.sin_port; - natLookup.nl_inip = http->conn->me.sin_addr; - natLookup.nl_outip = http->conn->peer.sin_addr; - natLookup.nl_flags = IPN_TCP; - if (natfd < 0) - natfd = open(IPL_NAT, O_RDONLY, 0); - if (natfd < 0) { - debug(50, 1) ("parseHttpRequest: NAT open failed: %s\n", - xstrerror()); - return parseHttpRequestAbort(conn, "error:nat-open-failed"); - } - /* - * 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 - * put something in configure and use ifdefs here, but - * this seems simpler. + snprintf(http->uri, url_sz, "%s://%s%s", + conn->port->protocol, conn->port->defaultsite, url); + debug(33, 5) ("DEFAULTSITE REWRITE: '%s'\n", http->uri); + } else if (vport) { + /* Put the local socket IP address as the hostname. + * Note: In transparent mode clientNatLookup() has replaced + * the local socket IP with the real destination */ - if (63 == siocgnatl_cmd) { - struct natlookup *nlp = &natLookup; - x = ioctl(natfd, SIOCGNATL, &nlp); - } else { - x = ioctl(natfd, SIOCGNATL, &natLookup); - } - if (x < 0) { - if (errno != ESRCH) { - debug(50, 1) ("parseHttpRequest: NAT lookup failed: ioctl(SIOCGNATL)\n"); - close(natfd); - natfd = -1; - return parseHttpRequestAbort(conn, "error:nat-lookup-failed"); - } else - snprintf(http->uri, url_sz, "http://%s:%d%s", - inet_ntoa(http->conn->me.sin_addr), - vport, url); - } else { - if (vport_mode) - vport = natLookup.nl_realport; - snprintf(http->uri, url_sz, "http://%s:%d%s", - inet_ntoa(natLookup.nl_realip), - vport, url); - } -#else -#if LINUX_NETFILTER - /* If the call fails the address structure will be unchanged */ - getsockopt(conn->fd, SOL_IP, SO_ORIGINAL_DST, &conn->me, &sock_sz); - debug(33, 5) ("parseHttpRequest: addr = %s", inet_ntoa(conn->me.sin_addr)); - if (vport_mode) - vport = (int) ntohs(http->conn->me.sin_port); -#endif - snprintf(http->uri, url_sz, "http://%s:%d%s", + url_sz = strlen(url) + 32 + Config.appendDomainLen; + http->uri = xcalloc(url_sz, 1); + snprintf(http->uri, url_sz, "%s://%s:%d%s", + http->conn->port->protocol, inet_ntoa(http->conn->me.sin_addr), - vport, url); -#endif - debug(33, 5) ("VHOST REWRITE: '%s'\n", http->uri); + ntohs(http->conn->me.sin_port), url); + debug(33, 5) ("VPORT REWRITE: '%s'\n", http->uri); } else { - url_sz = strlen(Config2.Accel.prefix) + strlen(url) + + /* Use our own name */ + const char *host = getMyHostname(); + int port = ntohs(http->conn->me.sin_port); + url_sz = strlen(host) + 32 + strlen(url) + Config.appendDomainLen + 1; http->uri = xcalloc(url_sz, 1); - snprintf(http->uri, url_sz, "%s%s", Config2.Accel.prefix, url); + snprintf(http->uri, url_sz, "http://%s:%d%s", host, port, url); } http->flags.accel = 1; } else { + /* Proxy request */ /* URL may be rewritten later, so make extra room */ url_sz = strlen(url) + Config.appendDomainLen + 5; http->uri = xcalloc(url_sz, 1); @@ -3011,8 +3298,10 @@ request->flags.body_sent = 1; /* Invoke callback function */ callback(buf, size, cbdata); - if (request != NULL) + if (request != NULL) { requestUnlink(request); /* Linked in clientReadBody */ + conn->body.request = NULL; + } debug(33, 2) ("clientProcessBody: end fd=%d size=%d body_size=%d in.offset=%d cb=%p req=%p\n", conn->fd, size, conn->body.size_left, conn->in.offset, callback, request); } } @@ -3140,10 +3429,73 @@ return 1; } +#if IPF_TRANSPARENT +static void +clientNatLookup(ConnStateData * conn) +{ + struct natlookup natLookup; + static int natfd = -1; + static int siocgnatl_cmd = SIOCGNATL & 0xff; + int x; + + natLookup.nl_inport = conn->me.sin_port; + natLookup.nl_outport = conn->peer.sin_port; + natLookup.nl_inip = conn->me.sin_addr; + natLookup.nl_outip = conn->peer.sin_addr; + natLookup.nl_flags = IPN_TCP; + if (natfd < 0) + natfd = open(IPL_NAT, O_RDONLY, 0); + if (natfd < 0) { + debug(50, 1) ("parseHttpRequest: NAT open failed: %s\n", + xstrerror()); + return parseHttpRequestAbort(conn, "error:nat-open-failed"); + } + /* + * 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 + * put something in configure and use ifdefs here, but + * this seems simpler. + */ + if (63 == siocgnatl_cmd) { + struct natlookup *nlp = &natLookup; + x = ioctl(natfd, SIOCGNATL, &nlp); + } else { + x = ioctl(natfd, SIOCGNATL, &natLookup); + } + if (x < 0) { + if (errno != ESRCH) { + debug(50, 1) ("parseHttpRequest: NAT lookup failed: ioctl(SIOCGNATL)\n"); + close(natfd); + natfd = -1; + } + } else { + conn->me.sin_port = natLookup.nl_realport; + conn->me.sin_addr = natLookup.nl_realip; + } +} +#elsif LINUX_NETFILTER +static void +clientNatLookup(ConnStateData * conn) +{ + size_t sock_sz = sizeof(conn->me); + /* If the call fails the address structure will be unchanged */ + getsockopt(conn->fd, SOL_IP, SO_ORIGINAL_DST, &conn->me, &sock_sz); + debug(33, 5) ("parseHttpRequest: addr = %s", inet_ntoa(conn->me.sin_addr)); +} +#else +static void inline +clientNatLookup(ConnStateData * conn) +{ +} + +#endif + /* Handle a new connection on HTTP socket. */ void httpAccept(int sock, void *data) { + http_port_list *s = data; int *N = &incoming_sockets_accepted; int fd = -1; ConnStateData *connState = NULL; @@ -3153,7 +3505,7 @@ #if USE_IDENT static aclCheck_t identChecklist; #endif - commSetSelect(sock, COMM_SELECT_READ, httpAccept, NULL, 0); + commSetSelect(sock, COMM_SELECT_READ, httpAccept, data, 0); while (max-- && !httpAcceptDefer(sock, NULL)) { memset(&peer, '\0', sizeof(struct sockaddr_in)); memset(&me, '\0', sizeof(struct sockaddr_in)); @@ -3165,6 +3517,8 @@ } debug(33, 4) ("httpAccept: FD %d: accepted\n", fd); connState = cbdataAlloc(ConnStateData); + connState->port = s; + cbdataLock(connState->port); connState->peer = peer; connState->log_addr = peer.sin_addr; connState->log_addr.s_addr &= Config.Addrs.client_netmask.s_addr; @@ -3172,7 +3526,8 @@ connState->fd = fd; connState->in.size = CLIENT_REQ_BUF_SZ; connState->in.buf = memAllocate(MEM_CLIENT_REQ_BUF); - /* XXX account connState->in.buf */ + if (connState->port->transparent) + clientNatLookup(connState); comm_add_close_handler(fd, connStateFree, connState); if (Config.onoff.log_fqdn) fqdncache_gethostbyaddr(peer.sin_addr, FQDN_LOOKUP_IF_MISS); @@ -3232,19 +3587,13 @@ commSetSelect(fd, COMM_SELECT_READ, clientReadRequest, conn, 0); } -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, void *data) { int *N = &incoming_sockets_accepted; - https_port_data *https_port = data; - SSL_CTX *sslContext = https_port->sslContext; + https_port_list *s = data; + SSL_CTX *sslContext = s->sslContext; int fd = -1; ConnStateData *connState = NULL; struct sockaddr_in peer; @@ -3255,7 +3604,7 @@ #if USE_IDENT static aclCheck_t identChecklist; #endif - commSetSelect(sock, COMM_SELECT_READ, httpsAccept, https_port, 0); + commSetSelect(sock, COMM_SELECT_READ, httpsAccept, s, 0); while (max-- && !httpAcceptDefer(sock, NULL)) { memset(&peer, '\0', sizeof(struct sockaddr_in)); memset(&me, '\0', sizeof(struct sockaddr_in)); @@ -3278,6 +3627,8 @@ debug(50, 5) ("httpsAccept: FD %d accepted, starting SSL negotiation.\n", fd); connState = cbdataAlloc(ConnStateData); + connState->port = (http_port_list *) s; + cbdataLock(connState->port); connState->peer = peer; connState->log_addr = peer.sin_addr; connState->log_addr.s_addr &= Config.Addrs.client_netmask.s_addr; @@ -3285,7 +3636,9 @@ connState->fd = fd; connState->in.size = CLIENT_REQ_BUF_SZ; connState->in.buf = memAllocate(MEM_CLIENT_REQ_BUF); - /* XXX account connState->in.buf */ + /* transparent on SSL does not really make sense, but what the heck */ + if (connState->port->transparent) + clientNatLookup(connState); comm_add_close_handler(fd, connStateFree, connState); if (Config.onoff.log_fqdn) fqdncache_gethostbyaddr(peer.sin_addr, FQDN_LOOKUP_IF_MISS); @@ -3433,7 +3786,7 @@ 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) { @@ -3452,7 +3805,7 @@ if (fd < 0) continue; comm_listen(fd); - commSetSelect(fd, COMM_SELECT_READ, httpAccept, NULL, 0); + commSetSelect(fd, COMM_SELECT_READ, httpAccept, s, 0); /* * We need to set a defer handler here so that we don't * peg the CPU with select() when we hit the FD limit. @@ -3471,28 +3824,27 @@ 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) { + s->sslContext = sslLoadCert(s->cert, s->key); + if (!s->sslContext) + continue; enter_suid(); fd = comm_open(SOCK_STREAM, 0, - s->s.sin_addr, - ntohs(s->s.sin_port), + 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 = sslLoadCert(s->cert, s->key); comm_listen(fd); - commSetSelect(fd, COMM_SELECT_READ, httpsAccept, https_port, 0); + commSetSelect(fd, COMM_SELECT_READ, httpsAccept, s, 0); 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), + inet_ntoa(s->http.s.sin_addr), + (int) ntohs(s->http.s.sin_port), fd); HttpSockets[NHttpSockets++] = fd; } Index: squid/src/enums.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/enums.h,v retrieving revision 1.22 retrieving revision 1.22.6.1 diff -u -r1.22 -r1.22.6.1 --- squid/src/enums.h 12 Aug 2001 15:20:28 -0000 1.22 +++ squid/src/enums.h 26 Aug 2001 20:02:41 -0000 1.22.6.1 @@ -1,6 +1,6 @@ /* - * $Id: enums.h,v 1.22 2001/08/12 15:20:28 squidadm Exp $ + * $Id: enums.h,v 1.22.6.1 2001/08/26 20:02:41 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -130,6 +130,8 @@ ACL_REQ_MIME_TYPE, ACL_REP_MIME_TYPE, ACL_MAX_USER_IP, + ACL_URLGROUP, + ACL_EXTERNAL, ACL_ENUM_MAX } squid_acl; @@ -239,6 +241,8 @@ #if X_ACCELERATOR_VARY HDR_X_ACCELERATOR_VARY, #endif + HDR_X_ERROR_URL, /* errormap, requested URL */ + HDR_X_ERROR_STATUS, /* errormap, received HTTP status line */ HDR_OTHER, HDR_ENUM_END } http_hdr_type; @@ -305,6 +309,7 @@ CARP, #endif ANY_OLD_PARENT, + USERHASH_PARENT, HIER_MAX } hier_code; --- /dev/null Wed Feb 14 00:52:54 2007 +++ squid/src/errormap.c Wed Feb 14 00:54:34 2007 @@ -0,0 +1,213 @@ + +/* + * $Id$ + * + * DEBUG: section ?? Error Beautifier + * AUTHOR: Henrik Nordstrom + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" + +static const char * +getErrorMap(const errormap *map, const http_status status, const char *squid_error, const char *aclname) +{ + while (map) { + struct error_map_entry *m; + for (m = map->map; m; m = m->next) { + if (m->status == status) + return map->url; + if (squid_error && strcmp(m->value, squid_error) == 0) + return map->url; + if (aclname && strcmp(m->value, aclname) == 0) + return map->url; + } + map = map->next; + } + return NULL; +} + + +static int client_header_identities[] = { + HDR_USER_AGENT, + HDR_COOKIE, + HDR_X_FORWARDED_FOR, + HDR_VIA, + HDR_AUTHORIZATION, + HDR_ACCEPT, + HDR_REFERER +}; +HttpHeaderMask client_headers; + +static int server_header_identities[] = { + HDR_VIA, + HDR_SERVER, + HDR_LOCATION, + HDR_CONTENT_LOCATION +}; +HttpHeaderMask server_headers; + +typedef struct { + request_t *req; + StoreEntry *e; + store_client *sc; + ERRMAPCB *callback; + void *callback_data; + char *buf; +} ErrorMapState; + +CBDATA_TYPE(ErrorMapState); + +static void +errorMapFetchComplete(ErrorMapState *state) +{ + storeUnregister(state->sc, state->e, state); + state->sc = NULL; + storeUnlockObject(state->e); + state->e = NULL; + requestUnlink(state->req); + state->req = NULL; + memFree(state->buf, MEM_4K_BUF); + cbdataUnlock(state->callback_data); + state->callback_data = NULL; + cbdataFree(state); +} + +static void +errorMapFetchAbort(ErrorMapState *state) +{ + if (cbdataValid(state->callback_data)) + state->callback(NULL, -1, -1, state->callback_data); + errorMapFetchComplete(state); +} + +static void +errorMapFetchHeaders(void *data, char *buf, ssize_t size) +{ + ErrorMapState *state = data; + size_t hdr_size; + + if (EBIT_TEST(state->e->flags, ENTRY_ABORTED)) + return errorMapFetchAbort(state); + if (size == 0) + return errorMapFetchAbort(state); + if (!cbdataValid(state->callback_data)) + return errorMapFetchAbort(state); + + if ((hdr_size = headersEnd(buf, size))) { + http_status status; + /* httpReplyParse(reply, buf, hdr_size); */ + HttpReply *reply = state->e->mem_obj->reply; + assert(reply); + status = reply->sline.status; + if (status != HTTP_OK) + return errorMapFetchAbort(state); + /* Send object to caller (cbdataValid verified above) */ + state->callback(state->e, hdr_size, httpHeaderGetInt(&reply->header, HDR_CONTENT_LENGTH), state->callback_data); + return errorMapFetchComplete(state); + } + if (size >= 4096) { + /* Not enought space for reply headers */ + return errorMapFetchAbort(state); + } + /* Need more data */ + storeClientCopy(state->sc, state->e, size, 0, 4096, state->buf, errorMapFetchHeaders, state); +} + +int +errorMapStart(const errormap *map, request_t *client_req, HttpReply *reply, const char *aclname, ERRMAPCB *callback, void *callback_data) +{ + char squid_error[100]; + int len = 0; + const char *errorUrl; + ErrorMapState *state; + const char *tmp; + http_status status; + request_t *req; + HttpHeaderPos hdrpos; + HttpHeaderEntry *hdr; + + if (!client_req || !reply) + return 0; + + status = reply->sline.status; + + tmp = httpHeaderGetStr(&reply->header, HDR_X_SQUID_ERROR); + squid_error[0] = '\0'; + if (tmp) { + xstrncpy(squid_error, tmp, sizeof(squid_error)); + len = strcspn(squid_error, " "); + } + squid_error[len] = '\0'; + errorUrl = getErrorMap(map, status, squid_error, aclname); + if (!errorUrl) + return 0; + req = urlParse(METHOD_GET, (char *)errorUrl); + if (!req) { + debug(0, 0) ("error_map: Invalid error URL '%s'\n", errorUrl); + return 0; + } + req->urlgroup = xstrdup("error"); + + state = cbdataAlloc(ErrorMapState); + state->req = requestLink(req); + state->e = storeCreateEntry(errorUrl, errorUrl, req->flags, req->method); + state->sc = storeClientListAdd(state->e, state); + state->callback = callback; + state->callback_data = callback_data; + cbdataLock(callback_data); + + hdrpos = HttpHeaderInitPos; + while ((hdr = httpHeaderGetEntry(&client_req->header, &hdrpos)) != NULL) { + if (CBIT_TEST(client_headers, hdr->id)) + httpHeaderAddEntry(&req->header, httpHeaderEntryClone(hdr)); + } + hdrpos = HttpHeaderInitPos; + while ((hdr = httpHeaderGetEntry(&reply->header, &hdrpos)) != NULL) { + if (CBIT_TEST(server_headers, hdr->id)) + httpHeaderAddEntry(&req->header, httpHeaderEntryClone(hdr)); + } + httpHeaderPutInt(&req->header, HDR_X_ERROR_STATUS, (int)reply->sline.status); + httpHeaderPutStr(&req->header, HDR_X_REQUEST_URI, urlCanonical(client_req)); + + state->buf = memAllocate(MEM_4K_BUF); + fwdStart(-1, state->e, req); + storeClientCopy(state->sc, state->e, 0, 0, 4096, state->buf, errorMapFetchHeaders, state); + return 1; +} + +void +errorMapInit(void) +{ + CBDATA_INIT_TYPE(ErrorMapState); + + httpHeaderCalcMask(&client_headers, client_header_identities, sizeof(client_header_identities) / sizeof (*client_header_identities)); + httpHeaderCalcMask(&server_headers, server_header_identities, sizeof(server_header_identities) / sizeof (*server_header_identities)); +} + Index: squid/src/errorpage.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/errorpage.c,v retrieving revision 1.13 retrieving revision 1.13.14.1 diff -u -r1.13 -r1.13.14.1 --- squid/src/errorpage.c 21 May 2001 18:51:19 -0000 1.13 +++ squid/src/errorpage.c 26 Aug 2001 20:02:41 -0000 1.13.14.1 @@ -1,6 +1,6 @@ /* - * $Id: errorpage.c,v 1.13 2001/05/21 18:51:19 squidadm Exp $ + * $Id: errorpage.c,v 1.13.14.1 2001/08/26 20:02:41 hno Exp $ * * DEBUG: section 4 Error Generation * AUTHOR: Duane Wessels @@ -221,11 +221,23 @@ if (pageId >= ERR_NONE && pageId < ERR_MAX) /* common case */ return err_type_str[pageId]; if (pageId >= ERR_MAX && pageId - ERR_MAX < ErrorDynamicPages.count) - return ((ErrorDynamicPageInfo *) ErrorDynamicPages. - items[pageId - ERR_MAX])->page_name; + return ((ErrorDynamicPageInfo *) ErrorDynamicPages.items[pageId - ERR_MAX])->page_name; return "ERR_UNKNOWN"; /* should not happen */ } +int +errorPageId(const char *name) +{ + int i; + for (i = ERR_NONE; i < ERR_MAX; i++) + if (strcmp(err_type_str[i], name) == 0) + return i; + for (i = 0; i < ErrorDynamicPages.count; i++) + if (strcmp(((ErrorDynamicPageInfo *)ErrorDynamicPages.items[i])->page_name, name) == 0) + return i + ERR_MAX; + return -1; +} + /* * Function: errorCon * --- /dev/null Wed Feb 14 00:52:54 2007 +++ squid/src/external_acl.c Wed Feb 14 00:54:34 2007 @@ -0,0 +1,563 @@ + +/* + * $Id: external_acl.c,v 1.1.12.1 2001/08/26 20:02:41 hno Exp $ + * + * DEBUG: section 82 External ACL + * AUTHOR: Henrik Nordstrom + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" + +typedef struct _external_acl_format external_acl_format; +typedef struct _external_acl_data external_acl_data; +typedef struct _external_acl_cache_entry external_acl_cache_entry; + +static char *makeExternalAclKey(aclCheck_t *ch, external_acl_data *acl_data); +static int external_acl_cache_lookup(external_acl *def, const char *key); +static FREE free_external_acl_hash; + +/****************************************************************** + * external_acl directive + */ +struct _external_acl { + external_acl *next; + time_t ttl; + char *name; + external_acl_format *format; + wordlist *cmdline; + int children; + helper *helper; + hash_table *cache; +}; +struct _external_acl_format { + enum { + EXT_ACL_LOGIN = 1, + EXT_ACL_IDENT, + EXT_ACL_SRC, + EXT_ACL_DST, + EXT_ACL_PROTO, + EXT_ACL_PORT, + EXT_ACL_METHOD, + EXT_ACL_HEADER + } type; + external_acl_format *next; + char *header; +}; +/* FIXME: These are not really cbdata, but it is an easy way + * to get them pooled, refcounted, accounted and freed properly... + */ +CBDATA_TYPE(external_acl); +CBDATA_TYPE(external_acl_format); + +static void free_external_acl_format(void *data) +{ + external_acl_format *p = data; + safe_free(p->header); +} + +static void free_external_acl(void *data) +{ + external_acl *p = data; + safe_free(p->name); + while(p->format) { + external_acl_format *f = p->format; + p->format = f->next; + cbdataFree(f); + } + wordlistDestroy(&p->cmdline); + if (p->helper) { + helperShutdown(p->helper); + helperFree(p->helper); + p->helper = NULL; + } + if (p->cache) { + hashFreeItems(p->cache, free_external_acl_hash); + hashFreeMemory(p->cache); + } +} + +void parse_externalAclHelper(external_acl **list) +{ + external_acl *a; + char *token; + external_acl_format **p; + + CBDATA_INIT_TYPE_FREECB(external_acl, free_external_acl); + CBDATA_INIT_TYPE_FREECB(external_acl_format, free_external_acl_format); + + a = cbdataAlloc(external_acl); + + a->ttl = Config.externalAclTTL; + a->children = Config.externalAclChildren; + + token = strtok(NULL, w_space); + if (!token) + self_destruct(); + a->name = xstrdup(token); + + p = &a->format; + while((token = strtok(NULL, w_space)) != NULL) { + external_acl_format *format = cbdataAlloc(external_acl_format); + + /* stop on forst non-format token found */ + if (*token != '%') + break; + + if (strncmp(token, "%{", 2) == 0) { + /* header format */ + format->type = EXT_ACL_HEADER; + format->header = xstrdup(token+2); + /* and cut away the terminating } */ + if (!strlen(format->header)) + self_destruct(); + format->header[strlen(format->header)-1] = '\0'; + } +#define PARSE_EXT_ACL_TYPE(a) \ + else if (strcmp(token, "%" #a) == 0) { \ + format->type = EXT_ACL_##a; \ + } + PARSE_EXT_ACL_TYPE(LOGIN) + PARSE_EXT_ACL_TYPE(IDENT) + PARSE_EXT_ACL_TYPE(SRC) + PARSE_EXT_ACL_TYPE(DST) + PARSE_EXT_ACL_TYPE(PROTO) + PARSE_EXT_ACL_TYPE(PORT) + PARSE_EXT_ACL_TYPE(METHOD) + else { + self_destruct(); + } + *p = format; + p = &format->next; + } + if (!token) + self_destruct(); + wordlistAdd(&a->cmdline, token); + while((token = strtok(NULL, w_space)) != NULL) + wordlistAdd(&a->cmdline, token); + while(*list) + list = &(*list)->next; + *list = a; +} + +void dump_externalAclHelper(StoreEntry *sentry, char *name, external_acl *list) +{ + time_t ttl = Config.externalAclTTL; + int children = Config.externalAclChildren; + external_acl *node; + external_acl_format *format; + wordlist *word; + for (node = list; node; node = node->next) { + if (node->ttl != ttl) { + ttl = node->ttl; + storeAppendPrintf(sentry, "external_acl_ttl %d seconds\n", (int)node->ttl); + } + if (node->children != children) { + children = node->children; + storeAppendPrintf(sentry, "external_acl_children %d\n", node->children); + } + storeAppendPrintf(sentry, "%s %s", name, node->name); + for (format = node->format; format; format = format->next) { + switch(format->type) { + case EXT_ACL_HEADER: + storeAppendPrintf(sentry, " %%{%s}", format->header); + break; +#define DUMP_EXT_ACL_TYPE(a) \ + case EXT_ACL_##a: \ + storeAppendPrintf(sentry, " %%%s", #a); \ + break + DUMP_EXT_ACL_TYPE(LOGIN); + DUMP_EXT_ACL_TYPE(IDENT); + DUMP_EXT_ACL_TYPE(SRC); + DUMP_EXT_ACL_TYPE(DST); + DUMP_EXT_ACL_TYPE(PROTO); + DUMP_EXT_ACL_TYPE(PORT); + DUMP_EXT_ACL_TYPE(METHOD); + } + } + for (word = node->cmdline; word; word = word->next) + storeAppendPrintf(sentry, " %s", word->key); + storeAppendPrintf(sentry, "\n"); + } +} + +void free_externalAclHelper(external_acl **list) +{ + while(*list) { + external_acl *node = *list; + *list = node->next; + node->next = NULL; + cbdataFree(node); + } +} + +static external_acl *find_externalAclHelper(const char *name) +{ + external_acl *node; + + for (node = Config.externalAclHelperList; node; node = node->next) { + if (strcmp(node->name, name) == 0) + return node; + } + return NULL; +} + + +/****************************************************************** + * external acl type + */ + +struct _external_acl_data { + external_acl *def; + wordlist *arguments; +}; +CBDATA_TYPE(external_acl_data); +static void free_external_acl_data(void *data) +{ + external_acl_data *p = data; + wordlistDestroy(&p->arguments); + cbdataUnlock(p->def); + p->def = NULL; +} + +void aclParseExternal(void *dataptr) +{ + external_acl_data **datap = dataptr; + external_acl_data *data; + char *token; + if (*datap) + self_destruct(); + CBDATA_INIT_TYPE_FREECB(external_acl_data, free_external_acl_data); + data = cbdataAlloc(external_acl_data); + token = strtok(NULL, w_space); + if (!token) + self_destruct(); + data->def = find_externalAclHelper(token); + cbdataLock(data->def); + if (!data->def) + self_destruct(); + while ((token = strtok(NULL, w_space))) { + wordlistAdd(&data->arguments, token); + } + *datap = data; +} + +void aclDestroyExternal(void **dataptr) +{ + cbdataFree(*dataptr); +} + +int aclMatchExternal(void *data, aclCheck_t *ch) +{ + int result; + external_acl_data *acl = data; + const char *key = makeExternalAclKey(ch, acl); + debug(82, 0) ("aclMatchExternal: key=\"%s\"\n", key); + result = external_acl_cache_lookup(acl->def, key); + if (result < 0) { + debug(82, 2) ("aclMatchExternal: %s(\"%s\") = lookup needed\n", acl->def->name, key); + ch->state[ACL_EXTERNAL] = ACL_LOOKUP_NEEDED; + return 0; + } + debug(82, 2) ("aclMatchExternal: %s(\"%s\") = %d\n", acl->def->name, key, result); + return result; +} + +wordlist *aclDumpExternal(void *data) +{ + external_acl_data *acl = data; + wordlist *result = NULL; + wordlist *arg; + MemBuf mb; + memBufDefInit(&mb); + memBufPrintf(&mb, "%s", acl->def->name); + for (arg = acl->arguments; arg; arg = arg->next) { + memBufPrintf(&mb, " %s", arg->key); + } + wordlistAdd(&result, mb.buf); + memBufClean(&mb); + return result; +} + +/****************************************************************** + * external_acl cache + */ + +struct _external_acl_cache_entry { + hash_link hash; + int result; + time_t date; + hash_table *hash_table; /* yuck, but hashFreeItems don't tell us... */ +}; +CBDATA_TYPE(external_acl_cache_entry); + +static char *makeExternalAclKey(aclCheck_t *ch, external_acl_data *acl_data) +{ + static MemBuf mb = MemBufNULL; + char buf[256]; + int err = 0; + int first = 1; + wordlist *arg; + external_acl_format *format; + request_t *request = ch->request; + String sb = StringNull; + memBufReset(&mb); + for (format = acl_data->def->format; format; format = format->next) { + const char *str = NULL; + switch(format->type) { + case EXT_ACL_LOGIN: + str = authenticateUserRequestUsername(request->auth_user_request); + /* FIXME: How to request authentication if not done? */ + break; + case EXT_ACL_IDENT: + str = ch->rfc931; + if (!str) { + err = 1; + ch->state[ACL_IDENT] = ACL_LOOKUP_NEEDED; + } + break; + case EXT_ACL_SRC: + str = inet_ntoa(ch->src_addr); + break; + case EXT_ACL_DST: + str = request->host; + break; + case EXT_ACL_PROTO: + str = ProtocolStr[request->protocol]; + break; + case EXT_ACL_PORT: + snprintf(buf, sizeof(buf), "%d", request->port); + str = buf; + case EXT_ACL_METHOD: + str = RequestMethodStr[request->method]; + break; + case EXT_ACL_HEADER: + stringClean(&sb); + sb = httpHeaderGetByName(&request->header, format->header); + str = strBuf(sb); + break; + } + if (str) + if (!*str) + str = NULL; + if (!str) + str = "-"; + if (first) + memBufPrintf(&mb, "%s", log_quote(str)); + else + memBufPrintf(&mb, " %s", log_quote(str)); + first = 0; + } + for (arg = acl_data->arguments; arg; arg = arg->next) { + if (first) + memBufPrintf(&mb, "%s", log_quote(arg->key)); + else + memBufPrintf(&mb, " %s", log_quote(arg->key)); + first = 0; + } + stringClean(&sb); + if (!err) + return mb.buf; + else + return NULL; +} + +static int external_acl_cache_lookup(external_acl * def, const char *key) +{ + external_acl_cache_entry * entry = hash_lookup(def->cache, key); + if (!entry) { + debug(82, 2) ("external_acl_cache_lookup: '%s' = unknown\n", key); + return -1; + } + if (entry->date + def->ttl < squid_curtime) { + /* Expired entry, ignore */ + debug(82, 2) ("external_acl_cache_lookup: '%s' = expired\n", key); + return -1; + } + if (entry->result == -1 && entry->date + 2 < squid_curtime) { + /* Negatively cached */ + debug(82, 1) ("external_acl_cache_lookup: '%s' = negative (overload)\n", key); + return 0; + } + debug(82, 2) ("external_acl_cache_lookup: '%s' = %d\n", key, entry->result); + return entry->result; +} + +static void free_external_acl_cache_entry(void *data) +{ + external_acl_cache_entry *entry = data; + safe_free(entry->hash.key); +} +static void free_external_acl_hash(void *data) +{ + external_acl_cache_entry *entry = data; + hash_remove_link(entry->hash_table, &entry->hash); + cbdataFree(data); +} +static void external_acl_cache_add(external_acl *def, const char *key, int result) +{ + external_acl_cache_entry * entry = hash_lookup(def->cache, key); + debug(82, 2) ("external_acl_cache_add: Adding '%s' = %d\n", key, result); + if (entry) { + debug(82, 3) ("external_acl_cache_add: updating existing entry\n"); + entry->date = squid_curtime; + entry->result = result; + return; + } + CBDATA_INIT_TYPE_FREECB(external_acl_cache_entry, free_external_acl_cache_entry); + entry = cbdataAlloc(external_acl_cache_entry); + entry->hash.key = xstrdup(key); + entry->date = squid_curtime; + entry->result = result; + entry->hash_table = def->cache; + hash_join(def->cache, &entry->hash); +} + +/****************************************************************** + * external_acl helpers + */ + +typedef struct _externalAclState externalAclState; +struct _externalAclState { + EAH *callback; + void *callback_data; + char *key; + external_acl *def; +}; +CBDATA_TYPE(externalAclState); +static void free_externalAclState(void *data) +{ + externalAclState *state = data; + safe_free(state->key); + cbdataUnlock(state->callback_data); + cbdataUnlock(state->def); +} + +static void externalAclHandleReply(void *data, char *reply) +{ + externalAclState *state = data; + int result = 0; + + if (reply) + result = (strncmp(reply, "OK", 2) == 0); + + if (cbdataValid(state->def)) + external_acl_cache_add(state->def, state->key, result); + cbdataUnlock(state->def); + state->def = NULL; + + if (cbdataValid(state->callback_data)) + state->callback(result, state->callback_data); + cbdataUnlock(state->callback_data); + state->callback_data = NULL; + + cbdataFree(state); +} + +void externalAclLookup(aclCheck_t *ch, void *acl_data, EAH *callback, void *callback_data) +{ + MemBuf buf; + external_acl_data *acl = acl_data; + external_acl *def = acl->def; + const char *key = makeExternalAclKey(ch, acl); + externalAclState *state; + debug(82, 2) ("externalAclLookup: lookup in '%s' for '%s'\n", def->name, key); + if (!key) { + debug(82, 1) ("externalAclLookup: lookup in '%s', prerequisit failure\n", def->name); + callback(0, callback_data); + return; + } + if (def->helper->stats.queue_size >= def->helper->n_running) { + int result = -1; + external_acl_cache_entry * entry = hash_lookup(def->cache, key); + debug(82, 1) ("externalAclLookup: '%s' queue overload\n", def->name); + if (entry) + result = entry->result; + external_acl_cache_add(def, key, result); + callback(result, callback_data); + return; + } + state = cbdataAlloc(externalAclState); + state->def = def; + cbdataLock(state->def); + state->callback = callback; + state->callback_data = callback_data; + state->key = xstrdup(key); + cbdataLock(state->callback_data); + memBufDefInit(&buf); + memBufPrintf(&buf, "%s\n", key); + helperSubmit(def->helper, buf.buf, externalAclHandleReply, state); + memBufClean(&buf); +} + +static void +externalAclStats(StoreEntry * sentry) +{ + external_acl *p; + + for (p = Config.externalAclHelperList; p; p = p->next) { + storeAppendPrintf(sentry, "External ACL Statistics: %s\n", p->name); + storeAppendPrintf(sentry, "Cache size: %d\n", p->cache->count); + helperStats(sentry, p->helper); + storeAppendPrintf(sentry, "\n"); + } +} + +void externalAclInit(void) +{ + static int firstTimeInit = 1; + external_acl *p; + + for (p = Config.externalAclHelperList; p; p = p->next) { + if (!p->cache) + p->cache = hash_create((HASHCMP *)strcmp, hashPrime(1024), hash4); + if (!p->helper) + p->helper = helperCreate(p->name); + p->helper->cmdline = p->cmdline; + p->helper->n_to_start = p->children; + p->helper->ipc_type = IPC_TCP_SOCKET; + helperOpenServers(p->helper); + } + if (firstTimeInit) { + firstTimeInit = 0; + cachemgrRegister("external_acl", + "External ACL stats", + externalAclStats, 0, 1); + CBDATA_INIT_TYPE_FREECB(externalAclState, free_externalAclState); + } +} +void externalAclShutdown(void) +{ + external_acl *p; + for (p = Config.externalAclHelperList; p; p = p->next) { + hashFreeItems(p->cache, free_external_acl_hash); + helperShutdown(p->helper); + } +} + Index: squid/src/forward.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/forward.c,v retrieving revision 1.12 retrieving revision 1.12.38.1 diff -u -r1.12 -r1.12.38.1 --- squid/src/forward.c 30 Mar 2001 22:29:38 -0000 1.12 +++ squid/src/forward.c 26 Aug 2001 20:02:41 -0000 1.12.38.1 @@ -1,6 +1,6 @@ /* - * $Id: forward.c,v 1.12 2001/03/30 22:29:38 squidadm Exp $ + * $Id: forward.c,v 1.12.38.1 2001/08/26 20:02:41 hno Exp $ * * DEBUG: section 17 Request Forwarding * AUTHOR: Duane Wessels @@ -285,11 +285,6 @@ port = fs->peer->http_port; ctimeout = fs->peer->connect_timeout > 0 ? fs->peer->connect_timeout : Config.Timeout.peer_connect; - } else if (fwdState->request->flags.accelerated && - Config.Accel.single_host && Config.Accel.host) { - host = Config.Accel.host; - port = Config.Accel.port; - ctimeout = Config.Timeout.connect; } else { host = fwdState->request->host; port = fwdState->request->port; @@ -389,9 +384,11 @@ if (fwdState->servers && (p = fwdState->servers->peer)) { p->stats.fetches++; fwdState->request->peer_login = p->login; + fwdState->request->peer_domain = p->domain; httpStart(fwdState); } else { fwdState->request->peer_login = NULL; + fwdState->request->peer_domain = NULL; switch (request->protocol) { case PROTO_HTTP: httpStart(fwdState); @@ -486,6 +483,30 @@ } void +fwdStartPeer(peer * p, StoreEntry * e, request_t * r) +{ + FwdState *fwdState; + FwdServer *peer = NULL; + debug(17, 3) ("fwdStartPeer: '%s'\n", storeUrl(e)); + e->mem_obj->request = requestLink(r); + e->mem_obj->fd = -1; +#if URL_CHECKSUM_DEBUG + assert(e->mem_obj->chksum == url_checksum(e->mem_obj->url)); +#endif + fwdState = cbdataAlloc(FwdState); + fwdState->entry = e; + fwdState->client_fd = -1; + fwdState->server_fd = -1; + fwdState->request = requestLink(r); + fwdState->start = squid_curtime; + storeLockObject(e); + EBIT_SET(e->flags, ENTRY_FWD_HDR_WAIT); + storeRegisterAbort(e, fwdAbort, fwdState); + peerAddFwdServer(&peer, p, DIRECT); + fwdStartComplete(peer, fwdState); +} + +void fwdStart(int fd, StoreEntry * e, request_t * r) { FwdState *fwdState; Index: squid/src/globals.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/globals.h,v retrieving revision 1.11 retrieving revision 1.11.4.1 diff -u -r1.11 -r1.11.4.1 --- squid/src/globals.h 16 Aug 2001 07:39:03 -0000 1.11 +++ squid/src/globals.h 26 Aug 2001 20:02:41 -0000 1.11.4.1 @@ -1,6 +1,6 @@ /* - * $Id: globals.h,v 1.11 2001/08/16 07:39:03 squidadm Exp $ + * $Id: globals.h,v 1.11.4.1 2001/08/26 20:02:41 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -96,8 +96,6 @@ extern int theOutSnmpConnection; /* -1 */ extern char *snmp_agentinfo; #endif -extern int vhost_mode; /* 0 */ -extern int vport_mode; /* 0 */ extern int n_disk_objects; /* 0 */ extern iostats IOStats; extern struct _acl_deny_info_list *DenyInfoList; /* NULL */ Index: squid/src/http.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/http.c,v retrieving revision 1.14 retrieving revision 1.14.12.1 diff -u -r1.14 -r1.14.12.1 --- squid/src/http.c 12 Jul 2001 06:03:54 -0000 1.14 +++ squid/src/http.c 26 Aug 2001 20:02:41 -0000 1.14.12.1 @@ -1,6 +1,6 @@ /* - * $Id: http.c,v 1.14 2001/07/12 06:03:54 squidadm Exp $ + * $Id: http.c,v 1.14.12.1 2001/08/26 20:02:41 hno Exp $ * * DEBUG: section 11 Hypertext Transfer Protocol (HTTP) * AUTHOR: Harvest Derived @@ -732,7 +732,6 @@ const HttpHeader *hdr_in = &orig_request->header; int we_do_ranges; const HttpHeaderEntry *e; - String strVia; String strFwd; HttpHeaderPos pos = HttpHeaderInitPos; httpHeaderInit(hdr_out, hoRequest); @@ -775,24 +774,23 @@ /* Only pass on proxy authentication to peers for which * authentication forwarding is explicitly enabled */ - if (request->flags.proxying && orig_request->peer_login && - strcmp(orig_request->peer_login, "PASS") == 0) { + if (flags.proxying && orig_request->peer_login && (strcmp(orig_request->peer_login, "PASS") == 0 || strcmp(orig_request->peer_login, "PROXYPASS") == 0)) { httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e)); } break; case HDR_AUTHORIZATION: - /* Pass on WWW authentication even if used locally. If this is - * not wanted in an accelerator then the header can be removed - * using the anonymization functions + /* Pass on WWW authentication. */ + if (!flags.originpeer) { httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e)); - /* XXX Some accelerators might want to strip the header - * and regard the reply as cacheable, but authentication - * is not normally enabled for accelerators without reading - * the code, so there is not much use in adding logics here - * without first defining the concept of having authentication - * in the accelerator... + } else { + /* In accelerators, only forward authentication if enabled + * (see also below for proxy->server authentication) */ + if (orig_request->peer_login && (strcmp(orig_request->peer_login, "PASS") == 0 || strcmp(orig_request->peer_login, "PROXYPASS") == 0)) { + httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e)); + } + } break; case HDR_HOST: /* @@ -826,9 +824,13 @@ if (!we_do_ranges) httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e)); break; + case HDR_VIA: + /* If Via is disabled then forward any received header as-is */ + if (!Config.onoff.via) + httpHeaderAddEntry(hdr_out, httpHeaderEntryClone(e)); + break; case HDR_PROXY_CONNECTION: case HDR_CONNECTION: - case HDR_VIA: case HDR_X_FORWARDED_FOR: case HDR_CACHE_CONTROL: /* append these after the loop if needed */ @@ -840,13 +842,15 @@ } /* append Via */ - strVia = httpHeaderGetList(hdr_in, HDR_VIA); + if (Config.onoff.via) { + String strVia = httpHeaderGetList(hdr_in, HDR_VIA); snprintf(bbuf, BBUF_SZ, "%d.%d %s", orig_request->http_ver.major, orig_request->http_ver.minor, ThisCache); strListAdd(&strVia, bbuf, ','); httpHeaderPutStr(hdr_out, HDR_VIA, strBuf(strVia)); stringClean(&strVia); + } /* append X-Forwarded-For */ strFwd = httpHeaderGetList(hdr_in, HDR_X_FORWARDED_FOR); @@ -856,8 +860,10 @@ /* append Host if not there already */ if (!httpHeaderHas(hdr_out, HDR_HOST)) { + if (orig_request->peer_domain) { + httpHeaderPutStr(hdr_out, HDR_HOST, orig_request->peer_domain); + } else if (orig_request->port == urlDefaultPort(orig_request->protocol)) { /* use port# only if not default */ - if (orig_request->port == urlDefaultPort(orig_request->protocol)) { httpHeaderPutStr(hdr_out, HDR_HOST, orig_request->host); } else { httpHeaderPutStrf(hdr_out, HDR_HOST, "%s:%d", @@ -889,6 +895,32 @@ base64_encode(orig_request->peer_login)); } } + /* append WWW-Authorization if configured for peer */ + if (flags.originpeer && orig_request->peer_login && + !httpHeaderHas(hdr_out, HDR_AUTHORIZATION)) { + if (strcmp(orig_request->peer_login, "PASS") == 0) { + /* No credentials to forward.. (should have been done above if available) */ + } else if (strcmp(orig_request->peer_login, "PROXYPASS") == 0) { + /* Special mode, convert proxy authentication to WWW authentication */ + const char *auth = httpHeaderGetStr(hdr_in, HDR_PROXY_AUTHORIZATION); + if (auth && strncasecmp(auth, "basic ", 6) == 0) { + httpHeaderPutStr(hdr_out, HDR_AUTHORIZATION, auth); + } + } else if (*orig_request->peer_login == '*') { + /* Special mode, to pass the username to the upstream cache */ + char loginbuf[256]; + char *username = "-"; + if (orig_request->auth_user_request) + username = authenticateUserRequestUsername(orig_request->auth_user_request); + snprintf(loginbuf, sizeof(loginbuf), "%s%s", username, orig_request->peer_login + 1); + httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s", + base64_encode(loginbuf)); + } else { + /* Fixed login string */ + httpHeaderPutStrf(hdr_out, HDR_AUTHORIZATION, "Basic %s", + base64_encode(orig_request->peer_login)); + } + } /* append Cache-Control, add max-age if not there already */ { HttpHdrCc *cc = httpHeaderGetCc(hdr_in); @@ -971,10 +1003,15 @@ else cfd = entry->mem_obj->fd; assert(-1 == cfd || FD_SOCKET == fd_table[cfd].type); - if (p != NULL) - httpState->flags.proxying = 1; + if (p != NULL) { + if (p->options.originserver) + httpState->flags.originpeer = 1; else + httpState->flags.proxying = 1; + } else { httpState->flags.proxying = 0; + httpState->flags.originpeer = 0; + } /* * Is keep-alive okay for all request methods? */ @@ -1019,8 +1056,13 @@ if (fwd->servers) httpState->peer = fwd->servers->peer; /* might be NULL */ if (httpState->peer) { + const char *url; + if (httpState->peer->options.originserver) + url = strBuf(orig_req->urlpath); + else + url = storeUrl(httpState->entry); proxy_req = requestCreate(orig_req->method, - PROTO_NONE, storeUrl(httpState->entry)); + PROTO_NONE, url); xstrncpy(proxy_req->host, httpState->peer->host, SQUIDHOSTNAMELEN); proxy_req->port = httpState->peer->http_port; proxy_req->flags = orig_req->flags; Index: squid/src/icp_v2.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/icp_v2.c,v retrieving revision 1.5 retrieving revision 1.5.16.1 diff -u -r1.5 -r1.5.16.1 --- squid/src/icp_v2.c 4 May 2001 13:39:12 -0000 1.5 +++ squid/src/icp_v2.c 26 Aug 2001 20:02:41 -0000 1.5.16.1 @@ -1,6 +1,6 @@ /* - * $Id: icp_v2.c,v 1.5 2001/05/04 13:39:12 squidadm Exp $ + * $Id: icp_v2.c,v 1.5.16.1 2001/08/26 20:02:41 hno Exp $ * * DEBUG: section 12 Internet Cache Protocol * AUTHOR: Duane Wessels @@ -407,8 +407,6 @@ int x; socklen_t len; wordlist *s; - if (Config2.Accel.on && !Config.onoff.accel_with_proxy) - return; if ((port = Config.Port.icp) <= 0) return; enter_suid(); --- /dev/null Wed Feb 14 00:52:54 2007 +++ squid/src/locrewrite.c Wed Feb 14 00:54:34 2007 @@ -0,0 +1,161 @@ + +/* + * $Id: locrewrite.c,v 1.1.24.1 2001/08/26 20:02:41 hno Exp $ + * + * DEBUG: section 29 Redirector + * AUTHOR: Henrik Nordstrom + * BASED ON: redirect.c by Duane Wessels + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" + +typedef struct { + void *data; + char *orig_url; + RH *handler; +} rewriteStateData; + +static HLPCB locationRewriteHandleReply; +static void locationRewriteStateFree(rewriteStateData * r); +static helper *locrewriters = NULL; +static OBJH locationRewriteStats; +static int n_bypassed = 0; +CBDATA_TYPE(rewriteStateData); + +static void +locationRewriteHandleReply(void *data, char *reply) +{ + rewriteStateData *r = data; + int valid; + char *t; + debug(29, 5) ("rewriteHandleRead: {%s}\n", reply ? reply : ""); + if (reply) { + if ((t = strchr(reply, ' '))) + *t = '\0'; + if (*reply == '\0') + reply = NULL; + } + valid = cbdataValid(r->data); + cbdataUnlock(r->data); + if (valid) + r->handler(r->data, reply); + locationRewriteStateFree(r); +} + +static void +locationRewriteStateFree(rewriteStateData * r) +{ + safe_free(r->orig_url); + cbdataFree(r); +} + +static void +locationRewriteStats(StoreEntry * sentry) +{ + storeAppendPrintf(sentry, "Redirector Statistics:\n"); + helperStats(sentry, locrewriters); + if (Config.onoff.redirector_bypass) + storeAppendPrintf(sentry, "\nNumber of requests bypassed " + "because all rewriters were busy: %d\n", n_bypassed); +} + +/**** PUBLIC FUNCTIONS ****/ + +void +locationRewriteStart(HttpReply * rep, clientHttpRequest * http, RH * handler, void *data) +{ + rewriteStateData *r = NULL; + const char *location = httpHeaderGetStr(&rep->header, HDR_LOCATION); + char *urlgroup; + char buf[8192]; + + if (http->orig_request && http->orig_request->urlgroup) + urlgroup = http->orig_request->urlgroup; + else if (http->request && http->request->urlgroup) + urlgroup = http->request->urlgroup; + else + urlgroup = NULL; + + assert(handler); + if (!urlgroup || !*urlgroup) + urlgroup = "-"; + debug(29, 5) ("locationRewriteStart: '%s'\n", location); + if (Config.Program.location_rewrite.command == NULL) { + handler(data, NULL); + return; + } + if (Config.onoff.redirector_bypass && locrewriters->stats.queue_size) { + /* Skip rewriter if there is one request queued */ + n_bypassed++; + handler(data, NULL); + return; + } + r = cbdataAlloc(rewriteStateData); + r->orig_url = xstrdup(location); + r->handler = handler; + r->data = data; + cbdataLock(r->data); + snprintf(buf, 8192, "%s %s %s\n", + r->orig_url, http->uri, urlgroup); + helperSubmit(locrewriters, buf, locationRewriteHandleReply, r); +} + +void +locationRewriteInit(void) +{ + static int init = 0; + if (!Config.Program.location_rewrite.command) + return; + if (locrewriters == NULL) + locrewriters = helperCreate("location_rewriter"); + locrewriters->cmdline = Config.Program.location_rewrite.command; + locrewriters->n_to_start = Config.Program.location_rewrite.children; + locrewriters->ipc_type = IPC_TCP_SOCKET; + helperOpenServers(locrewriters); + if (!init) { + cachemgrRegister("location_rewriter", + "Location Rewriter Stats", + locationRewriteStats, 0, 1); + init = 1; + CBDATA_INIT_TYPE(rewriteStateData); + } +} + +void +locationRewriteShutdown(void) +{ + if (!locrewriters) + return; + helperShutdown(locrewriters); + if (!shutting_down) + return; + helperFree(locrewriters); + locrewriters = NULL; +} Index: squid/src/main.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/main.c,v retrieving revision 1.25 retrieving revision 1.25.4.1 diff -u -r1.25 -r1.25.4.1 --- squid/src/main.c 16 Aug 2001 07:39:03 -0000 1.25 +++ squid/src/main.c 26 Aug 2001 20:02:41 -0000 1.25.4.1 @@ -1,6 +1,6 @@ /* - * $Id: main.c,v 1.25 2001/08/16 07:39:03 squidadm Exp $ + * $Id: main.c,v 1.25.4.1 2001/08/26 20:02:41 hno Exp $ * * DEBUG: section 1 Startup and Main Loop * AUTHOR: Harvest Derived @@ -136,7 +136,14 @@ opt_store_doublecheck = 1; break; case 'V': - vhost_mode = 1; + if (Config.Sockaddr.http) + Config.Sockaddr.http->vhost = 1; +#if USE_SSL + else if (Config.Sockaddr.https) + Config.Sockaddr.https->http.vhost = 1; +#endif + else + fatal("No http_port specified\n"); break; case 'X': /* force full debugging */ @@ -299,6 +306,8 @@ #if USE_CARP carpInit(); #endif + peerUserHashInit(); + peerMonitorInit(); } void @@ -343,7 +352,9 @@ idnsShutdown(); #endif redirectShutdown(); + locationRewriteShutdown(); authenticateShutdown(); + externalAclShutdown(); storeDirCloseSwapLogs(); errorClean(); parseConfigFile(ConfigFile); @@ -359,22 +370,20 @@ idnsInit(); #endif redirectInit(); + locationRewriteInit(); authenticateInit(&Config.authConfig); + externalAclInit(); #if USE_WCCP wccpInit(); #endif serverConnectionsOpen(); - if (theOutIcpConnection >= 0) { - if (!Config2.Accel.on || Config.onoff.accel_with_proxy) - neighbors_open(theOutIcpConnection); - else - debug(1, 1) ("ICP port disabled in httpd_accelerator mode\n"); - } + neighbors_init(); storeDirOpenSwapLogs(); mimeInit(Config.mimeTablePathname); writePidFile(); /* write PID file */ debug(1, 1) ("Ready to serve requests.\n"); reconfiguring = 0; + peerMonitorInit(); } static void @@ -385,7 +394,9 @@ dnsShutdown(); #endif redirectShutdown(); + locationRewriteShutdown(); authenticateShutdown(); + externalAclShutdown(); _db_rotate_log(); /* cache.log */ storeDirWriteCleanLogs(1); storeLogRotate(); /* store.log */ @@ -400,7 +411,9 @@ dnsInit(); #endif redirectInit(); + locationRewriteInit(); authenticateInit(&Config.authConfig); + externalAclInit(); } static void @@ -480,7 +493,10 @@ idnsInit(); #endif redirectInit(); + locationRewriteInit(); + errorMapInit(); authenticateInit(&Config.authConfig); + externalAclInit(); useragentOpenLog(); refererOpenLog(); httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */ @@ -520,12 +536,7 @@ wccpInit(); #endif serverConnectionsOpen(); - if (theOutIcpConnection >= 0) { - if (!Config2.Accel.on || Config.onoff.accel_with_proxy) - neighbors_open(theOutIcpConnection); - else - debug(1, 1) ("ICP port disabled in httpd_accelerator mode\n"); - } + neighbors_init(); if (Config.chroot_dir) no_suid(); if (!configured_once) @@ -711,6 +722,8 @@ idnsShutdown(); #endif redirectShutdown(); + locationRewriteShutdown(); + externalAclShutdown(); eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1); } eventRun(); Index: squid/src/mib.txt =================================================================== RCS file: /cvsroot/squid-sf//squid/src/mib.txt,v retrieving revision 1.3 retrieving revision 1.3.92.1 diff -u -r1.3 -r1.3.92.1 --- squid/src/mib.txt 23 Oct 2000 15:04:21 -0000 1.3 +++ squid/src/mib.txt 26 Aug 2001 20:02:41 -0000 1.3.92.1 @@ -2,7 +2,7 @@ DEFINITIONS ::= BEGIN -- --- $Id: mib.txt,v 1.3 2000/10/23 15:04:21 hno Exp $ +-- $Id: mib.txt,v 1.3.92.1 2001/08/26 20:02:41 hno Exp $ -- IMPORTS @@ -677,7 +677,7 @@ the peer caches, complete with info " ::= { cacheMesh 1 } - cachePeerEntry OBJECT-TYPE + OLDcachePeerEntry OBJECT-TYPE SYNTAX CachePeerEntry MAX-ACCESS not-accessible STATUS current @@ -686,7 +686,18 @@ INDEX { cachePeerAddr } ::= { cachePeerTable 1 } + cachePeerEntry OBJECT-TYPE + SYNTAX CachePeerEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + " An entry in cachePeerTable " + INDEX { cachePeerIndex } + ::= { cachePeerTable 2 } + CachePeerEntry ::= SEQUENCE { + cachePeerIndex Integer32, + cachePeerHost DisplayString, cachePeerName DisplayString, cachePeerAddr IpAddress, cachePeerPortHttp Integer32 (1..65535), @@ -808,6 +819,22 @@ " Number of keepalives received " ::= { cachePeerEntry 13 } + cachePeerIndex OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " Reference Index for each peer " + ::= { cachePeerEntry 14 } + + cachePeerHost OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " The FQDN name for the peer cache " + ::= { cachePeerEntry 15 } + --- --- Table of cache's clients, with statistics. Children caches can be identified --- by non-zero number of ICP requests (unless browsers start using ICP). Index: squid/src/neighbors.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/neighbors.c,v retrieving revision 1.12 retrieving revision 1.12.12.1 diff -u -r1.12 -r1.12.12.1 --- squid/src/neighbors.c 27 Jun 2001 06:49:54 -0000 1.12 +++ squid/src/neighbors.c 26 Aug 2001 20:02:41 -0000 1.12.12.1 @@ -1,6 +1,6 @@ /* - * $Id: neighbors.c,v 1.12 2001/06/27 06:49:54 squidadm Exp $ + * $Id: neighbors.c,v 1.12.12.1 2001/08/26 20:02:41 hno Exp $ * * DEBUG: section 15 Neighbor Routines * AUTHOR: Harvest Derived @@ -355,7 +355,7 @@ } void -neighbors_open(int fd) +neighbors_init(void) { struct sockaddr_in name; socklen_t len = sizeof(struct sockaddr_in); @@ -363,11 +363,13 @@ const char *me = getMyHostname(); peer *this; peer *next; + int fd = theInIcpConnection; + if (fd >= 0) { memset(&name, '\0', sizeof(struct sockaddr_in)); if (getsockname(fd, (struct sockaddr *) &name, &len) < 0) debug(15, 1) ("getsockname(%d,%p,%p) failed.\n", fd, &name, &len); for (this = Config.peers; this; this = next) { - sockaddr_in_list *s; + http_port_list *s; next = this->next; if (0 != strcmp(this->host, me)) continue; @@ -381,6 +383,7 @@ neighborRemove(this); } } + } peerRefreshDNS((void *) 1); if (0 == echo_hdr.opcode) { @@ -398,10 +401,12 @@ cachemgrRegister("server_list", "Peer Cache Statistics", neighborDumpPeers, 0, 1); + if (theInIcpConnection >= 0) { cachemgrRegister("non_peers", "List of Unknown sites sending ICP messages", neighborDumpNonPeers, 0, 1); } +} int neighborsUdpPing(request_t * request, @@ -496,9 +501,8 @@ /* Neighbor is dead; ping it anyway, but don't expect a reply */ /* log it once at the threshold */ if (p->stats.logged_state == PEER_ALIVE) { - debug(15, 1) ("Detected DEAD %s: %s/%d/%d\n", - neighborTypeStr(p), - p->host, p->http_port, p->icp.port); + debug(15, 1) ("Detected DEAD %s: %s\n", + neighborTypeStr(p), p->name); p->stats.logged_state = PEER_DEAD; } } @@ -673,9 +677,8 @@ neighborAlive(peer * p, const MemObject * mem, const icp_common_t * header) { if (p->stats.logged_state == PEER_DEAD && p->tcp_up) { - debug(15, 1) ("Detected REVIVED %s: %s/%d/%d\n", - neighborTypeStr(p), - p->host, p->http_port, p->icp.port); + debug(15, 1) ("Detected REVIVED %s: %s\n", + neighborTypeStr(p), p->name); p->stats.logged_state = PEER_ALIVE; } p->stats.last_reply = squid_curtime; @@ -706,9 +709,8 @@ neighborAliveHtcp(peer * p, const MemObject * mem, const htcpReplyData * htcp) { if (p->stats.logged_state == PEER_DEAD && p->tcp_up) { - debug(15, 1) ("Detected REVIVED %s: %s/%d/%d\n", - neighborTypeStr(p), - p->host, p->http_port, p->icp.port); + debug(15, 1) ("Detected REVIVED %s: %s\n", + neighborTypeStr(p), p->name); p->stats.logged_state = PEER_ALIVE; } p->stats.last_reply = squid_curtime; @@ -899,7 +901,7 @@ { peer *p = NULL; for (p = Config.peers; p; p = p->next) { - if (!strcasecmp(name, p->host)) + if (!strcasecmp(name, p->name)) break; } return p; @@ -910,7 +912,7 @@ { peer *p = NULL; for (p = Config.peers; p; p = p->next) { - if (strcasecmp(name, p->host)) + if (strcasecmp(name, p->name)) continue; if (port != p->http_port) continue; @@ -926,6 +928,10 @@ peerProbeConnect((peer *) p); return 0; } + if (p->stats.logged_state != PEER_ALIVE) + return 0; + if (p->monitor.state != PEER_ALIVE) + return 0; if (p->options.no_query) return 1; if (p->stats.probe_start != 0 && @@ -1024,8 +1030,9 @@ eventAddIsh("peerRefreshDNS", peerRefreshDNS, NULL, 180.0, 1); return; } - for (p = Config.peers; p; p = p->next) + for (p = Config.peers; p; p = p->next) { ipcache_nbgethostbyname(p->host, peerDNSConfigure, p); + } /* Reconfigure the peers every hour */ eventAddIsh("peerRefreshDNS", peerRefreshDNS, NULL, 3600.0, 1); } @@ -1041,9 +1048,8 @@ debug(15, 1) ("TCP connection to %s/%d failed\n", p->host, p->http_port); p->tcp_up--; if (!p->tcp_up) { - debug(15, 1) ("Detected DEAD %s: %s/%d/%d\n", - neighborTypeStr(p), - p->host, p->http_port, p->icp.port); + debug(15, 1) ("Detected DEAD %s: %s\n", + neighborTypeStr(p), p->name); p->stats.logged_state = PEER_DEAD; } } @@ -1053,9 +1059,8 @@ { if (!p->tcp_up) { debug(15, 2) ("TCP connection to %s/%d succeded\n", p->host, p->http_port); - debug(15, 1) ("Detected REVIVED %s: %s/%d/%d\n", - neighborTypeStr(p), - p->host, p->http_port, p->icp.port); + debug(15, 1) ("Detected REVIVED %s: %s\n", + neighborTypeStr(p), p->name); p->stats.logged_state = PEER_ALIVE; } p->tcp_up = PEER_TCP_MAGIC_COUNT; @@ -1070,7 +1075,7 @@ int fd; if (p->test_fd != -1) return; /* probe already running */ - if (squid_curtime - p->stats.last_connect_probe < Config.Timeout.connect) + if (squid_curtime - p->stats.last_connect_probe < 1) return; /* don't probe to often */ fd = comm_open(SOCK_STREAM, 0, Config.Addrs.tcp_outgoing, 0, COMM_NONBLOCKING, p->host); @@ -1222,14 +1227,20 @@ storeAppendPrintf(sentry, " no-query"); if (p->options.no_digest) storeAppendPrintf(sentry, " no-digest"); - if (p->options.default_parent) - storeAppendPrintf(sentry, " default"); - if (p->options.roundrobin) - storeAppendPrintf(sentry, " round-robin"); if (p->options.mcast_responder) storeAppendPrintf(sentry, " multicast-responder"); + if (p->weight != 1) + storeAppendPrintf(sentry, " weight=%d", p->weight); if (p->options.closest_only) storeAppendPrintf(sentry, " closest-only"); + if (p->mcast.ttl > 0) + storeAppendPrintf(sentry, " ttl=%d", p->mcast.ttl); + if (p->options.default_parent) + storeAppendPrintf(sentry, " default"); + if (p->options.roundrobin) + storeAppendPrintf(sentry, " round-robin"); + if (p->options.userhash) + storeAppendPrintf(sentry, " userhash"); #if USE_HTCP if (p->options.htcp) storeAppendPrintf(sentry, " htcp"); @@ -1242,8 +1253,29 @@ #endif if (p->login) storeAppendPrintf(sentry, " login=%s", p->login); - if (p->mcast.ttl > 0) - storeAppendPrintf(sentry, " ttl=%d", p->mcast.ttl); + if (p->connect_timeout > 0) + storeAppendPrintf(sentry, " connect-timeout=%d", p->connect_timeout); +#if USE_CACHE_DIGESTS + if (p->digest_url) + storeAppendPrintf(sentry, " digest-url=%s", p->digest_url); +#endif + if (p->options.allow_miss) + storeAppendPrintf(sentry, " allow-miss"); + if (p->max_conn > 0) + storeAppendPrintf(sentry, " max-conn=%d", p->max_conn); + if (p->options.originserver) + storeAppendPrintf(sentry, " originserver"); + /* name is used in the heading */ + if (p->monitor.url) + storeAppendPrintf(sentry, " monitorurl=%s", p->monitor.url); + if (p->monitor.min > 0 || p->monitor.max > 0) { + if (p->monitor.max > 0) + storeAppendPrintf(sentry, " monitorsize=%d:%d", p->monitor.min, p->monitor.max); + else + storeAppendPrintf(sentry, " monitorsize=%d", p->monitor.min); + } + if (p->domain) + storeAppendPrintf(sentry, " forceddomain=%s", p->domain); storeAppendPrintf(sentry, "\n"); } @@ -1258,8 +1290,10 @@ storeAppendPrintf(sentry, "There are no neighbors installed.\n"); for (e = peers; e; e = e->next) { assert(e->host != NULL); - storeAppendPrintf(sentry, "\n%-11.11s: %s/%d/%d\n", + storeAppendPrintf(sentry, "\n%-11.11s: %s\n", neighborTypeStr(e), + e->name); + storeAppendPrintf(sentry, "Host : %s/%d/%d\n", e->host, e->http_port, e->icp.port); @@ -1273,20 +1307,26 @@ neighborUp(e) ? "Up" : "Down"); storeAppendPrintf(sentry, "AVG RTT : %d msec\n", e->stats.rtt); storeAppendPrintf(sentry, "OPEN CONNS : %d\n", e->stats.conn_open); + if (!e->options.no_query) { storeAppendPrintf(sentry, "LAST QUERY : %8d seconds ago\n", (int) (squid_curtime - e->stats.last_query)); + if (e->stats.last_reply > 0) storeAppendPrintf(sentry, "LAST REPLY : %8d seconds ago\n", (int) (squid_curtime - e->stats.last_reply)); + else + storeAppendPrintf(sentry, "LAST REPLY : none received\n"); storeAppendPrintf(sentry, "PINGS SENT : %8d\n", e->stats.pings_sent); storeAppendPrintf(sentry, "PINGS ACKED: %8d %3d%%\n", e->stats.pings_acked, percent(e->stats.pings_acked, e->stats.pings_sent)); + } storeAppendPrintf(sentry, "FETCHES : %8d %3d%%\n", e->stats.fetches, percent(e->stats.fetches, e->stats.pings_acked)); storeAppendPrintf(sentry, "IGNORED : %8d %3d%%\n", e->stats.ignored_replies, percent(e->stats.ignored_replies, e->stats.pings_acked)); + if (!e->options.no_query) { storeAppendPrintf(sentry, "Histogram of PINGS ACKED:\n"); #if USE_HTCP if (e->options.htcp) { @@ -1309,6 +1349,7 @@ #if USE_HTCP } #endif + } if (e->stats.last_connect_failure) { storeAppendPrintf(sentry, "Last failed connect() at: %s\n", mkhttpdlogtime(&(e->stats.last_connect_failure))); --- /dev/null Wed Feb 14 00:52:54 2007 +++ squid/src/peer_monitor.c Wed Feb 14 00:54:34 2007 @@ -0,0 +1,215 @@ + +/* + * $Id: peer_monitor.c,v 1.1.18.1 2001/08/26 20:02:41 hno Exp $ + * + * DEBUG: section ?? Peer monitoring + * AUTHOR: Henrik Nordstrom + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#define DBG 1 +#include "squid.h" + +/* local types */ + +typedef struct { + peer *peer; + time_t last_probe; + struct { + request_t *req; + StoreEntry *e; + store_client *sc; + int size; + http_status status; + int hdr_size; + int offset; + char *buf; + } running; + char name[40]; + char url[80]; +} PeerMonitor; + +CBDATA_TYPE(PeerMonitor); + +static void peerMonitorCompleted(PeerMonitor * pm); + +static void +freePeerMonitor(void *data) +{ + PeerMonitor *pm = data; + cbdataUnlock(pm->peer); + pm->peer = NULL; +} + +static void +peerMonitorFetchReply(void *data, char *buf, ssize_t size) +{ + PeerMonitor *pm = data; + + if (size == 0) + return peerMonitorCompleted(pm); + + pm->running.size += size; + pm->running.offset += size; + storeClientCopy(pm->running.sc, pm->running.e, pm->running.offset, pm->running.offset, 4096, buf, peerMonitorFetchReply, pm); +} + +static void +peerMonitorFetchReplyHeaders(void *data, char *buf, ssize_t size) +{ + PeerMonitor *pm = data; + size_t hdr_size; + + if (EBIT_TEST(pm->running.e->flags, ENTRY_ABORTED)) + return peerMonitorCompleted(pm); + if (size == 0) + return peerMonitorCompleted(pm); + + if ((hdr_size = headersEnd(buf, size))) { + http_status status; + HttpReply *reply = pm->running.e->mem_obj->reply; + assert(reply); + /* httpReplyParse(reply, buf, hdr_size); */ + status = reply->sline.status; + pm->running.status = status; + if (status != HTTP_OK) + return peerMonitorCompleted(pm); + pm->running.size = size - hdr_size; + pm->running.offset = size; + storeClientCopy(pm->running.sc, pm->running.e, pm->running.offset, pm->running.offset, 4096, buf, peerMonitorFetchReply, pm); + } else { + /* need more data, do we have space? */ + if (size >= 4096) + peerMonitorCompleted(pm); + else + storeClientCopy(pm->running.sc, pm->running.e, size, 0, 4096, buf, peerMonitorFetchReplyHeaders, pm); + } + +} + +static void +peerMonitorRequest(void *data) +{ + PeerMonitor *pm = data; + char *url = pm->url; + request_t *req = urlParse(METHOD_GET, url); + + if (!req) { + debug(DBG, 1) ("peerMonitorRequest: Failed to parse URL '%s' for cach_peer %s\n", url, pm->peer->name); + cbdataFree(pm); + return; + } + pm->last_probe = squid_curtime; + + httpHeaderPutStr(&req->header, HDR_ACCEPT, "*/*"); + httpHeaderPutStr(&req->header, HDR_USER_AGENT, full_appname_string); + if (pm->peer->login) + xstrncpy(req->login, pm->peer->login, MAX_LOGIN_SZ); + pm->running.req = requestLink(req); + pm->running.e = storeCreateEntry(url, url, req->flags, req->method); + pm->running.sc = storeClientListAdd(pm->running.e, pm); + pm->running.buf = memAllocate(MEM_4K_BUF); + fwdStartPeer(pm->peer, pm->running.e, pm->running.req); + storeClientCopy(pm->running.sc, pm->running.e, 0, 0, 4096, pm->running.buf, peerMonitorFetchReplyHeaders, pm); + return; +} + +static void +peerMonitorCompleted(PeerMonitor * pm) +{ + int state = PEER_ALIVE; + peer *p = pm->peer; + storeUnregister(pm->running.sc, pm->running.e, pm); + storeUnlockObject(pm->running.e); + requestUnlink(pm->running.req); + memFree(pm->running.buf, MEM_4K_BUF); + /* Figure out if the response was OK or not */ + if (pm->running.status != HTTP_OK) { + debug(DBG, 1) ("peerMonitor %s: Failed, status != 200 (%d)\n", + p->name, pm->running.status); + state = PEER_DEAD; + } else if (pm->running.size < p->monitor.min) { + debug(DBG, 1) ("peerMonitor %s: Failed, reply size %d < min %d\n", + p->name, pm->running.size, p->monitor.min); + state = PEER_DEAD; + } else if (pm->running.size > p->monitor.max && p->monitor.max > 0) { + debug(DBG, 1) ("peerMonitor %s: Failed, reply size %d > max %d\n", + p->name, pm->running.size, p->monitor.max); + state = PEER_DEAD; + } else { + debug(DBG, 2) ("peerMonitor %s: OK\n"); + } + p->monitor.state = state; + if (state != p->stats.logged_state) { + switch (state) { + case PEER_ALIVE: + debug(DBG, 1) ("Detected REVIVED %s: %s\n", + neighborTypeStr(p), p->name); + break; + case PEER_DEAD: + debug(DBG, 1) ("Detected DEAD %s: %s\n", + neighborTypeStr(p), p->name); + break; + } + p->stats.logged_state = state; + } + memset(&pm->running, 0, sizeof(pm->running)); + eventAdd(pm->name, peerMonitorRequest, pm, (double) (pm->last_probe + pm->peer->monitor.interval - current_dtime), 1); +} + +static void +peerMonitorStart(peer * peer) +{ + PeerMonitor *pm; + char *url = peer->monitor.url; + if (!url || !*url) + return; + if (!peer->monitor.interval) + return; + CBDATA_INIT_TYPE_FREECB(PeerMonitor, freePeerMonitor); + pm = cbdataAlloc(PeerMonitor); + snprintf(pm->name, sizeof(pm->name), "monitor %s", peer->name); + pm->peer = peer; + cbdataLock(pm->peer); + if (*url == '/') { + snprintf(pm->url, sizeof(pm->url), "http://%s:%d%s", + pm->peer->host, pm->peer->http_port, url); + } else { + xstrncpy(pm->url, url, sizeof(pm->url)); + } + peerMonitorRequest(pm); +} + +void +peerMonitorInit(void) +{ + peer *p; + for (p = Config.peers; p; p = p->next) + peerMonitorStart(p); +} Index: squid/src/peer_select.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/peer_select.c,v retrieving revision 1.9 retrieving revision 1.9.26.1 diff -u -r1.9 -r1.9.26.1 --- squid/src/peer_select.c 14 Apr 2001 00:31:02 -0000 1.9 +++ squid/src/peer_select.c 26 Aug 2001 20:02:41 -0000 1.9.26.1 @@ -1,6 +1,6 @@ /* - * $Id: peer_select.c,v 1.9 2001/04/14 00:31:02 squidadm Exp $ + * $Id: peer_select.c,v 1.9.26.1 2001/08/26 20:02:41 hno Exp $ * * DEBUG: section 44 Peer Selection Algorithm * AUTHOR: Duane Wessels @@ -59,6 +59,7 @@ "CARP", #endif "ANY_PARENT", + "USERHASH_PARENT", "INVALID CODE" }; @@ -90,7 +91,6 @@ static void peerGetSomeDirect(ps_state *); static void peerGetSomeParent(ps_state *); static void peerGetAllParents(ps_state *); -static void peerAddFwdServer(FwdServer **, peer *, hier_code); static void peerSelectStateFree(ps_state * psstate) @@ -443,6 +443,8 @@ return; if ((p = getDefaultParent(request))) { code = DEFAULT_PARENT; + } else if ((p = peerUserHashSelectParent(request))) { + code = USERHASH_PARENT; } else if ((p = getRoundRobinParent(request))) { code = ROUNDROBIN_PARENT; } else if ((p = getFirstUpParent(request))) { @@ -642,7 +644,7 @@ debug(44, 1) ("peerHandlePingReply: unknown protocol_t %d\n", (int) proto); } -static void +void peerAddFwdServer(FwdServer ** FS, peer * p, hier_code code) { FwdServer *fs = memAllocate(MEM_FWD_SERVER); --- /dev/null Wed Feb 14 00:52:54 2007 +++ squid/src/peer_userhash.c Wed Feb 14 00:54:34 2007 @@ -0,0 +1,164 @@ + +/* + * $Id: peer_userhash.c,v 1.1.18.1 2001/08/26 20:02:41 hno Exp $ + * + * DEBUG: section 44 Peer user hash based selection + * AUTHOR: Henrik Nordstrom + * BASED ON: carp.c by Eric Stern + * + * SQUID Web Proxy Cache http://www.squid-cache.org/ + * ---------------------------------------------------------- + * + * Squid is the result of efforts by numerous individuals from + * the Internet community; see the CONTRIBUTORS file for full + * details. Many organizations have provided support for Squid's + * development; see the SPONSORS file for full details. Squid is + * Copyrighted (C) 2001 by the Regents of the University of + * California; see the COPYRIGHT file for full details. Squid + * incorporates software developed and/or copyrighted by other + * sources; see the CREDITS file for full details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + * + */ + +#include "squid.h" + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (((sizeof(unsigned long)*8)-(n))))) + +static int n_userhash_peers = 0; +static peer **userhash_peers = NULL; + +static int +peerSortWeight(const void *a, const void *b) +{ + const peer *p1 = a, *p2 = b; + return p1->weight - p2->weight; +} + +void +peerUserHashInit(void) +{ + int W = 0; + int K; + int k; + double P_last, X_last, Xn; + peer *p; + peer **P; + char *t; + /* Clean up */ + for (k = 0; k < n_userhash_peers; k++) { + cbdataUnlock(userhash_peers[k]); + } + safe_free(userhash_peers); + n_userhash_peers = 0; + /* find out which peers we have */ + for (p = Config.peers; p; p = p->next) { + if (!p->options.userhash) + continue; + assert(p->type == PEER_PARENT); + if (p->weight == 0) + continue; + n_userhash_peers++; + W += p->weight; + } + if (n_userhash_peers == 0) + return; + userhash_peers = xcalloc(n_userhash_peers, sizeof(*userhash_peers)); + /* Build a list of the found peers and calculate hashes and load factors */ + for (P = userhash_peers, p = Config.peers; p; p = p->next) { + if (!p->options.userhash) + continue; + if (p->weight == 0) + continue; + /* calculate this peers hash */ + p->userhash.hash = 0; + for (t = p->host; *t != 0; t++) + p->userhash.hash += ROTATE_LEFT(p->userhash.hash, 19) + (unsigned int) *t; + p->userhash.hash += p->userhash.hash * 0x62531965; + p->userhash.hash = ROTATE_LEFT(p->userhash.hash, 21); + /* and load factor */ + p->userhash.load_factor = ((double) p->weight) / (double) W; + if (floor(p->userhash.load_factor * 1000.0) == 0.0) + p->userhash.load_factor = 0.0; + /* add it to our list of peers */ + *P++ = p; + cbdataLock(p); + } + /* Sort our list on weight */ + qsort(userhash_peers, n_userhash_peers, sizeof(*userhash_peers), peerSortWeight); + /* Calculate the load factor multipliers X_k + * + * X_1 = pow ((K*p_1), (1/K)) + * X_k = ([K-k+1] * [P_k - P_{k-1}])/(X_1 * X_2 * ... * X_{k-1}) + * X_k += pow ((X_{k-1}, {K-k+1}) + * X_k = pow (X_k, {1/(K-k+1)}) + * simplified to have X_1 part of the loop + */ + K = n_userhash_peers; + P_last = 0.0; /* Empty P_0 */ + Xn = 1.0; /* Empty starting point of X_1 * X_2 * ... * X_{x-1} */ + X_last = 0.0; /* Empty X_0, nullifies the first pow statement */ + for (k = 1; k <= K; k++) { + double Kk1 = (double) (K - k + 1); + p = userhash_peers[k - 1]; + p->userhash.load_multiplier = (Kk1 * (p->userhash.load_factor - P_last)) / Xn; + p->userhash.load_multiplier += pow(X_last, Kk1); + p->userhash.load_multiplier = pow(p->userhash.load_multiplier, 1.0 / Kk1); + Xn *= p->userhash.load_multiplier; + X_last = p->userhash.load_multiplier; + P_last = p->userhash.load_factor; + } +} + +peer * +peerUserHashSelectParent(request_t * request) +{ + int k; + const char *c; + peer *p = NULL; + peer *tp; + unsigned long user_hash = 0; + unsigned long combined_hash; + unsigned long high_score = 0; + const char *user = NULL; + /* Find the username */ + if (request->auth_user_request) { + user = authenticateUserRequestUsername(request->auth_user_request); + } + if (!user) + return NULL; + /* calculate username hash */ + debug(39, 2) ("carpSelectParent: userhash Calculating hash for %s\n", user); + for (c = user; *c != 0; c++) + user_hash += ROTATE_LEFT(user_hash, 19) + *c; + /* select peer */ + for (k = 0; k < n_userhash_peers; k++) { + tp = userhash_peers[k]; + combined_hash = (user_hash ^ tp->userhash.hash); + combined_hash += combined_hash * 0x62531965; + combined_hash = ROTATE_LEFT(combined_hash, 21); + combined_hash = combined_hash * tp->userhash.load_multiplier; + debug(39, 3) ("carpSelectParent: %s combined_hash %d\n", + tp->host, combined_hash); + if ((combined_hash > high_score) && peerHTTPOkay(tp, request)) { + p = tp; + high_score = combined_hash; + } + } + if (p) + debug(39, 3) ("carpSelectParent: selected CARP %s\n", p->host); + return p; +} Index: squid/src/protos.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/protos.h,v retrieving revision 1.32 retrieving revision 1.32.4.1 diff -u -r1.32 -r1.32.4.1 --- squid/src/protos.h 16 Aug 2001 07:39:03 -0000 1.32 +++ squid/src/protos.h 26 Aug 2001 20:02:41 -0000 1.32.4.1 @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.32 2001/08/16 07:39:03 squidadm Exp $ + * $Id: protos.h,v 1.32.4.1 2001/08/26 20:02:41 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -647,7 +647,7 @@ extern void neighborAddAcl(const char *, const char *); extern void neighborsUdpAck(const cache_key *, icp_common_t *, const struct sockaddr_in *); extern void neighborAdd(const char *, const char *, int, int, int, int, int); -extern void neighbors_open(int); +extern void neighbors_init(void); extern peer *peerFindByName(const char *); extern peer *peerFindByNameAndPort(const char *, unsigned short); extern peer *getDefaultParent(request_t * request); @@ -670,6 +670,7 @@ #if USE_HTCP extern void neighborsHtcpReply(const cache_key *, htcpReplyData *, const struct sockaddr_in *); #endif +extern void peerAddFwdServer(FwdServer ** FS, peer * p, hier_code code); extern void netdbInit(void); extern void netdbHandlePingReply(const struct sockaddr_in *from, int hops, int rtt); @@ -705,6 +706,7 @@ /* forward.c */ extern void fwdStart(int, StoreEntry *, request_t *); +extern void fwdStartPeer(peer *, StoreEntry *, request_t *); extern DEFER fwdCheckDeferRead; extern void fwdFail(FwdState *, ErrorState *); extern void fwdUnregister(int fd, FwdState *); @@ -724,6 +726,10 @@ extern void redirectInit(void); extern void redirectShutdown(void); +extern void locationRewriteStart(HttpReply *, clientHttpRequest *, RH *, void *); +extern void locationRewriteInit(void); +extern void locationRewriteShutdown(void); + /* auth_modules.c */ extern void authSchemeSetup(void); @@ -1127,6 +1133,7 @@ extern void errorStateFree(ErrorState * err); extern int errorReservePageId(const char *page_name); extern ErrorState *errorCon(err_type type, http_status); +extern int errorPageId(const char *page_name); extern void pconnPush(int, const char *host, u_short port); extern int pconnPop(const char *host, u_short port); @@ -1222,6 +1229,9 @@ extern peer *carpSelectParent(request_t *); #endif +extern void peerUserHashInit(void); +extern peer *peerUserHashSelectParent(request_t *); + #if DELAY_POOLS extern void delayPoolsInit(void); extern void delayInitDelayData(unsigned short pools); @@ -1316,3 +1326,24 @@ extern int WIN32_Subsystem_Init(void); extern void WIN32_Exit(void); #endif + +/* peer_monitor.c */ +extern void peerMonitorInit(void); + +/* errormap.c */ +extern void errorMapInit(void); +extern int errorMapStart(const errormap *map, request_t *req, HttpReply *reply, const char *aclname, ERRMAPCB *callback, void *data); + +/* external_acl.c */ +extern void parse_externalAclHelper(external_acl **); +extern void dump_externalAclHelper(StoreEntry *sentry, char *name, external_acl *); +extern void free_externalAclHelper(external_acl **); +extern void aclParseExternal(void *curlist); +extern void aclDestroyExternal(void **curlust); +extern int aclMatchExternal(void *dataptr, aclCheck_t *ch); +extern wordlist *aclDumpExternal(void *dataptr); +typedef void EAH(int result, void *data); +extern void externalAclLookup(aclCheck_t *ch, void *acl_data, EAH *handler, void *data); +extern void externalAclInit(void); +extern void externalAclShutdown(void); + Index: squid/src/redirect.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/redirect.c,v retrieving revision 1.7 retrieving revision 1.7.44.1 diff -u -r1.7 -r1.7.44.1 --- squid/src/redirect.c 3 Mar 2001 10:44:32 -0000 1.7 +++ squid/src/redirect.c 26 Aug 2001 20:02:41 -0000 1.7.44.1 @@ -1,6 +1,6 @@ /* - * $Id: redirect.c,v 1.7 2001/03/03 10:44:32 squidadm Exp $ + * $Id: redirect.c,v 1.7.44.1 2001/08/26 20:02:41 hno Exp $ * * DEBUG: section 29 Redirector * AUTHOR: Duane Wessels @@ -96,22 +96,23 @@ ConnStateData *conn = http->conn; redirectStateData *r = NULL; const char *fqdn; + char *urlgroup = conn->port->urlgroup; char buf[8192]; assert(http); assert(handler); debug(29, 5) ("redirectStart: '%s'\n", http->uri); - if (Config.Program.redirect == NULL) { + if (Config.Program.url_rewrite.command == NULL) { handler(data, NULL); return; } - if (Config.accessList.redirector) { + if (Config.accessList.url_rewrite) { aclCheck_t ch; memset(&ch, '\0', sizeof(ch)); ch.src_addr = http->conn->peer.sin_addr; ch.my_addr = http->conn->me.sin_addr; ch.my_port = ntohs(http->conn->me.sin_port); ch.request = http->request; - if (!aclCheckFast(Config.accessList.redirector, &ch)) { + if (!aclCheckFast(Config.accessList.url_rewrite, &ch)) { /* denied -- bypass redirector */ handler(data, NULL); return; @@ -139,12 +140,13 @@ cbdataLock(r->data); if ((fqdn = fqdncache_gethostbyaddr(r->client_addr, 0)) == NULL) fqdn = dash_str; - snprintf(buf, 8192, "%s %s/%s %s %s\n", + snprintf(buf, 8192, "%s %s/%s %s %s %s\n", r->orig_url, inet_ntoa(r->client_addr), fqdn, r->client_ident, - r->method_s); + r->method_s, + urlgroup ? urlgroup : "-"); helperSubmit(redirectors, buf, redirectHandleReply, r); } @@ -152,17 +154,17 @@ redirectInit(void) { static int init = 0; - if (!Config.Program.redirect) + if (!Config.Program.url_rewrite.command) return; if (redirectors == NULL) - redirectors = helperCreate("redirector"); - redirectors->cmdline = Config.Program.redirect; - redirectors->n_to_start = Config.redirectChildren; + redirectors = helperCreate("url_rewriter"); + redirectors->cmdline = Config.Program.url_rewrite.command; + redirectors->n_to_start = Config.Program.url_rewrite.children; redirectors->ipc_type = IPC_TCP_SOCKET; helperOpenServers(redirectors); if (!init) { - cachemgrRegister("redirector", - "URL Redirector Stats", + cachemgrRegister("url_rewriter", + "URL Rewriter Stats", redirectStats, 0, 1); init = 1; CBDATA_INIT_TYPE(redirectStateData); Index: squid/src/snmp_agent.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/snmp_agent.c,v retrieving revision 1.6 retrieving revision 1.6.56.1 diff -u -r1.6 -r1.6.56.1 --- squid/src/snmp_agent.c 7 Feb 2001 19:11:48 -0000 1.6 +++ squid/src/snmp_agent.c 26 Aug 2001 20:02:41 -0000 1.6.56.1 @@ -1,6 +1,6 @@ /* - * $Id: snmp_agent.c,v 1.6 2001/02/07 19:11:48 hno Exp $ + * $Id: snmp_agent.c,v 1.6.56.1 2001/08/26 20:02:41 hno Exp $ * * DEBUG: section 49 SNMP Interface * AUTHOR: Kostas Anagnostakis @@ -146,21 +146,46 @@ { variable_list *Answer = NULL; struct in_addr *laddr; + int loop, index = 0; char *cp = NULL; peer *p = NULL; int cnt = 0; debug(49, 5) ("snmp_meshPtblFn: peer %d requested!\n", Var->name[LEN_SQ_MESH + 3]); *ErrP = SNMP_ERR_NOERROR; + switch (Var->name[LEN_SQ_MESH + 1]) { + case 1: laddr = oid2addr(&Var->name[LEN_SQ_MESH + 3]); - for (p = Config.peers; p != NULL; p = p->next, cnt++) + for (p = Config.peers; p != NULL; p = p->next, cnt++) { + index++; if (p->in_addr.sin_addr.s_addr == laddr->s_addr) break; + } + break; + case 2: + index = Var->name[LEN_SQ_MESH + 3]; + loop = 1; + p = Config.peers; + while(loop != index && p != NULL) { + loop++; + p = p->next; + } + break; + default: + break; + } if (p == NULL) { *ErrP = SNMP_ERR_NOSUCHNAME; return NULL; } switch (Var->name[LEN_SQ_MESH + 2]) { case MESH_PTBL_NAME: + cp = p->name; + Answer = snmp_var_new(Var->name, Var->name_length); + Answer->type = ASN_OCTET_STR; + Answer->val_len = strlen(cp); + Answer->val.string = (u_char *) xstrdup(cp); + break; + case MESH_PTBL_HOST: cp = p->host; Answer = snmp_var_new(Var->name, Var->name_length); Answer->type = ASN_OCTET_STR; @@ -195,12 +220,12 @@ case MESH_PTBL_SENT: Answer = snmp_var_new_integer(Var->name, Var->name_length, p->stats.pings_sent, - ASN_INTEGER); + SMI_COUNTER32); break; case MESH_PTBL_PACKED: Answer = snmp_var_new_integer(Var->name, Var->name_length, p->stats.pings_acked, - ASN_INTEGER); + SMI_COUNTER32); break; case MESH_PTBL_FETCHES: Answer = snmp_var_new_integer(Var->name, Var->name_length, @@ -227,6 +252,11 @@ p->stats.n_keepalives_recv, SMI_COUNTER32); break; + case MESH_PTBL_INDEX: + Answer = snmp_var_new_integer(Var->name, Var->name_length, + index, + ASN_INTEGER); + break; default: *ErrP = SNMP_ERR_NOSUCHNAME; break; Index: squid/src/snmp_core.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/snmp_core.c,v retrieving revision 1.7 retrieving revision 1.7.12.1 diff -u -r1.7 -r1.7.12.1 --- squid/src/snmp_core.c 28 May 2001 04:24:15 -0000 1.7 +++ squid/src/snmp_core.c 26 Aug 2001 20:02:41 -0000 1.7.12.1 @@ -1,6 +1,6 @@ /* - * $Id: snmp_core.c,v 1.7 2001/05/28 04:24:15 squidadm Exp $ + * $Id: snmp_core.c,v 1.7.12.1 2001/08/26 20:02:41 hno Exp $ * * DEBUG: section 49 SNMP support * AUTHOR: Glenn Chisholm @@ -65,6 +65,7 @@ static oid *static_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); static oid *time_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); static oid *peer_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); +static oid *peer_InstIndex(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); static oid *client_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); static void snmpDecodePacket(snmp_request_t * rq); static void snmpConstructReponse(snmp_request_t * rq); @@ -280,9 +281,9 @@ snmpAddNode(snmpCreateOid(LEN_SQ_MESH, SQ_MESH), LEN_SQ_MESH, NULL, NULL, 2, snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 1, SQ_MESH, 1), - LEN_SQ_MESH + 1, NULL, NULL, 1, + LEN_SQ_MESH + 1, NULL, NULL, 2, snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 2, SQ_MESH, 1, 1), - LEN_SQ_MESH + 2, NULL, NULL, 13, + LEN_SQ_MESH + 2, NULL, NULL, 14, snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 1), LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_Inst, 0), snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 2), @@ -308,7 +309,41 @@ snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 12), LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_Inst, 0), snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 13), - LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_Inst, 0))), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_Inst, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 1, 15), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_Inst, 0)), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 2, SQ_MESH, 1, 2), + LEN_SQ_MESH + 2, NULL, NULL, 15, + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 1), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 2), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 3), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 4), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 5), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 6), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 7), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 8), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 9), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 10), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 11), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 12), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 13), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 14), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0), + snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 3, SQ_MESH, 1, 2, 15), + LEN_SQ_MESH + 3, snmp_meshPtblFn, peer_InstIndex, 0))), snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 1, SQ_MESH, 2), LEN_SQ_MESH + 1, NULL, NULL, 1, snmpAddNode(snmpCreateOid(LEN_SQ_MESH + 2, SQ_MESH, 2, 1), @@ -779,19 +814,17 @@ { oid *instance = NULL; u_char *cp = NULL; - peer *peers = Config.peers; + peer *peerptr = Config.peers; + peer *peerptr2; struct in_addr *laddr = NULL; char *host_addr = NULL, *current_addr = NULL, *last_addr = NULL; - if (peers == NULL) { - current = current->parent->parent->parent->leaves[1]; - while ((current) && (!current->parsefunction)) - current = current->leaves[0]; - instance = client_Inst(current->name, len, current, Fn); + if (peerptr == NULL) { + /* Do nothing */ } else if (*len <= current->len) { instance = xmalloc(sizeof(name) * (*len + 4)); xmemcpy(instance, name, (sizeof(name) * *len)); - cp = (u_char *) & (peers->in_addr.sin_addr.s_addr); + cp = (u_char *) & (peerptr->in_addr.sin_addr.s_addr); instance[*len] = *cp++; instance[*len + 1] = *cp++; instance[*len + 2] = *cp++; @@ -800,33 +833,74 @@ } else { laddr = oid2addr(&name[*len - 4]); host_addr = inet_ntoa(*laddr); - last_addr = xmalloc(strlen(host_addr)); - strncpy(last_addr, host_addr, strlen(host_addr)); - current_addr = inet_ntoa(peers->in_addr.sin_addr); - while ((peers) && (strncmp(last_addr, current_addr, strlen(current_addr)))) { - if (peers->next) { - peers = peers->next; - current_addr = inet_ntoa(peers->in_addr.sin_addr); - } else { - peers = NULL; + last_addr = xstrdup(host_addr); +skip_duplicate: + current_addr = inet_ntoa(peerptr->in_addr.sin_addr); + while (peerptr && strcmp(last_addr, current_addr) != 0) { + peerptr = peerptr->next; + if (peerptr) + current_addr = inet_ntoa(peerptr->in_addr.sin_addr); + } + + /* Find the next peer */ + if (peerptr) + peerptr = peerptr->next; + + /* watch out for duplicate addresses */ + for (peerptr2 = Config.peers; peerptr && peerptr2 != peerptr; peerptr2 = peerptr2->next) { + if (peerptr2->in_addr.sin_addr.s_addr == peerptr->in_addr.sin_addr.s_addr) { + /* ouch.. there are more than one peer on this IP. Skip the second one */ + peerptr = peerptr->next; + if (peerptr) + goto skip_duplicate; } } + xfree(last_addr); - if (peers) { - if (peers->next) { - peers = peers->next; + + if (peerptr) { instance = xmalloc(sizeof(name) * (*len)); xmemcpy(instance, name, (sizeof(name) * *len)); - cp = (u_char *) & (peers->in_addr.sin_addr.s_addr); + cp = (u_char *) & (peerptr->in_addr.sin_addr.s_addr); instance[*len - 4] = *cp++; instance[*len - 3] = *cp++; instance[*len - 2] = *cp++; instance[*len - 1] = *cp++; - } else { + } + } + *Fn = current->parsefunction; return (instance); } + +static oid * +peer_InstIndex(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn) +{ + oid *instance = NULL; + + if (!Config.peers) { + /* Do nothing */ + } else if (*len <= current->len) { + instance = xmalloc(sizeof(name) * (*len + 1)); + xmemcpy(instance, name, (sizeof(name) * *len)); + instance[*len] = 1; + *len += 1; } else { - return (instance); + int identifier, loop = 1; /* our index starts at 1 */ + peer *p = Config.peers; + identifier = name[*len - 1]; + + /* We want the next one... */ + identifier += 1; + + /* Make sure it exists */ + while ((identifier != loop) && (p != NULL)) { + loop++; + p = p->next; + } + if (p != NULL) { + instance = xmalloc(sizeof(name) * (*len)); + xmemcpy(instance, name, (sizeof(name) * *len)); + instance[*len - 1] = loop; } } *Fn = current->parsefunction; Index: squid/src/ssl_support.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/ssl_support.c,v retrieving revision 1.3 retrieving revision 1.3.16.1 diff -u -r1.3 -r1.3.16.1 --- squid/src/ssl_support.c 4 May 2001 13:39:12 -0000 1.3 +++ squid/src/ssl_support.c 26 Aug 2001 20:02:41 -0000 1.3.16.1 @@ -137,18 +137,23 @@ debug(81, 1) ("Using certificate in %s\n", certfile); if (!SSL_CTX_use_certificate_file(sslContext, certfile, SSL_FILETYPE_PEM)) { ssl_error = ERR_get_error(); - fatalf("Failed to acquire SSL certificate: %s\n", - ERR_error_string(ssl_error, NULL)); + debug(81, 0) ("Failed to acquire SSL certificate %s: %s\n", + certfile, ERR_error_string(ssl_error, NULL)); + return NULL; } debug(81, 1) ("Using private key in %s\n", keyfile); if (!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)) { ssl_error = ERR_get_error(); - fatalf("Failed to acquire SSL private key: %s\n", - ERR_error_string(ssl_error, NULL)); + debug(81, 0) ("Failed to acquire SSL private key %s: %s\n", + keyfile, ERR_error_string(ssl_error, NULL)); + return NULL; } debug(81, 5) ("Comparing private and public SSL keys.\n"); - if (!SSL_CTX_check_private_key(sslContext)) - fatal("SSL private key does not match public key: %s\n"); + if (!SSL_CTX_check_private_key(sslContext)) { + debug(81, 0) ("SSL private key %s does not match public key %s\n", + keyfile, certfile); + return NULL; + } debug(81, 9) ("Setting RSA key generation callback.\n"); SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb); Index: squid/src/store_key_md5.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/store_key_md5.c,v retrieving revision 1.6 retrieving revision 1.6.26.1 diff -u -r1.6 -r1.6.26.1 --- squid/src/store_key_md5.c 14 Apr 2001 00:31:02 -0000 1.6 +++ squid/src/store_key_md5.c 26 Aug 2001 20:02:41 -0000 1.6.26.1 @@ -1,6 +1,6 @@ /* - * $Id: store_key_md5.c,v 1.6 2001/04/14 00:31:02 squidadm Exp $ + * $Id: store_key_md5.c,v 1.6.26.1 2001/08/26 20:02:41 hno Exp $ * * DEBUG: section 20 Storage Manager MD5 Cache Keys * AUTHOR: Duane Wessels @@ -138,6 +138,10 @@ MD5Update(&M, (unsigned char *) url, strlen(url)); if (request->vary_headers) MD5Update(&M, (unsigned char *) request->vary_headers, strlen(request->vary_headers)); + if (request->urlgroup) { + MD5Update(&M, (unsigned char *) " ", 1); + MD5Update(&M, (unsigned char *) request->urlgroup, strlen(request->urlgroup)); + } MD5Final(digest, &M); return digest; } Index: squid/src/structs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/structs.h,v retrieving revision 1.38 retrieving revision 1.38.6.1 diff -u -r1.38 -r1.38.6.1 --- squid/src/structs.h 12 Aug 2001 15:20:28 -0000 1.38 +++ squid/src/structs.h 26 Aug 2001 20:02:41 -0000 1.38.6.1 @@ -1,6 +1,6 @@ /* - * $Id: structs.h,v 1.38 2001/08/12 15:20:28 squidadm Exp $ + * $Id: structs.h,v 1.38.6.1 2001/08/26 20:02:41 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -311,12 +311,24 @@ sockaddr_in_list *next; }; +struct _http_port_list { + http_port_list *next; + struct sockaddr_in s; + char *protocol; /* protocol name */ + char *name; /* visible name */ + char *defaultsite; /* default web site */ + char *urlgroup; /* default urlgroup */ + unsigned int transparent:1; /* transparent proxy */ + unsigned int vhost:1; /* uses host header */ + unsigned int vport:1; /* virtual port support */ +}; + #if USE_SSL struct _https_port_list { - https_port_list *next; - struct sockaddr_in s; + http_port_list http; /* must be first */ char *cert; char *key; + SSL_CTX *sslContext; }; #endif @@ -408,7 +420,7 @@ #endif } Port; struct { - sockaddr_in_list *http; + http_port_list *http; #if USE_SSL https_port_list *https; #endif @@ -451,7 +463,14 @@ #if USE_DNSSERVERS char *dnsserver; #endif - wordlist *redirect; + struct { + wordlist *command; + int children; + } url_rewrite; + struct { + wordlist *command; + int children; + } location_rewrite; #if USE_ICMP char *pinger; #endif @@ -463,15 +482,9 @@ #if USE_DNSSERVERS int dnsChildren; #endif - int redirectChildren; time_t authenticateGCInterval; time_t authenticateTTL; time_t authenticateIpTTL; - struct { - int single_host; - char *host; - u_short port; - } Accel; char *appendDomain; size_t appendDomainLen; char *debugOptions; @@ -546,7 +559,6 @@ int log_mime_hdrs; int log_fqdn; int announce; - int accel_with_proxy; int mem_pools; int test_reachability; int half_closed_clients; @@ -569,10 +581,12 @@ int ie_refresh; int vary_ignore_expire; int pipeline_prefetch; + int via; } onoff; acl *aclList; struct { acl_access *http; + acl_access *http2; acl_access *icp; acl_access *miss; acl_access *NeverDirect; @@ -586,7 +600,8 @@ #if USE_IDENT acl_access *identLookup; #endif - acl_access *redirector; + acl_access *url_rewrite; + acl_access *location_rewrite; acl_access *reply; } accessList; acl_deny_info_list *denyInfoList; @@ -666,14 +681,14 @@ size_t high_memory; } warnings; char *store_dir_select_algorithm; + errormap *errorMapList; + external_acl *externalAclHelperList; + time_t externalAclTTL; + int externalAclChildren; }; struct _SquidConfig2 { struct { - char *prefix; - int on; - } Accel; - struct { int enable_purge; } onoff; uid_t effectiveUserID; @@ -935,6 +950,7 @@ unsigned int proxying:1; unsigned int keepalive:1; unsigned int only_if_cached:1; + unsigned int originpeer:1; }; struct _HttpStateData { @@ -1020,6 +1036,7 @@ struct _clientHttpRequest { ConnStateData *conn; request_t *request; /* Parsed URL ... */ + request_t *orig_request; /* Parsed URL ... */ store_client *sc; /* The store_client we're using */ store_client *old_sc; /* ... for entry to be validated */ char *uri; @@ -1085,6 +1102,7 @@ int n; time_t until; } defer; + http_port_list *port; }; struct _ipcache_addrs { @@ -1188,6 +1206,7 @@ #endif struct _peer { + char *name; char *host; peer_t type; struct sockaddr_in in_addr; @@ -1239,6 +1258,8 @@ unsigned int no_delay:1; #endif unsigned int allow_miss:1; + unsigned int originserver:1; + unsigned int userhash:1; } options; int weight; struct { @@ -1270,9 +1291,22 @@ float load_factor; } carp; #endif + struct { + unsigned int hash; + double load_multiplier; + float load_factor; + } userhash; char *login; /* Proxy authorization */ time_t connect_timeout; int max_conn; + struct { + char *url; + ssize_t min,max; + int interval; + int timeout; + int state; + } monitor; + char *domain; /* Forced domain */ }; struct _net_db_name { @@ -1562,7 +1596,7 @@ unsigned int hierarchical:1; unsigned int loopdetect:1; unsigned int proxy_keepalive:1; - unsigned int proxying:1; + unsigned int proxying:1; /* this should be killed, also in httpstateflags */ unsigned int refresh:1; unsigned int redirected:1; unsigned int need_validation:1; @@ -1628,6 +1662,8 @@ 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 */ + char *urlgroup; /* urlgroup, returned by redirectors */ + char *peer_domain; /* Configured peer forceddomain */ }; struct _cachemgr_passwd { @@ -2135,3 +2171,14 @@ void (*parse) (SwapDir * sd, const char *option, const char *value, int reconfiguring); void (*dump) (StoreEntry * e, const char *option, SwapDir * sd); }; + +struct error_map_entry { + struct error_map_entry *next; + char *value; + int status; +}; +struct _errormap { + errormap *next; + char *url; + struct error_map_entry *map; +}; Index: squid/src/typedefs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/typedefs.h,v retrieving revision 1.23 retrieving revision 1.23.6.1 diff -u -r1.23 -r1.23.6.1 --- squid/src/typedefs.h 12 Aug 2001 15:20:28 -0000 1.23 +++ squid/src/typedefs.h 26 Aug 2001 20:02:41 -0000 1.23.6.1 @@ -1,6 +1,6 @@ /* - * $Id: typedefs.h,v 1.23 2001/08/12 15:20:28 squidadm Exp $ + * $Id: typedefs.h,v 1.23.6.1 2001/08/26 20:02:41 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -82,6 +82,7 @@ typedef struct _ushortlist ushortlist; typedef struct _relist relist; typedef struct _sockaddr_in_list sockaddr_in_list; +typedef struct _http_port_list http_port_list; typedef struct _https_port_list https_port_list; typedef struct _SquidConfig SquidConfig; typedef struct _SquidConfig2 SquidConfig2; @@ -190,6 +191,7 @@ typedef struct _RemovalPurgeWalker RemovalPurgeWalker; typedef struct _RemovalPolicyNode RemovalPolicyNode; typedef struct _RemovalPolicySettings RemovalPolicySettings; +typedef struct _errormap errormap; typedef struct _http_version_t http_version_t; @@ -358,4 +360,8 @@ typedef int STDIRSELECT(const StoreEntry *); +typedef void ERRMAPCB(StoreEntry *, int body_offset, ssize_t content_length, void *data); + +typedef struct _external_acl external_acl; + #endif /* _TYPEDEFS_H_ */