1 /* 2 * Copyright (c) 1998-2004 Hannes Gredler <hannes@tcpdump.org> 3 * The TCPDUMP project 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code 7 * distributions retain the above copyright notice and this paragraph 8 * in its entirety, and (2) distributions including binary code include 9 * the above copyright notice and this paragraph in its entirety in 10 * the documentation or other materials provided with the distribution. 11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 12 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 13 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 14 * FOR A PARTICULAR PURPOSE. 15 */ 16 17 #include <sys/cdefs.h> 18 #ifndef lint 19 __RCSID("$NetBSD: print-eigrp.c,v 1.6 2015/03/31 21:59:35 christos Exp $"); 20 #endif 21 22 #define NETDISSECT_REWORKED 23 #ifdef HAVE_CONFIG_H 24 #include "config.h" 25 #endif 26 27 #include <tcpdump-stdinc.h> 28 29 #include <string.h> 30 31 #include "interface.h" 32 #include "extract.h" 33 #include "addrtoname.h" 34 35 /* 36 * packet format documented at 37 * http://www.rhyshaden.com/eigrp.htm 38 */ 39 40 struct eigrp_common_header { 41 uint8_t version; 42 uint8_t opcode; 43 uint8_t checksum[2]; 44 uint8_t flags[4]; 45 uint8_t seq[4]; 46 uint8_t ack[4]; 47 uint8_t asn[4]; 48 }; 49 50 #define EIGRP_VERSION 2 51 52 #define EIGRP_OPCODE_UPDATE 1 53 #define EIGRP_OPCODE_QUERY 3 54 #define EIGRP_OPCODE_REPLY 4 55 #define EIGRP_OPCODE_HELLO 5 56 #define EIGRP_OPCODE_IPXSAP 6 57 #define EIGRP_OPCODE_PROBE 7 58 59 static const struct tok eigrp_opcode_values[] = { 60 { EIGRP_OPCODE_UPDATE, "Update" }, 61 { EIGRP_OPCODE_QUERY, "Query" }, 62 { EIGRP_OPCODE_REPLY, "Reply" }, 63 { EIGRP_OPCODE_HELLO, "Hello" }, 64 { EIGRP_OPCODE_IPXSAP, "IPX SAP" }, 65 { EIGRP_OPCODE_PROBE, "Probe" }, 66 { 0, NULL} 67 }; 68 69 static const struct tok eigrp_common_header_flag_values[] = { 70 { 0x01, "Init" }, 71 { 0x02, "Conditionally Received" }, 72 { 0, NULL} 73 }; 74 75 struct eigrp_tlv_header { 76 uint8_t type[2]; 77 uint8_t length[2]; 78 }; 79 80 #define EIGRP_TLV_GENERAL_PARM 0x0001 81 #define EIGRP_TLV_AUTH 0x0002 82 #define EIGRP_TLV_SEQ 0x0003 83 #define EIGRP_TLV_SW_VERSION 0x0004 84 #define EIGRP_TLV_MCAST_SEQ 0x0005 85 #define EIGRP_TLV_IP_INT 0x0102 86 #define EIGRP_TLV_IP_EXT 0x0103 87 #define EIGRP_TLV_AT_INT 0x0202 88 #define EIGRP_TLV_AT_EXT 0x0203 89 #define EIGRP_TLV_AT_CABLE_SETUP 0x0204 90 #define EIGRP_TLV_IPX_INT 0x0302 91 #define EIGRP_TLV_IPX_EXT 0x0303 92 93 static const struct tok eigrp_tlv_values[] = { 94 { EIGRP_TLV_GENERAL_PARM, "General Parameters"}, 95 { EIGRP_TLV_AUTH, "Authentication"}, 96 { EIGRP_TLV_SEQ, "Sequence"}, 97 { EIGRP_TLV_SW_VERSION, "Software Version"}, 98 { EIGRP_TLV_MCAST_SEQ, "Next Multicast Sequence"}, 99 { EIGRP_TLV_IP_INT, "IP Internal routes"}, 100 { EIGRP_TLV_IP_EXT, "IP External routes"}, 101 { EIGRP_TLV_AT_INT, "AppleTalk Internal routes"}, 102 { EIGRP_TLV_AT_EXT, "AppleTalk External routes"}, 103 { EIGRP_TLV_AT_CABLE_SETUP, "AppleTalk Cable setup"}, 104 { EIGRP_TLV_IPX_INT, "IPX Internal routes"}, 105 { EIGRP_TLV_IPX_EXT, "IPX External routes"}, 106 { 0, NULL} 107 }; 108 109 struct eigrp_tlv_general_parm_t { 110 uint8_t k1; 111 uint8_t k2; 112 uint8_t k3; 113 uint8_t k4; 114 uint8_t k5; 115 uint8_t res; 116 uint8_t holdtime[2]; 117 }; 118 119 struct eigrp_tlv_sw_version_t { 120 uint8_t ios_major; 121 uint8_t ios_minor; 122 uint8_t eigrp_major; 123 uint8_t eigrp_minor; 124 }; 125 126 struct eigrp_tlv_ip_int_t { 127 uint8_t nexthop[4]; 128 uint8_t delay[4]; 129 uint8_t bandwidth[4]; 130 uint8_t mtu[3]; 131 uint8_t hopcount; 132 uint8_t reliability; 133 uint8_t load; 134 uint8_t reserved[2]; 135 uint8_t plen; 136 uint8_t destination; /* variable length [1-4] bytes encoding */ 137 }; 138 139 struct eigrp_tlv_ip_ext_t { 140 uint8_t nexthop[4]; 141 uint8_t origin_router[4]; 142 uint8_t origin_as[4]; 143 uint8_t tag[4]; 144 uint8_t metric[4]; 145 uint8_t reserved[2]; 146 uint8_t proto_id; 147 uint8_t flags; 148 uint8_t delay[4]; 149 uint8_t bandwidth[4]; 150 uint8_t mtu[3]; 151 uint8_t hopcount; 152 uint8_t reliability; 153 uint8_t load; 154 uint8_t reserved2[2]; 155 uint8_t plen; 156 uint8_t destination; /* variable length [1-4] bytes encoding */ 157 }; 158 159 struct eigrp_tlv_at_cable_setup_t { 160 uint8_t cable_start[2]; 161 uint8_t cable_end[2]; 162 uint8_t router_id[4]; 163 }; 164 165 struct eigrp_tlv_at_int_t { 166 uint8_t nexthop[4]; 167 uint8_t delay[4]; 168 uint8_t bandwidth[4]; 169 uint8_t mtu[3]; 170 uint8_t hopcount; 171 uint8_t reliability; 172 uint8_t load; 173 uint8_t reserved[2]; 174 uint8_t cable_start[2]; 175 uint8_t cable_end[2]; 176 }; 177 178 struct eigrp_tlv_at_ext_t { 179 uint8_t nexthop[4]; 180 uint8_t origin_router[4]; 181 uint8_t origin_as[4]; 182 uint8_t tag[4]; 183 uint8_t proto_id; 184 uint8_t flags; 185 uint8_t metric[2]; 186 uint8_t delay[4]; 187 uint8_t bandwidth[4]; 188 uint8_t mtu[3]; 189 uint8_t hopcount; 190 uint8_t reliability; 191 uint8_t load; 192 uint8_t reserved2[2]; 193 uint8_t cable_start[2]; 194 uint8_t cable_end[2]; 195 }; 196 197 static const struct tok eigrp_ext_proto_id_values[] = { 198 { 0x01, "IGRP" }, 199 { 0x02, "EIGRP" }, 200 { 0x03, "Static" }, 201 { 0x04, "RIP" }, 202 { 0x05, "Hello" }, 203 { 0x06, "OSPF" }, 204 { 0x07, "IS-IS" }, 205 { 0x08, "EGP" }, 206 { 0x09, "BGP" }, 207 { 0x0a, "IDRP" }, 208 { 0x0b, "Connected" }, 209 { 0, NULL} 210 }; 211 212 void 213 eigrp_print(netdissect_options *ndo, register const u_char *pptr, register u_int len) 214 { 215 const struct eigrp_common_header *eigrp_com_header; 216 const struct eigrp_tlv_header *eigrp_tlv_header; 217 const u_char *tptr,*tlv_tptr; 218 u_int tlen,eigrp_tlv_len,eigrp_tlv_type,tlv_tlen, byte_length, bit_length; 219 uint8_t prefix[4]; 220 221 union { 222 const struct eigrp_tlv_general_parm_t *eigrp_tlv_general_parm; 223 const struct eigrp_tlv_sw_version_t *eigrp_tlv_sw_version; 224 const struct eigrp_tlv_ip_int_t *eigrp_tlv_ip_int; 225 const struct eigrp_tlv_ip_ext_t *eigrp_tlv_ip_ext; 226 const struct eigrp_tlv_at_cable_setup_t *eigrp_tlv_at_cable_setup; 227 const struct eigrp_tlv_at_int_t *eigrp_tlv_at_int; 228 const struct eigrp_tlv_at_ext_t *eigrp_tlv_at_ext; 229 } tlv_ptr; 230 231 tptr=pptr; 232 eigrp_com_header = (const struct eigrp_common_header *)pptr; 233 ND_TCHECK(*eigrp_com_header); 234 235 /* 236 * Sanity checking of the header. 237 */ 238 if (eigrp_com_header->version != EIGRP_VERSION) { 239 ND_PRINT((ndo, "EIGRP version %u packet not supported",eigrp_com_header->version)); 240 return; 241 } 242 243 /* in non-verbose mode just lets print the basic Message Type*/ 244 if (ndo->ndo_vflag < 1) { 245 ND_PRINT((ndo, "EIGRP %s, length: %u", 246 tok2str(eigrp_opcode_values, "unknown (%u)",eigrp_com_header->opcode), 247 len)); 248 return; 249 } 250 251 /* ok they seem to want to know everything - lets fully decode it */ 252 253 tlen=len-sizeof(struct eigrp_common_header); 254 255 /* FIXME print other header info */ 256 ND_PRINT((ndo, "\n\tEIGRP v%u, opcode: %s (%u), chksum: 0x%04x, Flags: [%s]\n\tseq: 0x%08x, ack: 0x%08x, AS: %u, length: %u", 257 eigrp_com_header->version, 258 tok2str(eigrp_opcode_values, "unknown, type: %u",eigrp_com_header->opcode), 259 eigrp_com_header->opcode, 260 EXTRACT_16BITS(&eigrp_com_header->checksum), 261 tok2str(eigrp_common_header_flag_values, 262 "none", 263 EXTRACT_32BITS(&eigrp_com_header->flags)), 264 EXTRACT_32BITS(&eigrp_com_header->seq), 265 EXTRACT_32BITS(&eigrp_com_header->ack), 266 EXTRACT_32BITS(&eigrp_com_header->asn), 267 tlen)); 268 269 tptr+=sizeof(const struct eigrp_common_header); 270 271 while(tlen>0) { 272 /* did we capture enough for fully decoding the object header ? */ 273 ND_TCHECK2(*tptr, sizeof(struct eigrp_tlv_header)); 274 275 eigrp_tlv_header = (const struct eigrp_tlv_header *)tptr; 276 eigrp_tlv_len=EXTRACT_16BITS(&eigrp_tlv_header->length); 277 eigrp_tlv_type=EXTRACT_16BITS(&eigrp_tlv_header->type); 278 279 280 if (eigrp_tlv_len < sizeof(struct eigrp_tlv_header) || 281 eigrp_tlv_len > tlen) { 282 print_unknown_data(ndo,tptr+sizeof(struct eigrp_tlv_header),"\n\t ",tlen); 283 return; 284 } 285 286 ND_PRINT((ndo, "\n\t %s TLV (0x%04x), length: %u", 287 tok2str(eigrp_tlv_values, 288 "Unknown", 289 eigrp_tlv_type), 290 eigrp_tlv_type, 291 eigrp_tlv_len)); 292 293 tlv_tptr=tptr+sizeof(struct eigrp_tlv_header); 294 tlv_tlen=eigrp_tlv_len-sizeof(struct eigrp_tlv_header); 295 296 /* did we capture enough for fully decoding the object ? */ 297 ND_TCHECK2(*tptr, eigrp_tlv_len); 298 299 switch(eigrp_tlv_type) { 300 301 case EIGRP_TLV_GENERAL_PARM: 302 tlv_ptr.eigrp_tlv_general_parm = (const struct eigrp_tlv_general_parm_t *)tlv_tptr; 303 304 ND_PRINT((ndo, "\n\t holdtime: %us, k1 %u, k2 %u, k3 %u, k4 %u, k5 %u", 305 EXTRACT_16BITS(tlv_ptr.eigrp_tlv_general_parm->holdtime), 306 tlv_ptr.eigrp_tlv_general_parm->k1, 307 tlv_ptr.eigrp_tlv_general_parm->k2, 308 tlv_ptr.eigrp_tlv_general_parm->k3, 309 tlv_ptr.eigrp_tlv_general_parm->k4, 310 tlv_ptr.eigrp_tlv_general_parm->k5)); 311 break; 312 313 case EIGRP_TLV_SW_VERSION: 314 tlv_ptr.eigrp_tlv_sw_version = (const struct eigrp_tlv_sw_version_t *)tlv_tptr; 315 316 ND_PRINT((ndo, "\n\t IOS version: %u.%u, EIGRP version %u.%u", 317 tlv_ptr.eigrp_tlv_sw_version->ios_major, 318 tlv_ptr.eigrp_tlv_sw_version->ios_minor, 319 tlv_ptr.eigrp_tlv_sw_version->eigrp_major, 320 tlv_ptr.eigrp_tlv_sw_version->eigrp_minor)); 321 break; 322 323 case EIGRP_TLV_IP_INT: 324 tlv_ptr.eigrp_tlv_ip_int = (const struct eigrp_tlv_ip_int_t *)tlv_tptr; 325 326 bit_length = tlv_ptr.eigrp_tlv_ip_int->plen; 327 if (bit_length > 32) { 328 ND_PRINT((ndo, "\n\t illegal prefix length %u",bit_length)); 329 break; 330 } 331 byte_length = (bit_length + 7) / 8; /* variable length encoding */ 332 memset(prefix, 0, 4); 333 memcpy(prefix,&tlv_ptr.eigrp_tlv_ip_int->destination,byte_length); 334 335 ND_PRINT((ndo, "\n\t IPv4 prefix: %15s/%u, nexthop: ", 336 ipaddr_string(ndo, prefix), 337 bit_length)); 338 if (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_int->nexthop) == 0) 339 ND_PRINT((ndo, "self")); 340 else 341 ND_PRINT((ndo, "%s",ipaddr_string(ndo, &tlv_ptr.eigrp_tlv_ip_int->nexthop))); 342 343 ND_PRINT((ndo, "\n\t delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u", 344 (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_int->delay)/100), 345 EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_int->bandwidth), 346 EXTRACT_24BITS(&tlv_ptr.eigrp_tlv_ip_int->mtu), 347 tlv_ptr.eigrp_tlv_ip_int->hopcount, 348 tlv_ptr.eigrp_tlv_ip_int->reliability, 349 tlv_ptr.eigrp_tlv_ip_int->load)); 350 break; 351 352 case EIGRP_TLV_IP_EXT: 353 tlv_ptr.eigrp_tlv_ip_ext = (const struct eigrp_tlv_ip_ext_t *)tlv_tptr; 354 355 bit_length = tlv_ptr.eigrp_tlv_ip_ext->plen; 356 if (bit_length > 32) { 357 ND_PRINT((ndo, "\n\t illegal prefix length %u",bit_length)); 358 break; 359 } 360 byte_length = (bit_length + 7) / 8; /* variable length encoding */ 361 memset(prefix, 0, 4); 362 memcpy(prefix,&tlv_ptr.eigrp_tlv_ip_ext->destination,byte_length); 363 364 ND_PRINT((ndo, "\n\t IPv4 prefix: %15s/%u, nexthop: ", 365 ipaddr_string(ndo, prefix), 366 bit_length)); 367 if (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_ext->nexthop) == 0) 368 ND_PRINT((ndo, "self")); 369 else 370 ND_PRINT((ndo, "%s",ipaddr_string(ndo, &tlv_ptr.eigrp_tlv_ip_ext->nexthop))); 371 372 ND_PRINT((ndo, "\n\t origin-router %s, origin-as %u, origin-proto %s, flags [0x%02x], tag 0x%08x, metric %u", 373 ipaddr_string(ndo, tlv_ptr.eigrp_tlv_ip_ext->origin_router), 374 EXTRACT_32BITS(tlv_ptr.eigrp_tlv_ip_ext->origin_as), 375 tok2str(eigrp_ext_proto_id_values,"unknown",tlv_ptr.eigrp_tlv_ip_ext->proto_id), 376 tlv_ptr.eigrp_tlv_ip_ext->flags, 377 EXTRACT_32BITS(tlv_ptr.eigrp_tlv_ip_ext->tag), 378 EXTRACT_32BITS(tlv_ptr.eigrp_tlv_ip_ext->metric))); 379 380 ND_PRINT((ndo, "\n\t delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u", 381 (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_ext->delay)/100), 382 EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_ip_ext->bandwidth), 383 EXTRACT_24BITS(&tlv_ptr.eigrp_tlv_ip_ext->mtu), 384 tlv_ptr.eigrp_tlv_ip_ext->hopcount, 385 tlv_ptr.eigrp_tlv_ip_ext->reliability, 386 tlv_ptr.eigrp_tlv_ip_ext->load)); 387 break; 388 389 case EIGRP_TLV_AT_CABLE_SETUP: 390 tlv_ptr.eigrp_tlv_at_cable_setup = (const struct eigrp_tlv_at_cable_setup_t *)tlv_tptr; 391 392 ND_PRINT((ndo, "\n\t Cable-range: %u-%u, Router-ID %u", 393 EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_cable_setup->cable_start), 394 EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_cable_setup->cable_end), 395 EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_cable_setup->router_id))); 396 break; 397 398 case EIGRP_TLV_AT_INT: 399 tlv_ptr.eigrp_tlv_at_int = (const struct eigrp_tlv_at_int_t *)tlv_tptr; 400 401 ND_PRINT((ndo, "\n\t Cable-Range: %u-%u, nexthop: ", 402 EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_int->cable_start), 403 EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_int->cable_end))); 404 405 if (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_int->nexthop) == 0) 406 ND_PRINT((ndo, "self")); 407 else 408 ND_PRINT((ndo, "%u.%u", 409 EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_int->nexthop), 410 EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_int->nexthop[2]))); 411 412 ND_PRINT((ndo, "\n\t delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u", 413 (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_int->delay)/100), 414 EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_int->bandwidth), 415 EXTRACT_24BITS(&tlv_ptr.eigrp_tlv_at_int->mtu), 416 tlv_ptr.eigrp_tlv_at_int->hopcount, 417 tlv_ptr.eigrp_tlv_at_int->reliability, 418 tlv_ptr.eigrp_tlv_at_int->load)); 419 break; 420 421 case EIGRP_TLV_AT_EXT: 422 tlv_ptr.eigrp_tlv_at_ext = (const struct eigrp_tlv_at_ext_t *)tlv_tptr; 423 424 ND_PRINT((ndo, "\n\t Cable-Range: %u-%u, nexthop: ", 425 EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_ext->cable_start), 426 EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_ext->cable_end))); 427 428 if (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_ext->nexthop) == 0) 429 ND_PRINT((ndo, "self")); 430 else 431 ND_PRINT((ndo, "%u.%u", 432 EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_ext->nexthop), 433 EXTRACT_16BITS(&tlv_ptr.eigrp_tlv_at_ext->nexthop[2]))); 434 435 ND_PRINT((ndo, "\n\t origin-router %u, origin-as %u, origin-proto %s, flags [0x%02x], tag 0x%08x, metric %u", 436 EXTRACT_32BITS(tlv_ptr.eigrp_tlv_at_ext->origin_router), 437 EXTRACT_32BITS(tlv_ptr.eigrp_tlv_at_ext->origin_as), 438 tok2str(eigrp_ext_proto_id_values,"unknown",tlv_ptr.eigrp_tlv_at_ext->proto_id), 439 tlv_ptr.eigrp_tlv_at_ext->flags, 440 EXTRACT_32BITS(tlv_ptr.eigrp_tlv_at_ext->tag), 441 EXTRACT_16BITS(tlv_ptr.eigrp_tlv_at_ext->metric))); 442 443 ND_PRINT((ndo, "\n\t delay %u ms, bandwidth %u Kbps, mtu %u, hop %u, reliability %u, load %u", 444 (EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_ext->delay)/100), 445 EXTRACT_32BITS(&tlv_ptr.eigrp_tlv_at_ext->bandwidth), 446 EXTRACT_24BITS(&tlv_ptr.eigrp_tlv_at_ext->mtu), 447 tlv_ptr.eigrp_tlv_at_ext->hopcount, 448 tlv_ptr.eigrp_tlv_at_ext->reliability, 449 tlv_ptr.eigrp_tlv_at_ext->load)); 450 break; 451 452 /* 453 * FIXME those are the defined TLVs that lack a decoder 454 * you are welcome to contribute code ;-) 455 */ 456 457 case EIGRP_TLV_AUTH: 458 case EIGRP_TLV_SEQ: 459 case EIGRP_TLV_MCAST_SEQ: 460 case EIGRP_TLV_IPX_INT: 461 case EIGRP_TLV_IPX_EXT: 462 463 default: 464 if (ndo->ndo_vflag <= 1) 465 print_unknown_data(ndo,tlv_tptr,"\n\t ",tlv_tlen); 466 break; 467 } 468 /* do we want to see an additionally hexdump ? */ 469 if (ndo->ndo_vflag > 1) 470 print_unknown_data(ndo,tptr+sizeof(struct eigrp_tlv_header),"\n\t ", 471 eigrp_tlv_len-sizeof(struct eigrp_tlv_header)); 472 473 tptr+=eigrp_tlv_len; 474 tlen-=eigrp_tlv_len; 475 } 476 return; 477 trunc: 478 ND_PRINT((ndo, "\n\t\t packet exceeded snapshot")); 479 } 480