1 /*
2 * Copyright (c) 2007-2011 Grégoire Henry, Juliusz Chroboczek
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. Neither the name of the project nor the names of its contributors
13 * may be used to endorse or promote products derived from this software
14 * without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 /* \summary: Babel Routing Protocol printer */
30 /* Specifications:
31 *
32 * RFC 6126
33 * RFC 7298
34 * RFC 7557
35 * draft-ietf-babel-rfc6126bis-17
36 * draft-ietf-babel-hmac-10
37 * draft-ietf-babel-source-specific-0
38 */
39
40 #include <config.h>
41
42 #include "netdissect-stdinc.h"
43
44 #include <stdio.h>
45 #include <string.h>
46
47 #include "netdissect.h"
48 #include "addrtoname.h"
49 #include "extract.h"
50
51 static void babel_print_v2(netdissect_options *, const u_char *cp, u_int length);
52
53 void
babel_print(netdissect_options * ndo,const u_char * cp,u_int length)54 babel_print(netdissect_options *ndo,
55 const u_char *cp, u_int length)
56 {
57 ndo->ndo_protocol = "babel";
58 ND_PRINT("babel");
59
60 ND_TCHECK_4(cp);
61
62 if(GET_U_1(cp) != 42) {
63 ND_PRINT(" invalid header");
64 return;
65 } else {
66 ND_PRINT(" %u", GET_U_1(cp + 1));
67 }
68
69 switch(GET_U_1(cp + 1)) {
70 case 2:
71 babel_print_v2(ndo, cp, length);
72 break;
73 default:
74 ND_PRINT(" unknown version");
75 break;
76 }
77
78 return;
79
80 trunc:
81 nd_print_trunc(ndo);
82 }
83
84 /* TLVs */
85 #define MESSAGE_PAD1 0
86 #define MESSAGE_PADN 1
87 #define MESSAGE_ACK_REQ 2
88 #define MESSAGE_ACK 3
89 #define MESSAGE_HELLO 4
90 #define MESSAGE_IHU 5
91 #define MESSAGE_ROUTER_ID 6
92 #define MESSAGE_NH 7
93 #define MESSAGE_UPDATE 8
94 #define MESSAGE_ROUTE_REQUEST 9
95 #define MESSAGE_SEQNO_REQUEST 10
96 #define MESSAGE_TSPC 11
97 #define MESSAGE_HMAC 12
98 #define MESSAGE_UPDATE_SRC_SPECIFIC 13 /* last appearance in draft-boutier-babel-source-specific-01 */
99 #define MESSAGE_REQUEST_SRC_SPECIFIC 14 /* idem */
100 #define MESSAGE_MH_REQUEST_SRC_SPECIFIC 15 /* idem */
101 #define MESSAGE_MAC 16
102 #define MESSAGE_PC 17
103 #define MESSAGE_CHALLENGE_REQUEST 18
104 #define MESSAGE_CHALLENGE_REPLY 19
105
106 /* sub-TLVs */
107 #define MESSAGE_SUB_PAD1 0
108 #define MESSAGE_SUB_PADN 1
109 #define MESSAGE_SUB_DIVERSITY 2
110 #define MESSAGE_SUB_TIMESTAMP 3
111
112 /* "Mandatory" bit in sub-TLV types */
113 #define MANDATORY_MASK 0x80
114
115 /* Flags for the Hello TLV */
116 #define UNICAST_MASK 0x8000
117
118 /* Diversity sub-TLV channel codes */
119 static const struct tok diversity_str[] = {
120 { 0, "reserved" },
121 { 255, "all" },
122 { 0, NULL }
123 };
124
125 static const char *
format_id(netdissect_options * ndo,const u_char * id)126 format_id(netdissect_options *ndo, const u_char *id)
127 {
128 static char buf[25];
129 snprintf(buf, 25, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
130 GET_U_1(id), GET_U_1(id + 1), GET_U_1(id + 2),
131 GET_U_1(id + 3), GET_U_1(id + 4), GET_U_1(id + 5),
132 GET_U_1(id + 6), GET_U_1(id + 7));
133 buf[24] = '\0';
134 return buf;
135 }
136
137 static const unsigned char v4prefix[16] =
138 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
139
140 static const char *
format_prefix(netdissect_options * ndo,const u_char * prefix,unsigned char plen)141 format_prefix(netdissect_options *ndo, const u_char *prefix, unsigned char plen)
142 {
143 static char buf[50];
144
145 /*
146 * prefix points to a buffer on the stack into which the prefix has
147 * been placed, so we can't use GET_IPADDR_STRING() or
148 * GET_IP6ADDR_STRING() on it.
149 */
150 if(plen >= 96 && memcmp(prefix, v4prefix, 12) == 0)
151 snprintf(buf, 50, "%s/%u", ipaddr_string(ndo, prefix + 12), plen - 96);
152 else
153 snprintf(buf, 50, "%s/%u", ip6addr_string(ndo, prefix), plen);
154 buf[49] = '\0';
155 return buf;
156 }
157
158 static const char *
format_address(netdissect_options * ndo,const u_char * prefix)159 format_address(netdissect_options *ndo, const u_char *prefix)
160 {
161 /*
162 * prefix points to a buffer on the stack into which the prefix has
163 * been placed, so we can't use GET_IPADDR_STRING() or
164 * GET_IP6ADDR_STRING() on it.
165 */
166 if(memcmp(prefix, v4prefix, 12) == 0)
167 return ipaddr_string(ndo, prefix + 12);
168 else
169 return ip6addr_string(ndo, prefix);
170 }
171
172 static const char *
format_interval(const uint16_t i)173 format_interval(const uint16_t i)
174 {
175 static char buf[sizeof("000.00s")];
176
177 if (i == 0)
178 return "0.0s (bogus)";
179 snprintf(buf, sizeof(buf), "%u.%02us", i / 100, i % 100);
180 return buf;
181 }
182
183 static const char *
format_interval_update(const uint16_t i)184 format_interval_update(const uint16_t i)
185 {
186 return i == 0xFFFF ? "infinity" : format_interval(i);
187 }
188
189 static const char *
format_timestamp(const uint32_t i)190 format_timestamp(const uint32_t i)
191 {
192 static char buf[sizeof("0000.000000s")];
193 snprintf(buf, sizeof(buf), "%u.%06us", i / 1000000, i % 1000000);
194 return buf;
195 }
196
197 /* Return number of octets consumed from the input buffer (not the prefix length
198 * in bytes), or -1 for encoding error. */
199 static int
network_prefix(int ae,int plen,unsigned int omitted,const unsigned char * p,const unsigned char * dp,unsigned int len,unsigned char * p_r)200 network_prefix(int ae, int plen, unsigned int omitted,
201 const unsigned char *p, const unsigned char *dp,
202 unsigned int len, unsigned char *p_r)
203 {
204 unsigned pb;
205 unsigned char prefix[16];
206 int consumed = 0;
207
208 if(plen >= 0)
209 pb = (plen + 7) / 8;
210 else if(ae == 1)
211 pb = 4;
212 else
213 pb = 16;
214
215 if(pb > 16)
216 return -1;
217
218 memset(prefix, 0, 16);
219
220 switch(ae) {
221 case 0: break;
222 case 1:
223 if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted))
224 return -1;
225 memcpy(prefix, v4prefix, 12);
226 if(omitted) {
227 if (dp == NULL) return -1;
228 memcpy(prefix, dp, 12 + omitted);
229 }
230 if(pb > omitted) {
231 memcpy(prefix + 12 + omitted, p, pb - omitted);
232 consumed = pb - omitted;
233 }
234 break;
235 case 2:
236 if(omitted > 16 || (pb > omitted && len < pb - omitted))
237 return -1;
238 if(omitted) {
239 if (dp == NULL) return -1;
240 memcpy(prefix, dp, omitted);
241 }
242 if(pb > omitted) {
243 memcpy(prefix + omitted, p, pb - omitted);
244 consumed = pb - omitted;
245 }
246 break;
247 case 3:
248 if(pb > 8 && len < pb - 8) return -1;
249 prefix[0] = 0xfe;
250 prefix[1] = 0x80;
251 if(pb > 8) {
252 memcpy(prefix + 8, p, pb - 8);
253 consumed = pb - 8;
254 }
255 break;
256 default:
257 return -1;
258 }
259
260 memcpy(p_r, prefix, 16);
261 return consumed;
262 }
263
264 static int
network_address(int ae,const unsigned char * a,unsigned int len,unsigned char * a_r)265 network_address(int ae, const unsigned char *a, unsigned int len,
266 unsigned char *a_r)
267 {
268 return network_prefix(ae, -1, 0, a, NULL, len, a_r);
269 }
270
271 /*
272 * Sub-TLVs consume the "extra data" of Babel TLVs (see Section 4.3 of RFC6126),
273 * their encoding is similar to the encoding of TLVs, but the type namespace is
274 * different:
275 *
276 * o Type 0 stands for Pad1 sub-TLV with the same encoding as the Pad1 TLV.
277 * o Type 1 stands for PadN sub-TLV with the same encoding as the PadN TLV.
278 * o Type 2 stands for Diversity sub-TLV, which propagates diversity routing
279 * data. Its body is a variable-length sequence of 8-bit unsigned integers,
280 * each representing per-hop number of interfering radio channel for the
281 * prefix. Channel 0 is invalid and must not be used in the sub-TLV, channel
282 * 255 interferes with any other channel.
283 * o Type 3 stands for Timestamp sub-TLV, used to compute RTT between
284 * neighbours. In the case of a Hello TLV, the body stores a 32-bits
285 * timestamp, while in the case of a IHU TLV, two 32-bits timestamps are
286 * stored.
287 *
288 * Sub-TLV types 0 and 1 are valid for any TLV type, whether sub-TLV type 2 is
289 * only valid for TLV type 8 (Update). Note that within an Update TLV a missing
290 * Diversity sub-TLV is not the same as a Diversity sub-TLV with an empty body.
291 * The former would mean a lack of any claims about the interference, and the
292 * latter would state that interference is definitely absent.
293 * A type 3 sub-TLV is valid both for Hello and IHU TLVs, though the exact
294 * semantic of the sub-TLV is different in each case.
295 */
296 static void
subtlvs_print(netdissect_options * ndo,const u_char * cp,const u_char * ep,const uint8_t tlv_type)297 subtlvs_print(netdissect_options *ndo,
298 const u_char *cp, const u_char *ep, const uint8_t tlv_type)
299 {
300 uint8_t subtype, sublen;
301 const char *sep;
302 uint32_t t1, t2;
303
304 while (cp < ep) {
305 subtype = GET_U_1(cp);
306 cp++;
307 if(subtype == MESSAGE_SUB_PAD1) {
308 ND_PRINT(" sub-pad1");
309 continue;
310 }
311 if ((MANDATORY_MASK & subtype) != 0)
312 ND_PRINT(" (M)");
313 if(cp == ep)
314 goto invalid;
315 sublen = GET_U_1(cp);
316 cp++;
317 if(cp + sublen > ep)
318 goto invalid;
319
320 switch(subtype) {
321 case MESSAGE_SUB_PADN:
322 ND_PRINT(" sub-padn");
323 cp += sublen;
324 break;
325 case MESSAGE_SUB_DIVERSITY:
326 ND_PRINT(" sub-diversity");
327 if (sublen == 0) {
328 ND_PRINT(" empty");
329 break;
330 }
331 sep = " ";
332 while (sublen) {
333 ND_PRINT("%s%s", sep,
334 tok2str(diversity_str, "%u", GET_U_1(cp)));
335 cp++;
336 sep = "-";
337 sublen--;
338 }
339 if(tlv_type != MESSAGE_UPDATE &&
340 tlv_type != MESSAGE_UPDATE_SRC_SPECIFIC)
341 ND_PRINT(" (bogus)");
342 break;
343 case MESSAGE_SUB_TIMESTAMP:
344 ND_PRINT(" sub-timestamp");
345 if(tlv_type == MESSAGE_HELLO) {
346 if(sublen < 4)
347 goto invalid;
348 t1 = GET_BE_U_4(cp);
349 ND_PRINT(" %s", format_timestamp(t1));
350 } else if(tlv_type == MESSAGE_IHU) {
351 if(sublen < 8)
352 goto invalid;
353 t1 = GET_BE_U_4(cp);
354 ND_PRINT(" %s", format_timestamp(t1));
355 t2 = GET_BE_U_4(cp + 4);
356 ND_PRINT("|%s", format_timestamp(t2));
357 } else
358 ND_PRINT(" (bogus)");
359 cp += sublen;
360 break;
361 default:
362 ND_PRINT(" sub-unknown-0x%02x", subtype);
363 cp += sublen;
364 } /* switch */
365 } /* while */
366 return;
367
368 invalid:
369 nd_print_invalid(ndo);
370 }
371
372 #define ICHECK(i, l) \
373 if ((i) + (l) > tlvs_length || (i) + (l) > packet_length_remaining) \
374 goto invalid;
375
376 static int
babel_print_v2_tlvs(netdissect_options * ndo,const u_char * cp,u_int tlvs_length,u_int packet_length_remaining)377 babel_print_v2_tlvs(netdissect_options *ndo,
378 const u_char *cp, u_int tlvs_length,
379 u_int packet_length_remaining)
380 {
381 u_int i;
382 u_char v4_prefix[16] =
383 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
384 u_char v6_prefix[16] = {0};
385
386 i = 0;
387 while(i < tlvs_length) {
388 const u_char *message;
389 uint8_t type;
390 u_int len;
391
392 message = cp + i;
393
394 ICHECK(i, 1);
395 if((type = GET_U_1(message)) == MESSAGE_PAD1) {
396 ND_PRINT(ndo->ndo_vflag ? "\n\tPad 1" : " pad1");
397 i += 1;
398 continue;
399 }
400
401 ICHECK(i, 2);
402 ND_TCHECK_2(message);
403 len = GET_U_1(message + 1);
404
405 ICHECK(i, 2 + len);
406 ND_TCHECK_LEN(message, 2 + len);
407
408 switch(type) {
409 case MESSAGE_PADN: {
410 if (!ndo->ndo_vflag)
411 ND_PRINT(" padN");
412 else
413 ND_PRINT("\n\tPad %u", len + 2);
414 }
415 break;
416
417 case MESSAGE_ACK_REQ: {
418 u_short nonce, interval;
419 if (!ndo->ndo_vflag)
420 ND_PRINT(" ack-req");
421 else {
422 ND_PRINT("\n\tAcknowledgment Request ");
423 if(len < 6) goto invalid;
424 nonce = GET_BE_U_2(message + 4);
425 interval = GET_BE_U_2(message + 6);
426 ND_PRINT("%04x %s", nonce, format_interval(interval));
427 }
428 }
429 break;
430
431 case MESSAGE_ACK: {
432 u_short nonce;
433 if (!ndo->ndo_vflag)
434 ND_PRINT(" ack");
435 else {
436 ND_PRINT("\n\tAcknowledgment ");
437 if(len < 2) goto invalid;
438 nonce = GET_BE_U_2(message + 2);
439 ND_PRINT("%04x", nonce);
440 }
441 }
442 break;
443
444 case MESSAGE_HELLO: {
445 u_short seqno, interval, unicast;
446 if (!ndo->ndo_vflag)
447 ND_PRINT(" hello");
448 else {
449 ND_PRINT("\n\tHello ");
450 if(len < 6) goto invalid;
451 unicast = (GET_BE_U_2(message + 2) & UNICAST_MASK);
452 seqno = GET_BE_U_2(message + 4);
453 interval = GET_BE_U_2(message + 6);
454 if(unicast)
455 ND_PRINT("(Unicast) ");
456 ND_PRINT("seqno %u ", seqno);
457 if(interval!=0)
458 ND_PRINT("interval %s", format_interval(interval));
459 else
460 ND_PRINT("unscheduled");
461 /* Extra data. */
462 if(len > 6)
463 subtlvs_print(ndo, message + 8, message + 2 + len, type);
464 }
465 }
466 break;
467
468 case MESSAGE_IHU: {
469 unsigned short rxcost, interval;
470 if (!ndo->ndo_vflag)
471 ND_PRINT(" ihu");
472 else {
473 u_char address[16];
474 u_char ae;
475 int rc;
476 ND_PRINT("\n\tIHU ");
477 if(len < 6) goto invalid;
478 rxcost = GET_BE_U_2(message + 4);
479 interval = GET_BE_U_2(message + 6);
480 ae = GET_U_1(message + 2);
481 rc = network_address(ae, message + 8,
482 len - 6, address);
483 if(rc < 0) { nd_print_trunc(ndo); break; }
484 ND_PRINT("%s rxcost %u interval %s",
485 ae == 0 ? "any" : format_address(ndo, address),
486 rxcost, format_interval(interval));
487 /* Extra data. */
488 if((u_int)rc < len - 6)
489 subtlvs_print(ndo, message + 8 + rc, message + 2 + len,
490 type);
491 }
492 }
493 break;
494
495 case MESSAGE_ROUTER_ID: {
496 if (!ndo->ndo_vflag)
497 ND_PRINT(" router-id");
498 else {
499 ND_PRINT("\n\tRouter Id");
500 if(len < 10) goto invalid;
501 ND_PRINT(" %s", format_id(ndo, message + 4));
502 }
503 }
504 break;
505
506 case MESSAGE_NH: {
507 if (!ndo->ndo_vflag)
508 ND_PRINT(" nh");
509 else {
510 int rc;
511 u_char ae;
512 u_char nh[16];
513 ND_PRINT("\n\tNext Hop");
514 if(len < 2) goto invalid;
515 ae = GET_U_1(message + 2);
516 rc = network_address(ae, message + 4,
517 len - 2, nh);
518 if(rc < 0) goto invalid;
519 ND_PRINT(" %s", ae == 0 ? "invalid AE 0" : format_address(ndo, nh));
520 }
521 }
522 break;
523
524 case MESSAGE_UPDATE: {
525 if (!ndo->ndo_vflag) {
526 ND_PRINT(" update");
527 if(len < 10)
528 goto invalid;
529 else
530 ND_PRINT("%s%s%s",
531 (GET_U_1(message + 3) & 0x80) ? "/prefix": "",
532 (GET_U_1(message + 3) & 0x40) ? "/id" : "",
533 (GET_U_1(message + 3) & 0x3f) ? "/unknown" : "");
534 } else {
535 u_short interval, seqno, metric;
536 u_char ae, plen;
537 int rc;
538 u_char prefix[16];
539 ND_PRINT("\n\tUpdate");
540 if(len < 10) goto invalid;
541 ae = GET_U_1(message + 2);
542 plen = GET_U_1(message + 4) + (GET_U_1(message + 2) == 1 ? 96 : 0);
543 rc = network_prefix(ae,
544 GET_U_1(message + 4),
545 GET_U_1(message + 5),
546 message + 12,
547 GET_U_1(message + 2) == 1 ? v4_prefix : v6_prefix,
548 len - 10, prefix);
549 if(rc < 0) goto invalid;
550 interval = GET_BE_U_2(message + 6);
551 seqno = GET_BE_U_2(message + 8);
552 metric = GET_BE_U_2(message + 10);
553 ND_PRINT("%s%s%s %s metric %u seqno %u interval %s",
554 (GET_U_1(message + 3) & 0x80) ? "/prefix": "",
555 (GET_U_1(message + 3) & 0x40) ? "/id" : "",
556 (GET_U_1(message + 3) & 0x3f) ? "/unknown" : "",
557 ae == 0 ? "any" : format_prefix(ndo, prefix, plen),
558 metric, seqno, format_interval_update(interval));
559 if(GET_U_1(message + 3) & 0x80) {
560 if(GET_U_1(message + 2) == 1)
561 memcpy(v4_prefix, prefix, 16);
562 else
563 memcpy(v6_prefix, prefix, 16);
564 }
565 /* extra data? */
566 if((u_int)rc < len - 10)
567 subtlvs_print(ndo, message + 12 + rc, message + 2 + len, type);
568 }
569 }
570 break;
571
572 case MESSAGE_ROUTE_REQUEST: {
573 if (!ndo->ndo_vflag)
574 ND_PRINT(" route-request");
575 else {
576 int rc;
577 u_char prefix[16], ae, plen;
578 ND_PRINT("\n\tRoute Request ");
579 if(len < 2) goto invalid;
580 ae = GET_U_1(message + 2);
581 plen = GET_U_1(message + 3) + (GET_U_1(message + 2) == 1 ? 96 : 0);
582 rc = network_prefix(ae,
583 GET_U_1(message + 3), 0,
584 message + 4, NULL, len - 2, prefix);
585 if(rc < 0) goto invalid;
586 ND_PRINT("for %s",
587 ae == 0 ? "any" : format_prefix(ndo, prefix, plen));
588 }
589 }
590 break;
591
592 case MESSAGE_SEQNO_REQUEST : {
593 if (!ndo->ndo_vflag)
594 ND_PRINT(" seqno-request");
595 else {
596 int rc;
597 u_short seqno;
598 u_char prefix[16], ae, plen;
599 ND_PRINT("\n\tSeqno Request ");
600 if(len < 14) goto invalid;
601 ae = GET_U_1(message + 2);
602 seqno = GET_BE_U_2(message + 4);
603 rc = network_prefix(ae,
604 GET_U_1(message + 3), 0,
605 message + 16, NULL, len - 14, prefix);
606 if(rc < 0) goto invalid;
607 plen = GET_U_1(message + 3) + (GET_U_1(message + 2) == 1 ? 96 : 0);
608 ND_PRINT("(%u hops) for %s seqno %u id %s",
609 GET_U_1(message + 6),
610 ae == 0 ? "invalid AE 0" : format_prefix(ndo, prefix, plen),
611 seqno, format_id(ndo, message + 8));
612 }
613 }
614 break;
615 case MESSAGE_TSPC :
616 if (!ndo->ndo_vflag)
617 ND_PRINT(" tspc");
618 else {
619 ND_PRINT("\n\tTS/PC ");
620 if(len < 6) goto invalid;
621 ND_PRINT("timestamp %u packetcounter %u",
622 GET_BE_U_4(message + 4),
623 GET_BE_U_2(message + 2));
624 }
625 break;
626 case MESSAGE_HMAC : {
627 if (!ndo->ndo_vflag)
628 ND_PRINT(" hmac");
629 else {
630 unsigned j;
631 ND_PRINT("\n\tHMAC ");
632 if(len < 18) goto invalid;
633 ND_PRINT("key-id %u digest-%u ", GET_BE_U_2(message + 2),
634 len - 2);
635 for (j = 0; j < len - 2; j++)
636 ND_PRINT("%02X", GET_U_1(message + j + 4));
637 }
638 }
639 break;
640
641 case MESSAGE_UPDATE_SRC_SPECIFIC : {
642 if(!ndo->ndo_vflag) {
643 ND_PRINT(" ss-update");
644 } else {
645 u_char prefix[16], src_prefix[16];
646 u_short interval, seqno, metric;
647 u_char ae, plen, src_plen, omitted;
648 int rc;
649 int parsed_len = 10;
650 ND_PRINT("\n\tSS-Update");
651 if(len < 10) goto invalid;
652 ae = GET_U_1(message + 2);
653 src_plen = GET_U_1(message + 3);
654 plen = GET_U_1(message + 4);
655 omitted = GET_U_1(message + 5);
656 interval = GET_BE_U_2(message + 6);
657 seqno = GET_BE_U_2(message + 8);
658 metric = GET_BE_U_2(message + 10);
659 rc = network_prefix(ae, plen, omitted, message + 2 + parsed_len,
660 ae == 1 ? v4_prefix : v6_prefix,
661 len - parsed_len, prefix);
662 if(rc < 0) goto invalid;
663 if(ae == 1)
664 plen += 96;
665 parsed_len += rc;
666 rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
667 NULL, len - parsed_len, src_prefix);
668 if(rc < 0) goto invalid;
669 if(ae == 1)
670 src_plen += 96;
671 parsed_len += rc;
672
673 ND_PRINT(" %s from", format_prefix(ndo, prefix, plen));
674 ND_PRINT(" %s metric %u seqno %u interval %s",
675 format_prefix(ndo, src_prefix, src_plen),
676 metric, seqno, format_interval_update(interval));
677 /* extra data? */
678 if((u_int)parsed_len < len)
679 subtlvs_print(ndo, message + 2 + parsed_len,
680 message + 2 + len, type);
681 }
682 }
683 break;
684
685 case MESSAGE_REQUEST_SRC_SPECIFIC : {
686 if(!ndo->ndo_vflag)
687 ND_PRINT(" ss-request");
688 else {
689 int rc, parsed_len = 3;
690 u_char ae, plen, src_plen, prefix[16], src_prefix[16];
691 ND_PRINT("\n\tSS-Request ");
692 if(len < 3) goto invalid;
693 ae = GET_U_1(message + 2);
694 plen = GET_U_1(message + 3);
695 src_plen = GET_U_1(message + 4);
696 rc = network_prefix(ae, plen, 0, message + 2 + parsed_len,
697 NULL, len - parsed_len, prefix);
698 if(rc < 0) goto invalid;
699 if(ae == 1)
700 plen += 96;
701 parsed_len += rc;
702 rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
703 NULL, len - parsed_len, src_prefix);
704 if(rc < 0) goto invalid;
705 if(ae == 1)
706 src_plen += 96;
707 parsed_len += rc;
708 if(ae == 0) {
709 ND_PRINT("for any");
710 } else {
711 ND_PRINT("for (%s, ", format_prefix(ndo, prefix, plen));
712 ND_PRINT("%s)", format_prefix(ndo, src_prefix, src_plen));
713 }
714 }
715 }
716 break;
717
718 case MESSAGE_MH_REQUEST_SRC_SPECIFIC : {
719 if(!ndo->ndo_vflag)
720 ND_PRINT(" ss-mh-request");
721 else {
722 int rc, parsed_len = 14;
723 u_short seqno;
724 u_char ae, plen, src_plen, prefix[16], src_prefix[16], hopc;
725 const u_char *router_id = NULL;
726 ND_PRINT("\n\tSS-MH-Request ");
727 if(len < 14) goto invalid;
728 ae = GET_U_1(message + 2);
729 plen = GET_U_1(message + 3);
730 seqno = GET_BE_U_2(message + 4);
731 hopc = GET_U_1(message + 6);
732 src_plen = GET_U_1(message + 7);
733 router_id = message + 8;
734 rc = network_prefix(ae, plen, 0, message + 2 + parsed_len,
735 NULL, len - parsed_len, prefix);
736 if(rc < 0) goto invalid;
737 if(ae == 1)
738 plen += 96;
739 parsed_len += rc;
740 rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len,
741 NULL, len - parsed_len, src_prefix);
742 if(rc < 0) goto invalid;
743 if(ae == 1)
744 src_plen += 96;
745 ND_PRINT("(%u hops) for (%s, ",
746 hopc, format_prefix(ndo, prefix, plen));
747 ND_PRINT("%s) seqno %u id %s",
748 format_prefix(ndo, src_prefix, src_plen),
749 seqno, format_id(ndo, router_id));
750 }
751 }
752 break;
753
754 case MESSAGE_MAC: {
755 if (!ndo->ndo_vflag)
756 ND_PRINT(" mac");
757 else {
758 ND_PRINT("\n\tMAC ");
759 ND_PRINT("len %u", len);
760 }
761 }
762 break;
763
764 case MESSAGE_PC: {
765 if (!ndo->ndo_vflag)
766 ND_PRINT(" pc");
767 else {
768 ND_PRINT("\n\tPC");
769 if(len < 4) goto invalid;
770 ND_PRINT(" value %u",
771 GET_BE_U_4(message + 2));
772 ND_PRINT(" index len %u", len-4);
773 }
774 }
775 break;
776
777 case MESSAGE_CHALLENGE_REQUEST: {
778 if (!ndo->ndo_vflag)
779 ND_PRINT(" challenge_request");
780 else {
781 ND_PRINT("\n\tChallenge Request");
782 if(len > 192) goto invalid;
783 ND_PRINT(" len %u", len);
784 }
785 }
786 break;
787
788 case MESSAGE_CHALLENGE_REPLY: {
789 if (!ndo->ndo_vflag)
790 ND_PRINT(" challenge_reply");
791 else {
792 ND_PRINT("\n\tChallenge Reply");
793 if (len > 192) goto invalid;
794 ND_PRINT(" len %u", len);
795 }
796 }
797 break;
798
799 default:
800 if (!ndo->ndo_vflag)
801 ND_PRINT(" unknown");
802 else
803 ND_PRINT("\n\tUnknown message type %u", type);
804 }
805 i += len + 2;
806 }
807
808 return 0; /* OK */
809
810 trunc:
811 return -1; /* packet truncated by capture process */
812
813 invalid:
814 return -2; /* packet is invalid */
815 }
816
817 static void
babel_print_v2(netdissect_options * ndo,const u_char * cp,u_int length)818 babel_print_v2(netdissect_options *ndo,
819 const u_char *cp, u_int length)
820 {
821 u_short bodylen;
822 int ret;
823
824 ND_TCHECK_4(cp);
825 if (length < 4)
826 goto invalid;
827 bodylen = GET_BE_U_2(cp + 2);
828 ND_PRINT(" (%u)", bodylen);
829 length -= 4;
830 cp += 4;
831
832 /* Process the TLVs in the body */
833 if (length < bodylen)
834 goto invalid;
835 ret = babel_print_v2_tlvs(ndo, cp, bodylen, length);
836 if (ret == -1)
837 goto trunc;
838 if (ret == -2)
839 goto invalid;
840 length -= bodylen;
841 cp += bodylen;
842
843 /* If there's a trailer, process the TLVs in the trailer */
844 if (length != 0) {
845 if(ndo->ndo_vflag) ND_PRINT("\n\t----");
846 else ND_PRINT(" |");
847 ret = babel_print_v2_tlvs(ndo, cp, length, length);
848 if (ret == -1)
849 goto trunc;
850 if (ret == -2)
851 goto invalid;
852 }
853 return;
854
855 trunc:
856 nd_print_trunc(ndo);
857 return;
858
859 invalid:
860 nd_print_invalid(ndo);
861 }
862