Внедрение необработанного пакета в сеть в C (Linux)
Я пытаюсь написать функцию, которая принимает поток байтов (включая заголовки Ethernet и, возможно, протоколы верхнего уровня, также инкапсулированные в пакет Ethernet) и отправляет их по сети через определенный интерфейс.
Вот краткое изложение моего кода:
// create socket
int s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (s < 0) {
// error handling
}
// set up to just receive/send packets on one interface (stored in the variable iface_name e.g. eth0)
struct ifreq ifr;
bzero(&ifr, sizeof(struct ifreq));
strncpy(ifr.ifr_ifrn.ifrn_name, iface_name, IFNAMSIZ);
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
// error handling
}
// set up socaddr for write
struct sockaddr sa;
sa.sa_family = PF_PACKET;
sa.sa_data = htons(ETH_P_ALL);
// write to wire
// buf has type char* and len has type int
// buf contains ethernet header, followed by payload (e.g. ARP packet or IP packet)
if ( sendto(s, buf, len, 0, &sa, sizeof(struct sockaddr) ) < 0 ) {
perror("sendto");
// more error handling
}
Я получаю ошибку
sendto: Invalid argument
Как я могу исправить эту ошибку?
Мое первоначальное предположение, что это как-то вызвано sa
аргумент, так как все остальные довольно стандартны и не так много, чтобы пойти не так. Я мог бы заменить это аргументом sockaddr_ll
введите, как в этом примере, но это будет означать извлечение информации заголовка из buf
и это кажется немного бессмысленным, так как он уже там, готов к работе. Должен быть лучший способ? Инкапсулируйте, не инкапсулируйте, повторно инкапсулируйте, отправляйте, кажется, что в нем слишком много ненужных шагов. Я пишу базовый интерфейс для некоторого ранее существующего кода, поэтому я не могу адаптировать ввод, чтобы в него еще не были включены заголовки канального уровня.
1 ответ
Это ваши библиотеки:
http://linux.die.net/man/7/raw посмотрите определение заголовка и посмотрите, как он делает свой сокет, он не использует htons, а скорее: IPPROTO_RAW находится в
#include <netinet/in.h>