1 /* $OpenBSD: log.c,v 1.54 2010/11/18 12:51:24 claudio 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 USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <err.h> 20 #include <errno.h> 21 #include <netdb.h> 22 #include <stdarg.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <syslog.h> 27 #include <time.h> 28 #include <unistd.h> 29 30 #include "bgpd.h" 31 #include "session.h" 32 #include "log.h" 33 34 int debug; 35 int verbose; 36 37 void logit(int, const char *, ...); 38 39 char * 40 log_fmt_peer(const struct peer_config *peer) 41 { 42 const char *ip; 43 char *pfmt, *p; 44 45 ip = log_addr(&peer->remote_addr); 46 if ((peer->remote_addr.aid == AID_INET && peer->remote_masklen != 32) || 47 (peer->remote_addr.aid == AID_INET6 && 48 peer->remote_masklen != 128)) { 49 if (asprintf(&p, "%s/%u", ip, peer->remote_masklen) == -1) 50 fatal(NULL); 51 } else { 52 if ((p = strdup(ip)) == NULL) 53 fatal(NULL); 54 } 55 56 if (peer->descr[0]) { 57 if (asprintf(&pfmt, "neighbor %s (%s)", p, peer->descr) == 58 -1) 59 fatal(NULL); 60 } else { 61 if (asprintf(&pfmt, "neighbor %s", p) == -1) 62 fatal(NULL); 63 } 64 free(p); 65 return (pfmt); 66 } 67 68 void 69 log_init(int n_debug) 70 { 71 extern char *__progname; 72 73 debug = n_debug; 74 verbose = n_debug; 75 76 if (!debug) 77 openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON); 78 79 tzset(); 80 } 81 82 void 83 log_verbose(int v) 84 { 85 verbose = v; 86 } 87 88 void 89 logit(int pri, const char *fmt, ...) 90 { 91 va_list ap; 92 93 va_start(ap, fmt); 94 vlog(pri, fmt, ap); 95 va_end(ap); 96 } 97 98 void 99 vlog(int pri, const char *fmt, va_list ap) 100 { 101 char *nfmt; 102 103 if (debug) { 104 /* best effort in out of mem situations */ 105 if (asprintf(&nfmt, "%s\n", fmt) == -1) { 106 vfprintf(stderr, fmt, ap); 107 fprintf(stderr, "\n"); 108 } else { 109 vfprintf(stderr, nfmt, ap); 110 free(nfmt); 111 } 112 fflush(stderr); 113 } else 114 vsyslog(pri, fmt, ap); 115 } 116 117 118 void 119 log_peer_warn(const struct peer_config *peer, const char *emsg, ...) 120 { 121 char *p, *nfmt; 122 va_list ap; 123 124 p = log_fmt_peer(peer); 125 if (emsg == NULL) { 126 if (asprintf(&nfmt, "%s: %s", p, strerror(errno)) == -1) 127 fatal(NULL); 128 } else { 129 if (asprintf(&nfmt, "%s: %s: %s", p, emsg, strerror(errno)) == 130 -1) 131 fatal(NULL); 132 } 133 va_start(ap, emsg); 134 vlog(LOG_CRIT, nfmt, ap); 135 va_end(ap); 136 free(p); 137 free(nfmt); 138 } 139 140 void 141 log_peer_warnx(const struct peer_config *peer, const char *emsg, ...) 142 { 143 char *p, *nfmt; 144 va_list ap; 145 146 p = log_fmt_peer(peer); 147 if (asprintf(&nfmt, "%s: %s", p, emsg) == -1) 148 fatal(NULL); 149 va_start(ap, emsg); 150 vlog(LOG_CRIT, nfmt, ap); 151 va_end(ap); 152 free(p); 153 free(nfmt); 154 } 155 156 void 157 log_warn(const char *emsg, ...) 158 { 159 char *nfmt; 160 va_list ap; 161 162 /* best effort to even work in out of memory situations */ 163 if (emsg == NULL) 164 logit(LOG_CRIT, "%s", strerror(errno)); 165 else { 166 va_start(ap, emsg); 167 168 if (asprintf(&nfmt, "%s: %s", emsg, strerror(errno)) == -1) { 169 /* we tried it... */ 170 vlog(LOG_CRIT, emsg, ap); 171 logit(LOG_CRIT, "%s", strerror(errno)); 172 } else { 173 vlog(LOG_CRIT, nfmt, ap); 174 free(nfmt); 175 } 176 va_end(ap); 177 } 178 } 179 180 void 181 log_warnx(const char *emsg, ...) 182 { 183 va_list ap; 184 185 va_start(ap, emsg); 186 vlog(LOG_CRIT, emsg, ap); 187 va_end(ap); 188 } 189 190 void 191 log_info(const char *emsg, ...) 192 { 193 va_list ap; 194 195 va_start(ap, emsg); 196 vlog(LOG_INFO, emsg, ap); 197 va_end(ap); 198 } 199 200 void 201 log_debug(const char *emsg, ...) 202 { 203 va_list ap; 204 205 if (verbose) { 206 va_start(ap, emsg); 207 vlog(LOG_DEBUG, emsg, ap); 208 va_end(ap); 209 } 210 } 211 212 void 213 fatal(const char *emsg) 214 { 215 if (emsg == NULL) 216 logit(LOG_CRIT, "fatal in %s: %s", procnames[bgpd_process], 217 strerror(errno)); 218 else 219 if (errno) 220 logit(LOG_CRIT, "fatal in %s: %s: %s", 221 procnames[bgpd_process], emsg, strerror(errno)); 222 else 223 logit(LOG_CRIT, "fatal in %s: %s", 224 procnames[bgpd_process], emsg); 225 226 if (bgpd_process == PROC_MAIN) 227 exit(1); 228 else /* parent copes via SIGCHLD */ 229 _exit(1); 230 } 231 232 void 233 fatalx(const char *emsg) 234 { 235 errno = 0; 236 fatal(emsg); 237 } 238 239 void 240 log_statechange(struct peer *peer, enum session_state nstate, 241 enum session_events event) 242 { 243 char *p; 244 245 /* don't clutter the logs with constant Connect -> Active -> Connect */ 246 if (nstate == STATE_CONNECT && peer->state == STATE_ACTIVE && 247 peer->prev_state == STATE_CONNECT) 248 return; 249 if (nstate == STATE_ACTIVE && peer->state == STATE_CONNECT && 250 peer->prev_state == STATE_ACTIVE) 251 return; 252 253 peer->lasterr = 0; 254 p = log_fmt_peer(&peer->conf); 255 logit(LOG_INFO, "%s: state change %s -> %s, reason: %s", 256 p, statenames[peer->state], statenames[nstate], eventnames[event]); 257 free(p); 258 } 259 260 void 261 log_notification(const struct peer *peer, u_int8_t errcode, u_int8_t subcode, 262 u_char *data, u_int16_t datalen, const char *dir) 263 { 264 char *p; 265 const char *suberrname = NULL; 266 int uk = 0; 267 268 p = log_fmt_peer(&peer->conf); 269 switch (errcode) { 270 case ERR_HEADER: 271 if (subcode >= sizeof(suberr_header_names)/sizeof(char *)) 272 uk = 1; 273 else 274 suberrname = suberr_header_names[subcode]; 275 break; 276 case ERR_OPEN: 277 if (subcode >= sizeof(suberr_open_names)/sizeof(char *)) 278 uk = 1; 279 else 280 suberrname = suberr_open_names[subcode]; 281 break; 282 case ERR_UPDATE: 283 if (subcode >= sizeof(suberr_update_names)/sizeof(char *)) 284 uk = 1; 285 else 286 suberrname = suberr_update_names[subcode]; 287 break; 288 case ERR_CEASE: 289 if (subcode >= sizeof(suberr_cease_names)/sizeof(char *)) 290 uk = 1; 291 else 292 suberrname = suberr_cease_names[subcode]; 293 break; 294 case ERR_HOLDTIMEREXPIRED: 295 case ERR_FSM: 296 uk = 1; 297 break; 298 default: 299 logit(LOG_CRIT, "%s: %s notification, unknown errcode " 300 "%u, subcode %u", p, dir, errcode, subcode); 301 free(p); 302 return; 303 } 304 305 if (uk) 306 logit(LOG_CRIT, "%s: %s notification: %s, unknown subcode %u", 307 p, dir, errnames[errcode], subcode); 308 else { 309 if (suberrname == NULL) 310 logit(LOG_CRIT, "%s: %s notification: %s", p, 311 dir, errnames[errcode]); 312 else 313 logit(LOG_CRIT, "%s: %s notification: %s, %s", 314 p, dir, errnames[errcode], suberrname); 315 } 316 free(p); 317 } 318 319 void 320 log_conn_attempt(const struct peer *peer, struct sockaddr *sa) 321 { 322 char *p; 323 const char *b; 324 325 if (peer == NULL) { /* connection from non-peer, drop */ 326 b = log_sockaddr(sa); 327 logit(LOG_INFO, "connection from non-peer %s refused", b); 328 } else { 329 /* only log if there is a chance that the session may come up */ 330 if (peer->conf.down && peer->state == STATE_IDLE) 331 return; 332 p = log_fmt_peer(&peer->conf); 333 logit(LOG_INFO, "Connection attempt from %s while session is " 334 "in state %s", p, statenames[peer->state]); 335 free(p); 336 } 337 } 338