# HG changeset patch # User Igor Sysoev # Date 1257255765 0 # Node ID ab9f5a715805fb05aa768ddc0b891ed44b659084 # Parent f8ec17eeeaa6986a64fb32ba37e9101dd5811919 IPv6 support in ngx_http_access_module diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c --- a/src/http/modules/ngx_http_access_module.c +++ b/src/http/modules/ngx_http_access_module.c @@ -10,18 +10,37 @@ typedef struct { - in_addr_t mask; - in_addr_t addr; - ngx_uint_t deny; /* unsigned deny:1; */ + in_addr_t mask; + in_addr_t addr; + ngx_uint_t deny; /* unsigned deny:1; */ } ngx_http_access_rule_t; +#if (NGX_HAVE_INET6) typedef struct { - ngx_array_t *rules; /* array of ngx_http_access_rule_t */ + struct in6_addr addr; + struct in6_addr mask; + ngx_uint_t deny; /* unsigned deny:1; */ +} ngx_http_access_rule6_t; + +#endif + +typedef struct { + ngx_array_t *rules; /* array of ngx_http_access_rule_t */ +#if (NGX_HAVE_INET6) + ngx_array_t *rules6; /* array of ngx_http_access_rule6_t */ +#endif } ngx_http_access_loc_conf_t; static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_access_inet(ngx_http_request_t *r, + ngx_http_access_loc_conf_t *alcf, in_addr_t addr); +#if (NGX_HAVE_INET6) +static ngx_int_t ngx_http_access_inet6(ngx_http_request_t *r, + ngx_http_access_loc_conf_t *alcf, u_char *p); +#endif +static ngx_int_t ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny); static char *ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void *ngx_http_access_create_loc_conf(ngx_conf_t *cf); @@ -87,46 +106,59 @@ ngx_module_t ngx_http_access_module = { static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r) { - ngx_uint_t i; struct sockaddr_in *sin; - ngx_http_access_rule_t *rule; - ngx_http_core_loc_conf_t *clcf; ngx_http_access_loc_conf_t *alcf; alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module); - if (alcf->rules == NULL) { - return NGX_DECLINED; +#if (NGX_HAVE_INET6) + + if (r->connection->sockaddr->sa_family == AF_INET6) { + u_char *p; + in_addr_t addr; + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *) r->connection->sockaddr; + p = sin6->sin6_addr.s6_addr; + + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + addr = p[12] << 24; + addr += p[13] << 16; + addr += p[14] << 8; + addr += p[15]; + return ngx_http_access_inet(r, alcf, htonl(addr)); + } + + return ngx_http_access_inet6(r, alcf, p); } - /* AF_INET only */ +#endif - if (r->connection->sockaddr->sa_family != AF_INET) { - return NGX_DECLINED; + if (r->connection->sockaddr->sa_family == AF_INET) { + sin = (struct sockaddr_in *) r->connection->sockaddr; + return ngx_http_access_inet(r, alcf, sin->sin_addr.s_addr); } - sin = (struct sockaddr_in *) r->connection->sockaddr; + return NGX_DECLINED; +} + + +static ngx_int_t +ngx_http_access_inet(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf, + in_addr_t addr) +{ + ngx_uint_t i; + ngx_http_access_rule_t *rule; rule = alcf->rules->elts; for (i = 0; i < alcf->rules->nelts; i++) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "access: %08XD %08XD %08XD", - sin->sin_addr.s_addr, rule[i].mask, rule[i].addr); - - if ((sin->sin_addr.s_addr & rule[i].mask) == rule[i].addr) { - if (rule[i].deny) { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + addr, rule[i].mask, rule[i].addr); - if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "access forbidden by rule"); - } - - return NGX_HTTP_FORBIDDEN; - } - - return NGX_OK; + if ((addr & rule[i].mask) == rule[i].addr) { + return ngx_http_access_found(r, rule[i].deny); } } @@ -134,62 +166,159 @@ ngx_http_access_handler(ngx_http_request } +#if (NGX_HAVE_INET6) + +static ngx_int_t +ngx_http_access_inet6(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf, + u_char *p) +{ + ngx_uint_t n; + ngx_uint_t i; + ngx_http_access_rule6_t *rule6; + + rule6 = alcf->rules6->elts; + for (i = 0; i < alcf->rules6->nelts; i++) { + +#if (NGX_DEBUG) + { + size_t cl, ml, al; + u_char ct[NGX_INET6_ADDRSTRLEN]; + u_char mt[NGX_INET6_ADDRSTRLEN]; + u_char at[NGX_INET6_ADDRSTRLEN]; + + cl = ngx_inet6_ntop(p, ct, NGX_INET6_ADDRSTRLEN); + ml = ngx_inet6_ntop(rule6[i].mask.s6_addr, mt, NGX_INET6_ADDRSTRLEN); + al = ngx_inet6_ntop(rule6[i].addr.s6_addr, at, NGX_INET6_ADDRSTRLEN); + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "access: %*s %*s %*s", cl, ct, ml, mt, al, at); + } +#endif + + for (n = 0; n < 16; n++) { + if ((p[n] & rule6[i].mask.s6_addr[n]) != rule6[i].addr.s6_addr[n]) { + goto next; + } + } + + return ngx_http_access_found(r, rule6[i].deny); + + next: + continue; + } + + return NGX_DECLINED; +} + +#endif + + +static ngx_int_t +ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny) +{ + ngx_http_core_loc_conf_t *clcf; + + if (deny) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "access forbidden by rule"); + } + + return NGX_HTTP_FORBIDDEN; + } + + return NGX_OK; +} + + static char * ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_access_loc_conf_t *alcf = conf; - ngx_int_t rc; - ngx_str_t *value; - ngx_cidr_t cidr; - ngx_http_access_rule_t *rule; + ngx_int_t rc; + ngx_uint_t all; + ngx_str_t *value; + ngx_cidr_t cidr; + ngx_http_access_rule_t *rule; +#if (NGX_HAVE_INET6) + ngx_http_access_rule6_t *rule6; +#endif - if (alcf->rules == NULL) { - alcf->rules = ngx_array_create(cf->pool, 4, - sizeof(ngx_http_access_rule_t)); - if (alcf->rules == NULL) { - return NGX_CONF_ERROR; - } - } - - rule = ngx_array_push(alcf->rules); - if (rule == NULL) { - return NGX_CONF_ERROR; - } + ngx_memzero(&cidr, sizeof(ngx_cidr_t)); value = cf->args->elts; - rule->deny = (value[0].data[0] == 'd') ? 1 : 0; + all = (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0); + + if (!all) { + + rc = ngx_ptocidr(&value[1], &cidr); - if (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0) { - rule->mask = 0; - rule->addr = 0; + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } - return NGX_CONF_OK; + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", &value[1]); + } } - rc = ngx_ptocidr(&value[1], &cidr); + switch (cidr.family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + case 0: /* all */ - if (rc == NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", - &value[1]); - return NGX_CONF_ERROR; - } + if (alcf->rules6 == NULL) { + alcf->rules6 = ngx_array_create(cf->pool, 4, + sizeof(ngx_http_access_rule6_t)); + if (alcf->rules6 == NULL) { + return NGX_CONF_ERROR; + } + } + + rule6 = ngx_array_push(alcf->rules6); + if (rule6 == NULL) { + return NGX_CONF_ERROR; + } + + rule6->mask = cidr.u.in6.mask; + rule6->addr = cidr.u.in6.addr; + rule6->deny = (value[0].data[0] == 'd') ? 1 : 0; - if (cidr.family != AF_INET) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"allow\" supports IPv4 only"); - return NGX_CONF_ERROR; - } + if (!all) { + break; + } + + /* "all" passes through */ +#endif + + default: /* AF_INET */ - if (rc == NGX_DONE) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "low address bits of %V are meaningless", &value[1]); + if (alcf->rules == NULL) { + alcf->rules = ngx_array_create(cf->pool, 4, + sizeof(ngx_http_access_rule_t)); + if (alcf->rules == NULL) { + return NGX_CONF_ERROR; + } + } + + rule = ngx_array_push(alcf->rules); + if (rule == NULL) { + return NGX_CONF_ERROR; + } + + rule->mask = cidr.u.in.mask; + rule->addr = cidr.u.in.addr; + rule->deny = (value[0].data[0] == 'd') ? 1 : 0; } - rule->mask = cidr.u.in.mask; - rule->addr = cidr.u.in.addr; - return NGX_CONF_OK; } @@ -218,6 +347,12 @@ ngx_http_access_merge_loc_conf(ngx_conf_ conf->rules = prev->rules; } +#if (NGX_HAVE_INET6) + if (conf->rules6 == NULL) { + conf->rules6 = prev->rules6; + } +#endif + return NGX_CONF_OK; }