2011-09-19 15 views
11

Mantengo GPSD, un daemon de servicio open-source ampliamente implementado que monitorea los GPS y otros sensores geodésicos. Escucha conexiones de aplicación de cliente en el puerto 2947 en ambos IPv4 e IPv6. Por razones de seguridad y privacidad, normalmente solo escucha en la dirección de bucle invertido, pero hay una opción -G para el daemon que tiene la intención de hacer que escuche en cualquier dirección.Cómo escuchar en todas las direcciones IPV6 con sockets C API

El problema: la opción -G funciona en IPv4, pero no entiendo cómo hacer que funcione con IPv6. El método que debería funcionar basado en varios ejemplos de tutoriales no lo hace, lo que produce un error que sugiere que la dirección ya está en uso. Estoy buscando ayuda para solucionar esto por parte de personas con experiencia en programación de redes IPv6.

código pertinente se encuentra en http://git.berlios.de/cgi-bin/gitweb.cgi?p=gpsd;a=blob;f=gpsd.c;h=ee2156caf03ca23405f57f3e04e9ef306a75686f;hb=HEAD

Este código funciona correctamente en los casos tanto el -G y no -G menores de IPv4, como se verifica fácilmente con -l netstat.

Ahora mire alrededor de la línea 398 después de "caso AF_INET6:". La opción listen_global está establecida por -G; cuando es falso, el código tiene éxito. Existe actualmente un siguiente comentario, heredado de un colaborador desconocido, que se lee como este:

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

Según diversos ejemplos del manual He hacia arriba, la asignación "sat.sa_in6.sin6_addr = in6addr_any;" es (a pesar del comentario) correcto y compila. Sin embargo, el inicio con -G falla al afirmar que la dirección de escucha ya está en uso.

es la asignación "sat.sa_in6.sin6_addr = in6addr_any;" nominalmente correcto aquí? ¿Qué más, en todo caso, me estoy perdiendo?

+0

¿Intentaste dar cuerda al daemon? – jpalecek

Respuesta

19

La razón por la que la dirección ya está en uso es porque en muchas pilas de redes IPv6, de forma predeterminada, un socket IPv6 escuchará tanto IPv4 como IPv6 al mismo tiempo. Las conexiones IPv4 se manejarán de forma transparente y se correlacionarán con un subset of the IPv6 space. Sin embargo, esto significa que no puede vincularse a un zócalo IPv6 en el mismo puerto que un zócalo IPv4 sin cambiar la configuración en el zócalo IPv6. ¿Tener sentido?

Sólo hacer esto antes de su llamada a bind (esto es tomado de uno de mis proyectos):

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

Por desgracia, no hay ningún valor por defecto en todas las plataformas para IPV6_V6ONLY - que básicamente significa que siempre hay que activarlo o desactivarlo explícitamente si te importa, a menos que no te importen otras plataformas. Linux deja desactivada por defecto, Windows deja de forma predeterminada ...

+1

El valor predeterminado de Linux es en realidad de sysctl. Por lo tanto, no puede confiar en el valor predeterminado allí. Pero si el administrador del sistema no lo ha cambiado, se desactiva de manera predeterminada. (off es el IMO predeterminado más razonable). –

+1

Tu respuesta es correcta y mi error es reparado. Gracias. – ESR

1

De un vistazo en los archivos de incluir un sistema Linux al azar, in6addr_any se declara así:

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

Por lo tanto, tal vez la cercanía a el arreglo INIT confundió a quien dejó ese comentario en las fuentes de GPSD. El tipo real es claramente struct in6_addr, que es asignable.

Miré a mi alrededor y encontré algunos indicios que sugerían que si IPv4 ya está escuchando la dirección "cualquiera", IPv6 no puede. Quizás eso es lo que te está mordiendo.

+0

La segunda parte de su diagnóstico es correcta (consulte la respuesta de Dietrich Epp) y sospecho que tiene razón acerca de la primera parte también. – ESR

Cuestiones relacionadas