結構體邊界對齊問題

結構體邊界對齊問題

在構造DNS應答包的Answer字段時,我定義了一個結構體,如下所示:

typedef struct{
    __u16 name;
    __u16 type;
    __u16 class;
    __u32 ttl;
    __u16 length;
    __u32 ipv4_addr;
}DNS_ANSWER_DATA;

但是在進行數據包的構造的時候,在測試時,發送的數據包總是從length字段開始出現錯誤,導致DNS數據報文最終不能被正確解析,原因在於結構體的邊界對其原則。
在debug的時候發現,sizeof(DNS_ANSWER_DATA) = 20,按理來說應該爲16。
C語言中邊界對齊原則如下所示:

  • 原則1:普通數據成員對齊規則:第一個數據成員放在offset爲0的地方,以後每個數據成員存儲的起始位置要從該成員大小的整數倍開始(比如int在32位機爲4字節,則要從4的整數倍地址開始存儲)。
  • 原則2:結構體成員對齊規則:如果一個結構裏有某些結構體成員,則該結構體成員要從其內部最大元素大小的整數倍地址開始存儲。(struct a裏存有struct b,b裏有char,int,double等元素,那b應該從8的整數倍開始存儲。)
  • 原則3:結構體大小對齊規則:結構體大小也就是sizeof的結果,必須是其內部成員中最大的對齊參數的整數倍,不足的要補齊。

根據我上面定義的結構體成員的順序以及其大小可知,其在存儲的時候存儲結構如下圖所示:
在64位系統:
在這裏插入圖片描述
在32位系統
在這裏插入圖片描述
因此在實驗中,僞造的DNS報文的結構如下所示:
在這裏插入圖片描述
解決方式:參考博客:

https://blog.csdn.net/zhangxiong2532/article/details/50826917
https://wenku.baidu.com/view/96c2d256f01dc281e53af026.html

當不希望編譯器對結構體做對齊處理,而希望按照他原有的大小分配空間時,這裏就要用到 attribute((packed)) ,這個意思是告訴編譯器不要做對齊處理。

#pragma pack(push,1)
typedef struct{	
	unsigned short a_name;
	unsigned short a_type;
	unsigned short a_class;
	unsigned int a_ttl;
	unsigned short a_data_len;
	unsigned int a_ipv4_addr;
}DNS_ANSWER_DATA;
#pragma pack(pop)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章