web-dev-qa-db-ja.com

UDPチェックサム計算

/usr/include/netinet/udp.hで定義されているUDPヘッダー構造体は次のとおりです。

struct udphdr
{
  u_int16_t source;
  u_int16_t dest;
  u_int16_t len;
  u_int16_t check;
};

ヘッダーのチェックフィールドに保存される値は何ですか?チェックサムが正しいかどうかを確認する方法は?チェックサムが計算されるデータは何ですか? (それは単にudpヘッダーまたはudpヘッダーとそれに続くペイロードですか?)

ありがとう。

21
Deepak

UDPチェックサムは、ペイロード全体andヘッダー内の他のフィールド、andIPヘッダーの一部のフィールド。擬似ヘッダーは、計算を実行するためにIPヘッダーから構築されます(これは、この擬似ヘッダー、UDPヘッダー、およびペイロードで実行されます)。疑似ヘッダーが含まれる理由は、間違ったIPアドレスにルーティングされたパケットをキャッチするためです。

基本的に、受信側では、ヘッダーのすべての16ビットワードとデータ領域が加算され(16ビットでラップ)、結果が0xffffに対してチェックされます。

送信側では、もう少し複雑です。 1の補数の合計がすべての16ビット値で実行され、その値の1の補数(つまり、すべてのビットの反転)が取られて、チェックサムフィールドに計算されます(計算されたゼロのチェックサムがすべてに変更されるという追加条件付き) 1ビット)。

1の補数の合計は、notすべての1の補数の合計です。少し複雑です。

基本的に、ゼロから開始する実行中の16ビットアキュムレータがあり、それに16ビット値をすべて追加します。これらの加算のいずれかがキャリーになると、値はラップアラウンドされ、値に再度加算されます。これにより、16ビット加算のキャリービットが効率的に取得され、値に加算されます。


余談ですが、これは私の側では純粋な推測ですが、これはおそらくADC(驚くほど十分、add)ではなく、ADD(キャリー付きのadd)命令を使用することで効率的に実行できます。または、その時点でCPUで利用可能な同等の命令は何でも。

キャリーがない場合、ADCはキャリーからゼロビットを追加します。このようなことが行われた日(そして、残念ながら、私amその古い)では、メモリは速度よりもはるかに多くの制約でした。今日ではほとんどの場合、コードに数バイトを保存すると、demi-god-emperor-of-the-universeのレベルに格上げされる可能性があります:-)


2回の最大16ビット値のため、2回目のキャリー(または、前の段落で言及したメソッドを使用している場合、次のADCとのキャリー2)を心配する必要はありません。合計すると、(0x1fffeから切り捨てられた)0xfffeを生成します-これに1を追加しても、別のキャリーは発生しません。

計算された補数の合計が計算され、そのビットが反転されてパケットに挿入されると、受信側で計算が0xffffを生成します。

ペイロードが常にパディングされ、整数の16ビットワードが確保されることに注意してください。 wasが埋め込まれた場合、長さフィールドは実際の長さを示します。

RFC768 は、これを詳述する仕様です。

35
paxdiablo

UDPチェックサム計算のわかりやすくわかりやすい例は、Gerd Hoffmannによって行われました。

「net-checksum.c Gerd Hoffmann」をグーグル検索するか、こちらのファイルをご覧ください。

https://Gist.github.com/fxlv/81209bbd150abfeaceb1f85ff076c9f

_net_checksum_tcpudp_関数を使用して、UDPペイロードの長さ、proto、src、dstのIPを入力し、UDPペイロード自体を入力すると、正しい処理が行われます。

最後に、チェックサムでhtons()を呼び出す必要があります。

1
fxlv

私はudpヘッダーを計算するコードをネットで検索していました(上記の擬似IPヘッダーを使用)。

最後に、open-bsd dhclient packet.cを見つけました。

https://github.com/DragonFlyBSD/DragonFlyBSD/blob/master/sbin/dhclient/packet.c

関数assemble_udp_ip_header()をチェックしてください

1
Guy L