前些天发现了十分不错的人工智能学习网站,通俗易懂,风趣幽默,没有广告,分享给大家,大家可以自行看看。(点击跳转人工智能学习资料)
微信公众号:创享日记
发送关键词:协议实现
获取各个协议C语言实现源代码源文件
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 上层协议*/