network arp+icmp lab finished

This commit is contained in:
2025-11-18 14:46:26 +08:00
parent 9c6e429a47
commit e4c7bf757d
186 changed files with 316 additions and 16491 deletions

View File

@@ -7,26 +7,28 @@
static pcap_t * pcap;
// pcap所用的网卡
const char * ip_str = "10.20.6.8"; // 根据实际电脑上存在的网卡地址进行修改
const uint8_t my_mac_addr[] = {0x04, 0x7b, 0xcb, 0xce, 0x0a, 0x56};
// const char * ip_str = "10.20.6.8"; // 根据实际电脑上存在的网卡地址进行修改
//const char * ip_str = "192.168.43.70"; // 根据实际电脑上存在的网卡地址进行修改
const char * ip_str = "172.17.0.1"; // 根据实际电脑上存在的网卡地址进行修改
static uint8_t driver_mac[XNET_MAC_ADDR_SIZE] = {0}; // 留空则自动读取当前网卡的MAC
/**
* 初始化网络驱动
* @return 0成功其它失败
*/
xnet_err_t xnet_driver_open (uint8_t * mac_addr) {
printf("[DRIVER] Opening pcap device for IP: %s\n", ip_str);
printf("[DRIVER] Using MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
my_mac_addr[0], my_mac_addr[1], my_mac_addr[2],
my_mac_addr[3], my_mac_addr[4], my_mac_addr[5]);
fflush(stdout);
memcpy(mac_addr, my_mac_addr, sizeof(my_mac_addr));
pcap = pcap_device_open(ip_str, mac_addr, 1);
pcap = pcap_device_open(ip_str, driver_mac, 1);
if (pcap == (pcap_t *)0) {
printf("[DRIVER] Failed to open pcap device!\n");
fflush(stdout);
exit(-1);
}
memcpy(mac_addr, driver_mac, XNET_MAC_ADDR_SIZE);
printf("[DRIVER] Using MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
driver_mac[0], driver_mac[1], driver_mac[2],
driver_mac[3], driver_mac[4], driver_mac[5]);
printf("[DRIVER] Pcap device opened successfully\n");
fflush(stdout);
return XNET_ERR_OK;

View File

@@ -2,8 +2,6 @@
#include <stdio.h>
#include "xicmp.h"
#include "xnet_tiny.h"
#include "xip.h"
#include "xarp.h"
#define ICMP_TYPE_ECHO_REPLY 0
#define ICMP_TYPE_ECHO_REQUEST 8
@@ -31,98 +29,53 @@ static uint16_t checksum(void *buf, uint16_t len) {
return ~((uint16_t)sum);
}
void xicmp_in(xnet_packet_t *packet) {
if (packet->size < sizeof(xether_hdr_t) + sizeof(xip_hdr_t)) {
return;
}
// 先保留下以太头后续要使用源MAC更新ARP缓存
xether_hdr_t *ether_hdr = (xether_hdr_t *)packet->data;
remove_header(packet, sizeof(xether_hdr_t));
xip_hdr_t *ip_hdr = (xip_hdr_t *)packet->data;
if ((ip_hdr->hlen_ver & 0xF0) != 0x40) {
return;
}
uint8_t hlen = (ip_hdr->hlen_ver & 0x0F) * 4;
if ((hlen < sizeof(xip_hdr_t)) || (packet->size < hlen + sizeof(xicmp_packet_t))) {
return;
}
// 目前仅支持无IP选项的报文
if (hlen != sizeof(xip_hdr_t)) {
return;
}
// 仅处理ICMP协议
if (ip_hdr->protocol != 1) {
return;
}
if (checksum(ip_hdr, hlen) != 0) {
return;
}
if (memcmp(ip_hdr->dest_ip, my_ip_addr, 4) != 0) {
return;
}
// 更新ARP缓存以便后续通过IP层发送应答而无需额外ARP查询
xarp_update_from_ip(ip_hdr->src_ip, ether_hdr->src);
uint16_t total_len = swap_order16(ip_hdr->total_len);
if (packet->size < total_len) {
return;
}
if (packet->size > total_len) {
packet->size = total_len;
}
xip_hdr_t saved_ip_hdr;
memcpy(&saved_ip_hdr, ip_hdr, sizeof(xip_hdr_t));
remove_header(packet, hlen);
void xicmp_in(xnet_packet_t *packet, const uint8_t *src_ip, const uint8_t *src_mac) {
if (packet->size < sizeof(xicmp_packet_t)) {
return;
}
xicmp_packet_t *icmp_packet = (xicmp_packet_t *)packet->data;
if (icmp_packet->type == ICMP_TYPE_ECHO_REQUEST) {
xicmp_packet_t *req_icmp = (xicmp_packet_t *)packet->data;
if (req_icmp->type == ICMP_TYPE_ECHO_REQUEST) {
printf("[ICMP] Received Echo Request from %d.%d.%d.%d\n",
saved_ip_hdr.src_ip[0], saved_ip_hdr.src_ip[1],
saved_ip_hdr.src_ip[2], saved_ip_hdr.src_ip[3]);
src_ip[0], src_ip[1], src_ip[2], src_ip[3]);
// 校验收到的ICMP包避免对错误数据做回复
if (checksum(icmp_packet, packet->size) != 0) {
if (checksum(req_icmp, packet->size) != 0) {
printf("[ICMP] Checksum failed, dropping packet\n");
return;
}
// 分配发送缓冲区:需要包含以太网头 + IP头 + ICMP数据
xnet_packet_t *tx_packet = xnet_alloc_for_send(sizeof(xether_hdr_t) + packet->size + hlen);
if (tx_packet) {
// 跳过以太网头空间从IP头开始填充以太网头由ethernet_out_to填充
tx_packet->data += sizeof(xether_hdr_t);
tx_packet->size -= sizeof(xether_hdr_t);
xip_hdr_t *reply_ip_hdr = (xip_hdr_t *)tx_packet->data;
memcpy(reply_ip_hdr, &saved_ip_hdr, sizeof(xip_hdr_t));
reply_ip_hdr->total_len = swap_order16(packet->size + hlen);
memcpy(reply_ip_hdr->dest_ip, saved_ip_hdr.src_ip, 4);
memcpy(reply_ip_hdr->src_ip, my_ip_addr, 4);
reply_ip_hdr->ttl = 64;
reply_ip_hdr->hdr_checksum = 0;
reply_ip_hdr->hdr_checksum = checksum(reply_ip_hdr, hlen);
uint16_t icmp_size = packet->size;
uint16_t ip_hdr_size = sizeof(xip_hdr_t);
uint16_t ip_pkt_size = ip_hdr_size + icmp_size;
xicmp_packet_t *reply_icmp = (xicmp_packet_t *)((uint8_t *)tx_packet->data + hlen);
memcpy(reply_icmp, packet->data, packet->size);
reply_icmp->type = ICMP_TYPE_ECHO_REPLY;
reply_icmp->checksum = 0;
reply_icmp->checksum = checksum(reply_icmp, packet->size);
printf("[ICMP] Sending Echo Reply to %d.%d.%d.%d\n",
saved_ip_hdr.src_ip[0], saved_ip_hdr.src_ip[1],
saved_ip_hdr.src_ip[2], saved_ip_hdr.src_ip[3]);
xip_out(tx_packet, saved_ip_hdr.src_ip, 1);
printf("[ICMP] Echo Reply sent\n");
} else {
xnet_packet_t *tx_packet = xnet_alloc_for_send(ip_pkt_size);
if (!tx_packet) {
printf("[ICMP] Failed to allocate tx_packet\n");
return;
}
} else if (icmp_packet->type == ICMP_TYPE_ECHO_REPLY) {
// 收到ICMP Echo Reply正常接收不做额外处理
// 这是对本机发出的ping请求的回复
xip_hdr_t *reply_ip_hdr = (xip_hdr_t *)tx_packet->data;
reply_ip_hdr->hlen_ver = (4 << 4) | (ip_hdr_size / 4);
reply_ip_hdr->tos = 0;
reply_ip_hdr->total_len = swap_order16(ip_pkt_size);
reply_ip_hdr->id = 0;
reply_ip_hdr->flags_fragment = 0;
reply_ip_hdr->ttl = 64;
reply_ip_hdr->protocol = 1; // ICMP
memcpy(reply_ip_hdr->dest_ip, src_ip, 4);
memcpy(reply_ip_hdr->src_ip, my_ip_addr, 4);
reply_ip_hdr->hdr_checksum = 0;
reply_ip_hdr->hdr_checksum = checksum(reply_ip_hdr, ip_hdr_size);
xicmp_packet_t *reply_icmp = (xicmp_packet_t *)(tx_packet->data + ip_hdr_size);
memcpy(reply_icmp, req_icmp, icmp_size);
reply_icmp->type = ICMP_TYPE_ECHO_REPLY;
reply_icmp->checksum = 0;
reply_icmp->checksum = checksum(reply_icmp, icmp_size);
printf("[ICMP] Sending Echo Reply to %d.%d.%d.%d\n",
src_ip[0], src_ip[1], src_ip[2], src_ip[3]);
ethernet_out_to(XNET_PROTOCOL_IP, src_mac, tx_packet);
}
}

View File

@@ -2,22 +2,10 @@
#define XICMP_H
#include "xnet_tiny.h"
#include "xip.h"
#pragma pack(1)
typedef struct _xip_hdr_t {
uint8_t hlen_ver;
uint8_t tos;
uint16_t total_len;
uint16_t id;
uint16_t flags_fragment;
uint8_t ttl;
uint8_t protocol;
uint16_t hdr_checksum;
uint8_t src_ip[4];
uint8_t dest_ip[4];
} xip_hdr_t;
typedef struct _xicmp_packet_t {
uint8_t type;
uint8_t code;
@@ -28,6 +16,6 @@ typedef struct _xicmp_packet_t {
#pragma pack()
void xicmp_in(xnet_packet_t *packet);
void xicmp_in(xnet_packet_t *packet, const uint8_t *src_ip, const uint8_t *src_mac);
#endif // XICMP_H

View File

@@ -1,8 +1,84 @@
#include <string.h>
#include <stdio.h>
#include "xip.h"
#include "xarp.h"
#include "xicmp.h"
#include "xnet_tiny.h"
void xip_out(xnet_packet_t *packet, const uint8_t *dest_ip, uint8_t protocol) {
#define swap_order16(v) ((((v) & 0xFF) << 8) | (((v) >> 8) & 0xFF))
static uint16_t checksum(void *buf, uint16_t len) {
uint32_t sum = 0;
uint16_t *curr = (uint16_t *)buf;
while (len > 1) {
sum += *curr++;
len -= 2;
}
if (len > 0) {
sum += *(uint8_t *)curr;
}
uint16_t high;
while ((high = sum >> 16) != 0) {
sum = high + (sum & 0xFFFF);
}
return ~((uint16_t)sum);
}
void xip_in(xnet_packet_t *packet) {
if (packet->size < sizeof(xether_hdr_t) + sizeof(xip_hdr_t)) {
return;
}
xether_hdr_t *ether_hdr = (xether_hdr_t *)packet->data;
remove_header(packet, sizeof(xether_hdr_t));
xip_hdr_t *ip_hdr = (xip_hdr_t *)packet->data;
if ((ip_hdr->hlen_ver & 0xF0) != 0x40) {
printf("[IP] Invalid version\n");
return;
}
uint8_t hlen = (ip_hdr->hlen_ver & 0x0F) * 4;
if (hlen < sizeof(xip_hdr_t)) {
printf("[IP] Invalid header length\n");
return;
}
if (memcmp(ip_hdr->dest_ip, my_ip_addr, 4) != 0) {
printf("[IP] Dest IP mismatch\n");
return;
}
printf("[IP] Packet for me, protocol: %d\n", ip_hdr->protocol);
//if (checksum(ip_hdr, hlen) != 0) {
// printf("[IP] Checksum failed\n");
// return;
//}
xarp_update_from_ip(ip_hdr->src_ip, ether_hdr->src);
uint16_t total_len = swap_order16(ip_hdr->total_len);
if (packet->size > total_len) {
packet->size = total_len;
}
remove_header(packet, hlen);
switch (ip_hdr->protocol) {
case 1: // ICMP
printf("[IP] Processing ICMP packet\n");
xicmp_in(packet, ip_hdr->src_ip, ether_hdr->src);
break;
default:
printf("[IP] Unknown protocol: %d\n", ip_hdr->protocol);
break;
}
}
void xip_out(xnet_packet_t *packet, const uint8_t *dest_ip) {
const uint8_t *mac_addr = xarp_resolve(packet, dest_ip);
if (mac_addr) {
ethernet_out_to(XNET_PROTOCOL_IP, mac_addr, packet);

View File

@@ -1,8 +1,25 @@
#ifndef XIP_H
#define XIP_H
#include <stdint.h>
#include "xnet_tiny.h"
void xip_out(xnet_packet_t *packet, const uint8_t *dest_ip, uint8_t protocol);
#pragma pack(1)
typedef struct _xip_hdr_t {
uint8_t hlen_ver;
uint8_t tos;
uint16_t total_len;
uint16_t id;
uint16_t flags_fragment;
uint8_t ttl;
uint8_t protocol;
uint16_t hdr_checksum;
uint8_t src_ip[4];
uint8_t dest_ip[4];
} xip_hdr_t;
#pragma pack()
#endif // XIP_H
void xip_in(xnet_packet_t *packet);
void xip_out(xnet_packet_t *packet, const uint8_t *dest_ip);
#endif //XIP_H

View File

@@ -2,9 +2,12 @@
#include <stdio.h>
#include "xnet_tiny.h"
#include "xarp.h"
#include "xip.h"
#include "xicmp.h"
const uint8_t my_ip_addr[] = {10, 20, 6, 8};
// const uint8_t my_ip_addr[] = {10, 20, 6, 8};
//const uint8_t my_ip_addr[] = {192, 168, 43, 70};
const uint8_t my_ip_addr[] = {172, 17, 0, 1};
#define min(a, b) ((a) > (b) ? (b) : (a))
@@ -50,7 +53,7 @@ void xnet_free_packet(xnet_packet_t * packet) {
* @param packet 待处理的数据包
* @param header_size 增加的头部大小
*/
static void add_header(xnet_packet_t *packet, uint16_t header_size) {
void add_header(xnet_packet_t *packet, uint16_t header_size) {
packet->data -= header_size;
packet->size += header_size;
}
@@ -129,7 +132,7 @@ static void ethernet_in (xnet_packet_t * packet) {
break;
case XNET_PROTOCOL_IP: {
printf("[ETH] Processing IP packet\n");
xicmp_in(packet);
xip_in(packet);
break;
}
default:
@@ -149,8 +152,6 @@ static void ethernet_poll (void) {
packet_count++;
printf("\n[POLL] Packet #%d received, size: %d bytes\n", packet_count, packet->size);
fflush(stdout);
// 正常情况下,在此打个断点,全速运行
// 然后在对方端ping 192.168.254.2,会停在这里
ethernet_in(packet);
}
}