やろうとしたら色々はまったので
ここにそのメモを残す。まあ今時のウェブ系エンジニアには役に立たないと思う。
ネットワーク系でC/C++などコンパイル言語のプログラマには役立つかな。
サンプルコードはないのでキーワードから検索してほしい。
IPv6におけるECHO
ヘッダの構造は struct icmp6_hdr であり、IPv4のstruct icmphdr と同じである。
違うのはチェックサムの計算方法だ。
IPv4にはIPヘッダにチェックサムがあり、icmphdrのチェックサムだけ計算すれば良かった。
IPv6では諸事情からチェックサムは上位プロトコルで計算することになった。
そこでIPヘッダのIPv6アドレスと付帯データを含めて計算する疑似ヘッダが考案された。
疑似ヘッダについては RFC8200 の 8.1節を参照してほしい。
ここでさらに問題が
チェックサム用の疑似ヘッダを用意して必要な値を格納しなければ計算できない。
チェックサムには自身と対象のIPv6アドレスを(struct in6_addr形式で)格納する。
つまり自身のIPv6アドレスを取得する必要に迫られる。
このAPIは getifaddr() 関数で、検索すればサンプルが出てくる。
相手のIPアドレスは getaddrinfo() でソケット構造体が取得できるのでそこから設定する。
チェックサムはicmp6_hdrを含めて計算するので、疑似ヘッダの構造体に含める。
疑似ヘッダのデータサイズに設定するのは icmp6_hdrのサイズである点に注意。
データサイズは32bitなので Network Byte Order(BigEndian) で設定する。
同様に上位プロトコル番号も ICMPv6の58(10進)をNetwork Byte Orderで設定する。
最後に疑似ヘッダと連結して定義したicmp6_hdrにICMP6_ECHO_REQUESTをセットする。
チェックサムを0で初期化して、やっとチェックサム計算の準備が整った。
チェックサムの計算方法
についてはRFC792を参照してほしい。1の補数和の1の補数をとったもの、だそうだ。
な、何を言ってるのかわからねーと思うが、俺も何が何だかわからなかった。
理屈は抜きで結論だけ書くと
- 対象のバッファをunsigned shortで取り出し、unsigned int(32bit)以上の変数に加算。
- もし1バイト余ったら末尾に0x00を加えて加算
- sum値の下16bitに(もしあれば)上位16bitを加算
- 3を桁上がりがなくなるまで繰り返す
※unsigned shortのEndianは意識しなくて良い(らしい)
これだけ。詳しい理屈はTCP/IP関係のネット検索や書籍参照で理解してほしい。
疑似ヘッダとicmp6_hdrを含めた領域のサムを計算すれば答えが得られる。
icmp6_hdrにチェックサムをセットしたらsend系APIで icmp6_hdrを 送信する。
応答もicmp6_hdrで返る。送信で使った疑似ヘッダに代入してチェックサムを計算する。
※当然だがこの時はチェックサムを0初期化しない。
計算したチェックサムが0になれば正常。このへんの理屈はRFC700らしい。
応答がICMP6_ECHO_REPLYであることもチェックする。
以上