2014-12-04 119 views
5

我想解析一個tcp數據包,然後分配給一個指向有效負載開始的指針。解析TCP數據包的數據

我正在使用C,這是我到目前爲止的代碼:

void dump(const unsigned char *data, int length) { //*data contains the raw packet data 
    unsigned int i; 
    static unsigned long pcount = 0; 

    // Decode Packet Header 
    struct ether_header *eth_header = (struct ether_header *) data; 

    printf("\n\n === PACKET %ld HEADER ===\n", pcount); 

    printf("\nSource MAC: "); 
    for (i = 0; i < 6; ++i) { 
     printf("%02x", eth_header->ether_shost[i]); //? Why don't i use nthos here? 
     if (i < 5) printf(":"); 
    } 

    unsigned short ethernet_type = ntohs(eth_header->ether_type); 
    printf("\nType: %hu\n", ethernet_type); 

    if (ethernet_type == ETHERTYPE_IP) { //IP Header 
     printf("\n == IP HEADER ==\n"); 
     struct ip *ip_hdr = (struct ip*) data + sizeof(struct ether_header); 
     unsigned int size_ip = ip_hdr->ip_hl * 4; 
     printf("\nIP Version: %u", ip_hdr->ip_v); //? Nthos or no nthos 
     printf("\nHeader Length: %u", ip_hdr->ip_hl); //? Nthos or no nthos 
     printf("\nTotal Length: %hu", ntohs(ip_hdr->ip_len)); //? Nthos or no nthos 

     // TCP Header 
     printf("\n== TCP HEADER ==\n"); 
     struct tcphdr *tcp_hdr = (struct tcphdr*) data + sizeof(struct ether_header) + size_ip; 
     printf("\n Source Port: %" PRIu16, nthos(tcp_hdr->th_sport)); 
     printf("\n Destination Port: %" PRIu16, nthos(tcp_hdr->th_dport)); 
     printf("\n fin: %" PRIu16, tcp_hdr->fin); 
     printf("\n urg: %" PRIu16, tcp_hdr->urg); 
     printf("\n ack_seq: %" PRIu32, ntohl(tcp_hdr->ack_seq)); 

     //Transport payload! i.e. rest of the data 
     const unsigned char *payload = data + ETH_HLEN + size_ip + sizeof(struct tcphdr) + tcp_hdr->doff; 

    } 

我敢肯定有這個代碼的錯誤,因爲端口號都是怪異。沒有一個分配給80.輸出的IP版本也可能非常奇怪(如版本11)。我究竟做錯了什麼?謝謝!

此外,我不確定何時使用nthos和何時不使用。我知道nos是16位無符號整數,我知道nthol是32位無符號整數,但我知道你不打算在這些數據包中使用它們(比如:tcp_hdr-> fin)。爲什麼某些事情,而不是他們?

很多謝謝!

編輯:

感謝爲藝術而固定大部分F中的問題。我編輯了我的tcp_hdr和ip_hdr,所以括號現在是正確的!

我仍然有2個問題:

  • 的前10個字節有效載荷的具有怪異符號(所以我認爲我還沒有正確分配的有效載荷)。
  • 我還不確定何時使用nthos/nthol。我知道u_int16_t是ntohs,而u_int32_t是ntohl。但是,如何處理int或unisgned short int。例如,我沒有使用ntohs或nthol來使ip_v工作。爲什麼不?是「ip_hdr-> ip_hl」nthol?等等...

EDIT2

我有固定的,爲什麼我的有效載荷不正確輸出(這是因爲我計算的TCP_header大小錯誤)。

儘管我仍然對何時使用底座感到困惑,但我會把它作爲一個單獨的問題,因爲我想我在這篇文章中提出了太多問題!

When to use ntohs and ntohl in C?

+0

你知道,之類的東西端口號是*網絡*字節順序?使用'ntohs'將網絡字節順序中的短(16位)值轉換爲主機字節順序。 – 2014-12-04 14:15:20

+0

我試了兩次,但得到eitehr奇怪的數字。無論如何更新代碼! – 2014-12-04 14:17:35

+0

是否有其他字段看起來正確?像源/目標地址一樣?以太網頭?它與在例如同一個數據包中的比較看起來如何? Wireshark的?你*做*接收這個原始的插座?並接收所有的數據包? – 2014-12-04 14:26:28

回答

5

最有可能您的問題就在這裏:

struct ip *ip_hdr = (struct ip*) data + sizeof(struct ether_header); 
struct tcphdr *tcp_hdr = (struct tcphdr*) data + sizeof(struct ether_header) + size_ip; 

(struct ip*) data + sizeof(struct ether_header)第一蒙上數據struct ip *,然後將sizeof(struct ether_header)給它,這是我們從指針算術知道不會做你希望它是什麼去做。

如果問題仍不清楚,這裏有一個簡單的程序,應該指向你在正確的方向:

#include <stdio.h> 

struct foo { 
    int a, b; 
}; 

int 
main(int argc, char **argv) 
{ 
    char *x = NULL; 

    printf("%p\n", x); 
    printf("%p\n", (struct foo *)x + 4); 
    printf("%p\n", (struct foo *)(x + 4)); 

    return 0; 
} 
+0

這就解決了我幾乎所有的問題。你介意如果你也回答我的問題的第二部分是什麼時候使用ntohs。我現在制定的規則是針對任何類型的u_int16_t是ntohs而u_int32_t是ntohl。但是,如何處理int或unisgned short int。例如,我沒有使用iph的ntohs來運行它。爲什麼不?謝謝 – 2014-12-04 14:48:32

+0

看看ip頭和一個定義。基本規則是:不要轉換1B或更短的值(ip_v,ip_hl)。你使用2B值的ntohs(ip_len,ip_p)。您使用ntohl獲取4B值。 「但是,如何處理int或unisgned short int」:它是否簽名並不重要(我認爲ip hdr中沒有任何有符號的值),所以signed int只是4B值無符號短是2B值。你可以在這裏看到IP頭文件:http://en.wikipedia.org/wiki/IPv4#Header – davak 2014-12-04 15:38:11

+0

因此等待「ip_hdr-> ip_hl」使用htol,因爲它的類型爲「unsigned int ip_hl:4;」 當我添加htol時,甚至在讀取TCP頭之前程序終止(可能意味着它讀取了它不應該記憶的一部分內容)。但是,當我離開它沒有ntohl或ntohs它工作得很好! – 2014-12-04 15:52:04