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@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