任务描述
本关任务的目标是合成理解arp协议的语法和语义,并实现该协议。
任务1:根据已经给定的缓存表结构及定义,完成初始化函数:
void arp_cache_init(void);
其功能就是全局量
struct arpentry arpcache[ARP_CACHE_SIZE]; /* ARP cache */
进行初始化。
任务2:根据输入参数ip在表中查询对应的mac地址,如果表中没有该ip的地址,则启用arp请求进行解析:
byte *arp_resolve(uint32 ip, byte *mac);
任务3:根据网卡参数及目的ip,构建arp请求帧:
int generate_arp_request(uint32 dstip, struct etherPkt *eth ) ;
任务4:据网卡参数及目的ip,目的mac,构建arp响应帧:
int generate_arp_response(uint32 dstip, byte *dstmac, struct etherPkt *eth ) ;
任务5:根据收到的免费arp请求,更新arp缓存:
void update_arpcache(struct arppacket *arppkt, int curtime);
注意与下面add_arpcache( )的区别,更新只是对记录已经有的记录用新的时间和mac进行替换,而add_arpcache( )除了更新功能外,如果记录中没有该ip对应的记录,还要添加一条记录。
任务6: 根据收到的arp请求或响应,更新或添加arp缓存:
void add_arpcache(struct arppacket *arppkt, int curtime);
任务7:处理收到的arp帧:
当收到arp协议数据单元时启用,它会根据arp类型是请求还是响应做不同的操作,如果是请求,则表示有主机查询自己的mac,此时需要将该请求中的ip和mac添加到缓存中,因此收到请求意味着,该主机要与自己通信,所以预先存储它的mac。如果收到的是响应,表示是自己发出的请求得到了回应,此时也应添加记录。
void arp_in( struct etherPkt *eth);
/* arp.c - arp_init, arp_resolve, arp_in, arp_alloc, arp_ntoh, arp_hton */
#include "datalink_arp.h"
struct arpentry arpcache[ARP_CACHE_SIZE]; /* ARP cache */
struct network networkdata;
unsigned char out_eth[MAX_ETH_LENTH] = { 0 };
/*------------------------------------------------------------------------
* init_network - 网卡初始化
*------------------------------------------------------------------------
*/
void init_network(char *configfile) {
get_local_netdata(configfile);
arp_cache_init();
}
void print_arpcache(void) {
printf("打印arpchae列表:\n");
char str[100];
for (int i = 0; i < ARP_CACHE_SIZE; i++) {
printf("%d time:%d ",i,0);
printf("ip:%s ",ip2str(arpcache[i].ipaddr,str) );
printf("mac:");
print_eth_addr(arpcache[i].macaddr);
printf("\n");
}
}
/*------------------------------------------------------------------------
* get_local_netdata - 获取本地网络参数
*------------------------------------------------------------------------
*/
struct network * get_local_netdata(char *configfile) {
printf("输出主机配置信息:\n");
struct network *NetData = &networkdata;
char ip[100] = { 0 }, mask[100] = { 0 }, gate[100] = { 0 }, dns[100] = { 0 };
getconfig(configfile, ip, mask, gate, dns);
printf("ip:%s\nmask:%s\ngate:%s\ndns:%s\n", ip, mask, gate, dns);
uint32 uip = str2ip(ip), umask = str2ip(mask), ugate = str2ip(gate), udns = str2ip(dns);
if (uip == 0) {
NetData->ipucast = 0;
return NetData;
}
byte bcast[6] = { 0xff,0xff,0xff,0xff,0xff,0xff };
byte mac[6] = { 0x00,0xf1,0xf3,0x05,0x39,0x4b };
printf("mac:");
print_eth_addr(mac);
printf("\n");
NetData->dnsserver = udns;
memcpy(NetData->ethbcast, bcast, 6);
memcpy(NetData->ethucast, mac, 6);
NetData->ipmask = umask;
NetData->ipprefix = uip & umask;
NetData->ipbcast = NetData->ipprefix | ~NetData->ipmask;
NetData->iprouter = ugate;
NetData->ipucast = uip;
return NetData;
}
/*------------------------------------------------------------------------
* arp_cache_init - 初始化arp缓存
*------------------------------------------------------------------------
*/
void arp_cache_init(void){
/**********Begin 1 **********/
/********End 1 **********/
}
/*------------------------------------------------------------------------
*arp_resolve - 根据ip查找对应的mac,如果没找到有效的mac,则发arp请求
*------------------------------------------------------------------------
*/
byte * arp_resolve( uint32 ip, byte *mac) {
int validtime = time(NULL) - 60;//超过60秒的,记录无效
struct arpentry *arptr; /* arp缓存记录指针 */
/* 如果ip是广播地址,则返回mac广播地址 */
if (ip == 0xffffffff || ip == networkdata.ipbcast) {
memcpy(mac, networkdata .ethbcast, ETH_ADDR_LEN);
return mac;
}
/**************Begin 2 ************/
for(int i = 0 ; i < ARP_CACHE_SIZE; i++){
if(arpcache[i].ipaddr == ip){
memcpy(mac, arpcache[i].macaddr, ETH_ADDR_LEN);
return mac;
}
}
/************End 2 *************/
int len=generate_arp_request(ip,(struct etherPkt *) out_eth);
char str[100];
printf("%s搜索失败,发送arp请求!\n",ip2str(ip,str));
sendpkt((byte *) out_eth,len);
return NULL;
}
/*------------------------------------------------------------------------
*generate_arp_request - 根据网卡参数及目的ip,构建arp请求帧
*------------------------------------------------------------------------
*/
int generate_arp_request(uint32 dstip, struct etherPkt *eth ){
struct arppacket *arppkt = (struct arppacket*)eth->data;
int len = 0;/*帧长,不包含校验码*/
/************** Begin 3 ***********/
/* 填充以太网帧的协议字段*/
memcpy(eth->src, networkdata.ethucast, ETH_ADDR_LEN);
memcpy(eth->dst, networkdata.ethbcast, ETH_ADDR_LEN);
eth->type = 0x0608;
arppkt->htype = 0x0100;
arppkt->ptype = 0x008;
arppkt->hlen = 0x06;
arppkt->plen = 0x04;
arppkt->op = 0x0100;
memcpy(arppkt->srcmac, networkdata.ethucast, ETH_ADDR_LEN);
arppkt->srcip = networkdata.ipucast;
// memcpy(arppkt->dstmac, eth->dst, ETH_ADDR_LEN);
arppkt->dstip = dstip;
len = 60;
/********** End 3 ************/
return len;
}
/*------------------------------------------------------------------------
*generate_arp_response - 根据网卡参数及目的ip,目的mac,构建arp响应帧
*------------------------------------------------------------------------
*/
int generate_arp_response(uint32 dstip, byte *dstmac, struct etherPkt *eth ){
struct arppacket *arppkt = (struct arppacket*)eth->data;
int len = 0;/*帧长,不包含校验码*/
/************** Begin 4 ******************/
memcpy(eth->src, networkdata.ethucast, ETH_ADDR_LEN);
memcpy(eth->dst, dstmac, ETH_ADDR_LEN);
eth->type = 0x0608;
arppkt->htype = 0x0100;
arppkt->ptype = 0x008;
arppkt->hlen = 0x06;
arppkt->plen = 0x04;
arppkt->op = 0x0200;
memcpy(arppkt->srcmac, networkdata.ethucast, ETH_ADDR_LEN);
arppkt->srcip = networkdata.ipucast;
memcpy(arppkt->dstmac, eth->dst, ETH_ADDR_LEN);
arppkt->dstip = dstip;
len = 60;
/********** End 4 *************/
return len;
}
/*------------------------------------------------------------------------
*update_arpcache - 根据收到的免费arp请求,更新arp缓存
*------------------------------------------------------------------------
*/
void update_arpcache(struct arppacket *arppkt, int curtime) {
struct arpentry *arptr;
/*****************Begin 5 ***********/
/**********End 5 **************/
}
/*------------------------------------------------------------------------
*add_arpcache - 根据收到的arp请求和响应,更新或添加arp缓存
*------------------------------------------------------------------------
*/
void add_arpcache(struct arppacket *arppkt, int curtime) {
struct arpentry *arptr;
/***************** Begin 6 ***********/
for(int i = 0; i < ARP_CACHE_SIZE; i++){
if(arpcache[i].timestampe == 0){
arpcache[i].timestampe = curtime;
arpcache[i].ipaddr = arppkt->srcip;
memcpy(arpcache[i].macaddr, arppkt->srcmac, ETH_ADDR_LEN);
break;
}
}
/********** End 6 **************/
}
/*------------------------------------------------------------------------
* arp_in - 处理收到的arp帧
*------------------------------------------------------------------------
*/
void arp_in( struct etherPkt *eth){
int curtime = time(NULL);
struct arppacket * arppkt = (struct arppacket*)eth->data;
/* 验证 ARP 是 IPv4 和 Ethernet */
if ((arppkt->htype !=htons( ARP_HTYPE)) || (arppkt->ptype != ntohs(ARP_PTYPE)))
return;
if (arppkt->dstip == networkdata.ipucast)
add_arpcache(arppkt, curtime);
else if(arppkt->dstip == arppkt->srcip)
update_arpcache(arppkt, curtime);
/*********** Begin 7 *************/
/*如果收到的是给本机的arp请求,则需要发送arp响应帧*/
if (arppkt->dstip == networkdata.ipucast){
int len = generate_arp_response(arppkt->srcip, arppkt->srcmac, (struct etherPkt *) out_eth);
char str[100];
printf("收到arp请求,发送arp响应!\n");
sendpkt((byte *) out_eth,len);
}
/*********** End 7 *************/
return;
}
/*------------------------------------------------------------------------
* arp_alloc - 为新加入的arp记录,分配一个位置
*------------------------------------------------------------------------
*/
int arp_alloc(void){
/*搜索空闲的记录空间 ,如果arpcache满了,踢出时间最早的*/
int slot = 0;
/********** Begin 8 ***********/
/********** End 8 ************/
memset((char *)&arpcache[slot], 0, sizeof(struct arpentry));
return slot;
}
/*------------------------------------------------------------------------
* sendpkt - 模拟发送帧
*------------------------------------------------------------------------
*/
void sendpkt(byte *eth,int len) {
print_pkt(eth, len);
}