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
interpret_rip(int flags,struct rip * rip,int fraglen)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 *
show_cmd(int c)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
get_numtokens(unsigned int mask)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 *
rip_next_sec_entry(const struct rip_sec_entry * rsep,int len)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