xref: /openbsd/usr.sbin/ripctl/ripctl.c (revision d415bd75)
1 /*	$OpenBSD: ripctl.c,v 1.17 2016/08/02 16:05:32 jca Exp $
2  *
3  * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
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/socket.h>
23 #include <sys/un.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <net/if_media.h>
27 #include <net/if_types.h>
28 
29 #include <err.h>
30 #include <errno.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <unistd.h>
35 
36 #include "rip.h"
37 #include "ripd.h"
38 #include "ripe.h"
39 #include "parser.h"
40 
41 __dead void	 usage(void);
42 const char	*fmt_timeframe_core(time_t);
43 const char	*get_linkstate(uint8_t, int);
44 int		 show_interface_msg(struct imsg *);
45 uint64_t	 get_ifms_type(uint8_t);
46 int		 show_rib_msg(struct imsg *);
47 int		 show_nbr_msg(struct imsg *);
48 void		 show_fib_head(void);
49 int		 show_fib_msg(struct imsg *);
50 void		 show_interface_head(void);
51 int		 show_fib_interface_msg(struct imsg *);
52 const char	*get_media_descr(uint64_t);
53 void		 print_baudrate(uint64_t);
54 
55 struct imsgbuf	*ibuf;
56 
57 __dead void
58 usage(void)
59 {
60 	extern char *__progname;
61 
62 	fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n",
63 	    __progname);
64 	exit(1);
65 }
66 
67 int
68 main(int argc, char *argv[])
69 {
70 	struct sockaddr_un	 sun;
71 	struct parse_result	*res;
72 	struct imsg		 imsg;
73 	unsigned int		 ifidx = 0;
74 	int			 ctl_sock;
75 	int			 done = 0, verbose = 0;
76 	int			 n;
77 	int			 ch;
78 	char			*sockname = RIPD_SOCKET;
79 
80 	while ((ch = getopt(argc, argv, "s:")) != -1) {
81 		switch (ch) {
82 		case 's':
83 			sockname = optarg;
84 			break;
85 		default:
86 			usage();
87 			/* NOTREACHED */
88 		}
89 	}
90 
91 	argc -= optind;
92 	argv += optind;
93 
94 	/* parse options */
95 	if ((res = parse(argc, argv)) == NULL)
96 		exit(1);
97 
98 	/* connect to ripd control socket */
99 	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
100 		err(1, "socket");
101 
102 	bzero(&sun, sizeof(sun));
103 	sun.sun_family = AF_UNIX;
104 	strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path));
105 	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
106 		err(1, "connect: %s", sockname);
107 
108 	if (pledge("stdio", NULL) == -1)
109 		err(1, "pledge");
110 
111 	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
112 		err(1, NULL);
113 	imsg_init(ibuf, ctl_sock);
114 	done = 0;
115 
116 	/* process user request */
117 	switch (res->action) {
118 	case NONE:
119 		usage();
120 		/* not reached */
121 	case SHOW:
122 	case SHOW_IFACE:
123 		printf("%-11s %-18s %-10s %-10s %-8s\n",
124 		    "Interface", "Address", "State", "Linkstate",
125 		    "Uptime");
126 		if (*res->ifname) {
127 			ifidx = if_nametoindex(res->ifname);
128 			if (ifidx == 0)
129 				errx(1, "no such interface %s", res->ifname);
130 		}
131 		imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
132 		    &ifidx, sizeof(ifidx));
133 		break;
134 	case SHOW_NBR:
135 		printf("%-15s %-15s %-15s %-9s %-10s\n", "ID",
136 		    "State", "Address", "Iface", "Uptime");
137 		imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0);
138 		break;
139 	case SHOW_RIB:
140 		printf("%-20s %-17s %-7s\n", "Destination",
141 		    "Nexthop", "Cost");
142 		imsg_compose(ibuf, IMSG_CTL_SHOW_RIB, 0, 0, -1, NULL, 0);
143 		break;
144 	case SHOW_FIB:
145 		if (!res->addr.s_addr)
146 			imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1,
147 			    &res->flags, sizeof(res->flags));
148 		else
149 			imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1,
150 			    &res->addr, sizeof(res->addr));
151 		show_fib_head();
152 		break;
153 	case SHOW_FIB_IFACE:
154 		if (*res->ifname)
155 			imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1,
156 			    res->ifname, sizeof(res->ifname));
157 		else
158 			imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, NULL, 0);
159 		show_interface_head();
160 		break;
161 	case FIB:
162 		errx(1, "fib couple|decouple");
163 		break;
164 	case FIB_COUPLE:
165 		imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0);
166 		printf("couple request sent.\n");
167 		done = 1;
168 		break;
169 	case FIB_DECOUPLE:
170 		imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0);
171 		printf("decouple request sent.\n");
172 		done = 1;
173 		break;
174 	case LOG_VERBOSE:
175 		verbose = 1;
176 		/* FALLTHROUGH */
177 	case LOG_BRIEF:
178 		imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
179 		    &verbose, sizeof(verbose));
180 		printf("logging request sent.\n");
181 		done = 1;
182 		break;
183 	case RELOAD:
184 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
185 		printf("reload request sent.\n");
186 		done = 1;
187 		break;
188 	}
189 
190 	while (ibuf->w.queued)
191 		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
192 			err(1, "write error");
193 
194 	while (!done) {
195 		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
196 			errx(1, "imsg_read error");
197 		if (n == 0)
198 			errx(1, "pipe closed");
199 
200 		while (!done) {
201 			if ((n = imsg_get(ibuf, &imsg)) == -1)
202 				errx(1, "imsg_get error");
203 			if (n == 0)
204 				break;
205 			switch (res->action) {
206 			case SHOW:
207 			case SHOW_IFACE:
208 				done = show_interface_msg(&imsg);
209 				break;
210 			case SHOW_NBR:
211 				done = show_nbr_msg(&imsg);
212 				break;
213 			case SHOW_RIB:
214 				done = show_rib_msg(&imsg);
215 				break;
216 			case SHOW_FIB:
217 				done = show_fib_msg(&imsg);
218 				break;
219 			case SHOW_FIB_IFACE:
220 				done = show_fib_interface_msg(&imsg);
221 				break;
222 			case NONE:
223 			case FIB:
224 			case FIB_COUPLE:
225 			case FIB_DECOUPLE:
226 			case LOG_VERBOSE:
227 			case LOG_BRIEF:
228 			case RELOAD:
229 				break;
230 			}
231 			imsg_free(&imsg);
232 		}
233 	}
234 	close(ctl_sock);
235 	free(ibuf);
236 
237 	return (0);
238 }
239 
240 uint64_t
241 get_ifms_type(uint8_t if_type)
242 {
243 	switch (if_type) {
244 	case IFT_ETHER:
245 		return (IFM_ETHER);
246 		break;
247 	case IFT_FDDI:
248 		return (IFM_FDDI);
249 		break;
250 	case IFT_CARP:
251 		return (IFM_CARP);
252 		break;
253 	default:
254 		return (0);
255 		break;
256 	}
257 }
258 
259 #define	TF_BUFS	8
260 #define	TF_LEN	9
261 
262 const char *
263 fmt_timeframe_core(time_t t)
264 {
265 	char		*buf;
266 	static char	 tfbuf[TF_BUFS][TF_LEN];	/* ring buffer */
267 	static int	 idx = 0;
268 	unsigned int	 sec, min, hrs, day;
269 	unsigned long long	week;
270 
271 	if (t == 0)
272 		return ("Stopped");
273 
274 	buf = tfbuf[idx++];
275 	if (idx == TF_BUFS)
276 		idx = 0;
277 
278 	week = t;
279 
280 	sec = week % 60;
281 	week /= 60;
282 	min = week % 60;
283 	week /= 60;
284 	hrs = week % 24;
285 	week /= 24;
286 	day = week % 7;
287 	week /= 7;
288 
289 	if (week > 0)
290 		snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs);
291 	else if (day > 0)
292 		snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
293 	else
294 		snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
295 
296 	return (buf);
297 }
298 
299 /* prototype defined in ripd.h and shared with the kroute.c version */
300 u_int8_t
301 mask2prefixlen(in_addr_t ina)
302 {
303 	if (ina == 0)
304 		return (0);
305 	else
306 		return (33 - ffs(ntohl(ina)));
307 }
308 
309 int
310 show_interface_msg(struct imsg *imsg)
311 {
312 	struct ctl_iface	*iface;
313 	char			*netid;
314 
315 	switch (imsg->hdr.type) {
316 	case IMSG_CTL_SHOW_IFACE:
317 		iface = imsg->data;
318 
319 		if (asprintf(&netid, "%s/%d", inet_ntoa(iface->addr),
320 		    mask2prefixlen(iface->mask.s_addr)) == -1)
321 			err(1, NULL);
322 		printf("%-11s %-18s %-10s %-10s %-8s\n",
323 		    iface->name, netid, if_state_name(iface->state),
324 		    get_linkstate(iface->if_type, iface->linkstate),
325 		    iface->uptime == 0 ? "00:00:00" :
326 		    fmt_timeframe_core(iface->uptime));
327 		free(netid);
328 		break;
329 	case IMSG_CTL_END:
330 		printf("\n");
331 		return (1);
332 	default:
333 		break;
334 	}
335 
336 	return (0);
337 }
338 
339 int
340 show_rib_msg(struct imsg *imsg)
341 {
342 	struct ctl_rt	*rt;
343 	char		*dstnet;
344 
345 	switch (imsg->hdr.type) {
346 	case IMSG_CTL_SHOW_RIB:
347 		rt = imsg->data;
348 		if (asprintf(&dstnet, "%s/%d", inet_ntoa(rt->prefix),
349 		    mask2prefixlen(rt->netmask.s_addr)) == -1)
350 			err(1, NULL);
351 
352 		printf("%-20s %-17s %-7d\n", dstnet,
353 		    inet_ntoa(rt->nexthop),
354 		    rt->metric);
355 		free(dstnet);
356 
357 		break;
358 	case IMSG_CTL_END:
359 		printf("\n");
360 		return (1);
361 	default:
362 		break;
363 	}
364 
365 	return (0);
366 }
367 
368 int
369 show_nbr_msg(struct imsg *imsg)
370 {
371 	struct ctl_nbr	*nbr;
372 	char		*state;
373 
374 	switch (imsg->hdr.type) {
375 	case IMSG_CTL_SHOW_NBR:
376 		nbr = imsg->data;
377 		if (asprintf(&state, "%s/%s", nbr_state_name(nbr->nbr_state),
378 		    if_state_name(nbr->iface_state)) == -1)
379 			err(1, NULL);
380 		printf("%-15s %-16s", inet_ntoa(nbr->id),
381 		    state);
382 		printf("%-15s %-10s", inet_ntoa(nbr->addr), nbr->name);
383 		printf("%-15s\n", nbr->uptime == 0 ? "-" :
384 		    fmt_timeframe_core(nbr->uptime));
385 		free(state);
386 		break;
387 	case IMSG_CTL_END:
388 		printf("\n");
389 		return (1);
390 	default:
391 		break;
392 	}
393 
394 	return (0);
395 }
396 
397 void
398 show_fib_head(void)
399 {
400 	printf("flags: * = valid, R = RIP, C = Connected, S = Static\n");
401 	printf("%-6s %-20s %-17s\n", "Flags", "Destination", "Nexthop");
402 }
403 
404 int
405 show_fib_msg(struct imsg *imsg)
406 {
407 	struct kroute		*k;
408 	char			*p;
409 
410 	switch (imsg->hdr.type) {
411 	case IMSG_CTL_KROUTE:
412 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute))
413 			errx(1, "wrong imsg len");
414 		k = imsg->data;
415 
416 		if (k->flags & F_DOWN)
417 			printf(" ");
418 		else
419 			printf("*");
420 
421 		if (k->flags & F_RIPD_INSERTED)
422 			printf("R");
423 		else if (k->flags & F_CONNECTED)
424 			printf("C");
425 		else if (k->flags & F_STATIC)
426 			printf("S");
427 		else
428 			printf(" ");
429 
430 		printf("     ");
431 		if (asprintf(&p, "%s/%u", inet_ntoa(k->prefix),
432 		    mask2prefixlen(k->netmask.s_addr)) == -1)
433 			err(1, NULL);
434 		printf("%-20s ", p);
435 		free(p);
436 
437 		if (k->nexthop.s_addr)
438 			printf("%s", inet_ntoa(k->nexthop));
439 		else if (k->flags & F_CONNECTED)
440 			printf("link#%u", k->ifindex);
441 		printf("\n");
442 
443 		break;
444 	case IMSG_CTL_END:
445 		printf("\n");
446 		return (1);
447 	default:
448 		break;
449 	}
450 
451 	return (0);
452 }
453 
454 void
455 show_interface_head(void)
456 {
457 	printf("%-15s%-15s%s\n", "Interface", "Flags",
458 	    "Link state");
459 }
460 
461 int
462 show_fib_interface_msg(struct imsg *imsg)
463 {
464 	struct kif	*k;
465 	uint64_t	 ifms_type;
466 
467 	switch (imsg->hdr.type) {
468 	case IMSG_CTL_IFINFO:
469 		k = imsg->data;
470 		printf("%-15s", k->ifname);
471 		printf("%-15s", k->flags & IFF_UP ? "UP" : "");
472 		ifms_type = get_ifms_type(k->if_type);
473 		if (ifms_type)
474 			printf("%s, ", get_media_descr(ifms_type));
475 
476 		printf("%s", get_linkstate(k->if_type, k->link_state));
477 
478 		if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) {
479 			printf(", ");
480 			print_baudrate(k->baudrate);
481 		}
482 		printf("\n");
483 		break;
484 	case IMSG_CTL_END:
485 		printf("\n");
486 		return (1);
487 	default:
488 		break;
489 	}
490 
491 	return (0);
492 }
493 
494 const struct if_status_description
495 		if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
496 const struct ifmedia_description
497 		ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
498 
499 const char *
500 get_media_descr(uint64_t media_type)
501 {
502 	const struct ifmedia_description	*p;
503 
504 	for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++)
505 		if (media_type == p->ifmt_word)
506 			return (p->ifmt_string);
507 
508 	return ("unknown");
509 }
510 
511 const char *
512 get_linkstate(uint8_t if_type, int link_state)
513 {
514 	const struct if_status_description *p;
515 	static char buf[8];
516 
517 	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
518 		if (LINK_STATE_DESC_MATCH(p, if_type, link_state))
519 			return (p->ifs_string);
520 	}
521 	snprintf(buf, sizeof(buf), "[#%d]", link_state);
522 	return (buf);
523 }
524 
525 void
526 print_baudrate(uint64_t baudrate)
527 {
528 	if (baudrate > IF_Gbps(1))
529 		printf("%llu GBit/s", baudrate / IF_Gbps(1));
530 	else if (baudrate > IF_Mbps(1))
531 		printf("%llu MBit/s", baudrate / IF_Mbps(1));
532 	else if (baudrate > IF_Kbps(1))
533 		printf("%llu KBit/s", baudrate / IF_Kbps(1));
534 	else
535 		printf("%llu Bit/s", baudrate);
536 }
537