Home | History | Annotate | Line # | Download | only in dist
print-egp.c revision 1.1.1.7
      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 #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
    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
    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