首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在SOCK_RAW通信中创建以太网帧

在SOCK_RAW通信中创建以太网帧
EN

Stack Overflow用户
提问于 2014-03-03 14:35:09
回答 1查看 3.1K关注 0票数 2

我做了一个简单的IP frame ping程序,因为我创建了一个缓冲区,其中只有我填充了icmp stucture,当我运行该程序时,它工作正常。

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

另一个问题是,我的朋友尝试了同样的代码,但是当他在00.00.00.00.00.00以太网报头中签入Wireshark时,MAC地址是,这意味着它将发送到每个设备,相应的设备具有正确的IP将作出答复,但对我来说并非如此。

密码就在这里

代码语言:javascript
复制
#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;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-03-03 15:07:36

区别在于您如何声明套接字。

使用IPPROTO_RAW -以太网报头为您提供,您提供一切从IP报头开始。

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

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

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

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

在这里阅读更多关于IP_HDRINCL的信息:http://man7.org/linux/man-pages/man7/raw.7.html

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22149452

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档