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