xref: /openbsd-src/usr.sbin/bgpd/log.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
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