Возможен ли необработанный сокет на петлевом интерфейсе? - PullRequest
8 голосов
/ 26 июля 2010

Мы пытаемся установить связь с сервером, прослушивающим интерфейс обратной связи Linux через raw-сокет, и кажется, что сервер не получает от нас ни одного пакета. Посылаемые нами пакеты видны в Wireshark.

Возможно ли вообще использовать raw loop on loopback? (Пожалуйста, не спрашивайте, зачем нам это нужно: здесь слишком сложно объяснить)

РЕДАКТИРОВАТЬ: вот как мы его открываем

_I_RawSocket = socket( PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)))

memset( &ifr, 0, sizeof( ifr ) );
strcpy( ifr.ifr_ifrn.ifrn_name, _InterfaceName);

ioctl( _I_RawSocket, SIOCGIFINDEX, &ifr )

memset( &sll, 0, sizeof( sll ) );
sll.sll_family   = AF_PACKET;
sll.sll_ifindex  = ifr.ifr_ifindex;
sll.sll_protocol = htons( ETH_P_ALL );

bind( _I_RawSocket, (struct sockaddr *) &sll, sizeof( sll ))

Сервер - lighttpd, и он доступен через обычный сокет на localhost. netstat --raw печатает пустую таблицу, но я абсолютно уверен, что у нас есть два функциональных необработанных сокета на обычных устройствах eth.

Ответы [ 2 ]

3 голосов
/ 26 июля 2010

Необработанные сокеты ведут себя особенно шокирующе с bind () и connect (), но я не могу подтвердить, что ваша проблема связана с ними. Я предлагаю вам следовать более простому подходу:

Отправитель

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define DEST "127.0.0.1"

int main(int argc, char **argv)
{

 int s;
 struct sockaddr_in dst_addr;
 char packet[50];

 struct iphdr *ip = (struct iphdr *)packet;  

 if((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
  perror("error:");
  exit(EXIT_FAILURE);
 }

 dst_addr.sin_family = AF_INET;
 dst_addr.sin_port = 0; /* not needed in SOCK_RAW */
 inet_pton(AF_INET, DEST, (struct in_addr *)&dst_addr.sin_addr.s_addr);
 memset(dst_addr.sin_zero, 0, sizeof(dst_addr.sin_zero));

 memset(packet, 'A', sizeof(packet));   /* payload will be all As */

 ip->ihl = 5;
 ip->version = 4;
 ip->tos = 0;
 ip->tot_len = htons(40);
 ip->frag_off = 0;  /* NF */
 ip->ttl = 64;
 ip->protocol = IPPROTO_RAW; /* this has to be IPPROTO_RAW */
 ip->check = 0;
 ip->saddr = dst_addr.sin_addr.s_addr;
 ip->daddr = dst_addr.sin_addr.s_addr;

 while(42) {
  sleep(5);
  if (sendto(s, packet, sizeof(packet), 0, 
   (struct sockaddr *)&dst_addr, (socklen_t)sizeof(dst_addr)) < 0)
   perror("uh oh:");
 }
 return(0);
}

Приемник

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>


int main(int argc, char **argv)
{
 int s;
 struct sockaddr_in src_addr;
 char packet[50];

 if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
  perror("error:");
  exit(EXIT_FAILURE);
 }

 memset(packet, 0, sizeof(packet));
 socklen_t *len = (socklen_t *)sizeof(src_addr);
 int fromlen = sizeof(src_addr);

 while(42) {
  if (recvfrom(s, &packet, sizeof(packet), 0,
   (struct sockaddr *)&src_addr, &fromlen) < 0)
   perror("uh oh:");

  int i = sizeof(struct iphdr); /* print the payload */
  for(; i < sizeof(packet); i++) {
   printf("%c", packet[i]);
  }
  printf("\n");
 }
 return(0);
}

Я надеюсь, что они ведут себя так, как вы этого хотите. Прочитайте man 7 raw, чтобы узнать о том, почему это работает, и , что более важно, man 7 packet, если вы хотите его расширить. Также обратите внимание, что IPPROTO_RAW подразумевает опцию сокета IP_HDRINCL, поэтому мы сами создаем заголовок ip - хотя контрольная сумма IP и общая длина вычисляются и заполняются ядром, все же.

edit: Кроме того, если вы хотите использовать необработанный сокет для отправки действительных данных в приложение, такое как lighttpd, вам нужно будет сопоставить аргумент protocol с socket(), а также указать действительные значения для IP. поля заголовка. Правильный заголовок Ethernet не обязателен - единственное важное поле будет заполнено для вас стеком ядра.

0 голосов
/ 04 июля 2012

Пожалуйста, убедитесь, что привязаны к if_index

if (ioctl(sock, SIOCGIFINDEX, &stEthReq ) < 0 )
{
    printf( "failed to get IF index!" );
    return -1;
}
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sll_family   = AF_PACKET;
client_addr.sll_ifindex  = stEthReq.ifr_ifru.ifru_ivalue;
client_addr.sll_protocol = VOS_HTONS(usEthType);
ret = bind(sock,(struct sockaddr *)(&client_addr), sizeof(client_addr));
...