1 /*
2 * Copyright (c) 1989, 1990, 1991, 1993, 1994, 1996
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22 /* \summary: Routing Information Protocol (RIP) printer */
23
24 /* specification: RFC 1058, RFC 2453, RFC 4822 */
25
26 #include <config.h>
27
28 #include "netdissect-stdinc.h"
29
30 #include "netdissect.h"
31 #include "addrtoname.h"
32 #include "extract.h"
33
34 #include "af.h"
35
36
37 /*
38 * RFC 1058 and RFC 2453 header of packet.
39 *
40 * 0 1 2 3 3
41 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
42 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43 * | Command (1) | Version (1) | unused |
44 * +---------------+---------------+-------------------------------+
45 */
46 struct rip {
47 nd_uint8_t rip_cmd; /* request/response */
48 nd_uint8_t rip_vers; /* protocol version # */
49 nd_byte unused[2]; /* unused */
50 };
51
52 #define RIPCMD_REQUEST 1 /* want info */
53 #define RIPCMD_RESPONSE 2 /* responding to request */
54 #define RIPCMD_TRACEON 3 /* turn tracing on */
55 #define RIPCMD_TRACEOFF 4 /* turn it off */
56 /* 5 is reserved */
57 #define RIPCMD_TRIGREQ 6
58 #define RIPCMD_TRIGRESP 7
59 #define RIPCMD_TRIGACK 8
60 #define RIPCMD_UPDREQ 9
61 #define RIPCMD_UPDRESP 10
62 #define RIPCMD_UPDACK 11
63
64 static const struct tok rip_cmd_values[] = {
65 { RIPCMD_REQUEST, "Request" },
66 { RIPCMD_RESPONSE, "Response" },
67 { RIPCMD_TRACEON, "Trace on" },
68 { RIPCMD_TRACEOFF, "Trace off" },
69 { RIPCMD_TRIGREQ, "Triggered Request" },
70 { RIPCMD_TRIGRESP, "Triggered Response" },
71 { RIPCMD_TRIGACK, "Triggered Acknowledgement" },
72 { RIPCMD_UPDREQ, "Update Request" },
73 { RIPCMD_UPDRESP, "Update Response" },
74 { RIPCMD_UPDACK, "Update Acknowledge" },
75 { 0, NULL}
76 };
77
78 #define RIP_AUTHLEN 16
79 #define RIP_ROUTELEN 20
80
81 /*
82 * First 4 bytes of all RIPv1/RIPv2 entries.
83 */
84 struct rip_entry_header {
85 nd_uint16_t rip_family;
86 nd_uint16_t rip_tag;
87 };
88
89 /*
90 * RFC 1058 entry.
91 *
92 * 0 1 2 3 3
93 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
94 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
95 * | Address Family Identifier (2) | must be zero (2) |
96 * +-------------------------------+-------------------------------+
97 * | IP Address (4) |
98 * +---------------------------------------------------------------+
99 * | must be zero (4) |
100 * +---------------------------------------------------------------+
101 * | must be zero (4) |
102 * +---------------------------------------------------------------+
103 * | Metric (4) |
104 * +---------------------------------------------------------------+
105 */
106 struct rip_netinfo_v1 {
107 nd_uint16_t rip_family;
108 nd_byte rip_mbz1[2];
109 nd_ipv4 rip_dest;
110 nd_byte rip_mbz2[4];
111 nd_byte rip_mbz3[4];
112 nd_uint32_t rip_metric; /* cost of route */
113 };
114
115
116 /*
117 * RFC 2453 route entry
118 *
119 * 0 1 2 3 3
120 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
121 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
122 * | Address Family Identifier (2) | Route Tag (2) |
123 * +-------------------------------+-------------------------------+
124 * | IP Address (4) |
125 * +---------------------------------------------------------------+
126 * | Subnet Mask (4) |
127 * +---------------------------------------------------------------+
128 * | Next Hop (4) |
129 * +---------------------------------------------------------------+
130 * | Metric (4) |
131 * +---------------------------------------------------------------+
132 *
133 */
134
135 struct rip_netinfo_v2 {
136 nd_uint16_t rip_family;
137 nd_uint16_t rip_tag;
138 nd_ipv4 rip_dest;
139 nd_uint32_t rip_dest_mask;
140 nd_ipv4 rip_router;
141 nd_uint32_t rip_metric; /* cost of route */
142 };
143
144 /*
145 * RFC 2453 authentication entry
146 *
147 * 0 1 2 3 3
148 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
149 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
150 * | 0xFFFF | Authentication Type (2) |
151 * +-------------------------------+-------------------------------+
152 * - Authentication (16) -
153 * +---------------------------------------------------------------+
154 */
155
156 struct rip_auth_v2 {
157 nd_uint16_t rip_family;
158 nd_uint16_t rip_tag;
159 nd_byte rip_auth[16];
160 };
161
162 /*
163 * RFC 4822 Cryptographic Authentication entry.
164 *
165 * 0 1 2 3 3
166 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
167 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
168 * | RIPv2 Packet Length | Key ID | Auth Data Len |
169 * +---------------+---------------+---------------+---------------+
170 * | Sequence Number (non-decreasing) |
171 * +---------------+---------------+---------------+---------------+
172 * | reserved must be zero |
173 * +---------------+---------------+---------------+---------------+
174 * | reserved must be zero |
175 * +---------------+---------------+---------------+---------------+
176 */
177 struct rip_auth_crypto_v2 {
178 nd_uint16_t rip_packet_len;
179 nd_uint8_t rip_key_id;
180 nd_uint8_t rip_auth_data_len;
181 nd_uint32_t rip_seq_num;
182 nd_byte rip_mbz1[4];
183 nd_byte rip_mbz2[4];
184 };
185
186 static unsigned
rip_entry_print_v1(netdissect_options * ndo,const u_char * p,unsigned remaining)187 rip_entry_print_v1(netdissect_options *ndo, const u_char *p,
188 unsigned remaining)
189 {
190 const struct rip_entry_header *eh = (const struct rip_entry_header *)p;
191 u_short family;
192 const struct rip_netinfo_v1 *ni = (const struct rip_netinfo_v1 *)p;
193
194 /* RFC 1058 */
195 if (remaining < RIP_ROUTELEN)
196 return (0);
197 ND_TCHECK_SIZE(ni);
198 family = GET_BE_U_2(ni->rip_family);
199 if (family != BSD_AFNUM_INET && family != 0) {
200 ND_PRINT("\n\t AFI %s, ", tok2str(bsd_af_values, "Unknown (%u)", family));
201 print_unknown_data(ndo, p + sizeof(*eh), "\n\t ", RIP_ROUTELEN - sizeof(*eh));
202 return (RIP_ROUTELEN);
203 }
204 if (GET_BE_U_2(ni->rip_mbz1) ||
205 GET_BE_U_4(ni->rip_mbz2) ||
206 GET_BE_U_4(ni->rip_mbz3)) {
207 /* MBZ fields not zero */
208 print_unknown_data(ndo, p, "\n\t ", RIP_ROUTELEN);
209 return (RIP_ROUTELEN);
210 }
211 if (family == 0) {
212 ND_PRINT("\n\t AFI 0, %s, metric: %u",
213 GET_IPADDR_STRING(ni->rip_dest),
214 GET_BE_U_4(ni->rip_metric));
215 return (RIP_ROUTELEN);
216 } /* BSD_AFNUM_INET */
217 ND_PRINT("\n\t %s, metric: %u",
218 GET_IPADDR_STRING(ni->rip_dest),
219 GET_BE_U_4(ni->rip_metric));
220 return (RIP_ROUTELEN);
221 trunc:
222 return 0;
223 }
224
225 static unsigned
rip_entry_print_v2(netdissect_options * ndo,const u_char * p,unsigned remaining)226 rip_entry_print_v2(netdissect_options *ndo, const u_char *p,
227 unsigned remaining)
228 {
229 const struct rip_entry_header *eh = (const struct rip_entry_header *)p;
230 u_short family;
231 const struct rip_netinfo_v2 *ni;
232
233 if (remaining < sizeof(*eh))
234 return (0);
235 ND_TCHECK_SIZE(eh);
236 family = GET_BE_U_2(eh->rip_family);
237 if (family == 0xFFFF) { /* variable-sized authentication structures */
238 uint16_t auth_type = GET_BE_U_2(eh->rip_tag);
239
240 p += sizeof(*eh);
241 remaining -= sizeof(*eh);
242 if (auth_type == 2) {
243 ND_PRINT("\n\t Simple Text Authentication data: ");
244 nd_printjnp(ndo, p, RIP_AUTHLEN);
245 } else if (auth_type == 3) {
246 const struct rip_auth_crypto_v2 *ch;
247
248 ch = (const struct rip_auth_crypto_v2 *)p;
249 ND_TCHECK_SIZE(ch);
250 if (remaining < sizeof(*ch))
251 return (0);
252 ND_PRINT("\n\t Auth header:");
253 ND_PRINT(" Packet Len %u,",
254 GET_BE_U_2(ch->rip_packet_len));
255 ND_PRINT(" Key-ID %u,", GET_U_1(ch->rip_key_id));
256 ND_PRINT(" Auth Data Len %u,",
257 GET_U_1(ch->rip_auth_data_len));
258 ND_PRINT(" SeqNo %u,", GET_BE_U_4(ch->rip_seq_num));
259 ND_PRINT(" MBZ %u,", GET_BE_U_4(ch->rip_mbz1));
260 ND_PRINT(" MBZ %u", GET_BE_U_4(ch->rip_mbz2));
261 } else if (auth_type == 1) {
262 ND_PRINT("\n\t Auth trailer:");
263 print_unknown_data(ndo, p, "\n\t ", remaining);
264 return (sizeof(*eh) + remaining); /* AT spans till the packet end */
265 } else {
266 ND_PRINT("\n\t Unknown (%u) Authentication data:",
267 auth_type);
268 print_unknown_data(ndo, p, "\n\t ", remaining);
269 return (sizeof(*eh) + remaining); /* we don't know how long this is, so we go to the packet end */
270 }
271 } else if (family != BSD_AFNUM_INET && family != 0) {
272 ND_PRINT("\n\t AFI %s", tok2str(bsd_af_values, "Unknown (%u)", family));
273 print_unknown_data(ndo, p + sizeof(*eh), "\n\t ", RIP_ROUTELEN - sizeof(*eh));
274 } else { /* BSD_AFNUM_INET or AFI 0 */
275 ni = (const struct rip_netinfo_v2 *)p;
276 ND_TCHECK_SIZE(ni);
277 if (remaining < sizeof(*ni))
278 return (0);
279 ND_PRINT("\n\t AFI %s, %15s/%-2d, tag 0x%04x, metric: %u, next-hop: ",
280 tok2str(bsd_af_values, "%u", family),
281 GET_IPADDR_STRING(ni->rip_dest),
282 mask2plen(GET_BE_U_4(ni->rip_dest_mask)),
283 GET_BE_U_2(ni->rip_tag),
284 GET_BE_U_4(ni->rip_metric));
285 if (GET_BE_U_4(ni->rip_router))
286 ND_PRINT("%s", GET_IPADDR_STRING(ni->rip_router));
287 else
288 ND_PRINT("self");
289 }
290 return (RIP_ROUTELEN);
291 trunc:
292 return 0;
293 }
294
295 void
rip_print(netdissect_options * ndo,const u_char * dat,u_int length)296 rip_print(netdissect_options *ndo,
297 const u_char *dat, u_int length)
298 {
299 const struct rip *rp;
300 uint8_t vers, cmd;
301 const u_char *p;
302 u_int len, routecount;
303 unsigned entry_size;
304
305 ndo->ndo_protocol = "rip";
306 if (ndo->ndo_snapend < dat) {
307 nd_print_trunc(ndo);
308 return;
309 }
310 len = ND_BYTES_AVAILABLE_AFTER(dat);
311 if (len > length)
312 len = length;
313 if (len < sizeof(*rp)) {
314 nd_print_trunc(ndo);
315 return;
316 }
317 len -= sizeof(*rp);
318
319 rp = (const struct rip *)dat;
320
321 ND_TCHECK_SIZE(rp);
322 vers = GET_U_1(rp->rip_vers);
323 ND_PRINT("%sRIPv%u",
324 (ndo->ndo_vflag >= 1) ? "\n\t" : "",
325 vers);
326
327 /* dump version and lets see if we know the commands name*/
328 cmd = GET_U_1(rp->rip_cmd);
329 ND_PRINT(", %s, length: %u",
330 tok2str(rip_cmd_values, "unknown command (%u)", cmd),
331 length);
332
333 if (ndo->ndo_vflag < 1)
334 return;
335
336 switch (cmd) {
337
338 case RIPCMD_REQUEST:
339 case RIPCMD_RESPONSE:
340 switch (vers) {
341
342 case 1:
343 routecount = length / RIP_ROUTELEN;
344 ND_PRINT(", routes: %u", routecount);
345 p = (const u_char *)(rp + 1);
346 while (len != 0) {
347 entry_size = rip_entry_print_v1(ndo, p, len);
348 if (entry_size == 0) {
349 /* Error */
350 nd_print_trunc(ndo);
351 break;
352 }
353 if (len < entry_size) {
354 ND_PRINT(" [remaining entries length %u < %u]",
355 len, entry_size);
356 nd_print_invalid(ndo);
357 break;
358 }
359 p += entry_size;
360 len -= entry_size;
361 }
362 break;
363
364 case 2:
365 routecount = length / RIP_ROUTELEN;
366 ND_PRINT(", routes: %u or less", routecount);
367 p = (const u_char *)(rp + 1);
368 while (len != 0) {
369 entry_size = rip_entry_print_v2(ndo, p, len);
370 if (entry_size == 0) {
371 /* Error */
372 nd_print_trunc(ndo);
373 break;
374 }
375 if (len < entry_size) {
376 ND_PRINT(" [remaining entries length %u < %u]",
377 len, entry_size);
378 nd_print_invalid(ndo);
379 break;
380 }
381 p += entry_size;
382 len -= entry_size;
383 }
384 break;
385
386 default:
387 ND_PRINT(", unknown version");
388 break;
389 }
390 break;
391
392 case RIPCMD_TRACEON:
393 case RIPCMD_TRACEOFF:
394 case RIPCMD_TRIGREQ:
395 case RIPCMD_TRIGRESP:
396 case RIPCMD_TRIGACK:
397 case RIPCMD_UPDREQ:
398 case RIPCMD_UPDRESP:
399 case RIPCMD_UPDACK:
400 break;
401
402 default:
403 if (ndo->ndo_vflag <= 1) {
404 if (!print_unknown_data(ndo, (const uint8_t *)rp, "\n\t", length))
405 return;
406 }
407 break;
408 }
409 /* do we want to see an additionally hexdump ? */
410 if (ndo->ndo_vflag> 1) {
411 if (!print_unknown_data(ndo, (const uint8_t *)rp, "\n\t", length))
412 return;
413 }
414 trunc:
415 return;
416 }
417