Comment obtenir votre propre (local) Adresse IP à partir d'un udp socket (C/C++)

StackOverflow https://stackoverflow.com/questions/29890

  •  09-06-2019
  •  | 
  •  

Question

  1. Vous avez plusieurs cartes réseau.
  2. Lier un socket UDP à un port local, sans spécifier une adresse.
  3. Recevoir des paquets sur une des cartes.

Comment obtenez-vous l'adresse ip locale de l'adaptateur qui a reçu le paquet?

La question est: "Quelle est l'adresse ip du récepteur adaptateur?" non à l'adresse de l'expéditeur de laquelle nous avons, dans le

receive_from( ..., &senderAddr, ... );

appel.

Était-ce utile?

La solution

Vous pourrait énumérer tous les cartes réseau, obtenir leurs adresses IP et de comparer la partie recouverte par le masque de sous-réseau avec l'adresse de l'expéditeur.

Comme:

IPAddress FindLocalIPAddressOfIncomingPacket( senderAddr )
{
    foreach( adapter in EnumAllNetworkAdapters() )
    {
        adapterSubnet = adapter.subnetmask & adapter.ipaddress;
        senderSubnet = adapter.subnetmask & senderAddr;
        if( adapterSubnet == senderSubnet )
        {
            return adapter.ipaddress;
        }
    }
}

Autres conseils

G'day,

Je suppose que vous avez fait votre lier à l'aide d'INADDR_ANY de spécifier l'adresse.

Si c'est le cas, alors la sémantique de INADDR_ANY est telle qu'une socket UDP est créé sur le port spécifié sur l'ensemble de vos interfaces.Le socket va récupérer tous les paquets envoyés à toutes les interfaces sur le port spécifié.

Lors de l'envoi à l'aide de cette prise, le plus petit numéro d'interface est utilisé.Les sortants adresse de l'expéditeur est indiqué dans le champ adresse IP de ce premier sortant de l'interface utilisée.

Première interface de sortie est définie comme la séquence lorsque vous faites une commande ifconfig-a.Il sera probablement eth0.

HTH.

cheers, Rob

La solution fournie par timbo suppose que les plages d'adresses sont uniques et ne pas se chevaucher.Tout cela est généralement le cas, ce n'est pas une solution générique.

Il est une excellente mise en œuvre d'une fonction qui fait exactement ce que vous êtes après fournies dans l'Steven livre "Unix network programming" (article 20.2) C'est une fonction sur la base recvmsg(), plutôt que de recvfrom().Si votre socket a la IP_RECVIF option est activée alors recvmsg() retourne l'index de l'interface sur laquelle le paquet a été reçu.Cela peut ensuite être utilisé pour rechercher l'adresse de destination.

Le code source est disponible ici.La fonction en question est " recvfrom_flags()'

Malheureusement, le sendto et recvfrom des appels d'API sont fondamentalement brisé lorsqu'il est utilisé avec les sockets lié à "Tout IP", car ils n'ont pas de champ pour l'adresse IP locale de l'information.

Alors, que pouvez-vous faire à ce sujet?

  1. Vous pouvez le deviner (par exemple basé sur la table de routage).
  2. Vous pouvez obtenir une liste des adresses locales et de se lier à une prise séparée pour chaque adresse locale.
  3. Vous pouvez utiliser les nouvelles Api à l'appui de cette information.Il y a deux parties, tout d'abord, vous devez utiliser le ème option de socket (ip_recvif pour IPv4, ipv6_recvif pour IPv6) pour dire à la pile que vous souhaitez cette information.Ensuite, vous devez utiliser une autre fonction (recvmsg sur linux et d'autres systèmes de type unix, WSArecvmsg sur windows) pour recevoir le paquet.

Aucune de ces options est grande.La supposition évidemment de produire des réponses incorrectes soemtimes.La liaison séparée sockets augmente la complexité de votre logiciel et source de problèmes si la liste des adresses locales des changements de votre programme est en cours d'exécution.Les nouvelles Api sont la bonne technique soloution mais peut réduire la portabilité (en particulier, il ressemble à WSArecvmsg n'est pas disponible sur windows XP) et peut exiger des modifications à la prise de wrapper de la bibliothèque que vous utilisez.

Edit semble que j'ai été mauvais, il semble que le MS documentation est trompeuse et que WSArecvmsg est disponible sur windows XP.Voir https://stackoverflow.com/a/37334943/5083516

ssize_t
     recvfrom(int socket, void *restrict buffer, size_t length, int flags,
         struct sockaddr *restrict address, socklen_t *restrict address_len);

     ssize_t
     recvmsg(int socket, struct msghdr *message, int flags);

[..]
     If address is not a null pointer and the socket is not connection-oriented, the
     source address of the message is filled in.

Code:

int nbytes = recvfrom(sock, buf, MAXBUFSIZE, MSG_WAITALL, (struct sockaddr *)&bindaddr, &addrlen);

fprintf(stdout, "Read %d bytes on local address %s\n", nbytes, inet_ntoa(bindaddr.sin_addr.s_addr));

espérons que cette aide.

Essayez ceci:

gethostbyname("localhost");
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top