Netstatのtcp 4/6



Netstatが傍受するサービスポートを表示すると、tcp 6の監視しか表示されませんが、サービスはtcp 4のipv 4アドレスでアクセスできるのに、なぜtcp 4の傍受が表示されないのでしょうか.
sshdが傍受する22ポートを例に挙げると、
# netstat -tlnp | grep :22
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1444/sshd
tcp6       0      0 :::22                   :::*                    LISTEN      1444/sshd

netstatは、sshdがipv 4のアドレスを傍受するとともに、ipv 6のアドレスを傍受することを示す.
httpdプロセスを見てみましょう
# netstat -tlnp | grep :80
tcp6       0      0 :::80                   :::*                    LISTEN      19837/httpd

しかし、ipv 6に傍受されているアドレスのみが表示されていることに気づいたが、ipv 4を介したアドレスはアクセス可能であるのに.
この現象をどう説明するかを見てみましょう.
まず、ipv 6を閉じてhttpdを再起動します.
# sysctl net.ipv6.conf.all.disable_ipv6=1
# systemctl restart httpd

httpの傍受先を見てみましょう.
# netstat -tlnp | grep :80
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      33697/httpd

IPv 4アドレスのみが傍受されていることがわかります.
では、なぜipv 6がオンになったとき、netstatはsshdのようにtcpとtcp 6の両方を表示するのではなく、tcp 6の傍受のみを表示したのでしょうか.
httpのソースコードをダウンロードしてみましょう.コードserver/listen.cのopen_Listeners()関数には、関連するコメントがあります.
/* If we have the unspecified IPv4 address (0.0.0.0) and
 * the unspecified IPv6 address (::) is next, we need to
 * swap the order of these in the list. We always try to
 * bind to IPv6 first, then IPv4, since an IPv6 socket
 * might be able to receive IPv4 packets if V6ONLY is not
 * enabled, but never the other way around.
 * ...   ...
 */

上述したように、ipv 6は、実際にはipv 4の要求を処理することができ、V 6 ONLYがオンになっていない場合、逆にそうではない.では、V 6 ONLYはいつオープンしますか?
followコードをmake_に続行sock()関数では、次のコードが見つかります.
#if APR_HAVE_IPV6
#ifdef AP_ENABLE_V4_MAPPED
    int v6only_setting = 0;
#else
    int v6only_setting = 1;
#endif
#endif

この関数では、リスニングされたアドレスがipv 6である場合、IPV 6_が設定されることがわかります.V 6 ONLYというsocketオプション、今、肝心なのはAP_を見ることですENABLE_V4_MAPPEEDはどのように定義されていますか.
configure(コード数で直接取得した場合、このファイルはなく、configure.ac/inファイルのみ)ファイルでは、次のことがわかります.
# Check whether --enable-v4-mapped was given.
if test "${enable_v4_mapped+set}" = set; then :
  enableval=$enable_v4_mapped;
  v4mapped=$enableval

else

    case $host in
    *freebsd5*|*netbsd*|*openbsd*)
        v4mapped=no
        ;;
    *)
        v4mapped=yes
        ;;
    esac
    if ap_mpm_is_enabled winnt; then
                v4mapped=no
    fi

fi


if test $v4mapped = "yes" -a $ac_cv_define_APR_HAVE_IPV6 = "yes"; then

$as_echo "#define AP_ENABLE_V4_MAPPED 1" >>confdefs.h

したがって、Linuxでは、デフォルトでは、AP_ENABLE_V4_MAPPEEDが1であると、httpdはipv 6を直接傍受します.このとき、ipv 6のsocketはipv 4の要求を処理することができるからです.またbind()システム呼び出しは、ユーザ空間のプロセスに対してipv 6がオンになっていない場合を透過的に処理し、ipv 4が傍受される.
一方、httpdをコンパイルするときに--disable-v4-mappedパラメータを使用してipv 4 mappedを禁止すると、デフォルトでは、ipv 6のみを傍受するのではなく、ipv 4とipv 6でそれぞれ傍受されます.以下に示します.
# netstat -tlnp | grep :80
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      40576/httpd
tcp6       0      0 :::80                   :::*                    LISTEN      40576/httpd

一方、/etc/httpd/conf/httpd.confにおいてListenがipv 6アドレスのみを傍受するように設定されている場合、以下のようにする.
Listen :::80

では、netstatはtcp 6のリスニングのみを表示することがわかります.
# systemctl restart httpd
# netstat -tlnp | grep :80
tcp6       0      0 :::80                   :::*                    LISTEN      40980/httpd

そして、ipv 4アドレスでhttpにアクセスできないことに気づきます.
# telnet 192.168.1.100 80
Trying 192.168.1.100...
telnet: Unable to connect to remote host: Connection refused

したがって、netstatはリスニングされたポートをリアルに表示するだけですが、ipv 6は実際にLinuxでもipv 4をサポートしていることに注意してください.