comparison src/stream/ngx_stream_ssl_preread_module.c @ 7314:3dfc1584ad75

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.
author Roman Arutyunyan <arut@nginx.com>
date Wed, 11 Jul 2018 17:56:51 +0300
parents 0f811890f2f0
children 6649d4433266
comparison
equal deleted inserted replaced
7313:e45f09198dab 7314:3dfc1584ad75
19 size_t size; 19 size_t size;
20 size_t ext; 20 size_t ext;
21 u_char *pos; 21 u_char *pos;
22 u_char *dst; 22 u_char *dst;
23 u_char buf[4]; 23 u_char buf[4];
24 u_char version[2];
24 ngx_str_t host; 25 ngx_str_t host;
25 ngx_str_t alpn; 26 ngx_str_t alpn;
26 ngx_log_t *log; 27 ngx_log_t *log;
27 ngx_pool_t *pool; 28 ngx_pool_t *pool;
28 ngx_uint_t state; 29 ngx_uint_t state;
30 31
31 32
32 static ngx_int_t ngx_stream_ssl_preread_handler(ngx_stream_session_t *s); 33 static ngx_int_t ngx_stream_ssl_preread_handler(ngx_stream_session_t *s);
33 static ngx_int_t ngx_stream_ssl_preread_parse_record( 34 static ngx_int_t ngx_stream_ssl_preread_parse_record(
34 ngx_stream_ssl_preread_ctx_t *ctx, u_char *pos, u_char *last); 35 ngx_stream_ssl_preread_ctx_t *ctx, u_char *pos, u_char *last);
36 static ngx_int_t ngx_stream_ssl_preread_protocol_variable(
37 ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
35 static ngx_int_t ngx_stream_ssl_preread_server_name_variable( 38 static ngx_int_t ngx_stream_ssl_preread_server_name_variable(
36 ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); 39 ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
37 static ngx_int_t ngx_stream_ssl_preread_alpn_protocols_variable( 40 static ngx_int_t ngx_stream_ssl_preread_alpn_protocols_variable(
38 ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); 41 ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
39 static ngx_int_t ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf); 42 static ngx_int_t ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf);
84 }; 87 };
85 88
86 89
87 static ngx_stream_variable_t ngx_stream_ssl_preread_vars[] = { 90 static ngx_stream_variable_t ngx_stream_ssl_preread_vars[] = {
88 91
92 { ngx_string("ssl_preread_protocol"), NULL,
93 ngx_stream_ssl_preread_protocol_variable, 0, 0, 0 },
94
89 { ngx_string("ssl_preread_server_name"), NULL, 95 { ngx_string("ssl_preread_server_name"), NULL,
90 ngx_stream_ssl_preread_server_name_variable, 0, 0, 0 }, 96 ngx_stream_ssl_preread_server_name_variable, 0, 0, 0 },
91 97
92 { ngx_string("ssl_preread_alpn_protocols"), NULL, 98 { ngx_string("ssl_preread_alpn_protocols"), NULL,
93 ngx_stream_ssl_preread_alpn_protocols_variable, 0, 0, 0 }, 99 ngx_stream_ssl_preread_alpn_protocols_variable, 0, 0, 0 },
194 u_char *dst, *p; 200 u_char *dst, *p;
195 201
196 enum { 202 enum {
197 sw_start = 0, 203 sw_start = 0,
198 sw_header, /* handshake msg_type, length */ 204 sw_header, /* handshake msg_type, length */
199 sw_head_tail, /* version, random */ 205 sw_version, /* client_version */
206 sw_random, /* random */
200 sw_sid_len, /* session_id length */ 207 sw_sid_len, /* session_id length */
201 sw_sid, /* session_id */ 208 sw_sid, /* session_id */
202 sw_cs_len, /* cipher_suites length */ 209 sw_cs_len, /* cipher_suites length */
203 sw_cs, /* cipher_suites */ 210 sw_cs, /* cipher_suites */
204 sw_cm_len, /* compression_methods length */ 211 sw_cm_len, /* compression_methods length */
208 sw_sni_len, /* SNI length */ 215 sw_sni_len, /* SNI length */
209 sw_sni_host_head, /* SNI name_type, host_name length */ 216 sw_sni_host_head, /* SNI name_type, host_name length */
210 sw_sni_host, /* SNI host_name */ 217 sw_sni_host, /* SNI host_name */
211 sw_alpn_len, /* ALPN length */ 218 sw_alpn_len, /* ALPN length */
212 sw_alpn_proto_len, /* ALPN protocol_name length */ 219 sw_alpn_proto_len, /* ALPN protocol_name length */
213 sw_alpn_proto_data /* ALPN protocol_name */ 220 sw_alpn_proto_data, /* ALPN protocol_name */
221 sw_supver_len /* supported_versions length */
214 } state; 222 } state;
215 223
216 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0, 224 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
217 "ssl preread: state %ui left %z", ctx->state, ctx->left); 225 "ssl preread: state %ui left %z", ctx->state, ctx->left);
218 226
252 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, 260 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
253 "ssl preread: not a client hello"); 261 "ssl preread: not a client hello");
254 return NGX_DECLINED; 262 return NGX_DECLINED;
255 } 263 }
256 264
257 state = sw_head_tail; 265 state = sw_version;
258 dst = NULL; 266 dst = ctx->version;
259 size = 34; 267 size = 2;
260 left = (p[1] << 16) + (p[2] << 8) + p[3]; 268 left = (p[1] << 16) + (p[2] << 8) + p[3];
261 break; 269 break;
262 270
263 case sw_head_tail: 271 case sw_version:
272 state = sw_random;
273 dst = NULL;
274 size = 32;
275 break;
276
277 case sw_random:
264 state = sw_sid_len; 278 state = sw_sid_len;
265 dst = p; 279 dst = p;
266 size = 1; 280 size = 1;
267 break; 281 break;
268 282
332 dst = p; 346 dst = p;
333 size = 2; 347 size = 2;
334 break; 348 break;
335 } 349 }
336 350
351 if (p[0] == 0 && p[1] == 43) {
352 /* supported_versions extension */
353 state = sw_supver_len;
354 dst = p;
355 size = 1;
356 break;
357 }
358
337 state = sw_ext; 359 state = sw_ext;
338 dst = NULL; 360 dst = NULL;
339 size = (p[2] << 8) + p[3]; 361 size = (p[2] << 8) + p[3];
340 break; 362 break;
341 363
432 454
433 state = sw_ext; 455 state = sw_ext;
434 dst = NULL; 456 dst = NULL;
435 size = 0; 457 size = 0;
436 break; 458 break;
459
460 case sw_supver_len:
461 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
462 "ssl preread: supported_versions");
463
464 /* set TLSv1.3 */
465 ctx->version[0] = 3;
466 ctx->version[1] = 4;
467
468 state = sw_ext;
469 dst = NULL;
470 size = p[0];
471 break;
437 } 472 }
438 473
439 if (left < size) { 474 if (left < size) {
440 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, 475 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
441 "ssl preread: failed to parse handshake"); 476 "ssl preread: failed to parse handshake");
452 return NGX_AGAIN; 487 return NGX_AGAIN;
453 } 488 }
454 489
455 490
456 static ngx_int_t 491 static ngx_int_t
492 ngx_stream_ssl_preread_protocol_variable(ngx_stream_session_t *s,
493 ngx_variable_value_t *v, uintptr_t data)
494 {
495 ngx_str_t version;
496 ngx_stream_ssl_preread_ctx_t *ctx;
497
498 ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module);
499
500 if (ctx == NULL) {
501 v->not_found = 1;
502 return NGX_OK;
503 }
504
505 /* SSL_get_version() format */
506
507 ngx_str_null(&version);
508
509 switch (ctx->version[0]) {
510 case 2:
511 ngx_str_set(&version, "SSLv2");
512 break;
513 case 3:
514 switch (ctx->version[1]) {
515 case 0:
516 ngx_str_set(&version, "SSLv3");
517 break;
518 case 1:
519 ngx_str_set(&version, "TLSv1");
520 break;
521 case 2:
522 ngx_str_set(&version, "TLSv1.1");
523 break;
524 case 3:
525 ngx_str_set(&version, "TLSv1.2");
526 break;
527 case 4:
528 ngx_str_set(&version, "TLSv1.3");
529 break;
530 }
531 }
532
533 v->valid = 1;
534 v->no_cacheable = 0;
535 v->not_found = 0;
536 v->len = version.len;
537 v->data = version.data;
538
539 return NGX_OK;
540 }
541
542
543 static ngx_int_t
457 ngx_stream_ssl_preread_server_name_variable(ngx_stream_session_t *s, 544 ngx_stream_ssl_preread_server_name_variable(ngx_stream_session_t *s,
458 ngx_variable_value_t *v, uintptr_t data) 545 ngx_variable_value_t *v, uintptr_t data)
459 { 546 {
460 ngx_stream_ssl_preread_ctx_t *ctx; 547 ngx_stream_ssl_preread_ctx_t *ctx;
461 548