]> The Tcpdump Group git mirrors - tcpdump/blob - print-egp.c
Revert "Clean a bunch of fuzzed files not to fuzz the container."
[tcpdump] / print-egp.c
1 /*
2 * Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Lawrence Berkeley Laboratory,
11 * Berkeley, CA. The name of the University may not be used to
12 * endorse or promote products derived from this software without
13 * specific prior written permission.
14 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17 *
18 * Initial contribution from Jeff Honig (jch@MITCHELL.CIT.CORNELL.EDU).
19 */
20
21 /* \summary: Exterior Gateway Protocol (EGP) printer */
22
23 /* specification: RFC 827 */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include "netdissect-stdinc.h"
30
31 #define ND_LONGJMP_FROM_TCHECK
32 #include "netdissect.h"
33 #include "addrtoname.h"
34 #include "extract.h"
35
36 struct egp_packet {
37 nd_uint8_t egp_version;
38 #define EGP_VERSION 2
39 nd_uint8_t egp_type;
40 #define EGPT_ACQUIRE 3
41 #define EGPT_REACH 5
42 #define EGPT_POLL 2
43 #define EGPT_UPDATE 1
44 #define EGPT_ERROR 8
45 nd_uint8_t egp_code;
46 #define EGPC_REQUEST 0
47 #define EGPC_CONFIRM 1
48 #define EGPC_REFUSE 2
49 #define EGPC_CEASE 3
50 #define EGPC_CEASEACK 4
51 #define EGPC_HELLO 0
52 #define EGPC_HEARDU 1
53 nd_uint8_t egp_status;
54 #define EGPS_UNSPEC 0
55 #define EGPS_ACTIVE 1
56 #define EGPS_PASSIVE 2
57 #define EGPS_NORES 3
58 #define EGPS_ADMIN 4
59 #define EGPS_GODOWN 5
60 #define EGPS_PARAM 6
61 #define EGPS_PROTO 7
62 #define EGPS_INDET 0
63 #define EGPS_UP 1
64 #define EGPS_DOWN 2
65 #define EGPS_UNSOL 0x80
66 nd_uint16_t egp_checksum;
67 nd_uint16_t egp_as;
68 nd_uint16_t egp_sequence;
69 union {
70 nd_uint16_t egpu_hello;
71 nd_uint8_t egpu_gws[2];
72 nd_uint16_t egpu_reason;
73 #define EGPR_UNSPEC 0
74 #define EGPR_BADHEAD 1
75 #define EGPR_BADDATA 2
76 #define EGPR_NOREACH 3
77 #define EGPR_XSPOLL 4
78 #define EGPR_NORESP 5
79 #define EGPR_UVERSION 6
80 } egp_handg;
81 #define egp_hello egp_handg.egpu_hello
82 #define egp_intgw egp_handg.egpu_gws[0]
83 #define egp_extgw egp_handg.egpu_gws[1]
84 #define egp_reason egp_handg.egpu_reason
85 union {
86 nd_uint16_t egpu_poll;
87 nd_ipv4 egpu_sourcenet;
88 } egp_pands;
89 #define egp_poll egp_pands.egpu_poll
90 #define egp_sourcenet egp_pands.egpu_sourcenet
91 };
92
93 static const struct tok egp_type_str[] = {
94 { EGPT_ACQUIRE, "acquire" },
95 { EGPT_REACH, "reach" },
96 { EGPT_POLL, "poll" },
97 { EGPT_UPDATE, "update" },
98 { EGPT_ERROR, "error" },
99 { 0, NULL }
100 };
101
102 static const struct tok egp_acquire_codes_str[] = {
103 { EGPC_REQUEST, "request" },
104 { EGPC_CONFIRM, "confirm" },
105 { EGPC_REFUSE, "refuse" },
106 { EGPC_CEASE, "cease" },
107 { EGPC_CEASEACK, "cease_ack" },
108 { 0, NULL }
109 };
110
111 static const struct tok egp_acquire_status_str[] = {
112 { EGPS_UNSPEC, "unspecified" },
113 { EGPS_ACTIVE, "active_mode" },
114 { EGPS_PASSIVE, "passive_mode" },
115 { EGPS_NORES, "insufficient_resources" },
116 { EGPS_ADMIN, "administratively_prohibited" },
117 { EGPS_GODOWN, "going_down" },
118 { EGPS_PARAM, "parameter_violation" },
119 { EGPS_PROTO, "protocol_violation" },
120 { 0, NULL }
121 };
122
123 static const struct tok egp_reach_codes_str[] = {
124 { EGPC_HELLO, "hello" },
125 { EGPC_HEARDU, "i-h-u" },
126 { 0, NULL }
127 };
128
129 static const struct tok egp_status_updown_str[] = {
130 { EGPS_INDET, "indeterminate" },
131 { EGPS_UP, "up" },
132 { EGPS_DOWN, "down" },
133 { 0, NULL }
134 };
135
136 static const struct tok egp_reasons_str[] = {
137 { EGPR_UNSPEC, "unspecified" },
138 { EGPR_BADHEAD, "bad_EGP_header_format" },
139 { EGPR_BADDATA, "bad_EGP_data_field_format" },
140 { EGPR_NOREACH, "reachability_info_unavailable" },
141 { EGPR_XSPOLL, "excessive_polling_rate" },
142 { EGPR_NORESP, "no_response" },
143 { EGPR_UVERSION, "unsupported_version" },
144 { 0, NULL }
145 };
146
147 static void
148 egpnr_print(netdissect_options *ndo,
149 const struct egp_packet *egp, u_int length)
150 {
151 const uint8_t *cp;
152 uint32_t addr;
153 uint32_t net;
154 u_int netlen;
155 u_int gateways, distances, networks;
156 u_int intgw, extgw, t_gateways;
157 const char *comma;
158
159 addr = GET_IPV4_TO_NETWORK_ORDER(egp->egp_sourcenet);
160 if (IN_CLASSA(addr)) {
161 net = addr & IN_CLASSA_NET;
162 netlen = 1;
163 } else if (IN_CLASSB(addr)) {
164 net = addr & IN_CLASSB_NET;
165 netlen = 2;
166 } else if (IN_CLASSC(addr)) {
167 net = addr & IN_CLASSC_NET;
168 netlen = 3;
169 } else {
170 net = 0;
171 netlen = 0;
172 }
173 cp = (const uint8_t *)(egp + 1);
174 length -= sizeof(*egp);
175
176 intgw = GET_U_1(egp->egp_intgw);
177 extgw = GET_U_1(egp->egp_extgw);
178 t_gateways = intgw + extgw;
179 for (gateways = 0; gateways < t_gateways; ++gateways) {
180 /* Pickup host part of gateway address */
181 addr = 0;
182 if (length < 4 - netlen)
183 goto invalid;
184 ND_TCHECK_LEN(cp, 4 - netlen);
185 switch (netlen) {
186
187 case 1:
188 addr = GET_U_1(cp);
189 cp++;
190 /* fall through */
191 case 2:
192 addr = (addr << 8) | GET_U_1(cp);
193 cp++;
194 /* fall through */
195 case 3:
196 addr = (addr << 8) | GET_U_1(cp);
197 cp++;
198 break;
199 }
200 addr |= net;
201 length -= 4 - netlen;
202 if (length < 1)
203 goto invalid;
204 distances = GET_U_1(cp);
205 cp++;
206 length--;
207 ND_PRINT(" %s %s ",
208 gateways < intgw ? "int" : "ext",
209 ipaddr_string(ndo, (const u_char *)&addr)); /* local buffer, not packet data; don't use GET_IPADDR_STRING() */
210
211 comma = "";
212 ND_PRINT("(");
213 while (distances != 0) {
214 if (length < 2)
215 goto invalid;
216 ND_PRINT("%sd%u:", comma, GET_U_1(cp));
217 cp++;
218 comma = ", ";
219 networks = GET_U_1(cp);
220 cp++;
221 length -= 2;
222 while (networks != 0) {
223 /* Pickup network number */
224 if (length < 1)
225 goto invalid;
226 addr = ((uint32_t) GET_U_1(cp)) << 24;
227 cp++;
228 length--;
229 if (IN_CLASSB(addr)) {
230 if (length < 1)
231 goto invalid;
232 addr |= ((uint32_t) GET_U_1(cp)) << 16;
233 cp++;
234 length--;
235 } else if (!IN_CLASSA(addr)) {
236 if (length < 2)
237 goto invalid;
238 addr |= ((uint32_t) GET_U_1(cp)) << 16;
239 cp++;
240 addr |= ((uint32_t) GET_U_1(cp)) << 8;
241 cp++;
242 length -= 2;
243 }
244 ND_PRINT(" %s", ipaddr_string(ndo, (const u_char *)&addr)); /* local buffer, not packet data; don't use GET_IPADDR_STRING() */
245 networks--;
246 }
247 distances--;
248 }
249 ND_PRINT(")");
250 }
251 return;
252 invalid:
253 nd_print_invalid(ndo);
254 }
255
256 void
257 egp_print(netdissect_options *ndo,
258 const uint8_t *bp, u_int length)
259 {
260 const struct egp_packet *egp;
261 u_int version;
262 u_int type;
263 u_int code;
264 u_int status;
265
266 ndo->ndo_protocol = "egp";
267 egp = (const struct egp_packet *)bp;
268 ND_ICHECKMSG_ZU("packet length", length, <, sizeof(*egp));
269 ND_TCHECK_SIZE(egp);
270
271 version = GET_U_1(egp->egp_version);
272 if (!ndo->ndo_vflag) {
273 ND_PRINT("EGPv%u, AS %u, seq %u, length %u",
274 version,
275 GET_BE_U_2(egp->egp_as),
276 GET_BE_U_2(egp->egp_sequence),
277 length);
278 return;
279 } else
280 ND_PRINT("EGPv%u, length %u",
281 version,
282 length);
283
284 if (version != EGP_VERSION) {
285 ND_PRINT("[version %u]", version);
286 return;
287 }
288
289 type = GET_U_1(egp->egp_type);
290 ND_PRINT(" %s", tok2str(egp_type_str, "[type %u]", type));
291 code = GET_U_1(egp->egp_code);
292 status = GET_U_1(egp->egp_status);
293
294 switch (type) {
295 case EGPT_ACQUIRE:
296 ND_PRINT(" %s", tok2str(egp_acquire_codes_str, "[code %u]", code));
297 switch (code) {
298 case EGPC_REQUEST:
299 case EGPC_CONFIRM:
300 switch (status) {
301 case EGPS_UNSPEC:
302 case EGPS_ACTIVE:
303 case EGPS_PASSIVE:
304 ND_PRINT(" %s", tok2str(egp_acquire_status_str, "%u", status));
305 break;
306
307 default:
308 ND_PRINT(" [status %u]", status);
309 break;
310 }
311 ND_PRINT(" hello:%u poll:%u",
312 GET_BE_U_2(egp->egp_hello),
313 GET_BE_U_2(egp->egp_poll));
314 break;
315
316 case EGPC_REFUSE:
317 case EGPC_CEASE:
318 case EGPC_CEASEACK:
319 switch (status ) {
320 case EGPS_UNSPEC:
321 case EGPS_NORES:
322 case EGPS_ADMIN:
323 case EGPS_GODOWN:
324 case EGPS_PARAM:
325 case EGPS_PROTO:
326 ND_PRINT(" %s", tok2str(egp_acquire_status_str, "%u", status));
327 break;
328
329 default:
330 ND_PRINT("[status %u]", status);
331 break;
332 }
333 break;
334 }
335 break;
336
337 case EGPT_REACH:
338 ND_PRINT(" %s", tok2str(egp_reach_codes_str, "[reach code %u]", code));
339 switch (code) {
340 case EGPC_HELLO:
341 case EGPC_HEARDU:
342 ND_PRINT(" state:%s", tok2str(egp_status_updown_str, "%u", status));
343 break;
344 }
345 break;
346
347 case EGPT_POLL:
348 ND_PRINT(" state:%s", tok2str(egp_status_updown_str, "%u", status));
349 ND_PRINT(" net:%s", GET_IPADDR_STRING(egp->egp_sourcenet));
350 break;
351
352 case EGPT_UPDATE:
353 if (status & EGPS_UNSOL) {
354 status &= ~EGPS_UNSOL;
355 ND_PRINT(" unsolicited");
356 }
357 ND_PRINT(" state:%s", tok2str(egp_status_updown_str, "%u", status));
358 ND_PRINT(" %s int %u ext %u",
359 GET_IPADDR_STRING(egp->egp_sourcenet),
360 GET_U_1(egp->egp_intgw),
361 GET_U_1(egp->egp_extgw));
362 if (ndo->ndo_vflag)
363 egpnr_print(ndo, egp, length);
364 break;
365
366 case EGPT_ERROR:
367 ND_PRINT(" state:%s", tok2str(egp_status_updown_str, "%u", status));
368 ND_PRINT(" %s", tok2str(egp_reasons_str, "[reason %u]", GET_BE_U_2(egp->egp_reason)));
369 break;
370 }
371 return;
372 invalid:
373 nd_print_invalid(ndo);
374 }