繁体   English   中英

在pcap文件中获取数据包的IP地址

[英]getting ip address of a packet in pcap file

我正在用“ winpcap”编程,我在程序中读取了一个“ .pcap”文件,此后,我想获取数据包的IP地址,我写了这些代码来获取IP地址,这是我的代码片段:

  struct sniff_ip {
        u_char ip_vhl;      /* version << 4 | header length >> 2 */
        u_char ip_tos;      /* type of service */
        u_short ip_len;     /* total length */
        u_short ip_id;      /* identification */
        u_short ip_off;     /* fragment offset field */
    #define IP_RF 0x8000        /* reserved fragment flag */
    #define IP_DF 0x4000        /* dont fragment flag */
    #define IP_MF 0x2000        /* more fragments flag */
    #define IP_OFFMASK 0x1fff   /* mask for fragmenting bits */
        u_char ip_ttl;      /* time to live */
        u_char ip_p;        /* protocol */
        u_short ip_sum;     /* checksum */
        struct in_addr ip_src;
        struct in_addr ip_dst; /* source and dest address */



      struct sniff_tcp {
                u_short th_sport;   /* source port */
                u_short th_dport;   /* destination port */
                u_int32_t th_seq;       /* sequence number */
                u_int32_t th_ack;       /* acknowledgement number */};

然后,我读取了文件:

while (pcap_next_ex(handler, &header, &packet) >= 0)
    {

        ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
        tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);

        printf("src port: %d dest port: %d \n", tcp->th_sport, tcp->th_dport);
        fprintf(fp,"src port: %d dest port: %d \n", tcp->th_sport, tcp->th_dport);

        printf("src address: %s dest address: %s \n",  inet_ntoa(ip->ip_src),  inet_ntoa(ip->ip_dst));
        fprintf(fp,"src address: %s dest address: %s \n",  inet_ntoa(ip->ip_src),  inet_ntoa(ip->ip_dst));

        printf("seq number: %u ack number: %u \n", (unsigned int)tcp-> th_seq, (unsigned int)tcp->th_ack);
        fprintf(fp,"seq number: %u ack number: %u \n", (unsigned int)tcp-> th_seq, (unsigned int)tcp->th_ack);

但是源地址和IP地址相同!!!它打印的源端口和目标端口不正确!这是什么问题?我该怎么办?请帮助我。

源端口和目标端口按网络字节顺序 (big-endian) 排列 使用ntohs以正确的字节顺序为您的计算机获取它们。 SEQ和ACK同样适用,对它们使用ntohl IP标头的大小可能并不总是20,将ip_hdr_len的值乘以4得到实际大小。

如果您的编译器支持位域,则可以将它们用于IP标头声明,以简化操作:

struct sniff_ip {
    u_char ip_hdr_len:4;
    u_char ip_ver:4;

固定代码:

while (pcap_next_ex(handler, &header, &packet) >= 0) {      
    ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);

    if (ip->ip_p == 6 /* tcp protocol number */) {
        tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + ip->ip_hdr_len * 4);

        u_short srcport = ntohs(tcp->th_sport);
        u_short dstport = ntohs(tcp->th_dport);
        printf("src port: %d dest port: %d \n", srcport, dstport);

        char srcname[100];
        strcpy(srcname, inet_ntoa(ip->ip_src));
        char dstname[100];
        strcpy(dstname, inet_ntoa(ip->ip_dst));
        printf("src address: %s dest address: %s \n", srcname, dstname);

        u_long seq = ntohl(tcp->th_seq);
        u_long ack = ntohl(tcp->th_ack);
        printf("seq number: %u ack number: %u \n", seq, ack);
    }       
}

请注意,除非您使用pcap_compilepcap_setfilter应用了过滤器,或者可以确保您正在读取的文件仅包含TCP数据包,否则并非每个数据包都将包含TCP数据。 因此,您可能希望将IP头协议字段的值检查为6 (TCP),如上面的代码所示。

还要注意,Wireshark默认情况下显示相对的SEQ和ACK编号,因此它们与您在此处看到的不匹配。

结构包装应该没问题。

如何打包结构取决于编译器。 例如,gcc使用#pragma pack() Google for pack pragma gccpack pragma visual c或您使用的任何编译器。

如果您两次将inet_ntoa的结果调用给printf,则需要保存结果,例如

char *srcname=strdup(inet_ntoa(ip->ip_src));
char *dstname=strdup(inet_ntoa(ip->ip_dst));
printf("src address: %s dest address: %s \n", srcname, dstname);
free(srcname);
free(dstname);

(请注意,您应该添加错误检查,函数结果指针可能为NULL)。

inet_ntoa()返回静态缓冲区中的点和数字字符串,该字符串在每次调用该函数时都会被覆盖。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM