在SOCK_RAW通信中创build以太网帧

我做了一个简单的ping程序,我创build了一个缓冲区 ,只填充IP frameicmp stucture ,当我运行程序时它正常工作。

我已经看了Wireshark的执行情况,以太网帧已经正确地包含在正确的目标MAC地址回显请求 (MAC可能会在ARPcaching中find),但即使我没有填写,以太网帧已经自动创build我在sock_raw套接字通信中使用的缓冲区。

另一个问题是我的朋友尝试了相同的代码,但是当他在以太网头中的Wireshark中检查MAC地址是00.00.00.00.00.00 ,这意味着它将发送到每个设备,具有正确IP的相应设备将回复,但对我来说并不是这样

代码在这里

 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <netdb.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/ip_icmp.h> #include <string.h> #include <arpa/inet.h> #include <sys/socket.h> #define BUFFER_SIZE 100 #define DEFAULT_NUM_PACKETS 10 char buf[BUFFER_SIZE]; char *message = "\n ./output_file <sender_ip_addr> <dest_ip_addr> <no_of_reqs>\n \ <no_of_req> = is the number of requests to send and 10 is the default and mentioning 0 is infinite\n"; void set_ip_layer_fields(struct icmphdr *icmp, struct ip *ip) { // IP layer ip->ip_v = 4; ip->ip_hl = sizeof*ip >> 2; ip->ip_tos = 0; ip->ip_len = htons(sizeof(buf)); ip->ip_id = 0; ip->ip_off = 0; ip->ip_ttl = 255; ip->ip_p = 1; ip->ip_sum = 0; // ICMP Layer icmp->type = 8; icmp->code = 0; icmp->checksum = htons(~(ICMP_ECHO << 8)); } int main(int argc, char *argv[]) { int s, i ; struct ip *ip = (struct ip *)buf; struct icmphdr *icmp = (struct icmphdr *)(ip + 1); struct hostent *hp, *hp2; struct sockaddr_in dst; int num = DEFAULT_NUM_PACKETS; if(argc < 3) { fprintf(stdout, "%s\n",message); exit(1); } // If enough arguments supplied if(argc == 4) num = atoi(argv[3]); // Loop based on the no of requests for(i = 1; num == 0 ? num == 0 : i <= num; i++) { memset(buf, 0, sizeof(buf)); if((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { perror("socket() error"); exit(1); } if((hp = gethostbyname(argv[2])) == NULL) { if((ip->ip_dst.s_addr = inet_addr(argv[2])) == -1) { fprintf(stderr, "%s: unknown host.\n", argv[2]); exit(1); } } else memcpy(&ip->ip_dst.s_addr, hp->h_addr_list[0], hp->h_length); if((hp2 = gethostbyname(argv[1])) == NULL) { if((ip->ip_src.s_addr = inet_addr(argv[1])) == -1) { fprintf(stderr, "%s: unknown host\n", argv[1]); exit(1); } } else memcpy(&ip->ip_src.s_addr, hp2->h_addr_list[0], hp->h_length); set_ip_layer_fields(icmp, ip); dst.sin_addr = ip->ip_dst; dst.sin_family = AF_INET; if(sendto(s, buf, sizeof(buf), 0, (struct sockaddr *)&dst, sizeof(dst)) < 0) { fprintf(stderr, "error while sending\n"); } else printf("request:%d sended successfully\n",i); close(s); } return 0; } 

不同的是你如何声明你的套接字。

使用IPPROTO_RAW – 为您提供以太网报头,并提供IP报头之后的所有内容。

使用htons(ETH_P_ALL) – 您提供了一切,包括以太网报头。

更多信息在这里: http : //www.pdbuchan.com/rawsock/rawsock.html

同样使用IPPROTO_RAW意味着选项IP_HDRINCL是隐式设置的,这意味着从包中的IP头使用IP,而不是放在sendto中的信息。

通常,如果你在一个原始套接字中指定了所有的东西,你可以使用send而不是sendto因为send的所有信息在标题中都是可用的。

在这里阅读更多关于IP_HDRINCL : http : IP_HDRINCL