Mercurial > hg > nginx
annotate src/stream/ngx_stream_access_module.c @ 9263:388a801e9bb9
Request body: discarded body now treated as no body.
Notably, proxying of such requests now uses no Content-Length instead
of "Content-Length: 0", and the $content_length variable is empty (instead
of "0").
This might be beneficial from correctness point of view, since requests
with discarded body, such as during processing of error pages, do not pretend
there is a zero-length body, but instead do not contain body at all. For
example, this might be important for PUT requests, where a zero-length
body could be incorrectly interpreted as a real request body.
This also slightly simplifies the code.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Sat, 27 Apr 2024 18:23:52 +0300 |
parents | 72188d1bcab5 |
children |
rev | line source |
---|---|
6175 | 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 = { | |
6606
2f41d383c9c7
Stream: added preconfiguration step.
Vladimir Homutov <vl@nginx.com>
parents:
6175
diff
changeset
|
91 NULL, /* preconfiguration */ |
6175 | 92 ngx_stream_access_init, /* postconfiguration */ |
93 | |
94 NULL, /* create main configuration */ | |
95 NULL, /* init main configuration */ | |
96 | |
97 ngx_stream_access_create_srv_conf, /* create server configuration */ | |
98 ngx_stream_access_merge_srv_conf /* merge server configuration */ | |
99 }; | |
100 | |
101 | |
102 ngx_module_t ngx_stream_access_module = { | |
103 NGX_MODULE_V1, | |
104 &ngx_stream_access_module_ctx, /* module context */ | |
105 ngx_stream_access_commands, /* module directives */ | |
106 NGX_STREAM_MODULE, /* module type */ | |
107 NULL, /* init master */ | |
108 NULL, /* init module */ | |
109 NULL, /* init process */ | |
110 NULL, /* init thread */ | |
111 NULL, /* exit thread */ | |
112 NULL, /* exit process */ | |
113 NULL, /* exit master */ | |
114 NGX_MODULE_V1_PADDING | |
115 }; | |
116 | |
117 | |
118 static ngx_int_t | |
119 ngx_stream_access_handler(ngx_stream_session_t *s) | |
120 { | |
121 struct sockaddr_in *sin; | |
122 ngx_stream_access_srv_conf_t *ascf; | |
123 #if (NGX_HAVE_INET6) | |
124 u_char *p; | |
125 in_addr_t addr; | |
126 struct sockaddr_in6 *sin6; | |
127 #endif | |
128 | |
129 ascf = ngx_stream_get_module_srv_conf(s, ngx_stream_access_module); | |
130 | |
131 switch (s->connection->sockaddr->sa_family) { | |
132 | |
133 case AF_INET: | |
134 if (ascf->rules) { | |
135 sin = (struct sockaddr_in *) s->connection->sockaddr; | |
136 return ngx_stream_access_inet(s, ascf, sin->sin_addr.s_addr); | |
137 } | |
138 break; | |
139 | |
140 #if (NGX_HAVE_INET6) | |
141 | |
142 case AF_INET6: | |
143 sin6 = (struct sockaddr_in6 *) s->connection->sockaddr; | |
144 p = sin6->sin6_addr.s6_addr; | |
145 | |
146 if (ascf->rules && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { | |
147 addr = p[12] << 24; | |
148 addr += p[13] << 16; | |
149 addr += p[14] << 8; | |
150 addr += p[15]; | |
151 return ngx_stream_access_inet(s, ascf, htonl(addr)); | |
152 } | |
153 | |
154 if (ascf->rules6) { | |
155 return ngx_stream_access_inet6(s, ascf, p); | |
156 } | |
157 | |
158 break; | |
159 | |
160 #endif | |
161 | |
162 #if (NGX_HAVE_UNIX_DOMAIN) | |
163 | |
164 case AF_UNIX: | |
165 if (ascf->rules_un) { | |
166 return ngx_stream_access_unix(s, ascf); | |
167 } | |
168 | |
169 break; | |
170 | |
171 #endif | |
172 } | |
173 | |
174 return NGX_DECLINED; | |
175 } | |
176 | |
177 | |
178 static ngx_int_t | |
179 ngx_stream_access_inet(ngx_stream_session_t *s, | |
180 ngx_stream_access_srv_conf_t *ascf, in_addr_t addr) | |
181 { | |
182 ngx_uint_t i; | |
183 ngx_stream_access_rule_t *rule; | |
184 | |
185 rule = ascf->rules->elts; | |
186 for (i = 0; i < ascf->rules->nelts; i++) { | |
187 | |
188 ngx_log_debug3(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, | |
189 "access: %08XD %08XD %08XD", | |
190 addr, rule[i].mask, rule[i].addr); | |
191 | |
192 if ((addr & rule[i].mask) == rule[i].addr) { | |
193 return ngx_stream_access_found(s, rule[i].deny); | |
194 } | |
195 } | |
196 | |
197 return NGX_DECLINED; | |
198 } | |
199 | |
200 | |
201 #if (NGX_HAVE_INET6) | |
202 | |
203 static ngx_int_t | |
204 ngx_stream_access_inet6(ngx_stream_session_t *s, | |
205 ngx_stream_access_srv_conf_t *ascf, u_char *p) | |
206 { | |
207 ngx_uint_t n; | |
208 ngx_uint_t i; | |
209 ngx_stream_access_rule6_t *rule6; | |
210 | |
211 rule6 = ascf->rules6->elts; | |
212 for (i = 0; i < ascf->rules6->nelts; i++) { | |
213 | |
214 #if (NGX_DEBUG) | |
215 { | |
216 size_t cl, ml, al; | |
217 u_char ct[NGX_INET6_ADDRSTRLEN]; | |
218 u_char mt[NGX_INET6_ADDRSTRLEN]; | |
219 u_char at[NGX_INET6_ADDRSTRLEN]; | |
220 | |
221 cl = ngx_inet6_ntop(p, ct, NGX_INET6_ADDRSTRLEN); | |
222 ml = ngx_inet6_ntop(rule6[i].mask.s6_addr, mt, NGX_INET6_ADDRSTRLEN); | |
223 al = ngx_inet6_ntop(rule6[i].addr.s6_addr, at, NGX_INET6_ADDRSTRLEN); | |
224 | |
225 ngx_log_debug6(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, | |
226 "access: %*s %*s %*s", cl, ct, ml, mt, al, at); | |
227 } | |
228 #endif | |
229 | |
230 for (n = 0; n < 16; n++) { | |
231 if ((p[n] & rule6[i].mask.s6_addr[n]) != rule6[i].addr.s6_addr[n]) { | |
232 goto next; | |
233 } | |
234 } | |
235 | |
236 return ngx_stream_access_found(s, rule6[i].deny); | |
237 | |
238 next: | |
239 continue; | |
240 } | |
241 | |
242 return NGX_DECLINED; | |
243 } | |
244 | |
245 #endif | |
246 | |
247 | |
248 #if (NGX_HAVE_UNIX_DOMAIN) | |
249 | |
250 static ngx_int_t | |
251 ngx_stream_access_unix(ngx_stream_session_t *s, | |
252 ngx_stream_access_srv_conf_t *ascf) | |
253 { | |
254 ngx_uint_t i; | |
255 ngx_stream_access_rule_un_t *rule_un; | |
256 | |
257 rule_un = ascf->rules_un->elts; | |
258 for (i = 0; i < ascf->rules_un->nelts; i++) { | |
259 | |
260 /* TODO: check path */ | |
261 if (1) { | |
262 return ngx_stream_access_found(s, rule_un[i].deny); | |
263 } | |
264 } | |
265 | |
266 return NGX_DECLINED; | |
267 } | |
268 | |
269 #endif | |
270 | |
271 | |
272 static ngx_int_t | |
273 ngx_stream_access_found(ngx_stream_session_t *s, ngx_uint_t deny) | |
274 { | |
275 if (deny) { | |
276 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, | |
277 "access forbidden by rule"); | |
6693 | 278 return NGX_STREAM_FORBIDDEN; |
6175 | 279 } |
280 | |
281 return NGX_OK; | |
282 } | |
283 | |
284 | |
285 static char * | |
286 ngx_stream_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
287 { | |
288 ngx_stream_access_srv_conf_t *ascf = conf; | |
289 | |
290 ngx_int_t rc; | |
291 ngx_uint_t all; | |
292 ngx_str_t *value; | |
293 ngx_cidr_t cidr; | |
294 ngx_stream_access_rule_t *rule; | |
295 #if (NGX_HAVE_INET6) | |
296 ngx_stream_access_rule6_t *rule6; | |
297 #endif | |
298 #if (NGX_HAVE_UNIX_DOMAIN) | |
299 ngx_stream_access_rule_un_t *rule_un; | |
300 #endif | |
301 | |
6996
72188d1bcab5
Access: simplified rule parser code.
Ruslan Ermilov <ru@nginx.com>
parents:
6693
diff
changeset
|
302 all = 0; |
6175 | 303 ngx_memzero(&cidr, sizeof(ngx_cidr_t)); |
304 | |
305 value = cf->args->elts; | |
306 | |
6996
72188d1bcab5
Access: simplified rule parser code.
Ruslan Ermilov <ru@nginx.com>
parents:
6693
diff
changeset
|
307 if (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0) { |
72188d1bcab5
Access: simplified rule parser code.
Ruslan Ermilov <ru@nginx.com>
parents:
6693
diff
changeset
|
308 all = 1; |
6175 | 309 |
310 #if (NGX_HAVE_UNIX_DOMAIN) | |
6996
72188d1bcab5
Access: simplified rule parser code.
Ruslan Ermilov <ru@nginx.com>
parents:
6693
diff
changeset
|
311 } else if (value[1].len == 5 && ngx_strcmp(value[1].data, "unix:") == 0) { |
72188d1bcab5
Access: simplified rule parser code.
Ruslan Ermilov <ru@nginx.com>
parents:
6693
diff
changeset
|
312 cidr.family = AF_UNIX; |
72188d1bcab5
Access: simplified rule parser code.
Ruslan Ermilov <ru@nginx.com>
parents:
6693
diff
changeset
|
313 #endif |
6175 | 314 |
6996
72188d1bcab5
Access: simplified rule parser code.
Ruslan Ermilov <ru@nginx.com>
parents:
6693
diff
changeset
|
315 } else { |
6175 | 316 rc = ngx_ptocidr(&value[1], &cidr); |
317 | |
318 if (rc == NGX_ERROR) { | |
319 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
320 "invalid parameter \"%V\"", &value[1]); | |
321 return NGX_CONF_ERROR; | |
322 } | |
323 | |
324 if (rc == NGX_DONE) { | |
325 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | |
326 "low address bits of %V are meaningless", &value[1]); | |
327 } | |
328 } | |
329 | |
330 if (cidr.family == AF_INET || all) { | |
331 | |
332 if (ascf->rules == NULL) { | |
333 ascf->rules = ngx_array_create(cf->pool, 4, | |
334 sizeof(ngx_stream_access_rule_t)); | |
335 if (ascf->rules == NULL) { | |
336 return NGX_CONF_ERROR; | |
337 } | |
338 } | |
339 | |
340 rule = ngx_array_push(ascf->rules); | |
341 if (rule == NULL) { | |
342 return NGX_CONF_ERROR; | |
343 } | |
344 | |
345 rule->mask = cidr.u.in.mask; | |
346 rule->addr = cidr.u.in.addr; | |
347 rule->deny = (value[0].data[0] == 'd') ? 1 : 0; | |
348 } | |
349 | |
350 #if (NGX_HAVE_INET6) | |
351 if (cidr.family == AF_INET6 || all) { | |
352 | |
353 if (ascf->rules6 == NULL) { | |
354 ascf->rules6 = ngx_array_create(cf->pool, 4, | |
355 sizeof(ngx_stream_access_rule6_t)); | |
356 if (ascf->rules6 == NULL) { | |
357 return NGX_CONF_ERROR; | |
358 } | |
359 } | |
360 | |
361 rule6 = ngx_array_push(ascf->rules6); | |
362 if (rule6 == NULL) { | |
363 return NGX_CONF_ERROR; | |
364 } | |
365 | |
366 rule6->mask = cidr.u.in6.mask; | |
367 rule6->addr = cidr.u.in6.addr; | |
368 rule6->deny = (value[0].data[0] == 'd') ? 1 : 0; | |
369 } | |
370 #endif | |
371 | |
372 #if (NGX_HAVE_UNIX_DOMAIN) | |
373 if (cidr.family == AF_UNIX || all) { | |
374 | |
375 if (ascf->rules_un == NULL) { | |
376 ascf->rules_un = ngx_array_create(cf->pool, 1, | |
377 sizeof(ngx_stream_access_rule_un_t)); | |
378 if (ascf->rules_un == NULL) { | |
379 return NGX_CONF_ERROR; | |
380 } | |
381 } | |
382 | |
383 rule_un = ngx_array_push(ascf->rules_un); | |
384 if (rule_un == NULL) { | |
385 return NGX_CONF_ERROR; | |
386 } | |
387 | |
388 rule_un->deny = (value[0].data[0] == 'd') ? 1 : 0; | |
389 } | |
390 #endif | |
391 | |
392 return NGX_CONF_OK; | |
393 } | |
394 | |
395 | |
396 static void * | |
397 ngx_stream_access_create_srv_conf(ngx_conf_t *cf) | |
398 { | |
399 ngx_stream_access_srv_conf_t *conf; | |
400 | |
401 conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_access_srv_conf_t)); | |
402 if (conf == NULL) { | |
403 return NULL; | |
404 } | |
405 | |
406 return conf; | |
407 } | |
408 | |
409 | |
410 static char * | |
411 ngx_stream_access_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) | |
412 { | |
413 ngx_stream_access_srv_conf_t *prev = parent; | |
414 ngx_stream_access_srv_conf_t *conf = child; | |
415 | |
416 if (conf->rules == NULL | |
417 #if (NGX_HAVE_INET6) | |
418 && conf->rules6 == NULL | |
419 #endif | |
420 #if (NGX_HAVE_UNIX_DOMAIN) | |
421 && conf->rules_un == NULL | |
422 #endif | |
423 ) { | |
424 conf->rules = prev->rules; | |
425 #if (NGX_HAVE_INET6) | |
426 conf->rules6 = prev->rules6; | |
427 #endif | |
428 #if (NGX_HAVE_UNIX_DOMAIN) | |
429 conf->rules_un = prev->rules_un; | |
430 #endif | |
431 } | |
432 | |
433 return NGX_CONF_OK; | |
434 } | |
435 | |
436 | |
437 static ngx_int_t | |
438 ngx_stream_access_init(ngx_conf_t *cf) | |
439 { | |
6693 | 440 ngx_stream_handler_pt *h; |
6175 | 441 ngx_stream_core_main_conf_t *cmcf; |
442 | |
443 cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); | |
6693 | 444 |
445 h = ngx_array_push(&cmcf->phases[NGX_STREAM_ACCESS_PHASE].handlers); | |
446 if (h == NULL) { | |
447 return NGX_ERROR; | |
448 } | |
449 | |
450 *h = ngx_stream_access_handler; | |
6175 | 451 |
452 return NGX_OK; | |
453 } |