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