Como o Apache pode ser configurado para escutar em um único endereço IPv6 que não pertence a uma interface?

3

Estou tentando configurar vários vhosts do Apache SSL, cada um em um endereço IPv6 diferente.

Meu VOS do CentOS7 tem um bloco IPv4 roteado / 64 atribuído a ele, digamos 2001:db8:acac:acac::/64 , e já consigo ver pacotes chegando ( tcpdump -nn -i eth0 'ip6 and src or dst net 2001:db8:acac:acac::/64' mostra os pacotes bem).

Estou ciente de que posso designar quantos endereços individuais eu quiser para eth0 ( ip -6 addr add 2001:db8:acac:acac::1234 dev eth0 ), mas quero que a interface permita que os aplicativos se liguem a qualquer um dos 2 ^ 64 endereços.

Seguindo os conselhos (veja os links na parte inferior), adicionei uma regra ( ip -6 rule add from 2001:db8:acac:acac::/64 iif eth0 lookup 200 ) e uma rota ( ip route add local 2001:db8:acac:acac::/64 dev lo table 200 ) e agora posso ping6 de qualquer endereço IP no bloco / 64 e posso me conectar a serviços escutando em curinga (por exemplo, :::22 para ssh) usando qualquer endereço no bloco / 64.

A questão é: como posso fazer um programa vincular-se a um endereço único no bloco / 64? Como nenhuma interface possui nenhum dos endereços no bloco, vejo o seguinte nos logs do apache:

... AH00072: make_sock: could not bind to address [2001:db8:acac:acac::1234]:443

Eu tenho visto menções de IP_TRANSPARENT como uma possível solução, mas não consigo encontrar isso mencionado na fonte do Apache, apenas em bits/in.h , incluído por netinet/in.h .

Alguém já fez isso funcionar, seja para o Apache ou para outros aplicativos (em particular: dovecot, postfix, bind)?

Artigos relevantes lidos antes de postar esta pergunta:

por Ashley GC 10.12.2015 / 17:46

2 respostas

0

Você pode atribuir esse endereço a qualquer interface. Por exemplo, atribua-o a lo (além de :: 1). O IPv6 é muito bom em ter vários endereços em qualquer interface. Então, depois de tornar o endereço local, você pode ouvi-lo.

UPD: Como eu vejo, essa ideia não difere muito da mencionada no seu primeiro link sobre atribuição de bloco de endereços para lo. Essencialmente, isso é o mesmo, mas o bloco é degenerado para um único endereço.

    
por 10.12.2015 / 18:04
0

Embora eu ainda não tenha conseguido fazer com que o apache se vincule a um único endereço que não pertence a uma interface, fiz um programa C de teste que funciona e pode vincular a qualquer endereço IPv6 , independentemente de o endereço pertencer a uma interface:

/*
  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);
     }
}
    
por 12.12.2015 / 16:12