static void r_print_string(int code, int len, const u_char *data) { char string[128]; if(!len) { fputs(" ?", stdout); return; } if(len > 127) len = 127; memset(string, 0, 128); memcpy(string, data, len); fprintf(stdout, " "); safeputs(string); }
void vqp_print(netdissect_options *ndo, register const u_char *pptr, register 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; 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(*vqp_common_header); if (sizeof(struct vqp_common_header_t) > tlen) goto trunc; /* * Sanity checking of the header. */ if (VQP_EXTRACT_VERSION(vqp_common_header->version) != VQP_VERSION) { ND_PRINT((ndo, "VQP version %u packet not supported", VQP_EXTRACT_VERSION(vqp_common_header->version))); return; } /* in non-verbose mode just lets print the basic Message Type */ if (ndo->ndo_vflag < 1) { ND_PRINT((ndo, "VQPv%u %s Message, error-code %s (%u), length %u", VQP_EXTRACT_VERSION(vqp_common_header->version), tok2str(vqp_msg_type_values, "unknown (%u)",vqp_common_header->msg_type), tok2str(vqp_error_code_values, "unknown (%u)",vqp_common_header->error_code), vqp_common_header->error_code, len)); return; } /* ok they seem to want to know everything - lets fully decode it */ nitems = vqp_common_header->nitems; ND_PRINT((ndo, "\n\tVQPv%u, %s Message, error-code %s (%u), seq 0x%08x, items %u, length %u", VQP_EXTRACT_VERSION(vqp_common_header->version), tok2str(vqp_msg_type_values, "unknown (%u)",vqp_common_header->msg_type), tok2str(vqp_error_code_values, "unknown (%u)",vqp_common_header->error_code), vqp_common_header->error_code, EXTRACT_32BITS(&vqp_common_header->sequence), nitems, len)); /* skip VQP Common header */ tptr+=sizeof(const struct vqp_common_header_t); tlen-=sizeof(const struct vqp_common_header_t); while (nitems > 0 && tlen > 0) { vqp_obj_tlv = (const struct vqp_obj_tlv_t *)tptr; ND_TCHECK(*vqp_obj_tlv); if (sizeof(struct vqp_obj_tlv_t) > tlen) goto trunc; vqp_obj_type = EXTRACT_32BITS(vqp_obj_tlv->obj_type); vqp_obj_len = EXTRACT_16BITS(vqp_obj_tlv->obj_length); tptr+=sizeof(struct vqp_obj_tlv_t); tlen-=sizeof(struct vqp_obj_tlv_t); ND_PRINT((ndo, "\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_TCHECK2(*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((ndo, "%s (0x%08x)", ipaddr_string(ndo, tptr), EXTRACT_32BITS(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 != ETHER_ADDR_LEN) goto trunc; ND_PRINT((ndo, "%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((ndo, "\n\t[|VQP]")); }
/* * Print EAP requests / responses */ void eap_print(netdissect_options *ndo, register const u_char *cp, u_int length _U_) { const struct eap_frame_t *eap; const u_char *tptr; u_int tlen, type, subtype; int count=0, len; tptr = cp; tlen = length; eap = (const struct eap_frame_t *)cp; ND_TCHECK(*eap); /* in non-verbose mode just lets print the basic info */ if (ndo->ndo_vflag < 1) { ND_PRINT((ndo, "%s (%u) v%u, len %u", tok2str(eap_frame_type_values, "unknown", eap->type), eap->type, eap->version, EXTRACT_16BITS(eap->length))); return; } ND_PRINT((ndo, "%s (%u) v%u, len %u", tok2str(eap_frame_type_values, "unknown", eap->type), eap->type, eap->version, EXTRACT_16BITS(eap->length))); tptr += sizeof(const struct eap_frame_t); tlen -= sizeof(const struct eap_frame_t); switch (eap->type) { case EAP_FRAME_TYPE_PACKET: type = *(tptr); len = EXTRACT_16BITS(tptr+2); ND_PRINT((ndo, ", %s (%u), id %u, len %u", tok2str(eap_code_values, "unknown", type), type, *(tptr+1), len)); ND_TCHECK2(*tptr, len); if (type <= 2) { /* For EAP_REQUEST and EAP_RESPONSE only */ subtype = *(tptr+4); ND_PRINT((ndo, "\n\t\t Type %s (%u)", tok2str(eap_type_values, "unknown", *(tptr+4)), *(tptr + 4))); switch (subtype) { case EAP_TYPE_IDENTITY: if (len - 5 > 0) { ND_PRINT((ndo, ", Identity: ")); safeputs(ndo, tptr + 5, len - 5); } break; case EAP_TYPE_NOTIFICATION: if (len - 5 > 0) { ND_PRINT((ndo, ", Notification: ")); safeputs(ndo, tptr + 5, len - 5); } break; case EAP_TYPE_NAK: count = 5; /* * one or more octets indicating * the desired authentication * type one octet per type */ while (count < len) { ND_PRINT((ndo, " %s (%u),", tok2str(eap_type_values, "unknown", *(tptr+count)), *(tptr + count))); count++; } break; case EAP_TYPE_TTLS: ND_PRINT((ndo, " TTLSv%u", EAP_TTLS_VERSION(*(tptr + 5)))); /* fall through */ case EAP_TYPE_TLS: ND_PRINT((ndo, " flags [%s] 0x%02x,", bittok2str(eap_tls_flags_values, "none", *(tptr+5)), *(tptr + 5))); if (EAP_TLS_EXTRACT_BIT_L(*(tptr+5))) { ND_PRINT((ndo, " len %u", EXTRACT_32BITS(tptr + 6))); } break; case EAP_TYPE_FAST: ND_PRINT((ndo, " FASTv%u", EAP_TTLS_VERSION(*(tptr + 5)))); ND_PRINT((ndo, " flags [%s] 0x%02x,", bittok2str(eap_tls_flags_values, "none", *(tptr+5)), *(tptr + 5))); if (EAP_TLS_EXTRACT_BIT_L(*(tptr+5))) { ND_PRINT((ndo, " len %u", EXTRACT_32BITS(tptr + 6))); } /* FIXME - TLV attributes follow */ break; case EAP_TYPE_AKA: case EAP_TYPE_SIM: ND_PRINT((ndo, " subtype [%s] 0x%02x,", tok2str(eap_aka_subtype_values, "unknown", *(tptr+5)), *(tptr + 5))); /* FIXME - TLV attributes follow */ break; case EAP_TYPE_MD5_CHALLENGE: case EAP_TYPE_OTP: case EAP_TYPE_GTC: case EAP_TYPE_EXPANDED_TYPES: case EAP_TYPE_EXPERIMENTAL: default: break; } } break; case EAP_FRAME_TYPE_LOGOFF: case EAP_FRAME_TYPE_ENCAP_ASF_ALERT: default: break; } return; trunc: ND_PRINT((ndo, "\n\t[|EAP]")); }
void cfm_print(netdissect_options *ndo, register const u_char *pptr, register u_int length) { const struct cfm_common_header_t *cfm_common_header; const struct cfm_tlv_header_t *cfm_tlv_header; const uint8_t *tptr, *tlv_ptr, *ma_name, *ma_nameformat, *ma_namelength; 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; ND_TCHECK(*cfm_common_header); /* * Sanity checking of the header. */ if (CFM_EXTRACT_VERSION(cfm_common_header->mdlevel_version) != CFM_VERSION) { ND_PRINT((ndo, "CFMv%u not supported, length %u", CFM_EXTRACT_VERSION(cfm_common_header->mdlevel_version), length)); return; } ND_PRINT((ndo, "CFMv%u %s, MD Level %u, length %u", CFM_EXTRACT_VERSION(cfm_common_header->mdlevel_version), tok2str(cfm_opcode_values, "unknown (%u)", cfm_common_header->opcode), CFM_EXTRACT_MD_LEVEL(cfm_common_header->mdlevel_version), length)); /* * In non-verbose mode just print the opcode and md-level. */ if (ndo->ndo_vflag < 1) { return; } ND_PRINT((ndo, "\n\tFirst TLV offset %u", cfm_common_header->first_tlv_offset)); tptr += sizeof(const struct cfm_common_header_t); tlen = length - sizeof(struct cfm_common_header_t); switch (cfm_common_header->opcode) { case CFM_OPCODE_CCM: msg_ptr.cfm_ccm = (const struct cfm_ccm_t *)tptr; ccm_interval = CFM_EXTRACT_CCM_INTERVAL(cfm_common_header->flags); ND_PRINT((ndo, ", Flags [CCM Interval %u%s]", ccm_interval, cfm_common_header->flags & CFM_CCM_RDI_FLAG ? ", RDI" : "")); /* * Resolve the CCM interval field. */ if (ccm_interval) { ND_PRINT((ndo, "\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((ndo, "\n\t Sequence Number 0x%08x, MA-End-Point-ID 0x%04x", EXTRACT_32BITS(msg_ptr.cfm_ccm->sequence), EXTRACT_16BITS(msg_ptr.cfm_ccm->ma_epi))); /* * Resolve the MD fields. */ ND_PRINT((ndo, "\n\t MD Name Format %s (%u), MD Name length %u", tok2str(cfm_md_nameformat_values, "Unknown", msg_ptr.cfm_ccm->md_nameformat), msg_ptr.cfm_ccm->md_nameformat, msg_ptr.cfm_ccm->md_namelength)); if (msg_ptr.cfm_ccm->md_nameformat != CFM_CCM_MD_FORMAT_NONE) { ND_PRINT((ndo, "\n\t MD Name: ")); switch (msg_ptr.cfm_ccm->md_nameformat) { case CFM_CCM_MD_FORMAT_DNS: case CFM_CCM_MD_FORMAT_CHAR: safeputs(ndo, msg_ptr.cfm_ccm->md_name, msg_ptr.cfm_ccm->md_namelength); break; case CFM_CCM_MD_FORMAT_MAC: ND_PRINT((ndo, "\n\t MAC %s", etheraddr_string(ndo, msg_ptr.cfm_ccm->md_name))); break; /* FIXME add printers for those MD formats - hexdump for now */ case CFM_CCM_MA_FORMAT_8021: default: print_unknown_data(ndo, msg_ptr.cfm_ccm->md_name, "\n\t ", msg_ptr.cfm_ccm->md_namelength); } } /* * Resolve the MA fields. */ ma_nameformat = msg_ptr.cfm_ccm->md_name + msg_ptr.cfm_ccm->md_namelength; ma_namelength = msg_ptr.cfm_ccm->md_name + msg_ptr.cfm_ccm->md_namelength + 1; ma_name = msg_ptr.cfm_ccm->md_name + msg_ptr.cfm_ccm->md_namelength + 2; ND_PRINT((ndo, "\n\t MA Name-Format %s (%u), MA name length %u", tok2str(cfm_ma_nameformat_values, "Unknown", *ma_nameformat), *ma_nameformat, *ma_namelength)); ND_PRINT((ndo, "\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; ND_PRINT((ndo, ", Flags [%s]", bittok2str(cfm_ltm_flag_values, "none", cfm_common_header->flags))); ND_PRINT((ndo, "\n\t Transaction-ID 0x%08x, Egress-ID %s, ttl %u", EXTRACT_32BITS(msg_ptr.cfm_ltm->transaction_id), cfm_egress_id_string(ndo, msg_ptr.cfm_ltm->egress_id), msg_ptr.cfm_ltm->ttl)); ND_PRINT((ndo, "\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; ND_PRINT((ndo, ", Flags [%s]", bittok2str(cfm_ltr_flag_values, "none", cfm_common_header->flags))); ND_PRINT((ndo, "\n\t Transaction-ID 0x%08x, Last-Egress-ID %s", EXTRACT_32BITS(msg_ptr.cfm_ltr->transaction_id), cfm_egress_id_string(ndo, msg_ptr.cfm_ltr->last_egress_id))); ND_PRINT((ndo, "\n\t Next-Egress-ID %s, ttl %u", cfm_egress_id_string(ndo, msg_ptr.cfm_ltr->next_egress_id), msg_ptr.cfm_ltr->ttl)); ND_PRINT((ndo, "\n\t Replay-Action %s (%u)", tok2str(cfm_ltr_replay_action_values, "Unknown", msg_ptr.cfm_ltr->replay_action), 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: if (tlen > cfm_common_header->first_tlv_offset) { print_unknown_data(ndo, tptr, "\n\t ", tlen - cfm_common_header->first_tlv_offset); } break; } /* * Sanity check for not walking off. */ if (tlen <= cfm_common_header->first_tlv_offset) { return; } tptr += cfm_common_header->first_tlv_offset; tlen -= cfm_common_header->first_tlv_offset; while (tlen > 0) { cfm_tlv_header = (const struct cfm_tlv_header_t *)tptr; /* Enough to read the tlv type ? */ ND_TCHECK2(*tptr, 1); cfm_tlv_type=cfm_tlv_header->type; if (cfm_tlv_type != CFM_TLV_END) { /* did we capture enough for fully decoding the object header ? */ ND_TCHECK2(*tptr, sizeof(struct cfm_tlv_header_t)); cfm_tlv_len=EXTRACT_16BITS(&cfm_tlv_header->length); } else { cfm_tlv_len = 0; } ND_PRINT((ndo, "\n\t%s TLV (0x%02x), length %u", tok2str(cfm_tlv_values, "Unknown", cfm_tlv_type), cfm_tlv_type, cfm_tlv_len)); /* sanity check for not walking off and infinite loop check. */ if ((cfm_tlv_type != CFM_TLV_END) && ((cfm_tlv_len + sizeof(struct cfm_tlv_header_t) > tlen) || (!cfm_tlv_len))) { print_unknown_data(ndo, tptr, "\n\t ", tlen); return; } tptr += sizeof(struct cfm_tlv_header_t); tlen -= sizeof(struct cfm_tlv_header_t); tlv_ptr = tptr; /* did we capture enough for fully decoding the object ? */ if (cfm_tlv_type != CFM_TLV_END) { ND_TCHECK2(*tptr, cfm_tlv_len); } hexdump = FALSE; switch(cfm_tlv_type) { case CFM_TLV_END: /* we are done - bail out */ return; case CFM_TLV_PORT_STATUS: ND_PRINT((ndo, ", Status: %s (%u)", tok2str(cfm_tlv_port_status_values, "Unknown", *tptr), *tptr)); break; case CFM_TLV_INTERFACE_STATUS: ND_PRINT((ndo, ", Status: %s (%u)", tok2str(cfm_tlv_interface_status_values, "Unknown", *tptr), *tptr)); break; case CFM_TLV_PRIVATE: ND_PRINT((ndo, ", Vendor: %s (%u), Sub-Type %u", tok2str(oui_values,"Unknown", EXTRACT_24BITS(tptr)), EXTRACT_24BITS(tptr), *(tptr + 3))); hexdump = TRUE; break; case CFM_TLV_SENDER_ID: { u_int chassis_id_type, chassis_id_length; u_int mgmt_addr_length; /* * Check if there is a Chassis-ID. */ chassis_id_length = *tptr; if (chassis_id_length > tlen) { hexdump = TRUE; break; } tptr++; tlen--; if (chassis_id_length) { chassis_id_type = *tptr; ND_PRINT((ndo, "\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)); switch (chassis_id_type) { case CFM_CHASSIS_ID_MAC_ADDRESS: ND_PRINT((ndo, "\n\t MAC %s", etheraddr_string(ndo, tptr + 1))); break; case CFM_CHASSIS_ID_NETWORK_ADDRESS: hexdump |= cfm_mgmt_addr_print(ndo, tptr); 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; } } tptr += chassis_id_length; tlen -= chassis_id_length; /* * Check if there is a Management Address. */ mgmt_addr_length = *tptr; if (mgmt_addr_length > tlen) { hexdump = TRUE; break; } tptr++; tlen--; if (mgmt_addr_length) { hexdump |= cfm_mgmt_addr_print(ndo, tptr); } 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); tptr+=cfm_tlv_len; tlen-=cfm_tlv_len; } return; trunc: ND_PRINT((ndo, "\n\t\t packet exceeded snapshot")); }
/** * main: main function for dcon * * flags: * -a <addr> listen on specific IP address (default INADDR_ANY) * -p <port> listen on the specified port (default to random port) * -f <fmt> output format code (default 'dhtflm') * * format letters: * d=date, h=host, H=host w/domain stripped, t=tag, * f=facility, l=level, m=message, s=src_ip * * -l <log> logfile output is copied to (default=none) */ int main(int argc, char **argv) { char *ipstr, *portstr; static const char *fmt = "dhtflm"; char *logfile; int c, errflg, len; socklen_t slen; struct sockaddr_in ip; struct hostent *he; int udpsock; #define BIG (1024*1024) char bigbuf[BIG], tmpbuf[64]; char *chunks[6]; const char *f; char *ptr; errflg = 0; ipstr = portstr = logfile = 0; while ((c = getopt(argc, argv, "a:p:f:l:")) != -1) { switch (c) { case 'a': ipstr = optarg; break; case 'p': if (*optarg < '0' || *optarg > '9') { fprintf(stderr, "invalid port: %s\n", optarg); errflg++; } portstr = optarg; break; case 'f': fmt = optarg; break; case 'l': logfile = optarg; break; case '?': fprintf(stderr, "unknown option: -%c\n", optopt); errflg++; break; } } if (errflg) { fprintf(stderr, "usage: %s [options]\n", *argv); fprintf(stderr, "\t-a <addr> listen on addr (default=INADDR_ANY)\n"); fprintf(stderr, "\t-p <port> listen on port (default=random)\n"); fprintf(stderr, "\t-f <fmt> output format\n"); fprintf(stderr, "\t-l <log> output logfile\n"); fprintf(stderr, "\n\tformat: d=date, h=host, H=host (no domain),\n"); fprintf(stderr, "\tt=tag, f=facility, l=level, m=message, s=src_ip\n"); exit(1); } /* * start parsing */ memset(&ip, 0, sizeof(ip)); ip.sin_family = AF_INET; if (!ipstr) { ip.sin_addr.s_addr = INADDR_ANY; } else { if (*ipstr >= '0' && *ipstr <= '9') { ip.sin_addr.s_addr = inet_addr(ipstr); if (ip.sin_addr.s_addr == 0 || ip.sin_addr.s_addr == ((in_addr_t) -1)) { fprintf(stderr, "dcon: invalid host %s\n", ipstr); exit(1); } } else { he = gethostbyname(ipstr); if (!he || he->h_addrtype != AF_INET || he->h_length != sizeof(in_addr_t) || !he->h_addr) { fprintf(stderr, "dcon: invalid host %s\n", ipstr); exit(1); } memcpy(&ip.sin_addr.s_addr, he->h_addr, he->h_length); } } if (portstr) { ip.sin_port = htons(atoi(portstr)); } if (logfile) { logfp = fopen(logfile, "a"); if (!logfp) { fprintf(stderr, "fopen: %s: %s\n", logfile, strerror(errno)); exit(1); } } /* * setup udp socket */ udpsock = socket(PF_INET, SOCK_DGRAM, 0); if (udpsock < 0) { } if (bind(udpsock, (struct sockaddr *)&ip, sizeof(ip)) < 0) { fprintf(stderr, "dcon: bind: %s\n", strerror(errno)); exit(1); } slen = sizeof(ip); if (getsockname(udpsock, (struct sockaddr *)&ip, &slen) < 0) { fprintf(stderr, "dcon: getsockname: %s\n", strerror(errno)); exit(1); } printf("dcon listening on %s:%d, logfile=%s, format=%s\n", (ip.sin_addr.s_addr == INADDR_ANY) ? "*" : inet_ntoa(ip.sin_addr), ntohs(ip.sin_port), logfile ? logfile : "<none>", fmt); /* * signal handlers. */ (void) signal(SIGUSR1, truncatelog); (void) signal(SIGUSR2, flushlog); (void) signal(SIGINT, exitlog); (void) signal(SIGTERM, exitlog); /* * main loop */ while (1) { slen = sizeof(ip); len = recvfrom(udpsock, bigbuf, BIG-1, 0, (struct sockaddr *)&ip, &slen); if (len <= 0) { if (errno == EINTR) continue; if (len == 0) fprintf(stderr, "recvfrom: returned zero/EOF?\n"); else fprintf(stderr, "recvfrom: %s\n", strerror(errno)); break; } /* ensure null terminated */ bigbuf[len] = 0; /* get rid of the trailing \n */ if (bigbuf[len-1] == '\n') bigbuf[len-1] = 0; if (bigbuf[0] < '0' || bigbuf[0] > '9') { safeputs("INVALID-MSG: "); safeputs(bigbuf); } if (stringsplit(bigbuf, 6, chunks) < 0) { safeputs("PARSE-ERR: "); safeputs(bigbuf); } for (f = fmt ; *f ; f++) { if (f != fmt) safeputs(" "); switch (*f) { case 'd': /* date */ safeputs(chunks[MR_DATE]); break; case 'h': /* host */ safeputs(chunks[MR_HOST]); break; case 'H': /* host (no domain) */ ptr = chunks[MR_HOST]; while (*ptr) { if (*ptr == '.') { *ptr = 0; break; } ptr++; } safeputs(chunks[MR_HOST]); break; case 't': /* tag */ safeputs(chunks[MR_TAG]); break; case 'f': /* facility */ safeputs(chunks[MR_FAC]); break; case 'l': /* level */ safeputs(chunks[MR_LVL]); break; case 'm': /* message */ safeputs(chunks[MR_MSG]); break; case 's': /* source IP */ snprintf(tmpbuf, sizeof(tmpbuf), "%s:%d", inet_ntoa(ip.sin_addr), ntohs(ip.sin_port)); safeputs(tmpbuf); break; default: break; } } safeputs("\n"); } if (logfp) { fflush(logfp); fclose(logfp); } exit(1); }
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); }