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