Определение интерфейса - отправителя (сети, netlink, rtnetlink и иже с ними)

Модератор: Модераторы разделов

Faurn
Сообщения: 12

Определение интерфейса - отправителя

Сообщение Faurn »

Здравствуй, Олл

(Slackware 12.2)

Пишу программу, работающую с сырыми сокетами. Нужно - в заголовок IP-пакетов подставлять адрес целевого хоста и свой адрес, с которого пакет уходит в сеть

Проблема: у меня есть несколько интерфейсов. Как (програмно) определить, с какого из них я буду посылать пакет?

Как сделано сейчас: отправляю целевому хосту ICMP/ECHO-пакет (формирование IP-заголовка оставляю за системой). Получаю ICMP/ECHO-REPLY пакет - и из него выдираю адрес своего интерфейса

Есть мнение, что netlink/rtnetlink мне поможет. Действительно ничего попроще нет?

Спасибо
Спасибо сказали:
svary
Сообщения: 49
ОС: Linux FC-9

Re: Определение интерфейса - отправителя

Сообщение svary »

Faurn писал(а):
17.06.2009 02:31
Как (програмно) определить, с какого из интерфейсов я буду посылать пакет?

Насколько я понимаю - никак. Если у Вас на компе стоит два интерфейса (пусть даже физически - на одной карточке), вопрос о том, куда именно уйдет пакет решает РОУТЕР, на основании информации о назначении пакета. Причем, для принятия такого решения, он вполне может "проконсультироваться" с DNS.
Но мне кажется совершенно надуманной сама постановка задачи. Это что - лаба по сетевому программированию ? :-) Если же на "том" конце соединения действительно необходимо узнать адрес отправителя, то это легко сделать с помощью системного вызова :


NAME
getpeername - get name of connected peer socket

SYNOPSIS
#include <sys/socket.h>

int getpeername(int s, struct sockaddr *name, socklen_t *namelen);

DESCRIPTION
getpeername() returns the name of the peer connected to socket s. The namelen argument should be ini-
tialized to indicate the amount of space pointed to by name. On return it contains the actual size of
the name returned (in bytes). The name is truncated if the buffer provided is too small.
Спасибо сказали:
Аватара пользователя
Portnov
Модератор
Сообщения: 1786
Статус: Матёрый линуксоид
ОС: Debian testing/unstable

Re: Определение интерфейса - отправителя

Сообщение Portnov »

Я в своё время сталкивался с таким вопросом. Точного решения не помню, но помню что выдрал его из исходников traceroute.
Работа: Ubuntu 9.10
Дом: Debian testing/unstable и на всякий случай winxp в virtualbox.
Для разнообразия: моя домашняя страница -http://iportnov.ru
Спасибо сказали:
Faurn
Сообщения: 12

Re: Определение интерфейса - отправителя

Сообщение Faurn »

svary писал(а):
17.06.2009 06:18
Насколько я понимаю - никак. Если у Вас на компе стоит два интерфейса (пусть даже физически - на одной карточке), вопрос о том, куда именно уйдет пакет решает РОУТЕР, на основании информации о назначении пакета.


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

Кроме того, для подсчета checksum TCP-пакета приходится брать поле "адрес отправителя" из заголовка IP-пакета.

svary писал(а):
17.06.2009 06:18
Но мне кажется совершенно надуманной сама постановка задачи. Это что - лаба по сетевому программированию ? :-)


Программа пишется исключительно just for fun :rolleyes:

(Portnov) писал(а):Я в своё время сталкивался с таким вопросом. Точного решения не помню, но помню что выдрал его из исходников traceroute.


Спасибо за наводку. Посмотрим
Спасибо сказали:
Faurn
Сообщения: 12

Re: Определение интерфейса - отправителя

Сообщение Faurn »

Проблема решена. Спасибо traceroute, Portnov и функции getsockname

Кому интересно - код (местами, возможно, не особенно красивый):

Код: Выделить всё

/* на входе: строка - IP-адрес целевого хоста,
  на выходе: in_addr_t (uint32_t) - IP-адрес интерфейса,
                с которого от нас уйдет пакет на целевой хост */

in_addr_t getMyIP(const char* dest)
{
    int sock = socket(AF_INET,SOCK_RAW,IPPROTO_RAW);
    if(sock == -1)
        return -1;

    struct sockaddr_in sa;
    sa.sin_family = AF_INET;
    sa.sin_port = 0;
    sa.sin_addr.s_addr = inet_addr(dest);

    if(connect(sock,(struct sockaddr*) &sa,sizeof(sa)) == -1)
    {
        close(sock);
        return -1;
    }

    struct sockaddr addr;
    socklen_t len = sizeof(addr);
    if(getsockname(sock,&addr,&len))
    {
        close(sock);
        return -1;
    }

    close(sock);

    in_addr_t ret = ((struct sockaddr_in*) & addr)->sin_addr.s_addr;

    return ret;
}
Спасибо сказали:
svary
Сообщения: 49
ОС: Linux FC-9

Re: Определение интерфейса - отправителя

Сообщение svary »

Faurn писал(а):
17.06.2009 13:06
Кому интересно - код (местами, возможно, не особенно красивый):

Интересно! Не знаю, насколько это существенно для Вас, но получается (как я и говорил),
что определить интерфейс отправки пакета можно только ПОСЛЕ установления соединения:

Код: Выделить всё

if(connect(sock,(struct sockaddr*) &sa,sizeof(sa)) == -1)


В принципе, конечно, соединение устанавливать надо...
Но ведь Вы говорили о сырых пакетах, отправляемых без установления соединения ?
Или я неправильно понял ?
Спасибо сказали: