我有一个简单的代码来发送和接收ICMP数据包,就像ping一样,一切正常:我的数据包被发送,我收到了一个结果。在recvfrom结果中,我遇到了一个问题,我的缓冲区中的ip dest/src不是服务器的dest ip。
结果
$> ./my_ping qwant.com
IPv4: hdr-size=20 pkt-size=56 protocol=1 TTL=254 src=10.0.2.2 dest=172.17.0.2但对于真正的平:
$> ping qwant.com
PING qwant.com (194.187.168.99): 48 data bytes
56 bytes from 194.187.168.99: icmp_seq=0 ttl=61 time=101.742 ms它不是相同的TTL和ip
代码
Init struct addrinfo:
struct addrinfo hints;
struct addrinfo *a_info;
bzero(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = 0;
hints.ai_flags = AI_ADDRCONFIG;
getaddrinfo(host, NULL, &hints, &a_info)Init插座:
sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
setsockopt(sock, SOL_IP, IP_TTL, (void *)&val, sizeof(val);发送和接收时间:
size_t i;
t_ping pack;
int count = 1;
struct iphdr buff;
while (TRUE)
{
bzero(&pack, sizeof(pack));
pack.head.type = 8;
pack.head.code = getpid();
pack.id = count++;
while (i < 15)
{
pack.seq[i] = i + '0';
i++;
}
pack.seq[i] = 0;
pack.head.chk = checksum(&pack, sizeof(pack));
ft_bzero((void *)&buff, sizeof(buff));
if (sendto(sock, &pack, sizeof(pack), 0, a_info->ai_addr, a_info->ai_addrlen) < 0)
perror("sendto");
if (recvfrom(sock, (void *)&buff, sizeof(buff), 0, a_info->ai_addr, &a_info->ai_addrlen) < 0)
perror("recvfrom");
display((void *)&buff);
sleep(1);
}最后,我的展示功能:
struct iphdr *ip = buff;
char src[INET6_ADDRSTRLEN];
char dest[INET6_ADDRSTRLEN];
inet_ntop( AF_INET, (void *)&ip->saddr, src, sizeof(src) );
inet_ntop( AF_INET, (void *)&ip->daddr, dest, sizeof(dest) );
printf("IPv%d: hdr-size=%d pkt-size=%d protocol=%d TTL=%d src=%s dest=%s\n",
ip->version,
ip->ihl*4,
ntohs(ip->tot_len),
ip->protocol,
ip->ttl,
src,
dest);在我看来,我的缓冲区包含有关最后一个数据包步骤(路由器->我的家)的信息,这些信息解释了为什么TTL值为254,以及为什么我在traceroute中找到了相同的IP:
$> traceroute qwant.com traceroute到qwant.com (194.187.168.99),最多30跳,60个字节数据包 172.17.0.1 (172.17.0.1) 0.026 ms 0.011 ms 0.010 ms 10.0.2.2 (10.0.2.2) 0.149 ms 0.160 ms 0.156 ms ..。 194.187.168.99 (194.187.168.99) 147.634 ms 147.506 ms 147.540 ms
为什么收到的信息不是关于我的服务器目标?我怎样才能收到这些信息?
发布于 2015-12-01 14:49:31
解决办法:
我更改了getaddrinfo调用和套接字init:
getaddrinfo(stats.host, NULL, NULL, &addrinfo);
sd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val));接下来,我创建了2个struct sockaddr_in:一个用于sendto,另一个用于recvfrom。
struct sockaddr_in send;
struct sockaddr_in recv;现在,在发送结构中指定sendto的目的地,但不更改recv :它是在第一次recvfrom调用期间自动分配的。
bzero(&send, sizeof(send));
send.sin_family = addrinfo->ai_family;
send.sin_port = 0;
send.sin_addr.s_addr = ((struct sockaddr_in *)addrinfo->ai_addr)->sin_addr.s_addr;最后,我改变了我的包结构
struct packet
{
struct icmphdr hdr;
char msg[PACKETSIZE-sizeof(struct icmphdr)];
};现在,只需这样调用sendto和recvfrom:
socklen_t len = sizeof(recv);
sendto(sd, &pckt, sizeof(pckt), 0, (struct sockaddr*)&send, sizeof(send));
recvfrom(sd, &pckt, sizeof(pckt), 0, (struct sockaddr*)&recv, &len);发布于 2015-11-30 16:22:46
因特网分配数字管理局(IANA)为专用网络预留了以下三块IP地址空间: 10.0.0.0 - 10.255.255.255 172.16.0.0 - 172.31.255.255 192.168.0.0 - 192.168.255.255
172.17.0.2是专用网络的地址。我想你的机器就在这个网络里,还有服务器。
getaddrinfo()可以返回多个地址。试着查看所有的回复,并检查你是否也得到了互联网地址。
来自人类获取信息
/* getaddrinfo()返回一个地址结构列表。尝试每个地址,直到我们成功绑定(2)。如果套接字(2)(或绑定(2))失败,我们(关闭套接字并)尝试下一个地址。*/ 对于(rp ===;rp != NULL;rp = rp->ai_next) { sfd =套接字(rp->ai_族,rp->ai_socktype,rp->ai_protocol);if (sfd -1)继续;if (sfd,rp->ai_addr,rp->ai_addrlen) == 0;/* Success */ close(sfd);}
https://stackoverflow.com/questions/34002113
复制相似问题