GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/slaacctl/slaacctl.c Lines: 140 172 81.4 %
Date: 2017-11-13 Branches: 53 86 61.6 %

Line Branch Exec Source
1
/*	$OpenBSD: slaacctl.c,v 1.13 2017/08/28 15:35:48 florian Exp $	*/
2
3
/*
4
 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5
 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
6
 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
7
 *
8
 * Permission to use, copy, modify, and distribute this software for any
9
 * purpose with or without fee is hereby granted, provided that the above
10
 * copyright notice and this permission notice appear in all copies.
11
 *
12
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
 */
20
21
#include <sys/types.h>
22
#include <sys/queue.h>
23
#include <sys/socket.h>
24
#include <sys/un.h>
25
#include <arpa/inet.h>
26
27
#include <net/if.h>
28
#include <net/if_media.h>
29
#include <net/if_types.h>
30
31
#include <netinet/in.h>
32
#include <netinet/if_ether.h>
33
#include <netinet6/nd6.h>
34
35
#include <err.h>
36
#include <errno.h>
37
#include <event.h>
38
#include <imsg.h>
39
#include <netdb.h>
40
#include <stdio.h>
41
#include <stdlib.h>
42
#include <string.h>
43
#include <unistd.h>
44
45
#include "slaacd.h"
46
#include "frontend.h"
47
#include "parser.h"
48
49
__dead void	 usage(void);
50
int		 show_interface_msg(struct imsg *);
51
52
struct imsgbuf	*ibuf;
53
54
__dead void
55
usage(void)
56
{
57
	extern char *__progname;
58
59
	fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n",
60
	    __progname);
61
	exit(1);
62
}
63
64
int
65
main(int argc, char *argv[])
66
{
67
36
	struct sockaddr_un	 sun;
68
	struct parse_result	*res;
69
18
	struct imsg		 imsg;
70
	int			 ctl_sock;
71
	int			 done = 0;
72
18
	int			 n, verbose = 0;
73
	int			 ch;
74
	char			*sockname;
75
76
	sockname = SLAACD_SOCKET;
77
72
	while ((ch = getopt(argc, argv, "s:")) != -1) {
78
18
		switch (ch) {
79
		case 's':
80
18
			sockname = optarg;
81
			break;
82
		default:
83
			usage();
84
		}
85
	}
86
18
	argc -= optind;
87
18
	argv += optind;
88
89
	/* Parse command line. */
90
18
	if ((res = parse(argc, argv)) == NULL)
91
		exit(1);
92
93
	/* Connect to control socket. */
94
18
	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
95
		err(1, "socket");
96
97
18
	memset(&sun, 0, sizeof(sun));
98
18
	sun.sun_family = AF_UNIX;
99
100
18
	strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path));
101
18
	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
102
		err(1, "connect: %s", sockname);
103
104
18
	if (pledge("stdio flock rpath cpath wpath", NULL) == -1)
105
		err(1, "pledge");
106
107
18
	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
108
		err(1, NULL);
109
18
	imsg_init(ibuf, ctl_sock);
110
	done = 0;
111
112
	/* Process user request. */
113

18
	switch (res->action) {
114
	case LOG_VERBOSE:
115
		verbose = 1;
116
		/* FALLTHROUGH */
117
	case LOG_BRIEF:
118
		imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
119
		    &verbose, sizeof(verbose));
120
		printf("logging request sent.\n");
121
		done = 1;
122
		break;
123
	case SHOW_INTERFACE:
124
12
		imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE_INFO, 0, 0, -1,
125
6
		    &res->if_index, sizeof(res->if_index));
126
6
		break;
127
	case SEND_SOLICITATION:
128
24
		imsg_compose(ibuf, IMSG_CTL_SEND_SOLICITATION, 0, 0, -1,
129
12
		    &res->if_index, sizeof(res->if_index));
130
		done = 1;
131
12
		break;
132
	default:
133
		usage();
134
	}
135
136
72
	while (ibuf->w.queued)
137

18
		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
138
			err(1, "write error");
139
140
48
	while (!done) {
141

6
		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
142
			errx(1, "imsg_read error");
143
6
		if (n == 0)
144
			errx(1, "pipe closed");
145
146
156
		while (!done) {
147
72
			if ((n = imsg_get(ibuf, &imsg)) == -1)
148
				errx(1, "imsg_get error");
149
72
			if (n == 0)
150
				break;
151
152
72
			switch (res->action) {
153
			case SHOW_INTERFACE:
154
72
				done = show_interface_msg(&imsg);
155
72
				break;
156
			default:
157
				break;
158
			}
159
160
72
			imsg_free(&imsg);
161
		}
162
	}
163
18
	close(ctl_sock);
164
18
	free(ibuf);
165
166
18
	return (0);
167
18
}
168
169
int
170
show_interface_msg(struct imsg *imsg)
171
{
172
	static int				 if_count = 0;
173
	struct ctl_engine_info			*cei;
174
	struct ctl_engine_info_ra		*cei_ra;
175
	struct ctl_engine_info_ra_prefix	*cei_ra_prefix;
176
	struct ctl_engine_info_ra_rdns		*cei_ra_rdns;
177
	struct ctl_engine_info_ra_dnssl		*cei_ra_dnssl;
178
	struct ctl_engine_info_address_proposal	*cei_addr_proposal;
179
	struct ctl_engine_info_dfr_proposal	*cei_dfr_proposal;
180
	struct tm				*t;
181
210
	struct timespec				 now, diff;
182
138
	char					 buf[IF_NAMESIZE], *bufp;
183
138
	char					 hbuf[NI_MAXHOST], whenbuf[255];
184
138
	char					 ntopbuf[INET6_ADDRSTRLEN];
185
186


138
	switch (imsg->hdr.type) {
187
	case IMSG_CTL_SHOW_INTERFACE_INFO:
188
6
		cei = imsg->data;
189
190
6
		if (if_count++ > 0)
191
			printf("\n");
192
193
6
		bufp = if_indextoname(cei->if_index, buf);
194
6
		printf("%s:\n", bufp != NULL ? bufp : "unknown");
195
6
		printf("\t index: %3u ", cei->if_index);
196
6
		printf("running: %3s ", cei->running ? "yes" : "no");
197
6
		printf("privacy: %3s\n", cei->autoconfprivacy ? "yes" : "no");
198
6
		printf("\tlladdr: %s\n", ether_ntoa(&cei->hw_address));
199
12
		if (getnameinfo((struct sockaddr *)&cei->ll_address,
200
6
		    cei->ll_address.sin6_len, hbuf, sizeof(hbuf), NULL, 0,
201
		    NI_NUMERICHOST | NI_NUMERICSERV))
202
			err(1, "cannot get link local address");
203
6
		printf("\t inet6: %s\n", hbuf);
204
6
		break;
205
	case IMSG_CTL_SHOW_INTERFACE_INFO_RA:
206
6
		cei_ra = imsg->data;
207
208
12
		if (getnameinfo((struct sockaddr *)&cei_ra->from,
209
6
		    cei_ra->from.sin6_len, hbuf, sizeof(hbuf), NULL, 0,
210
		    NI_NUMERICHOST | NI_NUMERICSERV))
211
			err(1, "cannot get router IP");
212
213
6
		if (clock_gettime(CLOCK_MONOTONIC, &now))
214
			err(1, "clock_gettime");
215
216
7
		timespecsub(&now, &cei_ra->uptime, &diff);
217
218
6
		t = localtime(&cei_ra->when.tv_sec);
219
6
		strftime(whenbuf, sizeof(whenbuf), "%F %T", t);
220
6
		printf("\tRouter Advertisement from %s\n", hbuf);
221
6
		printf("\t\treceived: %s; %llds ago\n", whenbuf, diff.tv_sec);
222
6
		printf("\t\tCur Hop Limit: %3u, M: %d, O: %d, Router Lifetime:"
223
6
		    " %5us\n", cei_ra->curhoplimit, cei_ra->managed ? 1: 0,
224
6
		    cei_ra->other ? 1 : 0, cei_ra->router_lifetime);
225
6
		printf("\t\tDefault Router Preference: %s\n", cei_ra->rpref);
226
6
		printf("\t\tReachable Time: %9ums, Retrans Timer: %9ums\n",
227
6
		    cei_ra->reachable_time, cei_ra->retrans_time);
228
6
		break;
229
	case IMSG_CTL_SHOW_INTERFACE_INFO_RA_PREFIX:
230
6
		cei_ra_prefix = imsg->data;
231
12
		printf("\t\tprefix: %s/%u\n", inet_ntop(AF_INET6,
232
6
		    &cei_ra_prefix->prefix, ntopbuf, INET6_ADDRSTRLEN),
233
6
			    cei_ra_prefix->prefix_len);
234
6
		printf("\t\t\tOn-link: %d, Autonomous address-configuration: %d"
235
6
		    "\n", cei_ra_prefix->onlink ? 1 : 0,
236
6
		    cei_ra_prefix->autonomous ? 1 : 0);
237
6
		if (cei_ra_prefix->vltime == ND6_INFINITE_LIFETIME)
238
			printf("\t\t\tvltime: %10s, ", "infinity");
239
		else
240
6
			printf("\t\t\tvltime: %10u, ", cei_ra_prefix->vltime);
241
6
		if (cei_ra_prefix->pltime == ND6_INFINITE_LIFETIME)
242
			printf("pltime: %10s\n", "infinity");
243
		else
244
6
			printf("pltime: %10u\n", cei_ra_prefix->pltime);
245
		break;
246
	case IMSG_CTL_SHOW_INTERFACE_INFO_RA_RDNS:
247
12
		cei_ra_rdns = imsg->data;
248
24
		printf("\t\trdns: %s, lifetime: %u\n", inet_ntop(AF_INET6,
249
12
		    &cei_ra_rdns->rdns, ntopbuf, INET6_ADDRSTRLEN),
250
12
		    cei_ra_rdns->lifetime);
251
12
		break;
252
	case IMSG_CTL_SHOW_INTERFACE_INFO_RA_DNSSL:
253
6
		cei_ra_dnssl = imsg->data;
254
12
		printf("\t\tsearch: %s, lifetime: %u\n", cei_ra_dnssl->dnssl,
255
6
		    cei_ra_dnssl->lifetime);
256
6
		break;
257
	case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSALS:
258
6
		printf("\tAddress proposals\n");
259
6
		break;
260
	case IMSG_CTL_SHOW_INTERFACE_INFO_ADDR_PROPOSAL:
261
12
		cei_addr_proposal = imsg->data;
262
263
24
		if (getnameinfo((struct sockaddr *)&cei_addr_proposal->addr,
264
12
		    cei_addr_proposal->addr.sin6_len, hbuf, sizeof(hbuf),
265
		    NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV))
266
			err(1, "cannot get proposal IP");
267
268
12
		printf("\t\tid: %4lld, state: %15s, privacy: %s\n",
269
12
		    cei_addr_proposal->id, cei_addr_proposal->state,
270
12
		    cei_addr_proposal->privacy ? "y" : "n");
271
272
12
		if (clock_gettime(CLOCK_MONOTONIC, &now))
273
			err(1, "clock_gettime");
274
275
14
		timespecsub(&now, &cei_addr_proposal->uptime, &diff);
276
277
12
		if (cei_addr_proposal->vltime == ND6_INFINITE_LIFETIME)
278
			printf("\t\tvltime: %10s, ", "infinity");
279
		else
280
12
			printf("\t\tvltime: %10u, ", cei_addr_proposal->vltime);
281
12
		if (cei_addr_proposal->pltime == ND6_INFINITE_LIFETIME)
282
			printf("pltime: %10s", "infinity");
283
		else
284
12
			printf("pltime: %10u", cei_addr_proposal->pltime);
285
12
		if (cei_addr_proposal->next_timeout != 0)
286
12
			printf(", timeout: %10llds\n",
287
12
			    cei_addr_proposal->next_timeout - diff.tv_sec);
288
		else
289
			printf("\n");
290
291
12
		t = localtime(&cei_addr_proposal->when.tv_sec);
292
12
		strftime(whenbuf, sizeof(whenbuf), "%F %T", t);
293
12
		printf("\t\tupdated: %s; %llds ago\n", whenbuf, diff.tv_sec);
294
24
		printf("\t\t%s, %s/%u\n", hbuf, inet_ntop(AF_INET6,
295
12
		    &cei_addr_proposal->prefix, ntopbuf, INET6_ADDRSTRLEN),
296
12
		    cei_addr_proposal->prefix_len);
297
12
		break;
298
	case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS:
299
6
		printf("\tDefault router proposals\n");
300
6
		break;
301
	case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL:
302
6
		cei_dfr_proposal = imsg->data;
303
304
12
		if (getnameinfo((struct sockaddr *)&cei_dfr_proposal->addr,
305
6
		    cei_dfr_proposal->addr.sin6_len, hbuf, sizeof(hbuf),
306
		    NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV))
307
			err(1, "cannot get router IP");
308
309
6
		printf("\t\tid: %4lld, state: %15s\n",
310
6
		    cei_dfr_proposal->id, cei_dfr_proposal->state);
311
6
		printf("\t\trouter: %s\n", hbuf);
312
6
		printf("\t\trouter lifetime: %10u\n",
313
6
		    cei_dfr_proposal->router_lifetime);
314
6
		printf("\t\tPreference: %s\n", cei_dfr_proposal->rpref);
315
6
		if (clock_gettime(CLOCK_MONOTONIC, &now))
316
			err(1, "clock_gettime");
317
318
7
		timespecsub(&now, &cei_dfr_proposal->uptime, &diff);
319
320
6
		t = localtime(&cei_dfr_proposal->when.tv_sec);
321
6
		strftime(whenbuf, sizeof(whenbuf), "%F %T", t);
322
6
		printf("\t\tupdated: %s; %llds ago", whenbuf, diff.tv_sec);
323
6
		if (cei_dfr_proposal->next_timeout != 0)
324
6
			printf(", timeout: %10llds\n",
325
6
			    cei_dfr_proposal->next_timeout - diff.tv_sec);
326
		else
327
			printf("\n");
328
329
		break;
330
	case IMSG_CTL_END:
331
6
		printf("\n");
332
6
		return (1);
333
	default:
334
		break;
335
	}
336
337
66
	return (0);
338
72
}