libicmp/src/packet/parse_ip.c

71 lines
1.5 KiB
C

#include "internal/icmp_packet_internal.h"
#include "internal/icmp_packet.h"
#include <netinet/in.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
/* Minimum IP header size */
#define MIN_IP_HEADER_SIZE 20
/* Forward declarations */
static int validate_ip_header(const struct ip_header *hdr, size_t buffer_len);
static size_t extract_ip_header_length(uint8_t version_ihl);
/* -------------------- */
int
icmp_parse_ip_header(const void *buffer, size_t buffer_len, uint8_t *ttl,
struct in_addr *src_addr, size_t *ip_hdr_len,
struct in_addr *dst_addr, uint8_t *protocol)
{
const struct ip_header *h;
size_t ihl_bytes;
if (buffer_len < MIN_IP_HEADER_SIZE)
return -1;
h = (const struct ip_header *)buffer;
ihl_bytes = extract_ip_header_length(h->version_ihl);
if (0 != validate_ip_header(h, buffer_len))
return -1;
if (ttl)
*ttl = h->ttl;
if (src_addr)
src_addr->s_addr = h->saddr;
if (dst_addr)
dst_addr->s_addr = h->daddr;
if (protocol)
*protocol = h->protocol;
if (ip_hdr_len)
*ip_hdr_len = ihl_bytes;
return 0;
}
static int
validate_ip_header(const struct ip_header *hdr, size_t buffer_len)
{
uint8_t ihl;
size_t header_len;
if (4 != (hdr->version_ihl >> 4))
return -1;
ihl = hdr->version_ihl & 0x0F;
if (ihl < 5)
return -1;
header_len = (size_t)(ihl << 2);
if (header_len > buffer_len)
return -1;
return 0;
}
static size_t
extract_ip_header_length(uint8_t version_ihl)
{
return (size_t)((version_ihl & 0x0F) << 2);
}