2014-11-23 66 views
0

我正在使用原始套接字發送數據報,如this教程(第III部分)中給出的。但是,我無法正確打印響應(顯示垃圾字符)。不知道該程序有什麼問題。 任何人都能夠識別錯誤?無法使用原始套接字打印TCP響應

#define P 80  /* TCP port 80 - HTTP */ 

unsigned short /* this function generates header checksums */ 
csum(unsigned short *buf, int nwords) 
{ 
    //checksum code here, omitting for stackoverflow question 
} 

int main() 
{ 
    int s = socket(PF_INET, SOCK_RAW, IPPROTO_TCP); /* open raw socket */ 
    char datagram[4096]; /* this buffer will contain ip header, tcp header, 
    and payload. we'll point an ip header structure 
    at its beginning, and a tcp header structure after 
    that to write the header values into it */ 
    struct ip *iph = (struct ip *) datagram; 
    struct tcphdr *tcph = (struct tcphdr *) datagram + sizeof(struct ip); 
    struct sockaddr_in sin; 
    /* the sockaddr_in containing the dest. address is used 
    in sendto() to determine the datagrams path */ 

    sin.sin_family = AF_INET; 
    sin.sin_port = htons(P);/* you byte-order >1byte header values to network 
    byte order (not needed on big endian machines) */ 
    sin.sin_addr.s_addr = inet_addr("74.125.224.72"); //google's ip address 

    memset(datagram, 0, 4096); /* zero out the buffer */ 

    /* we'll now fill in the ip/tcp header values, see above for explanations */ 
    iph->ip_hl = 5; 
    iph->ip_v = 4; 
    iph->ip_tos = 0; 
    iph->ip_len = sizeof(struct ip) + sizeof(struct tcphdr); /* no payload */ 
    iph->ip_id = htonl(54321); /* the value doesn't matter here */ 
    iph->ip_off = 0; 
    iph->ip_ttl = 255; 
    iph->ip_p = 6; 
    iph->ip_sum = 0; /* set it to 0 before computing the actual checksum later */ 
    iph->ip_src.s_addr = inet_addr("1.2.3.4");/* SYN's can be blindly spoofed */ 
    iph->ip_dst.s_addr = sin.sin_addr.s_addr; 
    tcph->th_sport = htons(1234); /* arbitrary port */ 
    tcph->th_dport = htons(P); 
    tcph->th_seq = random();/* in a SYN packet, the sequence is a random */ 
    tcph->th_ack = 0;/* number, and the ack sequence is 0 in the 1st packet */ 
    tcph->th_x2 = 0; 
    tcph->th_off = 0; /* first and only tcp segment */ 
    tcph->th_flags = TH_SYN; /* initial connection request */ 
    tcph->th_win = htonl(65535); /* maximum allowed window size */ 
    tcph->th_sum = 0;/* if you set a checksum to zero, your kernel's IP stack 
    should fill in the correct checksum during transmission */ 
    tcph->th_urp = 0; 

    iph->ip_sum = csum((unsigned short *) datagram, iph->ip_len >> 1); 

    /* finally, it is very advisable to do a IP_HDRINCL call, to make sure 
    that the kernel knows the header is included in the data, and doesn't 
    insert its own header into the packet before our data */ 
    int one = 1; 
    const int *val = &one; 
    if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0) 
     printf("Warning: Cannot set HDRINCL!\n"); 

    if (sendto(s,datagram,iph->ip_len,0,(struct sockaddr *) &sin, sizeof(sin)) < 0) 
     printf("error\n"); 
    else 
     printf(".\n\n"); 

    sleep(2); // giving enough time to receive response 

    char buffer[8192]; /* single packets are usually not bigger than 8192 bytes */ 
    memset(buffer, 0, 8192); /* zero out the buffer */ 
    while (recv(s, buffer, 8192, 0) > 0) 
     printf("Caught tcp packet: %s\n", buffer + sizeof(struct iphdr) + sizeof(struct tcphdr)); 

    close(s); 
    return 0; 
} 

我得到的輸出顯示此圖像中:http://imgur.com/jjjhp39

+1

首先,使用諸如[Wireshark](http://www.wireshark.org/)的工具來查看網絡上發生了什麼。其次,看起來您正在嘗試[建立連接](http://en.wikipedia.org/wiki/Transmission_Control_Protocol#Connection_establishment),在這種情況下,您將不會收到任何回覆的數據。而且,如果您收到數據回覆,您甚至不會檢查*,而只是打印「數據」。 – 2014-11-23 03:57:15

+0

我認爲只有在用'recv()'函數接收到某些數據時纔會打印程序。由於它是一個SYN數據包,我認爲服務器應該發送一個ACK。 – Sumit 2014-11-23 04:00:46

+0

由於您使用的是原始套接字,因此您收到的數據包將包含IP和TCP標頭,並且這些數據包將以返回的大小計算。 – 2014-11-23 04:04:40

回答

0

嘗試改變:

printf("Caught tcp packet: %s\n", buffer + sizeof(struct iphdr) + sizeof(struct tcphdr)); 

到:

printf("Caught tcp packet: %s\n", buffer); 
+0

感謝Davinder,但收到的回覆只會在ipheader和tcpheader後給出清晰的輸出。 – Sumit 2014-11-23 03:58:19

+0

沒錯。我發佈迴應後意識到。 – Davinder 2014-11-23 04:02:48

0
while (recv(s, buffer, 8192, 0) > 0) 
    printf("Caught tcp packet: %s\n", buffer + sizeof(struct iphdr) + sizeof(struct tcphdr)); 

這是從來沒有正確不存儲結果的recv()在一個變量中。您需要測試它爲零和-1,否則將其用作接收數據的長度。你似乎在嘗試打印一個SYN-ACK數據包的內容

int count; 
while ((count = recv(s, buffer, sizeof buffer, 0)) > 0) 
    printf("Caught tcp packet: %.*s\n", count - sizeof(struct iphdr) - sizeof(struct tcphdr, buffer + sizeof(struct iphdr) + sizeof(struct tcphdr)); 
if (count < 0) 
    perror("recv"); 

編輯:試試這個。沒有任何。

+0

感謝EJP,但我仍然在使用您的代碼收到類似的「垃圾字符」。 – Sumit 2014-11-23 03:56:47

+2

這是因爲'count'是接收到的字節的原始數量,而不是要打印的字符數量。你從不寫任何代碼來正確接收數據並安排打印。你期望它能夠通過魔法工作。 – 2014-11-23 04:17:53

+0

@sam請參閱編輯。但是所有這些都遵循您的假設,即數據實際上是可打印的。 – EJP 2014-11-23 04:57:54

0

您需要使用libpcap庫從鏈路層檢索數據包。