gpt4 book ai didi

c - 关于 c : 中 traceroute 的一些相关问题

转载 作者:太空宇宙 更新时间:2023-11-03 23:24:27 25 4
gpt4 key购买 nike

根据 Wikipedia , 一个跟踪程序

Traceroute, by default, sends a sequence of User Datagram Protocol (UDP) packets addressed to a destination host[...] The time-to-live (TTL) value, also known as hop limit, is used in determining the intermediate routers being traversed towards the destination. Routers decrement packets' TTL value by 1 when routing and discard packets whose TTL value has reached zero, returning the ICMP error message ICMP Time Exceeded.[..]

我开始编写程序(使用示例 UDP 程序作为指南)来遵守此规范,

#include <sys/socket.h>
#include <assert.h>
#include <netinet/udp.h> //Provides declarations for udp header
#include <netinet/ip.h> //Provides declarations for ip header
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>

#define DATAGRAM_LEN sizeof(struct iphdr) + sizeof(struct iphdr)

unsigned short csum(unsigned short *ptr,int nbytes) {
register long sum;
unsigned short oddbyte;
register short answer;

sum=0;
while(nbytes>1) {
sum+=*ptr++;
nbytes-=2;
}
if(nbytes==1) {
oddbyte=0;
*((u_char*)&oddbyte)=*(u_char*)ptr;
sum+=oddbyte;
}

sum = (sum>>16)+(sum & 0xffff);
sum = sum + (sum>>16);
answer=(short)~sum;

return(answer);
}

char *new_packet(int ttl, struct sockaddr_in sin) {
static int id = 0;
char *datagram = malloc(DATAGRAM_LEN);
struct iphdr *iph = (struct iphdr*) datagram;
struct udphdr *udph = (struct udphdr*)(datagram + sizeof (struct iphdr));

iph->ihl = 5;
iph->version = 4;
iph->tos = 0;
iph->tot_len = DATAGRAM_LEN;
iph->id = htonl(++id); //Id of this packet
iph->frag_off = 0;
iph->ttl = ttl;
iph->protocol = IPPROTO_UDP;
iph->saddr = inet_addr("127.0.0.1");//Spoof the source ip address
iph->daddr = sin.sin_addr.s_addr;
iph->check = csum((unsigned short*)datagram, iph->tot_len);

udph->source = htons(6666);
udph->dest = htons(8622);
udph->len = htons(8); //udp header size
udph->check = csum((unsigned short*)datagram, DATAGRAM_LEN);

return datagram;
}

int main(int argc, char **argv) {
int s, ttl, repeat;
struct sockaddr_in sin;
char *data;

printf("\n");

if (argc != 3) {
printf("usage: %s <host> <port>", argv[0]);
return __LINE__;
}

sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr(argv[1]);
sin.sin_port = htons(atoi(argv[2]));

if ((s = socket(AF_PACKET, SOCK_RAW, 0)) < 0) {
printf("Failed to create socket.\n");
return __LINE__;
}

ttl = 1, repeat = 0;
while (ttl < 2) {
data = new_packet(ttl);
if (write(s, data, DATAGRAM_LEN) != DATAGRAM_LEN) {
printf("Socket failed to send packet.\n");
return __LINE__;
}
read(s, data, DATAGRAM_LEN);
free(data);
if (++repeat > 2) {
repeat = 0;
ttl++;
}
}
return 0;
}

...不过此时我有几个问题。

  • read(s, data, ... 一次读取整个数据包,还是我需要解析从套接字读取的数据;寻找特定于 IP 数据包的标记?
  • 当我的包裹返回我的盒子时,最好的唯一标记方式是什么?
  • 我应该使用 IPPROTO_ICMP 标志设置第二个套接字,还是编写一个过滤器更容易;接受一切?
  • 是否存在任何其他常见错误;还是可以预见任何共同的障碍?

最佳答案

以下是我的一些建议(基于假设它是一台 Linux 机器)。

  1. 读取数据包您可能想要读取整个 1500 字节的数据包(整个以太网帧)。别担心 - 较小的帧仍然可以通过 read 返回读取数据的长度来完全读取。

  2. 添加标记的最佳方法是使用一些 UDP 负载(一个简单的无符号整数)就足够了。在发送的每个数据包上增加它。 (我刚刚在 traceroute 上做了一个 tcpdump - ICMP 错误 - 确实返回了整个 IP 帧 - 所以你可以查看返回的 IP 帧,解析 UDP 有效负载等等。注意你的 DATAGRAM_LEN 会相应地改变。)当然你可以使用ID - 但要注意ID主要用于分片。你应该没问题 - 因为你不会接近具有这些数据包大小的任何中间路由器的碎片限制。一般来说,为了我们的自定义目的而“窃取”协议(protocol)字段并不是一个好主意。

  3. 更简洁的方法可能是在原始套接字上实际使用 IPPROTO_ICMP(如果您的机器上安装了手册 man 7 rawman 7 icmp)。您不希望在您的设备上接收所有 数据包的副本并忽略那些不是 ICMP 的数据包。

  4. 如果您在 AF_PACKET 上使用 SOCKET_RAW 类型,您将必须手动附加一个链路层 header ,或者您可以执行 SOCKET_DGRAM 并检查。还有 man 7 packet 很多细节。

希望对您有所帮助,或者您正在查看一些实际代码?

关于c - 关于 c : 中 traceroute 的一些相关问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30541234/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com