upstream nginx-0.7.31
[nginx.git] / nginx / src / http / modules / ngx_http_access_module.c
1
2 /*
3  * Copyright (C) Igor Sysoev
4  */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_http.h>
10
11
12 /* AF_INET only */
13
14 typedef struct {
15     in_addr_t     mask;
16     in_addr_t     addr;
17     ngx_uint_t    deny;      /* unsigned  deny:1; */
18 } ngx_http_access_rule_t;
19
20
21 typedef struct {
22     ngx_array_t  *rules;     /* array of ngx_http_access_rule_t */
23 } ngx_http_access_loc_conf_t;
24
25
26 static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r);
27 static char *ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd,
28     void *conf);
29 static void *ngx_http_access_create_loc_conf(ngx_conf_t *cf);
30 static char *ngx_http_access_merge_loc_conf(ngx_conf_t *cf,
31     void *parent, void *child);
32 static ngx_int_t ngx_http_access_init(ngx_conf_t *cf);
33
34
35 static ngx_command_t  ngx_http_access_commands[] = {
36
37     { ngx_string("allow"),
38       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
39                         |NGX_CONF_TAKE1,
40       ngx_http_access_rule,
41       NGX_HTTP_LOC_CONF_OFFSET,
42       0,
43       NULL },
44
45     { ngx_string("deny"),
46       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF
47                         |NGX_CONF_TAKE1,
48       ngx_http_access_rule,
49       NGX_HTTP_LOC_CONF_OFFSET,
50       0,
51       NULL },
52
53       ngx_null_command
54 };
55
56
57
58 static ngx_http_module_t  ngx_http_access_module_ctx = {
59     NULL,                                  /* preconfiguration */
60     ngx_http_access_init,                  /* postconfiguration */
61
62     NULL,                                  /* create main configuration */
63     NULL,                                  /* init main configuration */
64
65     NULL,                                  /* create server configuration */
66     NULL,                                  /* merge server configuration */
67
68     ngx_http_access_create_loc_conf,       /* create location configuration */
69     ngx_http_access_merge_loc_conf         /* merge location configuration */
70 };
71
72
73 ngx_module_t  ngx_http_access_module = {
74     NGX_MODULE_V1,
75     &ngx_http_access_module_ctx,           /* module context */
76     ngx_http_access_commands,              /* module directives */
77     NGX_HTTP_MODULE,                       /* module type */
78     NULL,                                  /* init master */
79     NULL,                                  /* init module */
80     NULL,                                  /* init process */
81     NULL,                                  /* init thread */
82     NULL,                                  /* exit thread */
83     NULL,                                  /* exit process */
84     NULL,                                  /* exit master */
85     NGX_MODULE_V1_PADDING
86 };
87
88
89 static ngx_int_t
90 ngx_http_access_handler(ngx_http_request_t *r)
91 {
92     ngx_uint_t                   i;
93     struct sockaddr_in          *sin;
94     ngx_http_access_rule_t      *rule;
95     ngx_http_core_loc_conf_t    *clcf;
96     ngx_http_access_loc_conf_t  *alcf;
97
98     alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module);
99
100     if (alcf->rules == NULL) {
101         return NGX_DECLINED;
102     }
103
104     /* AF_INET only */
105
106     sin = (struct sockaddr_in *) r->connection->sockaddr;
107
108     rule = alcf->rules->elts;
109     for (i = 0; i < alcf->rules->nelts; i++) {
110
111         ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
112                        "access: %08XD %08XD %08XD",
113                        sin->sin_addr.s_addr, rule[i].mask, rule[i].addr);
114
115         if ((sin->sin_addr.s_addr & rule[i].mask) == rule[i].addr) {
116             if (rule[i].deny) {
117                 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
118
119                 if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) {
120                     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
121                                   "access forbidden by rule");
122                 }
123
124                 return NGX_HTTP_FORBIDDEN;
125             }
126
127             return NGX_OK;
128         }
129     }
130
131     return NGX_DECLINED;
132 }
133
134
135 static char *
136 ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
137 {
138     ngx_http_access_loc_conf_t *alcf = conf;
139
140     ngx_int_t                rc;
141     ngx_str_t               *value;
142     ngx_inet_cidr_t          in_cidr;
143     ngx_http_access_rule_t  *rule;
144
145     if (alcf->rules == NULL) {
146         alcf->rules = ngx_array_create(cf->pool, 4,
147                                        sizeof(ngx_http_access_rule_t));
148         if (alcf->rules == NULL) {
149             return NGX_CONF_ERROR;
150         }
151     }
152
153     rule = ngx_array_push(alcf->rules);
154     if (rule == NULL) {
155         return NGX_CONF_ERROR;
156     }
157
158     value = cf->args->elts;
159
160     rule->deny = (value[0].data[0] == 'd') ? 1 : 0;
161
162     if (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0) {
163         rule->mask = 0;
164         rule->addr = 0;
165
166         return NGX_CONF_OK;
167     }
168
169     rc = ngx_ptocidr(&value[1], &in_cidr);
170
171     if (rc == NGX_ERROR) {
172         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"",
173                            &value[1]);
174         return NGX_CONF_ERROR;
175     }
176
177     if (rc == NGX_DONE) {
178         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
179                            "low address bits of %V are meaningless", &value[1]);
180     }
181
182     rule->mask = in_cidr.mask;
183     rule->addr = in_cidr.addr;
184
185     return NGX_CONF_OK;
186 }
187
188
189 static void *
190 ngx_http_access_create_loc_conf(ngx_conf_t *cf)
191 {
192     ngx_http_access_loc_conf_t  *conf;
193
194     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_access_loc_conf_t));
195     if (conf == NULL) {
196         return NGX_CONF_ERROR;
197     }
198
199     return conf;
200 }
201
202
203 static char *
204 ngx_http_access_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
205 {
206     ngx_http_access_loc_conf_t  *prev = parent;
207     ngx_http_access_loc_conf_t  *conf = child;
208
209     if (conf->rules == NULL) {
210         conf->rules = prev->rules;
211     }
212
213     return NGX_CONF_OK;
214 }
215
216
217 static ngx_int_t
218 ngx_http_access_init(ngx_conf_t *cf)
219 {
220     ngx_http_handler_pt        *h;
221     ngx_http_core_main_conf_t  *cmcf;
222
223     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
224
225     h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
226     if (h == NULL) {
227         return NGX_ERROR;
228     }
229
230     *h = ngx_http_access_handler;
231
232     return NGX_OK;
233 }