xref: /openbsd-src/usr.sbin/bgpd/logmsg.c (revision 9db223a96eba0880e7fcc87a3b1797a32a733584)
1*9db223a9Sclaudio /*	$OpenBSD: logmsg.c,v 1.14 2024/05/20 10:00:00 claudio Exp $ */
2db9ad1b1Sbenno 
3db9ad1b1Sbenno /*
4db9ad1b1Sbenno  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5db9ad1b1Sbenno  *
6db9ad1b1Sbenno  * Permission to use, copy, modify, and distribute this software for any
7db9ad1b1Sbenno  * purpose with or without fee is hereby granted, provided that the above
8db9ad1b1Sbenno  * copyright notice and this permission notice appear in all copies.
9db9ad1b1Sbenno  *
10db9ad1b1Sbenno  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11db9ad1b1Sbenno  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12db9ad1b1Sbenno  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13db9ad1b1Sbenno  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14db9ad1b1Sbenno  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15db9ad1b1Sbenno  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16db9ad1b1Sbenno  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17db9ad1b1Sbenno  */
18db9ad1b1Sbenno 
19db9ad1b1Sbenno #include <errno.h>
20db9ad1b1Sbenno #include <stdarg.h>
21db9ad1b1Sbenno #include <stdio.h>
22db9ad1b1Sbenno #include <stdlib.h>
23db9ad1b1Sbenno #include <string.h>
24db9ad1b1Sbenno #include <sys/types.h>
25db9ad1b1Sbenno #include <syslog.h>
26db9ad1b1Sbenno 
27db9ad1b1Sbenno #include "bgpd.h"
28db9ad1b1Sbenno #include "session.h"
295e3f6f95Sbenno #include "log.h"
30db9ad1b1Sbenno 
31db9ad1b1Sbenno char *
log_fmt_peer(const struct peer_config * peer)32db9ad1b1Sbenno log_fmt_peer(const struct peer_config *peer)
33db9ad1b1Sbenno {
34db9ad1b1Sbenno 	const char	*ip;
35db9ad1b1Sbenno 	char		*pfmt, *p;
36db9ad1b1Sbenno 
37db9ad1b1Sbenno 	ip = log_addr(&peer->remote_addr);
38db9ad1b1Sbenno 	if ((peer->remote_addr.aid == AID_INET && peer->remote_masklen != 32) ||
39db9ad1b1Sbenno 	    (peer->remote_addr.aid == AID_INET6 &&
40db9ad1b1Sbenno 	    peer->remote_masklen != 128)) {
41db9ad1b1Sbenno 		if (asprintf(&p, "%s/%u", ip, peer->remote_masklen) == -1)
42db9ad1b1Sbenno 			fatal(NULL);
43db9ad1b1Sbenno 	} else {
44db9ad1b1Sbenno 		if ((p = strdup(ip)) == NULL)
45db9ad1b1Sbenno 			fatal(NULL);
46db9ad1b1Sbenno 	}
47db9ad1b1Sbenno 
48db9ad1b1Sbenno 	if (peer->descr[0]) {
49db9ad1b1Sbenno 		if (asprintf(&pfmt, "neighbor %s (%s)", p, peer->descr) ==
50db9ad1b1Sbenno 		    -1)
51db9ad1b1Sbenno 			fatal(NULL);
52db9ad1b1Sbenno 	} else {
53db9ad1b1Sbenno 		if (asprintf(&pfmt, "neighbor %s", p) == -1)
54db9ad1b1Sbenno 			fatal(NULL);
55db9ad1b1Sbenno 	}
56db9ad1b1Sbenno 	free(p);
57db9ad1b1Sbenno 	return (pfmt);
58db9ad1b1Sbenno }
59db9ad1b1Sbenno 
60db9ad1b1Sbenno void
log_peer_info(const struct peer_config * peer,const char * emsg,...)613e416abfSclaudio log_peer_info(const struct peer_config *peer, const char *emsg, ...)
623e416abfSclaudio {
632fed7a8bSclaudio 	char	*p, *msg;
643e416abfSclaudio 	va_list	 ap;
653e416abfSclaudio 
663e416abfSclaudio 	p = log_fmt_peer(peer);
673e416abfSclaudio 	va_start(ap, emsg);
682fed7a8bSclaudio 	if (vasprintf(&msg, emsg, ap) == -1)
692fed7a8bSclaudio 		fatal(NULL);
703e416abfSclaudio 	va_end(ap);
712fed7a8bSclaudio 	logit(LOG_INFO, "%s: %s", p, msg);
722fed7a8bSclaudio 	free(msg);
733e416abfSclaudio 	free(p);
743e416abfSclaudio }
753e416abfSclaudio 
763e416abfSclaudio void
log_peer_warn(const struct peer_config * peer,const char * emsg,...)77db9ad1b1Sbenno log_peer_warn(const struct peer_config *peer, const char *emsg, ...)
78db9ad1b1Sbenno {
792fed7a8bSclaudio 	char	*p, *msg;
80db9ad1b1Sbenno 	va_list	 ap;
812fed7a8bSclaudio 	int	 saved_errno = errno;
82db9ad1b1Sbenno 
83db9ad1b1Sbenno 	p = log_fmt_peer(peer);
84db9ad1b1Sbenno 	if (emsg == NULL) {
852fed7a8bSclaudio 		logit(LOG_ERR, "%s: %s", p, strerror(saved_errno));
86db9ad1b1Sbenno 	} else {
87db9ad1b1Sbenno 		va_start(ap, emsg);
882fed7a8bSclaudio 		if (vasprintf(&msg, emsg, ap) == -1)
892fed7a8bSclaudio 			fatal(NULL);
90db9ad1b1Sbenno 		va_end(ap);
912fed7a8bSclaudio 		logit(LOG_ERR, "%s: %s: %s", p, msg, strerror(saved_errno));
922fed7a8bSclaudio 		free(msg);
932fed7a8bSclaudio 	}
94db9ad1b1Sbenno 	free(p);
95db9ad1b1Sbenno }
96db9ad1b1Sbenno 
97db9ad1b1Sbenno void
log_peer_warnx(const struct peer_config * peer,const char * emsg,...)98db9ad1b1Sbenno log_peer_warnx(const struct peer_config *peer, const char *emsg, ...)
99db9ad1b1Sbenno {
1002fed7a8bSclaudio 	char	*p, *msg;
101db9ad1b1Sbenno 	va_list	 ap;
102db9ad1b1Sbenno 
103db9ad1b1Sbenno 	p = log_fmt_peer(peer);
104db9ad1b1Sbenno 	va_start(ap, emsg);
1052fed7a8bSclaudio 	if (vasprintf(&msg, emsg, ap) == -1)
1062fed7a8bSclaudio 		fatal(NULL);
107db9ad1b1Sbenno 	va_end(ap);
1082fed7a8bSclaudio 	logit(LOG_ERR, "%s: %s", p, msg);
1092fed7a8bSclaudio 	free(msg);
110db9ad1b1Sbenno 	free(p);
111db9ad1b1Sbenno }
112db9ad1b1Sbenno 
113db9ad1b1Sbenno void
log_statechange(struct peer * peer,enum session_state nstate,enum session_events event)114db9ad1b1Sbenno log_statechange(struct peer *peer, enum session_state nstate,
115db9ad1b1Sbenno     enum session_events event)
116db9ad1b1Sbenno {
117db9ad1b1Sbenno 	char	*p;
118db9ad1b1Sbenno 
119db9ad1b1Sbenno 	/* don't clutter the logs with constant Connect -> Active -> Connect */
120db9ad1b1Sbenno 	if (nstate == STATE_CONNECT && peer->state == STATE_ACTIVE &&
121db9ad1b1Sbenno 	    peer->prev_state == STATE_CONNECT)
122db9ad1b1Sbenno 		return;
123db9ad1b1Sbenno 	if (nstate == STATE_ACTIVE && peer->state == STATE_CONNECT &&
124db9ad1b1Sbenno 	    peer->prev_state == STATE_ACTIVE)
125db9ad1b1Sbenno 		return;
126db9ad1b1Sbenno 
127db9ad1b1Sbenno 	peer->lasterr = 0;
128db9ad1b1Sbenno 	p = log_fmt_peer(&peer->conf);
129db9ad1b1Sbenno 	logit(LOG_INFO, "%s: state change %s -> %s, reason: %s",
130db9ad1b1Sbenno 	    p, statenames[peer->state], statenames[nstate], eventnames[event]);
131db9ad1b1Sbenno 	free(p);
132db9ad1b1Sbenno }
133db9ad1b1Sbenno 
134db9ad1b1Sbenno void
log_notification(const struct peer * peer,uint8_t errcode,uint8_t subcode,const struct ibuf * data,const char * dir)13539386878Sclaudio log_notification(const struct peer *peer, uint8_t errcode, uint8_t subcode,
136beb044e9Sclaudio     const struct ibuf *data, const char *dir)
137db9ad1b1Sbenno {
138beb044e9Sclaudio 	struct ibuf	 ibuf;
139db9ad1b1Sbenno 	char		*p;
140db9ad1b1Sbenno 	const char	*suberrname = NULL;
141db9ad1b1Sbenno 	int		 uk = 0;
142db9ad1b1Sbenno 
143beb044e9Sclaudio 	if (data != NULL)
144beb044e9Sclaudio 		ibuf_from_ibuf(&ibuf, data);
145beb044e9Sclaudio 	else
146beb044e9Sclaudio 		ibuf_from_buffer(&ibuf, NULL, 0);
147beb044e9Sclaudio 
148db9ad1b1Sbenno 	p = log_fmt_peer(&peer->conf);
149db9ad1b1Sbenno 	switch (errcode) {
150db9ad1b1Sbenno 	case ERR_HEADER:
151347f9e6cSclaudio 		if (subcode >= sizeof(suberr_header_names) / sizeof(char *) ||
152347f9e6cSclaudio 		    suberr_header_names[subcode] == NULL)
153db9ad1b1Sbenno 			uk = 1;
154db9ad1b1Sbenno 		else
155db9ad1b1Sbenno 			suberrname = suberr_header_names[subcode];
156db9ad1b1Sbenno 		break;
157db9ad1b1Sbenno 	case ERR_OPEN:
158347f9e6cSclaudio 		if (subcode >= sizeof(suberr_open_names) / sizeof(char *) ||
159347f9e6cSclaudio 		    suberr_open_names[subcode] == NULL)
160db9ad1b1Sbenno 			uk = 1;
161db9ad1b1Sbenno 		else
162db9ad1b1Sbenno 			suberrname = suberr_open_names[subcode];
163beb044e9Sclaudio 		if (errcode == ERR_OPEN && subcode == ERR_OPEN_CAPA) {
164beb044e9Sclaudio 			uint8_t capa_code;
165beb044e9Sclaudio 
166beb044e9Sclaudio 			if (ibuf_get_n8(&ibuf, &capa_code) == -1)
167beb044e9Sclaudio 				break;
168beb044e9Sclaudio 
169beb044e9Sclaudio 			logit(LOG_ERR, "%s: %s notification: %s, %s: %s",
170beb044e9Sclaudio 			    p, dir, errnames[errcode], suberrname,
171beb044e9Sclaudio 			    log_capability(capa_code));
172beb044e9Sclaudio 			free(p);
173beb044e9Sclaudio 			return;
174beb044e9Sclaudio 		}
175db9ad1b1Sbenno 		break;
176db9ad1b1Sbenno 	case ERR_UPDATE:
177347f9e6cSclaudio 		if (subcode >= sizeof(suberr_update_names) / sizeof(char *) ||
178347f9e6cSclaudio 		    suberr_update_names[subcode] == NULL)
179db9ad1b1Sbenno 			uk = 1;
180db9ad1b1Sbenno 		else
181db9ad1b1Sbenno 			suberrname = suberr_update_names[subcode];
182db9ad1b1Sbenno 		break;
183db9ad1b1Sbenno 	case ERR_CEASE:
184347f9e6cSclaudio 		if (subcode >= sizeof(suberr_cease_names) / sizeof(char *) ||
185347f9e6cSclaudio 		    suberr_cease_names[subcode] == NULL)
186db9ad1b1Sbenno 			uk = 1;
187db9ad1b1Sbenno 		else
188db9ad1b1Sbenno 			suberrname = suberr_cease_names[subcode];
189beb044e9Sclaudio 
190beb044e9Sclaudio 		if (subcode == ERR_CEASE_ADMIN_DOWN ||
191beb044e9Sclaudio 		    subcode == ERR_CEASE_ADMIN_RESET) {
192eff7ddafSclaudio 			uint8_t len;
193eff7ddafSclaudio 			/* check if shutdown reason is included */
194eff7ddafSclaudio 			if (ibuf_get_n8(&ibuf, &len) != -1 && len != 0) {
195eff7ddafSclaudio 				char *s;
196eff7ddafSclaudio 				if ((s = ibuf_get_string(&ibuf, len)) != NULL) {
197eff7ddafSclaudio 					logit(LOG_ERR, "%s: %s notification: "
198eff7ddafSclaudio 					    "%s, %s: reason \"%s\"", p, dir,
199beb044e9Sclaudio 					    errnames[errcode], suberrname,
200eff7ddafSclaudio 					    log_reason(s));
201eff7ddafSclaudio 					free(s);
202beb044e9Sclaudio 					free(p);
203beb044e9Sclaudio 					return;
204beb044e9Sclaudio 				}
205beb044e9Sclaudio 			}
206eff7ddafSclaudio 		}
207db9ad1b1Sbenno 		break;
208db9ad1b1Sbenno 	case ERR_HOLDTIMEREXPIRED:
209db9ad1b1Sbenno 		if (subcode != 0)
210db9ad1b1Sbenno 			uk = 1;
211db9ad1b1Sbenno 		break;
212db9ad1b1Sbenno 	case ERR_FSM:
213347f9e6cSclaudio 		if (subcode >= sizeof(suberr_fsm_names) / sizeof(char *) ||
214347f9e6cSclaudio 		    suberr_fsm_names[subcode] == NULL)
215db9ad1b1Sbenno 			uk = 1;
216db9ad1b1Sbenno 		else
217db9ad1b1Sbenno 			suberrname = suberr_fsm_names[subcode];
218db9ad1b1Sbenno 		break;
21963c2de87Sclaudio 	case ERR_RREFRESH:
220347f9e6cSclaudio 		if (subcode >= sizeof(suberr_rrefresh_names) / sizeof(char *) ||
221347f9e6cSclaudio 		    suberr_rrefresh_names[subcode] == NULL)
22263c2de87Sclaudio 			uk = 1;
22363c2de87Sclaudio 		else
22463c2de87Sclaudio 			suberrname = suberr_rrefresh_names[subcode];
22563c2de87Sclaudio 		break;
226db9ad1b1Sbenno 	default:
2273e416abfSclaudio 		logit(LOG_ERR, "%s: %s notification, unknown errcode "
228db9ad1b1Sbenno 		    "%u, subcode %u", p, dir, errcode, subcode);
229db9ad1b1Sbenno 		free(p);
230db9ad1b1Sbenno 		return;
231db9ad1b1Sbenno 	}
232db9ad1b1Sbenno 
233db9ad1b1Sbenno 	if (uk)
2343e416abfSclaudio 		logit(LOG_ERR, "%s: %s notification: %s, unknown subcode %u",
235db9ad1b1Sbenno 		    p, dir, errnames[errcode], subcode);
236db9ad1b1Sbenno 	else {
237db9ad1b1Sbenno 		if (suberrname == NULL)
2383e416abfSclaudio 			logit(LOG_ERR, "%s: %s notification: %s", p,
239db9ad1b1Sbenno 			    dir, errnames[errcode]);
240db9ad1b1Sbenno 		else
2413e416abfSclaudio 			logit(LOG_ERR, "%s: %s notification: %s, %s",
242db9ad1b1Sbenno 			    p, dir, errnames[errcode], suberrname);
243db9ad1b1Sbenno 	}
244db9ad1b1Sbenno 	free(p);
245db9ad1b1Sbenno }
246db9ad1b1Sbenno 
247db9ad1b1Sbenno void
log_conn_attempt(const struct peer * peer,struct sockaddr * sa,socklen_t len)248255fe563Sclaudio log_conn_attempt(const struct peer *peer, struct sockaddr *sa, socklen_t len)
249db9ad1b1Sbenno {
250db9ad1b1Sbenno 	char		*p;
251db9ad1b1Sbenno 
252db9ad1b1Sbenno 	if (peer == NULL) {	/* connection from non-peer, drop */
25306af690fSclaudio 		if (log_getverbose())
25406af690fSclaudio 			logit(LOG_INFO, "connection from non-peer %s refused",
25506af690fSclaudio 			    log_sockaddr(sa, len));
256db9ad1b1Sbenno 	} else {
257db9ad1b1Sbenno 		/* only log if there is a chance that the session may come up */
258db9ad1b1Sbenno 		if (peer->conf.down && peer->state == STATE_IDLE)
259db9ad1b1Sbenno 			return;
260db9ad1b1Sbenno 		p = log_fmt_peer(&peer->conf);
261db9ad1b1Sbenno 		logit(LOG_INFO, "Connection attempt from %s while session is "
262db9ad1b1Sbenno 		    "in state %s", p, statenames[peer->state]);
263db9ad1b1Sbenno 		free(p);
264db9ad1b1Sbenno 	}
265db9ad1b1Sbenno }
266