Linux C ++ IPv6 UDP Многоадресная отправка завершается неудачно с ошибкой EADDRNOTAVAIL (99) Невозможно назначить запрошенный адрес - PullRequest
0 голосов
/ 03 апреля 2020

Я пытаюсь отправить многоадресные сообщения UDP IPv6.

В приведенном ниже тестовом коде показаны две части: одна для отправки многоадресных сообщений IPv6, а другая для отправки многоадресных сообщений IPv4.

Код для IPv4 работает нормально.

Код для IPv6 всегда завершается ошибкой в ​​sendto, возвращаясь с EADDRNOTAVAIL (99) Невозможно назначить запрошенный адрес.

...

  if (ipV6Select)
  {
    // Create IPv6 DGRAM Socket
    int sock = socket(AF_INET6, SOCK_DGRAM, 0);
    if (sock < 0)
      throw OIP::OipException(OIP_SOCK_ACTION_FAILED("Cannot set socket option IPV6 socket, socket function failed with retVal " <<
                                                      sock << " (errno=" << strerror(errno) << " (" << errno << ")."));

    // Register multicast interface.
    int ifIdx{static_cast<int>(if_nametoindex("svlan1_260"))};
    std::cout << "Temp:ifIdx=" << ifIdx << std::endl;
    std::lock_guard<std::mutex> lockGuard(setSockoptMutex);
    retVal = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifIdx, sizeof(ifIdx));
    if (retVal < 0)
       throw OIP::OipException(OIP_SOCK_ACTION_FAILED("Cannot set socket option IPV6_MULTICAST_IF, setsockopt function failed with retVal " <<
                                                      retVal << " (errno=" << strerror(errno) << " (" << errno << ")."));

    // Create IPv6 address.
    struct sockaddr_in6 sockAddrIpV6{};
    sockAddrIpV6.sin6_family = {AF_INET6};
    sockAddrIpV6.sin6_port = {htons(2020)};
    sockAddrIpV6.sin6_scope_id = {static_cast<uint32_t>(ifIdx)};
    inet_pton(AF_INET6, "FF02:0000:0000:0000:0000:0000:0000:00FE", &sockAddrIpV6.sin6_addr);

    std::cout << "IPV6 Send: family=" << sockAddrIpV6.sin6_family << ", sin6_port=" << sockAddrIpV6.sin6_port  << ", sin6_scope_id=" << sockAddrIpV6.sin6_scope_id
              << ", addr=FF02:0000:0000:0000:0000:0000:0000:00FE" << std::endl;


    // Send message to socket.
    retVal = sendto(sock,
                    sendMsgCharBufVect.data(),
                    sendMsgCharBufVect.size(),
                    0,
                    reinterpret_cast<struct sockaddr*>(&sockAddrIpV6),
                    sizeof(struct sockaddr_in6));
    if (retVal < 0)
      throw OIP::OipException(OIP_SOCK_ACTION_FAILED("IPV6 Socket send data (socket sendto function) failed with retVal " << retVal <<
                                                      " (errno=" << strerror(errno) << " (" << errno << "))."));
  }

  // Send IPV4 multicast message.
  else
  {
    // Create IPv4 DGRAM Socket
    std::string ipV4Str{"239.0.0.254"};
    int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (sock < 0)
      throw OIP::OipException(OIP_SOCK_ACTION_FAILED("Cannot set socket option IPV4 socket, socket function failed with retVal " <<
                                                      sock << " (errno=" << strerror(errno) << " (" << errno << ")."));

    // Register multicast interface.
    struct ip_mreqn mreqn{};
    inet_aton(ipV4Str.c_str(), &mreqn.imr_multiaddr);
    mreqn.imr_ifindex        = {static_cast<int>(if_nametoindex("svlan1_260"))};
    retVal = setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &mreqn, sizeof(mreqn));
    if (retVal < 0)
       throw OIP::OipException(OIP_SOCK_ACTION_FAILED("Cannot set socket option IP_MULTICAST_IF, setsockopt function failed with retVal " <<
                                                      retVal << " (errno=" << strerror(errno) << " (" << errno << ")."));

    // Create IPv4 address.
     struct sockaddr_in sockAddrIpV4{};
     sockAddrIpV4.sin_family = {AF_INET};
     sockAddrIpV4.sin_port = {htons(2020)};
     inet_aton(ipV4Str.c_str(), &sockAddrIpV4.sin_addr);

     std::cout << "IPV4 Send: family=" << sockAddrIpV4.sin_family << ", sin_port=" << sockAddrIpV4.sin_port  << ", addr=" << std::hex << sockAddrIpV4.sin_addr.s_addr<< std::dec <<std::endl;

     // Send message to socket.
     retVal = sendto(sock,
                     sendMsgCharBufVect.data(),
                     sendMsgCharBufVect.size(),
                     0,
                     reinterpret_cast<struct sockaddr*>(&sockAddrIpV4),
                     sizeof(struct sockaddr_in));
     if (retVal < 0)
       throw OIP::OipException(OIP_SOCK_ACTION_FAILED("IPV4 Socket send data (socket sendto function) failed with retVal " << retVal <<
                                                      " (errno=" << strerror(errno) << " (" << errno << "))."));
  }

...

tcpdump IPv4 показывает исходящее многоадресное сообщение с запрошенным адресом:

2020-04-02 23:30:19.384892 00:60:1d:7d:08:07 (oui Unknown) > 01:00:5e:00:00:fe (oui Unknown), ethertype 802.1Q (0x8100), length 90: vlan 260, p 0, ethertype IPv4, (tos 0x0, ttl 1, id 54916, offset 0, flags [none], proto UDP (17), length 72)
    100.5.81.1.38790 > 239.0.0.254.2020: UDP, length 44
        0x0000:  0100 5e00 00fe 0060 1d7d 0807 8100 0104
        0x0010:  0800 4500 0048 d684 0000 0111 3e1c 6405
        0x0020:  5101 ef00 00fe 9786 07e4 0034 a54a 4479

tcpdump для IPV6 показывает только автоматику c сгенерированные многоадресные сообщения IPV6:

2020-04-02 22:48:19.569203 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 174: vlan 260, p 0, ethertype IPv6, [|ip6]
        0x0000:  3333 0000 0016 0060 1d7d 0807 8100 0104
        0x0010:  86dd 6000 0000 0074 0001 0000 0000 0000
        0x0020:  0000 0000 0000 0000 0000 ff02 0000 0000
2020-04-02 22:48:20.049156 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 174: vlan 260, p 0, ethertype IPv6, [|ip6]
        0x0000:  3333 0000 0016 0060 1d7d 0807 8100 0104
        0x0010:  86dd 6000 0000 0074 0001 0000 0000 0000
        0x0020:  0000 0000 0000 0000 0000 ff02 0000 0000
2020-04-02 22:48:20.329171 00:60:1d:7d:08:07 (oui Unknown) > 33:33:ff:7d:08:07 (oui Unknown), ethertype 802.1Q (0x8100), length 90: vlan 260, p 0, ethertype IPv6, [|ip6]
        0x0000:  3333 ff7d 0807 0060 1d7d 0807 8100 0104
        0x0010:  86dd 6000 0000 0020 3aff 0000 0000 0000
        0x0020:  0000 0000 0000 0000 0000 ff02 0000 0000
root@MEC2-81-1-STDBY:/lib# 2020-04-02 22:48:21.359289 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 134: vlan 260, p 0, ethertype IPv6, [|ip6]
        0x0000:  3333 0000 0016 0060 1d7d 0807 8100 0104
        0x0010:  86dd 6000 0000 004c 0001 fe80 0000 0000
        0x0020:  0000 0260 1dff fe7d 0807 ff02 0000 0000
2020-04-02 22:48:21.389154 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 94: vlan 260, p 0, ethertype IPv6, [|ip6]
        0x0000:  3333 0000 0016 0060 1d7d 0807 8100 0104
        0x0010:  86dd 6000 0000 0024 0001 fe80 0000 0000
        0x0020:  0000 0260 1dff fe7d 0807 ff02 0000 0000
2020-04-02 22:48:22.159152 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 134: vlan 260, p 0, ethertype IPv6, [|ip6]
        0x0000:  3333 0000 0016 0060 1d7d 0807 8100 0104
        0x0010:  86dd 6000 0000 004c 0001 fe80 0000 0000
        0x0020:  0000 0260 1dff fe7d 0807 ff02 0000 0000
2020-04-02 22:48:22.319152 00:60:1d:7d:08:07 (oui Unknown) > 33:33:00:00:00:16 (oui Unknown), ethertype 802.1Q (0x8100), length 94: vlan 260, p 0, ethertype IPv6, [|ip6]
        0x0000:  3333 0000 0016 0060 1d7d 0807 8100 0104
        0x0010:  86dd 6000 0000 0024 0001 fe80 0000 0000
        0x0020:  0000 0260 1dff fe7d 0807 ff02 0000 0000

Сетевой интерфейс: Используемый сетевой интерфейс - это интерфейс VLAN svlan1_260 с VLAN ID 260, созданный на физическом сетевом интерфейсе eth2.

eth2      Link encap:Ethernet  HWaddr 00:00:00:00:81:01  
          UP BROADCAST RUNNING PROMISC MULTICAST  MTU:1513  Metric:1
          RX packets:3684437 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3410666 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:572562185 (546.0 MiB)  TX bytes:109620349 (104.5 MiB)
          Interrupt:32
svlan1_260 Link encap:Ethernet  HWaddr 00:60:1d:7d:08:07  
          inet addr:100.5.81.1  Bcast:100.5.255.255  Mask:255.255.0.0
          inet6 addr: fe80::260:1dff:fe7d:807/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:709 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:85982 (83.9 KiB)

Вопросы:

Есть какие-нибудь идеи, что не так для IPv6?

Может быть неправильный адрес, хотя я пробовал несколько?

Отсутствует ли конфигурация сокета?

Любые с Настройки системы, не правильно установлены?

спасибо

1 Ответ

0 голосов
/ 04 апреля 2020

Найдена причина проблемы после большой отладки.

T-битный флаг (динамически назначенный адрес многоадресной рассылки), упомянутый в комментариях выше, наверняка должен быть правильно установлен. Но отправка также работает, если T-бит установлен в 0 (общеизвестный адрес многоадресной рассылки).

Существует следующая причина сбоя вызова sendto. Незадолго до создания сокета и отправки сообщения на соответствующем сетевом интерфейсе адрес MA C был изменен с помощью ioctl SIOCSIFHWADDR. Для автоматического обновления локального IPv6-адреса новым адресом MA C сетевой интерфейс был настроен и снова настроен с помощью ioctl SIOCSIFFLAGS.

Когда был создан сокет и отправлено сообщение, соединение не было законченный. Поэтому sendto не удалось. Сообщения IPv6 в tcpdump выше относятся к запуску сетевого интерфейса.

При ожидании через несколько секунд после запуска сетевого интерфейса все работает нормально.

...