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