/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #define RIPVERSION RIPv2 #include #include "snoop.h" static const char *show_cmd(int); static int get_numtokens(unsigned int); static const struct rip_sec_entry *rip_next_sec_entry( const struct rip_sec_entry *, int); int interpret_rip(int flags, struct rip *rip, int fraglen) { const struct netinfo *nip; const struct entryinfo *ep; const struct netauth *nap; const struct rip_sec_entry *rsep, *rsn; const struct rip_emetric *rep; const uint32_t *tokp; 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; case RIPCMD_SEC_RESPONSE: cmdstr = "R - SEC"; break; case RIPCMD_SEC_T_RESPONSE: cmdstr = "R - SEC_T"; 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; case RIPCMD_SEC_RESPONSE: case RIPCMD_SEC_T_RESPONSE: if (len < sizeof (rip->rip_tsol.rip_generation)) break; len -= sizeof (rip->rip_tsol.rip_generation); count = 0; rsep = rip->rip_tsol.rip_sec_entry; while (len > 0) { rsn = rip_next_sec_entry(rsep, len); if (rsn == NULL) break; len -= (const char *)rsn - (const char *)rsep; rsep = rsn; count++; } (void) snprintf(get_sum_line(), MAXLINE, "%s %s (%d destinations%s)", ripvers, cmdstr, count, (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(0, 0), get_line_remain(), "Opcode = %d (%s)", rip->rip_cmd, show_cmd(rip->rip_cmd)); (void) snprintf(get_line(0, 0), 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(0, 0), 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, (long)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(0, 0), get_line_remain(), " *** All routes"); continue; } if (nip->n_family != RIP_AF_INET) { (void) snprintf(get_line(0, 0), 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(0, 0), 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(0, 0), 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(0, 0), get_line_remain(), "Router = %s %s", inet_ntoa(sin->sin_addr), addrtoname(AF_INET, (void *)&sin->sin_addr)); (void) snprintf(get_line(0, 0), get_line_remain(), "Flags = %4x", (unsigned)ep->rtu_flags); (void) snprintf(get_line(0, 0), get_line_remain(), "State = %d", ep->rtu_state); (void) snprintf(get_line(0, 0), get_line_remain(), "Timer = %d", ep->rtu_timer); (void) snprintf(get_line(0, 0), get_line_remain(), "Metric = %d", ep->rtu_metric); (void) snprintf(get_line(0, 0), get_line_remain(), "Int flags = %8x", ep->int_flags); (void) snprintf(get_line(0, 0), get_line_remain(), "Int name = \"%.*s\"", sizeof (ep->int_name), ep->int_name); break; case RIPCMD_SEC_RESPONSE: case RIPCMD_SEC_T_RESPONSE: if (len < sizeof (rip->rip_tsol.rip_generation)) break; len -= sizeof (rip->rip_tsol.rip_generation); show_space(); (void) snprintf(get_line(0, 0), get_line_remain(), "Generation = %u", (unsigned)ntohl(rip->rip_tsol.rip_generation)); rsep = rip->rip_tsol.rip_sec_entry; (void) snprintf(get_line(0, 0), get_line_remain(), "Address E-METRIC"); rsep = rip->rip_tsol.rip_sec_entry; while (len > 0) { char *cp; int blen, num; rsn = rip_next_sec_entry(rsep, len); if (rsn == NULL) break; dst.s_addr = rsep->rip_dst; cp = get_line(0, 0); blen = get_line_remain(); (void) snprintf(cp, blen, "%-16s ", inet_ntoa(dst)); cp += 17; blen -= 17; rep = rsep->rip_emetric; for (count = ntohl(rsep->rip_count); count > 0; count--) { (void) snprintf(cp, blen, "metric=%d", ntohs(rep->rip_metric)); blen -= strlen(cp); cp += strlen(cp); tokp = rep->rip_token; num = get_numtokens( ntohs(rep->rip_mask)); /* advance to the next emetric */ rep = (const struct rip_emetric *) &rep->rip_token[num]; if (num > 0) { (void) snprintf(cp, blen, ",tokens=%lx", (long)ntohl(*tokp)); tokp++; num--; } else { (void) strlcpy(cp, ",no tokens", blen); } while (num > 0) { blen -= strlen(cp); cp += strlen(cp); (void) snprintf(cp, blen, ",%lx", (long)ntohl(*tokp)); tokp++; num--; } blen -= strlen(cp); cp += strlen(cp); } if (rsep->rip_count == 0) { (void) strlcpy(cp, "NULL (not reachable)", blen); } len -= (const char *)rsn - (const char *)rsep; rsep = rsn; } break; case RIPCMD_TRACEON: case RIPCMD_TRACEOFF: (void) snprintf(get_line(0, 0), get_line_remain(), "Trace file = %.*s", len, rip->rip_tracefile); len = 0; break; } } return (fraglen - len); } static const 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"); case RIPCMD_SEC_RESPONSE: return ("route sec response"); case RIPCMD_SEC_T_RESPONSE: return ("route sec_t response"); } return ("?"); } static int get_numtokens(unsigned int mask) { int num = 0; while (mask != 0) { num++; mask &= mask - 1; } return (num); } static const struct rip_sec_entry * rip_next_sec_entry(const struct rip_sec_entry *rsep, int len) { const struct rip_emetric *rep; const char *limit = (const char *)rsep + len; long count; if ((const char *)(rep = rsep->rip_emetric) > limit) return (NULL); count = ntohl(rsep->rip_count); while (count > 0) { if ((const char *)rep->rip_token > limit) return (NULL); rep = (struct rip_emetric *) &rep->rip_token[get_numtokens(ntohs(rep->rip_mask))]; if ((const char *)rep > limit) return (NULL); count--; } return ((const struct rip_sec_entry *)rep); }