xref: /openbsd-src/usr.sbin/ripd/control.c (revision f1b790a5738b7375271fee81f99119b1f82f2cfd)
1*f1b790a5Sclaudio /*	$OpenBSD: control.c,v 1.34 2024/11/21 13:38:15 claudio Exp $ */
2ddeeec14Snorby 
3ddeeec14Snorby /*
4ddeeec14Snorby  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
5ddeeec14Snorby  *
6ddeeec14Snorby  * Permission to use, copy, modify, and distribute this software for any
7ddeeec14Snorby  * purpose with or without fee is hereby granted, provided that the above
8ddeeec14Snorby  * copyright notice and this permission notice appear in all copies.
9ddeeec14Snorby  *
10ddeeec14Snorby  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11ddeeec14Snorby  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12ddeeec14Snorby  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13ddeeec14Snorby  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14ddeeec14Snorby  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15ddeeec14Snorby  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16ddeeec14Snorby  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17ddeeec14Snorby  */
18ddeeec14Snorby 
19ddeeec14Snorby #include <sys/types.h>
20ddeeec14Snorby #include <sys/stat.h>
21ddeeec14Snorby #include <sys/socket.h>
22ddeeec14Snorby #include <sys/un.h>
23ddeeec14Snorby #include <errno.h>
24ddeeec14Snorby #include <fcntl.h>
25ddeeec14Snorby #include <stdlib.h>
26ddeeec14Snorby #include <string.h>
27ddeeec14Snorby #include <unistd.h>
28ddeeec14Snorby 
29ddeeec14Snorby #include "ripd.h"
30ddeeec14Snorby #include "rip.h"
31ddeeec14Snorby #include "ripe.h"
32ddeeec14Snorby #include "log.h"
33ddeeec14Snorby #include "control.h"
34ddeeec14Snorby 
357b5b21dbSclaudio TAILQ_HEAD(ctl_conns, ctl_conn)	ctl_conns = TAILQ_HEAD_INITIALIZER(ctl_conns);
367b5b21dbSclaudio 
37ddeeec14Snorby #define	CONTROL_BACKLOG	5
38ddeeec14Snorby 
39ddeeec14Snorby struct ctl_conn	*control_connbyfd(int);
40ddeeec14Snorby struct ctl_conn	*control_connbypid(pid_t);
41ddeeec14Snorby void		 control_close(int);
42ddeeec14Snorby 
437b5b21dbSclaudio struct {
447b5b21dbSclaudio 	struct event	ev;
457b5b21dbSclaudio 	struct event	evt;
467b5b21dbSclaudio 	int		fd;
477b5b21dbSclaudio } control_state;
487b5b21dbSclaudio 
49ddeeec14Snorby int
503dabc796Sjca control_init(char *path)
51ddeeec14Snorby {
52ddeeec14Snorby 	struct sockaddr_un	 sun;
53ddeeec14Snorby 	int			 fd;
54ddeeec14Snorby 	mode_t			 old_umask;
55ddeeec14Snorby 
5633229c10Sclaudio 	if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
5733229c10Sclaudio 	    0)) == -1) {
58ddeeec14Snorby 		log_warn("control_init: socket");
59ddeeec14Snorby 		return (-1);
60ddeeec14Snorby 	}
61ddeeec14Snorby 
62ddeeec14Snorby 	bzero(&sun, sizeof(sun));
63ddeeec14Snorby 	sun.sun_family = AF_UNIX;
643dabc796Sjca 	strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
65ddeeec14Snorby 
663dabc796Sjca 	if (unlink(path) == -1)
67ddeeec14Snorby 		if (errno != ENOENT) {
683dabc796Sjca 			log_warn("control_init: unlink %s", path);
69ddeeec14Snorby 			close(fd);
70ddeeec14Snorby 			return (-1);
71ddeeec14Snorby 		}
72ddeeec14Snorby 
73ddeeec14Snorby 	old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
74ddeeec14Snorby 	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
753dabc796Sjca 		log_warn("control_init: bind: %s", path);
76ddeeec14Snorby 		close(fd);
77ddeeec14Snorby 		umask(old_umask);
78ddeeec14Snorby 		return (-1);
79ddeeec14Snorby 	}
80ddeeec14Snorby 	umask(old_umask);
81ddeeec14Snorby 
823dabc796Sjca 	if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) {
83ddeeec14Snorby 		log_warn("control_init: chmod");
84ddeeec14Snorby 		close(fd);
853dabc796Sjca 		(void)unlink(path);
86ddeeec14Snorby 		return (-1);
87ddeeec14Snorby 	}
88ddeeec14Snorby 
89ddeeec14Snorby 	control_state.fd = fd;
90ddeeec14Snorby 
91ddeeec14Snorby 	return (0);
92ddeeec14Snorby }
93ddeeec14Snorby 
94ddeeec14Snorby int
95ddeeec14Snorby control_listen(void)
96ddeeec14Snorby {
97ddeeec14Snorby 	if (listen(control_state.fd, CONTROL_BACKLOG) == -1) {
98ddeeec14Snorby 		log_warn("control_listen: listen");
99ddeeec14Snorby 		return (-1);
100ddeeec14Snorby 	}
101ddeeec14Snorby 
102e215f40dSderaadt 	event_set(&control_state.ev, control_state.fd, EV_READ,
103ddeeec14Snorby 	    control_accept, NULL);
104ddeeec14Snorby 	event_add(&control_state.ev, NULL);
105e215f40dSderaadt 	evtimer_set(&control_state.evt, control_accept, NULL);
106ddeeec14Snorby 
107ddeeec14Snorby 	return (0);
108ddeeec14Snorby }
109ddeeec14Snorby 
110ddeeec14Snorby void
111ddeeec14Snorby control_accept(int listenfd, short event, void *bula)
112ddeeec14Snorby {
113ddeeec14Snorby 	int			 connfd;
114ddeeec14Snorby 	socklen_t		 len;
115ddeeec14Snorby 	struct sockaddr_un	 sun;
116ddeeec14Snorby 	struct ctl_conn		*c;
117ddeeec14Snorby 
118e215f40dSderaadt 	event_add(&control_state.ev, NULL);
119e215f40dSderaadt 	if ((event & EV_TIMEOUT))
120e215f40dSderaadt 		return;
121e215f40dSderaadt 
122ddeeec14Snorby 	len = sizeof(sun);
12333229c10Sclaudio 	if ((connfd = accept4(listenfd, (struct sockaddr *)&sun, &len,
12433229c10Sclaudio 	    SOCK_CLOEXEC | SOCK_NONBLOCK)) == -1) {
125e215f40dSderaadt 		/*
126e215f40dSderaadt 		 * Pause accept if we are out of file descriptors, or
127e215f40dSderaadt 		 * libevent will haunt us here too.
128e215f40dSderaadt 		 */
129e215f40dSderaadt 		if (errno == ENFILE || errno == EMFILE) {
130e215f40dSderaadt 			struct timeval evtpause = { 1, 0 };
131e215f40dSderaadt 
132e215f40dSderaadt 			event_del(&control_state.ev);
133e215f40dSderaadt 			evtimer_add(&control_state.evt, &evtpause);
13462e3c252Sderaadt 		} else if (errno != EWOULDBLOCK && errno != EINTR &&
13562e3c252Sderaadt 		    errno != ECONNABORTED)
136e7464dffSmk 			log_warn("control_accept: accept");
137ddeeec14Snorby 		return;
138ddeeec14Snorby 	}
139ddeeec14Snorby 
14088d8283aSclaudio 	if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) {
141ddeeec14Snorby 		log_warn("control_accept");
142ac50b3daShenning 		close(connfd);
143ddeeec14Snorby 		return;
144ddeeec14Snorby 	}
145ddeeec14Snorby 
146*f1b790a5Sclaudio 	if (imsgbuf_init(&c->iev.ibuf, connfd) == -1) {
147*f1b790a5Sclaudio 		log_warn("control_accept");
148*f1b790a5Sclaudio 		close(connfd);
149*f1b790a5Sclaudio 		free(c);
150*f1b790a5Sclaudio 		return;
151*f1b790a5Sclaudio 	}
152f7ce36daSeric 	c->iev.handler = control_dispatch_imsg;
153f7ce36daSeric 	c->iev.events = EV_READ;
154f7ce36daSeric 	event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events,
155f7ce36daSeric 	    c->iev.handler, &c->iev);
156f7ce36daSeric 	event_add(&c->iev.ev, NULL);
157ddeeec14Snorby 
158ddeeec14Snorby 	TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
159ddeeec14Snorby }
160ddeeec14Snorby 
161ddeeec14Snorby struct ctl_conn *
162ddeeec14Snorby control_connbyfd(int fd)
163ddeeec14Snorby {
164ddeeec14Snorby 	struct ctl_conn	*c;
165ddeeec14Snorby 
166c39b7208Skrw 	TAILQ_FOREACH(c, &ctl_conns, entry) {
167c39b7208Skrw 		if (c->iev.ibuf.fd == fd)
168c39b7208Skrw 			break;
169c39b7208Skrw 	}
170ddeeec14Snorby 
171ddeeec14Snorby 	return (c);
172ddeeec14Snorby }
173ddeeec14Snorby 
174ddeeec14Snorby struct ctl_conn *
175ddeeec14Snorby control_connbypid(pid_t pid)
176ddeeec14Snorby {
177ddeeec14Snorby 	struct ctl_conn	*c;
178ddeeec14Snorby 
179c39b7208Skrw 	TAILQ_FOREACH(c, &ctl_conns, entry) {
180c39b7208Skrw 		if (c->iev.ibuf.pid == pid)
181c39b7208Skrw 			break;
182c39b7208Skrw 	}
183ddeeec14Snorby 
184ddeeec14Snorby 	return (c);
185ddeeec14Snorby }
186ddeeec14Snorby 
187ddeeec14Snorby void
188ddeeec14Snorby control_close(int fd)
189ddeeec14Snorby {
190ddeeec14Snorby 	struct ctl_conn	*c;
191ddeeec14Snorby 
192bca0e58eSclaudio 	if ((c = control_connbyfd(fd)) == NULL) {
193ddeeec14Snorby 		log_warn("control_close: fd %d: not found", fd);
194bca0e58eSclaudio 		return;
195bca0e58eSclaudio 	}
196ddeeec14Snorby 
1979cbf9e90Sclaudio 	imsgbuf_clear(&c->iev.ibuf);
198ddeeec14Snorby 	TAILQ_REMOVE(&ctl_conns, c, entry);
199ddeeec14Snorby 
200f7ce36daSeric 	event_del(&c->iev.ev);
201f7ce36daSeric 	close(c->iev.ibuf.fd);
202e215f40dSderaadt 
203e215f40dSderaadt 	/* Some file descriptors are available again. */
204e215f40dSderaadt 	if (evtimer_pending(&control_state.evt, NULL)) {
205e215f40dSderaadt 		evtimer_del(&control_state.evt);
206e215f40dSderaadt 		event_add(&control_state.ev, NULL);
207e215f40dSderaadt 	}
208e215f40dSderaadt 
209ddeeec14Snorby 	free(c);
210ddeeec14Snorby }
211ddeeec14Snorby 
212ddeeec14Snorby void
213ddeeec14Snorby control_dispatch_imsg(int fd, short event, void *bula)
214ddeeec14Snorby {
215ddeeec14Snorby 	struct ctl_conn	*c;
216ddeeec14Snorby 	struct imsg	 imsg;
2174acb39a0Sclaudio 	ssize_t		 n;
218ddeeec14Snorby 	unsigned int	 ifidx;
219dce97bddSclaudio 	int		 verbose;
220ddeeec14Snorby 
221ddeeec14Snorby 	if ((c = control_connbyfd(fd)) == NULL) {
222ddeeec14Snorby 		log_warn("control_dispatch_imsg: fd %d: not found", fd);
223ddeeec14Snorby 		return;
224ddeeec14Snorby 	}
225ddeeec14Snorby 
226bd6053efSclaudio 	if (event & EV_READ) {
227668e5ba9Sclaudio 		if (imsgbuf_read(&c->iev.ibuf) != 1) {
228ddeeec14Snorby 			control_close(fd);
229ddeeec14Snorby 			return;
230ddeeec14Snorby 		}
231bd6053efSclaudio 	}
232bd6053efSclaudio 	if (event & EV_WRITE) {
233dd7efffeSclaudio 		if (imsgbuf_write(&c->iev.ibuf) == -1) {
234ddeeec14Snorby 			control_close(fd);
235ddeeec14Snorby 			return;
236ddeeec14Snorby 		}
237ddeeec14Snorby 	}
238ddeeec14Snorby 
239ddeeec14Snorby 	for (;;) {
240f7ce36daSeric 		if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) {
241ddeeec14Snorby 			control_close(fd);
242ddeeec14Snorby 			return;
243ddeeec14Snorby 		}
244ddeeec14Snorby 
245ddeeec14Snorby 		if (n == 0)
246ddeeec14Snorby 			break;
247ddeeec14Snorby 
248ddeeec14Snorby 		switch (imsg.hdr.type) {
249ddeeec14Snorby 		case IMSG_CTL_SHOW_INTERFACE:
250ddeeec14Snorby 			if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(ifidx))
251ddeeec14Snorby 				return;
252ddeeec14Snorby 
253ddeeec14Snorby 			memcpy(&ifidx, imsg.data, sizeof(ifidx));
254ddeeec14Snorby 			ripe_iface_ctl(c, ifidx);
255f7ce36daSeric 			imsg_compose(&c->iev.ibuf, IMSG_CTL_END, 0, 0,
256f7ce36daSeric 			    -1, NULL, 0);
257ddeeec14Snorby 
258ddeeec14Snorby 			break;
259ddeeec14Snorby 		case IMSG_CTL_SHOW_RIB:
260f7ce36daSeric 			c->iev.ibuf.pid = imsg.hdr.pid;
261ddeeec14Snorby 			ripe_imsg_compose_rde(imsg.hdr.type, 0,
262ddeeec14Snorby 			    imsg.hdr.pid, imsg.data, imsg.hdr.len -
263ddeeec14Snorby 			    IMSG_HEADER_SIZE);
264ddeeec14Snorby 			break;
265ddeeec14Snorby 		case IMSG_CTL_SHOW_NBR:
266ddeeec14Snorby 			ripe_nbr_ctl(c);
267ddeeec14Snorby 			break;
268ddeeec14Snorby 		case IMSG_CTL_KROUTE_ADDR:
269ddeeec14Snorby 		case IMSG_CTL_KROUTE:
270ddeeec14Snorby 		case IMSG_CTL_IFINFO:
271f7ce36daSeric 			c->iev.ibuf.pid = imsg.hdr.pid;
272ddeeec14Snorby 			ripe_imsg_compose_parent(imsg.hdr.type,
273ddeeec14Snorby 			    imsg.hdr.pid, imsg.data,
274ddeeec14Snorby 			    imsg.hdr.len - IMSG_HEADER_SIZE);
275ddeeec14Snorby 			break;
276ddeeec14Snorby 		case IMSG_CTL_FIB_COUPLE:
277ddeeec14Snorby 		case IMSG_CTL_FIB_DECOUPLE:
278ddeeec14Snorby 		case IMSG_CTL_RELOAD:
279f7ce36daSeric 			c->iev.ibuf.pid = imsg.hdr.pid;
280ddeeec14Snorby 			ripe_imsg_compose_parent(imsg.hdr.type, 0, NULL, 0);
281ddeeec14Snorby 			break;
282dce97bddSclaudio 		case IMSG_CTL_LOG_VERBOSE:
283dce97bddSclaudio 			if (imsg.hdr.len != IMSG_HEADER_SIZE +
284dce97bddSclaudio 			    sizeof(verbose))
285dce97bddSclaudio 				break;
286dce97bddSclaudio 
287307aca1bSjsg 			/* forward to other processes */
288dce97bddSclaudio 			ripe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid,
289dce97bddSclaudio 			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
290dce97bddSclaudio 			ripe_imsg_compose_rde(imsg.hdr.type, 0, imsg.hdr.pid,
291dce97bddSclaudio 			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
292dce97bddSclaudio 
293dce97bddSclaudio 			memcpy(&verbose, imsg.data, sizeof(verbose));
294dce97bddSclaudio 			log_verbose(verbose);
295dce97bddSclaudio 			break;
296ddeeec14Snorby 		default:
297ddeeec14Snorby 			log_debug("control_dispatch_imsg: "
298ddeeec14Snorby 			    "error handling imsg %d", imsg.hdr.type);
299ddeeec14Snorby 			break;
300ddeeec14Snorby 		}
301ddeeec14Snorby 		imsg_free(&imsg);
302ddeeec14Snorby 	}
303ddeeec14Snorby 
304f7ce36daSeric 	imsg_event_add(&c->iev);
305ddeeec14Snorby }
306ddeeec14Snorby 
307ddeeec14Snorby int
308ddeeec14Snorby control_imsg_relay(struct imsg *imsg)
309ddeeec14Snorby {
310ddeeec14Snorby 	struct ctl_conn	*c;
311ddeeec14Snorby 
312ddeeec14Snorby 	if ((c = control_connbypid(imsg->hdr.pid)) == NULL)
313ddeeec14Snorby 		return (0);
314ddeeec14Snorby 
315f7ce36daSeric 	return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid,
316f7ce36daSeric 	    -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE));
317ddeeec14Snorby }
318