xref: /openbsd-src/usr.sbin/relayd/log.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: log.c,v 1.17 2011/04/12 12:37:22 reyk Exp $	*/
2 
3 /*
4  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/queue.h>
21 #include <sys/socket.h>
22 #include <sys/tree.h>
23 
24 #include <net/if.h>
25 #include <netinet/in_systm.h>
26 #include <netinet/in.h>
27 #include <netinet/ip.h>
28 #include <arpa/inet.h>
29 
30 #include <errno.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <syslog.h>
36 #include <event.h>
37 #include <netdb.h>
38 #include <ctype.h>
39 
40 #include <openssl/ssl.h>
41 
42 #include "relayd.h"
43 
44 int	 debug;
45 int	 verbose;
46 
47 void	 vlog(int, const char *, va_list);
48 void	 logit(int, const char *, ...);
49 
50 void
51 log_init(int n_debug)
52 {
53 	extern char	*__progname;
54 
55 	debug = n_debug;
56 	verbose = n_debug;
57 
58 	if (!debug)
59 		openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
60 
61 	tzset();
62 }
63 
64 void
65 log_verbose(int v)
66 {
67 	verbose = v;
68 }
69 
70 void
71 logit(int pri, const char *fmt, ...)
72 {
73 	va_list	ap;
74 
75 	va_start(ap, fmt);
76 	vlog(pri, fmt, ap);
77 	va_end(ap);
78 }
79 
80 void
81 vlog(int pri, const char *fmt, va_list ap)
82 {
83 	char	*nfmt;
84 
85 	if (debug) {
86 		/* best effort in out of mem situations */
87 		if (asprintf(&nfmt, "%s\n", fmt) == -1) {
88 			vfprintf(stderr, fmt, ap);
89 			fprintf(stderr, "\n");
90 		} else {
91 			vfprintf(stderr, nfmt, ap);
92 			free(nfmt);
93 		}
94 		fflush(stderr);
95 	} else
96 		vsyslog(pri, fmt, ap);
97 }
98 
99 
100 void
101 log_warn(const char *emsg, ...)
102 {
103 	char	*nfmt;
104 	va_list	 ap;
105 
106 	/* best effort to even work in out of memory situations */
107 	if (emsg == NULL)
108 		logit(LOG_CRIT, "%s", strerror(errno));
109 	else {
110 		va_start(ap, emsg);
111 
112 		if (asprintf(&nfmt, "%s: %s", emsg, strerror(errno)) == -1) {
113 			/* we tried it... */
114 			vlog(LOG_CRIT, emsg, ap);
115 			logit(LOG_CRIT, "%s", strerror(errno));
116 		} else {
117 			vlog(LOG_CRIT, nfmt, ap);
118 			free(nfmt);
119 		}
120 		va_end(ap);
121 	}
122 }
123 
124 void
125 log_warnx(const char *emsg, ...)
126 {
127 	va_list	 ap;
128 
129 	va_start(ap, emsg);
130 	vlog(LOG_CRIT, emsg, ap);
131 	va_end(ap);
132 }
133 
134 void
135 log_info(const char *emsg, ...)
136 {
137 	va_list	 ap;
138 
139 	va_start(ap, emsg);
140 	vlog(LOG_INFO, emsg, ap);
141 	va_end(ap);
142 }
143 
144 void
145 log_debug(const char *emsg, ...)
146 {
147 	va_list	 ap;
148 
149 	if (verbose > 1) {
150 		va_start(ap, emsg);
151 		vlog(LOG_DEBUG, emsg, ap);
152 		va_end(ap);
153 	}
154 }
155 
156 void
157 fatal(const char *emsg)
158 {
159 	if (emsg == NULL)
160 		logit(LOG_CRIT, "fatal: %s", strerror(errno));
161 	else
162 		if (errno)
163 			logit(LOG_CRIT, "fatal: %s: %s",
164 			    emsg, strerror(errno));
165 		else
166 			logit(LOG_CRIT, "fatal: %s", emsg);
167 
168 	exit(1);
169 }
170 
171 void
172 fatalx(const char *emsg)
173 {
174 	errno = 0;
175 	fatal(emsg);
176 }
177 
178 const char *
179 host_error(enum host_error he)
180 {
181 	switch (he) {
182 	case HCE_NONE:
183 		return ("none");
184 		break;
185 	case HCE_ABORT:
186 		return ("aborted");
187 		break;
188 	case HCE_INTERVAL_TIMEOUT:
189 		return ("interval timeout");
190 		break;
191 	case HCE_ICMP_OK:
192 		return ("icmp ok");
193 		break;
194 	case HCE_ICMP_READ_TIMEOUT:
195 		return ("icmp read timeout");
196 		break;
197 	case HCE_ICMP_WRITE_TIMEOUT:
198 		return ("icmp write timeout");
199 		break;
200 	case HCE_TCP_SOCKET_ERROR:
201 		return ("tcp socket error");
202 		break;
203 	case HCE_TCP_SOCKET_LIMIT:
204 		return ("tcp socket limit");
205 		break;
206 	case HCE_TCP_SOCKET_OPTION:
207 		return ("tcp socket option");
208 		break;
209 	case HCE_TCP_CONNECT_FAIL:
210 		return ("tcp connect failed");
211 		break;
212 	case HCE_TCP_CONNECT_TIMEOUT:
213 		return ("tcp connect timeout");
214 		break;
215 	case HCE_TCP_CONNECT_OK:
216 		return ("tcp connect ok");
217 		break;
218 	case HCE_TCP_WRITE_TIMEOUT:
219 		return ("tcp write timeout");
220 		break;
221 	case HCE_TCP_WRITE_FAIL:
222 		return ("tcp write failed");
223 		break;
224 	case HCE_TCP_READ_TIMEOUT:
225 		return ("tcp read timeout");
226 		break;
227 	case HCE_TCP_READ_FAIL:
228 		return ("tcp read failed");
229 		break;
230 	case HCE_SCRIPT_OK:
231 		return ("script ok");
232 		break;
233 	case HCE_SCRIPT_FAIL:
234 		return ("script failed");
235 		break;
236 	case HCE_SSL_CONNECT_OK:
237 		return ("ssl connect ok");
238 		break;
239 	case HCE_SSL_CONNECT_FAIL:
240 		return ("ssl connect failed");
241 		break;
242 	case HCE_SSL_CONNECT_TIMEOUT:
243 		return ("ssl connect timeout");
244 		break;
245 	case HCE_SSL_CONNECT_ERROR:
246 		return ("ssl connect error");
247 		break;
248 	case HCE_SSL_READ_TIMEOUT:
249 		return ("ssl read timeout");
250 		break;
251 	case HCE_SSL_WRITE_TIMEOUT:
252 		return ("ssl write timeout");
253 		break;
254 	case HCE_SSL_READ_ERROR:
255 		return ("ssl read error");
256 		break;
257 	case HCE_SSL_WRITE_ERROR:
258 		return ("ssl write error");
259 		break;
260 	case HCE_SEND_EXPECT_FAIL:
261 		return ("send/expect failed");
262 		break;
263 	case HCE_SEND_EXPECT_OK:
264 		return ("send/expect ok");
265 		break;
266 	case HCE_HTTP_CODE_ERROR:
267 		return ("http code malformed");
268 		break;
269 	case HCE_HTTP_CODE_FAIL:
270 		return ("http code mismatch");
271 		break;
272 	case HCE_HTTP_CODE_OK:
273 		return ("http code ok");
274 		break;
275 	case HCE_HTTP_DIGEST_ERROR:
276 		return ("http digest malformed");
277 		break;
278 	case HCE_HTTP_DIGEST_FAIL:
279 		return ("http digest mismatch");
280 		break;
281 	case HCE_HTTP_DIGEST_OK:
282 		return ("http digest ok");
283 		break;
284 	}
285 	/* NOTREACHED */
286 	return ("invalid");
287 }
288 
289 const char *
290 host_status(enum host_status status)
291 {
292 	switch (status) {
293 	case HOST_DOWN:
294 		return ("down");
295 	case HOST_UNKNOWN:
296 		return ("unknown");
297 	case HOST_UP:
298 		return ("up");
299 	};
300 	/* NOTREACHED */
301 	return ("invalid");
302 }
303 
304 const char *
305 table_check(enum table_check check)
306 {
307 	switch (check) {
308 	case CHECK_NOCHECK:
309 		return ("none");
310 	case CHECK_ICMP:
311 		return ("icmp");
312 	case CHECK_TCP:
313 		return ("tcp");
314 	case CHECK_HTTP_CODE:
315 		return ("http code");
316 	case CHECK_HTTP_DIGEST:
317 		return ("http digest");
318 	case CHECK_SEND_EXPECT:
319 		return ("send expect");
320 	case CHECK_SCRIPT:
321 		return ("script");
322 	};
323 	/* NOTREACHED */
324 	return ("invalid");
325 }
326 
327 const char *
328 print_availability(u_long cnt, u_long up)
329 {
330 	static char buf[BUFSIZ];
331 
332 	if (cnt == 0)
333 		return ("");
334 	bzero(buf, sizeof(buf));
335 	snprintf(buf, sizeof(buf), "%.2f%%", (double)up / cnt * 100);
336 	return (buf);
337 }
338 
339 const char *
340 print_host(struct sockaddr_storage *ss, char *buf, size_t len)
341 {
342 	if (getnameinfo((struct sockaddr *)ss, ss->ss_len,
343 	    buf, len, NULL, 0, NI_NUMERICHOST) != 0) {
344 		buf[0] = '\0';
345 		return (NULL);
346 	}
347 	return (buf);
348 }
349 
350 const char *
351 print_time(struct timeval *a, struct timeval *b, char *buf, size_t len)
352 {
353 	struct timeval		tv;
354 	u_long			h, sec, min;
355 
356 	timerclear(&tv);
357 	timersub(a, b, &tv);
358 	sec = tv.tv_sec % 60;
359 	min = tv.tv_sec / 60 % 60;
360 	h = tv.tv_sec / 60 / 60;
361 
362 	snprintf(buf, len, "%.2lu:%.2lu:%.2lu", h, min, sec);
363 	return (buf);
364 }
365 
366 const char *
367 print_httperror(u_int code)
368 {
369 	u_int			 i;
370 	struct {
371 		u_int		 ht_code;
372 		const char	*ht_err;
373 	}			 httperr[] = {
374 		{ 100, "Continue" },
375 		{ 101, "Switching Protocols" },
376 		{ 200, "OK" },
377 		{ 201, "Created" },
378 		{ 202, "Accepted" },
379 		{ 203, "Non-Authorative Information" },
380 		{ 204, "No Content" },
381 		{ 205, "Reset Content" },
382 		{ 206, "Partial Content" },
383 		{ 300, "Multiple Choices" },
384 		{ 301, "Moved Permanently" },
385 		{ 302, "Moved Temporarily" },
386 		{ 303, "See Other" },
387 		{ 304, "Not Modified" },
388 		{ 307, "Temporary Redirect" },
389 		{ 400, "Bad Request" },
390 		{ 401, "Unauthorized" },
391 		{ 402, "Payment Required" },
392 		{ 403, "Forbidden" },
393 		{ 404, "Not Found" },
394 		{ 405, "Method Not Allowed" },
395 		{ 406, "Not Acceptable" },
396 		{ 407, "Proxy Authentication Required" },
397 		{ 408, "Request Timeout" },
398 		{ 409, "Conflict" },
399 		{ 410, "Gone" },
400 		{ 411, "Length Required" },
401 		{ 412, "Precondition Failed" },
402 		{ 413, "Request Entity Too Large" },
403 		{ 414, "Request-URL Too Long" },
404 		{ 415, "Unsupported Media Type" },
405 		{ 416, "Requested Range Not Satisfiable" },
406 		{ 417, "Expectation Failed" },
407 		{ 500, "Internal Server Error" },
408 		{ 501, "Not Implemented" },
409 		{ 502, "Bad Gateway" },
410 		{ 503, "Service Unavailable" },
411 		{ 504, "Gateway Timeout" },
412 		{ 505, "HTTP Version Not Supported" },
413 		{ 0 }
414 	};
415 
416 	for (i = 0; httperr[i].ht_code != 0; i++)
417 		if (httperr[i].ht_code == code)
418 			return (httperr[i].ht_err);
419 	return ("Unknown Error");
420 }
421 
422 const char *
423 printb_flags(const u_int32_t v, const char *bits)
424 {
425 	static char	 buf[2][BUFSIZ];
426 	static int	 idx = 0;
427 	int		 i, any = 0;
428 	char		 c, *p, *r;
429 
430 	p = r = buf[++idx % 2];
431 	bzero(p, BUFSIZ);
432 
433 	if (bits) {
434 		bits++;
435 		while ((i = *bits++)) {
436 			if (v & (1 << (i - 1))) {
437 				if (any) {
438 					*p++ = ',';
439 					*p++ = ' ';
440 				}
441 				any = 1;
442 				for (; (c = *bits) > 32; bits++) {
443 					if (c == '_')
444 						*p++ = ' ';
445 					else
446 						*p++ = tolower(c);
447 				}
448 			} else
449 				for (; *bits > 32; bits++)
450 					;
451 		}
452 	}
453 
454 	return (r);
455 }
456