Mercurial > hg > nginx-quic
annotate src/stream/ngx_stream_upstream_least_conn_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 | 29bf0dbc0a77 |
children |
rev | line source |
---|---|
6115 | 1 |
2 /* | |
3 * Copyright (C) Maxim Dounin | |
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 static ngx_int_t ngx_stream_upstream_init_least_conn_peer( | |
14 ngx_stream_session_t *s, ngx_stream_upstream_srv_conf_t *us); | |
15 static ngx_int_t ngx_stream_upstream_get_least_conn_peer( | |
16 ngx_peer_connection_t *pc, void *data); | |
17 static char *ngx_stream_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, | |
18 void *conf); | |
19 | |
20 | |
21 static ngx_command_t ngx_stream_upstream_least_conn_commands[] = { | |
22 | |
23 { ngx_string("least_conn"), | |
24 NGX_STREAM_UPS_CONF|NGX_CONF_NOARGS, | |
25 ngx_stream_upstream_least_conn, | |
26 0, | |
27 0, | |
28 NULL }, | |
29 | |
30 ngx_null_command | |
31 }; | |
32 | |
33 | |
34 static ngx_stream_module_t ngx_stream_upstream_least_conn_module_ctx = { | |
6606
2f41d383c9c7
Stream: added preconfiguration step.
Vladimir Homutov <vl@nginx.com>
parents:
6474
diff
changeset
|
35 NULL, /* preconfiguration */ |
6174
68c106e6fa0a
Stream: added postconfiguration method to stream modules.
Vladimir Homutov <vl@nginx.com>
parents:
6115
diff
changeset
|
36 NULL, /* postconfiguration */ |
68c106e6fa0a
Stream: added postconfiguration method to stream modules.
Vladimir Homutov <vl@nginx.com>
parents:
6115
diff
changeset
|
37 |
6115 | 38 NULL, /* create main configuration */ |
39 NULL, /* init main configuration */ | |
40 | |
41 NULL, /* create server configuration */ | |
6629 | 42 NULL /* merge server configuration */ |
6115 | 43 }; |
44 | |
45 | |
46 ngx_module_t ngx_stream_upstream_least_conn_module = { | |
47 NGX_MODULE_V1, | |
48 &ngx_stream_upstream_least_conn_module_ctx, /* module context */ | |
49 ngx_stream_upstream_least_conn_commands, /* module directives */ | |
50 NGX_STREAM_MODULE, /* module type */ | |
51 NULL, /* init master */ | |
52 NULL, /* init module */ | |
53 NULL, /* init process */ | |
54 NULL, /* init thread */ | |
55 NULL, /* exit thread */ | |
56 NULL, /* exit process */ | |
57 NULL, /* exit master */ | |
58 NGX_MODULE_V1_PADDING | |
59 }; | |
60 | |
61 | |
62 static ngx_int_t | |
63 ngx_stream_upstream_init_least_conn(ngx_conf_t *cf, | |
64 ngx_stream_upstream_srv_conf_t *us) | |
65 { | |
66 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, cf->log, 0, | |
67 "init least conn"); | |
68 | |
69 if (ngx_stream_upstream_init_round_robin(cf, us) != NGX_OK) { | |
70 return NGX_ERROR; | |
71 } | |
72 | |
73 us->peer.init = ngx_stream_upstream_init_least_conn_peer; | |
74 | |
75 return NGX_OK; | |
76 } | |
77 | |
78 | |
79 static ngx_int_t | |
80 ngx_stream_upstream_init_least_conn_peer(ngx_stream_session_t *s, | |
81 ngx_stream_upstream_srv_conf_t *us) | |
82 { | |
83 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, | |
84 "init least conn peer"); | |
85 | |
86 if (ngx_stream_upstream_init_round_robin_peer(s, us) != NGX_OK) { | |
87 return NGX_ERROR; | |
88 } | |
89 | |
90 s->upstream->peer.get = ngx_stream_upstream_get_least_conn_peer; | |
91 | |
92 return NGX_OK; | |
93 } | |
94 | |
95 | |
96 static ngx_int_t | |
97 ngx_stream_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data) | |
98 { | |
99 ngx_stream_upstream_rr_peer_data_t *rrp = data; | |
100 | |
101 time_t now; | |
102 uintptr_t m; | |
103 ngx_int_t rc, total; | |
104 ngx_uint_t i, n, p, many; | |
105 ngx_stream_upstream_rr_peer_t *peer, *best; | |
106 ngx_stream_upstream_rr_peers_t *peers; | |
107 | |
108 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
109 "get least conn peer, try: %ui", pc->tries); | |
110 | |
111 if (rrp->peers->single) { | |
112 return ngx_stream_upstream_get_round_robin_peer(pc, rrp); | |
113 } | |
114 | |
115 pc->connection = NULL; | |
116 | |
117 now = ngx_time(); | |
118 | |
119 peers = rrp->peers; | |
120 | |
121 ngx_stream_upstream_rr_peers_wlock(peers); | |
122 | |
123 best = NULL; | |
124 total = 0; | |
125 | |
126 #if (NGX_SUPPRESS_WARN) | |
127 many = 0; | |
128 p = 0; | |
129 #endif | |
130 | |
131 for (peer = peers->peer, i = 0; | |
132 peer; | |
133 peer = peer->next, i++) | |
134 { | |
135 n = i / (8 * sizeof(uintptr_t)); | |
136 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); | |
137 | |
138 if (rrp->tried[n] & m) { | |
139 continue; | |
140 } | |
141 | |
142 if (peer->down) { | |
143 continue; | |
144 } | |
145 | |
146 if (peer->max_fails | |
147 && peer->fails >= peer->max_fails | |
148 && now - peer->checked <= peer->fail_timeout) | |
149 { | |
150 continue; | |
151 } | |
152 | |
6705 | 153 if (peer->max_conns && peer->conns >= peer->max_conns) { |
154 continue; | |
155 } | |
156 | |
6115 | 157 /* |
158 * select peer with least number of connections; if there are | |
159 * multiple peers with the same number of connections, select | |
160 * based on round-robin | |
161 */ | |
162 | |
163 if (best == NULL | |
164 || peer->conns * best->weight < best->conns * peer->weight) | |
165 { | |
166 best = peer; | |
167 many = 0; | |
168 p = i; | |
169 | |
170 } else if (peer->conns * best->weight == best->conns * peer->weight) { | |
171 many = 1; | |
172 } | |
173 } | |
174 | |
175 if (best == NULL) { | |
176 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
177 "get least conn peer, no peer found"); | |
178 | |
179 goto failed; | |
180 } | |
181 | |
182 if (many) { | |
183 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
184 "get least conn peer, many"); | |
185 | |
186 for (peer = best, i = p; | |
187 peer; | |
188 peer = peer->next, i++) | |
189 { | |
190 n = i / (8 * sizeof(uintptr_t)); | |
191 m = (uintptr_t) 1 << i % (8 * sizeof(uintptr_t)); | |
192 | |
193 if (rrp->tried[n] & m) { | |
194 continue; | |
195 } | |
196 | |
197 if (peer->down) { | |
198 continue; | |
199 } | |
200 | |
201 if (peer->conns * best->weight != best->conns * peer->weight) { | |
202 continue; | |
203 } | |
204 | |
205 if (peer->max_fails | |
206 && peer->fails >= peer->max_fails | |
207 && now - peer->checked <= peer->fail_timeout) | |
208 { | |
209 continue; | |
210 } | |
211 | |
6705 | 212 if (peer->max_conns && peer->conns >= peer->max_conns) { |
213 continue; | |
214 } | |
215 | |
6115 | 216 peer->current_weight += peer->effective_weight; |
217 total += peer->effective_weight; | |
218 | |
219 if (peer->effective_weight < peer->weight) { | |
220 peer->effective_weight++; | |
221 } | |
222 | |
223 if (peer->current_weight > best->current_weight) { | |
224 best = peer; | |
225 p = i; | |
226 } | |
227 } | |
228 } | |
229 | |
230 best->current_weight -= total; | |
231 | |
232 if (now - best->checked > best->fail_timeout) { | |
233 best->checked = now; | |
234 } | |
235 | |
236 pc->sockaddr = best->sockaddr; | |
237 pc->socklen = best->socklen; | |
238 pc->name = &best->name; | |
239 | |
240 best->conns++; | |
241 | |
242 rrp->current = best; | |
243 | |
244 n = p / (8 * sizeof(uintptr_t)); | |
245 m = (uintptr_t) 1 << p % (8 * sizeof(uintptr_t)); | |
246 | |
247 rrp->tried[n] |= m; | |
248 | |
249 ngx_stream_upstream_rr_peers_unlock(peers); | |
250 | |
251 return NGX_OK; | |
252 | |
253 failed: | |
254 | |
255 if (peers->next) { | |
256 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, | |
257 "get least conn peer, backup servers"); | |
258 | |
259 rrp->peers = peers->next; | |
260 | |
261 n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1)) | |
262 / (8 * sizeof(uintptr_t)); | |
263 | |
264 for (i = 0; i < n; i++) { | |
6474 | 265 rrp->tried[i] = 0; |
6115 | 266 } |
267 | |
268 ngx_stream_upstream_rr_peers_unlock(peers); | |
269 | |
270 rc = ngx_stream_upstream_get_least_conn_peer(pc, rrp); | |
271 | |
272 if (rc != NGX_BUSY) { | |
273 return rc; | |
274 } | |
275 | |
276 ngx_stream_upstream_rr_peers_wlock(peers); | |
277 } | |
278 | |
279 ngx_stream_upstream_rr_peers_unlock(peers); | |
280 | |
281 pc->name = peers->name; | |
282 | |
283 return NGX_BUSY; | |
284 } | |
285 | |
286 | |
287 static char * | |
288 ngx_stream_upstream_least_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
289 { | |
290 ngx_stream_upstream_srv_conf_t *uscf; | |
291 | |
292 uscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_upstream_module); | |
293 | |
294 if (uscf->peer.init_upstream) { | |
295 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | |
296 "load balancing method redefined"); | |
297 } | |
298 | |
299 uscf->peer.init_upstream = ngx_stream_upstream_init_least_conn; | |
300 | |
301 uscf->flags = NGX_STREAM_UPSTREAM_CREATE | |
302 |NGX_STREAM_UPSTREAM_WEIGHT | |
6705 | 303 |NGX_STREAM_UPSTREAM_MAX_CONNS |
6115 | 304 |NGX_STREAM_UPSTREAM_MAX_FAILS |
305 |NGX_STREAM_UPSTREAM_FAIL_TIMEOUT | |
306 |NGX_STREAM_UPSTREAM_DOWN | |
307 |NGX_STREAM_UPSTREAM_BACKUP; | |
308 | |
309 return NGX_CONF_OK; | |
310 } |