Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fields in a struct skipping bytes

I have a struct I have written which is supposed to represent an entire UDP packet, with the ethernet header and all. Here it is:

#pragma pack(1)
struct UDPPacket {
    // an array to hold the destination mac address of the packet
    unsigned char dstmac[6];

    // an array to hold the source mac address of the packet
    unsigned char srcmac[6];

    // two bytes to hold the packet type, this is almost always IP (08 00)
    WORD ethtype;

    // each of the subfields of this take up 4 bits. ver, the first half,
    // is the ip version, which should usually be 4 for ipv4, and the second
    // is the length of the header divided by 4, which is almost always 5
    struct {
        unsigned ver : 4;
        unsigned len : 4;
    } verlen;

    // this isn't used in ipv4 and is 0
    BYTE tos;

    // the total length of the header + data
    WORD iplen;

    // the id of this datagram for reassembling fragmented packets
    WORD id;

    // the first subfield occupies 3 bits and is the flags of this packet, which is usually 0
    // the second subfield is the fragmentation offset for large datagrams that have been split up for sending, usually 0
    struct {
        unsigned flags : 3;
        unsigned fragmentation : 13;
    } flagfrag;

    // time to live; usually 35 or 128
    BYTE ttl;

    // the protocol with which this packet is being transported
    // 1 = ICMP, 2 = IGMP, 6 = TCP, 17 = UDP
    BYTE protocol;

    // the ip checksum of this packet
    WORD ipchecksum;

    // the source ip of this packet
    DWORD src;

    // the destination ip of this packet
    DWORD dest;
    // the port from which this packet is coming
    WORD srcport;

    // the port this packet is headed to
    WORD destport;

    // the length of the udp header + data, not including the ip header
    // so it's usually basically iplen - 20
    WORD udplen;

    // the udp checksum of this packet
    WORD udpchecksum;

    // a char pointer to the data of the packet
    unsigned char data[10000];
};
#pragma pack()

Of course, this being a representation of a real UDP packet, the bytes have to be at the same offset as they would be in a packet, and pointers to this type of struct will be cast to unsigned char*s for sending.
My problem is that when I try to assign anything after UDPPacket.verlen, it skips ahead about 5 bytes and starts there. For instance, when I assign the iplen feild, rather than setting the bytes at offsets 16 and 17, it assigns them at something like 23 and 24 (I can't say exactly because I don't have my program available here on my phone).
Is there an apparent reason for this that I'm missing, or did I just do something wrong?

like image 229
Hock Avatar asked Sep 11 '26 12:09

Hock


1 Answers

Your #pragmas look right. Bitfields don't "auto-pack" to the smallest type that fits the number of bits explicitly specified. I suspect that verlen is taking your given type "unsigned" and assuming that it's a bitfiend of size unsigned int, which sounds like 32 bits in your compiler. Try making the fields of verlen "unsigned char" instead.

More here. The ability to specify "unsigned char" here is an MSFT extension (to ANSI C), but should work: http://msdn.microsoft.com/en-us/library/yszfawxh(VS.80).aspx

N.B. Same here goes for flagfrag, which should be "unsigned short".

like image 112
Ben Zotto Avatar answered Sep 13 '26 02:09

Ben Zotto