Mercurial > hg > nginx-quic
comparison src/stream/ngx_stream_ssl_preread_module.c @ 7227:79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
The variable keeps a comma-separated list of protocol names from ALPN TLS
extension defined by RFC 7301.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Mon, 12 Mar 2018 16:03:08 +0300 |
parents | 2a288909abc6 |
children | 0f811890f2f0 |
comparison
equal
deleted
inserted
replaced
7226:0b1eb40de6da | 7227:79eb4f7b6725 |
---|---|
15 | 15 |
16 | 16 |
17 typedef struct { | 17 typedef struct { |
18 size_t left; | 18 size_t left; |
19 size_t size; | 19 size_t size; |
20 size_t ext; | |
20 u_char *pos; | 21 u_char *pos; |
21 u_char *dst; | 22 u_char *dst; |
22 u_char buf[4]; | 23 u_char buf[4]; |
23 ngx_str_t host; | 24 ngx_str_t host; |
25 ngx_str_t alpn; | |
24 ngx_log_t *log; | 26 ngx_log_t *log; |
25 ngx_pool_t *pool; | 27 ngx_pool_t *pool; |
26 ngx_uint_t state; | 28 ngx_uint_t state; |
27 } ngx_stream_ssl_preread_ctx_t; | 29 } ngx_stream_ssl_preread_ctx_t; |
28 | 30 |
29 | 31 |
30 static ngx_int_t ngx_stream_ssl_preread_handler(ngx_stream_session_t *s); | 32 static ngx_int_t ngx_stream_ssl_preread_handler(ngx_stream_session_t *s); |
31 static ngx_int_t ngx_stream_ssl_preread_parse_record( | 33 static ngx_int_t ngx_stream_ssl_preread_parse_record( |
32 ngx_stream_ssl_preread_ctx_t *ctx, u_char *pos, u_char *last); | 34 ngx_stream_ssl_preread_ctx_t *ctx, u_char *pos, u_char *last); |
33 static ngx_int_t ngx_stream_ssl_preread_server_name_variable( | 35 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); | |
37 static ngx_int_t ngx_stream_ssl_preread_alpn_protocols_variable( | |
34 ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); | 38 ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); |
35 static ngx_int_t ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf); | 39 static ngx_int_t ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf); |
36 static void *ngx_stream_ssl_preread_create_srv_conf(ngx_conf_t *cf); | 40 static void *ngx_stream_ssl_preread_create_srv_conf(ngx_conf_t *cf); |
37 static char *ngx_stream_ssl_preread_merge_srv_conf(ngx_conf_t *cf, void *parent, | 41 static char *ngx_stream_ssl_preread_merge_srv_conf(ngx_conf_t *cf, void *parent, |
38 void *child); | 42 void *child); |
83 static ngx_stream_variable_t ngx_stream_ssl_preread_vars[] = { | 87 static ngx_stream_variable_t ngx_stream_ssl_preread_vars[] = { |
84 | 88 |
85 { ngx_string("ssl_preread_server_name"), NULL, | 89 { ngx_string("ssl_preread_server_name"), NULL, |
86 ngx_stream_ssl_preread_server_name_variable, 0, 0, 0 }, | 90 ngx_stream_ssl_preread_server_name_variable, 0, 0, 0 }, |
87 | 91 |
92 { ngx_string("ssl_preread_alpn_protocols"), NULL, | |
93 ngx_stream_ssl_preread_alpn_protocols_variable, 0, 0, 0 }, | |
94 | |
88 ngx_stream_null_variable | 95 ngx_stream_null_variable |
89 }; | 96 }; |
90 | 97 |
91 | 98 |
92 static ngx_int_t | 99 static ngx_int_t |
137 while (last - p >= 5) { | 144 while (last - p >= 5) { |
138 | 145 |
139 if (p[0] != 0x16) { | 146 if (p[0] != 0x16) { |
140 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, | 147 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, |
141 "ssl preread: not a handshake"); | 148 "ssl preread: not a handshake"); |
149 ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module); | |
142 return NGX_DECLINED; | 150 return NGX_DECLINED; |
143 } | 151 } |
144 | 152 |
145 if (p[1] != 3) { | 153 if (p[1] != 3) { |
146 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, | 154 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, |
147 "ssl preread: unsupported SSL version"); | 155 "ssl preread: unsupported SSL version"); |
156 ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module); | |
148 return NGX_DECLINED; | 157 return NGX_DECLINED; |
149 } | 158 } |
150 | 159 |
151 len = (p[3] << 8) + p[4]; | 160 len = (p[3] << 8) + p[4]; |
152 | 161 |
156 } | 165 } |
157 | 166 |
158 p += 5; | 167 p += 5; |
159 | 168 |
160 rc = ngx_stream_ssl_preread_parse_record(ctx, p, p + len); | 169 rc = ngx_stream_ssl_preread_parse_record(ctx, p, p + len); |
170 | |
171 if (rc == NGX_DECLINED) { | |
172 ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module); | |
173 return NGX_DECLINED; | |
174 } | |
175 | |
161 if (rc != NGX_AGAIN) { | 176 if (rc != NGX_AGAIN) { |
162 return rc; | 177 return rc; |
163 } | 178 } |
164 | 179 |
165 p += len; | 180 p += len; |
173 | 188 |
174 static ngx_int_t | 189 static ngx_int_t |
175 ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx, | 190 ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx, |
176 u_char *pos, u_char *last) | 191 u_char *pos, u_char *last) |
177 { | 192 { |
178 size_t left, n, size; | 193 size_t left, n, size, ext; |
179 u_char *dst, *p; | 194 u_char *dst, *p; |
180 | 195 |
181 enum { | 196 enum { |
182 sw_start = 0, | 197 sw_start = 0, |
183 sw_header, /* handshake msg_type, length */ | 198 sw_header, /* handshake msg_type, length */ |
190 sw_cm, /* compression_methods */ | 205 sw_cm, /* compression_methods */ |
191 sw_ext, /* extension */ | 206 sw_ext, /* extension */ |
192 sw_ext_header, /* extension_type, extension_data length */ | 207 sw_ext_header, /* extension_type, extension_data length */ |
193 sw_sni_len, /* SNI length */ | 208 sw_sni_len, /* SNI length */ |
194 sw_sni_host_head, /* SNI name_type, host_name length */ | 209 sw_sni_host_head, /* SNI name_type, host_name length */ |
195 sw_sni_host /* SNI host_name */ | 210 sw_sni_host, /* SNI host_name */ |
211 sw_alpn_len, /* ALPN length */ | |
212 sw_alpn_proto_len, /* ALPN protocol_name length */ | |
213 sw_alpn_proto_data /* ALPN protocol_name */ | |
196 } state; | 214 } state; |
197 | 215 |
198 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0, | 216 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0, |
199 "ssl preread: state %ui left %z", ctx->state, ctx->left); | 217 "ssl preread: state %ui left %z", ctx->state, ctx->left); |
200 | 218 |
201 state = ctx->state; | 219 state = ctx->state; |
202 size = ctx->size; | 220 size = ctx->size; |
203 left = ctx->left; | 221 left = ctx->left; |
222 ext = ctx->ext; | |
204 dst = ctx->dst; | 223 dst = ctx->dst; |
205 p = ctx->buf; | 224 p = ctx->buf; |
206 | 225 |
207 for ( ;; ) { | 226 for ( ;; ) { |
208 n = ngx_min((size_t) (last - pos), size); | 227 n = ngx_min((size_t) (last - pos), size); |
297 dst = p; | 316 dst = p; |
298 size = 4; | 317 size = 4; |
299 break; | 318 break; |
300 | 319 |
301 case sw_ext_header: | 320 case sw_ext_header: |
302 if (p[0] == 0 && p[1] == 0) { | 321 if (p[0] == 0 && p[1] == 0 && ctx->host.data == NULL) { |
303 /* SNI extension */ | 322 /* SNI extension */ |
304 state = sw_sni_len; | 323 state = sw_sni_len; |
305 dst = NULL; | 324 dst = p; |
306 size = 2; | 325 size = 2; |
307 break; | 326 break; |
308 } | 327 } |
309 | 328 |
329 if (p[0] == 0 && p[1] == 16 && ctx->alpn.data == NULL) { | |
330 /* ALPN extension */ | |
331 state = sw_alpn_len; | |
332 dst = p; | |
333 size = 2; | |
334 break; | |
335 } | |
336 | |
310 state = sw_ext; | 337 state = sw_ext; |
311 dst = NULL; | 338 dst = NULL; |
312 size = (p[2] << 8) + p[3]; | 339 size = (p[2] << 8) + p[3]; |
313 break; | 340 break; |
314 | 341 |
315 case sw_sni_len: | 342 case sw_sni_len: |
343 ext = (p[0] << 8) + p[1]; | |
316 state = sw_sni_host_head; | 344 state = sw_sni_host_head; |
317 dst = p; | 345 dst = p; |
318 size = 3; | 346 size = 3; |
319 break; | 347 break; |
320 | 348 |
323 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, | 351 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, |
324 "ssl preread: SNI hostname type is not DNS"); | 352 "ssl preread: SNI hostname type is not DNS"); |
325 return NGX_DECLINED; | 353 return NGX_DECLINED; |
326 } | 354 } |
327 | 355 |
328 state = sw_sni_host; | |
329 size = (p[1] << 8) + p[2]; | 356 size = (p[1] << 8) + p[2]; |
357 | |
358 if (ext < 3 + size) { | |
359 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, | |
360 "ssl preread: SNI format error"); | |
361 return NGX_DECLINED; | |
362 } | |
363 ext -= 3 + size; | |
330 | 364 |
331 ctx->host.data = ngx_pnalloc(ctx->pool, size); | 365 ctx->host.data = ngx_pnalloc(ctx->pool, size); |
332 if (ctx->host.data == NULL) { | 366 if (ctx->host.data == NULL) { |
333 return NGX_ERROR; | 367 return NGX_ERROR; |
334 } | 368 } |
335 | 369 |
370 state = sw_sni_host; | |
336 dst = ctx->host.data; | 371 dst = ctx->host.data; |
337 break; | 372 break; |
338 | 373 |
339 case sw_sni_host: | 374 case sw_sni_host: |
340 ctx->host.len = (p[1] << 8) + p[2]; | 375 ctx->host.len = (p[1] << 8) + p[2]; |
341 | 376 |
342 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0, | 377 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0, |
343 "ssl preread: SNI hostname \"%V\"", &ctx->host); | 378 "ssl preread: SNI hostname \"%V\"", &ctx->host); |
344 return NGX_OK; | 379 |
380 state = sw_ext; | |
381 dst = NULL; | |
382 size = ext; | |
383 break; | |
384 | |
385 case sw_alpn_len: | |
386 ext = (p[0] << 8) + p[1]; | |
387 | |
388 ctx->alpn.data = ngx_pnalloc(ctx->pool, ext); | |
389 if (ctx->alpn.data == NULL) { | |
390 return NGX_ERROR; | |
391 } | |
392 | |
393 state = sw_alpn_proto_len; | |
394 dst = p; | |
395 size = 1; | |
396 break; | |
397 | |
398 case sw_alpn_proto_len: | |
399 size = p[0]; | |
400 | |
401 if (size == 0) { | |
402 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, | |
403 "ssl preread: ALPN empty protocol"); | |
404 return NGX_DECLINED; | |
405 } | |
406 | |
407 if (ext < 1 + size) { | |
408 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, | |
409 "ssl preread: ALPN format error"); | |
410 return NGX_DECLINED; | |
411 } | |
412 ext -= 1 + size; | |
413 | |
414 state = sw_alpn_proto_data; | |
415 dst = ctx->alpn.data + ctx->alpn.len; | |
416 break; | |
417 | |
418 case sw_alpn_proto_data: | |
419 ctx->alpn.len += p[0]; | |
420 | |
421 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0, | |
422 "ssl preread: ALPN protocols \"%V\"", &ctx->alpn); | |
423 | |
424 if (ext) { | |
425 ctx->alpn.data[ctx->alpn.len++] = ','; | |
426 | |
427 state = sw_alpn_proto_len; | |
428 dst = p; | |
429 size = 1; | |
430 break; | |
431 } | |
432 | |
433 state = sw_ext; | |
434 dst = NULL; | |
435 size = 0; | |
436 break; | |
345 } | 437 } |
346 | 438 |
347 if (left < size) { | 439 if (left < size) { |
348 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, | 440 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, |
349 "ssl preread: failed to parse handshake"); | 441 "ssl preread: failed to parse handshake"); |
352 } | 444 } |
353 | 445 |
354 ctx->state = state; | 446 ctx->state = state; |
355 ctx->size = size; | 447 ctx->size = size; |
356 ctx->left = left; | 448 ctx->left = left; |
449 ctx->ext = ext; | |
357 ctx->dst = dst; | 450 ctx->dst = dst; |
358 | 451 |
359 return NGX_AGAIN; | 452 return NGX_AGAIN; |
360 } | 453 } |
361 | 454 |
382 return NGX_OK; | 475 return NGX_OK; |
383 } | 476 } |
384 | 477 |
385 | 478 |
386 static ngx_int_t | 479 static ngx_int_t |
480 ngx_stream_ssl_preread_alpn_protocols_variable(ngx_stream_session_t *s, | |
481 ngx_variable_value_t *v, uintptr_t data) | |
482 { | |
483 ngx_stream_ssl_preread_ctx_t *ctx; | |
484 | |
485 ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module); | |
486 | |
487 if (ctx == NULL) { | |
488 v->not_found = 1; | |
489 return NGX_OK; | |
490 } | |
491 | |
492 v->valid = 1; | |
493 v->no_cacheable = 0; | |
494 v->not_found = 0; | |
495 v->len = ctx->alpn.len; | |
496 v->data = ctx->alpn.data; | |
497 | |
498 return NGX_OK; | |
499 } | |
500 | |
501 | |
502 static ngx_int_t | |
387 ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf) | 503 ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf) |
388 { | 504 { |
389 ngx_stream_variable_t *var, *v; | 505 ngx_stream_variable_t *var, *v; |
390 | 506 |
391 for (v = ngx_stream_ssl_preread_vars; v->name.len; v++) { | 507 for (v = ngx_stream_ssl_preread_vars; v->name.len; v++) { |