Home | History | Annotate | Download | only in snoop
      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