xref: /netbsd-src/external/bsd/tcpdump/dist/print-egp.c (revision 3117ece4fc4a4ca4489ba793710b60b0d26bab6c)
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
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
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