2013-03-25 31 views
9

我google了一下,有人說「保持與struct sockaddr相同的大小」。但是Kernel不會直接使用sockaddr(對吧?)。使用它時。內核將把它重新轉換成它的內容。那麼爲什麼零填充需要?爲什麼在sockaddr_in中需要零填充?

struct sockaddr { 
    unsigned short sa_family; // address family, AF_xxx 
    char    sa_data[14]; // 14 bytes of protocol address 
}; 

struct sockaddr_in { 
    short   sin_family; // e.g. AF_INET, AF_INET6 
    unsigned short sin_port;  // e.g. htons(3490) 
    struct in_addr sin_addr;  // see struct in_addr, below 
    char    sin_zero[8]; // zero this if you want to 
}; 

struct in_addr { 
    unsigned long s_addr;   // load with inet_pton() 
}; 
+0

隨着免責聲明,我完全沒有已知的水域: 它可能是endiannes? – 2013-03-25 06:21:01

+0

@ G.Stoynev我不知道... 16字節對齊? – louxiu 2013-03-25 06:25:26

+0

它在這裏被擴展...... http://silviocesare.wordpress.com/2007/10/22/setting-sin_zero-to-0-in-struct-sockaddr_in/ – 2013-03-25 06:49:13

回答

7

兩個更多的信息,有關片段,我能找到的

談到的代碼,不會明確字節的片段

這是一個錯誤。我發現它偶爾會發生。此錯誤可能導致應用程序中的未定義行爲。

其次一些吃茶

大部分的淨代碼不sockaddr_in的使用,它使用套接字地址。當你使用像sendto這樣的函數時,你必須明確地將sockaddr_in或者你使用的任何地址轉換爲sockaddr。 sockaddr_in的大小與sockaddr相同,但內部大小相同,因爲有輕微的黑客攻擊。

這種攻擊是sin_zero。真的,sockaddr_in中有用數據的長度比sockaddr短。但是差異是使用一個小緩衝區填充在sockaddr_in中;該緩衝區是sin_zero。

,最後,可以在不同的地方

在一些體系中找到的信息,它不會引起任何問題不清除的sin_zero。但在其他架構上可能。它的規範要求清除sin_zero,所以如果你打算讓你的代碼在現在和將來都是無bug的,你必須這樣做。

回答這個問題

爲什麼我們需要這8個字節的填充?

和答案

的Unix網絡程序設計3.2章說,「POSIX規範 需要在結構只有三個成員:sin_family,sin_addr,屬於和 sin_port它爲POSIX上可接受的的兼容實現來定義 其他結構成員,這對於Internet套接字地址 結構是正常的。幾乎所有實現都添加sin_zero成員,以便所有套接字 地址結構的大小至少爲16字節。「

它有點像結構填充,也許保留在未來的額外領域。就像評論一樣,你永遠不會使用它。

這與第一個鏈接一致。清除字節會告訴接收方「這些字節不在我們這邊使用」。

0

結構填充的發生是因爲結構的成員必須出現在correect字節的邊界上才能實現此目的,編譯器將填充字節(或位,如果位字段正在使用中)放入,以便結構成員出現在正確的位置。此外,結構的大小必須是這樣的:在結構陣列中,所有結構都在內存中正確對齊。

因此,可能需要忽略內存泄漏。

2

由於struct sockaddr_in需要轉換爲struct sockaddr它必須保持相同的大小,sin_zero是一個未使用的成員,其唯一目的是將結構填充到16字節(這是sock_addr的大小)。此填充大小可能因地址系列而異。例如;

struct sockaddr_in { 
    short int sin_family;  // Address family, AF_INET 
    unsigned short int sin_port;  // Port number 
    struct in_addr sin_addr;  // Internet address 
    unsigned char sin_zero[8];  // For padding, to make it same size as struct sockaddr 
}; 

現在採取施樂NS系列具有不同的結構成員:

struct sockaddr_ns { 
    u_short sns_family;  // Address family, AF_NS 
    struct ns_addr sns_addr;  // the 12-byte XNS address 
    char sns_zero[2];  // unused except for padding 
}; 
0

struct sockaddr是這種結構的抽象的,不完整的版本,只有家庭。 struct sockaddr_in是此結構的IPv4版本。它只使用前8個字節。 struct sockaddr_in6是此結構的IPv6版本,並且較大。填充允許較小的結構適應這種結構的最大變化,所以緩衝區不會過小。

當您將地址傳遞給函數或系統調用時,額外的字節不是必需的。但是檢索一個地址,你提供了結果的結構地址。該結構必須是所有可能變化中最大的。如果沒有 - 想象你提供了一個IPv4版本,但收回了一個IPv6地址 - 那麼結果將超過結構並破壞內存中的任何內容。

爲了避免這種內存損壞,大部分相關函數都將結構大小作爲參數。但是現在,當你通過這個IPv4版本並且它的尺寸太小時,你會得到一個結構不完整的IPv6版本。縱觀家庭,你可以看到它是IPv6。但是,如果將結構轉換爲IPv6並嘗試使用它,那麼內容是錯誤的,因爲結構太小而無法包含完整的有效數據。

填充較小的結構避免了這些障礙,並避免了任何相關的潛在安全問題。