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