Mercurial > hg > nginx
comparison src/stream/ngx_stream_access_module.c @ 6175:8807a2369b1a
Stream: access module.
stream {
server {
...
allow 127.0.0.1;
deny all;
}
}
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Thu, 04 Jun 2015 13:04:12 +0300 |
parents | |
children | 2f41d383c9c7 |
comparison
equal
deleted
inserted
replaced
6174:68c106e6fa0a | 6175:8807a2369b1a |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 * Copyright (C) Nginx, Inc. | |
5 */ | |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_stream.h> | |
11 | |
12 | |
13 typedef struct { | |
14 in_addr_t mask; | |
15 in_addr_t addr; | |
16 ngx_uint_t deny; /* unsigned deny:1; */ | |
17 } ngx_stream_access_rule_t; | |
18 | |
19 #if (NGX_HAVE_INET6) | |
20 | |
21 typedef struct { | |
22 struct in6_addr addr; | |
23 struct in6_addr mask; | |
24 ngx_uint_t deny; /* unsigned deny:1; */ | |
25 } ngx_stream_access_rule6_t; | |
26 | |
27 #endif | |
28 | |
29 #if (NGX_HAVE_UNIX_DOMAIN) | |
30 | |
31 typedef struct { | |
32 ngx_uint_t deny; /* unsigned deny:1; */ | |
33 } ngx_stream_access_rule_un_t; | |
34 | |
35 #endif | |
36 | |
37 typedef struct { | |
38 ngx_array_t *rules; /* array of ngx_stream_access_rule_t */ | |
39 #if (NGX_HAVE_INET6) | |
40 ngx_array_t *rules6; /* array of ngx_stream_access_rule6_t */ | |
41 #endif | |
42 #if (NGX_HAVE_UNIX_DOMAIN) | |
43 ngx_array_t *rules_un; /* array of ngx_stream_access_rule_un_t */ | |
44 #endif | |
45 } ngx_stream_access_srv_conf_t; | |
46 | |
47 | |
48 static ngx_int_t ngx_stream_access_handler(ngx_stream_session_t *s); | |
49 static ngx_int_t ngx_stream_access_inet(ngx_stream_session_t *s, | |
50 ngx_stream_access_srv_conf_t *ascf, in_addr_t addr); | |
51 #if (NGX_HAVE_INET6) | |
52 static ngx_int_t ngx_stream_access_inet6(ngx_stream_session_t *s, | |
53 ngx_stream_access_srv_conf_t *ascf, u_char *p); | |
54 #endif | |
55 #if (NGX_HAVE_UNIX_DOMAIN) | |
56 static ngx_int_t ngx_stream_access_unix(ngx_stream_session_t *s, | |
57 ngx_stream_access_srv_conf_t *ascf); | |
58 #endif | |
59 static ngx_int_t ngx_stream_access_found(ngx_stream_session_t *s, | |
60 ngx_uint_t deny); | |
61 static char *ngx_stream_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, | |
62 void *conf); | |
63 static void *ngx_stream_access_create_srv_conf(ngx_conf_t *cf); | |
64 static char *ngx_stream_access_merge_srv_conf(ngx_conf_t *cf, | |
65 void *parent, void *child); | |
66 static ngx_int_t ngx_stream_access_init(ngx_conf_t *cf); | |
67 | |
68 | |
69 static ngx_command_t ngx_stream_access_commands[] = { | |
70 | |
71 { ngx_string("allow"), | |
72 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, | |
73 ngx_stream_access_rule, | |
74 NGX_STREAM_SRV_CONF_OFFSET, | |
75 0, | |
76 NULL }, | |
77 | |
78 { ngx_string("deny"), | |
79 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, | |
80 ngx_stream_access_rule, | |
81 NGX_STREAM_SRV_CONF_OFFSET, | |
82 0, | |
83 NULL }, | |
84 | |
85 ngx_null_command | |
86 }; | |
87 | |
88 | |
89 | |
90 static ngx_stream_module_t ngx_stream_access_module_ctx = { | |
91 ngx_stream_access_init, /* postconfiguration */ | |
92 | |
93 NULL, /* create main configuration */ | |
94 NULL, /* init main configuration */ | |
95 | |
96 ngx_stream_access_create_srv_conf, /* create server configuration */ | |
97 ngx_stream_access_merge_srv_conf /* merge server configuration */ | |
98 }; | |
99 | |
100 | |
101 ngx_module_t ngx_stream_access_module = { | |
102 NGX_MODULE_V1, | |
103 &ngx_stream_access_module_ctx, /* module context */ | |
104 ngx_stream_access_commands, /* module directives */ | |
105 NGX_STREAM_MODULE, /* module type */ | |
106 NULL, /* init master */ | |
107 NULL, /* init module */ | |
108 NULL, /* init process */ | |
109 NULL, /* init thread */ | |
110 NULL, /* exit thread */ | |
111 NULL, /* exit process */ | |
112 NULL, /* exit master */ | |
113 NGX_MODULE_V1_PADDING | |
114 }; | |
115 | |
116 | |
117 static ngx_int_t | |
118 ngx_stream_access_handler(ngx_stream_session_t *s) | |
119 { | |
120 struct sockaddr_in *sin; | |
121 ngx_stream_access_srv_conf_t *ascf; | |
122 #if (NGX_HAVE_INET6) | |
123 u_char *p; | |
124 in_addr_t addr; | |
125 struct sockaddr_in6 *sin6; | |
126 #endif | |
127 | |
128 ascf = ngx_stream_get_module_srv_conf(s, ngx_stream_access_module); | |
129 | |
130 switch (s->connection->sockaddr->sa_family) { | |
131 | |
132 case AF_INET: | |
133 if (ascf->rules) { | |
134 sin = (struct sockaddr_in *) s->connection->sockaddr; | |
135 return ngx_stream_access_inet(s, ascf, sin->sin_addr.s_addr); | |
136 } | |
137 break; | |
138 | |
139 #if (NGX_HAVE_INET6) | |
140 | |
141 case AF_INET6: | |
142 sin6 = (struct sockaddr_in6 *) s->connection->sockaddr; | |
143 p = sin6->sin6_addr.s6_addr; | |
144 | |
145 if (ascf->rules && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { | |
146 addr = p[12] << 24; | |
147 addr += p[13] << 16; | |
148 addr += p[14] << 8; | |
149 addr += p[15]; | |
150 return ngx_stream_access_inet(s, ascf, htonl(addr)); | |
151 } | |
152 | |
153 if (ascf->rules6) { | |
154 return ngx_stream_access_inet6(s, ascf, p); | |
155 } | |
156 | |
157 break; | |
158 | |
159 #endif | |
160 | |
161 #if (NGX_HAVE_UNIX_DOMAIN) | |
162 | |
163 case AF_UNIX: | |
164 if (ascf->rules_un) { | |
165 return ngx_stream_access_unix(s, ascf); | |
166 } | |
167 | |
168 break; | |
169 | |
170 #endif | |
171 } | |
172 | |
173 return NGX_DECLINED; | |
174 } | |
175 | |
176 | |
177 static ngx_int_t | |
178 ngx_stream_access_inet(ngx_stream_session_t *s, | |
179 ngx_stream_access_srv_conf_t *ascf, in_addr_t addr) | |
180 { | |
181 ngx_uint_t i; | |
182 ngx_stream_access_rule_t *rule; | |
183 | |
184 rule = ascf->rules->elts; | |
185 for (i = 0; i < ascf->rules->nelts; i++) { | |
186 | |
187 ngx_log_debug3(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, | |
188 "access: %08XD %08XD %08XD", | |
189 addr, rule[i].mask, rule[i].addr); | |
190 | |
191 if ((addr & rule[i].mask) == rule[i].addr) { | |
192 return ngx_stream_access_found(s, rule[i].deny); | |
193 } | |
194 } | |
195 | |
196 return NGX_DECLINED; | |
197 } | |
198 | |
199 | |
200 #if (NGX_HAVE_INET6) | |
201 | |
202 static ngx_int_t | |
203 ngx_stream_access_inet6(ngx_stream_session_t *s, | |
204 ngx_stream_access_srv_conf_t *ascf, u_char *p) | |
205 { | |
206 ngx_uint_t n; | |
207 ngx_uint_t i; | |
208 ngx_stream_access_rule6_t *rule6; | |
209 | |
210 rule6 = ascf->rules6->elts; | |
211 for (i = 0; i < ascf->rules6->nelts; i++) { | |
212 | |
213 #if (NGX_DEBUG) | |
214 { | |
215 size_t cl, ml, al; | |
216 u_char ct[NGX_INET6_ADDRSTRLEN]; | |
217 u_char mt[NGX_INET6_ADDRSTRLEN]; | |
218 u_char at[NGX_INET6_ADDRSTRLEN]; | |
219 | |
220 cl = ngx_inet6_ntop(p, ct, NGX_INET6_ADDRSTRLEN); | |
221 ml = ngx_inet6_ntop(rule6[i].mask.s6_addr, mt, NGX_INET6_ADDRSTRLEN); | |
222 al = ngx_inet6_ntop(rule6[i].addr.s6_addr, at, NGX_INET6_ADDRSTRLEN); | |
223 | |
224 ngx_log_debug6(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, | |
225 "access: %*s %*s %*s", cl, ct, ml, mt, al, at); | |
226 } | |
227 #endif | |
228 | |
229 for (n = 0; n < 16; n++) { | |
230 if ((p[n] & rule6[i].mask.s6_addr[n]) != rule6[i].addr.s6_addr[n]) { | |
231 goto next; | |
232 } | |
233 } | |
234 | |
235 return ngx_stream_access_found(s, rule6[i].deny); | |
236 | |
237 next: | |
238 continue; | |
239 } | |
240 | |
241 return NGX_DECLINED; | |
242 } | |
243 | |
244 #endif | |
245 | |
246 | |
247 #if (NGX_HAVE_UNIX_DOMAIN) | |
248 | |
249 static ngx_int_t | |
250 ngx_stream_access_unix(ngx_stream_session_t *s, | |
251 ngx_stream_access_srv_conf_t *ascf) | |
252 { | |
253 ngx_uint_t i; | |
254 ngx_stream_access_rule_un_t *rule_un; | |
255 | |
256 rule_un = ascf->rules_un->elts; | |
257 for (i = 0; i < ascf->rules_un->nelts; i++) { | |
258 | |
259 /* TODO: check path */ | |
260 if (1) { | |
261 return ngx_stream_access_found(s, rule_un[i].deny); | |
262 } | |
263 } | |
264 | |
265 return NGX_DECLINED; | |
266 } | |
267 | |
268 #endif | |
269 | |
270 | |
271 static ngx_int_t | |
272 ngx_stream_access_found(ngx_stream_session_t *s, ngx_uint_t deny) | |
273 { | |
274 if (deny) { | |
275 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, | |
276 "access forbidden by rule"); | |
277 return NGX_ABORT; | |
278 } | |
279 | |
280 return NGX_OK; | |
281 } | |
282 | |
283 | |
284 static char * | |
285 ngx_stream_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
286 { | |
287 ngx_stream_access_srv_conf_t *ascf = conf; | |
288 | |
289 ngx_int_t rc; | |
290 ngx_uint_t all; | |
291 ngx_str_t *value; | |
292 ngx_cidr_t cidr; | |
293 ngx_stream_access_rule_t *rule; | |
294 #if (NGX_HAVE_INET6) | |
295 ngx_stream_access_rule6_t *rule6; | |
296 #endif | |
297 #if (NGX_HAVE_UNIX_DOMAIN) | |
298 ngx_stream_access_rule_un_t *rule_un; | |
299 #endif | |
300 | |
301 ngx_memzero(&cidr, sizeof(ngx_cidr_t)); | |
302 | |
303 value = cf->args->elts; | |
304 | |
305 all = (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0); | |
306 | |
307 if (!all) { | |
308 | |
309 #if (NGX_HAVE_UNIX_DOMAIN) | |
310 | |
311 if (value[1].len == 5 && ngx_strcmp(value[1].data, "unix:") == 0) { | |
312 cidr.family = AF_UNIX; | |
313 rc = NGX_OK; | |
314 | |
315 } else { | |
316 rc = ngx_ptocidr(&value[1], &cidr); | |
317 } | |
318 | |
319 #else | |
320 rc = ngx_ptocidr(&value[1], &cidr); | |
321 #endif | |
322 | |
323 if (rc == NGX_ERROR) { | |
324 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
325 "invalid parameter \"%V\"", &value[1]); | |
326 return NGX_CONF_ERROR; | |
327 } | |
328 | |
329 if (rc == NGX_DONE) { | |
330 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | |
331 "low address bits of %V are meaningless", &value[1]); | |
332 } | |
333 } | |
334 | |
335 if (cidr.family == AF_INET || all) { | |
336 | |
337 if (ascf->rules == NULL) { | |
338 ascf->rules = ngx_array_create(cf->pool, 4, | |
339 sizeof(ngx_stream_access_rule_t)); | |
340 if (ascf->rules == NULL) { | |
341 return NGX_CONF_ERROR; | |
342 } | |
343 } | |
344 | |
345 rule = ngx_array_push(ascf->rules); | |
346 if (rule == NULL) { | |
347 return NGX_CONF_ERROR; | |
348 } | |
349 | |
350 rule->mask = cidr.u.in.mask; | |
351 rule->addr = cidr.u.in.addr; | |
352 rule->deny = (value[0].data[0] == 'd') ? 1 : 0; | |
353 } | |
354 | |
355 #if (NGX_HAVE_INET6) | |
356 if (cidr.family == AF_INET6 || all) { | |
357 | |
358 if (ascf->rules6 == NULL) { | |
359 ascf->rules6 = ngx_array_create(cf->pool, 4, | |
360 sizeof(ngx_stream_access_rule6_t)); | |
361 if (ascf->rules6 == NULL) { | |
362 return NGX_CONF_ERROR; | |
363 } | |
364 } | |
365 | |
366 rule6 = ngx_array_push(ascf->rules6); | |
367 if (rule6 == NULL) { | |
368 return NGX_CONF_ERROR; | |
369 } | |
370 | |
371 rule6->mask = cidr.u.in6.mask; | |
372 rule6->addr = cidr.u.in6.addr; | |
373 rule6->deny = (value[0].data[0] == 'd') ? 1 : 0; | |
374 } | |
375 #endif | |
376 | |
377 #if (NGX_HAVE_UNIX_DOMAIN) | |
378 if (cidr.family == AF_UNIX || all) { | |
379 | |
380 if (ascf->rules_un == NULL) { | |
381 ascf->rules_un = ngx_array_create(cf->pool, 1, | |
382 sizeof(ngx_stream_access_rule_un_t)); | |
383 if (ascf->rules_un == NULL) { | |
384 return NGX_CONF_ERROR; | |
385 } | |
386 } | |
387 | |
388 rule_un = ngx_array_push(ascf->rules_un); | |
389 if (rule_un == NULL) { | |
390 return NGX_CONF_ERROR; | |
391 } | |
392 | |
393 rule_un->deny = (value[0].data[0] == 'd') ? 1 : 0; | |
394 } | |
395 #endif | |
396 | |
397 return NGX_CONF_OK; | |
398 } | |
399 | |
400 | |
401 static void * | |
402 ngx_stream_access_create_srv_conf(ngx_conf_t *cf) | |
403 { | |
404 ngx_stream_access_srv_conf_t *conf; | |
405 | |
406 conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_access_srv_conf_t)); | |
407 if (conf == NULL) { | |
408 return NULL; | |
409 } | |
410 | |
411 return conf; | |
412 } | |
413 | |
414 | |
415 static char * | |
416 ngx_stream_access_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) | |
417 { | |
418 ngx_stream_access_srv_conf_t *prev = parent; | |
419 ngx_stream_access_srv_conf_t *conf = child; | |
420 | |
421 if (conf->rules == NULL | |
422 #if (NGX_HAVE_INET6) | |
423 && conf->rules6 == NULL | |
424 #endif | |
425 #if (NGX_HAVE_UNIX_DOMAIN) | |
426 && conf->rules_un == NULL | |
427 #endif | |
428 ) { | |
429 conf->rules = prev->rules; | |
430 #if (NGX_HAVE_INET6) | |
431 conf->rules6 = prev->rules6; | |
432 #endif | |
433 #if (NGX_HAVE_UNIX_DOMAIN) | |
434 conf->rules_un = prev->rules_un; | |
435 #endif | |
436 } | |
437 | |
438 return NGX_CONF_OK; | |
439 } | |
440 | |
441 | |
442 static ngx_int_t | |
443 ngx_stream_access_init(ngx_conf_t *cf) | |
444 { | |
445 ngx_stream_core_main_conf_t *cmcf; | |
446 | |
447 cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); | |
448 cmcf->access_handler = ngx_stream_access_handler; | |
449 | |
450 return NGX_OK; | |
451 } |