static void print_attr_string(netdissect_options *ndo, const u_char *data, u_int length, u_short attr_code) { u_int i; ND_TCHECK_LEN(data, length); switch(attr_code) { case TUNNEL_PASS: if (length < 3) goto trunc; if (EXTRACT_U_1(data) && (EXTRACT_U_1(data) <= 0x1F)) ND_PRINT("Tag[%u] ", EXTRACT_U_1(data)); else ND_PRINT("Tag[Unused] "); data++; length--; ND_PRINT("Salt %u ", EXTRACT_BE_U_2(data)); data+=2; length-=2; break; case TUNNEL_CLIENT_END: case TUNNEL_SERVER_END: case TUNNEL_PRIV_GROUP: case TUNNEL_ASSIGN_ID: case TUNNEL_CLIENT_AUTH: case TUNNEL_SERVER_AUTH: if (EXTRACT_U_1(data) <= 0x1F) { if (length < 1) goto trunc; if (EXTRACT_U_1(data)) ND_PRINT("Tag[%u] ", EXTRACT_U_1(data)); else ND_PRINT("Tag[Unused] "); data++; length--; } break; case EGRESS_VLAN_NAME: if (length < 1) goto trunc; ND_PRINT("%s (0x%02x) ", tok2str(rfc4675_tagged,"Unknown tag",EXTRACT_U_1(data)), EXTRACT_U_1(data)); data++; length--; break; } for (i=0; i < length && EXTRACT_U_1(data); i++, data++) ND_PRINT("%c", ND_ISPRINT(EXTRACT_U_1(data)) ? EXTRACT_U_1(data) : '.'); return; trunc: nd_print_trunc(ndo); }
static void cmu_print(netdissect_options *ndo, const u_char *bp) { const struct cmu_vend *cmu; uint8_t v_flags; ND_PRINT(" vend-cmu"); cmu = (const struct cmu_vend *)bp; /* Only print if there are unknown bits */ ND_TCHECK_4(cmu->v_flags); v_flags = EXTRACT_U_1(cmu->v_flags); if ((v_flags & ~(VF_SMASK)) != 0) ND_PRINT(" F:0x%x", v_flags); PRINTCMUADDR(v_dgate, "DG"); PRINTCMUADDR(v_smask, v_flags & VF_SMASK ? "SM" : "SM*"); PRINTCMUADDR(v_dns1, "NS1"); PRINTCMUADDR(v_dns2, "NS2"); PRINTCMUADDR(v_ins1, "IEN1"); PRINTCMUADDR(v_ins2, "IEN2"); PRINTCMUADDR(v_ts1, "TS1"); PRINTCMUADDR(v_ts2, "TS2"); return; trunc: nd_print_trunc(ndo); }
static int ahcp_time_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) { time_t t; struct tm *tm; char buf[BUFSIZE]; if (cp + 4 != ep) goto invalid; ND_TCHECK_4(cp); t = EXTRACT_BE_U_4(cp); if (NULL == (tm = gmtime(&t))) ND_PRINT(": gmtime() error"); else if (0 == strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm)) ND_PRINT(": strftime() error"); else ND_PRINT(": %s UTC", buf); return 0; invalid: ND_PRINT("%s", istr); ND_TCHECK_LEN(cp, ep - cp); return 0; trunc: nd_print_trunc(ndo); return -1; }
void gre_print(netdissect_options *ndo, const u_char *bp, u_int length) { u_int len = length, vers; ndo->ndo_protocol = "gre"; ND_TCHECK_2(bp); if (len < 2) goto trunc; vers = EXTRACT_BE_U_2(bp) & GRE_VERS_MASK; ND_PRINT("GREv%u",vers); switch(vers) { case 0: gre_print_0(ndo, bp, len); break; case 1: gre_print_1(ndo, bp, len); break; default: ND_PRINT(" ERROR: unknown-version"); break; } return; trunc: nd_print_trunc(ndo); return; }
void vxlan_print(netdissect_options *ndo, const u_char *bp, u_int len) { uint8_t flags; uint32_t vni; ndo->ndo_protocol = "vxlan"; if (len < VXLAN_HDR_LEN) goto trunc; ND_TCHECK_LEN(bp, VXLAN_HDR_LEN); flags = EXTRACT_U_1(bp); bp += 4; vni = EXTRACT_BE_U_3(bp); bp += 4; ND_PRINT("VXLAN, "); ND_PRINT("flags [%s] (0x%02x), ", flags & 0x08 ? "I" : ".", flags); ND_PRINT("vni %u\n", vni); ether_print(ndo, bp, len - VXLAN_HDR_LEN, ndo->ndo_snapend - bp, NULL, NULL); return; trunc: nd_print_trunc(ndo); }
void nfsreply_print(netdissect_options *ndo, const u_char *bp, u_int length, const u_char *bp2) { const struct sunrpc_msg *rp; char srcid[20], dstid[20]; /*fits 32bit*/ ndo->ndo_protocol = "nfs"; nfserr = 0; /* assume no error */ rp = (const struct sunrpc_msg *)bp; ND_TCHECK_4(rp->rm_xid); if (!ndo->ndo_nflag) { strlcpy(srcid, "nfs", sizeof(srcid)); nd_snprintf(dstid, sizeof(dstid), "%u", EXTRACT_BE_U_4(rp->rm_xid)); } else { nd_snprintf(srcid, sizeof(srcid), "%u", NFS_PORT); nd_snprintf(dstid, sizeof(dstid), "%u", EXTRACT_BE_U_4(rp->rm_xid)); } print_nfsaddr(ndo, bp2, srcid, dstid); nfsreply_noaddr_print(ndo, bp, length, bp2); return; trunc: if (!nfserr) nd_print_trunc(ndo); }
/* * This is the top level routine of the printer. 'p' points * to the bluetooth header of the packet, 'h->ts' is the timestamp, * 'h->len' is the length of the packet off the wire, and 'h->caplen' * is the number of bytes actually captured. */ u_int bt_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { u_int length = h->len; u_int caplen = h->caplen; const bluetooth_h4_header* hdr = (const bluetooth_h4_header*)p; ndo->ndo_protocol = "bt_if"; if (caplen < BT_HDRLEN || length < BT_HDRLEN) goto trunc; caplen -= BT_HDRLEN; length -= BT_HDRLEN; p += BT_HDRLEN; ND_TCHECK_4(&hdr->direction); if (ndo->ndo_eflag) ND_PRINT("hci length %u, direction %s, ", length, (EXTRACT_BE_U_4(hdr->direction)&0x1) ? "in" : "out"); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); return (BT_HDRLEN); trunc: nd_print_trunc(ndo); return (BT_HDRLEN); }
static void print_attr_time(netdissect_options *ndo, const u_char *data, u_int length, u_short attr_code _U_) { time_t attr_time; char string[26]; if (length != 4) { ND_PRINT("ERROR: length %u != 4", length); return; } ND_TCHECK_4(data); attr_time = EXTRACT_BE_U_4(data); strlcpy(string, ctime(&attr_time), sizeof(string)); /* Get rid of the newline */ string[24] = '\0'; ND_PRINT("%.24s", string); return; trunc: nd_print_trunc(ndo); }
static void print_attr_netmask6(netdissect_options *ndo, const u_char *data, u_int length, u_short attr_code _U_) { u_char data2[16]; if (length < 2 || length > 18) { ND_PRINT("ERROR: length %u not in range (2..18)", length); return; } ND_TCHECK_LEN(data, length); if (EXTRACT_U_1(data + 1) > 128) { ND_PRINT("ERROR: netmask %u not in range (0..128)", EXTRACT_U_1(data + 1)); return; } memset(data2, 0, sizeof(data2)); if (length > 2) memcpy(data2, data+2, length-2); ND_PRINT("%s/%u", ip6addr_string(ndo, data2), EXTRACT_U_1(data + 1)); if (EXTRACT_U_1(data + 1) > 8 * (length - 2)) ND_PRINT(" (inconsistent prefix length)"); return; trunc: nd_print_trunc(ndo); }
static void print_attr_address(netdissect_options *ndo, const u_char *data, u_int length, u_short attr_code) { if (length != 4) { ND_PRINT("ERROR: length %u != 4", length); return; } ND_TCHECK_4(data); switch(attr_code) { case FRM_IPADDR: case LOG_IPHOST: if (EXTRACT_BE_U_4(data) == 0xFFFFFFFF ) ND_PRINT("User Selected"); else if (EXTRACT_BE_U_4(data) == 0xFFFFFFFE ) ND_PRINT("NAS Select"); else ND_PRINT("%s",ipaddr_string(ndo, data)); break; default: ND_PRINT("%s", ipaddr_string(ndo, data)); break; } return; trunc: nd_print_trunc(ndo); }
void radius_print(netdissect_options *ndo, const u_char *dat, u_int length) { const struct radius_hdr *rad; u_int len, auth_idx; ndo->ndo_protocol = "radius"; ND_TCHECK_LEN(dat, MIN_RADIUS_LEN); rad = (const struct radius_hdr *)dat; len = EXTRACT_BE_U_2(rad->len); if (len < MIN_RADIUS_LEN) { nd_print_trunc(ndo); return; } if (len > length) len = length; if (ndo->ndo_vflag < 1) { ND_PRINT("RADIUS, %s (%u), id: 0x%02x length: %u", tok2str(radius_command_values,"Unknown Command",EXTRACT_U_1(rad->code)), EXTRACT_U_1(rad->code), EXTRACT_U_1(rad->id), len); return; } else { ND_PRINT("RADIUS, length: %u\n\t%s (%u), id: 0x%02x, Authenticator: ", len, tok2str(radius_command_values,"Unknown Command",EXTRACT_U_1(rad->code)), EXTRACT_U_1(rad->code), EXTRACT_U_1(rad->id)); for(auth_idx=0; auth_idx < 16; auth_idx++) ND_PRINT("%02x", rad->auth[auth_idx]); } if (len > MIN_RADIUS_LEN) radius_attrs_print(ndo, dat + MIN_RADIUS_LEN, len - MIN_RADIUS_LEN); return; trunc: nd_print_trunc(ndo); }
/* * Print RRCP requests */ void rrcp_print(netdissect_options *ndo, const u_char *cp, u_int length _U_, const struct lladdr_info *src, const struct lladdr_info *dst) { uint8_t rrcp_proto; uint8_t rrcp_opcode; ndo->ndo_protocol = "rrcp"; ND_TCHECK_1(cp + RRCP_PROTO_OFFSET); rrcp_proto = EXTRACT_U_1(cp + RRCP_PROTO_OFFSET); ND_TCHECK_1(cp + RRCP_OPCODE_ISREPLY_OFFSET); rrcp_opcode = EXTRACT_U_1((cp + RRCP_OPCODE_ISREPLY_OFFSET)) & RRCP_OPCODE_MASK; if (src != NULL && dst != NULL) { ND_PRINT("%s > %s, ", (src->addr_string)(ndo, src->addr), (dst->addr_string)(ndo, dst->addr)); } ND_PRINT("%s %s", tok2str(proto_values,"RRCP-0x%02x",rrcp_proto), ((EXTRACT_U_1(cp + RRCP_OPCODE_ISREPLY_OFFSET)) & RRCP_ISREPLY) ? "reply" : "query"); if (rrcp_proto==1){ ND_PRINT(": %s", tok2str(opcode_values,"unknown opcode (0x%02x)",rrcp_opcode)); } if (rrcp_opcode==1 || rrcp_opcode==2){ ND_TCHECK_6(cp + RRCP_REG_ADDR_OFFSET); ND_PRINT(" addr=0x%04x, data=0x%08x", EXTRACT_LE_U_2(cp + RRCP_REG_ADDR_OFFSET), EXTRACT_LE_U_4(cp + RRCP_REG_DATA_OFFSET)); } if (rrcp_proto==1){ ND_TCHECK_2(cp + RRCP_AUTHKEY_OFFSET); ND_PRINT(", auth=0x%04x", EXTRACT_BE_U_2(cp + RRCP_AUTHKEY_OFFSET)); } if (rrcp_proto==1 && rrcp_opcode==0 && ((EXTRACT_U_1(cp + RRCP_OPCODE_ISREPLY_OFFSET)) & RRCP_ISREPLY)){ ND_TCHECK_4(cp + RRCP_VENDOR_ID_OFFSET); ND_PRINT(" downlink_port=%u, uplink_port=%u, uplink_mac=%s, vendor_id=%08x ,chip_id=%04x ", EXTRACT_U_1(cp + RRCP_DOWNLINK_PORT_OFFSET), EXTRACT_U_1(cp + RRCP_UPLINK_PORT_OFFSET), etheraddr_string(ndo, cp + RRCP_UPLINK_MAC_OFFSET), EXTRACT_BE_U_4(cp + RRCP_VENDOR_ID_OFFSET), EXTRACT_BE_U_2(cp + RRCP_CHIP_ID_OFFSET)); }else if (rrcp_opcode==1 || rrcp_opcode==2 || rrcp_proto==2){ ND_TCHECK_4(cp + RRCP_COOKIE2_OFFSET); ND_PRINT(", cookie=0x%08x%08x ", EXTRACT_BE_U_4(cp + RRCP_COOKIE2_OFFSET), EXTRACT_BE_U_4(cp + RRCP_COOKIE1_OFFSET)); } return; trunc: nd_print_trunc(ndo); }
void timed_print(netdissect_options *ndo, const u_char *bp) { const struct tsp *tsp = (const struct tsp *)bp; uint8_t tsp_type; int sec, usec; ndo->ndo_protocol = "timed"; ND_TCHECK_1(tsp->tsp_type); tsp_type = EXTRACT_U_1(tsp->tsp_type); if (tsp_type < TSPTYPENUMBER) ND_PRINT("TSP_%s", tsptype[tsp_type]); else ND_PRINT("(tsp_type %#x)", tsp_type); ND_TCHECK_1(tsp->tsp_vers); ND_PRINT(" vers %u", EXTRACT_U_1(tsp->tsp_vers)); ND_TCHECK_2(tsp->tsp_seq); ND_PRINT(" seq %u", EXTRACT_BE_U_2(tsp->tsp_seq)); switch (tsp_type) { case TSP_LOOP: ND_TCHECK_1(tsp->tsp_hopcnt); ND_PRINT(" hopcnt %u", EXTRACT_U_1(tsp->tsp_hopcnt)); break; case TSP_SETTIME: case TSP_ADJTIME: case TSP_SETDATE: case TSP_SETDATEREQ: ND_TCHECK_8(&tsp->tsp_time); sec = EXTRACT_BE_S_4(tsp->tsp_time.tv_sec); usec = EXTRACT_BE_S_4(tsp->tsp_time.tv_usec); /* XXX The comparison below is always false? */ if (usec < 0) /* invalid, skip the rest of the packet */ return; ND_PRINT(" time "); if (sec < 0 && usec != 0) { sec++; if (sec == 0) ND_PRINT("-"); usec = 1000000 - usec; } ND_PRINT("%d.%06d", sec, usec); break; } ND_PRINT(" name "); if (nd_printzp(ndo, tsp->tsp_name, sizeof(tsp->tsp_name), ndo->ndo_snapend)) goto trunc; return; trunc: nd_print_trunc(ndo); }
/* * print vendor specific attributes */ static void print_vendor_attr(netdissect_options *ndo, const u_char *data, u_int length, u_short attr_code _U_) { u_int idx; u_int vendor_id; u_int vendor_type; u_int vendor_length; if (length < 4) goto trunc; ND_TCHECK_4(data); vendor_id = EXTRACT_BE_U_4(data); data+=4; length-=4; ND_PRINT("Vendor: %s (%u)", tok2str(smi_values,"Unknown",vendor_id), vendor_id); while (length >= 2) { ND_TCHECK_2(data); vendor_type = EXTRACT_U_1(data); vendor_length = EXTRACT_U_1(data + 1); if (vendor_length < 2) { ND_PRINT("\n\t Vendor Attribute: %u, Length: %u (bogus, must be >= 2)", vendor_type, vendor_length); return; } if (vendor_length > length) { ND_PRINT("\n\t Vendor Attribute: %u, Length: %u (bogus, goes past end of vendor-specific attribute)", vendor_type, vendor_length); return; } data+=2; vendor_length-=2; length-=2; ND_TCHECK_LEN(data, vendor_length); ND_PRINT("\n\t Vendor Attribute: %u, Length: %u, Value: ", vendor_type, vendor_length); for (idx = 0; idx < vendor_length ; idx++, data++) ND_PRINT("%c", ND_ISPRINT(EXTRACT_U_1(data)) ? EXTRACT_U_1(data) : '.'); length-=vendor_length; } return; trunc: nd_print_trunc(ndo); }
/* * Print NTP control message requests and responses */ static void ntp_control_print(netdissect_options *ndo, const struct ntp_control_data *cd, u_int length) { uint8_t control, R, E, M, opcode; uint16_t sequence, status, assoc, offset, count; if (length < NTP_CTRLMSG_MINLEN) goto invalid; ND_TCHECK_1(cd->control); control = EXTRACT_U_1(cd->control); R = (control & 0x80) != 0; E = (control & 0x40) != 0; M = (control & 0x20) != 0; opcode = control & 0x1f; ND_PRINT(", %s, %s, %s, OpCode=%u\n", R ? "Response" : "Request", E ? "Error" : "OK", M ? "More" : "Last", opcode); ND_TCHECK_2(cd->sequence); sequence = EXTRACT_BE_U_2(cd->sequence); ND_PRINT("\tSequence=%hu", sequence); ND_TCHECK_2(cd->status); status = EXTRACT_BE_U_2(cd->status); ND_PRINT(", Status=%#hx", status); ND_TCHECK_2(cd->assoc); assoc = EXTRACT_BE_U_2(cd->assoc); ND_PRINT(", Assoc.=%hu", assoc); ND_TCHECK_2(cd->offset); offset = EXTRACT_BE_U_2(cd->offset); ND_PRINT(", Offset=%hu", offset); ND_TCHECK_2(cd->count); count = EXTRACT_BE_U_2(cd->count); ND_PRINT(", Count=%hu", count); if (NTP_CTRLMSG_MINLEN + count > length) goto invalid; if (count != 0) { ND_TCHECK_LEN(cd->data, count); ND_PRINT("\n\tTO-BE-DONE: data not interpreted"); } return; invalid: nd_print_invalid(ndo); ND_TCHECK_LEN(cd, length); return; trunc: nd_print_trunc(ndo); }
void hsrp_print(netdissect_options *ndo, const u_char *bp, u_int len) { const struct hsrp *hp = (const struct hsrp *) bp; uint8_t version; ndo->ndo_protocol = "hsrp"; ND_TCHECK_1(hp->hsrp_version); version = GET_U_1(hp->hsrp_version); ND_PRINT("HSRPv%u", version); if (version != 0) return; ND_TCHECK_1(hp->hsrp_op_code); ND_PRINT("-"); ND_PRINT("%s ", tok2strary(op_code_str, "unknown (%u)", GET_U_1(hp->hsrp_op_code))); ND_PRINT("%u: ", len); ND_TCHECK_1(hp->hsrp_state); ND_PRINT("state=%s ", tok2str(states, "Unknown (%u)", GET_U_1(hp->hsrp_state))); ND_TCHECK_1(hp->hsrp_group); ND_PRINT("group=%u ", GET_U_1(hp->hsrp_group)); ND_TCHECK_1(hp->hsrp_reserved); if (GET_U_1(hp->hsrp_reserved) != 0) { ND_PRINT("[reserved=%u!] ", GET_U_1(hp->hsrp_reserved)); } ND_TCHECK_4(hp->hsrp_virtaddr); ND_PRINT("addr=%s", ipaddr_string(ndo, hp->hsrp_virtaddr)); if (ndo->ndo_vflag) { ND_PRINT(" hellotime="); unsigned_relts_print(ndo, GET_U_1(hp->hsrp_hellotime)); ND_PRINT(" holdtime="); unsigned_relts_print(ndo, GET_U_1(hp->hsrp_holdtime)); ND_PRINT(" priority=%u", GET_U_1(hp->hsrp_priority)); ND_PRINT(" auth=\""); if (nd_printn(ndo, hp->hsrp_authdata, sizeof(hp->hsrp_authdata), ndo->ndo_snapend)) { ND_PRINT("\""); goto trunc; } ND_PRINT("\""); } return; trunc: nd_print_trunc(ndo); }
static int ahcp_seconds_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) { if (cp + 4 != ep) goto invalid; ND_TCHECK_4(cp); ND_PRINT(": %us", EXTRACT_BE_U_4(cp)); return 0; invalid: ND_PRINT("%s", istr); ND_TCHECK_LEN(cp, ep - cp); return 0; trunc: nd_print_trunc(ndo); return -1; }
static void ahcp1_body_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) { uint8_t type, mbz; uint16_t body_len; if (cp + AHCP1_BODY_MIN_LEN > ep) goto invalid; /* Type */ ND_TCHECK_1(cp); type = EXTRACT_U_1(cp); cp += 1; /* MBZ */ ND_TCHECK_1(cp); mbz = EXTRACT_U_1(cp); cp += 1; /* Length */ ND_TCHECK_2(cp); body_len = EXTRACT_BE_U_2(cp); cp += 2; if (ndo->ndo_vflag) { ND_PRINT("\n\t%s", tok2str(ahcp1_msg_str, "Unknown-%u", type)); if (mbz != 0) ND_PRINT(", MBZ %u", mbz); ND_PRINT(", Length %u", body_len); } if (cp + body_len > ep) goto invalid; /* Options */ if (ndo->ndo_vflag >= 2) ahcp1_options_print(ndo, cp, cp + body_len); /* not ep (ignore extra data) */ else ND_TCHECK_LEN(cp, body_len); return; invalid: ND_PRINT("%s", istr); ND_TCHECK_LEN(cp, ep - cp); return; trunc: nd_print_trunc(ndo); }
static void print_attr_address6(netdissect_options *ndo, const u_char *data, u_int length, u_short attr_code _U_) { if (length != 16) { ND_PRINT("ERROR: length %u != 16", length); return; } ND_TCHECK_16(data); ND_PRINT("%s", ip6addr_string(ndo, data)); return; trunc: nd_print_trunc(ndo); }
/* XXX should probably pass in the snap header and do checks like arp_print() */ void aarp_print(netdissect_options *ndo, const u_char *bp, u_int length) { const struct aarp *ap; #define AT(member) ataddr_string(ndo, (ap->member[1]<<8)|ap->member[2],ap->member[3]) ndo->ndo_protocol = "aarp"; ND_PRINT("aarp "); ap = (const struct aarp *)bp; if (!ND_TTEST_SIZE(ap)) { /* Just bail if we don't have the whole chunk. */ nd_print_trunc(ndo); return; } if (length < sizeof(*ap)) { ND_PRINT(" [|aarp %u]", length); return; } if (EXTRACT_BE_U_2(ap->htype) == 1 && EXTRACT_BE_U_2(ap->ptype) == ETHERTYPE_ATALK && EXTRACT_U_1(ap->halen) == 6 && EXTRACT_U_1(ap->palen) == 4 ) switch (EXTRACT_BE_U_2(ap->op)) { case 1: /* request */ ND_PRINT("who-has %s tell %s", AT(pdaddr), AT(psaddr)); return; case 2: /* response */ ND_PRINT("reply %s is-at %s", AT(psaddr), etheraddr_string(ndo, ap->hsaddr)); return; case 3: /* probe (oy!) */ ND_PRINT("probe %s tell %s", AT(pdaddr), AT(psaddr)); return; } ND_PRINT("len %u op %u htype %u ptype %#x halen %u palen %u", length, EXTRACT_BE_U_2(ap->op), EXTRACT_BE_U_2(ap->htype), EXTRACT_BE_U_2(ap->ptype), EXTRACT_U_1(ap->halen), EXTRACT_U_1(ap->palen)); }
static void ahcp1_options_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) { uint8_t option_no, option_len; while (cp < ep) { /* Option no */ ND_TCHECK_1(cp); option_no = EXTRACT_U_1(cp); cp += 1; ND_PRINT("\n\t %s", tok2str(ahcp1_opt_str, "Unknown-%u", option_no)); if (option_no == AHCP1_OPT_PAD || option_no == AHCP1_OPT_MANDATORY) continue; /* Length */ if (cp + 1 > ep) goto invalid; ND_TCHECK_1(cp); option_len = EXTRACT_U_1(cp); cp += 1; if (cp + option_len > ep) goto invalid; /* Value */ if (option_no <= AHCP1_OPT_MAX && data_decoders[option_no] != NULL) { if (data_decoders[option_no](ndo, cp, cp + option_len) < 0) break; /* truncated and already marked up */ } else { ND_PRINT(" (Length %u)", option_len); ND_TCHECK_LEN(cp, option_len); } cp += option_len; } return; invalid: ND_PRINT("%s", istr); ND_TCHECK_LEN(cp, ep - cp); return; trunc: nd_print_trunc(ndo); }
/* * This is the top level routine of the printer. 'p' points * to the ether header of the packet, 'h->ts' is the timestamp, * 'h->len' is the length of the packet off the wire, and 'h->caplen' * is the number of bytes actually captured. */ u_int ap1394_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { u_int length = h->len; u_int caplen = h->caplen; const struct firewire_header *fp; u_short ether_type; struct lladdr_info src, dst; ndo->ndo_protocol = "ap1394_if"; if (caplen < FIREWIRE_HDRLEN) { nd_print_trunc(ndo); return FIREWIRE_HDRLEN; } if (ndo->ndo_eflag) ap1394_hdr_print(ndo, p, length); length -= FIREWIRE_HDRLEN; caplen -= FIREWIRE_HDRLEN; fp = (const struct firewire_header *)p; p += FIREWIRE_HDRLEN; ether_type = GET_BE_U_2(fp->firewire_type); src.addr = fp->firewire_shost; src.addr_string = fwaddr_string; dst.addr = fp->firewire_dhost; dst.addr_string = fwaddr_string; if (ethertype_print(ndo, ether_type, p, length, caplen, &src, &dst) == 0) { /* ether_type not known, print raw packet */ if (!ndo->ndo_eflag) ap1394_hdr_print(ndo, (const u_char *)fp, length + FIREWIRE_HDRLEN); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } return FIREWIRE_HDRLEN; }
static int ahcp_ipv6_addresses_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) { const char *sep = ": "; while (cp < ep) { if (cp + 16 > ep) goto invalid; ND_TCHECK_16(cp); ND_PRINT("%s%s", sep, ip6addr_string(ndo, cp)); cp += 16; sep = ", "; } return 0; invalid: ND_PRINT("%s", istr); ND_TCHECK_LEN(cp, ep - cp); return 0; trunc: nd_print_trunc(ndo); return -1; }
static int ahcp_ipv4_prefixes_print(netdissect_options *ndo, const u_char *cp, const u_char *ep) { const char *sep = ": "; while (cp < ep) { if (cp + 5 > ep) goto invalid; ND_TCHECK_5(cp); ND_PRINT("%s%s/%u", sep, ipaddr_string(ndo, cp), EXTRACT_U_1(cp + 4)); cp += 5; sep = ", "; } return 0; invalid: ND_PRINT("%s", istr); ND_TCHECK_LEN(cp, ep - cp); return 0; trunc: nd_print_trunc(ndo); return -1; }
/* * This is the top level routine of the printer. 'p' points * to the ether header of the packet, 'h->ts' is the timestamp, * 'h->len' is the length of the packet off the wire, and 'h->caplen' * is the number of bytes actually captured. */ u_int pktap_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) { uint32_t dlt, hdrlen, rectype; u_int caplen = h->caplen; u_int length = h->len; if_printer printer; const pktap_header_t *hdr; struct pcap_pkthdr nhdr; ndo->ndo_protocol = "pktap_if"; if (caplen < sizeof(pktap_header_t)) { nd_print_trunc(ndo); return (caplen); } hdr = (const pktap_header_t *)p; dlt = EXTRACT_LE_U_4(hdr->pkt_dlt); hdrlen = EXTRACT_LE_U_4(hdr->pkt_len); if (hdrlen < sizeof(pktap_header_t)) { /* * Claimed header length < structure length. * XXX - does this just mean some fields aren't * being supplied, or is it truly an error (i.e., * is the length supplied so that the header can * be expanded in the future)? */ nd_print_trunc(ndo); return (caplen); } if (caplen < hdrlen) { nd_print_trunc(ndo); return (caplen); } if (ndo->ndo_eflag) pktap_header_print(ndo, p, length); length -= hdrlen; caplen -= hdrlen; p += hdrlen; rectype = EXTRACT_LE_U_4(hdr->pkt_rectype); switch (rectype) { case PKT_REC_NONE: ND_PRINT("no data"); break; case PKT_REC_PACKET: if ((printer = lookup_printer(dlt)) != NULL) { nhdr = *h; nhdr.caplen = caplen; nhdr.len = length; hdrlen += printer(ndo, &nhdr, p); } else { if (!ndo->ndo_eflag) pktap_header_print(ndo, (const u_char *)hdr, length + hdrlen); if (!ndo->ndo_suppress_default_print) ND_DEFAULTPRINT(p, caplen); } break; } return (hdrlen); }
void msdp_print(netdissect_options *ndo, const u_char *sp, u_int length) { unsigned int type, len; ndo->ndo_protocol = "msdp"; ND_TCHECK_3(sp); /* See if we think we're at the beginning of a compound packet */ type = EXTRACT_U_1(sp); len = EXTRACT_BE_U_2(sp + 1); if (len > 1500 || len < 3 || type == 0 || type > MSDP_TYPE_MAX) goto trunc; /* not really truncated, but still not decodable */ ND_PRINT(" msdp:"); while (length != 0) { ND_TCHECK_3(sp); type = EXTRACT_U_1(sp); len = EXTRACT_BE_U_2(sp + 1); if (len > 1400 || ndo->ndo_vflag) ND_PRINT(" [len %u]", len); if (len < 3) goto trunc; if (length < len) goto trunc; sp += 3; length -= 3; switch (type) { case 1: /* IPv4 Source-Active */ case 3: /* IPv4 Source-Active Response */ if (type == 1) ND_PRINT(" SA"); else ND_PRINT(" SA-Response"); ND_TCHECK_1(sp); ND_PRINT(" %u entries", EXTRACT_U_1(sp)); if ((u_int)((EXTRACT_U_1(sp) * 12) + 8) < len) { ND_PRINT(" [w/data]"); if (ndo->ndo_vflag > 1) { ND_PRINT(" "); ip_print(ndo, sp + EXTRACT_U_1(sp) * 12 + 8 - 3, len - (EXTRACT_U_1(sp) * 12 + 8)); } } break; case 2: ND_PRINT(" SA-Request"); ND_TCHECK_5(sp); ND_PRINT(" for %s", ipaddr_string(ndo, sp + 1)); break; case 4: ND_PRINT(" Keepalive"); if (len != 3) ND_PRINT("[len=%u] ", len); break; case 5: ND_PRINT(" Notification"); break; default: ND_PRINT(" [type=%u len=%u]", type, len); break; } sp += (len - 3); length -= (len - 3); } return; trunc: nd_print_trunc(ndo); }
void geneve_print(netdissect_options *ndo, const u_char *bp, u_int len) { uint8_t ver_opt; u_int version; uint8_t flags; uint16_t prot; uint32_t vni; uint8_t reserved; u_int opts_len; ndo->ndo_protocol = "geneve"; ND_PRINT("Geneve"); ND_TCHECK_8(bp); ver_opt = GET_U_1(bp); bp += 1; len -= 1; version = ver_opt >> VER_SHIFT; if (version != 0) { ND_PRINT(" ERROR: unknown-version %u", version); return; } flags = GET_U_1(bp); bp += 1; len -= 1; prot = GET_BE_U_2(bp); bp += 2; len -= 2; vni = GET_BE_U_3(bp); bp += 3; len -= 3; reserved = GET_U_1(bp); bp += 1; len -= 1; ND_PRINT(", Flags [%s]", bittok2str_nosep(geneve_flag_values, "none", flags)); ND_PRINT(", vni 0x%x", vni); if (reserved) ND_PRINT(", rsvd 0x%x", reserved); if (ndo->ndo_eflag) ND_PRINT(", proto %s (0x%04x)", tok2str(ethertype_values, "unknown", prot), prot); opts_len = (ver_opt & HDR_OPTS_LEN_MASK) * 4; if (len < opts_len) { ND_PRINT(" truncated-geneve - %u bytes missing", opts_len - len); return; } ND_TCHECK_LEN(bp, opts_len); if (opts_len > 0) { ND_PRINT(", options ["); if (ndo->ndo_vflag) geneve_opts_print(ndo, bp, opts_len); else ND_PRINT("%u bytes", opts_len); ND_PRINT("]"); } bp += opts_len; len -= opts_len; if (ndo->ndo_vflag < 1) ND_PRINT(": "); else ND_PRINT("\n\t"); if (ethertype_print(ndo, prot, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL) == 0) { if (prot == ETHERTYPE_TEB) ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL); else ND_PRINT("geneve-proto-0x%x", prot); } return; trunc: nd_print_trunc(ndo); }
void dvmrp_print(netdissect_options *ndo, const u_char *bp, u_int len) { const u_char *ep; u_char type; uint8_t major_version, minor_version; ndo->ndo_protocol = "dvmrp"; ep = ndo->ndo_snapend; if (bp >= ep) return; ND_TCHECK_1(bp + 1); type = GET_U_1(bp + 1); /* Skip IGMP header */ bp += 8; len -= 8; switch (type) { case DVMRP_PROBE: ND_PRINT(" Probe"); if (ndo->ndo_vflag) { if (print_probe(ndo, bp, ep, len) < 0) goto trunc; } break; case DVMRP_REPORT: ND_PRINT(" Report"); if (ndo->ndo_vflag > 1) { if (print_report(ndo, bp, ep, len) < 0) goto trunc; } break; case DVMRP_ASK_NEIGHBORS: ND_PRINT(" Ask-neighbors(old)"); break; case DVMRP_NEIGHBORS: ND_PRINT(" Neighbors(old)"); if (print_neighbors(ndo, bp, ep, len) < 0) goto trunc; break; case DVMRP_ASK_NEIGHBORS2: ND_PRINT(" Ask-neighbors2"); break; case DVMRP_NEIGHBORS2: ND_PRINT(" Neighbors2"); /* * extract version from IGMP group address field */ bp -= 4; ND_TCHECK_4(bp); major_version = GET_U_1(bp + 3); minor_version = GET_U_1(bp + 2); bp += 4; if (print_neighbors2(ndo, bp, ep, len, major_version, minor_version) < 0) goto trunc; break; case DVMRP_PRUNE: ND_PRINT(" Prune"); if (print_prune(ndo, bp) < 0) goto trunc; break; case DVMRP_GRAFT: ND_PRINT(" Graft"); if (print_graft(ndo, bp) < 0) goto trunc; break; case DVMRP_GRAFT_ACK: ND_PRINT(" Graft-ACK"); if (print_graft_ack(ndo, bp) < 0) goto trunc; break; default: ND_PRINT(" [type %u]", type); break; } return; trunc: nd_print_trunc(ndo); return; }
void nsh_print(netdissect_options *ndo, const u_char *bp, u_int len) { u_int n, vn; uint8_t ver; uint8_t flags; u_int length; uint8_t md_type; uint8_t next_protocol; uint32_t service_path_id; uint8_t service_index; uint32_t ctx; uint16_t tlv_class; uint8_t tlv_type; uint8_t tlv_len; u_int next_len; ndo->ndo_protocol = "nsh"; /* print Base Header and Service Path Header */ if (len < NSH_BASE_HDR_LEN + NSH_SERVICE_PATH_HDR_LEN) goto trunc; ND_TCHECK_LEN(bp, NSH_BASE_HDR_LEN + NSH_SERVICE_PATH_HDR_LEN); ver = (uint8_t)(GET_U_1(bp) >> 6); flags = GET_U_1(bp); bp += 1; length = GET_U_1(bp); bp += 1; md_type = GET_U_1(bp); bp += 1; next_protocol = GET_U_1(bp); bp += 1; service_path_id = GET_BE_U_3(bp); bp += 3; service_index = GET_U_1(bp); bp += 1; ND_PRINT("NSH, "); if (ndo->ndo_vflag > 1) { ND_PRINT("ver %u, ", ver); } ND_PRINT("flags [%s], ", bittok2str_nosep(nsh_flags, "none", flags)); if (ndo->ndo_vflag > 2) { ND_PRINT("length %u, ", length); ND_PRINT("md type 0x%x, ", md_type); } if (ndo->ndo_vflag > 1) { ND_PRINT("next-protocol 0x%x, ", next_protocol); } ND_PRINT("service-path-id 0x%06x, ", service_path_id); ND_PRINT("service-index 0x%x", service_index); /* Make sure we have all the headers */ if (len < length * NSH_HDR_WORD_SIZE) goto trunc; ND_TCHECK_LEN(bp, length * NSH_HDR_WORD_SIZE); /* * length includes the lengths of the Base and Service Path headers. * That means it must be at least 2. */ if (length < 2) goto trunc; /* * Print, or skip, the Context Headers. * (length - 2) is the length of those headers. */ if (ndo->ndo_vflag > 2) { if (md_type == 0x01) { for (n = 0; n < length - 2; n++) { ctx = GET_BE_U_4(bp); bp += NSH_HDR_WORD_SIZE; ND_PRINT("\n Context[%02u]: 0x%08x", n, ctx); } } else if (md_type == 0x02) { n = 0; while (n < length - 2) { tlv_class = GET_BE_U_2(bp); bp += 2; tlv_type = GET_U_1(bp); bp += 1; tlv_len = GET_U_1(bp); bp += 1; ND_PRINT("\n TLV Class %u, Type %u, Len %u", tlv_class, tlv_type, tlv_len); n += 1; if (length - 2 < n + tlv_len) { ND_PRINT(" ERROR: invalid-tlv-length"); return; } for (vn = 0; vn < tlv_len; vn++) { ctx = GET_BE_U_4(bp); bp += NSH_HDR_WORD_SIZE; ND_PRINT("\n Value[%02u]: 0x%08x", vn, ctx); } n += tlv_len; } } else { ND_PRINT("ERROR: unknown-next-protocol"); return; } } else { bp += (length - 2) * NSH_HDR_WORD_SIZE; } ND_PRINT(ndo->ndo_vflag ? "\n " : ": "); /* print Next Protocol */ next_len = len - length * NSH_HDR_WORD_SIZE; switch (next_protocol) { case 0x1: ip_print(ndo, bp, next_len); break; case 0x2: ip6_print(ndo, bp, next_len); break; case 0x3: ether_print(ndo, bp, next_len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL); break; default: ND_PRINT("ERROR: unknown-next-protocol"); return; } return; trunc: nd_print_trunc(ndo); }
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("]"); }