C/C++详解实现二层转发

 更新时间:2022年05月24日 08:37:07   作者:程序猿编码  
数据链路层是开放系统互连 (OSI) 模型中的第二层,该层用于通过 LAN 等单一网络进行通信的节点,第二层数据包不能从一个网络传输到另一个网络。而二层转发是根据报文的目的MAC直接进行转发,转发过程中不用对报文的头部做任何的修改

OSI第2层

前两个字段分别是目的地址和源地址字段。第3个字段是2字节的类型字段,用来标识上一层是什么协议。

数据链路层有两个子层:逻辑链路控制 (LLC) 子层和媒体访问控制 (MAC) 子层。

媒体访问控制 (MAC):MAC 子层处理硬件标识号的分配,称为 MAC 地址,它唯一地标识网络上的每个设备。 任何两个设备都不应具有相同的 MAC 地址。 MAC 地址是在制造时分配的。 大多数网络都会自动识别它。 MAC 地址位于网卡 上。

交换机跟踪网络上的所有 MAC 地址。

逻辑链路控制 (LLC):LLC 子层处理成帧寻址和流量控制。 速度取决于节点之间的链接,例如以太网或 Wifi。

第 2 层上的数据单元是一个帧。每个帧都包含一个帧头、正文和一个帧尾:

Header:通常包括源节点和目标节点的 MAC 地址。

Body:由正在传输的位组成。

Trailer:包括错误检测信息。 当检测到错误时,根据网络或协议的实现或配置,帧可能会被丢弃,或者可能会将错误报告给更高层以进行进一步的纠错。

error detection mechanisms::循环冗余校验 (CRC) 和帧校验序列 (FCS)。

通常有一个最大帧大小限制,称为最大传输单元,MTU。 巨型帧超过标准 MTU.

通过ARP解析出目标 MAC 地址?

传统交换在 OSI 模型的第 2 层运行,其中数据包根据目标 MAC 地址发送到特定的交换机端口。第 2 层网段中的设备不需要路由即可到达本地对等点。 然而,需要的是可以通过地址解析协议 (ARP) 解析的目标 MAC 地址,如下所示:

在这里,PC A 想要将流量发送到 IP 地址为 192.168.1.6 的 PC B。 然而,它不知道唯一的 MAC 地址,直到它通过 ARP 发现它,该 ARP 在整个第 2 层网段中广播。

然后将数据包发送到适当的目标 MAC 地址,交换机将根据其 MAC 地址表将正确的端口转发出去。

什么是MAC地址表

MAC地址表是在交换机中记录局域网主机和对应接口关系的表,交换机就是根据这张表负责将数据帧传输到指定的主机上的。

MAC地址表可以动态的学习数据帧中的原MAC地址。在MAC地址表中,交换机的一个接口可以对应多个MAC地址。一个MAC地址只能对应在一个接口上。下面是MAC地址表形成的具体过程,如下:

二层转发C/C++代码实现

cethping:

void ethping(char *destination, char* interface){
    //创建原始套接字。 指定接口名称
    struct RawSocket* rawsocket = new_RawSocket(interface);
    //数据包数据缓冲区
    unsigned char buf[1024];
    //定义数据包。 投射以匹配以太网帧的格式
    struct ethhdr_frame* eth_packet = (struct ethhdr_frame*)buf;
    //存储发送方和接收方的 MAC 地址。 协议类型是可选的,并且指定了 0x0806。
    //根据指定的接口名称获取发送者的MAC地址
    memset(buf, 0x0, sizeof(eth_packet));
    set_macaddr_from_string(destination, eth_packet->h_dest);
    set_macaddr_from_ifname(interface, eth_packet->h_source);
	eth_packet->h_proto = 0x0806;
    //在payload中设置字符串“Hello”
    char* data = "Hello";
    memcpy(eth_packet->payload, data, sizeof(data)); 
    //绑定指定接口上的socket
    rawsocket->bind_rawsocket(rawsocket);
    int send_size = send(rawsocket->socket, &buf, sizeof(buf), 0);
    printf("%dbyte send.\n", send_size);
    //关闭原始套接字
    rawsocket->close_rawsocket(rawsocket);
}
int main(int argc, char *argv[]){
    if(argc != 3){
        printf("usage: %s <destination> <interface>", argv[0]);
        exit(0);
    }
    char *destination = argv[1];
    char *if_name = argv[2];
    ethping(destination, if_name);
    return 0;
}

cethpingd:

void start_daemon(char *interface){
    //创建原始套接字(指定接收器接口名称)
    struct RawSocket* rawsocket = new_RawSocket(interface);
    int len;
    //使用 bind 绑定到接口
    rawsocket->bind_rawsocket(rawsocket);
    while(1){
        int len = rawsocket->recv_rawsocket(rawsocket);
        struct ethhdr_frame *data = (struct ethhdr_frame*)(rawsocket->buf);
        fflush(stdout);
        //显示接收到的数据包的内容
        if(len > 0){
            printf("src: ");
            print_macaddr(data->h_source);
            printf(", ");
            printf("dst: ");
            print_macaddr(data->h_dest);
            printf(", ");
            printf("type: ");
            printf("%02x", (uint16_t)data->h_proto);
            printf(", ");
            printf("payload: ");
            printf("%s", data->payload);
            printf("\n");
        }
    }
}
int main(int argc, char *argv[]){
    if(argc != 2){
        printf("usage: %s <interface>", argv[0]);
        exit(0);
    }
    char *if_name = argv[1];
    start_daemon(if_name);
    return 0;
}

编译:

增加两个虚拟网卡:

运行:

总结

转发是将连接到网络交换机一个端口的设备的网络流量传递到连接到交换机上另一个端口的另一个设备的过程。

当第 2 层以太网帧到达网络交换机上的端口时,交换机会读取以太网帧的源 MAC 地址作为学习功能的一部分,它还会读取目标 MAC 地址作为转发功能的一部分。目标 MAC 地址对于确定连接目标设备的端口号很重要。如果在 MAC 地址表中找到目的 MAC 地址,则交换机通过 MAC 地址对应的端口转发以太网帧。

参考:

《TCP IP详解卷一》

到此这篇关于C/C++详解实现二层转发的文章就介绍到这了,更多相关C语言二层转发内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++深入讲解对象的销毁之析构函数

    C++深入讲解对象的销毁之析构函数

    构造函数在创建对象时被系统自动调用,而析构函数(Destructor)在对象被撤销时被自动调用,相比构造函数,析构函数要简单的多
    2022-04-04
  • C语言回溯法 实现组合数 从N个数中选择M个数

    C语言回溯法 实现组合数 从N个数中选择M个数

    在平时的算法的题目中,时常会遇到组合数相关的问题,暴力枚举。在N个数中挑选M个数出来。利用for循环也可以处理,但是可拓展性不强,于是写这个模板供以后参考
    2018-08-08
  • C语言数据结构之图的遍历实例详解

    C语言数据结构之图的遍历实例详解

    这篇文章主要介绍了C语言数据结构之图的遍历实例详解的相关资料,需要的朋友可以参考下
    2017-07-07
  • C语言 const修饰普通变量和指针的操作代码

    C语言 const修饰普通变量和指针的操作代码

    这篇文章主要介绍了C语言const修饰普通变量和指针,用const修饰普通变量时,是在语法层面限制了变量的修改,但是本质上,变量还是变量,是一种不能被修改的变量,本文通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-08-08
  • C、C++线性表基本操作的详细介绍

    C、C++线性表基本操作的详细介绍

    这篇文章主要给大家介绍了关于C、C++线性表基本操作的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • 用C语言实现排雷游戏

    用C语言实现排雷游戏

    大家好,本篇文章主要讲的是用C语言实现排雷游戏,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • C++中顺序表操作的示例代码

    C++中顺序表操作的示例代码

    这篇文章主要为大家详细介绍了C++中顺序表的基础操作的相关代码,主要有顺序表的输出、插入和删除数据等,感兴趣的小伙伴可以了解一下
    2022-10-10
  • C语言实现简单的三子棋小游戏

    C语言实现简单的三子棋小游戏

    这篇文章主要为大家详细介绍了C语言实现简单的三子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-03-03
  • c++关键字const的用法详解

    c++关键字const的用法详解

    在类中,如果你不希望某些数据被修改,可以使用const关键字加以限定。const 可以用来修饰成员变量、成员函数以及对象,希望能够给你带来帮助
    2021-09-09
  • C语言数据结构超详细讲解单向链表

    C语言数据结构超详细讲解单向链表

    链表可以说是一种最为基础的数据结构了,而单向链表更是基础中的基础。链表是由一组元素以特定的顺序组合或链接在一起的,不同元素之间在逻辑上相邻,但是在物理上并不一定相邻。在维护一组数据集合时,就可以使用链表,这一点和数组很相似
    2022-03-03

最新评论