libicmp/src/recv/api/extract_offending.c
2026-02-07 11:15:42 +01:00

99 lines
2.7 KiB
C

#include "icmp.h"
#include "icmp_types.h"
#include "internal/icmp_packet.h"
#include "internal/icmp_packet_internal.h"
#include <netinet/in.h>
#include <stdint.h>
#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);
}
}