gpt4 book ai didi

c++ - 在 SOCK_RAW 通信中创建以太网帧

转载 作者:太空狗 更新时间:2023-10-29 12:16:43 24 4
gpt4 key购买 nike

我做了一个简单的 ping 程序,因为我创建了一个 buffer 并且只有我填充了 IP frameicmp 结构,当我运行该程序时它工作正常。

我查看了 Wireshark 中的执行情况,以太网帧已正确包含在具有正确目标 MAC 地址回显请求中( MAC 可能会在 arp 缓存中找到),但是即使我没有将其填充到我在 sock_raw 套接字通信中使用的缓冲区中,以太网帧也会自动创建。

另一个问题是我的 friend 尝试了相同的代码,但是当他在 ethernet header 中检查 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 - 为您提供以太网 header ,您提供从 IP header 开始的所有内容。

使用 htons(ETH_P_ALL) - 您提供所有内容,包括以太网 header 。

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

同时使用 IPPROTO_RAW 意味着选项 IP_HDRINCL 是隐式设置的,这意味着 IP 是从数据包中的 IP header 使用的,而不是放在 中的信息>发送到

通常,如果您在原始套接字中指定所有内容,您会使用 send 而不是 sendto,因为所有要发送的信息都在 header 中可用。

在此处阅读有关 IP_HDRINCL 的更多信息:http://man7.org/linux/man-pages/man7/raw.7.html

关于c++ - 在 SOCK_RAW 通信中创建以太网帧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22149452/

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