Discussion:
IPv4 header and memory alignment...
(too old to reply)
TDH1978
2019-03-11 22:57:42 UTC
Permalink
This question is in regards to the iphdr struct that can be found in
/usr/include/linux/ip.h and /usr/include/netinet/ip.h.  In some
open-source projects, I have seen this header mapped onto packet data,
to extract individual IPv4 header fields, like so:


    struct iphdr
    {
        unsigned int ihl:4;
        unsigned int version:4;
        uint8_t tos;
        uint16_t tot_len;
        uint16_t id;
        uint16_t frag_off;
        uint8_t ttl;
        uint8_t protocol;
        uint16_t check;
        uint32_t saddr;
        uint32_t daddr;
    };


    struct iphdr* hdr = (struct iphdr*) packet_data;
  
    uint32_t ipv4_src_addr = hdr->saddr;
    uint32_t ipv4_dst_addr = hdr->daddr;
   
   
Is this safe?  Given that the packet data could start at any memory
location, what guarantee is there that the 32-bit 'saddr' and 'daddr'
fields are properly aligned in memory at 32-bit boundaries?
Jorgen Grahn
2019-03-12 09:20:52 UTC
Permalink
Post by TDH1978
This question is in regards to the iphdr struct that can be found in
/usr/include/linux/ip.h and /usr/include/netinet/ip.h.  In some
open-source projects, I have seen this header mapped onto packet data,
    struct iphdr
    {
        unsigned int ihl:4;
        unsigned int version:4;
        uint8_t tos;
        uint16_t tot_len;
        uint16_t id;
        uint16_t frag_off;
        uint8_t ttl;
        uint8_t protocol;
        uint16_t check;
        uint32_t saddr;
        uint32_t daddr;
    };
    struct iphdr* hdr = (struct iphdr*) packet_data;
  
    uint32_t ipv4_src_addr = hdr->saddr;
    uint32_t ipv4_dst_addr = hdr->daddr;
   
   
Is this safe?  Given that the packet data could start at any memory
location, what guarantee is there that the 32-bit 'saddr' and 'daddr'
fields are properly aligned in memory at 32-bit boundaries?
In the Linux kernel, they make sure it's safe by aligning that memory,
and knowing things about how the compiler treats structs, more than
what the C language guarantees.

In my own code, I prefer not to rely on such things. It gets messy,
and you still need to take care of endianness. I write my own accessor
functions instead:

/* assuming buf points to a full IPv4 header
*/
struct in_addr get_saddr(const unsigned char* buf);

As a bonus, you get a better type than uint32_t.

/Jorgen
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
TDH1978
2019-03-15 01:37:46 UTC
Permalink
Post by Jorgen Grahn
In the Linux kernel, they make sure it's safe by aligning that memory,
and knowing things about how the compiler treats structs, more than
what the C language guarantees.
In my own code, I prefer not to rely on such things. It gets messy,
and you still need to take care of endianness. I write my own accessor
/* assuming buf points to a full IPv4 header
*/
struct in_addr get_saddr(const unsigned char* buf);
As a bonus, you get a better type than uint32_t.
Thank you for your reply. I agree your method is safer but I assume
that, by calling your accessor functions, you will incur a slight
run-time overhead. If you do this for, say, a billion incoming
packets, this overhead may become significant.
Jorgen Grahn
2019-03-15 14:04:02 UTC
Permalink
Post by TDH1978
Post by Jorgen Grahn
In the Linux kernel, they make sure it's safe by aligning that memory,
and knowing things about how the compiler treats structs, more than
what the C language guarantees.
In my own code, I prefer not to rely on such things. It gets messy,
and you still need to take care of endianness. I write my own accessor
/* assuming buf points to a full IPv4 header
*/
struct in_addr get_saddr(const unsigned char* buf);
As a bonus, you get a better type than uint32_t.
Thank you for your reply. I agree your method is safer but I assume
that, by calling your accessor functions, you will incur a slight
run-time overhead. If you do this for, say, a billion incoming
packets, this overhead may become significant.
Probably only if you're writing an IP stack. If you act on the
information you extract I think that processing cost will quickly
overshadow this inefficiency in the parsing.

Profiling might be a good idea.

/Jorgen
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
Loading...