Linux数据链路层的包解析
仅以此文作为学习笔记,初学者,如有错误欢迎批评指正,但求轻喷。
一般而言,Linux系统截获数据包后,会通过协议栈,按照TCP/IP层次进行解析,那我们如何直接获得更为底层的数据报文呢,这里用到一个类型SOCK_PACKET类型。
int sockfd = socket(AF_INET,SOCK_PACKET,htons(0x0003));
通过上面这个函数可以获得一个特殊的套接字,其中:
AF_INET: 表示因特网协议族
SOCK_PACKET: 表示数据包截取在物理层
0x0003: 表示数据帧类型不确定
修改网络接口结构:
struct ifreq ifr;
strcpy(ifr.ifr_name,"eth0");
ioctl(sockfd,SIOCGIFFLAGS,&ifr);
设置混杂模式
ifr.ifr_flags| = IFR_PROMISC;
ioctl(sockfd,SIOCSIFFLAGS,&ifr);
注意:
进行标志位设定时,遵循以下步骤:
(1)取出原标识位;
(2)与待设定标志位进行位或运算(“|”);
(3)重新写入;
一个小小的抓包程序
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<sys/ioctl.h>
#include<net/if.h>
#include<arpa/inet.h>
#include<netinet/if_ether.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<netinet/tcp.h>
#include<netinet/udp.h> using namespace std; char ethernet_frame[ETH_FRAME_LEN];//定义一个数据帧的长度
struct iphdr *ipheader;//定义ip头部指针 int socketcreate()
{
int sockfd = socket(AF_INET,SOCK_PACKET,htons(0x0003));
//构建了一个数据链路层的数据包;
if(sockfd == -)
{
cout<<"Socket init error!"<<endl;
return -;
}
/*
下面设置接口结构
*/
char *ifname = "eth0";
struct ifreq ifr;
strcpy(ifr.ifr_name,ifname);
int result = ioctl(sockfd,SIOCGIFFLAGS,&ifr);
if(result == -)
{
cout<<"Can't get flags!"<<endl;
close(sockfd);
return -;
}
ifr.ifr_flags|= IFF_PROMISC;
/*
一般而言,Linux系统截获数据包后,会通过协议栈,按照TCP/IP层次进行解析,那我们如何直接获得更为底层的数据报文呢,这里用到一个类型SOCK_PACKET类型。
int sockfd = socket(AF_INET,SOCK_PACKET,htons(0x0003));
通过上面这个函数可以获得一个特殊的套接字,其中:
AF_INET: 表示因特网协议族
SOCK_PACKET: 表示数据包截取在物理层
0x0003: 表示数据帧类型不确定 修改网络接口结构:
struct ifreq ifr;
strcpy(ifr.ifr_name,"eth0");
ioctl(sockfd,SIOCGIFFLAGS,&ifr); 设置混杂模式
ifr.ifr_flags| = IFR_PROMISC;
ioctl(sockfd,SIOCSIFFLAGS,&ifr);
注意:
进行标志位设定时,遵循以下步骤:
(1)取出原标识位;
(2)与待设定标志位进行位或运算(“|”);
(3)重新写入;
*/
result = ioctl(sockfd,SIOCSIFFLAGS,&ifr);
if(result == -)
{
cout<<"Can't set flags!"<<endl;
close(sockfd);
return -;
} return sockfd;
}
int getframe(int sockfd,int num)
{
struct ethhdr* fheader;
fheader = (struct ethhdr*)ethernet_frame;
memset(ethernet_frame,,ETH_FRAME_LEN);
int size = read(sockfd,ethernet_frame,ETH_FRAME_LEN);
if(size <= )
{
cout<<"No packet or packet error!"<<endl;
return -;
}
cout<<"************************Packet"<<num<<"received from eth0 START!************************"<<endl;
printf("DST MAC: ");
for(int i=;i<ETH_ALEN-;i++)
{
printf("%2x-",fheader->h_dest[i]);
}
printf("%2x\n",fheader->h_dest[ETH_ALEN-]);
printf("SRC MAC: ");
for(int i=;i<ETH_ALEN-;i++)
{
printf("%2x-",fheader->h_source[i]);
}
printf("%2x\n",fheader->h_source[ETH_ALEN-]);
if(ntohs(fheader->h_proto) == 0x0800)
{
cout<<"Protocol: IP"<<endl;
}
if(ntohs(fheader->h_proto) == 0x0806)
{
cout<<"Protocol: RAP"<<endl;
}
if(ntohs(fheader->h_proto) == 0x8035)
{
cout<<"Protocol: RARP"<<endl;
}
int ret = ntohs(fheader->h_proto);
return ret;
} int getip(int protocol,int num)
{
if(protocol != 0x0800)
{
cout<<"NO IP Packet!"<<endl;
cout<<"************************Packet"<<num<<"received from eth0 END!**************************"<<endl;
return ;
}
ipheader = (struct iphdr*)(ethernet_frame+ETH_HLEN);
printf("Version: 4");
cout<<endl;
in_addr *p,*q;
p = (struct in_addr*)&ipheader->saddr;
printf("SRC IP: %s",inet_ntoa(*p));
cout<<endl;
q = (struct in_addr*)&ipheader->daddr;
printf("DST IP: %s",inet_ntoa(*q));
cout<<endl;
if(ipheader->protocol == )
{
cout<<"PROTOCOL: ICMP"<<endl;
}
if(ipheader->protocol == )
{
cout<<"PROTOCOL: TCP"<<endl;
}
if(ipheader->protocol == )
{
cout<<"PROTOCOL: UDP"<<endl;
}
return ipheader->protocol;
} int gettcp(int protocol)
{
if(protocol != )
{
return -;
}
struct tcphdr* tcph;
tcph = (struct tcphdr*)(ipheader+((ipheader->ihl)*));
printf("SRC PORT: %d",ntohs(tcph->source));
cout<<endl;
printf("DST PORT: %d",ntohs(tcph->dest));
cout<<endl;
return ;
} int getudp(int protocol)
{
if(protocol != )
{
return -;
}
struct udphdr* udph;
udph = (struct udphdr*)(ipheader+((ipheader->ihl)*));
printf("SRC PORT: %d",ntohs(udph->source));
cout<<endl;
printf("DST PORT: %d",ntohs(udph->dest));
cout<<endl;
return ;
} int main(int argc,char *argv[])
{
if(argc < )
{
cout<<"Please input the nummber of packet that you want to catch!"<<endl;
return ;
}
int num = (int)argv[][];
int sock = socketcreate();
for(int i=;i<num;i++)
{
int ip_protocol = getframe(sock,i);
int trasnport_protocol = getip(ip_protocol,i);
gettcp(trasnport_protocol);
getudp(trasnport_protocol);
cout<<"************************Packet"<<num<<"received from eth0 END!**************************"<<endl;
cout<<endl;
cout<<endl;
cout<<endl;
cout<<endl;
}
return ;
}
Linux数据链路层的包解析的更多相关文章
- linux下抓包工具tcpdump详解
本文转自:http://www.cnblogs.com/ggjucheng/archive/2012/01/14/2322659.html 简介 用简单的话来定义tcpdump,就是:dump the ...
- linux网络配置完全解析
概述:熟悉了windows下面的网络配置,对linux下的网络配置缺未必了解透彻.熟练掌握linux下的网络配置原理,能帮助我们更容易掌握网络传输原理:同时具备一些网络连接不通对应问题的排查能力.文本 ...
- Linux下 解包/打包 Android 映像文件 system.img, boot.img, ramdisk.img, userdata.img.
Linux下 解包/打包 Android 映像文件 system.img, boot.img, ramdisk.img, userdata.img. 2014年10月20日 ⁄ 计算机视觉 ⁄ 共 1 ...
- linux ssh使用深度解析(key登录详解)
linux ssh使用深度解析(key登录详解) SSH全称Secure SHell,顾名思义就是非常安全的shell的意思,SSH协议是IETF(Internet Engineering Task ...
- [Docker]Docker与Linux ip_forward数据包转发
背景 今天在一台新虚拟机上需要临时启动一个consul服务,安装Docker后使用docker启动,但是在执行启动命令后发现docker有一个警告: WARNING: IPv4 forwarding ...
- Wireshark-过滤器-数据包解析
目录 过滤器 数据包解析 参考 推荐阅读: https://www.cnblogs.com/zwtblog/tag/计算机网络/ 过滤器 显示过滤器 和 捕获过滤器,俩者使用非常类似. 在Wiresh ...
- java jar包解析:打包文件,引入文件
java jar包解析:打包文件,引入文件 cmd下: jar命令:package包打包 javac命令:普通类文件打包 Hello.java: package org.lxh.demo; publi ...
- Linux内核数据包的发送传输
本文主要讲解了Linux内核数据包的传输流程,使用的内核的版本是2.6.32.27 为了方便理解,本文采用整体流程图加伪代码的方式从内核高层面上梳理了二层数据包发送传输的流程,希望可以对大家有所帮助. ...
- Android做法说明(3)---Fragment使用app袋或v4包解析
Android做法说明(3)---Fragment使用app袋或v4包解析 1)问题简述 相信非常多的朋友在调用Fragment都会遇到以下的情况: watermark/2/text/aHR0cDov ...
随机推荐
- YAML的使用
YAML 语言教程 编程免不了要写配置文件,怎么写配置也是一门学问. YAML 是专门用来写配置文件的语言,非常简洁和强大,远 ...
- C++中前置声明的应用与陷阱
前置声明的使用 有一定C++开发经验的朋友可能会遇到这样的场景:两个类A与B是强耦合关系,类A要引用B的对象,类B也要引用类A的对象.好的,不难,我的第一直觉让我写出这样的代码: // A.h #in ...
- HBase系统入门--整体介绍
转自:http://www.aboutyun.com/thread-8957-1-2.html 问题导读:1.HBase查询与写入哪个更好一些?2.HBase面对复杂操作能否实现?3.Region服务 ...
- spark学习系列
转自: http://www.cnblogs.com/magj2006/p/4316264.html spark 系列文章汇总 源码导读 spark 源码导读1 从spark启动脚本开始 spark ...
- 关于Cocos2d-x中增加暂停按钮的步骤
1.在GameScene.cpp的init方法中先定义一个里面放着可变换并在变换的时候会响应事件的MenuItem的Menu,这个Menu里面的可变换MenuItem又由两个小MenuItem组成,每 ...
- 有关JSP隐式对象,以下( )描述正确。
A.隐式对象是WEB容器加载的一组类的实例,可以直接在JSP页面使用 B.不能通过config对象获取ServletContext对象 C.response对象通过sendRedirect方法实现重定 ...
- 多种方法实现div两列等高(收集整理)
HTML骨架 <div id="header">头部</div> <div id ="container"> <div ...
- C Language Study - 函数指针的使用
函数指针的使用 1.函数指针定义 第一次使用函数指针,我是这样声明的,typedef void ( *pSimulatepks )( uint8 *prxBuf, uint8 *prxBufLen ) ...
- R语言低级绘图函数-arrows
arrows 函数用来在一张图表上添加箭头,只需要分别指定起始坐标和终止坐标,就可以添加箭头了,还可以通过一些属性对箭头的形状,大小进行调整 基本用法: xo, yo 指定起始点的x和y坐标,x1, ...
- c#后台访问接口
直接上代码 后台代码 //接口地址string url = "http://spherefg.topsmoon.com:6666/restapi/Comment/SubmitCommentF ...