【问题标题】:Getting wrong ip and port number from libpcap captured packet从 libpcap 捕获的数据包中获取错误的 ip 和端口号
【发布时间】:2012-11-23 03:00:40
【问题描述】:

我的 Ubuntu 虚拟机的 IP 地址是 192.168.1.110。其他一切看起来都很好。我不知道代码有什么问题。也许我使用了错误的包头结构? 下面是我的代码和输出。同样,我的主机 IP 应该是 192.168.1.110 并且端口现在肯定是错误的。

sudo ./sniffall 0
84.72.137.105:38055  192.168.1.105:56652
192.168.1.105:56652  174.141.213.124:28073
84.72.137.105:38055  192.168.1.105:56652
192.168.1.105:56652  174.141.213.124:28073
84.72.137.105:38055  192.168.1.105:56652


#include <pcap.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/if_ether.h>
#include <netinet/ether.h>
#include <sys/socket.h>
#include <netinet/tcp.h>

void getPacket(u_char *args, const struct pcap_pkthdr *pkthdr, const u_char *packet){
    struct ip *ip;
    struct tcphdr *tcp;
    ip = (struct ip*)(packet+sizeof(struct ether_header));
    tcp = (struct tcphdr*)(packet+sizeof(struct ether_header)+sizeof(struct ip));

    char* src = inet_ntoa(ip->ip_src);

    printf("%s:%d ",src,tcp->source);
    char* dst = inet_ntoa(ip->ip_dst);
    printf(" %s:%d\n", dst, tcp->dest);

}

int main(int argc, char *argv[]){
    char errbuf[PCAP_ERRBUF_SIZE], *device;
    device = argv[1];
    pcap_t *handle;
    handle = pcap_open_live(device, BUFSIZ, 1, 1000, errbuf);
    if(!handle){
        device = pcap_lookupdev(errbuf);
        handle = pcap_open_live(device, BUFSIZ, 1, 1000, errbuf);
        if(!handle){
                printf("Couldn't open device %s: %s\n", device, errbuf);
        }
    }

    pcap_loop(handle, 5, getPacket, NULL);
    return 0;
}

【问题讨论】:

  • 您正在以混杂模式打开 pcap 句柄。也许您正在看到其他流量?
  • 这看起来不像你的程序的输出。它没有打印: 后跟端口号。您还应该使用ntohs 将端口号从网络转换为主机字节顺序。
  • 你有一大块代码被注释掉了。如果不需要,这只是试图帮助回答您问题的人的噪音 :-) 只是一个友好的说明!
  • 感谢您的建议...我更新了我的输出,我保留评论区基本上是因为我不确定哪个可以工作....但是谢谢,我会删除它。
  • 好的,我现在做一些改变,首先我将混杂模式改为false,然后我添加了ntohs来转换端口号,但输出仍然没有意义。

标签: c libpcap


【解决方案1】:

如果您处于混杂模式,Pcap 会显示系统以外的其他流量。为什么您会看到未从您的系统发送或接收的特定数据包将取决于您的网络配置。如果某些以太网交换机不确定它们应该去哪里等,它们偶尔会泄漏发往其他系统的数据包。

您还需要在字节顺序之间进行转换。在现在最常见的情况下,“网络字节顺序”与您机器的字节顺序不同。要打印出端口号,您需要执行以下操作:

printf("%s:%d ",src,ntohs(tcp->source));

另外,您可能想尝试struct iphdr 而不是struct ip。我以前见过这样的例子,在标题中有多个名为 ip 的结构定义,但 iphdr 总是适合我。

请记住,您始终可以在另一个窗口中运行 tcpdump 以查看实际进入的数据包,您收到的流量可能比您预期的要多。

【讨论】:

    【解决方案2】:

    首先,在调用pcap_open_live() 之后,在handle 上调用pcap_datalink(),如果它没有返回DLT_EN10MB,则退出或重写你的程序,以便它可以处理它返回的值。请参阅 the tcpdump.org link-layer header types page,了解来自 pcap_datalink() 的受支持值的说明。

    其次,请假定数据包是 IPv4 数据包,除非您安装了 "ip" 过滤器或检查了数据包类型(例如,以太网标头中的类型字段)以确保数据包是 IPv4 数据包。

    第三,NOT 假设 IPv4 数据包的标头正好是 sizeof(struct ip) 字节长。我假设sizeof(struct ip) 将是 20,这是 IPv4 标头的 最小 长度,但标头可能包含选项 - 检查 IPv4 标头的“标头长度”字段(以4 字节字,因此值 5 表示“20 字节”)并将其用作标头的长度(确保它至少为 5 - 如果小于 5,则数据包无效 - 然后乘以 4获取标题的长度)。

    第四,NOT 假设数据包是 TCP 数据包,除非您安装了 "ip and tcp" 或只是 "tcp" 的过滤器(对于后者,您仍然需要检查自己查看它是否是 IPv4 数据包)或检查 IPv4 标头的“协议”字段以确保其值为 6(对于 TCP)。

    【讨论】:

      猜你喜欢
      • 2012-02-18
      • 1970-01-01
      • 2017-07-28
      • 1970-01-01
      • 2020-01-28
      • 2014-03-12
      • 2015-10-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多