web-dev-qa-db-fra.com

Comment prendre en charge les connexions IPv4 et IPv6

Je travaille actuellement sur une application de socket UDP et je dois intégrer la prise en charge afin que les connexions IPV4 et IPV6 puissent envoyer des paquets à un serveur.

J'espérais que quelqu'un pourrait m'aider et me diriger dans la bonne direction; la majorité de la documentation que j'ai trouvée n'était pas complète. Il serait également utile de signaler les différences entre les sockets Winsock et BSD.

Merci d'avance!

52
Charles

La meilleure approche consiste à créer un socket de serveur IPv6 qui peut également accepter des connexions IPv4. Pour ce faire, créez un socket IPv6 standard, désactivez l'option socket IPV6_V6ONLY, liez-le à l'adresse "any" et commencez à recevoir. Les adresses IPv4 seront présentées comme des adresses IPv6, au format mappé IPv4 .

La principale différence entre les systèmes est de savoir si IPV6_V6ONLY est a) disponible et b) activé ou désactivé par défaut. Il est désactivé par défaut sous Linux (c'est-à-dire autorisant les sockets à double pile sans setsockopt), et est activé sur la plupart des autres systèmes.

De plus, la pile IPv6 sous Windows XP ne prend pas en charge cette option. Dans ces cas, vous devrez créer deux sockets de serveur distincts et les placer dans select ou dans plusieurs threads.

80
Martin v. Löwis

L'API de socket est régie par les RFC IETF et doit être la même sur toutes les plates-formes, y compris Windows WRT IPv6.

Pour les applications IPv4/IPv6, c'est ALL about getaddrinfo() and getnameinfo(). getaddrinfo est un génie - regarde le DNS, les noms de port et les capacités du client pour résoudre la question éternelle de "puis-je utiliser IPv4, IPv6 ou les deux pour atteindre une destination particulière?" Ou si vous allez route à double pile et que vous souhaitez qu'elle renvoie des adresses IPv6 mappées IPv4, elle le fera également.

Il fournit une structure directe sockaddr * Qui peut être connectée à bind(), recvfrom(), sendto() et la famille d'adresses pour socket()… Dans de nombreux cas, cela signifie pas de structures sockaddr_in(6) en désordre à remplir et à gérer.

Pour les implémentations UDP, je ferais attention de définir des sockets à double pile ou, plus généralement, de lier à toutes les interfaces (INADDR_ANY). Le problème classique est que, lorsque les adresses ne sont pas verrouillées (voir bind()) vers des interfaces spécifiques et que le système a plusieurs demandes d'interfaces, les réponses peuvent transiter à partir d'adresses différentes pour des ordinateurs avec plusieurs adresses en fonction des caprices du Table de routage du système d'exploitation, protocoles d'application déroutants, en particulier tous les systèmes ayant des exigences d'authentification.

Pour les implémentations UDP où ce n'est pas un problème, ou TCP, les sockets à double pile peuvent gagner beaucoup de temps lors de l'activation d'IPv * sur votre système. Il faut faire attention à ne pas compter entièrement sur la double pile là où ce n'est pas absolument nécessaire car il n'y a pas de pénurie de plates-formes raisonnables (Old Linux, BSD, Windows 2003) déployées avec des piles IPv6 non capables de sockets double pile.

7
Einstein

J'ai joué avec cela sous Windows et cela semble être un problème de sécurité, si vous vous liez à l'adresse de bouclage, le socket IPv6 est correctement lié à [:: 1] mais le socket IPv4 mappé est lié à INADDR_ANY , de sorte que votre application locale (supposée) en toute sécurité est réellement exposée au monde.

4
Dave

Les RFC ne spécifient pas vraiment l'existence de l'option de socket IPV6_V6ONLY, mais, si elle est absente, les RFC indiquent assez clairement que l'implémentation doit être comme si cette option était FALSE.

Lorsque l'option est présente, je dirais qu'elle devrait être FALSE par défaut, mais, pour des raisons de compréhension, les implémentations BSD et Windows par défaut sont TRUE. Il y a une affirmation bizarre qu'il s'agit d'un problème de sécurité car un programmeur IPv6 inconnu pourrait se lier en pensant qu'il ne se liait qu'à IN6ADDR_ANY pour IPv6 uniquement et accepter accidentellement une connexion IPv4 provoquant un problème de sécurité. Je pense que c'est à la fois farfelu et absurde en plus d'une surprise pour quiconque s'attend à une mise en œuvre conforme à la RFC.

Dans le cas de Windows, la non-conformité ne sera généralement pas une surprise. Dans le cas de BSD, c'est au mieux malheureux.

3
Owen DeLong