[英]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_compile
和pcap_setfilter
应用了过滤器,或者可以确保您正在读取的文件仅包含TCP数据包,否则并非每个数据包都将包含TCP数据。 因此,您可能希望将IP头协议字段的值检查为6
(TCP),如上面的代码所示。
还要注意,Wireshark默认情况下显示相对的SEQ和ACK编号,因此它们与您在此处看到的不匹配。
结构包装应该没问题。
如何打包结构取决于编译器。 例如,gcc使用#pragma pack()
。 Google for pack pragma gcc
或pack 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.