#include "icmp.h" #include "icmp_types.h" #include "internal/icmp_packet.h" #include "internal/icmp_packet_internal.h" #include #include #define MIN_ERROR_PAYLOAD_LEN 28 #define MIN_ICMP_HEADER_LEN 8 /* Forward declarations */ static int is_error_type(uint8_t type); static int is_echo_type(uint8_t type); static int is_frag_needed(uint8_t type, uint8_t code); static int parse_embedded_ip(const icmp_reply_t *reply, icmp_offending_packet_t *offending, size_t *ip_hdr_len); static const struct icmp_header *get_embedded_icmp(const icmp_reply_t *reply, size_t ip_hdr_len); static void extract_icmp_fields(const struct icmp_header *hdr, icmp_offending_packet_t *offending); /* -------------------- */ int icmp_error_extract_offending(const icmp_reply_t *reply, icmp_offending_packet_t *offending) { size_t ip_hdr_len; const struct icmp_header *hdr; if ((NULL == reply || NULL == offending) || (!is_error_type(reply->type)) || (reply->payload_len < MIN_ERROR_PAYLOAD_LEN) || (parse_embedded_ip(reply, offending, &ip_hdr_len) < 0) || (reply->payload_len < ip_hdr_len + MIN_ICMP_HEADER_LEN)) return -1; hdr = get_embedded_icmp(reply, ip_hdr_len); extract_icmp_fields(hdr, offending); return 0; } static int is_error_type(uint8_t type) { return ICMP_TYPE_DEST_UNREACHABLE == type || ICMP_TYPE_REDIRECT == type || ICMP_TYPE_TIME_EXCEEDED == type || ICMP_TYPE_PARAMETER_PROBLEM == type; } static int is_echo_type(uint8_t type) { return ICMP_TYPE_ECHO_REPLY == type || ICMP_TYPE_ECHO_REQUEST == type || ICMP_TYPE_TIMESTAMP_REQUEST == type || ICMP_TYPE_TIMESTAMP_REPLY == type; } static int is_frag_needed(uint8_t type, uint8_t code) { return ICMP_TYPE_DEST_UNREACHABLE == type && ICMP_CODE_FRAG_NEEDED == code; } static int parse_embedded_ip(const icmp_reply_t *reply, icmp_offending_packet_t *offending, size_t *ip_hdr_len) { return icmp_parse_ip_header(reply->payload, reply->payload_len, NULL, &offending->src, ip_hdr_len, &offending->dst, &offending->protocol); } static const struct icmp_header * get_embedded_icmp(const icmp_reply_t *reply, size_t ip_hdr_len) { return (const struct icmp_header *)((const uint8_t *)reply->payload + ip_hdr_len); } static void extract_icmp_fields(const struct icmp_header *hdr, icmp_offending_packet_t *offending) { offending->icmp_type = hdr->type; offending->icmp_code = hdr->code; offending->rest.gateway = hdr->un.gateway; if (is_echo_type(hdr->type)) { offending->rest.echo.id = ntohs(hdr->un.echo.id); offending->rest.echo.seq = ntohs(hdr->un.echo.seq); } else if (is_frag_needed(hdr->type, hdr->code)) { offending->rest.frag.mtu = ntohs(hdr->un.frag.mtu); } }