原始套接字抓取所有以太网数据包与分析

If you have any idea, just send comments to me.

####1.原始套接字介绍
关于socket使用客户机/服务器模型的 SOCK_STREAM 或者 SOCK_DGRAM 用于 TCP 和 UDP 连接的应用更为普遍一些,而如果考虑到从网卡中直接捕获原始报文数据就需要用到原始套接字 SOCK_RAW 类型了。其中原始套接字根据 socket 选项可以工作在网络不同层级上。如果 socket 的第一个参数 domain 设置为 AF_INET 那么套接字就工作在 IP 层,如果设置为 AF_PACKET, 那么套接字就工作在网络接口层和 IP层;本文所给例程将使用后者以便于抓取更多协议类型的数据;关于 socket 最后一个参数 protocol 需要根据第一个参数来选择,本文使用 ETH_P_ALL。更多的使用细节参考 socket 和 protocols 的 man page 即可;

####2.网卡模式
默认情况下网卡只接收 MAC 地址和自己相关的数据包,因此要抓取网络中所有数据包需要将网卡设置为混杂模式,关于混杂模式请参阅我的其他博客。在编程实现上,通过 ioctl 即可将我们程序中设定的参数传递给网卡驱动以实现控制,同样关闭混杂模式也是通过该方法;

####3.数据解析
首先 linux 系统头文件中已经提供好了所有协议类型相关的头文件,这点也可以在例程中发现。但作为程序员,还是要十分清楚每一种协议下报文的基本结构以及报文中每一个字段的含义,关于报文结构也请参阅我的其他博文。在下面解析程序里也可以对每种报文协议略知一二。

####4.源代码
代码如下,具体使用步骤可以阅读代码,也可以直接输入: ./capture -h 来查看用法。关于其中的数据类型最好配合内核源代码进行查看,也更利于协议记忆。另外数据读取采取了最基本的 while 循环解析模式,为了提升效率可以采用 libevent 进行实现。当然目前缺点是退出 while(1) 循环会直接退出程序,无法取消网卡混杂模式和关闭套接字,优化任务就交给你们啦。
PS:如果在网卡上抓取到了大于 MTU 的数据包,不要慌张, 这是正常现象。解决办法参考我的其他博文,或者 send comments to me ? 。

/* normal header files */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include <string.h>
#include <signal.h>

/* network header files */
#include <arpa/inet.h>
#include <netdb.h>
#include <linux/if_ether.h>
#include <linux/igmp.h>
#include <netinet/ip_icmp.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <net/if.h>
#include <net/ethernet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <linux/if_arp.h>

/* type definations */
struct global_info{
	unsigned int bytes;
	unsigned int packet_all;

	unsigned int packet_arp;
	unsigned int packet_rarp;

	unsigned int packet_ip;
	unsigned int packet_icmp;
	unsigned int packet_igmp;

	unsigned int packet_tcp;
	unsigned int packet_udp;

	bool print_flag_frame;
	bool print_flag_arp;
	bool print_flag_rarp;
	bool print_flag_ip;
	bool print_flag_icmp;
	bool print_flag_igmp;
	bool print_flag_tcp;
	bool print_flag_udp;
};

struct ip_pair {
	unsigned int source_ip;
	unsigned int dest_ip;
};

/* varibles */
struct global_info global;

struct ip_pair ip_pair[1000];

/* function declaration */
void mac_to_str(char *buf, char *mac_buf);

void init_global(struct global_info *info)
{
	info->bytes = 0;
	info->packet_all = 0;

	info->packet_arp = 0;
	info->packet_rarp = 0;
	info->packet_ip = 0;
	info->packet_icmp = 0;
	info->packet_igmp = 0;
	info->packet_tcp = 0;
	info->packet_udp = 0;

	info->print_flag_arp = false;
	info->print_flag_rarp = false;
	info->print_flag_ip = false;
	info->print_flag_icmp = false;
	info->print_flag_igmp = false;
	info->print_flag_tcp = false;
	info->print_flag_udp = false;
}

void print_global(struct global_info *info)
{
	printf("=============== GLOBAL MESSAGE ===============\n");
	printf("Capture size: %.1f KB\n", (float)(info->bytes / 1024));
	printf("%d packet captured.\n", info->packet_all);
	if (info->packet_arp) 
		printf("Num of arp packet: %d\n", info->packet_arp);
	if (info->packet_rarp) 
		printf("Num of rarp packet: %d\n", info->packet_rarp);
	if (info->packet_ip) 
		printf("Num of ip packet: %d\n", info->packet_ip);
	if (info->packet_icmp) 
		printf("Num of icmp packet: %d\n", info->packet_icmp);
	if (info->packet_igmp) 
		printf("Num of igmp packet: %d\n", info->packet_igmp);
	if (info->packet_tcp) 
		printf("Num of tcp packet: %d\n", info-&g
  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值