control.c revision 1.11
1/*	$OpenBSD: control.c,v 1.11 2004/01/06 03:43:50 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/stat.h>
21#include <sys/socket.h>
22#include <sys/un.h>
23#include <errno.h>
24#include <stdlib.h>
25#include <string.h>
26#include <unistd.h>
27
28#include "bgpd.h"
29#include "session.h"
30
31#define	CONTROL_BACKLOG	5
32
33struct {
34	int	fd;
35} control_state;
36
37struct ctl_conn	*control_connbyfd(int);
38
39int
40control_init(void)
41{
42	struct sockaddr_un	 sun;
43	int			 fd;
44	mode_t			 old_umask;
45
46	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
47		log_err("control_init: socket");
48		return (-1);
49	}
50
51	old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
52	bzero(&sun, sizeof(sun));
53	sun.sun_family = AF_UNIX;
54	strlcpy(sun.sun_path, SOCKET_NAME, sizeof(sun.sun_path));
55
56	if (unlink(SOCKET_NAME) == -1)
57		if (errno != ENOENT) {
58			log_err("unlink %s", SOCKET_NAME);
59			return (-1);
60		}
61
62	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
63		log_err("control_init: bind: %s", SOCKET_NAME);
64		return (-1);
65	}
66
67	if (chmod(SOCKET_NAME, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) {
68		log_err("control_init chmod");
69		return (-1);
70	}
71
72	umask(old_umask);
73
74	control_state.fd = fd;
75
76	return (fd);
77}
78
79int
80control_listen(void)
81{
82	if (listen(control_state.fd, CONTROL_BACKLOG) == -1) {
83		log_err("control_listen: listen");
84		return (-1);
85	}
86
87	return (control_state.fd);
88}
89
90void
91control_shutdown(void)
92{
93	close(control_state.fd);
94}
95
96void
97control_cleanup(void)
98{
99	unlink(SOCKET_NAME);
100}
101
102void
103control_accept(int listenfd)
104{
105	int			 connfd;
106	socklen_t		 len;
107	struct sockaddr_un	 sun;
108	uid_t			 uid;
109	gid_t			 gid;
110	struct ctl_conn		*ctl_conn;
111
112	len = sizeof(sun);
113	if ((connfd = accept(listenfd,
114	    (struct sockaddr *)&sun, &len)) == -1) {
115		if (errno == EWOULDBLOCK || errno == EINTR)
116			return;
117		else
118			log_err("session_control_accept");
119	}
120
121	if (getpeereid(connfd, &uid, &gid) == -1) {
122		log_err("session_control_accept");
123		return;
124	}
125
126	if (uid) {
127		log_err("Connection to control socket with uid %ld", uid);
128		return;
129	}
130
131	if ((ctl_conn = malloc(sizeof(struct ctl_conn))) == NULL) {
132		log_err("session_control_accept");
133		return;
134	}
135
136	imsg_init(&ctl_conn->ibuf, connfd);
137
138	TAILQ_INSERT_TAIL(&ctl_conns, ctl_conn, entries);
139}
140
141struct ctl_conn *
142control_connbyfd(int fd)
143{
144	struct ctl_conn	*c;
145
146	for (c = TAILQ_FIRST(&ctl_conns); c != NULL && c->ibuf.sock != fd;
147	    c = TAILQ_NEXT(c, entries))
148		;	/* nothing */
149
150	return (c);
151}
152
153void
154control_close(int fd)
155{
156	struct ctl_conn	*c;
157
158	if ((c = control_connbyfd(fd)) == NULL) {
159		log_err("control_close: fd %d: not found", fd);
160		return;
161	}
162
163	TAILQ_REMOVE(&ctl_conns, c, entries);
164
165	close(c->ibuf.sock);
166	free(c);
167}
168
169int
170control_dispatch_msg(struct pollfd *pfd, int i)
171{
172	struct imsg		 imsg;
173	struct ctl_conn		*c;
174	int			 n;
175	struct peer		*p;
176	struct bgpd_addr	*addr;
177
178	if ((c = control_connbyfd(pfd->fd)) == NULL) {
179		log_err("control_dispatch_msg: fd %d: not found", pfd->fd);
180		return (0);
181	}
182
183	if (imsg_read(&c->ibuf) <= 0) {
184		control_close(pfd->fd);
185		return (1);
186	}
187
188	for (;;) {
189		if ((n = imsg_get(&c->ibuf, &imsg)) == -1) {
190			control_close(pfd->fd);
191			return (1);
192		}
193
194		if (n == 0)
195			break;
196
197		switch (imsg.hdr.type) {
198		case IMSG_CTL_SHOW_NEIGHBOR:
199			if (imsg.hdr.len == IMSG_HEADER_SIZE +
200			    sizeof(struct bgpd_addr)) {
201				addr = imsg.data;
202				p = getpeerbyip(addr->v4.s_addr);
203				if (p != NULL)
204					imsg_compose(&c->ibuf,
205					    IMSG_CTL_SHOW_NEIGHBOR,
206					    0, p, sizeof(struct peer));
207			} else
208				for (p = peers; p != NULL; p = p->next)
209					imsg_compose(&c->ibuf,
210					    IMSG_CTL_SHOW_NEIGHBOR,
211					    0, p, sizeof(struct peer));
212			imsg_compose(&c->ibuf, IMSG_CTL_END, 0, NULL, 0);
213			break;
214		case IMSG_CTL_RELOAD:
215		case IMSG_CTL_FIB_COUPLE:
216		case IMSG_CTL_FIB_DECOUPLE:
217			imsg_compose_parent(imsg.hdr.type, 0, NULL, 0);
218			break;
219		default:
220			break;
221		}
222		imsg_free(&imsg);
223	}
224
225	return (0);
226}
227