Mercurial > hg > nginx-quic
annotate src/stream/ngx_stream_ssl_preread_module.c @ 7385:1c6b6163c039 stable-1.14
HTTP/2: flood detection.
Fixed uncontrolled memory growth in case peer is flooding us with
some frames (e.g., SETTINGS and PING) and doesn't read data. Fix
is to limit the number of allocated control frames.
author | Ruslan Ermilov <ru@nginx.com> |
---|---|
date | Tue, 06 Nov 2018 16:29:35 +0300 |
parents | 0f811890f2f0 |
children | 3dfc1584ad75 |
rev | line source |
---|---|
6695 | 1 |
2 /* | |
3 * Copyright (C) Nginx, Inc. | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_stream.h> | |
10 | |
11 | |
12 typedef struct { | |
13 ngx_flag_t enabled; | |
14 } ngx_stream_ssl_preread_srv_conf_t; | |
15 | |
16 | |
17 typedef struct { | |
18 size_t left; | |
19 size_t size; | |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
20 size_t ext; |
6695 | 21 u_char *pos; |
22 u_char *dst; | |
23 u_char buf[4]; | |
24 ngx_str_t host; | |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
25 ngx_str_t alpn; |
6695 | 26 ngx_log_t *log; |
27 ngx_pool_t *pool; | |
28 ngx_uint_t state; | |
29 } ngx_stream_ssl_preread_ctx_t; | |
30 | |
31 | |
32 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 ngx_stream_ssl_preread_ctx_t *ctx, u_char *pos, u_char *last); | |
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); | |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
37 static ngx_int_t ngx_stream_ssl_preread_alpn_protocols_variable( |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
38 ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); |
6695 | 39 static ngx_int_t ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf); |
40 static void *ngx_stream_ssl_preread_create_srv_conf(ngx_conf_t *cf); | |
41 static char *ngx_stream_ssl_preread_merge_srv_conf(ngx_conf_t *cf, void *parent, | |
42 void *child); | |
43 static ngx_int_t ngx_stream_ssl_preread_init(ngx_conf_t *cf); | |
44 | |
45 | |
46 static ngx_command_t ngx_stream_ssl_preread_commands[] = { | |
47 | |
48 { ngx_string("ssl_preread"), | |
49 NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, | |
50 ngx_conf_set_flag_slot, | |
51 NGX_STREAM_SRV_CONF_OFFSET, | |
52 offsetof(ngx_stream_ssl_preread_srv_conf_t, enabled), | |
53 NULL }, | |
54 | |
55 ngx_null_command | |
56 }; | |
57 | |
58 | |
59 static ngx_stream_module_t ngx_stream_ssl_preread_module_ctx = { | |
60 ngx_stream_ssl_preread_add_variables, /* preconfiguration */ | |
61 ngx_stream_ssl_preread_init, /* postconfiguration */ | |
62 | |
63 NULL, /* create main configuration */ | |
64 NULL, /* init main configuration */ | |
65 | |
66 ngx_stream_ssl_preread_create_srv_conf, /* create server configuration */ | |
67 ngx_stream_ssl_preread_merge_srv_conf /* merge server configuration */ | |
68 }; | |
69 | |
70 | |
71 ngx_module_t ngx_stream_ssl_preread_module = { | |
72 NGX_MODULE_V1, | |
73 &ngx_stream_ssl_preread_module_ctx, /* module context */ | |
74 ngx_stream_ssl_preread_commands, /* module directives */ | |
75 NGX_STREAM_MODULE, /* module type */ | |
76 NULL, /* init master */ | |
77 NULL, /* init module */ | |
78 NULL, /* init process */ | |
79 NULL, /* init thread */ | |
80 NULL, /* exit thread */ | |
81 NULL, /* exit process */ | |
82 NULL, /* exit master */ | |
83 NGX_MODULE_V1_PADDING | |
84 }; | |
85 | |
86 | |
87 static ngx_stream_variable_t ngx_stream_ssl_preread_vars[] = { | |
88 | |
89 { ngx_string("ssl_preread_server_name"), NULL, | |
90 ngx_stream_ssl_preread_server_name_variable, 0, 0, 0 }, | |
91 | |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
92 { ngx_string("ssl_preread_alpn_protocols"), NULL, |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
93 ngx_stream_ssl_preread_alpn_protocols_variable, 0, 0, 0 }, |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
94 |
7077
2a288909abc6
Variables: macros for null variables.
Ruslan Ermilov <ru@nginx.com>
parents:
6849
diff
changeset
|
95 ngx_stream_null_variable |
6695 | 96 }; |
97 | |
98 | |
99 static ngx_int_t | |
100 ngx_stream_ssl_preread_handler(ngx_stream_session_t *s) | |
101 { | |
102 u_char *last, *p; | |
103 size_t len; | |
104 ngx_int_t rc; | |
105 ngx_connection_t *c; | |
106 ngx_stream_ssl_preread_ctx_t *ctx; | |
107 ngx_stream_ssl_preread_srv_conf_t *sscf; | |
108 | |
109 c = s->connection; | |
110 | |
111 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "ssl preread handler"); | |
112 | |
113 sscf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_preread_module); | |
114 | |
115 if (!sscf->enabled) { | |
116 return NGX_DECLINED; | |
117 } | |
118 | |
119 if (c->type != SOCK_STREAM) { | |
120 return NGX_DECLINED; | |
121 } | |
122 | |
123 if (c->buffer == NULL) { | |
124 return NGX_AGAIN; | |
125 } | |
126 | |
127 ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module); | |
128 if (ctx == NULL) { | |
129 ctx = ngx_pcalloc(c->pool, sizeof(ngx_stream_ssl_preread_ctx_t)); | |
130 if (ctx == NULL) { | |
131 return NGX_ERROR; | |
132 } | |
133 | |
134 ngx_stream_set_ctx(s, ctx, ngx_stream_ssl_preread_module); | |
135 | |
136 ctx->pool = c->pool; | |
137 ctx->log = c->log; | |
138 ctx->pos = c->buffer->pos; | |
139 } | |
140 | |
141 p = ctx->pos; | |
142 last = c->buffer->last; | |
143 | |
144 while (last - p >= 5) { | |
145 | |
146 if (p[0] != 0x16) { | |
6696
e83540f825cd
Stream ssl_preread: removed internal macro.
Vladimir Homutov <vl@nginx.com>
parents:
6695
diff
changeset
|
147 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, |
e83540f825cd
Stream ssl_preread: removed internal macro.
Vladimir Homutov <vl@nginx.com>
parents:
6695
diff
changeset
|
148 "ssl preread: not a handshake"); |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
149 ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module); |
6695 | 150 return NGX_DECLINED; |
151 } | |
152 | |
6849
01adb18a5d23
Stream ssl_preread: relaxed SSL version check.
Roman Arutyunyan <arut@nginx.com>
parents:
6728
diff
changeset
|
153 if (p[1] != 3) { |
6696
e83540f825cd
Stream ssl_preread: removed internal macro.
Vladimir Homutov <vl@nginx.com>
parents:
6695
diff
changeset
|
154 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, |
e83540f825cd
Stream ssl_preread: removed internal macro.
Vladimir Homutov <vl@nginx.com>
parents:
6695
diff
changeset
|
155 "ssl preread: unsupported SSL version"); |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
156 ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module); |
6695 | 157 return NGX_DECLINED; |
158 } | |
159 | |
160 len = (p[3] << 8) + p[4]; | |
161 | |
162 /* read the whole record before parsing */ | |
163 if ((size_t) (last - p) < len + 5) { | |
164 break; | |
165 } | |
166 | |
167 p += 5; | |
168 | |
169 rc = ngx_stream_ssl_preread_parse_record(ctx, p, p + len); | |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
170 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
171 if (rc == NGX_DECLINED) { |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
172 ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module); |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
173 return NGX_DECLINED; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
174 } |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
175 |
6695 | 176 if (rc != NGX_AGAIN) { |
177 return rc; | |
178 } | |
179 | |
180 p += len; | |
181 } | |
182 | |
183 ctx->pos = p; | |
184 | |
185 return NGX_AGAIN; | |
186 } | |
187 | |
188 | |
189 static ngx_int_t | |
190 ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx, | |
191 u_char *pos, u_char *last) | |
192 { | |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
193 size_t left, n, size, ext; |
6695 | 194 u_char *dst, *p; |
195 | |
196 enum { | |
197 sw_start = 0, | |
198 sw_header, /* handshake msg_type, length */ | |
199 sw_head_tail, /* version, random */ | |
200 sw_sid_len, /* session_id length */ | |
201 sw_sid, /* session_id */ | |
202 sw_cs_len, /* cipher_suites length */ | |
203 sw_cs, /* cipher_suites */ | |
204 sw_cm_len, /* compression_methods length */ | |
205 sw_cm, /* compression_methods */ | |
206 sw_ext, /* extension */ | |
207 sw_ext_header, /* extension_type, extension_data length */ | |
208 sw_sni_len, /* SNI length */ | |
209 sw_sni_host_head, /* SNI name_type, host_name length */ | |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
210 sw_sni_host, /* SNI host_name */ |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
211 sw_alpn_len, /* ALPN length */ |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
212 sw_alpn_proto_len, /* ALPN protocol_name length */ |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
213 sw_alpn_proto_data /* ALPN protocol_name */ |
6695 | 214 } state; |
215 | |
216 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0, | |
217 "ssl preread: state %ui left %z", ctx->state, ctx->left); | |
218 | |
219 state = ctx->state; | |
220 size = ctx->size; | |
221 left = ctx->left; | |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
222 ext = ctx->ext; |
6695 | 223 dst = ctx->dst; |
224 p = ctx->buf; | |
225 | |
226 for ( ;; ) { | |
227 n = ngx_min((size_t) (last - pos), size); | |
228 | |
229 if (dst) { | |
230 dst = ngx_cpymem(dst, pos, n); | |
231 } | |
232 | |
233 pos += n; | |
234 size -= n; | |
235 left -= n; | |
236 | |
237 if (size != 0) { | |
238 break; | |
239 } | |
240 | |
241 switch (state) { | |
242 | |
243 case sw_start: | |
244 state = sw_header; | |
245 dst = p; | |
246 size = 4; | |
247 left = size; | |
248 break; | |
249 | |
250 case sw_header: | |
251 if (p[0] != 1) { | |
6696
e83540f825cd
Stream ssl_preread: removed internal macro.
Vladimir Homutov <vl@nginx.com>
parents:
6695
diff
changeset
|
252 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, |
e83540f825cd
Stream ssl_preread: removed internal macro.
Vladimir Homutov <vl@nginx.com>
parents:
6695
diff
changeset
|
253 "ssl preread: not a client hello"); |
6695 | 254 return NGX_DECLINED; |
255 } | |
256 | |
257 state = sw_head_tail; | |
258 dst = NULL; | |
259 size = 34; | |
260 left = (p[1] << 16) + (p[2] << 8) + p[3]; | |
261 break; | |
262 | |
263 case sw_head_tail: | |
264 state = sw_sid_len; | |
265 dst = p; | |
266 size = 1; | |
267 break; | |
268 | |
269 case sw_sid_len: | |
270 state = sw_sid; | |
271 dst = NULL; | |
272 size = p[0]; | |
273 break; | |
274 | |
275 case sw_sid: | |
276 state = sw_cs_len; | |
277 dst = p; | |
278 size = 2; | |
279 break; | |
280 | |
281 case sw_cs_len: | |
282 state = sw_cs; | |
283 dst = NULL; | |
284 size = (p[0] << 8) + p[1]; | |
285 break; | |
286 | |
287 case sw_cs: | |
288 state = sw_cm_len; | |
289 dst = p; | |
290 size = 1; | |
291 break; | |
292 | |
293 case sw_cm_len: | |
294 state = sw_cm; | |
295 dst = NULL; | |
296 size = p[0]; | |
297 break; | |
298 | |
299 case sw_cm: | |
300 if (left == 0) { | |
301 /* no extensions */ | |
302 return NGX_OK; | |
303 } | |
304 | |
305 state = sw_ext; | |
306 dst = p; | |
307 size = 2; | |
308 break; | |
309 | |
310 case sw_ext: | |
311 if (left == 0) { | |
312 return NGX_OK; | |
313 } | |
314 | |
315 state = sw_ext_header; | |
316 dst = p; | |
317 size = 4; | |
318 break; | |
319 | |
320 case sw_ext_header: | |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
321 if (p[0] == 0 && p[1] == 0 && ctx->host.data == NULL) { |
6695 | 322 /* SNI extension */ |
323 state = sw_sni_len; | |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
324 dst = p; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
325 size = 2; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
326 break; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
327 } |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
328 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
329 if (p[0] == 0 && p[1] == 16 && ctx->alpn.data == NULL) { |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
330 /* ALPN extension */ |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
331 state = sw_alpn_len; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
332 dst = p; |
6695 | 333 size = 2; |
334 break; | |
335 } | |
336 | |
337 state = sw_ext; | |
338 dst = NULL; | |
339 size = (p[2] << 8) + p[3]; | |
340 break; | |
341 | |
342 case sw_sni_len: | |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
343 ext = (p[0] << 8) + p[1]; |
6695 | 344 state = sw_sni_host_head; |
345 dst = p; | |
346 size = 3; | |
347 break; | |
348 | |
349 case sw_sni_host_head: | |
350 if (p[0] != 0) { | |
351 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, | |
352 "ssl preread: SNI hostname type is not DNS"); | |
353 return NGX_DECLINED; | |
354 } | |
355 | |
356 size = (p[1] << 8) + p[2]; | |
357 | |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
358 if (ext < 3 + size) { |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
359 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
360 "ssl preread: SNI format error"); |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
361 return NGX_DECLINED; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
362 } |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
363 ext -= 3 + size; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
364 |
6695 | 365 ctx->host.data = ngx_pnalloc(ctx->pool, size); |
366 if (ctx->host.data == NULL) { | |
367 return NGX_ERROR; | |
368 } | |
369 | |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
370 state = sw_sni_host; |
6695 | 371 dst = ctx->host.data; |
372 break; | |
373 | |
374 case sw_sni_host: | |
6728
8f75d9883730
Stream ssl_preread: fixed $ssl_preread_server_name variable.
Sergey Kandaurov <pluknet@nginx.com>
parents:
6696
diff
changeset
|
375 ctx->host.len = (p[1] << 8) + p[2]; |
8f75d9883730
Stream ssl_preread: fixed $ssl_preread_server_name variable.
Sergey Kandaurov <pluknet@nginx.com>
parents:
6696
diff
changeset
|
376 |
6695 | 377 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0, |
378 "ssl preread: SNI hostname \"%V\"", &ctx->host); | |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
379 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
380 state = sw_ext; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
381 dst = NULL; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
382 size = ext; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
383 break; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
384 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
385 case sw_alpn_len: |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
386 ext = (p[0] << 8) + p[1]; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
387 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
388 ctx->alpn.data = ngx_pnalloc(ctx->pool, ext); |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
389 if (ctx->alpn.data == NULL) { |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
390 return NGX_ERROR; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
391 } |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
392 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
393 state = sw_alpn_proto_len; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
394 dst = p; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
395 size = 1; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
396 break; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
397 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
398 case sw_alpn_proto_len: |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
399 size = p[0]; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
400 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
401 if (size == 0) { |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
402 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
403 "ssl preread: ALPN empty protocol"); |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
404 return NGX_DECLINED; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
405 } |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
406 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
407 if (ext < 1 + size) { |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
408 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
409 "ssl preread: ALPN format error"); |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
410 return NGX_DECLINED; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
411 } |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
412 ext -= 1 + size; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
413 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
414 state = sw_alpn_proto_data; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
415 dst = ctx->alpn.data + ctx->alpn.len; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
416 break; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
417 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
418 case sw_alpn_proto_data: |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
419 ctx->alpn.len += p[0]; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
420 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
421 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0, |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
422 "ssl preread: ALPN protocols \"%V\"", &ctx->alpn); |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
423 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
424 if (ext) { |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
425 ctx->alpn.data[ctx->alpn.len++] = ','; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
426 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
427 state = sw_alpn_proto_len; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
428 dst = p; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
429 size = 1; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
430 break; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
431 } |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
432 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
433 state = sw_ext; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
434 dst = NULL; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
435 size = 0; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
436 break; |
6695 | 437 } |
438 | |
439 if (left < size) { | |
7228 | 440 ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, |
441 "ssl preread: failed to parse handshake"); | |
442 return NGX_DECLINED; | |
6695 | 443 } |
444 } | |
445 | |
446 ctx->state = state; | |
447 ctx->size = size; | |
448 ctx->left = left; | |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
449 ctx->ext = ext; |
6695 | 450 ctx->dst = dst; |
451 | |
452 return NGX_AGAIN; | |
453 } | |
454 | |
455 | |
456 static ngx_int_t | |
457 ngx_stream_ssl_preread_server_name_variable(ngx_stream_session_t *s, | |
458 ngx_variable_value_t *v, uintptr_t data) | |
459 { | |
460 ngx_stream_ssl_preread_ctx_t *ctx; | |
461 | |
462 ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module); | |
463 | |
464 if (ctx == NULL) { | |
465 v->not_found = 1; | |
466 return NGX_OK; | |
467 } | |
468 | |
469 v->valid = 1; | |
470 v->no_cacheable = 0; | |
471 v->not_found = 0; | |
472 v->len = ctx->host.len; | |
473 v->data = ctx->host.data; | |
474 | |
475 return NGX_OK; | |
476 } | |
477 | |
478 | |
479 static ngx_int_t | |
7227
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
480 ngx_stream_ssl_preread_alpn_protocols_variable(ngx_stream_session_t *s, |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
481 ngx_variable_value_t *v, uintptr_t data) |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
482 { |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
483 ngx_stream_ssl_preread_ctx_t *ctx; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
484 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
485 ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module); |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
486 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
487 if (ctx == NULL) { |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
488 v->not_found = 1; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
489 return NGX_OK; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
490 } |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
491 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
492 v->valid = 1; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
493 v->no_cacheable = 0; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
494 v->not_found = 0; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
495 v->len = ctx->alpn.len; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
496 v->data = ctx->alpn.data; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
497 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
498 return NGX_OK; |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
499 } |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
500 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
501 |
79eb4f7b6725
Stream ssl_preread: $ssl_preread_alpn_protocols variable.
Roman Arutyunyan <arut@nginx.com>
parents:
7077
diff
changeset
|
502 static ngx_int_t |
6695 | 503 ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf) |
504 { | |
505 ngx_stream_variable_t *var, *v; | |
506 | |
507 for (v = ngx_stream_ssl_preread_vars; v->name.len; v++) { | |
508 var = ngx_stream_add_variable(cf, &v->name, v->flags); | |
509 if (var == NULL) { | |
510 return NGX_ERROR; | |
511 } | |
512 | |
513 var->get_handler = v->get_handler; | |
514 var->data = v->data; | |
515 } | |
516 | |
517 return NGX_OK; | |
518 } | |
519 | |
520 | |
521 static void * | |
522 ngx_stream_ssl_preread_create_srv_conf(ngx_conf_t *cf) | |
523 { | |
524 ngx_stream_ssl_preread_srv_conf_t *conf; | |
525 | |
526 conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_ssl_preread_srv_conf_t)); | |
527 if (conf == NULL) { | |
528 return NULL; | |
529 } | |
530 | |
531 conf->enabled = NGX_CONF_UNSET; | |
532 | |
533 return conf; | |
534 } | |
535 | |
536 | |
537 static char * | |
538 ngx_stream_ssl_preread_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) | |
539 { | |
540 ngx_stream_ssl_preread_srv_conf_t *prev = parent; | |
541 ngx_stream_ssl_preread_srv_conf_t *conf = child; | |
542 | |
543 ngx_conf_merge_value(conf->enabled, prev->enabled, 0); | |
544 | |
545 return NGX_CONF_OK; | |
546 } | |
547 | |
548 | |
549 static ngx_int_t | |
550 ngx_stream_ssl_preread_init(ngx_conf_t *cf) | |
551 { | |
552 ngx_stream_handler_pt *h; | |
553 ngx_stream_core_main_conf_t *cmcf; | |
554 | |
555 cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module); | |
556 | |
557 h = ngx_array_push(&cmcf->phases[NGX_STREAM_PREREAD_PHASE].handlers); | |
558 if (h == NULL) { | |
559 return NGX_ERROR; | |
560 } | |
561 | |
562 *h = ngx_stream_ssl_preread_handler; | |
563 | |
564 return NGX_OK; | |
565 } |