RAW SOCKET能够对较低层次的协议直接访问,网络监听技术很大程度上依赖于它。该文介绍了利用RAW SOCKET捕获网络底层数据包的步骤和方法
【原理】网卡对数据帧进行硬过滤(根据网卡的模式不同采取不同的操作,如果设置了混杂模式,则不做任何过滤直接交给下一层,否则非本机mac或者广播mac的会被直接丢弃)。在进入ip层之前,系统会检查系统中是否有通过socket(AP_PACKET,SOCK_RAW,…)创建的套接字,如果有并且协议相符,系统就给每个这样的socket接收缓冲区发送一个数据帧的拷贝。如果数据的校验和出错的话,内核直接丢弃该数据包,而不会拷贝给sock_raw的套接字。
发送接收ip数据包
socket(AF_INET, SOCK_RAW, IPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP)
发送接收以太网数据帧
socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))
使用SOCK_RAW发送接受的数据包含链路层的协议头。
struct ifreq ifr;
strcpy(ifr.ifr_name, "eth0");
ifr.ifr_flags |= IFF_PROMISC;
ioctl(sock, SIOCGIFFLAGS, ifr);
SIOCGIFFLAGS, SIOCSIFFLAGS 读取 或 设置 设备的 活动标志字
设备标志 | |
IFF_UP | 接口正在运行. |
IFF_BROADCAST | 有效的广播地址集. |
IFF_DEBUG | 内部调试标志. |
IFF_LOOPBACK | 这是自环接口. |
IFF_POINTOPOINT | 这是点到点的链路接口. |
IFF_RUNNING | 资源已分配. |
IFF_NOARP | 无arp协议, 没有设置第二层目的地址. |
IFF_PROMISC | 接口为杂凑(promiscuous)模式. |
IFF_NOTRAILERS | 避免使用trailer . |
IFF_ALLMULTI | 接收所有组播(multicast)报文. |
IFF_MASTER | 主负载平衡群(bundle). |
IFF_SLAVE | 从负载平衡群(bundle). |
IFF_MULTICAST | 支持组播(multicast). |
IFF_PORTSEL | 可以通过ifmap选择介质(media)类型. |
IFF_AUTOMEDIA | 自动选择介质. |
IFF_DYNAMIC | 接口关闭时丢弃地址. |
recvfrom(sock, buffer, BUF_SIZE, 0, NULL, NULL)
最后两个参数置为NULL,表示不绑定地址,来了的数据包都接收
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int socketfd;
ssize_t recvlen;
unsigned char buffer[1024];
socketfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (socketfd < 0)
{
print("sock create fail!\n");
return socketfd;
}
int id = 1;
while (1)
{
recvlen = recvfrom(socketfd, buffer, sizeof(buffer), 0, NULL, NULL);
if (recvlen < 42)
{
continue;
}
int i = 0;
print("id: %d\n",id);
for (i; i < sizeof(buffer); i++)
{
print(" %02x",buffer[i]);
if ((i + 1) % 16 == 0)
{
print("\n");
}
}
id ++;
print("\n\n");
}
}
然后就可以根据ethernet,ip,tcp等各协议头部字段对报文进行解析,
例如:这个报文的前6个字节目的mac:
接下来的6个字节源mac:
再接下来的两个字节为3层协议类型:
0x0800 即 IP协议
以太网头部就解析完成,接下来的报文就是ip头部了,以此类推。
具体解析过程详情附代码可参照另一篇使用libpcap抓包文章。
https://blog.csdn.net/Sophisticated_/article/details/83339483