1 /*
2  * General logging functions.
3  *
4  * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version
9  * 2 of the License, or (at your option) any later version.
10  *
11  */
12 
13 #include <ctype.h>
14 #include <fcntl.h>
15 #include <stdarg.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <syslog.h>
20 #include <time.h>
21 #include <unistd.h>
22 #include <errno.h>
23 
24 #include <sys/time.h>
25 #include <sys/uio.h>
26 
27 #include <common/config.h>
28 #include <common/compat.h>
29 #include <common/initcall.h>
30 #include <common/standard.h>
31 #include <common/time.h>
32 
33 #include <types/cli.h>
34 #include <types/global.h>
35 #include <types/log.h>
36 
37 #include <proto/applet.h>
38 #include <proto/cli.h>
39 #include <proto/fd.h>
40 #include <proto/frontend.h>
41 #include <proto/log.h>
42 #include <proto/ring.h>
43 #include <proto/sample.h>
44 #include <proto/sink.h>
45 #include <proto/ssl_sock.h>
46 #include <proto/stream.h>
47 #include <proto/stream_interface.h>
48 
49 struct log_fmt {
50 	char *name;
51 	struct {
52 		struct buffer sep1; /* first pid separator */
53 		struct buffer sep2; /* second pid separator */
54 	} pid;
55 };
56 
57 static const struct log_fmt log_formats[LOG_FORMATS] = {
58 	[LOG_FORMAT_RFC3164] = {
59 		.name = "rfc3164",
60 		.pid = {
61 			.sep1 = { .area = "[",   .data = 1 },
62 			.sep2 = { .area = "]: ", .data = 3 }
63 		}
64 	},
65 	[LOG_FORMAT_RFC5424] = {
66 		.name = "rfc5424",
67 		.pid = {
68 			.sep1 = { .area = " ",   .data = 1 },
69 			.sep2 = { .area = " - ", .data = 3 }
70 		}
71 	},
72 	[LOG_FORMAT_SHORT] = {
73 		.name = "short",
74 		.pid = {
75 			.sep1 = { .area = "",  .data = 0 },
76 			.sep2 = { .area = " ", .data = 1 },
77 		}
78 	},
79 	[LOG_FORMAT_RAW] = {
80 		.name = "raw",
81 		.pid = {
82 			.sep1 = { .area = "", .data = 0 },
83 			.sep2 = { .area = "", .data = 0 },
84 		}
85 	},
86 };
87 
88 /*
89  * This map is used with all the FD_* macros to check whether a particular bit
90  * is set or not. Each bit represents an ACSII code. ha_bit_set() sets those
91  * bytes which should be escaped. When ha_bit_test() returns non-zero, it means
92  * that the byte should be escaped. Be careful to always pass bytes from 0 to
93  * 255 exclusively to the macros.
94  */
95 long rfc5424_escape_map[(256/8) / sizeof(long)];
96 long hdr_encode_map[(256/8) / sizeof(long)];
97 long url_encode_map[(256/8) / sizeof(long)];
98 long http_encode_map[(256/8) / sizeof(long)];
99 
100 
101 const char *log_facilities[NB_LOG_FACILITIES] = {
102 	"kern", "user", "mail", "daemon",
103 	"auth", "syslog", "lpr", "news",
104 	"uucp", "cron", "auth2", "ftp",
105 	"ntp", "audit", "alert", "cron2",
106 	"local0", "local1", "local2", "local3",
107 	"local4", "local5", "local6", "local7"
108 };
109 
110 const char *log_levels[NB_LOG_LEVELS] = {
111 	"emerg", "alert", "crit", "err",
112 	"warning", "notice", "info", "debug"
113 };
114 
115 const char sess_term_cond[16] = "-LcCsSPRIDKUIIII"; /* normal, Local, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal, Down, Killed, Up, -- */
116 const char sess_fin_state[8]  = "-RCHDLQT";	/* cliRequest, srvConnect, srvHeader, Data, Last, Queue, Tarpit */
117 
118 
119 /* log_format   */
120 struct logformat_type {
121 	char *name;
122 	int type;
123 	int mode;
124 	int lw; /* logwait bitsfield */
125 	int (*config_callback)(struct logformat_node *node, struct proxy *curproxy);
126 	const char *replace_by; /* new option to use instead of old one */
127 };
128 
129 int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy);
130 
131 /* log_format variable names */
132 static const struct logformat_type logformat_keywords[] = {
133 	{ "o", LOG_FMT_GLOBAL, PR_MODE_TCP, 0, NULL },  /* global option */
134 
135 	/* please keep these lines sorted ! */
136 	{ "B", LOG_FMT_BYTES, PR_MODE_TCP, LW_BYTES, NULL },     /* bytes from server to client */
137 	{ "CC", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL },  /* client cookie */
138 	{ "CS", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL },  /* server cookie */
139 	{ "H", LOG_FMT_HOSTNAME, PR_MODE_TCP, LW_INIT, NULL }, /* Hostname */
140 	{ "ID", LOG_FMT_UNIQUEID, PR_MODE_HTTP, LW_BYTES, NULL }, /* Unique ID */
141 	{ "ST", LOG_FMT_STATUS, PR_MODE_TCP, LW_RESP, NULL },   /* status code */
142 	{ "T", LOG_FMT_DATEGMT, PR_MODE_TCP, LW_INIT, NULL },   /* date GMT */
143 	{ "Ta", LOG_FMT_Ta, PR_MODE_HTTP, LW_BYTES, NULL },      /* Time active (tr to end) */
144 	{ "Tc", LOG_FMT_TC, PR_MODE_TCP, LW_BYTES, NULL },       /* Tc */
145 	{ "Th", LOG_FMT_Th, PR_MODE_TCP, LW_BYTES, NULL },       /* Time handshake */
146 	{ "Ti", LOG_FMT_Ti, PR_MODE_HTTP, LW_BYTES, NULL },      /* Time idle */
147 	{ "Tl", LOG_FMT_DATELOCAL, PR_MODE_TCP, LW_INIT, NULL }, /* date local timezone */
148 	{ "Tq", LOG_FMT_TQ, PR_MODE_HTTP, LW_BYTES, NULL },      /* Tq=Th+Ti+TR */
149 	{ "Tr", LOG_FMT_Tr, PR_MODE_HTTP, LW_BYTES, NULL },      /* Tr */
150 	{ "TR", LOG_FMT_TR, PR_MODE_HTTP, LW_BYTES, NULL },      /* Time to receive a valid request */
151 	{ "Td", LOG_FMT_TD, PR_MODE_TCP, LW_BYTES, NULL },       /* Td = Tt - (Tq + Tw + Tc + Tr) */
152 	{ "Ts", LOG_FMT_TS, PR_MODE_TCP, LW_INIT, NULL },   /* timestamp GMT */
153 	{ "Tt", LOG_FMT_TT, PR_MODE_TCP, LW_BYTES, NULL },       /* Tt */
154 	{ "Tw", LOG_FMT_TW, PR_MODE_TCP, LW_BYTES, NULL },       /* Tw */
155 	{ "U", LOG_FMT_BYTES_UP, PR_MODE_TCP, LW_BYTES, NULL },  /* bytes from client to server */
156 	{ "ac", LOG_FMT_ACTCONN, PR_MODE_TCP, LW_BYTES, NULL },  /* actconn */
157 	{ "b", LOG_FMT_BACKEND, PR_MODE_TCP, LW_INIT, NULL },   /* backend */
158 	{ "bc", LOG_FMT_BECONN, PR_MODE_TCP, LW_BYTES, NULL },   /* beconn */
159 	{ "bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source ip */
160 	{ "bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source port */
161 	{ "bq", LOG_FMT_BCKQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* backend_queue */
162 	{ "ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL },  /* client ip */
163 	{ "cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client port */
164 	{ "f", LOG_FMT_FRONTEND, PR_MODE_TCP, LW_INIT, NULL },  /* frontend */
165 	{ "fc", LOG_FMT_FECONN, PR_MODE_TCP, LW_BYTES, NULL },   /* feconn */
166 	{ "fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend ip */
167 	{ "fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend port */
168 	{ "ft", LOG_FMT_FRONTEND_XPRT, PR_MODE_TCP, LW_INIT, NULL },  /* frontend with transport mode */
169 	{ "hr", LOG_FMT_HDRREQUEST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request */
170 	{ "hrl", LOG_FMT_HDRREQUESTLIST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request list */
171 	{ "hs", LOG_FMT_HDRRESPONS, PR_MODE_TCP, LW_RSPHDR, NULL },  /* header response */
172 	{ "hsl", LOG_FMT_HDRRESPONSLIST, PR_MODE_TCP, LW_RSPHDR, NULL },  /* header response list */
173 	{ "HM", LOG_FMT_HTTP_METHOD, PR_MODE_HTTP, LW_REQ, NULL },  /* HTTP method */
174 	{ "HP", LOG_FMT_HTTP_PATH, PR_MODE_HTTP, LW_REQ, NULL },  /* HTTP path */
175 	{ "HQ", LOG_FMT_HTTP_QUERY, PR_MODE_HTTP, LW_REQ, NULL },  /* HTTP query */
176 	{ "HU", LOG_FMT_HTTP_URI, PR_MODE_HTTP, LW_REQ, NULL },  /* HTTP full URI */
177 	{ "HV", LOG_FMT_HTTP_VERSION, PR_MODE_HTTP, LW_REQ, NULL },  /* HTTP version */
178 	{ "lc", LOG_FMT_LOGCNT, PR_MODE_TCP, LW_INIT, NULL }, /* log counter */
179 	{ "ms", LOG_FMT_MS, PR_MODE_TCP, LW_INIT, NULL },       /* accept date millisecond */
180 	{ "pid", LOG_FMT_PID, PR_MODE_TCP, LW_INIT, NULL }, /* log pid */
181 	{ "r", LOG_FMT_REQ, PR_MODE_HTTP, LW_REQ, NULL },  /* request */
182 	{ "rc", LOG_FMT_RETRIES, PR_MODE_TCP, LW_BYTES, NULL },  /* retries */
183 	{ "rt", LOG_FMT_COUNTER, PR_MODE_TCP, LW_REQ, NULL }, /* request counter (HTTP or TCP session) */
184 	{ "s", LOG_FMT_SERVER, PR_MODE_TCP, LW_SVID, NULL },    /* server */
185 	{ "sc", LOG_FMT_SRVCONN, PR_MODE_TCP, LW_BYTES, NULL },  /* srv_conn */
186 	{ "si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination ip */
187 	{ "sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination port */
188 	{ "sq", LOG_FMT_SRVQUEUE, PR_MODE_TCP, LW_BYTES, NULL  }, /* srv_queue */
189 	{ "sslc", LOG_FMT_SSL_CIPHER, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL ciphers */
190 	{ "sslv", LOG_FMT_SSL_VERSION, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL protocol version */
191 	{ "t", LOG_FMT_DATE, PR_MODE_TCP, LW_INIT, NULL },      /* date */
192 	{ "tr", LOG_FMT_tr, PR_MODE_HTTP, LW_INIT, NULL },      /* date of start of request */
193 	{ "trg",LOG_FMT_trg, PR_MODE_HTTP, LW_INIT, NULL },     /* date of start of request, GMT */
194 	{ "trl",LOG_FMT_trl, PR_MODE_HTTP, LW_INIT, NULL },     /* date of start of request, local */
195 	{ "ts", LOG_FMT_TERMSTATE, PR_MODE_TCP, LW_BYTES, NULL },/* termination state */
196 	{ "tsc", LOG_FMT_TERMSTATE_CK, PR_MODE_TCP, LW_INIT, NULL },/* termination state */
197 
198 	/* The following tags are deprecated and will be removed soon */
199 	{ "Bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bi" }, /* backend source ip */
200 	{ "Bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bp" }, /* backend source port */
201 	{ "Ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "ci" },  /* client ip */
202 	{ "Cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "cp" }, /* client port */
203 	{ "Fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fi" }, /* frontend ip */
204 	{ "Fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fp" }, /* frontend port */
205 	{ "Si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL, "si" }, /* server destination ip */
206 	{ "Sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL, "sp" }, /* server destination port */
207 	{ "cc", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL, "CC" },  /* client cookie */
208 	{ "cs", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL, "CS" },  /* server cookie */
209 	{ "st", LOG_FMT_STATUS, PR_MODE_HTTP, LW_RESP, NULL, "ST" },   /* status code */
210 	{ 0, 0, 0, 0, NULL }
211 };
212 
213 char default_http_log_format[] = "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"; // default format
214 char clf_http_log_format[] = "%{+Q}o %{-Q}ci - - [%trg] %r %ST %B \"\" \"\" %cp %ms %ft %b %s %TR %Tw %Tc %Tr %Ta %tsc %ac %fc %bc %sc %rc %sq %bq %CC %CS %hrl %hsl";
215 char default_tcp_log_format[] = "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq";
216 char *log_format = NULL;
217 
218 /* Default string used for structured-data part in RFC5424 formatted
219  * syslog messages.
220  */
221 char default_rfc5424_sd_log_format[] = "- ";
222 
223 /* total number of dropped logs */
224 unsigned int dropped_logs = 0;
225 
226 /* This is a global syslog header, common to all outgoing messages in
227  * RFC3164 format. It begins with time-based part and is updated by
228  * update_log_hdr().
229  */
230 THREAD_LOCAL char *logheader = NULL;
231 THREAD_LOCAL char *logheader_end = NULL;
232 
233 /* This is a global syslog header for messages in RFC5424 format. It is
234  * updated by update_log_hdr_rfc5424().
235  */
236 THREAD_LOCAL char *logheader_rfc5424 = NULL;
237 THREAD_LOCAL char *logheader_rfc5424_end = NULL;
238 
239 /* This is a global syslog message buffer, common to all outgoing
240  * messages. It contains only the data part.
241  */
242 THREAD_LOCAL char *logline = NULL;
243 
244 /* A global syslog message buffer, common to all RFC5424 syslog messages.
245  * Currently, it is used for generating the structured-data part.
246  */
247 THREAD_LOCAL char *logline_rfc5424 = NULL;
248 
249 /* A global buffer used to store all startup alerts/warnings. It will then be
250  * retrieve on the CLI. */
251 static struct ring *startup_logs = NULL;
252 
253 struct logformat_var_args {
254 	char *name;
255 	int mask;
256 };
257 
258 struct logformat_var_args var_args_list[] = {
259 // global
260 	{ "M", LOG_OPT_MANDATORY },
261 	{ "Q", LOG_OPT_QUOTE },
262 	{ "X", LOG_OPT_HEXA },
263 	{ "E", LOG_OPT_ESC },
264 	{  0,  0 }
265 };
266 
267 /* return the name of the directive used in the current proxy for which we're
268  * currently parsing a header, when it is known.
269  */
fmt_directive(const struct proxy * curproxy)270 static inline const char *fmt_directive(const struct proxy *curproxy)
271 {
272 	switch (curproxy->conf.args.ctx) {
273 	case ARGC_ACL:
274 		return "acl";
275 	case ARGC_STK:
276 		return "stick";
277 	case ARGC_TRK:
278 		return "track-sc";
279 	case ARGC_LOG:
280 		return "log-format";
281 	case ARGC_LOGSD:
282 		return "log-format-sd";
283 	case ARGC_HRQ:
284 		return "http-request";
285 	case ARGC_HRS:
286 		return "http-response";
287 	case ARGC_UIF:
288 		return "unique-id-format";
289 	case ARGC_RDR:
290 		return "redirect";
291 	case ARGC_CAP:
292 		return "capture";
293 	case ARGC_SRV:
294 		return "server";
295 	case ARGC_SPOE:
296 		return "spoe-message";
297 	case ARGC_UBK:
298 		return "use_backend";
299 	default:
300 		return "undefined(please report this bug)"; /* must never happen */
301 	}
302 }
303 
304 /*
305  * callback used to configure addr source retrieval
306  */
prepare_addrsource(struct logformat_node * node,struct proxy * curproxy)307 int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy)
308 {
309 	curproxy->options2 |= PR_O2_SRC_ADDR;
310 
311 	return 0;
312 }
313 
314 
315 /*
316  * Parse args in a logformat_var. Returns 0 in error
317  * case, otherwise, it returns 1.
318  */
parse_logformat_var_args(char * args,struct logformat_node * node,char ** err)319 int parse_logformat_var_args(char *args, struct logformat_node *node, char **err)
320 {
321 	int i = 0;
322 	int end = 0;
323 	int flags = 0;  // 1 = +  2 = -
324 	char *sp = NULL; // start pointer
325 
326 	if (args == NULL) {
327 		memprintf(err, "internal error: parse_logformat_var_args() expects non null 'args'");
328 		return 0;
329 	}
330 
331 	while (1) {
332 		if (*args == '\0')
333 			end = 1;
334 
335 		if (*args == '+') {
336 			// add flag
337 			sp = args + 1;
338 			flags = 1;
339 		}
340 		if (*args == '-') {
341 			// delete flag
342 			sp = args + 1;
343 			flags = 2;
344 		}
345 
346 		if (*args == '\0' || *args == ',') {
347 			*args = '\0';
348 			for (i = 0; sp && var_args_list[i].name; i++) {
349 				if (strcmp(sp, var_args_list[i].name) == 0) {
350 					if (flags == 1) {
351 						node->options |= var_args_list[i].mask;
352 						break;
353 					} else if (flags == 2) {
354 						node->options &= ~var_args_list[i].mask;
355 						break;
356 					}
357 				}
358 			}
359 			sp = NULL;
360 			if (end)
361 				break;
362 		}
363 		args++;
364 	}
365 	return 1;
366 }
367 
368 /*
369  * Parse a variable '%varname' or '%{args}varname' in log-format. The caller
370  * must pass the args part in the <arg> pointer with its length in <arg_len>,
371  * and varname with its length in <var> and <var_len> respectively. <arg> is
372  * ignored when arg_len is 0. Neither <var> nor <var_len> may be null.
373  * Returns false in error case and err is filled, otherwise returns true.
374  */
parse_logformat_var(char * arg,int arg_len,char * var,int var_len,struct proxy * curproxy,struct list * list_format,int * defoptions,char ** err)375 int parse_logformat_var(char *arg, int arg_len, char *var, int var_len, struct proxy *curproxy, struct list *list_format, int *defoptions, char **err)
376 {
377 	int j;
378 	struct logformat_node *node = NULL;
379 
380 	for (j = 0; logformat_keywords[j].name; j++) { // search a log type
381 		if (strlen(logformat_keywords[j].name) == var_len &&
382 		    strncmp(var, logformat_keywords[j].name, var_len) == 0) {
383 			if (logformat_keywords[j].mode != PR_MODE_HTTP || curproxy->mode == PR_MODE_HTTP) {
384 				node = calloc(1, sizeof(*node));
385 				if (!node) {
386 					memprintf(err, "out of memory error");
387 					goto error_free;
388 				}
389 				node->type = logformat_keywords[j].type;
390 				node->options = *defoptions;
391 				if (arg_len) {
392 					node->arg = my_strndup(arg, arg_len);
393 					if (!parse_logformat_var_args(node->arg, node, err))
394 						goto error_free;
395 				}
396 				if (node->type == LOG_FMT_GLOBAL) {
397 					*defoptions = node->options;
398 					free(node->arg);
399 					free(node);
400 				} else {
401 					if (logformat_keywords[j].config_callback &&
402 					    logformat_keywords[j].config_callback(node, curproxy) != 0) {
403 						goto error_free;
404 					}
405 					curproxy->to_log |= logformat_keywords[j].lw;
406 					LIST_ADDQ(list_format, &node->list);
407 				}
408 				if (logformat_keywords[j].replace_by)
409 					ha_warning("parsing [%s:%d] : deprecated variable '%s' in '%s', please replace it with '%s'.\n",
410 						   curproxy->conf.args.file, curproxy->conf.args.line,
411 						   logformat_keywords[j].name, fmt_directive(curproxy), logformat_keywords[j].replace_by);
412 				return 1;
413 			} else {
414 				memprintf(err, "format variable '%s' is reserved for HTTP mode",
415 				          logformat_keywords[j].name);
416 				goto error_free;
417 			}
418 		}
419 	}
420 
421 	j = var[var_len];
422 	var[var_len] = 0;
423 	memprintf(err, "no such format variable '%s'. If you wanted to emit the '%%' character verbatim, you need to use '%%%%'", var);
424 	var[var_len] = j;
425 
426   error_free:
427 	if (node) {
428 		free(node->arg);
429 		free(node);
430 	}
431 	return 0;
432 }
433 
434 /*
435  *  push to the logformat linked list
436  *
437  *  start: start pointer
438  *  end: end text pointer
439  *  type: string type
440  *  list_format: destination list
441  *
442  *  LOG_TEXT: copy chars from start to end excluding end.
443  *
444 */
add_to_logformat_list(char * start,char * end,int type,struct list * list_format,char ** err)445 int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err)
446 {
447 	char *str;
448 
449 	if (type == LF_TEXT) { /* type text */
450 		struct logformat_node *node = calloc(1, sizeof(*node));
451 		if (!node) {
452 			memprintf(err, "out of memory error");
453 			return 0;
454 		}
455 		str = calloc(1, end - start + 1);
456 		strncpy(str, start, end - start);
457 		str[end - start] = '\0';
458 		node->arg = str;
459 		node->type = LOG_FMT_TEXT; // type string
460 		LIST_ADDQ(list_format, &node->list);
461 	} else if (type == LF_SEPARATOR) {
462 		struct logformat_node *node = calloc(1, sizeof(*node));
463 		if (!node) {
464 			memprintf(err, "out of memory error");
465 			return 0;
466 		}
467 		node->type = LOG_FMT_SEPARATOR;
468 		LIST_ADDQ(list_format, &node->list);
469 	}
470 	return 1;
471 }
472 
473 /*
474  * Parse the sample fetch expression <text> and add a node to <list_format> upon
475  * success. At the moment, sample converters are not yet supported but fetch arguments
476  * should work. The curpx->conf.args.ctx must be set by the caller.
477  *
478  * In error case, the function returns 0, otherwise it returns 1.
479  */
add_sample_to_logformat_list(char * text,char * arg,int arg_len,struct proxy * curpx,struct list * list_format,int options,int cap,char ** err)480 int add_sample_to_logformat_list(char *text, char *arg, int arg_len, struct proxy *curpx, struct list *list_format, int options, int cap, char **err)
481 {
482 	char *cmd[2];
483 	struct sample_expr *expr = NULL;
484 	struct logformat_node *node = NULL;
485 	int cmd_arg;
486 
487 	cmd[0] = text;
488 	cmd[1] = "";
489 	cmd_arg = 0;
490 
491 	expr = sample_parse_expr(cmd, &cmd_arg, curpx->conf.args.file, curpx->conf.args.line, err, &curpx->conf.args);
492 	if (!expr) {
493 		memprintf(err, "failed to parse sample expression <%s> : %s", text, *err);
494 		goto error_free;
495 	}
496 
497 	node = calloc(1, sizeof(*node));
498 	if (!node) {
499 		memprintf(err, "out of memory error");
500 		goto error_free;
501 	}
502 	node->type = LOG_FMT_EXPR;
503 	node->expr = expr;
504 	node->options = options;
505 
506 	if (arg_len) {
507 		node->arg = my_strndup(arg, arg_len);
508 		if (!parse_logformat_var_args(node->arg, node, err))
509 			goto error_free;
510 	}
511 	if (expr->fetch->val & cap & SMP_VAL_REQUEST)
512 		node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */
513 
514 	if (expr->fetch->val & cap & SMP_VAL_RESPONSE)
515 		node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */
516 
517 	if (!(expr->fetch->val & cap)) {
518 		memprintf(err, "sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here",
519 		          text, sample_src_names(expr->fetch->use));
520 		goto error_free;
521 	}
522 
523 	/* check if we need to allocate an http_txn struct for HTTP parsing */
524 	/* Note, we may also need to set curpx->to_log with certain fetches */
525 	curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
526 
527 	/* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags
528 	 * needed with some sample fetches (eg: ssl*). We always set it for
529 	 * now on, but this will leave with sample capabilities soon.
530 	 */
531 	curpx->to_log |= LW_XPRT;
532 	curpx->to_log |= LW_REQ;
533 	LIST_ADDQ(list_format, &node->list);
534 	return 1;
535 
536   error_free:
537 	release_sample_expr(expr);
538 	if (node) {
539 		free(node->arg);
540 		free(node);
541 	}
542 	return 0;
543 }
544 
545 /*
546  * Parse the log_format string and fill a linked list.
547  * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
548  * You can set arguments using { } : %{many arguments}varname.
549  * The curproxy->conf.args.ctx must be set by the caller.
550  *
551  *  str: the string to parse
552  *  curproxy: the proxy affected
553  *  list_format: the destination list
554  *  options: LOG_OPT_* to force on every node
555  *  cap: all SMP_VAL_* flags supported by the consumer
556  *
557  * The function returns 1 in success case, otherwise, it returns 0 and err is filled.
558  */
parse_logformat_string(const char * fmt,struct proxy * curproxy,struct list * list_format,int options,int cap,char ** err)559 int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list *list_format, int options, int cap, char **err)
560 {
561 	char *sp, *str, *backfmt; /* start pointer for text parts */
562 	char *arg = NULL; /* start pointer for args */
563 	char *var = NULL; /* start pointer for vars */
564 	int arg_len = 0;
565 	int var_len = 0;
566 	int cformat; /* current token format */
567 	int pformat; /* previous token format */
568 	struct logformat_node *tmplf, *back;
569 
570 	sp = str = backfmt = strdup(fmt);
571 	if (!str) {
572 		memprintf(err, "out of memory error");
573 		return 0;
574 	}
575 	curproxy->to_log |= LW_INIT;
576 
577 	/* flush the list first. */
578 	list_for_each_entry_safe(tmplf, back, list_format, list) {
579 		LIST_DEL(&tmplf->list);
580 		release_sample_expr(tmplf->expr);
581 		free(tmplf->arg);
582 		free(tmplf);
583 	}
584 
585 	for (cformat = LF_INIT; cformat != LF_END; str++) {
586 		pformat = cformat;
587 
588 		if (!*str)
589 			cformat = LF_END;              // preset it to save all states from doing this
590 
591 		/* The principle of the two-step state machine below is to first detect a change, and
592 		 * second have all common paths processed at one place. The common paths are the ones
593 		 * encountered in text areas (LF_INIT, LF_TEXT, LF_SEPARATOR) and at the end (LF_END).
594 		 * We use the common LF_INIT state to dispatch to the different final states.
595 		 */
596 		switch (pformat) {
597 		case LF_STARTVAR:                      // text immediately following a '%'
598 			arg = NULL; var = NULL;
599 			arg_len = var_len = 0;
600 			if (*str == '{') {             // optional argument
601 				cformat = LF_STARG;
602 				arg = str + 1;
603 			}
604 			else if (*str == '[') {
605 				cformat = LF_STEXPR;
606 				var = str + 1;         // store expr in variable name
607 			}
608 			else if (isalpha((unsigned char)*str)) { // variable name
609 				cformat = LF_VAR;
610 				var = str;
611 			}
612 			else if (*str == '%')
613 				cformat = LF_TEXT;     // convert this character to a litteral (useful for '%')
614 			else if (isdigit((unsigned char)*str) || *str == ' ' || *str == '\t') {
615 				/* single '%' followed by blank or digit, send them both */
616 				cformat = LF_TEXT;
617 				pformat = LF_TEXT; /* finally we include the previous char as well */
618 				sp = str - 1; /* send both the '%' and the current char */
619 				memprintf(err, "unexpected variable name near '%c' at position %d line : '%s'. Maybe you want to write a single '%%', use the syntax '%%%%'",
620 				          *str, (int)(str - backfmt), fmt);
621 				goto fail;
622 
623 			}
624 			else
625 				cformat = LF_INIT;     // handle other cases of litterals
626 			break;
627 
628 		case LF_STARG:                         // text immediately following '%{'
629 			if (*str == '}') {             // end of arg
630 				cformat = LF_EDARG;
631 				arg_len = str - arg;
632 				*str = 0;              // used for reporting errors
633 			}
634 			break;
635 
636 		case LF_EDARG:                         // text immediately following '%{arg}'
637 			if (*str == '[') {
638 				cformat = LF_STEXPR;
639 				var = str + 1;         // store expr in variable name
640 				break;
641 			}
642 			else if (isalnum((unsigned char)*str)) { // variable name
643 				cformat = LF_VAR;
644 				var = str;
645 				break;
646 			}
647 			memprintf(err, "parse argument modifier without variable name near '%%{%s}'", arg);
648 			goto fail;
649 
650 		case LF_STEXPR:                        // text immediately following '%['
651 			if (*str == ']') {             // end of arg
652 				cformat = LF_EDEXPR;
653 				var_len = str - var;
654 				*str = 0;              // needed for parsing the expression
655 			}
656 			break;
657 
658 		case LF_VAR:                           // text part of a variable name
659 			var_len = str - var;
660 			if (!isalnum((unsigned char)*str))
661 				cformat = LF_INIT;     // not variable name anymore
662 			break;
663 
664 		default:                               // LF_INIT, LF_TEXT, LF_SEPARATOR, LF_END, LF_EDEXPR
665 			cformat = LF_INIT;
666 		}
667 
668 		if (cformat == LF_INIT) { /* resynchronize state to text/sep/startvar */
669 			switch (*str) {
670 			case '%': cformat = LF_STARTVAR;  break;
671 			case ' ': cformat = LF_SEPARATOR; break;
672 			case  0 : cformat = LF_END;       break;
673 			default : cformat = LF_TEXT;      break;
674 			}
675 		}
676 
677 		if (cformat != pformat || pformat == LF_SEPARATOR) {
678 			switch (pformat) {
679 			case LF_VAR:
680 				if (!parse_logformat_var(arg, arg_len, var, var_len, curproxy, list_format, &options, err))
681 					goto fail;
682 				break;
683 			case LF_STEXPR:
684 				if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err))
685 					goto fail;
686 				break;
687 			case LF_TEXT:
688 			case LF_SEPARATOR:
689 				if (!add_to_logformat_list(sp, str, pformat, list_format, err))
690 					goto fail;
691 				break;
692 			}
693 			sp = str; /* new start of text at every state switch and at every separator */
694 		}
695 	}
696 
697 	if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR) {
698 		memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
699 		goto fail;
700 	}
701 	free(backfmt);
702 
703 	return 1;
704  fail:
705 	free(backfmt);
706 	return 0;
707 }
708 
709 /*
710  * Parse the first range of indexes from a string made of a list of comma seperated
711  * ranges of indexes. Note that an index may be considered as a particular range
712  * with a high limit to the low limit.
713  */
get_logsrv_smp_range(unsigned int * low,unsigned int * high,char ** arg,char ** err)714 int get_logsrv_smp_range(unsigned int *low, unsigned int *high, char **arg, char **err)
715 {
716 	char *end, *p;
717 
718 	*low = *high = 0;
719 
720 	p = *arg;
721 	end = strchr(p, ',');
722 	if (!end)
723 		end = p + strlen(p);
724 
725 	*high = *low = read_uint((const char **)&p, end);
726 	if (!*low || (p != end && *p != '-'))
727 		goto err;
728 
729 	if (p == end)
730 		goto done;
731 
732 	p++;
733 	*high = read_uint((const char **)&p, end);
734 	if (!*high || *high <= *low || p != end)
735 		goto err;
736 
737  done:
738 	if (*end == ',')
739 		end++;
740 	*arg = end;
741 	return 1;
742 
743  err:
744 	memprintf(err, "wrong sample range '%s'", *arg);
745 	return 0;
746 }
747 
748 /*
749  * Returns 1 if the range defined by <low> and <high> overlaps
750  * one of them in <rgs> array of ranges with <sz> the size of this
751  * array, 0 if not.
752  */
smp_log_ranges_overlap(struct smp_log_range * rgs,size_t sz,unsigned int low,unsigned int high,char ** err)753 int smp_log_ranges_overlap(struct smp_log_range *rgs, size_t sz,
754                            unsigned int low, unsigned int high, char **err)
755 {
756 	size_t i;
757 
758 	for (i = 0; i < sz; i++) {
759 		if ((low  >= rgs[i].low && low  <= rgs[i].high) ||
760 		    (high >= rgs[i].low && high <= rgs[i].high)) {
761 			memprintf(err, "ranges are overlapping");
762 			return 1;
763 		}
764 	}
765 
766 	return 0;
767 }
768 
smp_log_range_cmp(const void * a,const void * b)769 int smp_log_range_cmp(const void *a, const void *b)
770 {
771 	const struct smp_log_range *rg_a = a;
772 	const struct smp_log_range *rg_b = b;
773 
774 	if (rg_a->high < rg_b->low)
775 		return -1;
776 	else if (rg_a->low > rg_b->high)
777 		return 1;
778 
779 	return 0;
780 }
781 
782 /*
783  * Parse "log" keyword and update <logsrvs> list accordingly.
784  *
785  * When <do_del> is set, it means the "no log" line was parsed, so all log
786  * servers in <logsrvs> are released.
787  *
788  * Otherwise, we try to parse the "log" line. First of all, when the list is not
789  * the global one, we look for the parameter "global". If we find it,
790  * global.logsrvs is copied. Else we parse each arguments.
791  *
792  * The function returns 1 in success case, otherwise, it returns 0 and err is
793  * filled.
794  */
parse_logsrv(char ** args,struct list * logsrvs,int do_del,char ** err)795 int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
796 {
797 	struct smp_log_range *smp_rgs = NULL;
798 	struct sockaddr_storage *sk;
799 	struct logsrv *logsrv = NULL;
800 	int port1, port2;
801 	int cur_arg;
802 
803 	/*
804 	 * "no log": delete previous herited or defined syslog
805 	 *           servers.
806 	 */
807 	if (do_del) {
808 		struct logsrv *back;
809 
810 		if (*(args[1]) != 0) {
811 			memprintf(err, "'no log' does not expect arguments");
812 			goto error;
813 		}
814 
815 		list_for_each_entry_safe(logsrv, back, logsrvs, list) {
816 			LIST_DEL(&logsrv->list);
817 			free(logsrv);
818 		}
819 		return 1;
820 	}
821 
822 	/*
823 	 * "log global": copy global.logrsvs linked list to the end of logsrvs
824 	 *               list. But first, we check (logsrvs != global.logsrvs).
825 	 */
826 	if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
827 		if (logsrvs == &global.logsrvs) {
828 			memprintf(err, "'global' is not supported for a global syslog server");
829 			goto error;
830 		}
831 		list_for_each_entry(logsrv, &global.logsrvs, list) {
832 			struct logsrv *node;
833 
834 			list_for_each_entry(node, logsrvs, list) {
835 				if (node->ref == logsrv)
836 					goto skip_logsrv;
837 			}
838 
839 			node = malloc(sizeof(*node));
840 			memcpy(node, logsrv, sizeof(struct logsrv));
841 			node->ref = logsrv;
842 			LIST_INIT(&node->list);
843 			LIST_ADDQ(logsrvs, &node->list);
844 
845 		  skip_logsrv:
846 			continue;
847 		}
848 		return 1;
849 	}
850 
851 	/*
852 	* "log <address> ...: parse a syslog server line
853 	*/
854 	if (*(args[1]) == 0 || *(args[2]) == 0) {
855 		memprintf(err, "expects <address> and <facility> %s as arguments",
856 			  ((logsrvs == &global.logsrvs) ? "" : "or global"));
857 		goto error;
858 	}
859 
860 	/* take care of "stdout" and "stderr" as regular aliases for fd@1 / fd@2 */
861 	if (strcmp(args[1], "stdout") == 0)
862 		args[1] = "fd@1";
863 	else if (strcmp(args[1], "stderr") == 0)
864 		args[1] = "fd@2";
865 
866 	logsrv = calloc(1, sizeof(*logsrv));
867 	if (!logsrv) {
868 		memprintf(err, "out of memory");
869 		goto error;
870 	}
871 
872 	/* skip address for now, it will be parsed at the end */
873 	cur_arg = 2;
874 
875 	/* just after the address, a length may be specified */
876 	logsrv->maxlen = MAX_SYSLOG_LEN;
877 	if (strcmp(args[cur_arg], "len") == 0) {
878 		int len = atoi(args[cur_arg+1]);
879 		if (len < 80 || len > 65535) {
880 			memprintf(err, "invalid log length '%s', must be between 80 and 65535",
881 				  args[cur_arg+1]);
882 			goto error;
883 		}
884 		logsrv->maxlen = len;
885 		cur_arg += 2;
886 	}
887 	if (logsrv->maxlen > global.max_syslog_len)
888 		global.max_syslog_len = logsrv->maxlen;
889 
890 	/* after the length, a format may be specified */
891 	if (strcmp(args[cur_arg], "format") == 0) {
892 		logsrv->format = get_log_format(args[cur_arg+1]);
893 		if (logsrv->format < 0) {
894 			memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
895 			goto error;
896 		}
897 		cur_arg += 2;
898 	}
899 
900 	if (strcmp(args[cur_arg], "sample") == 0) {
901 		unsigned low, high;
902 		char *p, *beg, *end, *smp_sz_str;
903 		size_t smp_rgs_sz = 0, smp_sz = 0, new_smp_sz;
904 
905 		p = args[cur_arg+1];
906 		smp_sz_str = strchr(p, ':');
907 		if (!smp_sz_str) {
908 			memprintf(err, "Missing sample size");
909 			goto error;
910 		}
911 
912 		*smp_sz_str++ = '\0';
913 
914 		end = p + strlen(p);
915 
916 		while (p != end) {
917 			if (!get_logsrv_smp_range(&low, &high, &p, err))
918 				goto error;
919 
920 			if (smp_rgs && smp_log_ranges_overlap(smp_rgs, smp_rgs_sz, low, high, err))
921 				goto error;
922 
923 			smp_rgs = my_realloc2(smp_rgs, (smp_rgs_sz + 1) * sizeof *smp_rgs);
924 			if (!smp_rgs) {
925 				memprintf(err, "out of memory error");
926 				goto error;
927 			}
928 
929 			smp_rgs[smp_rgs_sz].low = low;
930 			smp_rgs[smp_rgs_sz].high = high;
931 			smp_rgs[smp_rgs_sz].sz = high - low + 1;
932 			smp_rgs[smp_rgs_sz].curr_idx = 0;
933 			if (smp_rgs[smp_rgs_sz].high > smp_sz)
934 				smp_sz = smp_rgs[smp_rgs_sz].high;
935 			smp_rgs_sz++;
936 		}
937 
938 		if (smp_rgs == NULL) {
939 			memprintf(err, "no sampling ranges given");
940 			goto error;
941 		}
942 
943 		beg = smp_sz_str;
944 		end = beg + strlen(beg);
945 		new_smp_sz = read_uint((const char **)&beg, end);
946 		if (!new_smp_sz || beg != end) {
947 			memprintf(err, "wrong sample size '%s' for sample range '%s'",
948 						   smp_sz_str, args[cur_arg+1]);
949 			goto error;
950 		}
951 
952 		if (new_smp_sz < smp_sz) {
953 			memprintf(err, "sample size %zu should be greater or equal to "
954 						   "%zu the maximum of the high ranges limits",
955 						   new_smp_sz, smp_sz);
956 			goto error;
957 		}
958 		smp_sz = new_smp_sz;
959 
960 		/* Let's order <smp_rgs> array. */
961 		qsort(smp_rgs, smp_rgs_sz, sizeof(struct smp_log_range), smp_log_range_cmp);
962 
963 		logsrv->lb.smp_rgs = smp_rgs;
964 		logsrv->lb.smp_rgs_sz = smp_rgs_sz;
965 		logsrv->lb.smp_sz = smp_sz;
966 
967 		cur_arg += 2;
968 	}
969 	HA_SPIN_INIT(&logsrv->lock);
970 	/* parse the facility */
971 	logsrv->facility = get_log_facility(args[cur_arg]);
972 	if (logsrv->facility < 0) {
973 		memprintf(err, "unknown log facility '%s'", args[cur_arg]);
974 		goto error;
975 	}
976 	cur_arg++;
977 
978 	/* parse the max syslog level (default: debug) */
979 	logsrv->level = 7;
980 	if (*(args[cur_arg])) {
981 		logsrv->level = get_log_level(args[cur_arg]);
982 		if (logsrv->level < 0) {
983 			memprintf(err, "unknown optional log level '%s'", args[cur_arg]);
984 			goto error;
985 		}
986 		cur_arg++;
987 	}
988 
989 	/* parse the limit syslog level (default: emerg) */
990 	logsrv->minlvl = 0;
991 	if (*(args[cur_arg])) {
992 		logsrv->minlvl = get_log_level(args[cur_arg]);
993 		if (logsrv->minlvl < 0) {
994 			memprintf(err, "unknown optional minimum log level '%s'", args[cur_arg]);
995 			goto error;
996 		}
997 		cur_arg++;
998 	}
999 
1000 	/* Too many args */
1001 	if (*(args[cur_arg])) {
1002 		memprintf(err, "cannot handle unexpected argument '%s'", args[cur_arg]);
1003 		goto error;
1004 	}
1005 
1006 	/* now, back to the address */
1007 	logsrv->type = LOG_TARGET_DGRAM;
1008 	if (strncmp(args[1], "ring@", 5) == 0) {
1009 		struct sink *sink = sink_find(args[1] + 5);
1010 
1011 		if (!sink || sink->type != SINK_TYPE_BUFFER) {
1012 			memprintf(err, "cannot find ring buffer '%s'", args[1] + 5);
1013 			goto error;
1014 		}
1015 
1016 		logsrv->addr.ss_family = AF_UNSPEC;
1017 		logsrv->type = LOG_TARGET_BUFFER;
1018 		logsrv->ring = sink->ctx.ring;
1019 		goto done;
1020 	}
1021 
1022 	if (strncmp(args[1], "fd@", 3) == 0)
1023 		logsrv->type = LOG_TARGET_FD;
1024 
1025 	sk = str2sa_range(args[1], NULL, &port1, &port2, err, NULL, NULL, 1);
1026 	if (!sk)
1027 		goto error;
1028 	logsrv->addr = *sk;
1029 
1030 	if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
1031 		if (port1 != port2) {
1032 			memprintf(err, "port ranges and offsets are not allowed in '%s'", args[1]);
1033 			goto error;
1034 		}
1035 		logsrv->addr = *sk;
1036 		if (!port1)
1037 			set_host_port(&logsrv->addr, SYSLOG_PORT);
1038 	}
1039  done:
1040 	LIST_ADDQ(logsrvs, &logsrv->list);
1041 	return 1;
1042 
1043   error:
1044 	free(smp_rgs);
1045 	free(logsrv);
1046 	return 0;
1047 }
1048 
1049 
1050 /* Generic function to display messages prefixed by a label */
print_message(const char * label,const char * fmt,va_list argp)1051 static void print_message(const char *label, const char *fmt, va_list argp)
1052 {
1053 	struct tm tm;
1054 	char *head, *msg;
1055 
1056 	head = msg = NULL;
1057 
1058 	get_localtime(date.tv_sec, &tm);
1059 	memprintf(&head, "[%s] %03d/%02d%02d%02d (%d) : ",
1060 		  label, tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
1061 	memvprintf(&msg, fmt, argp);
1062 
1063 	if (global.mode & MODE_STARTING) {
1064 		if (unlikely(!startup_logs))
1065 			startup_logs = ring_new(STARTUP_LOG_SIZE);
1066 
1067 		if (likely(startup_logs)) {
1068 			struct ist m[2];
1069 
1070 			m[0] = ist(head);
1071 			m[1] = ist(msg);
1072 			/* trim the trailing '\n' */
1073 			if (m[1].len > 0 && m[1].ptr[m[1].len - 1] == '\n')
1074 				m[1].len--;
1075 			ring_write(startup_logs, ~0, 0, 0, m, 2);
1076 		}
1077 	}
1078 
1079 	fprintf(stderr, "%s%s", head, msg);
1080 	fflush(stderr);
1081 
1082 	free(head);
1083 	free(msg);
1084 }
1085 
1086 /*
1087  * Displays the message on stderr with the date and pid. Overrides the quiet
1088  * mode during startup.
1089  */
ha_alert(const char * fmt,...)1090 void ha_alert(const char *fmt, ...)
1091 {
1092 	va_list argp;
1093 
1094 	if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
1095 		va_start(argp, fmt);
1096 		print_message("ALERT", fmt, argp);
1097 		va_end(argp);
1098 	}
1099 }
1100 
1101 
1102 /*
1103  * Displays the message on stderr with the date and pid.
1104  */
ha_warning(const char * fmt,...)1105 void ha_warning(const char *fmt, ...)
1106 {
1107 	va_list argp;
1108 
1109 	if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1110 		va_start(argp, fmt);
1111 		print_message("WARNING", fmt, argp);
1112 		va_end(argp);
1113 	}
1114 }
1115 
1116 /*
1117  * Displays the message on stderr with the date and pid.
1118  */
ha_notice(const char * fmt,...)1119 void ha_notice(const char *fmt, ...)
1120 {
1121 	va_list argp;
1122 
1123 	if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1124 		va_start(argp, fmt);
1125 		print_message("NOTICE", fmt, argp);
1126 		va_end(argp);
1127 	}
1128 }
1129 
1130 /*
1131  * Displays the message on <out> only if quiet mode is not set.
1132  */
qfprintf(FILE * out,const char * fmt,...)1133 void qfprintf(FILE *out, const char *fmt, ...)
1134 {
1135 	va_list argp;
1136 
1137 	if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1138 		va_start(argp, fmt);
1139 		vfprintf(out, fmt, argp);
1140 		fflush(out);
1141 		va_end(argp);
1142 	}
1143 }
1144 
1145 /*
1146  * returns log format for <fmt> or -1 if not found.
1147  */
get_log_format(const char * fmt)1148 int get_log_format(const char *fmt)
1149 {
1150 	int format;
1151 
1152 	format = LOG_FORMATS - 1;
1153 	while (format >= 0 && strcmp(log_formats[format].name, fmt))
1154 		format--;
1155 
1156 	return format;
1157 }
1158 
1159 /*
1160  * returns log level for <lev> or -1 if not found.
1161  */
get_log_level(const char * lev)1162 int get_log_level(const char *lev)
1163 {
1164 	int level;
1165 
1166 	level = NB_LOG_LEVELS - 1;
1167 	while (level >= 0 && strcmp(log_levels[level], lev))
1168 		level--;
1169 
1170 	return level;
1171 }
1172 
1173 /*
1174  * returns log facility for <fac> or -1 if not found.
1175  */
get_log_facility(const char * fac)1176 int get_log_facility(const char *fac)
1177 {
1178 	int facility;
1179 
1180 	facility = NB_LOG_FACILITIES - 1;
1181 	while (facility >= 0 && strcmp(log_facilities[facility], fac))
1182 		facility--;
1183 
1184 	return facility;
1185 }
1186 
1187 /*
1188  * Encode the string.
1189  *
1190  * When using the +E log format option, it will try to escape '"\]'
1191  * characters with '\' as prefix. The same prefix should not be used as
1192  * <escape>.
1193  */
lf_encode_string(char * start,char * stop,const char escape,const long * map,const char * string,struct logformat_node * node)1194 static char *lf_encode_string(char *start, char *stop,
1195                               const char escape, const long *map,
1196                               const char *string,
1197                               struct logformat_node *node)
1198 {
1199 	if (node->options & LOG_OPT_ESC) {
1200 		if (start < stop) {
1201 			stop--; /* reserve one byte for the final '\0' */
1202 			while (start < stop && *string != '\0') {
1203 				if (!ha_bit_test((unsigned char)(*string), map)) {
1204 					if (!ha_bit_test((unsigned char)(*string), rfc5424_escape_map))
1205 						*start++ = *string;
1206 					else {
1207 						if (start + 2 >= stop)
1208 							break;
1209 						*start++ = '\\';
1210 						*start++ = *string;
1211 					}
1212 				}
1213 				else {
1214 					if (start + 3 >= stop)
1215 						break;
1216 					*start++ = escape;
1217 					*start++ = hextab[(*string >> 4) & 15];
1218 					*start++ = hextab[*string & 15];
1219 				}
1220 				string++;
1221 			}
1222 			*start = '\0';
1223 		}
1224 	}
1225 	else {
1226 		return encode_string(start, stop, escape, map, string);
1227 	}
1228 
1229 	return start;
1230 }
1231 
1232 /*
1233  * Encode the chunk.
1234  *
1235  * When using the +E log format option, it will try to escape '"\]'
1236  * characters with '\' as prefix. The same prefix should not be used as
1237  * <escape>.
1238  */
lf_encode_chunk(char * start,char * stop,const char escape,const long * map,const struct buffer * chunk,struct logformat_node * node)1239 static char *lf_encode_chunk(char *start, char *stop,
1240                              const char escape, const long *map,
1241                              const struct buffer *chunk,
1242                              struct logformat_node *node)
1243 {
1244 	char *str, *end;
1245 
1246 	if (node->options & LOG_OPT_ESC) {
1247 		if (start < stop) {
1248 			str = chunk->area;
1249 			end = chunk->area + chunk->data;
1250 
1251 			stop--; /* reserve one byte for the final '\0' */
1252 			while (start < stop && str < end) {
1253 				if (!ha_bit_test((unsigned char)(*str), map)) {
1254 					if (!ha_bit_test((unsigned char)(*str), rfc5424_escape_map))
1255 						*start++ = *str;
1256 					else {
1257 						if (start + 2 >= stop)
1258 							break;
1259 						*start++ = '\\';
1260 						*start++ = *str;
1261 					}
1262 				}
1263 				else {
1264 					if (start + 3 >= stop)
1265 						break;
1266 					*start++ = escape;
1267 					*start++ = hextab[(*str >> 4) & 15];
1268 					*start++ = hextab[*str & 15];
1269 				}
1270 				str++;
1271 			}
1272 			*start = '\0';
1273 		}
1274 	}
1275 	else {
1276 		return encode_chunk(start, stop, escape, map, chunk);
1277 	}
1278 
1279 	return start;
1280 }
1281 
1282 /*
1283  * Write a string in the log string
1284  * Take cares of quote and escape options
1285  *
1286  * Return the address of the \0 character, or NULL on error
1287  */
lf_text_len(char * dst,const char * src,size_t len,size_t size,const struct logformat_node * node)1288 char *lf_text_len(char *dst, const char *src, size_t len, size_t size, const struct logformat_node *node)
1289 {
1290 	if (size < 2)
1291 		return NULL;
1292 
1293 	if (node->options & LOG_OPT_QUOTE) {
1294 		*(dst++) = '"';
1295 		size--;
1296 	}
1297 
1298 	if (src && len) {
1299 		if (++len > size)
1300 			len = size;
1301 		if (node->options & LOG_OPT_ESC) {
1302 			char *ret;
1303 
1304 			ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src);
1305 			if (ret == NULL || *ret != '\0')
1306 				return NULL;
1307 			len = ret - dst;
1308 		}
1309 		else {
1310 			len = strlcpy2(dst, src, len);
1311 		}
1312 
1313 		size -= len;
1314 		dst += len;
1315 	}
1316 	else if ((node->options & (LOG_OPT_QUOTE|LOG_OPT_MANDATORY)) == LOG_OPT_MANDATORY) {
1317 		if (size < 2)
1318 			return NULL;
1319 		*(dst++) = '-';
1320 	}
1321 
1322 	if (node->options & LOG_OPT_QUOTE) {
1323 		if (size < 2)
1324 			return NULL;
1325 		*(dst++) = '"';
1326 	}
1327 
1328 	*dst = '\0';
1329 	return dst;
1330 }
1331 
lf_text(char * dst,const char * src,size_t size,const struct logformat_node * node)1332 static inline char *lf_text(char *dst, const char *src, size_t size, const struct logformat_node *node)
1333 {
1334 	return lf_text_len(dst, src, size, size, node);
1335 }
1336 
1337 /*
1338  * Write a IP address to the log string
1339  * +X option write in hexadecimal notation, most signifant byte on the left
1340  */
lf_ip(char * dst,const struct sockaddr * sockaddr,size_t size,const struct logformat_node * node)1341 char *lf_ip(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
1342 {
1343 	char *ret = dst;
1344 	int iret;
1345 	char pn[INET6_ADDRSTRLEN];
1346 
1347 	if (node->options & LOG_OPT_HEXA) {
1348 		unsigned char *addr = NULL;
1349 		switch (sockaddr->sa_family) {
1350 		case AF_INET:
1351 			addr = (unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr;
1352 			iret = snprintf(dst, size, "%02X%02X%02X%02X", addr[0], addr[1], addr[2], addr[3]);
1353 			break;
1354 		case AF_INET6:
1355 			addr = (unsigned char *)&((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr;
1356 			iret = snprintf(dst, size, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
1357 			                addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
1358 			                addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
1359 			break;
1360 		default:
1361 			return NULL;
1362 		}
1363 		if (iret < 0 || iret > size)
1364 			return NULL;
1365 		ret += iret;
1366 	} else {
1367 		addr_to_str((struct sockaddr_storage *)sockaddr, pn, sizeof(pn));
1368 		ret = lf_text(dst, pn, size, node);
1369 		if (ret == NULL)
1370 			return NULL;
1371 	}
1372 	return ret;
1373 }
1374 
1375 /*
1376  * Write a port to the log
1377  * +X option write in hexadecimal notation, most signifant byte on the left
1378  */
lf_port(char * dst,const struct sockaddr * sockaddr,size_t size,const struct logformat_node * node)1379 char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
1380 {
1381 	char *ret = dst;
1382 	int iret;
1383 
1384 	if (node->options & LOG_OPT_HEXA) {
1385 		const unsigned char *port = (const unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_port;
1386 		iret = snprintf(dst, size, "%02X%02X", port[0], port[1]);
1387 		if (iret < 0 || iret > size)
1388 			return NULL;
1389 		ret += iret;
1390 	} else {
1391 		ret = ltoa_o(get_host_port((struct sockaddr_storage *)sockaddr), dst, size);
1392 		if (ret == NULL)
1393 			return NULL;
1394 	}
1395 	return ret;
1396 }
1397 
1398 /* Re-generate time-based part of the syslog header in RFC3164 format at
1399  * the beginning of logheader once a second and return the pointer to the
1400  * first character after it.
1401  */
update_log_hdr(const time_t time)1402 static char *update_log_hdr(const time_t time)
1403 {
1404 	static THREAD_LOCAL long tvsec;
1405 	static THREAD_LOCAL struct buffer host = { };
1406 	static THREAD_LOCAL int sep = 0;
1407 
1408 	if (unlikely(time != tvsec || logheader_end == NULL)) {
1409 		/* this string is rebuild only once a second */
1410 		struct tm tm;
1411 		int hdr_len;
1412 
1413 		tvsec = time;
1414 		get_localtime(tvsec, &tm);
1415 
1416 		if (unlikely(global.log_send_hostname != host.area)) {
1417 			host.area = global.log_send_hostname;
1418 			host.data = host.area ? strlen(host.area) : 0;
1419 			sep = host.data ? 1 : 0;
1420 		}
1421 
1422 		hdr_len = snprintf(logheader, global.max_syslog_len,
1423 				   "<<<<>%s %2d %02d:%02d:%02d %.*s%*s",
1424 				   monthname[tm.tm_mon],
1425 				   tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
1426 				   (int)host.data, host.area, sep, "");
1427 		/* WARNING: depending upon implementations, snprintf may return
1428 		 * either -1 or the number of bytes that would be needed to store
1429 		 * the total message. In both cases, we must adjust it.
1430 		 */
1431 		if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1432 			hdr_len = global.max_syslog_len;
1433 
1434 		logheader_end = logheader + hdr_len;
1435 	}
1436 
1437 	logheader_end[0] = 0; // ensure we get rid of any previous attempt
1438 
1439 	return logheader_end;
1440 }
1441 
1442 /* Re-generate time-based part of the syslog header in RFC5424 format at
1443  * the beginning of logheader_rfc5424 once a second and return the pointer
1444  * to the first character after it.
1445  */
update_log_hdr_rfc5424(const time_t time)1446 static char *update_log_hdr_rfc5424(const time_t time)
1447 {
1448 	static THREAD_LOCAL long tvsec;
1449 	const char *gmt_offset;
1450 
1451 	if (unlikely(time != tvsec || logheader_rfc5424_end == NULL)) {
1452 		/* this string is rebuild only once a second */
1453 		struct tm tm;
1454 		int hdr_len;
1455 
1456 		tvsec = time;
1457 		get_localtime(tvsec, &tm);
1458 		gmt_offset = get_gmt_offset(time, &tm);
1459 
1460 		hdr_len = snprintf(logheader_rfc5424, global.max_syslog_len,
1461 				   "<<<<>1 %4d-%02d-%02dT%02d:%02d:%02d%.3s:%.2s %s ",
1462 				   tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
1463 				   tm.tm_hour, tm.tm_min, tm.tm_sec,
1464 				   gmt_offset, gmt_offset+3,
1465 				   global.log_send_hostname ? global.log_send_hostname : hostname);
1466 		/* WARNING: depending upon implementations, snprintf may return
1467 		 * either -1 or the number of bytes that would be needed to store
1468 		 * the total message. In both cases, we must adjust it.
1469 		 */
1470 		if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1471 			hdr_len = global.max_syslog_len;
1472 
1473 		logheader_rfc5424_end = logheader_rfc5424 + hdr_len;
1474 	}
1475 
1476 	logheader_rfc5424_end[0] = 0; // ensure we get rid of any previous attempt
1477 
1478 	return logheader_rfc5424_end;
1479 }
1480 
1481 /*
1482  * This function sends the syslog message using a printf format string. It
1483  * expects an LF-terminated message.
1484  */
send_log(struct proxy * p,int level,const char * format,...)1485 void send_log(struct proxy *p, int level, const char *format, ...)
1486 {
1487 	va_list argp;
1488 	int  data_len;
1489 
1490 	if (level < 0 || format == NULL || logline == NULL)
1491 		return;
1492 
1493 	va_start(argp, format);
1494 	data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
1495 	if (data_len < 0 || data_len > global.max_syslog_len)
1496 		data_len = global.max_syslog_len;
1497 	va_end(argp);
1498 
1499 	__send_log((p ? &p->logsrvs : NULL), (p ? &p->log_tag : NULL), level,
1500 		   logline, data_len, default_rfc5424_sd_log_format, 2);
1501 }
1502 
1503 /*
1504  * This function sends a syslog message to <logsrv>.
1505  * <pid_str> is the string to be used for the PID of the caller, <pid_size> is length.
1506  * Same thing for <sd> and <sd_size> which are used for the structured-data part
1507  * in RFC5424 formatted syslog messages, and <tag_str> and <tag_size> the syslog tag.
1508  * It overrides the last byte of the message vector with an LF character.
1509  * Does not return any error,
1510  */
__do_send_log(struct logsrv * logsrv,int nblogger,char * pid_str,size_t pid_size,int level,char * message,size_t size,char * sd,size_t sd_size,char * tag_str,size_t tag_size)1511 static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_str, size_t pid_size,
1512                                  int level, char *message, size_t size, char *sd, size_t sd_size,
1513                                  char *tag_str, size_t tag_size)
1514 {
1515 	static THREAD_LOCAL struct iovec iovec[NB_MSG_IOVEC_ELEMENTS] = { };
1516 	static THREAD_LOCAL struct msghdr msghdr = {
1517 		//.msg_iov = iovec,
1518 		.msg_iovlen = NB_MSG_IOVEC_ELEMENTS
1519 	};
1520 	static THREAD_LOCAL int logfdunix = -1;	/* syslog to AF_UNIX socket */
1521 	static THREAD_LOCAL int logfdinet = -1;	/* syslog to AF_INET socket */
1522 	static THREAD_LOCAL char *dataptr = NULL;
1523 	time_t time = date.tv_sec;
1524 	char *hdr, *hdr_ptr;
1525 	size_t hdr_size;
1526 	int fac_level;
1527 	int *plogfd;
1528 	char *pid_sep1 = "", *pid_sep2 = "";
1529 	char logheader_short[3];
1530 	int sent;
1531 	int maxlen;
1532 	int hdr_max = 0;
1533 	int tag_max = 0;
1534 	int pid_sep1_max = 0;
1535 	int pid_max = 0;
1536 	int pid_sep2_max = 0;
1537 	int sd_max = 0;
1538 	int max = 0;
1539 
1540 	msghdr.msg_iov = iovec;
1541 
1542 	dataptr = message;
1543 
1544 	/* historically some messages used to already contain the trailing LF
1545 	 * or Zero. Let's remove all trailing LF or Zero
1546 	 */
1547 	while (size && ((dataptr[size-1] == '\n' || (dataptr[size-1] == 0))))
1548 		size--;
1549 
1550 	if (logsrv->type == LOG_TARGET_FD) {
1551 		/* the socket's address is a file descriptor */
1552 		plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
1553 	}
1554 	else if (logsrv->type == LOG_TARGET_BUFFER) {
1555 		plogfd = NULL;
1556 	}
1557 	else if (logsrv->addr.ss_family == AF_UNIX)
1558 		plogfd = &logfdunix;
1559 	else
1560 		plogfd = &logfdinet;
1561 
1562 	if (plogfd && unlikely(*plogfd < 0)) {
1563 		/* socket not successfully initialized yet */
1564 		if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
1565 							  (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
1566 			static char once;
1567 
1568 			if (!once) {
1569 				once = 1; /* note: no need for atomic ops here */
1570 				ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
1571 						 nblogger, strerror(errno), errno);
1572 			}
1573 			return;
1574 		} else {
1575 			/* we don't want to receive anything on this socket */
1576 			setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
1577 			/* does nothing under Linux, maybe needed for others */
1578 			shutdown(*plogfd, SHUT_RD);
1579 			fcntl(*plogfd, F_SETFD, fcntl(*plogfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
1580 		}
1581 	}
1582 
1583 	switch (logsrv->format) {
1584 	case LOG_FORMAT_RFC3164:
1585 		hdr = logheader;
1586 		hdr_ptr = update_log_hdr(time);
1587 		break;
1588 
1589 	case LOG_FORMAT_RFC5424:
1590 		hdr = logheader_rfc5424;
1591 		hdr_ptr = update_log_hdr_rfc5424(time);
1592 		sd_max = sd_size; /* the SD part allowed only in RFC5424 */
1593 		break;
1594 
1595 	case LOG_FORMAT_SHORT:
1596 		/* all fields are known, skip the header generation */
1597 		hdr = logheader_short;
1598 		hdr[0] = '<';
1599 		hdr[1] = '0' + MAX(level, logsrv->minlvl);
1600 		hdr[2] = '>';
1601 		hdr_ptr = hdr;
1602 		hdr_max = 3;
1603 		maxlen = logsrv->maxlen - hdr_max;
1604 		max = MIN(size, maxlen - 1);
1605 		goto send;
1606 
1607 	case LOG_FORMAT_RAW:
1608 		/* all fields are known, skip the header generation */
1609 		hdr_ptr = hdr = "";
1610 		hdr_max = 0;
1611 		maxlen = logsrv->maxlen;
1612 		max = MIN(size, maxlen - 1);
1613 		goto send;
1614 
1615 	default:
1616 		return; /* must never happen */
1617 	}
1618 
1619 	hdr_size = hdr_ptr - hdr;
1620 
1621 	/* For each target, we may have a different facility.
1622 	 * We can also have a different log level for each message.
1623 	 * This induces variations in the message header length.
1624 	 * Since we don't want to recompute it each time, nor copy it every
1625 	 * time, we only change the facility in the pre-computed header,
1626 	 * and we change the pointer to the header accordingly.
1627 	 */
1628 	fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
1629 	hdr_ptr = hdr + 3; /* last digit of the log level */
1630 	do {
1631 		*hdr_ptr = '0' + fac_level % 10;
1632 		fac_level /= 10;
1633 		hdr_ptr--;
1634 	} while (fac_level && hdr_ptr > hdr);
1635 	*hdr_ptr = '<';
1636 
1637 	hdr_max = hdr_size - (hdr_ptr - hdr);
1638 
1639 	/* time-based header */
1640 	if (unlikely(hdr_size >= logsrv->maxlen)) {
1641 		hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
1642 		sd_max = 0;
1643 		goto send;
1644 	}
1645 
1646 	maxlen = logsrv->maxlen - hdr_max;
1647 
1648 	/* tag */
1649 	tag_max = tag_size;
1650 	if (unlikely(tag_max >= maxlen)) {
1651 		tag_max = maxlen - 1;
1652 		sd_max = 0;
1653 		goto send;
1654 	}
1655 
1656 	maxlen -= tag_max;
1657 
1658 	/* first pid separator */
1659 	pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
1660 	if (unlikely(pid_sep1_max >= maxlen)) {
1661 		pid_sep1_max = maxlen - 1;
1662 		sd_max = 0;
1663 		goto send;
1664 	}
1665 
1666 	pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
1667 	maxlen -= pid_sep1_max;
1668 
1669 	/* pid */
1670 	pid_max = pid_size;
1671 	if (unlikely(pid_size >= maxlen)) {
1672 		pid_size = maxlen - 1;
1673 		sd_max = 0;
1674 		goto send;
1675 	}
1676 
1677 	maxlen -= pid_size;
1678 
1679 	/* second pid separator */
1680 	pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
1681 	if (unlikely(pid_sep2_max >= maxlen)) {
1682 		pid_sep2_max = maxlen - 1;
1683 		sd_max = 0;
1684 		goto send;
1685 	}
1686 
1687 	pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
1688 	maxlen -= pid_sep2_max;
1689 
1690 	/* structured-data */
1691 	if (sd_max >= maxlen) {
1692 		sd_max = maxlen - 1;
1693 		goto send;
1694 	}
1695 
1696 	max = MIN(size, maxlen - sd_max - 1);
1697 send:
1698 	if (logsrv->addr.ss_family == AF_UNSPEC) {
1699 		/* the target is a file descriptor or a ring buffer */
1700 		struct ist msg[7];
1701 
1702 		msg[0].ptr = hdr_ptr;  msg[0].len = hdr_max;
1703 		msg[1].ptr = tag_str;  msg[1].len = tag_max;
1704 		msg[2].ptr = pid_sep1; msg[2].len = pid_sep1_max;
1705 		msg[3].ptr = pid_str;  msg[3].len = pid_max;
1706 		msg[4].ptr = pid_sep2; msg[4].len = pid_sep2_max;
1707 		msg[5].ptr = sd;       msg[5].len = sd_max;
1708 		msg[6].ptr = dataptr;  msg[6].len = max;
1709 
1710 		if (logsrv->type == LOG_TARGET_BUFFER)
1711 			sent = ring_write(logsrv->ring, ~0, NULL, 0, msg, 7);
1712 		else /* LOG_TARGET_FD */
1713 			sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
1714 	}
1715 	else {
1716 		iovec[0].iov_base = hdr_ptr;
1717 		iovec[0].iov_len  = hdr_max;
1718 		iovec[1].iov_base = tag_str;
1719 		iovec[1].iov_len  = tag_max;
1720 		iovec[2].iov_base = pid_sep1;
1721 		iovec[2].iov_len  = pid_sep1_max;
1722 		iovec[3].iov_base = pid_str;
1723 		iovec[3].iov_len  = pid_max;
1724 		iovec[4].iov_base = pid_sep2;
1725 		iovec[4].iov_len  = pid_sep2_max;
1726 		iovec[5].iov_base = sd;
1727 		iovec[5].iov_len  = sd_max;
1728 		iovec[6].iov_base = dataptr;
1729 		iovec[6].iov_len  = max;
1730 		iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
1731 		iovec[7].iov_len  = 1;
1732 
1733 		msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
1734 		msghdr.msg_namelen = get_addr_len(&logsrv->addr);
1735 
1736 		sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
1737 	}
1738 
1739 	if (sent < 0) {
1740 		static char once;
1741 
1742 		if (errno == EAGAIN)
1743 			_HA_ATOMIC_ADD(&dropped_logs, 1);
1744 		else if (!once) {
1745 			once = 1; /* note: no need for atomic ops here */
1746 			ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
1747 					 nblogger, strerror(errno), errno);
1748 		}
1749 	}
1750 }
1751 
1752 /*
1753  * This function sends a syslog message.
1754  * It doesn't care about errors nor does it report them.
1755  * The arguments <sd> and <sd_size> are used for the structured-data part
1756  * in RFC5424 formatted syslog messages.
1757  */
__send_log(struct list * logsrvs,struct buffer * tag,int level,char * message,size_t size,char * sd,size_t sd_size)1758 void __send_log(struct list *logsrvs, struct buffer *tag, int level,
1759 		char *message, size_t size, char *sd, size_t sd_size)
1760 {
1761 	struct logsrv *logsrv;
1762 	int nblogger;
1763 	static THREAD_LOCAL int curr_pid;
1764 	static THREAD_LOCAL char pidstr[100];
1765 	static THREAD_LOCAL struct buffer pid;
1766 
1767 	if (logsrvs == NULL) {
1768 		if (!LIST_ISEMPTY(&global.logsrvs)) {
1769 			logsrvs = &global.logsrvs;
1770 		}
1771 	}
1772 	if (!tag || !tag->area)
1773 		tag = &global.log_tag;
1774 
1775 	if (!logsrvs || LIST_ISEMPTY(logsrvs))
1776 		return;
1777 
1778 	if (unlikely(curr_pid != getpid())) {
1779 		curr_pid = getpid();
1780 		ltoa_o(curr_pid, pidstr, sizeof(pidstr));
1781 		chunk_initstr(&pid, pidstr);
1782 	}
1783 
1784 	/* Send log messages to syslog server. */
1785 	nblogger = 0;
1786 	list_for_each_entry(logsrv, logsrvs, list) {
1787 		int in_range = 1;
1788 
1789 		/* we can filter the level of the messages that are sent to each logger */
1790 		if (level > logsrv->level)
1791 			continue;
1792 
1793 		if (logsrv->lb.smp_rgs) {
1794 			struct smp_log_range *curr_rg;
1795 
1796 			HA_SPIN_LOCK(LOGSRV_LOCK, &logsrv->lock);
1797 			curr_rg = &logsrv->lb.smp_rgs[logsrv->lb.curr_rg];
1798 			in_range = in_smp_log_range(curr_rg, logsrv->lb.curr_idx);
1799 			if (in_range) {
1800 				/* Let's consume this range. */
1801 				curr_rg->curr_idx = (curr_rg->curr_idx + 1) % curr_rg->sz;
1802 				if (!curr_rg->curr_idx) {
1803 					/* If consumed, let's select the next range. */
1804 					logsrv->lb.curr_rg = (logsrv->lb.curr_rg + 1) % logsrv->lb.smp_rgs_sz;
1805 				}
1806 			}
1807 			logsrv->lb.curr_idx = (logsrv->lb.curr_idx + 1) % logsrv->lb.smp_sz;
1808 			HA_SPIN_UNLOCK(LOGSRV_LOCK, &logsrv->lock);
1809 		}
1810 		if (in_range)
1811 			__do_send_log(logsrv, ++nblogger, pid.area, pid.data, level,
1812 			              message, size, sd, sd_size, tag->area, tag->data);
1813 	}
1814 }
1815 
1816 
1817 const char sess_cookie[8]     = "NIDVEOU7";	/* No cookie, Invalid cookie, cookie for a Down server, Valid cookie, Expired cookie, Old cookie, Unused, unknown */
1818 const char sess_set_cookie[8] = "NPDIRU67";	/* No set-cookie, Set-cookie found and left unchanged (passive),
1819 						   Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
1820 						   Set-cookie Updated, unknown, unknown */
1821 
1822 /*
1823  * try to write a character if there is enough space, or goto out
1824  */
1825 #define LOGCHAR(x) do { \
1826 			if (tmplog < dst + maxsize - 1) { \
1827 				*(tmplog++) = (x);                     \
1828 			} else {                                       \
1829 				goto out;                              \
1830 			}                                              \
1831 		} while(0)
1832 
1833 
1834 /* Initializes some log data at boot */
init_log()1835 static void init_log()
1836 {
1837 	char *tmp;
1838 	int i;
1839 
1840 	/* Initialize the escape map for the RFC5424 structured-data : '"\]'
1841 	 * inside PARAM-VALUE should be escaped with '\' as prefix.
1842 	 * See https://tools.ietf.org/html/rfc5424#section-6.3.3 for more
1843 	 * details.
1844 	 */
1845 	memset(rfc5424_escape_map, 0, sizeof(rfc5424_escape_map));
1846 
1847 	tmp = "\"\\]";
1848 	while (*tmp) {
1849 		ha_bit_set(*tmp, rfc5424_escape_map);
1850 		tmp++;
1851 	}
1852 
1853 	/* initialize the log header encoding map : '{|}"#' should be encoded with
1854 	 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
1855 	 * URL encoding only requires '"', '#' to be encoded as well as non-
1856 	 * printable characters above.
1857 	 */
1858 	memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
1859 	memset(url_encode_map, 0, sizeof(url_encode_map));
1860 	for (i = 0; i < 32; i++) {
1861 		ha_bit_set(i, hdr_encode_map);
1862 		ha_bit_set(i, url_encode_map);
1863 	}
1864 	for (i = 127; i < 256; i++) {
1865 		ha_bit_set(i, hdr_encode_map);
1866 		ha_bit_set(i, url_encode_map);
1867 	}
1868 
1869 	tmp = "\"#{|}";
1870 	while (*tmp) {
1871 		ha_bit_set(*tmp, hdr_encode_map);
1872 		tmp++;
1873 	}
1874 
1875 	tmp = "\"#";
1876 	while (*tmp) {
1877 		ha_bit_set(*tmp, url_encode_map);
1878 		tmp++;
1879 	}
1880 
1881 	/* initialize the http header encoding map. The draft httpbis define the
1882 	 * header content as:
1883 	 *
1884 	 *    HTTP-message   = start-line
1885 	 *                     *( header-field CRLF )
1886 	 *                     CRLF
1887 	 *                     [ message-body ]
1888 	 *    header-field   = field-name ":" OWS field-value OWS
1889 	 *    field-value    = *( field-content / obs-fold )
1890 	 *    field-content  = field-vchar [ 1*( SP / HTAB ) field-vchar ]
1891 	 *    obs-fold       = CRLF 1*( SP / HTAB )
1892 	 *    field-vchar    = VCHAR / obs-text
1893 	 *    VCHAR          = %x21-7E
1894 	 *    obs-text       = %x80-FF
1895 	 *
1896 	 * All the chars are encoded except "VCHAR", "obs-text", SP and HTAB.
1897 	 * The encoded chars are form 0x00 to 0x08, 0x0a to 0x1f and 0x7f. The
1898 	 * "obs-fold" is voluntarily forgotten because haproxy remove this.
1899 	 */
1900 	memset(http_encode_map, 0, sizeof(http_encode_map));
1901 	for (i = 0x00; i <= 0x08; i++)
1902 		ha_bit_set(i, http_encode_map);
1903 	for (i = 0x0a; i <= 0x1f; i++)
1904 		ha_bit_set(i, http_encode_map);
1905 	ha_bit_set(0x7f, http_encode_map);
1906 }
1907 
1908 INITCALL0(STG_PREPARE, init_log);
1909 
1910 /* Initialize log buffers used for syslog messages */
init_log_buffers()1911 int init_log_buffers()
1912 {
1913 	logheader = my_realloc2(logheader, global.max_syslog_len + 1);
1914 	logheader_end = NULL;
1915 	logheader_rfc5424 = my_realloc2(logheader_rfc5424, global.max_syslog_len + 1);
1916 	logheader_rfc5424_end = NULL;
1917 	logline = my_realloc2(logline, global.max_syslog_len + 1);
1918 	logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
1919 	if (!logheader || !logline_rfc5424 || !logline || !logline_rfc5424)
1920 		return 0;
1921 	return 1;
1922 }
1923 
1924 /* Deinitialize log buffers used for syslog messages */
deinit_log_buffers()1925 void deinit_log_buffers()
1926 {
1927 	free(logheader);
1928 	free(logheader_rfc5424);
1929 	free(logline);
1930 	free(logline_rfc5424);
1931 	ring_free(_HA_ATOMIC_XCHG(&startup_logs, NULL));
1932 	logheader         = NULL;
1933 	logheader_rfc5424 = NULL;
1934 	logline           = NULL;
1935 	logline_rfc5424   = NULL;
1936 }
1937 
1938 /* Builds a log line in <dst> based on <list_format>, and stops before reaching
1939  * <maxsize> characters. Returns the size of the output string in characters,
1940  * not counting the trailing zero which is always added if the resulting size
1941  * is not zero. It requires a valid session and optionally a stream. If the
1942  * stream is NULL, default values will be assumed for the stream part.
1943  */
sess_build_logline(struct session * sess,struct stream * s,char * dst,size_t maxsize,struct list * list_format)1944 int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t maxsize, struct list *list_format)
1945 {
1946 	struct proxy *fe = sess->fe;
1947 	struct proxy *be;
1948 	struct http_txn *txn;
1949 	const struct strm_logs *logs;
1950 	struct connection *be_conn;
1951 	unsigned int s_flags;
1952 	unsigned int uniq_id;
1953 	struct buffer chunk;
1954 	char *uri;
1955 	char *spc;
1956 	char *qmark;
1957 	char *end;
1958 	struct tm tm;
1959 	int t_request;
1960 	int hdr;
1961 	int last_isspace = 1;
1962 	int nspaces = 0;
1963 	char *tmplog;
1964 	char *ret;
1965 	int iret;
1966 	struct logformat_node *tmp;
1967 	struct timeval tv;
1968 	struct strm_logs tmp_strm_log;
1969 
1970 	/* FIXME: let's limit ourselves to frontend logging for now. */
1971 
1972 	if (likely(s)) {
1973 		be = s->be;
1974 		txn = s->txn;
1975 		be_conn = cs_conn(objt_cs(s->si[1].end));
1976 		s_flags = s->flags;
1977 		uniq_id = s->uniq_id;
1978 		logs = &s->logs;
1979 	} else {
1980 		/* we have no stream so we first need to initialize a few
1981 		 * things that are needed later. We do increment the request
1982 		 * ID so that it's uniquely assigned to this request just as
1983 		 * if the request had reached the point of being processed.
1984 		 * A request error is reported as it's the only element we have
1985 		 * here and which justifies emitting such a log.
1986 		 */
1987 		be = fe;
1988 		txn = NULL;
1989 		be_conn = NULL;
1990 		s_flags = SF_ERR_PRXCOND | SF_FINST_R;
1991 		uniq_id = _HA_ATOMIC_XADD(&global.req_count, 1);
1992 
1993 		/* prepare a valid log structure */
1994 		tmp_strm_log.tv_accept = sess->tv_accept;
1995 		tmp_strm_log.accept_date = sess->accept_date;
1996 		tmp_strm_log.t_handshake = sess->t_handshake;
1997 		tmp_strm_log.t_idle = tv_ms_elapsed(&sess->tv_accept, &now) - sess->t_handshake;
1998 		tv_zero(&tmp_strm_log.tv_request);
1999 		tmp_strm_log.t_queue = -1;
2000 		tmp_strm_log.t_connect = -1;
2001 		tmp_strm_log.t_data = -1;
2002 		tmp_strm_log.t_close = tv_ms_elapsed(&sess->tv_accept, &now);
2003 		tmp_strm_log.bytes_in = 0;
2004 		tmp_strm_log.bytes_out = 0;
2005 		tmp_strm_log.prx_queue_pos = 0;
2006 		tmp_strm_log.srv_queue_pos = 0;
2007 
2008 		logs = &tmp_strm_log;
2009 	}
2010 
2011 	t_request = -1;
2012 	if (tv_isge(&logs->tv_request, &logs->tv_accept))
2013 		t_request = tv_ms_elapsed(&logs->tv_accept, &logs->tv_request);
2014 
2015 	tmplog = dst;
2016 
2017 	/* fill logbuffer */
2018 	if (LIST_ISEMPTY(list_format))
2019 		return 0;
2020 
2021 	list_for_each_entry(tmp, list_format, list) {
2022 		struct connection *conn;
2023 		const char *src = NULL;
2024 		struct sample *key;
2025 		const struct buffer empty = { };
2026 
2027 		switch (tmp->type) {
2028 			case LOG_FMT_SEPARATOR:
2029 				if (!last_isspace) {
2030 					LOGCHAR(' ');
2031 					last_isspace = 1;
2032 				}
2033 				break;
2034 
2035 			case LOG_FMT_TEXT: // text
2036 				src = tmp->arg;
2037 				iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
2038 				if (iret == 0)
2039 					goto out;
2040 				tmplog += iret;
2041 				last_isspace = 0;
2042 				break;
2043 
2044 			case LOG_FMT_EXPR: // sample expression, may be request or response
2045 				key = NULL;
2046 				if (tmp->options & LOG_OPT_REQ_CAP && s)
2047 					key = sample_fetch_as_type(be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, tmp->expr, SMP_T_STR);
2048 				if (!key && (tmp->options & LOG_OPT_RES_CAP) && s)
2049 					key = sample_fetch_as_type(be, sess, s, SMP_OPT_DIR_RES|SMP_OPT_FINAL, tmp->expr, SMP_T_STR);
2050 				if (tmp->options & LOG_OPT_HTTP)
2051 					ret = lf_encode_chunk(tmplog, dst + maxsize,
2052 					                      '%', http_encode_map, key ? &key->data.u.str : &empty, tmp);
2053 				else
2054 					ret = lf_text_len(tmplog,
2055 							  key ? key->data.u.str.area : NULL,
2056 							  key ? key->data.u.str.data : 0,
2057 							  dst + maxsize - tmplog,
2058 							  tmp);
2059 				if (ret == 0)
2060 					goto out;
2061 				tmplog = ret;
2062 				last_isspace = 0;
2063 				break;
2064 
2065 			case LOG_FMT_CLIENTIP:  // %ci
2066 				conn = objt_conn(sess->origin);
2067 				if (conn && conn_get_src(conn))
2068 					ret = lf_ip(tmplog, (struct sockaddr *)conn->src, dst + maxsize - tmplog, tmp);
2069 				else
2070 					ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2071 				if (ret == NULL)
2072 					goto out;
2073 				tmplog = ret;
2074 				last_isspace = 0;
2075 				break;
2076 
2077 			case LOG_FMT_CLIENTPORT:  // %cp
2078 				conn = objt_conn(sess->origin);
2079 				if (conn && conn_get_src(conn)) {
2080 					if (conn->src->ss_family == AF_UNIX) {
2081 						ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
2082 					} else {
2083 						ret = lf_port(tmplog, (struct sockaddr *)conn->src,
2084 						              dst + maxsize - tmplog, tmp);
2085 					}
2086 				}
2087 				else
2088 					ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2089 
2090 				if (ret == NULL)
2091 					goto out;
2092 				tmplog = ret;
2093 				last_isspace = 0;
2094 				break;
2095 
2096 			case LOG_FMT_FRONTENDIP: // %fi
2097 				conn = objt_conn(sess->origin);
2098 				if (conn && conn_get_dst(conn)) {
2099 					ret = lf_ip(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
2100 				}
2101 				else
2102 					ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2103 
2104 				if (ret == NULL)
2105 					goto out;
2106 				tmplog = ret;
2107 				last_isspace = 0;
2108 				break;
2109 
2110 			case  LOG_FMT_FRONTENDPORT: // %fp
2111 				conn = objt_conn(sess->origin);
2112 				if (conn && conn_get_dst(conn)) {
2113 					if (conn->dst->ss_family == AF_UNIX)
2114 						ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
2115 					else
2116 						ret = lf_port(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
2117 				}
2118 				else
2119 					ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2120 
2121 				if (ret == NULL)
2122 					goto out;
2123 				tmplog = ret;
2124 				last_isspace = 0;
2125 				break;
2126 
2127 			case LOG_FMT_BACKENDIP:  // %bi
2128 				if (be_conn && conn_get_src(be_conn))
2129 					ret = lf_ip(tmplog, (const struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
2130 				else
2131 					ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2132 
2133 				if (ret == NULL)
2134 					goto out;
2135 				tmplog = ret;
2136 				last_isspace = 0;
2137 				break;
2138 
2139 			case LOG_FMT_BACKENDPORT:  // %bp
2140 				if (be_conn && conn_get_src(be_conn))
2141 					ret = lf_port(tmplog, (struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
2142 				else
2143 					ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2144 
2145 				if (ret == NULL)
2146 					goto out;
2147 				tmplog = ret;
2148 				last_isspace = 0;
2149 				break;
2150 
2151 			case LOG_FMT_SERVERIP: // %si
2152 				if (be_conn && conn_get_dst(be_conn))
2153 					ret = lf_ip(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
2154 				else
2155 					ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2156 
2157 				if (ret == NULL)
2158 					goto out;
2159 				tmplog = ret;
2160 				last_isspace = 0;
2161 				break;
2162 
2163 			case LOG_FMT_SERVERPORT: // %sp
2164 				if (be_conn && conn_get_dst(be_conn))
2165 					ret = lf_port(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
2166 				else
2167 					ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2168 
2169 				if (ret == NULL)
2170 					goto out;
2171 				tmplog = ret;
2172 				last_isspace = 0;
2173 				break;
2174 
2175 			case LOG_FMT_DATE: // %t = accept date
2176 				get_localtime(logs->accept_date.tv_sec, &tm);
2177 				ret = date2str_log(tmplog, &tm, &logs->accept_date, dst + maxsize - tmplog);
2178 				if (ret == NULL)
2179 					goto out;
2180 				tmplog = ret;
2181 				last_isspace = 0;
2182 				break;
2183 
2184 			case LOG_FMT_tr: // %tr = start of request date
2185 				/* Note that the timers are valid if we get here */
2186 				tv_ms_add(&tv, &logs->accept_date, logs->t_idle >= 0 ? logs->t_idle + logs->t_handshake : 0);
2187 				get_localtime(tv.tv_sec, &tm);
2188 				ret = date2str_log(tmplog, &tm, &tv, dst + maxsize - tmplog);
2189 				if (ret == NULL)
2190 					goto out;
2191 				tmplog = ret;
2192 				last_isspace = 0;
2193 				break;
2194 
2195 			case LOG_FMT_DATEGMT: // %T = accept date, GMT
2196 				get_gmtime(logs->accept_date.tv_sec, &tm);
2197 				ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
2198 				if (ret == NULL)
2199 					goto out;
2200 				tmplog = ret;
2201 				last_isspace = 0;
2202 				break;
2203 
2204 			case LOG_FMT_trg: // %trg = start of request date, GMT
2205 				tv_ms_add(&tv, &logs->accept_date, logs->t_idle >= 0 ? logs->t_idle + logs->t_handshake : 0);
2206 				get_gmtime(tv.tv_sec, &tm);
2207 				ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
2208 				if (ret == NULL)
2209 					goto out;
2210 				tmplog = ret;
2211 				last_isspace = 0;
2212 				break;
2213 
2214 			case LOG_FMT_DATELOCAL: // %Tl = accept date, local
2215 				get_localtime(logs->accept_date.tv_sec, &tm);
2216 				ret = localdate2str_log(tmplog, logs->accept_date.tv_sec, &tm, dst + maxsize - tmplog);
2217 				if (ret == NULL)
2218 					goto out;
2219 				tmplog = ret;
2220 				last_isspace = 0;
2221 				break;
2222 
2223 			case LOG_FMT_trl: // %trl = start of request date, local
2224 				tv_ms_add(&tv, &logs->accept_date, logs->t_idle >= 0 ? logs->t_idle + logs->t_handshake : 0);
2225 				get_localtime(tv.tv_sec, &tm);
2226 				ret = localdate2str_log(tmplog, tv.tv_sec, &tm, dst + maxsize - tmplog);
2227 				if (ret == NULL)
2228 					goto out;
2229 				tmplog = ret;
2230 				last_isspace = 0;
2231 				break;
2232 
2233 			case LOG_FMT_TS: // %Ts
2234 				if (tmp->options & LOG_OPT_HEXA) {
2235 					iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", (unsigned int)logs->accept_date.tv_sec);
2236 					if (iret < 0 || iret > dst + maxsize - tmplog)
2237 						goto out;
2238 					last_isspace = 0;
2239 					tmplog += iret;
2240 				} else {
2241 					ret = ltoa_o(logs->accept_date.tv_sec, tmplog, dst + maxsize - tmplog);
2242 					if (ret == NULL)
2243 						goto out;
2244 					tmplog = ret;
2245 					last_isspace = 0;
2246 				}
2247 			break;
2248 
2249 			case LOG_FMT_MS: // %ms
2250 			if (tmp->options & LOG_OPT_HEXA) {
2251 					iret = snprintf(tmplog, dst + maxsize - tmplog, "%02X",(unsigned int)logs->accept_date.tv_usec/1000);
2252 					if (iret < 0 || iret > dst + maxsize - tmplog)
2253 						goto out;
2254 					last_isspace = 0;
2255 					tmplog += iret;
2256 			} else {
2257 				if ((dst + maxsize - tmplog) < 4)
2258 					goto out;
2259 				ret = utoa_pad((unsigned int)logs->accept_date.tv_usec/1000,
2260 				               tmplog, 4);
2261 				if (ret == NULL)
2262 					goto out;
2263 				tmplog = ret;
2264 				last_isspace = 0;
2265 			}
2266 			break;
2267 
2268 			case LOG_FMT_FRONTEND: // %f
2269 				src = fe->id;
2270 				ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2271 				if (ret == NULL)
2272 					goto out;
2273 				tmplog = ret;
2274 				last_isspace = 0;
2275 				break;
2276 
2277 			case LOG_FMT_FRONTEND_XPRT: // %ft
2278 				src = fe->id;
2279 				if (tmp->options & LOG_OPT_QUOTE)
2280 					LOGCHAR('"');
2281 				iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
2282 				if (iret == 0)
2283 					goto out;
2284 				tmplog += iret;
2285 				if (sess->listener->bind_conf->xprt == xprt_get(XPRT_SSL))
2286 					LOGCHAR('~');
2287 				if (tmp->options & LOG_OPT_QUOTE)
2288 					LOGCHAR('"');
2289 				last_isspace = 0;
2290 				break;
2291 #ifdef USE_OPENSSL
2292 			case LOG_FMT_SSL_CIPHER: // %sslc
2293 				src = NULL;
2294 				conn = objt_conn(sess->origin);
2295 				if (conn) {
2296 					src = ssl_sock_get_cipher_name(conn);
2297 				}
2298 				ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2299 				if (ret == NULL)
2300 					goto out;
2301 				tmplog = ret;
2302 				last_isspace = 0;
2303 				break;
2304 
2305 			case LOG_FMT_SSL_VERSION: // %sslv
2306 				src = NULL;
2307 				conn = objt_conn(sess->origin);
2308 				if (conn) {
2309 					src = ssl_sock_get_proto_version(conn);
2310 				}
2311 				ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2312 				if (ret == NULL)
2313 					goto out;
2314 				tmplog = ret;
2315 				last_isspace = 0;
2316 				break;
2317 #endif
2318 			case LOG_FMT_BACKEND: // %b
2319 				src = be->id;
2320 				ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2321 				if (ret == NULL)
2322 					goto out;
2323 				tmplog = ret;
2324 				last_isspace = 0;
2325 				break;
2326 
2327 			case LOG_FMT_SERVER: // %s
2328 				switch (obj_type(s ? s->target : NULL)) {
2329 				case OBJ_TYPE_SERVER:
2330 					src = __objt_server(s->target)->id;
2331 					break;
2332 				case OBJ_TYPE_APPLET:
2333 					src = __objt_applet(s->target)->name;
2334 					break;
2335 				default:
2336 					src = "<NOSRV>";
2337 					break;
2338 				}
2339 				ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2340 				if (ret == NULL)
2341 					goto out;
2342 				tmplog = ret;
2343 				last_isspace = 0;
2344 				break;
2345 
2346 			case LOG_FMT_Th: // %Th = handshake time
2347 				ret = ltoa_o(logs->t_handshake, tmplog, dst + maxsize - tmplog);
2348 				if (ret == NULL)
2349 					goto out;
2350 				tmplog = ret;
2351 				last_isspace = 0;
2352 				break;
2353 
2354 			case LOG_FMT_Ti: // %Ti = HTTP idle time
2355 				ret = ltoa_o(logs->t_idle, tmplog, dst + maxsize - tmplog);
2356 				if (ret == NULL)
2357 					goto out;
2358 				tmplog = ret;
2359 				last_isspace = 0;
2360 				break;
2361 
2362 			case LOG_FMT_TR: // %TR = HTTP request time
2363 				ret = ltoa_o((t_request >= 0) ? t_request - logs->t_idle - logs->t_handshake : -1,
2364 				             tmplog, dst + maxsize - tmplog);
2365 				if (ret == NULL)
2366 					goto out;
2367 				tmplog = ret;
2368 				last_isspace = 0;
2369 				break;
2370 
2371 			case LOG_FMT_TQ: // %Tq = Th + Ti + TR
2372 				ret = ltoa_o(t_request, tmplog, dst + maxsize - tmplog);
2373 				if (ret == NULL)
2374 					goto out;
2375 				tmplog = ret;
2376 				last_isspace = 0;
2377 				break;
2378 
2379 			case LOG_FMT_TW: // %Tw
2380 				ret = ltoa_o((logs->t_queue >= 0) ? logs->t_queue - t_request : -1,
2381 						tmplog, dst + maxsize - tmplog);
2382 				if (ret == NULL)
2383 					goto out;
2384 				tmplog = ret;
2385 				last_isspace = 0;
2386 				break;
2387 
2388 			case LOG_FMT_TC: // %Tc
2389 				ret = ltoa_o((logs->t_connect >= 0) ? logs->t_connect - logs->t_queue : -1,
2390 						tmplog, dst + maxsize - tmplog);
2391 				if (ret == NULL)
2392 					goto out;
2393 				tmplog = ret;
2394 				last_isspace = 0;
2395 				break;
2396 
2397 			case LOG_FMT_Tr: // %Tr
2398 				ret = ltoa_o((logs->t_data >= 0) ? logs->t_data - logs->t_connect : -1,
2399 						tmplog, dst + maxsize - tmplog);
2400 				if (ret == NULL)
2401 					goto out;
2402 				tmplog = ret;
2403 				last_isspace = 0;
2404 				break;
2405 
2406 			case LOG_FMT_TD: // %Td
2407 				if (be->mode == PR_MODE_HTTP)
2408 					ret = ltoa_o((logs->t_data >= 0) ? logs->t_close - logs->t_data : -1,
2409 					             tmplog, dst + maxsize - tmplog);
2410 				else
2411 					ret = ltoa_o((logs->t_connect >= 0) ? logs->t_close - logs->t_connect : -1,
2412 					             tmplog, dst + maxsize - tmplog);
2413 				if (ret == NULL)
2414 					goto out;
2415 				tmplog = ret;
2416 				last_isspace = 0;
2417 				break;
2418 
2419 			case LOG_FMT_Ta:  // %Ta = active time = Tt - Th - Ti
2420 				if (!(fe->to_log & LW_BYTES))
2421 					LOGCHAR('+');
2422 				ret = ltoa_o(logs->t_close - (logs->t_idle >= 0 ? logs->t_idle + logs->t_handshake : 0),
2423 					     tmplog, dst + maxsize - tmplog);
2424 				if (ret == NULL)
2425 					goto out;
2426 				tmplog = ret;
2427 				last_isspace = 0;
2428 				break;
2429 
2430 			case LOG_FMT_TT:  // %Tt = total time
2431 				if (!(fe->to_log & LW_BYTES))
2432 					LOGCHAR('+');
2433 				ret = ltoa_o(logs->t_close, tmplog, dst + maxsize - tmplog);
2434 				if (ret == NULL)
2435 					goto out;
2436 				tmplog = ret;
2437 				last_isspace = 0;
2438 				break;
2439 
2440 			case LOG_FMT_STATUS: // %ST
2441 				ret = ltoa_o(txn ? txn->status : 0, tmplog, dst + maxsize - tmplog);
2442 				if (ret == NULL)
2443 					goto out;
2444 				tmplog = ret;
2445 				last_isspace = 0;
2446 				break;
2447 
2448 			case LOG_FMT_BYTES: // %B
2449 				if (!(fe->to_log & LW_BYTES))
2450 					LOGCHAR('+');
2451 				ret = lltoa(logs->bytes_out, tmplog, dst + maxsize - tmplog);
2452 				if (ret == NULL)
2453 					goto out;
2454 				tmplog = ret;
2455 				last_isspace = 0;
2456 				break;
2457 
2458 			case LOG_FMT_BYTES_UP: // %U
2459 				ret = lltoa(logs->bytes_in, tmplog, dst + maxsize - tmplog);
2460 				if (ret == NULL)
2461 					goto out;
2462 				tmplog = ret;
2463 				last_isspace = 0;
2464 				break;
2465 
2466 			case LOG_FMT_CCLIENT: // %CC
2467 				src = txn ? txn->cli_cookie : NULL;
2468 				ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2469 				if (ret == NULL)
2470 					goto out;
2471 				tmplog = ret;
2472 				last_isspace = 0;
2473 				break;
2474 
2475 			case LOG_FMT_CSERVER: // %CS
2476 				src = txn ? txn->srv_cookie : NULL;
2477 				ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2478 				if (ret == NULL)
2479 					goto out;
2480 				tmplog = ret;
2481 				last_isspace = 0;
2482 				break;
2483 
2484 			case LOG_FMT_TERMSTATE: // %ts
2485 				LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2486 				LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
2487 				*tmplog = '\0';
2488 				last_isspace = 0;
2489 				break;
2490 
2491 			case LOG_FMT_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
2492 				LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2493 				LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
2494 				LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-');
2495 				LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_set_cookie[(txn->flags & TX_SCK_MASK) >> TX_SCK_SHIFT] : '-');
2496 				last_isspace = 0;
2497 				break;
2498 
2499 			case LOG_FMT_ACTCONN: // %ac
2500 				ret = ltoa_o(actconn, tmplog, dst + maxsize - tmplog);
2501 				if (ret == NULL)
2502 					goto out;
2503 				tmplog = ret;
2504 				last_isspace = 0;
2505 				break;
2506 
2507 			case LOG_FMT_FECONN:  // %fc
2508 				ret = ltoa_o(fe->feconn, tmplog, dst + maxsize - tmplog);
2509 				if (ret == NULL)
2510 					goto out;
2511 				tmplog = ret;
2512 				last_isspace = 0;
2513 				break;
2514 
2515 			case LOG_FMT_BECONN:  // %bc
2516 				ret = ltoa_o(be->beconn, tmplog, dst + maxsize - tmplog);
2517 				if (ret == NULL)
2518 					goto out;
2519 				tmplog = ret;
2520 				last_isspace = 0;
2521 				break;
2522 
2523 			case LOG_FMT_SRVCONN:  // %sc
2524 				ret = ultoa_o(objt_server(s ? s->target : NULL) ?
2525 				                 objt_server(s->target)->cur_sess :
2526 				                 0, tmplog, dst + maxsize - tmplog);
2527 				if (ret == NULL)
2528 					goto out;
2529 				tmplog = ret;
2530 				last_isspace = 0;
2531 				break;
2532 
2533 			case LOG_FMT_RETRIES:  // %rq
2534 				if (s_flags & SF_REDISP)
2535 					LOGCHAR('+');
2536 				ret = ltoa_o((s && s->si[1].conn_retries > 0) ?
2537 				                (be->conn_retries - s->si[1].conn_retries) :
2538 				                be->conn_retries, tmplog, dst + maxsize - tmplog);
2539 				if (ret == NULL)
2540 					goto out;
2541 				tmplog = ret;
2542 				last_isspace = 0;
2543 				break;
2544 
2545 			case LOG_FMT_SRVQUEUE: // %sq
2546 				ret = ltoa_o(logs->srv_queue_pos, tmplog, dst + maxsize - tmplog);
2547 				if (ret == NULL)
2548 					goto out;
2549 				tmplog = ret;
2550 				last_isspace = 0;
2551 				break;
2552 
2553 			case LOG_FMT_BCKQUEUE:  // %bq
2554 				ret = ltoa_o(logs->prx_queue_pos, tmplog, dst + maxsize - tmplog);
2555 				if (ret == NULL)
2556 					goto out;
2557 				tmplog = ret;
2558 				last_isspace = 0;
2559 				break;
2560 
2561 			case LOG_FMT_HDRREQUEST: // %hr
2562 				/* request header */
2563 				if (fe->nb_req_cap && s && s->req_cap) {
2564 					if (tmp->options & LOG_OPT_QUOTE)
2565 						LOGCHAR('"');
2566 					LOGCHAR('{');
2567 					for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2568 						if (hdr)
2569 							LOGCHAR('|');
2570 						if (s->req_cap[hdr] != NULL) {
2571 							ret = lf_encode_string(tmplog, dst + maxsize,
2572 							                       '#', hdr_encode_map, s->req_cap[hdr], tmp);
2573 							if (ret == NULL || *ret != '\0')
2574 								goto out;
2575 							tmplog = ret;
2576 						}
2577 					}
2578 					LOGCHAR('}');
2579 					if (tmp->options & LOG_OPT_QUOTE)
2580 						LOGCHAR('"');
2581 					last_isspace = 0;
2582 				}
2583 				break;
2584 
2585 			case LOG_FMT_HDRREQUESTLIST: // %hrl
2586 				/* request header list */
2587 				if (fe->nb_req_cap && s && s->req_cap) {
2588 					for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2589 						if (hdr > 0)
2590 							LOGCHAR(' ');
2591 						if (tmp->options & LOG_OPT_QUOTE)
2592 							LOGCHAR('"');
2593 						if (s->req_cap[hdr] != NULL) {
2594 							ret = lf_encode_string(tmplog, dst + maxsize,
2595 							                       '#', hdr_encode_map, s->req_cap[hdr], tmp);
2596 							if (ret == NULL || *ret != '\0')
2597 								goto out;
2598 							tmplog = ret;
2599 						} else if (!(tmp->options & LOG_OPT_QUOTE))
2600 							LOGCHAR('-');
2601 						if (tmp->options & LOG_OPT_QUOTE)
2602 							LOGCHAR('"');
2603 						last_isspace = 0;
2604 					}
2605 				}
2606 				break;
2607 
2608 
2609 			case LOG_FMT_HDRRESPONS: // %hs
2610 				/* response header */
2611 				if (fe->nb_rsp_cap && s && s->res_cap) {
2612 					if (tmp->options & LOG_OPT_QUOTE)
2613 						LOGCHAR('"');
2614 					LOGCHAR('{');
2615 					for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2616 						if (hdr)
2617 							LOGCHAR('|');
2618 						if (s->res_cap[hdr] != NULL) {
2619 							ret = lf_encode_string(tmplog, dst + maxsize,
2620 							                       '#', hdr_encode_map, s->res_cap[hdr], tmp);
2621 							if (ret == NULL || *ret != '\0')
2622 								goto out;
2623 							tmplog = ret;
2624 						}
2625 					}
2626 					LOGCHAR('}');
2627 					last_isspace = 0;
2628 					if (tmp->options & LOG_OPT_QUOTE)
2629 						LOGCHAR('"');
2630 				}
2631 				break;
2632 
2633 			case LOG_FMT_HDRRESPONSLIST: // %hsl
2634 				/* response header list */
2635 				if (fe->nb_rsp_cap && s && s->res_cap) {
2636 					for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2637 						if (hdr > 0)
2638 							LOGCHAR(' ');
2639 						if (tmp->options & LOG_OPT_QUOTE)
2640 							LOGCHAR('"');
2641 						if (s->res_cap[hdr] != NULL) {
2642 							ret = lf_encode_string(tmplog, dst + maxsize,
2643 							                       '#', hdr_encode_map, s->res_cap[hdr], tmp);
2644 							if (ret == NULL || *ret != '\0')
2645 								goto out;
2646 							tmplog = ret;
2647 						} else if (!(tmp->options & LOG_OPT_QUOTE))
2648 							LOGCHAR('-');
2649 						if (tmp->options & LOG_OPT_QUOTE)
2650 							LOGCHAR('"');
2651 						last_isspace = 0;
2652 					}
2653 				}
2654 				break;
2655 
2656 			case LOG_FMT_REQ: // %r
2657 				/* Request */
2658 				if (tmp->options & LOG_OPT_QUOTE)
2659 					LOGCHAR('"');
2660 				uri = txn && txn->uri ? txn->uri : "<BADREQ>";
2661 				ret = lf_encode_string(tmplog, dst + maxsize,
2662 				                       '#', url_encode_map, uri, tmp);
2663 				if (ret == NULL || *ret != '\0')
2664 					goto out;
2665 				tmplog = ret;
2666 				if (tmp->options & LOG_OPT_QUOTE)
2667 					LOGCHAR('"');
2668 				last_isspace = 0;
2669 				break;
2670 
2671 			case LOG_FMT_HTTP_PATH: // %HP
2672 				uri = txn && txn->uri ? txn->uri : "<BADREQ>";
2673 
2674 				if (tmp->options & LOG_OPT_QUOTE)
2675 					LOGCHAR('"');
2676 
2677 				end = uri + strlen(uri);
2678 				// look for the first whitespace character
2679 				while (uri < end && !HTTP_IS_SPHT(*uri))
2680 					uri++;
2681 
2682 				// keep advancing past multiple spaces
2683 				while (uri < end && HTTP_IS_SPHT(*uri)) {
2684 					uri++; nspaces++;
2685 				}
2686 
2687 				// look for first space or question mark after url
2688 				spc = uri;
2689 				while (spc < end && *spc != '?' && !HTTP_IS_SPHT(*spc))
2690 					spc++;
2691 
2692 				if (!txn || !txn->uri || nspaces == 0) {
2693 					chunk.area = "<BADREQ>";
2694 					chunk.data = strlen("<BADREQ>");
2695 				} else {
2696 					chunk.area = uri;
2697 					chunk.data = spc - uri;
2698 				}
2699 
2700 				ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
2701 				if (ret == NULL || *ret != '\0')
2702 					goto out;
2703 
2704 				tmplog = ret;
2705 				if (tmp->options & LOG_OPT_QUOTE)
2706 					LOGCHAR('"');
2707 
2708 				last_isspace = 0;
2709 				break;
2710 
2711 			case LOG_FMT_HTTP_QUERY: // %HQ
2712 				if (tmp->options & LOG_OPT_QUOTE)
2713 					LOGCHAR('"');
2714 
2715 				if (!txn || !txn->uri) {
2716 					chunk.area = "<BADREQ>";
2717 					chunk.data = strlen("<BADREQ>");
2718 				} else {
2719 					uri = txn->uri;
2720 					end = uri + strlen(uri);
2721 					// look for the first question mark
2722 					while (uri < end && *uri != '?')
2723 						uri++;
2724 
2725 					qmark = uri;
2726 					// look for first space or question mark after url
2727 					while (uri < end && !HTTP_IS_SPHT(*uri))
2728 						uri++;
2729 
2730 					chunk.area = qmark;
2731 					chunk.data = uri - qmark;
2732 				}
2733 
2734 				ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
2735 				if (ret == NULL || *ret != '\0')
2736 					goto out;
2737 
2738 				tmplog = ret;
2739 				if (tmp->options & LOG_OPT_QUOTE)
2740 					LOGCHAR('"');
2741 
2742 				last_isspace = 0;
2743 				break;
2744 
2745 			case LOG_FMT_HTTP_URI: // %HU
2746 				uri = txn && txn->uri ? txn->uri : "<BADREQ>";
2747 
2748 				if (tmp->options & LOG_OPT_QUOTE)
2749 					LOGCHAR('"');
2750 
2751 				end = uri + strlen(uri);
2752 				// look for the first whitespace character
2753 				while (uri < end && !HTTP_IS_SPHT(*uri))
2754 					uri++;
2755 
2756 				// keep advancing past multiple spaces
2757 				while (uri < end && HTTP_IS_SPHT(*uri)) {
2758 					uri++; nspaces++;
2759 				}
2760 
2761 				// look for first space after url
2762 				spc = uri;
2763 				while (spc < end && !HTTP_IS_SPHT(*spc))
2764 					spc++;
2765 
2766 				if (!txn || !txn->uri || nspaces == 0) {
2767 					chunk.area = "<BADREQ>";
2768 					chunk.data = strlen("<BADREQ>");
2769 				} else {
2770 					chunk.area = uri;
2771 					chunk.data = spc - uri;
2772 				}
2773 
2774 				ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
2775 				if (ret == NULL || *ret != '\0')
2776 					goto out;
2777 
2778 				tmplog = ret;
2779 				if (tmp->options & LOG_OPT_QUOTE)
2780 					LOGCHAR('"');
2781 
2782 				last_isspace = 0;
2783 				break;
2784 
2785 			case LOG_FMT_HTTP_METHOD: // %HM
2786 				uri = txn && txn->uri ? txn->uri : "<BADREQ>";
2787 				if (tmp->options & LOG_OPT_QUOTE)
2788 					LOGCHAR('"');
2789 
2790 				end = uri + strlen(uri);
2791 				// look for the first whitespace character
2792 				spc = uri;
2793 				while (spc < end && !HTTP_IS_SPHT(*spc))
2794 					spc++;
2795 
2796 				if (spc == end) { // odd case, we have txn->uri, but we only got a verb
2797 					chunk.area = "<BADREQ>";
2798 					chunk.data = strlen("<BADREQ>");
2799 				} else {
2800 					chunk.area = uri;
2801 					chunk.data = spc - uri;
2802 				}
2803 
2804 				ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
2805 				if (ret == NULL || *ret != '\0')
2806 					goto out;
2807 
2808 				tmplog = ret;
2809 				if (tmp->options & LOG_OPT_QUOTE)
2810 					LOGCHAR('"');
2811 
2812 				last_isspace = 0;
2813 				break;
2814 
2815 			case LOG_FMT_HTTP_VERSION: // %HV
2816 				uri = txn && txn->uri ? txn->uri : "<BADREQ>";
2817 				if (tmp->options & LOG_OPT_QUOTE)
2818 					LOGCHAR('"');
2819 
2820 				end = uri + strlen(uri);
2821 				// look for the first whitespace character
2822 				while (uri < end && !HTTP_IS_SPHT(*uri))
2823 					uri++;
2824 
2825 				// keep advancing past multiple spaces
2826 				while (uri < end && HTTP_IS_SPHT(*uri)) {
2827 					uri++; nspaces++;
2828 				}
2829 
2830 				// look for the next whitespace character
2831 				while (uri < end && !HTTP_IS_SPHT(*uri))
2832 					uri++;
2833 
2834 				// keep advancing past multiple spaces
2835 				while (uri < end && HTTP_IS_SPHT(*uri))
2836 					uri++;
2837 
2838 				if (!txn || !txn->uri || nspaces == 0) {
2839 					chunk.area = "<BADREQ>";
2840 					chunk.data = strlen("<BADREQ>");
2841 				} else if (uri == end) {
2842 					chunk.area = "HTTP/0.9";
2843 					chunk.data = strlen("HTTP/0.9");
2844 				} else {
2845 					chunk.area = uri;
2846 					chunk.data = end - uri;
2847 				}
2848 
2849 				ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
2850 				if (ret == NULL || *ret != '\0')
2851 					goto out;
2852 
2853 				tmplog = ret;
2854 				if (tmp->options & LOG_OPT_QUOTE)
2855 					LOGCHAR('"');
2856 
2857 				last_isspace = 0;
2858 				break;
2859 
2860 			case LOG_FMT_COUNTER: // %rt
2861 				if (tmp->options & LOG_OPT_HEXA) {
2862 					iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", uniq_id);
2863 					if (iret < 0 || iret > dst + maxsize - tmplog)
2864 						goto out;
2865 					last_isspace = 0;
2866 					tmplog += iret;
2867 				} else {
2868 					ret = ltoa_o(uniq_id, tmplog, dst + maxsize - tmplog);
2869 					if (ret == NULL)
2870 						goto out;
2871 					tmplog = ret;
2872 					last_isspace = 0;
2873 				}
2874 				break;
2875 
2876 			case LOG_FMT_LOGCNT: // %lc
2877 				if (tmp->options & LOG_OPT_HEXA) {
2878 					iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", fe->log_count);
2879 					if (iret < 0 || iret > dst + maxsize - tmplog)
2880 						goto out;
2881 					last_isspace = 0;
2882 					tmplog += iret;
2883 				} else {
2884 					ret = ultoa_o(fe->log_count, tmplog, dst + maxsize - tmplog);
2885 					if (ret == NULL)
2886 						goto out;
2887 					tmplog = ret;
2888 					last_isspace = 0;
2889 				}
2890 				break;
2891 
2892 			case LOG_FMT_HOSTNAME: // %H
2893 				src = hostname;
2894 				ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2895 				if (ret == NULL)
2896 					goto out;
2897 				tmplog = ret;
2898 				last_isspace = 0;
2899 				break;
2900 
2901 			case LOG_FMT_PID: // %pid
2902 				if (tmp->options & LOG_OPT_HEXA) {
2903 					iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", pid);
2904 					if (iret < 0 || iret > dst + maxsize - tmplog)
2905 						goto out;
2906 					last_isspace = 0;
2907 					tmplog += iret;
2908 				} else {
2909 					ret = ltoa_o(pid, tmplog, dst + maxsize - tmplog);
2910 					if (ret == NULL)
2911 						goto out;
2912 					tmplog = ret;
2913 					last_isspace = 0;
2914 				}
2915 				break;
2916 
2917 			case LOG_FMT_UNIQUEID: // %ID
2918 				ret = NULL;
2919 				src = s ? s->unique_id : NULL;
2920 				ret = lf_text(tmplog, src, maxsize - (tmplog - dst), tmp);
2921 				if (ret == NULL)
2922 					goto out;
2923 				tmplog = ret;
2924 				last_isspace = 0;
2925 				break;
2926 
2927 		}
2928 	}
2929 
2930 out:
2931 	/* *tmplog is a unused character */
2932 	*tmplog = '\0';
2933 	return tmplog - dst;
2934 
2935 }
2936 
2937 /*
2938  * send a log for the stream when we have enough info about it.
2939  * Will not log if the frontend has no log defined.
2940  */
strm_log(struct stream * s)2941 void strm_log(struct stream *s)
2942 {
2943 	struct session *sess = s->sess;
2944 	int size, err, level;
2945 	int sd_size = 0;
2946 
2947 	/* if we don't want to log normal traffic, return now */
2948 	err = (s->flags & SF_REDISP) ||
2949               ((s->flags & SF_ERR_MASK) > SF_ERR_LOCAL) ||
2950 	      (((s->flags & SF_ERR_MASK) == SF_ERR_NONE) &&
2951 	       (s->si[1].conn_retries != s->be->conn_retries)) ||
2952 	      ((sess->fe->mode == PR_MODE_HTTP) && s->txn && s->txn->status >= 500);
2953 
2954 	if (!err && (sess->fe->options2 & PR_O2_NOLOGNORM))
2955 		return;
2956 
2957 	if (LIST_ISEMPTY(&sess->fe->logsrvs))
2958 		return;
2959 
2960 	if (s->logs.level) { /* loglevel was overridden */
2961 		if (s->logs.level == -1) {
2962 			s->logs.logwait = 0; /* logs disabled */
2963 			return;
2964 		}
2965 		level = s->logs.level - 1;
2966 	}
2967 	else {
2968 		level = LOG_INFO;
2969 		if (err && (sess->fe->options2 & PR_O2_LOGERRORS))
2970 			level = LOG_ERR;
2971 	}
2972 
2973 	/* if unique-id was not generated */
2974 	if (!s->unique_id && !LIST_ISEMPTY(&sess->fe->format_unique_id)) {
2975 		if ((s->unique_id = pool_alloc(pool_head_uniqueid)) != NULL)
2976 			build_logline(s, s->unique_id, UNIQUEID_LEN, &sess->fe->format_unique_id);
2977 	}
2978 
2979 	if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
2980 		sd_size = build_logline(s, logline_rfc5424, global.max_syslog_len,
2981 		                        &sess->fe->logformat_sd);
2982 	}
2983 
2984 	size = build_logline(s, logline, global.max_syslog_len, &sess->fe->logformat);
2985 	if (size > 0) {
2986 		_HA_ATOMIC_ADD(&sess->fe->log_count, 1);
2987 		__send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
2988 			   logline, size + 1, logline_rfc5424, sd_size);
2989 		s->logs.logwait = 0;
2990 	}
2991 }
2992 
2993 /*
2994  * send a minimalist log for the session. Will not log if the frontend has no
2995  * log defined. It is assumed that this is only used to report anomalies that
2996  * cannot lead to the creation of a regular stream. Because of this the log
2997  * level is LOG_INFO or LOG_ERR depending on the "log-separate-error" setting
2998  * in the frontend. The caller must simply know that it should not call this
2999  * function to report unimportant events. It is safe to call this function with
3000  * sess==NULL (will not do anything).
3001  */
sess_log(struct session * sess)3002 void sess_log(struct session *sess)
3003 {
3004 	int size, level;
3005 	int sd_size = 0;
3006 
3007 	if (!sess)
3008 		return;
3009 
3010 	if (LIST_ISEMPTY(&sess->fe->logsrvs))
3011 		return;
3012 
3013 	level = LOG_INFO;
3014 	if (sess->fe->options2 & PR_O2_LOGERRORS)
3015 		level = LOG_ERR;
3016 
3017 	if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3018 		sd_size = sess_build_logline(sess, NULL,
3019 		                             logline_rfc5424, global.max_syslog_len,
3020 		                             &sess->fe->logformat_sd);
3021 	}
3022 
3023 	size = sess_build_logline(sess, NULL, logline, global.max_syslog_len, &sess->fe->logformat);
3024 	if (size > 0) {
3025 		_HA_ATOMIC_ADD(&sess->fe->log_count, 1);
3026 		__send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3027 			   logline, size + 1, logline_rfc5424, sd_size);
3028 	}
3029 }
3030 
app_log(struct list * logsrvs,struct buffer * tag,int level,const char * format,...)3031 void app_log(struct list *logsrvs, struct buffer *tag, int level, const char *format, ...)
3032 {
3033 	va_list argp;
3034 	int  data_len;
3035 
3036 	if (level < 0 || format == NULL || logline == NULL)
3037 		return;
3038 
3039 	va_start(argp, format);
3040 	data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
3041 	if (data_len < 0 || data_len > global.max_syslog_len)
3042 		data_len = global.max_syslog_len;
3043 	va_end(argp);
3044 
3045 	__send_log(logsrvs, tag, level, logline, data_len, default_rfc5424_sd_log_format, 2);
3046 }
3047 
3048 /* parse the "show startup-logs" command, returns 1 if a message is returned, otherwise zero */
cli_parse_show_startup_logs(char ** args,char * payload,struct appctx * appctx,void * private)3049 static int cli_parse_show_startup_logs(char **args, char *payload, struct appctx *appctx, void *private)
3050 {
3051 	if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3052 		return 1;
3053 
3054 	if (!startup_logs)
3055 		return cli_msg(appctx, LOG_INFO, "\n"); // nothing to print
3056 
3057 	return ring_attach_cli(startup_logs, appctx);
3058 }
3059 
3060 /* register cli keywords */
3061 static struct cli_kw_list cli_kws = {{ },{
3062 	{ { "show", "startup-logs",  NULL },
3063 	  "show startup-logs : report logs emitted during HAProxy startup", cli_parse_show_startup_logs, NULL, NULL },
3064 	{{},}
3065 }};
3066 
3067 INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
3068 
3069 REGISTER_PER_THREAD_ALLOC(init_log_buffers);
3070 REGISTER_PER_THREAD_FREE(deinit_log_buffers);
3071 
3072 /*
3073  * Local variables:
3074  *  c-indent-level: 8
3075  *  c-basic-offset: 8
3076  * End:
3077  */
3078