Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (c) 2007-2011 Grgoire 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 #define NETDISSECT_REWORKED
     30 #ifdef HAVE_CONFIG_H
     31 #include "config.h"
     32 #endif
     33 
     34 #include <tcpdump-stdinc.h>
     35 
     36 #include <stdio.h>
     37 #include <string.h>
     38 
     39 #include "interface.h"
     40 #include "addrtoname.h"
     41 #include "extract.h"
     42 
     43 static const char tstr[] = "[|babel]";
     44 
     45 static void babel_print_v2(netdissect_options *, const u_char *cp, u_int length);
     46 
     47 void
     48 babel_print(netdissect_options *ndo,
     49             const u_char *cp, u_int length)
     50 {
     51     ND_PRINT((ndo, "babel"));
     52 
     53     ND_TCHECK2(*cp, 4);
     54 
     55     if(cp[0] != 42) {
     56         ND_PRINT((ndo, " malformed header"));
     57         return;
     58     } else {
     59         ND_PRINT((ndo, " %d", cp[1]));
     60     }
     61 
     62     switch(cp[1]) {
     63     case 2:
     64         babel_print_v2(ndo, cp, length);
     65         break;
     66     default:
     67         ND_PRINT((ndo, " unknown version"));
     68         break;
     69     }
     70 
     71     return;
     72 
     73  trunc:
     74     ND_PRINT((ndo, " %s", tstr));
     75     return;
     76 }
     77 
     78 /* TLVs */
     79 #define MESSAGE_PAD1 0
     80 #define MESSAGE_PADN 1
     81 #define MESSAGE_ACK_REQ 2
     82 #define MESSAGE_ACK 3
     83 #define MESSAGE_HELLO 4
     84 #define MESSAGE_IHU 5
     85 #define MESSAGE_ROUTER_ID 6
     86 #define MESSAGE_NH 7
     87 #define MESSAGE_UPDATE 8
     88 #define MESSAGE_REQUEST 9
     89 #define MESSAGE_MH_REQUEST 10
     90 #define MESSAGE_TSPC 11
     91 #define MESSAGE_HMAC 12
     92 
     93 /* sub-TLVs */
     94 #define MESSAGE_SUB_PAD1 0
     95 #define MESSAGE_SUB_PADN 1
     96 #define MESSAGE_SUB_DIVERSITY 2
     97 #define MESSAGE_SUB_TIMESTAMP 3
     98 
     99 /* Diversity sub-TLV channel codes */
    100 static const struct tok diversity_str[] = {
    101     { 0,   "reserved" },
    102     { 255, "all"      },
    103     { 0, NULL }
    104 };
    105 
    106 static const char *
    107 format_id(const u_char *id)
    108 {
    109     static char buf[25];
    110     snprintf(buf, 25, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
    111              id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7]);
    112     buf[24] = '\0';
    113     return buf;
    114 }
    115 
    116 static const unsigned char v4prefix[16] =
    117     {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
    118 
    119 static const char *
    120 format_prefix(netdissect_options *ndo, const u_char *prefix, unsigned char plen)
    121 {
    122     static char buf[50];
    123     if(plen >= 96 && memcmp(prefix, v4prefix, 12) == 0)
    124         snprintf(buf, 50, "%s/%u", ipaddr_string(ndo, prefix + 12), plen - 96);
    125     else
    126 #ifdef INET6
    127         snprintf(buf, 50, "%s/%u", ip6addr_string(ndo, prefix), plen);
    128 #else
    129         snprintf(buf, 50, "IPv6 addresses not supported");
    130 #endif
    131     buf[49] = '\0';
    132     return buf;
    133 }
    134 
    135 static const char *
    136 format_address(netdissect_options *ndo, const u_char *prefix)
    137 {
    138     if(memcmp(prefix, v4prefix, 12) == 0)
    139         return ipaddr_string(ndo, prefix + 12);
    140     else
    141 #ifdef INET6
    142         return ip6addr_string(ndo, prefix);
    143 #else
    144         return "IPv6 addresses not supported";
    145 #endif
    146 }
    147 
    148 static const char *
    149 format_interval(const uint16_t i)
    150 {
    151     static char buf[sizeof("000.00s")];
    152 
    153     if (i == 0)
    154         return "0.0s (bogus)";
    155     snprintf(buf, sizeof(buf), "%u.%02us", i / 100, i % 100);
    156     return buf;
    157 }
    158 
    159 static const char *
    160 format_interval_update(const uint16_t i)
    161 {
    162     return i == 0xFFFF ? "infinity" : format_interval(i);
    163 }
    164 
    165 static const char *
    166 format_timestamp(const uint32_t i)
    167 {
    168     static char buf[sizeof("0000.000000s")];
    169     snprintf(buf, sizeof(buf), "%u.%06us", i / 1000000, i % 1000000);
    170     return buf;
    171 }
    172 
    173 /* Return number of octets consumed from the input buffer (not the prefix length
    174  * in bytes), or -1 for encoding error. */
    175 static int
    176 network_prefix(int ae, int plen, unsigned int omitted,
    177                const unsigned char *p, const unsigned char *dp,
    178                unsigned int len, unsigned char *p_r)
    179 {
    180     unsigned pb;
    181     unsigned char prefix[16];
    182     int consumed = 0;
    183 
    184     if(plen >= 0)
    185         pb = (plen + 7) / 8;
    186     else if(ae == 1)
    187         pb = 4;
    188     else
    189         pb = 16;
    190 
    191     if(pb > 16)
    192         return -1;
    193 
    194     memset(prefix, 0, 16);
    195 
    196     switch(ae) {
    197     case 0: break;
    198     case 1:
    199         if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted))
    200             return -1;
    201         memcpy(prefix, v4prefix, 12);
    202         if(omitted) {
    203             if (dp == NULL) return -1;
    204             memcpy(prefix, dp, 12 + omitted);
    205         }
    206         if(pb > omitted) {
    207             memcpy(prefix + 12 + omitted, p, pb - omitted);
    208             consumed = pb - omitted;
    209         }
    210         break;
    211     case 2:
    212         if(omitted > 16 || (pb > omitted && len < pb - omitted))
    213             return -1;
    214         if(omitted) {
    215             if (dp == NULL) return -1;
    216             memcpy(prefix, dp, omitted);
    217         }
    218         if(pb > omitted) {
    219             memcpy(prefix + omitted, p, pb - omitted);
    220             consumed = pb - omitted;
    221         }
    222         break;
    223     case 3:
    224         if(pb > 8 && len < pb - 8) return -1;
    225         prefix[0] = 0xfe;
    226         prefix[1] = 0x80;
    227         if(pb > 8) {
    228             memcpy(prefix + 8, p, pb - 8);
    229             consumed = pb - 8;
    230         }
    231         break;
    232     default:
    233         return -1;
    234     }
    235 
    236     memcpy(p_r, prefix, 16);
    237     return consumed;
    238 }
    239 
    240 static int
    241 network_address(int ae, const unsigned char *a, unsigned int len,
    242                 unsigned char *a_r)
    243 {
    244     return network_prefix(ae, -1, 0, a, NULL, len, a_r);
    245 }
    246 
    247 /*
    248  * Sub-TLVs consume the "extra data" of Babel TLVs (see Section 4.3 of RFC6126),
    249  * their encoding is similar to the encoding of TLVs, but the type namespace is
    250  * different:
    251  *
    252  * o Type 0 stands for Pad1 sub-TLV with the same encoding as the Pad1 TLV.
    253  * o Type 1 stands for PadN sub-TLV with the same encoding as the PadN TLV.
    254  * o Type 2 stands for Diversity sub-TLV, which propagates diversity routing
    255  *   data. Its body is a variable-length sequence of 8-bit unsigned integers,
    256  *   each representing per-hop number of interferring radio channel for the
    257  *   prefix. Channel 0 is invalid and must not be used in the sub-TLV, channel
    258  *   255 interferes with any other channel.
    259  * o Type 3 stands for Timestamp sub-TLV, used to compute RTT between
    260  *   neighbours. In the case of a Hello TLV, the body stores a 32-bits
    261  *   timestamp, while in the case of a IHU TLV, two 32-bits timestamps are
    262  *   stored.
    263  *
    264  * Sub-TLV types 0 and 1 are valid for any TLV type, whether sub-TLV type 2 is
    265  * only valid for TLV type 8 (Update). Note that within an Update TLV a missing
    266  * Diversity sub-TLV is not the same as a Diversity sub-TLV with an empty body.
    267  * The former would mean a lack of any claims about the interference, and the
    268  * latter would state that interference is definitely absent.
    269  * A type 3 sub-TLV is valid both for Hello and IHU TLVs, though the exact
    270  * semantic of the sub-TLV is different in each case.
    271  */
    272 static void
    273 subtlvs_print(netdissect_options *ndo,
    274               const u_char *cp, const u_char *ep, const uint8_t tlv_type)
    275 {
    276     uint8_t subtype, sublen;
    277     const char *sep;
    278     uint32_t t1, t2;
    279 
    280     while (cp < ep) {
    281         subtype = *cp++;
    282         if(subtype == MESSAGE_SUB_PAD1) {
    283             ND_PRINT((ndo, " sub-pad1"));
    284             continue;
    285         }
    286         if(cp == ep)
    287             goto corrupt;
    288         sublen = *cp++;
    289         if(cp + sublen > ep)
    290             goto corrupt;
    291 
    292         switch(subtype) {
    293         case MESSAGE_SUB_PADN:
    294             ND_PRINT((ndo, " sub-padn"));
    295             cp += sublen;
    296             break;
    297         case MESSAGE_SUB_DIVERSITY:
    298             ND_PRINT((ndo, " sub-diversity"));
    299             if (sublen == 0) {
    300                 ND_PRINT((ndo, " empty"));
    301                 break;
    302             }
    303             sep = " ";
    304             while(sublen--) {
    305                 ND_PRINT((ndo, "%s%s", sep, tok2str(diversity_str, "%u", *cp++)));
    306                 sep = "-";
    307             }
    308             if(tlv_type != MESSAGE_UPDATE)
    309                 ND_PRINT((ndo, " (bogus)"));
    310             break;
    311         case MESSAGE_SUB_TIMESTAMP:
    312             ND_PRINT((ndo, " sub-timestamp"));
    313             if(tlv_type == MESSAGE_HELLO) {
    314                 if(sublen < 4)
    315                     goto corrupt;
    316                 t1 = EXTRACT_32BITS(cp);
    317                 ND_PRINT((ndo, " %s", format_timestamp(t1)));
    318             } else if(tlv_type == MESSAGE_IHU) {
    319                 if(sublen < 8)
    320                     goto corrupt;
    321                 t1 = EXTRACT_32BITS(cp);
    322                 ND_PRINT((ndo, " %s", format_timestamp(t1)));
    323                 t2 = EXTRACT_32BITS(cp + 4);
    324                 ND_PRINT((ndo, "|%s", format_timestamp(t2)));
    325             } else
    326                 ND_PRINT((ndo, " (bogus)"));
    327             cp += sublen;
    328             break;
    329         default:
    330             ND_PRINT((ndo, " sub-unknown-0x%02x", subtype));
    331             cp += sublen;
    332         } /* switch */
    333     } /* while */
    334     return;
    335 
    336  corrupt:
    337     ND_PRINT((ndo, " (corrupt)"));
    338 }
    339 
    340 #define ICHECK(i, l) \
    341 	if ((i) + (l) > bodylen || (i) + (l) > length) goto corrupt;
    342 
    343 static void
    344 babel_print_v2(netdissect_options *ndo,
    345                const u_char *cp, u_int length)
    346 {
    347     u_int i;
    348     u_short bodylen;
    349     u_char v4_prefix[16] =
    350         {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 };
    351     u_char v6_prefix[16] = {0};
    352 
    353     ND_TCHECK2(*cp, 4);
    354     if (length < 4)
    355         goto corrupt;
    356     bodylen = EXTRACT_16BITS(cp + 2);
    357     ND_PRINT((ndo, " (%u)", bodylen));
    358 
    359     /* Process the TLVs in the body */
    360     i = 0;
    361     while(i < bodylen) {
    362         const u_char *message;
    363         u_int type, len;
    364 
    365         message = cp + 4 + i;
    366 
    367         ND_TCHECK2(*message, 1);
    368         if((type = message[0]) == MESSAGE_PAD1) {
    369             ND_PRINT((ndo, ndo->ndo_vflag ? "\n\tPad 1" : " pad1"));
    370             i += 1;
    371             continue;
    372         }
    373 
    374         ND_TCHECK2(*message, 2);
    375         ICHECK(i, 2);
    376         len = message[1];
    377 
    378         ND_TCHECK2(*message, 2 + len);
    379         ICHECK(i, 2 + len);
    380 
    381         switch(type) {
    382         case MESSAGE_PADN: {
    383             if (!ndo->ndo_vflag)
    384                 ND_PRINT((ndo, " padN"));
    385             else
    386                 ND_PRINT((ndo, "\n\tPad %d", len + 2));
    387         }
    388             break;
    389 
    390         case MESSAGE_ACK_REQ: {
    391             u_short nonce, interval;
    392             if (!ndo->ndo_vflag)
    393                 ND_PRINT((ndo, " ack-req"));
    394             else {
    395                 ND_PRINT((ndo, "\n\tAcknowledgment Request "));
    396                 if(len < 6) goto corrupt;
    397                 nonce = EXTRACT_16BITS(message + 4);
    398                 interval = EXTRACT_16BITS(message + 6);
    399                 ND_PRINT((ndo, "%04x %s", nonce, format_interval(interval)));
    400             }
    401         }
    402             break;
    403 
    404         case MESSAGE_ACK: {
    405             u_short nonce;
    406             if (!ndo->ndo_vflag)
    407                 ND_PRINT((ndo, " ack"));
    408             else {
    409                 ND_PRINT((ndo, "\n\tAcknowledgment "));
    410                 if(len < 2) goto corrupt;
    411                 nonce = EXTRACT_16BITS(message + 2);
    412                 ND_PRINT((ndo, "%04x", nonce));
    413             }
    414         }
    415             break;
    416 
    417         case MESSAGE_HELLO:  {
    418             u_short seqno, interval;
    419             if (!ndo->ndo_vflag)
    420                 ND_PRINT((ndo, " hello"));
    421             else {
    422                 ND_PRINT((ndo, "\n\tHello "));
    423                 if(len < 6) goto corrupt;
    424                 seqno = EXTRACT_16BITS(message + 4);
    425                 interval = EXTRACT_16BITS(message + 6);
    426                 ND_PRINT((ndo, "seqno %u interval %s", seqno, format_interval(interval)));
    427                 /* Extra data. */
    428                 if(len > 6)
    429                     subtlvs_print(ndo, message + 8, message + 2 + len, type);
    430             }
    431         }
    432             break;
    433 
    434         case MESSAGE_IHU: {
    435             unsigned short txcost, interval;
    436             if (!ndo->ndo_vflag)
    437                 ND_PRINT((ndo, " ihu"));
    438             else {
    439                 u_char address[16];
    440                 int rc;
    441                 ND_PRINT((ndo, "\n\tIHU "));
    442                 if(len < 6) goto corrupt;
    443                 txcost = EXTRACT_16BITS(message + 4);
    444                 interval = EXTRACT_16BITS(message + 6);
    445                 rc = network_address(message[2], message + 8, len - 6, address);
    446                 if(rc < 0) { ND_PRINT((ndo, "%s", tstr)); break; }
    447                 ND_PRINT((ndo, "%s txcost %u interval %s",
    448                        format_address(ndo, address), txcost, format_interval(interval)));
    449                 /* Extra data. */
    450                 if((u_int)rc < len - 6)
    451                     subtlvs_print(ndo, message + 8 + rc, message + 2 + len,
    452                                   type);
    453             }
    454         }
    455             break;
    456 
    457         case MESSAGE_ROUTER_ID: {
    458             if (!ndo->ndo_vflag)
    459                 ND_PRINT((ndo, " router-id"));
    460             else {
    461                 ND_PRINT((ndo, "\n\tRouter Id"));
    462                 if(len < 10) goto corrupt;
    463                 ND_PRINT((ndo, " %s", format_id(message + 4)));
    464             }
    465         }
    466             break;
    467 
    468         case MESSAGE_NH: {
    469             if (!ndo->ndo_vflag)
    470                 ND_PRINT((ndo, " nh"));
    471             else {
    472                 int rc;
    473                 u_char nh[16];
    474                 ND_PRINT((ndo, "\n\tNext Hop"));
    475                 if(len < 2) goto corrupt;
    476                 rc = network_address(message[2], message + 4, len - 2, nh);
    477                 if(rc < 0) goto corrupt;
    478                 ND_PRINT((ndo, " %s", format_address(ndo, nh)));
    479             }
    480         }
    481             break;
    482 
    483         case MESSAGE_UPDATE: {
    484             if (!ndo->ndo_vflag) {
    485                 ND_PRINT((ndo, " update"));
    486                 if(len < 1)
    487                     ND_PRINT((ndo, "/truncated"));
    488                 else
    489                     ND_PRINT((ndo, "%s%s%s",
    490                            (message[3] & 0x80) ? "/prefix": "",
    491                            (message[3] & 0x40) ? "/id" : "",
    492                            (message[3] & 0x3f) ? "/unknown" : ""));
    493             } else {
    494                 u_short interval, seqno, metric;
    495                 u_char plen;
    496                 int rc;
    497                 u_char prefix[16];
    498                 ND_PRINT((ndo, "\n\tUpdate"));
    499                 if(len < 10) goto corrupt;
    500                 plen = message[4] + (message[2] == 1 ? 96 : 0);
    501                 rc = network_prefix(message[2], message[4], message[5],
    502                                     message + 12,
    503                                     message[2] == 1 ? v4_prefix : v6_prefix,
    504                                     len - 10, prefix);
    505                 if(rc < 0) goto corrupt;
    506                 interval = EXTRACT_16BITS(message + 6);
    507                 seqno = EXTRACT_16BITS(message + 8);
    508                 metric = EXTRACT_16BITS(message + 10);
    509                 ND_PRINT((ndo, "%s%s%s %s metric %u seqno %u interval %s",
    510                        (message[3] & 0x80) ? "/prefix": "",
    511                        (message[3] & 0x40) ? "/id" : "",
    512                        (message[3] & 0x3f) ? "/unknown" : "",
    513                        format_prefix(ndo, prefix, plen),
    514                        metric, seqno, format_interval_update(interval)));
    515                 if(message[3] & 0x80) {
    516                     if(message[2] == 1)
    517                         memcpy(v4_prefix, prefix, 16);
    518                     else
    519                         memcpy(v6_prefix, prefix, 16);
    520                 }
    521                 /* extra data? */
    522                 if((u_int)rc < len - 10)
    523                     subtlvs_print(ndo, message + 12 + rc, message + 2 + len, type);
    524             }
    525         }
    526             break;
    527 
    528         case MESSAGE_REQUEST: {
    529             if (!ndo->ndo_vflag)
    530                 ND_PRINT((ndo, " request"));
    531             else {
    532                 int rc;
    533                 u_char prefix[16], plen;
    534                 ND_PRINT((ndo, "\n\tRequest "));
    535                 if(len < 2) goto corrupt;
    536                 plen = message[3] + (message[2] == 1 ? 96 : 0);
    537                 rc = network_prefix(message[2], message[3], 0,
    538                                     message + 4, NULL, len - 2, prefix);
    539                 if(rc < 0) goto corrupt;
    540                 ND_PRINT((ndo, "for %s",
    541                        message[2] == 0 ? "any" : format_prefix(ndo, prefix, plen)));
    542             }
    543         }
    544             break;
    545 
    546         case MESSAGE_MH_REQUEST : {
    547             if (!ndo->ndo_vflag)
    548                 ND_PRINT((ndo, " mh-request"));
    549             else {
    550                 int rc;
    551                 u_short seqno;
    552                 u_char prefix[16], plen;
    553                 ND_PRINT((ndo, "\n\tMH-Request "));
    554                 if(len < 14) goto corrupt;
    555                 seqno = EXTRACT_16BITS(message + 4);
    556                 rc = network_prefix(message[2], message[3], 0,
    557                                     message + 16, NULL, len - 14, prefix);
    558                 if(rc < 0) goto corrupt;
    559                 plen = message[3] + (message[2] == 1 ? 96 : 0);
    560                 ND_PRINT((ndo, "(%u hops) for %s seqno %u id %s",
    561                        message[6], format_prefix(ndo, prefix, plen),
    562                        seqno, format_id(message + 8)));
    563             }
    564         }
    565             break;
    566         case MESSAGE_TSPC :
    567             if (!ndo->ndo_vflag)
    568                 ND_PRINT((ndo, " tspc"));
    569             else {
    570                 ND_PRINT((ndo, "\n\tTS/PC "));
    571                 if(len < 6) goto corrupt;
    572                 ND_PRINT((ndo, "timestamp %u packetcounter %u", EXTRACT_32BITS (message + 4),
    573                        EXTRACT_16BITS(message + 2)));
    574             }
    575             break;
    576         case MESSAGE_HMAC : {
    577             if (!ndo->ndo_vflag)
    578                 ND_PRINT((ndo, " hmac"));
    579             else {
    580                 unsigned j;
    581                 ND_PRINT((ndo, "\n\tHMAC "));
    582                 if(len < 18) goto corrupt;
    583                 ND_PRINT((ndo, "key-id %u digest-%u ", EXTRACT_16BITS(message + 2), len - 2));
    584                 for (j = 0; j < len - 2; j++)
    585                     ND_PRINT((ndo, "%02X", message[4 + j]));
    586             }
    587         }
    588             break;
    589         default:
    590             if (!ndo->ndo_vflag)
    591                 ND_PRINT((ndo, " unknown"));
    592             else
    593                 ND_PRINT((ndo, "\n\tUnknown message type %d", type));
    594         }
    595         i += len + 2;
    596     }
    597     return;
    598 
    599  trunc:
    600     ND_PRINT((ndo, " %s", tstr));
    601     return;
    602 
    603  corrupt:
    604     ND_PRINT((ndo, " (corrupt)"));
    605     return;
    606 }
    607