什么是ARP协议

ARP协议是Address Resolution Protocol(地址解析协议)的缩写。在局域网中,网络中实际传输的是数据帧,数据帧里面有目的主机的MAC地址。但这个目的MAC地址是如何获取的呢?就是通过地址解析协议获得的。所谓“地址解析”就是主机在发送数据帧之前将目标IP地址转化成目标MAC地址的过程。ARP协议的基本功能就是通过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的顺利进行。

ARP协议的封装

图1 ARP数据报格式

1.硬件类型字段:2字节。用来定义运行ARP的网络类型。每一个局域网基于其类型被指定一个整数。例如,以太网的类型为1。

2.协议类型字段:2字节。用来定义高层协议的类型。例如,对IPv4协议,这个字段的值为0x0806。

3.硬件地址长度:1字节。用来定义以字节为单位的物理地址长度。例如,对以太网这个值为6。

4.协议地址长度:1字节。用来定义以字节为单位的协议地址长度。例如,对IPv4这个值是4。

5.操作字段:占2字节。用来定义分组的类型。例如,ARP请求分组为1,ARP响应分组为2。

6.发送端硬件地址:6字节。
7.发送端协议地址:4字节。
8.目标端硬件地址:6字节。
9.目标端协议地址:4字节。

如图2所示,ARP数据报是直接封装在数据链路层的数据帧中。

图2 ARP数据报的封装

原始套接字发送ARP数据包

通过以下建立发送ARP数据包的原始套接字:

socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP) )

第一个参数协议族为PF_PACKET,定义数据链路层上封包;第二个参数socket类型为SOCK_RAW,定义为原始套接字;第三个参数协议类型不能为0,此处定义为ARP协议。
    由于是数据链路层上封包,地址定义需要使用协议无关的sockaddr_ll结构,填写其中的接口索引字段。
    按照以太网帧的头部和ARP数据包定义构造发送数据,用sendto函数发送。具体的代码见附录1

实验

实验采用两台虚拟机,IP地址分别为192.168.182.133和192.168.182.132,使用192.168.182.133作为ARP请求端。
    先在ARP请求端删除关于192.168.182.132的ARP记录:

arp -d 192.168.182.132

然后打开wireshark进行抓包,最后执行编写的ARP发送程序,观察wireshark结果。如图3所示,对方进行了ARP应答。

图3 wireshark抓包结果

附录1

#include <sys/types.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <net/ethernet.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <string.h>int main()
{int sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP) );if (sockfd == -1){printf("socket error\n"); return 0;}//获取网卡信息sockaddr_ll addr_ll;memset(&addr_ll, 0, sizeof(sockaddr_ll));addr_ll.sll_family = PF_PACKET;ifreq ifr;strcpy(ifr.ifr_name, "ens33");if (ioctl(sockfd, SIOCGIFINDEX, &ifr) == -1){printf("error ioctl SIOCGIFINDEX\n"); return 0;}addr_ll.sll_ifindex = ifr.ifr_ifindex; //接口索引if (ioctl(sockfd, SIOCGIFADDR, &ifr) == -1){printf("error ioctl SIOCGIFADDR\n"); return 0;}char* ipSrc = inet_ntoa(((struct sockaddr_in*)(&(ifr.ifr_addr)))->sin_addr);printf("ip address : %s\n", ipSrc); //source ipif (ioctl(sockfd, SIOCGIFHWADDR, &ifr) == -1){printf("error ioctl SIOCGIFHWADDR\n"); return 0;}unsigned char macSrc[ETH_ALEN];memcpy(macSrc, ifr.ifr_hwaddr.sa_data, ETH_ALEN); //mac addressprintf("mac address");for (int i = 0; i < ETH_ALEN; i++)printf(":%02x", macSrc[i]);printf("\n");//填充以太网首部 和 ARP信息unsigned char macDst[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};ether_header header;memcpy(header.ether_dhost, macDst, ETH_ALEN);memcpy(header.ether_shost, macSrc, ETH_ALEN);header.ether_type = htons(ETHERTYPE_ARP);ether_arp arp;arp.arp_hrd = htons(ARPHRD_ETHER);arp.arp_pro = htons(ETHERTYPE_IP);arp.arp_hln = ETH_ALEN;arp.arp_pln = 4; //IPv4arp.arp_op = htons(ARPOP_REQUEST);in_addr src_in_addr, dst_in_addr;inet_pton(AF_INET, ipSrc, &src_in_addr);inet_pton(AF_INET, "192.168.182.132", &dst_in_addr);memcpy(arp.arp_sha, macSrc, ETH_ALEN);memcpy(arp.arp_spa, &src_in_addr, 4);memcpy(arp.arp_tha, macDst, ETH_ALEN);memcpy(arp.arp_tpa, &dst_in_addr, 4);unsigned char sendBuf[sizeof(ether_header) + sizeof(ether_arp) ];memcpy(sendBuf, &header, sizeof(ether_header) );memcpy(sendBuf + sizeof(ether_header), &arp, sizeof(ether_arp));int len = sendto(sockfd, sendBuf, sizeof(sendBuf), 0, (const sockaddr*)&addr_ll, sizeof(addr_ll) );if (len > 0){printf("send success\n");}return 0;
}

参考

刘兵,刘欣等编著.计算机网络基础[M].北京:中国水利水电出版社.2006.

原始套接字发送ARP数据包相关推荐

  1. java使用原始套接字技术进行数据包截获_Linux零拷贝技术,看完这篇文章就懂了...

    本文讲解 Linux 的零拷贝技术,云计算是一门很庞大的技术学科,融合了很多技术,Linux 算是比较基础的技术,所以,学好 Linux 对于云计算的学习会有比较大的帮助. 为什么需要零拷贝 传统的 ...

  2. 原始套接字发送IP数据报

    IP是TCP/IP协议族中的核心协议.所有TCP.UDP.ICMP和IGMP数据都通过IP数据报传输.IP提供了一种尽力而为.无连接的数据报交付服务. IPv4头部 图1 IPv4头部 图1显示了IP ...

  3. python通信原理_用python通过原始套接字发送scapy包

    要使用原始套接字发送scapy数据包,必须先将数据包转换为原始字节.例如,使用scapy制作的数据包如下:p = IP(dst="192.168.1.254")/TCP(flags ...

  4. af_packet_C语言中利用AF_PACKET 原始套接字发送一个任意以太网帧 (一)

    目标 利用AF_PACKET 套接字发送一个任意的以太网帧 背景 以太网是一个链路层协议.大多数网络程序员关注网络栈的传输层及以上,所以不需要直接处理以太网帧,但是某些场景下关注传输层以下也是有必要的 ...

  5. 原始套接字SOCK_RAW发送UDP数据包

    使用原始套接字发送udp数据包,从传输层封包到链路层(mac头+ip头+udp头).udp数据包,从传输层封包到链路层(mac头+ip头+udp头). head.h文件如下: #ifndef _HEA ...

  6. 【网络编程】---C++实现原始套接字捕获数据包

    C++实现原始套接字捕获数据包 引言 原始套接字与TCP套接字和UDP套接字的区别 原始套接字编程使用的场合 原始套接字的通信过程 (1)基于原始套接字的数据发送过程 (2)基于原始套接字的数据接收过 ...

  7. Linux原始套接字学习总结

    Linux网络编程:原始套接字的魔力[上] http://blog.chinaunix.net/uid-23069658-id-3280895.html 基于原始套接字编程        在开发面向连 ...

  8. Linux网络编程:原始套接字的魔力【续】

    如何从链路层直接发送数据帧        本来以为这部分都弄完了,结果有朋友反映说看了半天还是没看到如何从链路层直接发送数据.因为上一篇里面提到的是从链路层"收发"数据,结果只&q ...

  9. Windows平台的原始套接字编程的知识点概要(备忘)

    其实从大学学习了C语言后,翻看整本教材只有C语言的语法,根本没有网络编程相关的任何内容,现在回想起来,都记不起自己何时在哪本书上学习了套接字编程,说起TCP.UDP,能知道他们的区别,相关的编程的&q ...

最新文章

  1. c语言动态迁移mysql,flask-migrate动态迁移数据库
  2. 整系数多项式的整除平移不变性
  3. Spring Boot Maven插件
  4. Python基础教程:in和not in操作
  5. enterprise search for Object is not enabled
  6. java 循环map 优雅写法_Java for循环Map集合优化实现解析
  7. SQL服务器引擎组件概览
  8. 【VS开发】图像颜色
  9. 普中科技51单片机_【笔记】-普中科技-51单片机-按键
  10. 关于visio安装时出现出现回滚更改以至于安装失败的解决办法
  11. 学计算机干眼,电脑族预防干眼的7个小妙招_39健康网
  12. Python 玩转数据 8 - Pandas Indexing and Slicing
  13. 高铁对合肥及周边城市可达性及商业腹地变化影响研究
  14. android x86 uc,UC浏览器X86版下载|UC浏览器X86版老版 V10.8.5 安卓版 下载_当下软件园_软件下载...
  15. 图像修复:专栏博文推荐查阅顺序
  16. 在技术招聘中,HR 如何识别候选人的“味道”?
  17. 关于cpu-z,everest,IntelCoreSeries的一些认识
  18. 2021年ECNU计科考研复试机试 C. 子序列 (尺取)
  19. 光标自动定位到输入框
  20. 2018年10月训练记录(10.1~10.23)

热门文章

  1. 贪心埃及分数函数c语言,贪心算法之埃及分数问题
  2. Python——类的声明与定义
  3. 用递归方法扫描 SVN 仓库下载符合条件的文件
  4. bootstrap常用的图标集
  5. Excel如何标出两列重复值
  6. 详解linux下mnt目录作用
  7. linux查找nginx配置文件并修改
  8. 得物购买截图生成_这应该是目前为止,iPhone上最好的长截图工具
  9. WEB自动化-获取tbody下面tr的个数
  10. Java 高级软件工程师面试题,java 教程多态,Java 程序员面试笔记 pdf