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