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