共计 4150 个字符,预计需要花费 11 分钟才能阅读完成。
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); |
注意:进行标志位设定时,遵循以下步骤:
- 取出原标识位;
- 与待设定标志位进行位或运算(“|”);
- 重新写入;
一个小小的抓包程序
#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 == -1) | |
{ | |
cout<<"Socket init error!"<<endl; | |
return -1; | |
} | |
/* | |
下面设置接口结构 | |
*/ | |
char *ifname = "eth0"; | |
struct ifreq ifr; | |
strcpy(ifr.ifr_name,ifname); | |
int result = ioctl(sockfd,SIOCGIFFLAGS,&ifr); | |
if(result == -1) | |
{ | |
cout<<"Can't get flags!"<<endl; | |
close(sockfd); | |
return -2; | |
} | |
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 == -1) | |
{ | |
cout<<"Can't set flags!"<<endl; | |
close(sockfd); | |
return -3; | |
} | |
return sockfd; | |
} | |
int getframe(int sockfd,int num) | |
{ | |
struct ethhdr* fheader; | |
fheader = (struct ethhdr*)ethernet_frame; | |
memset(ethernet_frame,0,ETH_FRAME_LEN); | |
int size = read(sockfd,ethernet_frame,ETH_FRAME_LEN); | |
if(size <= 0) | |
{ | |
cout<<"No packet or packet error!"<<endl; | |
return -1; | |
} | |
cout<<"************************Packet"<<num<<"received from eth0 START!************************"<<endl; | |
printf("DST MAC:"); | |
for(int i=0;i<ETH_ALEN-1;i++) | |
{printf("%2x-",fheader->h_dest[i]); | |
} | |
printf("%2x\n",fheader->h_dest[ETH_ALEN-1]); | |
printf("SRC MAC:"); | |
for(int i=0;i<ETH_ALEN-1;i++) | |
{printf("%2x-",fheader->h_source[i]); | |
} | |
printf("%2x\n",fheader->h_source[ETH_ALEN-1]); | |
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 0; | |
} | |
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 == 1) | |
{cout<<"PROTOCOL: ICMP"<<endl;} | |
if(ipheader->protocol == 6) | |
{cout<<"PROTOCOL: TCP"<<endl;} | |
if(ipheader->protocol == 17) | |
{cout<<"PROTOCOL: UDP"<<endl;} | |
return ipheader->protocol; | |
} | |
int gettcp(int protocol) | |
{if(protocol != 6) | |
{return -1;} | |
struct tcphdr* tcph; | |
tcph = (struct tcphdr*)(ipheader+((ipheader->ihl)*4)); | |
printf("SRC PORT: %d",ntohs(tcph->source)); | |
cout<<endl; | |
printf("DST PORT: %d",ntohs(tcph->dest)); | |
cout<<endl; | |
return 0; | |
} | |
int getudp(int protocol) | |
{if(protocol != 17) | |
{return -1;} | |
struct udphdr* udph; | |
udph = (struct udphdr*)(ipheader+((ipheader->ihl)*4)); | |
printf("SRC PORT: %d",ntohs(udph->source)); | |
cout<<endl; | |
printf("DST PORT: %d",ntohs(udph->dest)); | |
cout<<endl; | |
return 0; | |
} | |
int main(int argc,char *argv[]) | |
{if(argc < 2) | |
{ | |
cout<<"Please input the nummber of packet that you want to catch!"<<endl; | |
return 0; | |
} | |
int num = (int)argv[1][0]; | |
int sock = socketcreate(); | |
for(int i=1;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 0; | |
} |
正文完