1 /* $OpenBSD: log.c,v 1.14 2008/12/05 16:37:55 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 39 #include <openssl/ssl.h> 40 41 #include "relayd.h" 42 43 int debug; 44 45 void vlog(int, const char *, va_list); 46 void logit(int, const char *, ...); 47 48 void 49 log_init(int n_debug) 50 { 51 extern char *__progname; 52 53 debug = n_debug; 54 55 if (!debug) 56 openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON); 57 58 tzset(); 59 } 60 61 void 62 logit(int pri, const char *fmt, ...) 63 { 64 va_list ap; 65 66 va_start(ap, fmt); 67 vlog(pri, fmt, ap); 68 va_end(ap); 69 } 70 71 void 72 vlog(int pri, const char *fmt, va_list ap) 73 { 74 char *nfmt; 75 76 if (debug) { 77 /* best effort in out of mem situations */ 78 if (asprintf(&nfmt, "%s\n", fmt) == -1) { 79 vfprintf(stderr, fmt, ap); 80 fprintf(stderr, "\n"); 81 } else { 82 vfprintf(stderr, nfmt, ap); 83 free(nfmt); 84 } 85 fflush(stderr); 86 } else 87 vsyslog(pri, fmt, ap); 88 } 89 90 91 void 92 log_warn(const char *emsg, ...) 93 { 94 char *nfmt; 95 va_list ap; 96 97 /* best effort to even work in out of memory situations */ 98 if (emsg == NULL) 99 logit(LOG_CRIT, "%s", strerror(errno)); 100 else { 101 va_start(ap, emsg); 102 103 if (asprintf(&nfmt, "%s: %s", emsg, strerror(errno)) == -1) { 104 /* we tried it... */ 105 vlog(LOG_CRIT, emsg, ap); 106 logit(LOG_CRIT, "%s", strerror(errno)); 107 } else { 108 vlog(LOG_CRIT, nfmt, ap); 109 free(nfmt); 110 } 111 va_end(ap); 112 } 113 } 114 115 void 116 log_warnx(const char *emsg, ...) 117 { 118 va_list ap; 119 120 va_start(ap, emsg); 121 vlog(LOG_CRIT, emsg, ap); 122 va_end(ap); 123 } 124 125 void 126 log_info(const char *emsg, ...) 127 { 128 va_list ap; 129 130 va_start(ap, emsg); 131 vlog(LOG_INFO, emsg, ap); 132 va_end(ap); 133 } 134 135 void 136 log_debug(const char *emsg, ...) 137 { 138 va_list ap; 139 140 if (debug > 1) { 141 va_start(ap, emsg); 142 vlog(LOG_DEBUG, emsg, ap); 143 va_end(ap); 144 } 145 } 146 147 void 148 fatal(const char *emsg) 149 { 150 if (emsg == NULL) 151 logit(LOG_CRIT, "fatal: %s", strerror(errno)); 152 else 153 if (errno) 154 logit(LOG_CRIT, "fatal: %s: %s", 155 emsg, strerror(errno)); 156 else 157 logit(LOG_CRIT, "fatal: %s", emsg); 158 159 exit(1); 160 } 161 162 void 163 fatalx(const char *emsg) 164 { 165 errno = 0; 166 fatal(emsg); 167 } 168 169 const char * 170 host_error(enum host_error he) 171 { 172 switch (he) { 173 case HCE_NONE: 174 return ("none"); 175 break; 176 case HCE_ABORT: 177 return ("aborted"); 178 break; 179 case HCE_INTERVAL_TIMEOUT: 180 return ("interval timeout"); 181 break; 182 case HCE_ICMP_OK: 183 return ("icmp ok"); 184 break; 185 case HCE_ICMP_READ_TIMEOUT: 186 return ("icmp read timeout"); 187 break; 188 case HCE_ICMP_WRITE_TIMEOUT: 189 return ("icmp write timeout"); 190 break; 191 case HCE_TCP_CONNECT_ERROR: 192 return ("tcp connect error"); 193 break; 194 case HCE_TCP_CONNECT_FAIL: 195 return ("tcp connect failed"); 196 break; 197 case HCE_TCP_CONNECT_TIMEOUT: 198 return ("tcp connect timeout"); 199 break; 200 case HCE_TCP_CONNECT_OK: 201 return ("tcp connect ok"); 202 break; 203 case HCE_TCP_WRITE_TIMEOUT: 204 return ("tcp write timeout"); 205 break; 206 case HCE_TCP_WRITE_FAIL: 207 return ("tcp write failed"); 208 break; 209 case HCE_TCP_READ_TIMEOUT: 210 return ("tcp read timeout"); 211 break; 212 case HCE_TCP_READ_FAIL: 213 return ("tcp read failed"); 214 break; 215 case HCE_SCRIPT_OK: 216 return ("script ok"); 217 break; 218 case HCE_SCRIPT_FAIL: 219 return ("script failed"); 220 break; 221 case HCE_SSL_CONNECT_OK: 222 return ("ssl connect ok"); 223 break; 224 case HCE_SSL_CONNECT_FAIL: 225 return ("ssl connect failed"); 226 break; 227 case HCE_SSL_CONNECT_TIMEOUT: 228 return ("ssl connect timeout"); 229 break; 230 case HCE_SSL_CONNECT_ERROR: 231 return ("ssl connect error"); 232 break; 233 case HCE_SSL_READ_TIMEOUT: 234 return ("ssl read timeout"); 235 break; 236 case HCE_SSL_WRITE_TIMEOUT: 237 return ("ssl write timeout"); 238 break; 239 case HCE_SSL_READ_ERROR: 240 return ("ssl read error"); 241 break; 242 case HCE_SSL_WRITE_ERROR: 243 return ("ssl write error"); 244 break; 245 case HCE_SEND_EXPECT_FAIL: 246 return ("send/expect failed"); 247 break; 248 case HCE_SEND_EXPECT_OK: 249 return ("send/expect ok"); 250 break; 251 case HCE_HTTP_CODE_ERROR: 252 return ("http code malformed"); 253 break; 254 case HCE_HTTP_CODE_FAIL: 255 return ("http code mismatch"); 256 break; 257 case HCE_HTTP_CODE_OK: 258 return ("http code ok"); 259 break; 260 case HCE_HTTP_DIGEST_ERROR: 261 return ("http digest malformed"); 262 break; 263 case HCE_HTTP_DIGEST_FAIL: 264 return ("http digest mismatch"); 265 break; 266 case HCE_HTTP_DIGEST_OK: 267 return ("http digest ok"); 268 break; 269 } 270 /* NOTREACHED */ 271 return ("invalid"); 272 } 273 274 const char * 275 host_status(enum host_status status) 276 { 277 switch (status) { 278 case HOST_DOWN: 279 return ("down"); 280 case HOST_UNKNOWN: 281 return ("unknown"); 282 case HOST_UP: 283 return ("up"); 284 }; 285 /* NOTREACHED */ 286 return ("invalid"); 287 } 288 289 const char * 290 table_check(enum table_check check) 291 { 292 switch (check) { 293 case CHECK_NOCHECK: 294 return ("none"); 295 case CHECK_ICMP: 296 return ("icmp"); 297 case CHECK_TCP: 298 return ("tcp"); 299 case CHECK_HTTP_CODE: 300 return ("http code"); 301 case CHECK_HTTP_DIGEST: 302 return ("http digest"); 303 case CHECK_SEND_EXPECT: 304 return ("send expect"); 305 case CHECK_SCRIPT: 306 return ("script"); 307 }; 308 /* NOTREACHED */ 309 return ("invalid"); 310 } 311 312 const char * 313 print_availability(u_long cnt, u_long up) 314 { 315 static char buf[BUFSIZ]; 316 317 if (cnt == 0) 318 return (""); 319 bzero(buf, sizeof(buf)); 320 snprintf(buf, sizeof(buf), "%.2f%%", (double)up / cnt * 100); 321 return (buf); 322 } 323 324 const char * 325 print_host(struct sockaddr_storage *ss, char *buf, size_t len) 326 { 327 if (getnameinfo((struct sockaddr *)ss, ss->ss_len, 328 buf, len, NULL, 0, NI_NUMERICHOST) != 0) { 329 buf[0] = '\0'; 330 return (NULL); 331 } 332 return (buf); 333 } 334 335 const char * 336 print_time(struct timeval *a, struct timeval *b, char *buf, size_t len) 337 { 338 struct timeval tv; 339 u_long h, sec, min; 340 341 timerclear(&tv); 342 timersub(a, b, &tv); 343 sec = tv.tv_sec % 60; 344 min = tv.tv_sec / 60 % 60; 345 h = tv.tv_sec / 60 / 60; 346 347 snprintf(buf, len, "%.2lu:%.2lu:%.2lu", h, min, sec); 348 return (buf); 349 } 350 351 const char * 352 print_httperror(u_int code) 353 { 354 u_int i; 355 struct { 356 u_int ht_code; 357 const char *ht_err; 358 } httperr[] = { 359 { 100, "Continue" }, 360 { 101, "Switching Protocols" }, 361 { 200, "OK" }, 362 { 201, "Created" }, 363 { 202, "Accepted" }, 364 { 203, "Non-Authorative Information" }, 365 { 204, "No Content" }, 366 { 205, "Reset Content" }, 367 { 206, "Partial Content" }, 368 { 300, "Multiple Choices" }, 369 { 301, "Moved Permanently" }, 370 { 302, "Moved Temporarily" }, 371 { 303, "See Other" }, 372 { 304, "Not Modified" }, 373 { 307, "Temporary Redirect" }, 374 { 400, "Bad Request" }, 375 { 401, "Unauthorized" }, 376 { 402, "Payment Required" }, 377 { 403, "Forbidden" }, 378 { 404, "Not Found" }, 379 { 405, "Method Not Allowed" }, 380 { 406, "Not Acceptable" }, 381 { 407, "Proxy Authentication Required" }, 382 { 408, "Request Timeout" }, 383 { 409, "Conflict" }, 384 { 410, "Gone" }, 385 { 411, "Length Required" }, 386 { 412, "Precondition Failed" }, 387 { 413, "Request Entity Too Large" }, 388 { 414, "Request-URL Too Long" }, 389 { 415, "Unsupported Media Type" }, 390 { 416, "Requested Range Not Satisfiable" }, 391 { 417, "Expectation Failed" }, 392 { 500, "Internal Server Error" }, 393 { 501, "Not Implemented" }, 394 { 502, "Bad Gateway" }, 395 { 503, "Service Unavailable" }, 396 { 504, "Gateway Timeout" }, 397 { 505, "HTTP Version Not Supported" }, 398 { 0 } 399 }; 400 401 for (i = 0; httperr[i].ht_code != 0; i++) 402 if (httperr[i].ht_code == code) 403 return (httperr[i].ht_err); 404 return ("Unknown Error"); 405 } 406