LINUX.ORG.RU

Как из сокета прочитанного recvmsg вытащить IP адрес?

 ,


0

1

Мучаю тут тему с приклеиванием трассировки к библиотеки пинга

описание приходящей структуры msghdr и вытаскиваемой макросами из нее cmsghdr посмотрел, но как из них получить IP адрес отправителя ICMP пакета что то не догоняю

подскажите если не затруднит куда искать, на что смотреть???

на всякий случай дублирую то место в коде liboping.c где происходит чтение

payload_buffer_len = recvmsg (fd, &msghdr, /* flags = */ 0);
        if (payload_buffer_len < 0)
        {
#if WITH_DEBUG
                char errbuf[PING_ERRMSG_LEN];
                dprintf ("recvfrom: %s\n",
                                sstrerror (errno, errbuf, sizeof (errbuf)));
#endif
                return (-1);
        }
        dprintf ("Read %zi bytes from fd = %i\n", payload_buffer_len, fd);

        /* Iterate over all auxiliary data in msghdr */
        recv_ttl = -1;
        recv_qos = 0;
        for (cmsg = CMSG_FIRSTHDR (&msghdr); /* {{{ */
                        cmsg != NULL;
                        cmsg = CMSG_NXTHDR (&msghdr, cmsg))
        {
                if (cmsg->cmsg_level == SOL_SOCKET)
                {
#ifdef SO_TIMESTAMP
                        if (cmsg->cmsg_type == SO_TIMESTAMP)
                                memcpy (&pkt_now, CMSG_DATA (cmsg), sizeof (pkt_now));
#endif /* SO_TIMESTAMP */
                }
                else if (addrfam == AF_INET) /* {{{ */
                {
                        if (cmsg->cmsg_level != IPPROTO_IP)
                                continue;

                        if (cmsg->cmsg_type == IP_TOS)
                        {
                                memcpy (&recv_qos, CMSG_DATA (cmsg),
                                                sizeof (recv_qos));
                                dprintf ("TOSv4 = 0x%02"PRIx8";\n", recv_qos);
                        } else
                        if (cmsg->cmsg_type == IP_TTL)
                        {
                                memcpy (&recv_ttl, CMSG_DATA (cmsg),
                                                sizeof (recv_ttl));
                                dprintf ("TTLv4 = %i;\n", recv_ttl);
                        }
                        else
                        {
                                dprintf ("Not handling option %i.\n",
                                                cmsg->cmsg_type);
                        }
                } /* }}} */
★★★

Ответ на: комментарий от vel

в мане для msg_name смущает формулировка о необязательности и в моем случае там почему то NULL, может для сокета какого то параметра не устанавливается, поэтому там пусто!?

второе сейчас проверю, но возможно та же самая проблема

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от wolverin

У тебя там NULL потому что ты туда записал NULL. Запиши туда адрес буфера, в который recvmsg должно записать адрес, а в msg_namelen - размер этого буфера. recvmsg (как и остальные сокетные функции) не выделяет динамически никакую память, только пишет в ту что ты предоставишь. На возврате в msg_namelen будет количество реально записанных байт адреса (не больше чем ты разрешил).

И зачем тебе recvmsg для пинга? Так recvfrom вполне достаточно, а он проще.

firkax ★★★★★
()
Ответ на: комментарий от firkax

спасибо, сейчас попробую, т.е. отдельно устанавливать setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) не требуется???

recvmsg библиотека использует, видимо чтобы пинговать сразу пул адресов

wolverin ★★★
() автор топика
Последнее исправление: wolverin (всего исправлений: 1)
Ответ на: комментарий от wolverin

Указанные тобой setsockopt не требуется, да.

recvfrom-у тоже ничего не мешает принимать ответы сразу от всех.

Основная фича recvmsg это слать (принимать) файловые дескрипторы через unix-сокеты.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)