1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <string.h> 30 #include <strings.h> 31 #include <fcntl.h> 32 #include <sys/types.h> 33 #include <sys/socket.h> 34 #include <netinet/in.h> 35 #include <arpa/inet.h> 36 #define RIPVERSION RIPv2 37 #include <protocols/routed.h> 38 #include "snoop.h" 39 40 static const char *show_cmd(int); 41 static int get_numtokens(unsigned int); 42 static const struct rip_sec_entry *rip_next_sec_entry( 43 const struct rip_sec_entry *, int); 44 45 int 46 interpret_rip(int flags, struct rip *rip, int fraglen) 47 { 48 const struct netinfo *nip; 49 const struct entryinfo *ep; 50 const struct netauth *nap; 51 const struct rip_sec_entry *rsep, *rsn; 52 const struct rip_emetric *rep; 53 const uint32_t *tokp; 54 int len, count; 55 const char *cmdstr, *auth; 56 struct in_addr dst; 57 uint32_t mval; 58 const struct sockaddr_in *sin; 59 /* Room for IP destination + "/" + IP mask */ 60 char addrstr[15+1+15+1]; 61 /* Room for "RIPv" + uint8_t as %d */ 62 char ripvers[4+3+1]; 63 64 /* RIP header is 4 octets long */ 65 if ((len = fraglen - 4) < 0) 66 return (0); 67 68 if (flags & F_SUM) { 69 switch (rip->rip_cmd) { 70 case RIPCMD_REQUEST: cmdstr = "C"; break; 71 case RIPCMD_RESPONSE: cmdstr = "R"; break; 72 case RIPCMD_TRACEON: cmdstr = "Traceon"; break; 73 case RIPCMD_TRACEOFF: cmdstr = "Traceoff"; break; 74 case RIPCMD_POLL: cmdstr = "Poll"; break; 75 case RIPCMD_POLLENTRY: cmdstr = "Poll entry"; break; 76 case RIPCMD_SEC_RESPONSE: cmdstr = "R - SEC"; break; 77 case RIPCMD_SEC_T_RESPONSE: cmdstr = "R - SEC_T"; break; 78 default: cmdstr = "?"; break; 79 } 80 81 if (rip->rip_vers == RIPv1) 82 (void) strlcpy(ripvers, "RIP", sizeof (ripvers)); 83 else 84 (void) snprintf(ripvers, sizeof (ripvers), "RIPv%d", 85 rip->rip_vers); 86 87 switch (rip->rip_cmd) { 88 case RIPCMD_REQUEST: 89 case RIPCMD_RESPONSE: 90 case RIPCMD_POLL: 91 nip = rip->rip_nets; 92 auth = ""; 93 if (len >= sizeof (*nip) && 94 nip->n_family == RIP_AF_AUTH) { 95 nap = (struct netauth *)nip; 96 len -= sizeof (*nip); 97 if (nap->a_type == RIP_AUTH_MD5 && 98 len >= ntohs(nap->au.a_md5.md5_auth_len)) 99 len -= ntohs(nap->au.a_md5. 100 md5_auth_len); 101 auth = " +Auth"; 102 } 103 count = len / sizeof (*nip); 104 len %= sizeof (*nip); 105 (void) snprintf(get_sum_line(), MAXLINE, 106 "%s %s (%d destinations%s%s)", ripvers, cmdstr, 107 count, (len != 0 ? "?" : ""), auth); 108 break; 109 110 case RIPCMD_TRACEON: 111 case RIPCMD_TRACEOFF: 112 (void) snprintf(get_sum_line(), MAXLINE, 113 "%s %s File=\"%.*s\"", ripvers, cmdstr, len, 114 rip->rip_tracefile); 115 len = 0; 116 break; 117 118 case RIPCMD_SEC_RESPONSE: 119 case RIPCMD_SEC_T_RESPONSE: 120 if (len < sizeof (rip->rip_tsol.rip_generation)) 121 break; 122 len -= sizeof (rip->rip_tsol.rip_generation); 123 count = 0; 124 rsep = rip->rip_tsol.rip_sec_entry; 125 while (len > 0) { 126 rsn = rip_next_sec_entry(rsep, len); 127 if (rsn == NULL) 128 break; 129 len -= (const char *)rsn - (const char *)rsep; 130 rsep = rsn; 131 count++; 132 } 133 (void) snprintf(get_sum_line(), MAXLINE, 134 "%s %s (%d destinations%s)", ripvers, cmdstr, 135 count, (len != 0 ? "?" : "")); 136 break; 137 138 default: 139 (void) snprintf(get_sum_line(), MAXLINE, 140 "%s %d (%s)", ripvers, rip->rip_cmd, cmdstr); 141 len = 0; 142 break; 143 } 144 } 145 146 if (flags & F_DTAIL) { 147 148 len = fraglen - 4; 149 show_header("RIP: ", "Routing Information Protocol", fraglen); 150 show_space(); 151 (void) snprintf(get_line(0, 0), get_line_remain(), 152 "Opcode = %d (%s)", rip->rip_cmd, 153 show_cmd(rip->rip_cmd)); 154 (void) snprintf(get_line(0, 0), get_line_remain(), 155 "Version = %d", rip->rip_vers); 156 157 switch (rip->rip_cmd) { 158 case RIPCMD_REQUEST: 159 case RIPCMD_RESPONSE: 160 case RIPCMD_POLL: 161 show_space(); 162 (void) snprintf(get_line(0, 0), get_line_remain(), 163 "Destination Next Hop " 164 "Tag Metric"); 165 for (nip = rip->rip_nets; len >= sizeof (*nip); nip++, 166 len -= sizeof (*nip)) { 167 if (nip->n_family == RIP_AF_AUTH) { 168 nap = (const struct netauth *)nip; 169 if (nap->a_type == RIP_AUTH_NONE) { 170 (void) snprintf(get_line 171 ((char *)nip - dlc_header, 172 sizeof (*nip)), 173 get_line_remain(), 174 " *** Auth None"); 175 } else if (nap->a_type == RIP_AUTH_PW) { 176 (void) snprintf(get_line 177 ((char *)nip - dlc_header, 178 sizeof (*nip)), 179 get_line_remain(), 180 " *** Auth PW \"%.*s\"", 181 RIP_AUTH_PW_LEN, 182 nap->au.au_pw); 183 } else if (nap->a_type == 184 RIP_AUTH_MD5) { 185 (void) snprintf(get_line(0, 0), 186 get_line_remain(), 187 " *** Auth MD5 pkt len %d, " 188 "keyid %d, sequence %08lX, " 189 "authlen %d", 190 ntohs(nap->au.a_md5. 191 md5_pkt_len), 192 nap->au.a_md5.md5_keyid, 193 (long)ntohl(nap->au.a_md5. 194 md5_seqno), 195 ntohs(nap->au.a_md5. 196 md5_auth_len)); 197 if (len - sizeof (*nip) >= 198 ntohs(nap->au.a_md5. 199 md5_auth_len)) 200 len -= ntohs(nap->au. 201 a_md5.md5_auth_len); 202 else 203 len = sizeof (*nip); 204 } else { 205 (void) snprintf(get_line 206 ((char *)nip - dlc_header, 207 sizeof (*nip)), 208 get_line_remain(), 209 " *** Auth Type %d?", 210 ntohs(nap->a_type)); 211 } 212 continue; 213 } 214 if (nip->n_family == RIP_AF_UNSPEC && 215 rip->rip_cmd == RIPCMD_REQUEST) { 216 (void) snprintf(get_line(0, 0), 217 get_line_remain(), 218 " *** All routes"); 219 continue; 220 } 221 if (nip->n_family != RIP_AF_INET) { 222 (void) snprintf(get_line(0, 0), 223 get_line_remain(), 224 " *** Address Family %d?", 225 ntohs(nip->n_family)); 226 continue; 227 } 228 if (nip->n_dst == htonl(RIP_DEFAULT)) { 229 (void) strcpy(addrstr, "default"); 230 } else { 231 dst.s_addr = nip->n_dst; 232 (void) strlcpy(addrstr, inet_ntoa(dst), 233 sizeof (addrstr)); 234 } 235 if (nip->n_dst != htonl(RIP_DEFAULT) && 236 rip->rip_vers >= RIPv2) { 237 count = strlen(addrstr); 238 mval = ntohl(nip->n_mask); 239 /* LINTED */ 240 if (mval == INADDR_ANY) { 241 /* No mask */; 242 } else if ((mval + (mval & -mval)) == 243 0) { 244 (void) snprintf(addrstr + count, 245 sizeof (addrstr) - count, 246 "/%d", 33 - ffs(mval)); 247 } else { 248 dst.s_addr = nip->n_mask; 249 (void) snprintf(addrstr + count, 250 sizeof (addrstr) - count, 251 "/%s", inet_ntoa(dst)); 252 } 253 } 254 dst.s_addr = nip->n_nhop; 255 mval = ntohl(nip->n_metric); 256 (void) snprintf(get_line(0, 0), 257 get_line_remain(), 258 "%-31s %-15s %-6d %d%s", 259 addrstr, 260 dst.s_addr == htonl(INADDR_ANY) ? 261 "--" : addrtoname(AF_INET, &dst), 262 ntohs(nip->n_tag), 263 mval, 264 (mval == HOPCNT_INFINITY ? 265 " (not reachable)" : "")); 266 } 267 break; 268 269 case RIPCMD_POLLENTRY: 270 if (len < sizeof (*ep)) 271 break; 272 len -= sizeof (*ep); 273 ep = (const struct entryinfo *)rip->rip_nets; 274 /* LINTED */ 275 sin = (const struct sockaddr_in *)&ep->rtu_dst; 276 (void) snprintf(get_line(0, 0), get_line_remain(), 277 "Destination = %s %s", 278 inet_ntoa(sin->sin_addr), 279 addrtoname(AF_INET, (void *)&sin->sin_addr)); 280 /* LINTED */ 281 sin = (const struct sockaddr_in *)&ep->rtu_router; 282 (void) snprintf(get_line(0, 0), get_line_remain(), 283 "Router = %s %s", 284 inet_ntoa(sin->sin_addr), 285 addrtoname(AF_INET, (void *)&sin->sin_addr)); 286 (void) snprintf(get_line(0, 0), get_line_remain(), 287 "Flags = %4x", (unsigned)ep->rtu_flags); 288 (void) snprintf(get_line(0, 0), get_line_remain(), 289 "State = %d", ep->rtu_state); 290 (void) snprintf(get_line(0, 0), get_line_remain(), 291 "Timer = %d", ep->rtu_timer); 292 (void) snprintf(get_line(0, 0), get_line_remain(), 293 "Metric = %d", ep->rtu_metric); 294 (void) snprintf(get_line(0, 0), get_line_remain(), 295 "Int flags = %8x", ep->int_flags); 296 (void) snprintf(get_line(0, 0), get_line_remain(), 297 "Int name = \"%.*s\"", sizeof (ep->int_name), 298 ep->int_name); 299 break; 300 301 case RIPCMD_SEC_RESPONSE: 302 case RIPCMD_SEC_T_RESPONSE: 303 if (len < sizeof (rip->rip_tsol.rip_generation)) 304 break; 305 len -= sizeof (rip->rip_tsol.rip_generation); 306 show_space(); 307 (void) snprintf(get_line(0, 0), get_line_remain(), 308 "Generation = %u", 309 (unsigned)ntohl(rip->rip_tsol.rip_generation)); 310 rsep = rip->rip_tsol.rip_sec_entry; 311 (void) snprintf(get_line(0, 0), get_line_remain(), 312 "Address E-METRIC"); 313 rsep = rip->rip_tsol.rip_sec_entry; 314 while (len > 0) { 315 char *cp; 316 int blen, num; 317 318 rsn = rip_next_sec_entry(rsep, len); 319 if (rsn == NULL) 320 break; 321 dst.s_addr = rsep->rip_dst; 322 cp = get_line(0, 0); 323 blen = get_line_remain(); 324 (void) snprintf(cp, blen, "%-16s ", 325 inet_ntoa(dst)); 326 cp += 17; 327 blen -= 17; 328 rep = rsep->rip_emetric; 329 for (count = ntohl(rsep->rip_count); count > 0; 330 count--) { 331 (void) snprintf(cp, blen, "metric=%d", 332 ntohs(rep->rip_metric)); 333 blen -= strlen(cp); 334 cp += strlen(cp); 335 tokp = rep->rip_token; 336 num = get_numtokens( 337 ntohs(rep->rip_mask)); 338 /* advance to the next emetric */ 339 rep = (const struct rip_emetric *) 340 &rep->rip_token[num]; 341 if (num > 0) { 342 (void) snprintf(cp, blen, 343 ",tokens=%lx", 344 (long)ntohl(*tokp)); 345 tokp++; 346 num--; 347 } else { 348 (void) strlcpy(cp, ",no tokens", 349 blen); 350 } 351 while (num > 0) { 352 blen -= strlen(cp); 353 cp += strlen(cp); 354 (void) snprintf(cp, blen, 355 ",%lx", 356 (long)ntohl(*tokp)); 357 tokp++; 358 num--; 359 } 360 blen -= strlen(cp); 361 cp += strlen(cp); 362 } 363 if (rsep->rip_count == 0) { 364 (void) strlcpy(cp, 365 "NULL (not reachable)", blen); 366 } 367 len -= (const char *)rsn - (const char *)rsep; 368 rsep = rsn; 369 } 370 break; 371 372 case RIPCMD_TRACEON: 373 case RIPCMD_TRACEOFF: 374 (void) snprintf(get_line(0, 0), get_line_remain(), 375 "Trace file = %.*s", len, rip->rip_tracefile); 376 len = 0; 377 break; 378 } 379 } 380 381 return (fraglen - len); 382 } 383 384 static const char * 385 show_cmd(int c) 386 { 387 switch (c) { 388 case RIPCMD_REQUEST: 389 return ("route request"); 390 case RIPCMD_RESPONSE: 391 return ("route response"); 392 case RIPCMD_TRACEON: 393 return ("route trace on"); 394 case RIPCMD_TRACEOFF: 395 return ("route trace off"); 396 case RIPCMD_POLL: 397 return ("route poll"); 398 case RIPCMD_POLLENTRY: 399 return ("route poll entry"); 400 case RIPCMD_SEC_RESPONSE: 401 return ("route sec response"); 402 case RIPCMD_SEC_T_RESPONSE: 403 return ("route sec_t response"); 404 } 405 return ("?"); 406 } 407 408 static int 409 get_numtokens(unsigned int mask) 410 { 411 int num = 0; 412 413 while (mask != 0) { 414 num++; 415 mask &= mask - 1; 416 } 417 return (num); 418 } 419 420 static const struct rip_sec_entry * 421 rip_next_sec_entry(const struct rip_sec_entry *rsep, int len) 422 { 423 const struct rip_emetric *rep; 424 const char *limit = (const char *)rsep + len; 425 long count; 426 427 if ((const char *)(rep = rsep->rip_emetric) > limit) 428 return (NULL); 429 count = ntohl(rsep->rip_count); 430 while (count > 0) { 431 if ((const char *)rep->rip_token > limit) 432 return (NULL); 433 rep = (struct rip_emetric *) 434 &rep->rip_token[get_numtokens(ntohs(rep->rip_mask))]; 435 if ((const char *)rep > limit) 436 return (NULL); 437 count--; 438 } 439 return ((const struct rip_sec_entry *)rep); 440 } 441