pcap_loop調用pcap_read_linux_mmap_v3循環捕獲數據,此時程序已經進入正常嗅探過程,而我們應該重點關注的點應該是在這之前的啓動過程。
整體瞭解之後發現一切都是圍繞着socket展開,這個socket和以往純應用層tcp/udp的socket不一樣,它將Ethernet、ip、tcp層的數據都暴露出來,被稱作原始套接字。
libpcap/tcpdump就是用原始套接字來捕獲網卡數據,圍繞着原始套接字又做了豐富的功能。本文拋開libpcap/tcpdump,用原始套接字實現了一個收和一個發。
收
#include <sys/socket.h>
#include <netinet/ether.h>
#include <stdio.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netpacket/packet.h>
#include <string.h>
#include <zconf.h>
#include <sys/ioctl.h>
void printf_hex(char *data, int len, int count);
int main(int argc,char *argv[]) {
int sock_raw_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if(sock_raw_fd < 0){
perror("socket");
return -1;
}
unsigned char buf[1024] = {0};
int len = recvfrom(sock_raw_fd, buf, sizeof(buf), 0, NULL, NULL);
printf_hex(buf,len,16);
return 0;
}
void printf_hex(char *data, int len, int count)
{
printf("start data=%p _pDataLen=%d", data,len);
int i = 0;
printf("\n");
for(i = 0; i < len; i++)
{
if(data[i] < 0x10) {
printf("0x0%x, ", data[i]);
} else {
printf("0x%x, ", data[i]);
}
if((!((i + 1) %count)) && (i > 0))
{
printf("\n");
}
}
printf("\n");
printf("\n");
printf("end _pData\n");
return;
}
上面的代碼編譯執行後會抓一個數據包並打印出來,同時用wireshark進行抓包,可以在抓包中發現打印的數據,並且是從鏈路層開始打印的。如果想獲取ip,端口和網卡等信息,直接讀數據即可,很多系統調用可能也是利用原始socket開發。
發
#include <sys/socket.h>
#include <netinet/ether.h>
#include <stdio.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netpacket/packet.h>
#include <string.h>
#include <zconf.h>
#include <sys/ioctl.h>
void printf_hex(char *data, int len, int count);
int main(int argc,char *argv[]) {
int sock_raw_fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if(sock_raw_fd < 0){
perror("socket");
return -1;
}
unsigned char buf[14] = {0};//6+6+2
// int len = recvfrom(sock_raw_fd, buf, sizeof(buf), 0, NULL, NULL);
// printf_hex(buf,len,16);
struct sockaddr_ll sll;
struct ifreq req;
strncpy(req.ifr_name, "ens33", IFNAMSIZ);
if(ioctl(sock_raw_fd, SIOCGIFINDEX, &req) == -1){
perror("ioctl");
close(sock_raw_fd);
return -1;
}
bzero(&sll,sizeof(sll));
sll.sll_ifindex = req.ifr_ifindex;
buf[0]=0x00;
buf[1]=0x0c;
buf[2]=0x29;
buf[3]=0xbf;
buf[4]=0xfc;
buf[5]=0xef;
int len = sendto(sock_raw_fd, buf, sizeof(buf), 0, (struct sockaddr *)&sll, sizeof(sll));
if(len == -1){
perror("sendto");
return -1;
}
return 0;
}
void printf_hex(char *data, int len, int count)
{
printf("start data=%p _pDataLen=%d", data,len);
int i = 0;
printf("\n");
for(i = 0; i < len; i++)
{
if(data[i] < 0x10) {
printf("0x0%x, ", data[i]);
} else {
printf("0x%x, ", data[i]);
}
if((!((i + 1) %count)) && (i > 0))
{
printf("\n");
}
}
printf("\n");
printf("\n");
printf("end _pData\n");
return;
}
用tcpdump抓包會找到此包,如下圖所示。
尾
原始socket可以做很多事情,網上有篇文章講如何用原始socket竊取ftp明文的用戶名密碼用ping命令發回。我想到的最有意思的也就是去做各種偵聽僞造。哈哈哈。就像有一篇文章寫的這個是駭客初級知識。tcpdump的最基本原理其實已經懂了,後面其實想把重心放在ffmpeg上,但也真心不希望這個是libpcap/tcpdump的最後一篇文章。