1 /* $OpenBSD: log.c,v 1.27 2004/01/28 22:12:33 henning 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 <sys/types.h> 20 #include <sys/socket.h> 21 #include <netinet/in.h> 22 #include <arpa/inet.h> 23 24 #include <err.h> 25 #include <errno.h> 26 #include <stdarg.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <syslog.h> 31 #include <unistd.h> 32 33 #include "bgpd.h" 34 #include "session.h" 35 #include "log.h" 36 37 int debug; 38 39 static const char *eventnames[] = { 40 "None", 41 "Start", 42 "Stop", 43 "Connection opened", 44 "Connection closed", 45 "Connection open failed", 46 "Fatal error", 47 "ConnectRetryTimer expired", 48 "HoldTimer expired", 49 "KeepaliveTimer expired", 50 "OPEN message received", 51 "KEEPALIVE message received", 52 "UPDATE message received", 53 "NOTIFICATION received" 54 }; 55 56 static const char *errnames[] = { 57 "none", 58 "Header error", 59 "error in OPEN message", 60 "error in UPDATE message", 61 "HoldTimer expired", 62 "Finite State Machine error", 63 "Cease" 64 }; 65 66 static const char *suberr_header_names[] = { 67 "none", 68 "synchronization error", 69 "wrong length", 70 "unknown message type" 71 }; 72 73 static const char *suberr_open_names[] = { 74 "none", 75 "version mismatch", 76 "AS unacceptable", 77 "BGPID invalid", 78 "optional parameter error", 79 "Authentication error", 80 "unacceptable holdtime" 81 }; 82 83 static const char *suberr_update_names[] = { 84 "none", 85 "attribute list error", 86 "unknown well-known attribute", 87 "well-known attribute missing", 88 "attribute flags error", 89 "attribute length wrong", 90 "origin unacceptable", 91 "loop detected", 92 "nexthop unacceptable", 93 "optional attribute error", 94 "network unacceptable", 95 "AS-Path unacceptable" 96 }; 97 98 static const char *procnames[] = { 99 "parent", 100 "SE", 101 "RDE" 102 }; 103 104 char *log_fmt_peer(const struct peer_config *); 105 void logit(int, const char *, ...); 106 107 char * 108 log_fmt_peer(const struct peer_config *peer) 109 { 110 const char *ip; 111 char *pfmt; 112 113 ip = log_addr(&peer->remote_addr); 114 if (peer->descr[0]) { 115 if (asprintf(&pfmt, "neighbor %s (%s)", ip, peer->descr) == 116 -1) 117 fatal(NULL); 118 } else { 119 if (asprintf(&pfmt, "neighbor %s", ip) == -1) 120 fatal(NULL); 121 } 122 return (pfmt); 123 } 124 125 void 126 log_init(int n_debug) 127 { 128 debug = n_debug; 129 130 if (!debug) 131 openlog("bgpd", LOG_PID | LOG_NDELAY, LOG_DAEMON); 132 } 133 134 void 135 logit(int pri, const char *fmt, ...) 136 { 137 va_list ap; 138 139 va_start(ap, fmt); 140 vlog(pri, fmt, ap); 141 va_end(ap); 142 } 143 144 void 145 vlog(int pri, const char *fmt, va_list ap) 146 { 147 char *nfmt; 148 149 if (debug) { 150 /* best effort in out of mem situations */ 151 if (asprintf(&nfmt, "%s\n", fmt) == -1) { 152 vfprintf(stderr, fmt, ap); 153 fprintf(stderr, "\n"); 154 } else { 155 vfprintf(stderr, nfmt, ap); 156 free(nfmt); 157 } 158 } else 159 vsyslog(pri, fmt, ap); 160 } 161 162 163 void 164 log_peer_warn(const struct peer_config *peer, const char *emsg, ...) 165 { 166 char *p, *nfmt; 167 va_list ap; 168 169 p = log_fmt_peer(peer); 170 if (emsg == NULL) { 171 if (asprintf(&nfmt, "%s: %s", p, strerror(errno)) == -1) 172 fatal(NULL); 173 } else { 174 if (asprintf(&nfmt, "%s: %s: %s", p, emsg, strerror(errno)) == 175 -1) 176 fatal(NULL); 177 } 178 va_start(ap, emsg); 179 vlog(LOG_CRIT, nfmt, ap); 180 va_end(ap); 181 free(p); 182 free(nfmt); 183 } 184 185 void 186 log_peer_warnx(const struct peer_config *peer, const char *emsg, ...) 187 { 188 char *p, *nfmt; 189 va_list ap; 190 191 p = log_fmt_peer(peer); 192 if (asprintf(&nfmt, "%s: %s", p, emsg) == -1) 193 fatal(NULL); 194 va_start(ap, emsg); 195 vlog(LOG_CRIT, nfmt, ap); 196 va_end(ap); 197 free(p); 198 free(nfmt); 199 } 200 201 void 202 log_warn(const char *emsg, ...) 203 { 204 char *nfmt; 205 va_list ap; 206 207 /* best effort to even work in out of memory situations */ 208 if (emsg == NULL) 209 logit(LOG_CRIT, "%s", strerror(errno)); 210 else { 211 va_start(ap, emsg); 212 213 if (asprintf(&nfmt, "%s: %s", emsg, strerror(errno)) == -1) { 214 /* we tried it... */ 215 vlog(LOG_CRIT, emsg, ap); 216 logit(LOG_CRIT, "%s", strerror(errno)); 217 } else { 218 vlog(LOG_CRIT, nfmt, ap); 219 free(nfmt); 220 } 221 va_end(ap); 222 } 223 } 224 225 void 226 log_warnx(const char *emsg, ...) 227 { 228 va_list ap; 229 230 va_start(ap, emsg); 231 vlog(LOG_CRIT, emsg, ap); 232 va_end(ap); 233 } 234 235 void 236 log_info(const char *emsg, ...) 237 { 238 va_list ap; 239 240 va_start(ap, emsg); 241 vlog(LOG_INFO, emsg, ap); 242 va_end(ap); 243 } 244 245 void 246 log_debug(const char *emsg, ...) 247 { 248 va_list ap; 249 250 va_start(ap, emsg); 251 vlog(LOG_DEBUG, emsg, ap); 252 va_end(ap); 253 } 254 255 void 256 fatal(const char *emsg) 257 { 258 if (emsg == NULL) 259 logit(LOG_CRIT, "fatal in %s: %s", procnames[bgpd_process], 260 strerror(errno)); 261 else 262 if (errno) 263 logit(LOG_CRIT, "fatal in %s: %s: %s", 264 procnames[bgpd_process], emsg, strerror(errno)); 265 else 266 logit(LOG_CRIT, "fatal in %s: %s", 267 procnames[bgpd_process], emsg); 268 269 if (bgpd_process == PROC_MAIN) 270 exit(1); 271 else /* parent copes via SIGCHLD */ 272 _exit(1); 273 } 274 275 void 276 fatalx(const char *emsg) 277 { 278 errno = 0; 279 fatal(emsg); 280 } 281 282 void 283 fatal_ensure(const char *file, int line, const char *cond) 284 { 285 logit(LOG_CRIT, "ENSURE (%s) failed in file %s on line %d", 286 cond, file, line); 287 288 /* XXX check which process we are and notify others! */ 289 sleep(10); 290 _exit(1); 291 } 292 293 void 294 log_statechange(const struct peer *peer, enum session_state nstate, 295 enum session_events event) 296 { 297 char *p; 298 299 p = log_fmt_peer(&peer->conf); 300 logit(LOG_INFO, "%s: state change %s -> %s, reason: %s", 301 p, statenames[peer->state], statenames[nstate], eventnames[event]); 302 free(p); 303 } 304 305 void 306 log_notification(const struct peer *peer, u_int8_t errcode, u_int8_t subcode, 307 u_char *data, u_int16_t datalen) 308 { 309 char *p; 310 const char *suberrname = NULL; 311 int uk = 0; 312 313 p = log_fmt_peer(&peer->conf); 314 switch (errcode) { 315 case ERR_HEADER: 316 if (subcode > sizeof(suberr_header_names)/sizeof(char *)) 317 uk = 1; 318 else 319 suberrname = suberr_header_names[subcode]; 320 break; 321 case ERR_OPEN: 322 if (subcode > sizeof(suberr_open_names)/sizeof(char *)) 323 uk = 1; 324 else 325 suberrname = suberr_open_names[subcode]; 326 break; 327 case ERR_UPDATE: 328 if (subcode > sizeof(suberr_update_names)/sizeof(char *)) 329 uk = 1; 330 else 331 suberrname = suberr_update_names[subcode]; 332 break; 333 case ERR_HOLDTIMEREXPIRED: 334 case ERR_FSM: 335 case ERR_CEASE: 336 uk = 1; 337 break; 338 default: 339 logit(LOG_CRIT, "%s: received notification, unknown errcode " 340 "%u, subcode %u", p, errcode, subcode); 341 free(p); 342 return; 343 } 344 345 if (uk) 346 logit(LOG_CRIT, 347 "%s: received notification: %s, unknown subcode %u", 348 p, errnames[errcode], subcode); 349 else { 350 if (suberrname == NULL) 351 logit(LOG_CRIT, "%s: received notification: %s", 352 p, errnames[errcode]); 353 else 354 logit(LOG_CRIT, "%s: received notification: %s, %s", 355 p, errnames[errcode], suberrname); 356 } 357 free(p); 358 } 359 360 void 361 log_conn_attempt(const struct peer *peer, struct in_addr remote) 362 { 363 char *p; 364 365 if (peer == NULL) /* connection from non-peer, drop */ 366 logit(LOG_INFO, "connection from non-peer %s refused", 367 inet_ntoa(remote)); 368 else { 369 p = log_fmt_peer(&peer->conf); 370 logit(LOG_INFO, "Connection attempt from %s while session is " 371 "in state %s", p, statenames[peer->state]); 372 free(p); 373 } 374 } 375 376 const char * 377 log_addr(const struct bgpd_addr *addr) 378 { 379 static char buf[48]; 380 381 if (inet_ntop(addr->af, &addr->ba, buf, sizeof(buf)) == NULL) 382 return ("?"); 383 else 384 return (buf); 385 } 386