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