c-router-emulator/router/test/main.c

419 lines
17 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/ether.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netpacket/packet.h>
#include <sys/ioctl.h>
#include "get_interface.h"
#include "link.h"
MY_ROU * roulink_head = NULL;
MY_ARP * arplink_head = NULL;
int sockfd = 0;
//*************************人机交互线程**********************************
void *callback1(void *arg)
{
while(1)
{
printf("输入相应的序号,实现对应功能\n");
int usercmd = -1;
scanf("%d", &usercmd);
switch (usercmd)
{
case 0:
getchar();
title();
break;
case 2:
getchar();//接收输入2的回车
roulink_head=rou_pTailInsert(roulink_head);
break;
case 3:
getchar();
roulink_head=rou_pDeleteLink(roulink_head);
break;
case 4:
getchar();
rou_print_link(roulink_head);/*将指针pHead传入输出函数遍历输出*/
printf("链表打印完毕!\n");
break;
case 5:
arp_print_link(arplink_head);
break;
case 10:
printf("10退出路由器,释放IP、ARP链表\n");
getchar();
arp_freeLink(arplink_head);
rou_freeLink(roulink_head);//释放链表
exit(1);
break;
}
}
pthread_exit(NULL);
}
//*************************人机交互线程**********************************
//*************************ARP应答的IP和MAC存入缓存链表线程【开始】**************//
void * callback2_arp(void *arg)
{
arp_mac_ip *p = (arp_mac_ip*)arg;
//printf("将 ARP 应答的 IP 和 MAC 存入缓存链\n");
//printf("### %s\n", p->stc_ip);
if(arp_searcharpLink(arplink_head, p->stc_ip) == 0)
{
printf("插入链表中没有的ARP 应答 IP 和 MAC\n");
arplink_head = arp_pTailInsert( arplink_head, p->stc_mac ,p->stc_ip);
}
pthread_exit(NULL);
}
//*************************ARP应答的IP和MAC存入缓存链表线程【结束】***************//
//*************************IP包转发线程【开始】**********************************//
void *callback3_ip(void *arg)
{
//发送接口的结构体
struct sockaddr_ll sll;
ip_buf *pthread_ip_buf = (ip_buf *)arg;
unsigned char * ip_head= pthread_ip_buf->buf + 14;
char dst_ip[16] = "";
inet_ntop(AF_INET, ip_head + 16, dst_ip, 16);
printf("IP包转发线程中 目的 dst_ip = %s\n", dst_ip);
int i = 0;
for (i = 0; i < 16; i++)
{
unsigned char ip[16]="";
inet_ntop(AF_INET,net_interface[i].ip, ip, 16);//get_interface文件中得到的都是32位无符号整形数据计算机数据现转成成点分十进制人能够书别的
//---------------------[调试]----------------------------------------//
//printf("设置网卡循环进入次数 i = %d\n", i);
//printf("检索到的所有网卡名字net_interface[i].name = %s\n", net_interface[i].name);
//printf("net_interface[i].ip = %s\n",ip);
//---------------------[调试]----------------------------------------//
if(strncmp(ip, dst_ip, 9) == 0)//根据目标网段 查找活跃网卡
{
//网卡结构体
struct ifreq ethreq;
strncpy(ethreq.ifr_name, net_interface[i].name , IFNAMSIZ);//指定网卡名字
printf("网卡名字:%s\n", ethreq.ifr_name);
if(ioctl(sockfd, SIOCGIFINDEX, &ethreq) == -1)//获取网卡接口地址
{
return 0;
}
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ethreq.ifr_ifindex;//将网卡的接口类型赋值给发送接口
break;
}
else
{
//printf("找不到网段对应的网卡,继续查\n");
continue;
}
}
//--------------------------------------------拿到网卡,开始检索对应网卡所有数据,对比【开始】------------------------------------------------------//
if(strcmp(dst_ip + strlen(dst_ip) - 3, "255") == 0)//是 否为广 播地址
{
// printf("是广播地址, 退出线\n");
return;
}
else
{
//printf("不是广播地址,判断是否为回 环地址\n");
if(strcmp("127.0.0.1", dst_ip) == 0)
{
//printf("是回 环地址, 退出线\n");
return;
}
else
{
//printf("查找ARP缓存表 对应 MAC\n");
//指定目的MAC地址
//可以在链表中找到目的IP组ICMP包的目的MAC就可以了
//之所以这样是因为在网络中的ICMP包里变化的只有目的MAC源MAC、IP都不会发生变动
if(arp_searcharpLink(arplink_head, dst_ip) == 1)
{
//1网段中 指定目标IP是主机的IP、MAC
//2C-4D-54-57-04-7F
//printf("****icmp****\n");
if(strncmp("192.168.1.49", dst_ip, 9) == 0)
{
pthread_ip_buf->buf[0]=0x2C;
pthread_ip_buf->buf[1]=0x4D;
pthread_ip_buf->buf[2]=0x54;
pthread_ip_buf->buf[3]=0x57;
pthread_ip_buf->buf[4]=0x04;
pthread_ip_buf->buf[5]=0x7F;//目标
int send_len = sendto(sockfd, pthread_ip_buf->buf, pthread_ip_buf->my_buf_date_len, 0, (struct sockaddr *)&sll, sizeof(sll));
//-------------------[调试]------------------------//
//printf("****1 网段 icmp缓存表****\n");
// printf("send_len ICMP 1 = %d\n", send_len);
//-------------------[调试]------------------------//
}
//2网段中 指定目标IP是开发板的IP、MAC
// 00:53:50:00:01:33
else if(strncmp("192.168.2.100", dst_ip, 9) == 0)
{
pthread_ip_buf->buf[0]=0x00;
pthread_ip_buf->buf[1]=0x53;
pthread_ip_buf->buf[2]=0x50;
pthread_ip_buf->buf[3]=0x00;
pthread_ip_buf->buf[4]=0x59;
pthread_ip_buf->buf[5]=0x12;
//发送给套接字的数据长度是实际传送过来的长度main中的IP包有收到具体长度信息
int send_len = sendto(sockfd, pthread_ip_buf->buf, pthread_ip_buf->my_buf_date_len, 0, (struct sockaddr *)&sll, sizeof(sll));
//-------------------[调试]------------------------//
//printf("****2 网段 icmp缓存表****\n");
// printf("send_len ICMP 2 = %d\n", send_len);
//-------------------[调试]------------------------//
}
}
else
{//没在链表中没有找到目的IP需要重新组arp包才行
//printf("***************组ARP包\n");
int i = 0;
for(; i < 3; i++)
{
//printf("%s\n",dst_ip);
//比对到1网段的数据
if(strstr(dst_ip,"192.168.1") != 0)
{
printf("发送网段1arp包\n");
unsigned char arp_buf[42] = {
0xff,0xff,0xff,0xff,0xff,0xff,//目的mac广播的形式发出去等待目的IP恢复后覆盖
0x00,0x0c,0x29,0xfa,0x7c,0x9e,//源mac
0x08, 0x00,//协议类型
0, 1,//硬件类型
6,
4,
0, 1,//op
0x00,0x0c,0x29,0xfa,0x7c,0x9e,//源mac网卡1 ech0的MAC
192,168,1,88,//源IP是路由器1网段的网关通过它发送到2网段
0x00,0x00,0x00,0x00,0x00,0x00,//目的mac等待目的IP恢复后覆盖
0,0,0,0
//192,168,1,49,
};
int int_ip=0;
inet_pton(AF_INET, dst_ip, &int_ip);
unsigned char *intp=(char *)&int_ip;
arp_buf[38]=intp[0];
arp_buf[39]=intp[1];
arp_buf[40]=intp[2];
arp_buf[41]=intp[3];
int send_len = sendto(sockfd, arp_buf, sizeof(arp_buf), 0, (struct sockaddr *)&sll, sizeof(sll));
printf("send_len 11 = %d\n",send_len);
}
//网卡2ech1的MAC00:0c:29:fa:7c:a8
else if(strstr(dst_ip,"192.168.2") != 0)
{
printf("发送网段2arp包\n");
unsigned char arp_buf[42] = {
0xff,0xff,0xff,0xff,0xff,0xff,//目的mac
0x00,0x0c,0x29,0xfa,0x7c,0xa8,//源mac
0x08, 0x00,//协议类型
0, 1,//硬件类型
6,
4,
0, 1,//op
0x00,0x0c,0x29,0xfa,0x7c,0xa8,//源mac
192,168,2,89,//源IP是路由器2网段的网关通过它发送到1网段
0x00,0x00,0x00,0x00,0x00,0x00,//目的mac
192,168,2,100,
};
int send_len = sendto(sockfd, arp_buf, sizeof(arp_buf), 0, (struct sockaddr *)&sll, sizeof(sll));
printf("send_len 22 = %d\n",send_len);
}
if(arp_searcharpLink(arplink_head, dst_ip) == 1)
{
//1
//2C-4D-54-57-04-7F
if(strncmp("192.168.0.11", dst_ip, 9) == 0)
{
pthread_ip_buf->buf[0] = 0xA8;
pthread_ip_buf->buf[1] = 0x5E;
pthread_ip_buf->buf[2] = 0x45;
pthread_ip_buf->buf[3] = 0xC1;
pthread_ip_buf->buf[4] = 0x8B;
pthread_ip_buf->buf[5] = 0x99;
int send_len = sendto(sockfd, pthread_ip_buf->buf, pthread_ip_buf->my_buf_date_len, 0, (struct sockaddr *)&sll, sizeof(sll));
//-------------------[调试]------------------------//
//printf("****3次发ARP过程中检索到ICMP包 1 网段****\n");
// printf("send_len ICMP 1 = %d\n", send_len);
//-------------------[调试]------------------------//
}
//2
// 开发板MAC每次启动都会变化1C:59:74:81:4A:43
// 1C:59:74:81:4A:43
else if(strncmp("192.168.1.1", dst_ip, 9) == 0)
{
pthread_ip_buf->buf[0] = 0x1c;
pthread_ip_buf->buf[1] = 0x59;
pthread_ip_buf->buf[2] = 0x74;
pthread_ip_buf->buf[3] = 0x81;
pthread_ip_buf->buf[4] = 0x4A;
pthread_ip_buf->buf[5] = 0x43;
int send_len = sendto(sockfd, pthread_ip_buf->buf, pthread_ip_buf->my_buf_date_len, 0, (struct sockaddr *)&sll, sizeof(sll));
//-------------------[调试]------------------------//
//printf("****3次发ARP过程中检索到ICMP包 2 网段****\n");
// printf("send_len ICMP 2 = %d\n", send_len);
//-------------------[调试]------------------------//
}
break;
}
}
}
return;
}
}
//--------------------------------------------拿到网卡,开始检索对应网卡所有数据,对比【结束】------------------------------------------------------//
pthread_exit(NULL);
}
//*************************建IP包转发线程【结束】**********************************//
int main()
{
//创建原始套接字,接收发送方的网卡信息
sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if(sockfd<0)
{
perror("sockfd:");
return 0;
}
getinterface();//拿取网卡信息(虚拟机的所有网卡,包括回环网卡)
pthread_t pth;
pthread_create(&pth, NULL, callback1, NULL);//人机交互线程这里可以放在main里面
int len = 0;
char recv_buff[RECV_SIZE]="";//原始套接字数据包大约为1500个字节
ssize_t recv_len=0;
while(1)
{
//开始接收其他人的网卡信息
bzero(recv_buff,sizeof(recv_buff));
//[recv_len]设置成全局变量,让线程可以共用数据
recv_len = recvfrom(sockfd, recv_buff, sizeof(recv_buff), 0, NULL, NULL);
if(recv_len<=0||recv_len>RECV_SIZE)
{
perror("recvfrom");
continue;
}
//printf("链路层截取数据包长度 recv_len=%d\n",recv_len);
//MAC包类型
unsigned short mac_type = 0;
mac_type = ntohs( *((unsigned short *)(recv_buff + 12)));
if(mac_type == 0x0800)
{
//printf("-----------ip数据包------------\n");
unsigned char *ip_head = recv_buff + 14;
unsigned char dst_ip[16] ="";
inet_ntop(AF_INET, ip_head + 16, dst_ip, 16);
//IP包的类型
if(ip_head[9] == 1)
{
//printf("-----ICMP数据包\n");
//查找过滤IP链表中存在我们指定的目的IP吗
if(rou_searcharpLink(roulink_head, dst_ip) == 0)
{
static int i=0;
//-----------调试,打印原始套接字接收到的数据内容是否是空--------------------//
//printf("i=%d IP包中的目的IP = %d\n",++i, strlen(recv_buff + 30));
// printf("Rvfbuf=%p\n",recv_buff);
// int kk=0;
// while(kk<98)
// {
// printf("Rvfbuf[%d]=%d\n",kk,recv_buff[kk]);
// kk++;
// }
//----------------------------[调试]---------------------------------------//
usleep(1000);
ip_buf *recv = (ip_buf *)malloc(sizeof(ip_buf));
recv->my_buf_date_len = recv_len;
memcpy(recv->buf, recv_buff, recv_len);
//线程的创建放在满足它的条件中while循环满足就进来创建一个切记不要放到条件外面创建线程否则只会创建一个导致所有情况共用一个线程
pthread_t pth2;
//最后数据包是ICMP的整包
pthread_create(&pth2, NULL, callback3_ip, (void*)recv);
pthread_detach(pth2);
}
}
}
else if(mac_type == 0x0806)
{
arp_mac_ip * head_mac_ip = NULL;//保存目的MAC\IP的结构体,安全措施,防止栈空间释放导致给线程传参为空,失败
head_mac_ip = (arp_mac_ip *)malloc(sizeof(arp_mac_ip ));
unsigned char *arp_head = recv_buff + 14;
unsigned char * arp_src_mac = arp_head + 8;//跳过[4.硬件类型、5.协议类型、6.硬件地址长度、7.协议地址长度、8.OP拿到源MAC地址首地址信息]
unsigned char stc_mac[18] = "";
sprintf(stc_mac, "%02x:%02x:%02x:%02x:%02x:%02x", arp_src_mac[0],\
arp_src_mac[1],\
arp_src_mac[2], \
arp_src_mac[3],\
arp_src_mac[4], \
arp_src_mac[5]);
strcpy(head_mac_ip->stc_mac, stc_mac);
unsigned char src_ip[16] = "";
inet_ntop(AF_INET, arp_head + 14, src_ip, 16);//拿到源IP
strcpy(head_mac_ip->stc_ip, src_ip);
//-----------------------------------[调试]-----------------------------------//
//printf("-----------arp数据包------------\n");
//printf("arp 源mac%s\n",head_mac_ip->stc_mac);
//printf("arp 源IPsrc_ip = %s \n", src_ip);
//-----------------------------------[调试]-----------------------------------//
//线程中只保存源ARP的MAC、IP目的主机的MAC、IP在IP线程中指定写死
pthread_t pth1;
pthread_create(&pth1, NULL, callback2_arp, (void*)head_mac_ip);
pthread_detach(pth1);
}
}
return 0;
}