]> The Tcpdump Group git mirrors - tcpdump/blob - print-rip.c
Update ND_PRINT() as a variadic macro
[tcpdump] / print-rip.c
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 */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <netdissect-stdinc.h>
31
32 #include <stdio.h>
33
34 #include "netdissect.h"
35 #include "addrtoname.h"
36 #include "extract.h"
37
38 #include "af.h"
39
40 static const char tstr[] = "[|rip]";
41
42 struct rip {
43 nd_uint8_t rip_cmd; /* request/response */
44 nd_uint8_t rip_vers; /* protocol version # */
45 nd_byte unused[2]; /* unused */
46 };
47
48 #define RIPCMD_REQUEST 1 /* want info */
49 #define RIPCMD_RESPONSE 2 /* responding to request */
50 #define RIPCMD_TRACEON 3 /* turn tracing on */
51 #define RIPCMD_TRACEOFF 4 /* turn it off */
52 #define RIPCMD_POLL 5 /* want info from everybody */
53 #define RIPCMD_POLLENTRY 6 /* poll for entry */
54
55 static const struct tok rip_cmd_values[] = {
56 { RIPCMD_REQUEST, "Request" },
57 { RIPCMD_RESPONSE, "Response" },
58 { RIPCMD_TRACEON, "Trace on" },
59 { RIPCMD_TRACEOFF, "Trace off" },
60 { RIPCMD_POLL, "Poll" },
61 { RIPCMD_POLLENTRY, "Poll Entry" },
62 { 0, NULL}
63 };
64
65 #define RIP_AUTHLEN 16
66 #define RIP_ROUTELEN 20
67
68 /*
69 * rfc 1723
70 *
71 * 0 1 2 3 3
72 * 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
73 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74 * | Command (1) | Version (1) | unused |
75 * +---------------+---------------+-------------------------------+
76 * | Address Family Identifier (2) | Route Tag (2) |
77 * +-------------------------------+-------------------------------+
78 * | IP Address (4) |
79 * +---------------------------------------------------------------+
80 * | Subnet Mask (4) |
81 * +---------------------------------------------------------------+
82 * | Next Hop (4) |
83 * +---------------------------------------------------------------+
84 * | Metric (4) |
85 * +---------------------------------------------------------------+
86 *
87 */
88
89 struct rip_netinfo {
90 nd_uint16_t rip_family;
91 nd_uint16_t rip_tag;
92 nd_uint32_t rip_dest;
93 nd_uint32_t rip_dest_mask;
94 nd_uint32_t rip_router;
95 nd_uint32_t rip_metric; /* cost of route */
96 };
97
98 static void
99 rip_entry_print_v1(netdissect_options *ndo,
100 const struct rip_netinfo *ni)
101 {
102 u_short family;
103
104 /* RFC 1058 */
105 family = EXTRACT_BE_U_2(ni->rip_family);
106 if (family != BSD_AFNUM_INET && family != 0) {
107 ND_PRINT("\n\t AFI %s, ", tok2str(bsd_af_values, "Unknown (%u)", family));
108 print_unknown_data(ndo, (const uint8_t *)&ni->rip_family, "\n\t ", RIP_ROUTELEN);
109 return;
110 }
111 if (EXTRACT_BE_U_2(ni->rip_tag) ||
112 EXTRACT_BE_U_4(ni->rip_dest_mask) ||
113 EXTRACT_BE_U_4(ni->rip_router)) {
114 /* MBZ fields not zero */
115 print_unknown_data(ndo, (const uint8_t *)&ni->rip_family, "\n\t ", RIP_ROUTELEN);
116 return;
117 }
118 if (family == 0) {
119 ND_PRINT("\n\t AFI 0, %s, metric: %u",
120 ipaddr_string(ndo, &ni->rip_dest),
121 EXTRACT_BE_U_4(ni->rip_metric));
122 return;
123 } /* BSD_AFNUM_INET */
124 ND_PRINT("\n\t %s, metric: %u",
125 ipaddr_string(ndo, &ni->rip_dest),
126 EXTRACT_BE_U_4(ni->rip_metric));
127 }
128
129 static unsigned
130 rip_entry_print_v2(netdissect_options *ndo,
131 const struct rip_netinfo *ni, const unsigned remaining)
132 {
133 u_short family;
134
135 family = EXTRACT_BE_U_2(ni->rip_family);
136 if (family == 0xFFFF) { /* variable-sized authentication structures */
137 uint16_t auth_type = EXTRACT_BE_U_2(ni->rip_tag);
138 if (auth_type == 2) {
139 const u_char *p = (const u_char *)&ni->rip_dest;
140 u_int i = 0;
141 ND_PRINT("\n\t Simple Text Authentication data: ");
142 for (; i < RIP_AUTHLEN; p++, i++)
143 ND_PRINT("%c",
144 ND_ISPRINT(EXTRACT_U_1(p)) ? EXTRACT_U_1(p) : '.');
145 } else if (auth_type == 3) {
146 ND_PRINT("\n\t Auth header:");
147 ND_PRINT(" Packet Len %u,", EXTRACT_BE_U_2((const uint8_t *)ni + 4));
148 ND_PRINT(" Key-ID %u,", EXTRACT_U_1((const uint8_t *)ni + 6));
149 ND_PRINT(" Auth Data Len %u,", EXTRACT_U_1((const uint8_t *)ni + 7));
150 ND_PRINT(" SeqNo %u,", EXTRACT_BE_U_4(ni->rip_dest_mask));
151 ND_PRINT(" MBZ %u,", EXTRACT_BE_U_4(ni->rip_router));
152 ND_PRINT(" MBZ %u", EXTRACT_BE_U_4(ni->rip_metric));
153 } else if (auth_type == 1) {
154 ND_PRINT("\n\t Auth trailer:");
155 print_unknown_data(ndo, (const uint8_t *)&ni->rip_dest, "\n\t ", remaining);
156 return remaining; /* AT spans till the packet end */
157 } else {
158 ND_PRINT("\n\t Unknown (%u) Authentication data:",
159 EXTRACT_BE_U_2(ni->rip_tag));
160 print_unknown_data(ndo, (const uint8_t *)&ni->rip_dest, "\n\t ", remaining);
161 }
162 } else if (family != BSD_AFNUM_INET && family != 0) {
163 ND_PRINT("\n\t AFI %s", tok2str(bsd_af_values, "Unknown (%u)", family));
164 print_unknown_data(ndo, (const uint8_t *)&ni->rip_tag, "\n\t ", RIP_ROUTELEN-2);
165 } else { /* BSD_AFNUM_INET or AFI 0 */
166 ND_PRINT("\n\t AFI %s, %15s/%-2d, tag 0x%04x, metric: %u, next-hop: ",
167 tok2str(bsd_af_values, "%u", family),
168 ipaddr_string(ndo, &ni->rip_dest),
169 mask2plen(EXTRACT_BE_U_4(ni->rip_dest_mask)),
170 EXTRACT_BE_U_2(ni->rip_tag),
171 EXTRACT_BE_U_4(ni->rip_metric));
172 if (EXTRACT_BE_U_4(ni->rip_router))
173 ND_PRINT("%s", ipaddr_string(ndo, &ni->rip_router));
174 else
175 ND_PRINT("self");
176 }
177 return sizeof (*ni);
178 }
179
180 void
181 rip_print(netdissect_options *ndo,
182 const u_char *dat, u_int length)
183 {
184 const struct rip *rp;
185 uint8_t vers, cmd;
186 const struct rip_netinfo *ni;
187 u_int i, j;
188
189 if (ndo->ndo_snapend < dat) {
190 ND_PRINT(" %s", tstr);
191 return;
192 }
193 i = ndo->ndo_snapend - dat;
194 if (i > length)
195 i = length;
196 if (i < sizeof(*rp)) {
197 ND_PRINT(" %s", tstr);
198 return;
199 }
200 i -= sizeof(*rp);
201
202 rp = (const struct rip *)dat;
203
204 vers = EXTRACT_U_1(rp->rip_vers);
205 ND_PRINT("%sRIPv%u",
206 (ndo->ndo_vflag >= 1) ? "\n\t" : "",
207 vers);
208
209 switch (vers) {
210 case 0:
211 /*
212 * RFC 1058.
213 *
214 * XXX - RFC 1058 says
215 *
216 * 0 Datagrams whose version number is zero are to be ignored.
217 * These are from a previous version of the protocol, whose
218 * packet format was machine-specific.
219 *
220 * so perhaps we should just dump the packet, in hex.
221 */
222 print_unknown_data(ndo, (const uint8_t *)&rp->rip_cmd, "\n\t", length);
223 break;
224 default:
225 /* dump version and lets see if we know the commands name*/
226 cmd = EXTRACT_U_1(rp->rip_cmd);
227 ND_PRINT(", %s, length: %u",
228 tok2str(rip_cmd_values,
229 "unknown command (%u)",
230 cmd),
231 length);
232
233 if (ndo->ndo_vflag < 1)
234 return;
235
236 switch (cmd) {
237 case RIPCMD_REQUEST:
238 case RIPCMD_RESPONSE:
239 j = length / sizeof(*ni);
240 ND_PRINT(", routes: %u%s", j, vers == 2 ? " or less" : "");
241 ni = (const struct rip_netinfo *)(rp + 1);
242 for (; i >= sizeof(*ni); ++ni) {
243 if (vers == 1)
244 {
245 rip_entry_print_v1(ndo, ni);
246 i -= sizeof(*ni);
247 }
248 else if (vers == 2)
249 i -= rip_entry_print_v2(ndo, ni, i);
250 else
251 break;
252 }
253 if (i)
254 ND_PRINT("%s", tstr);
255 break;
256
257 case RIPCMD_TRACEOFF:
258 case RIPCMD_POLL:
259 case RIPCMD_POLLENTRY:
260 break;
261
262 case RIPCMD_TRACEON:
263 /* fall through */
264 default:
265 if (ndo->ndo_vflag <= 1) {
266 if(!print_unknown_data(ndo, (const uint8_t *)rp, "\n\t", length))
267 return;
268 }
269 break;
270 }
271 /* do we want to see an additionally hexdump ? */
272 if (ndo->ndo_vflag> 1) {
273 if(!print_unknown_data(ndo, (const uint8_t *)rp, "\n\t", length))
274 return;
275 }
276 }
277 }
278
279