2016-04-12 2 views
0

Я пытаюсь отправить пакет (не IP-пакет, но идентификатор запроса EAP), но функция send() возвращает -1 ,«Требуется адрес назначения» при попытке отправить данные через сокет SOCK_RAW

int sockfd = socket(AF_INET, SOCK_RAW, 0); 
printf("socket: %d\n", sockfd); 
struct sockaddr_in sock; 
printf("creating packet\n"); 
char packet[27]; 
memcpy(packet + 0, (u_char*) ethernet->ether_dhost, 6); 
memcpy(packet + 6, (u_char*) ethernet->ether_shost, 6); 
memcpy(packet + 12, (u_char*) ethernet + 12, 2); 
memcpy(packet + 14, (u_char *)reqid, 1); 
memcpy(packet + 15, (u_char *)reqid+1, 1); 
memcpy(packet + 16, (u_char *)reqid+2, 4); 
memcpy(packet + 20, (u_char *)reqid+6, 1); 
memcpy(packet + 21, (u_char *)reqid+7, 1); 
memcpy(packet + 22, (u_char *)reqid+8, 4); 
memcpy(packet + 26, (u_char *)reqid+12, 1); 
printf("sending packet\n"); 
if(send(sockfd, packet, sizeof(packet), 0) == -1) 
{ 
    printf("packet not sent\n"); 
    //return; 
} 

Пакет состоит из пакета ethernet и идентификатора запроса. Я знаю, что пакет в порядке, и каждое значение находится в нужном месте. но функция send() не работает.
errno show «Требуется адрес назначения», а значение sockfd равно 4. Это, кстати, на FreeBSD.
Спасибо EDIT: У меня нет IP-адреса получателя. У меня есть только его MAC-адрес.

+0

Что такое 'errno'? Действительно ли 'sockfd'? Для ISTR 'SOCK_RAW' требуется root –

+0

@LightnessRacesinOrbit Требуется адрес назначения. – ipinlnd

+0

@LightnessRacesinOrbit также, да ** sockfd ** действителен. его значение равно 4. и я нахожусь в корневом пользователе. – ipinlnd

ответ

0

После этих ответов и дальнейших чтений я понял, что в моей FreeBSD нет возможности использовать сокет в FreeBSD.
Итак, теперь я использую для этого libpcap. С помощью pcap_sendPacket() я могу отправить пакеты с адресом ethernet.
Спасибо за вашу помощь

1

Из страницы руководства:

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

Я считаю, что вы хотите sendto, а не send.

+0

Но проблема заключается в том, что адрес отправителя соответствует адресу назначения. У меня этого нет. У меня есть только его MAC-адрес. – ipinlnd

+0

@ipinlnd: Оба делают. Единственное различие заключается в том, что 'send' принимает адресата из контекста соединения, которого у вас здесь нет. Вы должны иметь возможность использовать port = 0 и address = NULL, хотя вам также может понадобиться создать сокет с флагом 'IP_HDRINCL', чтобы API не добавлял собственный IP-заголовок. Какое руководство вы используете? –

+0

О, или вы можете использовать MAC-адрес назначения на https: // austinmarton.wordpress.com/2011/09/14/sending-raw-ethernet-packets-from-a-specific-interface-in-c-on-linux/ –

1

При использовании исходных сокетов вы не указываете адрес Ethernet. Необработанные сокеты позволяют создавать IP-датаграммы, в которых вы можете отправить только полезную нагрузку, и сетевой стек настроит заголовок IP, или вы также можете указать заголовок IP, если включена опция сокета IP_HDRINCL. Здесь вы не можете указать Ethernet-адрес. Читайте: http://man7.org/linux/man-pages/man7/raw.7.html

Если у вас нет IP-адреса и есть только адрес Ethernet, это еще одна проблема, которую вам нужно решить по-разному.

Во-первых, вам нужно будет использовать пакетные сокеты http://man7.org/linux/man-pages/man7/packet.7.html и отправить кадр Ethernet на другой узел.

Проблема в том, что другой узел передает этот кадр на верхний уровень (драйвер устройства сделает это). Там, если верхний уровень не видит своего IP-адреса, он отбросит сообщение. Поэтому вы можете отправить сообщение RARP и ожидать, что другой узел ответит вам на передачу своего IP-адреса. Другая возможность заключается в том, что вы реализуете свой собственный протокол уровня 2 ...