arp,udp,icmp编码实现理解

2023-11-19

一直关注tcp/ip的底层协议栈,终于有了大概的了解,通过ntytcp了解tcp相关的底层实现,发现除了tcp协议栈相关的东西,还有udp,arp,icmp(ping命令相关),以及通过netmap对网卡数据进行接收的相关基础知识点,幸好,听过king老师相关的课程,这里就简单的做一些整理。

1:概念介绍:

1:arp: 地址解析协议(ip层/数据链路层)

​ 维护了计算机ip和mac地址(物理地址)的对应关系。 (因为网络通信时实际传输的是“帧”,帧里面是有目标主机的MAC地址的)

​ ==》在TCP/IP模型中,ARP协议属于IP层;在OSI模型中,ARP协议属于链路层。

    ==》局域网内维护ip和mac地址的对应关系

    ==》如果是外网,路由器网关作为中转,网关直连的网卡上请求对方网关的MAC地址,然后网关通过IP层查询目标主机,获取mac地址发送。

    ==》参考连接:https://blog.csdn.net/jiejiemcu/article/details/88406088

2:icmp:网络控制消息协议(网络层)

​ 为了辅助IP 协议,交换各种各样的控制信息而被制造出来的。 属于网络层协议(IP,icmp)

​ 主要功能:差错通知和信息查询

​ 例如:ping命令,traceroute命令

3:udp:用户数据报协议(传输层)

​ UDP是基于IP的简单协议,不可靠的协议。

​ udp传输速度快,可以用在下载,游戏方向。

​ 用户可以自己实现可靠的数据传输,通过增加确认和重传机制,实现udp的可靠传输。

2:协议数据结构

1:根据协议栈分析数据的结构:

在这里插入图片描述

根据图形理解:

​ 发送数据时,其实就是应用层我们的数据外层以此包上各个协议栈的数据。

​ 而接受数据时,其实就是从链路层开始一层层解析最外层的数据,获得最后特定协议特定数据模块

2:以太帧的结构

以太帧起始部分由前同步码和帧开始定界符组成,后面紧跟着一个以太网报头,以 MAC 地址说明目的地址和源地址。以太帧的中部是该帧负载的包含其他协议报头的数据包,如 IP 协议。

以太帧由一个 32 位冗余校验码结尾,用于检验数据传输是否出现损坏。以太帧结构如图所示。

在这里插入图片描述

注意:其中的数据块长度最小为 46 字节,最大为 1500 字节。

3:arp协议的分析

​ arp属于网络层,就是给arp数据块加上网络层的arp头信息,再加上数据链路层头信息。

在这里插入图片描述

arp报文格式:

在这里插入图片描述

相关代码结构定义如下:

#define ETH_ALEN	6
//以太网协议头的定义
struct ethhdr {
	unsigned char h_dest[ETH_ALEN];
	unsigned char h_source[ETH_ALEN];
	unsigned short h_proto;     //arp 为0x0806   ip数据包为 0x0800
};
//arp协议头的定义
struct arphdr {
	unsigned short h_type;    //目标网卡的硬件类型 1为以太网地址
	unsigned short h_proto;   //协议类型 0x0800表示ip协议
	unsigned char h_addrlen;  //硬件地址长度 如以太网地址长度为6,对应硬件类型
	unsigned char protolen;   //协议地址长度 如arp,ip协议,值是4
	unsigned short oper;      // arp请求:1 arp应答:2 rarp请求:3 rarp应答4
	unsigned char smac[ETH_ALEN];  //源mac地址
	unsigned int sip;			   //源ip地址
	unsigned char dmac[ETH_ALEN];  //目标mac地址
	unsigned int dip;			   //目标ip地址
};

//arp的整体包,
struct arppkt {
	struct ethhdr eh;
	struct arphdr arp;
};

如果用wireshark抓包分析,参考网络上的图:
在这里插入图片描述
在这里插入图片描述

4:ICMP协议:控制报文协议

ICMP 协议用于在 IP 主机和路由器之间传递控制消息,描述网络是否通畅、主机是否可达、路由器是否可用等网络状态。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E07abpj1-1625752926028)(C:\Users\yun68\AppData\Roaming\Typora\typora-user-images\image-20210708212325165.png)]

icmp协议位于传输层:

struct ethhdr {
	unsigned char h_dest[ETH_ALEN];		//目的mac地址
	unsigned char h_source[ETH_ALEN];	//源mac地址
	unsigned short h_proto;				//上一层协议类型,如0x0800代表上一层是IP协议,0x0806为arp
};

struct iphdr {
	unsigned char version; 	//4 位IP版本号+4位首部长度
	unsigned char tos;		//8位服务类型TOS
	unsigned short tot_len; //16位IP包总长度(字节)
	unsigned short id;			//16位标识, 用于辅助IP包的拆装
	unsigned short flag_off;  	//3位标志位+13位偏移位, 也是用于IP包的拆装
	unsigned char ttl;			//8位IP包生存时间 TTL
	unsigned char protocol;		//8位协议 (TCP, UDP 或其他)
	unsigned short check;		//16位IP首部校验和,最初置零,等所有包头都填写正确后,计算并替换.
	unsigned int saddr;			//32位源IP地址
	unsigned int daddr;			//32位目的IP地址
};
struct icmphdr {
	unsigned char type;		//标识ICMP报文的类型,分为两种查询报文和差错报文
	unsigned char code;		//标识对应ICMP报文的代码,于type共同表示报文类型
	unsigned short check;   //ICMP报文数据部分在内的整个ICMP数据报的校验和 从TYPE开始,直到最后一位用户数据,如果为字节数为奇数则补充一位
	unsigned short identifier;	//识别号(一般用进程号作为识别号), 用于匹配ECHO和ECHO REPLY包
	unsigned short seq;			//报文序列号, 用于标记ECHO报文顺序
	unsigned char data[32];		//时间戳
};
//icmp协议包的定义
struct icmppkt {
	struct ethhdr eh;
	struct iphdr ip;
	struct icmphdr icmp;
};

5:UDP协议:用户数据报协议

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qqFKtafN-1625752926029)(C:\Users\yun68\AppData\Roaming\Typora\typora-user-images\image-20210708213734891.png)]

#define ETH_ALEN	6
struct ethhdr {
	unsigned char h_dest[ETH_ALEN];
	unsigned char h_source[ETH_ALEN];
	unsigned short h_proto;
};

struct iphdr {
	unsigned char version;
	unsigned char tos;
	unsigned short tot_len;
	unsigned short id;
	unsigned short flag_off;
	unsigned char ttl;
	unsigned char protocol;
	unsigned short check;
	unsigned int saddr;
	unsigned int daddr;
};
//共8个字节
struct udphdr {
	unsigned short source;  // 源端口号16bit
	unsigned short dest;	// 目的端口号16bit
	unsigned short len;		// 数据包长度16bit
	unsigned short check;	// 校验和16bit
};
//udp数据包
struct udppkt {
	struct ethhdr eh;
	struct iphdr ip;
	struct udphdr udp;
	unsigned char body[128];
};

3:测试抓包

1:arp抓包测试:

2:icmp抓包测试:

3:udp抓包测试:

4:tcp/ip抓包测试:

4:编码实现

用netmap和相关的自定义协议包实现对arp,udp,icmp报文的接受。

void echo_arp_pkt(struct arppkt *arp, struct arppkt *arp_rt, char *hmac) {
	memcpy(arp_rt, arp, sizeof(struct arppkt));

	memcpy(arp_rt->eh.h_dest, arp->eh.h_source, ETH_ALEN);
	str2mac(arp_rt->eh.h_source, hmac);
	arp_rt->eh.h_proto = arp->eh.h_proto;

	arp_rt->arp.h_addrlen = 6;
	arp_rt->arp.protolen = 4;
	arp_rt->arp.oper = htons(2);
	str2mac(arp_rt->arp.smac, hmac);
	arp_rt->arp.sip = arp->arp.dip;
	memcpy(arp_rt->arp.dmac, arp->arp.smac, ETH_ALEN);
	arp_rt->arp.dip = arp->arp.sip;
}


void echo_udp_pkt(struct udppkt *udp, struct udppkt *udp_rt) {
	memcpy(udp_rt, udp, sizeof(struct udppkt));
	memcpy(udp_rt->eh.h_dest, udp->eh.h_source, ETH_ALEN);
	memcpy(udp_rt->eh.h_source, udp->eh.h_dest, ETH_ALEN);
	udp_rt->ip.saddr = udp->ip.daddr;
	udp_rt->ip.daddr = udp->ip.saddr;
	udp_rt->udp.source = udp->udp.dest;
	udp_rt->udp.dest = udp->udp.source;
}

unsigned short in_cksum(unsigned short *addr, int len)
{
	register int nleft = len;
	register unsigned short *w = addr;
	register int sum = 0;
	unsigned short answer = 0;

	while (nleft > 1)  {
		sum += *w++;
		nleft -= 2;
	}

	if (nleft == 1) {
		*(u_char *)(&answer) = *(u_char *)w ;
		sum += answer;
	}
	sum = (sum >> 16) + (sum & 0xffff);	
	sum += (sum >> 16);			
	answer = ~sum;
	return (answer);
}

void echo_icmp_pkt(struct icmppkt *icmp, struct icmppkt *icmp_rt) {

	memcpy(icmp_rt, icmp, sizeof(struct icmppkt));

	icmp_rt->icmp.type = 0x0; //
	icmp_rt->icmp.code = 0x0; //
	icmp_rt->icmp.check = 0x0;

	icmp_rt->ip.saddr = icmp->ip.daddr;
	icmp_rt->ip.daddr = icmp->ip.saddr;

	memcpy(icmp_rt->eh.h_dest, icmp->eh.h_source, ETH_ALEN);
	memcpy(icmp_rt->eh.h_source, icmp->eh.h_dest, ETH_ALEN);

	icmp_rt->icmp.check = in_cksum((unsigned short*)&icmp_rt->icmp, sizeof(struct icmphdr));
}
#define PROTO_IP	0x0800
#define PROTO_ARP	0x0806

int main() {
	struct ethhdr *eh;
	struct pollfd pfd = {0};
	struct nm_pkthdr h;
	unsigned char *stream = NULL;

	struct nm_desc *nmr = nm_open("netmap:eth0", NULL, 0, NULL);
	if (nmr == NULL) {
		return -1;
	}

	pfd.fd = nmr->fd;
	pfd.events = POLLIN;

	while (1) {
		int ret = poll(&pfd, 1, -1);
		if (ret < 0) continue;
		
		if (pfd.revents & POLLIN) {
			stream = nm_nextpkt(nmr, &h);
            //解析以太网头
			eh = (struct ethhdr*)stream;
			//根据以太网头中的类型依次处理
			if (ntohs(eh->h_proto) == PROTO_IP) {

				struct udppkt *udp = (struct udppkt*)stream;
                //ip头中检验udp协议和icmp协议
				if (udp->ip.protocol == PROTO_UDP) {

					struct in_addr addr;
					addr.s_addr = udp->ip.saddr;

					int udp_length = ntohs(udp->udp.len);
					printf("%s:%d:length:%d, ip_len:%d --> ", inet_ntoa(addr), udp->udp.source, 
						udp_length, ntohs(udp->ip.tot_len));

					udp->body[udp_length-8] = '\0';
					printf("udp --> %s\n", udp->body);
#if 1
					struct udppkt udp_rt;
					echo_udp_pkt(udp, &udp_rt);
					nm_inject(nmr, &udp_rt, sizeof(struct udppkt));
#endif
				} else if (udp->ip.protocol == PROTO_ICMP) {
					
					struct icmppkt *icmp = (struct icmppkt*)stream;

					printf("icmp ---------- --> %d, %x\n", icmp->icmp.type, icmp->icmp.check);
					if (icmp->icmp.type == 0x08) {
						struct icmppkt icmp_rt = {0};
						echo_icmp_pkt(icmp, &icmp_rt);

						//printf("icmp check %x\n", icmp_rt.icmp.check);
						nm_inject(nmr, &icmp_rt, sizeof(struct icmppkt));
					}
					
				} else if (udp->ip.protocol == PROTO_IGMP) {

				} else {
					printf("other ip packet");
				}
				
			}  else if (ntohs(eh->h_proto) == PROTO_ARP) {

				struct arppkt *arp = (struct arppkt *)stream;
				struct arppkt arp_rt;

				if (arp->arp.dip == inet_addr("192.168.2.217")) {
					echo_arp_pkt(arp, &arp_rt, "00:50:56:33:1c:ca");
					nm_inject(nmr, &arp_rt, sizeof(struct arppkt));
				}
			}
		} 
	}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

arp,udp,icmp编码实现理解 的相关文章

  • 字节跳动最爱考的前端面试题:CSS 基础

    注意 每道题前面出现的 xx 数字代表这道题出现的频次 此 CSS 基础是基于 30 篇前端面经整理出的问题和对应的回答 参考链接等 文章内容为拿到 Offer 的本人整理 2 写代码 css div 垂直水平居中 并完成 div 高度永远
  • 【Ubuntu+python2】编译并运行PyQt5程序

    文章目录 前言 一 环境搭建 1 下载sip和PyQt5 2 移除本机自带sip 二 解压编译 1 sip解压编译 2 PyQt5解压编译 make j4编译过程出现报错error waitForEvents is not a member

随机推荐

  • springBoot 统一返回结果类

    统一返回结果类有很多 个人感觉这种好用 记录一下 为以后 copy 准备 package com xxxx pro common import lombok Data import java util ArrayList import ja
  • 安装cmake过程出错:Error when bootstrapping CMake: Cannot find a C++ compiler that supports both C++11 and ...

    Error when bootstrapping CMake Cannot find a C compiler that supports both C 11 and the specified C flags 1 没有装gcc 和 g 2
  • javaFX环境配置

    javaFX环境配置 JavaFx在JDK1 8之后从JDK中脱离了出来 由于明天开始今天决定复现一下课本中出现的程序 哪料环境都被苟了一手 其实配置过程很简单 主要分成三个步骤 第一步 官网下载系统对应的JDK javaFX依赖包 第二步
  • 字符串转换时间,时区问题

    1 字符串转化为时间 解决了关于相差8个小时的时区问题 NSString dateStr 2012 05 17 11 23 23 NSDateFormatter format NSDateFormatter alloc init forma
  • TP5使用predis

    1 安装 composer require predis predis 2 使用 use use Predis Client class Index 使用predis public function index 配置连接的IP 端口 以及相
  • 【数据结构】树的遍历

    Ctrl AC 一起 AC 目录 树有三种表示方法 树的遍历有三种 结点结构 树的前序遍历递归版 树的后序遍历递归版 按前序遍历顺序建立一颗树 树的层次遍历 树有三种表示方法 双亲表示法 孩子表示法和兄弟表示法 这里我们使用指针式的孩子表示
  • Unity震撼首发,最新一代高清数字人短片《Enemies》

    我们屡获殊荣的 Demo 团队又一次在 异教徒 The Heretic 累积了超 400 万观众 的基础上取得了进展 推出了 Enemies 一支全新的电影式预告片 以 4K 分辨率的实时渲染来展示眼睛 头发和皮肤渲染等方面的重大突破 创建
  • 大逃杀显示服务器崩溃,绝地求生大逃杀崩溃问题汇总 崩溃问题及完美解决方案...

    国外的游戏在中国的电脑和配置上玩起来都会有点卡顿的 闪退或者崩溃的情况都是常有的 那么在玩游戏中崩溃了怎么办呢 大家赶紧来看看绝地求生大逃杀崩溃问题汇总 崩溃问题及完美解决方案 前提准备 关闭杀毒 游戏使用BE反作弊系统 杀毒软件可能会拦截
  • 网址,URL,域名,IP地址,DNS,域名解析,只为你能成功访问

    计算机网络 计算机专业必修科目之一 是专业课 但是 很多的人除了进入浏览器 输入网址 然后回车就看到页面了 然后往下操作 基本没怎么关注过它的原理 但是 你回车之后 网络内部真的是发生了很多的事情 只是你不知道 今天 我就带大家解开网络的神
  • Android平台GB28181设备接入侧(编码前

    在之前 我有写过Android平台GB28181设备接入模块的好多blog 包括参数设置 功能支持与扩展等 以数据接入为例 支持的数据类型涉及编码前 编码后或直接流数据 RTSP或RTMP流 可用于如智能监控 智慧零售 智慧教育 远程办公
  • HTTPRunner学习笔记

    HttpRunner 是一款面向 HTTP S 协议的通用测试框架 只需编写维护一份 YAML JSON 脚本 即可实现自动化测试 性能测试 线上监控 持续集成等多种测试需求 在yaml文件中组织测试用例 在命令行执行 参考 HTTPRun
  • Wazuh agent的安装、注册与配置管理

    部署Wazuh Agent常用的环境变量 Linux系统下的常用环境变量 WAZUH MANAGER WAZUH MANAGER PORT WAZUH PROTOCOL WAZUH REGISTRATION SERVER WAZUH REG
  • vue 3 第三十四章:nextTick

    nextTick是Vue3中的一个非常有用的函数 它可以在下一次DOM更新循环结束后执行回调函数 这个函数可以用来解决一些异步更新视图的问题 例如在修改数据后立即获取更新后的DOM节点 以下是一个简单的示例
  • BUUCTF【Web】Exec(命令执行漏洞)

    在进入靶场后发现窗口ping 猜测可能是SQL注入 也有可能是命令执行漏洞 我们先随便ping一下本机地址127 0 0 1 发现有回显 PING 127 0 0 1 127 0 0 1 56 data bytes 既然有回显那么就可以确定
  • 前端做excel的录入解析,将excel的数据传给后端,显示在页面上。

    具体的流程如图所示 1 点击excel录入按钮 2 打开弹框 3 点击上传按钮 会自动打开计算机本地文件 选择想上传的文件 点击打开 4 会将excel的数据解析成一个表格 可以在表格中做删除操作 点击确定 5 将excel的人员与系统中的
  • Redis cluster集群搭建

    通过三台虚拟机搭建一个3主3从的cluster集群 1 安装 gcc c 依赖包 yum install gcc c 2 下载安装包并解压 wget https download redis io releases redis 6 0 9
  • Max Flow P

    Max Flow P 题目传送门 题目大意 题目大意就是给你一棵树 再给你K次操作将x到y的所有点的值都加1 然后输出所有点值的最大值 思路 这一题如果用暴力的话从范围来看肯定会T tle 所以我们要考虑用差分的思想去做 代码 先看代码 i
  • L2-1 分而治之PTA

    分而治之 各个击破是兵家常用的策略之一 在战争中 我们希望首先攻下敌方的部分城市 使其剩余的城市变成孤立无援 然后再分头各个击破 为此参谋部提供了若干打击方案 本题就请你编写程序 判断每个方案的可行性 输入格式 输入在第一行给出两个正整数
  • gdb attach 使用方法介绍

    1 假设进程 mcs 已启动 2 ps ef grep mcs 查询mcs进程号 获取进程号xxxx 3 gdb attach xxxx 进程号 attach到已启动的进程上 4 gdb stop 先暂停那个子进程 然后设置一些断点和一些W
  • arp,udp,icmp编码实现理解

    一直关注tcp ip的底层协议栈 终于有了大概的了解 通过ntytcp了解tcp相关的底层实现 发现除了tcp协议栈相关的东西 还有udp arp icmp ping命令相关 以及通过netmap对网卡数据进行接收的相关基础知识点 幸好 听