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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <string.h>
31 #include <strings.h>
32 #include <fcntl.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #define	RIPVERSION	RIPv2
38 #include <protocols/routed.h>
39 #include "snoop.h"
40 
41 static char *show_cmd(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 	int len, count;
50 	const char *cmdstr, *auth;
51 	struct in_addr dst;
52 	uint32_t mval;
53 	const struct sockaddr_in *sin;
54 	/* Room for IP destination + "/" + IP mask */
55 	char addrstr[15+1+15+1];
56 	/* Room for "RIPv" + uint8_t as %d */
57 	char ripvers[4+3+1];
58 
59 	/* RIP header is 4 octets long */
60 	if ((len = fraglen - 4) < 0)
61 		return (0);
62 
63 	if (flags & F_SUM) {
64 		switch (rip->rip_cmd) {
65 		case RIPCMD_REQUEST:	cmdstr = "C";		break;
66 		case RIPCMD_RESPONSE:	cmdstr = "R";		break;
67 		case RIPCMD_TRACEON:	cmdstr = "Traceon";	break;
68 		case RIPCMD_TRACEOFF:	cmdstr = "Traceoff";	break;
69 		case RIPCMD_POLL:	cmdstr = "Poll";	break;
70 		case RIPCMD_POLLENTRY:	cmdstr = "Poll entry";	break;
71 		default: cmdstr = "?"; break;
72 		}
73 
74 		if (rip->rip_vers == RIPv1)
75 			(void) strlcpy(ripvers, "RIP", sizeof (ripvers));
76 		else
77 			(void) snprintf(ripvers, sizeof (ripvers), "RIPv%d",
78 			    rip->rip_vers);
79 
80 		switch (rip->rip_cmd) {
81 		case RIPCMD_REQUEST:
82 		case RIPCMD_RESPONSE:
83 		case RIPCMD_POLL:
84 			nip = rip->rip_nets;
85 			auth = "";
86 			if (len >= sizeof (*nip) &&
87 			    nip->n_family == RIP_AF_AUTH) {
88 				nap = (struct netauth *)nip;
89 				len -= sizeof (*nip);
90 				if (nap->a_type == RIP_AUTH_MD5 &&
91 				    len >= ntohs(nap->au.a_md5.md5_auth_len))
92 					len -= ntohs(nap->au.a_md5.
93 					    md5_auth_len);
94 				auth = " +Auth";
95 			}
96 			count = len / sizeof (*nip);
97 			len %= sizeof (*nip);
98 			(void) snprintf(get_sum_line(), MAXLINE,
99 			    "%s %s (%d destinations%s%s)", ripvers, cmdstr,
100 			    count, (len != 0 ? "?" : ""), auth);
101 			break;
102 
103 		case RIPCMD_TRACEON:
104 		case RIPCMD_TRACEOFF:
105 			(void) snprintf(get_sum_line(), MAXLINE,
106 			    "%s %s File=\"%.*s\"", ripvers, cmdstr, len,
107 			    rip->rip_tracefile);
108 			len = 0;
109 			break;
110 
111 		default:
112 			(void) snprintf(get_sum_line(), MAXLINE,
113 			    "%s %d (%s)", ripvers, rip->rip_cmd, cmdstr);
114 			len = 0;
115 			break;
116 		}
117 	}
118 
119 	if (flags & F_DTAIL) {
120 
121 		len = fraglen - 4;
122 		show_header("RIP:  ", "Routing Information Protocol", fraglen);
123 		show_space();
124 		(void) snprintf(get_line((char *)(uintptr_t)rip->rip_cmd -
125 		    dlc_header, 1), get_line_remain(), "Opcode = %d (%s)",
126 		    rip->rip_cmd, show_cmd(rip->rip_cmd));
127 		(void) snprintf(get_line((char *)(uintptr_t)rip->rip_vers -
128 		    dlc_header, 1), get_line_remain(), "Version = %d",
129 		    rip->rip_vers);
130 
131 		switch (rip->rip_cmd) {
132 		case RIPCMD_REQUEST:
133 		case RIPCMD_RESPONSE:
134 		case RIPCMD_POLL:
135 			show_space();
136 			(void) snprintf(get_line(0, 0), get_line_remain(),
137 			    "Destination                     Next Hop        "
138 			    "Tag    Metric");
139 			for (nip = rip->rip_nets; len >= sizeof (*nip); nip++,
140 			    len -= sizeof (*nip)) {
141 				if (nip->n_family == RIP_AF_AUTH) {
142 					nap = (const struct netauth *)nip;
143 					if (nap->a_type == RIP_AUTH_NONE) {
144 						(void) snprintf(get_line
145 						    ((char *)nip - dlc_header,
146 							sizeof (*nip)),
147 						    get_line_remain(),
148 						    " *** Auth None");
149 					} else if (nap->a_type == RIP_AUTH_PW) {
150 						(void) snprintf(get_line
151 						    ((char *)nip - dlc_header,
152 							sizeof (*nip)),
153 						    get_line_remain(),
154 						    " *** Auth PW \"%.*s\"",
155 						    RIP_AUTH_PW_LEN,
156 						    nap->au.au_pw);
157 					} else if (nap->a_type ==
158 					    RIP_AUTH_MD5) {
159 						(void) snprintf(get_line
160 						    ((char *)nip - dlc_header,
161 							sizeof (*nip)),
162 						    get_line_remain(),
163 						    " *** Auth MD5 pkt len %d, "
164 						    "keyid %d, sequence %08lX, "
165 						    "authlen %d",
166 						    ntohs(nap->au.a_md5.
167 							md5_pkt_len),
168 						    nap->au.a_md5.md5_keyid,
169 						    ntohl(nap->au.a_md5.
170 							md5_seqno),
171 						    ntohs(nap->au.a_md5.
172 							md5_auth_len));
173 						if (len - sizeof (*nip) >=
174 						    ntohs(nap->au.a_md5.
175 						    md5_auth_len))
176 							len -= ntohs(nap->au.
177 							    a_md5.md5_auth_len);
178 						else
179 							len = sizeof (*nip);
180 					} else {
181 						(void) snprintf(get_line
182 						    ((char *)nip - dlc_header,
183 							sizeof (*nip)),
184 						    get_line_remain(),
185 						    " *** Auth Type %d?",
186 						    ntohs(nap->a_type));
187 					}
188 					continue;
189 				}
190 				if (nip->n_family == RIP_AF_UNSPEC &&
191 				    rip->rip_cmd == RIPCMD_REQUEST) {
192 					(void) snprintf(get_line((char *)nip -
193 					    dlc_header, sizeof (*nip)),
194 					    get_line_remain(),
195 					    " *** All routes");
196 					continue;
197 				}
198 				if (nip->n_family != RIP_AF_INET) {
199 					(void) snprintf(get_line((char *)nip -
200 					    dlc_header, sizeof (*nip)),
201 					    get_line_remain(),
202 					    " *** Address Family %d?",
203 					    ntohs(nip->n_family));
204 					continue;
205 				}
206 				if (nip->n_dst == htonl(RIP_DEFAULT)) {
207 					(void) strcpy(addrstr, "default");
208 				} else {
209 					dst.s_addr = nip->n_dst;
210 					(void) strlcpy(addrstr, inet_ntoa(dst),
211 					    sizeof (addrstr));
212 				}
213 				if (nip->n_dst != htonl(RIP_DEFAULT) &&
214 				    rip->rip_vers >= RIPv2) {
215 					count = strlen(addrstr);
216 					mval = ntohl(nip->n_mask);
217 					/* LINTED */
218 					if (mval == INADDR_ANY) {
219 						/* No mask */;
220 					} else if ((mval + (mval & -mval)) ==
221 					    0) {
222 						(void) snprintf(addrstr + count,
223 						    sizeof (addrstr) - count,
224 						    "/%d", 33 - ffs(mval));
225 					} else {
226 						dst.s_addr = nip->n_mask;
227 						(void) snprintf(addrstr + count,
228 						    sizeof (addrstr) - count,
229 						    "/%s", inet_ntoa(dst));
230 					}
231 				}
232 				dst.s_addr = nip->n_nhop;
233 				mval = ntohl(nip->n_metric);
234 				(void) snprintf(get_line((char *)nip -
235 				    dlc_header, sizeof (*nip)),
236 				    get_line_remain(),
237 				    "%-31s %-15s %-6d %d%s",
238 				    addrstr,
239 				    dst.s_addr == htonl(INADDR_ANY) ?
240 				    "--" : addrtoname(AF_INET, &dst),
241 				    ntohs(nip->n_tag),
242 				    mval,
243 				    (mval == HOPCNT_INFINITY ?
244 					" (not reachable)" : ""));
245 			}
246 			break;
247 
248 		case RIPCMD_POLLENTRY:
249 			if (len < sizeof (*ep))
250 				break;
251 			len -= sizeof (*ep);
252 			ep = (const struct entryinfo *)rip->rip_nets;
253 			/* LINTED */
254 			sin = (const struct sockaddr_in *)&ep->rtu_dst;
255 			(void) snprintf(get_line((char *)sin - dlc_header,
256 			    sizeof (struct sockaddr)), get_line_remain(),
257 			    "Destination = %s %s",
258 			    inet_ntoa(sin->sin_addr),
259 			    addrtoname(AF_INET, (void *)&sin->sin_addr));
260 			/* LINTED */
261 			sin = (const struct sockaddr_in *)&ep->rtu_router;
262 			(void) snprintf(get_line((char *)sin - dlc_header,
263 			    sizeof (struct sockaddr)), get_line_remain(),
264 			    "Router      = %s %s",
265 			    inet_ntoa(sin->sin_addr),
266 			    addrtoname(AF_INET, (void *)&sin->sin_addr));
267 			(void) snprintf(get_line((char *)&ep->rtu_flags -
268 			    dlc_header, 2), get_line_remain(),
269 			    "Flags = %4x", (unsigned)ep->rtu_flags);
270 			(void) snprintf(get_line((char *)&ep->rtu_state -
271 			    dlc_header, 2), get_line_remain(),
272 			    "State = %d", ep->rtu_state);
273 			(void) snprintf(get_line((char *)&ep->rtu_timer -
274 			    dlc_header, 4), get_line_remain(),
275 			    "Timer = %d", ep->rtu_timer);
276 			(void) snprintf(get_line((char *)&ep->rtu_metric -
277 			    dlc_header, 4), get_line_remain(),
278 			    "Metric = %d", ep->rtu_metric);
279 			(void) snprintf(get_line((char *)&ep->int_flags -
280 			    dlc_header, 4), get_line_remain(),
281 			    "Int flags = %8x", ep->int_flags);
282 			(void) snprintf(get_line((char *)ep->int_name -
283 			    dlc_header, sizeof (ep->int_name)),
284 			    get_line_remain(),
285 			    "Int name = \"%.*s\"", sizeof (ep->int_name),
286 			    ep->int_name);
287 			break;
288 
289 		case RIPCMD_TRACEON:
290 		case RIPCMD_TRACEOFF:
291 			(void) snprintf(get_line((char *)rip->rip_tracefile -
292 			    dlc_header, 2), get_line_remain(),
293 			    "Trace file = %.*s", len, rip->rip_tracefile);
294 			len = 0;
295 			break;
296 		}
297 	}
298 
299 	return (fraglen - len);
300 }
301 
302 static char *
303 show_cmd(int c)
304 {
305 	switch (c) {
306 	case RIPCMD_REQUEST:
307 		return ("route request");
308 	case RIPCMD_RESPONSE:
309 		return ("route response");
310 	case RIPCMD_TRACEON:
311 		return ("route trace on");
312 	case RIPCMD_TRACEOFF:
313 		return ("route trace off");
314 	case RIPCMD_POLL:
315 		return ("route poll");
316 	case RIPCMD_POLLENTRY:
317 		return ("route poll entry");
318 	}
319 	return ("?");
320 }
321