完成不同网段之间的通信,下面通过一个代码来具体演示路由器的工作过程
总结:这个项目耗时两天半完成,旨在理解原始套接字如何接收数据,发送数据。同时熟练使用sqlite3数据库
模拟两个不同网段进行通信,主要是进行ping的时候。
1.两个不同的网段再ping的时候,是ping不通的。
2.再ping其他网段的时候,首先是发送arp的请求包,然后再发送icmp数据包,arp来获取目的IP的MAC地址,如果能够找到这个mac地址,那么就能够组装到icmp数据包上,从而完成通信。
3.当发送icmp数据包的时候,到达我们所模拟的路由器的时候,查找arp缓存表中是否有对应IP的mac地址,如果有,那么就组装到目的mac上即可,没有就ping不同啦。
这个代码看看里面的内容就好,理解一下就行,实现起来硬件也需要进行改动,因为虚拟机和windows是同一个网段上的,本来就可以直接ping通,所以需要再加上两个网卡,将window上的网关改为虚拟机一端的ip,然后另两个端口再改成不一样的。。。
#include
#include
#include
#include
#include
#include //recvfrom
#include //ETH_P_ALL
#include //inet_ntop
#include //ifreq
#include //ioctl
#include //sockaddr_ll
#include
#include
#include
void show(void);//菜单函数
void * my_fun(void * arg);//线程的回调函数
//全局变量定义,方便线程使用
int sockfd; //套接字
int ret; //调用数据库是的返回值
char * errmsg;
sqlite3 *db;
char ** dbResult;
int nrow;
int ncolumn;
int main()
{
//创建套接字,原始套接字
sockfd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
if(sockfd > 0)
{
printf("原始套接字创建成功:%d\n",sockfd);
}
//**************************************************************************************************************************************************
//数据库的打开使用
//**************************************************************************************************************************************************
//打开数据库
ret = sqlite3_open("ip.db",&db);
//如果ret==SQLITE_OK 那么就是这一条语言成功执行了
if(ret == SQLITE_OK)
{
printf("防火墙数据库打开成功!\n");
}
else
{
printf("数据库打开失败!\n");
}
ret = sqlite3_open("mac.db",&db);
if(ret == SQLITE_OK)
{
printf("ARP缓存数据库打开成功!\n");
}
else
{
printf("数据库打开失败!\n");
}
//使用非回调办法增加一张数据表
sqlite3_get_table(db,"create table persons (IP text primary key);",&dbResult,&nrow,&ncolumn,&errmsg);
// arp缓存的数据库
sqlite3_get_table(db,"create table person (ip text primary key,mac text);",&dbResult,&nrow,&ncolumn,&errmsg);
//使用回调方法去增加数据
char str[128]="";
printf("防火墙中的IP有:\n");
//想要添加,从这个地方就可以添加
char get_ip[16]="192.168.7.5";
sprintf(str,"insert into persons values('%s');",get_ip);
sqlite3_get_table(db,str,&dbResult,&nrow,&ncolumn,&errmsg);
//使用非回调函数查询数据
ret == sqlite3_get_table(db,"select * from persons;",&dbResult,&nrow,&ncolumn,&errmsg);
if(ret==SQLITE_OK)
{
int i,j,index;
index=ncolumn;
for(i=0;i<nrow;i++)
{
for(j=0;j<ncolumn;j++)
{
printf(" %s ",dbResult[index]);
index++;
}
printf("\n");
}
sqlite3_free_table(dbResult);
}
//选择标志位
int chose = 0;
show();//菜单展示
int pthread_flag = 0;
while(1)
{
printf("请输入您的选择:");
scanf("%d",&chose);
getchar();
if(1 == chose)
{
char add_ip[32]="";
printf("请输入添加的黑名单IP:格式如:192.168.1.1\n");
fgets(add_ip,sizeof(add_ip),stdin);
add_ip[strlen(add_ip)-1]='\0';
//printf("获得到了:%s\n",add_ip);
//格式校验
int a=0,b=0,c=0,d=0;
sscanf(add_ip,"%d.%d.%d.%d",&a,&b,&c,&d);
if((a >= 0 && a <= 255) && (b >= 0 && b <= 255) && (c >= 0 && c <= 255) && (d >= 0 && d<= 255))
{
//写入数据库
char sqlite3_ip[64]="";
sprintf(sqlite3_ip,"insert into persons values('%s');",add_ip);
sqlite3_get_table(db,sqlite3_ip,&dbResult,&nrow,&ncolumn,&errmsg);
printf("数据库已更新!\n");
}
else
{
printf("您输入有误\n");
}
}
else if(2 == chose)
{
ret == sqlite3_get_table(db,"select * from persons;",&dbResult,&nrow,&ncolumn,&errmsg);
if(ret==SQLITE_OK)
{
int i,j,index;
index=ncolumn;
for(i=0;i<nrow;i++)
{
for(j=0;j<ncolumn;j++)
{
printf(" %s ",dbResult[index]);
index++;
}
printf("\n");
}
sqlite3_free_table(dbResult);
}
}
else if(3 == chose)
{
char delete_ip[32]="";
printf("请输入删除的黑名单IP:格式如:192.168.1.1\n");
fgets(delete_ip,sizeof(delete_ip),stdin);
delete_ip[strlen(delete_ip)-1]='\0';
printf("获得到了:%s\n",delete_ip);
//格式校验
int a=0,b=0,c=0,d=0;
sscanf(delete_ip,"%d.%d.%d.%d",&a,&b,&c,&d);
if((a >= 0 && a <= 255) && (b >= 0 && b <= 255) && (c >= 0 && c <= 255) && (d >= 0 && d<= 255))
{
//写入数据库
char sqlite3_ip[64]="";
sprintf(sqlite3_ip,"delete from persons where IP='%s';",delete_ip);
sqlite3_get_table(db,sqlite3_ip,&dbResult,&nrow,&ncolumn,&errmsg);
printf("数据库已更新!\n");
}
else
{
printf("您输入有误\n");
}
}
else if(4 == chose)
{
if(0 == pthread_flag )
{
printf("路由器已运行!\n");
pthread_flag++;
pthread_t pth;
pthread_create(&pth,NULL,my_fun,NULL);
pthread_detach(pth);
}
else
{
printf("路由器正在运行,请不要重复开启!\n");
}
}
else if(5 == chose)
{
//在路由器开启之前,发送arp广播数据包
//两个端口均要发送广播消息
printf("arp广播发送!\n");
int i = 1;
for(i = 1;i < 255 ;i++)
{
//ens33网口组arp的请求包
unsigned char buf_all_1[42]={
0xff,0xff,0xff,0xff,0xff,0xff,//目的mac广播
0x00,0x0c,0x29,0xf3,0x98,0x3e,//源mac
0x08,0x06,//帧类型
0x00,0x01,//硬件类型
0x08,0x00,//协议类型
6,
4,
0x00,0x01,//op
0x00,0x0c,0x29,0xf3,0x98,0x3e,//发送端mac
192,168,7,2,//发送端ip
0x00,0x00,0x00,0x00,0x00,0x00,
192,168,7,i
};
//获取网络接口类型
struct ifreq ethreq3;
strncpy(ethreq3.ifr_name, "ens33", IFNAMSIZ);
ioctl(sockfd, SIOCGIFINDEX, ðreq3);
//定义一个网络接口变量
struct sockaddr_ll sll3;
bzero(&sll3, sizeof(sll3));
sll3.sll_ifindex = ethreq3.ifr_ifindex;
//发送
sendto(sockfd,buf_all_1,42,0,(struct sockaddr *)&sll3,sizeof(sll3));
//ens33网口组arp的请求包
unsigned char buf_all_2[42]={
0xff,0xff,0xff,0xff,0xff,0xff,//目的mac广播
0x00,0x0c,0x29,0xf3,0x98,0x48,//源mac
0x08,0x06,//帧类型
0x00,0x01,//硬件类型
0x08,0x00,//协议类型
6,
4,
0x00,0x01,//op
0x00,0x0c,0x29,0xf3,0x98,0x48,//发送端mac
192,168,8,2,//发送端ip
0x00,0x00,0x00,0x00,0x00,0x00,
192,168,8,i
};
//获取网络接口类型
struct ifreq ethreq4;
strncpy(ethreq4.ifr_name, "ens33", IFNAMSIZ);
ioctl(sockfd, SIOCGIFINDEX, ðreq4);
//定义一个网络接口变量
struct sockaddr_ll sll4;
bzero(&sll4, sizeof(sll4));
sll4.sll_ifindex = ethreq4.ifr_ifindex;
//发送
sendto(sockfd,buf_all_2,42,0,(struct sockaddr *)&sll4,sizeof(sll4));
}
}
else if(6 == chose)
{
ret == sqlite3_get_table(db,"select * from person;",&dbResult,&nrow,&ncolumn,&errmsg);
if(ret==SQLITE_OK)
{
int i,j,index;
index=ncolumn;
for(i=0;i<nrow;i++)
{
for(j=0;j<ncolumn;j++)
{
printf(" %s ",dbResult[index]);
index++;
}
printf("\n");
}
//sqlite3_free_table(dbResult);
}
}
else if(9 == chose)
{
show();
}
else if(0 == chose)
{
//关闭套接字
close(sockfd);
//关闭数据库
sqlite3_close(db);
printf("系统结束!\n");
exit(0);
}
else
{
printf("对不起,您的输入有误");
}
}
//**************************************************************************************************************************************************
//接收数据包,并进行解析
//**************************************************************************************************************************************************
//接收所有的数据
//关闭套接字
close(sockfd);
//关闭数据库
sqlite3_close(db);
return 0;
}
void show(void)
{
printf("************************************************\n");
printf("**********路由器黑名单管理系统******************\n");
printf("**************1.添加黑名单IP********************\n");
printf("**************2.显示所有黑名单******************\n");
printf("**************3.删除黑名单**********************\n");
printf("**************4.开启路由器**********************\n");
printf("**************5.刷新ARP表缓存*******************\n");
printf("**************6.显示所有ARP表缓存***************\n");
printf("**************9.重新打印菜单********************\n");
printf("**************0.退出此系统**********************\n");
printf("************************************************\n");
}
void * my_fun(void * arg)
{
while(1)
{
unsigned char buf[1500] = "";
ssize_t len = recvfrom(sockfd,buf,sizeof(buf),0,NULL,NULL);
unsigned char det_mac[18] = "";
unsigned char src_mac[18] = "";
unsigned short mac_type = ntohs(*(unsigned short *)(buf + 12));
//printf("mac_type=\n", mac_type);
sprintf(det_mac,"%02x:%02x:%02x:%02x:%02x:%02x",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5]);
sprintf(src_mac,"%02x:%02x:%02x:%02x:%02x:%02x",buf[6],buf[7],buf[8],buf[9],buf[10],buf[11]);
//printf("[%3ld]MAC:[%s]->[%s]:%#x\n",len,src_mac,det_mac,mac_type);
if(mac_type == 0x0800)
{
unsigned char *ip_buf = buf + 14;
//源ip、目的ip
char src_ip[16] = "";
char dst_ip[16] = "";
inet_ntop(AF_INET,(void *)ip_buf+12,src_ip,16);
inet_ntop(AF_INET,(void *)ip_buf+16,dst_ip,16);
//设置标志为
int flag=0;
char find_ip[64]="";
char find_ip2[64]="";
sprintf(find_ip,"select * from persons where IP='%s';",src_ip);
sprintf(find_ip2,"select * from persons where IP='%s';",dst_ip);
ret == sqlite3_get_table(db,find_ip,&dbResult,&nrow,&ncolumn,&errmsg);
if(ret == SQLITE_OK)
{
int i,j,index;
index=ncolumn;
for(i=0;i<nrow;i++)
{
for(j=0;j<ncolumn;j++)
{
//printf(" %s ",dbResult[index]);
if(strcmp(src_ip,dbResult[index])==0)
{
flag ++;
}
index++;
}
}
sqlite3_free_table(dbResult);
if(flag != 0)
{
printf("防火墙发现含有隐患的IP,已将其拦截! \n");
continue;
}
}
flag = 0;//标志位归0
ret == sqlite3_get_table(db,find_ip2,&dbResult,&nrow,&ncolumn,&errmsg);
if(ret == SQLITE_OK)
{
int i,j,index;
index=ncolumn;
for(i=0;i<nrow;i++)
{
for(j=0;j<ncolumn;j++)
{
//printf(" %s ",dbResult[index]);
if(strcmp(dst_ip,dbResult[index])==0)
{
flag ++;
}
index++;
}
}
sqlite3_free_table(dbResult);
if(flag != 0)
{
printf("防火墙发现含有隐患的IP,已将其拦截! \n");
continue;
}
}
flag = 0; //柏标志为清0
if(ip_buf[9] == 1)
{
//ICMP
//通过目的ip找到目的MAC
char find_mac[18]="";
ret == sqlite3_get_table(db,"select * from person;",&dbResult,&nrow,&ncolumn,&errmsg);
if(ret==SQLITE_OK)
{
int i,j,index;
index=ncolumn;
for(i=0;i<nrow;i++)
{
for(j=0;j<ncolumn;j++)
{
if(strcmp(dst_ip,dbResult[index]) == 0)
{
memcpy(find_mac,dbResult[index+1],18);
}
index++;
}
}
}
//将获得到的目的MAC 进行解包
unsigned char find_buf_one[6]="";
sscanf(find_mac,"%02x:%02x:%02x:%02x:%02x:%02x",(unsigned int *)&find_buf_one[0],(unsigned int *)&find_buf_one[1],(unsigned int *)&find_buf_one[2],(unsigned int *)&find_buf_one[3],(unsigned int *)&find_buf_one[4],(unsigned int *)&find_buf_one[5]);
if(0 == strcmp(src_mac,"80:fa:5b:26:d4:10"))
{ //printf("MAC:[%s]->[%s]\n",src_mac,det_mac);
//printf("IP:[%s]->[%s]\n",src_ip,dst_ip);
//根据IP判断防火墙
//建立数据库,在数据库中遍历
//查询数据,如果没有此ip则创建一个数据,如果有判断其mac是否更改
//sqlite3_exec(db,"insert into persons values(arp_ip,arp_mac);",NULL,NULL,&errmsg);
//printf("协议类型:ICMP\n");
//printf("\n");
//在数据库中找到目的IP对应的mac组装到发送的位置
//网关到A53
unsigned char buf_34[1500] = "";
//目的MAC:00:53:50:00:2c:59
buf[0] = find_buf_one[0];
buf[1] = find_buf_one[1];
buf[2] = find_buf_one[2];
buf[3] = find_buf_one[3];
buf[4] = find_buf_one[4];
buf[5] = find_buf_one[5];
//源MAC 00:0c:29:f3:98:48
buf[6] = 0x00;
buf[7] = 0x0c;
buf[8] = 0x29;
buf[9] = 0xf3;
buf[10] = 0x98;
buf[11] = 0x48;
//memcpy(buf_34,buf,strlen(buf)+1);
//获取网络接口类型
struct ifreq ethreq;
strncpy(ethreq.ifr_name, "ens38", IFNAMSIZ);
ioctl(sockfd, SIOCGIFINDEX, ðreq);
//定义一个网络接口变量
struct sockaddr_ll sll;
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ethreq.ifr_ifindex;
//发送
sendto(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&sll,sizeof(sll));
}
if(0 == strcmp(src_mac,"00:53:50:00:2c:59"))
{
//printf("----------A53----------\n");
//printf("MAC:[%s]->[%s]\n",src_mac,det_mac);
//printf("IP:[%s]->[%s]\n",src_ip,dst_ip);
//printf("协议类型:ICMP\n");
//printf("\n");
//2->1
unsigned char buf_21[1500] = "";
//目的MAC 80:fa:5b:26:d4:10
buf[0] = find_buf_one[0];
buf[1] = find_buf_one[1];
buf[2] = find_buf_one[2];
buf[3] = find_buf_one[3];
buf[4] = find_buf_one[4];
buf[5] = find_buf_one[5];
//源MAC 00:0c:29:f3:98:3e
buf[6] = 0x00;
buf[7] = 0x0c;
buf[8] = 0x29;
buf[9] = 0xf3;
buf[10] = 0x98;
buf[11] = 0x3e;
//memcpy(buf_34,buf,strlen(buf)+1);
//获取网络接口类型
struct ifreq ethreq;
strncpy(ethreq.ifr_name, "ens33", IFNAMSIZ);
ioctl(sockfd, SIOCGIFINDEX, ðreq);
//定义一个网络接口变量
struct sockaddr_ll sll;
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ethreq.ifr_ifindex;
//发送
sendto(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&sll,sizeof(sll));
}
}
}
else if(mac_type == 0x0806)
{
unsigned char *ip_buf = buf + 14;
//源ip、目的ip
char src_ip[16] = "";
char dst_ip[16] = "";
inet_ntop(AF_INET,(void *)ip_buf+14,src_ip,16);
inet_ntop(AF_INET,(void *)ip_buf+24,dst_ip,16);
//将接收RP的应答包,将其ip与mac保存在数据库中,方便组装icmp
unsigned short arp_accept = ntohs(*(unsigned short * )(ip_buf+6));
if(2 == arp_accept)
{
int mac_flag = 0;
//再插入数据库之前,先判断有没有一样的IP和MAC
ret == sqlite3_get_table(db,"select * from person;",&dbResult,&nrow,&ncolumn,&errmsg);
if(ret==SQLITE_OK)
{
int i,j,index;
index=ncolumn;
for(i=0;i<nrow;i++)
{
for(j=0;j<ncolumn;j++)
{
if(strcmp(src_ip,dbResult[index])== 0)
{
if(strcmp(src_mac,dbResult[index+1])==0)
{
printf("数据库中已有此arp缓存,无需添加\n");
}
else
{
printf("IP对应的mac更改了!\n");
char update_buf[128]="";
sprintf(update_buf,"updata person set mac = '%s' where ip = '%s';",src_mac,src_ip);
}
}
else
{
//取出其应答包的源MAC和源IP
char str[128]="";
sprintf(str,"insert into person values('%s','%s');",src_ip,src_mac);
sqlite3_get_table(db,str,&dbResult,&nrow,&ncolumn,&errmsg);
}
index++;
}
}
}
}
}
}
}