URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 3332
[ Назад ]

Исходное сообщение
"Пакетный RAW Сокет и sendmsg"

Отправлено Alexzy , 03-Сен-04 12:13 
(Извините за откровенно ламерский вопрос, но это мой первый опыт программирования сокетов в Linux'e и как следствие первые непроходимые грабли)
Пробовал тут посылать пакет сформированый собственноручно с помощью
pcksck=socket(PF_PACKET,SOCK_RAW,ETH_P_ALL)
а затем отсылать его методом
sendmsg(psksck,hdr,0)
но сендмсг возвращает -1 и еррно = EINVAL (22), подозреваю, что дело в неправильно сформированном hdr. Заполнил я его согласно man'u, хотя возникли вопросы относительно полей msg_control и msg_name - пробовал подставлять в них мак карточки и названия девайса(ака /dev/eth).Не могли бы вы мне объяснить для чего предназначены данные поля и как их правильно заполнять, а может для моей задачи они и вовсе не нужны и грабли лежат где-то еще? Работаю под root'ом, создание самого сокета вроде проходит нормально (не возвращает -1).  
Заранее благодарен за любую конструктивную помощь :)

Содержание

Сообщения в этом обсуждении
"Пакетный RAW Сокет и sendmsg"
Отправлено Cadaver , 07-Сен-04 12:12 
>(Извините за откровенно ламерский вопрос, но это мой первый опыт программирования сокетов
>в Linux'e и как следствие первые непроходимые грабли)
>Пробовал тут посылать пакет сформированый собственноручно с помощью
>pcksck=socket(PF_PACKET,SOCK_RAW,ETH_P_ALL)
>а затем отсылать его методом
>sendmsg(psksck,hdr,0)
>но сендмсг возвращает -1 и еррно = EINVAL (22), подозреваю, что дело
>в неправильно сформированном hdr. Заполнил я его согласно man'u, хотя возникли
>вопросы относительно полей msg_control и msg_name - пробовал подставлять в них
>мак карточки и названия девайса(ака /dev/eth).Не могли бы вы мне объяснить
>для чего предназначены данные поля и как их правильно заполнять, а
>может для моей задачи они и вовсе не нужны и грабли
>лежат где-то еще? Работаю под root'ом, создание самого сокета вроде проходит
>нормально (не возвращает -1).
>Заранее благодарен за любую конструктивную помощь :)


Мне нужно было принимать/посылать только с одного интерфейса, поэтому я вначале сокет биндил к /dev/ethx, а EINVAL - это точно hdr, у меня такое было, надо проверить, заполнить ВСЕ поля, в том числе те, которые не знаешь как - поставить NULL и нули, память где надо аллоцировать. У меня было:

msg_name = NULL;
msg_namelen = 0;
msg_control = NULL;
msg_controllen = 0;
msg_iov = (struct iovec *) malloc (тратата);
msg_iov.base = malloc (сколько надо под пакет);
msg_iov.len = сколько надо под пакет;
msg_iovlen = 1;
msg_flags = 0;


После этого все работало. У меня инвал был потому что я имя не заполнял, то есть нулл не присваивал, а это надо


"Пакетный RAW Сокет и sendmsg"
Отправлено Alexzy , 07-Сен-04 17:59 
Методом чтения Man'ов/исходников/научного тыка я заставил это дело пахать прописав следующее
msg_name = &sockaddr_ll_obj;
msg_namelen = sizeof(sockaddr_ll_obj);
при этом необходимо заполнить
sockaddr_ll_obj.sll_family = AF_PACKET;
sockaddr_ll_obj.sll_ifindex = 2; //Это я установил методом тыка т.к. не знаю как можно получить индекс eth0
А как байндить я так и не разобрался - SOBINDTODEVICE все время ругается на неправильное устройство :(
Может кто научит как получать индекс сетевого интерфейса и байндить на него сокет?


"Пакетный RAW Сокет и sendmsg"
Отправлено jd , 07-Сен-04 23:22 
>Методом чтения Man'ов/исходников/научного тыка я заставил это дело пахать прописав следующее
> msg_name = &sockaddr_ll_obj;
> msg_namelen = sizeof(sockaddr_ll_obj);
>при этом необходимо заполнить
> sockaddr_ll_obj.sll_family = AF_PACKET;
> sockaddr_ll_obj.sll_ifindex = 2; //Это я установил методом тыка т.к. не знаю
>как можно получить индекс eth0
>А как байндить я так и не разобрался - SOBINDTODEVICE все время
>ругается на неправильное устройство :(
>Может кто научит как получать индекс сетевого интерфейса и байндить на него
>сокет?


Примерно так:

struct ifreq ifr;
struct sockaddr_ll sa;
int s=socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name));
ioctl(sock_fd, SIOCGIFINDEX, &ifr); /* ifr.ifr_index теперь содержит номер интерфейса eth0 */
sa.sll_family=AF_PACKET;
sa.sll_ifindex=ifr.ifr_index;
/* Остальные поля в sa тоже нужно заполнить */
bind(s, (struct sockaddr*)&sa, sizeof(sa)); /* теперь сокет привязан к eth0 */

Разумеется нужно ещё проверять, что возвращают все функции. Также неплохо почитать man packet(7), посмотреть заголовочники etc...