xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_rip.c (revision 1e56f352c1c208679012bca47d552e127f5b1072)
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 #include <stdio.h>
27 #include <string.h>
28 #include <strings.h>
29 #include <fcntl.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #define	RIPVERSION	RIPv2
35 #include <protocols/routed.h>
36 #include "snoop.h"
37 
38 static const char *show_cmd(int);
39 static int get_numtokens(unsigned int);
40 static const struct rip_sec_entry *rip_next_sec_entry(
41     const struct rip_sec_entry *, 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 	const struct rip_sec_entry *rsep, *rsn;
50 	const struct rip_emetric *rep;
51 	const uint32_t *tokp;
52 	int len, count;
53 	const char *cmdstr, *auth;
54 	struct in_addr dst;
55 	uint32_t mval;
56 	const struct sockaddr_in *sin;
57 	/* Room for IP destination + "/" + IP mask */
58 	char addrstr[15+1+15+1];
59 	/* Room for "RIPv" + uint8_t as %d */
60 	char ripvers[4+3+1];
61 
62 	/* RIP header is 4 octets long */
63 	if ((len = fraglen - 4) < 0)
64 		return (0);
65 
66 	if (flags & F_SUM) {
67 		switch (rip->rip_cmd) {
68 		case RIPCMD_REQUEST:	cmdstr = "C";		break;
69 		case RIPCMD_RESPONSE:	cmdstr = "R";		break;
70 		case RIPCMD_TRACEON:	cmdstr = "Traceon";	break;
71 		case RIPCMD_TRACEOFF:	cmdstr = "Traceoff";	break;
72 		case RIPCMD_POLL:	cmdstr = "Poll";	break;
73 		case RIPCMD_POLLENTRY:	cmdstr = "Poll entry";	break;
74 		case RIPCMD_SEC_RESPONSE: cmdstr = "R - SEC";	break;
75 		case RIPCMD_SEC_T_RESPONSE: cmdstr = "R - SEC_T"; break;
76 		default: cmdstr = "?"; break;
77 		}
78 
79 		if (rip->rip_vers == RIPv1)
80 			(void) strlcpy(ripvers, "RIP", sizeof (ripvers));
81 		else
82 			(void) snprintf(ripvers, sizeof (ripvers), "RIPv%d",
83 			    rip->rip_vers);
84 
85 		switch (rip->rip_cmd) {
86 		case RIPCMD_REQUEST:
87 		case RIPCMD_RESPONSE:
88 		case RIPCMD_POLL:
89 			nip = rip->rip_nets;
90 			auth = "";
91 			if (len >= sizeof (*nip) &&
92 			    nip->n_family == RIP_AF_AUTH) {
93 				nap = (struct netauth *)nip;
94 				len -= sizeof (*nip);
95 				if (nap->a_type == RIP_AUTH_MD5 &&
96 				    len >= ntohs(nap->au.a_md5.md5_auth_len))
97 					len -= ntohs(nap->au.a_md5.
98 					    md5_auth_len);
99 				auth = " +Auth";
100 			}
101 			count = len / sizeof (*nip);
102 			len %= sizeof (*nip);
103 			(void) snprintf(get_sum_line(), MAXLINE,
104 			    "%s %s (%d destinations%s%s)", ripvers, cmdstr,
105 			    count, (len != 0 ? "?" : ""), auth);
106 			break;
107 
108 		case RIPCMD_TRACEON:
109 		case RIPCMD_TRACEOFF:
110 			(void) snprintf(get_sum_line(), MAXLINE,
111 			    "%s %s File=\"%.*s\"", ripvers, cmdstr, len,
112 			    rip->rip_tracefile);
113 			len = 0;
114 			break;
115 
116 		case RIPCMD_SEC_RESPONSE:
117 		case RIPCMD_SEC_T_RESPONSE:
118 			if (len < sizeof (rip->rip_tsol.rip_generation))
119 				break;
120 			len -= sizeof (rip->rip_tsol.rip_generation);
121 			count = 0;
122 			rsep = rip->rip_tsol.rip_sec_entry;
123 			while (len > 0) {
124 				rsn = rip_next_sec_entry(rsep, len);
125 				if (rsn == NULL)
126 					break;
127 				len -= (const char *)rsn - (const char *)rsep;
128 				rsep = rsn;
129 				count++;
130 			}
131 			(void) snprintf(get_sum_line(), MAXLINE,
132 			    "%s %s (%d destinations%s)", ripvers, cmdstr,
133 			    count, (len != 0 ? "?" : ""));
134 			break;
135 
136 		default:
137 			(void) snprintf(get_sum_line(), MAXLINE,
138 			    "%s %d (%s)", ripvers, rip->rip_cmd, cmdstr);
139 			len = 0;
140 			break;
141 		}
142 	}
143 
144 	if (flags & F_DTAIL) {
145 
146 		len = fraglen - 4;
147 		show_header("RIP:  ", "Routing Information Protocol", fraglen);
148 		show_space();
149 		(void) snprintf(get_line(0, 0), get_line_remain(),
150 		    "Opcode = %d (%s)", rip->rip_cmd,
151 		    show_cmd(rip->rip_cmd));
152 		(void) snprintf(get_line(0, 0), get_line_remain(),
153 		    "Version = %d", rip->rip_vers);
154 
155 		switch (rip->rip_cmd) {
156 		case RIPCMD_REQUEST:
157 		case RIPCMD_RESPONSE:
158 		case RIPCMD_POLL:
159 			show_space();
160 			(void) snprintf(get_line(0, 0), get_line_remain(),
161 			    "Destination                     Next Hop        "
162 			    "Tag    Metric");
163 			for (nip = rip->rip_nets; len >= sizeof (*nip); nip++,
164 			    len -= sizeof (*nip)) {
165 				if (nip->n_family == RIP_AF_AUTH) {
166 					nap = (const struct netauth *)nip;
167 					if (nap->a_type == RIP_AUTH_NONE) {
168 						(void) snprintf(get_line
169 						    ((char *)nip - dlc_header,
170 							sizeof (*nip)),
171 						    get_line_remain(),
172 						    " *** Auth None");
173 					} else if (nap->a_type == RIP_AUTH_PW) {
174 						(void) snprintf(get_line
175 						    ((char *)nip - dlc_header,
176 							sizeof (*nip)),
177 						    get_line_remain(),
178 						    " *** Auth PW \"%.*s\"",
179 						    RIP_AUTH_PW_LEN,
180 						    nap->au.au_pw);
181 					} else if (nap->a_type ==
182 					    RIP_AUTH_MD5) {
183 						(void) snprintf(get_line(0, 0),
184 						    get_line_remain(),
185 						    " *** Auth MD5 pkt len %d, "
186 						    "keyid %d, sequence %08lX, "
187 						    "authlen %d",
188 						    ntohs(nap->au.a_md5.
189 							md5_pkt_len),
190 						    nap->au.a_md5.md5_keyid,
191 						    (long)ntohl(nap->au.a_md5.
192 							md5_seqno),
193 						    ntohs(nap->au.a_md5.
194 							md5_auth_len));
195 						if (len - sizeof (*nip) >=
196 						    ntohs(nap->au.a_md5.
197 						    md5_auth_len))
198 							len -= ntohs(nap->au.
199 							    a_md5.md5_auth_len);
200 						else
201 							len = sizeof (*nip);
202 					} else {
203 						(void) snprintf(get_line
204 						    ((char *)nip - dlc_header,
205 							sizeof (*nip)),
206 						    get_line_remain(),
207 						    " *** Auth Type %d?",
208 						    ntohs(nap->a_type));
209 					}
210 					continue;
211 				}
212 				if (nip->n_family == RIP_AF_UNSPEC &&
213 				    rip->rip_cmd == RIPCMD_REQUEST) {
214 					(void) snprintf(get_line(0, 0),
215 					    get_line_remain(),
216 					    " *** All routes");
217 					continue;
218 				}
219 				if (nip->n_family != RIP_AF_INET) {
220 					(void) snprintf(get_line(0, 0),
221 					    get_line_remain(),
222 					    " *** Address Family %d?",
223 					    ntohs(nip->n_family));
224 					continue;
225 				}
226 				if (nip->n_dst == htonl(RIP_DEFAULT)) {
227 					(void) strcpy(addrstr, "default");
228 				} else {
229 					dst.s_addr = nip->n_dst;
230 					(void) strlcpy(addrstr, inet_ntoa(dst),
231 					    sizeof (addrstr));
232 				}
233 				if (nip->n_dst != htonl(RIP_DEFAULT) &&
234 				    rip->rip_vers >= RIPv2) {
235 					count = strlen(addrstr);
236 					mval = ntohl(nip->n_mask);
237 					/* LINTED */
238 					if (mval == INADDR_ANY) {
239 						/* No mask */;
240 					} else if ((mval + (mval & -mval)) ==
241 					    0) {
242 						(void) snprintf(addrstr + count,
243 						    sizeof (addrstr) - count,
244 						    "/%d", 33 - ffs(mval));
245 					} else {
246 						dst.s_addr = nip->n_mask;
247 						(void) snprintf(addrstr + count,
248 						    sizeof (addrstr) - count,
249 						    "/%s", inet_ntoa(dst));
250 					}
251 				}
252 				dst.s_addr = nip->n_nhop;
253 				mval = ntohl(nip->n_metric);
254 				(void) snprintf(get_line(0, 0),
255 				    get_line_remain(),
256 				    "%-31s %-15s %-6d %d%s",
257 				    addrstr,
258 				    dst.s_addr == htonl(INADDR_ANY) ?
259 				    "--" : addrtoname(AF_INET, &dst),
260 				    ntohs(nip->n_tag),
261 				    mval,
262 				    (mval == HOPCNT_INFINITY ?
263 					" (not reachable)" : ""));
264 			}
265 			break;
266 
267 		case RIPCMD_POLLENTRY:
268 			if (len < sizeof (*ep))
269 				break;
270 			len -= sizeof (*ep);
271 			ep = (const struct entryinfo *)rip->rip_nets;
272 			/* LINTED */
273 			sin = (const struct sockaddr_in *)&ep->rtu_dst;
274 			(void) snprintf(get_line(0, 0), get_line_remain(),
275 			    "Destination = %s %s",
276 			    inet_ntoa(sin->sin_addr),
277 			    addrtoname(AF_INET, (void *)&sin->sin_addr));
278 			/* LINTED */
279 			sin = (const struct sockaddr_in *)&ep->rtu_router;
280 			(void) snprintf(get_line(0, 0), get_line_remain(),
281 			    "Router      = %s %s",
282 			    inet_ntoa(sin->sin_addr),
283 			    addrtoname(AF_INET, (void *)&sin->sin_addr));
284 			(void) snprintf(get_line(0, 0), get_line_remain(),
285 			    "Flags = %4x", (unsigned)ep->rtu_flags);
286 			(void) snprintf(get_line(0, 0), get_line_remain(),
287 			    "State = %d", ep->rtu_state);
288 			(void) snprintf(get_line(0, 0), get_line_remain(),
289 			    "Timer = %d", ep->rtu_timer);
290 			(void) snprintf(get_line(0, 0), get_line_remain(),
291 			    "Metric = %d", ep->rtu_metric);
292 			(void) snprintf(get_line(0, 0), get_line_remain(),
293 			    "Int flags = %8x", ep->int_flags);
294 			(void) snprintf(get_line(0, 0), get_line_remain(),
295 			    "Int name = \"%.*s\"", sizeof (ep->int_name),
296 			    ep->int_name);
297 			break;
298 
299 		case RIPCMD_SEC_RESPONSE:
300 		case RIPCMD_SEC_T_RESPONSE:
301 			if (len < sizeof (rip->rip_tsol.rip_generation))
302 				break;
303 			len -= sizeof (rip->rip_tsol.rip_generation);
304 			show_space();
305 			(void) snprintf(get_line(0, 0), get_line_remain(),
306 			    "Generation = %u",
307 			    (unsigned)ntohl(rip->rip_tsol.rip_generation));
308 			rsep = rip->rip_tsol.rip_sec_entry;
309 			(void) snprintf(get_line(0, 0), get_line_remain(),
310 			    "Address         E-METRIC");
311 			rsep = rip->rip_tsol.rip_sec_entry;
312 			while (len > 0) {
313 				char *cp;
314 				int blen, num;
315 
316 				rsn = rip_next_sec_entry(rsep, len);
317 				if (rsn == NULL)
318 					break;
319 				dst.s_addr = rsep->rip_dst;
320 				cp = get_line(0, 0);
321 				blen = get_line_remain();
322 				(void) snprintf(cp, blen, "%-16s ",
323 				    inet_ntoa(dst));
324 				cp += 17;
325 				blen -= 17;
326 				rep = rsep->rip_emetric;
327 				for (count = ntohl(rsep->rip_count); count > 0;
328 				    count--) {
329 					(void) snprintf(cp, blen, "metric=%d",
330 					    ntohs(rep->rip_metric));
331 					blen -= strlen(cp);
332 					cp += strlen(cp);
333 					tokp = rep->rip_token;
334 					num = get_numtokens(
335 					    ntohs(rep->rip_mask));
336 					/* advance to the next emetric */
337 					rep = (const struct rip_emetric *)
338 					    &rep->rip_token[num];
339 					if (num > 0) {
340 						(void) snprintf(cp, blen,
341 						    ",tokens=%lx",
342 						    (long)ntohl(*tokp));
343 						tokp++;
344 						num--;
345 					} else {
346 						(void) strlcpy(cp, ",no tokens",
347 						    blen);
348 					}
349 					while (num > 0) {
350 						blen -= strlen(cp);
351 						cp += strlen(cp);
352 						(void) snprintf(cp, blen,
353 						    ",%lx",
354 						    (long)ntohl(*tokp));
355 						tokp++;
356 						num--;
357 					}
358 					blen -= strlen(cp);
359 					cp += strlen(cp);
360 				}
361 				if (rsep->rip_count == 0) {
362 					(void) strlcpy(cp,
363 					    "NULL (not reachable)", blen);
364 				}
365 				len -= (const char *)rsn - (const char *)rsep;
366 				rsep = rsn;
367 			}
368 			break;
369 
370 		case RIPCMD_TRACEON:
371 		case RIPCMD_TRACEOFF:
372 			(void) snprintf(get_line(0, 0), get_line_remain(),
373 			    "Trace file = %.*s", len, rip->rip_tracefile);
374 			len = 0;
375 			break;
376 		}
377 	}
378 
379 	return (fraglen - len);
380 }
381 
382 static const char *
383 show_cmd(int c)
384 {
385 	switch (c) {
386 	case RIPCMD_REQUEST:
387 		return ("route request");
388 	case RIPCMD_RESPONSE:
389 		return ("route response");
390 	case RIPCMD_TRACEON:
391 		return ("route trace on");
392 	case RIPCMD_TRACEOFF:
393 		return ("route trace off");
394 	case RIPCMD_POLL:
395 		return ("route poll");
396 	case RIPCMD_POLLENTRY:
397 		return ("route poll entry");
398 	case RIPCMD_SEC_RESPONSE:
399 		return ("route sec response");
400 	case RIPCMD_SEC_T_RESPONSE:
401 		return ("route sec_t response");
402 	}
403 	return ("?");
404 }
405 
406 static int
407 get_numtokens(unsigned int mask)
408 {
409 	int num = 0;
410 
411 	while (mask != 0) {
412 		num++;
413 		mask &= mask - 1;
414 	}
415 	return (num);
416 }
417 
418 static const struct rip_sec_entry *
419 rip_next_sec_entry(const struct rip_sec_entry *rsep, int len)
420 {
421 	const struct rip_emetric *rep;
422 	const char *limit = (const char *)rsep + len;
423 	long count;
424 
425 	if ((const char *)(rep = rsep->rip_emetric) > limit)
426 		return (NULL);
427 	count = ntohl(rsep->rip_count);
428 	while (count > 0) {
429 		if ((const char *)rep->rip_token > limit)
430 			return (NULL);
431 		rep = (struct rip_emetric *)
432 		    &rep->rip_token[get_numtokens(ntohs(rep->rip_mask))];
433 		if ((const char *)rep > limit)
434 			return (NULL);
435 		count--;
436 	}
437 	return ((const struct rip_sec_entry *)rep);
438 }
439