16

私はそれをグーグルで検索しました、そして何人かの人々は「structsockaddrで同じサイズを保つために」と言います。しかし、カーネルはsockaddrを直接使用しません(右?)。使用する場合。カーネルはそれを元の状態に戻します。では、なぜゼロパディングが必要なのですか?

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()
};
4

4 に答える 4

13

私が見つけた2つのより関連性のある情報は次のとおりです。

バイトをクリアしないコードのスニペットについて話す

これはバグです。たまに発生するようです。このバグにより、アプリケーションで未定義の動作が発生する可能性があります。

いくつかの説明が続きます

ほとんどのネットコードはsockaddr_inを使用せず、sockaddrを使用します。sendtoのような関数を使用する場合は、sockaddr_inまたは使用しているアドレスをsockaddrに明示的にキャストする必要があります。sockaddr_inはsockaddrと同じサイズですが、わずかなハックのため、内部的にはサイズは同じです。

そのハックはsin_zeroです。実際、sockaddr_inの有用なデータの長さはsockaddrよりも短いです。ただし、違いは小さなバッファを使用してsockaddr_inに埋め込まれます。そのバッファはsin_zeroです。

そして最後に、さまざまな場所で見つけることができる情報

一部のアーキテクチャでは、sin_zeroをクリアしないと問題が発生しません。しかし、他のアーキテクチャではそうなる可能性があります。仕様ではsin_zeroをクリアする必要があるため、現在および将来、コードにバグがないようにする場合は、これを行う必要があります。

質問に答える

なぜこの8バイトのパディングが必要なのですか?

と答え

Unixネットワークプログラミングの3.2章では、「POSIX仕様では、構造体にsin_family、sin_addr、sin_portの3つのメンバーしか必要ありません。POSIX準拠の実装では、追加の構造体メンバーを定義できます。これは、インターネットソケットでは正常です。アドレス構造。ほとんどすべての実装でsin_zeroメンバーが追加されるため、すべてのソケットアドレス構造のサイズは少なくとも16バイトになります。 "

これは構造体のパディングのようなもので、将来的には追加のフィールド用に予約される可能性があります。コメントしたように、あなたはそれを決して使うことはありません。

これは最初のリンクと一致しています。バイトをクリアすると、受信者に「これらのバイトは私たちの側では使用されません」と通知されます。

于 2013-03-25T06:39:28.460 に答える
3

structsockaddr_inをキャストしてstructsockaddrを同じサイズに保つ必要があるため、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 
}; 

次に、異なる構造体メンバーを持つXeroxNSファミリーを取り上げます。

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 
};
于 2013-08-25T06:15:01.383 に答える
1

構造体のパディングは、構造体のメンバーが正しいバイト境界に表示される必要があるために発生します。これを実現するには、コンパイラーがパディングバイト(またはビットフィールドが使用されている場合はビット)を挿入して、構造体のメンバーが正しい位置に表示されるようにします。さらに、構造体のサイズは、構造体の配列内ですべての構造体がメモリ内で正しく整列されるようにする必要があります。

したがって、メモリリークを無視するために必要な場合があります。

于 2013-03-25T06:43:04.460 に答える
1

struct sockaddrは、この構造の抽象的で不完全なバージョンであり、ファミリのみが含まれています。 struct sockaddr_inこの構造のIPv4バージョンです。最初の8バイトのみを使用します。 struct sockaddr_in6はこの構造のIPv6バージョンであり、より大きくなっています。パディングにより、小さな構造体がこの構造体の最大のバリエーションに対応できるため、バッファーが小さくなりません。

関数またはシステムコールにアドレスを渡す場合、余分なバイトは実際には必要ありません。ただし、アドレスを取得するには、結果の構造アドレスを指定します。その構造は、考えられるすべてのバリエーションの中で最大である必要があります。そうでない場合(IPv4バージョンを提供したが、IPv6アドレスを取り戻した場合)、結果は構造を超え、メモリ内の隣にあるものはすべて破損します。

このメモリの破損を回避するために、関連する関数のほとんどは、構造体のサイズをパラメータとして取ります。しかし、今では、そのIPv4バージョンとその小さすぎるサイズを渡すと、構造のIPv6バージョンのデータが不完全になります。ファミリを見ると、IPv6であることがわかります。ただし、構造体をIPv6にキャストして使用しようとすると、構造体が小さすぎて完全で有効なデータを含めることができないため、内容が間違っています。

小さい構造をパディングすると、これらの障害が回避され、関連する潜在的なセキュリティ問題が回避されます。

于 2017-03-14T04:38:19.340 に答える