GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ldpd/control.c Lines: 0 129 0.0 %
Date: 2017-11-07 Branches: 0 81 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: control.c,v 1.29 2017/03/03 23:30:57 renato 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/un.h>
22
#include <errno.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <unistd.h>
26
27
#include "ldpd.h"
28
#include "ldpe.h"
29
#include "log.h"
30
#include "control.h"
31
32
#define	CONTROL_BACKLOG	5
33
34
static void		 control_accept(int, short, void *);
35
static struct ctl_conn	*control_connbyfd(int);
36
static struct ctl_conn	*control_connbypid(pid_t);
37
static void		 control_close(int);
38
static void		 control_dispatch_imsg(int, short, void *);
39
40
struct ctl_conns	 ctl_conns;
41
42
static int		 control_fd;
43
44
int
45
control_init(char *path)
46
{
47
	struct sockaddr_un	 sun;
48
	int			 fd;
49
	mode_t			 old_umask;
50
51
	if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
52
	    0)) == -1) {
53
		log_warn("%s: socket", __func__);
54
		return (-1);
55
	}
56
57
	memset(&sun, 0, sizeof(sun));
58
	sun.sun_family = AF_UNIX;
59
	strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
60
61
	if (unlink(path) == -1)
62
		if (errno != ENOENT) {
63
			log_warn("%s: unlink %s", __func__, path);
64
			close(fd);
65
			return (-1);
66
		}
67
68
	old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
69
	if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
70
		log_warn("%s: bind: %s", __func__, path);
71
		close(fd);
72
		umask(old_umask);
73
		return (-1);
74
	}
75
	umask(old_umask);
76
77
	if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) {
78
		log_warn("%s: chmod", __func__);
79
		close(fd);
80
		(void)unlink(path);
81
		return (-1);
82
	}
83
84
	control_fd = fd;
85
86
	return (0);
87
}
88
89
int
90
control_listen(void)
91
{
92
	if (listen(control_fd, CONTROL_BACKLOG) == -1) {
93
		log_warn("%s: listen", __func__);
94
		return (-1);
95
	}
96
97
	return (accept_add(control_fd, control_accept, NULL));
98
}
99
100
void
101
control_cleanup(char *path)
102
{
103
	accept_del(control_fd);
104
	close(control_fd);
105
	unlink(path);
106
}
107
108
/* ARGSUSED */
109
static void
110
control_accept(int listenfd, short event, void *bula)
111
{
112
	int			 connfd;
113
	socklen_t		 len;
114
	struct sockaddr_un	 sun;
115
	struct ctl_conn		*c;
116
117
	len = sizeof(sun);
118
	if ((connfd = accept4(listenfd, (struct sockaddr *)&sun, &len,
119
	    SOCK_NONBLOCK | SOCK_CLOEXEC)) == -1) {
120
		/*
121
		 * Pause accept if we are out of file descriptors, or
122
		 * libevent will haunt us here too.
123
		 */
124
		if (errno == ENFILE || errno == EMFILE)
125
			accept_pause();
126
		else if (errno != EWOULDBLOCK && errno != EINTR &&
127
		    errno != ECONNABORTED)
128
			log_warn("%s: accept4", __func__);
129
		return;
130
	}
131
132
	if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) {
133
		log_warn(__func__);
134
		close(connfd);
135
		return;
136
	}
137
138
	imsg_init(&c->iev.ibuf, connfd);
139
	c->iev.handler = control_dispatch_imsg;
140
	c->iev.events = EV_READ;
141
	event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events,
142
	    c->iev.handler, &c->iev);
143
	event_add(&c->iev.ev, NULL);
144
145
	TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
146
}
147
148
static struct ctl_conn *
149
control_connbyfd(int fd)
150
{
151
	struct ctl_conn	*c;
152
153
	TAILQ_FOREACH(c, &ctl_conns, entry) {
154
		if (c->iev.ibuf.fd == fd)
155
			break;
156
	}
157
158
	return (c);
159
}
160
161
static struct ctl_conn *
162
control_connbypid(pid_t pid)
163
{
164
	struct ctl_conn	*c;
165
166
	TAILQ_FOREACH(c, &ctl_conns, entry) {
167
		if (c->iev.ibuf.pid == pid)
168
			break;
169
	}
170
171
	return (c);
172
}
173
174
static void
175
control_close(int fd)
176
{
177
	struct ctl_conn	*c;
178
179
	if ((c = control_connbyfd(fd)) == NULL) {
180
		log_warnx("%s: fd %d: not found", __func__, fd);
181
		return;
182
	}
183
184
	msgbuf_clear(&c->iev.ibuf.w);
185
	TAILQ_REMOVE(&ctl_conns, c, entry);
186
187
	event_del(&c->iev.ev);
188
	close(c->iev.ibuf.fd);
189
	accept_unpause();
190
	free(c);
191
}
192
193
/* ARGSUSED */
194
static void
195
control_dispatch_imsg(int fd, short event, void *bula)
196
{
197
	struct ctl_conn	*c;
198
	struct imsg	 imsg;
199
	ssize_t		 n;
200
	unsigned int	 ifidx;
201
	int		 verbose;
202
203
	if ((c = control_connbyfd(fd)) == NULL) {
204
		log_warnx("%s: fd %d: not found", __func__, fd);
205
		return;
206
	}
207
208
	if (event & EV_READ) {
209
		if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) ||
210
		    n == 0) {
211
			control_close(fd);
212
			return;
213
		}
214
	}
215
	if (event & EV_WRITE) {
216
		if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) {
217
			control_close(fd);
218
			return;
219
		}
220
	}
221
222
	for (;;) {
223
		if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) {
224
			control_close(fd);
225
			return;
226
		}
227
228
		if (n == 0)
229
			break;
230
231
		switch (imsg.hdr.type) {
232
		case IMSG_CTL_FIB_COUPLE:
233
		case IMSG_CTL_FIB_DECOUPLE:
234
		case IMSG_CTL_RELOAD:
235
			c->iev.ibuf.pid = imsg.hdr.pid;
236
			ldpe_imsg_compose_parent(imsg.hdr.type, 0, NULL, 0);
237
			break;
238
		case IMSG_CTL_KROUTE:
239
		case IMSG_CTL_KROUTE_ADDR:
240
		case IMSG_CTL_IFINFO:
241
			c->iev.ibuf.pid = imsg.hdr.pid;
242
			ldpe_imsg_compose_parent(imsg.hdr.type,
243
			    imsg.hdr.pid, imsg.data,
244
			    imsg.hdr.len - IMSG_HEADER_SIZE);
245
			break;
246
		case IMSG_CTL_SHOW_INTERFACE:
247
			if (imsg.hdr.len == IMSG_HEADER_SIZE +
248
			    sizeof(ifidx)) {
249
				memcpy(&ifidx, imsg.data, sizeof(ifidx));
250
				ldpe_iface_ctl(c, ifidx);
251
				imsg_compose_event(&c->iev, IMSG_CTL_END, 0,
252
				    0, -1, NULL, 0);
253
			}
254
			break;
255
		case IMSG_CTL_SHOW_DISCOVERY:
256
			ldpe_adj_ctl(c);
257
			break;
258
		case IMSG_CTL_SHOW_LIB:
259
		case IMSG_CTL_SHOW_L2VPN_PW:
260
		case IMSG_CTL_SHOW_L2VPN_BINDING:
261
			c->iev.ibuf.pid = imsg.hdr.pid;
262
			ldpe_imsg_compose_lde(imsg.hdr.type, 0, imsg.hdr.pid,
263
			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
264
			break;
265
		case IMSG_CTL_SHOW_NBR:
266
			ldpe_nbr_ctl(c);
267
			break;
268
		case IMSG_CTL_CLEAR_NBR:
269
			if (imsg.hdr.len != IMSG_HEADER_SIZE +
270
			    sizeof(struct ctl_nbr))
271
				break;
272
273
			nbr_clear_ctl(imsg.data);
274
			break;
275
		case IMSG_CTL_LOG_VERBOSE:
276
			if (imsg.hdr.len != IMSG_HEADER_SIZE +
277
			    sizeof(verbose))
278
				break;
279
280
			/* forward to other processes */
281
			ldpe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid,
282
			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
283
			ldpe_imsg_compose_lde(imsg.hdr.type, 0, imsg.hdr.pid,
284
			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
285
286
			memcpy(&verbose, imsg.data, sizeof(verbose));
287
			log_verbose(verbose);
288
			break;
289
		default:
290
			log_debug("%s: error handling imsg %d", __func__,
291
			    imsg.hdr.type);
292
			break;
293
		}
294
		imsg_free(&imsg);
295
	}
296
297
	imsg_event_add(&c->iev);
298
}
299
300
int
301
control_imsg_relay(struct imsg *imsg)
302
{
303
	struct ctl_conn	*c;
304
305
	if ((c = control_connbypid(imsg->hdr.pid)) == NULL)
306
		return (0);
307
308
	return (imsg_compose_event(&c->iev, imsg->hdr.type, 0, imsg->hdr.pid,
309
	    -1, imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE));
310
}