【问题标题】:cannot receive raw ethernet frame packets I just sent无法接收我刚刚发送的原始以太网帧数据包
【发布时间】:2014-04-25 08:39:03
【问题描述】:

我在这个网站上引用了C代码:https://gist.github.com/austinmarton/2862515

这是一张图片来解释:

我分两部分编辑,一个是ethertype(把0x0800改成custom-protocol 0x1234) 另一部分是删除IP头处理的代码(因为原始代码是基于IP的,但我需要一个原始的以太网帧)。

我使用wireshark检测数据包,我可以收到我发送的数据包(在图片左侧),我可以看到send.out准确发送数据包(图片右下角)。但是recv.out不能接收数据包!?(图片右上角)。

但是,如果我使用 0x0800 作为协议,recv.out 可以接收来自外部的数据包,但仍然无法接收我发送的数据包。

设置socket有没有错误

这是我的代码:

发送.c

#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/ether.h>

#define MY_DEST_MAC0    0xbc
#define MY_DEST_MAC1    0xee
#define MY_DEST_MAC2    0x7b
#define MY_DEST_MAC3    0x75
#define MY_DEST_MAC4    0x56
#define MY_DEST_MAC5    0x2a

#define DEFAULT_IF  "eth0"
#define BUF_SIZ     1024

int main(int argc, char *argv[])
{
    int sockfd;
    struct ifreq if_idx;
    struct ifreq if_mac;
    int tx_len = 0;
    char sendbuf[BUF_SIZ];
    struct ether_header *eh = (struct ether_header *) sendbuf; /*structure*/
    struct iphdr *iph = (struct iphdr *) (sendbuf + sizeof(struct ether_header));
    struct sockaddr_ll socket_address;
    char ifName[IFNAMSIZ];

    unsigned short proto = 0x1234;

    /* Get interface name *//*eth0*/
    if (argc > 1)
        strcpy(ifName, argv[1]);
    else
        strcpy(ifName, DEFAULT_IF);

    /* Open RAW socket to send on *//*IPv4*/
    if ((sockfd = socket(AF_PACKET, SOCK_RAW, htons(proto))) == -1) {
        perror("socket");
    }

    /* Get the index of the interface to send on *//*0*/
    memset(&if_idx, 0, sizeof(struct ifreq));
    strncpy(if_idx.ifr_name, ifName, IFNAMSIZ-1);
    if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0)/*save INDEX info into if_idx*/
        perror("SIOCGIFINDEX");
    /* Get the MAC address of the interface to send on *//*local*//*save MAC info into if_mac*/
    memset(&if_mac, 0, sizeof(struct ifreq));
    strncpy(if_mac.ifr_name, ifName, IFNAMSIZ-1);
    if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0)
        perror("SIOCGIFHWADDR");

    /* Construct the Ethernet header */
    memset(sendbuf, 0, BUF_SIZ);
    /* Ethernet header */
    eh->ether_shost[0] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[0];
    eh->ether_shost[1] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[1];
    eh->ether_shost[2] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[2];
    eh->ether_shost[3] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[3];
    eh->ether_shost[4] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[4];
    eh->ether_shost[5] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[5];
    eh->ether_dhost[0] = MY_DEST_MAC0;
    eh->ether_dhost[1] = MY_DEST_MAC1;
    eh->ether_dhost[2] = MY_DEST_MAC2;
    eh->ether_dhost[3] = MY_DEST_MAC3;
    eh->ether_dhost[4] = MY_DEST_MAC4;
    eh->ether_dhost[5] = MY_DEST_MAC5;
    /* Ethertype field */
    eh->ether_type = htons(proto);
    tx_len += sizeof(struct ether_header);

    /* Packet data */
    sendbuf[tx_len++] = "h";
    sendbuf[tx_len++] = "e";
    sendbuf[tx_len++] = "l";
    sendbuf[tx_len++] = "l";
    sendbuf[tx_len++] = "o";

    /* Index of the network device */
    socket_address.sll_ifindex = if_idx.ifr_ifindex;
    /* Address length*/
    socket_address.sll_halen = ETH_ALEN;
    /* Destination MAC */
    socket_address.sll_addr[0] = MY_DEST_MAC0;
    socket_address.sll_addr[1] = MY_DEST_MAC1;
    socket_address.sll_addr[2] = MY_DEST_MAC2;
    socket_address.sll_addr[3] = MY_DEST_MAC3;
    socket_address.sll_addr[4] = MY_DEST_MAC4;
    socket_address.sll_addr[5] = MY_DEST_MAC5;

    /* Send packet */
int cnt=0;
while(cnt<5){
    if (sendto(sockfd, sendbuf, tx_len, 0, (struct sockaddr*)&socket_address, sizeof(struct sockaddr_ll)) < 0)
        printf("Send failed\n");
    else
        printf("success!\n");

    cnt++;
}
    return 0;

}

recv.c

#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/ether.h>

#define DEST_MAC0   0xbc
#define DEST_MAC1   0xee
#define DEST_MAC2   0x7b
#define DEST_MAC3   0x75
#define DEST_MAC4   0x56
#define DEST_MAC5   0x2a

#define ETHER_TYPE  0x1234

#define DEFAULT_IF  "eth0"
#define BUF_SIZ     1024

int main(int argc, char *argv[])
{
    char sender[INET6_ADDRSTRLEN];
    int sockfd, ret, i;
    int sockopt;
    ssize_t numbytes;
    struct ifreq ifopts;    /* set promiscuous mode */
    struct sockaddr_storage their_addr;
    uint8_t buf[BUF_SIZ];
    char ifName[IFNAMSIZ];

    /* Get interface name *//*eth0*/
    if (argc > 1)
        strcpy(ifName, argv[1]);
    else
        strcpy(ifName, DEFAULT_IF);

    /* Header structures */
    struct ether_header *eh = (struct ether_header *) buf;

    /* Open PF_PACKET socket, listening for EtherType ETHER_TYPE *//*0x1234*/
    if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE))) == -1) {
        perror("listener: socket"); 
        return -1;
    }

    /* Set interface to promiscuous mode - do we need to do this every time? *//*cpy ifname into ifr_name*/
    strncpy(ifopts.ifr_name, ifName, IFNAMSIZ-1);
    ioctl(sockfd, SIOCGIFFLAGS, &ifopts); /*set promisc mode*/
    ifopts.ifr_flags |= IFF_PROMISC;
    ioctl(sockfd, SIOCSIFFLAGS, &ifopts);
    /* Allow the socket to be reused - incase connection is closed prematurely */
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof sockopt) == -1) {
        perror("setsockopt");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
    /* Bind to device */
    if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, ifName, IFNAMSIZ-1) == -1)  {
        perror("SO_BINDTODEVICE");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

repeat: printf("listener: Waiting to recvfrom...\n");
    numbytes = recvfrom(sockfd, buf, BUF_SIZ, 0, NULL, NULL);
    printf("listener: got packet %lu bytes\n", numbytes);

    /* Check the packet is for me */
    if (eh->ether_dhost[0] == DEST_MAC0 &&
            eh->ether_dhost[1] == DEST_MAC1 &&
            eh->ether_dhost[2] == DEST_MAC2 &&
            eh->ether_dhost[3] == DEST_MAC3 &&
            eh->ether_dhost[4] == DEST_MAC4 &&
            eh->ether_dhost[5] == DEST_MAC5) {
        printf("Correct destination MAC address\n");
    } else {
        printf("Wrong destination MAC: %x:%x:%x:%x:%x:%x\n",
                        eh->ether_dhost[0],
                        eh->ether_dhost[1],
                        eh->ether_dhost[2],
                        eh->ether_dhost[3],
                        eh->ether_dhost[4],
                        eh->ether_dhost[5]);
        ret = -1;
        goto done;
    }

    /* Print packet */
    printf("\tData:");
    for (i=0; i<numbytes; i++) printf("%02x:", buf[i]);
    printf("\n");

done:   goto repeat;

    close(sockfd);
    return ret;
}

【问题讨论】:

    标签: sockets frame ethernet


    【解决方案1】:

    您可以通过以下更改接收代码从目标中获取所有帧:

    请替换行: if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE))) == -1) {

    用这一行: if ((sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {

    因为在您的原始代码中您更改了正常的以太网标头类型,所以操作系统无法检测到它的进程侦听器(您的程序)并将其发送给您,但是当您设置此行时,操作系统可以获得所有结果,因此您可以获得特殊的答案。

    【讨论】:

      【解决方案2】:

      我开始做套接字编程,所以应该有人确认一下。

      我很确定接口会丢弃数据包,因为源和目标 mac 相同...尝试使用另一台 PC 并更改每一侧的目标 mac 以确认这一点(虚拟机也可以)

      【讨论】:

        【解决方案3】:

        我也使用了类似的代码来传输以太网帧。这种类型的套接字在本地不起作用。正如@Goncalo 建议的那样,使用不同的 PC,或者如果您的 PC 上有两个 NIC,您应该使用它们。这是我用来接收帧的代码。

        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        #include <sys/socket.h>    
        #include <linux/if.h>
        #include <linux/if_ether.h>
        #include <linux/if_packet.h>
        #include <sys/ioctl.h>
        
        union ethframe
        {
          struct
          {
            struct ethhdr    header;
            unsigned char    data[ETH_DATA_LEN];
          } field;
          unsigned char    buffer[ETH_FRAME_LEN];
        };
        
        int main(int argc, char **argv) {
          char *iface = "eth1";
          unsigned char dest[ETH_ALEN]     
                  = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
          unsigned short proto = 0x1234;
          int recv_result,i;
          char buff[ETH_FRAME_LEN];
          unsigned short data_len;
        
          int s;
          if ((s = socket(AF_PACKET, SOCK_RAW, htons(proto))) < 0) {
            printf("Error: could not open socket\n");
            return -1;
          }
        
          struct ifreq buffer;
          int ifindex;
          memset(&buffer, 0x00, sizeof(buffer));
          strncpy(buffer.ifr_name, iface, IFNAMSIZ);
          if (ioctl(s, SIOCGIFINDEX, &buffer) < 0) {
            printf("Error: could not get interface index\n");
            close(s);
            return -1;
          }
          ifindex = buffer.ifr_ifindex;
        
          unsigned char source[ETH_ALEN];
          if (ioctl(s, SIOCGIFHWADDR, &buffer) < 0) {
            printf("Error: could not get interface address\n");
            close(s);
            return -1;
          }
          memcpy((void*)source, (void*)(buffer.ifr_hwaddr.sa_data),
                 ETH_ALEN);
        
        
          struct sockaddr_ll saddrll;
          memset((void*)&saddrll, 0, sizeof(saddrll));
          saddrll.sll_family = PF_PACKET;   
          saddrll.sll_ifindex = ifindex;
          saddrll.sll_halen = ETH_ALEN;
          memcpy((void*)(saddrll.sll_addr), (void*)dest, ETH_ALEN);
        
          socklen_t sll_len = (socklen_t)sizeof(saddrll);  
        
          if (recv_result = recvfrom(s, buff, ETH_FRAME_LEN, 0,
            (struct sockaddr *)&saddrll, &sll_len) > 0)
            printf("Success!\n");
          else
            printf("Error, could not send\n");
        
          data_len=sizeof(buff);
          printf("\tData:");
            for (i=0; i<data_len; i++) printf("%c", buff[i]);
        
        
          printf("\tDone: \n");
          close(s);
        
          return 0;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-12-02
          • 1970-01-01
          • 2018-11-29
          • 2012-08-27
          • 1970-01-01
          • 1970-01-01
          • 2010-12-24
          相关资源
          最近更新 更多