1 /* 2 * Copyright (c) 1989, 1990, 1991, 1993, 1994, 1996 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code distributions 7 * retain the above copyright notice and this paragraph in its entirety, (2) 8 * distributions including binary code include the above copyright notice and 9 * this paragraph in its entirety in the documentation or other materials 10 * provided with the distribution, and (3) all advertising materials mentioning 11 * features or use of this software display the following acknowledgement: 12 * ``This product includes software developed by the University of California, 13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14 * the University nor the names of its contributors may be used to endorse 15 * or promote products derived from this software without specific prior 16 * written permission. 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 */ 21 22 /* \summary: Routing Information Protocol (RIP) printer */ 23 24 /* specification: RFC 1058, RFC 2453, RFC 4822 */ 25 26 #ifdef HAVE_CONFIG_H 27 #include <config.h> 28 #endif 29 30 #include "netdissect-stdinc.h" 31 32 #include "netdissect.h" 33 #include "addrtoname.h" 34 #include "extract.h" 35 36 #include "af.h" 37 38 39 /* 40 * RFC 1058 and RFC 2453 header of packet. 41 * 42 * 0 1 2 3 3 43 * 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 44 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 45 * | Command (1) | Version (1) | unused | 46 * +---------------+---------------+-------------------------------+ 47 */ 48 struct rip { 49 nd_uint8_t rip_cmd; /* request/response */ 50 nd_uint8_t rip_vers; /* protocol version # */ 51 nd_byte unused[2]; /* unused */ 52 }; 53 54 #define RIPCMD_REQUEST 1 /* want info */ 55 #define RIPCMD_RESPONSE 2 /* responding to request */ 56 #define RIPCMD_TRACEON 3 /* turn tracing on */ 57 #define RIPCMD_TRACEOFF 4 /* turn it off */ 58 #define RIPCMD_POLL 5 /* want info from everybody */ 59 #define RIPCMD_POLLENTRY 6 /* poll for entry */ 60 61 static const struct tok rip_cmd_values[] = { 62 { RIPCMD_REQUEST, "Request" }, 63 { RIPCMD_RESPONSE, "Response" }, 64 { RIPCMD_TRACEON, "Trace on" }, 65 { RIPCMD_TRACEOFF, "Trace off" }, 66 { RIPCMD_POLL, "Poll" }, 67 { RIPCMD_POLLENTRY, "Poll Entry" }, 68 { 0, NULL} 69 }; 70 71 #define RIP_AUTHLEN 16 72 #define RIP_ROUTELEN 20 73 74 /* 75 * First 4 bytes of all RIPv1/RIPv2 entries. 76 */ 77 struct rip_entry_header { 78 nd_uint16_t rip_family; 79 nd_uint16_t rip_tag; 80 }; 81 82 /* 83 * RFC 1058 entry. 84 * 85 * 0 1 2 3 3 86 * 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 87 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 88 * | Address Family Identifier (2) | must be zero (2) | 89 * +-------------------------------+-------------------------------+ 90 * | IP Address (4) | 91 * +---------------------------------------------------------------+ 92 * | must be zero (4) | 93 * +---------------------------------------------------------------+ 94 * | must be zero (4) | 95 * +---------------------------------------------------------------+ 96 * | Metric (4) | 97 * +---------------------------------------------------------------+ 98 */ 99 struct rip_netinfo_v1 { 100 nd_uint16_t rip_family; 101 nd_byte rip_mbz1[2]; 102 nd_ipv4 rip_dest; 103 nd_byte rip_mbz2[4]; 104 nd_byte rip_mbz3[4]; 105 nd_uint32_t rip_metric; /* cost of route */ 106 }; 107 108 109 /* 110 * RFC 2453 route entry 111 * 112 * 0 1 2 3 3 113 * 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 114 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 115 * | Address Family Identifier (2) | Route Tag (2) | 116 * +-------------------------------+-------------------------------+ 117 * | IP Address (4) | 118 * +---------------------------------------------------------------+ 119 * | Subnet Mask (4) | 120 * +---------------------------------------------------------------+ 121 * | Next Hop (4) | 122 * +---------------------------------------------------------------+ 123 * | Metric (4) | 124 * +---------------------------------------------------------------+ 125 * 126 */ 127 128 struct rip_netinfo_v2 { 129 nd_uint16_t rip_family; 130 nd_uint16_t rip_tag; 131 nd_ipv4 rip_dest; 132 nd_uint32_t rip_dest_mask; 133 nd_ipv4 rip_router; 134 nd_uint32_t rip_metric; /* cost of route */ 135 }; 136 137 /* 138 * RFC 2453 authentication entry 139 * 140 * 0 1 2 3 3 141 * 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 142 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 143 * | 0xFFFF | Authentication Type (2) | 144 * +-------------------------------+-------------------------------+ 145 * - Authentication (16) - 146 * +---------------------------------------------------------------+ 147 */ 148 149 struct rip_auth_v2 { 150 nd_uint16_t rip_family; 151 nd_uint16_t rip_tag; 152 nd_byte rip_auth[16]; 153 }; 154 155 /* 156 * RFC 4822 Cryptographic Authentication entry. 157 * 158 * 0 1 2 3 3 159 * 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 160 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 161 * | RIPv2 Packet Length | Key ID | Auth Data Len | 162 * +---------------+---------------+---------------+---------------+ 163 * | Sequence Number (non-decreasing) | 164 * +---------------+---------------+---------------+---------------+ 165 * | reserved must be zero | 166 * +---------------+---------------+---------------+---------------+ 167 * | reserved must be zero | 168 * +---------------+---------------+---------------+---------------+ 169 */ 170 struct rip_auth_crypto_v2 { 171 nd_uint16_t rip_packet_len; 172 nd_uint8_t rip_key_id; 173 nd_uint8_t rip_auth_data_len; 174 nd_uint32_t rip_seq_num; 175 nd_byte rip_mbz1[4]; 176 nd_byte rip_mbz2[4]; 177 }; 178 179 static unsigned 180 rip_entry_print_v1(netdissect_options *ndo, const u_char *p, 181 unsigned remaining) 182 { 183 const struct rip_entry_header *eh = (const struct rip_entry_header *)p; 184 u_short family; 185 const struct rip_netinfo_v1 *ni = (const struct rip_netinfo_v1 *)p; 186 187 /* RFC 1058 */ 188 if (remaining < RIP_ROUTELEN) 189 return (0); 190 ND_TCHECK_SIZE(ni); 191 family = GET_BE_U_2(ni->rip_family); 192 if (family != BSD_AFNUM_INET && family != 0) { 193 ND_PRINT("\n\t AFI %s, ", tok2str(bsd_af_values, "Unknown (%u)", family)); 194 print_unknown_data(ndo, p + sizeof(*eh), "\n\t ", RIP_ROUTELEN - sizeof(*eh)); 195 return (RIP_ROUTELEN); 196 } 197 if (GET_BE_U_2(ni->rip_mbz1) || 198 GET_BE_U_4(ni->rip_mbz2) || 199 GET_BE_U_4(ni->rip_mbz3)) { 200 /* MBZ fields not zero */ 201 print_unknown_data(ndo, p, "\n\t ", RIP_ROUTELEN); 202 return (RIP_ROUTELEN); 203 } 204 if (family == 0) { 205 ND_PRINT("\n\t AFI 0, %s, metric: %u", 206 GET_IPADDR_STRING(ni->rip_dest), 207 GET_BE_U_4(ni->rip_metric)); 208 return (RIP_ROUTELEN); 209 } /* BSD_AFNUM_INET */ 210 ND_PRINT("\n\t %s, metric: %u", 211 GET_IPADDR_STRING(ni->rip_dest), 212 GET_BE_U_4(ni->rip_metric)); 213 return (RIP_ROUTELEN); 214 trunc: 215 return 0; 216 } 217 218 static unsigned 219 rip_entry_print_v2(netdissect_options *ndo, const u_char *p, 220 unsigned remaining) 221 { 222 const struct rip_entry_header *eh = (const struct rip_entry_header *)p; 223 u_short family; 224 const struct rip_netinfo_v2 *ni; 225 226 if (remaining < sizeof(*eh)) 227 return (0); 228 ND_TCHECK_SIZE(eh); 229 family = GET_BE_U_2(eh->rip_family); 230 if (family == 0xFFFF) { /* variable-sized authentication structures */ 231 uint16_t auth_type = GET_BE_U_2(eh->rip_tag); 232 233 p += sizeof(*eh); 234 remaining -= sizeof(*eh); 235 if (auth_type == 2) { 236 ND_PRINT("\n\t Simple Text Authentication data: "); 237 nd_printjnp(ndo, p, RIP_AUTHLEN); 238 } else if (auth_type == 3) { 239 const struct rip_auth_crypto_v2 *ch; 240 241 ch = (const struct rip_auth_crypto_v2 *)p; 242 ND_TCHECK_SIZE(ch); 243 if (remaining < sizeof(*ch)) 244 return (0); 245 ND_PRINT("\n\t Auth header:"); 246 ND_PRINT(" Packet Len %u,", 247 GET_BE_U_2(ch->rip_packet_len)); 248 ND_PRINT(" Key-ID %u,", GET_U_1(ch->rip_key_id)); 249 ND_PRINT(" Auth Data Len %u,", 250 GET_U_1(ch->rip_auth_data_len)); 251 ND_PRINT(" SeqNo %u,", GET_BE_U_4(ch->rip_seq_num)); 252 ND_PRINT(" MBZ %u,", GET_BE_U_4(ch->rip_mbz1)); 253 ND_PRINT(" MBZ %u", GET_BE_U_4(ch->rip_mbz2)); 254 } else if (auth_type == 1) { 255 ND_PRINT("\n\t Auth trailer:"); 256 print_unknown_data(ndo, p, "\n\t ", remaining); 257 return (sizeof(*eh) + remaining); /* AT spans till the packet end */ 258 } else { 259 ND_PRINT("\n\t Unknown (%u) Authentication data:", 260 auth_type); 261 print_unknown_data(ndo, p, "\n\t ", remaining); 262 return (sizeof(*eh) + remaining); /* we don't know how long this is, so we go to the packet end */ 263 } 264 } else if (family != BSD_AFNUM_INET && family != 0) { 265 ND_PRINT("\n\t AFI %s", tok2str(bsd_af_values, "Unknown (%u)", family)); 266 print_unknown_data(ndo, p + sizeof(*eh), "\n\t ", RIP_ROUTELEN - sizeof(*eh)); 267 } else { /* BSD_AFNUM_INET or AFI 0 */ 268 ni = (const struct rip_netinfo_v2 *)p; 269 ND_TCHECK_SIZE(ni); 270 if (remaining < sizeof(*ni)) 271 return (0); 272 ND_PRINT("\n\t AFI %s, %15s/%-2d, tag 0x%04x, metric: %u, next-hop: ", 273 tok2str(bsd_af_values, "%u", family), 274 GET_IPADDR_STRING(ni->rip_dest), 275 mask2plen(GET_BE_U_4(ni->rip_dest_mask)), 276 GET_BE_U_2(ni->rip_tag), 277 GET_BE_U_4(ni->rip_metric)); 278 if (GET_BE_U_4(ni->rip_router)) 279 ND_PRINT("%s", GET_IPADDR_STRING(ni->rip_router)); 280 else 281 ND_PRINT("self"); 282 } 283 return (RIP_ROUTELEN); 284 trunc: 285 return 0; 286 } 287 288 void 289 rip_print(netdissect_options *ndo, 290 const u_char *dat, u_int length) 291 { 292 const struct rip *rp; 293 uint8_t vers, cmd; 294 const u_char *p; 295 u_int len, routecount; 296 unsigned entry_size; 297 298 ndo->ndo_protocol = "rip"; 299 if (ndo->ndo_snapend < dat) { 300 nd_print_trunc(ndo); 301 return; 302 } 303 len = ND_BYTES_AVAILABLE_AFTER(dat); 304 if (len > length) 305 len = length; 306 if (len < sizeof(*rp)) { 307 nd_print_trunc(ndo); 308 return; 309 } 310 len -= sizeof(*rp); 311 312 rp = (const struct rip *)dat; 313 314 ND_TCHECK_SIZE(rp); 315 vers = GET_U_1(rp->rip_vers); 316 ND_PRINT("%sRIPv%u", 317 (ndo->ndo_vflag >= 1) ? "\n\t" : "", 318 vers); 319 320 if (vers == 0) { 321 /* 322 * RFC 1058. 323 * 324 * XXX - RFC 1058 says 325 * 326 * 0 Datagrams whose version number is zero are to be ignored. 327 * These are from a previous version of the protocol, whose 328 * packet format was machine-specific. 329 * 330 * so perhaps we should just dump the packet, in hex. 331 */ 332 print_unknown_data(ndo, (const uint8_t *)&rp->rip_cmd, "\n\t", length); 333 return; 334 } 335 336 /* dump version and lets see if we know the commands name*/ 337 cmd = GET_U_1(rp->rip_cmd); 338 ND_PRINT(", %s, length: %u", 339 tok2str(rip_cmd_values, "unknown command (%u)", cmd), 340 length); 341 342 if (ndo->ndo_vflag < 1) 343 return; 344 345 switch (cmd) { 346 347 case RIPCMD_REQUEST: 348 case RIPCMD_RESPONSE: 349 switch (vers) { 350 351 case 1: 352 routecount = length / RIP_ROUTELEN; 353 ND_PRINT(", routes: %u", routecount); 354 p = (const u_char *)(rp + 1); 355 while (len != 0) { 356 entry_size = rip_entry_print_v1(ndo, p, len); 357 if (entry_size == 0) { 358 /* Error */ 359 nd_print_trunc(ndo); 360 break; 361 } 362 if (len < entry_size) { 363 ND_PRINT(" [remaining entries length %u < %u]", 364 len, entry_size); 365 nd_print_invalid(ndo); 366 break; 367 } 368 p += entry_size; 369 len -= entry_size; 370 } 371 break; 372 373 case 2: 374 routecount = length / RIP_ROUTELEN; 375 ND_PRINT(", routes: %u or less", routecount); 376 p = (const u_char *)(rp + 1); 377 while (len != 0) { 378 entry_size = rip_entry_print_v2(ndo, p, len); 379 if (entry_size == 0) { 380 /* Error */ 381 nd_print_trunc(ndo); 382 break; 383 } 384 if (len < entry_size) { 385 ND_PRINT(" [remaining entries length %u < %u]", 386 len, entry_size); 387 nd_print_invalid(ndo); 388 break; 389 } 390 p += entry_size; 391 len -= entry_size; 392 } 393 break; 394 395 default: 396 ND_PRINT(", unknown version"); 397 break; 398 } 399 break; 400 401 case RIPCMD_TRACEOFF: 402 case RIPCMD_POLL: 403 case RIPCMD_POLLENTRY: 404 break; 405 406 case RIPCMD_TRACEON: 407 /* fall through */ 408 default: 409 if (ndo->ndo_vflag <= 1) { 410 if (!print_unknown_data(ndo, (const uint8_t *)rp, "\n\t", length)) 411 return; 412 } 413 break; 414 } 415 /* do we want to see an additionally hexdump ? */ 416 if (ndo->ndo_vflag> 1) { 417 if (!print_unknown_data(ndo, (const uint8_t *)rp, "\n\t", length)) 418 return; 419 } 420 trunc: 421 return; 422 } 423