Mercurial > hg > nginx
annotate src/stream/ngx_stream_access_module.c @ 6982:ac9b1df5b246
SSL: disabled renegotiation detection in client mode.
CVE-2009-3555 is no longer relevant and mitigated by the renegotiation
info extension (secure renegotiation). On the other hand, unexpected
renegotiation still introduces potential security risks, and hence we do
not allow renegotiation on the server side, as we never request renegotiation.
On the client side the situation is different though. There are backends
which explicitly request renegotiation, and disabled renegotiation
introduces interoperability problems. This change allows renegotiation
on the client side, and fixes interoperability problems as observed with
such backends (ticket #872).
Additionally, with TLSv1.3 the SSL_CB_HANDSHAKE_START flag is currently set
by OpenSSL when receiving a NewSessionTicket message, and was detected by
nginx as a renegotiation attempt. This looks like a bug in OpenSSL, though
this change also allows better interoperability till the problem is fixed.
author | Sergey Kandaurov <pluknet@nginx.com> |
---|---|
date | Tue, 18 Apr 2017 16:08:44 +0300 |
parents | 3908156a51fa |
children | 72188d1bcab5 |
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 | |
302 ngx_memzero(&cidr, sizeof(ngx_cidr_t)); | |
303 | |
304 value = cf->args->elts; | |
305 | |
306 all = (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0); | |
307 | |
308 if (!all) { | |
309 | |
310 #if (NGX_HAVE_UNIX_DOMAIN) | |
311 | |
312 if (value[1].len == 5 && ngx_strcmp(value[1].data, "unix:") == 0) { | |
313 cidr.family = AF_UNIX; | |
314 rc = NGX_OK; | |
315 | |
316 } else { | |
317 rc = ngx_ptocidr(&value[1], &cidr); | |
318 } | |
319 | |
320 #else | |
321 rc = ngx_ptocidr(&value[1], &cidr); | |
322 #endif | |
323 | |
324 if (rc == NGX_ERROR) { | |
325 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
326 "invalid parameter \"%V\"", &value[1]); | |
327 return NGX_CONF_ERROR; | |
328 } | |
329 | |
330 if (rc == NGX_DONE) { | |
331 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | |
332 "low address bits of %V are meaningless", &value[1]); | |
333 } | |
334 } | |
335 | |
336 if (cidr.family == AF_INET || all) { | |
337 | |
338 if (ascf->rules == NULL) { | |
339 ascf->rules = ngx_array_create(cf->pool, 4, | |
340 sizeof(ngx_stream_access_rule_t)); | |
341 if (ascf->rules == NULL) { | |
342 return NGX_CONF_ERROR; | |
343 } | |
344 } | |
345 | |
346 rule = ngx_array_push(ascf->rules); | |
347 if (rule == NULL) { | |
348 return NGX_CONF_ERROR; | |
349 } | |
350 | |
351 rule->mask = cidr.u.in.mask; | |
352 rule->addr = cidr.u.in.addr; | |
353 rule->deny = (value[0].data[0] == 'd') ? 1 : 0; | |
354 } | |
355 | |
356 #if (NGX_HAVE_INET6) | |
357 if (cidr.family == AF_INET6 || all) { | |
358 | |
359 if (ascf->rules6 == NULL) { | |
360 ascf->rules6 = ngx_array_create(cf->pool, 4, | |
361 sizeof(ngx_stream_access_rule6_t)); | |
362 if (ascf->rules6 == NULL) { | |
363 return NGX_CONF_ERROR; | |
364 } | |
365 } | |
366 | |
367 rule6 = ngx_array_push(ascf->rules6); | |
368 if (rule6 == NULL) { | |
369 return NGX_CONF_ERROR; | |
370 } | |
371 | |
372 rule6->mask = cidr.u.in6.mask; | |
373 rule6->addr = cidr.u.in6.addr; | |
374 rule6->deny = (value[0].data[0] == 'd') ? 1 : 0; | |
375 } | |
376 #endif | |
377 | |
378 #if (NGX_HAVE_UNIX_DOMAIN) | |
379 if (cidr.family == AF_UNIX || all) { | |
380 | |
381 if (ascf->rules_un == NULL) { | |
382 ascf->rules_un = ngx_array_create(cf->pool, 1, | |
383 sizeof(ngx_stream_access_rule_un_t)); | |
384 if (ascf->rules_un == NULL) { | |
385 return NGX_CONF_ERROR; | |
386 } | |
387 } | |
388 | |
389 rule_un = ngx_array_push(ascf->rules_un); | |
390 if (rule_un == NULL) { | |
391 return NGX_CONF_ERROR; | |
392 } | |
393 | |
394 rule_un->deny = (value[0].data[0] == 'd') ? 1 : 0; | |
395 } | |
396 #endif | |
397 | |
398 return NGX_CONF_OK; | |
399 } | |
400 | |
401 | |
402 static void * | |
403 ngx_stream_access_create_srv_conf(ngx_conf_t *cf) | |
404 { | |
405 ngx_stream_access_srv_conf_t *conf; | |
406 | |
407 conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_access_srv_conf_t)); | |
408 if (conf == NULL) { | |
409 return NULL; | |
410 } | |
411 | |
412 return conf; | |
413 } | |
414 | |
415 | |
416 static char * | |
417 ngx_stream_access_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) | |
418 { | |
419 ngx_stream_access_srv_conf_t *prev = parent; | |
420 ngx_stream_access_srv_conf_t *conf = child; | |
421 | |
422 if (conf->rules == NULL | |
423 #if (NGX_HAVE_INET6) | |
424 && conf->rules6 == NULL | |
425 #endif | |
426 #if (NGX_HAVE_UNIX_DOMAIN) | |
427 && conf->rules_un == NULL | |
428 #endif | |
429 ) { | |
430 conf->rules = prev->rules; | |
431 #if (NGX_HAVE_INET6) | |
432 conf->rules6 = prev->rules6; | |
433 #endif | |
434 #if (NGX_HAVE_UNIX_DOMAIN) | |
435 conf->rules_un = prev->rules_un; | |
436 #endif | |
437 } | |
438 | |
439 return NGX_CONF_OK; | |
440 } | |
441 | |
442 | |
443 static ngx_int_t | |
444 ngx_stream_access_init(ngx_conf_t *cf) | |
445 { | |
6693 | 446 ngx_stream_handler_pt *h; |
6175 | 447 ngx_stream_core_main_conf_t *cmcf; |
448 | |
449 cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); | |
6693 | 450 |
451 h = ngx_array_push(&cmcf->phases[NGX_STREAM_ACCESS_PHASE].handlers); | |
452 if (h == NULL) { | |
453 return NGX_ERROR; | |
454 } | |
455 | |
456 *h = ngx_stream_access_handler; | |
6175 | 457 |
458 return NGX_OK; | |
459 } |