src/http/modules/ngx_http_access_module.c - nginx-1.7.10

Global variables defined

Data types defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>


  8. typedef struct {
  9.     in_addr_t         mask;
  10.     in_addr_t         addr;
  11.     ngx_uint_t        deny;      /* unsigned  deny:1; */
  12. } ngx_http_access_rule_t;

  13. #if (NGX_HAVE_INET6)

  14. typedef struct {
  15.     struct in6_addr   addr;
  16.     struct in6_addr   mask;
  17.     ngx_uint_t        deny;      /* unsigned  deny:1; */
  18. } ngx_http_access_rule6_t;

  19. #endif

  20. #if (NGX_HAVE_UNIX_DOMAIN)

  21. typedef struct {
  22.     ngx_uint_t        deny;      /* unsigned  deny:1; */
  23. } ngx_http_access_rule_un_t;

  24. #endif

  25. typedef struct {
  26.     ngx_array_t      *rules;     /* array of ngx_http_access_rule_t */
  27. #if (NGX_HAVE_INET6)
  28.     ngx_array_t      *rules6;    /* array of ngx_http_access_rule6_t */
  29. #endif
  30. #if (NGX_HAVE_UNIX_DOMAIN)
  31.     ngx_array_t      *rules_un;  /* array of ngx_http_access_rule_un_t */
  32. #endif
  33. } ngx_http_access_loc_conf_t;


  34. static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r);
  35. static ngx_int_t ngx_http_access_inet(ngx_http_request_t *r,
  36.     ngx_http_access_loc_conf_t *alcf, in_addr_t addr);
  37. #if (NGX_HAVE_INET6)
  38. static ngx_int_t ngx_http_access_inet6(ngx_http_request_t *r,
  39.     ngx_http_access_loc_conf_t *alcf, u_char *p);
  40. #endif
  41. #if (NGX_HAVE_UNIX_DOMAIN)
  42. static ngx_int_t ngx_http_access_unix(ngx_http_request_t *r,
  43.     ngx_http_access_loc_conf_t *alcf);
  44. #endif
  45. static ngx_int_t ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny);
  46. static char *ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd,
  47.     void *conf);
  48. static void *ngx_http_access_create_loc_conf(ngx_conf_t *cf);
  49. static char *ngx_http_access_merge_loc_conf(ngx_conf_t *cf,
  50.     void *parent, void *child);
  51. static ngx_int_t ngx_http_access_init(ngx_conf_t *cf);


  52. static ngx_command_t  ngx_http_access_commands[] = {

  53.     { ngx_string("allow"),
  54.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
  55.                         |NGX_CONF_TAKE1,
  56.       ngx_http_access_rule,
  57.       NGX_HTTP_LOC_CONF_OFFSET,
  58.       0,
  59.       NULL },

  60.     { ngx_string("deny"),
  61.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
  62.                         |NGX_CONF_TAKE1,
  63.       ngx_http_access_rule,
  64.       NGX_HTTP_LOC_CONF_OFFSET,
  65.       0,
  66.       NULL },

  67.       ngx_null_command
  68. };



  69. static ngx_http_module_t  ngx_http_access_module_ctx = {
  70.     NULL,                                  /* preconfiguration */
  71.     ngx_http_access_init,                  /* postconfiguration */

  72.     NULL,                                  /* create main configuration */
  73.     NULL,                                  /* init main configuration */

  74.     NULL,                                  /* create server configuration */
  75.     NULL,                                  /* merge server configuration */

  76.     ngx_http_access_create_loc_conf,       /* create location configuration */
  77.     ngx_http_access_merge_loc_conf         /* merge location configuration */
  78. };


  79. ngx_module_t  ngx_http_access_module = {
  80.     NGX_MODULE_V1,
  81.     &ngx_http_access_module_ctx,           /* module context */
  82.     ngx_http_access_commands,              /* module directives */
  83.     NGX_HTTP_MODULE,                       /* module type */
  84.     NULL,                                  /* init master */
  85.     NULL,                                  /* init module */
  86.     NULL,                                  /* init process */
  87.     NULL,                                  /* init thread */
  88.     NULL,                                  /* exit thread */
  89.     NULL,                                  /* exit process */
  90.     NULL,                                  /* exit master */
  91.     NGX_MODULE_V1_PADDING
  92. };


  93. static ngx_int_t
  94. ngx_http_access_handler(ngx_http_request_t *r)
  95. {
  96.     struct sockaddr_in          *sin;
  97.     ngx_http_access_loc_conf_t  *alcf;
  98. #if (NGX_HAVE_INET6)
  99.     u_char                      *p;
  100.     in_addr_t                    addr;
  101.     struct sockaddr_in6         *sin6;
  102. #endif

  103.     alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module);

  104.     switch (r->connection->sockaddr->sa_family) {

  105.     case AF_INET:
  106.         if (alcf->rules) {
  107.             sin = (struct sockaddr_in *) r->connection->sockaddr;
  108.             return ngx_http_access_inet(r, alcf, sin->sin_addr.s_addr);
  109.         }
  110.         break;

  111. #if (NGX_HAVE_INET6)

  112.     case AF_INET6:
  113.         sin6 = (struct sockaddr_in6 *) r->connection->sockaddr;
  114.         p = sin6->sin6_addr.s6_addr;

  115.         if (alcf->rules && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
  116.             addr = p[12] << 24;
  117.             addr += p[13] << 16;
  118.             addr += p[14] << 8;
  119.             addr += p[15];
  120.             return ngx_http_access_inet(r, alcf, htonl(addr));
  121.         }

  122.         if (alcf->rules6) {
  123.             return ngx_http_access_inet6(r, alcf, p);
  124.         }

  125.         break;

  126. #endif

  127. #if (NGX_HAVE_UNIX_DOMAIN)

  128.     case AF_UNIX:
  129.         if (alcf->rules_un) {
  130.             return ngx_http_access_unix(r, alcf);
  131.         }

  132.         break;

  133. #endif
  134.     }

  135.     return NGX_DECLINED;
  136. }


  137. static ngx_int_t
  138. ngx_http_access_inet(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf,
  139.     in_addr_t addr)
  140. {
  141.     ngx_uint_t               i;
  142.     ngx_http_access_rule_t  *rule;

  143.     rule = alcf->rules->elts;
  144.     for (i = 0; i < alcf->rules->nelts; i++) {

  145.         ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  146.                        "access: %08XD %08XD %08XD",
  147.                        addr, rule[i].mask, rule[i].addr);

  148.         if ((addr & rule[i].mask) == rule[i].addr) {
  149.             return ngx_http_access_found(r, rule[i].deny);
  150.         }
  151.     }

  152.     return NGX_DECLINED;
  153. }


  154. #if (NGX_HAVE_INET6)

  155. static ngx_int_t
  156. ngx_http_access_inet6(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf,
  157.     u_char *p)
  158. {
  159.     ngx_uint_t                n;
  160.     ngx_uint_t                i;
  161.     ngx_http_access_rule6_t  *rule6;

  162.     rule6 = alcf->rules6->elts;
  163.     for (i = 0; i < alcf->rules6->nelts; i++) {

  164. #if (NGX_DEBUG)
  165.         {
  166.         size_t  cl, ml, al;
  167.         u_char  ct[NGX_INET6_ADDRSTRLEN];
  168.         u_char  mt[NGX_INET6_ADDRSTRLEN];
  169.         u_char  at[NGX_INET6_ADDRSTRLEN];

  170.         cl = ngx_inet6_ntop(p, ct, NGX_INET6_ADDRSTRLEN);
  171.         ml = ngx_inet6_ntop(rule6[i].mask.s6_addr, mt, NGX_INET6_ADDRSTRLEN);
  172.         al = ngx_inet6_ntop(rule6[i].addr.s6_addr, at, NGX_INET6_ADDRSTRLEN);

  173.         ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
  174.                        "access: %*s %*s %*s", cl, ct, ml, mt, al, at);
  175.         }
  176. #endif

  177.         for (n = 0; n < 16; n++) {
  178.             if ((p[n] & rule6[i].mask.s6_addr[n]) != rule6[i].addr.s6_addr[n]) {
  179.                 goto next;
  180.             }
  181.         }

  182.         return ngx_http_access_found(r, rule6[i].deny);

  183.     next:
  184.         continue;
  185.     }

  186.     return NGX_DECLINED;
  187. }

  188. #endif


  189. #if (NGX_HAVE_UNIX_DOMAIN)

  190. static ngx_int_t
  191. ngx_http_access_unix(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf)
  192. {
  193.     ngx_uint_t                  i;
  194.     ngx_http_access_rule_un_t  *rule_un;

  195.     rule_un = alcf->rules_un->elts;
  196.     for (i = 0; i < alcf->rules_un->nelts; i++) {

  197.         /* TODO: check path */
  198.         if (1) {
  199.             return ngx_http_access_found(r, rule_un[i].deny);
  200.         }
  201.     }

  202.     return NGX_DECLINED;
  203. }

  204. #endif


  205. static ngx_int_t
  206. ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny)
  207. {
  208.     ngx_http_core_loc_conf_t  *clcf;

  209.     if (deny) {
  210.         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

  211.         if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) {
  212.             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
  213.                           "access forbidden by rule");
  214.         }

  215.         return NGX_HTTP_FORBIDDEN;
  216.     }

  217.     return NGX_OK;
  218. }


  219. static char *
  220. ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  221. {
  222.     ngx_http_access_loc_conf_t *alcf = conf;

  223.     ngx_int_t                   rc;
  224.     ngx_uint_t                  all;
  225.     ngx_str_t                  *value;
  226.     ngx_cidr_t                  cidr;
  227.     ngx_http_access_rule_t     *rule;
  228. #if (NGX_HAVE_INET6)
  229.     ngx_http_access_rule6_t    *rule6;
  230. #endif
  231. #if (NGX_HAVE_UNIX_DOMAIN)
  232.     ngx_http_access_rule_un_t  *rule_un;
  233. #endif

  234.     ngx_memzero(&cidr, sizeof(ngx_cidr_t));

  235.     value = cf->args->elts;

  236.     all = (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0);

  237.     if (!all) {

  238. #if (NGX_HAVE_UNIX_DOMAIN)

  239.         if (value[1].len == 5 && ngx_strcmp(value[1].data, "unix:") == 0) {
  240.             cidr.family = AF_UNIX;
  241.             rc = NGX_OK;

  242.         } else {
  243.             rc = ngx_ptocidr(&value[1], &cidr);
  244.         }

  245. #else
  246.         rc = ngx_ptocidr(&value[1], &cidr);
  247. #endif

  248.         if (rc == NGX_ERROR) {
  249.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  250.                          "invalid parameter \"%V\"", &value[1]);
  251.             return NGX_CONF_ERROR;
  252.         }

  253.         if (rc == NGX_DONE) {
  254.             ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  255.                          "low address bits of %V are meaningless", &value[1]);
  256.         }
  257.     }

  258.     if (cidr.family == AF_INET || all) {

  259.         if (alcf->rules == NULL) {
  260.             alcf->rules = ngx_array_create(cf->pool, 4,
  261.                                            sizeof(ngx_http_access_rule_t));
  262.             if (alcf->rules == NULL) {
  263.                 return NGX_CONF_ERROR;
  264.             }
  265.         }

  266.         rule = ngx_array_push(alcf->rules);
  267.         if (rule == NULL) {
  268.             return NGX_CONF_ERROR;
  269.         }

  270.         rule->mask = cidr.u.in.mask;
  271.         rule->addr = cidr.u.in.addr;
  272.         rule->deny = (value[0].data[0] == 'd') ? 1 : 0;
  273.     }

  274. #if (NGX_HAVE_INET6)
  275.     if (cidr.family == AF_INET6 || all) {

  276.         if (alcf->rules6 == NULL) {
  277.             alcf->rules6 = ngx_array_create(cf->pool, 4,
  278.                                             sizeof(ngx_http_access_rule6_t));
  279.             if (alcf->rules6 == NULL) {
  280.                 return NGX_CONF_ERROR;
  281.             }
  282.         }

  283.         rule6 = ngx_array_push(alcf->rules6);
  284.         if (rule6 == NULL) {
  285.             return NGX_CONF_ERROR;
  286.         }

  287.         rule6->mask = cidr.u.in6.mask;
  288.         rule6->addr = cidr.u.in6.addr;
  289.         rule6->deny = (value[0].data[0] == 'd') ? 1 : 0;
  290.     }
  291. #endif

  292. #if (NGX_HAVE_UNIX_DOMAIN)
  293.     if (cidr.family == AF_UNIX || all) {

  294.         if (alcf->rules_un == NULL) {
  295.             alcf->rules_un = ngx_array_create(cf->pool, 1,
  296.                                             sizeof(ngx_http_access_rule_un_t));
  297.             if (alcf->rules_un == NULL) {
  298.                 return NGX_CONF_ERROR;
  299.             }
  300.         }

  301.         rule_un = ngx_array_push(alcf->rules_un);
  302.         if (rule_un == NULL) {
  303.             return NGX_CONF_ERROR;
  304.         }

  305.         rule_un->deny = (value[0].data[0] == 'd') ? 1 : 0;
  306.     }
  307. #endif

  308.     return NGX_CONF_OK;
  309. }


  310. static void *
  311. ngx_http_access_create_loc_conf(ngx_conf_t *cf)
  312. {
  313.     ngx_http_access_loc_conf_t  *conf;

  314.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_access_loc_conf_t));
  315.     if (conf == NULL) {
  316.         return NULL;
  317.     }

  318.     return conf;
  319. }


  320. static char *
  321. ngx_http_access_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  322. {
  323.     ngx_http_access_loc_conf_t  *prev = parent;
  324.     ngx_http_access_loc_conf_t  *conf = child;

  325.     if (conf->rules == NULL
  326. #if (NGX_HAVE_INET6)
  327.         && conf->rules6 == NULL
  328. #endif
  329. #if (NGX_HAVE_UNIX_DOMAIN)
  330.         && conf->rules_un == NULL
  331. #endif
  332.     ) {
  333.         conf->rules = prev->rules;
  334. #if (NGX_HAVE_INET6)
  335.         conf->rules6 = prev->rules6;
  336. #endif
  337. #if (NGX_HAVE_UNIX_DOMAIN)
  338.         conf->rules_un = prev->rules_un;
  339. #endif
  340.     }

  341.     return NGX_CONF_OK;
  342. }


  343. static ngx_int_t
  344. ngx_http_access_init(ngx_conf_t *cf)
  345. {
  346.     ngx_http_handler_pt        *h;
  347.     ngx_http_core_main_conf_t  *cmcf;

  348.     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

  349.     h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
  350.     if (h == NULL) {
  351.         return NGX_ERROR;
  352.     }

  353.     *h = ngx_http_access_handler;

  354.     return NGX_OK;
  355. }