Mercurial > hg > nginx
annotate src/stream/ngx_stream_upstream_least_conn_module.c @ 7360:8f25a44d9add
SSL: logging level of "no suitable key share".
The "no suitable key share" errors are reported by OpenSSL 1.1.1 when
using TLSv1.3 if there are no shared groups (that is, elliptic curves).
In particular, it is easy enough to trigger by using only a single
curve in ssl_ecdh_curve:
ssl_ecdh_curve secp384r1;
and using a different curve in the client:
openssl s_client -connect 127.0.0.1:443 -curves prime256v1
On the client side it is seen as "sslv3 alert handshake failure",
"SSL alert number 40":
0:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:ssl/record/rec_layer_s3.c:1528:SSL alert number 40
It can be also triggered with default ssl_ecdh_curve by using a curve
which is not in the default list (X25519, prime256v1, X448, secp521r1,
secp384r1):
openssl s_client -connect 127.0.0.1:8443 -curves brainpoolP512r1
Given that many clients hardcode prime256v1, these errors might become
a common problem with TLSv1.3 if ssl_ecdh_curve is redefined. Previously
this resulted in not using ECDH with such clients, but with TLSv1.3 it
is no longer possible and will result in a handshake failure.
The SSL_R_NO_SHARED_GROUP error is what BoringSSL returns in the same
situation.
Seen at:
https://serverfault.com/questions/932102/nginx-ssl-handshake-error-no-suitable-key-share
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Tue, 25 Sep 2018 13:59:53 +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 } |