2013-03-02 51 views
1

我想寫一個簡單的應用程序來輸出dst和src TCP端口號。爲了測試,我嘗試應用pcap過濾器來僅偵聽端口80或來自端口80的數據包。但是,儘管所有內容對我來說都是正確的,但我始終得到端口號爲0的端口號。大約10%的時間我得到了5位數的端口號。任何人都可以給我任何提示,我可能會做錯什麼?偶爾的TCP頭部端口號0

#include<pcap.h> 
#include<stdio.h> 
#include<net/ethernet.h> 
#include<netinet/ip.h> 
#include<netinet/tcp.h> 
#include<arpa/inet.h> 

void handle_packet(u_char* args, const struct pcap_pkthdr* pkthdr, const u_char* p) 
{ 
    struct iphdr* ip_hdr; 
    struct tcphdr* tcp_hdr; 

    ip_hdr = (struct iphdr*) (p+sizeof(struct ether_header)); 
    tcp_hdr = (struct tcphdr*) (ip_hdr+sizeof(struct iphdr)); 
    printf("src:%d\n", ntohs(tcp_hdr->source)); 
    printf("dst:%d\n", ntohs(tcp_hdr->dest)); 
} 

int main(int argc, char** argv) 
{ 
    pcap_t *handle;    /* Session handle */ 
    char *dev;      /* The device to sniff on */ 
    char errbuf[PCAP_ERRBUF_SIZE]; /* Error string */ 
    struct bpf_program filter;  /* The compiled filter */ 
    char filter_app[] = "tcp port 80"; /* The filter expression */ 
    bpf_u_int32 mask;    /* Our netmask */ 
    bpf_u_int32 net;    /* Our IP */ 

    /* Define the device */ 
    dev = pcap_lookupdev(errbuf); 

    /* Find the properties for the device */ 
    pcap_lookupnet(dev, &net, &mask, errbuf); 

    /* Open the session in promiscuous mode */ 
    handle = pcap_open_live(dev, BUFSIZ, 0, 0, errbuf); 

    /* Compile and apply the filter */ 
    pcap_compile(handle, &filter, filter_app, 0, net); 
    pcap_setfilter(handle, &filter); 

    pcap_loop(handle, 10, handle_packet, NULL); 

    pcap_close(handle); 
    return(0); 
} 

回答

3

這裏有兩個問題。首先,請記住C中的指針算術是,比例爲。所以,當你這樣說:

tcp_hdr = (struct tcphdr*) (ip_hdr+sizeof(struct iphdr)); 

你實際上推進更爲字節比您預期(sizeof(struct iphdr) * sizeof(struct iphdr)是精確的)。爲了實現你想要的東西你可以說:

tcp_hdr = (struct tcphdr*) &ip_hdr[1]; 

但是這也行不通。 IP標頭沒有固定的長度。相反,你應該檢查頭的ihl場和計算應該看起來更像是這樣的:

tcp_hdr = (struct tcphdr*) ((char*)ip_hdr + 4*ip_hdr->ihl); /* ihl is the number of 32-bit words in the header */ 

警告:我不知道關於以太網幀,如果他們的頭部有一個固定的長度。您還需要驗證。