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