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