1 /*
2 * Functions dedicated to statistics output and the stats socket
3 *
4 * Copyright 2000-2012 Willy Tarreau <w@1wt.eu>
5 * Copyright 2007-2009 Krzysztof Piotr Oledzki <ole@ans.pl>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14 #include <ctype.h>
15 #include <errno.h>
16 #include <fcntl.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <pwd.h>
21 #include <grp.h>
22
23 #include <sys/socket.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26
27 #include <net/if.h>
28
29 #include <haproxy/activity.h>
30 #include <haproxy/api.h>
31 #include <haproxy/applet-t.h>
32 #include <haproxy/base64.h>
33 #include <haproxy/cfgparse.h>
34 #include <haproxy/channel.h>
35 #include <haproxy/check.h>
36 #include <haproxy/cli.h>
37 #include <haproxy/compression.h>
38 #include <haproxy/dns-t.h>
39 #include <haproxy/errors.h>
40 #include <haproxy/fd.h>
41 #include <haproxy/freq_ctr.h>
42 #include <haproxy/frontend.h>
43 #include <haproxy/global.h>
44 #include <haproxy/list.h>
45 #include <haproxy/listener.h>
46 #include <haproxy/log.h>
47 #include <haproxy/mworker-t.h>
48 #include <haproxy/pattern-t.h>
49 #include <haproxy/peers.h>
50 #include <haproxy/pipe.h>
51 #include <haproxy/protocol.h>
52 #include <haproxy/proxy.h>
53 #include <haproxy/sample-t.h>
54 #include <haproxy/server.h>
55 #include <haproxy/session.h>
56 #include <haproxy/stats-t.h>
57 #include <haproxy/stream.h>
58 #include <haproxy/stream_interface.h>
59 #include <haproxy/task.h>
60 #include <haproxy/ticks.h>
61 #include <haproxy/time.h>
62 #include <haproxy/tools.h>
63 #include <haproxy/version.h>
64
65 #define PAYLOAD_PATTERN "<<"
66
67 static struct applet cli_applet;
68
69 static const char stats_sock_usage_msg[] =
70 "Unknown command. Please enter one of the following commands only :\n"
71 " help : this message\n"
72 " prompt : toggle interactive mode with prompt\n"
73 " quit : disconnect\n"
74 "";
75
76 static const char stats_permission_denied_msg[] =
77 "Permission denied\n"
78 "";
79
80
81 static THREAD_LOCAL char *dynamic_usage_msg = NULL;
82
83 /* List head of cli keywords */
84 static struct cli_kw_list cli_keywords = {
85 .list = LIST_HEAD_INIT(cli_keywords.list)
86 };
87
88 extern const char *stat_status_codes[];
89
90 struct proxy *mworker_proxy; /* CLI proxy of the master */
91
cli_gen_usage_msg(struct appctx * appctx)92 static char *cli_gen_usage_msg(struct appctx *appctx)
93 {
94 struct cli_kw_list *kw_list;
95 struct cli_kw *kw;
96 struct buffer *tmp = get_trash_chunk();
97 struct buffer out;
98
99 free(dynamic_usage_msg);
100 dynamic_usage_msg = NULL;
101
102 if (LIST_ISEMPTY(&cli_keywords.list))
103 goto end;
104
105 chunk_reset(tmp);
106 chunk_strcat(tmp, stats_sock_usage_msg);
107 list_for_each_entry(kw_list, &cli_keywords.list, list) {
108 kw = &kw_list->kw[0];
109 while (kw->str_kw[0]) {
110
111 /* in a worker or normal process, don't display master only commands */
112 if (master == 0 && (kw->level & ACCESS_MASTER_ONLY))
113 goto next_kw;
114
115 /* in master don't displays if we don't have the master bits */
116 if (master == 1 && !(kw->level & (ACCESS_MASTER_ONLY|ACCESS_MASTER)))
117 goto next_kw;
118
119 /* only show expert commands in expert mode */
120 if ((kw->level & ~appctx->cli_level) & ACCESS_EXPERT)
121 goto next_kw;
122
123 if (kw->usage)
124 chunk_appendf(tmp, " %s\n", kw->usage);
125
126 next_kw:
127
128 kw++;
129 }
130 }
131 chunk_init(&out, NULL, 0);
132 chunk_dup(&out, tmp);
133 dynamic_usage_msg = out.area;
134
135 end:
136 if (dynamic_usage_msg) {
137 appctx->ctx.cli.severity = LOG_INFO;
138 appctx->ctx.cli.msg = dynamic_usage_msg;
139 }
140 else {
141 appctx->ctx.cli.severity = LOG_INFO;
142 appctx->ctx.cli.msg = stats_sock_usage_msg;
143 }
144 appctx->st0 = CLI_ST_PRINT;
145
146 return dynamic_usage_msg;
147 }
148
cli_find_kw(char ** args)149 struct cli_kw* cli_find_kw(char **args)
150 {
151 struct cli_kw_list *kw_list;
152 struct cli_kw *kw;/* current cli_kw */
153 char **tmp_args;
154 const char **tmp_str_kw;
155 int found = 0;
156
157 if (LIST_ISEMPTY(&cli_keywords.list))
158 return NULL;
159
160 list_for_each_entry(kw_list, &cli_keywords.list, list) {
161 kw = &kw_list->kw[0];
162 while (*kw->str_kw) {
163 tmp_args = args;
164 tmp_str_kw = kw->str_kw;
165 while (*tmp_str_kw) {
166 if (strcmp(*tmp_str_kw, *tmp_args) == 0) {
167 found = 1;
168 } else {
169 found = 0;
170 break;
171 }
172 tmp_args++;
173 tmp_str_kw++;
174 }
175 if (found)
176 return (kw);
177 kw++;
178 }
179 }
180 return NULL;
181 }
182
cli_find_kw_exact(char ** args)183 struct cli_kw* cli_find_kw_exact(char **args)
184 {
185 struct cli_kw_list *kw_list;
186 int found = 0;
187 int i;
188 int j;
189
190 if (LIST_ISEMPTY(&cli_keywords.list))
191 return NULL;
192
193 list_for_each_entry(kw_list, &cli_keywords.list, list) {
194 for (i = 0; kw_list->kw[i].str_kw[0]; i++) {
195 found = 1;
196 for (j = 0; j < CLI_PREFIX_KW_NB; j++) {
197 if (args[j] == NULL && kw_list->kw[i].str_kw[j] == NULL) {
198 break;
199 }
200 if (args[j] == NULL || kw_list->kw[i].str_kw[j] == NULL) {
201 found = 0;
202 break;
203 }
204 if (strcmp(args[j], kw_list->kw[i].str_kw[j]) != 0) {
205 found = 0;
206 break;
207 }
208 }
209 if (found)
210 return &kw_list->kw[i];
211 }
212 }
213 return NULL;
214 }
215
cli_register_kw(struct cli_kw_list * kw_list)216 void cli_register_kw(struct cli_kw_list *kw_list)
217 {
218 LIST_ADDQ(&cli_keywords.list, &kw_list->list);
219 }
220
221
222 /* allocate a new stats frontend named <name>, and return it
223 * (or NULL in case of lack of memory).
224 */
alloc_stats_fe(const char * name,const char * file,int line)225 static struct proxy *alloc_stats_fe(const char *name, const char *file, int line)
226 {
227 struct proxy *fe;
228
229 fe = calloc(1, sizeof(*fe));
230 if (!fe)
231 return NULL;
232
233 init_new_proxy(fe);
234 fe->next = proxies_list;
235 proxies_list = fe;
236 fe->last_change = now.tv_sec;
237 fe->id = strdup("GLOBAL");
238 fe->cap = PR_CAP_FE;
239 fe->maxconn = 10; /* default to 10 concurrent connections */
240 fe->timeout.client = MS_TO_TICKS(10000); /* default timeout of 10 seconds */
241 fe->conf.file = strdup(file);
242 fe->conf.line = line;
243 fe->accept = frontend_accept;
244 fe->default_target = &cli_applet.obj_type;
245
246 /* the stats frontend is the only one able to assign ID #0 */
247 fe->conf.id.key = fe->uuid = 0;
248 eb32_insert(&used_proxy_id, &fe->conf.id);
249 return fe;
250 }
251
252 /* This function parses a "stats" statement in the "global" section. It returns
253 * -1 if there is any error, otherwise zero. If it returns -1, it will write an
254 * error message into the <err> buffer which will be preallocated. The trailing
255 * '\n' must not be written. The function must be called with <args> pointing to
256 * the first word after "stats".
257 */
stats_parse_global(char ** args,int section_type,struct proxy * curpx,struct proxy * defpx,const char * file,int line,char ** err)258 static int stats_parse_global(char **args, int section_type, struct proxy *curpx,
259 struct proxy *defpx, const char *file, int line,
260 char **err)
261 {
262 struct bind_conf *bind_conf;
263 struct listener *l;
264
265 if (!strcmp(args[1], "socket")) {
266 int cur_arg;
267
268 if (*args[2] == 0) {
269 memprintf(err, "'%s %s' in global section expects an address or a path to a UNIX socket", args[0], args[1]);
270 return -1;
271 }
272
273 if (!global.stats_fe) {
274 if ((global.stats_fe = alloc_stats_fe("GLOBAL", file, line)) == NULL) {
275 memprintf(err, "'%s %s' : out of memory trying to allocate a frontend", args[0], args[1]);
276 return -1;
277 }
278 }
279
280 bind_conf = bind_conf_alloc(global.stats_fe, file, line, args[2], xprt_get(XPRT_RAW));
281 bind_conf->level &= ~ACCESS_LVL_MASK;
282 bind_conf->level |= ACCESS_LVL_OPER; /* default access level */
283
284 if (!str2listener(args[2], global.stats_fe, bind_conf, file, line, err)) {
285 memprintf(err, "parsing [%s:%d] : '%s %s' : %s\n",
286 file, line, args[0], args[1], err && *err ? *err : "error");
287 return -1;
288 }
289
290 cur_arg = 3;
291 while (*args[cur_arg]) {
292 static int bind_dumped;
293 struct bind_kw *kw;
294
295 kw = bind_find_kw(args[cur_arg]);
296 if (kw) {
297 if (!kw->parse) {
298 memprintf(err, "'%s %s' : '%s' option is not implemented in this version (check build options).",
299 args[0], args[1], args[cur_arg]);
300 return -1;
301 }
302
303 if (kw->parse(args, cur_arg, global.stats_fe, bind_conf, err) != 0) {
304 if (err && *err)
305 memprintf(err, "'%s %s' : '%s'", args[0], args[1], *err);
306 else
307 memprintf(err, "'%s %s' : error encountered while processing '%s'",
308 args[0], args[1], args[cur_arg]);
309 return -1;
310 }
311
312 cur_arg += 1 + kw->skip;
313 continue;
314 }
315
316 if (!bind_dumped) {
317 bind_dump_kws(err);
318 indent_msg(err, 4);
319 bind_dumped = 1;
320 }
321
322 memprintf(err, "'%s %s' : unknown keyword '%s'.%s%s",
323 args[0], args[1], args[cur_arg],
324 err && *err ? " Registered keywords :" : "", err && *err ? *err : "");
325 return -1;
326 }
327
328 list_for_each_entry(l, &bind_conf->listeners, by_bind) {
329 l->accept = session_accept_fd;
330 l->default_target = global.stats_fe->default_target;
331 l->options |= LI_O_UNLIMITED; /* don't make the peers subject to global limits */
332 l->nice = -64; /* we want to boost priority for local stats */
333 global.maxsock++; /* for the listening socket */
334 }
335 }
336 else if (!strcmp(args[1], "timeout")) {
337 unsigned timeout;
338 const char *res = parse_time_err(args[2], &timeout, TIME_UNIT_MS);
339
340 if (res == PARSE_TIME_OVER) {
341 memprintf(err, "timer overflow in argument '%s' to '%s %s' (maximum value is 2147483647 ms or ~24.8 days)",
342 args[2], args[0], args[1]);
343 return -1;
344 }
345 else if (res == PARSE_TIME_UNDER) {
346 memprintf(err, "timer underflow in argument '%s' to '%s %s' (minimum non-null value is 1 ms)",
347 args[2], args[0], args[1]);
348 return -1;
349 }
350 else if (res) {
351 memprintf(err, "'%s %s' : unexpected character '%c'", args[0], args[1], *res);
352 return -1;
353 }
354
355 if (!timeout) {
356 memprintf(err, "'%s %s' expects a positive value", args[0], args[1]);
357 return -1;
358 }
359 if (!global.stats_fe) {
360 if ((global.stats_fe = alloc_stats_fe("GLOBAL", file, line)) == NULL) {
361 memprintf(err, "'%s %s' : out of memory trying to allocate a frontend", args[0], args[1]);
362 return -1;
363 }
364 }
365 global.stats_fe->timeout.client = MS_TO_TICKS(timeout);
366 }
367 else if (!strcmp(args[1], "maxconn")) {
368 int maxconn = atol(args[2]);
369
370 if (maxconn <= 0) {
371 memprintf(err, "'%s %s' expects a positive value", args[0], args[1]);
372 return -1;
373 }
374
375 if (!global.stats_fe) {
376 if ((global.stats_fe = alloc_stats_fe("GLOBAL", file, line)) == NULL) {
377 memprintf(err, "'%s %s' : out of memory trying to allocate a frontend", args[0], args[1]);
378 return -1;
379 }
380 }
381 global.stats_fe->maxconn = maxconn;
382 }
383 else if (!strcmp(args[1], "bind-process")) { /* enable the socket only on some processes */
384 int cur_arg = 2;
385 unsigned long set = 0;
386
387 if (!global.stats_fe) {
388 if ((global.stats_fe = alloc_stats_fe("GLOBAL", file, line)) == NULL) {
389 memprintf(err, "'%s %s' : out of memory trying to allocate a frontend", args[0], args[1]);
390 return -1;
391 }
392 }
393
394 while (*args[cur_arg]) {
395 if (strcmp(args[cur_arg], "all") == 0) {
396 set = 0;
397 break;
398 }
399 if (parse_process_number(args[cur_arg], &set, MAX_PROCS, NULL, err)) {
400 memprintf(err, "'%s %s' : %s", args[0], args[1], *err);
401 return -1;
402 }
403 cur_arg++;
404 }
405 global.stats_fe->bind_proc = set;
406 }
407 else {
408 memprintf(err, "'%s' only supports 'socket', 'maxconn', 'bind-process' and 'timeout' (got '%s')", args[0], args[1]);
409 return -1;
410 }
411 return 0;
412 }
413
414 /*
415 * This function exports the bound addresses of a <frontend> in the environment
416 * variable <varname>. Those addresses are separated by semicolons and prefixed
417 * with their type (abns@, unix@, sockpair@ etc)
418 * Return -1 upon error, 0 otherwise
419 */
listeners_setenv(struct proxy * frontend,const char * varname)420 int listeners_setenv(struct proxy *frontend, const char *varname)
421 {
422 struct buffer *trash = get_trash_chunk();
423 struct bind_conf *bind_conf;
424
425 if (frontend) {
426 list_for_each_entry(bind_conf, &frontend->conf.bind, by_fe) {
427 struct listener *l;
428
429 list_for_each_entry(l, &bind_conf->listeners, by_bind) {
430 char addr[46];
431 char port[6];
432
433 /* separate listener by semicolons */
434 if (trash->data)
435 chunk_appendf(trash, ";");
436
437 if (l->addr.ss_family == AF_UNIX) {
438 const struct sockaddr_un *un;
439
440 un = (struct sockaddr_un *)&l->addr;
441 if (un->sun_path[0] == '\0') {
442 chunk_appendf(trash, "abns@%s", un->sun_path+1);
443 } else {
444 chunk_appendf(trash, "unix@%s", un->sun_path);
445 }
446 } else if (l->addr.ss_family == AF_INET) {
447 addr_to_str(&l->addr, addr, sizeof(addr));
448 port_to_str(&l->addr, port, sizeof(port));
449 chunk_appendf(trash, "ipv4@%s:%s", addr, port);
450 } else if (l->addr.ss_family == AF_INET6) {
451 addr_to_str(&l->addr, addr, sizeof(addr));
452 port_to_str(&l->addr, port, sizeof(port));
453 chunk_appendf(trash, "ipv6@[%s]:%s", addr, port);
454 } else if (l->addr.ss_family == AF_CUST_SOCKPAIR) {
455 chunk_appendf(trash, "sockpair@%d", ((struct sockaddr_in *)&l->addr)->sin_addr.s_addr);
456 }
457 }
458 }
459 trash->area[trash->data++] = '\0';
460 if (setenv(varname, trash->area, 1) < 0)
461 return -1;
462 }
463
464 return 0;
465 }
466
cli_socket_setenv()467 int cli_socket_setenv()
468 {
469 if (listeners_setenv(global.stats_fe, "HAPROXY_CLI") < 0)
470 return -1;
471 if (listeners_setenv(mworker_proxy, "HAPROXY_MASTER_CLI") < 0)
472 return -1;
473
474 return 0;
475 }
476
477 REGISTER_CONFIG_POSTPARSER("cli", cli_socket_setenv);
478
479 /* Verifies that the CLI at least has a level at least as high as <level>
480 * (typically ACCESS_LVL_ADMIN). Returns 1 if OK, otherwise 0. In case of
481 * failure, an error message is prepared and the appctx's state is adjusted
482 * to print it so that a return 1 is enough to abort any processing.
483 */
cli_has_level(struct appctx * appctx,int level)484 int cli_has_level(struct appctx *appctx, int level)
485 {
486
487 if ((appctx->cli_level & ACCESS_LVL_MASK) < level) {
488 cli_err(appctx, stats_permission_denied_msg);
489 return 0;
490 }
491 return 1;
492 }
493
494 /* same as cli_has_level but for the CLI proxy and without error message */
pcli_has_level(struct stream * s,int level)495 int pcli_has_level(struct stream *s, int level)
496 {
497 if ((s->pcli_flags & ACCESS_LVL_MASK) < level) {
498 return 0;
499 }
500 return 1;
501 }
502
503 /* Returns severity_output for the current session if set, or default for the socket */
cli_get_severity_output(struct appctx * appctx)504 static int cli_get_severity_output(struct appctx *appctx)
505 {
506 if (appctx->cli_severity_output)
507 return appctx->cli_severity_output;
508 return strm_li(si_strm(appctx->owner))->bind_conf->severity_output;
509 }
510
511 /* Processes the CLI interpreter on the stats socket. This function is called
512 * from the CLI's IO handler running in an appctx context. The function returns 1
513 * if the request was understood, otherwise zero. It is called with appctx->st0
514 * set to CLI_ST_GETREQ and presets ->st2 to 0 so that parsers don't have to do
515 * it. It will possilbly leave st0 to CLI_ST_CALLBACK if the keyword needs to
516 * have its own I/O handler called again. Most of the time, parsers will only
517 * set st0 to CLI_ST_PRINT and put their message to be displayed into cli.msg.
518 * If a keyword parser is NULL and an I/O handler is declared, the I/O handler
519 * will automatically be used.
520 */
cli_parse_request(struct appctx * appctx)521 static int cli_parse_request(struct appctx *appctx)
522 {
523 char *args[MAX_STATS_ARGS + 1], *p, *end, *payload = NULL;
524 int i = 0;
525 struct cli_kw *kw;
526
527 appctx->st2 = 0;
528 memset(&appctx->ctx.cli, 0, sizeof(appctx->ctx.cli));
529
530 p = appctx->chunk->area;
531 end = p + appctx->chunk->data;
532
533 /*
534 * Get pointers on words.
535 * One extra slot is reserved to store a pointer on a null byte.
536 */
537 while (i < MAX_STATS_ARGS && p < end) {
538 int j, k;
539
540 /* skip leading spaces/tabs */
541 p += strspn(p, " \t");
542 if (!*p)
543 break;
544
545 if (strcmp(p, PAYLOAD_PATTERN) == 0) {
546 /* payload pattern recognized here, this is not an arg anymore,
547 * the payload starts at the first byte that follows the zero
548 * after the pattern.
549 */
550 payload = p + strlen(PAYLOAD_PATTERN) + 1;
551 break;
552 }
553
554 args[i] = p;
555 while (1) {
556 p += strcspn(p, " \t\\");
557 /* escaped chars using backlashes (\) */
558 if (*p == '\\') {
559 if (!*++p)
560 break;
561 if (!*++p)
562 break;
563 } else {
564 break;
565 }
566 }
567 *p++ = 0;
568
569 /* unescape backslashes (\) */
570 for (j = 0, k = 0; args[i][k]; k++) {
571 if (args[i][k] == '\\') {
572 if (args[i][k + 1] == '\\')
573 k++;
574 else
575 continue;
576 }
577 args[i][j] = args[i][k];
578 j++;
579 }
580 args[i][j] = 0;
581
582 i++;
583 }
584 /* fill unused slots */
585 p = appctx->chunk->area + appctx->chunk->data;
586 for (; i < MAX_STATS_ARGS + 1; i++)
587 args[i] = p;
588
589 kw = cli_find_kw(args);
590 if (!kw)
591 return 0;
592
593 /* in a worker or normal process, don't display master only commands */
594 if (master == 0 && (kw->level & ACCESS_MASTER_ONLY))
595 return 0;
596
597 /* in master don't displays if we don't have the master bits */
598 if (master == 1 && !(kw->level & (ACCESS_MASTER_ONLY|ACCESS_MASTER)))
599 return 0;
600
601 /* only accept expert commands in expert mode */
602 if ((kw->level & ~appctx->cli_level) & ACCESS_EXPERT)
603 return 0;
604
605 appctx->io_handler = kw->io_handler;
606 appctx->io_release = kw->io_release;
607
608 if (kw->parse && kw->parse(args, payload, appctx, kw->private) != 0)
609 goto fail;
610
611 /* kw->parse could set its own io_handler or io_release handler */
612 if (!appctx->io_handler)
613 goto fail;
614
615 appctx->st0 = CLI_ST_CALLBACK;
616 return 1;
617 fail:
618 appctx->io_handler = NULL;
619 appctx->io_release = NULL;
620 return 1;
621 }
622
623 /* prepends then outputs the argument msg with a syslog-type severity depending on severity_output value */
cli_output_msg(struct channel * chn,const char * msg,int severity,int severity_output)624 static int cli_output_msg(struct channel *chn, const char *msg, int severity, int severity_output)
625 {
626 struct buffer *tmp;
627
628 if (likely(severity_output == CLI_SEVERITY_NONE))
629 return ci_putblk(chn, msg, strlen(msg));
630
631 tmp = get_trash_chunk();
632 chunk_reset(tmp);
633
634 if (severity < 0 || severity > 7) {
635 ha_warning("socket command feedback with invalid severity %d", severity);
636 chunk_printf(tmp, "[%d]: ", severity);
637 }
638 else {
639 switch (severity_output) {
640 case CLI_SEVERITY_NUMBER:
641 chunk_printf(tmp, "[%d]: ", severity);
642 break;
643 case CLI_SEVERITY_STRING:
644 chunk_printf(tmp, "[%s]: ", log_levels[severity]);
645 break;
646 default:
647 ha_warning("Unrecognized severity output %d", severity_output);
648 }
649 }
650 chunk_appendf(tmp, "%s", msg);
651
652 return ci_putblk(chn, tmp->area, strlen(tmp->area));
653 }
654
655 /* This I/O handler runs as an applet embedded in a stream interface. It is
656 * used to processes I/O from/to the stats unix socket. The system relies on a
657 * state machine handling requests and various responses. We read a request,
658 * then we process it and send the response, and we possibly display a prompt.
659 * Then we can read again. The state is stored in appctx->st0 and is one of the
660 * CLI_ST_* constants. appctx->st1 is used to indicate whether prompt is enabled
661 * or not.
662 */
cli_io_handler(struct appctx * appctx)663 static void cli_io_handler(struct appctx *appctx)
664 {
665 struct stream_interface *si = appctx->owner;
666 struct channel *req = si_oc(si);
667 struct channel *res = si_ic(si);
668 struct bind_conf *bind_conf = strm_li(si_strm(si))->bind_conf;
669 int reql;
670 int len;
671
672 if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
673 goto out;
674
675 /* Check if the input buffer is available. */
676 if (res->buf.size == 0) {
677 /* buf.size==0 means we failed to get a buffer and were
678 * already subscribed to a wait list to get a buffer.
679 */
680 goto out;
681 }
682
683 while (1) {
684 if (appctx->st0 == CLI_ST_INIT) {
685 /* Stats output not initialized yet */
686 memset(&appctx->ctx.stats, 0, sizeof(appctx->ctx.stats));
687 /* reset severity to default at init */
688 appctx->cli_severity_output = bind_conf->severity_output;
689 appctx->st0 = CLI_ST_GETREQ;
690 appctx->cli_level = bind_conf->level;
691 }
692 else if (appctx->st0 == CLI_ST_END) {
693 /* Let's close for real now. We just close the request
694 * side, the conditions below will complete if needed.
695 */
696 si_shutw(si);
697 free_trash_chunk(appctx->chunk);
698 appctx->chunk = NULL;
699 break;
700 }
701 else if (appctx->st0 == CLI_ST_GETREQ) {
702 char *str;
703
704 /* use a trash chunk to store received data */
705 if (!appctx->chunk) {
706 appctx->chunk = alloc_trash_chunk();
707 if (!appctx->chunk) {
708 appctx->st0 = CLI_ST_END;
709 continue;
710 }
711 }
712
713 str = appctx->chunk->area + appctx->chunk->data;
714
715 /* ensure we have some output room left in the event we
716 * would want to return some info right after parsing.
717 */
718 if (buffer_almost_full(si_ib(si))) {
719 si_rx_room_blk(si);
720 break;
721 }
722
723 /* '- 1' is to ensure a null byte can always be inserted at the end */
724 reql = co_getline(si_oc(si), str,
725 appctx->chunk->size - appctx->chunk->data - 1);
726 if (reql <= 0) { /* closed or EOL not found */
727 if (reql == 0)
728 break;
729 appctx->st0 = CLI_ST_END;
730 continue;
731 }
732
733 if (!(appctx->st1 & APPCTX_CLI_ST1_PAYLOAD)) {
734 /* seek for a possible unescaped semi-colon. If we find
735 * one, we replace it with an LF and skip only this part.
736 */
737 for (len = 0; len < reql; len++) {
738 if (str[len] == '\\') {
739 len++;
740 continue;
741 }
742 if (str[len] == ';') {
743 str[len] = '\n';
744 reql = len + 1;
745 break;
746 }
747 }
748 }
749
750 /* now it is time to check that we have a full line,
751 * remove the trailing \n and possibly \r, then cut the
752 * line.
753 */
754 len = reql - 1;
755 if (str[len] != '\n') {
756 appctx->st0 = CLI_ST_END;
757 continue;
758 }
759
760 if (len && str[len-1] == '\r')
761 len--;
762
763 str[len] = '\0';
764 appctx->chunk->data += len;
765
766 if (appctx->st1 & APPCTX_CLI_ST1_PAYLOAD) {
767 appctx->chunk->area[appctx->chunk->data] = '\n';
768 appctx->chunk->area[appctx->chunk->data + 1] = 0;
769 appctx->chunk->data++;
770 }
771
772 appctx->st0 = CLI_ST_PROMPT;
773
774 if (appctx->st1 & APPCTX_CLI_ST1_PAYLOAD) {
775 /* empty line */
776 if (!len) {
777 /* remove the last two \n */
778 appctx->chunk->data -= 2;
779 appctx->chunk->area[appctx->chunk->data] = 0;
780
781 if (!cli_parse_request(appctx))
782 cli_gen_usage_msg(appctx);
783
784 chunk_reset(appctx->chunk);
785 /* NB: cli_sock_parse_request() may have put
786 * another CLI_ST_O_* into appctx->st0.
787 */
788
789 appctx->st1 &= ~APPCTX_CLI_ST1_PAYLOAD;
790 }
791 }
792 else {
793 /*
794 * Look for the "payload start" pattern at the end of a line
795 * Its location is not remembered here, this is just to switch
796 * to a gathering mode.
797 */
798 if (strcmp(appctx->chunk->area + appctx->chunk->data - strlen(PAYLOAD_PATTERN), PAYLOAD_PATTERN) == 0) {
799 appctx->st1 |= APPCTX_CLI_ST1_PAYLOAD;
800 appctx->chunk->data++; // keep the trailing \0 after '<<'
801 }
802 else {
803 /* no payload, the command is complete: parse the request */
804 if (!cli_parse_request(appctx))
805 cli_gen_usage_msg(appctx);
806
807 chunk_reset(appctx->chunk);
808 }
809 }
810
811 /* re-adjust req buffer */
812 co_skip(si_oc(si), reql);
813 req->flags |= CF_READ_DONTWAIT; /* we plan to read small requests */
814 }
815 else { /* output functions */
816 const char *msg;
817 int sev;
818
819 switch (appctx->st0) {
820 case CLI_ST_PROMPT:
821 break;
822 case CLI_ST_PRINT: /* print const message in msg */
823 case CLI_ST_PRINT_ERR: /* print const error in msg */
824 case CLI_ST_PRINT_DYN: /* print dyn message in msg, free */
825 case CLI_ST_PRINT_FREE: /* print dyn error in err, free */
826 if (appctx->st0 == CLI_ST_PRINT || appctx->st0 == CLI_ST_PRINT_ERR) {
827 sev = appctx->st0 == CLI_ST_PRINT_ERR ?
828 LOG_ERR : appctx->ctx.cli.severity;
829 msg = appctx->ctx.cli.msg;
830 }
831 else if (appctx->st0 == CLI_ST_PRINT_DYN || appctx->st0 == CLI_ST_PRINT_FREE) {
832 sev = appctx->st0 == CLI_ST_PRINT_FREE ?
833 LOG_ERR : appctx->ctx.cli.severity;
834 msg = appctx->ctx.cli.err;
835 if (!msg) {
836 sev = LOG_ERR;
837 msg = "Out of memory.\n";
838 }
839 }
840 else {
841 sev = LOG_ERR;
842 msg = "Internal error.\n";
843 }
844
845 if (cli_output_msg(res, msg, sev, cli_get_severity_output(appctx)) != -1) {
846 if (appctx->st0 == CLI_ST_PRINT_FREE ||
847 appctx->st0 == CLI_ST_PRINT_DYN) {
848 free(appctx->ctx.cli.err);
849 appctx->ctx.cli.err = NULL;
850 }
851 appctx->st0 = CLI_ST_PROMPT;
852 }
853 else
854 si_rx_room_blk(si);
855 break;
856
857 case CLI_ST_CALLBACK: /* use custom pointer */
858 if (appctx->io_handler)
859 if (appctx->io_handler(appctx)) {
860 appctx->st0 = CLI_ST_PROMPT;
861 if (appctx->io_release) {
862 appctx->io_release(appctx);
863 appctx->io_release = NULL;
864 }
865 }
866 break;
867 default: /* abnormal state */
868 si->flags |= SI_FL_ERR;
869 break;
870 }
871
872 /* The post-command prompt is either LF alone or LF + '> ' in interactive mode */
873 if (appctx->st0 == CLI_ST_PROMPT) {
874 const char *prompt = "";
875
876 if (appctx->st1 & APPCTX_CLI_ST1_PROMPT) {
877 /*
878 * when entering a payload with interactive mode, change the prompt
879 * to emphasize that more data can still be sent
880 */
881 if (appctx->chunk->data && appctx->st1 & APPCTX_CLI_ST1_PAYLOAD)
882 prompt = "+ ";
883 else
884 prompt = "\n> ";
885 }
886 else {
887 if (!(appctx->st1 & (APPCTX_CLI_ST1_PAYLOAD|APPCTX_CLI_ST1_NOLF)))
888 prompt = "\n";
889 }
890
891 if (ci_putstr(si_ic(si), prompt) != -1)
892 appctx->st0 = CLI_ST_GETREQ;
893 else
894 si_rx_room_blk(si);
895 }
896
897 /* If the output functions are still there, it means they require more room. */
898 if (appctx->st0 >= CLI_ST_OUTPUT)
899 break;
900
901 /* Now we close the output if one of the writers did so,
902 * or if we're not in interactive mode and the request
903 * buffer is empty. This still allows pipelined requests
904 * to be sent in non-interactive mode.
905 */
906 if (((res->flags & (CF_SHUTW|CF_SHUTW_NOW))) ||
907 (!(appctx->st1 & APPCTX_CLI_ST1_PROMPT) && !co_data(req) && (!(appctx->st1 & APPCTX_CLI_ST1_PAYLOAD)))) {
908 appctx->st0 = CLI_ST_END;
909 continue;
910 }
911
912 /* switch state back to GETREQ to read next requests */
913 appctx->st0 = CLI_ST_GETREQ;
914 /* reactivate the \n at the end of the response for the next command */
915 appctx->st1 &= ~APPCTX_CLI_ST1_NOLF;
916 }
917 }
918
919 if ((res->flags & CF_SHUTR) && (si->state == SI_ST_EST)) {
920 DPRINTF(stderr, "%s@%d: si to buf closed. req=%08x, res=%08x, st=%d\n",
921 __FUNCTION__, __LINE__, req->flags, res->flags, si->state);
922 /* Other side has closed, let's abort if we have no more processing to do
923 * and nothing more to consume. This is comparable to a broken pipe, so
924 * we forward the close to the request side so that it flows upstream to
925 * the client.
926 */
927 si_shutw(si);
928 }
929
930 if ((req->flags & CF_SHUTW) && (si->state == SI_ST_EST) && (appctx->st0 < CLI_ST_OUTPUT)) {
931 DPRINTF(stderr, "%s@%d: buf to si closed. req=%08x, res=%08x, st=%d\n",
932 __FUNCTION__, __LINE__, req->flags, res->flags, si->state);
933 /* We have no more processing to do, and nothing more to send, and
934 * the client side has closed. So we'll forward this state downstream
935 * on the response buffer.
936 */
937 si_shutr(si);
938 res->flags |= CF_READ_NULL;
939 }
940
941 out:
942 DPRINTF(stderr, "%s@%d: st=%d, rqf=%x, rpf=%x, rqh=%lu, rqs=%lu, rh=%lu, rs=%lu\n",
943 __FUNCTION__, __LINE__,
944 si->state, req->flags, res->flags, ci_data(req), co_data(req), ci_data(res), co_data(res));
945 }
946
947 /* This is called when the stream interface is closed. For instance, upon an
948 * external abort, we won't call the i/o handler anymore so we may need to
949 * remove back references to the stream currently being dumped.
950 */
cli_release_handler(struct appctx * appctx)951 static void cli_release_handler(struct appctx *appctx)
952 {
953 free_trash_chunk(appctx->chunk);
954 appctx->chunk = NULL;
955
956 if (appctx->io_release) {
957 appctx->io_release(appctx);
958 appctx->io_release = NULL;
959 }
960 else if (appctx->st0 == CLI_ST_PRINT_FREE || appctx->st0 == CLI_ST_PRINT_DYN) {
961 free(appctx->ctx.cli.err);
962 appctx->ctx.cli.err = NULL;
963 }
964 }
965
966 /* This function dumps all environmnent variables to the buffer. It returns 0
967 * if the output buffer is full and it needs to be called again, otherwise
968 * non-zero. Dumps only one entry if st2 == STAT_ST_END. It uses cli.p0 as the
969 * pointer to the current variable.
970 */
cli_io_handler_show_env(struct appctx * appctx)971 static int cli_io_handler_show_env(struct appctx *appctx)
972 {
973 struct stream_interface *si = appctx->owner;
974 char **var = appctx->ctx.cli.p0;
975
976 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW)))
977 return 1;
978
979 chunk_reset(&trash);
980
981 /* we have two inner loops here, one for the proxy, the other one for
982 * the buffer.
983 */
984 while (*var) {
985 chunk_printf(&trash, "%s\n", *var);
986
987 if (ci_putchk(si_ic(si), &trash) == -1) {
988 si_rx_room_blk(si);
989 return 0;
990 }
991 if (appctx->st2 == STAT_ST_END)
992 break;
993 var++;
994 appctx->ctx.cli.p0 = var;
995 }
996
997 /* dump complete */
998 return 1;
999 }
1000
1001 /* This function dumps all file descriptors states (or the requested one) to
1002 * the buffer. It returns 0 if the output buffer is full and it needs to be
1003 * called again, otherwise non-zero. Dumps only one entry if st2 == STAT_ST_END.
1004 * It uses cli.i0 as the fd number to restart from.
1005 */
cli_io_handler_show_fd(struct appctx * appctx)1006 static int cli_io_handler_show_fd(struct appctx *appctx)
1007 {
1008 struct stream_interface *si = appctx->owner;
1009 int fd = appctx->ctx.cli.i0;
1010 int ret = 1;
1011
1012 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW)))
1013 goto end;
1014
1015 chunk_reset(&trash);
1016
1017 /* isolate the threads once per round. We're limited to a buffer worth
1018 * of output anyway, it cannot last very long.
1019 */
1020 thread_isolate();
1021
1022 /* we have two inner loops here, one for the proxy, the other one for
1023 * the buffer.
1024 */
1025 while (fd >= 0 && fd < global.maxsock) {
1026 struct fdtab fdt;
1027 const struct listener *li = NULL;
1028 const struct server *sv = NULL;
1029 const struct proxy *px = NULL;
1030 const struct connection *conn = NULL;
1031 const struct mux_ops *mux = NULL;
1032 const struct xprt_ops *xprt = NULL;
1033 const void *ctx = NULL;
1034 const void *xprt_ctx = NULL;
1035 uint32_t conn_flags = 0;
1036 int is_back = 0;
1037 int suspicious = 0;
1038
1039 fdt = fdtab[fd];
1040
1041 /* When DEBUG_FD is set, we also report closed FDs that have a
1042 * non-null event count to detect stuck ones.
1043 */
1044 if (!fdt.owner) {
1045 #ifdef DEBUG_FD
1046 if (!fdt.event_count)
1047 #endif
1048 goto skip; // closed
1049 }
1050 else if (fdt.iocb == conn_fd_handler) {
1051 conn = (const struct connection *)fdt.owner;
1052 conn_flags = conn->flags;
1053 mux = conn->mux;
1054 ctx = conn->ctx;
1055 xprt = conn->xprt;
1056 xprt_ctx = conn->xprt_ctx;
1057 li = objt_listener(conn->target);
1058 sv = objt_server(conn->target);
1059 px = objt_proxy(conn->target);
1060 is_back = conn_is_back(conn);
1061 if (atleast2(fdt.thread_mask))
1062 suspicious = 1;
1063 if (conn->handle.fd != fd)
1064 suspicious = 1;
1065 }
1066 else if (fdt.iocb == listener_accept)
1067 li = fdt.owner;
1068
1069 if (!fdt.thread_mask)
1070 suspicious = 1;
1071
1072 chunk_printf(&trash,
1073 " %5d : st=0x%02x(R:%c%c W:%c%c) ev=0x%02x(%c%c%c%c%c) [%c%c] tmask=0x%lx umask=0x%lx owner=%p iocb=%p(",
1074 fd,
1075 fdt.state,
1076 (fdt.state & FD_EV_READY_R) ? 'R' : 'r',
1077 (fdt.state & FD_EV_ACTIVE_R) ? 'A' : 'a',
1078 (fdt.state & FD_EV_READY_W) ? 'R' : 'r',
1079 (fdt.state & FD_EV_ACTIVE_W) ? 'A' : 'a',
1080 fdt.ev,
1081 (fdt.ev & FD_POLL_HUP) ? 'H' : 'h',
1082 (fdt.ev & FD_POLL_ERR) ? 'E' : 'e',
1083 (fdt.ev & FD_POLL_OUT) ? 'O' : 'o',
1084 (fdt.ev & FD_POLL_PRI) ? 'P' : 'p',
1085 (fdt.ev & FD_POLL_IN) ? 'I' : 'i',
1086 fdt.linger_risk ? 'L' : 'l',
1087 fdt.cloned ? 'C' : 'c',
1088 fdt.thread_mask, fdt.update_mask,
1089 fdt.owner,
1090 fdt.iocb);
1091 resolve_sym_name(&trash, NULL, fdt.iocb);
1092
1093 if (!fdt.owner) {
1094 chunk_appendf(&trash, ")");
1095 }
1096 else if (fdt.iocb == conn_fd_handler) {
1097 chunk_appendf(&trash, ") back=%d cflg=0x%08x", is_back, conn_flags);
1098
1099 if (conn->handle.fd != fd) {
1100 chunk_appendf(&trash, " fd=%d(BOGUS)", conn->handle.fd);
1101 suspicious = 1;
1102 } else {
1103 struct sockaddr_storage sa;
1104 socklen_t salen;
1105
1106 salen = sizeof(sa);
1107 if (getsockname(fd, (struct sockaddr *)&sa, &salen) != -1) {
1108 if (sa.ss_family == AF_INET)
1109 chunk_appendf(&trash, " fam=ipv4 lport=%d", ntohs(((const struct sockaddr_in *)&sa)->sin_port));
1110 else if (sa.ss_family == AF_INET6)
1111 chunk_appendf(&trash, " fam=ipv6 lport=%d", ntohs(((const struct sockaddr_in6 *)&sa)->sin6_port));
1112 else if (sa.ss_family == AF_UNIX)
1113 chunk_appendf(&trash, " fam=unix");
1114 }
1115
1116 salen = sizeof(sa);
1117 if (getpeername(fd, (struct sockaddr *)&sa, &salen) != -1) {
1118 if (sa.ss_family == AF_INET)
1119 chunk_appendf(&trash, " rport=%d", ntohs(((const struct sockaddr_in *)&sa)->sin_port));
1120 else if (sa.ss_family == AF_INET6)
1121 chunk_appendf(&trash, " rport=%d", ntohs(((const struct sockaddr_in6 *)&sa)->sin6_port));
1122 }
1123 }
1124
1125 if (px)
1126 chunk_appendf(&trash, " px=%s", px->id);
1127 else if (sv)
1128 chunk_appendf(&trash, " sv=%s/%s", sv->proxy->id, sv->id);
1129 else if (li)
1130 chunk_appendf(&trash, " fe=%s", li->bind_conf->frontend->id);
1131
1132 if (mux) {
1133 chunk_appendf(&trash, " mux=%s ctx=%p", mux->name, ctx);
1134 if (!ctx)
1135 suspicious = 1;
1136 if (mux->show_fd)
1137 suspicious |= mux->show_fd(&trash, fdt.owner);
1138 }
1139 else
1140 chunk_appendf(&trash, " nomux");
1141
1142 chunk_appendf(&trash, " xprt=%s", xprt ? xprt->name : "");
1143 if (xprt) {
1144 if (xprt_ctx || xprt->show_fd)
1145 chunk_appendf(&trash, " xprt_ctx=%p", xprt_ctx);
1146 if (xprt->show_fd)
1147 suspicious |= xprt->show_fd(&trash, conn, xprt_ctx);
1148 }
1149 }
1150 else if (fdt.iocb == listener_accept) {
1151 struct sockaddr_storage sa;
1152 socklen_t salen;
1153
1154 chunk_appendf(&trash, ") l.st=%s fe=%s",
1155 listener_state_str(li),
1156 li->bind_conf->frontend->id);
1157
1158 salen = sizeof(sa);
1159 if (getsockname(fd, (struct sockaddr *)&sa, &salen) != -1) {
1160 if (sa.ss_family == AF_INET)
1161 chunk_appendf(&trash, " fam=ipv4 lport=%d", ntohs(((const struct sockaddr_in *)&sa)->sin_port));
1162 else if (sa.ss_family == AF_INET6)
1163 chunk_appendf(&trash, " fam=ipv6 lport=%d", ntohs(((const struct sockaddr_in6 *)&sa)->sin6_port));
1164 else if (sa.ss_family == AF_UNIX)
1165 chunk_appendf(&trash, " fam=unix");
1166 }
1167 }
1168 else
1169 chunk_appendf(&trash, ")");
1170
1171 #ifdef DEBUG_FD
1172 chunk_appendf(&trash, " evcnt=%u", fdtab[fd].event_count);
1173 if (fdtab[fd].event_count >= 1000000)
1174 suspicious = 1;
1175 #endif
1176 chunk_appendf(&trash, "%s\n", suspicious ? " !" : "");
1177
1178 if (ci_putchk(si_ic(si), &trash) == -1) {
1179 si_rx_room_blk(si);
1180 appctx->ctx.cli.i0 = fd;
1181 ret = 0;
1182 break;
1183 }
1184 skip:
1185 if (appctx->st2 == STAT_ST_END)
1186 break;
1187
1188 fd++;
1189 }
1190
1191 end:
1192 /* dump complete */
1193
1194 thread_release();
1195 return ret;
1196 }
1197
1198 /* This function dumps some activity counters used by developers and support to
1199 * rule out some hypothesis during bug reports. It returns 0 if the output
1200 * buffer is full and it needs to be called again, otherwise non-zero. It dumps
1201 * everything at once in the buffer and is not designed to do it in multiple
1202 * passes.
1203 */
cli_io_handler_show_activity(struct appctx * appctx)1204 static int cli_io_handler_show_activity(struct appctx *appctx)
1205 {
1206 struct stream_interface *si = appctx->owner;
1207 int thr;
1208
1209 if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW)))
1210 return 1;
1211
1212 chunk_reset(&trash);
1213
1214 #undef SHOW_TOT
1215 #define SHOW_TOT(t, x) \
1216 do { \
1217 unsigned int _v[MAX_THREADS]; \
1218 unsigned int _tot; \
1219 const unsigned int _nbt = global.nbthread; \
1220 for (_tot = t = 0; t < _nbt; t++) \
1221 _tot += _v[t] = (x); \
1222 if (_nbt == 1) { \
1223 chunk_appendf(&trash, " %u\n", _tot); \
1224 break; \
1225 } \
1226 chunk_appendf(&trash, " %u [", _tot); \
1227 for (t = 0; t < _nbt; t++) \
1228 chunk_appendf(&trash, " %u", _v[t]); \
1229 chunk_appendf(&trash, " ]\n"); \
1230 } while (0)
1231
1232 #undef SHOW_AVG
1233 #define SHOW_AVG(t, x) \
1234 do { \
1235 unsigned int _v[MAX_THREADS]; \
1236 unsigned int _tot; \
1237 const unsigned int _nbt = global.nbthread; \
1238 for (_tot = t = 0; t < _nbt; t++) \
1239 _tot += _v[t] = (x); \
1240 if (_nbt == 1) { \
1241 chunk_appendf(&trash, " %u\n", _tot); \
1242 break; \
1243 } \
1244 chunk_appendf(&trash, " %u [", (_tot + _nbt/2) / _nbt); \
1245 for (t = 0; t < _nbt; t++) \
1246 chunk_appendf(&trash, " %u", _v[t]); \
1247 chunk_appendf(&trash, " ]\n"); \
1248 } while (0)
1249
1250 chunk_appendf(&trash, "thread_id: %u (%u..%u)\n", tid + 1, 1, global.nbthread);
1251 chunk_appendf(&trash, "date_now: %lu.%06lu\n", (long)now.tv_sec, (long)now.tv_usec);
1252 chunk_appendf(&trash, "ctxsw:"); SHOW_TOT(thr, activity[thr].ctxsw);
1253 chunk_appendf(&trash, "tasksw:"); SHOW_TOT(thr, activity[thr].tasksw);
1254 chunk_appendf(&trash, "empty_rq:"); SHOW_TOT(thr, activity[thr].empty_rq);
1255 chunk_appendf(&trash, "long_rq:"); SHOW_TOT(thr, activity[thr].long_rq);
1256 chunk_appendf(&trash, "loops:"); SHOW_TOT(thr, activity[thr].loops);
1257 chunk_appendf(&trash, "wake_tasks:"); SHOW_TOT(thr, activity[thr].wake_tasks);
1258 chunk_appendf(&trash, "wake_signal:"); SHOW_TOT(thr, activity[thr].wake_signal);
1259 chunk_appendf(&trash, "poll_io:"); SHOW_TOT(thr, activity[thr].poll_io);
1260 chunk_appendf(&trash, "poll_exp:"); SHOW_TOT(thr, activity[thr].poll_exp);
1261 chunk_appendf(&trash, "poll_drop_fd:"); SHOW_TOT(thr, activity[thr].poll_drop_fd);
1262 chunk_appendf(&trash, "poll_dead_fd:"); SHOW_TOT(thr, activity[thr].poll_dead_fd);
1263 chunk_appendf(&trash, "poll_skip_fd:"); SHOW_TOT(thr, activity[thr].poll_skip_fd);
1264 chunk_appendf(&trash, "conn_dead:"); SHOW_TOT(thr, activity[thr].conn_dead);
1265 chunk_appendf(&trash, "stream_calls:"); SHOW_TOT(thr, activity[thr].stream_calls);
1266 chunk_appendf(&trash, "pool_fail:"); SHOW_TOT(thr, activity[thr].pool_fail);
1267 chunk_appendf(&trash, "buf_wait:"); SHOW_TOT(thr, activity[thr].buf_wait);
1268 chunk_appendf(&trash, "cpust_ms_tot:"); SHOW_TOT(thr, activity[thr].cpust_total / 2);
1269 chunk_appendf(&trash, "cpust_ms_1s:"); SHOW_TOT(thr, read_freq_ctr(&activity[thr].cpust_1s) / 2);
1270 chunk_appendf(&trash, "cpust_ms_15s:"); SHOW_TOT(thr, read_freq_ctr_period(&activity[thr].cpust_15s, 15000) / 2);
1271 chunk_appendf(&trash, "avg_loop_us:"); SHOW_AVG(thr, swrate_avg(activity[thr].avg_loop_us, TIME_STATS_SAMPLES));
1272 chunk_appendf(&trash, "accepted:"); SHOW_TOT(thr, activity[thr].accepted);
1273 chunk_appendf(&trash, "accq_pushed:"); SHOW_TOT(thr, activity[thr].accq_pushed);
1274 chunk_appendf(&trash, "accq_full:"); SHOW_TOT(thr, activity[thr].accq_full);
1275 #ifdef USE_THREAD
1276 chunk_appendf(&trash, "accq_ring:"); SHOW_TOT(thr, (accept_queue_rings[thr].tail - accept_queue_rings[thr].head + ACCEPT_QUEUE_SIZE) % ACCEPT_QUEUE_SIZE);
1277 chunk_appendf(&trash, "fd_takeover:"); SHOW_TOT(thr, activity[thr].fd_takeover);
1278 #endif
1279
1280 #if defined(DEBUG_DEV)
1281 /* keep these ones at the end */
1282 chunk_appendf(&trash, "ctr0:"); SHOW_TOT(thr, activity[thr].ctr0);
1283 chunk_appendf(&trash, "ctr1:"); SHOW_TOT(thr, activity[thr].ctr1);
1284 chunk_appendf(&trash, "ctr2:"); SHOW_TOT(thr, activity[thr].ctr2);
1285 #endif
1286
1287 if (ci_putchk(si_ic(si), &trash) == -1) {
1288 chunk_reset(&trash);
1289 chunk_printf(&trash, "[output too large, cannot dump]\n");
1290 si_rx_room_blk(si);
1291 }
1292
1293 #undef SHOW_AVG
1294 #undef SHOW_TOT
1295 /* dump complete */
1296 return 1;
1297 }
1298
1299 /*
1300 * CLI IO handler for `show cli sockets`.
1301 * Uses ctx.cli.p0 to store the restart pointer.
1302 */
cli_io_handler_show_cli_sock(struct appctx * appctx)1303 static int cli_io_handler_show_cli_sock(struct appctx *appctx)
1304 {
1305 struct bind_conf *bind_conf;
1306 struct stream_interface *si = appctx->owner;
1307
1308 chunk_reset(&trash);
1309
1310 switch (appctx->st2) {
1311 case STAT_ST_INIT:
1312 chunk_printf(&trash, "# socket lvl processes\n");
1313 if (ci_putchk(si_ic(si), &trash) == -1) {
1314 si_rx_room_blk(si);
1315 return 0;
1316 }
1317 appctx->st2 = STAT_ST_LIST;
1318 /* fall through */
1319
1320 case STAT_ST_LIST:
1321 if (global.stats_fe) {
1322 list_for_each_entry(bind_conf, &global.stats_fe->conf.bind, by_fe) {
1323 struct listener *l;
1324
1325 /*
1326 * get the latest dumped node in appctx->ctx.cli.p0
1327 * if the current node is the first of the list
1328 */
1329
1330 if (appctx->ctx.cli.p0 &&
1331 &bind_conf->by_fe == (&global.stats_fe->conf.bind)->n) {
1332 /* change the current node to the latest dumped and continue the loop */
1333 bind_conf = LIST_ELEM(appctx->ctx.cli.p0, typeof(bind_conf), by_fe);
1334 continue;
1335 }
1336
1337 list_for_each_entry(l, &bind_conf->listeners, by_bind) {
1338
1339 char addr[46];
1340 char port[6];
1341
1342 if (l->addr.ss_family == AF_UNIX) {
1343 const struct sockaddr_un *un;
1344
1345 un = (struct sockaddr_un *)&l->addr;
1346 if (un->sun_path[0] == '\0') {
1347 chunk_appendf(&trash, "abns@%s ", un->sun_path+1);
1348 } else {
1349 chunk_appendf(&trash, "unix@%s ", un->sun_path);
1350 }
1351 } else if (l->addr.ss_family == AF_INET) {
1352 addr_to_str(&l->addr, addr, sizeof(addr));
1353 port_to_str(&l->addr, port, sizeof(port));
1354 chunk_appendf(&trash, "ipv4@%s:%s ", addr, port);
1355 } else if (l->addr.ss_family == AF_INET6) {
1356 addr_to_str(&l->addr, addr, sizeof(addr));
1357 port_to_str(&l->addr, port, sizeof(port));
1358 chunk_appendf(&trash, "ipv6@[%s]:%s ", addr, port);
1359 } else if (l->addr.ss_family == AF_CUST_SOCKPAIR) {
1360 chunk_appendf(&trash, "sockpair@%d ", ((struct sockaddr_in *)&l->addr)->sin_addr.s_addr);
1361 } else
1362 chunk_appendf(&trash, "unknown ");
1363
1364 if ((bind_conf->level & ACCESS_LVL_MASK) == ACCESS_LVL_ADMIN)
1365 chunk_appendf(&trash, "admin ");
1366 else if ((bind_conf->level & ACCESS_LVL_MASK) == ACCESS_LVL_OPER)
1367 chunk_appendf(&trash, "operator ");
1368 else if ((bind_conf->level & ACCESS_LVL_MASK) == ACCESS_LVL_USER)
1369 chunk_appendf(&trash, "user ");
1370 else
1371 chunk_appendf(&trash, " ");
1372
1373 if (bind_conf->bind_proc != 0) {
1374 int pos;
1375 for (pos = 0; pos < 8 * sizeof(bind_conf->bind_proc); pos++) {
1376 if (bind_conf->bind_proc & (1UL << pos)) {
1377 chunk_appendf(&trash, "%d,", pos+1);
1378 }
1379 }
1380 /* replace the latest comma by a newline */
1381 trash.area[trash.data-1] = '\n';
1382
1383 } else {
1384 chunk_appendf(&trash, "all\n");
1385 }
1386
1387 if (ci_putchk(si_ic(si), &trash) == -1) {
1388 si_rx_room_blk(si);
1389 return 0;
1390 }
1391 }
1392 appctx->ctx.cli.p0 = &bind_conf->by_fe; /* store the latest list node dumped */
1393 }
1394 }
1395 /* fall through */
1396 default:
1397 appctx->st2 = STAT_ST_FIN;
1398 return 1;
1399 }
1400 }
1401
1402
1403 /* parse a "show env" CLI request. Returns 0 if it needs to continue, 1 if it
1404 * wants to stop here. It puts the variable to be dumped into cli.p0 if a single
1405 * variable is requested otherwise puts environ there.
1406 */
cli_parse_show_env(char ** args,char * payload,struct appctx * appctx,void * private)1407 static int cli_parse_show_env(char **args, char *payload, struct appctx *appctx, void *private)
1408 {
1409 extern char **environ;
1410 char **var;
1411
1412 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
1413 return 1;
1414
1415 var = environ;
1416
1417 if (*args[2]) {
1418 int len = strlen(args[2]);
1419
1420 for (; *var; var++) {
1421 if (strncmp(*var, args[2], len) == 0 &&
1422 (*var)[len] == '=')
1423 break;
1424 }
1425 if (!*var)
1426 return cli_err(appctx, "Variable not found\n");
1427
1428 appctx->st2 = STAT_ST_END;
1429 }
1430 appctx->ctx.cli.p0 = var;
1431 return 0;
1432 }
1433
1434 /* parse a "show fd" CLI request. Returns 0 if it needs to continue, 1 if it
1435 * wants to stop here. It puts the FD number into cli.i0 if a specific FD is
1436 * requested and sets st2 to STAT_ST_END, otherwise leaves 0 in i0.
1437 */
cli_parse_show_fd(char ** args,char * payload,struct appctx * appctx,void * private)1438 static int cli_parse_show_fd(char **args, char *payload, struct appctx *appctx, void *private)
1439 {
1440 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
1441 return 1;
1442
1443 appctx->ctx.cli.i0 = 0;
1444
1445 if (*args[2]) {
1446 appctx->ctx.cli.i0 = atoi(args[2]);
1447 appctx->st2 = STAT_ST_END;
1448 }
1449 return 0;
1450 }
1451
1452 /* parse a "set timeout" CLI request. It always returns 1. */
cli_parse_set_timeout(char ** args,char * payload,struct appctx * appctx,void * private)1453 static int cli_parse_set_timeout(char **args, char *payload, struct appctx *appctx, void *private)
1454 {
1455 struct stream_interface *si = appctx->owner;
1456 struct stream *s = si_strm(si);
1457
1458 if (strcmp(args[2], "cli") == 0) {
1459 unsigned timeout;
1460 const char *res;
1461
1462 if (!*args[3])
1463 return cli_err(appctx, "Expects an integer value.\n");
1464
1465 res = parse_time_err(args[3], &timeout, TIME_UNIT_S);
1466 if (res || timeout < 1)
1467 return cli_err(appctx, "Invalid timeout value.\n");
1468
1469 s->req.rto = s->res.wto = 1 + MS_TO_TICKS(timeout*1000);
1470 task_wakeup(s->task, TASK_WOKEN_MSG); // recompute timeouts
1471 return 1;
1472 }
1473
1474 return cli_err(appctx, "'set timeout' only supports 'cli'.\n");
1475 }
1476
1477 /* parse a "set maxconn global" command. It always returns 1. */
cli_parse_set_maxconn_global(char ** args,char * payload,struct appctx * appctx,void * private)1478 static int cli_parse_set_maxconn_global(char **args, char *payload, struct appctx *appctx, void *private)
1479 {
1480 int v;
1481
1482 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
1483 return 1;
1484
1485 if (!*args[3])
1486 return cli_err(appctx, "Expects an integer value.\n");
1487
1488 v = atoi(args[3]);
1489 if (v > global.hardmaxconn)
1490 return cli_err(appctx, "Value out of range.\n");
1491
1492 /* check for unlimited values */
1493 if (v <= 0)
1494 v = global.hardmaxconn;
1495
1496 global.maxconn = v;
1497
1498 /* Dequeues all of the listeners waiting for a resource */
1499 dequeue_all_listeners();
1500
1501 return 1;
1502 }
1503
set_severity_output(int * target,char * argument)1504 static int set_severity_output(int *target, char *argument)
1505 {
1506 if (!strcmp(argument, "none")) {
1507 *target = CLI_SEVERITY_NONE;
1508 return 1;
1509 }
1510 else if (!strcmp(argument, "number")) {
1511 *target = CLI_SEVERITY_NUMBER;
1512 return 1;
1513 }
1514 else if (!strcmp(argument, "string")) {
1515 *target = CLI_SEVERITY_STRING;
1516 return 1;
1517 }
1518 return 0;
1519 }
1520
1521 /* parse a "set severity-output" command. */
cli_parse_set_severity_output(char ** args,char * payload,struct appctx * appctx,void * private)1522 static int cli_parse_set_severity_output(char **args, char *payload, struct appctx *appctx, void *private)
1523 {
1524 if (*args[2] && set_severity_output(&appctx->cli_severity_output, args[2]))
1525 return 0;
1526
1527 return cli_err(appctx, "one of 'none', 'number', 'string' is a required argument\n");
1528 }
1529
1530
1531 /* show the level of the current CLI session */
cli_parse_show_lvl(char ** args,char * payload,struct appctx * appctx,void * private)1532 static int cli_parse_show_lvl(char **args, char *payload, struct appctx *appctx, void *private)
1533 {
1534 if ((appctx->cli_level & ACCESS_LVL_MASK) == ACCESS_LVL_ADMIN)
1535 return cli_msg(appctx, LOG_INFO, "admin\n");
1536 else if ((appctx->cli_level & ACCESS_LVL_MASK) == ACCESS_LVL_OPER)
1537 return cli_msg(appctx, LOG_INFO, "operator\n");
1538 else if ((appctx->cli_level & ACCESS_LVL_MASK) == ACCESS_LVL_USER)
1539 return cli_msg(appctx, LOG_INFO, "user\n");
1540 else
1541 return cli_msg(appctx, LOG_INFO, "unknown\n");
1542 }
1543
1544 /* parse and set the CLI level dynamically */
cli_parse_set_lvl(char ** args,char * payload,struct appctx * appctx,void * private)1545 static int cli_parse_set_lvl(char **args, char *payload, struct appctx *appctx, void *private)
1546 {
1547 /* this will ask the applet to not output a \n after the command */
1548 if (!strcmp(args[1], "-"))
1549 appctx->st1 |= APPCTX_CLI_ST1_NOLF;
1550
1551 if (!strcmp(args[0], "operator")) {
1552 if (!cli_has_level(appctx, ACCESS_LVL_OPER)) {
1553 return 1;
1554 }
1555 appctx->cli_level &= ~ACCESS_LVL_MASK;
1556 appctx->cli_level |= ACCESS_LVL_OPER;
1557
1558 } else if (!strcmp(args[0], "user")) {
1559 if (!cli_has_level(appctx, ACCESS_LVL_USER)) {
1560 return 1;
1561 }
1562 appctx->cli_level &= ~ACCESS_LVL_MASK;
1563 appctx->cli_level |= ACCESS_LVL_USER;
1564 }
1565 appctx->cli_level &= ~ACCESS_EXPERT;
1566 return 1;
1567 }
1568
1569
1570 /* parse and set the CLI expert-mode dynamically */
cli_parse_expert_mode(char ** args,char * payload,struct appctx * appctx,void * private)1571 static int cli_parse_expert_mode(char **args, char *payload, struct appctx *appctx, void *private)
1572 {
1573 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
1574 return 1;
1575
1576 if (!*args[1])
1577 return (appctx->cli_level & ACCESS_EXPERT)
1578 ? cli_msg(appctx, LOG_INFO, "expert-mode is ON\n")
1579 : cli_msg(appctx, LOG_INFO, "expert-mode is OFF\n");
1580
1581 appctx->cli_level &= ~ACCESS_EXPERT;
1582 if (strcmp(args[1], "on") == 0)
1583 appctx->cli_level |= ACCESS_EXPERT;
1584 return 1;
1585 }
1586
1587
cli_parse_default(char ** args,char * payload,struct appctx * appctx,void * private)1588 int cli_parse_default(char **args, char *payload, struct appctx *appctx, void *private)
1589 {
1590 return 0;
1591 }
1592
1593 /* parse a "set rate-limit" command. It always returns 1. */
cli_parse_set_ratelimit(char ** args,char * payload,struct appctx * appctx,void * private)1594 static int cli_parse_set_ratelimit(char **args, char *payload, struct appctx *appctx, void *private)
1595 {
1596 int v;
1597 int *res;
1598 int mul = 1;
1599
1600 if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
1601 return 1;
1602
1603 if (strcmp(args[2], "connections") == 0 && strcmp(args[3], "global") == 0)
1604 res = &global.cps_lim;
1605 else if (strcmp(args[2], "sessions") == 0 && strcmp(args[3], "global") == 0)
1606 res = &global.sps_lim;
1607 #ifdef USE_OPENSSL
1608 else if (strcmp(args[2], "ssl-sessions") == 0 && strcmp(args[3], "global") == 0)
1609 res = &global.ssl_lim;
1610 #endif
1611 else if (strcmp(args[2], "http-compression") == 0 && strcmp(args[3], "global") == 0) {
1612 res = &global.comp_rate_lim;
1613 mul = 1024;
1614 }
1615 else {
1616 return cli_err(appctx,
1617 "'set rate-limit' only supports :\n"
1618 " - 'connections global' to set the per-process maximum connection rate\n"
1619 " - 'sessions global' to set the per-process maximum session rate\n"
1620 #ifdef USE_OPENSSL
1621 " - 'ssl-sessions global' to set the per-process maximum SSL session rate\n"
1622 #endif
1623 " - 'http-compression global' to set the per-process maximum compression speed in kB/s\n");
1624 }
1625
1626 if (!*args[4])
1627 return cli_err(appctx, "Expects an integer value.\n");
1628
1629 v = atoi(args[4]);
1630 if (v < 0)
1631 return cli_err(appctx, "Value out of range.\n");
1632
1633 *res = v * mul;
1634
1635 /* Dequeues all of the listeners waiting for a resource */
1636 dequeue_all_listeners();
1637
1638 return 1;
1639 }
1640
1641 /* parse the "expose-fd" argument on the bind lines */
bind_parse_expose_fd(char ** args,int cur_arg,struct proxy * px,struct bind_conf * conf,char ** err)1642 static int bind_parse_expose_fd(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1643 {
1644 if (!*args[cur_arg + 1]) {
1645 memprintf(err, "'%s' : missing fd type", args[cur_arg]);
1646 return ERR_ALERT | ERR_FATAL;
1647 }
1648 if (!strcmp(args[cur_arg+1], "listeners")) {
1649 conf->level |= ACCESS_FD_LISTENERS;
1650 } else {
1651 memprintf(err, "'%s' only supports 'listeners' (got '%s')",
1652 args[cur_arg], args[cur_arg+1]);
1653 return ERR_ALERT | ERR_FATAL;
1654 }
1655
1656 return 0;
1657 }
1658
1659 /* parse the "level" argument on the bind lines */
bind_parse_level(char ** args,int cur_arg,struct proxy * px,struct bind_conf * conf,char ** err)1660 static int bind_parse_level(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1661 {
1662 if (!*args[cur_arg + 1]) {
1663 memprintf(err, "'%s' : missing level", args[cur_arg]);
1664 return ERR_ALERT | ERR_FATAL;
1665 }
1666
1667 if (!strcmp(args[cur_arg+1], "user")) {
1668 conf->level &= ~ACCESS_LVL_MASK;
1669 conf->level |= ACCESS_LVL_USER;
1670 } else if (!strcmp(args[cur_arg+1], "operator")) {
1671 conf->level &= ~ACCESS_LVL_MASK;
1672 conf->level |= ACCESS_LVL_OPER;
1673 } else if (!strcmp(args[cur_arg+1], "admin")) {
1674 conf->level &= ~ACCESS_LVL_MASK;
1675 conf->level |= ACCESS_LVL_ADMIN;
1676 } else {
1677 memprintf(err, "'%s' only supports 'user', 'operator', and 'admin' (got '%s')",
1678 args[cur_arg], args[cur_arg+1]);
1679 return ERR_ALERT | ERR_FATAL;
1680 }
1681
1682 return 0;
1683 }
1684
bind_parse_severity_output(char ** args,int cur_arg,struct proxy * px,struct bind_conf * conf,char ** err)1685 static int bind_parse_severity_output(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
1686 {
1687 if (!*args[cur_arg + 1]) {
1688 memprintf(err, "'%s' : missing severity format", args[cur_arg]);
1689 return ERR_ALERT | ERR_FATAL;
1690 }
1691
1692 if (set_severity_output(&conf->severity_output, args[cur_arg+1]))
1693 return 0;
1694 else {
1695 memprintf(err, "'%s' only supports 'none', 'number', and 'string' (got '%s')",
1696 args[cur_arg], args[cur_arg+1]);
1697 return ERR_ALERT | ERR_FATAL;
1698 }
1699 }
1700
1701 /*
1702 * For one proxy, fill the iov and send the msghdr. Also update fd_it and offset.
1703 * Return -1 upon error, otherwise 0.
1704 *
1705 * This function is only meant to deduplicate the code between the peers and
1706 * the proxy list in _getsocks(), not to be used anywhere else.
1707 */
_getsocks_gen_send(struct proxy * px,int sendfd,int * tmpfd,struct iovec * iov,int tot_fd_nb,int * fd_it,int * offset,struct msghdr * msghdr)1708 inline static int _getsocks_gen_send(struct proxy *px, int sendfd, int *tmpfd, struct iovec *iov,
1709 int tot_fd_nb, int *fd_it, int *offset, struct msghdr *msghdr)
1710 {
1711 int i = *fd_it;
1712 int curoff = *offset;
1713 struct listener *l;
1714 unsigned char *tmpbuf = iov->iov_base;
1715
1716 list_for_each_entry(l, &px->conf.listeners, by_fe) {
1717 int ret;
1718 /* Only transfer IPv4/IPv6 sockets */
1719 if (l->state >= LI_ZOMBIE &&
1720 (l->proto->sock_family == AF_INET ||
1721 l->proto->sock_family == AF_INET6 ||
1722 l->proto->sock_family == AF_UNIX)) {
1723 memcpy(&tmpfd[i % MAX_SEND_FD], &l->fd, sizeof(l->fd));
1724 if (!l->netns)
1725 tmpbuf[curoff++] = 0;
1726 #ifdef USE_NS
1727 else {
1728 char *name = l->netns->node.key;
1729 unsigned char len = l->netns->name_len;
1730 tmpbuf[curoff++] = len;
1731 memcpy(tmpbuf + curoff, name, len);
1732 curoff += len;
1733 }
1734 #endif
1735 if (l->interface) {
1736 unsigned char len = strlen(l->interface);
1737 tmpbuf[curoff++] = len;
1738 memcpy(tmpbuf + curoff, l->interface, len);
1739 curoff += len;
1740 } else
1741 tmpbuf[curoff++] = 0;
1742 memcpy(tmpbuf + curoff, &l->options,
1743 sizeof(l->options));
1744 curoff += sizeof(l->options);
1745
1746 i++;
1747 } else
1748 continue;
1749 /* if it reaches the max number of fd per msghdr */
1750 if ((!(i % MAX_SEND_FD))) {
1751 iov->iov_len = curoff;
1752 if (sendmsg(sendfd, msghdr, 0) != curoff) {
1753 ha_warning("Failed to transfer sockets\n");
1754 return -1;
1755 }
1756 /* Wait for an ack */
1757 do {
1758 ret = recv(sendfd, &tot_fd_nb,
1759 sizeof(tot_fd_nb), 0);
1760 } while (ret == -1 && errno == EINTR);
1761 if (ret <= 0) {
1762 ha_warning("Unexpected error while transferring sockets\n");
1763 return -1;
1764 }
1765 curoff = 0;
1766 }
1767 }
1768
1769 *fd_it = i;
1770 *offset = curoff;
1771
1772 return 0;
1773 }
1774
1775
1776 /* Send all the bound sockets, always returns 1 */
_getsocks(char ** args,char * payload,struct appctx * appctx,void * private)1777 static int _getsocks(char **args, char *payload, struct appctx *appctx, void *private)
1778 {
1779 char *cmsgbuf = NULL;
1780 unsigned char *tmpbuf = NULL;
1781 struct cmsghdr *cmsg;
1782 struct stream_interface *si = appctx->owner;
1783 struct stream *s = si_strm(si);
1784 struct connection *remote = cs_conn(objt_cs(si_opposite(si)->end));
1785 struct msghdr msghdr;
1786 struct iovec iov;
1787 struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
1788 int *tmpfd;
1789 int tot_fd_nb = 0;
1790 struct proxy *px;
1791 struct peers *prs;
1792 int i = 0;
1793 int fd = -1;
1794 int curoff = 0;
1795 int old_fcntl = -1;
1796 int ret;
1797
1798 if (!remote) {
1799 ha_warning("Only works on real connections\n");
1800 goto out;
1801 }
1802
1803 fd = remote->handle.fd;
1804
1805 /* Temporary set the FD in blocking mode, that will make our life easier */
1806 old_fcntl = fcntl(fd, F_GETFL);
1807 if (old_fcntl < 0) {
1808 ha_warning("Couldn't get the flags for the unix socket\n");
1809 goto out;
1810 }
1811 cmsgbuf = malloc(CMSG_SPACE(sizeof(int) * MAX_SEND_FD));
1812 if (!cmsgbuf) {
1813 ha_warning("Failed to allocate memory to send sockets\n");
1814 goto out;
1815 }
1816 if (fcntl(fd, F_SETFL, old_fcntl &~ O_NONBLOCK) == -1) {
1817 ha_warning("Cannot make the unix socket blocking\n");
1818 goto out;
1819 }
1820 setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv));
1821 iov.iov_base = &tot_fd_nb;
1822 iov.iov_len = sizeof(tot_fd_nb);
1823 if (!(strm_li(s)->bind_conf->level & ACCESS_FD_LISTENERS))
1824 goto out;
1825 memset(&msghdr, 0, sizeof(msghdr));
1826 /*
1827 * First, calculates the total number of FD, so that we can let
1828 * the caller know how much he should expects.
1829 */
1830 px = proxies_list;
1831 while (px) {
1832 struct listener *l;
1833
1834 list_for_each_entry(l, &px->conf.listeners, by_fe) {
1835 /* Only transfer IPv4/IPv6/UNIX sockets */
1836 if (l->state >= LI_ZOMBIE &&
1837 (l->proto->sock_family == AF_INET ||
1838 l->proto->sock_family == AF_INET6 ||
1839 l->proto->sock_family == AF_UNIX))
1840 tot_fd_nb++;
1841 }
1842 px = px->next;
1843 }
1844 prs = cfg_peers;
1845 while (prs) {
1846 if (prs->peers_fe) {
1847 struct listener *l;
1848
1849 list_for_each_entry(l, &prs->peers_fe->conf.listeners, by_fe) {
1850 /* Only transfer IPv4/IPv6/UNIX sockets */
1851 if (l->state >= LI_ZOMBIE &&
1852 (l->proto->sock_family == AF_INET ||
1853 l->proto->sock_family == AF_INET6 ||
1854 l->proto->sock_family == AF_UNIX))
1855 tot_fd_nb++;
1856 }
1857 }
1858 prs = prs->next;
1859 }
1860 if (tot_fd_nb == 0)
1861 goto out;
1862
1863 /* First send the total number of file descriptors, so that the
1864 * receiving end knows what to expect.
1865 */
1866 msghdr.msg_iov = &iov;
1867 msghdr.msg_iovlen = 1;
1868 ret = sendmsg(fd, &msghdr, 0);
1869 if (ret != sizeof(tot_fd_nb)) {
1870 ha_warning("Failed to send the number of sockets to send\n");
1871 goto out;
1872 }
1873
1874 /* Now send the fds */
1875 msghdr.msg_control = cmsgbuf;
1876 msghdr.msg_controllen = CMSG_SPACE(sizeof(int) * MAX_SEND_FD);
1877 cmsg = CMSG_FIRSTHDR(&msghdr);
1878 cmsg->cmsg_len = CMSG_LEN(MAX_SEND_FD * sizeof(int));
1879 cmsg->cmsg_level = SOL_SOCKET;
1880 cmsg->cmsg_type = SCM_RIGHTS;
1881 tmpfd = (int *)CMSG_DATA(cmsg);
1882
1883 /* For each socket, e message is sent, containing the following :
1884 * Size of the namespace name (or 0 if none), as an unsigned char.
1885 * The namespace name, if any
1886 * Size of the interface name (or 0 if none), as an unsigned char
1887 * The interface name, if any
1888 * Listener options, as an int.
1889 */
1890 /* We will send sockets MAX_SEND_FD per MAX_SEND_FD, allocate a
1891 * buffer big enough to store the socket information.
1892 */
1893 tmpbuf = malloc(MAX_SEND_FD * (1 + MAXPATHLEN + 1 + IFNAMSIZ + sizeof(int)));
1894 if (tmpbuf == NULL) {
1895 ha_warning("Failed to allocate memory to transfer socket information\n");
1896 goto out;
1897 }
1898 iov.iov_base = tmpbuf;
1899 px = proxies_list;
1900 while (px) {
1901 if (_getsocks_gen_send(px, fd, tmpfd, &iov,
1902 tot_fd_nb, &i, &curoff, &msghdr) < 0)
1903 goto out;
1904 px = px->next;
1905 }
1906 /* should be done for peers too */
1907 prs = cfg_peers;
1908 while (prs) {
1909 if (prs->peers_fe)
1910 if (_getsocks_gen_send(prs->peers_fe, fd, tmpfd, &iov,
1911 tot_fd_nb, &i, &curoff, &msghdr) < 0)
1912 goto out;
1913 prs = prs->next;
1914 }
1915
1916 if (i % MAX_SEND_FD) {
1917 iov.iov_len = curoff;
1918 cmsg->cmsg_len = CMSG_LEN((i % MAX_SEND_FD) * sizeof(int));
1919 msghdr.msg_controllen = CMSG_SPACE(sizeof(int) * (i % MAX_SEND_FD));
1920 if (sendmsg(fd, &msghdr, 0) != curoff) {
1921 ha_warning("Failed to transfer sockets\n");
1922 goto out;
1923 }
1924 }
1925
1926 out:
1927 if (fd >= 0 && old_fcntl >= 0 && fcntl(fd, F_SETFL, old_fcntl) == -1) {
1928 ha_warning("Cannot make the unix socket non-blocking\n");
1929 goto out;
1930 }
1931 appctx->st0 = CLI_ST_END;
1932 free(cmsgbuf);
1933 free(tmpbuf);
1934 return 1;
1935 }
1936
cli_parse_simple(char ** args,char * payload,struct appctx * appctx,void * private)1937 static int cli_parse_simple(char **args, char *payload, struct appctx *appctx, void *private)
1938 {
1939 if (*args[0] == 'h')
1940 /* help */
1941 cli_gen_usage_msg(appctx);
1942 else if (*args[0] == 'p')
1943 /* prompt */
1944 appctx->st1 ^= APPCTX_CLI_ST1_PROMPT;
1945 else if (*args[0] == 'q')
1946 /* quit */
1947 appctx->st0 = CLI_ST_END;
1948
1949 return 1;
1950 }
1951
pcli_write_prompt(struct stream * s)1952 void pcli_write_prompt(struct stream *s)
1953 {
1954 struct buffer *msg = get_trash_chunk();
1955 struct channel *oc = si_oc(&s->si[0]);
1956
1957 if (!(s->pcli_flags & PCLI_F_PROMPT))
1958 return;
1959
1960 if (s->pcli_flags & PCLI_F_PAYLOAD) {
1961 chunk_appendf(msg, "+ ");
1962 } else {
1963 if (s->pcli_next_pid == 0)
1964 chunk_appendf(msg, "master%s> ",
1965 (global.mode & MODE_MWORKER_WAIT) ? "[ReloadFailed]" : "");
1966 else
1967 chunk_appendf(msg, "%d> ", s->pcli_next_pid);
1968 }
1969 co_inject(oc, msg->area, msg->data);
1970 }
1971
1972
1973 /* The pcli_* functions are used for the CLI proxy in the master */
1974
pcli_reply_and_close(struct stream * s,const char * msg)1975 void pcli_reply_and_close(struct stream *s, const char *msg)
1976 {
1977 struct buffer *buf = get_trash_chunk();
1978
1979 chunk_initstr(buf, msg);
1980 si_retnclose(&s->si[0], buf);
1981 }
1982
pcli_pid_to_server(int proc_pid)1983 static enum obj_type *pcli_pid_to_server(int proc_pid)
1984 {
1985 struct mworker_proc *child;
1986
1987 /* return the CLI applet of the master */
1988 if (proc_pid == 0)
1989 return &cli_applet.obj_type;
1990
1991 list_for_each_entry(child, &proc_list, list) {
1992 if (child->pid == proc_pid){
1993 return &child->srv->obj_type;
1994 }
1995 }
1996 return NULL;
1997 }
1998
1999 /* Take a CLI prefix in argument (eg: @!1234 @master @1)
2000 * Return:
2001 * 0: master
2002 * > 0: pid of a worker
2003 * < 0: didn't find a worker
2004 */
pcli_prefix_to_pid(const char * prefix)2005 static int pcli_prefix_to_pid(const char *prefix)
2006 {
2007 int proc_pid;
2008 struct mworker_proc *child;
2009 char *errtol = NULL;
2010
2011 if (*prefix != '@') /* not a prefix, should not happen */
2012 return -1;
2013
2014 prefix++;
2015 if (!*prefix) /* sent @ alone, return the master */
2016 return 0;
2017
2018 if (strcmp("master", prefix) == 0) {
2019 return 0;
2020 } else if (*prefix == '!') {
2021 prefix++;
2022 if (!*prefix)
2023 return -1;
2024
2025 proc_pid = strtol(prefix, &errtol, 10);
2026 if (*errtol != '\0')
2027 return -1;
2028 list_for_each_entry(child, &proc_list, list) {
2029 if (!(child->options & PROC_O_TYPE_WORKER))
2030 continue;
2031 if (child->pid == proc_pid){
2032 return child->pid;
2033 }
2034 }
2035 } else {
2036 struct mworker_proc *chosen = NULL;
2037 /* this is a relative pid */
2038
2039 proc_pid = strtol(prefix, &errtol, 10);
2040 if (*errtol != '\0')
2041 return -1;
2042
2043 if (proc_pid == 0) /* return the master */
2044 return 0;
2045
2046 /* chose the right process, the current one is the one with the
2047 least number of reloads */
2048 list_for_each_entry(child, &proc_list, list) {
2049 if (!(child->options & PROC_O_TYPE_WORKER))
2050 continue;
2051 if (child->relative_pid == proc_pid){
2052 if (child->reloads == 0)
2053 return child->pid;
2054 else if (chosen == NULL || child->reloads < chosen->reloads)
2055 chosen = child;
2056 }
2057 }
2058 if (chosen)
2059 return chosen->pid;
2060 }
2061 return -1;
2062 }
2063
2064 /* Return::
2065 * >= 0 : number of words to escape
2066 * = -1 : error
2067 */
2068
pcli_find_and_exec_kw(struct stream * s,char ** args,int argl,char ** errmsg,int * next_pid)2069 int pcli_find_and_exec_kw(struct stream *s, char **args, int argl, char **errmsg, int *next_pid)
2070 {
2071 if (argl < 1)
2072 return 0;
2073
2074 /* there is a prefix */
2075 if (args[0][0] == '@') {
2076 int target_pid = pcli_prefix_to_pid(args[0]);
2077
2078 if (target_pid == -1) {
2079 memprintf(errmsg, "Can't find the target PID matching the prefix '%s'\n", args[0]);
2080 return -1;
2081 }
2082
2083 /* if the prefix is alone, define a default target */
2084 if (argl == 1)
2085 s->pcli_next_pid = target_pid;
2086 else
2087 *next_pid = target_pid;
2088 return 1;
2089 } else if (!strcmp("prompt", args[0])) {
2090 s->pcli_flags ^= PCLI_F_PROMPT;
2091 return argl; /* return the number of elements in the array */
2092
2093 } else if (!strcmp("quit", args[0])) {
2094 channel_shutr_now(&s->req);
2095 channel_shutw_now(&s->res);
2096 return argl; /* return the number of elements in the array */
2097 } else if (!strcmp(args[0], "operator")) {
2098 if (!pcli_has_level(s, ACCESS_LVL_OPER)) {
2099 memprintf(errmsg, "Permission denied!\n");
2100 return -1;
2101 }
2102 s->pcli_flags &= ~ACCESS_LVL_MASK;
2103 s->pcli_flags |= ACCESS_LVL_OPER;
2104 return argl;
2105
2106 } else if (!strcmp(args[0], "user")) {
2107 if (!pcli_has_level(s, ACCESS_LVL_USER)) {
2108 memprintf(errmsg, "Permission denied!\n");
2109 return -1;
2110 }
2111 s->pcli_flags &= ~ACCESS_LVL_MASK;
2112 s->pcli_flags |= ACCESS_LVL_USER;
2113 return argl;
2114 }
2115
2116 return 0;
2117 }
2118
2119 /*
2120 * Parse the CLI request:
2121 * - It does basically the same as the cli_io_handler, but as a proxy
2122 * - It can exec a command and strip non forwardable commands
2123 *
2124 * Return:
2125 * - the number of characters to forward or
2126 * - 1 if there is an error or not enough data
2127 */
pcli_parse_request(struct stream * s,struct channel * req,char ** errmsg,int * next_pid)2128 int pcli_parse_request(struct stream *s, struct channel *req, char **errmsg, int *next_pid)
2129 {
2130 char *str = (char *)ci_head(req);
2131 char *end = (char *)ci_stop(req);
2132 char *args[MAX_STATS_ARGS + 1]; /* +1 for storing a NULL */
2133 int argl; /* number of args */
2134 char *p;
2135 char *trim = NULL;
2136 char *payload = NULL;
2137 int wtrim = 0; /* number of words to trim */
2138 int reql = 0;
2139 int ret;
2140 int i = 0;
2141
2142 p = str;
2143
2144 if (!(s->pcli_flags & PCLI_F_PAYLOAD)) {
2145
2146 /* Looks for the end of one command */
2147 while (p+reql < end) {
2148 /* handle escaping */
2149 if (p[reql] == '\\') {
2150 reql+=2;
2151 continue;
2152 }
2153 if (p[reql] == ';' || p[reql] == '\n') {
2154 /* found the end of the command */
2155 p[reql] = '\n';
2156 reql++;
2157 break;
2158 }
2159 reql++;
2160 }
2161 } else {
2162 while (p+reql < end) {
2163 if (p[reql] == '\n') {
2164 /* found the end of the line */
2165 reql++;
2166 break;
2167 }
2168 reql++;
2169 }
2170 }
2171
2172 /* set end to first byte after the end of the command */
2173 end = p + reql;
2174
2175 /* there is no end to this command, need more to parse ! */
2176 if (*(end-1) != '\n') {
2177 return -1;
2178 }
2179
2180 if (s->pcli_flags & PCLI_F_PAYLOAD) {
2181 if (reql == 1) /* last line of the payload */
2182 s->pcli_flags &= ~PCLI_F_PAYLOAD;
2183 return reql;
2184 }
2185
2186 *(end-1) = '\0';
2187
2188 /* splits the command in words */
2189 while (i < MAX_STATS_ARGS && p < end) {
2190 /* skip leading spaces/tabs */
2191 p += strspn(p, " \t");
2192 if (!*p)
2193 break;
2194
2195 args[i] = p;
2196 while (1) {
2197 p += strcspn(p, " \t\\");
2198 /* escaped chars using backlashes (\) */
2199 if (*p == '\\') {
2200 if (!*++p)
2201 break;
2202 if (!*++p)
2203 break;
2204 } else {
2205 break;
2206 }
2207 }
2208 *p++ = 0;
2209 i++;
2210 }
2211
2212 argl = i;
2213
2214 for (; i < MAX_STATS_ARGS + 1; i++)
2215 args[i] = NULL;
2216
2217 wtrim = pcli_find_and_exec_kw(s, args, argl, errmsg, next_pid);
2218
2219 /* End of words are ending by \0, we need to replace the \0s by spaces
2220 1 before forwarding them */
2221 p = str;
2222 while (p < end-1) {
2223 if (*p == '\0')
2224 *p = ' ';
2225 p++;
2226 }
2227
2228 payload = strstr(str, PAYLOAD_PATTERN);
2229 if ((end - 1) == (payload + strlen(PAYLOAD_PATTERN))) {
2230 /* if the payload pattern is at the end */
2231 s->pcli_flags |= PCLI_F_PAYLOAD;
2232 ret = reql;
2233 }
2234
2235 *(end-1) = '\n';
2236
2237 if (wtrim > 0) {
2238 trim = &args[wtrim][0];
2239 if (trim == NULL) /* if this was the last word in the table */
2240 trim = end;
2241
2242 b_del(&req->buf, trim - str);
2243
2244 ret = end - trim;
2245 } else if (wtrim < 0) {
2246 /* parsing error */
2247 return -1;
2248 } else {
2249 /* the whole string */
2250 ret = end - str;
2251 }
2252
2253 if (ret > 1) {
2254 if (pcli_has_level(s, ACCESS_LVL_ADMIN)) {
2255 goto end;
2256 } else if (pcli_has_level(s, ACCESS_LVL_OPER)) {
2257 ci_insert_line2(req, 0, "operator -", strlen("operator -"));
2258 ret += strlen("operator -") + 2;
2259 } else if (pcli_has_level(s, ACCESS_LVL_USER)) {
2260 ci_insert_line2(req, 0, "user -", strlen("user -"));
2261 ret += strlen("user -") + 2;
2262 }
2263 }
2264 end:
2265
2266 return ret;
2267 }
2268
pcli_wait_for_request(struct stream * s,struct channel * req,int an_bit)2269 int pcli_wait_for_request(struct stream *s, struct channel *req, int an_bit)
2270 {
2271 int next_pid = -1;
2272 int to_forward;
2273 char *errmsg = NULL;
2274
2275 if ((s->pcli_flags & ACCESS_LVL_MASK) == ACCESS_LVL_NONE)
2276 s->pcli_flags |= strm_li(s)->bind_conf->level & ACCESS_LVL_MASK;
2277
2278 read_again:
2279 /* if the channel is closed for read, we won't receive any more data
2280 from the client, but we don't want to forward this close to the
2281 server */
2282 channel_dont_close(req);
2283
2284 /* We don't know yet to which server we will connect */
2285 channel_dont_connect(req);
2286
2287
2288 /* we are not waiting for a response, there is no more request and we
2289 * receive a close from the client, we can leave */
2290 if (!(ci_data(req)) && req->flags & CF_SHUTR) {
2291 channel_shutw_now(&s->res);
2292 s->req.analysers &= ~AN_REQ_WAIT_CLI;
2293 return 1;
2294 }
2295
2296 req->flags |= CF_READ_DONTWAIT;
2297
2298 /* need more data */
2299 if (!ci_data(req))
2300 return 0;
2301
2302 /* If there is data available for analysis, log the end of the idle time. */
2303 if (c_data(req) && s->logs.t_idle == -1)
2304 s->logs.t_idle = tv_ms_elapsed(&s->logs.tv_accept, &now) - s->logs.t_handshake;
2305
2306 to_forward = pcli_parse_request(s, req, &errmsg, &next_pid);
2307 if (to_forward > 0) {
2308 int target_pid;
2309 /* enough data */
2310
2311 /* forward only 1 command */
2312 channel_forward(req, to_forward);
2313
2314 if (!(s->pcli_flags & PCLI_F_PAYLOAD)) {
2315 /* we send only 1 command per request, and we write close after it */
2316 channel_shutw_now(req);
2317 } else {
2318 pcli_write_prompt(s);
2319 }
2320
2321 s->res.flags |= CF_WAKE_ONCE; /* need to be called again */
2322
2323 /* remove the XFER_DATA analysers, which forwards all
2324 * the data, we don't want to forward the next requests
2325 * We need to add CF_FLT_ANALYZE to abort the forward too.
2326 */
2327 req->analysers &= ~(AN_REQ_FLT_XFER_DATA|AN_REQ_WAIT_CLI);
2328 req->analysers |= AN_REQ_FLT_END|CF_FLT_ANALYZE;
2329 s->res.analysers |= AN_RES_WAIT_CLI;
2330
2331 if (!(s->flags & SF_ASSIGNED)) {
2332 if (next_pid > -1)
2333 target_pid = next_pid;
2334 else
2335 target_pid = s->pcli_next_pid;
2336 /* we can connect now */
2337 s->target = pcli_pid_to_server(target_pid);
2338
2339 s->flags |= (SF_DIRECT | SF_ASSIGNED);
2340 channel_auto_connect(req);
2341 }
2342
2343 } else if (to_forward == 0) {
2344 /* we trimmed things but we might have other commands to consume */
2345 pcli_write_prompt(s);
2346 goto read_again;
2347 } else if (to_forward == -1 && errmsg) {
2348 /* there was an error during the parsing */
2349 pcli_reply_and_close(s, errmsg);
2350 return 0;
2351 } else if (to_forward == -1 && channel_full(req, global.tune.maxrewrite)) {
2352 /* buffer is full and we didn't catch the end of a command */
2353 goto send_help;
2354 }
2355
2356 return 0;
2357
2358 send_help:
2359 b_reset(&req->buf);
2360 b_putblk(&req->buf, "help\n", 5);
2361 goto read_again;
2362 }
2363
pcli_wait_for_response(struct stream * s,struct channel * rep,int an_bit)2364 int pcli_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
2365 {
2366 struct proxy *fe = strm_fe(s);
2367 struct proxy *be = s->be;
2368
2369 if (rep->flags & CF_READ_ERROR) {
2370 pcli_reply_and_close(s, "Can't connect to the target CLI!\n");
2371 s->res.analysers &= ~AN_RES_WAIT_CLI;
2372 return 0;
2373 }
2374 rep->flags |= CF_READ_DONTWAIT; /* try to get back here ASAP */
2375 rep->flags |= CF_NEVER_WAIT;
2376
2377 /* don't forward the close */
2378 channel_dont_close(&s->res);
2379 channel_dont_close(&s->req);
2380
2381 if (s->pcli_flags & PCLI_F_PAYLOAD) {
2382 s->req.analysers |= AN_REQ_WAIT_CLI;
2383 s->res.analysers &= ~AN_RES_WAIT_CLI;
2384 s->req.flags |= CF_WAKE_ONCE; /* need to be called again if there is some command left in the request */
2385 return 0;
2386 }
2387
2388 /* forward the data */
2389 if (ci_data(rep)) {
2390 c_adv(rep, ci_data(rep));
2391 return 0;
2392 }
2393
2394 if ((rep->flags & (CF_SHUTR|CF_READ_NULL))) {
2395 /* stream cleanup */
2396
2397 pcli_write_prompt(s);
2398
2399 s->si[1].flags |= SI_FL_NOLINGER | SI_FL_NOHALF;
2400 si_shutr(&s->si[1]);
2401 si_shutw(&s->si[1]);
2402
2403 /*
2404 * starting from there this the same code as
2405 * http_end_txn_clean_session().
2406 *
2407 * It allows to do frontend keepalive while reconnecting to a
2408 * new server for each request.
2409 */
2410
2411 if (s->flags & SF_BE_ASSIGNED) {
2412 HA_ATOMIC_SUB(&be->beconn, 1);
2413 if (unlikely(s->srv_conn))
2414 sess_change_server(s, NULL);
2415 }
2416
2417 s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
2418 stream_process_counters(s);
2419
2420 /* don't count other requests' data */
2421 s->logs.bytes_in -= ci_data(&s->req);
2422 s->logs.bytes_out -= ci_data(&s->res);
2423
2424 /* we may need to know the position in the queue */
2425 pendconn_free(s);
2426
2427 /* let's do a final log if we need it */
2428 if (!LIST_ISEMPTY(&fe->logformat) && s->logs.logwait &&
2429 !(s->flags & SF_MONITOR) &&
2430 (!(fe->options & PR_O_NULLNOLOG) || s->req.total)) {
2431 s->do_log(s);
2432 }
2433
2434 /* stop tracking content-based counters */
2435 stream_stop_content_counters(s);
2436 stream_update_time_stats(s);
2437
2438 s->logs.accept_date = date; /* user-visible date for logging */
2439 s->logs.tv_accept = now; /* corrected date for internal use */
2440 s->logs.t_handshake = 0; /* There are no handshake in keep alive connection. */
2441 s->logs.t_idle = -1;
2442 tv_zero(&s->logs.tv_request);
2443 s->logs.t_queue = -1;
2444 s->logs.t_connect = -1;
2445 s->logs.t_data = -1;
2446 s->logs.t_close = 0;
2447 s->logs.prx_queue_pos = 0; /* we get the number of pending conns before us */
2448 s->logs.srv_queue_pos = 0; /* we will get this number soon */
2449
2450 s->logs.bytes_in = s->req.total = ci_data(&s->req);
2451 s->logs.bytes_out = s->res.total = ci_data(&s->res);
2452
2453 stream_del_srv_conn(s);
2454 if (objt_server(s->target)) {
2455 if (s->flags & SF_CURR_SESS) {
2456 s->flags &= ~SF_CURR_SESS;
2457 HA_ATOMIC_SUB(&__objt_server(s->target)->cur_sess, 1);
2458 }
2459 if (may_dequeue_tasks(__objt_server(s->target), be))
2460 process_srv_queue(__objt_server(s->target), 0);
2461 }
2462
2463 s->target = NULL;
2464
2465 /* only release our endpoint if we don't intend to reuse the
2466 * connection.
2467 */
2468 if (!si_conn_ready(&s->si[1])) {
2469 si_release_endpoint(&s->si[1]);
2470 s->srv_conn = NULL;
2471 }
2472
2473 sockaddr_free(&s->target_addr);
2474
2475 s->si[1].state = s->si[1].prev_state = SI_ST_INI;
2476 s->si[1].err_type = SI_ET_NONE;
2477 s->si[1].conn_retries = 0; /* used for logging too */
2478 s->si[1].exp = TICK_ETERNITY;
2479 s->si[1].flags &= SI_FL_ISBACK | SI_FL_DONT_WAKE; /* we're in the context of process_stream */
2480 s->req.flags &= ~(CF_SHUTW|CF_SHUTW_NOW|CF_AUTO_CONNECT|CF_WRITE_ERROR|CF_STREAMER|CF_STREAMER_FAST|CF_NEVER_WAIT|CF_WROTE_DATA);
2481 s->res.flags &= ~(CF_SHUTR|CF_SHUTR_NOW|CF_READ_ATTACHED|CF_READ_ERROR|CF_READ_NOEXP|CF_STREAMER|CF_STREAMER_FAST|CF_WRITE_PARTIAL|CF_NEVER_WAIT|CF_WROTE_DATA|CF_READ_NULL);
2482 s->flags &= ~(SF_DIRECT|SF_ASSIGNED|SF_ADDR_SET|SF_BE_ASSIGNED|SF_FORCE_PRST|SF_IGNORE_PRST);
2483 s->flags &= ~(SF_CURR_SESS|SF_REDIRECTABLE|SF_SRV_REUSED);
2484 s->flags &= ~(SF_ERR_MASK|SF_FINST_MASK|SF_REDISP);
2485 /* reinitialise the current rule list pointer to NULL. We are sure that
2486 * any rulelist match the NULL pointer.
2487 */
2488 s->current_rule_list = NULL;
2489
2490 s->be = strm_fe(s);
2491 s->logs.logwait = strm_fe(s)->to_log;
2492 s->logs.level = 0;
2493 stream_del_srv_conn(s);
2494 s->target = NULL;
2495 /* re-init store persistence */
2496 s->store_count = 0;
2497 s->uniq_id = global.req_count++;
2498
2499 s->req.flags |= CF_READ_DONTWAIT; /* one read is usually enough */
2500
2501 s->req.flags |= CF_WAKE_ONCE; /* need to be called again if there is some command left in the request */
2502
2503 s->req.analysers |= AN_REQ_WAIT_CLI;
2504 s->res.analysers &= ~AN_RES_WAIT_CLI;
2505
2506 /* We must trim any excess data from the response buffer, because we
2507 * may have blocked an invalid response from a server that we don't
2508 * want to accidentally forward once we disable the analysers, nor do
2509 * we want those data to come along with next response. A typical
2510 * example of such data would be from a buggy server responding to
2511 * a HEAD with some data, or sending more than the advertised
2512 * content-length.
2513 */
2514 if (unlikely(ci_data(&s->res)))
2515 b_set_data(&s->res.buf, co_data(&s->res));
2516
2517 /* Now we can realign the response buffer */
2518 c_realign_if_empty(&s->res);
2519
2520 s->req.rto = strm_fe(s)->timeout.client;
2521 s->req.wto = TICK_ETERNITY;
2522
2523 s->res.rto = TICK_ETERNITY;
2524 s->res.wto = strm_fe(s)->timeout.client;
2525
2526 s->req.rex = TICK_ETERNITY;
2527 s->req.wex = TICK_ETERNITY;
2528 s->req.analyse_exp = TICK_ETERNITY;
2529 s->res.rex = TICK_ETERNITY;
2530 s->res.wex = TICK_ETERNITY;
2531 s->res.analyse_exp = TICK_ETERNITY;
2532 s->si[1].hcto = TICK_ETERNITY;
2533
2534 /* we're removing the analysers, we MUST re-enable events detection.
2535 * We don't enable close on the response channel since it's either
2536 * already closed, or in keep-alive with an idle connection handler.
2537 */
2538 channel_auto_read(&s->req);
2539 channel_auto_close(&s->req);
2540 channel_auto_read(&s->res);
2541
2542
2543 return 1;
2544 }
2545 return 0;
2546 }
2547
2548 /*
2549 * The mworker functions are used to initialize the CLI in the master process
2550 */
2551
2552 /*
2553 * Stop the mworker proxy
2554 */
mworker_cli_proxy_stop()2555 void mworker_cli_proxy_stop()
2556 {
2557 if (mworker_proxy)
2558 stop_proxy(mworker_proxy);
2559 }
2560
2561 /*
2562 * Create the mworker CLI proxy
2563 */
mworker_cli_proxy_create()2564 int mworker_cli_proxy_create()
2565 {
2566 struct mworker_proc *child;
2567 char *msg = NULL;
2568 char *errmsg = NULL;
2569
2570 mworker_proxy = calloc(1, sizeof(*mworker_proxy));
2571 if (!mworker_proxy)
2572 return -1;
2573
2574 init_new_proxy(mworker_proxy);
2575 mworker_proxy->next = proxies_list;
2576 proxies_list = mworker_proxy;
2577 mworker_proxy->id = strdup("MASTER");
2578 mworker_proxy->mode = PR_MODE_CLI;
2579 mworker_proxy->state = PR_STNEW;
2580 mworker_proxy->last_change = now.tv_sec;
2581 mworker_proxy->cap = PR_CAP_LISTEN; /* this is a listen section */
2582 mworker_proxy->maxconn = 10; /* default to 10 concurrent connections */
2583 mworker_proxy->timeout.client = 0; /* no timeout */
2584 mworker_proxy->conf.file = strdup("MASTER");
2585 mworker_proxy->conf.line = 0;
2586 mworker_proxy->accept = frontend_accept;
2587 mworker_proxy-> lbprm.algo = BE_LB_ALGO_NONE;
2588
2589 /* Does not init the default target the CLI applet, but must be done in
2590 * the request parsing code */
2591 mworker_proxy->default_target = NULL;
2592
2593 /* the check_config_validity() will get an ID for the proxy */
2594 mworker_proxy->uuid = -1;
2595
2596 proxy_store_name(mworker_proxy);
2597
2598 /* create all servers using the mworker_proc list */
2599 list_for_each_entry(child, &proc_list, list) {
2600 struct server *newsrv = NULL;
2601 struct sockaddr_storage *sk;
2602 int port1, port2, port;
2603 struct protocol *proto;
2604
2605 /* only the workers support the master CLI */
2606 if (!(child->options & PROC_O_TYPE_WORKER))
2607 continue;
2608
2609 newsrv = new_server(mworker_proxy);
2610 if (!newsrv)
2611 goto error;
2612
2613 /* we don't know the new pid yet */
2614 if (child->pid == -1)
2615 memprintf(&msg, "cur-%d", child->relative_pid);
2616 else
2617 memprintf(&msg, "old-%d", child->pid);
2618
2619 newsrv->next = mworker_proxy->srv;
2620 mworker_proxy->srv = newsrv;
2621 newsrv->conf.file = strdup(msg);
2622 newsrv->id = strdup(msg);
2623 newsrv->conf.line = 0;
2624
2625 memprintf(&msg, "sockpair@%d", child->ipc_fd[0]);
2626 if ((sk = str2sa_range(msg, &port, &port1, &port2, &errmsg, NULL, NULL, 0)) == 0) {
2627 goto error;
2628 }
2629 free(msg);
2630 msg = NULL;
2631
2632 proto = protocol_by_family(sk->ss_family);
2633 if (!proto || !proto->connect) {
2634 goto error;
2635 }
2636
2637 /* no port specified */
2638 newsrv->flags |= SRV_F_MAPPORTS;
2639 newsrv->addr = *sk;
2640 /* don't let the server participate to load balancing */
2641 newsrv->iweight = 0;
2642 newsrv->uweight = 0;
2643 srv_lb_commit_status(newsrv);
2644
2645 child->srv = newsrv;
2646 }
2647 return 0;
2648
2649 error:
2650 ha_alert("%s\n", errmsg);
2651
2652 list_for_each_entry(child, &proc_list, list) {
2653 free((char *)child->srv->conf.file); /* cast because of const char * */
2654 free(child->srv->id);
2655 free(child->srv);
2656 child->srv = NULL;
2657 }
2658 free(mworker_proxy->id);
2659 free(mworker_proxy->conf.file);
2660 free(mworker_proxy);
2661 mworker_proxy = NULL;
2662 free(errmsg);
2663 free(msg);
2664
2665 return -1;
2666 }
2667
2668 /*
2669 * Create a new listener for the master CLI proxy
2670 */
mworker_cli_proxy_new_listener(char * line)2671 int mworker_cli_proxy_new_listener(char *line)
2672 {
2673 struct bind_conf *bind_conf;
2674 struct listener *l;
2675 char *err = NULL;
2676 char *args[MAX_LINE_ARGS + 1];
2677 int arg;
2678 int cur_arg;
2679
2680 arg = 1;
2681 args[0] = line;
2682
2683 /* args is a bind configuration with spaces replaced by commas */
2684 while (*line && arg < MAX_LINE_ARGS) {
2685
2686 if (*line == ',') {
2687 *line++ = '\0';
2688 while (*line == ',')
2689 line++;
2690 args[arg++] = line;
2691 }
2692 line++;
2693 }
2694
2695 args[arg] = "\0";
2696
2697 bind_conf = bind_conf_alloc(mworker_proxy, "master-socket", 0, "", xprt_get(XPRT_RAW));
2698 if (!bind_conf)
2699 goto err;
2700
2701 bind_conf->level &= ~ACCESS_LVL_MASK;
2702 bind_conf->level |= ACCESS_LVL_ADMIN;
2703
2704 if (!str2listener(args[0], mworker_proxy, bind_conf, "master-socket", 0, &err)) {
2705 ha_alert("Cannot create the listener of the master CLI\n");
2706 goto err;
2707 }
2708
2709 cur_arg = 1;
2710
2711 while (*args[cur_arg]) {
2712 static int bind_dumped;
2713 struct bind_kw *kw;
2714
2715 kw = bind_find_kw(args[cur_arg]);
2716 if (kw) {
2717 if (!kw->parse) {
2718 memprintf(&err, "'%s %s' : '%s' option is not implemented in this version (check build options).",
2719 args[0], args[1], args[cur_arg]);
2720 goto err;
2721 }
2722
2723 if (kw->parse(args, cur_arg, global.stats_fe, bind_conf, &err) != 0) {
2724 if (err)
2725 memprintf(&err, "'%s %s' : '%s'", args[0], args[1], err);
2726 else
2727 memprintf(&err, "'%s %s' : error encountered while processing '%s'",
2728 args[0], args[1], args[cur_arg]);
2729 goto err;
2730 }
2731
2732 cur_arg += 1 + kw->skip;
2733 continue;
2734 }
2735
2736 if (!bind_dumped) {
2737 bind_dump_kws(&err);
2738 indent_msg(&err, 4);
2739 bind_dumped = 1;
2740 }
2741
2742 memprintf(&err, "'%s %s' : unknown keyword '%s'.%s%s",
2743 args[0], args[1], args[cur_arg],
2744 err ? " Registered keywords :" : "", err ? err : "");
2745 goto err;
2746 }
2747
2748
2749 list_for_each_entry(l, &bind_conf->listeners, by_bind) {
2750 l->accept = session_accept_fd;
2751 l->default_target = mworker_proxy->default_target;
2752 /* don't make the peers subject to global limits and don't close it in the master */
2753 l->options |= (LI_O_UNLIMITED|LI_O_MWORKER); /* we are keeping this FD in the master */
2754 l->nice = -64; /* we want to boost priority for local stats */
2755 global.maxsock++; /* for the listening socket */
2756 }
2757 global.maxsock += mworker_proxy->maxconn;
2758
2759 return 0;
2760
2761 err:
2762 ha_alert("%s\n", err);
2763 free(err);
2764 free(bind_conf);
2765 return -1;
2766
2767 }
2768
2769 /*
2770 * Create a new CLI socket using a socketpair for a worker process
2771 * <mworker_proc> is the process structure, and <proc> is the process number
2772 */
mworker_cli_sockpair_new(struct mworker_proc * mworker_proc,int proc)2773 int mworker_cli_sockpair_new(struct mworker_proc *mworker_proc, int proc)
2774 {
2775 struct bind_conf *bind_conf;
2776 struct listener *l;
2777 char *path = NULL;
2778 char *err = NULL;
2779
2780 /* master pipe to ensure the master is still alive */
2781 if (socketpair(AF_UNIX, SOCK_STREAM, 0, mworker_proc->ipc_fd) < 0) {
2782 ha_alert("Cannot create worker socketpair.\n");
2783 return -1;
2784 }
2785
2786 /* XXX: we might want to use a separate frontend at some point */
2787 if (!global.stats_fe) {
2788 if ((global.stats_fe = alloc_stats_fe("GLOBAL", "master-socket", 0)) == NULL) {
2789 ha_alert("out of memory trying to allocate the stats frontend");
2790 goto error;
2791 }
2792 }
2793
2794 bind_conf = bind_conf_alloc(global.stats_fe, "master-socket", 0, "", xprt_get(XPRT_RAW));
2795 if (!bind_conf)
2796 goto error;
2797
2798 bind_conf->level &= ~ACCESS_LVL_MASK;
2799 bind_conf->level |= ACCESS_LVL_ADMIN; /* TODO: need to lower the rights with a CLI keyword*/
2800
2801 bind_conf->bind_proc = 1UL << proc;
2802 global.stats_fe->bind_proc = 0; /* XXX: we should be careful with that, it can be removed by configuration */
2803
2804 if (!memprintf(&path, "sockpair@%d", mworker_proc->ipc_fd[1])) {
2805 ha_alert("Cannot allocate listener.\n");
2806 goto error;
2807 }
2808
2809 if (!str2listener(path, global.stats_fe, bind_conf, "master-socket", 0, &err)) {
2810 free(path);
2811 ha_alert("Cannot create a CLI sockpair listener for process #%d\n", proc);
2812 goto error;
2813 }
2814 free(path);
2815 path = NULL;
2816
2817 list_for_each_entry(l, &bind_conf->listeners, by_bind) {
2818 l->accept = session_accept_fd;
2819 l->default_target = global.stats_fe->default_target;
2820 l->options |= (LI_O_UNLIMITED | LI_O_NOSTOP);
2821 /* it's a sockpair but we don't want to keep the fd in the master */
2822 l->options &= ~LI_O_INHERITED;
2823 l->nice = -64; /* we want to boost priority for local stats */
2824 global.maxsock++; /* for the listening socket */
2825 }
2826
2827 return 0;
2828
2829 error:
2830 close(mworker_proc->ipc_fd[0]);
2831 close(mworker_proc->ipc_fd[1]);
2832 free(err);
2833
2834 return -1;
2835 }
2836
2837 static struct applet cli_applet = {
2838 .obj_type = OBJ_TYPE_APPLET,
2839 .name = "<CLI>", /* used for logging */
2840 .fct = cli_io_handler,
2841 .release = cli_release_handler,
2842 };
2843
2844 /* register cli keywords */
2845 static struct cli_kw_list cli_kws = {{ },{
2846 { { "help", NULL }, NULL, cli_parse_simple, NULL },
2847 { { "prompt", NULL }, NULL, cli_parse_simple, NULL },
2848 { { "quit", NULL }, NULL, cli_parse_simple, NULL },
2849 { { "set", "maxconn", "global", NULL }, "set maxconn global : change the per-process maxconn setting", cli_parse_set_maxconn_global, NULL },
2850 { { "set", "rate-limit", NULL }, "set rate-limit : change a rate limiting value", cli_parse_set_ratelimit, NULL },
2851 { { "set", "severity-output", NULL }, "set severity-output [none|number|string] : set presence of severity level in feedback information", cli_parse_set_severity_output, NULL, NULL },
2852 { { "set", "timeout", NULL }, "set timeout : change a timeout setting", cli_parse_set_timeout, NULL, NULL },
2853 { { "show", "env", NULL }, "show env [var] : dump environment variables known to the process", cli_parse_show_env, cli_io_handler_show_env, NULL },
2854 { { "show", "cli", "sockets", NULL }, "show cli sockets : dump list of cli sockets", cli_parse_default, cli_io_handler_show_cli_sock, NULL, NULL, ACCESS_MASTER },
2855 { { "show", "cli", "level", NULL }, "show cli level : display the level of the current CLI session", cli_parse_show_lvl, NULL, NULL, NULL, ACCESS_MASTER},
2856 { { "show", "fd", NULL }, "show fd [num] : dump list of file descriptors in use", cli_parse_show_fd, cli_io_handler_show_fd, NULL },
2857 { { "show", "activity", NULL }, "show activity : show per-thread activity stats (for support/developers)", cli_parse_default, cli_io_handler_show_activity, NULL },
2858 { { "operator", NULL }, "operator : lower the level of the current CLI session to operator", cli_parse_set_lvl, NULL, NULL, NULL, ACCESS_MASTER},
2859 { { "user", NULL }, "user : lower the level of the current CLI session to user", cli_parse_set_lvl, NULL, NULL, NULL, ACCESS_MASTER},
2860 { { "_getsocks", NULL }, NULL, _getsocks, NULL },
2861 { { "expert-mode", NULL }, NULL, cli_parse_expert_mode, NULL }, // not listed
2862 {{},}
2863 }};
2864
2865 INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
2866
2867 static struct cfg_kw_list cfg_kws = {ILH, {
2868 { CFG_GLOBAL, "stats", stats_parse_global },
2869 { 0, NULL, NULL },
2870 }};
2871
2872 INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
2873
2874 static struct bind_kw_list bind_kws = { "STAT", { }, {
2875 { "level", bind_parse_level, 1 }, /* set the unix socket admin level */
2876 { "expose-fd", bind_parse_expose_fd, 1 }, /* set the unix socket expose fd rights */
2877 { "severity-output", bind_parse_severity_output, 1 }, /* set the severity output format */
2878 { NULL, NULL, 0 },
2879 }};
2880
2881 INITCALL1(STG_REGISTER, bind_register_keywords, &bind_kws);
2882
2883 /*
2884 * Local variables:
2885 * c-indent-level: 8
2886 * c-basic-offset: 8
2887 * End:
2888 */
2889