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