xref: /openbsd-src/usr.sbin/ripctl/ripctl.c (revision 43003dfe3ad45d1698bed8a37f2b0f5b14f20d4f)
1 /*	$OpenBSD: ripctl.c,v 1.9 2009/09/14 11:49:25 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;
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 RELOAD:
154 		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
155 		printf("reload request sent.\n");
156 		done = 1;
157 		break;
158 	}
159 
160 	while (ibuf->w.queued)
161 		if (msgbuf_write(&ibuf->w) < 0)
162 			err(1, "write error");
163 
164 	while (!done) {
165 		if ((n = imsg_read(ibuf)) == -1)
166 			errx(1, "imsg_read error");
167 		if (n == 0)
168 			errx(1, "pipe closed");
169 
170 		while (!done) {
171 			if ((n = imsg_get(ibuf, &imsg)) == -1)
172 				errx(1, "imsg_get error");
173 			if (n == 0)
174 				break;
175 			switch (res->action) {
176 			case SHOW:
177 			case SHOW_IFACE:
178 				done = show_interface_msg(&imsg);
179 				break;
180 			case SHOW_NBR:
181 				done = show_nbr_msg(&imsg);
182 				break;
183 			case SHOW_RIB:
184 				done = show_rib_msg(&imsg);
185 				break;
186 			case SHOW_FIB:
187 				done = show_fib_msg(&imsg);
188 				break;
189 			case SHOW_FIB_IFACE:
190 				done = show_fib_interface_msg(&imsg);
191 				break;
192 			case NONE:
193 			case FIB:
194 			case FIB_COUPLE:
195 			case FIB_DECOUPLE:
196 			case RELOAD:
197 				break;
198 			}
199 			imsg_free(&imsg);
200 		}
201 	}
202 	close(ctl_sock);
203 	free(ibuf);
204 
205 	return (0);
206 }
207 
208 int
209 get_ifms_type(int mediatype)
210 {
211 	switch (mediatype) {
212 	case IFT_ETHER:
213 		return (IFM_ETHER);
214 		break;
215 	case IFT_FDDI:
216 		return (IFM_FDDI);
217 		break;
218 	case IFT_CARP:
219 		return (IFM_CARP);
220 		break;
221 	default:
222 		return (0);
223 		break;
224 	}
225 }
226 
227 #define	TF_BUFS	8
228 #define	TF_LEN	9
229 
230 const char *
231 fmt_timeframe_core(time_t t)
232 {
233 	char		*buf;
234 	static char	 tfbuf[TF_BUFS][TF_LEN];	/* ring buffer */
235 	static int	 idx = 0;
236 	unsigned int	 sec, min, hrs, day, week;
237 
238 	if (t == 0)
239 		return ("Stopped");
240 
241 	buf = tfbuf[idx++];
242 	if (idx == TF_BUFS)
243 		idx = 0;
244 
245 	week = t;
246 
247 	sec = week % 60;
248 	week /= 60;
249 	min = week % 60;
250 	week /= 60;
251 	hrs = week % 24;
252 	week /= 24;
253 	day = week % 7;
254 	week /= 7;
255 
256 	if (week > 0)
257 		snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs);
258 	else if (day > 0)
259 		snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
260 	else
261 		snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
262 
263 	return (buf);
264 }
265 
266 /* prototype defined in ripd.h and shared with the kroute.c version */
267 u_int8_t
268 mask2prefixlen(in_addr_t ina)
269 {
270 	if (ina == 0)
271 		return (0);
272 	else
273 		return (33 - ffs(ntohl(ina)));
274 }
275 
276 int
277 show_interface_msg(struct imsg *imsg)
278 {
279 	struct ctl_iface	*iface;
280 	char			*netid;
281 
282 	switch (imsg->hdr.type) {
283 	case IMSG_CTL_SHOW_IFACE:
284 		iface = imsg->data;
285 
286 		if (asprintf(&netid, "%s/%d", inet_ntoa(iface->addr),
287 		    mask2prefixlen(iface->mask.s_addr)) == -1)
288 			err(1, NULL);
289 		printf("%-11s %-18s %-10s %-10s %-8s\n",
290 		    iface->name, netid, if_state_name(iface->state),
291 		    get_linkstate(iface->mediatype, iface->linkstate),
292 		    iface->uptime == 0 ? "00:00:00" :
293 		    fmt_timeframe_core(iface->uptime));
294 		free(netid);
295 		break;
296 	case IMSG_CTL_END:
297 		printf("\n");
298 		return (1);
299 	default:
300 		break;
301 	}
302 
303 	return (0);
304 }
305 
306 int
307 show_rib_msg(struct imsg *imsg)
308 {
309 	struct ctl_rt	*rt;
310 	char		*dstnet;
311 
312 	switch (imsg->hdr.type) {
313 	case IMSG_CTL_SHOW_RIB:
314 		rt = imsg->data;
315 		if (asprintf(&dstnet, "%s/%d", inet_ntoa(rt->prefix),
316 		    mask2prefixlen(rt->netmask.s_addr)) == -1)
317 			err(1, NULL);
318 
319 		printf("%-20s %-17s %-7d\n", dstnet,
320 		    inet_ntoa(rt->nexthop),
321 		    rt->metric);
322 		free(dstnet);
323 
324 		break;
325 	case IMSG_CTL_END:
326 		printf("\n");
327 		return (1);
328 	default:
329 		break;
330 	}
331 
332 	return (0);
333 }
334 
335 int
336 show_nbr_msg(struct imsg *imsg)
337 {
338 	struct ctl_nbr	*nbr;
339 	char		*state;
340 
341 	switch (imsg->hdr.type) {
342 	case IMSG_CTL_SHOW_NBR:
343 		nbr = imsg->data;
344 		if (asprintf(&state, "%s/%s", nbr_state_name(nbr->nbr_state),
345 		    if_state_name(nbr->iface_state)) == -1)
346 			err(1, NULL);
347 		printf("%-15s %-16s", inet_ntoa(nbr->id),
348 		    state);
349 		printf("%-15s %-10s", inet_ntoa(nbr->addr), nbr->name);
350 		printf("%-15s\n", nbr->uptime == 0 ? "-" :
351 		    fmt_timeframe_core(nbr->uptime));
352 		free(state);
353 		break;
354 	case IMSG_CTL_END:
355 		printf("\n");
356 		return (1);
357 	default:
358 		break;
359 	}
360 
361 	return (0);
362 }
363 
364 void
365 show_fib_head(void)
366 {
367 	printf("flags: * = valid, R = RIP, C = Connected, S = Static\n");
368 	printf("%-6s %-20s %-17s\n", "Flags", "Destination", "Nexthop");
369 }
370 
371 int
372 show_fib_msg(struct imsg *imsg)
373 {
374 	struct kroute		*k;
375 	char			*p;
376 
377 	switch (imsg->hdr.type) {
378 	case IMSG_CTL_KROUTE:
379 		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute))
380 			errx(1, "wrong imsg len");
381 		k = imsg->data;
382 
383 		if (k->flags & F_DOWN)
384 			printf(" ");
385 		else
386 			printf("*");
387 
388 		if (k->flags & F_RIPD_INSERTED)
389 			printf("R");
390 		else if (k->flags & F_CONNECTED)
391 			printf("C");
392 		else if (k->flags & F_STATIC)
393 			printf("S");
394 		else
395 			printf(" ");
396 
397 		printf("     ");
398 		if (asprintf(&p, "%s/%u", inet_ntoa(k->prefix),
399 		    mask2prefixlen(k->netmask.s_addr)) == -1)
400 			err(1, NULL);
401 		printf("%-20s ", p);
402 		free(p);
403 
404 		if (k->nexthop.s_addr)
405 			printf("%s", inet_ntoa(k->nexthop));
406 		else if (k->flags & F_CONNECTED)
407 			printf("link#%u", k->ifindex);
408 		printf("\n");
409 
410 		break;
411 	case IMSG_CTL_END:
412 		printf("\n");
413 		return (1);
414 	default:
415 		break;
416 	}
417 
418 	return (0);
419 }
420 
421 void
422 show_interface_head(void)
423 {
424 	printf("%-15s%-15s%s\n", "Interface", "Flags",
425 	    "Link state");
426 }
427 
428 int
429 show_fib_interface_msg(struct imsg *imsg)
430 {
431 	struct kif	*k;
432 	int		 ifms_type;
433 
434 	switch (imsg->hdr.type) {
435 	case IMSG_CTL_IFINFO:
436 		k = imsg->data;
437 		printf("%-15s", k->ifname);
438 		printf("%-15s", k->flags & IFF_UP ? "UP" : "");
439 		ifms_type = get_ifms_type(k->media_type);
440 		if (ifms_type)
441 			printf("%s, ", get_media_descr(ifms_type));
442 
443 		printf("%s", get_linkstate(k->media_type, k->link_state));
444 
445 		if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) {
446 			printf(", ");
447 			print_baudrate(k->baudrate);
448 		}
449 		printf("\n");
450 		break;
451 	case IMSG_CTL_END:
452 		printf("\n");
453 		return (1);
454 	default:
455 		break;
456 	}
457 
458 	return (0);
459 }
460 
461 const struct if_status_description
462 		if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
463 const struct ifmedia_description
464 		ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
465 
466 const char *
467 get_media_descr(int media_type)
468 {
469 	const struct ifmedia_description	*p;
470 
471 	for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++)
472 		if (media_type == p->ifmt_word)
473 			return (p->ifmt_string);
474 
475 	return ("unknown");
476 }
477 
478 const char *
479 get_linkstate(int media_type, int link_state)
480 {
481 	const struct if_status_description *p;
482 	static char buf[8];
483 
484 	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
485 		if (LINK_STATE_DESC_MATCH(p, media_type, link_state))
486 			return (p->ifs_string);
487 	}
488 	snprintf(buf, sizeof(buf), "[#%d]", link_state);
489 	return (buf);
490 }
491 
492 void
493 print_baudrate(u_int64_t baudrate)
494 {
495 	if (baudrate > IF_Gbps(1))
496 		printf("%llu GBit/s", baudrate / IF_Gbps(1));
497 	else if (baudrate > IF_Mbps(1))
498 		printf("%llu MBit/s", baudrate / IF_Mbps(1));
499 	else if (baudrate > IF_Kbps(1))
500 		printf("%llu KBit/s", baudrate / IF_Kbps(1));
501 	else
502 		printf("%llu Bit/s", baudrate);
503 }
504