IPv6ソケットでlistenするとIPv4でも接続可能に
「IPv6は自分には関係がない」と思っていたとしても、実は気がつかずにIPv6で通信可能な状態になっていることもあるので注意が必要です。
IPv4射影IPv6アドレスへの対応で、IPv6ソケットがIPv4での通信を行えるように実装されていることを、sshを使って前回紹介しました(IPv4アドレスを含むIPv6アドレス表記)。 前回は、クライアント側(connectを行う側)の例だったので、今回はサーバ側の話です。
IPv4だけで使っているつもりでも、IPv6対応のためにIPv6ソケットでサーバが実装されていれば、知らずにIPv6側でもサーバが稼働していることもあります。 たとえば、IPv4のみでApacheなどのWebサーバを起動していると思っていたら、実はIPv6側でもHTTPの受付をしていたということもあります。 Webサーバを起動している機器で、netstatかlsofかssを実行してみてください。 グローバルなIPv6アドレスが設定されていない機器であっても、気がつかずにlocalhost(::1)やリンクローカルアドレスでHTTPを受け付けているかも知れません。
サンプルコード
では、実際に試してみましょう。このサンプルは、特定のIPアドレスを指定せずにAF_INET6(IPv6)のTCPソケット(SOCK_STREAM)に対してbindを行っています。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
int
main()
{
int sock0;
struct sockaddr_in client;
socklen_t len;
int sock;
struct addrinfo hints, *res;
int err;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_flags = AI_PASSIVE;
hints.ai_socktype = SOCK_STREAM;
err = getaddrinfo(NULL, "12345", &hints, &res);
if (err != 0) {
printf("getaddrinfo : %s\n", gai_strerror(err));
return 1;
}
/* ソケットの作成 */
sock0 = socket(res->ai_family, res->ai_socktype, 0);
if (sock0 < 0) {
perror("socket");
return 1;
}
if (bind(sock0, res->ai_addr, res->ai_addrlen) != 0) {
perror("bind");
return 1;
}
freeaddrinfo(res); /* addrinfo構造体を解放 */
/* TCPクライアントからの接続要求を待てる状態にする */
listen(sock0, 5);
/* TCPクライアントからの接続要求を受け付ける */
len = sizeof(client);
sock = accept(sock0, (struct sockaddr *)&client, &len);
/* 6文字送信 */
write(sock, "HELLO\n", 6);
/* TCPセッションの終了 */
close(sock);
/* listen するsocketの終了 */
close(sock0);
return 0;
}
IPV6_V6ONLYがデフォルトでOFFになっていない環境でこのプログラムを実行すると、IPv4のTCPで12345番ポートに接続しても、IPv6のTCPで12345番ポートに接続しても接続できてしまいます。
試しに、telnet ::1 12345 と、telnet 127.0.0.1 12345をやってみてください。
IPv4とIPv6の両方でTCPの受付が行われていることは、他の方法でも確認できます。 たとえば、このサーバプログラムを実行中に「netstat -na」をすると次のような結果を含んでいます(このサンプルはmacOSで試しました)。
Proto部分が「tcp46」となっており、IPv4とIPv6の両方で受け付けているのがわかります。AF_INETで作ったソケットであれば、この部分が「tcp4」となり、IPV6_V6ONLYを有効にした状態のAF_INET6ソケットであれば「tcp6」になります。
Active Internet connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp46 0 0 *.12345 *.* LISTEN
draft-itojun-v6ops-v4mapped-harmful
さらに詳しい情報を知りたい方は、IPv4射影IPv6アドレスの危険性に関しての故itojunさんが指摘したdraft-itojun-v6ops-v4mapped-harmful-02をご覧ください。
最近のエントリ
- 「ピアリング戦記」の英訳版EPUBを無料配布します!
- IPv4アドレス移転の売買価格推移および移転組織ランキング100
- 例示用IPv6アドレス 3fff::/20 が新たに追加
- ShowNet 2024のL2L3
- ShowNet 2024 ローカル5G
- ShowNetのローカル5G企画(2022年、2023年)
過去記事