Подтвердить что ты не робот

Как прослушивать все адреса IPV6 с помощью API сокетов S

Я поддерживаю GPSD, широко развернутый демон службы с открытым исходным кодом, который контролирует GPS и другие геодезические датчики. Он прослушивает соединения клиент-приложение на порту 2947 как на IPv4, так и на IPv6. Для обеспечения безопасности и конфиденциальности он обычно прослушивает только адрес loopback, но есть опция -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;" номинально исправить здесь? Что еще, если что-нибудь, мне не хватает?

4b9b3361

Ответ 1

Причина, по которой адрес уже используется, заключается в том, что по многим сетевым стекам 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 по умолчанию отключает его...

Ответ 2

От взгляда в случайной системе 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 также не может. Возможно, это вас кусает.