手写用户态网络协议栈(udp)

手写用户态网络协议栈(udp)

分析

  1. 协议栈的数据如何封装
  2. 如何抓取网络原始数据

获取网卡原始数据

使用netmap工具

  1. raw socket
  2. pf_ring
  3. netmap
  4. dpdk

netmap安装

安装记录在我的另外一篇博客https://www.cnblogs.com/hunxiaoheibai/p/15802983.html

code

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/poll.h>
#include <arpa/inet.h>

#define NETMAP_WITH_LIBS //避免netmap和系统api冲突,用来区分
#include <net/netmap_user.h>

#pragma pack(1) //设置一个字节对齐

#define PROTO_IP 0x800 //ip标志
#define PROTO_UDP 17 //udp标志

#define ETH_LENGTH 6
//以太网协议头
struct ethhdr
{
    //目的地址
    unsigned char dst[ETH_LENGTH];
    //源地址
    unsigned char src[ETH_LENGTH];
    //类型
    unsigned short proto;
};
// ip协议封装
struct iphdr
{
    unsigned char version : 4; //版本
    unsigned char height : 4;  //首部长度。占用半个字节,两个一起占用一个字节
    unsigned char tos;         //服务类型
    unsigned short length;

    unsigned short id;          //标志
    unsigned short flag_offset; //偏移

    unsigned char ttl;          //生存时间
    unsigned char proto;        //协议
    unsigned short check;       //检验

    unsigned int sip;           //源ip
    unsigned int dip;           //目的ip
};
// udp协议封装
struct udphdr
{
    unsigned short sport; //源端口
    unsigned short dport; //目的端口
    unsigned short length;
    unsigned short check;
};

struct udppkt
{
    //转化为内存块,不适用指针
    struct ethhdr eh;      //14字节
    struct iphdr ip;       //20字节
    struct udphdr udp;     //8字节
    unsigned char data[0]; //零长数组,0字节
};
int main()
{
    struct nm_desc *nmr = nm_open("netmap:enp0s3", NULL, 0, NULL);
    if (nmr == NULL)
    {
        return 0;
    }

    struct pollfd pfd = {0};
    pfd.fd = nmr->fd; //操作标识网卡信息,区分多个网卡信息
    pfd.events = POLLIN;

    struct nm_pkthdr h;

    while (1)
    {
        int ret = poll(&pfd, 1, -1);

        if (ret < 0)
            continue;

        if (pfd.revents & POLLIN)
        {
            unsigned char *stream = nm_nextpkt(nmr, &h);
            struct ethhdr *eh = (struct ethhdr *)stream;
            // 可能有arp协议,加一层ip判断
            if (ntohs(eh->proto) == PROTO_IP)
            {
                struct udppkt *udp = (struct udppkt *)stream;
                if (udp->ip.proto == PROTO_UDP)
                {
                    int udp_length = ntohs(udp->udp.length);
                    udp->data[udp_length - 8] = '\0';
                    printf("udp->%s\n", udp->data);
                }
            }
        }
    }
}

测试

手写用户态网络协议栈(udp)

测试显示发送成功

参考

https://www.bilibili.com/video/BV113411v738

上一篇:【XJOI】生与死的境界【codeforces 878 E】numbers on the blackboard(贪心)


下一篇:机器人单关节力矩控制(前馈+反馈)