print-egp.c revision 1.7 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 (at) MITCHELL.CIT.CORNELL.EDU).
19 */
20
21 #include <sys/cdefs.h>
22 #ifndef lint
23 __RCSID("$NetBSD: print-egp.c,v 1.7 2023/08/17 20:19:40 christos Exp $");
24 #endif
25
26 /* \summary: Exterior Gateway Protocol (EGP) printer */
27
28 /* specification: RFC 827 */
29
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33
34 #include "netdissect-stdinc.h"
35
36 #include "netdissect.h"
37 #include "addrtoname.h"
38 #include "extract.h"
39
40 struct egp_packet {
41 nd_uint8_t egp_version;
42 #define EGP_VERSION 2
43 nd_uint8_t egp_type;
44 #define EGPT_ACQUIRE 3
45 #define EGPT_REACH 5
46 #define EGPT_POLL 2
47 #define EGPT_UPDATE 1
48 #define EGPT_ERROR 8
49 nd_uint8_t egp_code;
50 #define EGPC_REQUEST 0
51 #define EGPC_CONFIRM 1
52 #define EGPC_REFUSE 2
53 #define EGPC_CEASE 3
54 #define EGPC_CEASEACK 4
55 #define EGPC_HELLO 0
56 #define EGPC_HEARDU 1
57 nd_uint8_t egp_status;
58 #define EGPS_UNSPEC 0
59 #define EGPS_ACTIVE 1
60 #define EGPS_PASSIVE 2
61 #define EGPS_NORES 3
62 #define EGPS_ADMIN 4
63 #define EGPS_GODOWN 5
64 #define EGPS_PARAM 6
65 #define EGPS_PROTO 7
66 #define EGPS_INDET 0
67 #define EGPS_UP 1
68 #define EGPS_DOWN 2
69 #define EGPS_UNSOL 0x80
70 nd_uint16_t egp_checksum;
71 nd_uint16_t egp_as;
72 nd_uint16_t egp_sequence;
73 union {
74 nd_uint16_t egpu_hello;
75 nd_uint8_t egpu_gws[2];
76 nd_uint16_t egpu_reason;
77 #define EGPR_UNSPEC 0
78 #define EGPR_BADHEAD 1
79 #define EGPR_BADDATA 2
80 #define EGPR_NOREACH 3
81 #define EGPR_XSPOLL 4
82 #define EGPR_NORESP 5
83 #define EGPR_UVERSION 6
84 } egp_handg;
85 #define egp_hello egp_handg.egpu_hello
86 #define egp_intgw egp_handg.egpu_gws[0]
87 #define egp_extgw egp_handg.egpu_gws[1]
88 #define egp_reason egp_handg.egpu_reason
89 union {
90 nd_uint16_t egpu_poll;
91 nd_ipv4 egpu_sourcenet;
92 } egp_pands;
93 #define egp_poll egp_pands.egpu_poll
94 #define egp_sourcenet egp_pands.egpu_sourcenet
95 };
96
97 static const char *egp_acquire_codes[] = {
98 "request",
99 "confirm",
100 "refuse",
101 "cease",
102 "cease_ack"
103 };
104
105 static const char *egp_acquire_status[] = {
106 "unspecified",
107 "active_mode",
108 "passive_mode",
109 "insufficient_resources",
110 "administratively_prohibited",
111 "going_down",
112 "parameter_violation",
113 "protocol_violation"
114 };
115
116 static const char *egp_reach_codes[] = {
117 "hello",
118 "i-h-u"
119 };
120
121 static const char *egp_status_updown[] = {
122 "indeterminate",
123 "up",
124 "down"
125 };
126
127 static const char *egp_reasons[] = {
128 "unspecified",
129 "bad_EGP_header_format",
130 "bad_EGP_data_field_format",
131 "reachability_info_unavailable",
132 "excessive_polling_rate",
133 "no_response",
134 "unsupported_version"
135 };
136
137 static void
138 egpnr_print(netdissect_options *ndo,
139 const struct egp_packet *egp, u_int length)
140 {
141 const uint8_t *cp;
142 uint32_t addr;
143 uint32_t net;
144 u_int netlen;
145 u_int gateways, distances, networks;
146 u_int intgw, extgw, t_gateways;
147 const char *comma;
148
149 addr = GET_IPV4_TO_NETWORK_ORDER(egp->egp_sourcenet);
150 if (IN_CLASSA(addr)) {
151 net = addr & IN_CLASSA_NET;
152 netlen = 1;
153 } else if (IN_CLASSB(addr)) {
154 net = addr & IN_CLASSB_NET;
155 netlen = 2;
156 } else if (IN_CLASSC(addr)) {
157 net = addr & IN_CLASSC_NET;
158 netlen = 3;
159 } else {
160 net = 0;
161 netlen = 0;
162 }
163 cp = (const uint8_t *)(egp + 1);
164 length -= sizeof(*egp);
165
166 intgw = GET_U_1(egp->egp_intgw);
167 extgw = GET_U_1(egp->egp_extgw);
168 t_gateways = intgw + extgw;
169 for (gateways = 0; gateways < t_gateways; ++gateways) {
170 /* Pickup host part of gateway address */
171 addr = 0;
172 if (length < 4 - netlen)
173 goto trunc;
174 ND_TCHECK_LEN(cp, 4 - netlen);
175 switch (netlen) {
176
177 case 1:
178 addr = GET_U_1(cp);
179 cp++;
180 /* fall through */
181 case 2:
182 addr = (addr << 8) | GET_U_1(cp);
183 cp++;
184 /* fall through */
185 case 3:
186 addr = (addr << 8) | GET_U_1(cp);
187 cp++;
188 break;
189 }
190 addr |= net;
191 length -= 4 - netlen;
192 if (length < 1)
193 goto trunc;
194 distances = GET_U_1(cp);
195 cp++;
196 length--;
197 ND_PRINT(" %s %s ",
198 gateways < intgw ? "int" : "ext",
199 ipaddr_string(ndo, (const u_char *)&addr)); /* local buffer, not packet data; don't use GET_IPADDR_STRING() */
200
201 comma = "";
202 ND_PRINT("(");
203 while (distances != 0) {
204 if (length < 2)
205 goto trunc;
206 ND_PRINT("%sd%u:", comma, GET_U_1(cp));
207 cp++;
208 comma = ", ";
209 networks = GET_U_1(cp);
210 cp++;
211 length -= 2;
212 while (networks != 0) {
213 /* Pickup network number */
214 if (length < 1)
215 goto trunc;
216 addr = ((uint32_t) GET_U_1(cp)) << 24;
217 cp++;
218 length--;
219 if (IN_CLASSB(addr)) {
220 if (length < 1)
221 goto trunc;
222 addr |= ((uint32_t) GET_U_1(cp)) << 16;
223 cp++;
224 length--;
225 } else if (!IN_CLASSA(addr)) {
226 if (length < 2)
227 goto trunc;
228 addr |= ((uint32_t) GET_U_1(cp)) << 16;
229 cp++;
230 addr |= ((uint32_t) GET_U_1(cp)) << 8;
231 cp++;
232 length -= 2;
233 }
234 ND_PRINT(" %s", ipaddr_string(ndo, (const u_char *)&addr)); /* local buffer, not packet data; don't use GET_IPADDR_STRING() */
235 networks--;
236 }
237 distances--;
238 }
239 ND_PRINT(")");
240 }
241 return;
242 trunc:
243 nd_print_trunc(ndo);
244 }
245
246 void
247 egp_print(netdissect_options *ndo,
248 const uint8_t *bp, u_int length)
249 {
250 const struct egp_packet *egp;
251 u_int version;
252 u_int type;
253 u_int code;
254 u_int status;
255
256 ndo->ndo_protocol = "egp";
257 egp = (const struct egp_packet *)bp;
258 if (length < sizeof(*egp) || !ND_TTEST_SIZE(egp)) {
259 nd_print_trunc(ndo);
260 return;
261 }
262
263 version = GET_U_1(egp->egp_version);
264 if (!ndo->ndo_vflag) {
265 ND_PRINT("EGPv%u, AS %u, seq %u, length %u",
266 version,
267 GET_BE_U_2(egp->egp_as),
268 GET_BE_U_2(egp->egp_sequence),
269 length);
270 return;
271 } else
272 ND_PRINT("EGPv%u, length %u",
273 version,
274 length);
275
276 if (version != EGP_VERSION) {
277 ND_PRINT("[version %u]", version);
278 return;
279 }
280
281 type = GET_U_1(egp->egp_type);
282 code = GET_U_1(egp->egp_code);
283 status = GET_U_1(egp->egp_status);
284
285 switch (type) {
286 case EGPT_ACQUIRE:
287 ND_PRINT(" acquire");
288 switch (code) {
289 case EGPC_REQUEST:
290 case EGPC_CONFIRM:
291 ND_PRINT(" %s", egp_acquire_codes[code]);
292 switch (status) {
293 case EGPS_UNSPEC:
294 case EGPS_ACTIVE:
295 case EGPS_PASSIVE:
296 ND_PRINT(" %s", egp_acquire_status[status]);
297 break;
298
299 default:
300 ND_PRINT(" [status %u]", status);
301 break;
302 }
303 ND_PRINT(" hello:%u poll:%u",
304 GET_BE_U_2(egp->egp_hello),
305 GET_BE_U_2(egp->egp_poll));
306 break;
307
308 case EGPC_REFUSE:
309 case EGPC_CEASE:
310 case EGPC_CEASEACK:
311 ND_PRINT(" %s", egp_acquire_codes[code]);
312 switch (status ) {
313 case EGPS_UNSPEC:
314 case EGPS_NORES:
315 case EGPS_ADMIN:
316 case EGPS_GODOWN:
317 case EGPS_PARAM:
318 case EGPS_PROTO:
319 ND_PRINT(" %s", egp_acquire_status[status]);
320 break;
321
322 default:
323 ND_PRINT("[status %u]", status);
324 break;
325 }
326 break;
327
328 default:
329 ND_PRINT("[code %u]", code);
330 break;
331 }
332 break;
333
334 case EGPT_REACH:
335 switch (code) {
336
337 case EGPC_HELLO:
338 case EGPC_HEARDU:
339 ND_PRINT(" %s", egp_reach_codes[code]);
340 if (status <= EGPS_DOWN)
341 ND_PRINT(" state:%s", egp_status_updown[status]);
342 else
343 ND_PRINT(" [status %u]", status);
344 break;
345
346 default:
347 ND_PRINT("[reach code %u]", code);
348 break;
349 }
350 break;
351
352 case EGPT_POLL:
353 ND_PRINT(" poll");
354 if (status <= EGPS_DOWN)
355 ND_PRINT(" state:%s", egp_status_updown[status]);
356 else
357 ND_PRINT(" [status %u]", status);
358 ND_PRINT(" net:%s", GET_IPADDR_STRING(egp->egp_sourcenet));
359 break;
360
361 case EGPT_UPDATE:
362 ND_PRINT(" update");
363 if (status & EGPS_UNSOL) {
364 status &= ~EGPS_UNSOL;
365 ND_PRINT(" unsolicited");
366 }
367 if (status <= EGPS_DOWN)
368 ND_PRINT(" state:%s", egp_status_updown[status]);
369 else
370 ND_PRINT(" [status %u]", status);
371 ND_PRINT(" %s int %u ext %u",
372 GET_IPADDR_STRING(egp->egp_sourcenet),
373 GET_U_1(egp->egp_intgw),
374 GET_U_1(egp->egp_extgw));
375 if (ndo->ndo_vflag)
376 egpnr_print(ndo, egp, length);
377 break;
378
379 case EGPT_ERROR:
380 ND_PRINT(" error");
381 if (status <= EGPS_DOWN)
382 ND_PRINT(" state:%s", egp_status_updown[status]);
383 else
384 ND_PRINT(" [status %u]", status);
385
386 if (GET_BE_U_2(egp->egp_reason) <= EGPR_UVERSION)
387 ND_PRINT(" %s",
388 egp_reasons[GET_BE_U_2(egp->egp_reason)]);
389 else
390 ND_PRINT(" [reason %u]", GET_BE_U_2(egp->egp_reason));
391 break;
392
393 default:
394 ND_PRINT("[type %u]", type);
395 break;
396 }
397 }
398