Question

Si un socket est lié à IN6ADDR_ANY ou INADDR_ANY et que vous utilisez un appel tel que recvfrom () pour recevoir des messages sur le socket. Existe-t-il un moyen de savoir de quelle interface provient le message?

Dans le cas des messages IPv6 link-scope, j'espérais que l'argument from de recvfrom () aurait le champ scope_id initialisé à l'interface Id. Malheureusement, il est réglé sur 0 dans mon programme de test.

Quelqu'un connaît-il un moyen de découvrir cette information?

Était-ce utile?

La solution

Hormis la liaison à chaque interface, je ne suis pas au courant d'un moyen d'utiliser IPv4 en tant que tel.

IPv6 a ajouté l’option de socket IPV6_PKTINFO pour remédier à cette lacune. Lorsque cette option est activée, une struct in6_pktinfo sera renvoyée en tant que données auxiliaires.

Autres conseils

dwc a raison, IPV6_PKTINFO fonctionnera pour IPv6 sous Linux.

De plus, IP_PKTINFO fonctionnera pour IPv4 - vous pouvez voir les détails dans la page de manuel ip (7)

J'ai construit un exemple qui extrait les adresses de source, de destination et d'interface. Par souci de concision, aucune vérification d'erreur n'est fournie. Consultez cette copie: Obtenez l'adresse de destination d'un paquet UDP reçu .

// 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
}

Cela fait longtemps que je n’utilise pas le codage C / C ++ TCP / IP, mais dans la mesure où je me souviens de chaque message (ou socket dérivé), vous pouvez accéder aux informations des en-têtes IP. Ces en-têtes doivent inclure l'adresse de réception qui sera l'adresse IP de l'interface sur laquelle vous parlez.

En dehors de l’ouverture d’une socket distincte sur chaque interface, comme l’a suggéré Glomek, le seul moyen de le faire définitivement sous Windows consiste à utiliser une socket brute, par exemple,

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

Chaque destinataire de ce socket sera un paquet IP , contenant à la fois les sources et adresses de destination. Le programme sur lequel je travaille nécessite que je mette le socket en mode espion à l'aide de l'option SIO_RCVALL. Cela signifie que je reçois chaque paquet IP par l’interface "voit". sur le réseau. Pour extraire des paquets expressément pour mon application, je dois filtrer les données en utilisant les adresses et les ports des en-têtes IP et TCP / UDP. Évidemment, cela représente probablement plus de frais généraux que ce qui vous intéresse. Je le mentionne simplement pour dire ceci: je n'ai jamais utilisé de socket brut sans le mettre en mode promiscuous. Donc, je ne sais pas si vous pouvez le lier à INADDR_ANY et l'utiliser comme un socket ordinaire à partir de ce moment ou non. Il me semble que vous le pouvez; Je n’ai jamais essayé.

MODIFIER: lire ce article pour les limitations concernant les sockets bruts sous Windows. Le plus gros obstacle que j'ai rencontré dans mon projet était qu'il fallait être membre du groupe Administrateurs pour ouvrir une socket brute sous Windows 2000 et versions ultérieures.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top