C - result of recvfrom unexpected
我有一个简单的代码来发送和接收像ping这样的ICMP数据包,一切正常:我的数据包被发送,我收到了一个结果。
我在recvfrom结果中遇到问题,我的缓冲区中的ip dest / src不是服务器dest ip。
结果
1 2 | $> ./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:
1 2 3 | $> 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:
1 2 3 4 5 6 7 8 9 10 | 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套接字:
1 2 | sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); setsockopt(sock, SOL_IP, IP_TTL, (void *)&val, sizeof(val); |
发送& 接收时间:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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); } |
最后我的显示功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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 ", ip->version, ip->ihl*4, ntohs(ip->tot_len), ip->protocol, ip->ttl, src, dest); |
在我看来,我的缓冲区包含有关最后一个数据包步骤(路由器 - >我的家)的信息,它解释了为什么TTL值为254以及为什么我发现与traceroute相同的IP:
$> traceroute qwant.com
traceroute to qwant.com (194.187.168.99), 30 hops max, 60 byte packets
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
为什么收到的信息与我的服务器目标无关? 我怎样才能收到这些信息?
方案:
我更改了我的
1 2 3 | getaddrinfo(stats.host, NULL, NULL, &addrinfo); sd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP); setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)); |
接下来我创建了2
1 2 | struct sockaddr_in send; struct sockaddr_in recv; |
现在初始化send结构以指定
1 2 3 4 | 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; |
最后我改变了我的数据包结构
1 2 3 4 5 | struct packet { struct icmphdr hdr; char msg[PACKETSIZE-sizeof(struct icmphdr)]; }; |
现在,只需调用
1 2 3 | 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); |
The Internet Assigned Numbers Authority (IANA) has reserved the
following three blocks of the IP address space for private networks:
1
2
3 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是专用网络中的地址。 我想你的机器在这个网络里面,还有服务器。
来自man getaddrinfo:
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully bind(2).
If socket(2) (or bind(2)) fails, we (close the socket
and) try the next address. */
1
2
3
4
5
6
7
8
9
10
11 for (rp = result; rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sfd == -1)
continue;
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
break; /* Success */
close(sfd);
}