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