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