ospfctl.c revision 1.67
1/*	$OpenBSD: ospfctl.c,v 1.67 2020/05/18 17:52:18 denis Exp $ */
2
3/*
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 "ospf.h"
37#include "ospfd.h"
38#include "ospfctl.h"
39#include "ospfe.h"
40#include "parser.h"
41
42__dead void	 usage(void);
43
44int show(struct imsg *, struct parse_result *);
45
46struct imsgbuf	*ibuf;
47const struct output	*output = &show_output;
48
49__dead void
50usage(void)
51{
52	extern char *__progname;
53
54	fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n",
55	    __progname);
56	exit(1);
57}
58
59int
60main(int argc, char *argv[])
61{
62	struct sockaddr_un	 sun;
63	struct parse_result	*res;
64	struct imsg		 imsg;
65	unsigned int		 ifidx = 0;
66	int			 ctl_sock, r;
67	int			 done = 0;
68	int			 n, verbose = 0;
69	int			 ch;
70	char			*sockname;
71
72	r = getrtable();
73	if (asprintf(&sockname, "%s.%d", OSPFD_SOCKET, r) == -1)
74		err(1, "asprintf");
75
76	while ((ch = getopt(argc, argv, "s:")) != -1) {
77		switch (ch) {
78		case 's':
79			sockname = optarg;
80			break;
81		default:
82			usage();
83			/* NOTREACHED */
84		}
85	}
86	argc -= optind;
87	argv += optind;
88
89	/* parse options */
90	if ((res = parse(argc, argv)) == NULL)
91		exit(1);
92
93	/* connect to ospfd control socket */
94	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
95		err(1, "socket");
96
97	bzero(&sun, sizeof(sun));
98	sun.sun_family = AF_UNIX;
99	strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path));
100
101	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
102		err(1, "connect: %s", sockname);
103
104	if (pledge("stdio", NULL) == -1)
105		err(1, "pledge");
106
107	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
108		err(1, NULL);
109	imsg_init(ibuf, ctl_sock);
110	done = 0;
111
112	/* process user request */
113	switch (res->action) {
114	case NONE:
115		usage();
116		/* not reached */
117	case SHOW:
118	case SHOW_SUM:
119		imsg_compose(ibuf, IMSG_CTL_SHOW_SUM, 0, 0, -1, NULL, 0);
120		break;
121	case SHOW_IFACE:
122	case SHOW_IFACE_DTAIL:
123		if (*res->ifname) {
124			ifidx = if_nametoindex(res->ifname);
125			if (ifidx == 0)
126				errx(1, "no such interface %s", res->ifname);
127		}
128		imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1,
129		    &ifidx, sizeof(ifidx));
130		break;
131	case SHOW_NBR:
132	case SHOW_NBR_DTAIL:
133		imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0);
134		break;
135	case SHOW_DB:
136		imsg_compose(ibuf, IMSG_CTL_SHOW_DATABASE, 0, 0, -1, NULL, 0);
137		break;
138	case SHOW_DBBYAREA:
139		imsg_compose(ibuf, IMSG_CTL_SHOW_DATABASE, 0, 0, -1,
140		    &res->addr, sizeof(res->addr));
141		break;
142	case SHOW_DBEXT:
143		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_EXT, 0, 0, -1, NULL, 0);
144		break;
145	case SHOW_DBNET:
146		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_NET, 0, 0, -1, NULL, 0);
147		break;
148	case SHOW_DBRTR:
149		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_RTR, 0, 0, -1, NULL, 0);
150		break;
151	case SHOW_DBSELF:
152		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_SELF, 0, 0, -1, NULL, 0);
153		break;
154	case SHOW_DBSUM:
155		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_SUM, 0, 0, -1, NULL, 0);
156		break;
157	case SHOW_DBASBR:
158		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_ASBR, 0, 0, -1, NULL, 0);
159		break;
160	case SHOW_DBOPAQ:
161		imsg_compose(ibuf, IMSG_CTL_SHOW_DB_OPAQ, 0, 0, -1, NULL, 0);
162		break;
163	case SHOW_RIB:
164	case SHOW_RIB_DTAIL:
165		imsg_compose(ibuf, IMSG_CTL_SHOW_RIB, 0, 0, -1, NULL, 0);
166		break;
167	case SHOW_FIB:
168		if (!res->addr.s_addr)
169			imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1,
170			    &res->flags, sizeof(res->flags));
171		else
172			imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1,
173			    &res->addr, sizeof(res->addr));
174		break;
175	case SHOW_FIB_IFACE:
176		if (*res->ifname)
177			imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1,
178			    res->ifname, sizeof(res->ifname));
179		else
180			imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, NULL, 0);
181		break;
182	case FIB:
183		errx(1, "fib couple|decouple");
184		break;
185	case FIB_COUPLE:
186		imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0);
187		printf("couple request sent.\n");
188		done = 1;
189		break;
190	case FIB_DECOUPLE:
191		imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0);
192		printf("decouple request sent.\n");
193		done = 1;
194		break;
195	case FIB_RELOAD:
196		imsg_compose(ibuf, IMSG_CTL_FIB_RELOAD, 0, 0, -1, NULL, 0);
197		printf("reload request sent.\n");
198		done = 1;
199		break;
200	case LOG_VERBOSE:
201		verbose = 1;
202		/* FALLTHROUGH */
203	case LOG_BRIEF:
204		imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1,
205		    &verbose, sizeof(verbose));
206		printf("logging request sent.\n");
207		done = 1;
208		break;
209	case RELOAD:
210		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
211		printf("reload request sent.\n");
212		done = 1;
213		break;
214	}
215
216	while (ibuf->w.queued)
217		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
218			err(1, "write error");
219
220	/* no output for certain commands such as log verbose */
221	if(!done){
222		output->head(res);
223
224		while (!done) {
225			if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
226				errx(1, "imsg_read error");
227			if (n == 0)
228				errx(1, "pipe closed");
229
230			while (!done) {
231				if ((n = imsg_get(ibuf, &imsg)) == -1)
232					errx(1, "imsg_get error");
233				if (n == 0)
234					break;
235
236				done = show(&imsg, res);
237				imsg_free(&imsg);
238			}
239		}
240
241		output->tail();
242	}
243
244	close(ctl_sock);
245	free(ibuf);
246
247	return (0);
248}
249
250int
251show(struct imsg *imsg, struct parse_result *res)
252{
253	struct ctl_sum		*sum;
254	struct ctl_sum_area	*sumarea;
255	struct ctl_iface	*ctliface;
256	struct ctl_nbr		*nbr;
257	struct ctl_rt		*rt;
258	struct kroute		*k;
259	struct kif		*kif;
260	static struct in_addr	 area_id;
261	struct area		*area;
262	static u_int8_t		 lasttype;
263	static char		 ifname[IF_NAMESIZE];
264	struct iface		*iface;
265	struct lsa		*lsa;
266	struct lsa_hdr		*lsa_hdr;
267
268	switch (imsg->hdr.type) {
269	case IMSG_CTL_SHOW_SUM:
270		sum = imsg->data;
271		output->summary(sum);
272		break;
273	case IMSG_CTL_SHOW_SUM_AREA:
274		sumarea = imsg->data;
275		output->summary_area(sumarea);
276		break;
277	case IMSG_CTL_SHOW_INTERFACE:
278		ctliface = imsg->data;
279		if(res->action == SHOW_IFACE_DTAIL)
280			output->interface(ctliface, 1);
281		else
282			output->interface(ctliface, 0);
283		break;
284	case IMSG_CTL_SHOW_NBR:
285		nbr = imsg->data;
286		if(res->action == SHOW_NBR_DTAIL)
287			output->neighbor(nbr, 1);
288		else
289			output->neighbor(nbr, 0);
290		break;
291	case IMSG_CTL_SHOW_RIB:
292		rt = imsg->data;
293		if(res->action == SHOW_RIB_DTAIL)
294			output->rib(rt, 1);
295		else
296			output->rib(rt, 0);
297		break;
298	case IMSG_CTL_KROUTE:
299		if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute))
300			errx(1, "wrong imsg len");
301		k = imsg->data;
302		output->fib(k);
303		break;
304	case IMSG_CTL_IFINFO:
305		kif = imsg->data;
306		output->fib_interface(kif);
307		break;
308	case IMSG_CTL_SHOW_DB_EXT:
309	case IMSG_CTL_SHOW_DB_NET:
310	case IMSG_CTL_SHOW_DB_RTR:
311	case IMSG_CTL_SHOW_DB_SUM:
312	case IMSG_CTL_SHOW_DB_ASBR:
313	case IMSG_CTL_SHOW_DB_OPAQ:
314		lsa = imsg->data;
315		output->db(lsa, area_id, lasttype, ifname);
316		lasttype = lsa->hdr.type;
317		break;
318	case IMSG_CTL_SHOW_DATABASE:
319	case IMSG_CTL_SHOW_DB_SELF:
320		lsa_hdr = imsg->data;
321		output->db_simple(lsa_hdr, area_id, lasttype, ifname);
322		lasttype = lsa_hdr->type;
323		break;
324	case IMSG_CTL_AREA:
325		area = imsg->data;
326		area_id = area->id;
327		lasttype = 0;
328		break;
329	case IMSG_CTL_IFACE:
330		iface = imsg->data;
331		strlcpy(ifname, iface->name, sizeof(ifname));
332		lasttype = 0;
333		break;
334	case IMSG_CTL_END:
335		return (1);
336	default:
337		warnx("unknown imsg %d received", imsg->hdr.type);
338		break;
339	}
340
341	return (0);
342}
343
344uint64_t
345get_ifms_type(uint8_t if_type)
346{
347	switch (if_type) {
348	case IFT_ETHER:
349		return (IFM_ETHER);
350	case IFT_FDDI:
351		return (IFM_FDDI);
352	case IFT_CARP:
353		return (IFM_CARP);
354	case IFT_PPP:
355		return (IFM_TDM);
356	default:
357		return (0);
358	}
359}
360
361const char *
362print_link(int state)
363{
364	if (state & IFF_UP)
365		return ("UP");
366	else
367		return ("DOWN");
368}
369
370#define TF_BUFS	8
371#define TF_LEN	9
372
373const char *
374fmt_timeframe_core(time_t t)
375{
376	char			*buf;
377	static char		 tfbuf[TF_BUFS][TF_LEN];/* ring buffer */
378	static int		 idx = 0;
379	unsigned int		 sec, min, hrs, day;
380	unsigned long long	 week;
381
382	if (t == 0)
383		return ("00:00:00");
384
385	buf = tfbuf[idx++];
386	if (idx == TF_BUFS)
387		idx = 0;
388
389	week = t;
390
391	sec = week % 60;
392	week /= 60;
393	min = week % 60;
394	week /= 60;
395	hrs = week % 24;
396	week /= 24;
397	day = week % 7;
398	week /= 7;
399
400	if (week > 0)
401		snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs);
402	else if (day > 0)
403		snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
404	else
405		snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
406
407	return (buf);
408}
409
410const char *
411log_id(u_int32_t id)
412{
413	static char	buf[48];
414	struct in_addr	addr;
415
416	addr.s_addr = id;
417
418	if (inet_ntop(AF_INET, &addr, buf, sizeof(buf)) == NULL)
419		return ("?");
420	else
421		return (buf);
422}
423
424const char *
425log_adv_rtr(u_int32_t adv_rtr)
426{
427	static char	buf[48];
428	struct in_addr	addr;
429
430	addr.s_addr = adv_rtr;
431
432	if (inet_ntop(AF_INET, &addr, buf, sizeof(buf)) == NULL)
433		return ("?");
434	else
435		return (buf);
436}
437
438/* prototype defined in ospfd.h and shared with the kroute.c version */
439u_int8_t
440mask2prefixlen(in_addr_t ina)
441{
442	if (ina == 0)
443		return (0);
444	else
445		return (33 - ffs(ntohl(ina)));
446}
447
448char *
449print_ls_type(u_int8_t type)
450{
451	switch (type) {
452	case LSA_TYPE_ROUTER:
453		return ("Router");
454	case LSA_TYPE_NETWORK:
455		return ("Network");
456	case LSA_TYPE_SUM_NETWORK:
457		return ("Summary (Network)");
458	case LSA_TYPE_SUM_ROUTER:
459		return ("Summary (Router)");
460	case LSA_TYPE_EXTERNAL:
461		return ("AS External");
462	case LSA_TYPE_LINK_OPAQ:
463		return ("Type-9 Opaque");
464	case LSA_TYPE_AREA_OPAQ:
465		return ("Type-10 Opaque");
466	case LSA_TYPE_AS_OPAQ:
467		return ("Type-11 Opaque");
468	default:
469		return ("Unknown");
470	}
471}
472
473char *
474print_rtr_link_type(u_int8_t type)
475{
476	switch (type) {
477	case LINK_TYPE_POINTTOPOINT:
478		return ("Point-to-Point");
479	case LINK_TYPE_TRANSIT_NET:
480		return ("Transit Network");
481	case LINK_TYPE_STUB_NET:
482		return ("Stub Network");
483	case LINK_TYPE_VIRTUAL:
484		return ("Virtual Link");
485	default:
486		return ("Unknown");
487	}
488}
489
490const char *
491print_ospf_flags(u_int8_t opts)
492{
493	static char	optbuf[32];
494
495	snprintf(optbuf, sizeof(optbuf), "*|*|*|*|*|%s|%s|%s",
496	    opts & OSPF_RTR_V ? "V" : "-",
497	    opts & OSPF_RTR_E ? "E" : "-",
498	    opts & OSPF_RTR_B ? "B" : "-");
499	return (optbuf);
500}
501
502const char *
503print_ospf_options(u_int8_t opts)
504{
505	static char	optbuf[32];
506
507	snprintf(optbuf, sizeof(optbuf), "%s|%s|%s|%s|%s|%s|%s|%s",
508	    opts & OSPF_OPTION_DN ? "DN" : "-",
509	    opts & OSPF_OPTION_O ? "O" : "-",
510	    opts & OSPF_OPTION_DC ? "DC" : "-",
511	    opts & OSPF_OPTION_EA ? "EA" : "-",
512	    opts & OSPF_OPTION_NP ? "N/P" : "-",
513	    opts & OSPF_OPTION_MC ? "MC" : "-",
514	    opts & OSPF_OPTION_E ? "E" : "-",
515	    opts & OSPF_OPTION_MT ? "MT" : "-");
516	return (optbuf);
517}
518
519const char *
520print_ospf_rtr_flags(u_int8_t opts)
521{
522	static char	optbuf[32];
523
524	snprintf(optbuf, sizeof(optbuf), "%s%s%s",
525	    opts & OSPF_RTR_E ? "AS" : "",
526	    opts & OSPF_RTR_E && opts & OSPF_RTR_B ? "+" : "",
527	    opts & OSPF_RTR_B ? "ABR" : "");
528	return (optbuf);
529}
530
531const struct if_status_description
532		if_status_descriptions[] = LINK_STATE_DESCRIPTIONS;
533const struct ifmedia_description
534		ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS;
535
536const char *
537get_media_descr(uint64_t media_type)
538{
539	const struct ifmedia_description	*p;
540
541	for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++)
542		if (media_type == p->ifmt_word)
543			return (p->ifmt_string);
544
545	return ("unknown");
546}
547
548const char *
549get_linkstate(uint8_t if_type, int link_state)
550{
551	const struct if_status_description *p;
552	static char buf[8];
553
554	for (p = if_status_descriptions; p->ifs_string != NULL; p++) {
555		if (LINK_STATE_DESC_MATCH(p, if_type, link_state))
556			return (p->ifs_string);
557	}
558	snprintf(buf, sizeof(buf), "[#%d]", link_state);
559	return (buf);
560}
561
562const char *
563print_baudrate(u_int64_t baudrate)
564{
565	static char	buf[32];
566	if (baudrate > IF_Gbps(1))
567		snprintf(buf, sizeof(buf), "%llu GBit/s", baudrate / IF_Gbps(1));
568	else if (baudrate > IF_Mbps(1))
569		snprintf(buf, sizeof(buf), "%llu MBit/s", baudrate / IF_Mbps(1));
570	else if (baudrate > IF_Kbps(1))
571		snprintf(buf, sizeof(buf), "%llu KBit/s", baudrate / IF_Kbps(1));
572	else
573		snprintf(buf, sizeof(buf), "%llu Bit/s", baudrate);
574	return (buf);
575}
576
577