一.本文目的:

上一节中,我们已经在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请求的更多相关文章

  1. 多队列网卡简介以及Linux通过网卡发送数据包源码解读

    http://blog.csdn.net/yanghua_kobe/article/details/7485254 首先我们看一下一个主流多队列网卡(E1000)跟多核CPU之间的关系图: 非多队列: ...

  2. C#开发BIMFACE系列45 服务端API之创建离线数据包

    BIMFACE二次开发系列目录     [已更新最新开发文章,点击查看详细] BIMFACE的常规应用方式有公有云与私有化部署两种方式,并且浏览模型或者图纸需要使用ViewToken,ViewToke ...

  3. 从网卡发送数据再谈TCP/IP协议—网络传输速度计算-网卡构造

    在<在深谈TCP/IP三步握手&四步挥手原理及衍生问题—长文解剖IP>里面提到 单个TCP包每次打包1448字节的数据进行发送(以太网Ethernet最大的数据帧是1518字节,以 ...

  4. Linux内核网络数据包处理流程

    Linux内核网络数据包处理流程 from kernel-4.9: 0. Linux内核网络数据包处理流程 - 网络硬件 网卡工作在物理层和数据链路层,主要由PHY/MAC芯片.Tx/Rx FIFO. ...

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

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

  6. DE2-115 以太网通信之一88E1111网卡接收PC数据

    想利用手头上的DE2-115 写一个关于以太网通信的驱动,经过了这么多天的实验调试终于有了一些认识. 1.我在观察网卡发送数据与接收数据的过程中发现,我从fpga上的一个网卡发送数据,然后另一个网卡接 ...

  7. linux内核数据包转发流程(三)网卡帧接收分析

    [版权声明:转载请保留出处:blog.csdn.net/gentleliu.邮箱:shallnew*163.com] 每一个cpu都有队列来处理接收到的帧,都有其数据结构来处理入口和出口流量,因此,不 ...

  8. Linux内核中网络数据包的接收-第一部分 概念和框架

    与网络数据包的发送不同,网络收包是异步的的.由于你不确定谁会在什么时候突然发一个网络包给你.因此这个网络收包逻辑事实上包括两件事:1.数据包到来后的通知2.收到通知并从数据包中获取数据这两件事发生在协 ...

  9. 多CPU下基于e1000e驱动的数据包以及网卡中断流程分析.doc

    http://wenku.baidu.com/link?url=mMKDH_fKmUXN7L6rANIFHjoHdKCYBLlDrqoYB1daDTEkNFk9Bt9xlJtS_4BKBj6w22WD ...

随机推荐

  1. 在Java中如何实现“Pless presss any key to continue.”

    import java.util.*; class Continue{ public static void main(String[] args){ Scanner scanner=new Scan ...

  2. angular学习的一些小笔记(中)之ng-init

    ng-init是给angular执行给定的表达式,初始化变量的值 <!DOCTYPE html> <html> <head> <meta charset='U ...

  3. HTML自学基础

    关于自学HTML中遇到的各类细节问题 1.<a>表示链接标签,类似的有<img src>.链接的地址在<base>中填写.<base href="h ...

  4. 为你的网页图标(Favicon)添加炫丽的动画和图片

    Favico.js 在让你的网页图标显示徽章,图像或视频.你设置可以轻松地在网页图标中使用动画,可以自定义类型的动画,背景颜色和文字颜色.它支持的动画,像幻灯片,渐变,弹出等等. 您可能感兴趣的相关文 ...

  5. 【javascript激增的思考04】MVC与Backbone.js(beta)

    前言 最近整理了很多前端面试题的东西,今天又去参加了一次面试,不知各位烦不烦,我反正有点累了,于是我们今天继续回到我们前段时间研究的问题,我们再来看看MVC吧. 什么是MVC 又回到这个问题了,到底什 ...

  6. swift学习笔记之-属性

    //属性 import UIKit //属性(Properties)详解 /* 存储属性(Stored Properties):类.结构体中,不能在枚举中 计算属性(Computed Properti ...

  7. Atitit.Atiposter 发帖机 信息发布器 v7 q516

    Atitit.Atiposter 发帖机 信息发布器 v7 q516 V7 jetty 版本 基本访问改为web版. 这样发布调试 V1  初步实现sina csdn cnblogs V2  实现qz ...

  8. ArcGIS空间分析工具

    1. 3D分析 1.1. 3D Features toolset 工具 工具 描述 3D Features toolset (3D 要素工具集) Add Z Information 添加 Z 信息 添 ...

  9. SharePoint 开启网站匿名访问图文详解

    SharePoint 开启网站匿名,需要先开启web application的匿名访问,然后开启site的匿名访问.特别的,site可以选择整个网站开启或者列表和库开启匿名,如果选择列表和库开启匿名, ...

  10. 开发者账号续期后,itunes停止付款了

    开发者账号过期后,没有及时续期,等再续期后,itunes停止付款到公司银行账户了.过了一个多月了还是没有收到itunes的付款.然后开始联系苹果客服和技术支持,他们都说只能通过itunes的“联系我们 ...