GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/slaacctl/slaacctl.c Lines: 28 171 16.4 %
Date: 2017-11-07 Branches: 13 86 15.1 %

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
		imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE_INFO, 0, 0, -1,
125
		    &res->if_index, sizeof(res->if_index));
126
		break;
127
	case SEND_SOLICITATION:
128
36
		imsg_compose(ibuf, IMSG_CTL_SEND_SOLICITATION, 0, 0, -1,
129
18
		    &res->if_index, sizeof(res->if_index));
130
		done = 1;
131
18
		break;
132
	default:
133
		usage();
134
	}
135
136
36
	while (ibuf->w.queued)
137

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