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