Apache 反向代理遇到 IPv6 问题

Apache 反向代理遇到 IPv6 问题

问题:IPv6 客户端尝试联系反向代理后面的服务器失败。

在此示例中,客户端和服务器位于同一台机器上。

客户端的 IPv6 配置:

ip --oneline addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN \    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
1: lo    inet 127.0.0.1/8 scope host lo
1: lo    inet6 ::1/128 scope host \       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000\    link/ether 00:1e:67:57:31:3d brd ff:ff:ff:ff:ff:ff
2: eth0    inet6 2001:db8:0:1::131/64 scope global \       valid_lft forever preferred_lft forever
2: eth0    inet6 fe80::21e:67ff:fe57:313d/64 scope link \       valid_lft forever preferred_lft forever

由于在这种情况下客户端知道其服务器驻留在同一台机器上,因此它会尝试连接到其自己的 IP 2001:db8:0:1::131 上的端口 443。

Apache 服务器作为反向代理运行,监听 443 并转发到 42502 上的服务器。

我的.conf文件:

ProxyPass /api/xml http://localhost4:42502 retry=0

聆听过程:

netstat -lnutp | grep "42502\|443"
tcp        0      0 0.0.0.0:42502               0.0.0.0:*                   LISTEN      68163/python
tcp        0      0 :::443                      :::*                        LISTEN      68513/httpd

因此 Apache 正确监听所有 IPv6 端口 443,而 python(Twisted)进程正在监听所有 IPv4 端口 42502。

localhost4 被适当地定义:

cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

并且可以 ping 通

ping localhost4
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.035 ms

但连接失败。Apache 的提示如下:

2001:db8:0:1::131 - -... "POST /api/xml HTTP/1.0" 502 396

[error] [client 2001:db8:0:1::131] proxy: DNS lookup failure for: localhost4 returned by /api/xml

看起来失败是 Apache 尝试访问 42502 上的 Python 进程。如果我将 localhost4 更改为明确指向 127.0.0.1,同样会失败。

有任何想法吗?

更新:确切的 Apache 版本:

rpm -qa | grep httpd
httpd-tools-2.2.15-30.el6.centos.x86_64
httpd-2.2.15-30.el6.centos.x86_64

更新:localhost4 上的服务器有响应

curl -g -k -X POST http://localhost4:42502
Unauthenticated user

更新:在端口 42503 上执行 tcpdump,我发现没有任何内容尝试发送到后端服务器。在 Apache 上执行 strace,我看到:

strace -p 89954 -f -ff -s 10
accept4(4, {sa_family=AF_INET6, sin6_port=htons(39850), inet_pton(AF_INET6, "2001:db8:0:1::131", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, [28], SOCK_CLOEXEC) = 13
semop(9928708, {{0, 1, SEM_UNDO}}, 1)   = 0
getsockname(13, {sa_family=AF_INET6, sin6_port=htons(443), inet_pton(AF_INET6, "2001:db8:0:1::131", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, [28]) = 0
fcntl(13, F_GETFL)                      = 0x2 (flags O_RDWR)
fcntl(13, F_SETFL, O_RDWR|O_NONBLOCK)   = 0
brk(0x7f27e6dbb000)                     = 0x7f27e6dbb000
read(13, "\26\3\1\0\364\1\0\0\360\3"..., 8000) = 249
writev(13, [{"\26\3\3\0:\2\0\0006\3"..., 2484}], 1) = 2484
poll([{fd=13, events=POLLIN}], 1, 65535000) = 1 ([{fd=13, revents=POLLIN}])
read(13, "\26\3\3\0\206\20\0\0\202\0"..., 8000) = 190
writev(13, [{"\26\3\3\0\312\4\0\0\306\0"..., 258}], 1) = 258
poll([{fd=13, events=POLLIN}], 1, 65535000) = 1 ([{fd=13, revents=POLLIN}])
read(13, "\27\3\3\0\341-\323\5\227\256"..., 8000) = 230
socket(PF_NETLINK, SOCK_RAW, 0)         = 14
bind(14, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 0
getsockname(14, {sa_family=AF_NETLINK, pid=89954, groups=00000000}, [12]) = 0
sendto(14, "\24\0\0\0\26\0\1\3N\25"..., 20, 0, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 20
recvmsg(14, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"0\0\0\0\24\0\2\0N\25"..., 4096}], msg_controllen=0, msg_flags=0}, 0) = 48
recvmsg(14, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"@\0\0\0\24\0\2\0N\25"..., 4096}], msg_controllen=0, msg_flags=0}, 0) = 192
recvmsg(14, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"\24\0\0\0\3\0\2\0N\25"..., 4096}], msg_controllen=0, msg_flags=0}, 0) = 20
close(14)                               = 0
open("/etc/hosts", O_RDONLY|O_CLOEXEC)  = 14
fstat(14, {st_mode=S_IFREG|0644, st_size=158, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f27e660f000
read(14, "127.0.0.1 "..., 4096)         = 158
read(14, "", 4096)                      = 0
close(14)                               = 0
munmap(0x7f27e660f000, 4096)            = 0
socket(PF_INET6, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 14
connect(14, {sa_family=AF_INET6, sin6_port=htons(53), inet_pton(AF_INET6, "2001:db8:0:1::128", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0
poll([{fd=14, events=POLLOUT}], 1, 0)   = 1 ([{fd=14, revents=POLLOUT}])
sendto(14, "0\315\1\0\0\1\0\0\0\0"..., 52, MSG_NOSIGNAL, NULL, 0) = 52
poll([{fd=14, events=POLLIN}], 1, 5000) = 1 ([{fd=14, revents=POLLIN}])
ioctl(14, FIONREAD, [133])              = 0
recvfrom(14, "0\315\205\203\0\1\0\0\0\1"..., 1024, 0, {sa_family=AF_INET6, sin6_port=htons(53), inet_pton(AF_INET6, "2001:db8:0:1::128", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, [28]) = 133
close(14)                               = 0
write(7, "[Wed Feb 0"..., 125)          = 125
poll([{fd=13, events=POLLIN}], 1, 65535000) = 1 ([{fd=13, revents=POLLIN}])
read(13, "\27\3\3\2\217-\323\5\227\256"..., 8000) = 660
writev(13, [{"\27\3\3\0\305)z\0A7"..., 627}], 1) = 627
write(10, "2001:db8:0"..., 84)          = 84
writev(13, [{"\25\3\3\0\32)z\0A7"..., 31}], 1) = 31
shutdown(13, 1 /* send */)              = 0
poll([{fd=13, events=POLLIN}], 1, 2000) = 1 ([{fd=13, revents=POLLIN|POLLERR|POLLHUP}])
read(13, 0x7fff9e1d5740, 512)           = -1 ECONNRESET (Connection reset by peer)
close(13)                               = 0
read(5, 0x7fff9e1d596f, 1)              = -1 EAGAIN (Resource temporarily unavailable)

以下行:

open("/etc/hosts", O_RDONLY|O_CLOEXEC)  = 14

显示正在查找并找到名称 localhost4:

read(14, "127.0.0.1 "..., 4096)         = 158

以下行:

write(7, "[Wed Feb 0"..., 125)          = 125

是输出到错误日志的错误。

到目前为止的结论是:一旦客户端向 Apache 发出请求,Apache 就无法成功连接到 localhost4。我没有看到任何证据表明 Apache 甚至试图打开连接。尽管 netstat 显示 python 已成功打开并正在该地址和端口上监听,但 Apache 似乎找不到它。

相关内容