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