1/*	$OpenBSD: print-ospf6.c,v 1.11 2020/01/24 22:46:37 procter Exp $	*/
2
3
4/*
5 * Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that: (1) source code distributions
10 * retain the above copyright notice and this paragraph in its entirety, (2)
11 * distributions including binary code include the above copyright notice and
12 * this paragraph in its entirety in the documentation or other materials
13 * provided with the distribution, and (3) all advertising materials mentioning
14 * features or use of this software display the following acknowledgement:
15 * ``This product includes software developed by the University of California,
16 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
17 * the University nor the names of its contributors may be used to endorse
18 * or promote products derived from this software without specific prior
19 * written permission.
20 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
21 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
22 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 *
24 * OSPF support contributed by Jeffrey Honig (jch@mitchell.cit.cornell.edu)
25 */
26
27#include <sys/time.h>
28#include <sys/socket.h>
29
30#include <netinet/in.h>
31#include <netinet/ip.h>
32#include <netinet/ip_var.h>
33
34#include <ctype.h>
35#include <stdio.h>
36#include <string.h>
37
38#include "interface.h"
39#include "addrtoname.h"
40
41#include "ospf6.h"
42
43struct bits {
44	u_int32_t bit;
45	const char *str;
46};
47
48static const struct bits ospf6_option_bits[] = {
49	{ OSPF6_OPTION_V6,	"V6" },
50	{ OSPF6_OPTION_E,	"E" },
51	{ OSPF6_OPTION_MC,	"MC" },
52	{ OSPF6_OPTION_N,	"N" },
53	{ OSPF6_OPTION_R,	"R" },
54	{ OSPF6_OPTION_DC,	"DC" },
55	{ 0,			NULL }
56};
57
58static const struct bits ospf6_rla_flag_bits[] = {
59	{ RLA_FLAG_B,		"B" },
60	{ RLA_FLAG_E,		"E" },
61	{ RLA_FLAG_V,		"V" },
62	{ RLA_FLAG_W,		"W" },
63	{ 0,			NULL }
64};
65
66static struct tok type2str[] = {
67	{ OSPF_TYPE_UMD,	"umd" },
68	{ OSPF_TYPE_HELLO,	"hello" },
69	{ OSPF_TYPE_DB,		"dd" },
70	{ OSPF_TYPE_LSR,	"ls_req" },
71	{ OSPF_TYPE_LSU,	"ls_upd" },
72	{ OSPF_TYPE_LSA,	"ls_ack" },
73	{ 0,			NULL }
74};
75
76static char tstr[] = " [|ospf]";
77
78/* Forwards */
79static inline void ospf6_print_seqage(u_int32_t, time_t);
80static inline void ospf6_print_bits(const struct bits *, u_char);
81static void ospf6_print_ls_type(u_int, const rtrid_t *,
82    const rtrid_t *, const char *);
83static int ospf6_print_lshdr(const struct lsa_hdr *);
84static int ospf6_print_lsa(const struct lsa *);
85static int ospf6_decode_v3(const struct ospf6hdr *, const u_char *);
86
87static inline void
88ospf6_print_seqage(u_int32_t seq, time_t us)
89{
90	time_t sec = us % 60;
91	time_t mins = (us / 60) % 60;
92	time_t hour = us / 3600;
93
94	printf(" S %X age ", seq);
95	if (hour)
96		printf("%u:%02u:%02u",
97		    (u_int32_t) hour, (u_int32_t) mins, (u_int32_t) sec);
98	else if (mins)
99		printf("%u:%02u", (u_int32_t) mins, (u_int32_t) sec);
100	else
101		printf("%u", (u_int32_t) sec);
102}
103
104
105static inline void
106ospf6_print_bits(const struct bits *bp, u_char options)
107{
108	char sep = ' ';
109
110	do {
111		if (options & bp->bit) {
112			printf("%c%s", sep, bp->str);
113			sep = '/';
114		}
115	} while ((++bp)->bit);
116}
117
118static void
119ospf6_print_ls_type(u_int ls_type, const rtrid_t *ls_stateid,
120    const rtrid_t *ls_router, const char *fmt)
121{
122	char *scope;
123
124	switch (ls_type & LS_SCOPE_MASK) {
125	case LS_SCOPE_LINKLOCAL:
126		scope = "linklocal-";
127		break;
128	case LS_SCOPE_AREA:
129		scope = "area-";
130		break;
131	case LS_SCOPE_AS:
132		scope = "AS-";
133		break;
134	default:
135		scope = "";
136		break;
137	}
138
139	switch (ls_type & LS_TYPE_MASK) {
140	case LS_TYPE_ROUTER:
141		printf(" %srtr %s", scope, ipaddr_string(ls_router));
142		break;
143
144	case LS_TYPE_NETWORK:
145		printf(" %snet dr %s if %s", scope,
146		    ipaddr_string(ls_router),
147		    ipaddr_string(ls_stateid));
148		break;
149
150	case LS_TYPE_INTER_AP:
151		printf(" %sinter-area-prefix %s abr %s", scope,
152		    ipaddr_string(ls_stateid),
153		    ipaddr_string(ls_router));
154		break;
155
156	case LS_TYPE_INTER_AR:
157		printf(" %sinter-area-router %s rtr %s", scope,
158		    ipaddr_string(ls_router),
159		    ipaddr_string(ls_stateid));
160		break;
161
162	case LS_TYPE_ASE:
163		printf(" %sase %s asbr %s", scope,
164		    ipaddr_string(ls_stateid),
165		    ipaddr_string(ls_router));
166		break;
167
168	case LS_TYPE_GROUP:
169		printf(" %sgroup %s rtr %s", scope,
170		    ipaddr_string(ls_stateid),
171		    ipaddr_string(ls_router));
172		break;
173
174	case LS_TYPE_TYPE7:
175		printf(" %stype7 %s rtr %s", scope,
176		    ipaddr_string(ls_stateid),
177		    ipaddr_string(ls_router));
178		break;
179
180	case LS_TYPE_LINK:
181		printf(" %slink %s rtr %s", scope,
182		    ipaddr_string(ls_stateid),
183		    ipaddr_string(ls_router));
184		break;
185
186	case LS_TYPE_INTRA_AP:
187		printf(" %sintra-area-prefix %s rtr %s", scope,
188		    ipaddr_string(ls_stateid),
189		    ipaddr_string(ls_router));
190		break;
191
192	default:
193		printf(" %s", scope);
194		printf(fmt, ls_type);
195		break;
196	}
197
198}
199
200static int
201ospf6_print_lshdr(const struct lsa_hdr *lshp)
202{
203
204	TCHECK(lshp->ls_type);
205	printf(" {");						/* } (ctags) */
206
207	TCHECK(lshp->ls_seq);
208	ospf6_print_seqage(ntohl(lshp->ls_seq), ntohs(lshp->ls_age));
209	ospf6_print_ls_type(ntohs(lshp->ls_type), &lshp->ls_stateid,
210		&lshp->ls_router, "ls_type %d");
211
212	return (0);
213trunc:
214	return (1);
215}
216
217static int
218ospf6_print_lsaprefix(const struct lsa_prefix *lsapp)
219{
220	int k;
221	struct in6_addr prefix;
222
223	TCHECK(*lsapp);
224	k = (lsapp->lsa_p_len + 31) / 32;
225	if (k * 4 > sizeof(struct in6_addr)) {
226		printf("??prefixlen %d??", lsapp->lsa_p_len);
227		goto trunc;
228	}
229	memset(&prefix, 0, sizeof(prefix));
230	memcpy(&prefix, lsapp->lsa_p_prefix, k * 4);
231	printf(" %s/%d", ip6addr_string(&prefix),
232		lsapp->lsa_p_len);
233	if (lsapp->lsa_p_opt)
234		printf("(opt=%x)", lsapp->lsa_p_opt);
235	return sizeof(*lsapp) - 4 + k * 4;
236
237trunc:
238	return -1;
239}
240
241
242/*
243 * Print a single link state advertisement.  If truncated return 1, else 0.
244 */
245static int
246ospf6_print_lsa(const struct lsa *lsap)
247{
248	const u_char *ls_end;
249	const struct rlalink *rlp;
250#if 0
251	const struct tos_metric *tosp;
252#endif
253	const rtrid_t *ap;
254#if 0
255	const struct aslametric *almp;
256	const struct mcla *mcp;
257#endif
258	const struct llsa *llsap;
259	const struct lsa_prefix *lsapp;
260#if 0
261	const u_int32_t *lp;
262#endif
263	int j, k;
264
265	if (ospf6_print_lshdr(&lsap->ls_hdr))
266		return (1);
267	TCHECK(lsap->ls_hdr.ls_length);
268	ls_end = (u_char *)lsap + ntohs(lsap->ls_hdr.ls_length);
269	switch (ntohs(lsap->ls_hdr.ls_type)) {
270	case LS_TYPE_ROUTER | LS_SCOPE_AREA:
271		TCHECK(lsap->lsa_un.un_rla.rla_flags);
272		ospf6_print_bits(ospf6_rla_flag_bits,
273			lsap->lsa_un.un_rla.rla_flags);
274		TCHECK(lsap->lsa_un.un_rla.rla_options);
275		ospf6_print_bits(ospf6_option_bits,
276			ntohl(lsap->lsa_un.un_rla.rla_options));
277
278		TCHECK(lsap->lsa_un.un_rla.rla_link);
279		rlp = lsap->lsa_un.un_rla.rla_link;
280		while (rlp + sizeof(*rlp) <= (struct rlalink *)ls_end) {
281			TCHECK(*rlp);
282			printf(" {");				/* } (ctags) */
283			switch (rlp->link_type) {
284
285			case RLA_TYPE_VIRTUAL:
286				printf(" virt");
287				/* FALLTHROUGH */
288
289			case RLA_TYPE_ROUTER:
290				printf(" nbrid %s nbrif %s if %s",
291				    ipaddr_string(&rlp->link_nrtid),
292				    ipaddr_string(&rlp->link_nifid),
293				    ipaddr_string(&rlp->link_ifid));
294				break;
295
296			case RLA_TYPE_TRANSIT:
297				printf(" dr %s drif %s if %s",
298				    ipaddr_string(&rlp->link_nrtid),
299				    ipaddr_string(&rlp->link_nifid),
300				    ipaddr_string(&rlp->link_ifid));
301				break;
302
303			default:
304								/* { (ctags) */
305				printf(" ??RouterLinksType 0x%02x?? }",
306				    rlp->link_type);
307				return (0);
308			}
309			printf(" metric %d", ntohs(rlp->link_metric));
310								/* { (ctags) */
311			printf(" }");
312			rlp++;
313		}
314		break;
315
316	case LS_TYPE_NETWORK | LS_SCOPE_AREA:
317		TCHECK(lsap->lsa_un.un_nla.nla_options);
318		ospf6_print_bits(ospf6_option_bits,
319			ntohl(lsap->lsa_un.un_nla.nla_options));
320		printf(" rtrs");
321		ap = lsap->lsa_un.un_nla.nla_router;
322		while ((u_char *)ap < ls_end) {
323			TCHECK(*ap);
324			printf(" %s", ipaddr_string(ap));
325			++ap;
326		}
327		break;
328
329	case LS_TYPE_INTER_AP | LS_SCOPE_AREA:
330		TCHECK(lsap->lsa_un.un_inter_ap.inter_ap_metric);
331		printf(" metric %u",
332			(u_int32_t)ntohl(lsap->lsa_un.un_inter_ap.inter_ap_metric) & SLA_MASK_METRIC);
333		lsapp = lsap->lsa_un.un_inter_ap.inter_ap_prefix;
334		while (lsapp + sizeof(lsapp) <= (struct lsa_prefix *)ls_end) {
335			k = ospf6_print_lsaprefix(lsapp);
336			if (k < 0)
337				goto trunc;
338			lsapp = (struct lsa_prefix *)(((u_char *)lsapp) + k);
339		}
340		break;
341
342#if 0
343	case LS_TYPE_SUM_ABR:
344		TCHECK(lsap->lsa_un.un_sla.sla_tosmetric);
345		lp = lsap->lsa_un.un_sla.sla_tosmetric;
346		while ((u_char *)lp < ls_end) {
347			u_int32_t ul;
348
349			TCHECK(*lp);
350			ul = ntohl(*lp);
351			printf(" tos %d metric %d",
352			    (ul & SLA_MASK_TOS) >> SLA_SHIFT_TOS,
353			    ul & SLA_MASK_METRIC);
354			++lp;
355		}
356		break;
357
358	case LS_TYPE_ASE:
359		TCHECK(lsap->lsa_un.un_nla.nla_mask);
360		printf(" mask %s",
361		    ipaddr_string(&lsap->lsa_un.un_asla.asla_mask));
362
363		TCHECK(lsap->lsa_un.un_sla.sla_tosmetric);
364		almp = lsap->lsa_un.un_asla.asla_metric;
365		while ((u_char *)almp < ls_end) {
366			u_int32_t ul;
367
368			TCHECK(almp->asla_tosmetric);
369			ul = ntohl(almp->asla_tosmetric);
370			printf(" type %d tos %d metric %d",
371			    (ul & ASLA_FLAG_EXTERNAL) ? 2 : 1,
372			    (ul & ASLA_MASK_TOS) >> ASLA_SHIFT_TOS,
373			    (ul & ASLA_MASK_METRIC));
374			TCHECK(almp->asla_forward);
375			if (almp->asla_forward.s_addr) {
376				printf(" forward %s",
377				    ipaddr_string(&almp->asla_forward));
378			}
379			TCHECK(almp->asla_tag);
380			if (almp->asla_tag.s_addr) {
381				printf(" tag %s",
382				    ipaddr_string(&almp->asla_tag));
383			}
384			++almp;
385		}
386		break;
387
388	case LS_TYPE_GROUP:
389		/* Multicast extensions as of 23 July 1991 */
390		mcp = lsap->lsa_un.un_mcla;
391		while ((u_char *)mcp < ls_end) {
392			TCHECK(mcp->mcla_vid);
393			switch (ntohl(mcp->mcla_vtype)) {
394
395			case MCLA_VERTEX_ROUTER:
396				printf(" rtr rtrid %s",
397				    ipaddr_string(&mcp->mcla_vid));
398				break;
399
400			case MCLA_VERTEX_NETWORK:
401				printf(" net dr %s",
402				    ipaddr_string(&mcp->mcla_vid));
403				break;
404
405			default:
406				printf(" ??VertexType %u??",
407				    (u_int32_t)ntohl(mcp->mcla_vtype));
408				break;
409			}
410		++mcp;
411		}
412#endif
413
414	case LS_TYPE_LINK:
415		/* Link LSA */
416		llsap = &lsap->lsa_un.un_llsa;
417		TCHECK(llsap->llsa_options);
418		ospf6_print_bits(ospf6_option_bits, ntohl(llsap->llsa_options));
419		TCHECK(llsap->llsa_nprefix);
420		printf(" pri %d lladdr %s npref %d", llsap->llsa_priority,
421			ip6addr_string(&llsap->llsa_lladdr),
422			(u_int32_t)ntohl(llsap->llsa_nprefix));
423		lsapp = llsap->llsa_prefix;
424		for (j = 0; j < ntohl(llsap->llsa_nprefix); j++) {
425			k = ospf6_print_lsaprefix(lsapp);
426			if (k < 0)
427				goto trunc;
428			lsapp = (struct lsa_prefix *)(((u_char *)lsapp) + k);
429		}
430		break;
431
432	case LS_TYPE_INTRA_AP | LS_SCOPE_AREA:
433		/* Intra-Area-Prefix LSA */
434		TCHECK(lsap->lsa_un.un_intra_ap.intra_ap_rtid);
435		ospf6_print_ls_type(
436			ntohs(lsap->lsa_un.un_intra_ap.intra_ap_lstype),
437			&lsap->lsa_un.un_intra_ap.intra_ap_lsid,
438			&lsap->lsa_un.un_intra_ap.intra_ap_rtid,
439			"LinkStateType %d");
440		TCHECK(lsap->lsa_un.un_intra_ap.intra_ap_nprefix);
441		printf(" npref %d",
442			ntohs(lsap->lsa_un.un_intra_ap.intra_ap_nprefix));
443
444		lsapp = lsap->lsa_un.un_intra_ap.intra_ap_prefix;
445		for (j = 0;
446		     j < ntohs(lsap->lsa_un.un_intra_ap.intra_ap_nprefix);
447		     j++) {
448			k = ospf6_print_lsaprefix(lsapp);
449			if (k < 0)
450				goto trunc;
451			lsapp = (struct lsa_prefix *)(((u_char *)lsapp) + k);
452		}
453		break;
454
455	default:
456		printf(" ??LinkStateType 0x%04x??",
457			ntohs(lsap->ls_hdr.ls_type));
458	}
459
460								/* { (ctags) */
461	printf(" }");
462	return (0);
463trunc:
464	printf(" }");
465	return (1);
466}
467
468static int
469ospf6_decode_v3(const struct ospf6hdr *op, const u_char *dataend)
470{
471	const rtrid_t *ap;
472	const struct lsr *lsrp;
473	const struct lsa_hdr *lshp;
474	const struct lsa *lsap;
475	char sep;
476	int i;
477
478	switch (op->ospf6_type) {
479
480	case OSPF_TYPE_UMD:
481		/*
482		 * Rob Coltun's special monitoring packets;
483		 * do nothing
484		 */
485		break;
486
487	case OSPF_TYPE_HELLO:
488		if (vflag) {
489			TCHECK(op->ospf6_hello.hello_deadint);
490			ospf6_print_bits(ospf6_option_bits,
491			    ntohl(op->ospf6_hello.hello_options));
492			printf(" ifid %s pri %d int %d dead %u",
493			    ipaddr_string(&op->ospf6_hello.hello_ifid),
494			    op->ospf6_hello.hello_priority,
495			    ntohs(op->ospf6_hello.hello_helloint),
496			    ntohs(op->ospf6_hello.hello_deadint));
497		}
498		TCHECK(op->ospf6_hello.hello_dr);
499		if (op->ospf6_hello.hello_dr != 0)
500			printf(" dr %s",
501			    ipaddr_string(&op->ospf6_hello.hello_dr));
502		TCHECK(op->ospf6_hello.hello_bdr);
503		if (op->ospf6_hello.hello_bdr != 0)
504			printf(" bdr %s",
505			    ipaddr_string(&op->ospf6_hello.hello_bdr));
506		if (vflag) {
507			printf(" nbrs");
508			ap = op->ospf6_hello.hello_neighbor;
509			while ((u_char *)ap < dataend) {
510				TCHECK(*ap);
511				printf(" %s", ipaddr_string(ap));
512				++ap;
513			}
514		}
515		break;	/* HELLO */
516
517	case OSPF_TYPE_DB:
518		TCHECK(op->ospf6_db.db_options);
519		ospf6_print_bits(ospf6_option_bits,
520			ntohl(op->ospf6_db.db_options));
521		sep = ' ';
522		TCHECK(op->ospf6_db.db_flags);
523		if (op->ospf6_db.db_flags & OSPF6_DB_INIT) {
524			printf("%cI", sep);
525			sep = '/';
526		}
527		if (op->ospf6_db.db_flags & OSPF6_DB_MORE) {
528			printf("%cM", sep);
529			sep = '/';
530		}
531		if (op->ospf6_db.db_flags & OSPF6_DB_MASTER) {
532			printf("%cMS", sep);
533			sep = '/';
534		}
535		TCHECK(op->ospf6_db.db_seq);
536		printf(" mtu %u S %X", ntohs(op->ospf6_db.db_mtu),
537			(u_int32_t)ntohl(op->ospf6_db.db_seq));
538
539		if (vflag) {
540			/* Print all the LS adv's */
541			lshp = op->ospf6_db.db_lshdr;
542
543			while (!ospf6_print_lshdr(lshp)) {
544							/* { (ctags) */
545				printf(" }");
546				++lshp;
547			}
548		}
549		break;
550
551	case OSPF_TYPE_LSR:
552		if (vflag) {
553			lsrp = op->ospf6_lsr;
554			while ((u_char *)lsrp < dataend) {
555				TCHECK(*lsrp);
556				printf(" {");		/* } (ctags) */
557				ospf6_print_ls_type(ntohs(lsrp->ls_type),
558				    &lsrp->ls_stateid,
559				    &lsrp->ls_router,
560				    "LinkStateType %d");
561							/* { (ctags) */
562				printf(" }");
563				++lsrp;
564			}
565		}
566		break;
567
568	case OSPF_TYPE_LSU:
569		if (vflag) {
570			lsap = op->ospf6_lsu.lsu_lsa;
571			TCHECK(op->ospf6_lsu.lsu_count);
572			i = ntohl(op->ospf6_lsu.lsu_count);
573			while (i--) {
574				if (ospf6_print_lsa(lsap))
575					goto trunc;
576				lsap = (struct lsa *)((u_char *)lsap +
577				    ntohs(lsap->ls_hdr.ls_length));
578			}
579		}
580		break;
581
582
583	case OSPF_TYPE_LSA:
584		if (vflag) {
585			lshp = op->ospf6_lsa.lsa_lshdr;
586
587			while (!ospf6_print_lshdr(lshp)) {
588							/* { (ctags) */
589				printf(" }");
590				++lshp;
591			}
592		}
593		break;
594
595	default:
596		printf("v3 type %d", op->ospf6_type);
597		break;
598	}
599	return (0);
600trunc:
601	return (1);
602}
603
604void
605ospf6_print(const u_char *bp, u_int length)
606{
607	const struct ospf6hdr *op;
608	const u_char *dataend;
609	const char *cp;
610
611	op = (struct ospf6hdr *)bp;
612
613	/* If the type is valid translate it, or just print the type */
614	/* value.  If it's not valid, say so and return */
615	TCHECK(op->ospf6_type);
616	cp = tok2str(type2str, "type%d", op->ospf6_type);
617	printf(" OSPFv%d-%s %d:", op->ospf6_version, cp, length);
618	if (*cp == 't')
619		return;
620
621	TCHECK(op->ospf6_len);
622	if (length != ntohs(op->ospf6_len)) {
623		printf(" [len %d]", ntohs(op->ospf6_len));
624		return;
625	}
626	dataend = bp + length;
627
628	TCHECK(op->ospf6_routerid);
629	printf(" rtrid %s", ipaddr_string(&op->ospf6_routerid));
630
631	TCHECK(op->ospf6_areaid);
632	if (op->ospf6_areaid != 0)
633		printf(" area %s", ipaddr_string(&op->ospf6_areaid));
634	else
635		printf(" backbone");
636	TCHECK(op->ospf6_instanceid);
637	if (op->ospf6_instanceid)
638		printf(" instance %u", op->ospf6_instanceid);
639
640	/* Do rest according to version.	 */
641	switch (op->ospf6_version) {
642
643	case 3:
644		/* ospf version 3 */
645		if (ospf6_decode_v3(op, dataend))
646			goto trunc;
647		break;
648
649	default:
650		printf(" ospf [version %d]", op->ospf6_version);
651		break;
652	}			/* end switch on version */
653
654	return;
655trunc:
656	printf("%s", tstr);
657}
658