IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 原始套接字——发送UDP信息 -> 正文阅读

[网络协议]原始套接字——发送UDP信息

一、报文格式

信息传递:ubuntu---->windows
在这里插入图片描述

二、组包

①组MAC报头
在这里插入图片描述

//1.组mac报文头部
struct ether_header *eth_addr = (struct ether_header *)msg;
//赋值mac地址
memcpy(eth_addr->ether_dhost, dst_mac, 6);
memcpy(eth_addr->ether_shost, src_mac, 6);
//赋值帧类型
eth_addr->ether_type = htons(0x0800);

②组IP报头
所在位置/usr/include/netinet/ip.h>
头文件#include <netinet/ip.h>
在这里插入图片描述
在结构体定义时,若成员类型为u_int16_t则为2个字节,需要用htons函数。

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;

}

//2.组IP报文头部
struct iphdr *ip_hdr = (struct iphdr *)(msg+14);	//跳过mac头部
ip_hdr->verson = 4;							//赋值版本(IPv4);
ip_hdr->ihl = 5;							//赋值首部长度,IP头部单位是4比特,所以赋值5相当于5*4=20字节
ip_hdr->tos = 0;							//赋值服务类型
ip_hdr->tot_len = htons(20+8+data_len);		//赋值总长度(IP首部长度+IP数据长度(UDP+data))
ip_hdr->id = htons(0);						//赋值标识
ip_hdr->frag_off = htons(0);				//赋值标识、片偏移
ip_hdr->ttl = 128;							//赋值生产时间
ip_hdr->protocol = 17;						//赋值协议(UDP:17 TCP:6)
ip_hdr->check = htons(0);					//赋值首部校验和(先写0,后续赋值)
memcpy(&ip_hdr->saddr,src_ip,4);			//赋值源IP
memcpy(&ip_hdr->daddr,dst_ip,4);			//赋值目的IP
	
//校验需要等赋值好再覆盖才有效果
ip_hdr->check = checksum(ip_hdr,20);		//赋值校验

③组UDP报头
所在位置/usr/include/netinet/udp.h>
头文件#include <netinet/udp.h>
在这里插入图片描述
UDP校验方式:
1.在对UDP校验的时候需要在UDP报文之间加上伪头部,IP校验时不需要伪头部

注意:伪头部的源IP、目的IP必须和IP报文中源IP、目的IP一致。
如图所示:
在UDP前加伪头部,校验后在赋值回UDP结构体中的check;
在这里插入图片描述
创建伪首部结构体:

typedef struct
{
	u_int32_t saddr;	//源IP
	u_int32_t daddr;	//目的IP
	u_int8_t flag;		//标记(0)
	u_int8_t type;		//dup协议17
	u_int16_t len;		//长度
	
}WEIHDR;

伪头部校验:

unsigned char wei_head[256]="";
WEIHDR *wei_hdr = (WEIHDR *)wei_head;
memcpy(&wei_hdr->saddr,src_ip,4);
memcpy(&wei_hdr->daddr,dst_ip,4);
wei_hdr->flag = 0;
wei_hdr->type = 17;
wei_hdr->len = htons(8+data_len);
//将UDP拼接至伪头部后
memcpy(wei_head+12, udp_hdr, 8+data_len);	//将msg中的UDP头部信息以及DATA数据拷贝到伪头部后面
//校验UDP:伪头部+UDP头部+data部分
udp_hdr->check = checksum(wei_head, 12+8+data_len);

组UDP头部

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

④应用层数据

//发送数据
my_sendto(sockfd, "enp0s3", msg, 14+20+8+data_len);

三、代码

#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ether.h>
#include <pthread.h>
#include <sys/ioctl.h>			//ioctl头文件
#include <net/if.h>				//struct ifreq头文件
#include <netpacket/packet.h>	//struct sockaddr_ll头文件
#include <unistd.h>				//_exit头文件
#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头文件

typedef struct
{
	u_int32_t saddr;	//源IP
	u_int32_t daddr;	//目的IP
	u_int8_t flag;		//标记(0)
	u_int8_t type;		//dup协议17
	u_int16_t len;		//长度
	
}WEIHDR;


/*
参数说明:
sockfd:原始套接字
out:指定的网卡名称
msg:发送的消息(封装好的数字协议)
msg_len:长度
*/

void my_sendto(int sockfd, char *out, unsigned char *msg, int msg_len)
{
	//通过ioctl得到网络接口
	struct ifreq ethreq;
	strncpy(ethreq.ifr_name, "out", 16);
	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));
}

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("请输入要发送的消息:\n");
	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++;
	}
	
	
	unsigned char dst_mac[6]={0x80,0xC5,0xF2,0xB9,0x8C,0x03};	//目的mac地址(windows的mac))
	unsigned char src_mac[6]={0x08,0x00,0x27,0x2d,0x9b,0x84};	//源mac地址
	unsigned char src_ip[4]={192,168,199,208};				  	//源IP
	unsigned char dst_ip[4]={192,168,199,233};                  //目的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);
	memcpy(eth_addr->ether_shost, src_mac, 6);
	//赋值帧类型
	eth_addr->ether_type = htons(0x0800);
	
	//2.组IP报文头部
	struct iphdr *ip_hdr = (struct iphdr *)(msg+14);	//跳过mac头部
	ip_hdr->version = 4;						//赋值版本(IPv4);
	ip_hdr->ihl = 5;							//赋值首部长度,IP头部单位是4比特,所以赋值5相当于5*4=20字节
	ip_hdr->tos = 0;							//赋值服务类型
	ip_hdr->tot_len = htons(20+8+data_len);		//赋值总长度(IP首部长度+IP数据长度(UDP+data))
	ip_hdr->id = htons(0);						//赋值标识
	ip_hdr->frag_off = htons(0);				//赋值标识、片偏移
	ip_hdr->ttl = 128;							//赋值生产时间
	ip_hdr->protocol = 17;						//赋值协议(UDP:17 TCP:6)
	ip_hdr->check = htons(0);					//赋值首部校验和(先写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);
	memcpy(&wei_hdr->daddr,dst_ip,4);
	wei_hdr->flag = 0;
	wei_hdr->type = 17;
	wei_hdr->len = htons(8+data_len);
	//将UDP拼接至伪头部后
	memcpy(wei_head+12, udp_hdr, 8+data_len);	//将msg中的UDP头部信息以及DATA数据拷贝到伪头部后面
	//校验UDP:伪头部+UDP头部+data部分
	udp_hdr->check = checksum(wei_head, 12+8+data_len);
	
	//4.将data拷贝到UDP数据部分
	memcpy(udp_hdr+8,data,data_len);

	
	
	//发送数据
	my_sendto(sockfd, "enp0s3", msg, 14+20+8+data_len);


	//关闭原始套接字
	close(sockfd);
	
	return 0;
}

四、测试

运行
在这里插入图片描述

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-05-10 12:14:59  更:2022-05-10 12:15:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 2:04:45-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码