static int print_report(netdissect_options *ndo, const u_char *bp, const u_char *ep, u_int len) { uint32_t mask, origin; u_int metric, done; u_int i, width; while (len > 0) { if (len < 3) { ND_PRINT(" [|]"); return (0); } ND_TCHECK_3(bp); mask = (uint32_t)0xff << 24 | GET_U_1(bp) << 16 | GET_U_1(bp + 1) << 8 | GET_U_1(bp + 2); width = 1; if (GET_U_1(bp)) width = 2; if (GET_U_1(bp + 1)) width = 3; if (GET_U_1(bp + 2)) width = 4; ND_PRINT("\n\tMask %s", intoa(htonl(mask))); bp += 3; len -= 3; do { if (bp + width + 1 > ep) { ND_PRINT(" [|]"); return (0); } if (len < width + 1) { ND_PRINT("\n\t [Truncated Report]"); return (0); } origin = 0; for (i = 0; i < width; ++i) { ND_TCHECK_1(bp); origin = origin << 8 | GET_U_1(bp); bp++; } for ( ; i < 4; ++i) origin <<= 8; ND_TCHECK_1(bp); metric = GET_U_1(bp); bp++; done = metric & 0x80; metric &= 0x7f; ND_PRINT("\n\t %s metric %u", intoa(htonl(origin)), metric); len -= width + 1; } while (!done); } return (0); trunc: return (-1); }
/* * Print RRCP requests */ void rrcp_print(netdissect_options *ndo, const u_char *cp, u_int length _U_, const struct lladdr_info *src, const struct lladdr_info *dst) { uint8_t rrcp_proto; uint8_t rrcp_opcode; ndo->ndo_protocol = "rrcp"; ND_TCHECK_1(cp + RRCP_PROTO_OFFSET); rrcp_proto = EXTRACT_U_1(cp + RRCP_PROTO_OFFSET); ND_TCHECK_1(cp + RRCP_OPCODE_ISREPLY_OFFSET); rrcp_opcode = EXTRACT_U_1((cp + RRCP_OPCODE_ISREPLY_OFFSET)) & RRCP_OPCODE_MASK; if (src != NULL && dst != NULL) { ND_PRINT("%s > %s, ", (src->addr_string)(ndo, src->addr), (dst->addr_string)(ndo, dst->addr)); } ND_PRINT("%s %s", tok2str(proto_values,"RRCP-0x%02x",rrcp_proto), ((EXTRACT_U_1(cp + RRCP_OPCODE_ISREPLY_OFFSET)) & RRCP_ISREPLY) ? "reply" : "query"); if (rrcp_proto==1){ ND_PRINT(": %s", tok2str(opcode_values,"unknown opcode (0x%02x)",rrcp_opcode)); } if (rrcp_opcode==1 || rrcp_opcode==2){ ND_TCHECK_6(cp + RRCP_REG_ADDR_OFFSET); ND_PRINT(" addr=0x%04x, data=0x%08x", EXTRACT_LE_U_2(cp + RRCP_REG_ADDR_OFFSET), EXTRACT_LE_U_4(cp + RRCP_REG_DATA_OFFSET)); } if (rrcp_proto==1){ ND_TCHECK_2(cp + RRCP_AUTHKEY_OFFSET); ND_PRINT(", auth=0x%04x", EXTRACT_BE_U_2(cp + RRCP_AUTHKEY_OFFSET)); } if (rrcp_proto==1 && rrcp_opcode==0 && ((EXTRACT_U_1(cp + RRCP_OPCODE_ISREPLY_OFFSET)) & RRCP_ISREPLY)){ ND_TCHECK_4(cp + RRCP_VENDOR_ID_OFFSET); ND_PRINT(" downlink_port=%u, uplink_port=%u, uplink_mac=%s, vendor_id=%08x ,chip_id=%04x ", EXTRACT_U_1(cp + RRCP_DOWNLINK_PORT_OFFSET), EXTRACT_U_1(cp + RRCP_UPLINK_PORT_OFFSET), etheraddr_string(ndo, cp + RRCP_UPLINK_MAC_OFFSET), EXTRACT_BE_U_4(cp + RRCP_VENDOR_ID_OFFSET), EXTRACT_BE_U_2(cp + RRCP_CHIP_ID_OFFSET)); }else if (rrcp_opcode==1 || rrcp_opcode==2 || rrcp_proto==2){ ND_TCHECK_4(cp + RRCP_COOKIE2_OFFSET); ND_PRINT(", cookie=0x%08x%08x ", EXTRACT_BE_U_4(cp + RRCP_COOKIE2_OFFSET), EXTRACT_BE_U_4(cp + RRCP_COOKIE1_OFFSET)); } return; trunc: nd_print_trunc(ndo); }
void timed_print(netdissect_options *ndo, const u_char *bp) { const struct tsp *tsp = (const struct tsp *)bp; uint8_t tsp_type; int sec, usec; ndo->ndo_protocol = "timed"; ND_TCHECK_1(tsp->tsp_type); tsp_type = EXTRACT_U_1(tsp->tsp_type); if (tsp_type < TSPTYPENUMBER) ND_PRINT("TSP_%s", tsptype[tsp_type]); else ND_PRINT("(tsp_type %#x)", tsp_type); ND_TCHECK_1(tsp->tsp_vers); ND_PRINT(" vers %u", EXTRACT_U_1(tsp->tsp_vers)); ND_TCHECK_2(tsp->tsp_seq); ND_PRINT(" seq %u", EXTRACT_BE_U_2(tsp->tsp_seq)); switch (tsp_type) { case TSP_LOOP: ND_TCHECK_1(tsp->tsp_hopcnt); ND_PRINT(" hopcnt %u", EXTRACT_U_1(tsp->tsp_hopcnt)); break; case TSP_SETTIME: case TSP_ADJTIME: case TSP_SETDATE: case TSP_SETDATEREQ: ND_TCHECK_8(&tsp->tsp_time); sec = EXTRACT_BE_S_4(tsp->tsp_time.tv_sec); usec = EXTRACT_BE_S_4(tsp->tsp_time.tv_usec); /* XXX The comparison below is always false? */ if (usec < 0) /* invalid, skip the rest of the packet */ return; ND_PRINT(" time "); if (sec < 0 && usec != 0) { sec++; if (sec == 0) ND_PRINT("-"); usec = 1000000 - usec; } ND_PRINT("%d.%06d", sec, usec); break; } ND_PRINT(" name "); if (nd_printzp(ndo, tsp->tsp_name, sizeof(tsp->tsp_name), ndo->ndo_snapend)) goto trunc; return; trunc: nd_print_trunc(ndo); }
/* Print a single OpenFlow message. */ static const u_char * of_header_body_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) { uint8_t version, type; uint16_t length; uint32_t xid; if (ep < cp + OF_HEADER_LEN) goto invalid; /* version */ ND_TCHECK_1(cp); version = EXTRACT_U_1(cp); cp += 1; /* type */ ND_TCHECK_1(cp); type = EXTRACT_U_1(cp); cp += 1; /* length */ ND_TCHECK_2(cp); length = EXTRACT_BE_U_2(cp); cp += 2; /* xid */ ND_TCHECK_4(cp); xid = EXTRACT_BE_U_4(cp); cp += 4; /* Message length includes the header length and a message always includes * the basic header. A message length underrun fails decoding of the rest of * the current packet. At the same time, try decoding as much of the current * message as possible even when it does not end within the current TCP * segment. */ if (length < OF_HEADER_LEN) { of_header_print(ndo, version, type, length, xid); goto invalid; } /* Decode known protocol versions further without printing the header (the * type decoding is version-specific. */ switch (version) { case OF_VER_1_0: return of10_header_body_print(ndo, cp, ep, type, length, xid); default: of_header_print(ndo, version, type, length, xid); ND_TCHECK_LEN(cp, length - OF_HEADER_LEN); return cp + length - OF_HEADER_LEN; /* done with current message */ } invalid: /* fail current packet */ ND_PRINT("%s", istr); ND_TCHECK_LEN(cp, ep - cp); return ep; trunc: ND_PRINT("%s", tstr); return ep; }
void hsrp_print(netdissect_options *ndo, const u_char *bp, u_int len) { const struct hsrp *hp = (const struct hsrp *) bp; uint8_t version; ndo->ndo_protocol = "hsrp"; ND_TCHECK_1(hp->hsrp_version); version = GET_U_1(hp->hsrp_version); ND_PRINT("HSRPv%u", version); if (version != 0) return; ND_TCHECK_1(hp->hsrp_op_code); ND_PRINT("-"); ND_PRINT("%s ", tok2strary(op_code_str, "unknown (%u)", GET_U_1(hp->hsrp_op_code))); ND_PRINT("%u: ", len); ND_TCHECK_1(hp->hsrp_state); ND_PRINT("state=%s ", tok2str(states, "Unknown (%u)", GET_U_1(hp->hsrp_state))); ND_TCHECK_1(hp->hsrp_group); ND_PRINT("group=%u ", GET_U_1(hp->hsrp_group)); ND_TCHECK_1(hp->hsrp_reserved); if (GET_U_1(hp->hsrp_reserved) != 0) { ND_PRINT("[reserved=%u!] ", GET_U_1(hp->hsrp_reserved)); } ND_TCHECK_4(hp->hsrp_virtaddr); ND_PRINT("addr=%s", ipaddr_string(ndo, hp->hsrp_virtaddr)); if (ndo->ndo_vflag) { ND_PRINT(" hellotime="); unsigned_relts_print(ndo, GET_U_1(hp->hsrp_hellotime)); ND_PRINT(" holdtime="); unsigned_relts_print(ndo, GET_U_1(hp->hsrp_holdtime)); ND_PRINT(" priority=%u", GET_U_1(hp->hsrp_priority)); ND_PRINT(" auth=\""); if (nd_printn(ndo, hp->hsrp_authdata, sizeof(hp->hsrp_authdata), ndo->ndo_snapend)) { ND_PRINT("\""); goto trunc; } ND_PRINT("\""); } return; trunc: nd_print_trunc(ndo); }
static void ahcp1_body_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) { uint8_t type, mbz; uint16_t body_len; if (cp + AHCP1_BODY_MIN_LEN > ep) goto invalid; /* Type */ ND_TCHECK_1(cp); type = EXTRACT_U_1(cp); cp += 1; /* MBZ */ ND_TCHECK_1(cp); mbz = EXTRACT_U_1(cp); cp += 1; /* Length */ ND_TCHECK_2(cp); body_len = EXTRACT_BE_U_2(cp); cp += 2; if (ndo->ndo_vflag) { ND_PRINT("\n\t%s", tok2str(ahcp1_msg_str, "Unknown-%u", type)); if (mbz != 0) ND_PRINT(", MBZ %u", mbz); ND_PRINT(", Length %u", body_len); } if (cp + body_len > ep) goto invalid; /* Options */ if (ndo->ndo_vflag >= 2) ahcp1_options_print(ndo, cp, cp + body_len); /* not ep (ignore extra data) */ else ND_TCHECK_LEN(cp, body_len); return; invalid: ND_PRINT("%s", istr); ND_TCHECK_LEN(cp, ep - cp); return; trunc: nd_print_trunc(ndo); }
/* * Print NTP control message requests and responses */ static void ntp_control_print(netdissect_options *ndo, const struct ntp_control_data *cd, u_int length) { uint8_t control, R, E, M, opcode; uint16_t sequence, status, assoc, offset, count; if (length < NTP_CTRLMSG_MINLEN) goto invalid; ND_TCHECK_1(cd->control); control = EXTRACT_U_1(cd->control); R = (control & 0x80) != 0; E = (control & 0x40) != 0; M = (control & 0x20) != 0; opcode = control & 0x1f; ND_PRINT(", %s, %s, %s, OpCode=%u\n", R ? "Response" : "Request", E ? "Error" : "OK", M ? "More" : "Last", opcode); ND_TCHECK_2(cd->sequence); sequence = EXTRACT_BE_U_2(cd->sequence); ND_PRINT("\tSequence=%hu", sequence); ND_TCHECK_2(cd->status); status = EXTRACT_BE_U_2(cd->status); ND_PRINT(", Status=%#hx", status); ND_TCHECK_2(cd->assoc); assoc = EXTRACT_BE_U_2(cd->assoc); ND_PRINT(", Assoc.=%hu", assoc); ND_TCHECK_2(cd->offset); offset = EXTRACT_BE_U_2(cd->offset); ND_PRINT(", Offset=%hu", offset); ND_TCHECK_2(cd->count); count = EXTRACT_BE_U_2(cd->count); ND_PRINT(", Count=%hu", count); if (NTP_CTRLMSG_MINLEN + count > length) goto invalid; if (count != 0) { ND_TCHECK_LEN(cd->data, count); ND_PRINT("\n\tTO-BE-DONE: data not interpreted"); } return; invalid: nd_print_invalid(ndo); ND_TCHECK_LEN(cd, length); return; trunc: nd_print_trunc(ndo); }
static void ahcp1_options_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) { uint8_t option_no, option_len; while (cp < ep) { /* Option no */ ND_TCHECK_1(cp); option_no = EXTRACT_U_1(cp); cp += 1; ND_PRINT("\n\t %s", tok2str(ahcp1_opt_str, "Unknown-%u", option_no)); if (option_no == AHCP1_OPT_PAD || option_no == AHCP1_OPT_MANDATORY) continue; /* Length */ if (cp + 1 > ep) goto invalid; ND_TCHECK_1(cp); option_len = EXTRACT_U_1(cp); cp += 1; if (cp + option_len > ep) goto invalid; /* Value */ if (option_no <= AHCP1_OPT_MAX && data_decoders[option_no] != NULL) { if (data_decoders[option_no](ndo, cp, cp + option_len) < 0) break; /* truncated and already marked up */ } else { ND_PRINT(" (Length %u)", option_len); ND_TCHECK_LEN(cp, option_len); } cp += option_len; } return; invalid: ND_PRINT("%s", istr); ND_TCHECK_LEN(cp, ep - cp); return; trunc: nd_print_trunc(ndo); }
static int stp_print_config_bpdu(netdissect_options *ndo, const struct stp_bpdu_ *stp_bpdu, u_int length) { uint8_t bpdu_flags; ND_TCHECK_1(stp_bpdu->flags); bpdu_flags = EXTRACT_U_1(stp_bpdu->flags); ND_PRINT(", Flags [%s]", bittok2str(stp_bpdu_flag_values, "none", bpdu_flags)); ND_TCHECK_2(stp_bpdu->port_id); ND_PRINT(", bridge-id %s.%04x, length %u", stp_print_bridge_id((const u_char *)&stp_bpdu->bridge_id), EXTRACT_BE_U_2(stp_bpdu->port_id), length); /* in non-verbose mode just print the bridge-id */ if (!ndo->ndo_vflag) { return 1; } ND_TCHECK_2(stp_bpdu->forward_delay); ND_PRINT("\n\tmessage-age %.2fs, max-age %.2fs" ", hello-time %.2fs, forwarding-delay %.2fs", (float) EXTRACT_BE_U_2(stp_bpdu->message_age) / STP_TIME_BASE, (float) EXTRACT_BE_U_2(stp_bpdu->max_age) / STP_TIME_BASE, (float) EXTRACT_BE_U_2(stp_bpdu->hello_time) / STP_TIME_BASE, (float) EXTRACT_BE_U_2(stp_bpdu->forward_delay) / STP_TIME_BASE); ND_PRINT("\n\troot-id %s, root-pathcost %u", stp_print_bridge_id((const u_char *)&stp_bpdu->root_id), EXTRACT_BE_U_4(stp_bpdu->root_path_cost)); /* Port role is only valid for 802.1w */ if (EXTRACT_U_1(stp_bpdu->protocol_version) == STP_PROTO_RAPID) { ND_PRINT(", port-role %s", tok2str(rstp_obj_port_role_values, "Unknown", RSTP_EXTRACT_PORT_ROLE(bpdu_flags))); } return 1; trunc: return 0; }
static void ipnet_print(netdissect_options *ndo, const u_char *p, u_int length, u_int caplen) { const ipnet_hdr_t *hdr; if (caplen < sizeof(ipnet_hdr_t)) goto trunc; if (ndo->ndo_eflag) ipnet_hdr_print(ndo, p, length); length -= sizeof(ipnet_hdr_t); caplen -= sizeof(ipnet_hdr_t); hdr = (const ipnet_hdr_t *)p; p += sizeof(ipnet_hdr_t); ND_TCHECK_1(hdr->iph_family); switch (EXTRACT_U_1(hdr->iph_family)) { case IPH_AF_INET: ip_print(ndo, p, length); break; case IPH_AF_INET6: ip6_print(ndo, p, length); break; default: if (!ndo->ndo_eflag) ipnet_hdr_print(ndo, (const u_char *)hdr, length + sizeof(ipnet_hdr_t)); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); break; } return; trunc: ND_PRINT(" %s", tstr); }
/* LCP config options */ static u_int print_lcp_config_options(netdissect_options *ndo, const u_char *p, u_int length) { u_int opt, len; if (length < 2) return 0; ND_TCHECK_2(p); opt = EXTRACT_U_1(p); len = EXTRACT_U_1(p + 1); if (length < len) return 0; if (len < 2) { if (opt < NUM_LCPOPTS) ND_PRINT("\n\t %s Option (0x%02x), length %u (length bogus, should be >= 2)", lcpconfopts[opt], opt, len); else ND_PRINT("\n\tunknown LCP option 0x%02x", opt); return 0; } if (opt < NUM_LCPOPTS) ND_PRINT("\n\t %s Option (0x%02x), length %u", lcpconfopts[opt], opt, len); else { ND_PRINT("\n\tunknown LCP option 0x%02x", opt); return len; } switch (opt) { case LCPOPT_VEXT: if (len < 6) { ND_PRINT(" (length bogus, should be >= 6)"); return len; } ND_TCHECK_3(p + 2); ND_PRINT(": Vendor: %s (%u)", tok2str(oui_values,"Unknown",EXTRACT_BE_U_3(p + 2)), EXTRACT_BE_U_3(p + 2)); #if 0 ND_TCHECK_1(p + 5); ND_PRINT(", kind: 0x%02x", EXTRACT_U_1(p + 5)); ND_PRINT(", Value: 0x"); for (i = 0; i < len - 6; i++) { ND_TCHECK_1(p + 6 + i); ND_PRINT("%02x", EXTRACT_U_1(p + 6 + i)); } #endif break; case LCPOPT_MRU: if (len != 4) { ND_PRINT(" (length bogus, should be = 4)"); return len; } ND_TCHECK_2(p + 2); ND_PRINT(": %u", EXTRACT_BE_U_2(p + 2)); break; case LCPOPT_ACCM: if (len != 6) { ND_PRINT(" (length bogus, should be = 6)"); return len; } ND_TCHECK_4(p + 2); ND_PRINT(": 0x%08x", EXTRACT_BE_U_4(p + 2)); break; case LCPOPT_AP: if (len < 4) { ND_PRINT(" (length bogus, should be >= 4)"); return len; } ND_TCHECK_2(p + 2); ND_PRINT(": %s", tok2str(ppptype2str, "Unknown Auth Proto (0x04x)", EXTRACT_BE_U_2(p + 2))); switch (EXTRACT_BE_U_2(p + 2)) { case PPP_CHAP: ND_TCHECK_1(p + 4); ND_PRINT(", %s", tok2str(authalg_values, "Unknown Auth Alg %u", EXTRACT_U_1(p + 4))); break; case PPP_PAP: /* fall through */ case PPP_EAP: case PPP_SPAP: case PPP_SPAP_OLD: break; default: print_unknown_data(ndo, p, "\n\t", len); } break; case LCPOPT_QP: if (len < 4) { ND_PRINT(" (length bogus, should be >= 4)"); return 0; } ND_TCHECK_2(p + 2); if (EXTRACT_BE_U_2(p + 2) == PPP_LQM) ND_PRINT(": LQR"); else ND_PRINT(": unknown"); break; case LCPOPT_MN: if (len != 6) { ND_PRINT(" (length bogus, should be = 6)"); return 0; } ND_TCHECK_4(p + 2); ND_PRINT(": 0x%08x", EXTRACT_BE_U_4(p + 2)); break; case LCPOPT_PFC: break; case LCPOPT_ACFC: break; case LCPOPT_LD: if (len != 4) { ND_PRINT(" (length bogus, should be = 4)"); return 0; } ND_TCHECK_2(p + 2); ND_PRINT(": 0x%04x", EXTRACT_BE_U_2(p + 2)); break; case LCPOPT_CBACK: if (len < 3) { ND_PRINT(" (length bogus, should be >= 3)"); return 0; } ND_PRINT(": "); ND_TCHECK_1(p + 2); ND_PRINT(": Callback Operation %s (%u)", tok2str(ppp_callback_values, "Unknown", EXTRACT_U_1(p + 2)), EXTRACT_U_1(p + 2)); break; case LCPOPT_MLMRRU: if (len != 4) { ND_PRINT(" (length bogus, should be = 4)"); return 0; } ND_TCHECK_2(p + 2); ND_PRINT(": %u", EXTRACT_BE_U_2(p + 2)); break; case LCPOPT_MLED: if (len < 3) { ND_PRINT(" (length bogus, should be >= 3)"); return 0; } ND_TCHECK_1(p + 2); switch (EXTRACT_U_1(p + 2)) { /* class */ case MEDCLASS_NULL: ND_PRINT(": Null"); break; case MEDCLASS_LOCAL: ND_PRINT(": Local"); /* XXX */ break; case MEDCLASS_IPV4: if (len != 7) { ND_PRINT(" (length bogus, should be = 7)"); return 0; } ND_TCHECK_4(p + 3); ND_PRINT(": IPv4 %s", ipaddr_string(ndo, p + 3)); break; case MEDCLASS_MAC: if (len != 9) { ND_PRINT(" (length bogus, should be = 9)"); return 0; } ND_TCHECK_6(p + 3); ND_PRINT(": MAC %s", etheraddr_string(ndo, p + 3)); break; case MEDCLASS_MNB: ND_PRINT(": Magic-Num-Block"); /* XXX */ break; case MEDCLASS_PSNDN: ND_PRINT(": PSNDN"); /* XXX */ break; default: ND_PRINT(": Unknown class %u", EXTRACT_U_1(p + 2)); break; } break; /* XXX: to be supported */ #if 0 case LCPOPT_DEP6: case LCPOPT_FCSALT: case LCPOPT_SDP: case LCPOPT_NUMMODE: case LCPOPT_DEP12: case LCPOPT_DEP14: case LCPOPT_DEP15: case LCPOPT_DEP16: case LCPOPT_MLSSNHF: case LCPOPT_PROP: case LCPOPT_DCEID: case LCPOPT_MPP: case LCPOPT_LCPAOPT: case LCPOPT_COBS: case LCPOPT_PE: case LCPOPT_MLHF: case LCPOPT_I18N: case LCPOPT_SDLOS: case LCPOPT_PPPMUX: break; #endif default: /* * Unknown option; dump it as raw bytes now if we're * not going to do so below. */ if (ndo->ndo_vflag < 2) print_unknown_data(ndo, p + 2, "\n\t ", len - 2); break; } if (ndo->ndo_vflag > 1) print_unknown_data(ndo, p + 2, "\n\t ", len - 2); /* exclude TLV header */ return len; trunc: ND_PRINT("[|lcp]"); return 0; }
/* PAP (see RFC 1334) */ static void handle_pap(netdissect_options *ndo, const u_char *p, u_int length) { u_int code, len; u_int peerid_len, passwd_len, msg_len; const u_char *p0; u_int i; p0 = p; if (length < 1) { ND_PRINT("[|pap]"); return; } else if (length < 4) { ND_TCHECK_1(p); ND_PRINT("[|pap 0x%02x]", EXTRACT_U_1(p)); return; } ND_TCHECK_1(p); code = EXTRACT_U_1(p); ND_PRINT("PAP, %s (0x%02x)", tok2str(papcode_values, "unknown", code), code); p++; ND_TCHECK_1(p); ND_PRINT(", id %u", EXTRACT_U_1(p)); /* ID */ p++; ND_TCHECK_2(p); len = EXTRACT_BE_U_2(p); p += 2; if (len > length) { ND_PRINT(", length %u > packet size", len); return; } length = len; if (length < (size_t)(p - p0)) { ND_PRINT(", length %u < PAP header length", length); return; } switch (code) { case PAP_AREQ: /* A valid Authenticate-Request is 6 or more octets long. */ if (len < 6) goto trunc; if (length - (p - p0) < 1) return; ND_TCHECK_1(p); peerid_len = EXTRACT_U_1(p); /* Peer-ID Length */ p++; if (length - (p - p0) < peerid_len) return; ND_PRINT(", Peer "); for (i = 0; i < peerid_len; i++) { ND_TCHECK_1(p); safeputchar(ndo, EXTRACT_U_1(p)); p++; } if (length - (p - p0) < 1) return; ND_TCHECK_1(p); passwd_len = EXTRACT_U_1(p); /* Password Length */ p++; if (length - (p - p0) < passwd_len) return; ND_PRINT(", Name "); for (i = 0; i < passwd_len; i++) { ND_TCHECK_1(p); safeputchar(ndo, EXTRACT_U_1(p)); p++; } break; case PAP_AACK: case PAP_ANAK: /* Although some implementations ignore truncation at * this point and at least one generates a truncated * packet, RFC 1334 section 2.2.2 clearly states that * both AACK and ANAK are at least 5 bytes long. */ if (len < 5) goto trunc; if (length - (p - p0) < 1) return; ND_TCHECK_1(p); msg_len = EXTRACT_U_1(p); /* Msg-Length */ p++; if (length - (p - p0) < msg_len) return; ND_PRINT(", Msg "); for (i = 0; i< msg_len; i++) { ND_TCHECK_1(p); safeputchar(ndo, EXTRACT_U_1(p)); p++; } break; } return; trunc: ND_PRINT("[|pap]"); }
static u_int dccp_print_option(netdissect_options *ndo, const u_char *option, u_int hlen) { uint8_t optlen, i; ND_TCHECK_1(option); if (GET_U_1(option) >= 32) { ND_TCHECK_1(option + 1); optlen = GET_U_1(option + 1); if (optlen < 2) { if (GET_U_1(option) >= 128) ND_PRINT("CCID option %u optlen too short", GET_U_1(option)); else ND_PRINT("%s optlen too short", tok2str(dccp_option_values, "Option %u", GET_U_1(option))); return 0; } } else optlen = 1; if (hlen < optlen) { if (GET_U_1(option) >= 128) ND_PRINT("CCID option %u optlen goes past header length", GET_U_1(option)); else ND_PRINT("%s optlen goes past header length", tok2str(dccp_option_values, "Option %u", GET_U_1(option))); return 0; } ND_TCHECK_LEN(option, optlen); if (GET_U_1(option) >= 128) { ND_PRINT("CCID option %u", GET_U_1(option)); switch (optlen) { case 4: ND_PRINT(" %u", GET_BE_U_2(option + 2)); break; case 6: ND_PRINT(" %u", GET_BE_U_4(option + 2)); break; default: break; } } else { ND_PRINT("%s", tok2str(dccp_option_values, "Option %u", GET_U_1(option))); switch (GET_U_1(option)) { case 32: case 33: case 34: case 35: if (optlen < 3) { ND_PRINT(" optlen too short"); return optlen; } if (GET_U_1(option + 2) < 10){ ND_PRINT(" %s", dccp_feature_nums[GET_U_1(option + 2)]); for (i = 0; i < optlen - 3; i++) ND_PRINT(" %u", GET_U_1(option + 3 + i)); } break; case 36: if (optlen > 2) { ND_PRINT(" 0x"); for (i = 0; i < optlen - 2; i++) ND_PRINT("%02x", GET_U_1(option + 2 + i)); } break; case 37: for (i = 0; i < optlen - 2; i++) ND_PRINT(" %u", GET_U_1(option + 2 + i)); break; case 38: if (optlen > 2) { ND_PRINT(" 0x"); for (i = 0; i < optlen - 2; i++) ND_PRINT("%02x", GET_U_1(option + 2 + i)); } break; case 39: if (optlen > 2) { ND_PRINT(" 0x"); for (i = 0; i < optlen - 2; i++) ND_PRINT("%02x", GET_U_1(option + 2 + i)); } break; case 40: if (optlen > 2) { ND_PRINT(" 0x"); for (i = 0; i < optlen - 2; i++) ND_PRINT("%02x", GET_U_1(option + 2 + i)); } break; case 41: /* * 13.1. Timestamp Option * * +--------+--------+--------+--------+--------+--------+ * |00101001|00000110| Timestamp Value | * +--------+--------+--------+--------+--------+--------+ * Type=41 Length=6 */ if (optlen == 6) ND_PRINT(" %u", GET_BE_U_4(option + 2)); else ND_PRINT(" [optlen != 6]"); break; case 42: /* * 13.3. Timestamp Echo Option * * +--------+--------+--------+--------+--------+--------+ * |00101010|00000110| Timestamp Echo | * +--------+--------+--------+--------+--------+--------+ * Type=42 Len=6 * * +--------+--------+------- ... -------+--------+--------+ * |00101010|00001000| Timestamp Echo | Elapsed Time | * +--------+--------+------- ... -------+--------+--------+ * Type=42 Len=8 (4 bytes) * * +--------+--------+------- ... -------+------- ... -------+ * |00101010|00001010| Timestamp Echo | Elapsed Time | * +--------+--------+------- ... -------+------- ... -------+ * Type=42 Len=10 (4 bytes) (4 bytes) */ switch (optlen) { case 6: ND_PRINT(" %u", GET_BE_U_4(option + 2)); break; case 8: ND_PRINT(" %u", GET_BE_U_4(option + 2)); ND_PRINT(" (elapsed time %u)", GET_BE_U_2(option + 6)); break; case 10: ND_PRINT(" %u", GET_BE_U_4(option + 2)); ND_PRINT(" (elapsed time %u)", GET_BE_U_4(option + 6)); break; default: ND_PRINT(" [optlen != 6 or 8 or 10]"); break; } break; case 43: if (optlen == 6) ND_PRINT(" %u", GET_BE_U_4(option + 2)); else if (optlen == 4) ND_PRINT(" %u", GET_BE_U_2(option + 2)); else ND_PRINT(" [optlen != 4 or 6]"); break; case 44: if (optlen > 2) { ND_PRINT(" "); for (i = 0; i < optlen - 2; i++) ND_PRINT("%02x", GET_U_1(option + 2 + i)); } break; } } return optlen; trunc: nd_print_trunc(ndo); return 0; }
/* CCP config options */ static u_int print_ccp_config_options(netdissect_options *ndo, const u_char *p, u_int length) { u_int opt, len; if (length < 2) return 0; ND_TCHECK_2(p); opt = EXTRACT_U_1(p); len = EXTRACT_U_1(p + 1); if (length < len) return 0; if (len < 2) { ND_PRINT("\n\t %s Option (0x%02x), length %u (length bogus, should be >= 2)", tok2str(ccpconfopts_values, "Unknown", opt), opt, len); return 0; } ND_PRINT("\n\t %s Option (0x%02x), length %u", tok2str(ccpconfopts_values, "Unknown", opt), opt, len); switch (opt) { case CCPOPT_BSDCOMP: if (len < 3) { ND_PRINT(" (length bogus, should be >= 3)"); return len; } ND_TCHECK_1(p + 2); ND_PRINT(": Version: %u, Dictionary Bits: %u", EXTRACT_U_1(p + 2) >> 5, EXTRACT_U_1(p + 2) & 0x1f); break; case CCPOPT_MVRCA: if (len < 4) { ND_PRINT(" (length bogus, should be >= 4)"); return len; } ND_TCHECK_1(p + 3); ND_PRINT(": Features: %u, PxP: %s, History: %u, #CTX-ID: %u", (EXTRACT_U_1(p + 2) & 0xc0) >> 6, (EXTRACT_U_1(p + 2) & 0x20) ? "Enabled" : "Disabled", EXTRACT_U_1(p + 2) & 0x1f, EXTRACT_U_1(p + 3)); break; case CCPOPT_DEFLATE: if (len < 4) { ND_PRINT(" (length bogus, should be >= 4)"); return len; } ND_TCHECK_1(p + 3); ND_PRINT(": Window: %uK, Method: %s (0x%x), MBZ: %u, CHK: %u", (EXTRACT_U_1(p + 2) & 0xf0) >> 4, ((EXTRACT_U_1(p + 2) & 0x0f) == 8) ? "zlib" : "unknown", EXTRACT_U_1(p + 2) & 0x0f, (EXTRACT_U_1(p + 3) & 0xfc) >> 2, EXTRACT_U_1(p + 3) & 0x03); break; /* XXX: to be supported */ #if 0 case CCPOPT_OUI: case CCPOPT_PRED1: case CCPOPT_PRED2: case CCPOPT_PJUMP: case CCPOPT_HPPPC: case CCPOPT_STACLZS: case CCPOPT_MPPC: case CCPOPT_GFZA: case CCPOPT_V42BIS: case CCPOPT_LZSDCP: case CCPOPT_DEC: case CCPOPT_RESV: break; #endif default: /* * Unknown option; dump it as raw bytes now if we're * not going to do so below. */ if (ndo->ndo_vflag < 2) print_unknown_data(ndo, p + 2, "\n\t ", len - 2); break; } if (ndo->ndo_vflag > 1) print_unknown_data(ndo, p + 2, "\n\t ", len - 2); /* exclude TLV header */ return len; trunc: ND_PRINT("[|ccp]"); return 0; }
static void egpnrprint(netdissect_options *ndo, const struct egp_packet *egp, u_int length) { const uint8_t *cp; uint32_t addr; uint32_t net; u_int netlen; u_int gateways, distances, networks; u_int intgw, extgw, t_gateways; const char *comma; addr = EXTRACT_IPV4_TO_NETWORK_ORDER(egp->egp_sourcenet); if (IN_CLASSA(addr)) { net = addr & IN_CLASSA_NET; netlen = 1; } else if (IN_CLASSB(addr)) { net = addr & IN_CLASSB_NET; netlen = 2; } else if (IN_CLASSC(addr)) { net = addr & IN_CLASSC_NET; netlen = 3; } else { net = 0; netlen = 0; } cp = (const uint8_t *)(egp + 1); length -= sizeof(*egp); intgw = EXTRACT_U_1(egp->egp_intgw); extgw = EXTRACT_U_1(egp->egp_extgw); t_gateways = intgw + extgw; for (gateways = 0; gateways < t_gateways; ++gateways) { /* Pickup host part of gateway address */ addr = 0; if (length < 4 - netlen) goto trunc; ND_TCHECK_LEN(cp, 4 - netlen); switch (netlen) { case 1: addr = EXTRACT_U_1(cp); cp++; /* fall through */ case 2: addr = (addr << 8) | EXTRACT_U_1(cp); cp++; /* fall through */ case 3: addr = (addr << 8) | EXTRACT_U_1(cp); cp++; break; } addr |= net; length -= 4 - netlen; if (length < 1) goto trunc; ND_TCHECK_1(cp); distances = EXTRACT_U_1(cp); cp++; length--; ND_PRINT(" %s %s ", gateways < intgw ? "int" : "ext", ipaddr_string(ndo, (const u_char *)&addr)); comma = ""; ND_PRINT("("); while (distances != 0) { if (length < 2) goto trunc; ND_TCHECK_2(cp); ND_PRINT("%sd%u:", comma, EXTRACT_U_1(cp)); cp++; comma = ", "; networks = EXTRACT_U_1(cp); cp++; length -= 2; while (networks != 0) { /* Pickup network number */ if (length < 1) goto trunc; ND_TCHECK_1(cp); addr = ((uint32_t) EXTRACT_U_1(cp)) << 24; cp++; length--; if (IN_CLASSB(addr)) { if (length < 1) goto trunc; ND_TCHECK_1(cp); addr |= ((uint32_t) EXTRACT_U_1(cp)) << 16; cp++; length--; } else if (!IN_CLASSA(addr)) { if (length < 2) goto trunc; ND_TCHECK_2(cp); addr |= ((uint32_t) EXTRACT_U_1(cp)) << 16; cp++; addr |= ((uint32_t) EXTRACT_U_1(cp)) << 8; cp++; length -= 2; } ND_PRINT(" %s", ipaddr_string(ndo, (const u_char *)&addr)); networks--; } distances--; } ND_PRINT(")"); } return; trunc: ND_PRINT("[|]"); }
/* Standard PPP printer */ u_int ppp_print(netdissect_options *ndo, const u_char *p, u_int length) { u_int proto,ppp_header; u_int olen = length; /* _o_riginal length */ u_int hdr_len = 0; /* * Here, we assume that p points to the Address and Control * field (if they present). */ if (length < 2) goto trunc; ND_TCHECK_2(p); ppp_header = EXTRACT_BE_U_2(p); switch(ppp_header) { case (PPP_WITHDIRECTION_IN << 8 | PPP_CONTROL): if (ndo->ndo_eflag) ND_PRINT("In "); p += 2; length -= 2; hdr_len += 2; break; case (PPP_WITHDIRECTION_OUT << 8 | PPP_CONTROL): if (ndo->ndo_eflag) ND_PRINT("Out "); p += 2; length -= 2; hdr_len += 2; break; case (PPP_ADDRESS << 8 | PPP_CONTROL): p += 2; /* ACFC not used */ length -= 2; hdr_len += 2; break; default: break; } if (length < 2) goto trunc; ND_TCHECK_1(p); if (EXTRACT_U_1(p) % 2) { proto = EXTRACT_U_1(p); /* PFC is used */ p++; length--; hdr_len++; } else { ND_TCHECK_2(p); proto = EXTRACT_BE_U_2(p); p += 2; length -= 2; hdr_len += 2; } if (ndo->ndo_eflag) ND_PRINT("%s (0x%04x), length %u: ", tok2str(ppptype2str, "unknown", proto), proto, olen); handle_ppp(ndo, proto, p, length); return (hdr_len); trunc: ND_PRINT("[|ppp]"); return (0); }
/* CHAP */ static void handle_chap(netdissect_options *ndo, const u_char *p, u_int length) { u_int code, len; u_int val_size, name_size, msg_size; const u_char *p0; u_int i; p0 = p; if (length < 1) { ND_PRINT("[|chap]"); return; } else if (length < 4) { ND_TCHECK_1(p); ND_PRINT("[|chap 0x%02x]", EXTRACT_U_1(p)); return; } ND_TCHECK_1(p); code = EXTRACT_U_1(p); ND_PRINT("CHAP, %s (0x%02x)", tok2str(chapcode_values,"unknown",code), code); p++; ND_TCHECK_1(p); ND_PRINT(", id %u", EXTRACT_U_1(p)); /* ID */ p++; ND_TCHECK_2(p); len = EXTRACT_BE_U_2(p); p += 2; /* * Note that this is a generic CHAP decoding routine. Since we * don't know which flavor of CHAP (i.e. CHAP-MD5, MS-CHAPv1, * MS-CHAPv2) is used at this point, we can't decode packet * specifically to each algorithms. Instead, we simply decode * the GCD (Gratest Common Denominator) for all algorithms. */ switch (code) { case CHAP_CHAL: case CHAP_RESP: if (length - (p - p0) < 1) return; ND_TCHECK_1(p); val_size = EXTRACT_U_1(p); /* value size */ p++; if (length - (p - p0) < val_size) return; ND_PRINT(", Value "); for (i = 0; i < val_size; i++) { ND_TCHECK_1(p); ND_PRINT("%02x", EXTRACT_U_1(p)); p++; } name_size = len - (p - p0); ND_PRINT(", Name "); for (i = 0; i < name_size; i++) { ND_TCHECK_1(p); safeputchar(ndo, EXTRACT_U_1(p)); p++; } break; case CHAP_SUCC: case CHAP_FAIL: msg_size = len - (p - p0); ND_PRINT(", Msg "); for (i = 0; i< msg_size; i++) { ND_TCHECK_1(p); safeputchar(ndo, EXTRACT_U_1(p)); p++; } break; } return; trunc: ND_PRINT("[|chap]"); }
/* * Print bootp requests */ void bootp_print(netdissect_options *ndo, const u_char *cp, u_int length) { const struct bootp *bp; static const u_char vm_cmu[4] = VM_CMU; static const u_char vm_rfc1048[4] = VM_RFC1048; uint8_t bp_op, bp_htype, bp_hlen; ndo->ndo_protocol = "bootp"; bp = (const struct bootp *)cp; ND_TCHECK_1(bp->bp_op); bp_op = EXTRACT_U_1(bp->bp_op); ND_PRINT("BOOTP/DHCP, %s", tok2str(bootp_op_values, "unknown (0x%02x)", bp_op)); ND_TCHECK_1(bp->bp_hlen); bp_htype = EXTRACT_U_1(bp->bp_htype); bp_hlen = EXTRACT_U_1(bp->bp_hlen); if (bp_htype == 1 && bp_hlen == 6 && bp_op == BOOTPREQUEST) { ND_TCHECK_6(bp->bp_chaddr); ND_PRINT(" from %s", etheraddr_string(ndo, bp->bp_chaddr)); } ND_PRINT(", length %u", length); if (!ndo->ndo_vflag) return; ND_TCHECK_2(bp->bp_secs); /* The usual hardware address type is 1 (10Mb Ethernet) */ if (bp_htype != 1) ND_PRINT(", htype %u", bp_htype); /* The usual length for 10Mb Ethernet address is 6 bytes */ if (bp_htype != 1 || bp_hlen != 6) ND_PRINT(", hlen %u", bp_hlen); /* Only print interesting fields */ if (EXTRACT_U_1(bp->bp_hops)) ND_PRINT(", hops %u", EXTRACT_U_1(bp->bp_hops)); if (EXTRACT_BE_U_4(bp->bp_xid)) ND_PRINT(", xid 0x%x", EXTRACT_BE_U_4(bp->bp_xid)); if (EXTRACT_BE_U_2(bp->bp_secs)) ND_PRINT(", secs %u", EXTRACT_BE_U_2(bp->bp_secs)); ND_TCHECK_2(bp->bp_flags); ND_PRINT(", Flags [%s]", bittok2str(bootp_flag_values, "none", EXTRACT_BE_U_2(bp->bp_flags))); if (ndo->ndo_vflag > 1) ND_PRINT(" (0x%04x)", EXTRACT_BE_U_2(bp->bp_flags)); /* Client's ip address */ ND_TCHECK_4(bp->bp_ciaddr); if (EXTRACT_IPV4_TO_NETWORK_ORDER(bp->bp_ciaddr)) ND_PRINT("\n\t Client-IP %s", ipaddr_string(ndo, bp->bp_ciaddr)); /* 'your' ip address (bootp client) */ ND_TCHECK_4(bp->bp_yiaddr); if (EXTRACT_IPV4_TO_NETWORK_ORDER(bp->bp_yiaddr)) ND_PRINT("\n\t Your-IP %s", ipaddr_string(ndo, bp->bp_yiaddr)); /* Server's ip address */ ND_TCHECK_4(bp->bp_siaddr); if (EXTRACT_IPV4_TO_NETWORK_ORDER(bp->bp_siaddr)) ND_PRINT("\n\t Server-IP %s", ipaddr_string(ndo, bp->bp_siaddr)); /* Gateway's ip address */ ND_TCHECK_4(bp->bp_giaddr); if (EXTRACT_IPV4_TO_NETWORK_ORDER(bp->bp_giaddr)) ND_PRINT("\n\t Gateway-IP %s", ipaddr_string(ndo, bp->bp_giaddr)); /* Client's Ethernet address */ if (bp_htype == 1 && bp_hlen == 6) { ND_TCHECK_6(bp->bp_chaddr); ND_PRINT("\n\t Client-Ethernet-Address %s", etheraddr_string(ndo, bp->bp_chaddr)); } ND_TCHECK_1(bp->bp_sname); /* check first char only */ if (EXTRACT_U_1(bp->bp_sname)) { ND_PRINT("\n\t sname \""); if (nd_printztn(ndo, bp->bp_sname, (u_int)sizeof(bp->bp_sname), ndo->ndo_snapend) == 0) { ND_PRINT("\""); nd_print_trunc(ndo); return; } ND_PRINT("\""); } ND_TCHECK_1(bp->bp_file); /* check first char only */ if (EXTRACT_U_1(bp->bp_file)) { ND_PRINT("\n\t file \""); if (nd_printztn(ndo, bp->bp_file, (u_int)sizeof(bp->bp_file), ndo->ndo_snapend) == 0) { ND_PRINT("\""); nd_print_trunc(ndo); return; } ND_PRINT("\""); } /* Decode the vendor buffer */ ND_TCHECK_4(bp->bp_vend); if (memcmp((const char *)bp->bp_vend, vm_rfc1048, sizeof(uint32_t)) == 0) rfc1048_print(ndo, bp->bp_vend); else if (memcmp((const char *)bp->bp_vend, vm_cmu, sizeof(uint32_t)) == 0) cmu_print(ndo, bp->bp_vend); else { uint32_t ul; ul = EXTRACT_BE_U_4(bp->bp_vend); if (ul != 0) ND_PRINT("\n\t Vendor-#0x%x", ul); } return; trunc: nd_print_trunc(ndo); }
void vtp_print(netdissect_options *ndo, const u_char *pptr, u_int length) { u_int type, len, name_len, tlv_len, tlv_value, mgmtd_len; const u_char *tptr; const struct vtp_vlan_ *vtp_vlan; ndo->ndo_protocol = "vtp"; if (length < VTP_HEADER_LEN) goto trunc; tptr = pptr; ND_TCHECK_LEN(tptr, VTP_HEADER_LEN); type = EXTRACT_U_1(tptr + 1); ND_PRINT("VTPv%u, Message %s (0x%02x), length %u", EXTRACT_U_1(tptr), tok2str(vtp_message_type_values,"Unknown message type", type), type, length); /* In non-verbose mode, just print version and message type */ if (ndo->ndo_vflag < 1) { return; } /* verbose mode print all fields */ ND_PRINT("\n\tDomain name: "); mgmtd_len = EXTRACT_U_1(tptr + 3); if (mgmtd_len < 1 || mgmtd_len > 32) { ND_PRINT(" [invalid MgmtD Len %u]", mgmtd_len); return; } nd_printzp(ndo, tptr + 4, mgmtd_len, NULL); ND_PRINT(", %s: %u", tok2str(vtp_header_values, "Unknown", type), EXTRACT_U_1(tptr + 2)); tptr += VTP_HEADER_LEN; switch (type) { case VTP_SUMMARY_ADV: /* * SUMMARY ADVERTISEMENT * * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Version | Code | Followers | MgmtD Len | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Management Domain Name (zero-padded to 32 bytes) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Configuration revision number | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Updater Identity IP address | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Update Timestamp (12 bytes) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | MD5 digest (16 bytes) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */ ND_TCHECK_8(tptr); ND_PRINT("\n\t Config Rev %x, Updater %s", EXTRACT_BE_U_4(tptr), ipaddr_string(ndo, tptr+4)); tptr += 8; ND_TCHECK_LEN(tptr, VTP_UPDATE_TIMESTAMP_LEN); ND_PRINT(", Timestamp 0x%08x 0x%08x 0x%08x", EXTRACT_BE_U_4(tptr), EXTRACT_BE_U_4(tptr + 4), EXTRACT_BE_U_4(tptr + 8)); tptr += VTP_UPDATE_TIMESTAMP_LEN; ND_TCHECK_LEN(tptr, VTP_MD5_DIGEST_LEN); ND_PRINT(", MD5 digest: %08x%08x%08x%08x", EXTRACT_BE_U_4(tptr), EXTRACT_BE_U_4(tptr + 4), EXTRACT_BE_U_4(tptr + 8), EXTRACT_BE_U_4(tptr + 12)); tptr += VTP_MD5_DIGEST_LEN; break; case VTP_SUBSET_ADV: /* * SUBSET ADVERTISEMENT * * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Version | Code | Seq number | MgmtD Len | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Management Domain Name (zero-padded to 32 bytes) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Configuration revision number | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | VLAN info field 1 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ................ | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | VLAN info field N | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */ ND_TCHECK_4(tptr); ND_PRINT(", Config Rev %x", EXTRACT_BE_U_4(tptr)); /* * VLAN INFORMATION * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | V info len | Status | VLAN type | VLAN name len | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ISL vlan id | MTU size | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | 802.10 index (SAID) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | VLAN name | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */ tptr += 4; while (tptr < (pptr+length)) { ND_TCHECK_1(tptr); len = EXTRACT_U_1(tptr); if (len == 0) break; ND_TCHECK_LEN(tptr, len); vtp_vlan = (const struct vtp_vlan_*)tptr; if (len < VTP_VLAN_INFO_FIXED_PART_LEN) goto trunc; ND_TCHECK_SIZE(vtp_vlan); ND_PRINT("\n\tVLAN info status %s, type %s, VLAN-id %u, MTU %u, SAID 0x%08x, Name ", tok2str(vtp_vlan_status,"Unknown",EXTRACT_U_1(vtp_vlan->status)), tok2str(vtp_vlan_type_values,"Unknown",EXTRACT_U_1(vtp_vlan->type)), EXTRACT_BE_U_2(vtp_vlan->vlanid), EXTRACT_BE_U_2(vtp_vlan->mtu), EXTRACT_BE_U_4(vtp_vlan->index)); len -= VTP_VLAN_INFO_FIXED_PART_LEN; tptr += VTP_VLAN_INFO_FIXED_PART_LEN; name_len = EXTRACT_U_1(vtp_vlan->name_len); if (len < 4*((name_len + 3)/4)) goto trunc; ND_TCHECK_LEN(tptr, name_len); nd_printzp(ndo, tptr, name_len, NULL); /* * Vlan names are aligned to 32-bit boundaries. */ len -= 4*((name_len + 3)/4); tptr += 4*((name_len + 3)/4); /* TLV information follows */ while (len > 0) { /* * Cisco specs say 2 bytes for type + 2 bytes for length; * see http://docstore.mik.ua/univercd/cc/td/doc/product/lan/trsrb/frames.htm * However, actual packets on the wire appear to use 1 * byte for the type and 1 byte for the length, so that's * what we do. */ if (len < 2) goto trunc; ND_TCHECK_2(tptr); type = EXTRACT_U_1(tptr); tlv_len = EXTRACT_U_1(tptr + 1); ND_PRINT("\n\t\t%s (0x%04x) TLV", tok2str(vtp_vlan_tlv_values, "Unknown", type), type); if (len < tlv_len * 2 + 2) { ND_PRINT(" (TLV goes past the end of the packet)"); return; } ND_TCHECK_LEN(tptr, tlv_len * 2 + 2); /* * We assume the value is a 2-byte integer; the length is * in units of 16-bit words. */ if (tlv_len != 1) { ND_PRINT(" (invalid TLV length %u != 1)", tlv_len); return; } else { tlv_value = EXTRACT_BE_U_2(tptr + 2); switch (type) { case VTP_VLAN_STE_HOP_COUNT: ND_PRINT(", %u", tlv_value); break; case VTP_VLAN_PRUNING: ND_PRINT(", %s (%u)", tlv_value == 1 ? "Enabled" : "Disabled", tlv_value); break; case VTP_VLAN_STP_TYPE: ND_PRINT(", %s (%u)", tok2str(vtp_stp_type_values, "Unknown", tlv_value), tlv_value); break; case VTP_VLAN_BRIDGE_TYPE: ND_PRINT(", %s (%u)", tlv_value == 1 ? "SRB" : "SRT", tlv_value); break; case VTP_VLAN_BACKUP_CRF_MODE: ND_PRINT(", %s (%u)", tlv_value == 1 ? "Backup" : "Not backup", tlv_value); break; /* * FIXME those are the defined TLVs that lack a decoder * you are welcome to contribute code ;-) */ case VTP_VLAN_SOURCE_ROUTING_RING_NUMBER: case VTP_VLAN_SOURCE_ROUTING_BRIDGE_NUMBER: case VTP_VLAN_PARENT_VLAN: case VTP_VLAN_TRANS_BRIDGED_VLAN: case VTP_VLAN_ARP_HOP_COUNT: default: print_unknown_data(ndo, tptr, "\n\t\t ", 2 + tlv_len*2); break; } } len -= 2 + tlv_len*2; tptr += 2 + tlv_len*2; } } break; case VTP_ADV_REQUEST: /* * ADVERTISEMENT REQUEST * * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Version | Code | Reserved | MgmtD Len | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Management Domain Name (zero-padded to 32 bytes) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Start value | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */ ND_TCHECK_4(tptr); ND_PRINT("\n\tStart value: %u", EXTRACT_BE_U_4(tptr)); break; case VTP_JOIN_MESSAGE: /* FIXME - Could not find message format */ break; default: break; } return; trunc: nd_print_trunc(ndo); }
static void rfc1048_print(netdissect_options *ndo, const u_char *bp) { uint16_t tag; u_int len; const char *cp; char c; int first, idx; uint8_t subopt, suboptlen; ND_PRINT("\n\t Vendor-rfc1048 Extensions"); /* Step over magic cookie */ ND_PRINT("\n\t Magic Cookie 0x%08x", EXTRACT_BE_U_4(bp)); bp += sizeof(int32_t); /* Loop while we there is a tag left in the buffer */ while (ND_TTEST_1(bp)) { tag = EXTRACT_U_1(bp); bp++; if (tag == TAG_PAD && ndo->ndo_vflag < 3) continue; if (tag == TAG_END && ndo->ndo_vflag < 3) return; if (tag == TAG_EXTENDED_OPTION) { ND_TCHECK_2(bp + 1); tag = EXTRACT_BE_U_2(bp + 1); /* XXX we don't know yet if the IANA will * preclude overlap of 1-byte and 2-byte spaces. * If not, we need to offset tag after this step. */ cp = tok2str(xtag2str, "?xT%u", tag); } else cp = tok2str(tag2str, "?T%u", tag); c = *cp++; if (tag == TAG_PAD || tag == TAG_END) len = 0; else { /* Get the length; check for truncation */ ND_TCHECK_1(bp); len = EXTRACT_U_1(bp); bp++; } ND_PRINT("\n\t %s Option %u, length %u%s", cp, tag, len, len > 0 ? ": " : ""); if (tag == TAG_PAD && ndo->ndo_vflag > 2) { u_int ntag = 1; while (ND_TTEST_1(bp) && EXTRACT_U_1(bp) == TAG_PAD) { bp++; ntag++; } if (ntag > 1) ND_PRINT(", occurs %u", ntag); } ND_TCHECK_LEN(bp, len); if (tag == TAG_DHCP_MESSAGE && len == 1) { ND_PRINT("%s", tok2str(dhcp_msg_values, "Unknown (%u)", EXTRACT_U_1(bp))); bp++; continue; } if (tag == TAG_PARM_REQUEST) { idx = 0; while (len > 0) { cp = tok2str(tag2str, "?Option %u", EXTRACT_U_1(bp)); bp++; len--; if (idx % 4 == 0) ND_PRINT("\n\t "); else ND_PRINT(", "); ND_PRINT("%s", cp + 1); idx++; } continue; } if (tag == TAG_EXTENDED_REQUEST) { first = 1; while (len > 1) { cp = tok2str(xtag2str, "?xT%u", EXTRACT_BE_U_2(bp)); bp += 2; len -= 2; if (!first) ND_PRINT("+"); ND_PRINT("%s", cp + 1); first = 0; } continue; } /* Print data */ if (c == '?') { /* Base default formats for unknown tags on data size */ if (len & 1) c = 'b'; else if (len & 2) c = 's'; else c = 'l'; } first = 1; switch (c) { case 'a': /* ASCII strings */ ND_PRINT("\""); if (nd_printn(ndo, bp, len, ndo->ndo_snapend)) { ND_PRINT("\""); goto trunc; } ND_PRINT("\""); bp += len; len = 0; break; case 'i': case 'l': case 'L': /* ip addresses/32-bit words */ while (len >= 4) { if (!first) ND_PRINT(","); if (c == 'i') ND_PRINT("%s", ipaddr_string(ndo, bp)); else if (c == 'L') ND_PRINT("%d", EXTRACT_BE_S_4(bp)); else ND_PRINT("%u", EXTRACT_BE_U_4(bp)); bp += 4; len -= 4; first = 0; } break; case 'p': /* IP address pairs */ while (len >= 2*4) { if (!first) ND_PRINT(","); ND_PRINT("(%s:", ipaddr_string(ndo, bp)); bp += 4; len -= 4; ND_PRINT("%s)", ipaddr_string(ndo, bp)); bp += 4; len -= 4; first = 0; } break; case 's': /* shorts */ while (len >= 2) { if (!first) ND_PRINT(","); ND_PRINT("%u", EXTRACT_BE_U_2(bp)); bp += 2; len -= 2; first = 0; } break; case 'B': /* boolean */ while (len > 0) { uint8_t bool_value; if (!first) ND_PRINT(","); bool_value = EXTRACT_U_1(bp); switch (bool_value) { case 0: ND_PRINT("N"); break; case 1: ND_PRINT("Y"); break; default: ND_PRINT("%u?", bool_value); break; } ++bp; --len; first = 0; } break; case 'b': case 'x': default: /* Bytes */ while (len > 0) { uint8_t byte_value; if (!first) ND_PRINT(c == 'x' ? ":" : "."); byte_value = EXTRACT_U_1(bp); if (c == 'x') ND_PRINT("%02x", byte_value); else ND_PRINT("%u", byte_value); ++bp; --len; first = 0; } break; case '$': /* Guys we can't handle with one of the usual cases */ switch (tag) { case TAG_NETBIOS_NODE: /* this option should be at least 1 byte long */ if (len < 1) { ND_PRINT("ERROR: length < 1 bytes"); break; } tag = EXTRACT_U_1(bp); ++bp; --len; ND_PRINT("%s", tok2str(nbo2str, NULL, tag)); break; case TAG_OPT_OVERLOAD: /* this option should be at least 1 byte long */ if (len < 1) { ND_PRINT("ERROR: length < 1 bytes"); break; } tag = EXTRACT_U_1(bp); ++bp; --len; ND_PRINT("%s", tok2str(oo2str, NULL, tag)); break; case TAG_CLIENT_FQDN: /* this option should be at least 3 bytes long */ if (len < 3) { ND_PRINT("ERROR: length < 3 bytes"); bp += len; len = 0; break; } if (EXTRACT_U_1(bp)) ND_PRINT("[%s] ", client_fqdn_flags(EXTRACT_U_1(bp))); bp++; if (EXTRACT_U_1(bp) || EXTRACT_U_1(bp + 1)) ND_PRINT("%u/%u ", EXTRACT_U_1(bp), EXTRACT_U_1(bp + 1)); bp += 2; ND_PRINT("\""); if (nd_printn(ndo, bp, len - 3, ndo->ndo_snapend)) { ND_PRINT("\""); goto trunc; } ND_PRINT("\""); bp += len - 3; len = 0; break; case TAG_CLIENT_ID: { int type; /* this option should be at least 1 byte long */ if (len < 1) { ND_PRINT("ERROR: length < 1 bytes"); break; } type = EXTRACT_U_1(bp); bp++; len--; if (type == 0) { ND_PRINT("\""); if (nd_printn(ndo, bp, len, ndo->ndo_snapend)) { ND_PRINT("\""); goto trunc; } ND_PRINT("\""); bp += len; len = 0; break; } else { ND_PRINT("%s ", tok2str(arp2str, "hardware-type %u,", type)); while (len > 0) { if (!first) ND_PRINT(":"); ND_PRINT("%02x", EXTRACT_U_1(bp)); ++bp; --len; first = 0; } } break; } case TAG_AGENT_CIRCUIT: while (len >= 2) { subopt = EXTRACT_U_1(bp); suboptlen = EXTRACT_U_1(bp + 1); bp += 2; len -= 2; if (suboptlen > len) { ND_PRINT("\n\t %s SubOption %u, length %u: length goes past end of option", tok2str(agent_suboption_values, "Unknown", subopt), subopt, suboptlen); bp += len; len = 0; break; } ND_PRINT("\n\t %s SubOption %u, length %u: ", tok2str(agent_suboption_values, "Unknown", subopt), subopt, suboptlen); switch (subopt) { case AGENT_SUBOPTION_CIRCUIT_ID: /* fall through */ case AGENT_SUBOPTION_REMOTE_ID: case AGENT_SUBOPTION_SUBSCRIBER_ID: if (nd_printn(ndo, bp, suboptlen, ndo->ndo_snapend)) goto trunc; break; default: print_unknown_data(ndo, bp, "\n\t\t", suboptlen); } len -= suboptlen; bp += suboptlen; } break; case TAG_CLASSLESS_STATIC_RT: case TAG_CLASSLESS_STA_RT_MS: { u_int mask_width, significant_octets, i; /* this option should be at least 5 bytes long */ if (len < 5) { ND_PRINT("ERROR: length < 5 bytes"); bp += len; len = 0; break; } while (len > 0) { if (!first) ND_PRINT(","); mask_width = EXTRACT_U_1(bp); bp++; len--; /* mask_width <= 32 */ if (mask_width > 32) { ND_PRINT("[ERROR: Mask width (%u) > 32]", mask_width); bp += len; len = 0; break; } significant_octets = (mask_width + 7) / 8; /* significant octets + router(4) */ if (len < significant_octets + 4) { ND_PRINT("[ERROR: Remaining length (%u) < %u bytes]", len, significant_octets + 4); bp += len; len = 0; break; } ND_PRINT("("); if (mask_width == 0) ND_PRINT("default"); else { for (i = 0; i < significant_octets ; i++) { if (i > 0) ND_PRINT("."); ND_PRINT("%u", EXTRACT_U_1(bp)); bp++; } for (i = significant_octets ; i < 4 ; i++) ND_PRINT(".0"); ND_PRINT("/%u", mask_width); } ND_PRINT(":%s)", ipaddr_string(ndo, bp)); bp += 4; len -= (significant_octets + 4); first = 0; } break; } case TAG_USER_CLASS: { u_int suboptnumber = 1; first = 1; if (len < 2) { ND_PRINT("ERROR: length < 2 bytes"); bp += len; len = 0; break; } while (len > 0) { suboptlen = EXTRACT_U_1(bp); bp++; len--; ND_PRINT("\n\t "); ND_PRINT("instance#%u: ", suboptnumber); if (suboptlen == 0) { ND_PRINT("ERROR: suboption length must be non-zero"); bp += len; len = 0; break; } if (len < suboptlen) { ND_PRINT("ERROR: invalid option"); bp += len; len = 0; break; } ND_PRINT("\""); if (nd_printn(ndo, bp, suboptlen, ndo->ndo_snapend)) { ND_PRINT("\""); goto trunc; } ND_PRINT("\""); ND_PRINT(", length %u", suboptlen); suboptnumber++; len -= suboptlen; bp += suboptlen; } break; } default: ND_PRINT("[unknown special tag %u, size %u]", tag, len); bp += len; len = 0; break; } break; } /* Data left over? */ if (len) { ND_PRINT("\n\t trailing data length %u", len); bp += len; } } return; trunc: nd_print_trunc(ndo); }
void ahcp_print(netdissect_options *ndo, const u_char *cp, const u_int len) { const u_char *ep = ndo->ndo_snapend; uint8_t version; ndo->ndo_protocol = "ahcp"; ND_PRINT("AHCP"); if (len < 2) goto invalid; /* Magic */ ND_TCHECK_1(cp); if (EXTRACT_U_1(cp) != AHCP_MAGIC_NUMBER) goto invalid; cp += 1; /* Version */ ND_TCHECK_1(cp); version = EXTRACT_U_1(cp); cp += 1; switch (version) { case AHCP_VERSION_1: { ND_PRINT(" Version 1"); if (len < AHCP1_HEADER_FIX_LEN) goto invalid; if (!ndo->ndo_vflag) { ND_TCHECK_LEN(cp, AHCP1_HEADER_FIX_LEN - 2); cp += AHCP1_HEADER_FIX_LEN - 2; } else { /* Hopcount */ ND_TCHECK_1(cp); ND_PRINT("\n\tHopcount %u", EXTRACT_U_1(cp)); cp += 1; /* Original Hopcount */ ND_TCHECK_1(cp); ND_PRINT(", Original Hopcount %u", EXTRACT_U_1(cp)); cp += 1; /* Nonce */ ND_TCHECK_4(cp); ND_PRINT(", Nonce 0x%08x", EXTRACT_BE_U_4(cp)); cp += 4; /* Source Id */ ND_TCHECK_8(cp); ND_PRINT(", Source Id %s", linkaddr_string(ndo, cp, 0, 8)); cp += 8; /* Destination Id */ ND_TCHECK_8(cp); ND_PRINT(", Destination Id %s", linkaddr_string(ndo, cp, 0, 8)); cp += 8; } /* Body */ ahcp1_body_print(ndo, cp, ep); break; } default: ND_PRINT(" Version %u (unknown)", version); break; } return; invalid: ND_PRINT("%s", istr); ND_TCHECK_LEN(cp, ep - cp); return; trunc: nd_print_trunc(ndo); }
void slow_print(netdissect_options *ndo, const u_char *pptr, u_int len) { int print_version; u_int subtype; ndo->ndo_protocol = "slow"; if (len < 1) goto tooshort; ND_TCHECK_1(pptr); subtype = EXTRACT_U_1(pptr); /* * Sanity checking of the header. */ switch (subtype) { case SLOW_PROTO_LACP: if (len < 2) goto tooshort; ND_TCHECK_1(pptr + 1); if (EXTRACT_U_1(pptr + 1) != LACP_VERSION) { ND_PRINT("LACP version %u packet not supported", EXTRACT_U_1(pptr + 1)); return; } print_version = 1; break; case SLOW_PROTO_MARKER: if (len < 2) goto tooshort; ND_TCHECK_1(pptr + 1); if (EXTRACT_U_1(pptr + 1) != MARKER_VERSION) { ND_PRINT("MARKER version %u packet not supported", EXTRACT_U_1(pptr + 1)); return; } print_version = 1; break; case SLOW_PROTO_OAM: /* fall through */ print_version = 0; break; default: /* print basic information and exit */ print_version = -1; break; } if (print_version == 1) { ND_PRINT("%sv%u, length %u", tok2str(slow_proto_values, "unknown (%u)", subtype), EXTRACT_U_1((pptr + 1)), len); } else { /* some slow protos don't have a version number in the header */ ND_PRINT("%s, length %u", tok2str(slow_proto_values, "unknown (%u)", subtype), len); } /* unrecognized subtype */ if (print_version == -1) { print_unknown_data(ndo, pptr, "\n\t", len); return; } if (!ndo->ndo_vflag) return; switch (subtype) { default: /* should not happen */ break; case SLOW_PROTO_OAM: /* skip subtype */ len -= 1; pptr += 1; slow_oam_print(ndo, pptr, len); break; case SLOW_PROTO_LACP: /* LACP and MARKER share the same semantics */ case SLOW_PROTO_MARKER: /* skip subtype and version */ len -= 2; pptr += 2; slow_marker_lacp_print(ndo, pptr, len, subtype); break; } return; tooshort: if (!ndo->ndo_vflag) ND_PRINT(" (packet is too short)"); else ND_PRINT("\n\t\t packet is too short"); return; trunc: ND_PRINT("%s", tstr); }
void tcp_print(netdissect_options *ndo, const u_char *bp, u_int length, const u_char *bp2, int fragmented) { const struct tcphdr *tp; const struct ip *ip; u_char flags; u_int hlen; char ch; uint16_t sport, dport, win, urp; uint32_t seq, ack, thseq, thack; u_int utoval; uint16_t magic; int rev; const struct ip6_hdr *ip6; ndo->ndo_protocol = "tcp"; tp = (const struct tcphdr *)bp; ip = (const struct ip *)bp2; if (IP_V(ip) == 6) ip6 = (const struct ip6_hdr *)bp2; else ip6 = NULL; ch = '\0'; if (!ND_TTEST_2(tp->th_dport)) { if (ip6) { ND_PRINT("%s > %s:", ip6addr_string(ndo, ip6->ip6_src), ip6addr_string(ndo, ip6->ip6_dst)); } else { ND_PRINT("%s > %s:", ipaddr_string(ndo, ip->ip_src), ipaddr_string(ndo, ip->ip_dst)); } nd_print_trunc(ndo); return; } sport = GET_BE_U_2(tp->th_sport); dport = GET_BE_U_2(tp->th_dport); if (ip6) { if (GET_U_1(ip6->ip6_nxt) == IPPROTO_TCP) { ND_PRINT("%s.%s > %s.%s: ", ip6addr_string(ndo, ip6->ip6_src), tcpport_string(ndo, sport), ip6addr_string(ndo, ip6->ip6_dst), tcpport_string(ndo, dport)); } else { ND_PRINT("%s > %s: ", tcpport_string(ndo, sport), tcpport_string(ndo, dport)); } } else { if (GET_U_1(ip->ip_p) == IPPROTO_TCP) { ND_PRINT("%s.%s > %s.%s: ", ipaddr_string(ndo, ip->ip_src), tcpport_string(ndo, sport), ipaddr_string(ndo, ip->ip_dst), tcpport_string(ndo, dport)); } else { ND_PRINT("%s > %s: ", tcpport_string(ndo, sport), tcpport_string(ndo, dport)); } } ND_TCHECK_SIZE(tp); hlen = TH_OFF(tp) * 4; if (hlen < sizeof(*tp)) { ND_PRINT(" tcp %u [bad hdr length %u - too short, < %lu]", length - hlen, hlen, (unsigned long)sizeof(*tp)); return; } seq = GET_BE_U_4(tp->th_seq); ack = GET_BE_U_4(tp->th_ack); win = GET_BE_U_2(tp->th_win); urp = GET_BE_U_2(tp->th_urp); if (ndo->ndo_qflag) { ND_PRINT("tcp %u", length - hlen); if (hlen > length) { ND_PRINT(" [bad hdr length %u - too long, > %u]", hlen, length); } return; } flags = GET_U_1(tp->th_flags); ND_PRINT("Flags [%s]", bittok2str_nosep(tcp_flag_values, "none", flags)); if (!ndo->ndo_Sflag && (flags & TH_ACK)) { /* * Find (or record) the initial sequence numbers for * this conversation. (we pick an arbitrary * collating order so there's only one entry for * both directions). */ rev = 0; if (ip6) { struct tcp_seq_hash6 *th; struct tcp_seq_hash6 *tcp_seq_hash; const void *src, *dst; struct tha6 tha; tcp_seq_hash = tcp_seq_hash6; src = (const void *)ip6->ip6_src; dst = (const void *)ip6->ip6_dst; if (sport > dport) rev = 1; else if (sport == dport) { if (UNALIGNED_MEMCMP(src, dst, sizeof(ip6->ip6_dst)) > 0) rev = 1; } if (rev) { UNALIGNED_MEMCPY(&tha.src, dst, sizeof(ip6->ip6_dst)); UNALIGNED_MEMCPY(&tha.dst, src, sizeof(ip6->ip6_src)); tha.port = ((u_int)dport) << 16 | sport; } else { UNALIGNED_MEMCPY(&tha.dst, dst, sizeof(ip6->ip6_dst)); UNALIGNED_MEMCPY(&tha.src, src, sizeof(ip6->ip6_src)); tha.port = ((u_int)sport) << 16 | dport; } for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; th->nxt; th = th->nxt) if (memcmp((char *)&tha, (char *)&th->addr, sizeof(th->addr)) == 0) break; if (!th->nxt || (flags & TH_SYN)) { /* didn't find it or new conversation */ /* calloc() return used by the 'tcp_seq_hash6' hash table: do not free() */ if (th->nxt == NULL) { th->nxt = (struct tcp_seq_hash6 *) calloc(1, sizeof(*th)); if (th->nxt == NULL) (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC, "tcp_print: calloc"); } th->addr = tha; if (rev) th->ack = seq, th->seq = ack - 1; else th->seq = seq, th->ack = ack - 1; } else { if (rev) seq -= th->ack, ack -= th->seq; else seq -= th->seq, ack -= th->ack; } thseq = th->seq; thack = th->ack; } else { struct tcp_seq_hash *th; struct tcp_seq_hash *tcp_seq_hash; struct tha tha; tcp_seq_hash = tcp_seq_hash4; if (sport > dport) rev = 1; else if (sport == dport) { if (UNALIGNED_MEMCMP(ip->ip_src, ip->ip_dst, sizeof(ip->ip_dst)) > 0) rev = 1; } if (rev) { UNALIGNED_MEMCPY(&tha.src, ip->ip_dst, sizeof(ip->ip_dst)); UNALIGNED_MEMCPY(&tha.dst, ip->ip_src, sizeof(ip->ip_src)); tha.port = ((u_int)dport) << 16 | sport; } else { UNALIGNED_MEMCPY(&tha.dst, ip->ip_dst, sizeof(ip->ip_dst)); UNALIGNED_MEMCPY(&tha.src, ip->ip_src, sizeof(ip->ip_src)); tha.port = ((u_int)sport) << 16 | dport; } for (th = &tcp_seq_hash[tha.port % TSEQ_HASHSIZE]; th->nxt; th = th->nxt) if (memcmp((char *)&tha, (char *)&th->addr, sizeof(th->addr)) == 0) break; if (!th->nxt || (flags & TH_SYN)) { /* didn't find it or new conversation */ /* calloc() return used by the 'tcp_seq_hash4' hash table: do not free() */ if (th->nxt == NULL) { th->nxt = (struct tcp_seq_hash *) calloc(1, sizeof(*th)); if (th->nxt == NULL) (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC, "tcp_print: calloc"); } th->addr = tha; if (rev) th->ack = seq, th->seq = ack - 1; else th->seq = seq, th->ack = ack - 1; } else { if (rev) seq -= th->ack, ack -= th->seq; else seq -= th->seq, ack -= th->ack; } thseq = th->seq; thack = th->ack; } } else { /*fool gcc*/ thseq = thack = rev = 0; } if (hlen > length) { ND_PRINT(" [bad hdr length %u - too long, > %u]", hlen, length); return; } if (ndo->ndo_vflag && !ndo->ndo_Kflag && !fragmented) { /* Check the checksum, if possible. */ uint16_t sum, tcp_sum; if (IP_V(ip) == 4) { if (ND_TTEST_LEN(tp->th_sport, length)) { sum = tcp_cksum(ndo, ip, tp, length); tcp_sum = GET_BE_U_2(tp->th_sum); ND_PRINT(", cksum 0x%04x", tcp_sum); if (sum != 0) ND_PRINT(" (incorrect -> 0x%04x)", in_cksum_shouldbe(tcp_sum, sum)); else ND_PRINT(" (correct)"); } } else if (IP_V(ip) == 6 && ip6->ip6_plen) { if (ND_TTEST_LEN(tp->th_sport, length)) { sum = tcp6_cksum(ndo, ip6, tp, length); tcp_sum = GET_BE_U_2(tp->th_sum); ND_PRINT(", cksum 0x%04x", tcp_sum); if (sum != 0) ND_PRINT(" (incorrect -> 0x%04x)", in_cksum_shouldbe(tcp_sum, sum)); else ND_PRINT(" (correct)"); } } } length -= hlen; if (ndo->ndo_vflag > 1 || length > 0 || flags & (TH_SYN | TH_FIN | TH_RST)) { ND_PRINT(", seq %u", seq); if (length > 0) { ND_PRINT(":%u", seq + length); } } if (flags & TH_ACK) { ND_PRINT(", ack %u", ack); } ND_PRINT(", win %u", win); if (flags & TH_URG) ND_PRINT(", urg %u", urp); /* * Handle any options. */ if (hlen > sizeof(*tp)) { const u_char *cp; u_int i, opt, datalen; u_int len; hlen -= sizeof(*tp); cp = (const u_char *)tp + sizeof(*tp); ND_PRINT(", options ["); while (hlen > 0) { if (ch != '\0') ND_PRINT("%c", ch); ND_TCHECK_1(cp); opt = GET_U_1(cp); cp++; if (ZEROLENOPT(opt)) len = 1; else { ND_TCHECK_1(cp); len = GET_U_1(cp); cp++; /* total including type, len */ if (len < 2 || len > hlen) goto bad; --hlen; /* account for length byte */ } --hlen; /* account for type byte */ datalen = 0; /* Bail if "l" bytes of data are not left or were not captured */ #define LENCHECK(l) { if ((l) > hlen) goto bad; ND_TCHECK_LEN(cp, l); } ND_PRINT("%s", tok2str(tcp_option_values, "unknown-%u", opt)); switch (opt) { case TCPOPT_MAXSEG: datalen = 2; LENCHECK(datalen); ND_PRINT(" %u", GET_BE_U_2(cp)); break; case TCPOPT_WSCALE: datalen = 1; LENCHECK(datalen); ND_PRINT(" %u", GET_U_1(cp)); break; case TCPOPT_SACK: datalen = len - 2; if (datalen % 8 != 0) { ND_PRINT(" invalid sack"); } else { uint32_t s, e; ND_PRINT(" %u ", datalen / 8); for (i = 0; i < datalen; i += 8) { LENCHECK(i + 4); s = GET_BE_U_4(cp + i); LENCHECK(i + 8); e = GET_BE_U_4(cp + i + 4); if (rev) { s -= thseq; e -= thseq; } else { s -= thack; e -= thack; } ND_PRINT("{%u:%u}", s, e); } } break; case TCPOPT_CC: case TCPOPT_CCNEW: case TCPOPT_CCECHO: case TCPOPT_ECHO: case TCPOPT_ECHOREPLY: /* * those options share their semantics. * fall through */ datalen = 4; LENCHECK(datalen); ND_PRINT(" %u", GET_BE_U_4(cp)); break; case TCPOPT_TIMESTAMP: datalen = 8; LENCHECK(datalen); ND_PRINT(" val %u ecr %u", GET_BE_U_4(cp), GET_BE_U_4(cp + 4)); break; case TCPOPT_SIGNATURE: datalen = TCP_SIGLEN; LENCHECK(datalen); ND_PRINT(" "); #ifdef HAVE_LIBCRYPTO switch (tcp_verify_signature(ndo, ip, tp, bp + TH_OFF(tp) * 4, length, cp)) { case SIGNATURE_VALID: ND_PRINT("valid"); break; case SIGNATURE_INVALID: nd_print_invalid(ndo); break; case CANT_CHECK_SIGNATURE: ND_PRINT("can't check - "); for (i = 0; i < TCP_SIGLEN; ++i) ND_PRINT("%02x", GET_U_1(cp + i)); break; } #else for (i = 0; i < TCP_SIGLEN; ++i) ND_PRINT("%02x", GET_U_1(cp + i)); #endif break; case TCPOPT_SCPS: datalen = 2; LENCHECK(datalen); ND_PRINT(" cap %02x id %u", GET_U_1(cp), GET_U_1(cp + 1)); break; case TCPOPT_TCPAO: datalen = len - 2; /* RFC 5925 Section 2.2: * "The Length value MUST be greater than or equal to 4." * (This includes the Kind and Length fields already processed * at this point.) */ if (datalen < 2) { nd_print_invalid(ndo); } else { LENCHECK(1); ND_PRINT(" keyid %u", GET_U_1(cp)); LENCHECK(2); ND_PRINT(" rnextkeyid %u", GET_U_1(cp + 1)); if (datalen > 2) { ND_PRINT(" mac 0x"); for (i = 2; i < datalen; i++) { LENCHECK(i + 1); ND_PRINT("%02x", GET_U_1(cp + i)); } } } break; case TCPOPT_EOL: case TCPOPT_NOP: case TCPOPT_SACKOK: /* * Nothing interesting. * fall through */ break; case TCPOPT_UTO: datalen = 2; LENCHECK(datalen); utoval = GET_BE_U_2(cp); ND_PRINT(" 0x%x", utoval); if (utoval & 0x0001) utoval = (utoval >> 1) * 60; else utoval >>= 1; ND_PRINT(" %u", utoval); break; case TCPOPT_MPTCP: datalen = len - 2; LENCHECK(datalen); if (!mptcp_print(ndo, cp-2, len, flags)) goto bad; break; case TCPOPT_FASTOPEN: datalen = len - 2; LENCHECK(datalen); ND_PRINT(" "); print_tcp_fastopen_option(ndo, cp, datalen, FALSE); break; case TCPOPT_EXPERIMENT2: datalen = len - 2; LENCHECK(datalen); if (datalen < 2) goto bad; /* RFC6994 */ magic = GET_BE_U_2(cp); ND_PRINT("-"); switch(magic) { case 0xf989: /* TCP Fast Open RFC 7413 */ print_tcp_fastopen_option(ndo, cp + 2, datalen - 2, TRUE); break; default: /* Unknown magic number */ ND_PRINT("%04x", magic); break; } break; default: datalen = len - 2; if (datalen) ND_PRINT(" 0x"); for (i = 0; i < datalen; ++i) { LENCHECK(i + 1); ND_PRINT("%02x", GET_U_1(cp + i)); } break; } /* Account for data printed */ cp += datalen; hlen -= datalen; /* Check specification against observed length */ ++datalen; /* option octet */ if (!ZEROLENOPT(opt)) ++datalen; /* size octet */ if (datalen != len) ND_PRINT("[len %u]", len); ch = ','; if (opt == TCPOPT_EOL) break; } ND_PRINT("]"); }
/* * RFC3032: MPLS label stack encoding */ void mpls_print(netdissect_options *ndo, const u_char *bp, u_int length) { const u_char *p; uint32_t label_entry; uint16_t label_stack_depth = 0; enum mpls_packet_type pt = PT_UNKNOWN; ndo->ndo_protocol = "mpls"; p = bp; ND_PRINT("MPLS"); do { ND_TCHECK_LEN(p, sizeof(label_entry)); if (length < sizeof(label_entry)) goto trunc; label_entry = GET_BE_U_4(p); ND_PRINT("%s(label %u", (label_stack_depth && ndo->ndo_vflag) ? "\n\t" : " ", MPLS_LABEL(label_entry)); label_stack_depth++; if (ndo->ndo_vflag && MPLS_LABEL(label_entry) < sizeof(mpls_labelname) / sizeof(mpls_labelname[0])) ND_PRINT(" (%s)", mpls_labelname[MPLS_LABEL(label_entry)]); ND_PRINT(", exp %u", MPLS_EXP(label_entry)); if (MPLS_STACK(label_entry)) ND_PRINT(", [S]"); ND_PRINT(", ttl %u)", MPLS_TTL(label_entry)); p += sizeof(label_entry); length -= sizeof(label_entry); } while (!MPLS_STACK(label_entry)); /* * Try to figure out the packet type. */ switch (MPLS_LABEL(label_entry)) { case 0: /* IPv4 explicit NULL label */ case 3: /* IPv4 implicit NULL label */ pt = PT_IPV4; break; case 2: /* IPv6 explicit NULL label */ pt = PT_IPV6; break; default: /* * Generally there's no indication of protocol in MPLS label * encoding. * * However, draft-hsmit-isis-aal5mux-00.txt describes a * technique for encapsulating IS-IS and IP traffic on the * same ATM virtual circuit; you look at the first payload * byte to determine the network layer protocol, based on * the fact that * * 1) the first byte of an IP header is 0x45-0x4f * for IPv4 and 0x60-0x6f for IPv6; * * 2) the first byte of an OSI CLNP packet is 0x81, * the first byte of an OSI ES-IS packet is 0x82, * and the first byte of an OSI IS-IS packet is * 0x83; * * so the network layer protocol can be inferred from the * first byte of the packet, if the protocol is one of the * ones listed above. * * Cisco sends control-plane traffic MPLS-encapsulated in * this fashion. */ ND_TCHECK_1(p); if (length < 1) { /* nothing to print */ return; } switch(GET_U_1(p)) { case 0x45: case 0x46: case 0x47: case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: pt = PT_IPV4; break; case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67: case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f: pt = PT_IPV6; break; case 0x81: case 0x82: case 0x83: pt = PT_OSI; break; default: /* ok bail out - we did not figure out what it is*/ break; } } /* * Print the payload. */ if (pt == PT_UNKNOWN) { if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, length); return; } ND_PRINT(ndo->ndo_vflag ? "\n\t" : " "); switch (pt) { case PT_IPV4: ip_print(ndo, p, length); break; case PT_IPV6: ip6_print(ndo, p, length); break; case PT_OSI: isoclns_print(ndo, p, length); break; default: break; } return; trunc: nd_print_trunc(ndo); }
static int stp_print_mstp_bpdu(netdissect_options *ndo, const struct stp_bpdu_ *stp_bpdu, u_int length) { const u_char *ptr; uint8_t bpdu_flags; uint16_t v3len; uint16_t len; uint16_t msti; u_int offset; ptr = (const u_char *)stp_bpdu; ND_TCHECK_1(stp_bpdu->flags); bpdu_flags = EXTRACT_U_1(stp_bpdu->flags); ND_PRINT(", CIST Flags [%s], length %u", bittok2str(stp_bpdu_flag_values, "none", bpdu_flags), length); /* * in non-verbose mode just print the flags. */ if (!ndo->ndo_vflag) { return 1; } ND_PRINT("\n\tport-role %s, ", tok2str(rstp_obj_port_role_values, "Unknown", RSTP_EXTRACT_PORT_ROLE(bpdu_flags))); ND_TCHECK_4(stp_bpdu->root_path_cost); ND_PRINT("CIST root-id %s, CIST ext-pathcost %u", stp_print_bridge_id((const u_char *)&stp_bpdu->root_id), EXTRACT_BE_U_4(stp_bpdu->root_path_cost)); ND_TCHECK_SIZE(&stp_bpdu->bridge_id); ND_PRINT("\n\tCIST regional-root-id %s, ", stp_print_bridge_id((const u_char *)&stp_bpdu->bridge_id)); ND_TCHECK_2(stp_bpdu->port_id); ND_PRINT("CIST port-id %04x,", EXTRACT_BE_U_2(stp_bpdu->port_id)); ND_TCHECK_2(stp_bpdu->forward_delay); ND_PRINT("\n\tmessage-age %.2fs, max-age %.2fs" ", hello-time %.2fs, forwarding-delay %.2fs", (float) EXTRACT_BE_U_2(stp_bpdu->message_age) / STP_TIME_BASE, (float) EXTRACT_BE_U_2(stp_bpdu->max_age) / STP_TIME_BASE, (float) EXTRACT_BE_U_2(stp_bpdu->hello_time) / STP_TIME_BASE, (float) EXTRACT_BE_U_2(stp_bpdu->forward_delay) / STP_TIME_BASE); ND_TCHECK_2(ptr + MST_BPDU_VER3_LEN_OFFSET); ND_PRINT("\n\tv3len %u, ", EXTRACT_BE_U_2(ptr + MST_BPDU_VER3_LEN_OFFSET)); ND_TCHECK_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 12); ND_PRINT("MCID Name "); if (fn_printzp(ndo, ptr + MST_BPDU_CONFIG_NAME_OFFSET, 32, ndo->ndo_snapend)) goto trunc; ND_PRINT(", rev %u," "\n\t\tdigest %08x%08x%08x%08x, ", EXTRACT_BE_U_2(ptr + MST_BPDU_CONFIG_NAME_OFFSET + 32), EXTRACT_BE_U_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET), EXTRACT_BE_U_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 4), EXTRACT_BE_U_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 8), EXTRACT_BE_U_4(ptr + MST_BPDU_CONFIG_DIGEST_OFFSET + 12)); ND_TCHECK_4(ptr + MST_BPDU_CIST_INT_PATH_COST_OFFSET); ND_PRINT("CIST int-root-pathcost %u,", EXTRACT_BE_U_4(ptr + MST_BPDU_CIST_INT_PATH_COST_OFFSET)); ND_TCHECK_BRIDGE_ID(ptr + MST_BPDU_CIST_BRIDGE_ID_OFFSET); ND_PRINT("\n\tCIST bridge-id %s, ", stp_print_bridge_id(ptr + MST_BPDU_CIST_BRIDGE_ID_OFFSET)); ND_TCHECK_1(ptr + MST_BPDU_CIST_REMAIN_HOPS_OFFSET); ND_PRINT("CIST remaining-hops %u", EXTRACT_U_1(ptr + MST_BPDU_CIST_REMAIN_HOPS_OFFSET)); /* Dump all MSTI's */ ND_TCHECK_2(ptr + MST_BPDU_VER3_LEN_OFFSET); v3len = EXTRACT_BE_U_2(ptr + MST_BPDU_VER3_LEN_OFFSET); if (v3len > MST_BPDU_CONFIG_INFO_LENGTH) { len = v3len - MST_BPDU_CONFIG_INFO_LENGTH; offset = MST_BPDU_MSTI_OFFSET; while (len >= MST_BPDU_MSTI_LENGTH) { ND_TCHECK_LEN(ptr + offset, MST_BPDU_MSTI_LENGTH); msti = EXTRACT_BE_U_2(ptr + offset + MST_BPDU_MSTI_ROOT_PRIO_OFFSET); msti = msti & 0x0FFF; ND_PRINT("\n\tMSTI %u, Flags [%s], port-role %s", msti, bittok2str(stp_bpdu_flag_values, "none", EXTRACT_U_1(ptr + offset)), tok2str(rstp_obj_port_role_values, "Unknown", RSTP_EXTRACT_PORT_ROLE(EXTRACT_U_1(ptr + offset)))); ND_PRINT("\n\t\tMSTI regional-root-id %s, pathcost %u", stp_print_bridge_id(ptr + offset + MST_BPDU_MSTI_ROOT_PRIO_OFFSET), EXTRACT_BE_U_4(ptr + offset + MST_BPDU_MSTI_ROOT_PATH_COST_OFFSET)); ND_PRINT("\n\t\tMSTI bridge-prio %u, port-prio %u, hops %u", EXTRACT_U_1(ptr + offset + MST_BPDU_MSTI_BRIDGE_PRIO_OFFSET) >> 4, EXTRACT_U_1(ptr + offset + MST_BPDU_MSTI_PORT_PRIO_OFFSET) >> 4, EXTRACT_U_1(ptr + offset + MST_BPDU_MSTI_REMAIN_HOPS_OFFSET)); len -= MST_BPDU_MSTI_LENGTH; offset += MST_BPDU_MSTI_LENGTH; } }
/* * Print a single PDU. */ static u_int rpki_rtr_pdu_print(netdissect_options *ndo, const u_char *tptr, const u_int len, const u_char recurse, const u_int indent) { const rpki_rtr_pdu *pdu_header; u_int pdu_type, pdu_len, hexdump; const u_char *msg; /* Protocol Version */ ND_TCHECK_1(tptr); if (GET_U_1(tptr) != 0) { /* Skip the rest of the input buffer because even if this is * a well-formed PDU of a future RPKI-Router protocol version * followed by a well-formed PDU of RPKI-Router protocol * version 0, there is no way to know exactly how to skip the * current PDU. */ ND_PRINT("%sRPKI-RTRv%u (unknown)", indent_string(8), GET_U_1(tptr)); return len; } if (len < sizeof(rpki_rtr_pdu)) { ND_PRINT("(%u bytes is too few to decode)", len); goto invalid; } ND_TCHECK_LEN(tptr, sizeof(rpki_rtr_pdu)); pdu_header = (const rpki_rtr_pdu *)tptr; pdu_type = pdu_header->pdu_type; pdu_len = GET_BE_U_4(pdu_header->length); /* Do not check bounds with pdu_len yet, do it in the case blocks * below to make it possible to decode at least the beginning of * a truncated Error Report PDU or a truncated encapsulated PDU. */ hexdump = FALSE; ND_PRINT("%sRPKI-RTRv%u, %s PDU (%u), length: %u", indent_string(8), pdu_header->version, tok2str(rpki_rtr_pdu_values, "Unknown", pdu_type), pdu_type, pdu_len); if (pdu_len < sizeof(rpki_rtr_pdu) || pdu_len > len) goto invalid; switch (pdu_type) { /* * The following PDUs share the message format. */ case RPKI_RTR_SERIAL_NOTIFY_PDU: case RPKI_RTR_SERIAL_QUERY_PDU: case RPKI_RTR_END_OF_DATA_PDU: if (pdu_len != sizeof(rpki_rtr_pdu) + 4) goto invalid; ND_TCHECK_LEN(tptr, pdu_len); msg = (const u_char *)(pdu_header + 1); ND_PRINT("%sSession ID: 0x%04x, Serial: %u", indent_string(indent+2), GET_BE_U_2(pdu_header->u.session_id), GET_BE_U_4(msg)); break; /* * The following PDUs share the message format. */ case RPKI_RTR_RESET_QUERY_PDU: case RPKI_RTR_CACHE_RESET_PDU: if (pdu_len != sizeof(rpki_rtr_pdu)) goto invalid; /* no additional boundary to check */ /* * Zero payload PDUs. */ break; case RPKI_RTR_CACHE_RESPONSE_PDU: if (pdu_len != sizeof(rpki_rtr_pdu)) goto invalid; /* no additional boundary to check */ ND_PRINT("%sSession ID: 0x%04x", indent_string(indent+2), GET_BE_U_2(pdu_header->u.session_id)); break; case RPKI_RTR_IPV4_PREFIX_PDU: { const rpki_rtr_pdu_ipv4_prefix *pdu; if (pdu_len != sizeof(rpki_rtr_pdu) + 12) goto invalid; ND_TCHECK_LEN(tptr, pdu_len); pdu = (const rpki_rtr_pdu_ipv4_prefix *)tptr; ND_PRINT("%sIPv4 Prefix %s/%u-%u, origin-as %u, flags 0x%02x", indent_string(indent+2), ipaddr_string(ndo, pdu->prefix), pdu->prefix_length, pdu->max_length, GET_BE_U_4(pdu->as), pdu->flags); } break; case RPKI_RTR_IPV6_PREFIX_PDU: { const rpki_rtr_pdu_ipv6_prefix *pdu; if (pdu_len != sizeof(rpki_rtr_pdu) + 24) goto invalid; ND_TCHECK_LEN(tptr, pdu_len); pdu = (const rpki_rtr_pdu_ipv6_prefix *)tptr; ND_PRINT("%sIPv6 Prefix %s/%u-%u, origin-as %u, flags 0x%02x", indent_string(indent+2), ip6addr_string(ndo, pdu->prefix), pdu->prefix_length, pdu->max_length, GET_BE_U_4(pdu->as), pdu->flags); } break; case RPKI_RTR_ERROR_REPORT_PDU: { const rpki_rtr_pdu_error_report *pdu; u_int encapsulated_pdu_length, text_length, tlen, error_code; tlen = sizeof(rpki_rtr_pdu); /* Do not test for the "Length of Error Text" data element yet. */ if (pdu_len < tlen + 4) goto invalid; ND_TCHECK_LEN(tptr, tlen + 4); /* Safe up to and including the "Length of Encapsulated PDU" * data element, more data elements may be present. */ pdu = (const rpki_rtr_pdu_error_report *)tptr; encapsulated_pdu_length = GET_BE_U_4(pdu->encapsulated_pdu_length); tlen += 4; error_code = GET_BE_U_2(pdu->pdu_header.u.error_code); ND_PRINT("%sError code: %s (%u), Encapsulated PDU length: %u", indent_string(indent+2), tok2str(rpki_rtr_error_codes, "Unknown", error_code), error_code, encapsulated_pdu_length); if (encapsulated_pdu_length) { /* Section 5.10 of RFC 6810 says: * "An Error Report PDU MUST NOT be sent for an Error Report PDU." * * However, as far as the protocol encoding goes Error Report PDUs can * happen to be nested in each other, however many times, in which case * the decoder should still print such semantically incorrect PDUs. * * That said, "the Erroneous PDU field MAY be truncated" (ibid), thus * to keep things simple this implementation decodes only the two * outermost layers of PDUs and makes bounds checks in the outer and * the inner PDU independently. */ if (pdu_len < tlen + encapsulated_pdu_length) goto invalid; if (! recurse) { ND_TCHECK_LEN(tptr, tlen + encapsulated_pdu_length); } else { ND_PRINT("%s-----encapsulated PDU-----", indent_string(indent+4)); rpki_rtr_pdu_print(ndo, tptr + tlen, encapsulated_pdu_length, 0, indent + 2); } tlen += encapsulated_pdu_length; } if (pdu_len < tlen + 4) goto invalid; ND_TCHECK_LEN(tptr, tlen + 4); /* Safe up to and including the "Length of Error Text" data element, * one more data element may be present. */ /* * Extract, trail-zero and print the Error message. */ text_length = GET_BE_U_4(tptr + tlen); tlen += 4; if (text_length) { if (pdu_len < tlen + text_length) goto invalid; /* nd_printn() makes the bounds check */ ND_PRINT("%sError text: ", indent_string(indent+2)); if (nd_printn(ndo, tptr + tlen, text_length, ndo->ndo_snapend)) goto trunc; } } break; default: ND_TCHECK_LEN(tptr, pdu_len); /* * Unknown data, please hexdump. */ hexdump = TRUE; } /* do we also want to see a hex dump ? */ if (ndo->ndo_vflag > 1 || (ndo->ndo_vflag && hexdump)) { print_unknown_data(ndo,tptr,"\n\t ", pdu_len); } return pdu_len; invalid: nd_print_invalid(ndo); ND_TCHECK_LEN(tptr, len); return len; trunc: nd_print_trunc(ndo); return len; }
void dvmrp_print(netdissect_options *ndo, const u_char *bp, u_int len) { const u_char *ep; u_char type; uint8_t major_version, minor_version; ndo->ndo_protocol = "dvmrp"; ep = ndo->ndo_snapend; if (bp >= ep) return; ND_TCHECK_1(bp + 1); type = GET_U_1(bp + 1); /* Skip IGMP header */ bp += 8; len -= 8; switch (type) { case DVMRP_PROBE: ND_PRINT(" Probe"); if (ndo->ndo_vflag) { if (print_probe(ndo, bp, ep, len) < 0) goto trunc; } break; case DVMRP_REPORT: ND_PRINT(" Report"); if (ndo->ndo_vflag > 1) { if (print_report(ndo, bp, ep, len) < 0) goto trunc; } break; case DVMRP_ASK_NEIGHBORS: ND_PRINT(" Ask-neighbors(old)"); break; case DVMRP_NEIGHBORS: ND_PRINT(" Neighbors(old)"); if (print_neighbors(ndo, bp, ep, len) < 0) goto trunc; break; case DVMRP_ASK_NEIGHBORS2: ND_PRINT(" Ask-neighbors2"); break; case DVMRP_NEIGHBORS2: ND_PRINT(" Neighbors2"); /* * extract version from IGMP group address field */ bp -= 4; ND_TCHECK_4(bp); major_version = GET_U_1(bp + 3); minor_version = GET_U_1(bp + 2); bp += 4; if (print_neighbors2(ndo, bp, ep, len, major_version, minor_version) < 0) goto trunc; break; case DVMRP_PRUNE: ND_PRINT(" Prune"); if (print_prune(ndo, bp) < 0) goto trunc; break; case DVMRP_GRAFT: ND_PRINT(" Graft"); if (print_graft(ndo, bp) < 0) goto trunc; break; case DVMRP_GRAFT_ACK: ND_PRINT(" Graft-ACK"); if (print_graft_ack(ndo, bp) < 0) goto trunc; break; default: ND_PRINT(" [type %u]", type); break; } return; trunc: nd_print_trunc(ndo); return; }
/* * Print NTP time requests and responses */ static void ntp_time_print(netdissect_options *ndo, const struct ntp_time_data *bp, u_int length) { uint8_t stratum; if (length < NTP_TIMEMSG_MINLEN) goto invalid; ND_TCHECK_1(bp->stratum); stratum = EXTRACT_U_1(bp->stratum); ND_PRINT(", Stratum %u (%s)", stratum, tok2str(ntp_stratum_values, (stratum >=2 && stratum<=15) ? "secondary reference" : "reserved", stratum)); ND_TCHECK_1(bp->ppoll); ND_PRINT(", poll %d", EXTRACT_S_1(bp->ppoll)); p_poll(ndo, EXTRACT_S_1(bp->ppoll)); ND_TCHECK_1(bp->precision); ND_PRINT(", precision %d", EXTRACT_S_1(bp->precision)); ND_TCHECK_SIZE(&bp->root_delay); ND_PRINT("\n\tRoot Delay: "); p_sfix(ndo, &bp->root_delay); ND_TCHECK_SIZE(&bp->root_dispersion); ND_PRINT(", Root dispersion: "); p_sfix(ndo, &bp->root_dispersion); ND_TCHECK_4(bp->refid); ND_PRINT(", Reference-ID: "); /* Interpretation depends on stratum */ switch (stratum) { case UNSPECIFIED: ND_PRINT("(unspec)"); break; case PRIM_REF: if (nd_printn(ndo, (const u_char *)&(bp->refid), 4, ndo->ndo_snapend)) goto trunc; break; case INFO_QUERY: ND_PRINT("%s INFO_QUERY", ipaddr_string(ndo, bp->refid)); /* this doesn't have more content */ return; case INFO_REPLY: ND_PRINT("%s INFO_REPLY", ipaddr_string(ndo, bp->refid)); /* this is too complex to be worth printing */ return; default: /* In NTPv4 (RFC 5905) refid is an IPv4 address or first 32 bits of MD5 sum of IPv6 address */ ND_PRINT("0x%08x", EXTRACT_BE_U_4(bp->refid)); break; } ND_TCHECK_SIZE(&bp->ref_timestamp); ND_PRINT("\n\t Reference Timestamp: "); p_ntp_time(ndo, &(bp->ref_timestamp)); ND_TCHECK_SIZE(&bp->org_timestamp); ND_PRINT("\n\t Originator Timestamp: "); p_ntp_time(ndo, &(bp->org_timestamp)); ND_TCHECK_SIZE(&bp->rec_timestamp); ND_PRINT("\n\t Receive Timestamp: "); p_ntp_time(ndo, &(bp->rec_timestamp)); ND_TCHECK_SIZE(&bp->xmt_timestamp); ND_PRINT("\n\t Transmit Timestamp: "); p_ntp_time(ndo, &(bp->xmt_timestamp)); ND_PRINT("\n\t Originator - Receive Timestamp: "); p_ntp_delta(ndo, &(bp->org_timestamp), &(bp->rec_timestamp)); ND_PRINT("\n\t Originator - Transmit Timestamp: "); p_ntp_delta(ndo, &(bp->org_timestamp), &(bp->xmt_timestamp)); /* FIXME: this code is not aware of any extension fields */ if (length == NTP_TIMEMSG_MINLEN + 4) { /* Optional: key-id (crypto-NAK) */ ND_TCHECK_4(bp->key_id); ND_PRINT("\n\tKey id: %u", EXTRACT_BE_U_4(bp->key_id)); } else if (length == NTP_TIMEMSG_MINLEN + 4 + 16) { /* Optional: key-id + 128-bit digest */ ND_TCHECK_4(bp->key_id); ND_PRINT("\n\tKey id: %u", EXTRACT_BE_U_4(bp->key_id)); ND_TCHECK_LEN(bp->message_digest, 16); ND_PRINT("\n\tAuthentication: %08x%08x%08x%08x", EXTRACT_BE_U_4(bp->message_digest), EXTRACT_BE_U_4(bp->message_digest + 4), EXTRACT_BE_U_4(bp->message_digest + 8), EXTRACT_BE_U_4(bp->message_digest + 12)); } else if (length == NTP_TIMEMSG_MINLEN + 4 + 20) { /* Optional: key-id + 160-bit digest */ ND_TCHECK_4(bp->key_id); ND_PRINT("\n\tKey id: %u", EXTRACT_BE_U_4(bp->key_id)); ND_TCHECK_LEN(bp->message_digest, 20); ND_PRINT("\n\tAuthentication: %08x%08x%08x%08x%08x", EXTRACT_BE_U_4(bp->message_digest), EXTRACT_BE_U_4(bp->message_digest + 4), EXTRACT_BE_U_4(bp->message_digest + 8), EXTRACT_BE_U_4(bp->message_digest + 12), EXTRACT_BE_U_4(bp->message_digest + 16)); } else if (length > NTP_TIMEMSG_MINLEN) { ND_PRINT("\n\t(%u more bytes after the header)", length - NTP_TIMEMSG_MINLEN); } return; invalid: nd_print_invalid(ndo); ND_TCHECK_LEN(bp, length); return; trunc: nd_print_trunc(ndo); }
void msdp_print(netdissect_options *ndo, const u_char *sp, u_int length) { unsigned int type, len; ndo->ndo_protocol = "msdp"; ND_TCHECK_3(sp); /* See if we think we're at the beginning of a compound packet */ type = EXTRACT_U_1(sp); len = EXTRACT_BE_U_2(sp + 1); if (len > 1500 || len < 3 || type == 0 || type > MSDP_TYPE_MAX) goto trunc; /* not really truncated, but still not decodable */ ND_PRINT(" msdp:"); while (length != 0) { ND_TCHECK_3(sp); type = EXTRACT_U_1(sp); len = EXTRACT_BE_U_2(sp + 1); if (len > 1400 || ndo->ndo_vflag) ND_PRINT(" [len %u]", len); if (len < 3) goto trunc; if (length < len) goto trunc; sp += 3; length -= 3; switch (type) { case 1: /* IPv4 Source-Active */ case 3: /* IPv4 Source-Active Response */ if (type == 1) ND_PRINT(" SA"); else ND_PRINT(" SA-Response"); ND_TCHECK_1(sp); ND_PRINT(" %u entries", EXTRACT_U_1(sp)); if ((u_int)((EXTRACT_U_1(sp) * 12) + 8) < len) { ND_PRINT(" [w/data]"); if (ndo->ndo_vflag > 1) { ND_PRINT(" "); ip_print(ndo, sp + EXTRACT_U_1(sp) * 12 + 8 - 3, len - (EXTRACT_U_1(sp) * 12 + 8)); } } break; case 2: ND_PRINT(" SA-Request"); ND_TCHECK_5(sp); ND_PRINT(" for %s", ipaddr_string(ndo, sp + 1)); break; case 4: ND_PRINT(" Keepalive"); if (len != 3) ND_PRINT("[len=%u] ", len); break; case 5: ND_PRINT(" Notification"); break; default: ND_PRINT(" [type=%u len=%u]", type, len); break; } sp += (len - 3); length -= (len - 3); } return; trunc: nd_print_trunc(ndo); }
static void print_attr_strange(netdissect_options *ndo, const u_char *data, u_int length, u_short attr_code) { u_short len_data; u_int error_cause_value; switch(attr_code) { case ARAP_PASS: if (length != 16) { ND_PRINT("ERROR: length %u != 16", length); return; } ND_PRINT("User_challenge ("); ND_TCHECK_8(data); len_data = 8; PRINT_HEX(len_data, data); ND_PRINT(") User_resp("); ND_TCHECK_8(data); len_data = 8; PRINT_HEX(len_data, data); ND_PRINT(")"); break; case ARAP_FEATURES: if (length != 14) { ND_PRINT("ERROR: length %u != 14", length); return; } ND_TCHECK_1(data); if (EXTRACT_U_1(data)) ND_PRINT("User can change password"); else ND_PRINT("User cannot change password"); data++; ND_TCHECK_1(data); ND_PRINT(", Min password length: %u", EXTRACT_U_1(data)); data++; ND_PRINT(", created at: "); ND_TCHECK_4(data); len_data = 4; PRINT_HEX(len_data, data); ND_PRINT(", expires in: "); ND_TCHECK_4(data); len_data = 4; PRINT_HEX(len_data, data); ND_PRINT(", Current Time: "); ND_TCHECK_4(data); len_data = 4; PRINT_HEX(len_data, data); break; case ARAP_CHALLENGE_RESP: if (length < 8) { ND_PRINT("ERROR: length %u != 8", length); return; } ND_TCHECK_8(data); len_data = 8; PRINT_HEX(len_data, data); break; case ERROR_CAUSE: if (length != 4) { ND_PRINT("Error: length %u != 4", length); return; } ND_TCHECK_4(data); error_cause_value = EXTRACT_BE_U_4(data); ND_PRINT("Error cause %u: %s", error_cause_value, tok2str(errorcausetype, "Error-Cause %u not known", error_cause_value)); break; } return; trunc: nd_print_trunc(ndo); }