Ошибка в PF_ROUTE на macOS? - PullRequest
       3

Ошибка в PF_ROUTE на macOS?

0 голосов
/ 13 декабря 2018

У меня есть вопрос об использовании PF_ROUTE в macOS для обнаружения изменений IP-адреса.В принципе, мне кажется, что он не работает для IPv4.Я собрал пример программы, которая просто создает сокет PF_ROUTE и затем распечатывает при получении RTM_NEWADDR, RTM_DELADDR и RTM_IFINFO.

Что я замечаю, так это то, что при использовании одного интерфейса (кабель Wi-Fi или Ethernet) иотключить сетевой адаптер (отключить вайфай или отключить кабель) вообще ничего не получаю.Если я затем заново подключаюсь (включаю Wi-Fi или подключаю кабель), я получаю RTM_NEWADDR, но не RTM_IFINFO.

Если у меня одновременно подключены и Wi-Fi, и кабель, оба отключаются, а затем снова подключаются один из интерфейсов(например, отключить Wi-Fi, а затем повторно включить Wi-Fi) вообще не генерирует никаких событий.

IPv6 , кажется, работает.Если я тестирую IPv6 таким же образом, я получаю RTM_NEWADDR при соединении и RTM_DELADDR при разъединении (адрес - это локальный адрес канала IPv6 - мой DHCP-сервер не обслуживает адреса IPv6).

Несколько другихпримечания: если я пытаюсь сделать if_indextoname (), это не всегда работает.Мне нужно вставить спящий режим, чтобы иметь возможность последовательно возвращать имя (я выбрал 500 миллисекунд, я не тратил время, пытаясь найти другие значения, чтобы посмотреть, будет ли работать меньшее значение).

Кроме того, еслиЯ вызываю getifaddrs () в цикле (с небольшим перерывом между вызовами) после получения события IPv6 RTM_NEWADDR, чтобы попытаться найти отсутствующий адрес IPv4, может потребоваться много времени для его обнаружения в возвращенных данных.Я видел, что это занимает до 8 секунд в моей системе.Обратите внимание, что IP-адрес работает и может использоваться задолго до этого, так как непрерывный пинг на внешний адрес легко подтверждается.

Я тестировал эту программу на MacBook Pro с 10.13, iMac с 10.14 и виртуальной машиной с 10.12- все ведут себя одинаково.

Итак, мой вопрос: это ошибка в ОС, или у меня есть принципиальное недопонимание того, как сокет PF_ROUTE должен работать?

Спасибо, Кевин

#include <SystemConfiguration/SystemConfiguration.h>
#include <net/route.h>
#include <errno.h>

struct cmn_msghdr
{
    u_short    msglen;
    u_char    version;
    u_char    type;
};

int main(int argc, const char * argv[])
{
    char buf[1024];
    size_t len;
    int skt, family = AF_UNSPEC;

    if ( argv[1] && argv[1][0] == '4' )
        family = AF_INET;
    else if ( argv[1] && argv[1][0] == '6' )
        family = AF_INET6;

    // Create a PF_ROUTE socket over which we will receive change messages
    skt = socket( PF_ROUTE, SOCK_RAW, family );
    if ( skt == -1 )
    {
        printf( "ERR: Failed to create PF_ROUTE socket. error %d\n", errno );
        return -1;
    }

    printf( "Watching for %s address changes. Press Ctrl-C to exit\n",
           family == AF_UNSPEC ? "IP" : ( family == AF_INET6 ? "IPv6" : "IPv4" ) );

    // Loop forever waiting for messages
    for (;;)
    {
        len = recv( skt, buf, sizeof(buf), 0 );
        if ( len < 0 )
        {
            switch (errno)
            {
                case EINTR:
                case EAGAIN:
                    printf( "ERR: EINTR or EAGAIN on PF_ROUTE socket\n" );
                    continue;
                default:
                    printf( "ERR: Failed to receive on PF_ROUTE socket. error %d\n", errno );
                    continue;
            }
        }
        if ( len < sizeof( cmn_msghdr ) )
        {
            printf( "ERR: Data received on PF_ROUTE socket too small: %ld bytes\n", len );
            continue;
        }

        struct cmn_msghdr *hdr = (struct cmn_msghdr *)buf;
        if ( hdr->version != RTM_VERSION )
        {
            printf( "ERR: RTM version %d is not supported\n", hdr->version );
            continue;
        }

        switch( hdr->type )
        {
            case RTM_NEWADDR:
                printf( "RTM_NEWADDR\n" );
                break;
            case RTM_DELADDR:
                printf( "RTM_DELADDR\n" );
                break;
            case RTM_IFINFO:
                printf( "RTM_IFINFO\n" );
                break;
            default:
                // Don't care
                continue;
        }
    }

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