Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Redistribution and use in source and binary forms, with or without
      3  * modification, are permitted provided that: (1) source code
      4  * distributions retain the above copyright notice and this paragraph
      5  * in its entirety, and (2) distributions including binary code include
      6  * the above copyright notice and this paragraph in its entirety in
      7  * the documentation or other materials provided with the distribution.
      8  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
      9  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
     10  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     11  * FOR A PARTICULAR PURPOSE.
     12  *
     13  * Original code by Hannes Gredler (hannes (at) juniper.net)
     14  */
     15 
     16 #define NETDISSECT_REWORKED
     17 #ifdef HAVE_CONFIG_H
     18 #include "config.h"
     19 #endif
     20 
     21 #include <tcpdump-stdinc.h>
     22 
     23 #include "interface.h"
     24 #include "extract.h"
     25 
     26 #include "udp.h"
     27 
     28 /*
     29  * Control packet, BFDv0, draft-katz-ward-bfd-01.txt
     30  *
     31  *     0                   1                   2                   3
     32  *     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     33  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     34  *    |Vers |  Diag   |H|D|P|F| Rsvd  |  Detect Mult  |    Length     |
     35  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     36  *    |                       My Discriminator                        |
     37  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     38  *    |                      Your Discriminator                       |
     39  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     40  *    |                    Desired Min TX Interval                    |
     41  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     42  *    |                   Required Min RX Interval                    |
     43  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     44  *    |                 Required Min Echo RX Interval                 |
     45  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     46  */
     47 
     48 /*
     49  *  Control packet, BFDv1, draft-ietf-bfd-base-02.txt
     50  *
     51  *     0                   1                   2                   3
     52  *     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     53  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     54  *    |Vers |  Diag   |Sta|P|F|C|A|D|R|  Detect Mult  |    Length     |
     55  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     56  *    |                       My Discriminator                        |
     57  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     58  *    |                      Your Discriminator                       |
     59  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     60  *    |                    Desired Min TX Interval                    |
     61  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     62  *    |                   Required Min RX Interval                    |
     63  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     64  *    |                 Required Min Echo RX Interval                 |
     65  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     66  */
     67 
     68 struct bfd_header_t {
     69     uint8_t version_diag;
     70     uint8_t flags;
     71     uint8_t detect_time_multiplier;
     72     uint8_t length;
     73     uint8_t my_discriminator[4];
     74     uint8_t your_discriminator[4];
     75     uint8_t desired_min_tx_interval[4];
     76     uint8_t required_min_rx_interval[4];
     77     uint8_t required_min_echo_interval[4];
     78 };
     79 
     80 /*
     81  *    An optional Authentication Header may be present
     82  *
     83  *     0                   1                   2                   3
     84  *     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     85  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     86  *    |   Auth Type   |   Auth Len    |    Authentication Data...     |
     87  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     88  */
     89 
     90 struct bfd_auth_header_t {
     91     uint8_t auth_type;
     92     uint8_t auth_len;
     93     uint8_t auth_data;
     94 };
     95 
     96 static const struct tok bfd_v1_authentication_values[] = {
     97     { 0,        "Reserved" },
     98     { 1,        "Simple Password" },
     99     { 2,        "Keyed MD5" },
    100     { 3,        "Meticulous Keyed MD5" },
    101     { 4,        "Keyed SHA1" },
    102     { 5,        "Meticulous Keyed SHA1" },
    103     { 0, NULL }
    104 };
    105 
    106 #define	BFD_EXTRACT_VERSION(x) (((x)&0xe0)>>5)
    107 #define	BFD_EXTRACT_DIAG(x)     ((x)&0x1f)
    108 
    109 static const struct tok bfd_port_values[] = {
    110     { BFD_CONTROL_PORT, "Control" },
    111     { BFD_ECHO_PORT,    "Echo" },
    112     { 0, NULL }
    113 };
    114 
    115 
    116 static const struct tok bfd_diag_values[] = {
    117     { 0, "No Diagnostic" },
    118     { 1, "Control Detection Time Expired" },
    119     { 2, "Echo Function Failed" },
    120     { 3, "Neighbor Signaled Session Down" },
    121     { 4, "Forwarding Plane Reset" },
    122     { 5, "Path Down" },
    123     { 6, "Concatenated Path Down" },
    124     { 7, "Administratively Down" },
    125     { 8, "Reverse Concatenated Path Down" },
    126     { 0, NULL }
    127 };
    128 
    129 static const struct tok bfd_v0_flag_values[] = {
    130     { 0x80,	"I Hear You" },
    131     { 0x40,	"Demand" },
    132     { 0x20,	"Poll" },
    133     { 0x10,	"Final" },
    134     { 0x08,	"Reserved" },
    135     { 0x04,	"Reserved" },
    136     { 0x02,	"Reserved" },
    137     { 0x01,	"Reserved" },
    138     { 0, NULL }
    139 };
    140 
    141 #define BFD_FLAG_AUTH 0x04
    142 
    143 static const struct tok bfd_v1_flag_values[] = {
    144     { 0x20, "Poll" },
    145     { 0x10, "Final" },
    146     { 0x08, "Control Plane Independent" },
    147     { BFD_FLAG_AUTH, "Authentication Present" },
    148     { 0x02, "Demand" },
    149     { 0x01, "Reserved" },
    150     { 0, NULL }
    151 };
    152 
    153 static const struct tok bfd_v1_state_values[] = {
    154     { 0, "AdminDown" },
    155     { 1, "Down" },
    156     { 2, "Init" },
    157     { 3, "Up" },
    158     { 0, NULL }
    159 };
    160 
    161 void
    162 bfd_print(netdissect_options *ndo, register const u_char *pptr,
    163           register u_int len, register u_int port)
    164 {
    165         const struct bfd_header_t *bfd_header;
    166         const struct bfd_auth_header_t *bfd_auth_header;
    167         uint8_t version = 0;
    168 
    169         bfd_header = (const struct bfd_header_t *)pptr;
    170         if (port == BFD_CONTROL_PORT) {
    171             ND_TCHECK(*bfd_header);
    172             version = BFD_EXTRACT_VERSION(bfd_header->version_diag);
    173         } else if (port == BFD_ECHO_PORT) {
    174             /* Echo is BFD v1 only */
    175             version = 1;
    176         }
    177         switch ((port << 8) | version) {
    178 
    179             /* BFDv0 */
    180         case (BFD_CONTROL_PORT << 8):
    181             if (ndo->ndo_vflag < 1)
    182             {
    183                 ND_PRINT((ndo, "BFDv%u, %s, Flags: [%s], length: %u",
    184                        version,
    185                        tok2str(bfd_port_values, "unknown (%u)", port),
    186                        bittok2str(bfd_v0_flag_values, "none", bfd_header->flags),
    187                        len));
    188                 return;
    189             }
    190 
    191             ND_PRINT((ndo, "BFDv%u, length: %u\n\t%s, Flags: [%s], Diagnostic: %s (0x%02x)",
    192                    version,
    193                    len,
    194                    tok2str(bfd_port_values, "unknown (%u)", port),
    195                    bittok2str(bfd_v0_flag_values, "none", bfd_header->flags),
    196                    tok2str(bfd_diag_values,"unknown",BFD_EXTRACT_DIAG(bfd_header->version_diag)),
    197                    BFD_EXTRACT_DIAG(bfd_header->version_diag)));
    198 
    199             ND_PRINT((ndo, "\n\tDetection Timer Multiplier: %u (%u ms Detection time), BFD Length: %u",
    200                    bfd_header->detect_time_multiplier,
    201                    bfd_header->detect_time_multiplier * EXTRACT_32BITS(bfd_header->desired_min_tx_interval)/1000,
    202                    bfd_header->length));
    203 
    204 
    205             ND_PRINT((ndo, "\n\tMy Discriminator: 0x%08x", EXTRACT_32BITS(bfd_header->my_discriminator)));
    206             ND_PRINT((ndo, ", Your Discriminator: 0x%08x", EXTRACT_32BITS(bfd_header->your_discriminator)));
    207             ND_PRINT((ndo, "\n\t  Desired min Tx Interval:    %4u ms", EXTRACT_32BITS(bfd_header->desired_min_tx_interval)/1000));
    208             ND_PRINT((ndo, "\n\t  Required min Rx Interval:   %4u ms", EXTRACT_32BITS(bfd_header->required_min_rx_interval)/1000));
    209             ND_PRINT((ndo, "\n\t  Required min Echo Interval: %4u ms", EXTRACT_32BITS(bfd_header->required_min_echo_interval)/1000));
    210             break;
    211 
    212             /* BFDv1 */
    213         case (BFD_CONTROL_PORT << 8 | 1):
    214             if (ndo->ndo_vflag < 1)
    215             {
    216                 ND_PRINT((ndo, "BFDv%u, %s, State %s, Flags: [%s], length: %u",
    217                        version,
    218                        tok2str(bfd_port_values, "unknown (%u)", port),
    219                        tok2str(bfd_v1_state_values, "unknown (%u)", (bfd_header->flags & 0xc0) >> 6),
    220                        bittok2str(bfd_v1_flag_values, "none", bfd_header->flags & 0x3f),
    221                        len));
    222                 return;
    223             }
    224 
    225             ND_PRINT((ndo, "BFDv%u, length: %u\n\t%s, State %s, Flags: [%s], Diagnostic: %s (0x%02x)",
    226                    version,
    227                    len,
    228                    tok2str(bfd_port_values, "unknown (%u)", port),
    229                    tok2str(bfd_v1_state_values, "unknown (%u)", (bfd_header->flags & 0xc0) >> 6),
    230                    bittok2str(bfd_v1_flag_values, "none", bfd_header->flags & 0x3f),
    231                    tok2str(bfd_diag_values,"unknown",BFD_EXTRACT_DIAG(bfd_header->version_diag)),
    232                    BFD_EXTRACT_DIAG(bfd_header->version_diag)));
    233 
    234             ND_PRINT((ndo, "\n\tDetection Timer Multiplier: %u (%u ms Detection time), BFD Length: %u",
    235                    bfd_header->detect_time_multiplier,
    236                    bfd_header->detect_time_multiplier * EXTRACT_32BITS(bfd_header->desired_min_tx_interval)/1000,
    237                    bfd_header->length));
    238 
    239 
    240             ND_PRINT((ndo, "\n\tMy Discriminator: 0x%08x", EXTRACT_32BITS(bfd_header->my_discriminator)));
    241             ND_PRINT((ndo, ", Your Discriminator: 0x%08x", EXTRACT_32BITS(bfd_header->your_discriminator)));
    242             ND_PRINT((ndo, "\n\t  Desired min Tx Interval:    %4u ms", EXTRACT_32BITS(bfd_header->desired_min_tx_interval)/1000));
    243             ND_PRINT((ndo, "\n\t  Required min Rx Interval:   %4u ms", EXTRACT_32BITS(bfd_header->required_min_rx_interval)/1000));
    244             ND_PRINT((ndo, "\n\t  Required min Echo Interval: %4u ms", EXTRACT_32BITS(bfd_header->required_min_echo_interval)/1000));
    245 
    246             if (bfd_header->flags & BFD_FLAG_AUTH) {
    247                 pptr += sizeof (const struct bfd_header_t);
    248                 bfd_auth_header = (const struct bfd_auth_header_t *)pptr;
    249                 ND_TCHECK2(*bfd_auth_header, sizeof(const struct bfd_auth_header_t));
    250                 ND_PRINT((ndo, "\n\t%s (%u) Authentication, length %u present",
    251                        tok2str(bfd_v1_authentication_values,"Unknown",bfd_auth_header->auth_type),
    252                        bfd_auth_header->auth_type,
    253                        bfd_auth_header->auth_len));
    254             }
    255             break;
    256 
    257             /* BFDv0 */
    258         case (BFD_ECHO_PORT << 8): /* not yet supported - fall through */
    259             /* BFDv1 */
    260         case (BFD_ECHO_PORT << 8 | 1):
    261 
    262         default:
    263             ND_PRINT((ndo, "BFD, %s, length: %u",
    264                    tok2str(bfd_port_values, "unknown (%u)", port),
    265                    len));
    266             if (ndo->ndo_vflag >= 1) {
    267                     if(!print_unknown_data(ndo, pptr,"\n\t",len))
    268                             return;
    269             }
    270             break;
    271         }
    272         return;
    273 
    274 trunc:
    275         ND_PRINT((ndo, "[|BFD]"));
    276 }
    277 /*
    278  * Local Variables:
    279  * c-style: whitesmith
    280  * c-basic-offset: 8
    281  * End:
    282  */
    283