1

当我尝试发送原始以太网数据包时,我的代码中的 sendto 函数出现问题。

我使用的是 Ubuntu 12.04.01 LTS,通过两个 vde_switches 和一个 dpipe 连接了两个 Tap 设备

例子:

我的发送程序创建如下所示的数据包,程序由来自tap0的套接字绑定并将数据包发送到tap1。在 tap1 上,一个接收器等待套接字上的所有数据包。

我的原始以太网数据包看起来是这样的:

目的地地址__ __ _地址_ _ __ _ ___ 类型/长度__ _数据

00:00:01:00:00:00 _ __ 00:00:01:00:00:01 _ ___字节长度_一些数据

要发送的示例数据包:

00:00:01:00:00:00 00:00:01:00:00:01 (length in byte) (Message)test

但是当我查看wireshark时,我的程序会生成两个数据包:

第一个数据包是 IPX 数据包和 [Malformed Packet],看起来像十六进制(数据 = 测试)

00 04 00 01 00 06 00 00 01 00 00 01 00 00 00 01 74 65 73 74 00

Linux cooked capture

Packet type: sent by us (4)

Link-layer address type: 1

Link-layer address length: 6

Source: 00:00:01:00:00:01

Protocol: Raw 802.3 (0x0001)

[Malformed Packet: IPX]

第二个数据包未知协议

00 00 00 01 00 06 00 00 01 00 00 01 00 00 31 00 74 65 73 74 00

Linux cooked capture

Packet type: Unicast to us (0)

Link-layer address type: 1

Link-layer address length: 6

Source: 00:00:01:00:00:01

Protocol: Unknown (0x3100)

Data

Data: 7465737400

[Length: 5]

从我的源代码中删除

sock_desc = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));


/*struct for sending*/
    sock_addr.sll_family = AF_PACKET;
    sock_addr.sll_protocol = htons(ETH_P_802_3);
    sock_addr.sll_ifindex = if_nametoindex(argv[1]);
    sock_addr.sll_hatype = ARPHRD_ETHER; //Ethernet 10Mbps
    sock_addr.sll_pkttype = PACKET_HOST; // Paket zu irgendjemand
    sock_addr.sll_halen = ETH_ALEN; //6 Oktets in einer ethernet addr
    /*MAC Length 8 Oktets*/
    sock_addr.sll_addr[0] = frame.src_mac[0];
    sock_addr.sll_addr[1] = frame.src_mac[1];
    sock_addr.sll_addr[2] = frame.src_mac[2];
    sock_addr.sll_addr[3] = frame.src_mac[3];
    sock_addr.sll_addr[4] = frame.src_mac[4];
    sock_addr.sll_addr[5] = frame.src_mac[5];
    /*not in use*/  
    sock_addr.sll_addr[6] = 0x00;
    sock_addr.sll_addr[7] = 0x00;

    memset(buffer, '0', sizeof(char)*ETH_FRAME_LEN);
    /*set the frame header*/

    /*build RAW Ethernet packet*/
    buffer[0] = frame.dest_mac[0];
    buffer[1] = frame.dest_mac[1];
    buffer[2] = frame.dest_mac[2];
    buffer[3] = frame.dest_mac[3];
    buffer[4] = frame.dest_mac[4];
    buffer[5] = frame.dest_mac[5];

    buffer[6] = frame.src_mac[0];
    buffer[7] = frame.src_mac[1];
    buffer[8] = frame.src_mac[2];
    buffer[9] = frame.src_mac[3];
    buffer[10] = frame.src_mac[4];
    buffer[11] = frame.src_mac[5];

    while(frame.data[0] != '*'){
      printf("Input: ");
      scanf("%s", frame.data);

      tempLength = 0;
      while(frame.data[tempLength] != '\0'){
      tempLength++;
      }
      input = 0;
      for(sendLen = 14;sendLen <= (14+tempLength);sendLen++){
          buffer[sendLen] = frame.data[input];
          input++;
      }

      sprintf(convLen,"%x", (14 + input));
      buffer[12] = convLen[0];
      buffer[13] = convLen[1];

      length_in_byte = sendto(sock_desc, buffer, 14+input,0,(struct sockaddr*) &sock_addr,sizeof(struct sockaddr_ll));
      if(length_in_byte <= 0){
        printf("Error beim Senden");
      }else{
            printf("\n");
            printf("src: %02x:%02x:%02x:%02x:%02x:%02x\t->\tdest: %02x:%02x:%02x:%02x:%02x:%02x\n",frame.src_mac[0],frame.src_mac[1],frame.src_mac[2],frame.src_mac[3],frame.src_mac[4],frame.src_mac[5],frame.dest_mac[0],frame.dest_mac[1],frame.dest_mac[2],frame.dest_mac[3],frame.dest_mac[4],frame.dest_mac[5]);
            printf("Data: %s\n", frame.data);
      }
  }

请我需要一些帮助来找出我的错误。

谢谢转发。

4

3 回答 3

0

好的,我明白为什么我的接收器会收到两个数据包。第一个数据包是我们发送的数据包,第二个是单播给我们的数据包。我不需要接收第一个数据包的问题。我已经测试了我的代码,并以两个数据包为例进行了一次捕获。

来自 Wireshark 的十六进制代码的第一帧:

0004 0001 0006 0000010000020000 0060 the message

第二帧:

0000 0001 0006 0000010000020000 1234 the message

这是Linux熟抓的一种手段:

2 Bytes packet typ // 0 = To us; 1 = Broadcast; 2 = Multicast; 3 = from somebody to somebody; 4 = sent by us

2 Bytes LINUX ARPHDR_ value
2 Bytes Link layer addr. lenght
8 Bytes source address
2 Bytes Ethernet protocol //e.g. 1 Novell 802.3 without 802.2 header; 4 frames with 802.2 header

我的问题:

首先是否可以过滤或忽略第一个数据包?

其次,为什么包含来自发送结构的协议类型的第一个数据包和来自缓冲区的协议类型的第二个数据包?

例子:

对于第一个数据包

sock_addr.sll_family = AF_PACKET;
sock_addr.sll_protocol = htons(0x0060);
sock_addr.sll_ifindex = 3;
sock_addr.sll_hatype = ARPHRD_ETHER;
sock_addr.sll_pkttype = PACKET_HOST;
sock_addr.sll_halen = ETH_ALEN; 
/*MAC Length 8 Oktets*/
sock_addr.sll_addr[0] = 0x00;
sock_addr.sll_addr[1] = 0x00;
sock_addr.sll_addr[2] = 0x01
sock_addr.sll_addr[3] = 0x00;
sock_addr.sll_addr[4] = 0x00;
sock_addr.sll_addr[5] = 0x02;
/*not in use*/  
sock_addr.sll_addr[6] = 0x00;
sock_addr.sll_addr[7] = 0x00;

对于第二个数据包,缓冲区如 802.3 帧

buffer[0-5] = 0x00 0x00 0x01 0x00 0x00 0x03 // Destination address
buffer[6-11] = 0x00 0x00 0x01 0x00 0x00 0x02 // Source address
buffer[12-13] = 0x12 0x34 // Protocol dummy typ

我的接收器可以在两个 vde_switch 之间没有连接的情况下捕获第一个数据包,当我使用 dpipe 和 vde_plug 连接交换机时,我也可以捕获第二个数据包。

于 2013-07-25T12:34:12.837 回答
0

我认为您的代码缺少以太网“数据包类型 ID 字段”。请参阅if_ether.h 中的 struct ethhdr。现在你把convLen原型放在哪里。它可能与 IPX 的原型编号匹配。尝试将其设置为某个值(例如 ETH_P_IP)或测试将其设置为零时会发生什么。

我了解您想制作自己的协议,并使用以太网地址后面的字段作为长度。但是,我建议您至少保持以太网级标头标准兼容,并在此基础上构建您自己的标准(在以太网帧有效负载中)。否则你会遇到工具(如wireshark)和尝试解析以太网标头的设备驱动程序的问题。

至于为什么要发送两个数据包,我认为原因在于您扫描用户输入的方式。while 循环很奇特。我建议尝试使用固定输入发送一些数据,例如char msg[] = "Test";

对不起,如果答案含糊不清。很难为您提供帮助,因为您的代码不完整,我无法对其进行测试。

于 2013-07-23T08:57:50.170 回答
0

请给我们处理套接字创建操作的行。我假设您已经创建了这样的套接字:

int socket = socket(AF_PACKET,SOCK_RAW,IPPROTO_IP)

当您构建以太网标头时,您是对的(顺便说一下,您应该使用 struct ethhdr,它更干净)。之后,您发送数据,而不放置 L4 标头和 L3 标头......您的代码不起作用是正常的。我假设你现在是OSI 模型。如果不是这种情况,请在阅读下一篇文章之前阅读论文。

所以当你想创建一个 RAW 数据包时,你有很多事情要做。例如,如果您想使用 TCP/IP 协议,您将必须执行下一个操作

 #include <unistd.h>
 #include <stdio.h>
 #include <sys/socket.h>
 #include <netinet/ip.h>
 #include <netinet/tcp.h>
 #DEFINE SIZEMAX 1000
 int main() {
 char buffer[65535] // MDU
 // CREATE YOUR SOCKET 
 int socket = socket(AF_PACKET,SOCK_RAW,IPPROTO_RAW) ; 
 // You can also specify some opt to your socket but I let you done your own stuffs
 struct ethhdr * ethdr ; 
 struct iphdr * iph ; 
 struct tcphdr * tcph; 
 // Fill all the fields of these last structures (i can't do it for you too long). 
 // Fill the buffer
 memcpy(buffer,ethdr,sizeof(struct ethhdr)) ; 
 // Deplace it to the good addr
 buffer = buffer + sizeof(struct ethhdr) ; 
 memcpy(buffer,iph,sizeof(struct iphdr)) ; 
 buffer = buffer + sizeof(struct iphdr)) ; 
 memcpy(buffer,tcph,sizeof(struct tcphdr)) ; 
 printf("your entry : \n") ; 
 char * entry = malloc(SIZEMAX) ; 
 sncanf("%s",entry,100) ; 
 buffer = buffer+ 100 ; 
 memcpy(buffer,entry,100) ; 
 int size_send = sendto(socket,.......) ;  
 if(size_send =< 0) 
   perror("error sending data") ; 

 return 0 ; 

}

这是伪代码,但它告诉您如何发送原始数据包。本文将为您完成工作: RAW Socket TCP/IP

希望对你有帮助

安东尼

于 2013-07-22T13:50:59.910 回答