IPv6のソケットAPIには次のものがあります。
RFC 3493:Basic Socket Interface Extensions for IPv6
基本ソケットAPI
RFC 3542:Advanced Sockets Application Program Interface (API) for IPv6
拡張ソケットAPI
基本ソケットAPIは、ソケットを使用したプログラムのための標準的APIです。
これだけで、IP上のプログラムのほとんどは作成できます。
前半で使用したAPIはこれです。
以下のようなものが含まれています。
アドレスやポート番号を表現する型の定義
バイト配列操作関数
アドレス表記変換関数
ソケット入出力関数
UDP、TCP上でクライアントとしての動作に必要な関数
UDP、TCP上でサーバとしての動作に必要な関数
ソケットの動作を変更するための関数
ホスト名からアドレスへの変換関数
アドレスからホスト名への変換関数
サービス名からポート番号への変換関数
ポート番号からサービス名への変換関数
前半ではgetaddrinfo、getnameinfoなどを使いました。
拡張ソケットAPIは、ソケットを使用した高度なプログラムのためのAPIです。
以下のようなものが含まれています。
RAWソケットに関する関数
拡張ヘッダに対する操作を行うための関数
パケットに関する情報の取得・設定に関する関数
マルチキャストに関する操作を行うため関数
MTUに関する操作を行うための関数
後半で、これらも少し使用します。
getsockopt, setsockoptのIPPROTO_IPV6 レベルなど
ユニキャスト送信時のホップリミットの制御 DWORD dwHoplimit = 10; int iOptlen = sizeof(dwHoplimit); setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *)&dwHoplimit, sizeof(dwHoplimit)); getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *)&dwHoplimit, &iOptLen);
マルチキャスト送信時のインターフェースの制御 DWORD dwIfIndex = 4; int iOptlen = sizeof(dwIfIndex ); setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF , (char *)&dwIfIndex, sizeof(dwIfIndex)); getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF , (char *)&dwIfIndex, &iOptLen);
マルチキャスト送信時のホップリミットの制御 DWORD dwHoplimit = 10; int iOptlen = sizeof(dwHoplimit); setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&dwHoplimit, sizeof(dwHoplimit)); getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&dwHoplimit, &iOptLen);
パスMTUの取得 struct ip6_mtuinfo mtuinfo; socklen_t infolen = sizeof(mtuinfo); getsockopt(fd, IPPROTO_IPV6, IPV6_PATHMTU, &mtuinfo, &infolen);
マルチキャスト送信時のループバックの制御 DWORD dwLoop = 1; int iOptlen = sizeof(dwLoop); setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *)&dwLoop, sizeof(dwLoop)); getsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&dwLoop, &iOptLen);
マルチキャストグループへの参加 IPV6_MREQ member; setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&member, sizeof(member));
マルチキャストグループからの離脱 struct?ipv6_mreq member; setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *)&member, sizeof(member));
以下の説明で使用(更新)するのは前半で作成した次のプログラムです。
SimpleServerMChat :Windows版, Linux版
SimpleClientMEcho :Windows版, Linux版
WindowsとLinuxを同じリンクローカルなネットワーク(オンリンク)の
環境に設置してください。
前半に作成したインターフェースとIPアドレスを列挙するプログラムを動かしてみましょう
EnumInterface:Windows版、Linux版
【EnumInterface.exe(Windows)】 Adapter Name : イーサネット IfIndex : 7 IPv6: 2001:ce8:132:4332:7985:ee4e:75:1c54/64 IPv6: 2001:ce8:132:4332:7ca7:7833:1686:8a60/128 IPv6: 2001:ce8:132:4332:8105:e11e:2f50:b8b4/128 IPv6: fe80::7985:ee4e:75:1c54/64 IPv4: 192.168.101.57/24 Multicast IPv6: ff01::1 Multicast IPv6: ff02::1 Multicast IPv6: ff02::c Multicast IPv6: ff02::fb Multicast IPv6: ff02::1:3 Multicast IPv6: ff02::1:ff50:b8b4 Multicast IPv6: ff02::1:ff75:1c54 Multicast IPv6: ff02::1:ff86:8a60 Multicast IPv4: 224.0.0.1 Multicast IPv4: 224.0.0.251 Multicast IPv4: 224.0.0.252 Multicast IPv4: 239.255.255.250 Adapter Name : ローカル エリア接続* 3 IfIndex : 9 IPv6: fe80::8042:a753:7bb1:fc36/64 IPv4: 169.254.252.54/16 Multicast IPv6: ff01::1 Multicast IPv6: ff02::1 Multicast IPv6: ff02::1:ffb1:fc36 Multicast IPv4: 224.0.0.1 Adapter Name : ローカル エリア接続* 4 IfIndex : 5 IPv6: fe80::b8ee:d2a0:c1e7:e2e3/64 IPv4: 169.254.226.227/16 Multicast IPv6: ff01::1 Multicast IPv6: ff02::1 Multicast IPv6: ff02::1:ffe7:e2e3 Multicast IPv4: 224.0.0.1 Adapter Name : Wi-Fi IfIndex : 8 IPv6: fe80::3996:8cb7:30d6:adfe/64 IPv4: 169.254.173.254/16 Multicast IPv6: ff01::1 Multicast IPv6: ff02::1 Multicast IPv6: ff02::c Multicast IPv6: ff02::fb Multicast IPv6: ff02::1:3 Multicast IPv6: ff02::1:ffd6:adfe Multicast IPv4: 224.0.0.1 Multicast IPv4: 224.0.0.251 Multicast IPv4: 224.0.0.252 Multicast IPv4: 239.255.255.250 Adapter Name : Bluetooth ネットワーク接続 IfIndex : 6 IPv6: fe80::c03:39ae:f5c8:e91b/64 IPv4: 169.254.233.27/16 Multicast IPv6: ff01::1 Multicast IPv6: ff02::1 Multicast IPv6: ff02::1:ffc8:e91b Multicast IPv4: 224.0.0.1 Adapter Name : Loopback Pseudo-Interface 1 IfIndex : 1 IPv6: ::1/128 IPv4: 127.0.0.1/8 Multicast IPv6: ff02::c Multicast IPv4: 239.255.255.250
【EnumInterface(Linux)】 Name:lo Index:1 IPv4: 127.0.0.1 netmask 255.0.0.0 Name:eth0 Index:2 IPv4: 192.168.101.65 netmask 255.255.255.0 Name:wlan0 Index:3 IPv4: 192.168.101.63 netmask 255.255.255.0 Name:lo Index:1 IPv6: ::1 netmask ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff Name:eth0 Index:2 IPv6: 2001:ce8:132:4332:7819:7fb2:1ef9:f59 netmask ffff:ffff:ffff:ffff:: Name:eth0 Index:2 IPv6: fe80::581c:f2d9:e72f:9b7a netmask ffff:ffff:ffff:ffff:: Name:wlan0 Index:3 IPv6: 2001:ce8:132:4332:73e6:e5b7:2211:dea2 netmask ffff:ffff:ffff:ffff:: Name:wlan0 Index:3 IPv6: fe80::11a0:ecd4:2cf8:6e5c netmask ffff:ffff:ffff:ffff::
私の環境では上のようになりました。
これを見ると、Windowsではイーサーネット(IfIndex=7)に有効なアドレスがあります。
Linuxではeth0(Index=2)とwlan0(Index=3)に有効なアドレスがあります。
ここでちょっと実験をしてみましょう。
LinuxからWindowsにIPv4アドレス, IPv6グローバルアドレス, IPv6リンクローカル
アドレスを使ってpingを出してみましょう。
$ping -c 1 192.168.101.57 ping -c 1 2001:ce8:132:4332:7985:ee4e:75:1c54 ping -c 1 2001:ce8:132:4332:7ca7:7833:1686:8a60 ping -c 1 fe80::7985:ee4e:75:1c54 $ ping -c 1 192.168.101.57 PING 192.168.101.57 (192.168.101.57) 56(84) bytes of data. 64 bytes from 192.168.101.57: icmp_seq=1 ttl=128 time=0.741 ms — 192.168.101.57 ping statistics — 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.741/0.741/0.741/0.000 ms $ ping -c 1 2001:ce8:132:4332:7985:ee4e:75:1c54 PING 2001:ce8:132:4332:7985:ee4e:75:1c54(2001:ce8:132:4332:7985:ee4e:75:1c54) 56 data bytes 64 bytes from 2001:ce8:132:4332:7985:ee4e:75:1c54: icmp_seq=1 ttl=64 time=1.63 ms — 2001:ce8:132:4332:7985:ee4e:75:1c54 ping statistics — 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 1.637/1.637/1.637/0.000 ms $ ping -c 1 fe80::7985:ee4e:75:1c54 connect: 無効な引数です
結果は次のようになりました。
IPv4アドレス:成功
IPv6グローバルアドレス:成功
IPv6リンクローカル:失敗
IPv6リンクローカルアドレスでは失敗しました。
これは、リンクローカルアドレスにはネットワークの記述がないから
どのインターフェースを使えば良いかわからないからです。
(どのインターフェースに繋がっていても先頭10ビットは1111 1110 10
次の54ビットは0、つまり先頭64ビットが共通なのです)
それでは、インターフェースを指定してpingを出してみましょう。
$ ping -c 1 fe80::7985:ee4e:75:1c54%2 PING fe80::7985:ee4e:75:1c54%2(fe80::7985:ee4e:75:1c54%eth0) 56 data bytes 64 bytes from fe80::7985:ee4e:75:1c54%eth0: icmp_seq=1 ttl=64 time=1.00 ms — fe80::7985:ee4e:75:1c54%2 ping statistics — 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 1.003/1.003/1.003/0.000 ms $ ping -c 1 fe80::7985:ee4e:75:1c54%3 PING fe80::7985:ee4e:75:1c54%3(fe80::7985:ee4e:75:1c54%wlan0) 56 data bytes 64 bytes from fe80::7985:ee4e:75:1c54%wlan0: icmp_seq=1 ttl=64 time=16.0 ms — fe80::7985:ee4e:75:1c54%3 ping statistics — 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 16.021/16.021/16.021/0.000 ms
今度は成功しました。
つまり、IPv6リンクローカルアドレスを使って接続先を指定するときは、
使用する(発信元の)インターフェースを指定(%の後ろに書く)する必要があることが
わかります。もちろん%2, %3の代わりに%eth0, %wlan0と書くこともできます。
(*)Windowsについては、どういうわけかインターフェースを指定しなくても
成功します。きっとWindows独自のコードが実装されているのでしょう。
Windowsでもインターフェースを記述すべきと思います。
ちょっと長くなりましたので、続きは次回にしましょう。