static inline void ipnet_hdr_print(netdissect_options *ndo, const u_char *bp, u_int length) { const ipnet_hdr_t *hdr; hdr = (const ipnet_hdr_t *)bp; ND_TCHECK_SIZE(hdr); ND_PRINT("%u > %u", EXTRACT_BE_U_4(hdr->iph_zsrc), EXTRACT_BE_U_4(hdr->iph_zdst)); if (!ndo->ndo_qflag) { ND_PRINT(", family %s (%u)", tok2str(ipnet_values, "Unknown", EXTRACT_U_1(hdr->iph_family)), EXTRACT_U_1(hdr->iph_family)); } else { ND_PRINT(", %s", tok2str(ipnet_values, "Unknown Ethertype (0x%04x)", EXTRACT_U_1(hdr->iph_family))); } ND_PRINT(", length %u: ", length); return; trunc: ND_PRINT(" %s", tstr); }
static int parsepathconf(netdissect_options *ndo, const uint32_t *dp) { u_int er; const struct nfsv3_pathconf *spp; if (!(dp = parsestatus(ndo, dp, &er))) return (0); if (ndo->ndo_vflag) ND_PRINT(" POST:"); if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag))) return (0); if (er) return (1); spp = (const struct nfsv3_pathconf *)dp; ND_TCHECK_SIZE(spp); ND_PRINT(" linkmax %u namemax %u %s %s %s %s", EXTRACT_BE_U_4(&spp->pc_linkmax), EXTRACT_BE_U_4(&spp->pc_namemax), EXTRACT_BE_U_4(&spp->pc_notrunc) ? "notrunc" : "", EXTRACT_BE_U_4(&spp->pc_chownrestricted) ? "chownres" : "", EXTRACT_BE_U_4(&spp->pc_caseinsensitive) ? "igncase" : "", EXTRACT_BE_U_4(&spp->pc_casepreserving) ? "keepcase" : ""); return (1); trunc: return (0); }
void igrp_print(netdissect_options *ndo, const u_char *bp, u_int length) { const struct igrphdr *hdr; const u_char *cp; u_int nint, nsys, next; hdr = (const struct igrphdr *)bp; cp = (const u_char *)(hdr + 1); ND_PRINT("igrp:"); /* Header */ ND_TCHECK_SIZE(hdr); nint = EXTRACT_BE_U_2(hdr->ig_ni); nsys = EXTRACT_BE_U_2(hdr->ig_ns); next = EXTRACT_BE_U_2(hdr->ig_nx); ND_PRINT(" %s V%u edit=%u AS=%u (%u/%u/%u)", tok2str(op2str, "op-#%u", IGRP_OP(EXTRACT_U_1(hdr->ig_vop))), IGRP_V(EXTRACT_U_1(hdr->ig_vop)), EXTRACT_U_1(hdr->ig_ed), EXTRACT_BE_U_2(hdr->ig_as), nint, nsys, next); length -= sizeof(*hdr); while (length >= IGRP_RTE_SIZE) { if (nint > 0) { ND_TCHECK_LEN(cp, IGRP_RTE_SIZE); igrp_entry_print(ndo, (const struct igrprte *)cp, 1, 0); --nint; } else if (nsys > 0) { ND_TCHECK_LEN(cp, IGRP_RTE_SIZE); igrp_entry_print(ndo, (const struct igrprte *)cp, 0, 0); --nsys; } else if (next > 0) { ND_TCHECK_LEN(cp, IGRP_RTE_SIZE); igrp_entry_print(ndo, (const struct igrprte *)cp, 0, 1); --next; } else { ND_PRINT(" [extra bytes %u]", length); break; } cp += IGRP_RTE_SIZE; length -= IGRP_RTE_SIZE; } if (nint == 0 && nsys == 0 && next == 0) return; trunc: ND_PRINT(" [|igrp]"); }
void msnlb_print(netdissect_options *ndo, const u_char *bp) { const struct msnlb_heartbeat_pkt *hb; hb = (const struct msnlb_heartbeat_pkt *)bp; ND_TCHECK_SIZE(hb); ND_PRINT("MS NLB heartbeat, host priority: %u,", EXTRACT_LE_U_4((hb->host_prio))); ND_PRINT(" cluster IP: %s,", ipaddr_string(ndo, hb->virtual_ip)); ND_PRINT(" host IP: %s", ipaddr_string(ndo, hb->host_ip)); return; trunc: ND_PRINT("[|MS NLB]"); }
static int parsefsinfo(netdissect_options *ndo, const uint32_t *dp) { const struct nfsv3_fsinfo *sfp; u_int er; if (!(dp = parsestatus(ndo, dp, &er))) return (0); if (ndo->ndo_vflag) ND_PRINT(" POST:"); if (!(dp = parse_post_op_attr(ndo, dp, ndo->ndo_vflag))) return (0); if (er) return (1); sfp = (const struct nfsv3_fsinfo *)dp; ND_TCHECK_SIZE(sfp); ND_PRINT(" rtmax %u rtpref %u wtmax %u wtpref %u dtpref %u", EXTRACT_BE_U_4(&sfp->fs_rtmax), EXTRACT_BE_U_4(&sfp->fs_rtpref), EXTRACT_BE_U_4(&sfp->fs_wtmax), EXTRACT_BE_U_4(&sfp->fs_wtpref), EXTRACT_BE_U_4(&sfp->fs_dtpref)); if (ndo->ndo_vflag) { ND_PRINT(" rtmult %u wtmult %u maxfsz %" PRIu64, EXTRACT_BE_U_4(&sfp->fs_rtmult), EXTRACT_BE_U_4(&sfp->fs_wtmult), EXTRACT_BE_U_8((const uint32_t *)&sfp->fs_maxfilesize)); ND_PRINT(" delta %u.%06u ", EXTRACT_BE_U_4(&sfp->fs_timedelta.nfsv3_sec), EXTRACT_BE_U_4(&sfp->fs_timedelta.nfsv3_nsec)); } return (1); trunc: return (0); }
static void slow_oam_print(netdissect_options *ndo, const u_char *tptr, u_int tlen) { uint8_t code; uint8_t type, length; uint8_t state; uint8_t command; u_int hexdump; struct slow_oam_common_header_t { nd_uint16_t flags; nd_uint8_t code; }; struct slow_oam_tlv_header_t { nd_uint8_t type; nd_uint8_t length; }; union { const struct slow_oam_common_header_t *slow_oam_common_header; const struct slow_oam_tlv_header_t *slow_oam_tlv_header; } ptr; union { const struct slow_oam_info_t *slow_oam_info; const struct slow_oam_link_event_t *slow_oam_link_event; const struct slow_oam_variablerequest_t *slow_oam_variablerequest; const struct slow_oam_variableresponse_t *slow_oam_variableresponse; const struct slow_oam_loopbackctrl_t *slow_oam_loopbackctrl; } tlv; ptr.slow_oam_common_header = (const struct slow_oam_common_header_t *)tptr; if (tlen < sizeof(*ptr.slow_oam_common_header)) goto tooshort; ND_TCHECK_SIZE(ptr.slow_oam_common_header); tptr += sizeof(struct slow_oam_common_header_t); tlen -= sizeof(struct slow_oam_common_header_t); code = EXTRACT_U_1(ptr.slow_oam_common_header->code); ND_PRINT("\n\tCode %s OAM PDU, Flags [%s]", tok2str(slow_oam_code_values, "Unknown (%u)", code), bittok2str(slow_oam_flag_values, "none", EXTRACT_BE_U_2(ptr.slow_oam_common_header->flags))); switch (code) { case SLOW_OAM_CODE_INFO: while (tlen > 0) { ptr.slow_oam_tlv_header = (const struct slow_oam_tlv_header_t *)tptr; if (tlen < sizeof(*ptr.slow_oam_tlv_header)) goto tooshort; ND_TCHECK_SIZE(ptr.slow_oam_tlv_header); type = EXTRACT_U_1(ptr.slow_oam_tlv_header->type); length = EXTRACT_U_1(ptr.slow_oam_tlv_header->length); ND_PRINT("\n\t %s Information Type (%u), length %u", tok2str(slow_oam_info_type_values, "Reserved", type), type, length); if (type == SLOW_OAM_INFO_TYPE_END_OF_TLV) { /* * As IEEE Std 802.3-2015 says for the End of TLV Marker, * "(the length and value of the Type 0x00 TLV can be ignored)". */ return; } /* length includes the type and length fields */ if (length < sizeof(struct slow_oam_tlv_header_t)) { ND_PRINT("\n\t ERROR: illegal length - should be >= %u", (u_int)sizeof(struct slow_oam_tlv_header_t)); return; } if (tlen < length) goto tooshort; ND_TCHECK_LEN(tptr, length); hexdump = FALSE; switch (type) { case SLOW_OAM_INFO_TYPE_LOCAL: /* identical format - fall through */ case SLOW_OAM_INFO_TYPE_REMOTE: tlv.slow_oam_info = (const struct slow_oam_info_t *)tptr; if (EXTRACT_U_1(tlv.slow_oam_info->info_length) != sizeof(struct slow_oam_info_t)) { ND_PRINT("\n\t ERROR: illegal length - should be %lu", (unsigned long) sizeof(struct slow_oam_info_t)); hexdump = TRUE; goto badlength_code_info; } ND_PRINT("\n\t OAM-Version %u, Revision %u", EXTRACT_U_1(tlv.slow_oam_info->oam_version), EXTRACT_BE_U_2(tlv.slow_oam_info->revision)); state = EXTRACT_U_1(tlv.slow_oam_info->state); ND_PRINT("\n\t State-Parser-Action %s, State-MUX-Action %s", tok2str(slow_oam_info_type_state_parser_values, "Reserved", state & OAM_INFO_TYPE_PARSER_MASK), tok2str(slow_oam_info_type_state_mux_values, "Reserved", state & OAM_INFO_TYPE_MUX_MASK)); ND_PRINT("\n\t OAM-Config Flags [%s], OAM-PDU-Config max-PDU size %u", bittok2str(slow_oam_info_type_oam_config_values, "none", EXTRACT_U_1(tlv.slow_oam_info->oam_config)), EXTRACT_BE_U_2(tlv.slow_oam_info->oam_pdu_config) & OAM_INFO_TYPE_PDU_SIZE_MASK); ND_PRINT("\n\t OUI %s (0x%06x), Vendor-Private 0x%08x", tok2str(oui_values, "Unknown", EXTRACT_BE_U_3(tlv.slow_oam_info->oui)), EXTRACT_BE_U_3(tlv.slow_oam_info->oui), EXTRACT_BE_U_4(tlv.slow_oam_info->vendor_private)); break; case SLOW_OAM_INFO_TYPE_ORG_SPECIFIC: hexdump = TRUE; break; default: hexdump = TRUE; break; } badlength_code_info: /* do we also want to see a hex dump ? */ if (ndo->ndo_vflag > 1 || hexdump==TRUE) { print_unknown_data(ndo, tptr, "\n\t ", length); } tlen -= length; tptr += length; } break; case SLOW_OAM_CODE_EVENT_NOTIF: /* Sequence number */ if (tlen < 2) goto tooshort; ND_TCHECK_2(tptr); ND_PRINT("\n\t Sequence Number %u", EXTRACT_BE_U_2(tptr)); tlen -= 2; tptr += 2; /* TLVs */ while (tlen > 0) { ptr.slow_oam_tlv_header = (const struct slow_oam_tlv_header_t *)tptr; if (tlen < sizeof(*ptr.slow_oam_tlv_header)) goto tooshort; ND_TCHECK_SIZE(ptr.slow_oam_tlv_header); type = EXTRACT_U_1(ptr.slow_oam_tlv_header->type); length = EXTRACT_U_1(ptr.slow_oam_tlv_header->length); ND_PRINT("\n\t %s Link Event Type (%u), length %u", tok2str(slow_oam_link_event_values, "Reserved", type), type, length); if (type == SLOW_OAM_INFO_TYPE_END_OF_TLV) { /* * As IEEE Std 802.3-2015 says for the End of TLV Marker, * "(the length and value of the Type 0x00 TLV can be ignored)". */ return; } /* length includes the type and length fields */ if (length < sizeof(struct slow_oam_tlv_header_t)) { ND_PRINT("\n\t ERROR: illegal length - should be >= %u", (u_int)sizeof(struct slow_oam_tlv_header_t)); return; } if (tlen < length) goto tooshort; ND_TCHECK_LEN(tptr, length); hexdump = FALSE; switch (type) { case SLOW_OAM_LINK_EVENT_ERR_SYM_PER: /* identical format - fall through */ case SLOW_OAM_LINK_EVENT_ERR_FRM: case SLOW_OAM_LINK_EVENT_ERR_FRM_PER: case SLOW_OAM_LINK_EVENT_ERR_FRM_SUMM: tlv.slow_oam_link_event = (const struct slow_oam_link_event_t *)tptr; if (EXTRACT_U_1(tlv.slow_oam_link_event->event_length) != sizeof(struct slow_oam_link_event_t)) { ND_PRINT("\n\t ERROR: illegal length - should be %lu", (unsigned long) sizeof(struct slow_oam_link_event_t)); hexdump = TRUE; goto badlength_event_notif; } ND_PRINT("\n\t Timestamp %u ms, Errored Window %" PRIu64 "\n\t Errored Threshold %" PRIu64 "\n\t Errors %" PRIu64 "\n\t Error Running Total %" PRIu64 "\n\t Event Running Total %u", EXTRACT_BE_U_2(tlv.slow_oam_link_event->time_stamp)*100, EXTRACT_BE_U_8(tlv.slow_oam_link_event->window), EXTRACT_BE_U_8(tlv.slow_oam_link_event->threshold), EXTRACT_BE_U_8(tlv.slow_oam_link_event->errors), EXTRACT_BE_U_8(tlv.slow_oam_link_event->errors_running_total), EXTRACT_BE_U_4(tlv.slow_oam_link_event->event_running_total)); break; case SLOW_OAM_LINK_EVENT_ORG_SPECIFIC: hexdump = TRUE; break; default: hexdump = TRUE; break; } badlength_event_notif: /* do we also want to see a hex dump ? */ if (ndo->ndo_vflag > 1 || hexdump==TRUE) { print_unknown_data(ndo, tptr, "\n\t ", length); } tlen -= length; tptr += length; } break; case SLOW_OAM_CODE_LOOPBACK_CTRL: tlv.slow_oam_loopbackctrl = (const struct slow_oam_loopbackctrl_t *)tptr; if (tlen < sizeof(*tlv.slow_oam_loopbackctrl)) goto tooshort; ND_TCHECK_SIZE(tlv.slow_oam_loopbackctrl); command = EXTRACT_U_1(tlv.slow_oam_loopbackctrl->command); ND_PRINT("\n\t Command %s (%u)", tok2str(slow_oam_loopbackctrl_cmd_values, "Unknown", command), command); tptr ++; tlen --; break; /* * FIXME those are the defined codes that lack a decoder * you are welcome to contribute code ;-) */ case SLOW_OAM_CODE_VAR_REQUEST: case SLOW_OAM_CODE_VAR_RESPONSE: case SLOW_OAM_CODE_PRIVATE: default: if (ndo->ndo_vflag <= 1) { print_unknown_data(ndo, tptr, "\n\t ", tlen); } break; } return; tooshort: ND_PRINT("\n\t\t packet is too short"); return; trunc: ND_PRINT("%s", tstr); }
void lwapp_data_print(netdissect_options *ndo, const u_char *pptr, u_int len) { const struct lwapp_transport_header *lwapp_trans_header; const u_char *tptr; u_int tlen; u_int version; tptr=pptr; /* check if enough bytes for AP identity */ ND_TCHECK_6(tptr); lwapp_trans_header = (const struct lwapp_transport_header *)pptr; ND_TCHECK_SIZE(lwapp_trans_header); version = EXTRACT_U_1(lwapp_trans_header->version); /* * Sanity checking of the header. */ if (LWAPP_EXTRACT_VERSION(version) != LWAPP_VERSION) { ND_PRINT("LWAPP version %u packet not supported", LWAPP_EXTRACT_VERSION(version)); return; } /* non-verbose */ if (ndo->ndo_vflag < 1) { ND_PRINT("LWAPPv%u, %s frame, Flags [%s], length %u", LWAPP_EXTRACT_VERSION(version), LWAPP_EXTRACT_CONTROL_BIT(version) ? "Control" : "Data", bittok2str(lwapp_header_bits_values,"none",version&0x07), len); return; } /* ok they seem to want to know everything - lets fully decode it */ tlen=EXTRACT_BE_U_2(lwapp_trans_header->length); if (tlen < sizeof(struct lwapp_transport_header)) { ND_PRINT("LWAPPv%u, %s frame, Radio-id %u, Flags [%s], length %u < transport header length", LWAPP_EXTRACT_VERSION(version), LWAPP_EXTRACT_CONTROL_BIT(version) ? "Control" : "Data", LWAPP_EXTRACT_RID(version), bittok2str(lwapp_header_bits_values,"none",version&0x07), tlen); return; } ND_PRINT("LWAPPv%u, %s frame, Radio-id %u, Flags [%s], Frag-id %u, length %u", LWAPP_EXTRACT_VERSION(version), LWAPP_EXTRACT_CONTROL_BIT(version) ? "Control" : "Data", LWAPP_EXTRACT_RID(version), bittok2str(lwapp_header_bits_values,"none",version&0x07), EXTRACT_U_1(lwapp_trans_header->frag_id), tlen); tptr+=sizeof(struct lwapp_transport_header); tlen-=sizeof(struct lwapp_transport_header); /* FIX - An IEEE 802.11 frame follows - hexdump for now */ print_unknown_data(ndo, tptr, "\n\t", tlen); return; trunc: ND_PRINT("%s", data_tstr); }
void lwapp_control_print(netdissect_options *ndo, const u_char *pptr, u_int len, int has_ap_ident) { const struct lwapp_transport_header *lwapp_trans_header; const struct lwapp_control_header *lwapp_control_header; const u_char *tptr; uint8_t version; u_int tlen; u_int msg_type, msg_tlen; tptr=pptr; if (has_ap_ident) { /* check if enough bytes for AP identity */ ND_TCHECK_6(tptr); lwapp_trans_header = (const struct lwapp_transport_header *)(pptr+6); } else { lwapp_trans_header = (const struct lwapp_transport_header *)pptr; } ND_TCHECK_SIZE(lwapp_trans_header); version = EXTRACT_U_1(lwapp_trans_header->version); /* * Sanity checking of the header. */ if (LWAPP_EXTRACT_VERSION(version) != LWAPP_VERSION) { ND_PRINT("LWAPP version %u packet not supported", LWAPP_EXTRACT_VERSION(version)); return; } /* non-verbose */ if (ndo->ndo_vflag < 1) { ND_PRINT("LWAPPv%u, %s frame, Flags [%s], length %u", LWAPP_EXTRACT_VERSION(version), LWAPP_EXTRACT_CONTROL_BIT(version) ? "Control" : "Data", bittok2str(lwapp_header_bits_values,"none",version&0x07), len); return; } /* ok they seem to want to know everything - lets fully decode it */ tlen=EXTRACT_BE_U_2(lwapp_trans_header->length); ND_PRINT("LWAPPv%u, %s frame, Radio-id %u, Flags [%s], Frag-id %u, length %u", LWAPP_EXTRACT_VERSION(version), LWAPP_EXTRACT_CONTROL_BIT(version) ? "Control" : "Data", LWAPP_EXTRACT_RID(version), bittok2str(lwapp_header_bits_values,"none",version&0x07), EXTRACT_U_1(lwapp_trans_header->frag_id), tlen); if (has_ap_ident) { ND_PRINT("\n\tAP identity: %s", etheraddr_string(ndo, tptr)); tptr+=sizeof(struct lwapp_transport_header)+6; } else { tptr+=sizeof(struct lwapp_transport_header); } while(tlen!=0) { /* did we capture enough for fully decoding the object header ? */ ND_TCHECK_LEN(tptr, sizeof(struct lwapp_control_header)); if (tlen < sizeof(struct lwapp_control_header)) { ND_PRINT("\n\t Msg goes past end of PDU"); break; } lwapp_control_header = (const struct lwapp_control_header *)tptr; msg_tlen = EXTRACT_BE_U_2(lwapp_control_header->len); if (tlen < sizeof(struct lwapp_control_header) + msg_tlen) { ND_PRINT("\n\t Msg goes past end of PDU"); break; } /* print message header */ msg_type = EXTRACT_U_1(lwapp_control_header->msg_type); ND_PRINT("\n\t Msg type: %s (%u), Seqnum: %u, Msg len: %u, Session: 0x%08x", tok2str(lwapp_msg_type_values,"Unknown",msg_type), msg_type, EXTRACT_U_1(lwapp_control_header->seq_num), msg_tlen, EXTRACT_BE_U_4(lwapp_control_header->session_id)); /* did we capture enough for fully decoding the message */ ND_TCHECK_LEN(tptr, msg_tlen); /* XXX - Decode sub messages for each message */ switch(msg_type) { case LWAPP_MSGTYPE_DISCOVERY_REQUEST: case LWAPP_MSGTYPE_DISCOVERY_RESPONSE: case LWAPP_MSGTYPE_JOIN_REQUEST: case LWAPP_MSGTYPE_JOIN_RESPONSE: case LWAPP_MSGTYPE_JOIN_ACK: case LWAPP_MSGTYPE_JOIN_CONFIRM: case LWAPP_MSGTYPE_CONFIGURE_REQUEST: case LWAPP_MSGTYPE_CONFIGURE_RESPONSE: case LWAPP_MSGTYPE_CONF_UPDATE_REQUEST: case LWAPP_MSGTYPE_CONF_UPDATE_RESPONSE: case LWAPP_MSGTYPE_WTP_EVENT_REQUEST: case LWAPP_MSGTYPE_WTP_EVENT_RESPONSE: case LWAPP_MSGTYPE_CHANGE_STATE_EVENT_REQUEST: case LWAPP_MSGTYPE_CHANGE_STATE_EVENT_RESPONSE: case LWAPP_MSGTYPE_ECHO_REQUEST: case LWAPP_MSGTYPE_ECHO_RESPONSE: case LWAPP_MSGTYPE_IMAGE_DATA_REQUEST: case LWAPP_MSGTYPE_IMAGE_DATA_RESPONSE: case LWAPP_MSGTYPE_RESET_REQUEST: case LWAPP_MSGTYPE_RESET_RESPONSE: case LWAPP_MSGTYPE_KEY_UPDATE_REQUEST: case LWAPP_MSGTYPE_KEY_UPDATE_RESPONSE: case LWAPP_MSGTYPE_PRIMARY_DISCOVERY_REQUEST: case LWAPP_MSGTYPE_PRIMARY_DISCOVERY_RESPONSE: case LWAPP_MSGTYPE_DATA_TRANSFER_REQUEST: case LWAPP_MSGTYPE_DATA_TRANSFER_RESPONSE: case LWAPP_MSGTYPE_CLEAR_CONFIG_INDICATION: case LWAPP_MSGTYPE_WLAN_CONFIG_REQUEST: case LWAPP_MSGTYPE_WLAN_CONFIG_RESPONSE: case LWAPP_MSGTYPE_MOBILE_CONFIG_REQUEST: case LWAPP_MSGTYPE_MOBILE_CONFIG_RESPONSE: default: break; } tptr += sizeof(struct lwapp_control_header) + msg_tlen; tlen -= sizeof(struct lwapp_control_header) + msg_tlen; } return; trunc: ND_PRINT("%s", control_tstr); }
/** * dccp_print - show dccp packet * @bp - beginning of dccp packet * @data2 - beginning of enclosing * @len - length of ip packet */ void dccp_print(netdissect_options *ndo, const u_char *bp, const u_char *data2, u_int len) { const struct dccp_hdr *dh; const struct ip *ip; const struct ip6_hdr *ip6; const u_char *cp; u_short sport, dport; u_int hlen; u_int fixed_hdrlen; uint8_t dccph_type; ndo->ndo_protocol = "dccp"; dh = (const struct dccp_hdr *)bp; ip = (const struct ip *)data2; if (IP_V(ip) == 6) ip6 = (const struct ip6_hdr *)data2; else ip6 = NULL; /* make sure we have enough data to look at the X bit */ cp = (const u_char *)(dh + 1); if (cp > ndo->ndo_snapend) goto trunc; if (len < sizeof(struct dccp_hdr)) { ND_PRINT("truncated-dccp - %u bytes missing!", (u_int)sizeof(struct dccp_hdr) - len); return; } /* get the length of the generic header */ fixed_hdrlen = dccp_basic_hdr_len(ndo, dh); if (len < fixed_hdrlen) { ND_PRINT("truncated-dccp - %u bytes missing!", fixed_hdrlen - len); return; } ND_TCHECK_LEN(dh, fixed_hdrlen); sport = GET_BE_U_2(dh->dccph_sport); dport = GET_BE_U_2(dh->dccph_dport); hlen = GET_U_1(dh->dccph_doff) * 4; if (ip6) { ND_PRINT("%s.%u > %s.%u: ", ip6addr_string(ndo, ip6->ip6_src), sport, ip6addr_string(ndo, ip6->ip6_dst), dport); } else { ND_PRINT("%s.%u > %s.%u: ", ipaddr_string(ndo, ip->ip_src), sport, ipaddr_string(ndo, ip->ip_dst), dport); } ND_PRINT("DCCP"); if (ndo->ndo_qflag) { ND_PRINT(" %u", len - hlen); if (hlen > len) { ND_PRINT(" [bad hdr length %u - too long, > %u]", hlen, len); } return; } /* other variables in generic header */ if (ndo->ndo_vflag) { ND_PRINT(" (CCVal %u, CsCov %u, ", DCCPH_CCVAL(dh), DCCPH_CSCOV(dh)); } /* checksum calculation */ if (ndo->ndo_vflag && ND_TTEST_LEN(bp, len)) { uint16_t sum = 0, dccp_sum; dccp_sum = GET_BE_U_2(dh->dccph_checksum); ND_PRINT("cksum 0x%04x ", dccp_sum); if (IP_V(ip) == 4) sum = dccp_cksum(ndo, ip, dh, len); else if (IP_V(ip) == 6) sum = dccp6_cksum(ndo, ip6, dh, len); if (sum != 0) ND_PRINT("(incorrect -> 0x%04x)",in_cksum_shouldbe(dccp_sum, sum)); else ND_PRINT("(correct)"); } if (ndo->ndo_vflag) ND_PRINT(")"); ND_PRINT(" "); dccph_type = DCCPH_TYPE(dh); switch (dccph_type) { case DCCP_PKT_REQUEST: { const struct dccp_hdr_request *dhr = (const struct dccp_hdr_request *)(bp + fixed_hdrlen); fixed_hdrlen += 4; if (len < fixed_hdrlen) { ND_PRINT("truncated-%s - %u bytes missing!", tok2str(dccp_pkt_type_str, "", dccph_type), fixed_hdrlen - len); return; } ND_TCHECK_SIZE(dhr); ND_PRINT("%s (service=%u) ", tok2str(dccp_pkt_type_str, "", dccph_type), GET_BE_U_4(dhr->dccph_req_service)); break; } case DCCP_PKT_RESPONSE: { const struct dccp_hdr_response *dhr = (const struct dccp_hdr_response *)(bp + fixed_hdrlen); fixed_hdrlen += 12; if (len < fixed_hdrlen) { ND_PRINT("truncated-%s - %u bytes missing!", tok2str(dccp_pkt_type_str, "", dccph_type), fixed_hdrlen - len); return; } ND_TCHECK_SIZE(dhr); ND_PRINT("%s (service=%u) ", tok2str(dccp_pkt_type_str, "", dccph_type), GET_BE_U_4(dhr->dccph_resp_service)); break; } case DCCP_PKT_DATA: ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type)); break; case DCCP_PKT_ACK: { fixed_hdrlen += 8; if (len < fixed_hdrlen) { ND_PRINT("truncated-%s - %u bytes missing!", tok2str(dccp_pkt_type_str, "", dccph_type), fixed_hdrlen - len); return; } ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type)); break; } case DCCP_PKT_DATAACK: { fixed_hdrlen += 8; if (len < fixed_hdrlen) { ND_PRINT("truncated-%s - %u bytes missing!", tok2str(dccp_pkt_type_str, "", dccph_type), fixed_hdrlen - len); return; } ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type)); break; } case DCCP_PKT_CLOSEREQ: fixed_hdrlen += 8; if (len < fixed_hdrlen) { ND_PRINT("truncated-%s - %u bytes missing!", tok2str(dccp_pkt_type_str, "", dccph_type), fixed_hdrlen - len); return; } ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type)); break; case DCCP_PKT_CLOSE: fixed_hdrlen += 8; if (len < fixed_hdrlen) { ND_PRINT("truncated-%s - %u bytes missing!", tok2str(dccp_pkt_type_str, "", dccph_type), fixed_hdrlen - len); return; } ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type)); break; case DCCP_PKT_RESET: { const struct dccp_hdr_reset *dhr = (const struct dccp_hdr_reset *)(bp + fixed_hdrlen); fixed_hdrlen += 12; if (len < fixed_hdrlen) { ND_PRINT("truncated-%s - %u bytes missing!", tok2str(dccp_pkt_type_str, "", dccph_type), fixed_hdrlen - len); return; } ND_TCHECK_SIZE(dhr); ND_PRINT("%s (code=%s) ", tok2str(dccp_pkt_type_str, "", dccph_type), dccp_reset_code(GET_U_1(dhr->dccph_reset_code))); break; } case DCCP_PKT_SYNC: fixed_hdrlen += 8; if (len < fixed_hdrlen) { ND_PRINT("truncated-%s - %u bytes missing!", tok2str(dccp_pkt_type_str, "", dccph_type), fixed_hdrlen - len); return; } ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type)); break; case DCCP_PKT_SYNCACK: fixed_hdrlen += 8; if (len < fixed_hdrlen) { ND_PRINT("truncated-%s - %u bytes missing!", tok2str(dccp_pkt_type_str, "", dccph_type), fixed_hdrlen - len); return; } ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "", dccph_type)); break; default: ND_PRINT("%s ", tok2str(dccp_pkt_type_str, "unknown-type-%u", dccph_type)); break; } if ((DCCPH_TYPE(dh) != DCCP_PKT_DATA) && (DCCPH_TYPE(dh) != DCCP_PKT_REQUEST)) dccp_print_ack_no(ndo, bp); if (ndo->ndo_vflag < 2) return; ND_PRINT("seq %" PRIu64, dccp_seqno(ndo, bp)); /* process options */ if (hlen > fixed_hdrlen){ u_int optlen; cp = bp + fixed_hdrlen; ND_PRINT(" <"); hlen -= fixed_hdrlen; while(1){ optlen = dccp_print_option(ndo, cp, hlen); if (!optlen) break; if (hlen <= optlen) break; hlen -= optlen; cp += optlen; ND_PRINT(", "); } ND_PRINT(">"); } return; trunc: nd_print_trunc(ndo); return; }
u_int nflog_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { const nflog_hdr_t *hdr = (const nflog_hdr_t *)p; uint16_t size; uint16_t h_size = sizeof(nflog_hdr_t); u_int caplen = h->caplen; u_int length = h->len; if (caplen < sizeof(nflog_hdr_t) || length < sizeof(nflog_hdr_t)) goto trunc; ND_TCHECK_SIZE(hdr); if (hdr->nflog_version != 0) { ND_PRINT("version %u (unknown)", hdr->nflog_version); return h_size; } if (ndo->ndo_eflag) nflog_hdr_print(ndo, hdr, length); p += sizeof(nflog_hdr_t); length -= sizeof(nflog_hdr_t); caplen -= sizeof(nflog_hdr_t); while (length > 0) { const nflog_tlv_t *tlv; /* We have some data. Do we have enough for the TLV header? */ if (caplen < sizeof(nflog_tlv_t) || length < sizeof(nflog_tlv_t)) goto trunc; /* No. */ tlv = (const nflog_tlv_t *) p; ND_TCHECK_SIZE(tlv); size = tlv->tlv_length; if (size % 4 != 0) size += 4 - size % 4; /* Is the TLV's length less than the minimum? */ if (size < sizeof(nflog_tlv_t)) goto trunc; /* Yes. Give up now. */ /* Do we have enough data for the full TLV? */ if (caplen < size || length < size) goto trunc; /* No. */ if (tlv->tlv_type == NFULA_PAYLOAD) { /* * This TLV's data is the packet payload. * Skip past the TLV header, and break out * of the loop so we print the packet data. */ p += sizeof(nflog_tlv_t); h_size += sizeof(nflog_tlv_t); length -= sizeof(nflog_tlv_t); caplen -= sizeof(nflog_tlv_t); break; } p += size; h_size += size; length -= size; caplen -= size; } switch (hdr->nflog_family) { case AF_INET: ip_print(ndo, p, length); break; #ifdef AF_INET6 case AF_INET6: ip6_print(ndo, p, length); break; #endif /* AF_INET6 */ default: if (!ndo->ndo_eflag) nflog_hdr_print(ndo, hdr, length + sizeof(nflog_hdr_t)); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); break; } return h_size; trunc: ND_PRINT("%s", tstr); return h_size; }
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("]"); }
static int ldp_pdu_print(netdissect_options *ndo, const u_char *pptr) { const struct ldp_common_header *ldp_com_header; const struct ldp_msg_header *ldp_msg_header; const u_char *tptr,*msg_tptr; u_short tlen; u_short pdu_len,msg_len,msg_type,msg_tlen; int hexdump,processed; ldp_com_header = (const struct ldp_common_header *)pptr; ND_TCHECK_SIZE(ldp_com_header); /* * Sanity checking of the header. */ if (EXTRACT_BE_U_2(ldp_com_header->version) != LDP_VERSION) { ND_PRINT("%sLDP version %u packet not supported", (ndo->ndo_vflag < 1) ? "" : "\n\t", EXTRACT_BE_U_2(ldp_com_header->version)); return 0; } pdu_len = EXTRACT_BE_U_2(ldp_com_header->pdu_length); if (pdu_len < sizeof(struct ldp_common_header)-4) { /* length too short */ ND_PRINT("%sLDP, pdu-length: %u (too short, < %u)", (ndo->ndo_vflag < 1) ? "" : "\n\t", pdu_len, (u_int)(sizeof(struct ldp_common_header)-4)); return 0; } /* print the LSR-ID, label-space & length */ ND_PRINT("%sLDP, Label-Space-ID: %s:%u, pdu-length: %u", (ndo->ndo_vflag < 1) ? "" : "\n\t", ipaddr_string(ndo, &ldp_com_header->lsr_id), EXTRACT_BE_U_2(ldp_com_header->label_space), pdu_len); /* bail out if non-verbose */ if (ndo->ndo_vflag < 1) return 0; /* ok they seem to want to know everything - lets fully decode it */ tptr = pptr + sizeof(struct ldp_common_header); tlen = pdu_len - (sizeof(struct ldp_common_header)-4); /* Type & Length fields not included */ while(tlen>0) { /* did we capture enough for fully decoding the msg header ? */ ND_TCHECK_LEN(tptr, sizeof(struct ldp_msg_header)); ldp_msg_header = (const struct ldp_msg_header *)tptr; msg_len=EXTRACT_BE_U_2(ldp_msg_header->length); msg_type=LDP_MASK_MSG_TYPE(EXTRACT_BE_U_2(ldp_msg_header->type)); if (msg_len < sizeof(struct ldp_msg_header)-4) { /* length too short */ /* FIXME vendor private / experimental check */ ND_PRINT("\n\t %s Message (0x%04x), length: %u (too short, < %u)", tok2str(ldp_msg_values, "Unknown", msg_type), msg_type, msg_len, (u_int)(sizeof(struct ldp_msg_header)-4)); return 0; } /* FIXME vendor private / experimental check */ ND_PRINT("\n\t %s Message (0x%04x), length: %u, Message ID: 0x%08x, Flags: [%s if unknown]", tok2str(ldp_msg_values, "Unknown", msg_type), msg_type, msg_len, EXTRACT_BE_U_4(ldp_msg_header->id), LDP_MASK_U_BIT(EXTRACT_BE_U_2(ldp_msg_header->type)) ? "continue processing" : "ignore"); msg_tptr=tptr+sizeof(struct ldp_msg_header); msg_tlen=msg_len-(sizeof(struct ldp_msg_header)-4); /* Type & Length fields not included */ /* did we capture enough for fully decoding the message ? */ ND_TCHECK_LEN(tptr, msg_len); hexdump=FALSE; switch(msg_type) { case LDP_MSG_NOTIF: case LDP_MSG_HELLO: case LDP_MSG_INIT: case LDP_MSG_KEEPALIVE: case LDP_MSG_ADDRESS: case LDP_MSG_LABEL_MAPPING: case LDP_MSG_ADDRESS_WITHDRAW: case LDP_MSG_LABEL_WITHDRAW: while(msg_tlen >= 4) { processed = ldp_tlv_print(ndo, msg_tptr, msg_tlen); if (processed == 0) break; msg_tlen-=processed; msg_tptr+=processed; } break; /* * FIXME those are the defined messages that lack a decoder * you are welcome to contribute code ;-) */ case LDP_MSG_LABEL_REQUEST: case LDP_MSG_LABEL_RELEASE: case LDP_MSG_LABEL_ABORT_REQUEST: default: if (ndo->ndo_vflag <= 1) print_unknown_data(ndo, msg_tptr, "\n\t ", msg_tlen); break; } /* do we want to see an additionally hexdump ? */ if (ndo->ndo_vflag > 1 || hexdump==TRUE) print_unknown_data(ndo, tptr+sizeof(struct ldp_msg_header), "\n\t ", msg_len); tptr += msg_len+4; tlen -= msg_len+4; } return pdu_len+4; trunc: ND_PRINT("\n\t\t packet exceeded snapshot"); return 0; }
void bfd_print(netdissect_options *ndo, const u_char *pptr, u_int len, u_int port) { ndo->ndo_protocol = "bfd"; if (port == BFD_CONTROL_PORT || port == BFD_MULTIHOP_PORT || port == BFD_LAG_PORT) { /* * Control packet. */ const struct bfd_header_t *bfd_header; uint8_t version_diag; uint8_t version = 0; uint8_t flags; bfd_header = (const struct bfd_header_t *)pptr; ND_TCHECK_SIZE(bfd_header); version_diag = GET_U_1(bfd_header->version_diag); version = BFD_EXTRACT_VERSION(version_diag); flags = GET_U_1(bfd_header->flags); switch (version) { /* BFDv0 */ case 0: if (ndo->ndo_vflag < 1) { ND_PRINT("BFDv0, Control, Flags: [%s], length: %u", bittok2str(bfd_v0_flag_values, "none", flags), len); return; } ND_PRINT("BFDv0, length: %u\n\tControl, Flags: [%s], Diagnostic: %s (0x%02x)", len, bittok2str(bfd_v0_flag_values, "none", flags), tok2str(bfd_diag_values,"unknown",BFD_EXTRACT_DIAG(version_diag)), BFD_EXTRACT_DIAG(version_diag)); ND_PRINT("\n\tDetection Timer Multiplier: %u (%u ms Detection time), BFD Length: %u", GET_U_1(bfd_header->detect_time_multiplier), GET_U_1(bfd_header->detect_time_multiplier) * GET_BE_U_4(bfd_header->desired_min_tx_interval)/1000, GET_U_1(bfd_header->length)); ND_PRINT("\n\tMy Discriminator: 0x%08x", GET_BE_U_4(bfd_header->my_discriminator)); ND_PRINT(", Your Discriminator: 0x%08x", GET_BE_U_4(bfd_header->your_discriminator)); ND_PRINT("\n\t Desired min Tx Interval: %4u ms", GET_BE_U_4(bfd_header->desired_min_tx_interval)/1000); ND_PRINT("\n\t Required min Rx Interval: %4u ms", GET_BE_U_4(bfd_header->required_min_rx_interval)/1000); ND_PRINT("\n\t Required min Echo Interval: %4u ms", GET_BE_U_4(bfd_header->required_min_echo_interval)/1000); if (flags & BFD_FLAG_AUTH) { if (auth_print(ndo, pptr)) goto trunc; } break; /* BFDv1 */ case 1: if (ndo->ndo_vflag < 1) { ND_PRINT("BFDv1, %s, State %s, Flags: [%s], length: %u", tok2str(bfd_port_values, "unknown (%u)", port), tok2str(bfd_v1_state_values, "unknown (%u)", (flags & 0xc0) >> 6), bittok2str(bfd_v1_flag_values, "none", flags & 0x3f), len); return; } ND_PRINT("BFDv1, length: %u\n\t%s, State %s, Flags: [%s], Diagnostic: %s (0x%02x)", len, tok2str(bfd_port_values, "unknown (%u)", port), tok2str(bfd_v1_state_values, "unknown (%u)", (flags & 0xc0) >> 6), bittok2str(bfd_v1_flag_values, "none", flags & 0x3f), tok2str(bfd_diag_values,"unknown",BFD_EXTRACT_DIAG(version_diag)), BFD_EXTRACT_DIAG(version_diag)); ND_PRINT("\n\tDetection Timer Multiplier: %u (%u ms Detection time), BFD Length: %u", GET_U_1(bfd_header->detect_time_multiplier), GET_U_1(bfd_header->detect_time_multiplier) * GET_BE_U_4(bfd_header->desired_min_tx_interval)/1000, GET_U_1(bfd_header->length)); ND_PRINT("\n\tMy Discriminator: 0x%08x", GET_BE_U_4(bfd_header->my_discriminator)); ND_PRINT(", Your Discriminator: 0x%08x", GET_BE_U_4(bfd_header->your_discriminator)); ND_PRINT("\n\t Desired min Tx Interval: %4u ms", GET_BE_U_4(bfd_header->desired_min_tx_interval)/1000); ND_PRINT("\n\t Required min Rx Interval: %4u ms", GET_BE_U_4(bfd_header->required_min_rx_interval)/1000); ND_PRINT("\n\t Required min Echo Interval: %4u ms", GET_BE_U_4(bfd_header->required_min_echo_interval)/1000); if (flags & BFD_FLAG_AUTH) { if (auth_print(ndo, pptr)) goto trunc; } break; default: ND_PRINT("BFDv%u, Control, length: %u", version, len); if (ndo->ndo_vflag >= 1) { if(!print_unknown_data(ndo, pptr,"\n\t",len)) return; } break; } } else if (port == BFD_ECHO_PORT) {
static int auth_print(netdissect_options *ndo, const u_char *pptr) { const struct bfd_auth_header_t *bfd_auth_header; uint8_t auth_type, auth_len; int i; pptr += sizeof (struct bfd_header_t); bfd_auth_header = (const struct bfd_auth_header_t *)pptr; ND_TCHECK_SIZE(bfd_auth_header); auth_type = GET_U_1(bfd_auth_header->auth_type); auth_len = GET_U_1(bfd_auth_header->auth_len); ND_PRINT("\n\tAuthentication: %s (%u), length: %u", tok2str(bfd_v1_authentication_values,"Unknown",auth_type), auth_type, auth_len); pptr += 2; ND_PRINT("\n\t Auth Key ID: %u", GET_U_1(pptr)); switch(auth_type) { case AUTH_PASSWORD: /* * Simple Password Authentication Section Format * * 0 1 2 3 * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Auth Type | Auth Len | Auth Key ID | Password... | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ... | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ if (auth_len < AUTH_PASSWORD_FIELD_MIN_LEN || auth_len > AUTH_PASSWORD_FIELD_MAX_LEN) { ND_PRINT("[invalid length %u]", auth_len); break; } pptr++; ND_PRINT(", Password: "******"[invalid length %u]", auth_len); break; } pptr += 2; ND_TCHECK_4(pptr); ND_PRINT(", Sequence Number: 0x%08x", GET_BE_U_4(pptr)); pptr += 4; ND_TCHECK_LEN(pptr, AUTH_MD5_HASH_LEN); ND_PRINT("\n\t Digest: "); for(i = 0; i < AUTH_MD5_HASH_LEN; i++) ND_PRINT("%02x", GET_U_1(pptr + i)); break; case AUTH_SHA1: case AUTH_MET_SHA1: /* * Keyed SHA1 and Meticulous Keyed SHA1 Authentication Section Format * * 0 1 2 3 * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Auth Type | Auth Len | Auth Key ID | Reserved | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Sequence Number | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Auth Key/Hash... | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | ... | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ if (auth_len != AUTH_SHA1_FIELD_LEN) { ND_PRINT("[invalid length %u]", auth_len); break; } pptr += 2; ND_TCHECK_4(pptr); ND_PRINT(", Sequence Number: 0x%08x", GET_BE_U_4(pptr)); pptr += 4; ND_TCHECK_LEN(pptr, AUTH_SHA1_HASH_LEN); ND_PRINT("\n\t Hash: "); for(i = 0; i < AUTH_SHA1_HASH_LEN; i++) ND_PRINT("%02x", GET_U_1(pptr + i)); break; } return 0; trunc: return 1; }
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 radius_attrs_print(netdissect_options *ndo, const u_char *attr, u_int length) { const struct radius_attr *rad_attr = (const struct radius_attr *)attr; const char *attr_string; uint8_t type, len; while (length > 0) { if (length < 2) goto trunc; ND_TCHECK_SIZE(rad_attr); type = EXTRACT_U_1(rad_attr->type); len = EXTRACT_U_1(rad_attr->len); if (type != 0 && type < TAM_SIZE(attr_type)) attr_string = attr_type[type].name; else attr_string = "Unknown"; if (len < 2) { ND_PRINT("\n\t %s Attribute (%u), length: %u (bogus, must be >= 2)", attr_string, type, len); return; } if (len > length) { ND_PRINT("\n\t %s Attribute (%u), length: %u (bogus, goes past end of packet)", attr_string, type, len); return; } ND_PRINT("\n\t %s Attribute (%u), length: %u, Value: ", attr_string, type, len); if (type < TAM_SIZE(attr_type)) { if (len > 2) { if ( attr_type[type].print_func ) (*attr_type[type].print_func)( ndo, ((const u_char *)(rad_attr+1)), len - 2, type); } } /* do we also want to see a hex dump ? */ if (ndo->ndo_vflag> 1) print_unknown_data(ndo, (const u_char *)rad_attr+2, "\n\t ", (len)-2); length-=(len); rad_attr = (const struct radius_attr *)( ((const char *)(rad_attr))+len); } return; trunc: nd_print_trunc(ndo); }
u_int pflog_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { u_int length = h->len; u_int hdrlen; u_int caplen = h->caplen; const struct pfloghdr *hdr; uint8_t af; ndo->ndo_protocol = "pflog_if"; /* check length */ if (caplen < sizeof(uint8_t)) { ND_PRINT("%s", tstr); return (caplen); } #define MIN_PFLOG_HDRLEN 45 hdr = (const struct pfloghdr *)p; if (hdr->length < MIN_PFLOG_HDRLEN) { ND_PRINT("[pflog: invalid header length!]"); return (hdr->length); /* XXX: not really */ } hdrlen = BPF_WORDALIGN(hdr->length); if (caplen < hdrlen) { ND_PRINT("%s", tstr); return (hdrlen); /* XXX: true? */ } /* print what we know */ ND_TCHECK_SIZE(hdr); if (ndo->ndo_eflag) pflog_print(ndo, hdr); /* skip to the real packet */ af = EXTRACT_U_1(&hdr->af); length -= hdrlen; caplen -= hdrlen; p += hdrlen; switch (af) { case AF_INET: #if OPENBSD_AF_INET != AF_INET case OPENBSD_AF_INET: /* XXX: read pcap files */ #endif ip_print(ndo, p, length); break; #if defined(AF_INET6) || defined(OPENBSD_AF_INET6) #ifdef AF_INET6 case AF_INET6: #endif /* AF_INET6 */ #if !defined(AF_INET6) || OPENBSD_AF_INET6 != AF_INET6 case OPENBSD_AF_INET6: /* XXX: read pcap files */ #endif /* !defined(AF_INET6) || OPENBSD_AF_INET6 != AF_INET6 */ ip6_print(ndo, p, length); break; #endif /* defined(AF_INET6) || defined(OPENBSD_AF_INET6) */ default: /* address family not handled, print raw packet */ if (!ndo->ndo_eflag) pflog_print(ndo, hdr); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } return (hdrlen); trunc: ND_PRINT("%s", tstr); return (hdrlen); }
static int ldp_tlv_print(netdissect_options *ndo, const u_char *tptr, u_short msg_tlen) { struct ldp_tlv_header { nd_uint16_t type; nd_uint16_t length; }; const struct ldp_tlv_header *ldp_tlv_header; u_short tlv_type,tlv_len,tlv_tlen,af,ft_flags; u_char fec_type; u_int ui,vc_info_len, vc_info_tlv_type, vc_info_tlv_len,idx; char buf[100]; int i; ldp_tlv_header = (const struct ldp_tlv_header *)tptr; ND_TCHECK_SIZE(ldp_tlv_header); tlv_len=EXTRACT_BE_U_2(ldp_tlv_header->length); if (tlv_len + 4 > msg_tlen) { ND_PRINT("\n\t\t TLV contents go past end of message"); return 0; } tlv_tlen=tlv_len; tlv_type=LDP_MASK_TLV_TYPE(EXTRACT_BE_U_2(ldp_tlv_header->type)); /* FIXME vendor private / experimental check */ ND_PRINT("\n\t %s TLV (0x%04x), length: %u, Flags: [%s and %s forward if unknown]", tok2str(ldp_tlv_values, "Unknown", tlv_type), tlv_type, tlv_len, LDP_MASK_U_BIT(EXTRACT_BE_U_2(ldp_tlv_header->type)) ? "continue processing" : "ignore", LDP_MASK_F_BIT(EXTRACT_BE_U_2(ldp_tlv_header->type)) ? "do" : "don't"); tptr+=sizeof(struct ldp_tlv_header); switch(tlv_type) { case LDP_TLV_COMMON_HELLO: TLV_TCHECK(4); ND_PRINT("\n\t Hold Time: %us, Flags: [%s Hello%s]", EXTRACT_BE_U_2(tptr), (EXTRACT_BE_U_2(tptr + 2)&0x8000) ? "Targeted" : "Link", (EXTRACT_BE_U_2(tptr + 2)&0x4000) ? ", Request for targeted Hellos" : ""); break; case LDP_TLV_IPV4_TRANSPORT_ADDR: TLV_TCHECK(4); ND_PRINT("\n\t IPv4 Transport Address: %s", ipaddr_string(ndo, tptr)); break; case LDP_TLV_IPV6_TRANSPORT_ADDR: TLV_TCHECK(16); ND_PRINT("\n\t IPv6 Transport Address: %s", ip6addr_string(ndo, tptr)); break; case LDP_TLV_CONFIG_SEQ_NUMBER: TLV_TCHECK(4); ND_PRINT("\n\t Sequence Number: %u", EXTRACT_BE_U_4(tptr)); break; case LDP_TLV_ADDRESS_LIST: TLV_TCHECK(LDP_TLV_ADDRESS_LIST_AFNUM_LEN); af = EXTRACT_BE_U_2(tptr); tptr+=LDP_TLV_ADDRESS_LIST_AFNUM_LEN; tlv_tlen -= LDP_TLV_ADDRESS_LIST_AFNUM_LEN; ND_PRINT("\n\t Address Family: %s, addresses", tok2str(af_values, "Unknown (%u)", af)); switch (af) { case AFNUM_INET: while(tlv_tlen >= sizeof(struct in_addr)) { ND_TCHECK_LEN(tptr, sizeof(struct in_addr)); ND_PRINT(" %s", ipaddr_string(ndo, tptr)); tlv_tlen-=sizeof(struct in_addr); tptr+=sizeof(struct in_addr); } break; case AFNUM_INET6: while(tlv_tlen >= sizeof(struct in6_addr)) { ND_TCHECK_LEN(tptr, sizeof(struct in6_addr)); ND_PRINT(" %s", ip6addr_string(ndo, tptr)); tlv_tlen-=sizeof(struct in6_addr); tptr+=sizeof(struct in6_addr); } break; default: /* unknown AF */ break; } break; case LDP_TLV_COMMON_SESSION: TLV_TCHECK(8); ND_PRINT("\n\t Version: %u, Keepalive: %us, Flags: [Downstream %s, Loop Detection %s]", EXTRACT_BE_U_2(tptr), EXTRACT_BE_U_2(tptr + 2), (EXTRACT_BE_U_2(tptr + 6)&0x8000) ? "On Demand" : "Unsolicited", (EXTRACT_BE_U_2(tptr + 6)&0x4000) ? "Enabled" : "Disabled" ); break; case LDP_TLV_FEC: TLV_TCHECK(1); fec_type = EXTRACT_U_1(tptr); ND_PRINT("\n\t %s FEC (0x%02x)", tok2str(ldp_fec_values, "Unknown", fec_type), fec_type); tptr+=1; tlv_tlen-=1; switch(fec_type) { case LDP_FEC_WILDCARD: break; case LDP_FEC_PREFIX: TLV_TCHECK(2); af = EXTRACT_BE_U_2(tptr); tptr+=LDP_TLV_ADDRESS_LIST_AFNUM_LEN; tlv_tlen-=LDP_TLV_ADDRESS_LIST_AFNUM_LEN; if (af == AFNUM_INET) { i=decode_prefix4(ndo, tptr, tlv_tlen, buf, sizeof(buf)); if (i == -2) goto trunc; if (i == -3) ND_PRINT(": IPv4 prefix (goes past end of TLV)"); else if (i == -1) ND_PRINT(": IPv4 prefix (invalid length)"); else ND_PRINT(": IPv4 prefix %s", buf); } else if (af == AFNUM_INET6) { i=decode_prefix6(ndo, tptr, tlv_tlen, buf, sizeof(buf)); if (i == -2) goto trunc; if (i == -3) ND_PRINT(": IPv4 prefix (goes past end of TLV)"); else if (i == -1) ND_PRINT(": IPv6 prefix (invalid length)"); else ND_PRINT(": IPv6 prefix %s", buf); } else ND_PRINT(": Address family %u prefix", af); break; case LDP_FEC_HOSTADDRESS: break; case LDP_FEC_MARTINI_VC: /* * We assume the type was supposed to be one of the MPLS * Pseudowire Types. */ TLV_TCHECK(7); vc_info_len = EXTRACT_U_1(tptr + 2); /* * According to RFC 4908, the VC info Length field can be zero, * in which case not only are there no interface parameters, * there's no VC ID. */ if (vc_info_len == 0) { ND_PRINT(": %s, %scontrol word, group-ID %u, VC-info-length: %u", tok2str(mpls_pw_types_values, "Unknown", EXTRACT_BE_U_2(tptr)&0x7fff), EXTRACT_BE_U_2(tptr)&0x8000 ? "" : "no ", EXTRACT_BE_U_4(tptr + 3), vc_info_len); break; } /* Make sure we have the VC ID as well */ TLV_TCHECK(11); ND_PRINT(": %s, %scontrol word, group-ID %u, VC-ID %u, VC-info-length: %u", tok2str(mpls_pw_types_values, "Unknown", EXTRACT_BE_U_2(tptr)&0x7fff), EXTRACT_BE_U_2(tptr)&0x8000 ? "" : "no ", EXTRACT_BE_U_4(tptr + 3), EXTRACT_BE_U_4(tptr + 7), vc_info_len); if (vc_info_len < 4) { /* minimum 4, for the VC ID */ ND_PRINT(" (invalid, < 4"); return(tlv_len+4); /* Type & Length fields not included */ } vc_info_len -= 4; /* subtract out the VC ID, giving the length of the interface parameters */ /* Skip past the fixed information and the VC ID */ tptr+=11; tlv_tlen-=11; TLV_TCHECK(vc_info_len); while (vc_info_len > 2) { vc_info_tlv_type = EXTRACT_U_1(tptr); vc_info_tlv_len = EXTRACT_U_1(tptr + 1); if (vc_info_tlv_len < 2) break; if (vc_info_len < vc_info_tlv_len) break; ND_PRINT("\n\t\tInterface Parameter: %s (0x%02x), len %u", tok2str(ldp_fec_martini_ifparm_values,"Unknown",vc_info_tlv_type), vc_info_tlv_type, vc_info_tlv_len); switch(vc_info_tlv_type) { case LDP_FEC_MARTINI_IFPARM_MTU: ND_PRINT(": %u", EXTRACT_BE_U_2(tptr + 2)); break; case LDP_FEC_MARTINI_IFPARM_DESC: ND_PRINT(": "); for (idx = 2; idx < vc_info_tlv_len; idx++) safeputchar(ndo, EXTRACT_U_1(tptr + idx)); break; case LDP_FEC_MARTINI_IFPARM_VCCV: ND_PRINT("\n\t\t Control Channels (0x%02x) = [%s]", EXTRACT_U_1((tptr + 2)), bittok2str(ldp_fec_martini_ifparm_vccv_cc_values, "none", EXTRACT_U_1((tptr + 2)))); ND_PRINT("\n\t\t CV Types (0x%02x) = [%s]", EXTRACT_U_1((tptr + 3)), bittok2str(ldp_fec_martini_ifparm_vccv_cv_values, "none", EXTRACT_U_1((tptr + 3)))); break; default: print_unknown_data(ndo, tptr+2, "\n\t\t ", vc_info_tlv_len-2); break; } vc_info_len -= vc_info_tlv_len; tptr += vc_info_tlv_len; } break; } break; case LDP_TLV_GENERIC_LABEL: TLV_TCHECK(4); ND_PRINT("\n\t Label: %u", EXTRACT_BE_U_4(tptr) & 0xfffff); break; case LDP_TLV_STATUS: TLV_TCHECK(8); ui = EXTRACT_BE_U_4(tptr); tptr+=4; ND_PRINT("\n\t Status: 0x%02x, Flags: [%s and %s forward]", ui&0x3fffffff, ui&0x80000000 ? "Fatal error" : "Advisory Notification", ui&0x40000000 ? "do" : "don't"); ui = EXTRACT_BE_U_4(tptr); tptr+=4; if (ui) ND_PRINT(", causing Message ID: 0x%08x", ui); break; case LDP_TLV_FT_SESSION: TLV_TCHECK(8); ft_flags = EXTRACT_BE_U_2(tptr); ND_PRINT("\n\t Flags: [%sReconnect, %sSave State, %sAll-Label Protection, %s Checkpoint, %sRe-Learn State]", ft_flags&0x8000 ? "" : "No ", ft_flags&0x8 ? "" : "Don't ", ft_flags&0x4 ? "" : "No ", ft_flags&0x2 ? "Sequence Numbered Label" : "All Labels", ft_flags&0x1 ? "" : "Don't "); tptr+=4; ui = EXTRACT_BE_U_4(tptr); if (ui) ND_PRINT(", Reconnect Timeout: %ums", ui); tptr+=4; ui = EXTRACT_BE_U_4(tptr); if (ui) ND_PRINT(", Recovery Time: %ums", ui); break; case LDP_TLV_MTU: TLV_TCHECK(2); ND_PRINT("\n\t MTU: %u", EXTRACT_BE_U_2(tptr)); break; /* * FIXME those are the defined TLVs that lack a decoder * you are welcome to contribute code ;-) */ case LDP_TLV_HOP_COUNT: case LDP_TLV_PATH_VECTOR: case LDP_TLV_ATM_LABEL: case LDP_TLV_FR_LABEL: case LDP_TLV_EXTD_STATUS: case LDP_TLV_RETURNED_PDU: case LDP_TLV_RETURNED_MSG: case LDP_TLV_ATM_SESSION_PARM: case LDP_TLV_FR_SESSION_PARM: case LDP_TLV_LABEL_REQUEST_MSG_ID: default: if (ndo->ndo_vflag <= 1) print_unknown_data(ndo, tptr, "\n\t ", tlv_tlen); break; } return(tlv_len+4); /* Type & Length fields not included */ trunc: ND_PRINT("\n\t\t packet exceeded snapshot"); return 0; badtlv: ND_PRINT("\n\t\t TLV contents go past end of TLV"); return(tlv_len+4); /* Type & Length fields not included */ }
void lmp_print(netdissect_options *ndo, const u_char *pptr, u_int len) { const struct lmp_common_header *lmp_com_header; const struct lmp_object_header *lmp_obj_header; const u_char *tptr,*obj_tptr; u_int version_res, tlen, lmp_obj_len, lmp_obj_ctype, obj_tlen; int hexdump; u_int offset; u_int link_type; union { /* int to float conversion buffer */ float f; uint32_t i; } bw; ndo->ndo_protocol = "lmp"; tptr=pptr; lmp_com_header = (const struct lmp_common_header *)pptr; ND_TCHECK_SIZE(lmp_com_header); version_res = EXTRACT_BE_U_2(lmp_com_header->version_res); /* * Sanity checking of the header. */ if (LMP_EXTRACT_VERSION(version_res) != LMP_VERSION) { ND_PRINT("LMP version %u packet not supported", LMP_EXTRACT_VERSION(version_res)); return; } /* in non-verbose mode just lets print the basic Message Type*/ if (ndo->ndo_vflag < 1) { ND_PRINT("LMPv%u %s Message, length: %u", LMP_EXTRACT_VERSION(version_res), tok2str(lmp_msg_type_values, "unknown (%u)",EXTRACT_U_1(lmp_com_header->msg_type)), len); return; } /* ok they seem to want to know everything - lets fully decode it */ tlen=EXTRACT_BE_U_2(lmp_com_header->length); ND_PRINT("\n\tLMPv%u, msg-type: %s, Flags: [%s], length: %u", LMP_EXTRACT_VERSION(version_res), tok2str(lmp_msg_type_values, "unknown, type: %u",EXTRACT_U_1(lmp_com_header->msg_type)), bittok2str(lmp_header_flag_values,"none",EXTRACT_U_1(lmp_com_header->flags)), tlen); if (tlen < sizeof(struct lmp_common_header)) { ND_PRINT(" (too short)"); return; } if (tlen > len) { ND_PRINT(" (too long)"); tlen = len; } tptr+=sizeof(struct lmp_common_header); tlen-=sizeof(struct lmp_common_header); while(tlen>0) { /* did we capture enough for fully decoding the object header ? */ ND_TCHECK_LEN(tptr, sizeof(struct lmp_object_header)); lmp_obj_header = (const struct lmp_object_header *)tptr; lmp_obj_len=EXTRACT_BE_U_2(lmp_obj_header->length); lmp_obj_ctype=EXTRACT_U_1(lmp_obj_header->ctype)&0x7f; ND_PRINT("\n\t %s Object (%u), Class-Type: %s (%u) Flags: [%snegotiable], length: %u", tok2str(lmp_obj_values, "Unknown", EXTRACT_U_1(lmp_obj_header->class_num)), EXTRACT_U_1(lmp_obj_header->class_num), tok2str(lmp_ctype_values, "Unknown", (EXTRACT_U_1(lmp_obj_header->class_num)<<8)+lmp_obj_ctype), lmp_obj_ctype, EXTRACT_U_1(lmp_obj_header->ctype)&0x80 ? "" : "non-", lmp_obj_len); if (lmp_obj_len < 4) { ND_PRINT(" (too short)"); return; } if ((lmp_obj_len % 4) != 0) { ND_PRINT(" (not a multiple of 4)"); return; } obj_tptr=tptr+sizeof(struct lmp_object_header); obj_tlen=lmp_obj_len-sizeof(struct lmp_object_header); /* did we capture enough for fully decoding the object ? */ ND_TCHECK_LEN(tptr, lmp_obj_len); hexdump=FALSE; switch(EXTRACT_U_1(lmp_obj_header->class_num)) { case LMP_OBJ_CC_ID: switch(lmp_obj_ctype) { case LMP_CTYPE_LOC: case LMP_CTYPE_RMT: if (obj_tlen != 4) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Control Channel ID: %u (0x%08x)", EXTRACT_BE_U_4(obj_tptr), EXTRACT_BE_U_4(obj_tptr)); break; default: hexdump=TRUE; } break; case LMP_OBJ_LINK_ID: case LMP_OBJ_INTERFACE_ID: switch(lmp_obj_ctype) { case LMP_CTYPE_IPV4_LOC: case LMP_CTYPE_IPV4_RMT: if (obj_tlen != 4) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t IPv4 Link ID: %s (0x%08x)", ipaddr_string(ndo, obj_tptr), EXTRACT_BE_U_4(obj_tptr)); break; case LMP_CTYPE_IPV6_LOC: case LMP_CTYPE_IPV6_RMT: if (obj_tlen != 16) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t IPv6 Link ID: %s (0x%08x)", ip6addr_string(ndo, obj_tptr), EXTRACT_BE_U_4(obj_tptr)); break; case LMP_CTYPE_UNMD_LOC: case LMP_CTYPE_UNMD_RMT: if (obj_tlen != 4) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Link ID: %u (0x%08x)", EXTRACT_BE_U_4(obj_tptr), EXTRACT_BE_U_4(obj_tptr)); break; default: hexdump=TRUE; } break; case LMP_OBJ_MESSAGE_ID: switch(lmp_obj_ctype) { case LMP_CTYPE_1: if (obj_tlen != 4) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Message ID: %u (0x%08x)", EXTRACT_BE_U_4(obj_tptr), EXTRACT_BE_U_4(obj_tptr)); break; case LMP_CTYPE_2: if (obj_tlen != 4) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Message ID Ack: %u (0x%08x)", EXTRACT_BE_U_4(obj_tptr), EXTRACT_BE_U_4(obj_tptr)); break; default: hexdump=TRUE; } break; case LMP_OBJ_NODE_ID: switch(lmp_obj_ctype) { case LMP_CTYPE_LOC: case LMP_CTYPE_RMT: if (obj_tlen != 4) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Node ID: %s (0x%08x)", ipaddr_string(ndo, obj_tptr), EXTRACT_BE_U_4(obj_tptr)); break; default: hexdump=TRUE; } break; case LMP_OBJ_CONFIG: switch(lmp_obj_ctype) { case LMP_CTYPE_HELLO_CONFIG: if (obj_tlen != 4) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Hello Interval: %u\n\t Hello Dead Interval: %u", EXTRACT_BE_U_2(obj_tptr), EXTRACT_BE_U_2(obj_tptr + 2)); break; default: hexdump=TRUE; } break; case LMP_OBJ_HELLO: switch(lmp_obj_ctype) { case LMP_CTYPE_HELLO: if (obj_tlen != 8) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Tx Seq: %u, Rx Seq: %u", EXTRACT_BE_U_4(obj_tptr), EXTRACT_BE_U_4(obj_tptr + 4)); break; default: hexdump=TRUE; } break; case LMP_OBJ_TE_LINK: switch(lmp_obj_ctype) { case LMP_CTYPE_IPV4: if (obj_tlen != 12) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Flags: [%s]", bittok2str(lmp_obj_te_link_flag_values, "none", EXTRACT_U_1(obj_tptr))); ND_PRINT("\n\t Local Link-ID: %s (0x%08x)" "\n\t Remote Link-ID: %s (0x%08x)", ipaddr_string(ndo, obj_tptr+4), EXTRACT_BE_U_4(obj_tptr + 4), ipaddr_string(ndo, obj_tptr+8), EXTRACT_BE_U_4(obj_tptr + 8)); break; case LMP_CTYPE_IPV6: if (obj_tlen != 36) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Flags: [%s]", bittok2str(lmp_obj_te_link_flag_values, "none", EXTRACT_U_1(obj_tptr))); ND_PRINT("\n\t Local Link-ID: %s (0x%08x)" "\n\t Remote Link-ID: %s (0x%08x)", ip6addr_string(ndo, obj_tptr+4), EXTRACT_BE_U_4(obj_tptr + 4), ip6addr_string(ndo, obj_tptr+20), EXTRACT_BE_U_4(obj_tptr + 20)); break; case LMP_CTYPE_UNMD: if (obj_tlen != 12) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Flags: [%s]", bittok2str(lmp_obj_te_link_flag_values, "none", EXTRACT_U_1(obj_tptr))); ND_PRINT("\n\t Local Link-ID: %u (0x%08x)" "\n\t Remote Link-ID: %u (0x%08x)", EXTRACT_BE_U_4(obj_tptr + 4), EXTRACT_BE_U_4(obj_tptr + 4), EXTRACT_BE_U_4(obj_tptr + 8), EXTRACT_BE_U_4(obj_tptr + 8)); break; default: hexdump=TRUE; } break; case LMP_OBJ_DATA_LINK: switch(lmp_obj_ctype) { case LMP_CTYPE_IPV4: if (obj_tlen < 12) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Flags: [%s]", bittok2str(lmp_obj_data_link_flag_values, "none", EXTRACT_U_1(obj_tptr))); ND_PRINT("\n\t Local Interface ID: %s (0x%08x)" "\n\t Remote Interface ID: %s (0x%08x)", ipaddr_string(ndo, obj_tptr+4), EXTRACT_BE_U_4(obj_tptr + 4), ipaddr_string(ndo, obj_tptr+8), EXTRACT_BE_U_4(obj_tptr + 8)); if (lmp_print_data_link_subobjs(ndo, obj_tptr, obj_tlen - 12, 12)) hexdump=TRUE; break; case LMP_CTYPE_IPV6: if (obj_tlen < 36) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Flags: [%s]", bittok2str(lmp_obj_data_link_flag_values, "none", EXTRACT_U_1(obj_tptr))); ND_PRINT("\n\t Local Interface ID: %s (0x%08x)" "\n\t Remote Interface ID: %s (0x%08x)", ip6addr_string(ndo, obj_tptr+4), EXTRACT_BE_U_4(obj_tptr + 4), ip6addr_string(ndo, obj_tptr+20), EXTRACT_BE_U_4(obj_tptr + 20)); if (lmp_print_data_link_subobjs(ndo, obj_tptr, obj_tlen - 36, 36)) hexdump=TRUE; break; case LMP_CTYPE_UNMD: if (obj_tlen < 12) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Flags: [%s]", bittok2str(lmp_obj_data_link_flag_values, "none", EXTRACT_U_1(obj_tptr))); ND_PRINT("\n\t Local Interface ID: %u (0x%08x)" "\n\t Remote Interface ID: %u (0x%08x)", EXTRACT_BE_U_4(obj_tptr + 4), EXTRACT_BE_U_4(obj_tptr + 4), EXTRACT_BE_U_4(obj_tptr + 8), EXTRACT_BE_U_4(obj_tptr + 8)); if (lmp_print_data_link_subobjs(ndo, obj_tptr, obj_tlen - 12, 12)) hexdump=TRUE; break; default: hexdump=TRUE; } break; case LMP_OBJ_VERIFY_BEGIN: switch(lmp_obj_ctype) { case LMP_CTYPE_1: if (obj_tlen != 20) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Flags: %s", bittok2str(lmp_obj_begin_verify_flag_values, "none", EXTRACT_BE_U_2(obj_tptr))); ND_PRINT("\n\t Verify Interval: %u", EXTRACT_BE_U_2(obj_tptr + 2)); ND_PRINT("\n\t Data links: %u", EXTRACT_BE_U_4(obj_tptr + 4)); ND_PRINT("\n\t Encoding type: %s", tok2str(gmpls_encoding_values, "Unknown", EXTRACT_U_1((obj_tptr + 8)))); ND_PRINT("\n\t Verify Transport Mechanism: %u (0x%x)%s", EXTRACT_BE_U_2(obj_tptr + 10), EXTRACT_BE_U_2(obj_tptr + 10), EXTRACT_BE_U_2(obj_tptr + 10)&8000 ? " (Payload test messages capable)" : ""); bw.i = EXTRACT_BE_U_4(obj_tptr + 12); ND_PRINT("\n\t Transmission Rate: %.3f Mbps",bw.f*8/1000000); ND_PRINT("\n\t Wavelength: %u", EXTRACT_BE_U_4(obj_tptr + 16)); break; default: hexdump=TRUE; } break; case LMP_OBJ_VERIFY_BEGIN_ACK: switch(lmp_obj_ctype) { case LMP_CTYPE_1: if (obj_tlen != 4) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Verify Dead Interval: %u" "\n\t Verify Transport Response: %u", EXTRACT_BE_U_2(obj_tptr), EXTRACT_BE_U_2(obj_tptr + 2)); break; default: hexdump=TRUE; } break; case LMP_OBJ_VERIFY_ID: switch(lmp_obj_ctype) { case LMP_CTYPE_1: if (obj_tlen != 4) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Verify ID: %u", EXTRACT_BE_U_4(obj_tptr)); break; default: hexdump=TRUE; } break; case LMP_OBJ_CHANNEL_STATUS: switch(lmp_obj_ctype) { case LMP_CTYPE_IPV4: offset = 0; /* Decode pairs: <Interface_ID (4 bytes), Channel_status (4 bytes)> */ while (offset+8 <= obj_tlen) { ND_PRINT("\n\t Interface ID: %s (0x%08x)", ipaddr_string(ndo, obj_tptr+offset), EXTRACT_BE_U_4(obj_tptr + offset)); ND_PRINT("\n\t\t Active: %s (%u)", (EXTRACT_BE_U_4(obj_tptr + offset + 4)>>31) ? "Allocated" : "Non-allocated", (EXTRACT_BE_U_4(obj_tptr + offset + 4)>>31)); ND_PRINT("\n\t\t Direction: %s (%u)", (EXTRACT_BE_U_4(obj_tptr + offset + 4)>>30)&0x1 ? "Transmit" : "Receive", (EXTRACT_BE_U_4(obj_tptr + offset + 4)>>30)&0x1); ND_PRINT("\n\t\t Channel Status: %s (%u)", tok2str(lmp_obj_channel_status_values, "Unknown", EXTRACT_BE_U_4(obj_tptr + offset + 4)&0x3FFFFFF), EXTRACT_BE_U_4(obj_tptr + offset + 4)&0x3FFFFFF); offset+=8; } break; case LMP_CTYPE_IPV6: offset = 0; /* Decode pairs: <Interface_ID (16 bytes), Channel_status (4 bytes)> */ while (offset+20 <= obj_tlen) { ND_PRINT("\n\t Interface ID: %s (0x%08x)", ip6addr_string(ndo, obj_tptr+offset), EXTRACT_BE_U_4(obj_tptr + offset)); ND_PRINT("\n\t\t Active: %s (%u)", (EXTRACT_BE_U_4(obj_tptr + offset + 16)>>31) ? "Allocated" : "Non-allocated", (EXTRACT_BE_U_4(obj_tptr + offset + 16)>>31)); ND_PRINT("\n\t\t Direction: %s (%u)", (EXTRACT_BE_U_4(obj_tptr + offset + 16)>>30)&0x1 ? "Transmit" : "Receive", (EXTRACT_BE_U_4(obj_tptr + offset + 16)>>30)&0x1); ND_PRINT("\n\t\t Channel Status: %s (%u)", tok2str(lmp_obj_channel_status_values, "Unknown", EXTRACT_BE_U_4(obj_tptr + offset + 16)&0x3FFFFFF), EXTRACT_BE_U_4(obj_tptr + offset + 16)&0x3FFFFFF); offset+=20; } break; case LMP_CTYPE_UNMD: offset = 0; /* Decode pairs: <Interface_ID (4 bytes), Channel_status (4 bytes)> */ while (offset+8 <= obj_tlen) { ND_PRINT("\n\t Interface ID: %u (0x%08x)", EXTRACT_BE_U_4(obj_tptr + offset), EXTRACT_BE_U_4(obj_tptr + offset)); ND_PRINT("\n\t\t Active: %s (%u)", (EXTRACT_BE_U_4(obj_tptr + offset + 4)>>31) ? "Allocated" : "Non-allocated", (EXTRACT_BE_U_4(obj_tptr + offset + 4)>>31)); ND_PRINT("\n\t\t Direction: %s (%u)", (EXTRACT_BE_U_4(obj_tptr + offset + 4)>>30)&0x1 ? "Transmit" : "Receive", (EXTRACT_BE_U_4(obj_tptr + offset + 4)>>30)&0x1); ND_PRINT("\n\t\t Channel Status: %s (%u)", tok2str(lmp_obj_channel_status_values, "Unknown", EXTRACT_BE_U_4(obj_tptr + offset + 4)&0x3FFFFFF), EXTRACT_BE_U_4(obj_tptr + offset + 4)&0x3FFFFFF); offset+=8; } break; default: hexdump=TRUE; } break; case LMP_OBJ_CHANNEL_STATUS_REQ: switch(lmp_obj_ctype) { case LMP_CTYPE_IPV4: offset = 0; while (offset+4 <= obj_tlen) { ND_PRINT("\n\t Interface ID: %s (0x%08x)", ipaddr_string(ndo, obj_tptr+offset), EXTRACT_BE_U_4(obj_tptr + offset)); offset+=4; } break; case LMP_CTYPE_IPV6: offset = 0; while (offset+16 <= obj_tlen) { ND_PRINT("\n\t Interface ID: %s (0x%08x)", ip6addr_string(ndo, obj_tptr+offset), EXTRACT_BE_U_4(obj_tptr + offset)); offset+=16; } break; case LMP_CTYPE_UNMD: offset = 0; while (offset+4 <= obj_tlen) { ND_PRINT("\n\t Interface ID: %u (0x%08x)", EXTRACT_BE_U_4(obj_tptr + offset), EXTRACT_BE_U_4(obj_tptr + offset)); offset+=4; } break; default: hexdump=TRUE; } break; case LMP_OBJ_ERROR_CODE: switch(lmp_obj_ctype) { case LMP_CTYPE_BEGIN_VERIFY_ERROR: if (obj_tlen != 4) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Error Code: %s", bittok2str(lmp_obj_begin_verify_error_values, "none", EXTRACT_BE_U_4(obj_tptr))); break; case LMP_CTYPE_LINK_SUMMARY_ERROR: if (obj_tlen != 4) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Error Code: %s", bittok2str(lmp_obj_link_summary_error_values, "none", EXTRACT_BE_U_4(obj_tptr))); break; default: hexdump=TRUE; } break; case LMP_OBJ_SERVICE_CONFIG: switch (lmp_obj_ctype) { case LMP_CTYPE_SERVICE_CONFIG_SP: if (obj_tlen != 4) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Flags: %s", bittok2str(lmp_obj_service_config_sp_flag_values, "none", EXTRACT_U_1(obj_tptr))); ND_PRINT("\n\t UNI Version: %u", EXTRACT_U_1(obj_tptr + 1)); break; case LMP_CTYPE_SERVICE_CONFIG_CPSA: if (obj_tlen != 16) { ND_PRINT(" (not correct for object)"); break; } link_type = EXTRACT_U_1(obj_tptr); ND_PRINT("\n\t Link Type: %s (%u)", tok2str(lmp_sd_service_config_cpsa_link_type_values, "Unknown", link_type), link_type); switch (link_type) { case LMP_SD_SERVICE_CONFIG_CPSA_LINK_TYPE_SDH: ND_PRINT("\n\t Signal Type: %s (%u)", tok2str(lmp_sd_service_config_cpsa_signal_type_sdh_values, "Unknown", EXTRACT_U_1(obj_tptr + 1)), EXTRACT_U_1(obj_tptr + 1)); break; case LMP_SD_SERVICE_CONFIG_CPSA_LINK_TYPE_SONET: ND_PRINT("\n\t Signal Type: %s (%u)", tok2str(lmp_sd_service_config_cpsa_signal_type_sonet_values, "Unknown", EXTRACT_U_1(obj_tptr + 1)), EXTRACT_U_1(obj_tptr + 1)); break; } ND_PRINT("\n\t Transparency: %s", bittok2str(lmp_obj_service_config_cpsa_tp_flag_values, "none", EXTRACT_U_1(obj_tptr + 2))); ND_PRINT("\n\t Contiguous Concatenation Types: %s", bittok2str(lmp_obj_service_config_cpsa_cct_flag_values, "none", EXTRACT_U_1(obj_tptr + 3))); ND_PRINT("\n\t Minimum NCC: %u", EXTRACT_BE_U_2(obj_tptr + 4)); ND_PRINT("\n\t Maximum NCC: %u", EXTRACT_BE_U_2(obj_tptr + 6)); ND_PRINT("\n\t Minimum NVC:%u", EXTRACT_BE_U_2(obj_tptr + 8)); ND_PRINT("\n\t Maximum NVC:%u", EXTRACT_BE_U_2(obj_tptr + 10)); ND_PRINT("\n\t Local Interface ID: %s (0x%08x)", ipaddr_string(ndo, obj_tptr+12), EXTRACT_BE_U_4(obj_tptr + 12)); break; case LMP_CTYPE_SERVICE_CONFIG_TRANSPARENCY_TCM: if (obj_tlen != 8) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Transparency Flags: %s", bittok2str( lmp_obj_service_config_nsa_transparency_flag_values, "none", EXTRACT_BE_U_4(obj_tptr))); ND_PRINT("\n\t TCM Monitoring Flags: %s", bittok2str( lmp_obj_service_config_nsa_tcm_flag_values, "none", EXTRACT_U_1(obj_tptr + 7))); break; case LMP_CTYPE_SERVICE_CONFIG_NETWORK_DIVERSITY: if (obj_tlen != 4) { ND_PRINT(" (not correct for object)"); break; } ND_PRINT("\n\t Diversity: Flags: %s", bittok2str( lmp_obj_service_config_nsa_network_diversity_flag_values, "none", EXTRACT_U_1(obj_tptr + 3))); break; default: hexdump = TRUE; } break; default: if (ndo->ndo_vflag <= 1) print_unknown_data(ndo,obj_tptr,"\n\t ",obj_tlen); break; } /* do we want to see an additionally hexdump ? */ if (ndo->ndo_vflag > 1 || hexdump==TRUE) print_unknown_data(ndo,tptr+sizeof(struct lmp_object_header),"\n\t ", lmp_obj_len-sizeof(struct lmp_object_header)); tptr+=lmp_obj_len; tlen-=lmp_obj_len; } 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; } }
void sctp_print(netdissect_options *ndo, const u_char *bp, /* beginning of sctp packet */ const u_char *bp2, /* beginning of enclosing */ u_int sctpPacketLength) /* ip packet */ { u_int sctpPacketLengthRemaining; const struct sctpHeader *sctpPktHdr; const struct ip *ip; const struct ip6_hdr *ip6; uint8_t chunkID; u_short sourcePort, destPort; u_int chunkCount; const struct sctpChunkDesc *chunkDescPtr; const char *sep; int isforces = 0; ndo->ndo_protocol = "sctp"; if (sctpPacketLength < sizeof(struct sctpHeader)) { ND_PRINT("truncated-sctp - %ld bytes missing!", (long)(sizeof(struct sctpHeader) - sctpPacketLength)); return; } sctpPktHdr = (const struct sctpHeader*) bp; ND_TCHECK_SIZE(sctpPktHdr); sctpPacketLengthRemaining = sctpPacketLength; sourcePort = EXTRACT_BE_U_2(sctpPktHdr->source); destPort = EXTRACT_BE_U_2(sctpPktHdr->destination); ip = (const struct ip *)bp2; if (IP_V(ip) == 6) ip6 = (const struct ip6_hdr *)bp2; else ip6 = NULL; if (ip6) { ND_PRINT("%s.%u > %s.%u: sctp", ip6addr_string(ndo, ip6->ip6_src), sourcePort, ip6addr_string(ndo, ip6->ip6_dst), destPort); } else { ND_PRINT("%s.%u > %s.%u: sctp", ipaddr_string(ndo, ip->ip_src), sourcePort, ipaddr_string(ndo, ip->ip_dst), destPort); } if (isForCES_port(sourcePort)) { ND_PRINT("[%s]", tok2str(ForCES_channels, NULL, sourcePort)); isforces = 1; } if (isForCES_port(destPort)) { ND_PRINT("[%s]", tok2str(ForCES_channels, NULL, destPort)); isforces = 1; } bp += sizeof(struct sctpHeader); sctpPacketLengthRemaining -= sizeof(struct sctpHeader); if (ndo->ndo_vflag >= 2) sep = "\n\t"; else sep = " ("; /* cycle through all chunks, printing information on each one */ for (chunkCount = 0, chunkDescPtr = (const struct sctpChunkDesc *)bp; sctpPacketLengthRemaining != 0; chunkCount++) { uint16_t chunkLength, chunkLengthRemaining; uint16_t align; chunkDescPtr = (const struct sctpChunkDesc *)bp; if (sctpPacketLengthRemaining < sizeof(*chunkDescPtr)) { ND_PRINT("%s%u) [chunk descriptor cut off at end of packet]", sep, chunkCount+1); break; } ND_TCHECK_SIZE(chunkDescPtr); chunkLength = EXTRACT_BE_U_2(chunkDescPtr->chunkLength); if (chunkLength < sizeof(*chunkDescPtr)) { ND_PRINT("%s%u) [Bad chunk length %u, < size of chunk descriptor]", sep, chunkCount+1, chunkLength); break; } chunkLengthRemaining = chunkLength; align = chunkLength % 4; if (align != 0) align = 4 - align; if (sctpPacketLengthRemaining < align) { ND_PRINT("%s%u) [Bad chunk length %u, > remaining data in packet]", sep, chunkCount+1, chunkLength); break; } ND_TCHECK_LEN(bp, chunkLength); bp += sizeof(*chunkDescPtr); sctpPacketLengthRemaining -= sizeof(*chunkDescPtr); chunkLengthRemaining -= sizeof(*chunkDescPtr); ND_PRINT("%s%u) ", sep, chunkCount+1); chunkID = EXTRACT_U_1(chunkDescPtr->chunkID); ND_PRINT("[%s] ", tok2str(sctp_chunkid_str, "Unknown chunk type: 0x%x", chunkID)); switch (chunkID) { case SCTP_DATA : { const struct sctpDataPart *dataHdrPtr; uint8_t chunkFlg; uint32_t ppid; u_int payload_size; chunkFlg = EXTRACT_U_1(chunkDescPtr->chunkFlg); if ((chunkFlg & SCTP_DATA_UNORDERED) == SCTP_DATA_UNORDERED) ND_PRINT("(U)"); if ((chunkFlg & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG) ND_PRINT("(B)"); if ((chunkFlg & SCTP_DATA_LAST_FRAG) == SCTP_DATA_LAST_FRAG) ND_PRINT("(E)"); if( ((chunkFlg & SCTP_DATA_UNORDERED) == SCTP_DATA_UNORDERED) || ((chunkFlg & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG) || ((chunkFlg & SCTP_DATA_LAST_FRAG) == SCTP_DATA_LAST_FRAG) ) ND_PRINT(" "); if (chunkLengthRemaining < sizeof(*dataHdrPtr)) { ND_PRINT("bogus chunk length %u]", chunkLength); return; } dataHdrPtr=(const struct sctpDataPart*)bp; ppid = EXTRACT_BE_U_4(dataHdrPtr->payloadtype); ND_PRINT("[TSN: %u] ", EXTRACT_BE_U_4(dataHdrPtr->TSN)); ND_PRINT("[SID: %u] ", EXTRACT_BE_U_2(dataHdrPtr->streamId)); ND_PRINT("[SSEQ %u] ", EXTRACT_BE_U_2(dataHdrPtr->sequence)); ND_PRINT("[PPID %s] ", tok2str(PayloadProto_idents, "0x%x", ppid)); if (!isforces) { isforces = (ppid == SCTP_PPID_FORCES_HP) || (ppid == SCTP_PPID_FORCES_MP) || (ppid == SCTP_PPID_FORCES_LP); } bp += sizeof(*dataHdrPtr); sctpPacketLengthRemaining -= sizeof(*dataHdrPtr); chunkLengthRemaining -= sizeof(*dataHdrPtr); payload_size = chunkLengthRemaining; if (payload_size == 0) { ND_PRINT("bogus chunk length %u]", chunkLength); return; } if (isforces) { forces_print(ndo, bp, payload_size); } else if (ndo->ndo_vflag >= 2) { /* if verbose output is specified */ /* at the command line */ switch (ppid) { case SCTP_PPID_M3UA : m3ua_print(ndo, bp, payload_size); break; default: ND_PRINT("[Payload"); if (!ndo->ndo_suppress_default_print) { ND_PRINT(":"); ND_DEFAULTPRINT(bp, payload_size); } ND_PRINT("]"); break; } } bp += payload_size; sctpPacketLengthRemaining -= payload_size; chunkLengthRemaining -= payload_size; break; } case SCTP_INITIATION : { const struct sctpInitiation *init; if (chunkLengthRemaining < sizeof(*init)) { ND_PRINT("bogus chunk length %u]", chunkLength); return; } init=(const struct sctpInitiation*)bp; ND_PRINT("[init tag: %u] ", EXTRACT_BE_U_4(init->initTag)); ND_PRINT("[rwnd: %u] ", EXTRACT_BE_U_4(init->rcvWindowCredit)); ND_PRINT("[OS: %u] ", EXTRACT_BE_U_2(init->NumPreopenStreams)); ND_PRINT("[MIS: %u] ", EXTRACT_BE_U_2(init->MaxInboundStreams)); ND_PRINT("[init TSN: %u] ", EXTRACT_BE_U_4(init->initialTSN)); bp += sizeof(*init); sctpPacketLengthRemaining -= sizeof(*init); chunkLengthRemaining -= sizeof(*init); #if 0 /* ALC you can add code for optional params here */ if( chunkLengthRemaining != 0 ) ND_PRINT(" @@@@@ UNFINISHED @@@@@@%s\n", "Optional params present, but not printed."); #endif bp += chunkLengthRemaining; sctpPacketLengthRemaining -= chunkLengthRemaining; chunkLengthRemaining = 0; break; } case SCTP_INITIATION_ACK : { const struct sctpInitiation *init; if (chunkLengthRemaining < sizeof(*init)) { ND_PRINT("bogus chunk length %u]", chunkLength); return; } init=(const struct sctpInitiation*)bp; ND_PRINT("[init tag: %u] ", EXTRACT_BE_U_4(init->initTag)); ND_PRINT("[rwnd: %u] ", EXTRACT_BE_U_4(init->rcvWindowCredit)); ND_PRINT("[OS: %u] ", EXTRACT_BE_U_2(init->NumPreopenStreams)); ND_PRINT("[MIS: %u] ", EXTRACT_BE_U_2(init->MaxInboundStreams)); ND_PRINT("[init TSN: %u] ", EXTRACT_BE_U_4(init->initialTSN)); bp += sizeof(*init); sctpPacketLengthRemaining -= sizeof(*init); chunkLengthRemaining -= sizeof(*init); #if 0 /* ALC you can add code for optional params here */ if( chunkLengthRemaining != 0 ) ND_PRINT(" @@@@@ UNFINISHED @@@@@@%s\n", "Optional params present, but not printed."); #endif bp += chunkLengthRemaining; sctpPacketLengthRemaining -= chunkLengthRemaining; chunkLengthRemaining = 0; break; } case SCTP_SELECTIVE_ACK: { const struct sctpSelectiveAck *sack; const struct sctpSelectiveFrag *frag; u_int fragNo, tsnNo; const u_char *dupTSN; if (chunkLengthRemaining < sizeof(*sack)) { ND_PRINT("bogus chunk length %u]", chunkLength); return; } sack=(const struct sctpSelectiveAck*)bp; ND_PRINT("[cum ack %u] ", EXTRACT_BE_U_4(sack->highestConseqTSN)); ND_PRINT("[a_rwnd %u] ", EXTRACT_BE_U_4(sack->updatedRwnd)); ND_PRINT("[#gap acks %u] ", EXTRACT_BE_U_2(sack->numberOfdesc)); ND_PRINT("[#dup tsns %u] ", EXTRACT_BE_U_2(sack->numDupTsns)); bp += sizeof(*sack); sctpPacketLengthRemaining -= sizeof(*sack); chunkLengthRemaining -= sizeof(*sack); /* print gaps */ for (fragNo=0; chunkLengthRemaining != 0 && fragNo < EXTRACT_BE_U_2(sack->numberOfdesc); bp += sizeof(*frag), sctpPacketLengthRemaining -= sizeof(*frag), chunkLengthRemaining -= sizeof(*frag), fragNo++) { if (chunkLengthRemaining < sizeof(*frag)) { ND_PRINT("bogus chunk length %u]", chunkLength); return; } frag = (const struct sctpSelectiveFrag *)bp; ND_PRINT("\n\t\t[gap ack block #%u: start = %u, end = %u] ", fragNo+1, EXTRACT_BE_U_4(sack->highestConseqTSN) + EXTRACT_BE_U_2(frag->fragmentStart), EXTRACT_BE_U_4(sack->highestConseqTSN) + EXTRACT_BE_U_2(frag->fragmentEnd)); } /* print duplicate TSNs */ for (tsnNo=0; chunkLengthRemaining != 0 && tsnNo<EXTRACT_BE_U_2(sack->numDupTsns); bp += 4, sctpPacketLengthRemaining -= 4, chunkLengthRemaining -= 4, tsnNo++) { if (chunkLengthRemaining < 4) { ND_PRINT("bogus chunk length %u]", chunkLength); return; } dupTSN = (const u_char *)bp; ND_PRINT("\n\t\t[dup TSN #%u: %u] ", tsnNo+1, EXTRACT_BE_U_4(dupTSN)); } break; } default : { bp += chunkLengthRemaining; sctpPacketLengthRemaining -= chunkLengthRemaining; chunkLengthRemaining = 0; break; } } /* * Any extra stuff at the end of the chunk? * XXX - report this? */ bp += chunkLengthRemaining; sctpPacketLengthRemaining -= chunkLengthRemaining; if (ndo->ndo_vflag < 2) sep = ", ("; if (align != 0) { /* * Fail if the alignment padding isn't in the captured data. * Otherwise, skip it. */ ND_TCHECK_LEN(bp, align); bp += align; sctpPacketLengthRemaining -= align; } } return; trunc: ND_PRINT("[|sctp]"); }
static void dhcp6opt_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) { const struct dhcp6opt *dh6o; const u_char *tp; u_int i; uint16_t opttype; uint16_t optlen; uint8_t auth_proto; uint8_t auth_alg; uint8_t auth_rdm; u_int authinfolen, authrealmlen; u_int remain_len; /* Length of remaining options */ u_int label_len; /* Label length */ uint16_t subopt_code; uint16_t subopt_len; uint8_t dh6_reconf_type; uint8_t dh6_lq_query_type; if (cp == ep) return; while (cp < ep) { if (ep < cp + sizeof(*dh6o)) goto trunc; dh6o = (const struct dhcp6opt *)cp; ND_TCHECK_SIZE(dh6o); optlen = EXTRACT_BE_U_2(dh6o->dh6opt_len); if (ep < cp + sizeof(*dh6o) + optlen) goto trunc; opttype = EXTRACT_BE_U_2(dh6o->dh6opt_type); ND_PRINT(" (%s", tok2str(dh6opt_str, "opt_%u", opttype)); ND_TCHECK_LEN(cp + sizeof(*dh6o), optlen); switch (opttype) { case DH6OPT_CLIENTID: case DH6OPT_SERVERID: if (optlen < 2) { /*(*/ ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); switch (EXTRACT_BE_U_2(tp)) { case 1: if (optlen >= 2 + 6) { ND_PRINT(" hwaddr/time type %u time %u ", EXTRACT_BE_U_2(tp + 2), EXTRACT_BE_U_4(tp + 4)); for (i = 8; i < optlen; i++) ND_PRINT("%02x", EXTRACT_U_1(tp + i)); /*(*/ ND_PRINT(")"); } else { /*(*/ ND_PRINT(" ?)"); } break; case 2: if (optlen >= 2 + 8) { ND_PRINT(" vid "); for (i = 2; i < 2 + 8; i++) ND_PRINT("%02x", EXTRACT_U_1(tp + i)); /*(*/ ND_PRINT(")"); } else { /*(*/ ND_PRINT(" ?)"); } break; case 3: if (optlen >= 2 + 2) { ND_PRINT(" hwaddr type %u ", EXTRACT_BE_U_2(tp + 2)); for (i = 4; i < optlen; i++) ND_PRINT("%02x", EXTRACT_U_1(tp + i)); /*(*/ ND_PRINT(")"); } else { /*(*/ ND_PRINT(" ?)"); } break; default: ND_PRINT(" type %u)", EXTRACT_BE_U_2(tp)); break; } break; case DH6OPT_IA_ADDR: if (optlen < 24) { /*(*/ ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); ND_PRINT(" %s", ip6addr_string(ndo, tp)); ND_PRINT(" pltime:%u vltime:%u", EXTRACT_BE_U_4(tp + 16), EXTRACT_BE_U_4(tp + 20)); if (optlen > 24) { /* there are sub-options */ dhcp6opt_print(ndo, tp + 24, tp + optlen); } ND_PRINT(")"); break; case DH6OPT_ORO: case DH6OPT_ERO: if (optlen % 2) { ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); for (i = 0; i < optlen; i += 2) { ND_PRINT(" %s", tok2str(dh6opt_str, "opt_%u", EXTRACT_BE_U_2(tp + i))); } ND_PRINT(")"); break; case DH6OPT_PREFERENCE: if (optlen != 1) { ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); ND_PRINT(" %u)", EXTRACT_U_1(tp)); break; case DH6OPT_ELAPSED_TIME: if (optlen != 2) { ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); ND_PRINT(" %u)", EXTRACT_BE_U_2(tp)); break; case DH6OPT_RELAY_MSG: ND_PRINT(" ("); tp = (const u_char *)(dh6o + 1); dhcp6_print(ndo, tp, optlen); ND_PRINT(")"); break; case DH6OPT_AUTH: if (optlen < 11) { ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); auth_proto = EXTRACT_U_1(tp); switch (auth_proto) { case DH6OPT_AUTHPROTO_DELAYED: ND_PRINT(" proto: delayed"); break; case DH6OPT_AUTHPROTO_RECONFIG: ND_PRINT(" proto: reconfigure"); break; default: ND_PRINT(" proto: %u", auth_proto); break; } tp++; auth_alg = EXTRACT_U_1(tp); switch (auth_alg) { case DH6OPT_AUTHALG_HMACMD5: /* XXX: may depend on the protocol */ ND_PRINT(", alg: HMAC-MD5"); break; default: ND_PRINT(", alg: %u", auth_alg); break; } tp++; auth_rdm = EXTRACT_U_1(tp); switch (auth_rdm) { case DH6OPT_AUTHRDM_MONOCOUNTER: ND_PRINT(", RDM: mono"); break; default: ND_PRINT(", RDM: %u", auth_rdm); break; } tp++; ND_PRINT(", RD:"); for (i = 0; i < 4; i++, tp += 2) ND_PRINT(" %04x", EXTRACT_BE_U_2(tp)); /* protocol dependent part */ authinfolen = optlen - 11; switch (auth_proto) { case DH6OPT_AUTHPROTO_DELAYED: if (authinfolen == 0) break; if (authinfolen < 20) { ND_PRINT(" ??"); break; } authrealmlen = authinfolen - 20; if (authrealmlen > 0) { ND_PRINT(", realm: "); } for (i = 0; i < authrealmlen; i++, tp++) ND_PRINT("%02x", EXTRACT_U_1(tp)); ND_PRINT(", key ID: %08x", EXTRACT_BE_U_4(tp)); tp += 4; ND_PRINT(", HMAC-MD5:"); for (i = 0; i < 4; i++, tp+= 4) ND_PRINT(" %08x", EXTRACT_BE_U_4(tp)); break; case DH6OPT_AUTHPROTO_RECONFIG: if (authinfolen != 17) { ND_PRINT(" ??"); break; } switch (EXTRACT_U_1(tp)) { case DH6OPT_AUTHRECONFIG_KEY: ND_PRINT(" reconfig-key"); break; case DH6OPT_AUTHRECONFIG_HMACMD5: ND_PRINT(" type: HMAC-MD5"); break; default: ND_PRINT(" type: ??"); break; } tp++; ND_PRINT(" value:"); for (i = 0; i < 4; i++, tp+= 4) ND_PRINT(" %08x", EXTRACT_BE_U_4(tp)); break; default: ND_PRINT(" ??"); break; } ND_PRINT(")"); break; case DH6OPT_RAPID_COMMIT: /* nothing todo */ ND_PRINT(")"); break; case DH6OPT_INTERFACE_ID: case DH6OPT_SUBSCRIBER_ID: /* * Since we cannot predict the encoding, print hex dump * at most 10 characters. */ tp = (const u_char *)(dh6o + 1); ND_PRINT(" "); for (i = 0; i < optlen && i < 10; i++) ND_PRINT("%02x", EXTRACT_U_1(tp + i)); ND_PRINT("...)"); break; case DH6OPT_RECONF_MSG: if (optlen != 1) { ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); dh6_reconf_type = EXTRACT_U_1(tp); switch (dh6_reconf_type) { case DH6_RENEW: ND_PRINT(" for renew)"); break; case DH6_INFORM_REQ: ND_PRINT(" for inf-req)"); break; default: ND_PRINT(" for ?\?\?(%02x))", dh6_reconf_type); break; } break; case DH6OPT_RECONF_ACCEPT: /* nothing todo */ ND_PRINT(")"); break; case DH6OPT_SIP_SERVER_A: case DH6OPT_DNS_SERVERS: case DH6OPT_SNTP_SERVERS: case DH6OPT_NIS_SERVERS: case DH6OPT_NISP_SERVERS: case DH6OPT_BCMCS_SERVER_A: case DH6OPT_PANA_AGENT: case DH6OPT_LQ_CLIENT_LINK: if (optlen % 16) { ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); for (i = 0; i < optlen; i += 16) ND_PRINT(" %s", ip6addr_string(ndo, tp + i)); ND_PRINT(")"); break; case DH6OPT_SIP_SERVER_D: case DH6OPT_DOMAIN_LIST: tp = (const u_char *)(dh6o + 1); while (tp < cp + sizeof(*dh6o) + optlen) { ND_PRINT(" "); if ((tp = ns_nprint(ndo, tp, cp + sizeof(*dh6o) + optlen)) == NULL) goto trunc; } ND_PRINT(")"); break; case DH6OPT_STATUS_CODE: if (optlen < 2) { ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); ND_PRINT(" %s)", dhcp6stcode(EXTRACT_BE_U_2(tp))); break; case DH6OPT_IA_NA: case DH6OPT_IA_PD: if (optlen < 12) { ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); ND_PRINT(" IAID:%u T1:%u T2:%u", EXTRACT_BE_U_4(tp), EXTRACT_BE_U_4(tp + 4), EXTRACT_BE_U_4(tp + 8)); if (optlen > 12) { /* there are sub-options */ dhcp6opt_print(ndo, tp + 12, tp + optlen); } ND_PRINT(")"); break; case DH6OPT_IA_TA: if (optlen < 4) { ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); ND_PRINT(" IAID:%u", EXTRACT_BE_U_4(tp)); if (optlen > 4) { /* there are sub-options */ dhcp6opt_print(ndo, tp + 4, tp + optlen); } ND_PRINT(")"); break; case DH6OPT_IA_PD_PREFIX: if (optlen < 25) { ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); ND_PRINT(" %s/%u", ip6addr_string(ndo, tp + 9), EXTRACT_U_1(tp + 8)); ND_PRINT(" pltime:%u vltime:%u", EXTRACT_BE_U_4(tp), EXTRACT_BE_U_4(tp + 4)); if (optlen > 25) { /* there are sub-options */ dhcp6opt_print(ndo, tp + 25, tp + optlen); } ND_PRINT(")"); break; case DH6OPT_LIFETIME: case DH6OPT_CLT_TIME: if (optlen != 4) { ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); ND_PRINT(" %u)", EXTRACT_BE_U_4(tp)); break; case DH6OPT_REMOTE_ID: if (optlen < 4) { ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); ND_PRINT(" %u ", EXTRACT_BE_U_4(tp)); /* * Print hex dump first 10 characters. */ for (i = 4; i < optlen && i < 14; i++) ND_PRINT("%02x", EXTRACT_U_1(tp + i)); ND_PRINT("...)"); break; case DH6OPT_LQ_QUERY: if (optlen < 17) { ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); dh6_lq_query_type = EXTRACT_U_1(tp); switch (dh6_lq_query_type) { case 1: ND_PRINT(" by-address"); break; case 2: ND_PRINT(" by-clientID"); break; default: ND_PRINT(" type_%u", dh6_lq_query_type); break; } ND_PRINT(" %s", ip6addr_string(ndo, tp + 1)); if (optlen > 17) { /* there are query-options */ dhcp6opt_print(ndo, tp + 17, tp + optlen); } ND_PRINT(")"); break; case DH6OPT_CLIENT_DATA: tp = (const u_char *)(dh6o + 1); if (optlen > 0) { /* there are encapsulated options */ dhcp6opt_print(ndo, tp, tp + optlen); } ND_PRINT(")"); break; case DH6OPT_LQ_RELAY_DATA: if (optlen < 16) { ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); ND_PRINT(" %s ", ip6addr_string(ndo, tp)); /* * Print hex dump first 10 characters. */ for (i = 16; i < optlen && i < 26; i++) ND_PRINT("%02x", EXTRACT_U_1(tp + i)); ND_PRINT("...)"); break; case DH6OPT_NTP_SERVER: if (optlen < 4) { ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); while (tp < cp + sizeof(*dh6o) + optlen - 4) { subopt_code = EXTRACT_BE_U_2(tp); tp += 2; subopt_len = EXTRACT_BE_U_2(tp); tp += 2; if (tp + subopt_len > cp + sizeof(*dh6o) + optlen) goto trunc; ND_PRINT(" subopt:%u", subopt_code); switch (subopt_code) { case DH6OPT_NTP_SUBOPTION_SRV_ADDR: case DH6OPT_NTP_SUBOPTION_MC_ADDR: if (subopt_len != 16) { ND_PRINT(" ?"); break; } ND_PRINT(" %s", ip6addr_string(ndo, tp)); break; case DH6OPT_NTP_SUBOPTION_SRV_FQDN: ND_PRINT(" "); if (ns_nprint(ndo, tp, tp + subopt_len) == NULL) goto trunc; break; default: ND_PRINT(" ?"); break; } tp += subopt_len; } ND_PRINT(")"); break; case DH6OPT_AFTR_NAME: if (optlen < 3) { ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); remain_len = optlen; ND_PRINT(" "); /* Encoding is described in section 3.1 of RFC 1035 */ while (remain_len && EXTRACT_U_1(tp)) { label_len = EXTRACT_U_1(tp); tp++; if (label_len < remain_len - 1) { (void)fn_printn(ndo, tp, label_len, NULL); tp += label_len; remain_len -= (label_len + 1); if(EXTRACT_U_1(tp)) ND_PRINT("."); } else { ND_PRINT(" ?"); break; } } ND_PRINT(")"); break; case DH6OPT_NEW_POSIX_TIMEZONE: /* all three of these options */ case DH6OPT_NEW_TZDB_TIMEZONE: /* are encoded similarly */ case DH6OPT_MUDURL: /* although GMT might not work */ if (optlen < 5) { ND_PRINT(" ?)"); break; } tp = (const u_char *)(dh6o + 1); ND_PRINT("="); (void)fn_printn(ndo, tp, (u_int)optlen, NULL); ND_PRINT(")"); break; default: ND_PRINT(")"); break; } cp += sizeof(*dh6o) + optlen; } return; trunc: ND_PRINT("[|dhcp6ext]"); }
void vqp_print(netdissect_options *ndo, const u_char *pptr, u_int len) { const struct vqp_common_header_t *vqp_common_header; const struct vqp_obj_tlv_t *vqp_obj_tlv; const u_char *tptr; uint8_t version; uint16_t vqp_obj_len; uint32_t vqp_obj_type; u_int tlen; uint8_t nitems; tptr=pptr; tlen = len; vqp_common_header = (const struct vqp_common_header_t *)pptr; ND_TCHECK_SIZE(vqp_common_header); if (sizeof(struct vqp_common_header_t) > tlen) goto trunc; version = EXTRACT_U_1(vqp_common_header->version); /* * Sanity checking of the header. */ if (version != VQP_VERSION) { ND_PRINT("VQP version %u packet not supported", version); return; } /* in non-verbose mode just lets print the basic Message Type */ if (ndo->ndo_vflag < 1) { ND_PRINT("VQPv%u %s Message, error-code %s (%u), length %u", version, tok2str(vqp_msg_type_values, "unknown (%u)",EXTRACT_U_1(vqp_common_header->msg_type)), tok2str(vqp_error_code_values, "unknown (%u)",EXTRACT_U_1(vqp_common_header->error_code)), EXTRACT_U_1(vqp_common_header->error_code), len); return; } /* ok they seem to want to know everything - lets fully decode it */ nitems = EXTRACT_U_1(vqp_common_header->nitems); ND_PRINT("\n\tVQPv%u, %s Message, error-code %s (%u), seq 0x%08x, items %u, length %u", version, tok2str(vqp_msg_type_values, "unknown (%u)",EXTRACT_U_1(vqp_common_header->msg_type)), tok2str(vqp_error_code_values, "unknown (%u)",EXTRACT_U_1(vqp_common_header->error_code)), EXTRACT_U_1(vqp_common_header->error_code), EXTRACT_BE_U_4(vqp_common_header->sequence), nitems, len); /* skip VQP Common header */ tptr+=sizeof(struct vqp_common_header_t); tlen-=sizeof(struct vqp_common_header_t); while (nitems != 0 && tlen != 0) { vqp_obj_tlv = (const struct vqp_obj_tlv_t *)tptr; ND_TCHECK_SIZE(vqp_obj_tlv); if (sizeof(struct vqp_obj_tlv_t) > tlen) goto trunc; vqp_obj_type = EXTRACT_BE_U_4(vqp_obj_tlv->obj_type); vqp_obj_len = EXTRACT_BE_U_2(vqp_obj_tlv->obj_length); tptr+=sizeof(struct vqp_obj_tlv_t); tlen-=sizeof(struct vqp_obj_tlv_t); ND_PRINT("\n\t %s Object (0x%08x), length %u, value: ", tok2str(vqp_obj_values, "Unknown", vqp_obj_type), vqp_obj_type, vqp_obj_len); /* basic sanity check */ if (vqp_obj_type == 0 || vqp_obj_len ==0) { return; } /* did we capture enough for fully decoding the object ? */ ND_TCHECK_LEN(tptr, vqp_obj_len); if (vqp_obj_len > tlen) goto trunc; switch(vqp_obj_type) { case VQP_OBJ_IP_ADDRESS: if (vqp_obj_len != 4) goto trunc; ND_PRINT("%s (0x%08x)", ipaddr_string(ndo, tptr), EXTRACT_BE_U_4(tptr)); break; /* those objects have similar semantics - fall through */ case VQP_OBJ_PORT_NAME: case VQP_OBJ_VLAN_NAME: case VQP_OBJ_VTP_DOMAIN: case VQP_OBJ_ETHERNET_PKT: safeputs(ndo, tptr, vqp_obj_len); break; /* those objects have similar semantics - fall through */ case VQP_OBJ_MAC_ADDRESS: case VQP_OBJ_MAC_NULL: if (vqp_obj_len != MAC_ADDR_LEN) goto trunc; ND_PRINT("%s", etheraddr_string(ndo, tptr)); break; default: if (ndo->ndo_vflag <= 1) print_unknown_data(ndo,tptr, "\n\t ", vqp_obj_len); break; } tptr += vqp_obj_len; tlen -= vqp_obj_len; nitems--; } return; trunc: ND_PRINT("\n\t[|VQP]"); }
/* * 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 cfm_print(netdissect_options *ndo, const u_char *pptr, u_int length) { const struct cfm_common_header_t *cfm_common_header; uint8_t mdlevel_version, opcode, flags, first_tlv_offset; const struct cfm_tlv_header_t *cfm_tlv_header; const uint8_t *tptr, *tlv_ptr; const uint8_t *namesp; u_int names_data_remaining; uint8_t md_nameformat, md_namelength; const uint8_t *md_name; uint8_t ma_nameformat, ma_namelength; const uint8_t *ma_name; u_int hexdump, tlen, cfm_tlv_len, cfm_tlv_type, ccm_interval; union { const struct cfm_ccm_t *cfm_ccm; const struct cfm_lbm_t *cfm_lbm; const struct cfm_ltm_t *cfm_ltm; const struct cfm_ltr_t *cfm_ltr; } msg_ptr; tptr=pptr; cfm_common_header = (const struct cfm_common_header_t *)pptr; if (length < sizeof(*cfm_common_header)) goto tooshort; ND_TCHECK_SIZE(cfm_common_header); /* * Sanity checking of the header. */ mdlevel_version = EXTRACT_U_1(cfm_common_header->mdlevel_version); if (CFM_EXTRACT_VERSION(mdlevel_version) != CFM_VERSION) { ND_PRINT("CFMv%u not supported, length %u", CFM_EXTRACT_VERSION(mdlevel_version), length); return; } opcode = EXTRACT_U_1(cfm_common_header->opcode); ND_PRINT("CFMv%u %s, MD Level %u, length %u", CFM_EXTRACT_VERSION(mdlevel_version), tok2str(cfm_opcode_values, "unknown (%u)", opcode), CFM_EXTRACT_MD_LEVEL(mdlevel_version), length); /* * In non-verbose mode just print the opcode and md-level. */ if (ndo->ndo_vflag < 1) { return; } flags = EXTRACT_U_1(cfm_common_header->flags); first_tlv_offset = EXTRACT_U_1(cfm_common_header->first_tlv_offset); ND_PRINT("\n\tFirst TLV offset %u", first_tlv_offset); tptr += sizeof(struct cfm_common_header_t); tlen = length - sizeof(struct cfm_common_header_t); /* * Sanity check the first TLV offset. */ if (first_tlv_offset > tlen) { ND_PRINT(" (too large, must be <= %u)", tlen); return; } switch (opcode) { case CFM_OPCODE_CCM: msg_ptr.cfm_ccm = (const struct cfm_ccm_t *)tptr; if (first_tlv_offset < sizeof(*msg_ptr.cfm_ccm)) { ND_PRINT(" (too small 1, must be >= %lu)", (unsigned long) sizeof(*msg_ptr.cfm_ccm)); return; } if (tlen < sizeof(*msg_ptr.cfm_ccm)) goto tooshort; ND_TCHECK_SIZE(msg_ptr.cfm_ccm); ccm_interval = CFM_EXTRACT_CCM_INTERVAL(flags); ND_PRINT(", Flags [CCM Interval %u%s]", ccm_interval, flags & CFM_CCM_RDI_FLAG ? ", RDI" : ""); /* * Resolve the CCM interval field. */ if (ccm_interval) { ND_PRINT("\n\t CCM Interval %.3fs" ", min CCM Lifetime %.3fs, max CCM Lifetime %.3fs", ccm_interval_base[ccm_interval], ccm_interval_base[ccm_interval] * CCM_INTERVAL_MIN_MULTIPLIER, ccm_interval_base[ccm_interval] * CCM_INTERVAL_MAX_MULTIPLIER); } ND_PRINT("\n\t Sequence Number 0x%08x, MA-End-Point-ID 0x%04x", EXTRACT_BE_U_4(msg_ptr.cfm_ccm->sequence), EXTRACT_BE_U_2(msg_ptr.cfm_ccm->ma_epi)); namesp = msg_ptr.cfm_ccm->names; names_data_remaining = sizeof(msg_ptr.cfm_ccm->names); /* * Resolve the MD fields. */ md_nameformat = EXTRACT_U_1(namesp); namesp++; names_data_remaining--; /* We know this is != 0 */ if (md_nameformat != CFM_CCM_MD_FORMAT_NONE) { md_namelength = EXTRACT_U_1(namesp); namesp++; names_data_remaining--; /* We know this is !=0 */ ND_PRINT("\n\t MD Name Format %s (%u), MD Name length %u", tok2str(cfm_md_nameformat_values, "Unknown", md_nameformat), md_nameformat, md_namelength); /* * -3 for the MA short name format and length and one byte * of MA short name. */ if (md_namelength > names_data_remaining - 3) { ND_PRINT(" (too large, must be <= %u)", names_data_remaining - 2); return; } md_name = namesp; ND_PRINT("\n\t MD Name: "); switch (md_nameformat) { case CFM_CCM_MD_FORMAT_DNS: case CFM_CCM_MD_FORMAT_CHAR: safeputs(ndo, md_name, md_namelength); break; case CFM_CCM_MD_FORMAT_MAC: if (md_namelength == 6) { ND_PRINT("\n\t MAC %s", etheraddr_string(ndo, md_name)); } else { ND_PRINT("\n\t MAC (length invalid)"); } break; /* FIXME add printers for those MD formats - hexdump for now */ case CFM_CCM_MA_FORMAT_8021: default: print_unknown_data(ndo, md_name, "\n\t ", md_namelength); } namesp += md_namelength; names_data_remaining -= md_namelength; } else { ND_PRINT("\n\t MD Name Format %s (%u)", tok2str(cfm_md_nameformat_values, "Unknown", md_nameformat), md_nameformat); } /* * Resolve the MA fields. */ ma_nameformat = EXTRACT_U_1(namesp); namesp++; names_data_remaining--; /* We know this is != 0 */ ma_namelength = EXTRACT_U_1(namesp); namesp++; names_data_remaining--; /* We know this is != 0 */ ND_PRINT("\n\t MA Name-Format %s (%u), MA name length %u", tok2str(cfm_ma_nameformat_values, "Unknown", ma_nameformat), ma_nameformat, ma_namelength); if (ma_namelength > names_data_remaining) { ND_PRINT(" (too large, must be <= %u)", names_data_remaining); return; } ma_name = namesp; ND_PRINT("\n\t MA Name: "); switch (ma_nameformat) { case CFM_CCM_MA_FORMAT_CHAR: safeputs(ndo, ma_name, ma_namelength); break; /* FIXME add printers for those MA formats - hexdump for now */ case CFM_CCM_MA_FORMAT_8021: case CFM_CCM_MA_FORMAT_VID: case CFM_CCM_MA_FORMAT_INT: case CFM_CCM_MA_FORMAT_VPN: default: print_unknown_data(ndo, ma_name, "\n\t ", ma_namelength); } break; case CFM_OPCODE_LTM: msg_ptr.cfm_ltm = (const struct cfm_ltm_t *)tptr; if (first_tlv_offset < sizeof(*msg_ptr.cfm_ltm)) { ND_PRINT(" (too small 4, must be >= %lu)", (unsigned long) sizeof(*msg_ptr.cfm_ltm)); return; } if (tlen < sizeof(*msg_ptr.cfm_ltm)) goto tooshort; ND_TCHECK_SIZE(msg_ptr.cfm_ltm); ND_PRINT(", Flags [%s]", bittok2str(cfm_ltm_flag_values, "none", flags)); ND_PRINT("\n\t Transaction-ID 0x%08x, ttl %u", EXTRACT_BE_U_4(msg_ptr.cfm_ltm->transaction_id), EXTRACT_U_1(msg_ptr.cfm_ltm->ttl)); ND_PRINT("\n\t Original-MAC %s, Target-MAC %s", etheraddr_string(ndo, msg_ptr.cfm_ltm->original_mac), etheraddr_string(ndo, msg_ptr.cfm_ltm->target_mac)); break; case CFM_OPCODE_LTR: msg_ptr.cfm_ltr = (const struct cfm_ltr_t *)tptr; if (first_tlv_offset < sizeof(*msg_ptr.cfm_ltr)) { ND_PRINT(" (too small 5, must be >= %lu)", (unsigned long) sizeof(*msg_ptr.cfm_ltr)); return; } if (tlen < sizeof(*msg_ptr.cfm_ltr)) goto tooshort; ND_TCHECK_SIZE(msg_ptr.cfm_ltr); ND_PRINT(", Flags [%s]", bittok2str(cfm_ltr_flag_values, "none", flags)); ND_PRINT("\n\t Transaction-ID 0x%08x, ttl %u", EXTRACT_BE_U_4(msg_ptr.cfm_ltr->transaction_id), EXTRACT_U_1(msg_ptr.cfm_ltr->ttl)); ND_PRINT("\n\t Replay-Action %s (%u)", tok2str(cfm_ltr_replay_action_values, "Unknown", EXTRACT_U_1(msg_ptr.cfm_ltr->replay_action)), EXTRACT_U_1(msg_ptr.cfm_ltr->replay_action)); break; /* * No message decoder yet. * Hexdump everything up until the start of the TLVs */ case CFM_OPCODE_LBR: case CFM_OPCODE_LBM: default: print_unknown_data(ndo, tptr, "\n\t ", tlen - first_tlv_offset); break; } tptr += first_tlv_offset; tlen -= first_tlv_offset; while (tlen > 0) { cfm_tlv_header = (const struct cfm_tlv_header_t *)tptr; /* Enough to read the tlv type ? */ ND_TCHECK_1(cfm_tlv_header->type); cfm_tlv_type = EXTRACT_U_1(cfm_tlv_header->type); ND_PRINT("\n\t%s TLV (0x%02x)", tok2str(cfm_tlv_values, "Unknown", cfm_tlv_type), cfm_tlv_type); if (cfm_tlv_type == CFM_TLV_END) { /* Length is "Not present if the Type field is 0." */ return; } /* do we have the full tlv header ? */ if (tlen < sizeof(struct cfm_tlv_header_t)) goto tooshort; ND_TCHECK_LEN(tptr, sizeof(struct cfm_tlv_header_t)); cfm_tlv_len=EXTRACT_BE_U_2(cfm_tlv_header->length); ND_PRINT(", length %u", cfm_tlv_len); tptr += sizeof(struct cfm_tlv_header_t); tlen -= sizeof(struct cfm_tlv_header_t); tlv_ptr = tptr; /* do we have the full tlv ? */ if (tlen < cfm_tlv_len) goto tooshort; ND_TCHECK_LEN(tptr, cfm_tlv_len); hexdump = FALSE; switch(cfm_tlv_type) { case CFM_TLV_PORT_STATUS: if (cfm_tlv_len < 1) { ND_PRINT(" (too short, must be >= 1)"); return; } ND_PRINT(", Status: %s (%u)", tok2str(cfm_tlv_port_status_values, "Unknown", EXTRACT_U_1(tptr)), EXTRACT_U_1(tptr)); break; case CFM_TLV_INTERFACE_STATUS: if (cfm_tlv_len < 1) { ND_PRINT(" (too short, must be >= 1)"); return; } ND_PRINT(", Status: %s (%u)", tok2str(cfm_tlv_interface_status_values, "Unknown", EXTRACT_U_1(tptr)), EXTRACT_U_1(tptr)); break; case CFM_TLV_PRIVATE: if (cfm_tlv_len < 4) { ND_PRINT(" (too short, must be >= 4)"); return; } ND_PRINT(", Vendor: %s (%u), Sub-Type %u", tok2str(oui_values,"Unknown", EXTRACT_BE_U_3(tptr)), EXTRACT_BE_U_3(tptr), EXTRACT_U_1(tptr + 3)); hexdump = TRUE; break; case CFM_TLV_SENDER_ID: { u_int chassis_id_type, chassis_id_length; u_int mgmt_addr_length; if (cfm_tlv_len < 1) { ND_PRINT(" (too short, must be >= 1)"); goto next_tlv; } /* * Get the Chassis ID length and check it. * IEEE 802.1Q-2014 Section 21.5.3.1 */ chassis_id_length = EXTRACT_U_1(tptr); tptr++; tlen--; cfm_tlv_len--; if (chassis_id_length) { /* * IEEE 802.1Q-2014 Section 21.5.3.2: Chassis ID Subtype, references * IEEE 802.1AB-2005 Section 9.5.2.2, subsequently * IEEE 802.1AB-2016 Section 8.5.2.2: chassis ID subtype */ if (cfm_tlv_len < 1) { ND_PRINT("\n\t (TLV too short)"); goto next_tlv; } chassis_id_type = EXTRACT_U_1(tptr); cfm_tlv_len--; ND_PRINT("\n\t Chassis-ID Type %s (%u), Chassis-ID length %u", tok2str(cfm_tlv_senderid_chassisid_values, "Unknown", chassis_id_type), chassis_id_type, chassis_id_length); if (cfm_tlv_len < chassis_id_length) { ND_PRINT("\n\t (TLV too short)"); goto next_tlv; } /* IEEE 802.1Q-2014 Section 21.5.3.3: Chassis ID */ switch (chassis_id_type) { case CFM_CHASSIS_ID_MAC_ADDRESS: if (chassis_id_length != MAC_ADDR_LEN) { ND_PRINT(" (invalid MAC address length)"); hexdump = TRUE; break; } ND_PRINT("\n\t MAC %s", etheraddr_string(ndo, tptr + 1)); break; case CFM_CHASSIS_ID_NETWORK_ADDRESS: hexdump |= cfm_network_addr_print(ndo, tptr + 1, chassis_id_length); break; case CFM_CHASSIS_ID_INTERFACE_NAME: /* fall through */ case CFM_CHASSIS_ID_INTERFACE_ALIAS: case CFM_CHASSIS_ID_LOCAL: case CFM_CHASSIS_ID_CHASSIS_COMPONENT: case CFM_CHASSIS_ID_PORT_COMPONENT: safeputs(ndo, tptr + 1, chassis_id_length); break; default: hexdump = TRUE; break; } cfm_tlv_len -= chassis_id_length; tptr += 1 + chassis_id_length; tlen -= 1 + chassis_id_length; } /* * Check if there is a Management Address. * IEEE 802.1Q-2014 Section 21.5.3.4: Management Address Domain Length * This and all subsequent fields are not present if the TLV length * allows only the above fields. */ if (cfm_tlv_len == 0) { /* No, there isn't; we're done. */ break; } /* Here mgmt_addr_length stands for the management domain length. */ mgmt_addr_length = EXTRACT_U_1(tptr); tptr++; tlen--; cfm_tlv_len--; ND_PRINT("\n\t Management Address Domain Length %u", mgmt_addr_length); if (mgmt_addr_length) { /* IEEE 802.1Q-2014 Section 21.5.3.5: Management Address Domain */ if (cfm_tlv_len < mgmt_addr_length) { ND_PRINT("\n\t (TLV too short)"); goto next_tlv; } cfm_tlv_len -= mgmt_addr_length; /* * XXX - this is an OID; print it as such. */ hex_print(ndo, "\n\t Management Address Domain: ", tptr, mgmt_addr_length); tptr += mgmt_addr_length; tlen -= mgmt_addr_length; /* * IEEE 802.1Q-2014 Section 21.5.3.6: Management Address Length * This field is present if Management Address Domain Length is not 0. */ if (cfm_tlv_len < 1) { ND_PRINT(" (Management Address Length is missing)"); hexdump = TRUE; break; } /* Here mgmt_addr_length stands for the management address length. */ mgmt_addr_length = EXTRACT_U_1(tptr); tptr++; tlen--; cfm_tlv_len--; ND_PRINT("\n\t Management Address Length %u", mgmt_addr_length); if (mgmt_addr_length) { /* IEEE 802.1Q-2014 Section 21.5.3.7: Management Address */ if (cfm_tlv_len < mgmt_addr_length) { ND_PRINT("\n\t (TLV too short)"); return; } cfm_tlv_len -= mgmt_addr_length; /* * XXX - this is a TransportDomain; print it as such. */ hex_print(ndo, "\n\t Management Address: ", tptr, mgmt_addr_length); tptr += mgmt_addr_length; tlen -= mgmt_addr_length; } } break; } /* * FIXME those are the defined TLVs that lack a decoder * you are welcome to contribute code ;-) */ case CFM_TLV_DATA: case CFM_TLV_REPLY_INGRESS: case CFM_TLV_REPLY_EGRESS: default: hexdump = TRUE; break; } /* do we want to see an additional hexdump ? */ if (hexdump || ndo->ndo_vflag > 1) print_unknown_data(ndo, tlv_ptr, "\n\t ", cfm_tlv_len); next_tlv: tptr+=cfm_tlv_len; tlen-=cfm_tlv_len; } return; tooshort: ND_PRINT("\n\t\t packet is too short"); return; trunc: ND_PRINT("%s", tstr); }