网络嗅探器设计(一)

本文介绍如何使用libpcap库捕获和分析网络数据包。内容涵盖网络接口的选择、数据包的截取及过滤,以及对IP、TCP、UDP等协议数据包的解析方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

功能

@网络数据包的截取
扫描主机上的网络接口,使用Libcap 库截取数据报文
@主机端口扫描
指定要扫描的主机,以及要扫描的端口范围,构造TCP 数据报文,扫描目标主机端
@返回端口状态,端口服务类型
网络层数据报文分析
@分析数据报文,处理IP,ARP,RARP 数据报文
将IP 数据报文交给下一层再做进一步分析
@传输层数据报文分析
分析TCP,UDP,ICMP,IGMP 数据报文,将分析结果记录在日志文件中。
@查找网关
查找本地地址的网关,返回路由表,网关

模块分解:
程序入口main.c
嗅探程序sniffer.c
处理以太网层数据包ethernet.c
处理tcp 数据包tcp.c
处理udp 数据包udp.c
处理icmp 数据包icmp.c
处理arp 数据包arp.c
处理端口扫描port.c
处理查找网关gateway.c
工具common.c

准备工作:
1>了解libpcap库:

***libpcap的抓包框架:***
pcap_lookupdev():函数用来查找网络设备,返回可被pcap_open_live()函数调用的网络设备名指针。
pcap_lookupnet():函数获得指定网络设备的网络号和掩码。
pcap_open_live():函数用于打开设备,并且返回用于捕获网络数据包的数据包捕获描述字。对于此网络设备的操作都要基于此网络设备描述字。
pcap_compile():函数用于将用户制定的过滤策略编译到过滤程序中
pcap_setfilter():函数用于设置过滤器
pcap_loop():与pcap_next()和pcap_next_ex()两个函数一样用来捕获数据包
pcap_close():函数用于关闭网络设备,释放资源

///////////////////////////////////////
***libpcap使用步骤***

打开网络设备==>设置过滤规则==>捕获数据==>关闭网络设备

2>libpcap细节

@获取网络设备接口:

char *pcap_lookupdev(char * errbuf);
功能:自动获取可用的网络设备名指针
参数:errbuf,存放出错信息字符串
成功返回设备名指针(第一个合适的网络接口的字符串指针),失败则返回NULL,同时,errbuf存放出错信息字符串

////////////////////////////////////////////

@获取网络号(ip地址)和掩码:

int pcap_lookupnet(char* device,bpf_u_int32 *netp,bpf_u_int32 *maskp,char *errbuf);
功能:获取指定网卡的ip地址,子网掩码
device:网络设备名,为第一步获取的网络接口字符串,也可以人为指定,如“eth0”
netp  :存放ip地址的指针,buf_u_int32为32位无符号整型
maskp :存放子网掩码的指针
errbuf:存放出错信息
返回值 :成功返回0,失败返回1

///////////////////////////////////////////

@打开网络接口:

pcap_t *pcap_open_live(const char * device,int snaplen,int promisc,int to_ms,char *errbuf);
功能:打开一个用于捕获数据的网络端口
device:网络接口的名字,为第一步获取的网络接口字符串,也可以人为指定
snaplen:捕获数据包的长度,不能大于65535个字节
promise:”1“代表混杂模式,其他值代表非混杂模式
to_ms  :等待毫秒数,超时间,获得数据包的函数会立即返回,0表示一直等待
errbuf :存储错误信息
返回值:返回pcap_t类型指针,后面的所有操作都要使用这个指针。

///////////////////////////////////////////////

@获取数据包:

**方法一**:
const u_char *pcap_next(pcap_t *p,struct pcap_pkthdr *h);
功能:捕获一个网络数据包,收到一个数据包立即返回
p:pcap_open_live()返回的pcap_t类型的指针        h:数据包头
 struct pcap_pkthdr  
 {  
     struct timeval ts; // 抓到包的时间  
     bpf_u_int32 caplen; // 表示抓到的数据长度  
     bpf_u_int32 len; // 表示数据包的实际长度  
 }
len和caplen的区别:因为在某些情况下不能保证捕获的包是完整的,例如一个包长1480,但是你捕获到1000的时候,可能因为某些原因就终止捕获了,所以caplen是记录实际捕获的包长,也就是1000,而len就是1480
返回值:成功则返回捕获数据包的地址,失败返回NULL

**方法二**
int pcap_loop(pcap_t *p,int cnt,pcap_handler callback,u_char *user);
功能:循环捕获网络数据包,直到遇到错误或者满足退出条件,每次捕获一个数据包就会调用callback指定的回调函数,所以,可以在回调函数中进行数据包的处理操作。

p:pcap_open_live()返回的pcap_t类型的指针
cnt:指定捕获数据包的个数,一旦抓到cnt个数据包,pcap_loop立即返回,如果是-1,就会一直捕获直到出错
callback:回调函数,名字任意,根据需要自行取名
user:向回调函数中传递的参数

callback回调函数的定义:
void callback(u_char *userarg,const struct pcap_pkthdr *pkthdr,const u_char *packet)
userarg:pcap_loop()的最后一个参数,当收到足够数量的包后pcap_loop会调用callback回调函数,同时将pcap_loop()的user参数传递给它
pkthdr:是收到数据包的pcap_pkthdr类型的指针,和pcap_next()第二个参数是一样的
packet:收到的数据包数据
返回值:成功返回0,失败返回负数

**方法三**

int pcap_dispatch(pcap_t *p,int cnt,pcap_handler callback,u_char *user);
这个函数和pcap_loop()非常类似,只是在超过to_ms毫秒后就会返回(to_ms是pcap_open_live()的第四个参数)

////////////////////////////////////////////

***释放网络接口***
void pcap_close(pcap_t *p);
功能:关闭pcap_open_live()打开的网络接口,并释放相关资源
参数:p:需要关闭的网络接口,pcap_open_live()的返回值

/////////////////////////////////////////////

@过滤数据包:

int pcap_setfilter(pcap_t *p,struct bpf_program *fp);
功能:应用BPF过滤规则
p :pcap_open_live()返回的pcap_t类型的指针
fp:pcap_compile()的第二个参数
返回值:成功返回0,失败返回-1
关于嗅探器的源代码#include #include #include #include #include #pragma comment(lib,"ws2_32.lib") #define MAX_HOSTNAME_LAN 255 #define SIO_RCVALL _WSAIOW(IOC_VENDOR,1) #define MAX_ADDR_LEN 16 struct ipheader { unsigned char ip_hl:4; unsigned char ip_v:4; unsigned char ip_tos; unsigned short int ip_len; unsigned short int ip_id; unsigned short int ip_off; unsigned char ip_ttl; unsigned char ip_p; unsigned short int ip_sum; unsigned int ip_src; unsigned int ip_dst; }; typedef struct tcpheader { unsigned short int sport; unsigned short int dport; unsigned int th_seq; unsigned int th_ack; unsigned char th_x:4; unsigned char th_off:4; unsigned char Flags; unsigned short int th_win; unsigned short int th_sum; unsigned short int th_urp; }TCP_HDR; typedef struct udphdr { unsigned short sport; unsigned short dport; unsigned short len; unsigned short cksum; }UDP_HDR; void main(){ SOCKET sock; WSADATA wsd; DWORD dwBytesRet; unsigned int optval = 1; unsigned char *dataudp,*datatcp; int i,pCount=0,lentcp, lenudp; SOCKADDR_IN sa,saSource, saDest; struct hostent FAR * pHostent; char FAR name[MAX_HOSTNAME_LAN]; char szSourceIP[MAX_ADDR_LEN], szDestIP[MAX_ADDR_LEN],RecvBuf[65535] = {0}; struct udphdr *pUdpheader; struct ipheader *pIpheader; struct tcpheader *pTcpheader; WSAStartup(MAKEWORD(2,1),&wsd); if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP))==SOCKET_ERROR) exit(1); gethostname(name, MAX_HOSTNAME_LAN); pHostent = gethostbyname(name); sa.sin_family = AF_INET; sa.sin_port = htons(6000); memcpy(&sa.sin_addr.S_un.S_addr, pHostent->h_addr_list[0], pHostent->h_length); bind(sock, (SOCKADDR *)&sa, sizeof(sa)); if ((WSAGetLastError())==10013) exit(1); WSAIoctl(sock, SIO_RCVALL, &optval, sizeof(optval), NULL, 0, &dwBytesRet, NULL, NULL); pIpheader = (struct ipheader *)RecvBuf; pTcpheader = (struct tcpheader *)(RecvBuf+ sizeof(struct ipheader )); pUdpheader = (struct udphdr *) (RecvBuf+ sizeof(struct ipheader )); while (1){ memset(RecvBuf, 0, sizeof(RecvBuf)); recv(sock, RecvBuf, sizeof(RecvBuf), 0); saSource.sin_addr.s_addr = pIpheader->ip_src; strncpy(szSourceIP, inet_ntoa(saSource.sin_addr), MAX_ADDR_LEN); saDest.sin_addr.s_addr = pIpheader->ip_dst; strncpy(szDestIP, inet_ntoa(saDest.sin_addr), MAX_ADDR_LEN); lentcp =(ntohs(pIpheader->ip_len)-(sizeof(struct ipheader)+sizeof(struct tcpheader))); lenudp =(ntohs(pIpheader->ip_len)-(sizeof(struct ipheader)+sizeof(struct udphdr))); if((pIpheader->ip_p)==IPPROTO_TCP&&lentcp!=0){ printf("*******************************************\n"); pCount++; datatcp=(unsigned char *) RecvBuf+sizeof(struct ipheader)+sizeof(struct tcpheader); printf("-TCP-\n"); printf("\n%s\n",szDestIP); printf("\n%i\n",ntohs(pTcpheader->dport)); printf("datatcp address->%x\n",datatcp); printf("size of ipheader->%i\n",sizeof(struct ipheader)); printf("size of tcpheader->%i\n",sizeof(struct tcpheader)); printf("size of the hole packet->%i\n",ntohs(pIpheader->ip_len)); printf("\nchar Packet%i [%i]=\"",pCount,lentcp-1); for (i=0;i<lentcp;i++){ printf("\\x%.2x",*(datatcp+i)); if (i==0) printf("\"\n\""); } printf("\";\n\n\n"); for (i=0;i<lentcp;i++){ if( *(datatcp+i)=20) printf("%c",*(datatcp+i)); else printf("."); } printf("\n\n*******************************************\n"); } if((pIpheader->ip_p)==IPPROTO_UDP&&lentcp!=0){ pCount++; dataudp=(unsigned char *) RecvBuf+sizeof(struct ipheader)+sizeof(struct udphdr); printf("-UDP-\n"); printf("\n%s\n",szDestIP); printf("\n%d\n",ntohs(pTcpheader->dport)); printf("UDP%x\n",dataudp); printf("IP%i\n",sizeof(struct ipheader)); printf("UDP%i\n",sizeof(struct udphdr)); printf("%i\n",ntohs(pIpheader->ip_len)); printf("\nchar Packet%i [%i]=\"",pCount,lenudp-1); for (i=0;i<lenudp;i++){ printf("\\x%.2x",*(dataudp+i)); if (i==0) printf("\"\n\""); } printf("\";\n\n\n"); for (i=0;i<lenudp;i++){ if( *(dataudp+i)=20) printf("%c",*(dataudp+i)); else printf("."); } printf("\n\n*******************************************\n"); } } }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值