之前的几篇文章,分别介绍了 ARP 协议格式,在vs2012里配置winpcap环境,我们该做的准备都已经做完了。如今我们真正来实现了。

一、定义数据结构

依据ARP的协议格式,设计一个ARP协议格式

依据ARP的分组格式,我们知道它有两部分组成:

1、以太网首部,这是数据包在数据链路层上传输所必不可缺的部分。它的后面跟着相关的协议数据包(ARP/IP等)

2、ARP数据包

所以。我们有这么几个数据结构:

// 以太网的首部
typedef struct EthHead
{
u_char dest_mac[6]; // 以太网的目的地址
u_char src_mac[6]; // 以太网的源地址
u_char type[2]; // 帧类型 ARP:0x0806
}EthHead;
// ARP数据包
typedef struct ArpMsg
{
u_char mac_type[2]; // 硬件类型 以太网: 1
u_char protocal_type[2]; // 协议类型 IP地址:0x0800
u_char mac_len; // 硬件地址长度 6
u_char protocal_len; // 协议地址长度 4
u_char op[2]; // 操作字段 ARP请求:1 ARP应答:2 RARP请求:3 RARP应答:4
u_char sender_mac[6]; // 发送端以太网地址
u_char sender_ip[4]; // 发送端IP地址
u_char target_mac[6]; // 目的以太网地址
u_char target_ip[4]; // 目的IP地址
}ArpMsg;
// 以太网ARP
typedef struct Arp
{
EthHead eth_head;
ArpMsg arpmsg;
}Arp;

每一个数据结构都有凝视说明

注:

【1】因为网络传输数据都是大端模式,所以在设计这些数据结构,以及在封装数据的时候,注意要把本地序转为网络序

【2】为了方便,我把全部的字段类型都设为u_char(unsigned char)型。在封装数据的时候,仅仅要按字节赋值。就不须要在进行本地序和网络序的转换了(假设是多字节存储,如short、int等。切记要进行转换)

二、组包

/*
函数名: PacketArp
功 能: 封装ARP包
參 数:
arp_req : Arp类型,出參
op : 操作字段
ARP请求:1
ARP响应:2
RARP请求:3
RARP对应:4
dest_mac : 以太网目的地址
src_mac : 以太网源地址
sender_mac:发送端以太网地址
sender_ip : 发送端IP地址
target_mac: 目的以太网地址
target_ip : 目的IP地址
返 回: 0正确,-1错误 */
int PacketArp(Arp *arp_req, u_char op, u_char dest_mac[6], u_char src_mac[6], u_char sender_mac[6],
u_char sender_ip[4], u_char target_mac[6], u_char target_ip[4])
{
if(arp_req == NULL)
return -1;
memcpy(arp_req->eth_head.dest_mac, dest_mac, 6);
memcpy(arp_req->eth_head.src_mac, src_mac, 6);
arp_req->eth_head.type[0] = 0x08;
arp_req->eth_head.type[1] = 0x06;
//arp_req->eth_head.type = htons(arp_req->eth_head.type); arp_req->arpmsg.mac_type[0] = 0x00;
arp_req->arpmsg.mac_type[1] = 0x01;
arp_req->arpmsg.protocal_type[0] = 0x08;
arp_req->arpmsg.protocal_type[1] = 0x00;
arp_req->arpmsg.mac_len = 0x06;
arp_req->arpmsg.protocal_len = 0x04;
arp_req->arpmsg.op[0] = 0x00;
arp_req->arpmsg.op[1] = op;
memcpy(arp_req->arpmsg.sender_mac, sender_mac, 6);
memcpy(arp_req->arpmsg.sender_ip, sender_ip, 4);
memcpy(arp_req->arpmsg.target_mac, target_mac, 6);
memcpy(arp_req->arpmsg.target_ip, target_ip, 4); return 0;
} // ARP 请求包
int PacketArpRequest(Arp *arp_req, u_char dest_mac[6], u_char src_mac[6], u_char sender_mac[6],
<span style="white-space:pre"> </span> u_char sender_ip[4], u_char target_mac[6], u_char target_ip[4])
{
<span style="white-space:pre"> </span>return PacketArp(arp_req,0x01,dest_mac,src_mac,sender_mac,sender_ip,target_mac,target_ip);
} // ARP 响应包
int PacketArpReplay(Arp *arp_req, u_char dest_mac[6], u_char src_mac[6], u_char sender_mac[6],
<span style="white-space:pre"> </span> u_char sender_ip[4], u_char target_mac[6], u_char target_ip[4])
{
<span style="white-space:pre"> </span>return PacketArp(arp_req,0x02,dest_mac,src_mac,sender_mac,sender_ip,target_mac,target_ip);
}

三、发包

/*
功能: src_mac 向局域网广播:target_ip 192.168.1.111 的 mac 是多少
*/
int Text1(Arp *arp)
{
u_char dest_mac[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};// 广播
u_char src_mac[6] = {0xF0,0x7B,0xCB,0xA3,0x15,0x85};// 源mac地址 F0-7B-CB-A3-15-85
u_char sender_mac[6] = {0xF0,0x7B,0xCB,0xA3,0x15,0x85}; // 发送端mac F0-7B-CB-A3-15-85
u_char sender_ip[4] = {0xC0,0xA8,0x01,0x65}; //发送端IP地址 192.168.1.101
u_char target_mac[6] = {0x00,0x00,0x00,0x00,0x00,0x00}; // 由于不知道mac,所以mac为空
u_char target_ip[4] = {0xC0,0xA8,0x01,0x6F}; // 目的端ip 192.168.1.111; if(PacketArpRequest(arp,dest_mac,src_mac,sender_mac,sender_ip,target_mac,target_ip) == -1)
{
printf("Packet arp request error\n");
return -1;
}
return 0;
}
 Arp arp;
 if(Text1(&arp) == -1)
 {
  return ;
 }
 memcpy(packet, (void*)&arp, ARP_LEN);
 /* Send down the packet */
 if (pcap_sendpacket(fp, packet, ARP_LEN /* size */) != 0)
 {
  fprintf(stderr,"\nError sending the packet: %s\n", pcap_geterr(fp));
  return;
 }

注:pcap_sendpacket 是winpcap里面的发包函数,此函数不支持linux

至此,我们的ARP组包、发包就完毕了,就是这么简单(winpcap的功劳),以下我们用wireshark来抓包,看我们的包有没有发送出去。



从抓包来看,我们的包已经正确发出去了(192.168.1.111是我本机的ip),并且从还能够看出,已经有回包了。回包的详细内容:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

我们再来对照下请求包和响应包的差别:

不言而喻吧

同一时候。我们再看下我们本地的ARP缓存:

192.168.1.111这台机器的IP和MAC映射也就增加到ARP快速缓存了。

附源代码:

#include <stdlib.h>
#include <stdio.h> // pcap_findalldevs_ex
#define HAVE_REMOTE
#include <pcap.h> #define ARP_LEN 42 // 以太网的首部
typedef struct EthHead
{
u_char dest_mac[6]; // 以太网的目的地址
u_char src_mac[6]; // 以太网的源地址
u_char type[2]; // 帧类型 ARP:0x0806
}EthHead; // ARP数据包
typedef struct ArpMsg
{
u_char mac_type[2]; // 硬件类型 以太网: 1
u_char protocal_type[2]; // 协议类型 IP地址:0x0800
u_char mac_len; // 硬件地址长度 6
u_char protocal_len; // 协议地址长度 4
u_char op[2]; // 操作字段 ARP请求:1 ARP应答:2 RARP请求:3 RARP应答:4
u_char sender_mac[6]; // 发送端以太网地址
u_char sender_ip[4]; // 发送端IP地址
u_char target_mac[6]; // 目的以太网地址
u_char target_ip[4]; // 目的IP地址
}ArpMsg; // 以太网ARP
typedef struct Arp
{
EthHead eth_head;
ArpMsg arpmsg;
}Arp; /*
函数名: PacketArp
功 能: 封装ARP包
參 数:
arp_req : Arp类型,出參
op : 操作字段
ARP请求:1
ARP响应:2
RARP请求:3
RARP对应:4
dest_mac : 以太网目的地址
src_mac : 以太网源地址
sender_mac:发送端以太网地址
sender_ip : 发送端IP地址
target_mac: 目的以太网地址
target_ip : 目的IP地址
返 回: 0正确。-1错误 */
int PacketArp(Arp *arp_req, u_char op, u_char dest_mac[6], u_char src_mac[6], u_char sender_mac[6],
u_char sender_ip[4], u_char target_mac[6], u_char target_ip[4])
{
if(arp_req == NULL)
return -1;
memcpy(arp_req->eth_head.dest_mac, dest_mac, 6);
memcpy(arp_req->eth_head.src_mac, src_mac, 6);
arp_req->eth_head.type[0] = 0x08;
arp_req->eth_head.type[1] = 0x06;
//arp_req->eth_head.type = htons(arp_req->eth_head.type); arp_req->arpmsg.mac_type[0] = 0x00;
arp_req->arpmsg.mac_type[1] = 0x01;
arp_req->arpmsg.protocal_type[0] = 0x08;
arp_req->arpmsg.protocal_type[1] = 0x00;
arp_req->arpmsg.mac_len = 0x06;
arp_req->arpmsg.protocal_len = 0x04;
arp_req->arpmsg.op[0] = 0x00;
arp_req->arpmsg.op[1] = op;
memcpy(arp_req->arpmsg.sender_mac, sender_mac, 6);
memcpy(arp_req->arpmsg.sender_ip, sender_ip, 4);
memcpy(arp_req->arpmsg.target_mac, target_mac, 6);
memcpy(arp_req->arpmsg.target_ip, target_ip, 4); return 0;
} // ARP 请求包
int PacketArpRequest(Arp *arp_req, u_char dest_mac[6], u_char src_mac[6], u_char sender_mac[6],
u_char sender_ip[4], u_char target_mac[6], u_char target_ip[4])
{
return PacketArp(arp_req,0x01,dest_mac,src_mac,sender_mac,sender_ip,target_mac,target_ip);
} // ARP 响应包
int PacketArpReplay(Arp *arp_req, u_char dest_mac[6], u_char src_mac[6], u_char sender_mac[6],
u_char sender_ip[4], u_char target_mac[6], u_char target_ip[4])
{
return PacketArp(arp_req,0x02,dest_mac,src_mac,sender_mac,sender_ip,target_mac,target_ip);
} // 打开网络适配器
pcap_if_t* choose_interface()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
char errbuf[PCAP_ERRBUF_SIZE]; /* Retrieve the device list on the local machine */
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
} /* Print the list */
for(d=alldevs; d; d=d->next)
{
printf("%d. %s", ++i, d->name);
if (d->description)
printf(" (%s)\n", d->description);
else
printf(" (No description available)\n");
} if(i==0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return NULL;
} printf("Enter the interface number (1-%d):",i);
scanf_s("%d", &inum); if(inum < 1 || inum > i)
{
printf("\nInterface number out of range.\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return NULL;
} /* Jump to the selected adapter */
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++); return d;
} /*
功能: src_mac 向局域网广播:target_ip 192.168.1.111 的 mac 是多少
*/
int Text1(Arp *arp)
{
u_char dest_mac[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};// 广播
u_char src_mac[6] = {0xF0,0x7B,0xCB,0xA3,0x15,0x85};// 源mac地址 F0-7B-CB-A3-15-85
u_char sender_mac[6] = {0xF0,0x7B,0xCB,0xA3,0x15,0x85}; // 发送端mac F0-7B-CB-A3-15-85
u_char sender_ip[4] = {0xC0,0xA8,0x01,0x65}; //发送端IP地址 192.168.1.101
u_char target_mac[6] = {0x00,0x00,0x00,0x00,0x00,0x00}; // 由于不知道mac,所以mac为空
u_char target_ip[4] = {0xC0,0xA8,0x01,0x6F}; // 目的端ip 192.168.1.111; if(PacketArpRequest(arp,dest_mac,src_mac,sender_mac,sender_ip,target_mac,target_ip) == -1)
{
printf("Packet arp request error\n");
return -1;
}
return 0;
} void main(int argc, char **argv)
{
pcap_t *fp;
char errbuf[PCAP_ERRBUF_SIZE];
u_char packet[ARP_LEN];
int i; pcap_if_t *d = choose_interface();
if(d == NULL)
{
exit(1);
}
char *source = d->name; /* Open the output device */
if ( (fp= pcap_open(source, // name of the device
100, // portion of the packet to capture (only the first 100 bytes)
PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
1000, // read timeout
NULL, // authentication on the remote machine
errbuf // error buffer
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", argv[1]);
return;
} Arp arp;
if(Text1(&arp) == -1)
{
return ;
} memcpy(packet, (void*)&arp, ARP_LEN);
/* Send down the packet */
if (pcap_sendpacket(fp, packet, ARP_LEN /* size */) != 0)
{
fprintf(stderr,"\nError sending the packet: %s\n", pcap_geterr(fp));
return;
} return;
}

ARP协议(4)ARP编程的更多相关文章

  1. arp协议分析&python编程实现arp欺骗抓图片

    arp协议分析&python编程实现arp欺骗抓图片 序 学校tcp/ip协议分析课程老师布置的任务,要求分析一种网络协议并且研究安全问题并编程实现,于是我选择了研究arp协议,并且利用pyt ...

  2. ARP协议(3)ARP编程--winpcap&amp;vs2012配置

    好.之前说了那么多.最终到了,我们能够操刀的时候了. 在对ARP协议编程前.我们必需要能控制网络适配器(网卡).这个部分就是驱动! "我们要编写网卡驱动?",对,可是,至少我们现阶 ...

  3. 浅析ARP协议及ARP攻击

    一. ARP数据包结构 (1)硬件类型:指明发送方想知道的硬件接口类型,以太网的值为1:(2)协议类型:指明发送方提供的高层协议类型:它的值为 0x0800 即表示 IP地址.(3)硬件地址长度和协议 ...

  4. ARP协议与ARP攻击入门

    一 ARP协议 ARP协议是一个年代相当"久远"的网络协议.ARP协议制定于1982年11月,英文全称:Address Resolution Protocol,即"地址解 ...

  5. ARP协议格式、ARP运行机制入门学习

    相关学习资料 http://baike.baidu.com/view/149421.htm?fromtitle=ARP%E5%8D%8F%E8%AE%AE&fromid=1742212& ...

  6. Networking - ARP 协议

    ARP 协议概述 ARP(Address Resolution Protocol),即地址解析协议,用于把 IP 地址映射到物理地址.网段上的每台主机都维护着一个被称为 ARP Table 或 ARP ...

  7. 从零开始学安全(四十二)●利用Wireshark分析ARP协议数据包

    wireshark:是一个网络封包分析软件.网络封包分析软件的功能是撷取网络封包,并尽可能显示出最为详细的网络封包资料.Wireshark使用WinPCAP作为接口,直接与网卡进行数据报文交换,是目前 ...

  8. ARP协议分析

    一.ARP概述 网络中所有的协议(HTTP.URL.FTP.TELNET.TCP.UDP.ARP ······)都包含在TCP/IP协议栈中,从使用上来看:其中大部分协议都是大家平常上网所接触到的,不 ...

  9. ARP协议分析(Wireshark)

    一.说明 1.1 背景说明 以前学网络用的谢希仁的<计算机网络原理>,一是网开始学不太懂网络二是ARP协议是没有数据包格式的(如果没记错应该是没有).学完只记得老师说:ARP很简单的,就是 ...

随机推荐

  1. 启发式合并 CodeForces - 600E

    启发式合并最重要的思想就是指的是每次将小集合拷贝合并至大集合.考虑每个元素的合并开销.对于合并次数最多的那个元素来说,它每合并一次,所在集合的规模扩大两倍,最多只会合并 logN 次,因而对于所有元素 ...

  2. IO之转换流举例

    import java.io.*; public class TestTransForm1 { public static void main(String[] args) { try { Outpu ...

  3. LNMP构架搭建论坛

    1 yum install -y apr* autoconf automake bison bzip2 bzip2* compat* cpp curl curl-devel fontconfig fo ...

  4. SpringBoot第十六篇:自定义starter

    作者:追梦1819 原文:https://www.cnblogs.com/yanfei1819/p/11058502.html 版权声明:本文为博主原创文章,转载请附上博文链接! 前言   这一段时间 ...

  5. 九度oj 题目1057:众数

    题目1057:众数 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:9744 解决:3263 题目描述: 输入20个数,每个数都在1-10之间,求1-10中的众数(众数就是出现次数最多的数, ...

  6. 编程数学-∑(求和符号)-Sigma

    百度百科:∑ 在数学中,我们把它作为求和符号使用. 大写Σ用于数学上的总和符号,比如:∑Pi,其中i=1,2,...,T,即为求P1 + P2 + ... + PT的和.小写σ用于统计学上的标准差.西 ...

  7. Amoeba新版本MYSQL读写分离配置

    标签:mysql 数据库 读写分离 休闲 amoeba 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://skyson.blog.5 ...

  8. Codeforces Round #264 (Div. 2) D

    题意: 给出最多5个序列,问这几个序列的最长公共子序列的长度是多少. solution : 脑抽级别我是,第一个序列每个数字位置固定,这样只要维护一个k-1维的偏序集就好了.然后在保证每个位置合法的情 ...

  9. POJ 1330 (LCA)

    http://poj.org/problem?id=1330 题意:给出一个图,求两个点的最近公共祖先. sl :水题,贴个模板试试代码.本来是再敲HDU4757的中间发现要用LCA,  操蛋只好用这 ...

  10. Sumdiv(poj1845)

    题意:求A^B的因子的和. /* 首先将A分解 A=p1^a1*p2^a2*...*pn*an A^B=p1^a1B*p2^a2B*...*pn*anB 因子之和sum=(1+p1+p1^2+...+ ...