2011-09-19 1 views
11

Je gère GPSD, un démon de service open-source largement déployé qui surveille les GPS et autres capteurs géodésiques. Il écoute les connexions client-application sur le port 2947 sur IPv4 et IPv6. Pour la sécurité et la confidentialité, il n'écoute normalement que sur l'adresse de bouclage, mais il existe une option -G pour le démon qui doit l'écouter sur n'importe quelle adresse. Le problème: l'option -G fonctionne en IPv4, mais je n'arrive pas à comprendre comment le faire fonctionner avec IPv6. La méthode qui devrait fonctionner sur la base de divers exemples de tutoriel ne produit pas, produisant plutôt une erreur suggérant que l'adresse est déjà utilisée. Je cherche de l'aide pour résoudre ce problème auprès des personnes expérimentées en programmation réseau IPv6.Comment écouter sur toutes les adresses IPV6 utilisant des sockets C API

Code pertinente est http://git.berlios.de/cgi-bin/gitweb.cgi?p=gpsd;a=blob;f=gpsd.c;h=ee2156caf03ca23405f57f3e04e9ef306a75686f;hb=HEAD

Ce code fonctionne correctement dans les deux cas -G et non -G sous IPv4, comme il est difficile à cerner avec netstat -l.

Regardez maintenant autour de la ligne 398 après "cas AF_INET6:". L'option listen_global est définie par -G; quand faux, le code réussit. Il y a actuellement un commentaire ci-dessous, héritée d'un contributeur inconnu, qui se lit comme ceci:

/* else */ 
     /* BAD: sat.sa_in6.sin6_addr = in6addr_any; 
    * the simple assignment will not work (except as an initializer) 
    * because sin6_addr is an array not a simple type 
    * we could do something like this: 
    * memcpy(sat.sa_in6.sin6_addr, in6addr_any, sizeof(sin6_addr)); 
    * BUT, all zeros is IPv6 wildcard, and we just zeroed the array 
    * so really nothing to do here 
    */ 

Selon divers exemples tutoriel, j'ai levé les yeux, l'affectation « sat.sa_in6.sin6_addr = in6addr_any; » est (malgré le commentaire) correct, et il compile. Cependant, le démarrage avec -G échoue en déclarant que l'adresse d'écoute est déjà utilisée.

L'affectation "sat.sa_in6.sin6_addr = in6addr_any;" nominalement correct ici? Quoi d'autre, s'il y a quelque chose, est-ce que je manque?

+0

Avez-vous essayé de mettre le démon en place? – jpalecek

Répondre

19

La raison pour laquelle l'adresse est déjà utilisée est que, sur de nombreuses piles réseau IPv6, par défaut, un socket IPv6 écoute à la fois IPv4 et IPv6 en même temps. Les connexions IPv4 seront traitées de manière transparente et mappées à subset of the IPv6 space. Cependant, cela signifie que vous ne pouvez pas vous connecter à un socket IPv6 sur le même port qu'un socket IPv4 sans modifier les paramètres sur le socket IPv6. Avoir du sens?

Il suffit de faire cela avant votre appel à bind (cela est pris d'un de mes projets):

int on = 1; 
if (addr->sa_family == AF_INET6) { 
    r = setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); 
    if (r) 
     /* error */ 
} 

Malheureusement, il n'y a pas de valeur par défaut sur toutes les plateformes pour IPV6_V6ONLY - ce qui signifie essentiellement que vous devez toujours Activez-le ou désactivez-le explicitement si vous y tenez, à moins que vous ne vous souciez pas des autres plates-formes. Linux laisse désactivé par défaut, Windows laisse par défaut ...

+1

La valeur par défaut de Linux est en fait de sysctl. Vous ne pouvez donc pas compter sur la valeur par défaut. Mais si le sysadmin n'a pas changé, il est désactivé par défaut. (off est l'OMI par défaut la plus raisonnable). –

+1

Votre réponse est correcte et mon bug est corrigé. Je vous remercie. – ESR

1

D'un coup d'oeil dans un système de fichiers de Linux aléatoire comprennent, in6addr_any est déclarée comme ceci:

extern const struct in6_addr in6addr_any;  /* :: */ 
extern const struct in6_addr in6addr_loopback; /* ::1 */ 
#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } 

Alors, peut-être la proximité de le tableau INIT a confondu celui qui a laissé ce commentaire dans les sources de GPSD. Le type réel est clairement struct in6_addr, qui est assignable. J'ai regardé autour de moi et j'ai trouvé quelques indices qui suggéraient que si IPv4 écoute déjà l'adresse "any", IPv6 ne le peut pas. Peut-être que c'est ce qui vous mord.

+0

La deuxième partie de votre diagnostic est correcte (voir la réponse de Dietrich Epp) et je pense que vous avez raison sur la première partie également. – ESR

Questions connexes