xref: /openbsd-src/usr.sbin/tcpdump/print-ospf.c (revision c90a81c56dcebd6a1b73fe4aff9b03385b8e63b3)
1 /*	$OpenBSD: print-ospf.c,v 1.20 2015/11/16 00:16:39 mmcc Exp $	*/
2 
3 /*
4  * Copyright (c) 1992, 1993, 1994, 1995, 1996, 1997
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that: (1) source code distributions
9  * retain the above copyright notice and this paragraph in its entirety, (2)
10  * distributions including binary code include the above copyright notice and
11  * this paragraph in its entirety in the documentation or other materials
12  * provided with the distribution, and (3) all advertising materials mentioning
13  * features or use of this software display the following acknowledgement:
14  * ``This product includes software developed by the University of California,
15  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16  * the University nor the names of its contributors may be used to endorse
17  * or promote products derived from this software without specific prior
18  * written permission.
19  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22  *
23  * OSPF support contributed by Jeffrey Honig (jch@mitchell.cit.cornell.edu)
24  */
25 
26 #include <sys/time.h>
27 #include <sys/socket.h>
28 
29 #include <netinet/in.h>
30 #include <netinet/ip.h>
31 #include <netinet/ip_var.h>
32 
33 #include <ctype.h>
34 #include <stdio.h>
35 
36 #include "interface.h"
37 #include "addrtoname.h"
38 
39 #include "ospf.h"
40 
41 struct bits {
42 	u_int32_t bit;
43 	const char *str;
44 };
45 
46 static const struct bits ospf_option_bits[] = {
47 	{ OSPF_OPTION_T,	"T" },
48 	{ OSPF_OPTION_E,	"E" },
49 	{ OSPF_OPTION_MC,	"MC" },
50 	{ 0,			NULL }
51 };
52 
53 static const struct bits ospf_rla_flag_bits[] = {
54 	{ RLA_FLAG_B,		"B" },
55 	{ RLA_FLAG_E,		"E" },
56 	{ RLA_FLAG_W1,		"W1" },
57 	{ RLA_FLAG_W2,		"W2" },
58 	{ 0,			NULL }
59 };
60 
61 static struct tok type2str[] = {
62 	{ OSPF_TYPE_UMD,	"umd" },
63 	{ OSPF_TYPE_HELLO,	"hello" },
64 	{ OSPF_TYPE_DB,		"dd" },
65 	{ OSPF_TYPE_LSR,	"ls_req" },
66 	{ OSPF_TYPE_LSU,	"ls_upd" },
67 	{ OSPF_TYPE_LSA,	"ls_ack" },
68 	{ 0,			NULL }
69 };
70 
71 static char tstr[] = " [|ospf]";
72 
73 /* Forwards */
74 static inline void ospf_print_seqage(u_int32_t, time_t);
75 static inline void ospf_print_bits(const struct bits *, u_char);
76 static void ospf_print_ls_type(u_int, const struct in_addr *,
77     const struct in_addr *, const char *);
78 static int ospf_print_lshdr(const struct lsa_hdr *);
79 static int ospf_print_lsa(const struct lsa *);
80 static int ospf_decode_v2(const struct ospfhdr *, const u_char *);
81 
82 static inline void
83 ospf_print_seqage(u_int32_t seq, time_t us)
84 {
85 	time_t sec = us % 60;
86 	time_t mins = (us / 60) % 60;
87 	time_t hour = us / 3600;
88 
89 	printf(" S %X age ", seq);
90 	if (hour)
91 		printf("%u:%02u:%02u",
92 		    (u_int32_t) hour, (u_int32_t) mins, (u_int32_t) sec);
93 	else if (mins)
94 		printf("%u:%02u", (u_int32_t) mins, (u_int32_t) sec);
95 	else
96 		printf("%u", (u_int32_t) sec);
97 }
98 
99 
100 static inline void
101 ospf_print_bits(const struct bits *bp, u_char options)
102 {
103 	char sep = ' ';
104 
105 	do {
106 		if (options & bp->bit) {
107 			printf("%c%s", sep, bp->str);
108 			sep = '/';
109 		}
110 	} while ((++bp)->bit);
111 }
112 
113 static void
114 ospf_print_ls_type(u_int ls_type, const struct in_addr *ls_stateid,
115     const struct in_addr *ls_router, const char *fmt)
116 {
117 
118 	switch (ls_type) {
119 
120 	case LS_TYPE_ROUTER:
121 		printf(" rtr %s", ipaddr_string(ls_router));
122 		break;
123 
124 	case LS_TYPE_NETWORK:
125 		printf(" net dr %s if %s",
126 		    ipaddr_string(ls_router),
127 		    ipaddr_string(ls_stateid));
128 		break;
129 
130 	case LS_TYPE_SUM_IP:
131 		printf(" sum %s abr %s",
132 		    ipaddr_string(ls_stateid),
133 		    ipaddr_string(ls_router));
134 		break;
135 
136 	case LS_TYPE_SUM_ABR:
137 		printf(" abr %s rtr %s",
138 		    ipaddr_string(ls_router),
139 		    ipaddr_string(ls_stateid));
140 		break;
141 
142 	case LS_TYPE_ASE:
143 		printf(" ase %s asbr %s",
144 		    ipaddr_string(ls_stateid),
145 		    ipaddr_string(ls_router));
146 		break;
147 
148 	case LS_TYPE_GROUP:
149 		printf(" group %s rtr %s",
150 		    ipaddr_string(ls_stateid),
151 		    ipaddr_string(ls_router));
152 		break;
153 
154 	default:
155 		putchar(' ');
156 		printf(fmt, ls_type);
157 		break;
158 	}
159 }
160 
161 static int
162 ospf_print_lshdr(const struct lsa_hdr *lshp)
163 {
164 
165 	TCHECK(lshp->ls_type);
166 	printf(" {");						/* } (ctags) */
167 
168 	TCHECK(lshp->ls_options);
169 	ospf_print_bits(ospf_option_bits, lshp->ls_options);
170 	TCHECK(lshp->ls_seq);
171 	ospf_print_seqage(ntohl(lshp->ls_seq), ntohs(lshp->ls_age));
172 	ospf_print_ls_type(lshp->ls_type, &lshp->ls_stateid, &lshp->ls_router,
173 	    "ls_type %d");
174 
175 	return (0);
176 trunc:
177 	return (1);
178 }
179 
180 
181 /*
182  * Print a single link state advertisement.  If truncated return 1, else 0.
183  */
184 static int
185 ospf_print_lsa(const struct lsa *lsap)
186 {
187 	const u_char *ls_end;
188 	const struct rlalink *rlp;
189 	const struct tos_metric *tosp;
190 	const struct in_addr *ap;
191 	const struct aslametric *almp;
192 	const struct mcla *mcp;
193 	const u_int32_t *lp;
194 	int j, k;
195 
196 	if (ospf_print_lshdr(&lsap->ls_hdr))
197 		return (1);
198 	TCHECK(lsap->ls_hdr.ls_length);
199 	ls_end = (u_char *)lsap + ntohs(lsap->ls_hdr.ls_length);
200 	switch (lsap->ls_hdr.ls_type) {
201 
202 	case LS_TYPE_ROUTER:
203 		TCHECK(lsap->lsa_un.un_rla.rla_flags);
204 		ospf_print_bits(ospf_rla_flag_bits,
205 		    lsap->lsa_un.un_rla.rla_flags);
206 
207 		TCHECK(lsap->lsa_un.un_rla.rla_count);
208 		j = ntohs(lsap->lsa_un.un_rla.rla_count);
209 		TCHECK(lsap->lsa_un.un_rla.rla_link);
210 		rlp = lsap->lsa_un.un_rla.rla_link;
211 		while (j--) {
212 			TCHECK(*rlp);
213 			printf(" {");				/* } (ctags) */
214 			switch (rlp->link_type) {
215 
216 			case RLA_TYPE_VIRTUAL:
217 				printf(" virt");
218 				/* FALLTHROUGH */
219 
220 			case RLA_TYPE_ROUTER:
221 				printf(" nbrid %s if %s",
222 				    ipaddr_string(&rlp->link_id),
223 				    ipaddr_string(&rlp->link_data));
224 				break;
225 
226 			case RLA_TYPE_TRANSIT:
227 				printf(" dr %s if %s",
228 				    ipaddr_string(&rlp->link_id),
229 				    ipaddr_string(&rlp->link_data));
230 				break;
231 
232 			case RLA_TYPE_STUB:
233 				printf(" net %s mask %s",
234 				    ipaddr_string(&rlp->link_id),
235 				    ipaddr_string(&rlp->link_data));
236 				break;
237 
238 			default:
239 								/* { (ctags) */
240 				printf(" ??RouterLinksType %d?? }",
241 				    rlp->link_type);
242 				return (0);
243 			}
244 			printf(" tos 0 metric %d", ntohs(rlp->link_tos0metric));
245 			tosp = (struct tos_metric *)
246 			    ((sizeof rlp->link_tos0metric) + (u_char *) rlp);
247 			for (k = 0; k < (int) rlp->link_toscount; ++k, ++tosp) {
248 				TCHECK(*tosp);
249 				printf(" tos %d metric %d",
250 				    tosp->tos_type,
251 				    ntohs(tosp->tos_metric));
252 			}
253 								/* { (ctags) */
254 			printf(" }");
255 			rlp = (struct rlalink *)((u_char *)(rlp + 1) +
256 			    ((rlp->link_toscount) * sizeof(*tosp)));
257 		}
258 		break;
259 
260 	case LS_TYPE_NETWORK:
261 		TCHECK(lsap->lsa_un.un_nla.nla_mask);
262 		printf(" mask %s rtrs",
263 		    ipaddr_string(&lsap->lsa_un.un_nla.nla_mask));
264 		ap = lsap->lsa_un.un_nla.nla_router;
265 		while ((u_char *)ap < ls_end) {
266 			TCHECK(*ap);
267 			printf(" %s", ipaddr_string(ap));
268 			++ap;
269 		}
270 		break;
271 
272 	case LS_TYPE_SUM_IP:
273 		TCHECK(lsap->lsa_un.un_nla.nla_mask);
274 		printf(" mask %s",
275 		    ipaddr_string(&lsap->lsa_un.un_sla.sla_mask));
276 		/* FALLTHROUGH */
277 
278 	case LS_TYPE_SUM_ABR:
279 		TCHECK(lsap->lsa_un.un_sla.sla_tosmetric);
280 		lp = lsap->lsa_un.un_sla.sla_tosmetric;
281 		while ((u_char *)lp < ls_end) {
282 			u_int32_t ul;
283 
284 			TCHECK(*lp);
285 			ul = ntohl(*lp);
286 			printf(" tos %d metric %d",
287 			    (ul & SLA_MASK_TOS) >> SLA_SHIFT_TOS,
288 			    ul & SLA_MASK_METRIC);
289 			++lp;
290 		}
291 		break;
292 
293 	case LS_TYPE_ASE:
294 		TCHECK(lsap->lsa_un.un_nla.nla_mask);
295 		printf(" mask %s",
296 		    ipaddr_string(&lsap->lsa_un.un_asla.asla_mask));
297 
298 		TCHECK(lsap->lsa_un.un_sla.sla_tosmetric);
299 		almp = lsap->lsa_un.un_asla.asla_metric;
300 		while ((u_char *)almp < ls_end) {
301 			u_int32_t ul;
302 
303 			TCHECK(almp->asla_tosmetric);
304 			ul = ntohl(almp->asla_tosmetric);
305 			printf(" type %d tos %d metric %d",
306 			    (ul & ASLA_FLAG_EXTERNAL) ? 2 : 1,
307 			    (ul & ASLA_MASK_TOS) >> ASLA_SHIFT_TOS,
308 			    (ul & ASLA_MASK_METRIC));
309 			TCHECK(almp->asla_forward);
310 			if (almp->asla_forward.s_addr) {
311 				printf(" forward %s",
312 				    ipaddr_string(&almp->asla_forward));
313 			}
314 			TCHECK(almp->asla_tag);
315 			if (almp->asla_tag) {
316 				printf(" tag %u",
317 				    ntohl(almp->asla_tag));
318 			}
319 			++almp;
320 		}
321 		break;
322 
323 	case LS_TYPE_GROUP:
324 		/* Multicast extensions as of 23 July 1991 */
325 		mcp = lsap->lsa_un.un_mcla;
326 		while ((u_char *)mcp < ls_end) {
327 			TCHECK(mcp->mcla_vid);
328 			switch (ntohl(mcp->mcla_vtype)) {
329 
330 			case MCLA_VERTEX_ROUTER:
331 				printf(" rtr rtrid %s",
332 				    ipaddr_string(&mcp->mcla_vid));
333 				break;
334 
335 			case MCLA_VERTEX_NETWORK:
336 				printf(" net dr %s",
337 				    ipaddr_string(&mcp->mcla_vid));
338 				break;
339 
340 			default:
341 				printf(" ??VertexType %u??",
342 				    (u_int32_t)ntohl(mcp->mcla_vtype));
343 				break;
344 			}
345 		++mcp;
346 		}
347 	}
348 
349 								/* { (ctags) */
350 	fputs(" }", stdout);
351 	return (0);
352 trunc:
353 	fputs(" }", stdout);
354 	return (1);
355 }
356 
357 static int
358 ospf_decode_v2(const struct ospfhdr *op, const u_char *dataend)
359 {
360 	const struct in_addr *ap;
361 	const struct lsr *lsrp;
362 	const struct lsa_hdr *lshp;
363 	const struct lsa *lsap;
364 	char sep;
365 	int i;
366 
367 	switch (op->ospf_type) {
368 
369 	case OSPF_TYPE_UMD:
370 		/*
371 		 * Rob Coltun's special monitoring packets;
372 		 * do nothing
373 		 */
374 		break;
375 
376 	case OSPF_TYPE_HELLO:
377 		if (vflag) {
378 			TCHECK(op->ospf_hello.hello_deadint);
379 			ospf_print_bits(ospf_option_bits,
380 			    op->ospf_hello.hello_options);
381 			printf(" mask %s int %d pri %d dead %u",
382 			    ipaddr_string(&op->ospf_hello.hello_mask),
383 			    ntohs(op->ospf_hello.hello_helloint),
384 			    op->ospf_hello.hello_priority,
385 			    (u_int32_t)ntohl(op->ospf_hello.hello_deadint));
386 		}
387 		TCHECK(op->ospf_hello.hello_dr);
388 		if (op->ospf_hello.hello_dr.s_addr != 0)
389 			printf(" dr %s",
390 			    ipaddr_string(&op->ospf_hello.hello_dr));
391 		TCHECK(op->ospf_hello.hello_bdr);
392 		if (op->ospf_hello.hello_bdr.s_addr != 0)
393 			printf(" bdr %s",
394 			    ipaddr_string(&op->ospf_hello.hello_bdr));
395 		if (vflag) {
396 			printf(" nbrs");
397 			ap = op->ospf_hello.hello_neighbor;
398 			while ((u_char *)ap < dataend) {
399 				TCHECK(*ap);
400 				printf(" %s", ipaddr_string(ap));
401 				++ap;
402 			}
403 		}
404 		break;	/* HELLO */
405 
406 	case OSPF_TYPE_DB:
407 		TCHECK(op->ospf_db.db_options);
408 		ospf_print_bits(ospf_option_bits, op->ospf_db.db_options);
409 		sep = ' ';
410 		TCHECK(op->ospf_db.db_flags);
411 		if (op->ospf_db.db_flags & OSPF_DB_INIT) {
412 			printf("%cI", sep);
413 			sep = '/';
414 		}
415 		if (op->ospf_db.db_flags & OSPF_DB_MORE) {
416 			printf("%cM", sep);
417 			sep = '/';
418 		}
419 		if (op->ospf_db.db_flags & OSPF_DB_MASTER) {
420 			printf("%cMS", sep);
421 			sep = '/';
422 		}
423 		TCHECK(op->ospf_db.db_seq);
424 		printf(" mtu %u S %X", ntohs(op->ospf_db.db_mtu),
425 		    (u_int32_t)ntohl(op->ospf_db.db_seq));
426 
427 		if (vflag) {
428 			/* Print all the LS adv's */
429 			lshp = op->ospf_db.db_lshdr;
430 
431 			while (!ospf_print_lshdr(lshp)) {
432 							/* { (ctags) */
433 				printf(" }");
434 				++lshp;
435 			}
436 		}
437 		break;
438 
439 	case OSPF_TYPE_LSR:
440 		if (vflag) {
441 			lsrp = op->ospf_lsr;
442 			while ((u_char *)lsrp < dataend) {
443 				TCHECK(*lsrp);
444 				printf(" {");		/* } (ctags) */
445 				ospf_print_ls_type(ntohl(lsrp->ls_type),
446 				    &lsrp->ls_stateid,
447 				    &lsrp->ls_router,
448 				    "LinkStateType %d");
449 							/* { (ctags) */
450 				printf(" }");
451 				++lsrp;
452 			}
453 		}
454 		break;
455 
456 	case OSPF_TYPE_LSU:
457 		if (vflag) {
458 			lsap = op->ospf_lsu.lsu_lsa;
459 			TCHECK(op->ospf_lsu.lsu_count);
460 			i = ntohl(op->ospf_lsu.lsu_count);
461 			while (i--) {
462 				if (ospf_print_lsa(lsap))
463 					goto trunc;
464 				lsap = (struct lsa *)((u_char *)lsap +
465 				    ntohs(lsap->ls_hdr.ls_length));
466 			}
467 		}
468 		break;
469 
470 
471 	case OSPF_TYPE_LSA:
472 		if (vflag) {
473 			lshp = op->ospf_lsa.lsa_lshdr;
474 
475 			while (!ospf_print_lshdr(lshp)) {
476 							/* { (ctags) */
477 				printf(" }");
478 				++lshp;
479 			}
480 		}
481 		break;
482 
483 	default:
484 		printf("v2 type %d", op->ospf_type);
485 		break;
486 	}
487 	return (0);
488 trunc:
489 	return (1);
490 }
491 
492 void
493 ospf_print(const u_char *bp, u_int length, const u_char *bp2)
494 {
495 	const struct ospfhdr *op;
496 	const struct ip *ip;
497 	const u_char *dataend;
498 	const char *cp;
499 
500 	op = (struct ospfhdr *)bp;
501 	ip = (struct ip *)bp2;
502 	/* Print the source and destination address  */
503 	(void) printf("%s > %s:",
504 	    ipaddr_string(&ip->ip_src),
505 	    ipaddr_string(&ip->ip_dst));
506 
507         /* XXX Before we do anything else, strip off the MD5 trailer */
508         TCHECK(op->ospf_authtype);
509         if (ntohs(op->ospf_authtype) == OSPF_AUTH_MD5) {
510                 length -= OSPF_AUTH_MD5_LEN;
511                 snapend -= OSPF_AUTH_MD5_LEN;
512         }
513 
514 	/* If the type is valid translate it, or just print the type */
515 	/* value.  If it's not valid, say so and return */
516 	TCHECK(op->ospf_type);
517 	cp = tok2str(type2str, "type%d", op->ospf_type);
518 	printf(" OSPFv%d-%s ", op->ospf_version, cp);
519 	if (*cp == 't')
520 		return;
521 
522 	TCHECK(op->ospf_len);
523 	if (length < ntohs(op->ospf_len)) {
524 		printf(" [len %d]", ntohs(op->ospf_len));
525 		return;
526 	} else if (length > ntohs(op->ospf_len)) {
527 		printf(" %d[%d]:", ntohs(op->ospf_len), length);
528 		length = ntohs(op->ospf_len);
529 	} else
530 		printf(" %d:", length);
531 	dataend = bp + length;
532 
533 	TCHECK(op->ospf_routerid);
534 	printf(" rtrid %s", ipaddr_string(&op->ospf_routerid));
535 
536 	TCHECK(op->ospf_areaid);
537 	if (op->ospf_areaid.s_addr != 0)
538 		printf(" area %s", ipaddr_string(&op->ospf_areaid));
539 	else
540 		printf(" backbone");
541 
542 	if (vflag) {
543 		/* Print authentication data (should we really do this?) */
544 		TCHECK2(op->ospf_authdata[0], sizeof(op->ospf_authdata));
545 		switch (ntohs(op->ospf_authtype)) {
546 
547 		case OSPF_AUTH_NONE:
548 			break;
549 
550 		case OSPF_AUTH_SIMPLE:
551 			printf(" auth \"");
552 			(void)fn_printn(op->ospf_authdata,
553 			    sizeof(op->ospf_authdata), NULL);
554 			printf("\"");
555 			break;
556 
557 		case OSPF_AUTH_MD5:
558 			printf(" auth MD5");
559 			break;
560 
561 		default:
562 			printf(" ??authtype-%d??", ntohs(op->ospf_authtype));
563 			return;
564 		}
565 	}
566 	/* Do rest according to version.	 */
567 	switch (op->ospf_version) {
568 
569 	case 2:
570 		/* ospf version 2 */
571 		if (ospf_decode_v2(op, dataend))
572 			goto trunc;
573 		break;
574 
575 	default:
576 		printf(" ospf [version %d]", op->ospf_version);
577 		break;
578 	}			/* end switch on version */
579 
580 	return;
581 trunc:
582 	fputs(tstr, stdout);
583 }
584