Назад | Перейти на главную страницу

Обратный прокси 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

Поскольку в этом случае клиент знает, что его сервер находится на том же компьютере, он пытается подключиться к порту 443 по собственному IP-адресу 2001: db8: 0: 1 :: 131.

Сервер 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 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 пытается связаться с процессом Python на 42502. Если я изменю 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

ОБНОВЛЕНИЕ: Выполняя tcpdump на порту 42503, я вижу, что ничего не отправляется на внутренний сервер. Выполняя strace на Apache, я вижу:

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 даже пытался открыть соединение. Кажется, что Apache не может найти его, хотя netstat показывает, что python успешно открыт и прослушивает этот адрес и порт.