Stream ssl_preread: $ssl_preread_protocol variable.
The variable keeps the latest SSL protocol version supported by the client.
The variable has the same format as $ssl_protocol.
The version is read from the client_version field of ClientHello. If the
supported_versions extension is present in the ClientHello, then the version
is set to TLSv1.3.
Roman Arutyunyan
3 years ago
20 | 20 | u_char *pos; |
21 | 21 | u_char *dst; |
22 | 22 | u_char buf[4]; |
23 | u_char version[2]; | |
23 | 24 | ngx_str_t host; |
24 | 25 | ngx_str_t alpn; |
25 | 26 | ngx_log_t *log; |
31 | 32 | static ngx_int_t ngx_stream_ssl_preread_handler(ngx_stream_session_t *s); |
32 | 33 | static ngx_int_t ngx_stream_ssl_preread_parse_record( |
33 | 34 | ngx_stream_ssl_preread_ctx_t *ctx, u_char *pos, u_char *last); |
35 | static ngx_int_t ngx_stream_ssl_preread_protocol_variable( | |
36 | ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); | |
34 | 37 | static ngx_int_t ngx_stream_ssl_preread_server_name_variable( |
35 | 38 | ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); |
36 | 39 | static ngx_int_t ngx_stream_ssl_preread_alpn_protocols_variable( |
85 | 88 | |
86 | 89 | static ngx_stream_variable_t ngx_stream_ssl_preread_vars[] = { |
87 | 90 | |
91 | { ngx_string("ssl_preread_protocol"), NULL, | |
92 | ngx_stream_ssl_preread_protocol_variable, 0, 0, 0 }, | |
93 | ||
88 | 94 | { ngx_string("ssl_preread_server_name"), NULL, |
89 | 95 | ngx_stream_ssl_preread_server_name_variable, 0, 0, 0 }, |
90 | 96 | |
195 | 201 | enum { |
196 | 202 | sw_start = 0, |
197 | 203 | sw_header, /* handshake msg_type, length */ |
198 | sw_head_tail, /* version, random */ | |
204 | sw_version, /* client_version */ | |
205 | sw_random, /* random */ | |
199 | 206 | sw_sid_len, /* session_id length */ |
200 | 207 | sw_sid, /* session_id */ |
201 | 208 | sw_cs_len, /* cipher_suites length */ |
209 | 216 | sw_sni_host, /* SNI host_name */ |
210 | 217 | sw_alpn_len, /* ALPN length */ |
211 | 218 | sw_alpn_proto_len, /* ALPN protocol_name length */ |
212 | sw_alpn_proto_data /* ALPN protocol_name */ | |
219 | sw_alpn_proto_data, /* ALPN protocol_name */ | |
220 | sw_supver_len /* supported_versions length */ | |
213 | 221 | } state; |
214 | 222 | |
215 | 223 | ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0, |
253 | 261 | return NGX_DECLINED; |
254 | 262 | } |
255 | 263 | |
256 | state = sw_head_tail; | |
257 | dst = NULL; | |
258 | size = 34; | |
264 | state = sw_version; | |
265 | dst = ctx->version; | |
266 | size = 2; | |
259 | 267 | left = (p[1] << 16) + (p[2] << 8) + p[3]; |
260 | 268 | break; |
261 | 269 | |
262 | case sw_head_tail: | |
270 | case sw_version: | |
271 | state = sw_random; | |
272 | dst = NULL; | |
273 | size = 32; | |
274 | break; | |
275 | ||
276 | case sw_random: | |
263 | 277 | state = sw_sid_len; |
264 | 278 | dst = p; |
265 | 279 | size = 1; |
333 | 347 | break; |
334 | 348 | } |
335 | 349 | |
350 | if (p[0] == 0 && p[1] == 43) { | |
351 | /* supported_versions extension */ | |
352 | state = sw_supver_len; | |
353 | dst = p; | |
354 | size = 1; | |
355 | break; | |
356 | } | |
357 | ||
336 | 358 | state = sw_ext; |
337 | 359 | dst = NULL; |
338 | 360 | size = (p[2] << 8) + p[3]; |
433 | 455 | dst = NULL; |
434 | 456 | size = 0; |
435 | 457 | break; |
458 | ||
459 | case sw_supver_len: | |
460 | ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, | |
461 | "ssl preread: supported_versions"); | |
462 | ||
463 | /* set TLSv1.3 */ | |
464 | ctx->version[0] = 3; | |
465 | ctx->version[1] = 4; | |
466 | ||
467 | state = sw_ext; | |
468 | dst = NULL; | |
469 | size = p[0]; | |
470 | break; | |
436 | 471 | } |
437 | 472 | |
438 | 473 | if (left < size) { |
453 | 488 | |
454 | 489 | |
455 | 490 | static ngx_int_t |
491 | ngx_stream_ssl_preread_protocol_variable(ngx_stream_session_t *s, | |
492 | ngx_variable_value_t *v, uintptr_t data) | |
493 | { | |
494 | ngx_str_t version; | |
495 | ngx_stream_ssl_preread_ctx_t *ctx; | |
496 | ||
497 | ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module); | |
498 | ||
499 | if (ctx == NULL) { | |
500 | v->not_found = 1; | |
501 | return NGX_OK; | |
502 | } | |
503 | ||
504 | /* SSL_get_version() format */ | |
505 | ||
506 | ngx_str_null(&version); | |
507 | ||
508 | switch (ctx->version[0]) { | |
509 | case 2: | |
510 | ngx_str_set(&version, "SSLv2"); | |
511 | break; | |
512 | case 3: | |
513 | switch (ctx->version[1]) { | |
514 | case 0: | |
515 | ngx_str_set(&version, "SSLv3"); | |
516 | break; | |
517 | case 1: | |
518 | ngx_str_set(&version, "TLSv1"); | |
519 | break; | |
520 | case 2: | |
521 | ngx_str_set(&version, "TLSv1.1"); | |
522 | break; | |
523 | case 3: | |
524 | ngx_str_set(&version, "TLSv1.2"); | |
525 | break; | |
526 | case 4: | |
527 | ngx_str_set(&version, "TLSv1.3"); | |
528 | break; | |
529 | } | |
530 | } | |
531 | ||
532 | v->valid = 1; | |
533 | v->no_cacheable = 0; | |
534 | v->not_found = 0; | |
535 | v->len = version.len; | |
536 | v->data = version.data; | |
537 | ||
538 | return NGX_OK; | |
539 | } | |
540 | ||
541 | ||
542 | static ngx_int_t | |
456 | 543 | ngx_stream_ssl_preread_server_name_variable(ngx_stream_session_t *s, |
457 | 544 | ngx_variable_value_t *v, uintptr_t data) |
458 | 545 | { |