2011-04-16 73 views
5

我正在學習原始插座。我使用IP_HDRINCL選項來構建我自己的IP標頭。 IP頭後,我正在建立一個UDP頭。然後我將數據包發送到我的系統的環回地址。我有另一個運行的程序,它會在它們來的時候捕獲UDP數據包。爲了檢查數據包是否被正確地形成和接收,我正在運行另一個正在讀取原始IP數據報的進程。我的問題是,儘管第二個進程(讀取原​​始數據報)運行良好(所有IP和UDP字段似乎都沒問題),但第一個進程(接收UDP)沒有收到我創建的任何數據包。在IP頭的協議字段是好的,並且端口也匹配... 我使用Linux 2.6.35-22。 我想知道這在新內核中是否正常?請檢查下面的代碼是否有任何錯誤。該UDP進程應該接收數據包監聽綁定到端口50000在同一臺機器上的一個插座上...原始套接字幫助:爲什麼由原始套接字創建的UDP數據包沒有被內核UDP接收?

unsigned short in_cksum(unsigned short *addr, int len) 
{ 
    int nleft = len; 
    int sum = 0; 
    unsigned short *w = addr; 
    unsigned short answer = 0; 

    while (nleft > 1) { 
     sum += *w++; 
     nleft -= 2; 
    } 

    if (nleft == 1) { 
     *(unsigned char *) (&answer) = *(unsigned char *) w; 
     sum += answer; 
    } 

    sum = (sum >> 16) + (sum & 0xFFFF); 
    sum += (sum >> 16); 
    answer = ~sum; 
    return (answer); 
} 


main() 
{ 
    int fd=socket(AF_INET,SOCK_RAW,IPPROTO_UDP); 

    int val=1; 

    int ret=setsockopt(fd,IPPROTO_IP,IP_HDRINCL,&val,sizeof(val)); 

    char buf[8192]; 

    /* create a IP header */ 

    struct iphdr* ip=(struct iphdr*)buf;//(struct iphdr*) malloc(sizeof(struct iphdr)); 

    ip->version=4; 
    ip->ihl=5; 
    ip->tos=0; 
    ip->id=0; 
    ip->frag_off=0; 
    ip->ttl=255; 
    ip->protocol=IPPROTO_UDP; 
    ip->check=0; 
    ip->saddr=inet_addr("1.2.3.4"); 
    ip->daddr=inet_addr("127.0.0.1"); 


    struct udphdr* udp=(struct udphdr*)(buf+sizeof(struct iphdr));//(struct udphdr*) malloc(sizeof(struct udphdr)); 
    udp->source=htons(40000); 
    udp->dest=htons(50000); 
    udp->check=0; 
    char* data=(char*)buf+sizeof(struct iphdr)+sizeof(struct udphdr);strcpy(data,"Harry Potter and the Philosopher's Stone"); 
    udp->len=htons(sizeof(struct udphdr)+strlen(data)); 
    udp->check=in_cksum((unsigned short*) udp,8+strlen(data)); 

    ip->tot_len=htons(sizeof(struct iphdr)+sizeof(struct udphdr)+strlen(data)); 

    struct sockaddr_in d; 
    bzero(&d,sizeof(d)); 
    d.sin_family=AF_INET; 
    d.sin_port=htons(50000); 
    inet_pton(AF_INET,"localhost",&d.sin_addr.s_addr); 
    while(1) 
    sendto(fd,buf,sizeof(struct iphdr)+sizeof(struct udphdr)+strlen(data),0,(struct sockaddr*) &d,sizeof(d)); 
} 
+1

火起來的Wireshark。他們甚至擊中電線? – rook 2011-04-16 20:11:23

+0

是的,它們是......它正確地將協議顯示爲UDP,目標端口爲50000.但是,源端口被標記爲「saftynetp」。它具有正確的值40000,但我不知道這是什麼意思 – pflz 2011-04-16 20:14:49

+2

捕獲由socat或其他東西傳輸的真正的UDP數據包,然後嘗試僞造一個相同的數據包。確保檢查包括校驗和在內的所有內容。在數據包轉儲上運行一個像diff一樣的diff程序效果很好。 – rook 2011-04-16 20:28:16

回答

0

我用盡非常類似的東西。問題在於套接字API和通過擴展使用它們的任何程序都不會返回被接口寫入的數據,這與sniffer使用的原始套接字不同,比如wiresharks/tcpdump。所以,即使您的數據包形成正確,它們也不會被UDP應用程序讀取。 如果網絡上有另一臺計算機,請使用其中一臺生成流量,另一臺使用另一臺計算機讀取它。或者,如果你有兩個接口,你可以在每個接口上打開一個原始套接字,一個用於寫入,另一個用於讀取。

3

計算UDP校驗和似乎存在問題。

udp->check=in_cksum((unsigned short*) udp,8+strlen(data)); 

UDP校驗和必須在UDP頭之前包含一些名爲「Pseudo-Header」的內容。該代碼僅通過UDP報頭和有效負載計算校驗和。由於錯誤的校驗和,UDP接收過程可能不會接收數據包。

在Wireshark中啓用校驗和驗證,並檢查UDP數據包的校驗和字段是否正確。

請參閱以下內容: