Pergunta

Se um soquete é obrigado a IN6ADDR_ANY ou INADDR_ANY e você usar uma chamada como recvfrom() para receber mensagens no soquete. Existe uma maneira de descobrir qual a interface a mensagem veio?

No caso de mensagens de ligação de alcance IPv6, eu estava esperando que a partir de argumento de recvfrom() teria o campo scope_id inicializada com o Id interface. Infelizmente ele está definido para 0 no meu programa de teste.

Alguém sabe de uma maneira de descobrir esta informação?

Foi útil?

Solução

Além de ligação a cada interface, eu não estou ciente de uma maneira com IPv4, per se.

IPv6 adicionou a opção de socket IPV6_PKTINFO para suprir esta deficiência. Com essa opção com efeito, uma struct in6_pktinfo serão devolvidos como dados auxiliares.

Outras dicas

dwc é certo, IPV6_PKTINFO irá trabalhar para IPv6 em Linux.

Além disso, IP_PKTINFO irá trabalhar para IPv4 - você pode ver detalhes na página de manual ip (7)

eu construí um exemplo que extrai os endereços de origem, de destino e de interface. Para abreviar, nenhuma verificação de erro é fornecida. Veja este duplicado:. obter o endereço de destino de um recebeu UDP pacote

// sock is bound AF_INET socket, usually SOCK_DGRAM
// include struct in_pktinfo in the message "ancilliary" control data
setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt));
// the control data is dumped here
char cmbuf[0x100];
// the remote/source sockaddr is put here
struct sockaddr_in peeraddr;
// if you want access to the data you need to init the msg_iovec fields
struct msghdr mh = {
    .msg_name = &peeraddr,
    .msg_namelen = sizeof(peeraddr),
    .msg_control = cmbuf,
    .msg_controllen = sizeof(cmbuf),
};
recvmsg(sock, &mh, 0);
for ( // iterate through all the control headers
    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&mh);
    cmsg != NULL;
    cmsg = CMSG_NXTHDR(&mh, cmsg))
{
    // ignore the control headers that don't match what we want
    if (cmsg->cmsg_level != IPPROTO_IP ||
        cmsg->cmsg_type != IP_PKTINFO)
    {
        continue;
    }
    struct in_pktinfo *pi = CMSG_DATA(cmsg);
    // at this point, peeraddr is the source sockaddr
    // pi->ipi_spec_dst is the destination in_addr
    // pi->ipi_addr is the receiving interface in_addr
}

Tem sido um tempo desde que eu estive fazendo C / C ++ TCP / IP de codificação, mas tanto quanto eu me lembro em cada mensagem (ou tomada de derivados), você pode entrar em informações do IP cabeçalhos. Estes cabeçalhos deve incluir o endereço de recepção que será o IP da interface que você está perguntando.

Fora de abrir um soquete separado em cada interface como Glomek sugerido, a única forma que conheço para fazer isso definitivamente no Windows é usar um socket raw, por exemplo.,

  SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_IP);

Cada receber deste socket será um IP pacote , que contém tanto a origem eo endereços de destino. O programa que eu trabalho em me obriga a colocar o socket em modo promíscuo usando a opção SIO_RCVALL. Fazer isso significa que eu recebo todos os pacotes IP da interface "vê" na rede. Para extrair pacotes expressamente para a minha aplicação requer me para filtrar os dados usando os endereços e portas nos cabeçalhos IP e TCP / UDP. . Obviamente, isso é provavelmente mais sobrecarga do que você está interessado em eu só mencioná-lo dizer isso - eu nunca usei um socket raw sem colocá-lo em modo promíscuo. Então, eu não tenho certeza se você pode vinculá-lo a INADDR_ANY e apenas usá-lo como uma tomada regular a partir desse ponto em diante ou não. Parece-me que você pode; Eu apenas nunca tentou fazê-lo.

EDIT: Leia este artigo para limitações quanto sockets no Windows. Esta maior obstáculo que enfrentou no meu projeto era que um tem que ser um membro do grupo Administradores para abrir um socket raw no Windows 2000 e mais tarde.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top