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