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