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