我正在尝试使用C++中的RAW套接字捕获所有ICMP“目标不可达-端口不可达”消息。然后处理基础的UDP协议(protocol),以找出目标无法到达的端口。到目前为止,我设法接收了ICMP消息并根据它们的类型和代码对其进行过滤。但是,我很难访问udp header 。到目前为止,我尝试了这些:
*(struct udphdr*)(icmp + sizeof(struct icmphdr) + sizeof(struct iphdr))
和
struct iphdr *ip = (struct iphdr*)ether_frame;
struct icmphdr *icmp = (struct icmphdr*)(ether_frame + ip->ihl*4);
struct iphdr *ip2 = (struct iphdr*)(icmp + sizeof(struct icmphdr))
struct udphdr *udphdr = (struct udphdr*)(ip2 + ip2->ihl*4)
但是没有人工作。我敢肯定这只是一些简单的指针算术错误,但我无法弄清楚。所以我的问题是:ICMP响应中的协议(protocol)是如何组织的?如何访问原始icmp响应无法访问的端口号?
编辑:用于接收的套接字是使用
this->rcv_sd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP
创建的,并且响应是使用recv(this->rcv_sd, ether_frame, IP_MAXPACKET, 0)
接收的,其中ether_frame
是大小为uint8_t
的IP_MAXPACKET
数组。 最佳答案
您正在使用pointer arithmetic,将字节数按原样添加到结构指针中,因此(icmp + sizeof(struct icmphdr))
和(ip2 + ip2->ihl*4)
之类的语句未按您认为的方式运行,从而导致您以错误的地址结尾。
当您向类型化的指针添加数字时,该指针将通过基础类型的字节数乘以指定的数字来进行调整。
所以这:
struct iphdr *ip2 = (struct iphdr*)(icmp + sizeof(struct icmphdr))
等效于此:
struct iphdr *ip2 = (struct iphdr*)(((uint8_t*)icmp) + (sizeof(*icmp) * sizeof(struct icmphdr)))
还有这个:
struct udphdr *udphdr = (struct udphdr*)(ip2 + ip2->ihl*4)
等效于此:
struct udphdr *udphdr = (struct udphdr*)(((uint8_t*)ip2) + (sizeof(*ip2) * (ip2->ihl*4)))
由于要用字节而不是元素偏移结构指针,因此需要在将字节计数添加到字节指针之前将结构指针类型转换为字节指针:
struct iphdr *ip2 = (struct iphdr*)(((uint8_t*)icmp) + sizeof(struct icmphdr))
// or simpler, using correct pointer arithmetic:
// struct iphdr *ip2 = (struct iphdr*)(icmp + 1)
struct udphdr *udphdr = (struct udphdr*)(((uint8_t*)ip2) + (ip2->ihl*4))
从
ip
缓冲区分配icmp
和ether_frame
指针时,您不会遇到此问题,因为ether_frame
是uint8_t
数组,它按原样衰减到uint8_t*
指针。关于c++ - 从ICMP消息访问UDP,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47042355/