1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_stream.h>
11 #include <nginx.h>
12
13 static ngx_stream_variable_t *ngx_stream_add_prefix_variable(ngx_conf_t *cf,
14 ngx_str_t *name, ngx_uint_t flags);
15
16 static ngx_int_t ngx_stream_variable_binary_remote_addr(
17 ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
18 static ngx_int_t ngx_stream_variable_remote_addr(ngx_stream_session_t *s,
19 ngx_stream_variable_value_t *v, uintptr_t data);
20 static ngx_int_t ngx_stream_variable_remote_port(ngx_stream_session_t *s,
21 ngx_stream_variable_value_t *v, uintptr_t data);
22 static ngx_int_t ngx_stream_variable_proxy_protocol_addr(
23 ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
24 static ngx_int_t ngx_stream_variable_proxy_protocol_port(
25 ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
26 static ngx_int_t ngx_stream_variable_server_addr(ngx_stream_session_t *s,
27 ngx_stream_variable_value_t *v, uintptr_t data);
28 static ngx_int_t ngx_stream_variable_server_port(ngx_stream_session_t *s,
29 ngx_stream_variable_value_t *v, uintptr_t data);
30 static ngx_int_t ngx_stream_variable_bytes(ngx_stream_session_t *s,
31 ngx_stream_variable_value_t *v, uintptr_t data);
32 static ngx_int_t ngx_stream_variable_session_time(ngx_stream_session_t *s,
33 ngx_stream_variable_value_t *v, uintptr_t data);
34 static ngx_int_t ngx_stream_variable_status(ngx_stream_session_t *s,
35 ngx_stream_variable_value_t *v, uintptr_t data);
36 static ngx_int_t ngx_stream_variable_connection(ngx_stream_session_t *s,
37 ngx_stream_variable_value_t *v, uintptr_t data);
38
39 static ngx_int_t ngx_stream_variable_nginx_version(ngx_stream_session_t *s,
40 ngx_stream_variable_value_t *v, uintptr_t data);
41 static ngx_int_t ngx_stream_variable_hostname(ngx_stream_session_t *s,
42 ngx_stream_variable_value_t *v, uintptr_t data);
43 static ngx_int_t ngx_stream_variable_pid(ngx_stream_session_t *s,
44 ngx_stream_variable_value_t *v, uintptr_t data);
45 static ngx_int_t ngx_stream_variable_msec(ngx_stream_session_t *s,
46 ngx_stream_variable_value_t *v, uintptr_t data);
47 static ngx_int_t ngx_stream_variable_time_iso8601(ngx_stream_session_t *s,
48 ngx_stream_variable_value_t *v, uintptr_t data);
49 static ngx_int_t ngx_stream_variable_time_local(ngx_stream_session_t *s,
50 ngx_stream_variable_value_t *v, uintptr_t data);
51 static ngx_int_t ngx_stream_variable_protocol(ngx_stream_session_t *s,
52 ngx_stream_variable_value_t *v, uintptr_t data);
53
54
55 static ngx_stream_variable_t ngx_stream_core_variables[] = {
56
57 { ngx_string("binary_remote_addr"), NULL,
58 ngx_stream_variable_binary_remote_addr, 0, 0, 0 },
59
60 { ngx_string("remote_addr"), NULL,
61 ngx_stream_variable_remote_addr, 0, 0, 0 },
62
63 { ngx_string("remote_port"), NULL,
64 ngx_stream_variable_remote_port, 0, 0, 0 },
65
66 { ngx_string("proxy_protocol_addr"), NULL,
67 ngx_stream_variable_proxy_protocol_addr, 0, 0, 0 },
68
69 { ngx_string("proxy_protocol_port"), NULL,
70 ngx_stream_variable_proxy_protocol_port, 0, 0, 0 },
71
72 { ngx_string("server_addr"), NULL,
73 ngx_stream_variable_server_addr, 0, 0, 0 },
74
75 { ngx_string("server_port"), NULL,
76 ngx_stream_variable_server_port, 0, 0, 0 },
77
78 { ngx_string("bytes_sent"), NULL, ngx_stream_variable_bytes,
79 0, 0, 0 },
80
81 { ngx_string("bytes_received"), NULL, ngx_stream_variable_bytes,
82 1, 0, 0 },
83
84 { ngx_string("session_time"), NULL, ngx_stream_variable_session_time,
85 0, NGX_STREAM_VAR_NOCACHEABLE, 0 },
86
87 { ngx_string("status"), NULL, ngx_stream_variable_status,
88 0, NGX_STREAM_VAR_NOCACHEABLE, 0 },
89
90 { ngx_string("connection"), NULL,
91 ngx_stream_variable_connection, 0, 0, 0 },
92
93 { ngx_string("nginx_version"), NULL, ngx_stream_variable_nginx_version,
94 0, 0, 0 },
95
96 { ngx_string("hostname"), NULL, ngx_stream_variable_hostname,
97 0, 0, 0 },
98
99 { ngx_string("pid"), NULL, ngx_stream_variable_pid,
100 0, 0, 0 },
101
102 { ngx_string("msec"), NULL, ngx_stream_variable_msec,
103 0, NGX_STREAM_VAR_NOCACHEABLE, 0 },
104
105 { ngx_string("time_iso8601"), NULL, ngx_stream_variable_time_iso8601,
106 0, NGX_STREAM_VAR_NOCACHEABLE, 0 },
107
108 { ngx_string("time_local"), NULL, ngx_stream_variable_time_local,
109 0, NGX_STREAM_VAR_NOCACHEABLE, 0 },
110
111 { ngx_string("protocol"), NULL,
112 ngx_stream_variable_protocol, 0, 0, 0 },
113
114 ngx_stream_null_variable
115 };
116
117
118 ngx_stream_variable_value_t ngx_stream_variable_null_value =
119 ngx_stream_variable("");
120 ngx_stream_variable_value_t ngx_stream_variable_true_value =
121 ngx_stream_variable("1");
122
123
124 static ngx_uint_t ngx_stream_variable_depth = 100;
125
126
127 ngx_stream_variable_t *
ngx_stream_add_variable(ngx_conf_t * cf,ngx_str_t * name,ngx_uint_t flags)128 ngx_stream_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
129 {
130 ngx_int_t rc;
131 ngx_uint_t i;
132 ngx_hash_key_t *key;
133 ngx_stream_variable_t *v;
134 ngx_stream_core_main_conf_t *cmcf;
135
136 if (name->len == 0) {
137 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
138 "invalid variable name \"$\"");
139 return NULL;
140 }
141
142 if (flags & NGX_STREAM_VAR_PREFIX) {
143 return ngx_stream_add_prefix_variable(cf, name, flags);
144 }
145
146 cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
147
148 key = cmcf->variables_keys->keys.elts;
149 for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) {
150 if (name->len != key[i].key.len
151 || ngx_strncasecmp(name->data, key[i].key.data, name->len) != 0)
152 {
153 continue;
154 }
155
156 v = key[i].value;
157
158 if (!(v->flags & NGX_STREAM_VAR_CHANGEABLE)) {
159 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
160 "the duplicate \"%V\" variable", name);
161 return NULL;
162 }
163
164 if (!(flags & NGX_STREAM_VAR_WEAK)) {
165 v->flags &= ~NGX_STREAM_VAR_WEAK;
166 }
167
168 return v;
169 }
170
171 v = ngx_palloc(cf->pool, sizeof(ngx_stream_variable_t));
172 if (v == NULL) {
173 return NULL;
174 }
175
176 v->name.len = name->len;
177 v->name.data = ngx_pnalloc(cf->pool, name->len);
178 if (v->name.data == NULL) {
179 return NULL;
180 }
181
182 ngx_strlow(v->name.data, name->data, name->len);
183
184 v->set_handler = NULL;
185 v->get_handler = NULL;
186 v->data = 0;
187 v->flags = flags;
188 v->index = 0;
189
190 rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0);
191
192 if (rc == NGX_ERROR) {
193 return NULL;
194 }
195
196 if (rc == NGX_BUSY) {
197 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
198 "conflicting variable name \"%V\"", name);
199 return NULL;
200 }
201
202 return v;
203 }
204
205
206 static ngx_stream_variable_t *
ngx_stream_add_prefix_variable(ngx_conf_t * cf,ngx_str_t * name,ngx_uint_t flags)207 ngx_stream_add_prefix_variable(ngx_conf_t *cf, ngx_str_t *name,
208 ngx_uint_t flags)
209 {
210 ngx_uint_t i;
211 ngx_stream_variable_t *v;
212 ngx_stream_core_main_conf_t *cmcf;
213
214 cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
215
216 v = cmcf->prefix_variables.elts;
217 for (i = 0; i < cmcf->prefix_variables.nelts; i++) {
218 if (name->len != v[i].name.len
219 || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
220 {
221 continue;
222 }
223
224 v = &v[i];
225
226 if (!(v->flags & NGX_STREAM_VAR_CHANGEABLE)) {
227 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
228 "the duplicate \"%V\" variable", name);
229 return NULL;
230 }
231
232 if (!(flags & NGX_STREAM_VAR_WEAK)) {
233 v->flags &= ~NGX_STREAM_VAR_WEAK;
234 }
235
236 return v;
237 }
238
239 v = ngx_array_push(&cmcf->prefix_variables);
240 if (v == NULL) {
241 return NULL;
242 }
243
244 v->name.len = name->len;
245 v->name.data = ngx_pnalloc(cf->pool, name->len);
246 if (v->name.data == NULL) {
247 return NULL;
248 }
249
250 ngx_strlow(v->name.data, name->data, name->len);
251
252 v->set_handler = NULL;
253 v->get_handler = NULL;
254 v->data = 0;
255 v->flags = flags;
256 v->index = 0;
257
258 return v;
259 }
260
261
262 ngx_int_t
ngx_stream_get_variable_index(ngx_conf_t * cf,ngx_str_t * name)263 ngx_stream_get_variable_index(ngx_conf_t *cf, ngx_str_t *name)
264 {
265 ngx_uint_t i;
266 ngx_stream_variable_t *v;
267 ngx_stream_core_main_conf_t *cmcf;
268
269 if (name->len == 0) {
270 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
271 "invalid variable name \"$\"");
272 return NGX_ERROR;
273 }
274
275 cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
276
277 v = cmcf->variables.elts;
278
279 if (v == NULL) {
280 if (ngx_array_init(&cmcf->variables, cf->pool, 4,
281 sizeof(ngx_stream_variable_t))
282 != NGX_OK)
283 {
284 return NGX_ERROR;
285 }
286
287 } else {
288 for (i = 0; i < cmcf->variables.nelts; i++) {
289 if (name->len != v[i].name.len
290 || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
291 {
292 continue;
293 }
294
295 return i;
296 }
297 }
298
299 v = ngx_array_push(&cmcf->variables);
300 if (v == NULL) {
301 return NGX_ERROR;
302 }
303
304 v->name.len = name->len;
305 v->name.data = ngx_pnalloc(cf->pool, name->len);
306 if (v->name.data == NULL) {
307 return NGX_ERROR;
308 }
309
310 ngx_strlow(v->name.data, name->data, name->len);
311
312 v->set_handler = NULL;
313 v->get_handler = NULL;
314 v->data = 0;
315 v->flags = 0;
316 v->index = cmcf->variables.nelts - 1;
317
318 return v->index;
319 }
320
321
322 ngx_stream_variable_value_t *
ngx_stream_get_indexed_variable(ngx_stream_session_t * s,ngx_uint_t index)323 ngx_stream_get_indexed_variable(ngx_stream_session_t *s, ngx_uint_t index)
324 {
325 ngx_stream_variable_t *v;
326 ngx_stream_core_main_conf_t *cmcf;
327
328 cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
329
330 if (cmcf->variables.nelts <= index) {
331 ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
332 "unknown variable index: %ui", index);
333 return NULL;
334 }
335
336 if (s->variables[index].not_found || s->variables[index].valid) {
337 return &s->variables[index];
338 }
339
340 v = cmcf->variables.elts;
341
342 if (ngx_stream_variable_depth == 0) {
343 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
344 "cycle while evaluating variable \"%V\"",
345 &v[index].name);
346 return NULL;
347 }
348
349 ngx_stream_variable_depth--;
350
351 if (v[index].get_handler(s, &s->variables[index], v[index].data)
352 == NGX_OK)
353 {
354 ngx_stream_variable_depth++;
355
356 if (v[index].flags & NGX_STREAM_VAR_NOCACHEABLE) {
357 s->variables[index].no_cacheable = 1;
358 }
359
360 return &s->variables[index];
361 }
362
363 ngx_stream_variable_depth++;
364
365 s->variables[index].valid = 0;
366 s->variables[index].not_found = 1;
367
368 return NULL;
369 }
370
371
372 ngx_stream_variable_value_t *
ngx_stream_get_flushed_variable(ngx_stream_session_t * s,ngx_uint_t index)373 ngx_stream_get_flushed_variable(ngx_stream_session_t *s, ngx_uint_t index)
374 {
375 ngx_stream_variable_value_t *v;
376
377 v = &s->variables[index];
378
379 if (v->valid || v->not_found) {
380 if (!v->no_cacheable) {
381 return v;
382 }
383
384 v->valid = 0;
385 v->not_found = 0;
386 }
387
388 return ngx_stream_get_indexed_variable(s, index);
389 }
390
391
392 ngx_stream_variable_value_t *
ngx_stream_get_variable(ngx_stream_session_t * s,ngx_str_t * name,ngx_uint_t key)393 ngx_stream_get_variable(ngx_stream_session_t *s, ngx_str_t *name,
394 ngx_uint_t key)
395 {
396 size_t len;
397 ngx_uint_t i, n;
398 ngx_stream_variable_t *v;
399 ngx_stream_variable_value_t *vv;
400 ngx_stream_core_main_conf_t *cmcf;
401
402 cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
403
404 v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);
405
406 if (v) {
407 if (v->flags & NGX_STREAM_VAR_INDEXED) {
408 return ngx_stream_get_flushed_variable(s, v->index);
409 }
410
411 if (ngx_stream_variable_depth == 0) {
412 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
413 "cycle while evaluating variable \"%V\"", name);
414 return NULL;
415 }
416
417 ngx_stream_variable_depth--;
418
419 vv = ngx_palloc(s->connection->pool,
420 sizeof(ngx_stream_variable_value_t));
421
422 if (vv && v->get_handler(s, vv, v->data) == NGX_OK) {
423 ngx_stream_variable_depth++;
424 return vv;
425 }
426
427 ngx_stream_variable_depth++;
428 return NULL;
429 }
430
431 vv = ngx_palloc(s->connection->pool, sizeof(ngx_stream_variable_value_t));
432 if (vv == NULL) {
433 return NULL;
434 }
435
436 len = 0;
437
438 v = cmcf->prefix_variables.elts;
439 n = cmcf->prefix_variables.nelts;
440
441 for (i = 0; i < cmcf->prefix_variables.nelts; i++) {
442 if (name->len >= v[i].name.len && name->len > len
443 && ngx_strncmp(name->data, v[i].name.data, v[i].name.len) == 0)
444 {
445 len = v[i].name.len;
446 n = i;
447 }
448 }
449
450 if (n != cmcf->prefix_variables.nelts) {
451 if (v[n].get_handler(s, vv, (uintptr_t) name) == NGX_OK) {
452 return vv;
453 }
454
455 return NULL;
456 }
457
458 vv->not_found = 1;
459
460 return vv;
461 }
462
463
464 static ngx_int_t
ngx_stream_variable_binary_remote_addr(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)465 ngx_stream_variable_binary_remote_addr(ngx_stream_session_t *s,
466 ngx_stream_variable_value_t *v, uintptr_t data)
467 {
468 struct sockaddr_in *sin;
469 #if (NGX_HAVE_INET6)
470 struct sockaddr_in6 *sin6;
471 #endif
472
473 switch (s->connection->sockaddr->sa_family) {
474
475 #if (NGX_HAVE_INET6)
476 case AF_INET6:
477 sin6 = (struct sockaddr_in6 *) s->connection->sockaddr;
478
479 v->len = sizeof(struct in6_addr);
480 v->valid = 1;
481 v->no_cacheable = 0;
482 v->not_found = 0;
483 v->data = sin6->sin6_addr.s6_addr;
484
485 break;
486 #endif
487
488 #if (NGX_HAVE_UNIX_DOMAIN)
489 case AF_UNIX:
490
491 v->len = s->connection->addr_text.len;
492 v->valid = 1;
493 v->no_cacheable = 0;
494 v->not_found = 0;
495 v->data = s->connection->addr_text.data;
496
497 break;
498 #endif
499
500 default: /* AF_INET */
501 sin = (struct sockaddr_in *) s->connection->sockaddr;
502
503 v->len = sizeof(in_addr_t);
504 v->valid = 1;
505 v->no_cacheable = 0;
506 v->not_found = 0;
507 v->data = (u_char *) &sin->sin_addr;
508
509 break;
510 }
511
512 return NGX_OK;
513 }
514
515
516 static ngx_int_t
ngx_stream_variable_remote_addr(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)517 ngx_stream_variable_remote_addr(ngx_stream_session_t *s,
518 ngx_stream_variable_value_t *v, uintptr_t data)
519 {
520 v->len = s->connection->addr_text.len;
521 v->valid = 1;
522 v->no_cacheable = 0;
523 v->not_found = 0;
524 v->data = s->connection->addr_text.data;
525
526 return NGX_OK;
527 }
528
529
530 static ngx_int_t
ngx_stream_variable_remote_port(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)531 ngx_stream_variable_remote_port(ngx_stream_session_t *s,
532 ngx_stream_variable_value_t *v, uintptr_t data)
533 {
534 ngx_uint_t port;
535
536 v->len = 0;
537 v->valid = 1;
538 v->no_cacheable = 0;
539 v->not_found = 0;
540
541 v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1);
542 if (v->data == NULL) {
543 return NGX_ERROR;
544 }
545
546 port = ngx_inet_get_port(s->connection->sockaddr);
547
548 if (port > 0 && port < 65536) {
549 v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
550 }
551
552 return NGX_OK;
553 }
554
555
556 static ngx_int_t
ngx_stream_variable_proxy_protocol_addr(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)557 ngx_stream_variable_proxy_protocol_addr(ngx_stream_session_t *s,
558 ngx_stream_variable_value_t *v, uintptr_t data)
559 {
560 v->len = s->connection->proxy_protocol_addr.len;
561 v->valid = 1;
562 v->no_cacheable = 0;
563 v->not_found = 0;
564 v->data = s->connection->proxy_protocol_addr.data;
565
566 return NGX_OK;
567 }
568
569
570 static ngx_int_t
ngx_stream_variable_proxy_protocol_port(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)571 ngx_stream_variable_proxy_protocol_port(ngx_stream_session_t *s,
572 ngx_stream_variable_value_t *v, uintptr_t data)
573 {
574 ngx_uint_t port;
575
576 v->len = 0;
577 v->valid = 1;
578 v->no_cacheable = 0;
579 v->not_found = 0;
580
581 v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1);
582 if (v->data == NULL) {
583 return NGX_ERROR;
584 }
585
586 port = s->connection->proxy_protocol_port;
587
588 if (port > 0 && port < 65536) {
589 v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
590 }
591
592 return NGX_OK;
593 }
594
595
596 static ngx_int_t
ngx_stream_variable_server_addr(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)597 ngx_stream_variable_server_addr(ngx_stream_session_t *s,
598 ngx_stream_variable_value_t *v, uintptr_t data)
599 {
600 ngx_str_t str;
601 u_char addr[NGX_SOCKADDR_STRLEN];
602
603 str.len = NGX_SOCKADDR_STRLEN;
604 str.data = addr;
605
606 if (ngx_connection_local_sockaddr(s->connection, &str, 0) != NGX_OK) {
607 return NGX_ERROR;
608 }
609
610 str.data = ngx_pnalloc(s->connection->pool, str.len);
611 if (str.data == NULL) {
612 return NGX_ERROR;
613 }
614
615 ngx_memcpy(str.data, addr, str.len);
616
617 v->len = str.len;
618 v->valid = 1;
619 v->no_cacheable = 0;
620 v->not_found = 0;
621 v->data = str.data;
622
623 return NGX_OK;
624 }
625
626
627 static ngx_int_t
ngx_stream_variable_server_port(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)628 ngx_stream_variable_server_port(ngx_stream_session_t *s,
629 ngx_stream_variable_value_t *v, uintptr_t data)
630 {
631 ngx_uint_t port;
632
633 v->len = 0;
634 v->valid = 1;
635 v->no_cacheable = 0;
636 v->not_found = 0;
637
638 if (ngx_connection_local_sockaddr(s->connection, NULL, 0) != NGX_OK) {
639 return NGX_ERROR;
640 }
641
642 v->data = ngx_pnalloc(s->connection->pool, sizeof("65535") - 1);
643 if (v->data == NULL) {
644 return NGX_ERROR;
645 }
646
647 port = ngx_inet_get_port(s->connection->local_sockaddr);
648
649 if (port > 0 && port < 65536) {
650 v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
651 }
652
653 return NGX_OK;
654 }
655
656
657 static ngx_int_t
ngx_stream_variable_bytes(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)658 ngx_stream_variable_bytes(ngx_stream_session_t *s,
659 ngx_stream_variable_value_t *v, uintptr_t data)
660 {
661 u_char *p;
662
663 p = ngx_pnalloc(s->connection->pool, NGX_OFF_T_LEN);
664 if (p == NULL) {
665 return NGX_ERROR;
666 }
667
668 if (data == 1) {
669 v->len = ngx_sprintf(p, "%O", s->received) - p;
670
671 } else {
672 v->len = ngx_sprintf(p, "%O", s->connection->sent) - p;
673 }
674
675 v->valid = 1;
676 v->no_cacheable = 0;
677 v->not_found = 0;
678 v->data = p;
679
680 return NGX_OK;
681 }
682
683
684 static ngx_int_t
ngx_stream_variable_session_time(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)685 ngx_stream_variable_session_time(ngx_stream_session_t *s,
686 ngx_stream_variable_value_t *v, uintptr_t data)
687 {
688 u_char *p;
689 ngx_time_t *tp;
690 ngx_msec_int_t ms;
691
692 p = ngx_pnalloc(s->connection->pool, NGX_TIME_T_LEN + 4);
693 if (p == NULL) {
694 return NGX_ERROR;
695 }
696
697 tp = ngx_timeofday();
698
699 ms = (ngx_msec_int_t)
700 ((tp->sec - s->start_sec) * 1000 + (tp->msec - s->start_msec));
701 ms = ngx_max(ms, 0);
702
703 v->len = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000) - p;
704 v->valid = 1;
705 v->no_cacheable = 0;
706 v->not_found = 0;
707 v->data = p;
708
709 return NGX_OK;
710 }
711
712
713 static ngx_int_t
ngx_stream_variable_status(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)714 ngx_stream_variable_status(ngx_stream_session_t *s,
715 ngx_stream_variable_value_t *v, uintptr_t data)
716 {
717 v->data = ngx_pnalloc(s->connection->pool, NGX_INT_T_LEN);
718 if (v->data == NULL) {
719 return NGX_ERROR;
720 }
721
722 v->len = ngx_sprintf(v->data, "%03ui", s->status) - v->data;
723 v->valid = 1;
724 v->no_cacheable = 0;
725 v->not_found = 0;
726
727 return NGX_OK;
728 }
729
730
731 static ngx_int_t
ngx_stream_variable_connection(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)732 ngx_stream_variable_connection(ngx_stream_session_t *s,
733 ngx_stream_variable_value_t *v, uintptr_t data)
734 {
735 u_char *p;
736
737 p = ngx_pnalloc(s->connection->pool, NGX_ATOMIC_T_LEN);
738 if (p == NULL) {
739 return NGX_ERROR;
740 }
741
742 v->len = ngx_sprintf(p, "%uA", s->connection->number) - p;
743 v->valid = 1;
744 v->no_cacheable = 0;
745 v->not_found = 0;
746 v->data = p;
747
748 return NGX_OK;
749 }
750
751
752 static ngx_int_t
ngx_stream_variable_nginx_version(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)753 ngx_stream_variable_nginx_version(ngx_stream_session_t *s,
754 ngx_stream_variable_value_t *v, uintptr_t data)
755 {
756 v->len = sizeof(NGINX_VERSION) - 1;
757 v->valid = 1;
758 v->no_cacheable = 0;
759 v->not_found = 0;
760 v->data = (u_char *) NGINX_VERSION;
761
762 return NGX_OK;
763 }
764
765
766 static ngx_int_t
ngx_stream_variable_hostname(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)767 ngx_stream_variable_hostname(ngx_stream_session_t *s,
768 ngx_stream_variable_value_t *v, uintptr_t data)
769 {
770 v->len = ngx_cycle->hostname.len;
771 v->valid = 1;
772 v->no_cacheable = 0;
773 v->not_found = 0;
774 v->data = ngx_cycle->hostname.data;
775
776 return NGX_OK;
777 }
778
779
780 static ngx_int_t
ngx_stream_variable_pid(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)781 ngx_stream_variable_pid(ngx_stream_session_t *s,
782 ngx_stream_variable_value_t *v, uintptr_t data)
783 {
784 u_char *p;
785
786 p = ngx_pnalloc(s->connection->pool, NGX_INT64_LEN);
787 if (p == NULL) {
788 return NGX_ERROR;
789 }
790
791 v->len = ngx_sprintf(p, "%P", ngx_pid) - p;
792 v->valid = 1;
793 v->no_cacheable = 0;
794 v->not_found = 0;
795 v->data = p;
796
797 return NGX_OK;
798 }
799
800
801 static ngx_int_t
ngx_stream_variable_msec(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)802 ngx_stream_variable_msec(ngx_stream_session_t *s,
803 ngx_stream_variable_value_t *v, uintptr_t data)
804 {
805 u_char *p;
806 ngx_time_t *tp;
807
808 p = ngx_pnalloc(s->connection->pool, NGX_TIME_T_LEN + 4);
809 if (p == NULL) {
810 return NGX_ERROR;
811 }
812
813 tp = ngx_timeofday();
814
815 v->len = ngx_sprintf(p, "%T.%03M", tp->sec, tp->msec) - p;
816 v->valid = 1;
817 v->no_cacheable = 0;
818 v->not_found = 0;
819 v->data = p;
820
821 return NGX_OK;
822 }
823
824
825 static ngx_int_t
ngx_stream_variable_time_iso8601(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)826 ngx_stream_variable_time_iso8601(ngx_stream_session_t *s,
827 ngx_stream_variable_value_t *v, uintptr_t data)
828 {
829 u_char *p;
830
831 p = ngx_pnalloc(s->connection->pool, ngx_cached_http_log_iso8601.len);
832 if (p == NULL) {
833 return NGX_ERROR;
834 }
835
836 ngx_memcpy(p, ngx_cached_http_log_iso8601.data,
837 ngx_cached_http_log_iso8601.len);
838
839 v->len = ngx_cached_http_log_iso8601.len;
840 v->valid = 1;
841 v->no_cacheable = 0;
842 v->not_found = 0;
843 v->data = p;
844
845 return NGX_OK;
846 }
847
848
849 static ngx_int_t
ngx_stream_variable_time_local(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)850 ngx_stream_variable_time_local(ngx_stream_session_t *s,
851 ngx_stream_variable_value_t *v, uintptr_t data)
852 {
853 u_char *p;
854
855 p = ngx_pnalloc(s->connection->pool, ngx_cached_http_log_time.len);
856 if (p == NULL) {
857 return NGX_ERROR;
858 }
859
860 ngx_memcpy(p, ngx_cached_http_log_time.data, ngx_cached_http_log_time.len);
861
862 v->len = ngx_cached_http_log_time.len;
863 v->valid = 1;
864 v->no_cacheable = 0;
865 v->not_found = 0;
866 v->data = p;
867
868 return NGX_OK;
869 }
870
871
872 static ngx_int_t
ngx_stream_variable_protocol(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)873 ngx_stream_variable_protocol(ngx_stream_session_t *s,
874 ngx_stream_variable_value_t *v, uintptr_t data)
875 {
876 v->len = 3;
877 v->valid = 1;
878 v->no_cacheable = 0;
879 v->not_found = 0;
880 v->data = (u_char *) (s->connection->type == SOCK_DGRAM ? "UDP" : "TCP");
881
882 return NGX_OK;
883 }
884
885
886 void *
ngx_stream_map_find(ngx_stream_session_t * s,ngx_stream_map_t * map,ngx_str_t * match)887 ngx_stream_map_find(ngx_stream_session_t *s, ngx_stream_map_t *map,
888 ngx_str_t *match)
889 {
890 void *value;
891 u_char *low;
892 size_t len;
893 ngx_uint_t key;
894
895 len = match->len;
896
897 if (len) {
898 low = ngx_pnalloc(s->connection->pool, len);
899 if (low == NULL) {
900 return NULL;
901 }
902
903 } else {
904 low = NULL;
905 }
906
907 key = ngx_hash_strlow(low, match->data, len);
908
909 value = ngx_hash_find_combined(&map->hash, key, low, len);
910 if (value) {
911 return value;
912 }
913
914 #if (NGX_PCRE)
915
916 if (len && map->nregex) {
917 ngx_int_t n;
918 ngx_uint_t i;
919 ngx_stream_map_regex_t *reg;
920
921 reg = map->regex;
922
923 for (i = 0; i < map->nregex; i++) {
924
925 n = ngx_stream_regex_exec(s, reg[i].regex, match);
926
927 if (n == NGX_OK) {
928 return reg[i].value;
929 }
930
931 if (n == NGX_DECLINED) {
932 continue;
933 }
934
935 /* NGX_ERROR */
936
937 return NULL;
938 }
939 }
940
941 #endif
942
943 return NULL;
944 }
945
946
947 #if (NGX_PCRE)
948
949 static ngx_int_t
ngx_stream_variable_not_found(ngx_stream_session_t * s,ngx_stream_variable_value_t * v,uintptr_t data)950 ngx_stream_variable_not_found(ngx_stream_session_t *s,
951 ngx_stream_variable_value_t *v, uintptr_t data)
952 {
953 v->not_found = 1;
954 return NGX_OK;
955 }
956
957
958 ngx_stream_regex_t *
ngx_stream_regex_compile(ngx_conf_t * cf,ngx_regex_compile_t * rc)959 ngx_stream_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc)
960 {
961 u_char *p;
962 size_t size;
963 ngx_str_t name;
964 ngx_uint_t i, n;
965 ngx_stream_variable_t *v;
966 ngx_stream_regex_t *re;
967 ngx_stream_regex_variable_t *rv;
968 ngx_stream_core_main_conf_t *cmcf;
969
970 rc->pool = cf->pool;
971
972 if (ngx_regex_compile(rc) != NGX_OK) {
973 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V", &rc->err);
974 return NULL;
975 }
976
977 re = ngx_pcalloc(cf->pool, sizeof(ngx_stream_regex_t));
978 if (re == NULL) {
979 return NULL;
980 }
981
982 re->regex = rc->regex;
983 re->ncaptures = rc->captures;
984 re->name = rc->pattern;
985
986 cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
987 cmcf->ncaptures = ngx_max(cmcf->ncaptures, re->ncaptures);
988
989 n = (ngx_uint_t) rc->named_captures;
990
991 if (n == 0) {
992 return re;
993 }
994
995 rv = ngx_palloc(rc->pool, n * sizeof(ngx_stream_regex_variable_t));
996 if (rv == NULL) {
997 return NULL;
998 }
999
1000 re->variables = rv;
1001 re->nvariables = n;
1002
1003 size = rc->name_size;
1004 p = rc->names;
1005
1006 for (i = 0; i < n; i++) {
1007 rv[i].capture = 2 * ((p[0] << 8) + p[1]);
1008
1009 name.data = &p[2];
1010 name.len = ngx_strlen(name.data);
1011
1012 v = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE);
1013 if (v == NULL) {
1014 return NULL;
1015 }
1016
1017 rv[i].index = ngx_stream_get_variable_index(cf, &name);
1018 if (rv[i].index == NGX_ERROR) {
1019 return NULL;
1020 }
1021
1022 v->get_handler = ngx_stream_variable_not_found;
1023
1024 p += size;
1025 }
1026
1027 return re;
1028 }
1029
1030
1031 ngx_int_t
ngx_stream_regex_exec(ngx_stream_session_t * s,ngx_stream_regex_t * re,ngx_str_t * str)1032 ngx_stream_regex_exec(ngx_stream_session_t *s, ngx_stream_regex_t *re,
1033 ngx_str_t *str)
1034 {
1035 ngx_int_t rc, index;
1036 ngx_uint_t i, n, len;
1037 ngx_stream_variable_value_t *vv;
1038 ngx_stream_core_main_conf_t *cmcf;
1039
1040 cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
1041
1042 if (re->ncaptures) {
1043 len = cmcf->ncaptures;
1044
1045 if (s->captures == NULL) {
1046 s->captures = ngx_palloc(s->connection->pool, len * sizeof(int));
1047 if (s->captures == NULL) {
1048 return NGX_ERROR;
1049 }
1050 }
1051
1052 } else {
1053 len = 0;
1054 }
1055
1056 rc = ngx_regex_exec(re->regex, str, s->captures, len);
1057
1058 if (rc == NGX_REGEX_NO_MATCHED) {
1059 return NGX_DECLINED;
1060 }
1061
1062 if (rc < 0) {
1063 ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
1064 ngx_regex_exec_n " failed: %i on \"%V\" using \"%V\"",
1065 rc, str, &re->name);
1066 return NGX_ERROR;
1067 }
1068
1069 for (i = 0; i < re->nvariables; i++) {
1070
1071 n = re->variables[i].capture;
1072 index = re->variables[i].index;
1073 vv = &s->variables[index];
1074
1075 vv->len = s->captures[n + 1] - s->captures[n];
1076 vv->valid = 1;
1077 vv->no_cacheable = 0;
1078 vv->not_found = 0;
1079 vv->data = &str->data[s->captures[n]];
1080
1081 #if (NGX_DEBUG)
1082 {
1083 ngx_stream_variable_t *v;
1084
1085 v = cmcf->variables.elts;
1086
1087 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
1088 "stream regex set $%V to \"%v\"", &v[index].name, vv);
1089 }
1090 #endif
1091 }
1092
1093 s->ncaptures = rc * 2;
1094 s->captures_data = str->data;
1095
1096 return NGX_OK;
1097 }
1098
1099 #endif
1100
1101
1102 ngx_int_t
ngx_stream_variables_add_core_vars(ngx_conf_t * cf)1103 ngx_stream_variables_add_core_vars(ngx_conf_t *cf)
1104 {
1105 ngx_stream_variable_t *cv, *v;
1106 ngx_stream_core_main_conf_t *cmcf;
1107
1108 cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
1109
1110 cmcf->variables_keys = ngx_pcalloc(cf->temp_pool,
1111 sizeof(ngx_hash_keys_arrays_t));
1112 if (cmcf->variables_keys == NULL) {
1113 return NGX_ERROR;
1114 }
1115
1116 cmcf->variables_keys->pool = cf->pool;
1117 cmcf->variables_keys->temp_pool = cf->pool;
1118
1119 if (ngx_hash_keys_array_init(cmcf->variables_keys, NGX_HASH_SMALL)
1120 != NGX_OK)
1121 {
1122 return NGX_ERROR;
1123 }
1124
1125 if (ngx_array_init(&cmcf->prefix_variables, cf->pool, 8,
1126 sizeof(ngx_stream_variable_t))
1127 != NGX_OK)
1128 {
1129 return NGX_ERROR;
1130 }
1131
1132 for (cv = ngx_stream_core_variables; cv->name.len; cv++) {
1133 v = ngx_stream_add_variable(cf, &cv->name, cv->flags);
1134 if (v == NULL) {
1135 return NGX_ERROR;
1136 }
1137
1138 *v = *cv;
1139 }
1140
1141 return NGX_OK;
1142 }
1143
1144
1145 ngx_int_t
ngx_stream_variables_init_vars(ngx_conf_t * cf)1146 ngx_stream_variables_init_vars(ngx_conf_t *cf)
1147 {
1148 size_t len;
1149 ngx_uint_t i, n;
1150 ngx_hash_key_t *key;
1151 ngx_hash_init_t hash;
1152 ngx_stream_variable_t *v, *av, *pv;
1153 ngx_stream_core_main_conf_t *cmcf;
1154
1155 /* set the handlers for the indexed stream variables */
1156
1157 cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
1158
1159 v = cmcf->variables.elts;
1160 pv = cmcf->prefix_variables.elts;
1161 key = cmcf->variables_keys->keys.elts;
1162
1163 for (i = 0; i < cmcf->variables.nelts; i++) {
1164
1165 for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
1166
1167 av = key[n].value;
1168
1169 if (v[i].name.len == key[n].key.len
1170 && ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len)
1171 == 0)
1172 {
1173 v[i].get_handler = av->get_handler;
1174 v[i].data = av->data;
1175
1176 av->flags |= NGX_STREAM_VAR_INDEXED;
1177 v[i].flags = av->flags;
1178
1179 av->index = i;
1180
1181 if (av->get_handler == NULL
1182 || (av->flags & NGX_STREAM_VAR_WEAK))
1183 {
1184 break;
1185 }
1186
1187 goto next;
1188 }
1189 }
1190
1191 len = 0;
1192 av = NULL;
1193
1194 for (n = 0; n < cmcf->prefix_variables.nelts; n++) {
1195 if (v[i].name.len >= pv[n].name.len && v[i].name.len > len
1196 && ngx_strncmp(v[i].name.data, pv[n].name.data, pv[n].name.len)
1197 == 0)
1198 {
1199 av = &pv[n];
1200 len = pv[n].name.len;
1201 }
1202 }
1203
1204 if (av) {
1205 v[i].get_handler = av->get_handler;
1206 v[i].data = (uintptr_t) &v[i].name;
1207 v[i].flags = av->flags;
1208
1209 goto next;
1210 }
1211
1212 if (v[i].get_handler == NULL) {
1213 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
1214 "unknown \"%V\" variable", &v[i].name);
1215 return NGX_ERROR;
1216 }
1217
1218 next:
1219 continue;
1220 }
1221
1222
1223 for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
1224 av = key[n].value;
1225
1226 if (av->flags & NGX_STREAM_VAR_NOHASH) {
1227 key[n].key.data = NULL;
1228 }
1229 }
1230
1231
1232 hash.hash = &cmcf->variables_hash;
1233 hash.key = ngx_hash_key;
1234 hash.max_size = cmcf->variables_hash_max_size;
1235 hash.bucket_size = cmcf->variables_hash_bucket_size;
1236 hash.name = "variables_hash";
1237 hash.pool = cf->pool;
1238 hash.temp_pool = NULL;
1239
1240 if (ngx_hash_init(&hash, cmcf->variables_keys->keys.elts,
1241 cmcf->variables_keys->keys.nelts)
1242 != NGX_OK)
1243 {
1244 return NGX_ERROR;
1245 }
1246
1247 cmcf->variables_keys = NULL;
1248
1249 return NGX_OK;
1250 }
1251