基于Linux C的socketEthereal程序和Package分析 (一个)
执行测试平台:CentOS 6.5发行版,内核版本号3.11
1. Linux抓包源程序
在OSI七层模型中。网卡工作在物理层和数据链路层的MAC子层。
进行网络通信时。源主机通过socket(或其他)应用程序产生IP报文,经过各个OSI层层封装,数据包以Ethernet帧的形式进入物理层。Ethernet帧包括源主机地址、IP报文、目标地址(IP地址、port号或映射的6字节MAC地址)和须要传送到目标主机的其他信息。
目标的MAC地址是哪里来的呢?这牵扯到一个ARP协议(介乎于网络层和数据链路层的一个协议)。第一次传送某个目的IP地址的数据的时候,先会发出一个ARP包。其MAC的目标地址是广播地址,里面说到:"谁是xxx.xxx.xxx.xxx这个IP地址的主人?"由于是广播包,全部这个局域网的主机都收到了这个ARP请求。
收到请求的主机将这个IP地址和自己的相比較,假设不同样就不予理会,假设同样就发出ARP响应包。
这个IP地址的主机收到这个ARP请求包后回复的ARP响应里说到:"我是这个IP地址的主人"。这个包里面就包含了他的MAC地址。
以后的给这个IP地址的帧的目标MAC地址就被确定了。
就这样,以太网帧開始在数据链路层传播。Ethernet帧在链路层基于广播方式传播,即网段内的全部网卡都能观察该帧,但仅仅有一个网卡通过对照6字节MAC地址发现与自己相符。然后它就接收该帧。而其他网卡则放弃该帧。(其他网卡也能够接受该帧,即实际的网络Sniffer,可进行信息窃取等操作)
网卡得到Ethernet帧后。通过网络驱动程序和上层协议对其进行还原操作,即层层剥离报文头后将数据交由目标主机的socket(或其他)应用程序使用。
假设我们须要原始的以太网帧,以便观察与目标主机进行通信的源主机信息,则能够通过建立基于PF_PACKET的socket应用程序实现。PF_PACKET协议簇同意应用程序直接获得网络驱动程序得到的数据帧信息。PF_PACKET支持SOCK_DGRAM和SOCK_RAW两种socket类型,前者利用操作系统处理报文头,而后者则将以太网帧直接交由应用程序处理。
须要注意到是,仅仅有root权限用户才干使用PF_PACKET程序。
以下的代码就可以实现由应用程序直接获得以太网帧的需求。
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <linux/if_ether.h>
#include <linux/in.h> #define BUFFER_MAX 2048 int main(int argc, char *argv[]){
int SOCKET_SRC;
char buf[BUFFER_MAX];
int n_rd; if( (SOCKET_SRC = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) < 0 ){
fprintf(stderr, "create socket error.\n");
exit(0);
}
while(1){
n_rd = recvfrom(SOCKET_SRC, buf, BUFFER_MAX, 0, NULL, NULL);
if (n_rd<46) {
perror("recvfrom():");
printf("Incomplete packet (errno is %d)\n", errno);
close(SOCKET_SRC);
exit(0);
}
/* An Ethernet frame was written to buf, frame analysis can be processed here */
/* Termination control */
}
close(SOCKET_SRC);
return 0;
}
2. 数据包(以太网帧)分析
一个以太网帧(RFC894)的数据格式例如以下图所看到的。
以太网帧(RFC894)格式
程序通过运行一次
n_rd = recvfrom(SOCKET_SRC, buf, BUFFER_MAX, 0, NULL, NULL);
就将上面一条以太网帧写入buf中。
(1) 为了从buf中提取以太网报文头,我们能够定义例如以下结构体。
typedef struct mac_frm_hdr {
char dest_addr[6]; //destination MAC address shall be defined first.
char src_addr[6];
short type;
}__attribute__((packed)) MAC_FRM_HDR;
定义该结构体时,须要注意下面几点。
a.各属性需按帧格式的出现顺序定义。
b.数据类型长度必须和帧中对应区域的长度同样。
c. 使用__attribute__((packed))取消编译器自己主动优化对齐结构体,也是为了保证属性长度和帧中对应区域的长度同样。
(2)为了提取IP报文头。依据IP报文头的格式。我们可定义例如以下结构体。
typedef struct ip_hdr{ //header of IPV4
#ifdef __LITTLE_ENDIAN_BIFIELD
u_char ip_len:4, ip_ver:4;
#else
u_char ip_ver:4, ip_len:4;
#endif
u_char ip_tos;
u_short ip_total_len;
u_short ip_id;
u_short ip_flags;
u_char ip_ttl;
u_char ip_protocol;
u_short ip_chksum;
u_int32 ip_src;
u_int32 ip_dest;
}__attribute__((packed)) IP_HDR;
为保证各属性长度与IP报文头中一致,我们应该在定义该结构体前作例如以下声明。
typedef int int32;
typedef unsigned int u_int32;
typedef unsigned char u_char;
typedef unsigned short u_short;
注意事项參考定义以太网帧结构体。
(3)为了提取UDP/TCP报文头,可依据UDP/TCP报文头格式。定义对应结构体,这里不作赘述。
以下是对以太网帧进行解析的详细代码。
MAC_FRM_HDR *mac_hdr; //define a Ethernet frame header
IP_HDR *ip_hdr; //define a IP header
char *tmp1, *tmp2;
int AND_LOGIC = 0xFF; mac_hdr = buf; //buf is what we got from the socket program
ip_hdr = buf + sizeof(MAC_FRM_HDR);
//udp_hdr = buf + sizeof(MAC_FRM_HDR) + sizeof(IP_HDR); //if we want to analyses the UDP/TCP tmp1 = mac_hdr->src_addr;
tmp2 = mac_hdr->dest_addr;
/* print the MAC addresses of source and receiving host */
printf("MAC: %.2X:%.2X:%.2X:%.2X:%.2X:%.2X==>" "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
tmp1[0]&AND_LOGIC, tmp1[1]&AND_LOGIC, tmp1[2]&AND_LOGIC,tmp1[3]&AND_LOGIC,
tmp1[4]&AND_LOGIC, tmp1[5]&AND_LOGIC,
tmp2[0]&AND_LOGIC, tmp2[1]&AND_LOGIC, tmp2[2]&AND_LOGIC,tmp2[3]&AND_LOGIC,
tmp2[4]&AND_LOGIC, tmp2[5]&AND_LOGIC); tmp1 = (char*)&ip_hdr->ip_src;
tmp2 = (char*)&ip_hdr->ip_dest;
/* print the IP addresses of source and receiving host */
printf("IP: %d.%d.%d.%d => %d.%d.%d.%d",
tmp1[0]&AND_LOGIC, tmp1[1]&AND_LOGIC, tmp1[2]&AND_LOGIC,tmp1[3]&AND_LOGIC,
tmp2[0]&AND_LOGIC, tmp2[1]&AND_LOGIC, tmp2[2]&AND_LOGIC,tmp2[3]&AND_LOGIC);
/* print the IP protocol which was used by the socket communication */
switch(ip_hdr->ip_protocol) {
case IPPROTO_ICMP: LOGI("ICMP"); break;
case IPPROTO_IGMP: LOGI("IGMP"); break;
case IPPROTO_IPIP: LOGI("IPIP"); break;
case IPPROTO_TCP:
case IPPROTO_UDP:
LOGI("Protocol: %s", ip_hdr->ip_protocol == IPPROTO_TCP ? "TCP" : "UDP");
LOGI("Source port: %u, destination port: %u", udp_hdr->s_port, udp_hdr->d_port);
break;
case IPPROTO_RAW: LOGI("RAW"); break;
default: printf("Unknown, please query in inclued/linux/in.h\n"); break;
}
/*************************************************************************
> Author: kleguan
> 如用不当之处,欢迎指正
> 转载请注明出处
************************************************************************/
版权声明:本文博客原创文章。博客,未经同意,不得转载。
基于Linux C的socketEthereal程序和Package分析 (一个)的更多相关文章
- 基于linux与busybox的reboot命令流程分析
http://www.xuebuyuan.com/736763.html 基于Linux与Busybox的Reboot命令流程分析 ********************************** ...
- 基于Linux C的socket抓包程序和Package分析 (一)
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/guankle/article/details/27538031 測试执行平台:CentOS 6 ...
- (转载)基于Linux C的socket抓包程序和Package分析
转载自 https://blog.csdn.net/kleguan/article/details/27538031 1. Linux抓包源程序 在OSI七层模型中,网卡工作在物理层和数据链路层的MA ...
- C 语言实现基于 Linux 的端口扫描程序
Socket 常用函数: ⑴int socket(int protofamily, int type, int protocol); protofamily:即协议域,又称为协议族(family).常 ...
- 第一次作业:基于Linux操作系统深入源码进程模型分析
1.Linux操作系统的简易介绍 Linux系统一般有4个主要部分:内核.shell.文件系统和应用程序.内核.shell和文件系统一起形成了基本的操作系统结构,它们使得用户可以运行程序.管理文件并使 ...
- 写一个程序,用于分析一个字符串中各个单词出现的频率,并将单词和它出现的频率输出显示。(单词之间用空格隔开,如“Hello World My First Unit Test”)
public class Test { public void index() { String strWords = "Hello World My First Unit Test&quo ...
- 轻易实现基于linux或win运行的聊天服务端程序
对于不了解网络编程的开发人员来说,编写一个良好的服务端通讯程序是一件比较麻烦的事情.然而通过EC这个免费组件你可以非常简单地构建一个基于linux或win部署运行的网络服务程序.这种便利性完全得益于m ...
- 基于Linux ALSA音频驱动的wav文件解析及播放程序 2012
本设计思路:先打开一个普通wav音频文件,从定义的文件头前面的44个字节中,取出文件头的定义消息,置于一个文件头的结构体中.然后打开alsa音频驱动,从文件头结构体取出采样精度,声道数,采样频率三个重 ...
- 基于LINUX的多功能聊天室
原文:基于LINUX的多功能聊天室 基于LINUX的多功能聊天室 其实这个项目在我电脑已经躺了多时,最初写完项目规划后,我就认认真真地去实现了它,后来拿着这个项目区参加了面试,同样面试官也拿这个项目来 ...
随机推荐
- [GraphQL] Deploy a GraphQL dev playground with graphql-up
In this lesson we'll use a simple GraphQL IDL schema to deploy and explore a fully functional GraphQ ...
- 转载:使用bat命令来快速安装和卸载Service服务
一般我们在编写完Service服务程序后,都是通过cmd命令提示窗口来安装或卸载服务,但频繁的在cmd窗口中去“拼”文件的路径着实让人“不能忍”.所以,我们需要一钟“更快捷”的方式来进行安装或者卸载操 ...
- vs 外部依赖项、附加依赖项以及如何添加依赖项目
我们在 VS 中创建 Win32 控制台应用程序,vs 会为解决方案创建默认地创建 4 个 filters(资源管理器中没有对应的目录和文件夹): 头文件:一般为 .h 文件 外部依赖项 源文件:一般 ...
- 批量杀死MySQL连接的几种方法
法一: 通过information_schema.processlist表中的连接信息生成需要处理掉的MySQL连接的语句临时文件,然后执行临时文件中生成的指令. mysql> select ...
- notepad++ 正则替换
比如原来的代码是 {$id['nihao']}{$id['lal']}{pigcms:$id.leere} 查找目标写 \{\$id\['(\w+)'\]\} 替换为写 \{pigcms:\$id\. ...
- [Angular] Export directive functionalities by using 'exportAs'
Directive ables to change component behaives and lookings. Directive can also export some APIs which ...
- Python将被加入高考科目?你怎么看?
今天看到这样的一则新闻:不禁感叹,人工智能这股风来的太快,已经掀起全民学习Python的浪潮. 2017年中观察:看上去这个大纲内容基本是这样了,但是实行年份可能要往后推了,不在2017年执行了(据说 ...
- 支付宝开发之手机网站支付(H5支付)
其实官方的文档中:https://docs.open.alipay.com/203 介绍的已经很详细了,我就实地的看文档操作了一遍,具体步骤如下: 一.创建应用 流程如下: 首先要有支付宝开放平台: ...
- HDU 3215 The first place of 2^n (数论-水题)
The first place of 2^n Problem Description LMY and YY are mathematics and number theory lovers. They ...
- iOS中js与objective-c的简单交互
1.首先是objective-c调用js中的代码,可以用UIWebview中的一个方法 stringByEvaluatingJavaScriptFromString:后面接的是js中的方法名.这个函数 ...