arp、ethernet、icmp、udp、ip协议的C语言实现(计算机网络协议栈实验)

简介: arp、ethernet、icmp、udp、ip协议的C语言实现(计算机网络协议栈实验)

41996206f6b142e4b8aef8de5365c09d.png


ARP协议部分代码:


#include <string.h>
#include <stdio.h>
#include "net.h"
#include "arp.h"
#include "ethernet.h"
/**
 * @brief 初始的arp包
 *
 */
static const arp_pkt_t arp_init_pkt = {
    .hw_type16 = swap16(ARP_HW_ETHER),
    .pro_type16 = swap16(NET_PROTOCOL_IP),
    .hw_len = NET_MAC_LEN,
    .pro_len = NET_IP_LEN,
    .sender_ip = NET_IF_IP,
    .sender_mac = NET_IF_MAC,
    .target_mac = {0}};
/**
 * @brief arp地址转换表,<ip,mac>的容器
 *
 */
map_t arp_table;
/**
 * @brief arp buffer,<ip,buf_t>的容器
 *
 */
map_t arp_buf;
/**
 * @brief 打印一条arp表项
 *
 * @param ip 表项的ip地址
 * @param mac 表项的mac地址
 * @param timestamp 表项的更新时间
 */
void arp_entry_print(void *ip, void *mac, time_t *timestamp)
{
    printf("%s | %s | %s\n", iptos(ip), mactos(mac), timetos(*timestamp));
}
/**
 * @brief 打印整个arp表
 *
 */
void arp_print()
{
    printf("===ARP TABLE BEGIN===\n");
    map_foreach(&arp_table, arp_entry_print);
    printf("===ARP TABLE  END ===\n");
}
/**
 * @brief 发送一个arp请求
 *
 * @param target_ip 想要知道的目标的ip地址
 */
void arp_req(uint8_t *target_ip)
{
    buf_init(&txbuf, sizeof(arp_pkt_t)); //对txbuf进行初始化
    arp_pkt_t *pkt = (arp_pkt_t *)txbuf.data;
    pkt->hw_type16 = swap16(1);
    pkt->pro_type16 = swap16(NET_PROTOCOL_IP);
    pkt->hw_len = 6;
    pkt->pro_len = 4;
    pkt->opcode16 = swap16(ARP_REQUEST);
    // for (int i = 0; i < 6; i++)
    // {
    //     pkt->sender_mac[i] = net_if_mac[i];
    //     pkt->target_mac[i] = 0x00;
    // }
    // for (int i = 0; i < 4; i++)
    // {
    //     pkt->sender_ip[i] = net_if_ip[i];
    //     pkt->target_ip[i] = *(target_ip + i);
    // }
    memcpy(pkt->sender_mac, net_if_mac, NET_MAC_LEN);
    memcpy(pkt->sender_ip, net_if_ip, NET_IP_LEN);
    memset(pkt->target_mac, 0, NET_MAC_LEN);
    memcpy(pkt->target_ip, target_ip, NET_IP_LEN);
    ethernet_out(&txbuf, ether_broadcast_mac, NET_PROTOCOL_ARP); //发送ARP报文
}
/**
 * @brief 发送一个arp响应
 *
 * @param target_ip 目标ip地址
 * @param target_mac 目标mac地址
 */


ETH协议全部代码:


#include "ethernet.h"
#include "utils.h"
#include "driver.h"
#include "arp.h"
#include "ip.h"
/**
 * @brief 处理一个收到的数据包
 * 
 * @param buf 要处理的数据包
 */
void ethernet_in(buf_t *buf)
{
    if(buf->len < sizeof(ether_hdr_t))   //判断数据长度,小于以太网头部长度的话丢弃不处理
    {
        return;
    }
    ether_hdr_t *hdr = (ether_hdr_t *)buf->data;
    buf_remove_header(buf,sizeof(ether_hdr_t));  //移除以太网包头
    net_in(buf,swap16(hdr->protocol16),hdr->src);    //向上层传递数据包
}
/**
 * @brief 处理一个要发送的数据包
 * 
 * @param buf 要处理的数据包
 * @param mac 目标MAC地址
 * @param protocol 上层协议
 */
void ethernet_out(buf_t *buf, const uint8_t *mac, net_protocol_t protocol)
{
    if(buf->len < 46)
    {
        buf_add_padding(buf,46 - buf->len);
    }
    buf_add_header(buf,sizeof(ether_hdr_t));   //添加以太网包头
    ether_hdr_t *hdr = (ether_hdr_t *)buf->data;
    // for(int i = 0; i < 6; i++)   //填写目的MAC地址
    // {
    //     hdr->dst[i] = *(mac+i);
    // }
    // for(int i = 0; i < 6; i++)   //填写源MAC地址
    // {
    //     hdr->src[i] = net_if_mac[i]; //net_if_mac 得到本机的mac地址
    // }
    memcpy(hdr->dst, mac, NET_MAC_LEN);
    memcpy(hdr->src, net_if_mac, NET_MAC_LEN);
    hdr->protocol16 = swap16(protocol);
    driver_send(buf);   //将添加了以太网包头的数据帧发送到驱动层
}
/**
 * @brief 初始化以太网协议
 * 
 */
void ethernet_init()
{
    buf_init(&rxbuf, ETHERNET_MAX_TRANSPORT_UNIT + sizeof(ether_hdr_t));
}
/**
 * @brief 一次以太网轮询
 * 
 */
void ethernet_poll()
{
    if (driver_recv(&rxbuf) > 0)
        ethernet_in(&rxbuf);
}


ICMP协议部分代码:


#include "net.h"
#include "icmp.h"
#include "ip.h"
/**
 * @brief 发送icmp响应
 * 
 * @param req_buf 收到的icmp请求包
 * @param src_ip 源ip地址
 */
static void icmp_resp(buf_t *req_buf, uint8_t *src_ip)
{
    buf_t *buf = &txbuf;
    buf_init(buf, req_buf->len );
    memcpy(buf->data,req_buf->data,req_buf->len); 
    icmp_hdr_t *hdr1 = (icmp_hdr_t *)req_buf->data;
    icmp_hdr_t hdr2 = {
    .code = hdr1->code,
    .checksum16 = 0,
    .id16 = hdr1->id16,
    .seq16 = hdr1->seq16,
    .type = ICMP_TYPE_ECHO_REPLY};
    memcpy(buf->data, &hdr2, sizeof(icmp_hdr_t));
    hdr2.checksum16 = checksum16((uint16_t *)buf->data, buf->len);
    memcpy(buf->data, &hdr2, sizeof(icmp_hdr_t));
    ip_out(buf, src_ip, NET_PROTOCOL_ICMP);
}
/**
 * @brief 处理一个收到的数据包
 * 
 * @param buf 要处理的数据包
 * @param src_ip 源ip地址
 */
void icmp_in(buf_t *buf, uint8_t *src_ip)
{
    if (buf->len < sizeof(icmp_hdr_t))
    {
        return;
    }
    icmp_hdr_t *hdr = (icmp_hdr_t *)buf->data;
    if (hdr->type == ICMP_TYPE_ECHO_REQUEST)
    {
        icmp_resp(buf, src_ip);
    }
    else
    {
        return;
    }
}
/**
 * @brief 发送icmp不可达
 * 
 * @param recv_buf 收到的ip数据包
 * @param src_ip 源ip地址
 * @param code icmp code,协议不可达或端口不可达
 */


UDP协议部分代码:


#include "udp.h"
#include "ip.h"
#include "icmp.h"
/**
 * @brief udp处理程序表
 * 
 */
map_t udp_table;
/**
 * @brief udp伪校验和计算
 * 
 * @param buf 要计算的包
 * @param src_ip 源ip地址
 * @param dst_ip 目的ip地址
 * @return uint16_t 伪校验和
 */
static uint16_t udp_checksum(buf_t *buf, uint8_t *src_ip, uint8_t *dst_ip)
{
    uint8_t src[4];
    uint8_t dst[4];
    memcpy(src, src_ip, 4);
    memcpy(dst, dst_ip, 4);
    buf_add_header(buf, sizeof(udp_peso_hdr_t));
    udp_peso_hdr_t *peso_hdr = (udp_peso_hdr_t *)buf->data;
    memcpy(peso_hdr->src_ip, src, 4);
    memcpy(peso_hdr->dst_ip, dst, 4);
    peso_hdr->protocol = NET_PROTOCOL_UDP;
    peso_hdr->total_len16 = swap16(buf->len - sizeof(udp_peso_hdr_t));
    peso_hdr->placeholder = 0;
    uint16_t *p;
    p = (uint16_t *)peso_hdr;
    int n = buf->len / 2;
    int i = 0;
    uint32_t checksum = 0;
    while (i < n)
    {
        checksum += swap16(*p);
        p++;
        i++;
    }
    if (buf->len % 2 != 0)
    {
        checksum += swap16(*p) & 0xFF00;
    }
    while ((checksum >> 16) != 0)
    {
        checksum = (checksum >> 16) + (checksum & 0xFFFF);
    }
    buf_remove_header(buf, sizeof(udp_peso_hdr_t));
    memcpy(src_ip, src, 4);
    memcpy(dst_ip, dst, 4);
    return (uint16_t)(~checksum);
}
/**
 * @brief 处理一个收到的udp数据包
 * 
 * @param buf 要处理的包
 * @param src_ip 源ip地址
 */
void udp_in(buf_t *buf, uint8_t *src_ip)
{
    if (buf->len < sizeof(udp_hdr_t))
    {
        return;
    }
    udp_hdr_t *hdr = (udp_hdr_t *)buf->data;
    if (buf->len < swap16(hdr->total_len16))
    {
        return;
    }
    uint16_t temp = swap16(hdr->checksum16);
    hdr->checksum16 = 0;
    hdr->checksum16 = udp_checksum(buf, src_ip, net_if_ip);
    if (temp != hdr->checksum16)
    {
        return;
    }
    uint16_t dst_port16 = swap16(hdr->dst_port16);
    uint16_t src_port16 = swap16(hdr->src_port16);
    if (!(map_get(&udp_table, &dst_port16)))
    {
        buf_add_header(buf, sizeof(ip_hdr_t));
        icmp_unreachable(buf, src_ip, ICMP_CODE_PORT_UNREACH);
    }
    else
    {
        udp_handler_t *handler = map_get(&udp_table, &dst_port16);
        buf_remove_header(buf, sizeof(udp_hdr_t));
        (*handler)(buf->data, buf->len, src_ip, src_port16);
    }
}
/**
 * @brief 处理一个要发送的数据包
 * 
 * @param buf 要处理的包
 * @param src_port 源端口号
 * @param dst_ip 目的ip地址
 * @param dst_port 目的端口号
 */


IP协议部分代码:


#include "net.h"
#include "ip.h"
#include "ethernet.h"
#include "arp.h"
#include "icmp.h"
/**
 * @brief 处理一个收到的数据包
 * 
 * @param buf 要处理的数据包
 * @param src_mac 源mac地址
 */
void ip_in(buf_t *buf, uint8_t *src_mac)
{
    if(buf->len < sizeof(ip_hdr_t))
    {
        return;
    }
    ip_hdr_t *hdr = (ip_hdr_t *)buf->data;
    if(hdr->version != 4 || swap16(hdr->total_len16) > buf->len)
    {
        return;
    }
    uint16_t hdr_checksum_temp = hdr->hdr_checksum16;
    hdr->hdr_checksum16 = 0;
    uint16_t checksum = checksum16((uint16_t *)hdr, sizeof(ip_hdr_t));
    hdr->hdr_checksum16 = swap16(checksum);
    if(checksum != hdr_checksum_temp)
    {
        return;
    }
    else
    {
        hdr->hdr_checksum16 = hdr_checksum_temp;
    }
    for (size_t i = 0; i < NET_IP_LEN; i++)
    {
        if(hdr->dst_ip[i] != net_if_ip[i])
        {
            return;
        }
    }
    if(buf->len > swap16(hdr->total_len16))
    {
        buf_remove_padding(buf, buf->len - swap16(hdr->total_len16));
    }
    if(hdr->protocol != NET_PROTOCOL_ICMP && hdr->protocol != NET_PROTOCOL_UDP)
    {
        icmp_unreachable(buf, hdr->src_ip, ICMP_CODE_PROTOCOL_UNREACH);
    }
    else 
    {
        buf_remove_header(buf, sizeof(ip_hdr_t));
        net_in(buf, hdr->protocol, hdr->src_ip);
    }
}
/**
 * @brief 处理一个要发送的ip分片
 * 
 * @param buf 要发送的分片
 * @param ip 目标ip地址
 * @param protocol 上层协议
 * @param id 数据包id
 * @param offset 分片offset,必须被8整除
 * @param mf 分片mf标志,是否有下一个分片
 */
void ip_fragment_out(buf_t *buf, uint8_t *ip, net_protocol_t protocol, int id, uint16_t offset, int mf)
{
    buf_add_header(buf, sizeof(ip_hdr_t));
    ip_hdr_t *hdr = (ip_hdr_t *)buf->data;
    hdr->hdr_len = 5;
    hdr->version = 4;
    hdr->tos = 0;
    hdr->total_len16 = swap16(buf->len);
    hdr->id16 = swap16(id);
    hdr->protocol = protocol;
    hdr->ttl = 64;
    if (mf == 1)
    {
        hdr->flags_fragment16 = swap16((offset >> 3) + IP_MORE_FRAGMENT);
    }
    else
    {
        hdr->flags_fragment16 = swap16(offset >> 3);
    }
    memcpy(hdr->src_ip, net_if_ip, NET_IP_LEN);
    memcpy(hdr->dst_ip, ip, NET_IP_LEN);
    hdr->hdr_checksum16 = 0;
    hdr->hdr_checksum16 = checksum16((uint16_t *)hdr, sizeof(ip_hdr_t));
    arp_out(buf, ip);
}
/**
 * @brief 处理一个要发送的ip数据包
 * 
 * @param buf 要处理的包
 * @param ip 目标ip地址
 * @param protocol 上层协议
 */



相关文章
|
26天前
|
安全 网络安全 定位技术
网络通讯技术:HTTP POST协议用于发送本地压缩数据到服务器的方案。
总的来说,无论你是一名网络开发者,还是普通的IT工作人员,理解并掌握POST方法的运用是非常有价值的。它就像一艘快速,稳定,安全的大船,始终为我们在网络海洋中的冒险提供了可靠的支持。
64 22
|
16天前
|
网络协议 数据安全/隐私保护 网络架构
|
1月前
|
缓存 网络协议 API
掌握网络通信协议和技术:开发者指南
本文探讨了常见的网络通信协议和技术,如HTTP、SSE、GraphQL、TCP、WebSocket和Socket.IO,分析了它们的功能、优劣势及适用场景。开发者需根据应用需求选择合适的协议,以构建高效、可扩展的应用程序。同时,测试与调试工具(如Apipost)能助力开发者在不同网络环境下优化性能,提升用户体验。掌握这些协议是现代软件开发者的必备技能,对项目成功至关重要。
|
2月前
|
人工智能 自然语言处理 决策智能
智能体竟能自行组建通信网络,还能自创协议提升通信效率
《一种适用于大型语言模型网络的可扩展通信协议》提出创新协议Agora,解决多智能体系统中的“通信三难困境”,即异构性、通用性和成本问题。Agora通过标准协议、结构化数据和自然语言三种通信格式,实现高效协作,支持复杂任务自动化。演示场景显示其在预订服务和天气预报等应用中的优越性能。论文地址:https://arxiv.org/pdf/2410.11905。
58 6
|
4月前
|
前端开发 网络协议 安全
【网络原理】——HTTP协议、fiddler抓包
HTTP超文本传输,HTML,fiddler抓包,URL,urlencode,HTTP首行方法,GET方法,POST方法
|
4月前
|
SQL 安全 网络安全
网络安全与信息安全:知识分享####
【10月更文挑战第21天】 随着数字化时代的快速发展,网络安全和信息安全已成为个人和企业不可忽视的关键问题。本文将探讨网络安全漏洞、加密技术以及安全意识的重要性,并提供一些实用的建议,帮助读者提高自身的网络安全防护能力。 ####
120 17
|
4月前
|
SQL 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
随着互联网的普及,网络安全问题日益突出。本文将从网络安全漏洞、加密技术和安全意识三个方面进行探讨,旨在提高读者对网络安全的认识和防范能力。通过分析常见的网络安全漏洞,介绍加密技术的基本原理和应用,以及强调安全意识的重要性,帮助读者更好地保护自己的网络信息安全。
91 10
|
4月前
|
存储 SQL 安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
随着互联网的普及,网络安全问题日益突出。本文将介绍网络安全的重要性,分析常见的网络安全漏洞及其危害,探讨加密技术在保障网络安全中的作用,并强调提高安全意识的必要性。通过本文的学习,读者将了解网络安全的基本概念和应对策略,提升个人和组织的网络安全防护能力。
|
4月前
|
SQL 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
在数字化时代,网络安全和信息安全已成为我们生活中不可或缺的一部分。本文将介绍网络安全漏洞、加密技术和安全意识等方面的内容,并提供一些实用的代码示例。通过阅读本文,您将了解到如何保护自己的网络安全,以及如何提高自己的信息安全意识。
111 10
|
4月前
|
监控 安全 网络安全
网络安全与信息安全:漏洞、加密与意识的交织
在数字时代的浪潮中,网络安全与信息安全成为维护数据完整性、保密性和可用性的关键。本文深入探讨了网络安全中的漏洞概念、加密技术的应用以及提升安全意识的重要性。通过实际案例分析,揭示了网络攻击的常见模式和防御策略,强调了教育和技术并重的安全理念。旨在为读者提供一套全面的网络安全知识框架,从而在日益复杂的网络环境中保护个人和组织的资产安全。
下一篇
oss创建bucket