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