icmp_time_exceeded* IcmpLayer::setTimeExceededData(uint8_t code, IPv4Layer* ipHeader, Layer* l4Header) { if (code > 1) { LOG_ERROR("Unknown code %d for ICMP time exceeded data", (int)code); return NULL; } if (!cleanIcmpLayer()) return NULL; if (!this->extendLayer(m_DataLen, sizeof(icmp_time_exceeded) - sizeof(icmphdr))) return NULL; getIcmpHeader()->type = (uint8_t)ICMP_TIME_EXCEEDED; icmp_time_exceeded* header = getTimeExceededData(); header->code = code; header->unused = 0; if (!setIpAndL4Layers(ipHeader, l4Header)) return NULL; return header; }
bool IcmpLayer::setEchoData(IcmpMessageType echoType, uint16_t id, uint16_t sequence, uint64_t timestamp, const uint8_t* data, size_t dataLen) { if (!cleanIcmpLayer()) return false; if (!this->extendLayer(m_DataLen, sizeof(icmp_echo_hdr) - sizeof(icmphdr) + dataLen)) return false; getIcmpHeader()->type = (uint8_t)echoType; icmp_echo_request* header = NULL; if (echoType == ICMP_ECHO_REQUEST) header = getEchoRequestData(); else if (echoType == ICMP_ECHO_REPLY) header = (icmp_echo_request*)getEchoReplyData(); else return false; header->header->code = 0; header->header->checksum = 0; header->header->id = htons(id); header->header->sequence = htons(sequence); header->header->timestamp = timestamp; if (data != NULL && dataLen > 0) memcpy(header->data, data, dataLen); return true; }
icmp_param_problem* IcmpLayer::setParamProblemData(uint8_t code, uint8_t errorOctetPointer, IPv4Layer* ipHeader, Layer* l4Header) { if (code > 2) { LOG_ERROR("Unknown code %d for ICMP parameter problem data", (int)code); return NULL; } if (!cleanIcmpLayer()) return NULL; if (!this->extendLayer(m_DataLen, sizeof(icmp_param_problem) - sizeof(icmphdr))) return NULL; getIcmpHeader()->type = (uint8_t)ICMP_PARAM_PROBLEM; icmp_param_problem* header = getParamProblemData(); header->code = code; header->unused1 = 0; header->unused2 = 0; header->pointer = errorOctetPointer; if (!setIpAndL4Layers(ipHeader, l4Header)) return NULL; return header; }
icmp_router_advertisement* IcmpLayer::setRouterAdvertisementData(uint8_t code, uint16_t lifetimeInSeconds, const std::vector<icmp_router_address_structure>& routerAddresses) { if (code != 0 && code != 16) { LOG_ERROR("Unknown code %d for ICMP router advertisement data (only codes 0 and 16 are legal)", (int)code); return NULL; } if (!cleanIcmpLayer()) return NULL; if (!this->extendLayer(m_DataLen, sizeof(icmp_router_advertisement_hdr) + (routerAddresses.size()*sizeof(icmp_router_address_structure)) - sizeof(icmphdr))) return NULL; getIcmpHeader()->type = (uint8_t)ICMP_ROUTER_ADV; icmp_router_advertisement* header = getRouterAdvertisementData(); header->header->code = code; header->header->lifetime = htons(lifetimeInSeconds); header->header->advertisementCount = (uint8_t)routerAddresses.size(); header->header->addressEntrySize = 2; icmp_router_address_structure* curPos = (icmp_router_address_structure*)((uint8_t*)header->header + sizeof(icmp_router_advertisement_hdr)); for (std::vector<icmp_router_address_structure>::const_iterator iter = routerAddresses.begin(); iter != routerAddresses.end(); iter++) { curPos->routerAddress = iter->routerAddress; curPos->preferenceLevel = iter->preferenceLevel; curPos += 1; } return header; }
icmp_redirect* IcmpLayer::setRedirectData(uint8_t code, IPv4Address gatewayAddress, IPv4Layer* ipHeader, Layer* l4Header) { if (code > 3) { LOG_ERROR("Unknown code %d for ICMP redirect data", (int)code); return NULL; } if (!cleanIcmpLayer()) return NULL; if (!this->extendLayer(m_DataLen, sizeof(icmp_redirect) - sizeof(icmphdr))) return NULL; getIcmpHeader()->type = (uint8_t)ICMP_REDIRECT; icmp_redirect* header = getRedirectData(); header->code = code; header->gatewayAddress = gatewayAddress.toInt(); if (!setIpAndL4Layers(ipHeader, l4Header)) return NULL; return header; }
IcmpMessageType IcmpLayer::getMessageType() { uint8_t type = getIcmpHeader()->type; if (type > 18) return ICMP_UNSUPPORTED; return (IcmpMessageType)type; }
void IcmpLayer::computeCalculateFields() { // calculate checksum getIcmpHeader()->checksum = 0; size_t icmpLen = 0; Layer* curLayer = this; while (curLayer != NULL) { icmpLen += curLayer->getHeaderLen(); curLayer = curLayer->getNextLayer(); } ScalarBuffer<uint16_t> buffer; buffer.buffer = (uint16_t*)getIcmpHeader(); buffer.len = icmpLen; size_t checksum = compute_checksum(&buffer, 1); getIcmpHeader()->checksum = htons(checksum); }
icmp_router_solicitation* IcmpLayer::setRouterSolicitationData() { if (!cleanIcmpLayer()) return NULL; getIcmpHeader()->type = (uint8_t)ICMP_ROUTER_SOL; icmp_router_solicitation* header = getRouterSolicitationData(); header->code = 0; return header; }
icmp_info_reply* IcmpLayer::setInfoReplyData(uint16_t id, uint16_t sequence) { if (!cleanIcmpLayer()) return NULL; if (!this->extendLayer(m_DataLen, sizeof(icmp_info_reply) - sizeof(icmphdr))) return NULL; getIcmpHeader()->type = (uint8_t)ICMP_INFO_REPLY; icmp_info_reply* header = getInfoReplyData(); header->code = 0; header->id = htons(id); header->sequence = htons(sequence); return header; }
icmp_address_mask_reply* IcmpLayer::setAddressMaskReplyData(uint16_t id, uint16_t sequence, IPv4Address mask) { if (!cleanIcmpLayer()) return NULL; if (!this->extendLayer(m_DataLen, sizeof(icmp_address_mask_reply) - sizeof(icmphdr))) return NULL; getIcmpHeader()->type = (uint8_t)ICMP_ADDRESS_MASK_REPLY; icmp_address_mask_reply* header = getAddressMaskReplyData(); header->code = 0; header->id = htons(id); header->sequence = htons(sequence); header->addressMask = htonl(mask.toInt()); return header; }
icmp_source_quench* IcmpLayer::setSourceQuenchdata(IPv4Layer* ipHeader, Layer* l4Header) { if (!cleanIcmpLayer()) return NULL; if (!this->extendLayer(m_DataLen, sizeof(icmp_source_quench) - sizeof(icmphdr))) return NULL; getIcmpHeader()->type = (uint8_t)ICMP_SOURCE_QUENCH; icmp_source_quench* header = getSourceQuenchdata(); header->unused = 0; if (!setIpAndL4Layers(ipHeader, l4Header)) return NULL; return header; }
icmp_destination_unreachable* IcmpLayer::setDestUnreachableData(IcmpDestUnreachableCodes code, uint16_t nextHopMTU, IPv4Layer* ipHeader, Layer* l4Header) { if (!cleanIcmpLayer()) return NULL; if (!this->extendLayer(m_DataLen, sizeof(icmp_destination_unreachable) - sizeof(icmphdr))) return NULL; getIcmpHeader()->type = (uint8_t)ICMP_DEST_UNREACHABLE; icmp_destination_unreachable* header = getDestUnreachableData(); header->code = code; header->nextHopMTU = htons(nextHopMTU); header->unused = 0; if (!setIpAndL4Layers(ipHeader, l4Header)) return NULL; return header; }
icmp_timestamp_request* IcmpLayer::setTimestampRequestData(uint16_t id, uint16_t sequence, timeval originateTimestamp) { if (!cleanIcmpLayer()) return NULL; if (!this->extendLayer(m_DataLen, sizeof(icmp_timestamp_request) - sizeof(icmphdr))) return NULL; getIcmpHeader()->type = (uint8_t)ICMP_TIMESTAMP_REQUEST; icmp_timestamp_request* header = getTimestampRequestData(); header->code = 0; header->id = htons(id); header->sequence = htons(sequence); header->originateTimestamp = htonl(originateTimestamp.tv_sec*1000 + originateTimestamp.tv_usec/1000); header->receiveTimestamp = 0; header->transmitTimestamp = 0; return header; }
std::string IcmpLayer::toString() { std::string messageTypeAsString; IcmpMessageType type = getMessageType(); switch (type) { case ICMP_ECHO_REPLY: messageTypeAsString = "Echo (ping) reply"; break; case ICMP_DEST_UNREACHABLE: messageTypeAsString = "Destination unreachable"; break; case ICMP_SOURCE_QUENCH: messageTypeAsString = "Source quench (flow control)"; break; case ICMP_REDIRECT: messageTypeAsString = "Redirect"; break; case ICMP_ECHO_REQUEST: messageTypeAsString = "Echo (ping) request"; break; case ICMP_ROUTER_ADV: messageTypeAsString = "Router advertisement"; break; case ICMP_ROUTER_SOL: messageTypeAsString = "Router solicitation"; break; case ICMP_TIME_EXCEEDED: messageTypeAsString = "Time-to-live exceeded"; break; case ICMP_PARAM_PROBLEM: messageTypeAsString = "Parameter problem: bad IP header"; break; case ICMP_TIMESTAMP_REQUEST: messageTypeAsString = "Timestamp request"; break; case ICMP_TIMESTAMP_REPLY: messageTypeAsString = "Timestamp reply"; break; case ICMP_INFO_REQUEST: messageTypeAsString = "Information request"; break; case ICMP_INFO_REPLY: messageTypeAsString = "Information reply"; break; case ICMP_ADDRESS_MASK_REQUEST: messageTypeAsString = "Address mask request"; break; case ICMP_ADDRESS_MASK_REPLY: messageTypeAsString = "Address mask reply"; break; default: messageTypeAsString = "Unknown"; break; } std::ostringstream typeStream; typeStream << (int)getIcmpHeader()->type; return "ICMP Layer, " + messageTypeAsString + " (type: " + typeStream.str() + ")"; }
int processPacket (struct pcap_pkthdr *h, /* Captured stuff */ u_char *pp, /* packet pointer */ nfs_pkt_t *record ) { struct ip *ip_b = NULL; struct tcphdr *tcp_b = NULL; struct udphdr *udp_b = NULL; u_int32_t tot_len = h->caplen; u_int32_t consumed = 0; u_int32_t src_port = 0; u_int32_t dst_port = 0; u_int16_t id; int e_len, i_len, h_len; u_int32_t rpc_len; unsigned int length; u_int32_t srcHost, dstHost; unsigned int proto; if (OutFile == NULL) { OutFile = stdout; } /* * It doesn't make any sense to run this program with a small * caplen (aka snap length) because the important stuff will * get lost. * * Too-short packets *should* never happen, since the min * packet length is longer than this, but it's always better * to be safe than to be sucker-punched by a bug elsewhere... */ if (tot_len <= (MIN_ETHER_HDR_LEN + MIN_IP_HDR_LEN + MIN_UDP_HDR_LEN)) { return (0); } e_len = getEtherHeader (tot_len, pp, &proto, &length); if (e_len <= 0) { return (-1); } consumed += e_len; /* * If the type of the packet isn't IP, then we're not * interested in it-- chuck it now. * * Note-- ordinarily by the time we get here, we've already * filtered out the packets using a pattern in the pcap * library, so this shouldn't happen (unless we are running * off a capture of the entire traffic on the wire). */ if (proto != 0x0800) { return (0); } ip_b = (struct ip *) (pp + e_len); i_len = getIpHeader (ip_b, &proto, &id, &length, &srcHost, &dstHost); if (i_len <= 0) { return (-2); } record->ipLen = length; record->ipIdentifier = id; consumed += i_len; /* * Truncated packet-- what's up with that? At this point, * this can only happen if the packet is very short and the IP * options are very long. Still, must be cautious... */ if (consumed >= tot_len) { return (0); } if (proto == IPPROTO_TCP) { if (consumed + MIN_TCP_HDR_LEN >= tot_len) { /* fprintf (OutFile, "XX 1: TCP pkt too short.\n"); */ return (0); } tcp_b = (struct tcphdr *) (pp + consumed); h_len = getTcpHeader (tcp_b); if (h_len <= 0) { /* fprintf (OutFile, "XX 2: TCP header error\n"); */ return (-3); } consumed += h_len; if (consumed >= tot_len) { /* fprintf (OutFile, */ /* "XX 3: Dropped (consumed = %d, tot_len = %d)\n", */ /* consumed, tot_len); */ return (0); } h_len += sizeof (u_int32_t); src_port = ntohs (tcp_b->th_sport); dst_port = ntohs (tcp_b->th_dport); record->ipProto = 'T'; } else if (proto == IPPROTO_UDP) { if (consumed + MIN_UDP_HDR_LEN >= tot_len) { return (0); } udp_b = (struct udphdr *) (pp + consumed); h_len = getUdpHeader (udp_b); if (h_len <= 0) { return (-4); } consumed += h_len; if (consumed >= tot_len) { return (0); } src_port = ntohs (udp_b->uh_sport); dst_port = ntohs (udp_b->uh_dport); rpc_len = tot_len - consumed; record->ipProto = 'U'; } else if (proto == IPPROTO_ICMP) { struct icmp *icmp_b; if (consumed + sizeof(struct icmp) >= tot_len) { return (0); } icmp_b = (struct icmp *) (pp + consumed); h_len = getIcmpHeader (icmp_b); record->ipProto = 'C'; record->icmpType = icmp_b->icmp_type; if (icmp_b->icmp_type == ICMP_ECHO) { memmove(record->icmpPayload, (pp + consumed + sizeof(struct icmp)), 16); } } else { /* * If it's not TCP, UPD, or ICMP, then no matter what * it is, we don't care about it, so just ignore it. */ /* fprintf (OutFile, "XX 5: Not TCP or UDP.\n"); */ return (0); } /* * If we get to this point, there's a good chance this packet * contains something interesting, so we start filling in the * fields of the record immediately. */ record->secs = h->ts.tv_sec; record->usecs = h->ts.tv_usec; record->srcHost = srcHost; record->dstHost = dstHost; record->srcPort = src_port; record->dstPort = dst_port; record->ipLen = length; printPacketHeader(record, stdout); return 0; }