iPhoneがiOS9からIPv6(Internet Protocol version 6)が必須となるらしいです。これまでIPv4アドレスの枯渇から何度も、今年はIPv6元年だ、なんて言われつづけてきましたが、なかなかメリットが見えないことから、ブームごとに学習はするものの、使うことはあまりありませんでした。(機器は対応済なのに) インフラ開発の現場でもNATがあるからそれほど不便でもないし、特に要望もなければ、使う機会もありませんでした。iPhoneの影響力がIPv6移行をさらに進めることで、使う機会が増えるかも(?)、ということで、IPv6に慣れておくためにも、Ubuntu 14.04 とRaspberry PiとのIPv6通信をテストしてみました。
ラズパイは、/etc/modules に ipv6 を追加すると、IPv6対応になります。
また、サーバとしてApache2は走らせておきます。(apt-get install apache2でインストール。IPv6対応済)
Ubuntu側は、以下のプログラムを使います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <errno.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #define BUFFERSIZE 1024 int main(int argc, char **argv) { struct addrinfo hints, *res, *ai0; ssize_t l; int s; char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; char buf[1024]; int error; if (argc != 3) { fprintf(stderr, "usage: testip host port\n"); exit(1); } memset(&hints, 0, sizeof(hints)); hints.ai_family= AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_NUMERICSERV; error = getaddrinfo(argv[1], argv[2], &hints, &ai0); if(error){ fprintf(stderr, "%s %s: %s\n", argv[1], argv[2], gai_strerror(error)); exit(1); } for (res = ai0; res; res = res->ai_next) { error = getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),NI_NUMERICHOST | NI_NUMERICSERV); if(res->ai_family == AF_INET6){ printf("[IPv6] "); } else if(res->ai_family == AF_INET){ printf("[IPv4] "); } else{ printf("[Other] "); } printf("Host : %s Port : %s\n", hbuf, sbuf); if(error){ fprintf(stderr, "%s %s: %s\n", argv[1], argv[2], gai_strerror(error)); continue; } s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) continue; if (connect(s, res->ai_addr, res->ai_addrlen)< 0) { close(s); fprintf(stderr, "connect error!\n"); continue; } printf("-------\n"); write(s, "GET / \n\n", 8); while ((l = read(s, buf, sizeof(buf))) > 0){ write(STDOUT_FILENO, buf, l); } close(s); } } |
ホスト名からIPv4, IPv6のアドレスを取得して、それぞれのアドレスでサーバにアクセスします。/etc/hostsは下のようになっています。
localhostのテストのため、Ubuntu側もApache2を立ち上げておきます。
index.htmlの内容は、”Index Page”です。
ホスト名localhost、rpiで接続してみます。
rpiの場合は、アドレスは引けるのですが、IPv6の接続がうまくいきません。これは、リンクローカルアドレスになっているためと思われます。そこで、IPv6アドレスにネットワークインターフェイス名を追加して接続しました。netcatでも同様の結果になりました。
下は、プログラム実行したときのパケットキャプチャです。
次に、参考までにping6、curlによる接続です。
アドレスの記述方法に、随分トライ&エラーをしました。%25は、%をエスケープしたものです。eth0でなく2なのは、よくわかりませんでしたが、インターフェイスの順番指定なのでしようか。
環境が、グローバルユニキャストアドレスならば、もっと簡単にいきそうです。
一番興味があるのは、マルチキャストなのですが、環境がそろったらトライしてみたいです。
参考 : http://www.v6pc.jp/jp/upload/pdf/socket-sample-20121203.pdf