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

Как программно определить IP-адрес в Linux?

Есть ли способ автоматически определять изменения IP-адреса на локальном компьютере в Linux с помощью С++?

4b9b3361

Ответ 1

В C, чтобы получить текущий IP-адрес, я использую:

    int s;
    struct ifreq ifr = {};

    s = socket(PF_INET, SOCK_DGRAM, 0);

    strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name));

    if (ioctl(s, SIOCGIFADDR, &ifr) >= 0)
        printf("%s\n",
          inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));

Замените "eth0" на интерфейс, на который вы смотрите. Все, что вам нужно сделать, это опрос для изменения.

Ответ 2

здесь вы идете.. это делает это без опроса.

он прослушивает только RTM_NEWADDR, но его нужно легко изменить для поддержки RTM_DELADDR, если вам нужно

#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>

int
main()
{
    struct sockaddr_nl addr;
    int sock, len;
    char buffer[4096];
    struct nlmsghdr *nlh;

    if ((sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) {
        perror("couldn't open NETLINK_ROUTE socket");
        return 1;
    }

    memset(&addr, 0, sizeof(addr));
    addr.nl_family = AF_NETLINK;
    addr.nl_groups = RTMGRP_IPV4_IFADDR;

    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        perror("couldn't bind");
        return 1;
    }

    nlh = (struct nlmsghdr *)buffer;
    while ((len = recv(sock, nlh, 4096, 0)) > 0) {
        while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE)) {
            if (nlh->nlmsg_type == RTM_NEWADDR) {
                struct ifaddrmsg *ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh);
                struct rtattr *rth = IFA_RTA(ifa);
                int rtl = IFA_PAYLOAD(nlh);

                while (rtl && RTA_OK(rth, rtl)) {
                    if (rth->rta_type == IFA_LOCAL) {
                        uint32_t ipaddr = htonl(*((uint32_t *)RTA_DATA(rth)));
                        char name[IFNAMSIZ];
                        if_indextoname(ifa->ifa_index, name);
                        printf("%s is now %d.%d.%d.%d\n",
                               name,
                               (ipaddr >> 24) & 0xff,
                               (ipaddr >> 16) & 0xff,
                               (ipaddr >> 8) & 0xff,
                               ipaddr & 0xff);
                    }
                    rth = RTA_NEXT(rth, rtl);
                }
            }
            nlh = NLMSG_NEXT(nlh, len);
        }
    }
    return 0;
}

Ответ 3

Это не так просто. Каждый дистрибутив Linux использует разные места для хранения IP-адресов и т.д. (Больше вариантов, если вы рассматриваете другие варианты UNIX). Вы можете использовать, например, /sbin/ifconfig для получения IP-адресов интерфейсов, но вы даже не можете быть уверены, найдете ли вы в этом месте или вообще и т.д.

Кроме того, если у вас есть этот исполняемый файл, вам необходимо настроить поток, вызывающий его, чтобы получить данные с заданным периодом (например, 5 секунд) и интерпретировать вывод. Это может отличаться, например, если у вас есть мосты и т.д. И т.д. То есть это непросто.

Решение, которое приходит мне на ум, - если у вас есть возможность использовать GNOME или какое-то другое широко распространенное распространение как KDE, вы можете положиться на сообщения/информацию, которые они дают. Например, NetworkManager выводит сигнал на стандартную шину DBUS при изменении устройства. Вы должны реализовать слушателя для этого сигнала. Информация здесь (сейчас не работает, так что вот cache). Обратите внимание на разные сообщения при добавлении нового интерфейса или когда один из них изменяет IP-адрес. Это лучший способ, о котором я могу думать сейчас.

Ответ 4

Если ваши пользователи используют NetworkManager, вы можете опросить NetworkManager.Connection.Active и NetworkManager.IP4Config через D-Bus, чтобы получить более кросс-дистрибутивный способ определения этой информации.

Ответ 5

Если iproute2 установлен и вы находитесь на ядре 2.6,

/sbin/ip monitor

Выведет изменения в статусе локального интерфейса и адресах на стандартный вывод. Ваша программа может прочитать это.

Вы также можете использовать тот же механизм низкого уровня, что и инструмент iproute2 (я думаю, что это сокет netlink).

Ответ 6

Предложение по использованию ioctl SIOCGIFADDR было технически корректным, к сожалению, оно ненадежно для современных Linux-систем, где один интерфейс может иметь несколько адресов без использования под-интерфейсов (например, eth0: 1), как это было сделано с помощью современных технологий, устаревший ifconfig.

Лучше всего использовать getifaddrs (3), который присутствует в glibc 2.3: http://www.kernel.org/doc/man-pages/online/pages/man3/getifaddrs.3.html

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

Ответ 7

Одним из способов было бы написать задание cron, которое содержит вызов одного семейства функций gethost библиотечных функций. Если вы используете gethostbyname(), вы можете сравнить возвращаемые значения h_addr_list. См. Man gethostbyname.

Если вы хотите сделать это из своей программы, создайте pthread, который делает то же самое, затем спит в течение некоторого произвольного периода времени.

Ответ 8

Из справочной страницы rtnetlink:

ОПИСАНИЕ

Rtnetlink позволяет считывать и изменять таблицы маршрутизации ядра. Он используется в ядре для связи между различными подсистемами, хотя это использование не описано здесь и для связи с программами пользовательского пространства. Сетевые маршруты, IP-адреса, параметры связи, настройки соседей, дисциплины очередей, классы трафика и классификаторы пакетов могут управляться через сокеты NETLINK_ROUTE. Он основан на сообщениях netlink, для получения дополнительной информации см. Netlink (7).