slaacctl.c revision 1.9
1/*	$OpenBSD: slaacctl.c,v 1.9 2017/08/18 18:42:20 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);
50int		 show_interface_msg(struct imsg *);
51
52struct imsgbuf	*ibuf;
53
54__dead void
55usage(void)
56{
57	extern char *__progname;
58
59	fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n",
60	    __progname);
61	exit(1);
62}
63
64int
65main(int argc, char *argv[])
66{
67	struct sockaddr_un	 sun;
68	struct parse_result	*res;
69	struct imsg		 imsg;
70	int			 ctl_sock;
71	int			 done = 0;
72	int			 n, verbose = 0;
73	int			 ch;
74	char			*sockname;
75
76	sockname = SLAACD_SOCKET;
77	while ((ch = getopt(argc, argv, "s:")) != -1) {
78		switch (ch) {
79		case 's':
80			sockname = optarg;
81			break;
82		default:
83			usage();
84		}
85	}
86	argc -= optind;
87	argv += optind;
88
89	/* Parse command line. */
90	if ((res = parse(argc, argv)) == NULL)
91		exit(1);
92
93	/* Connect to control socket. */
94	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
95		err(1, "socket");
96
97	memset(&sun, 0, sizeof(sun));
98	sun.sun_family = AF_UNIX;
99
100	strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path));
101	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
102		err(1, "connect: %s", sockname);
103
104	if (pledge("stdio", NULL) == -1)
105		err(1, "pledge");
106
107	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
108		err(1, NULL);
109	imsg_init(ibuf, ctl_sock);
110	done = 0;
111
112	/* Process user request. */
113	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		imsg_compose(ibuf, IMSG_CTL_SEND_SOLICITATION, 0, 0, -1,
129		    &res->if_index, sizeof(res->if_index));
130		done = 1;
131		break;
132	default:
133		usage();
134	}
135
136	while (ibuf->w.queued)
137		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
138			err(1, "write error");
139
140	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	close(ctl_sock);
164	free(ibuf);
165
166	return (0);
167}
168
169int
170show_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 router 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		if (cei_addr_proposal->vltime == ND6_INFINITE_LIFETIME)
272			printf("\t\tvltime: %10s, ", "infinity");
273		else
274			printf("\t\tvltime: %10u, ", cei_addr_proposal->vltime);
275		if (cei_addr_proposal->pltime == ND6_INFINITE_LIFETIME)
276			printf("pltime: %10s\n", "infinity");
277		else
278			printf("pltime: %10u\n", cei_addr_proposal->pltime);
279
280		if (clock_gettime(CLOCK_MONOTONIC, &now))
281			err(1, "clock_gettime");
282
283		timespecsub(&now, &cei_addr_proposal->uptime, &diff);
284
285		t = localtime(&cei_addr_proposal->when.tv_sec);
286		strftime(whenbuf, sizeof(whenbuf), "%F %T", t);
287		printf("\t\tupdated: %s; %llds ago\n", whenbuf, diff.tv_sec);
288		printf("\t\t%s, %s/%u\n", hbuf, inet_ntop(AF_INET6,
289		    &cei_addr_proposal->prefix, ntopbuf, INET6_ADDRSTRLEN),
290		    cei_addr_proposal->prefix_len);
291		break;
292	case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSALS:
293		printf("\tDefault router proposals\n");
294		break;
295	case IMSG_CTL_SHOW_INTERFACE_INFO_DFR_PROPOSAL:
296		cei_dfr_proposal = imsg->data;
297
298		if (getnameinfo((struct sockaddr *)&cei_dfr_proposal->addr,
299		    cei_dfr_proposal->addr.sin6_len, hbuf, sizeof(hbuf),
300		    NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV))
301			err(1, "cannot get router IP");
302
303		printf("\t\tid: %4lld, state: %15s\n",
304		    cei_dfr_proposal->id, cei_dfr_proposal->state);
305		printf("\t\trouter lifetime: %10u\n",
306		    cei_dfr_proposal->router_lifetime);
307		printf("\t\tPreference: %s\n", cei_dfr_proposal->rpref);
308		if (clock_gettime(CLOCK_MONOTONIC, &now))
309			err(1, "clock_gettime");
310
311		timespecsub(&now, &cei_dfr_proposal->uptime, &diff);
312
313		t = localtime(&cei_dfr_proposal->when.tv_sec);
314		strftime(whenbuf, sizeof(whenbuf), "%F %T", t);
315		printf("\t\tupdated: %s; %llds ago\n", whenbuf, diff.tv_sec);
316
317		break;
318	case IMSG_CTL_END:
319		printf("\n");
320		return (1);
321	default:
322		break;
323	}
324
325	return (0);
326}
327