snoop_rip.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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 1991-2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define RIPVERSION RIPv2
#include <protocols/routed.h>
#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 *)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 *)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 ("?");
}