Модераторы: xvr

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Пакетные сокеты. PF_PACKET. Прием и отправка, Прием и отправка одного и того же пакета 
V
    Опции темы
konshyn
Дата 19.9.2013, 14:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 295
Регистрация: 19.9.2013

Репутация: нет
Всего: нет



Всем привет. 
Есть такая цель. Нужно принимать ВЕСЬ трафик, который приходит на интерфейс и не просматривая его, отправить на другой.

Есть код приема всех пакетов(обычный сниффер).

sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
  
struct sockaddr_ll  s_ll = {0};
s_ll.sll_family = PF_PACKET;    // Тип сокета
s_ll.sll_protocol = htons(ETH_P_ALL);   //Тип применяемого протокола
s_ll.sll_ifindex = index; //индекс сетевого интерфейса (2)

в бесконечном цикле принимаются пакеты 
while (true)
    {
        memset(buff, 0, ETH_FRAME_LEN);
        
        rec = recvfrom(eth0_if, (char *)buff, ifp.mtu + 18, 0, NULL, NULL);
    } 

как мне полученный пакет buff отправить на другой адрес?

UPD: Другими словами, мне нужно перенаправлять все пакеты, которые проходят через мою сетевую карту, на другой комп, а оттуда уже опять отправить адресату.

Это сообщение отредактировал(а) konshyn - 28.11.2013, 12:19


--------------------
«Потому что ценность акта действия в этой стране возрастает в несколько раз».
PM MAIL Skype   Вверх
StopPanic
Дата 20.9.2013, 10:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 16.6.2011

Репутация: 1
Всего: 1



А бридж подойдет, или нужен свой велосипед ?
man brctl 
http://www.opennet.ru/base/net/linux_bridge.txt.html
PM MAIL   Вверх
konshyn
Дата 20.9.2013, 10:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 295
Регистрация: 19.9.2013

Репутация: нет
Всего: нет



Цитата(StopPanic @ 20.9.2013,  10:17)
А бридж подойдет, или нужен свой велосипед ?
man brctl 
http://www.opennet.ru/base/net/linux_bridge.txt.html

Нужен свой велосипед smile


--------------------
«Потому что ценность акта действия в этой стране возрастает в несколько раз».
PM MAIL Skype   Вверх
StopPanic
Дата 20.9.2013, 22:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 16.6.2011

Репутация: 1
Всего: 1



Цитата(konshyn @ 20.9.2013,  10:59)
Нужен свой велосипед smile

Ну а в чем собственно проблема то ? Создаешь еще второй сокет, используя индекс второго интерфейса, пихаешь это дело в пол и при чтении из одного записываешь то что пришло в другой. Если мне память не изменяет, то это все работает даже в неблокирующем режиме с еполом. Только учти, что бродкаст тоже будет проходить через все это.
PM MAIL   Вверх
konshyn
Дата 21.9.2013, 12:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 295
Регистрация: 19.9.2013

Репутация: нет
Всего: нет



Цитата(StopPanic @ 20.9.2013,  22:01)
Цитата(konshyn @ 20.9.2013,  10:59)
Нужен свой велосипед smile

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

У меня одна сетевая карта, т.е. нет другого интерфейса.
Ну вот создал я другой сокет:

send_socket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));

принял пакет через первый.
отлично. в нем есть все данные. ethernet-заголовок, ip-заголовок, mac-заголовок 
т.е. я получил пакет без изменений, ядро linux ничего не отбрасывало от самого пакета.

прототип функции sendto:
int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen); 

const struct sockaddr *to - это общая структура. к примеру для TCP используется struct sockaddr_in
struct sockaddr_in {
    short int          sin_family;  // Семейство адресов
    unsigned short int sin_port;    // Номер порта
    struct in_addr     sin_addr;    // IP-адрес
    unsigned char      sin_zero[8]; // "Дополнение" до размера структуры sockaddr
};

в ней есть IP адрес.

для пакетных сокетов используется struct sockaddr_ll
struct sockaddr_ll {
unsigned short sll_family; /* AF_PACKET */
unsigned short sll_protocol; /* протокол канального уровня */
int sll_ifindex; /* номер интерфейса */
unsigned short sll_hatype; /* тип заголовка */
unsigned char sll_pkttype; /* тип пакета */
unsigned char sll_halen; /* размер адреса */
unsigned char sll_addr[8]; /* аппаратный адрес */
};

я не могу понять, как отправить, потому что если в sendto я использую sockaddr_in, то пакет отправляется, но до адресата не доходит. без понятия, куда он там отправляется, а как использовать sockaddr_ll?




--------------------
«Потому что ценность акта действия в этой стране возрастает в несколько раз».
PM MAIL Skype   Вверх
StopPanic
Дата 21.9.2013, 19:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 16.6.2011

Репутация: 1
Всего: 1



Чейта я не понял, а как у тебя вообще сетевая коммутация происходит ? Учитывая что у тебя всего 1 сетевой интерфейс на девайсе который должен только перекидывать пакеты ?

Читаешь - recv, пишешь write. То что пишешь и читаешь - это ethernet фрейм.
PM MAIL   Вверх
konshyn
Дата 21.9.2013, 20:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 295
Регистрация: 19.9.2013

Репутация: нет
Всего: нет



Цитата(StopPanic @ 21.9.2013,  19:10)
Чейта я не понял, а как у тебя вообще сетевая коммутация происходит ? Учитывая что у тебя всего 1 сетевой интерфейс на девайсе который должен только перекидывать пакеты ?

Читаешь - recv, пишешь write. То что пишешь и читаешь - это ethernet фрейм.

Ладно. Поправь, если я не прав.
Сетевой интерфейс есть сетевая карта. Я создаю пакетный сокет(socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)) , который принимает все пакеты без исключения. Связывать с сетевым интерфейсом его необязательно, т.к. у меня он только один. Имею ввиду функцию int bind()
Создаем еще один такой же сокет. Который будет отправлять пакет по нужному мне адресу. Вопрос, как задать адрес пакету, который получил? для пакетных сокетов используется функция sendto и структура, что писал выше struct sockaddr_ll.

Я не могу понять, где мне задавать адрес.

ethernet-фрейм, это:
(ip-заголовок(ethernet-заголовок(данные)))
правильно?


--------------------
«Потому что ценность акта действия в этой стране возрастает в несколько раз».
PM MAIL Skype   Вверх
StopPanic
Дата 21.9.2013, 22:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 16.6.2011

Репутация: 1
Всего: 1



Тэкс, понятно что чебе непонятно =) Ладно, сейчас попробую разжевать псевдокодом

Вот формат ethernet кадра, т.е. то что ты будешь получать и должен будешь отправлять.
http://ru.wikipedia.org/wiki/Ethernet#.D0.....B4.D1.80.D0.B0


socketfd = socket(AF_PACKET, SOCK_RAW, ethertype)
Это создает в системе сокет, и возвращает его дескриптор. Тут следует обратить внимание на ethertype (будет принимать пакеты только этого типа), но если тебе нужен будет весь трафик, то ставим htons(ETH_P_ALL).
Т.е. если в системе будет 2 физических интерфейса, то весь трафик с них с заданным ethertype будет валится в этот сокет, чтобы валилось с конкретного интерфейса, используется bind который опишу ниже.

struct ifreq ifMac;
const char *ethName = "eth0";
memset(&ifMac, 0, sizeof (ifMac));
strncpy(ifMac.ifr_name, ethName, strlen(ethName));

Если необходимо, переводим в PROMISC (http://ru.wikipedia.org/wiki/Promiscuous_mode) . Это нужно например для ethernet мультикаста, т.к. сетевая карта будет отсеивать все что не является ее dest адресом. В твоем случае по идее нужно, т.к. то что ты слушаешь не принадлежит тебе как конечному звену.
ioctl (socketfd, SIOCGIFFLAGS, &ifMac) 
ifMac.ifr_flags |= IFF_PROMISC;
ioctl (socketfd, SIOCSIFFLAGS, &ifMac)


Получаем индекс интефейса:
ioctl (socketfd, SIOCGIFINDEX, &ifMac)

Биндим конкретный интерфейс:
struct sockaddr_ll sAddr;
memset (&sAddr, 0, sizeof (sAddr));
sAddr.sll_family = AF_PACKET;
sAddr.sll_ifindex = ifMac.ifr_ifindex;
sAddr.sll_protocol = ethertype;
bind (socketfd, (struct sockaddr *) &sAddr, sizeof (struct sockaddr_ll))

Все, после того как это сделал, можно добавлять дескриптор socketfd в пол или епол.

Соответственно читаешь и пишешь данные с помощью recv и write, как я уже писал.

То что будешь получать - это будут структуры типа :
struct {
char destMac[6];
char srcMac[6];
char etherType[2];
char data[]
}

Там думаю разберешься после первого recv =) Только учти, у тебя возможен будет дубляж фреймов, если ты не будешь на своей прослушке менять dstmac. Надеюсь wireshark у тебя уже стоит.

Это сообщение отредактировал(а) StopPanic - 21.9.2013, 22:39
PM MAIL   Вверх
konshyn
Дата 21.9.2013, 23:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 295
Регистрация: 19.9.2013

Репутация: нет
Всего: нет



все, что ты написал. уже написано smile

while (true)
    {
        memset(buff, 0, ETH_FRAME_LEN);
        
        rec = recvfrom(eth0_if, (char *)buff, ifp.mtu + 18, 0, NULL, NULL);
    } 

код, где считывает пакет.
какой командой мне отправить этот пакет на адрес, к примеру, 192.168.1.1???
и как заполнить структуру?
Вот чего я не понимаю в пакетных сокетах. Я вроде отправляю пакет, и возвращает значение, сколько байт отправил, но! до адресата не доходит.


--------------------
«Потому что ценность акта действия в этой стране возрастает в несколько раз».
PM MAIL Skype   Вверх
StopPanic
Дата 22.9.2013, 00:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 16.6.2011

Репутация: 1
Всего: 1



Ну ёперный театр, так бы сразу и сказал, что ip адрес. Только вот проблемка - никаких таких команд нет. То что проинициализировано - это работа на mac уровне - тут либо писать свой парсер пакетов (http://ru.wikipedia.org/wiki/IPv4#.D0.A1.D1.82.D1.80.D1.83.D0.BA.D1.82.D1.83.D1.80.D0.B0_.D0.BF.D0.B0.D0.BA.D0.B5.D1.82.D0.B0), либо переходить на уровень выше. 
PM MAIL   Вверх
konshyn
Дата 22.9.2013, 00:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 295
Регистрация: 19.9.2013

Репутация: нет
Всего: нет



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

есть ведь функция sendto, или даже тот же write. я ведь могу сделать обычный сокет TCP или UDP и отправить полученный пакет на нужный мне адрес?

while (true)
    {
        memset(buff, 0, ETH_FRAME_LEN);
        
        rec = recvfrom(eth0_if, (char *)buff, ifp.mtu + 18, 0, NULL, NULL);
    }

он ведь будет мой buff воспринимать просто как данные, неважно, что там хранятся и mac-адреса отправителя и получателя, ip и другая инфа вместе с данными?

UPD:

есть структура о которой писал ранее

struct sockaddr_ll {
unsigned short sll_family; /* AF_PACKET */
unsigned short sll_protocol; /* протокол канального уровня */
int sll_ifindex; /* номер интерфейса */
unsigned short sll_hatype; /* тип заголовка */
unsigned char sll_pkttype; /* тип пакета */
unsigned char sll_halen; /* размер адреса */
unsigned char sll_addr[8]; /* аппаратный адрес */
};

что значит поле: unsigned char sll_addr[8]; /* аппаратный адрес */???

это mac-адрес?

а я могу отправить не по ip, а по mac???

Это сообщение отредактировал(а) konshyn - 22.9.2013, 00:29


--------------------
«Потому что ценность акта действия в этой стране возрастает в несколько раз».
PM MAIL Skype   Вверх
StopPanic
Дата 22.9.2013, 00:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 16.6.2011

Репутация: 1
Всего: 1



Да, на этом уровне ты конструируешь пакет сам, вот картинка :
http://www.tldp.org/LDP/tlk/net/protocols.gif

Т.е. добавляешь в буфер dest mac, потом src, потом ethertype ip протокола, потом ip заголовок и т.д. и все это отправляешь write'ом, а при приеме наоборот, парсишь.
PM MAIL   Вверх
konshyn
Дата 22.9.2013, 00:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 295
Регистрация: 19.9.2013

Репутация: нет
Всего: нет



StopPanic, понял. Спасибо!  smile 


--------------------
«Потому что ценность акта действия в этой стране возрастает в несколько раз».
PM MAIL Skype   Вверх
StopPanic
Дата 22.9.2013, 00:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 16.6.2011

Репутация: 1
Всего: 1



Да, кстати не стоит забывать еще про vlan, q-in-q и прочие ethertype-протоколы, которые делают свои преамбулы перед ip заголовком. Это тот еще гемор.
PM MAIL   Вверх
StopPanic
Дата 22.9.2013, 12:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 10
Регистрация: 16.6.2011

Репутация: 1
Всего: 1



Вот для уровня выше http://www.opennet.ru/cgi-bin/opennet/man....&category=7 , тут помочь особо не смогу, т.к. не писал протоколы ipv4 уровня. Удачи с экспериментами =)

PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Программирование под Unix/Linux"
xvr
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • Не забывайте пользоваться кнопкой "Код".
  • Вопросы мобильной разработки тут
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к разделу форума. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, xvr.

 
 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Программирование под Unix/Linux | Следующая тема »


 




[ Время генерации скрипта: 0.0933 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.