Как прослушивать все адреса IPV6 с помощью API-интерфейса C sockets - PullRequest
11 голосов
/ 19 сентября 2011

Я поддерживаю GPSD, широко распространенный сервисный демон с открытым исходным кодом, который отслеживает GPS и другие геодезические датчики. Он прослушивает соединения клиентских приложений через порт 2947 как на IPv4, так и на IPv6. В целях безопасности и конфиденциальности он обычно прослушивает только адрес обратной связи, но есть опция -G для демона, которая предназначена для того, чтобы заставить его прослушивать любой адрес.

Проблема: опция -G работает в IPv4, но я не могу понять, как заставить ее работать с IPv6. Метод, который должен работать на основе различных учебных примеров, не работает, вместо этого выдается ошибка, указывающая, что адрес уже используется. Мне нужна помощь, чтобы исправить это от людей, имеющих опыт программирования в сети IPv6.

Соответствующий код на http://git.berlios.de/cgi-bin/gitweb.cgi?p=gpsd;a=blob;f=gpsd.c;h=ee2156caf03ca23405f57f3e04e9ef306a75686f;hb=HEAD

Этот код работает правильно как в случаях -G, так и в случаях не -G в IPv4, что легко проверить с помощью netstat -l.

Теперь посмотрите вокруг строки 398 после "case AF_INET6:". Параметр listen_global устанавливается с помощью -G; если false, код успешно выполняется. В настоящее время существует следующий комментарий, унаследованный от неизвестного участника, который выглядит следующим образом:

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

Согласно различным учебным примерам, которые я посмотрел, задание "sat.sa_in6.sin6_addr = in6addr_any;" (несмотря на комментарий) правильно, и он компилируется. Тем не менее, запуск с -G не удается, утверждая, что адрес прослушивания уже используется.

Является ли задание "sat.sa_in6.sin6_addr = in6addr_any;" номинально правильно здесь? Что еще, если что, я пропускаю?

Ответы [ 2 ]

20 голосов
/ 19 сентября 2011

Причина, по которой адрес уже используется, заключается в том, что во многих сетевых стеках IPv6 сокет IPv6 по умолчанию будет одновременно прослушивать как IPv4, так и IPv6. Соединения IPv4 будут обрабатываться прозрачно и отображаться в подмножество пространства IPv6 . Однако это означает, что вы не можете привязать сокет IPv6 к тому же порту, что и сокет IPv4, не изменив настройки сокета IPv6. Имеет смысл?

Просто сделайте это до звонка на bind (это взято из одного из моих проектов):

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

К сожалению, для IPV6_V6ONLY по умолчанию нет значения по умолчанию для платформ *, что в основном означает, что вам всегда нужно явно включать или выключать его, если вам не безразличны другие платформы. Linux выключает его по умолчанию, Windows оставляет его включенным по умолчанию ...

1 голос
/ 19 сентября 2011

Из списка включаемых файлов случайной системы Linux, in6addr_any объявлен так:

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

Так что, возможно, близость к массиву INIT смутила любого, кто оставил этот комментарий в источниках GPSD. Фактический тип явно struct in6_addr, который можно назначить.

Я огляделся и обнаружил некоторые подсказки, которые подсказывают, что если IPv4 уже прослушивает «любой» адрес, IPv6 также не может. Возможно, это то, что кусает тебя.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...