2013-04-15 38 views
1

首先,我對以太網和數據鏈路層的主題相當陌生,我試圖編寫一個C程序,它允許發送和接收以太網幀。執行發送和接收原始以太網幀的C程序的問題

我想讓我的程序發送以太網幀給自己,所以程序將有相同的源和目標MAC地址。

,我正在使用的程序是從http://hacked10bits.blogspot.com/2011/12/sending-raw-ethernet-frames-in-6-easy.html

我一直有與recvfrom的()函數故障代碼的修改版本,它似乎只是阻止該程序不會終止。從代碼中,我嘗試發送以太網幀並使recvfrom()函數能夠檢索幀並將其存儲在緩衝區中。但是因爲recvfrom()函數只是阻塞,所以在我看來,sendto()函數無法成功發送幀。

任何想法我怎麼能解決這個問題?

這裏是我的代碼:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/socket.h> /* Must precede if*.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 = "eth0"; 
    unsigned char dest[ETH_ALEN] 
      = { 0x00, 0x12, 0x34, 0x56, 0x78, 0x90 }; 
    unsigned short proto = 0x1234; 
    unsigned char *data = "hello world"; 
    unsigned short data_len = strlen(data); 

    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); 

    //edited part... here we have it so that the destination mac address is 
    //the same as the source mac address 
    memcpy((void*)dest, (void*)(buffer.ifr_hwaddr.sa_data), 
     ETH_ALEN); 

    //probe source mac address 
    int k; 
    for(k = 0; k !=ETH_ALEN; k++) 
    { 
    printf("%x\n",source[k]); 
    printf("%x\n",dest[k]); 
    } 

    union ethframe frame; 
    memcpy(frame.field.header.h_dest, dest, ETH_ALEN); 
    memcpy(frame.field.header.h_source, source, ETH_ALEN); 
    frame.field.header.h_proto = htons(proto); 
    memcpy(frame.field.data, data, data_len); 

    unsigned int frame_len = data_len + ETH_HLEN; 

    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); 

    if (sendto(s, frame.buffer, frame_len, 0, 
      (struct sockaddr*)&saddrll, sizeof(saddrll)) > 0) 
    printf("Frame successfully sent!\n"); 
    else 
    printf("Error, could not send\n"); 


    struct sockaddr_ll saddrll_receive; 
    memset((void*)&saddrll_receive, 0, sizeof(saddrll_receive)); 
    socklen_t sll_len = (socklen_t)sizeof(saddrll_receive); 

    int recv_result; 
    char buffer_receive[ETH_FRAME_LEN]; 
    recv_result = recvfrom(s, buffer_receive, ETH_FRAME_LEN, 0, 
       (struct sockaddr*)&saddrll_receive, &sll_len); 


    close(s); 

    return 0; 
} 

當然,這是一臺Linux機器上。

+0

我知道這是一箇舊的線程,但嘿..它可能有可能你的框架形成,甚至傳輸,但在你的操作系統的驅動程序不夠聰明,'包裝'框架回來;據它所知,它是外向的,就是這樣。如果您有連接到端口的交換機,交換機可能會爲您反彈。 – JustJeff

回答

0

您必須擁有root權限才能使用原始套接字。

嘗試將插座設置爲非阻塞模式:

flags = fcntl (sock, F_GETFL); 
fcntl (sock, F_SETFL, flags | O_NONBLOCK); 
+0

是的,我知道。我已經在root權限下運行該程序。 sendto()命令返回值> = 0。但是,當recvfrom()函數被調用時,它只是阻塞。我不確定問題是什麼。 – user1664213

+0

你是否嘗試將你打開的套接字設置爲O_NONBLOCK(man fcntl,請參閱我編輯的答案)? – 0xBAADF00D

+0

我不明白你的編輯答案中的語法。 flag是否是recvfrom函數的輸入? – user1664213

0

你的代碼片段是一樣被張貼在博客上的一個!首先,您必須確保您的接口名稱是「eth0」。然後您必須將目標MAC地址設置爲您計算機的MAC地址 - 因爲您似乎希望在您的計算機上發送和接收數據。目前您的代碼正在使用假設的目標MAC地址。