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