You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by sf...@apache.org on 2010/09/25 17:16:17 UTC
svn commit: r1001234 - /httpd/httpd/trunk/modules/aaa/mod_authz_host.c
Author: sf
Date: Sat Sep 25 15:16:16 2010
New Revision: 1001234
URL: http://svn.apache.org/viewvc?rev=1001234&view=rev
Log:
in 'ip' authz provider, parse subnets only once on startup instead of once per
request
Modified:
httpd/httpd/trunk/modules/aaa/mod_authz_host.c
Modified: httpd/httpd/trunk/modules/aaa/mod_authz_host.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/aaa/mod_authz_host.c?rev=1001234&r1=1001233&r2=1001234&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/aaa/mod_authz_host.c (original)
+++ httpd/httpd/trunk/modules/aaa/mod_authz_host.c Sat Sep 25 15:16:16 2010
@@ -24,6 +24,7 @@
#include "apr_strings.h"
#include "apr_network_io.h"
#include "apr_md5.h"
+#include "apr_hash.h"
#define APR_WANT_STRFUNC
#define APR_WANT_BYTEFUNC
@@ -44,6 +45,17 @@
#include <netinet/in.h>
#endif
+/*
+ * To save memory if the same subnets are used in hundres of vhosts, we store
+ * each subnet only once and use this temporary hash to find it again.
+ */
+static apr_hash_t *parsed_subnets;
+
+static apr_ipsubnet_t *localhost_v4;
+#if APR_HAVE_IPV6
+static apr_ipsubnet_t *localhost_v6;
+#endif
+
static int in_domain(const char *domain, const char *what)
{
int dl = strlen(domain);
@@ -71,56 +83,77 @@ static int in_domain(const char *domain,
}
}
-static authz_status ip_check_authorization(request_rec *r,
- const char *require_line,
- const void *parsed_require_line)
+static const char *ip_parse_config(cmd_parms *cmd,
+ const char *require_line,
+ const void **parsed_require_line)
{
const char *t, *w;
+ int count = 0;
+ apr_ipsubnet_t **ip;
+ apr_pool_t *ptemp = cmd->temp_pool;
+ apr_pool_t *p = cmd->pool;
/* The 'ip' provider will allow the configuration to specify a list of
ip addresses to check rather than a single address. This is different
from the previous host based syntax. */
+
t = require_line;
- while ((w = ap_getword_conf(r->pool, &t)) && w[0]) {
- char *where = apr_pstrdup(r->pool, w);
- char *s;
- char msgbuf[120];
- apr_ipsubnet_t *ip;
+ while ((w = ap_getword_conf(ptemp, &t)) && w[0])
+ count++;
+
+ if (count == 0)
+ return "'require ip' requires an argument";
+
+ ip = apr_pcalloc(p, sizeof(apr_ipsubnet_t *) * (count + 1));
+ *parsed_require_line = ip;
+
+ t = require_line;
+ while ((w = ap_getword_conf(ptemp, &t)) && w[0]) {
+ char *addr = apr_pstrdup(ptemp, w);
+ char *mask;
apr_status_t rv;
- int got_ip = 0;
- if ((s = ap_strchr(where, '/'))) {
- *s++ = '\0';
- rv = apr_ipsubnet_create(&ip, where, s, r->pool);
- if(APR_STATUS_IS_EINVAL(rv)) {
- /* looked nothing like an IP address */
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "an ip address 'require' list appears to be invalid ");
- }
- else if (rv != APR_SUCCESS) {
- apr_strerror(rv, msgbuf, sizeof msgbuf);
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "an ip address 'require' list appears to be invalid; %s ",
- msgbuf);
- }
- else
- got_ip = 1;
+ *ip = apr_hash_get(parsed_subnets, w, APR_HASH_KEY_STRING);
+ if (*ip) {
+ /* we already have parsed this subnet */
+ ip++;
+ continue;
}
- else if (!APR_STATUS_IS_EINVAL(rv = apr_ipsubnet_create(&ip, where,
- NULL, r->pool))) {
- if (rv != APR_SUCCESS) {
- apr_strerror(rv, msgbuf, sizeof msgbuf);
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "an ip address 'require' list appears to be invalid; %s ",
- msgbuf);
- }
- else
- got_ip = 1;
+
+ if ((mask = ap_strchr(addr, '/')))
+ *mask++ = '\0';
+
+ rv = apr_ipsubnet_create(ip, addr, mask, p);
+
+ if(APR_STATUS_IS_EINVAL(rv)) {
+ /* looked nothing like an IP address */
+ return apr_psprintf(p, "ip address '%s' appears to be invalid", w);
}
+ else if (rv != APR_SUCCESS) {
+ char msgbuf[120];
+ apr_strerror(rv, msgbuf, sizeof msgbuf);
+ return apr_psprintf(p, "ip address '%s' appears to be invalid: %s",
+ w, msgbuf);
+ }
+
+ apr_hash_set(parsed_subnets, w, APR_HASH_KEY_STRING, *ip);
+ ip++;
+ }
+
+ return NULL;
+}
+
+static authz_status ip_check_authorization(request_rec *r,
+ const char *require_line,
+ const void *parsed_require_line)
+{
+ /* apr_ipsubnet_test should accept const but doesn't */
+ apr_ipsubnet_t **ip = (apr_ipsubnet_t **)parsed_require_line;
- if (got_ip && apr_ipsubnet_test(ip, r->connection->remote_addr)) {
+ while (*ip) {
+ if (apr_ipsubnet_test(*ip, r->connection->remote_addr))
return AUTHZ_GRANTED;
- }
+ ip++;
}
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
@@ -169,11 +202,6 @@ static authz_status host_check_authoriza
return AUTHZ_DENIED;
}
-static apr_ipsubnet_t *localhost_v4;
-#if APR_HAVE_IPV6
-static apr_ipsubnet_t *localhost_v6;
-#endif
-
static authz_status local_check_authorization(request_rec *r,
const char *require_line,
const void *parsed_require_line)
@@ -195,7 +223,7 @@ static authz_status local_check_authoriz
static const authz_provider authz_ip_provider =
{
&ip_check_authorization,
- NULL,
+ &ip_parse_config,
};
static const authz_provider authz_host_provider =
@@ -214,9 +242,15 @@ static const authz_provider authz_local_
static int authz_host_pre_config(apr_pool_t *p, apr_pool_t *plog,
apr_pool_t *ptemp)
{
+ /* we only use this hash in the parse config phase, ptemp is enough */
+ parsed_subnets = apr_hash_make(ptemp);
+
apr_ipsubnet_create(&localhost_v4, "127.0.0.0", "8", p);
+ apr_hash_set(parsed_subnets, "127.0.0.0/8", APR_HASH_KEY_STRING, localhost_v4);
+
#if APR_HAVE_IPV6
- apr_ipsubnet_create(&localhost_v6, "::1", "128", p);
+ apr_ipsubnet_create(&localhost_v6, "::1", NULL, p);
+ apr_hash_set(parsed_subnets, "::1", APR_HASH_KEY_STRING, localhost_v6);
#endif
return OK;