/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include #include #include #define RIPVERSION RIPv2 #include #include "snoop.h" static char *show_cmd(int); int interpret_rip(int flags, struct rip *rip, int fraglen) { const struct netinfo *nip; const struct entryinfo *ep; const struct netauth *nap; int len, count; const char *cmdstr, *auth; struct in_addr dst; uint32_t mval; const struct sockaddr_in *sin; /* Room for IP destination + "/" + IP mask */ char addrstr[15+1+15+1]; /* Room for "RIPv" + uint8_t as %d */ char ripvers[4+3+1]; /* RIP header is 4 octets long */ if ((len = fraglen - 4) < 0) return (0); if (flags & F_SUM) { switch (rip->rip_cmd) { case RIPCMD_REQUEST: cmdstr = "C"; break; case RIPCMD_RESPONSE: cmdstr = "R"; break; case RIPCMD_TRACEON: cmdstr = "Traceon"; break; case RIPCMD_TRACEOFF: cmdstr = "Traceoff"; break; case RIPCMD_POLL: cmdstr = "Poll"; break; case RIPCMD_POLLENTRY: cmdstr = "Poll entry"; break; default: cmdstr = "?"; break; } if (rip->rip_vers == RIPv1) (void) strlcpy(ripvers, "RIP", sizeof (ripvers)); else (void) snprintf(ripvers, sizeof (ripvers), "RIPv%d", rip->rip_vers); switch (rip->rip_cmd) { case RIPCMD_REQUEST: case RIPCMD_RESPONSE: case RIPCMD_POLL: nip = rip->rip_nets; auth = ""; if (len >= sizeof (*nip) && nip->n_family == RIP_AF_AUTH) { nap = (struct netauth *)nip; len -= sizeof (*nip); if (nap->a_type == RIP_AUTH_MD5 && len >= ntohs(nap->au.a_md5.md5_auth_len)) len -= ntohs(nap->au.a_md5. md5_auth_len); auth = " +Auth"; } count = len / sizeof (*nip); len %= sizeof (*nip); (void) snprintf(get_sum_line(), MAXLINE, "%s %s (%d destinations%s%s)", ripvers, cmdstr, count, (len != 0 ? "?" : ""), auth); break; case RIPCMD_TRACEON: case RIPCMD_TRACEOFF: (void) snprintf(get_sum_line(), MAXLINE, "%s %s File=\"%.*s\"", ripvers, cmdstr, len, rip->rip_tracefile); len = 0; break; default: (void) snprintf(get_sum_line(), MAXLINE, "%s %d (%s)", ripvers, rip->rip_cmd, cmdstr); len = 0; break; } } if (flags & F_DTAIL) { len = fraglen - 4; show_header("RIP: ", "Routing Information Protocol", fraglen); show_space(); (void) snprintf(get_line((char *)(uintptr_t)rip->rip_cmd - dlc_header, 1), get_line_remain(), "Opcode = %d (%s)", rip->rip_cmd, show_cmd(rip->rip_cmd)); (void) snprintf(get_line((char *)(uintptr_t)rip->rip_vers - dlc_header, 1), get_line_remain(), "Version = %d", rip->rip_vers); switch (rip->rip_cmd) { case RIPCMD_REQUEST: case RIPCMD_RESPONSE: case RIPCMD_POLL: show_space(); (void) snprintf(get_line(0, 0), get_line_remain(), "Destination Next Hop " "Tag Metric"); for (nip = rip->rip_nets; len >= sizeof (*nip); nip++, len -= sizeof (*nip)) { if (nip->n_family == RIP_AF_AUTH) { nap = (const struct netauth *)nip; if (nap->a_type == RIP_AUTH_NONE) { (void) snprintf(get_line ((char *)nip - dlc_header, sizeof (*nip)), get_line_remain(), " *** Auth None"); } else if (nap->a_type == RIP_AUTH_PW) { (void) snprintf(get_line ((char *)nip - dlc_header, sizeof (*nip)), get_line_remain(), " *** Auth PW \"%.*s\"", RIP_AUTH_PW_LEN, nap->au.au_pw); } else if (nap->a_type == RIP_AUTH_MD5) { (void) snprintf(get_line ((char *)nip - dlc_header, sizeof (*nip)), get_line_remain(), " *** Auth MD5 pkt len %d, " "keyid %d, sequence %08lX, " "authlen %d", ntohs(nap->au.a_md5. md5_pkt_len), nap->au.a_md5.md5_keyid, ntohl(nap->au.a_md5. md5_seqno), ntohs(nap->au.a_md5. md5_auth_len)); if (len - sizeof (*nip) >= ntohs(nap->au.a_md5. md5_auth_len)) len -= ntohs(nap->au. a_md5.md5_auth_len); else len = sizeof (*nip); } else { (void) snprintf(get_line ((char *)nip - dlc_header, sizeof (*nip)), get_line_remain(), " *** Auth Type %d?", ntohs(nap->a_type)); } continue; } if (nip->n_family == RIP_AF_UNSPEC && rip->rip_cmd == RIPCMD_REQUEST) { (void) snprintf(get_line((char *)nip - dlc_header, sizeof (*nip)), get_line_remain(), " *** All routes"); continue; } if (nip->n_family != RIP_AF_INET) { (void) snprintf(get_line((char *)nip - dlc_header, sizeof (*nip)), get_line_remain(), " *** Address Family %d?", ntohs(nip->n_family)); continue; } if (nip->n_dst == htonl(RIP_DEFAULT)) { (void) strcpy(addrstr, "default"); } else { dst.s_addr = nip->n_dst; (void) strlcpy(addrstr, inet_ntoa(dst), sizeof (addrstr)); } if (nip->n_dst != htonl(RIP_DEFAULT) && rip->rip_vers >= RIPv2) { count = strlen(addrstr); mval = ntohl(nip->n_mask); /* LINTED */ if (mval == INADDR_ANY) { /* No mask */; } else if ((mval + (mval & -mval)) == 0) { (void) snprintf(addrstr + count, sizeof (addrstr) - count, "/%d", 33 - ffs(mval)); } else { dst.s_addr = nip->n_mask; (void) snprintf(addrstr + count, sizeof (addrstr) - count, "/%s", inet_ntoa(dst)); } } dst.s_addr = nip->n_nhop; mval = ntohl(nip->n_metric); (void) snprintf(get_line((char *)nip - dlc_header, sizeof (*nip)), get_line_remain(), "%-31s %-15s %-6d %d%s", addrstr, dst.s_addr == htonl(INADDR_ANY) ? "--" : addrtoname(AF_INET, &dst), ntohs(nip->n_tag), mval, (mval == HOPCNT_INFINITY ? " (not reachable)" : "")); } break; case RIPCMD_POLLENTRY: if (len < sizeof (*ep)) break; len -= sizeof (*ep); ep = (const struct entryinfo *)rip->rip_nets; /* LINTED */ sin = (const struct sockaddr_in *)&ep->rtu_dst; (void) snprintf(get_line((char *)sin - dlc_header, sizeof (struct sockaddr)), get_line_remain(), "Destination = %s %s", inet_ntoa(sin->sin_addr), addrtoname(AF_INET, (void *)&sin->sin_addr)); /* LINTED */ sin = (const struct sockaddr_in *)&ep->rtu_router; (void) snprintf(get_line((char *)sin - dlc_header, sizeof (struct sockaddr)), get_line_remain(), "Router = %s %s", inet_ntoa(sin->sin_addr), addrtoname(AF_INET, (void *)&sin->sin_addr)); (void) snprintf(get_line((char *)&ep->rtu_flags - dlc_header, 2), get_line_remain(), "Flags = %4x", (unsigned)ep->rtu_flags); (void) snprintf(get_line((char *)&ep->rtu_state - dlc_header, 2), get_line_remain(), "State = %d", ep->rtu_state); (void) snprintf(get_line((char *)&ep->rtu_timer - dlc_header, 4), get_line_remain(), "Timer = %d", ep->rtu_timer); (void) snprintf(get_line((char *)&ep->rtu_metric - dlc_header, 4), get_line_remain(), "Metric = %d", ep->rtu_metric); (void) snprintf(get_line((char *)&ep->int_flags - dlc_header, 4), get_line_remain(), "Int flags = %8x", ep->int_flags); (void) snprintf(get_line((char *)ep->int_name - dlc_header, sizeof (ep->int_name)), get_line_remain(), "Int name = \"%.*s\"", sizeof (ep->int_name), ep->int_name); break; case RIPCMD_TRACEON: case RIPCMD_TRACEOFF: (void) snprintf(get_line((char *)rip->rip_tracefile - dlc_header, 2), get_line_remain(), "Trace file = %.*s", len, rip->rip_tracefile); len = 0; break; } } return (fraglen - len); } static char * show_cmd(int c) { switch (c) { case RIPCMD_REQUEST: return ("route request"); case RIPCMD_RESPONSE: return ("route response"); case RIPCMD_TRACEON: return ("route trace on"); case RIPCMD_TRACEOFF: return ("route trace off"); case RIPCMD_POLL: return ("route poll"); case RIPCMD_POLLENTRY: return ("route poll entry"); } return ("?"); }