我试图设置多个Apache SSL虚拟主机,每个在不同的IPv6地址。
我的CentOS7 VPS有一个路由/ 64 IPv6块分配给它,让我们说2001:db8:acac:acac::/64 ,我已经可以看到数据包进入( tcpdump -nn -i eth0 'ip6 and src or dst net 2001:db8:acac:acac::/64'显示数据包正常)。
我知道我可以分配尽可能多的个人地址,我喜欢eth0( ip -6 addr add 2001:db8:acac:acac::1234 dev eth0 ),但我想要的接口允许应用程序绑定到任何2 ^ 64地址。
以下的build议(见底部链接),我添加了一个规则( ip -6 rule add from 2001:db8:acac:acac::/64 iif eth0 lookup 200 )和一个路由( ip route add local 2001:db8:acac:acac::/64 dev lo table 200 ),现在我可以在/ 64块中ping6任何IP地址,并且可以使用/ 64块中的任何地址连接到通配符上监听的服务(例如,ssh为:::22 ) 。
问题是:如何让程序绑定到/ 64块中的单个地址? 由于没有接口拥有块中的任何地址,我在apache日志中看到以下内容:
... AH00072: make_sock: could not bind to address [2001:db8:acac:acac::1234]:443
我已经看到提到IP_TRANSPARENT作为一种可能的解决scheme,但是在Apache源代码中只能findnetinet/in.h包含的bits/in.h
有没有人得到这个工作,为Apache或其他应用程序(特别是:dovecot,后缀,绑定)?
发布这个问题之前阅读相关文章:
您可以将该地址分配给绝对的任何接口。 例如,将其分配给lo(除了:: 1)。 IPv6在任何接口上都有多个地址是相当不错的。 那么,当你把地址写在本地后,你可以听它。
UPD:正如我所看到的,这个想法与你在第一个关于分配地址块给lo的链接中提到的没什么不同。 本质上这是一样的,但块被简化为一个地址。
虽然我还没有能够将apache绑定到一个不属于接口的单个地址,但是我做了一个testingC程序,它可以工作,并且可以绑定到任何IPv6地址,而不pipe该地址是否属于接口:
/* Test program to bind to an IPv6 address not owned by an interface. This code is from public domain sources, and is released into the public domain. */ #include <arpa/inet.h> #include <error.h> #include <errno.h> #include <net/if.h> #include <netinet/in.h> // also includes bits/in.h #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> // also includes bits/ioctls.h #include <sys/socket.h> #include <sys/types.h> #include <time.h> #include <unistd.h> // A real address to use as a sanity check and make sure the program can // bind to an address which *is* owned by an interface #define REALADDR {{{0x2a,0x00, ...}}} // A fake address to show the program can bind to an address which is *not* // owned by any interface #define SOMEADDR {{{0x20,0x01, 0x0d,0xb8, 0x00,0x00, 0x00,0x00, \ 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x01 }}} int main(int argc, char *argv[]) { struct sockaddr_in6 serv_addr; int listenfd = 0, connfd = 0, i; char sendBuff[1025]; time_t ticks; listenfd = socket(AF_INET6, SOCK_STREAM, 0); printf("socket fd is %d\n", listenfd); memset(&serv_addr, 0, sizeof(serv_addr)); memset(sendBuff, 0, sizeof(sendBuff)); serv_addr.sin6_family = AF_INET6; serv_addr.sin6_port = htons(5000); struct in6_addr someaddr = SOMEADDR; serv_addr.sin6_addr = someaddr; // Here's the magic: int opt = 1; if (setsockopt(listenfd, SOL_IP, IP_FREEBIND, &opt, sizeof(opt)) < 0) error(1, errno, "setsockopt(IP_FREEBIND) failed"); printf("Binding to "); for (i = 0; i < 14; i += 2) printf("%x:", (serv_addr.sin6_addr.s6_addr[i] << 8) + serv_addr.sin6_addr.s6_addr[i+1]); printf("%x\n", (serv_addr.sin6_addr.s6_addr[14] << 8) + serv_addr.sin6_addr.s6_addr[15]); if (bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) error(1, errno, "bind failed"); if (listen(listenfd, 10) < 0) error(1, errno, "listen failed"); while(1) { connfd = accept(listenfd, (struct sockaddr*)NULL, NULL); printf("accept returned %d\n", connfd); // Send some data - the current date and time. ticks = time(NULL); snprintf(sendBuff, sizeof(sendBuff), "Now is %.24s\r\n", ctime(&ticks)); write(connfd, sendBuff, strlen(sendBuff)); close(connfd); sleep(1); } }