为什么 netstat 对某些服务只显示了 tcp6 监听端口

摘要:
最近,我偶尔发现一个奇怪的现象。当netstat查看被监控的服务端口时,它只显示了对tcp6的监控。但是可以通过tcp4的ipv4地址访问该服务。为什么没有显示tcp4的监控?当我们查看httpd进程:#netstat-tlnp|grep:80tcp600::80::*LISTEN19837/httpd时,我们发现只显示侦听ipv6的地址,但通过ipv4的地址显然是可访问的。首先,关闭ipv6并重新启动httpd:#sysctlnet.ipv6.conf.all.disable_ ipv6=1#systemctlrestarthttpd现在,查看httpd侦听的地址:#netstat tlnp | grep:80tcp000.0.0.0:800.0.0.0:*LISTEN33697/httpd。您可以看到只有ipv4地址被监听。那么,为什么启用ipv6时netstat只显示tcp 6监听,而不是像sshd那样显示tcp和tcp 6监听?

最近偶尔发现一个比较奇怪的现象,netstat 查看监听的服务端口时,却只显示了 tcp6 的监控, 但是服务明明是可以通过 tcp4 的 ipv4 地址访问的,那为什么没有显示 tcp4 的监听呢?

以 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 既监听在 ipv4 的地址,又监听在 ipv6 的地址。

而再看看 httpd 进程:

# netstat -tlnp | grep :80
tcp6       0      0 :::80                   :::*                    LISTEN      19837/httpd

却发现只显示了监听在 ipv6 的地址上 ,但是,通过 ipv4 的地址明明是可以访问访问的。

下面来看下怎样解释这个现象。

首先,关闭 ipv6 并且重启 httpd:

# sysctl net.ipv6.conf.all.disable_ipv6=1
# systemctl restart httpd

现在,看下 httpd 监听的地址:

# netstat -tlnp | grep :80
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      33697/httpd

可以看到,已经只监听到 ipv4 地址了。

那为什么在 ipv6 开启的时候,netstat 只显示了 tcp6 的监听而非像 sshd 那样既显示 tcp 又显示 tcp6 的监听呢?

我们下载 httpd 的源码看一看,在代码 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.
 * ... 省略 ...
 */

上面提到,ipv6 实际上是可以处理 ipv4 的请求的当 V6ONLY 没有开启的时候,反之不然; 那么 V6ONLY 是在什么时候开启呢?

继续 follow 代码到 make_sock() 函数,可以发现如下代码:

#if APR_HAVE_IPV6
#ifdef AP_ENABLE_V4_MAPPED
    int v6only_setting = 0;
#else
    int v6only_setting = 1;
#endif
#endif

在这个函数中,可以看到如果监听的地址是 ipv6,那么会去设置 IPV6_V6ONLY 这个 socket 选项, 现在,关键是看 AP_ENABLE_V4_MAPPED 是怎么定义的。

在 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_MAPPED 是 1,那么 httpd 就会直接监听 ipv6, 因为此时 ipv6 的 socket 能够处理 ipv4 的请求;另外,bind() 系统调用会对用户空间的进程透明处理 ipv6 没有开启的情况,此时会监听到 ipv4。

而如果我们在编译 httpd 的时候使用 --disable-v4-mapped 参数禁止 ipv4 mapped,那么默认情况下, httpd 会分别监听在 ipv4 和 ipv6,而非只监听 ipv6,如下所示:

# 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 设置为只监听 ipv6 地址,如下:

Listen :::80

那么,将可以看到 netstat 只显示 tcp6 的监听:

# systemctl restart httpd
# netstat -tlnp | grep :80
tcp6       0      0 :::80                   :::*                    LISTEN      40980/httpd

并且,你会发现现在不能通过 ipv4 地址访问 httpd 了。

# telnet 192.168.1.100 80
Trying 192.168.1.100...
telnet: Unable to connect to remote host: Connection refused

所以,netstat 只是很真实的显示监听的端口而已,但是需要注意 ipv6 实际上在 Linux 上也支持 ipv4。

免责声明:文章转载自《为什么 netstat 对某些服务只显示了 tcp6 监听端口》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇App自动化测试Robots.txt  禁止爬虫下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

centos7上如何禁用ipv6 转载

今天跑docker的时候发现映射端口之后的端口竟然是tcp6,这是因为ipv6没有关闭而docker默认使用tcp6的原因,所以我要把tcp6关闭,关闭方法如下: 方法 1 编辑文件/etc/sysctl.conf, vi /etc/sysctl.conf 添加下面的行: net.ipv6.conf.all.disable_ipv6 =1 net.i...

docker发现端口是tcp6的 导致无法访问前端

最近偶尔发现一个比较奇怪的现象,netstat 查看监听的服务端口时,却只显示了 tcp6 的监控, 但是服务明明是可以通过 tcp4 的 ipv4 地址访问的,那为什么没有显示 tcp4 的监听呢? 以 sshd 监听的 22 端口为例: # netstat -tlnp | grep :22 tcp 0 0 0.0.0.0:22...

开源EDR(OSSEC)

开源EDR(OSSEC)基础篇- 01 -设计定位与能力输出 前言 介绍OSSEC之前,不得不提到当前比较热门的技术EDR,近几年随着大数据SIEM系统的发展,EDR(端点威胁检测与响应)技术成为了安全界万众宠爱的骄子,广泛用于威胁检测、攻击溯源和响应处理的安全场景。 而OSSEC是一款开源的跨平台的准EDR入侵检测响应系统,可以实现商业EDR 大部分的...

netstat -st输出解析(二)

转自:http://perthcharles.github.io/2015/11/10/wiki-netstat-proc/ netstat -st输出的两个重要信息来源分别是/proc/net/snmp和/proc/net/netstat本文将分类整理这些counterd的含义以及一些注意事项。 在整理的过程中,发现Rover Yu前辈已经对这些coun...

nginx使用多端口监听多个服务

###### nginx监听多个端口并转发给不同的服务 ### 第一个监听: upstream odoo { server localhost:8067; } upstream odoochat{ server localhost:8072; } server { listen 8070default_server; listen [::]:80...

临时解决linux下time wait问题

 通过 netstat  -anp | grepTIME_WAIT | wc -l 命令查看数量,发现TIME_WAIT的连接数量超过了阈值   1、初步怀疑是程序没有关闭连接,codereview了两遍,发现,已经正常关闭。 2、网上看TIME_WAIT产生的原因,可能是因为服务器主动关闭连接导致TIME_WAIT产生。 3、查找TIME_WAIT解决...