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