2013-07-22 106 views
1

當我嘗試發送原始以太網數據包時,我在我的代碼中遇到了sendto函數的問題。原始套接字在虛擬網絡上發送兩個數據包

我使用的Ubuntu 12.04.01 LTS,具有連接在兩個vde_switches兩個抽頭的裝置和一個dpipe

實施例:

我的發送PROGRAMM創建像下面的分組時,PROGRAMM被插座綁定從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 

但我PROGRAMM生成兩個數據包,當我看到在Wireshark的:

第一分組是IPX包和[畸形報文]和十六進制看起來像(數據=試驗)

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] 

從我的源代碼outcut

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

請我需要一些幫助來查找我的錯誤。

謝謝你。

+0

這裏的信息太少。你能否嘗試做出一個完整的,可編輯的,有說服力的例子來展示你的問題。您是否使用RAW或DGRAM數據包套接字發送?請注意,PACKET_OTHERHOST對傳出數據沒有意義。 – thuovila

回答

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 

我的問題:

Fi首先是可以過濾還是忽略第一個數據包?

第二個爲什麼包含第一個數據包是來自send結構的協議類型,第二個數據包是來自緩衝區的協議類型?

實施例:

對於第一分組

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 

我的接收器可以捕獲第一分組而不2個vde_switches並且當我連接與dpipe和vde_plug開關我可以捕捉所述第二分組太之間的連接。

+0

我建議你讓這個問題成爲一個新問題。添加一個新問題作爲答案並不是這應該如何工作。 – thuovila

+0

你是從所有網絡設備捕獲?這將解釋你爲什麼得到兩次包。嘗試從一臺設備捕獲。爲了捕獲「到達」端,不要捕獲發送數據包的設備,而是捕獲發送數據包的設備。 – thuovila

+0

這是從我的接收器代碼剪斷:創建套接字:sock_desc =套接字(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL));在一個設備上綁定套接字:setsockopt(sock_desc,SOL_SOCKET,SO_BINDTODEVICE,&sock_in.ifr_name,strlen(sock_in.ifr_name));並接收數據包:recvfrom(sock_desc,buffer,ETH_FRAME_LEN,0,NULL,NULL); – Patzde

0

請給我們處理套接字創建操作的行。 我假設你已經創建了插座這樣的:

int socket = socket(AF_PACKET,SOCK_RAW,IPPROTO_IP) 

當你建立以太網頭(順便說一下,你應該使用而不是結構ethhdr,它的清潔劑),你是對的。 之後,您發送您的數據,而不會將L4標頭和L3標頭....這是正常的,您的代碼不起作用。 我現在假設你是OSI Model。 如果不是這樣的話,請在閱讀下一篇文章之前閱讀論文。

所以當你想創建一個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

希望它會幫助你

安東尼

+0

嗨安東尼,謝謝你的回答,但我有一個小問題。我不使用具有IP地址的網絡設備,我的通信應該在水龍頭設備上工作。我在Ubuntu論壇[鏈接](http://askubuntu.com/questions/322904/isolated-ethernet)中創建了一個線程,我的問題是如何通過一臺主機上的tap設備與以太網數據包進行通信。最好的問候帕特里克 – Patzde

+0

嗨,我很抱歉,我誤解了你的問題。我從來沒有使用TUN/TAP網絡,所以我無法幫助你。我希望你能得到你的答案。 – deadeert

0

我覺得你的代碼缺少以太網「包類型ID字段」。請參閱struct ethhdr in if_ether.h。現在您將convLen放在原始位置。它可能匹配IPX的原始號碼。嘗試將其設置爲某些內容(例如ETH_P_IP)或測試將其設置爲零時發生的情況。

我知道你想制定自己的協議,並使用長度以太網地址後的字段。不過,我建議您至少保持以太網級別標頭兼容,並在其之上(在以太網幀有效載荷中)構建自己的標頭。否則你會遇到工具(比如wireshark)和試圖解析以太網頭的設備驅動程序的問題。至於你爲什麼發送兩個數據包,我認爲原因在於你從用戶scanf輸入的方式。 while循環是特有的。我建議嘗試發送一些固定的輸入數據,例如char msg[] = "Test";

對不起,如果答案是模糊的。這很難幫助你,因爲你的代碼不完整,我無法測試它。