好的,所以我尝试使用讲师提供的 Material 编写一个简单的ICMP跟踪路由,这些 Material 是我想合并以实现目标的echo_request和icmp_receive程序,但这种方法行不通。
您可以看到这些程序的代码以及我包含在我的代码>here<中的其他代码
请记住,我是套接字编程的初学者。我从今天开始,但我仍然不了解某些事情。
所以我的代码看起来像这样(它不是traceroute的最终版本!这只是我认为应该给出一些结果的一个片段):
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <netinet/ip_icmp.h>
#include "sockwrap.h"
#include "icmp.h"
#include <time.h>
unsigned char buffer[IP_MAXPACKET+1];
unsigned char* buffer_ptr;
int re;
int main(int argc, char **argv){
if(argc != 2){
printf("Usage: ./traceroute <ip>\n");
return 1;
}
int sockfd = Socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
struct sockaddr_in remote_address;
bzero (&remote_address, sizeof(remote_address));
remote_address.sin_family = AF_INET;
inet_pton(AF_INET, argv[1], &remote_address.sin_addr);
int ttl = 1;
while(1){
struct icmp icmp_packet;
icmp_packet.icmp_type = ICMP_ECHO;
icmp_packet.icmp_code = 0;
icmp_packet.icmp_id = 123;
icmp_packet.icmp_seq = ttl;
icmp_packet.icmp_cksum = 0;
icmp_packet.icmp_cksum = in_cksum((u_short*)&icmp_packet, 8, 0);
Setsockopt (sockfd, IPPROTO_IP, IP_TTL, &ttl, sizeof(int));
Sendto(sockfd, &icmp_packet, ICMP_HEADER_LEN, 0, &remote_address, sizeof(remote_address));
Sendto(sockfd, &icmp_packet, ICMP_HEADER_LEN, 0, &remote_address, sizeof(remote_address));
Sendto(sockfd, &icmp_packet, ICMP_HEADER_LEN, 0, &remote_address, sizeof(remote_address));
clock_t start = clock();
float seconds = 0;
while(seconds < 1){
clock_t c = clock();
seconds = (float)(c - start)/CLOCKS_PER_SEC;
}
struct sockaddr_in sender;
socklen_t sender_len = sizeof(sender);
buffer_ptr = buffer;
re = Recvfrom (sockfd, buffer_ptr, IP_MAXPACKET,
0, &sender, &sender_len);
char str[20];
inet_ntop(AF_INET, &(sender.sin_addr), str, sizeof(str));
// this printf shows me ip adresses of routers on route to
// destination(probably?), but anything below it doesn't seem to work
// properly :(
//printf ("%s\n", str);
struct icmp* icmp_packet_recv = (struct icmp*) buffer_ptr;
printf("%d %d\n", icmp_packet_recv->icmp_id, icmp_packet_recv->icmp_seq);
if (icmp_packet_recv->icmp_type == ICMP_TIME_EXCEEDED &&
icmp_packet_recv->icmp_code == ICMP_EXC_TTL) {
struct ip* packet_orig = (struct ip*) buffer_ptr;
if (packet_orig->ip_p == IPPROTO_ICMP) {
if(icmp_packet_recv->icmp_seq == ttl && icmp_packet_recv->icmp_id == 123)
printf ("%s\n", str);
}
}
if (icmp_packet_recv->icmp_type == ICMP_ECHOREPLY) {
printf ("%s\n", str);
return 0;
}
ttl++;
}
return 0;
}
之所以可以这样工作,是因为当我
printf("%s\n", str);
的str是发件人的ip时,它看起来像是在跟踪路由,但是当我要检查接收到的软件包时,它会确定与我发送的邮件不同的icmp_id
和icmp_seq
。这对我来说似乎很奇怪,因为当我运行echo_request
和icmp_receive
并发送一个包含id
123和seq
1的程序包时,我收到了完全相同的id
和seq
,但是在我的程序中它是不同的(我正在通过此printf("%d %d\n", icmp_packet_recv->icmp_id, icmp_packet_recv->icmp_seq);
检查的内容)。如果您能指出我在代码中正在做愚蠢的事情并加以解释,我将不胜感激。结果这项任务比我预期的要难。
最佳答案
调用re
之后,您需要检查Recvfrom
。可能会有错误,也可能是您期望的长度不同。
另外,正如我记得的那样,使用此RAW套接字,您将获得所有发送到您的网络接口(interface)的ICMP数据包;因此,您需要接收所有数据包,并且只能使用包含相同序列号的数据包。
而且我看不到bind()
。没必要吗?
关于c - C语言中简单的icmp traceroute实现,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29344543/