010 使用netmap API接管网卡,接收数据包,回应ARP请求
一.本文目的:
上一节中,我们已经在CentOS 6.7 上安装好了netmap,也能接收和发送包了,这节我们来调用netmap中的API,接管网卡,对网卡上收到的数据包做分析,并回应ARP请求。
二.netmap API简要介绍:
1.netmap API 主要包含在两个头文件中:netmap.h和netmap_user.h。在netmap/sys/net/目录下,其中netmap_user.h调用netmap.h。
2.netmap API一共七八个函数调用:nm_open()生成文件描述符,并做一系列初始化操作。nm_mmap()被nm_open()调用,申请存放数据包的内存池,并做相应初始化。
3.nm_nexkpkt()函数负责取出内存池的数据包,nm_inject()函数往内存池中写入数据包,发送到网卡。
4.nm_close()函数关闭先前的有关操作,并做相应清理。
(本文的目的是对ARP数据报的接收发送分析,所以对netmap API先只是简单介绍。)
三.具体内容:
1.实验中主机为centos 6.7,虚拟机也为centos6.7.所以就直接用主机给虚拟机发udp数据包了。(单纯的网络环境,没有其它主机的干扰!)
2.当调用了netmap API的程序运行时,会接管网卡,网卡上的数据都要通过netmap API中的方法得到(包括发送)。
3.当我们拿到数据包的时候,是一个含以太网首部的完整数据包,我们需要查看数据包的结构,确认是发给自己的。
4.实验发现,当网卡被接管后,相应的ARP功能没有了,所以我们需要手动实现一个ARP reply程序。
四.数据结构的定义:
实验过程中,会收到ARP请求和UDP数据包,我们主要对这两者进行分析:
1.完整的以太网udp数据包结构
结构体定义:
struct udp_pkt /* 普通的完整udp数据包 */
{
struct ether_header eh; /* 以太网头部,14字节,<net/ethernet.h>头文件中 */
struct iphdr ip; /* ip部分,20字节,<netinet/ip.h>头文件中 */
struct udphdr udp; /* udp部分,8字节,<netinet/udp.h>头文件中 */
uint8_t body[]; /* 数据部分,暂时分配20字节 */
};
2.完整的以太网ARP数据包结构
ARP数据报结构图:
结构体定义:
struct arp_pkt /* 完整arp数据包(以太网首部 + ARP字段) */
{
struct ether_header eh; /* 以太网头部,14字节,<net/ethernet.h>头文件中 */
struct ether_arp arp; /* ARP字段 ,28字节,<netinet/if_ether.h>头文件中 */
};
五.相关的函数封装(以后使用)
1.打印mac地址函数:
void Print_mac_addr(const unsigned char *str) /* 打印mac地址 */
{
int i;
for (i = ; i < ; i++)
printf("%02x:", str[i]);
printf("%02x", str[i]);
}
2.打印ip地址:
void Print_ip_addr(const unsigned char *str) /* 打印ip地址 */
{
int i;
for (i = ; i < ; i++)
printf("%d.", str[i]);
printf("%d", str[i]);
}
3.打印完整的arp数据包的内容
void Print_arp_pkt(struct arp_pkt* arp_pkt) /* 打印完整的以太网arp数据包的内容 */
{
Print_mac_addr(arp_pkt->eh.ether_dhost), printf(" "); /* 以太网目的地址 */
Print_mac_addr(arp_pkt->eh.ether_shost), printf(" "); /* 以太网源地址 */
printf("0x%04x ", ntohs(arp_pkt->eh.ether_type)); /* 帧类型:0x0806 */
printf(" ");
printf("%d ", ntohs(arp_pkt->arp.ea_hdr.ar_hrd)); /* 硬件类型:1 */
printf("0x%04x ", ntohs(arp_pkt->arp.ea_hdr.ar_pro)); /* 协议类型:0x0800 */
printf("%d ",arp_pkt->arp.ea_hdr.ar_hln); /* 硬件地址:6 */
printf("%d ",arp_pkt->arp.ea_hdr.ar_pln); /* 协议地址长度:4 */
printf("%d ", ntohs(arp_pkt->arp.ea_hdr.ar_op)); /* 操作字段:ARP请求值为1,ARP应答值为2 */
printf(" ");
Print_mac_addr(arp_pkt->arp.arp_sha), printf(" "); /* 发送端以太网地址*/
Print_ip_addr(arp_pkt->arp.arp_spa), printf(" "); /* 发送端IP地址 */
Print_mac_addr(arp_pkt->arp.arp_tha), printf(" "); /* 目的以太网地址 */
Print_ip_addr(arp_pkt->arp.arp_tpa), printf(" "); /* 目的IP地址 */
printf("\n");
}
4.根据ARP request生成ARP reply的packet
/*
* 根据ARP request生成ARP reply的packet
* hmac为本机mac地址
*/
void Init_echo_pkt(struct arp_pkt *arp, struct arp_pkt *arp_rt, char *hmac)
{
bcopy(arp->eh.ether_shost, arp_rt->eh.ether_dhost, ); /* 填入目的地址 */
bcopy(ether_aton(hmac), arp_rt->eh.ether_shost, ); /* hmac为本机mac地址 */
arp_rt->eh.ether_type = arp->eh.ether_type; /* 以太网帧类型 */
;
arp_rt->arp.ea_hdr.ar_hrd = arp->arp.ea_hdr.ar_hrd;
arp_rt->arp.ea_hdr.ar_pro = arp->arp.ea_hdr.ar_pro;
arp_rt->arp.ea_hdr.ar_hln = ;
arp_rt->arp.ea_hdr.ar_pln = ;
arp_rt->arp.ea_hdr.ar_op = htons(); /* ARP应答 */
;
bcopy(ether_aton(hmac), &arp_rt->arp.arp_sha, ); /* 发送端以太网地址*/
bcopy(arp->arp.arp_tpa, &arp_rt->arp.arp_spa, ); /* 发送端IP地址 */
bcopy(arp->arp.arp_sha, &arp_rt->arp.arp_tha, ); /* 目的以太网地址 */
bcopy(arp->arp.arp_spa, &arp_rt->arp.arp_tpa, ); /* 目的IP地址 */
}
六.源码实现:
其中:
本机mac地址:00:0C:29:E4:D6:2A
本机ip地址:192.168.11.134
发送udp数据包程序:
/*
============================================================================
Name : send_packet_01.c
Author : huh
Version :
Copyright : huh's copyright notice
Description : Hello World in C, Ansi-style
============================================================================
*/ #include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h> #define MAXLINE 1024*10 int main()
{
int sockfd;
struct sockaddr_in server_addr;
//创建原始套接字
sockfd = socket(AF_INET, SOCK_DGRAM, );
//创建套接字地址
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons();
server_addr.sin_addr.s_addr = inet_addr("192.168.11.134");
char sendline[]="adcde";
while()
{
sendto(sockfd, sendline, strlen(sendline), , (struct sockaddr *)&server_addr, sizeof(server_addr));
printf("%s\n",sendline);
sleep();
}
return ;
}
send_packet_01.c
接收数据包程序:
/*
============================================================================
Name : recv_pkt.c
Author : huh
Version :
Copyright : huh's copyright notice
Description : Hello World in C, Ansi-style
============================================================================
*/ #include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ifaddrs.h>
#include <net/ethernet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/ether.h>
#include <netinet/if_ether.h> #include <unistd.h> // sysconf()
#include <sys/poll.h>
#include <arpa/inet.h> #include "netmap_user.h" /* 来源与netmap */
#pragma pack(1) /* 设置结构体的边界对齐为1个字节 */ struct udp_pkt /* 普通的完整udp数据包 */
{
struct ether_header eh; /* 以太网头部,14字节,<net/ethernet.h>头文件中 */
struct iphdr ip; /* ip部分,20字节,<netinet/ip.h>头文件中 */
struct udphdr udp; /* udp部分,8字节,<netinet/udp.h>头文件中 */
uint8_t body[]; /* 数据部分,暂时分配20字节 */
}; struct arp_pkt /* 完整arp数据包(以太网首部 + ARP字段) */
{
struct ether_header eh; /* 以太网头部,14字节,<net/ethernet.h>头文件中 */
struct ether_arp arp; /* ARP字段 ,28字节,<netinet/if_ether.h>头文件中 */
}; void Print_mac_addr(const unsigned char *str) /* 打印mac地址 */
{
int i;
for (i = ; i < ; i++)
printf("%02x:", str[i]);
printf("%02x", str[i]);
} void Print_ip_addr(const unsigned char *str) /* 打印ip地址 */
{
int i;
for (i = ; i < ; i++)
printf("%d.", str[i]);
printf("%d", str[i]);
} void Print_arp_pkt(struct arp_pkt* arp_pkt) /* 打印完整的arp数据包的内容 */
{
Print_mac_addr(arp_pkt->eh.ether_dhost), printf(" "); /* 以太网目的地址 */
Print_mac_addr(arp_pkt->eh.ether_shost), printf(" "); /* 以太网源地址 */
printf("0x%04x ", ntohs(arp_pkt->eh.ether_type)); /* 帧类型:0x0806 */
printf(" ");
printf("%d ", ntohs(arp_pkt->arp.ea_hdr.ar_hrd)); /* 硬件类型:1 */
printf("0x%04x ", ntohs(arp_pkt->arp.ea_hdr.ar_pro)); /* 协议类型:0x0800 */
printf("%d ",arp_pkt->arp.ea_hdr.ar_hln); /* 硬件地址:6 */
printf("%d ",arp_pkt->arp.ea_hdr.ar_pln); /* 协议地址长度:4 */
printf("%d ", ntohs(arp_pkt->arp.ea_hdr.ar_op)); /* 操作字段:ARP请求值为1,ARP应答值为2 */
printf(" ");
Print_mac_addr(arp_pkt->arp.arp_sha), printf(" "); /* 发送端以太网地址*/
Print_ip_addr(arp_pkt->arp.arp_spa), printf(" "); /* 发送端IP地址 */
Print_mac_addr(arp_pkt->arp.arp_tha), printf(" "); /* 目的以太网地址 */
Print_ip_addr(arp_pkt->arp.arp_tpa), printf(" "); /* 目的IP地址 */
printf("\n");
} /*
* 根据ARP request生成ARP reply的packet
* hmac为本机mac地址
*/
void Init_echo_pkt(struct arp_pkt *arp, struct arp_pkt *arp_rt, char *hmac)
{
bcopy(arp->eh.ether_shost, arp_rt->eh.ether_dhost, ); /* 填入目的地址 */
bcopy(ether_aton(hmac), arp_rt->eh.ether_shost, ); /* hmac为本机mac地址 */
arp_rt->eh.ether_type = arp->eh.ether_type; /* 以太网帧类型 */
;
arp_rt->arp.ea_hdr.ar_hrd = arp->arp.ea_hdr.ar_hrd;
arp_rt->arp.ea_hdr.ar_pro = arp->arp.ea_hdr.ar_pro;
arp_rt->arp.ea_hdr.ar_hln = ;
arp_rt->arp.ea_hdr.ar_pln = ;
arp_rt->arp.ea_hdr.ar_op = htons(); /* ARP应答 */
;
bcopy(ether_aton(hmac), &arp_rt->arp.arp_sha, ); /* 发送端以太网地址*/
bcopy(arp->arp.arp_tpa, &arp_rt->arp.arp_spa, ); /* 发送端IP地址 */
bcopy(arp->arp.arp_sha, &arp_rt->arp.arp_tha, ); /* 目的以太网地址 */
bcopy(arp->arp.arp_spa, &arp_rt->arp.arp_tpa, ); /* 目的IP地址 */
} int main()
{
struct ether_header *eh;
struct nm_pkthdr h;
struct nm_desc *nmr;
nmr = nm_open("netmap:eth0", NULL, , NULL); /* 打开netmap对应的文件描述符,并做了相关初始化操作! */
struct pollfd pfd;
pfd.fd = nmr->fd;
pfd.events = POLLIN;
u_char *str;
printf("ready!!!\n");
while ()
{
poll(&pfd, , -); /* 使用poll来监听是否有事件到来 */
if (pfd.revents & POLLIN)
{
str = nm_nextpkt(nmr, &h); /* 接收到来的数据包 */
eh = (struct ether_header *) str;
if (ntohs(eh->ether_type) == 0x0800) /* 接受的是普通IP包 */
{
struct udp_pkt *p = (struct udp_pkt *)str;
if(p->ip.protocol == IPPROTO_UDP) /*如果是udp协议的数据包*/
printf("udp:%s\n", p->body);
else
printf("其它IP协议包!\n");
}
else if (ntohs(eh->ether_type) == 0x0806) /* 接受的是ARP包 */
{
struct arp_pkt arp_rt;
struct arp_pkt *arp = (struct arp_pkt *)str;
if( *(uint32_t *)arp->arp.arp_tpa == inet_addr("192.168.11.134") ) /*如果请求的IP是本机IP地址(两边都是网络字节序)*/
{
printf("ARP请求:");
Print_arp_pkt(arp);
Init_echo_pkt(arp, &arp_rt, "00:0C:29:E4:D6:2A"); /*根据收到的ARP请求生成ARP应答数据包*/
printf("ARP应答:");
Print_arp_pkt(&arp_rt);
nm_inject(nmr, &arp_rt, sizeof(struct arp_pkt)); /* 发送ARP应答包 */
}
else
printf("其它主机的ARP请求!\n");
}
}
}
nm_close(nmr);
return ;
}
recv_pkt.c
七.运行结果:
ready!!!
udp:adcde
udp:adcde
udp:adcde
udp:adcde
udp:adcde
udp:adcde
udp:adcde
udp:adcde
udp:adcde
udp:adcde
ARP请求:00:0c:29:e4:d6:2a 00:50:56:c0:00:08 0x0806 1 0x0800 6 4 1 00:50:56:c0:00:08 192.168.11.1 00:00:00:00:00:00 192.168.11.134
ARP应答:00:50:56:c0:00:08 00:0c:29:e4:d6:2a 0x0806 1 0x0800 6 4 2 00:0c:29:e4:d6:2a 192.168.11.134 00:50:56:c0:00:08 192.168.11.1
udp:adcde
udp:adcde
udp:adcde
010 使用netmap API接管网卡,接收数据包,回应ARP请求的更多相关文章
- 多队列网卡简介以及Linux通过网卡发送数据包源码解读
http://blog.csdn.net/yanghua_kobe/article/details/7485254 首先我们看一下一个主流多队列网卡(E1000)跟多核CPU之间的关系图: 非多队列: ...
- C#开发BIMFACE系列45 服务端API之创建离线数据包
BIMFACE二次开发系列目录 [已更新最新开发文章,点击查看详细] BIMFACE的常规应用方式有公有云与私有化部署两种方式,并且浏览模型或者图纸需要使用ViewToken,ViewToke ...
- 从网卡发送数据再谈TCP/IP协议—网络传输速度计算-网卡构造
在<在深谈TCP/IP三步握手&四步挥手原理及衍生问题—长文解剖IP>里面提到 单个TCP包每次打包1448字节的数据进行发送(以太网Ethernet最大的数据帧是1518字节,以 ...
- Linux内核网络数据包处理流程
Linux内核网络数据包处理流程 from kernel-4.9: 0. Linux内核网络数据包处理流程 - 网络硬件 网卡工作在物理层和数据链路层,主要由PHY/MAC芯片.Tx/Rx FIFO. ...
- 从零开始学安全(四十二)●利用Wireshark分析ARP协议数据包
wireshark:是一个网络封包分析软件.网络封包分析软件的功能是撷取网络封包,并尽可能显示出最为详细的网络封包资料.Wireshark使用WinPCAP作为接口,直接与网卡进行数据报文交换,是目前 ...
- DE2-115 以太网通信之一88E1111网卡接收PC数据
想利用手头上的DE2-115 写一个关于以太网通信的驱动,经过了这么多天的实验调试终于有了一些认识. 1.我在观察网卡发送数据与接收数据的过程中发现,我从fpga上的一个网卡发送数据,然后另一个网卡接 ...
- linux内核数据包转发流程(三)网卡帧接收分析
[版权声明:转载请保留出处:blog.csdn.net/gentleliu.邮箱:shallnew*163.com] 每一个cpu都有队列来处理接收到的帧,都有其数据结构来处理入口和出口流量,因此,不 ...
- Linux内核中网络数据包的接收-第一部分 概念和框架
与网络数据包的发送不同,网络收包是异步的的.由于你不确定谁会在什么时候突然发一个网络包给你.因此这个网络收包逻辑事实上包括两件事:1.数据包到来后的通知2.收到通知并从数据包中获取数据这两件事发生在协 ...
- 多CPU下基于e1000e驱动的数据包以及网卡中断流程分析.doc
http://wenku.baidu.com/link?url=mMKDH_fKmUXN7L6rANIFHjoHdKCYBLlDrqoYB1daDTEkNFk9Bt9xlJtS_4BKBj6w22WD ...
随机推荐
- 在Java中如何实现“Pless presss any key to continue.”
import java.util.*; class Continue{ public static void main(String[] args){ Scanner scanner=new Scan ...
- angular学习的一些小笔记(中)之ng-init
ng-init是给angular执行给定的表达式,初始化变量的值 <!DOCTYPE html> <html> <head> <meta charset='U ...
- HTML自学基础
关于自学HTML中遇到的各类细节问题 1.<a>表示链接标签,类似的有<img src>.链接的地址在<base>中填写.<base href="h ...
- 为你的网页图标(Favicon)添加炫丽的动画和图片
Favico.js 在让你的网页图标显示徽章,图像或视频.你设置可以轻松地在网页图标中使用动画,可以自定义类型的动画,背景颜色和文字颜色.它支持的动画,像幻灯片,渐变,弹出等等. 您可能感兴趣的相关文 ...
- 【javascript激增的思考04】MVC与Backbone.js(beta)
前言 最近整理了很多前端面试题的东西,今天又去参加了一次面试,不知各位烦不烦,我反正有点累了,于是我们今天继续回到我们前段时间研究的问题,我们再来看看MVC吧. 什么是MVC 又回到这个问题了,到底什 ...
- swift学习笔记之-属性
//属性 import UIKit //属性(Properties)详解 /* 存储属性(Stored Properties):类.结构体中,不能在枚举中 计算属性(Computed Properti ...
- Atitit.Atiposter 发帖机 信息发布器 v7 q516
Atitit.Atiposter 发帖机 信息发布器 v7 q516 V7 jetty 版本 基本访问改为web版. 这样发布调试 V1 初步实现sina csdn cnblogs V2 实现qz ...
- ArcGIS空间分析工具
1. 3D分析 1.1. 3D Features toolset 工具 工具 描述 3D Features toolset (3D 要素工具集) Add Z Information 添加 Z 信息 添 ...
- SharePoint 开启网站匿名访问图文详解
SharePoint 开启网站匿名,需要先开启web application的匿名访问,然后开启site的匿名访问.特别的,site可以选择整个网站开启或者列表和库开启匿名,如果选择列表和库开启匿名, ...
- 开发者账号续期后,itunes停止付款了
开发者账号过期后,没有及时续期,等再续期后,itunes停止付款到公司银行账户了.过了一个多月了还是没有收到itunes的付款.然后开始联系苹果客服和技术支持,他们都说只能通过itunes的“联系我们 ...