抓包分析主机上网浏览了那些网页,并把浏览网页的网址写入一个文件。
首先我列举下我在写抓包程序所犯下的错误。供大家学习参考。
创建原始套接字失败:
分析原因:刚开始的时候运行程序正常,但是同事覃书芹帮我虚拟机添加了一个虚拟网卡的时候就出现错误了。原因说出来很简单,就是设备名称错误,但是当时我怎么调都调不出来。最后请他们看了下,一下就看出来了。起码让我明白创建套接字的时候要与监听的网卡名称相对应,不然要监听eth1,结果在绑定设备名称的时候绑成了eth0,那就可能出现错误,获得不到效果。
1. 写文件总是乱码:
分析原因:这个问题在我进公司前以前就犯过,那时候是用C++写,改正过来比较快。现在在全字符环境下,改了半天,最后发现,在写的时候直接传了地址,而没有加上所传字符串的长度。导致乱码,加上一个sizeof()以后问题解决。
2. 浏览部分网页时程序出现段错误:
在C环境下,出现段错误是很常见的,但对于我来说见的很少,所以出现这类问题的时候显得还不到哪错了。原因是我在定位域名字段的时候是以“com\r\n”结束为标记的。因为很多域名都是以.com结尾的,所以就忽略了还有以“.cn”或者以“.net”结尾的域名。我当时就奇怪了,为什么有的网页可以,但是访问有些域名的时候,一点击就出错。当找不到.com的时候就会定位到下一个包,定义到一个不存在的内存区域。所以导致段错误。
3. 分析的出是tcp包但是分析不出是http包:
错误原因:这个错误本来应该是不会出现的,就是我把usleep(1000),改为了sleep(1),都是停止一秒钟。在while循环里用sleep(1)可以让程序暂停执行一秒钟效果很明显,但是usleep(1000)就不是很明显了。在while循环里用sleep(1)就明显减慢了抓包的速度,所以就出现抓漏了包的情况。把while循环里的sleep(1)改成usleep(1000);就行了。
程序过程:
首先抓住经过网卡的数据包,首先检测他是不是ip包,如果是剥去包头,然后看是不是tcp包,如果是则检测它的端口是不是80端口。如果是则证明传输的是http协议。然后就可以分析是不是存在“get”字段,是不是存在“host”字段。然后取“host”后面的一个字符串,即我们要得到的主机访问的域名,即上网记录。
具体代码如下:
首先我列举下我在写抓包程序所犯下的错误。供大家学习参考。
创建原始套接字失败:
分析原因:刚开始的时候运行程序正常,但是同事覃书芹帮我虚拟机添加了一个虚拟网卡的时候就出现错误了。原因说出来很简单,就是设备名称错误,但是当时我怎么调都调不出来。最后请他们看了下,一下就看出来了。起码让我明白创建套接字的时候要与监听的网卡名称相对应,不然要监听eth1,结果在绑定设备名称的时候绑成了eth0,那就可能出现错误,获得不到效果。
1. 写文件总是乱码:
分析原因:这个问题在我进公司前以前就犯过,那时候是用C++写,改正过来比较快。现在在全字符环境下,改了半天,最后发现,在写的时候直接传了地址,而没有加上所传字符串的长度。导致乱码,加上一个sizeof()以后问题解决。
2. 浏览部分网页时程序出现段错误:
在C环境下,出现段错误是很常见的,但对于我来说见的很少,所以出现这类问题的时候显得还不到哪错了。原因是我在定位域名字段的时候是以“com\r\n”结束为标记的。因为很多域名都是以.com结尾的,所以就忽略了还有以“.cn”或者以“.net”结尾的域名。我当时就奇怪了,为什么有的网页可以,但是访问有些域名的时候,一点击就出错。当找不到.com的时候就会定位到下一个包,定义到一个不存在的内存区域。所以导致段错误。
3. 分析的出是tcp包但是分析不出是http包:
错误原因:这个错误本来应该是不会出现的,就是我把usleep(1000),改为了sleep(1),都是停止一秒钟。在while循环里用sleep(1)可以让程序暂停执行一秒钟效果很明显,但是usleep(1000)就不是很明显了。在while循环里用sleep(1)就明显减慢了抓包的速度,所以就出现抓漏了包的情况。把while循环里的sleep(1)改成usleep(1000);就行了。
程序过程:
首先抓住经过网卡的数据包,首先检测他是不是ip包,如果是剥去包头,然后看是不是tcp包,如果是则检测它的端口是不是80端口。如果是则证明传输的是http协议。然后就可以分析是不是存在“get”字段,是不是存在“host”字段。然后取“host”后面的一个字符串,即我们要得到的主机访问的域名,即上网记录。
具体代码如下:
#include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <net/ethernet.h> #include <netinet/in.h> #include <linux/if_ether.h> #include <linux/if_packet.h> #include <linux/if_arp.h> #define NOT_UNICAST(e) ((e[0] & 0x01) != 0) #define APP_NAME "pppc" #define APP_VER "0.1.0" #define PPPOE_DISCOVER 0x8863 #define PPPOE_SESSION 0x8864 #define ETH_ALEN 6 #define NET_FACE_LEN 8 #define TRUE 1 #define FALSE 0 #ifndef ETH_DATA_LEN #define ETH_DATA_LEN ETHERMTU #endif #pragma pack(1) typedef struct __st_pconn { unsigned char myName[NET_FACE_LEN]; unsigned char myEth[ETH_ALEN]; unsigned char peerEth[ETH_ALEN]; unsigned short session_id; int net_socket; } tPconn; typedef struct __st_eth_head { unsigned char dst[ETH_ALEN]; unsigned char src[ETH_ALEN]; unsigned short proto; } tEthHead; typedef struct __st_pppoe_head { unsigned char ver:4; unsigned char type:4; unsigned char code; unsigned short sid; unsigned short len; } tPPPPOEHead; typedef struct __st_pppoe_pkt_info { tEthHead ethHead; tPPPPOEHead pppoeHead; unsigned char payload[32]; } tPPPOEPkt; typedef struct __st_ip_pkt_head { //unsigned char hlen:4; //unsigned char ver:4; unsigned char vhlen; unsigned char tos; unsigned short tlen; unsigned short ipid; unsigned short flag; unsigned char ttl; unsigned char proto; unsigned short checksum; unsigned long sip; unsigned long dip; unsigned char data[1]; } tIPktHead; typedef struct _st_tcp { unsigned short sport; unsigned short dport; unsigned long seq; unsigned long ack; unsigned char offset; unsigned char code; unsigned short window; unsigned short cksum; unsigned short urg; unsigned char data[1]; } tTcp; #pragma pack() /////////////////////////////// Define public var ////////////////////////////// tPconn myConn; /////////////////////////// End of Define public var /////////////////////////// char *inet_htoa(unsigned long ipaddr) { static char buf[10][20]; static int old_index=0; int index; unsigned char t1; unsigned char bFlag = FALSE; char *pbuf; index = old_index; old_index = (old_index+1) % 10; pbuf = buf[index]; t1 = (ipaddr >> 24) & 0xff; *pbuf = (t1 / 100); if (*pbuf != 0) { *pbuf += 0x30; pbuf++; bFlag = TRUE; } *pbuf = ((t1 / 10) % 10); if (*pbuf != 0) { *pbuf += 0x30; pbuf++; } else if (bFlag) { *pbuf += 0x30; pbuf++; } *pbuf++ = (t1 % 10) + 0x30; *pbuf++ = '.'; /******************************/ bFlag = FALSE; t1 = (ipaddr >> 16) & 0xff; *pbuf = (t1 / 100); if (*pbuf != 0) { *pbuf += 0x30; pbuf++; bFlag = TRUE; } *pbuf = ((t1 / 10) % 10); if (*pbuf != 0) { *pbuf += 0x30; pbuf++; } else if (bFlag) { *pbuf += 0x30; pbuf++; } *pbuf++ = (t1 % 10) + 0x30; *pbuf++ = '.'; /******************************/ bFlag = FALSE; t1 = (ipaddr >> 8) & 0xff; *pbuf = (t1 / 100); if (*pbuf != 0) { *pbuf += 0x30; pbuf++; bFlag = TRUE; } *pbuf = ((t1 / 10) % 10); if (*pbuf != 0) { *pbuf += 0x30; pbuf++; } else if (bFlag) { *pbuf += 0x30; pbuf++; } *pbuf++ = (t1 % 10) + 0x30; *pbuf++ = '.'; /******************************/ bFlag = FALSE; t1 = ipaddr & 0xff; *pbuf = (t1 / 100); if (*pbuf != 0) { *pbuf += 0x30; pbuf++; bFlag = TRUE; } *pbuf = ((t1 / 10) % 10); if (*pbuf != 0) { *pbuf += 0x30; pbuf++; } else if (bFlag) { *pbuf += 0x30; pbuf++; } *pbuf++ = (t1 % 10) + 0x30; *pbuf = '\0'; pbuf = buf[index]; return pbuf; } int init_rawsocket(char *dev_name) { int raw_sock_fd; struct sockaddr_ll sll; struct ifreq ifstruct; memset(&sll, 0, sizeof(struct sockaddr_ll)); strcpy(ifstruct.ifr_name, dev_name); raw_sock_fd = socket(PF_PACKET, SOCK_RAW, htons(IPPROTO_RAW)); if (ioctl(raw_sock_fd, SIOCGIFINDEX, &ifstruct) == -1)//指定socket,把信息存入到ifstruct中 { printf("ioctl SIOCGIFINDEX [%s] Error!!!", dev_name); close(raw_sock_fd); exit(1); return -1; } sll.sll_family = PF_PACKET; sll.sll_ifindex = ifstruct.ifr_ifindex; sll.sll_protocol = htons(ETH_P_ALL); sll.sll_hatype = ARPHRD_ETHER; sll.sll_pkttype = PACKET_OTHERHOST; sll.sll_halen = ETH_ALEN; sll.sll_addr[6] = 0; sll.sll_addr[7] = 0; if (ioctl(raw_sock_fd, SIOCGIFHWADDR, &ifstruct) == -1) { printf("\nioctl SIOCGIFHWADDR [%s] Error!!!", dev_name); close(raw_sock_fd); exit(1); return -1; } if (ioctl(raw_sock_fd, SIOCGIFFLAGS, &ifstruct) < 0) { printf("ioctl SIOCGIFFLAGS [%s] Error!!!", dev_name); close(raw_sock_fd); exit(1); return -1; } #if 1 ifstruct.ifr_flags |= IFF_PROMISC; //set promisc if (ioctl(raw_sock_fd, SIOCSIFFLAGS, &ifstruct) == -1) { printf("Set [%s] promisc error\n", dev_name); close(raw_sock_fd); exit(1); return -1; } #endif if (bind(raw_sock_fd, (struct sockaddr *)&sll, sizeof(struct sockaddr_ll)) == -1) { printf("Bind %s Error!", dev_name); close(raw_sock_fd); exit(1); return -1; } return raw_sock_fd; } /* End of init_rawsocket */ int init_netface(tPconn *pPconn) { struct ifreq ifr; struct sockaddr_ll pSock; int optval = 1; if (!pPconn) return 0; //把创建 的socket套接字传给pCONN pPconn->net_socket = init_rawsocket(pPconn->myName); printf("Raw fd [%d]\n", pPconn->net_socket); strncpy(ifr.ifr_name, pPconn->myName, NET_FACE_LEN); //获取网卡的MAC地址 if (ioctl(pPconn->net_socket, SIOCGIFHWADDR, &ifr) < 0) { printf("ioctl(SIOCGIFHWADDR) error"); exit(0); } memcpy(pPconn->myEth, ifr.ifr_hwaddr.sa_data, ETH_ALEN); printf("Get [%s], MAC [%02x:%02x:%02x:%02x:%02x:%02x]\n", pPconn->myName, pPconn->myEth[0], pPconn->myEth[1], pPconn->myEth[2], pPconn->myEth[3], pPconn->myEth[4], pPconn->myEth[5]); return 1; } int main(int argc, char **argv) { int raw_fd = 0; int rlen = 0; int n = 0; char buff[1500] = {0}; tEthHead *pEth = NULL; tIPktHead*pOeh = NULL; tTcp *ptcp = NULL; char *tcpdata = NULL; char *tcpdend = NULL; int tcpdatalen = 0; char data [1024]={0} ; char *host = NULL; char *hostend = NULL; char hostdata[1024]={0}; char ptjay[30]; memset(&myConn, 0, sizeof(tPconn)); sprintf(myConn.myName, "eth0"); init_netface(&myConn); printf("%s (v%s) started\n", APP_NAME, APP_VER); printf("Eth head len %d, PPPOE head len %d, PPPOE pkt len %d\n", sizeof(tEthHead), sizeof(tPPPPOEHead), sizeof(tPPPOEPkt)); while (1) { //send_PADI(&myConn); rlen = read(myConn.net_socket, buff, 1514);//读取数据报 if (rlen > 0) { pEth = (tEthHead *)buff; // printf("Get a packet, DMAC [%02x:%02x:%02x:%02x:%02x:%02x], SMAC [%02x:%02x:%02x:%02x:%02x:%02x]\n", // pEth->dst[0], pEth->dst[1],pEth->dst[2],pEth->dst[3],pEth->dst[4],pEth->dst[5], // pEth->src[0], pEth->src[1],pEth->src[2],pEth->src[3],pEth->src[4],pEth->src[5]); switch (ntohs(pEth->proto)) { case 0x0800: { pOeh = (tIPktHead*)(buff+sizeof(tEthHead)); // printf("Get a ip packet\n"); // printf("SIP[%s], DIP[%s], ipid [%d], tlen [%d], ver [%d], hlen [%d]\n", // inet_htoa(ntohl(pOeh->sip)), inet_htoa(ntohl(pOeh->dip)), // ntohs(pOeh->ipid), ntohs(pOeh->tlen), (pOeh->vhlen&0xf0)>>4, (pOeh->vhlen&0x0f)<<2); switch (pOeh->proto) { case 0x06: { //printf("Get a TCP packet\n"); ptcp = (tTcp*)pOeh->data; //printf("%d\n",ntohs(ptcp->dport)); if (ntohs(ptcp->dport)==80) { // printf("Get a http packet\n"); tcpdata = (char*)(ptcp->data); if(strncmp(tcpdata, "GET ", 4) == 0) { //printf("Get a get http packet\n"); tcpdend = strstr(ptcp->data, " HTTP/1.1\r\n"); printf("http data is \n"); tcpdata += 4; tcpdatalen = tcpdend-tcpdata; printf("%d\n", tcpdatalen); printf("%s\n", strncpy(data, tcpdata, tcpdatalen)); host = strstr(ptcp->data, "Host: "); strncpy(ptjay,host,30); printf("测试用的%s\n",ptjay); hostend = strstr(ptjay, "\r\n"); strncpy(ptjay,hostend,5); printf("测试用的二%s",ptjay); tcpdatalen = hostend - host; printf("%s\n",strncpy(hostdata, host, tcpdatalen)); host=NULL; hostend=NULL; strncpy(data,"0",1); strncpy(ptjay,"0",1); } //else // printf("Get other http packet\n"); } // else // printf("Get not http packet\n"); } break; default: // printf("Get not tcp packet\n"); break; } } break; default: //printf("Get other packet\n"); break; } } //printf("Send PADI\n"); //printf("包结束\n"); usleep(1000); } }
int init_rawsocket(char *dev_name) { int raw_sock_fd; struct sockaddr_ll sll; struct ifreq ifstruct; memset(&sll, 0, sizeof(struct sockaddr_ll)); strcpy(ifstruct.ifr_name, dev_name); raw_sock_fd = socket(PF_PACKET, SOCK_RAW, htons(IPPROTO_RAW)); if (ioctl(raw_sock_fd, SIOCGIFINDEX, &ifstruct) == -1)//指定socket,把信息存入到ifstruct中 { printf("ioctl SIOCGIFINDEX [%s] Error!!!", dev_name); close(raw_sock_fd); exit(1); return -1; } sll.sll_family = PF_PACKET; sll.sll_ifindex = ifstruct.ifr_ifindex; sll.sll_protocol = htons(ETH_P_ALL); sll.sll_hatype = ARPHRD_ETHER; sll.sll_pkttype = PACKET_OTHERHOST; sll.sll_halen = ETH_ALEN; sll.sll_addr[6] = 0; sll.sll_addr[7] = 0; if (ioctl(raw_sock_fd, SIOCGIFHWADDR, &ifstruct) == -1) { printf("\nioctl SIOCGIFHWADDR [%s] Error!!!", dev_name); close(raw_sock_fd); exit(1); return -1; } if (ioctl(raw_sock_fd, SIOCGIFFLAGS, &ifstruct) < 0) { printf("ioctl SIOCGIFFLAGS [%s] Error!!!", dev_name); close(raw_sock_fd); exit(1); return -1; } #if 1 ifstruct.ifr_flags |= IFF_PROMISC; //set promisc if (ioctl(raw_sock_fd, SIOCSIFFLAGS, &ifstruct) == -1) { printf("Set [%s] promisc error\n", dev_name); close(raw_sock_fd); exit(1); return -1; } #endif if (bind(raw_sock_fd, (struct sockaddr *)&sll, sizeof(struct sockaddr_ll)) == -1) { printf("Bind %s Error!", dev_name); close(raw_sock_fd); exit(1); return -1; } return raw_sock_fd; } /* End of init_rawsocket */ int init_netface(tPconn *pPconn) { struct ifreq ifr; struct sockaddr_ll pSock; int optval = 1; if (!pPconn) return 0; //把创建 的socket套接字传给pCONN pPconn->net_socket = init_rawsocket(pPconn->myName); printf("Raw fd [%d]\n", pPconn->net_socket); strncpy(ifr.ifr_name, pPconn->myName, NET_FACE_LEN); //获取网卡的MAC地址 if (ioctl(pPconn->net_socket, SIOCGIFHWADDR, &ifr) < 0) { printf("ioctl(SIOCGIFHWADDR) error"); exit(0); } memcpy(pPconn->myEth, ifr.ifr_hwaddr.sa_data, ETH_ALEN); printf("Set mac?"); if(getchar()=='y') { printf("mac:"); scanf("%02x%02x%02x%02x%02x%02x",&pPconn->myEth[0], &pPconn->myEth[1], &pPconn->myEth[2], &pPconn->myEth[3], &pPconn->myEth[4], &pPconn->myEth[5]); } printf("Get [%s], MAC [%02x:%02x:%02x:%02x:%02x:%02x]\n", pPconn->myName, pPconn->myEth[0], pPconn->myEth[1], pPconn->myEth[2], pPconn->myEth[3], pPconn->myEth[4], pPconn->myEth[5]); return 1; } /*构造PADT数据包,结束PPPOE会话*/ tPPPOEPkt * makepadt(tPPPOEPkt * phead) { unsigned short sessionid; sessionid = phead->pppoeHead.sid; if (phead != NULL) { phead->pppoeHead.code= 0xA7; phead->pppoeHead.len = 0x0000; phead->pppoeHead.sid = sessionid; phead->payload[0] = 0; } return phead; } int main(int argc, char **argv) { int raw_fd = 0; int rlen = 0; int n = 0; char buff[1500] = {0}; char netcard[6]="eth0"; tEthHead * pEth= NULL; tPPPOEPkt * pPPPhd = NULL; int num = 0; unsigned short i; memset(&myConn, 0, sizeof(tPconn)); //scanf("%s",&netcard); //getchar(); sprintf(myConn.myName, netcard); init_netface(&myConn); while (1) { //send_PADI(&myConn); rlen = read(myConn.net_socket, buff, 1514); if (rlen > 0) { pEth = (tEthHead *)buff; /*过滤PPPOE的数据包*/ //if (ntohs(pEth->proto) == 0x8863) //{ pPPPhd = (tPPPOEPkt *)pEth; printf("%u\n",pPPPhd->pppoeHead.sid); if (ntohs(pPPPhd->pppoeHead.sid) != 0x0000) { printf("!0x0000\n"); pPPPhd = makepadt(pPPPhd); //send the changed package rlen = write(myConn.net_socket,(char *)pPPPhd, rlen); printf("the len is %d\n", rlen); } //} } usleep(1000); } return 0; }
相关推荐
linux下利用原始套接字抓取网络数据。用GCC编译,运行时要指定网口,以管理员身份运行Ubuntu下: gcc -o sniffer sniffer.c sudo ./sniffer eth0
linux下使用原始套接字抓包并发现网络网元,构造数据包,实现过滤规则与数据包统计
linux 下的一个小软件,使用原始套接字实现所有的底层抓包分析,注意用root 权限运行
本主题将深入探讨如何使用Linux原始套接字(raw sockets)来抓取网络数据包,以及`tgsniffer`这个源代码项目。原始套接字允许我们访问网络协议栈的底层,直接处理原始的数据包,而不仅仅是应用层的协议,如TCP或UDP...
在Linux环境下编写一个网卡抓包程序,可以通过原始套接字(raw socket)对本机网卡上的数据包进行捕获。原始套接字允许程序员访问网络层以下的数据包,可以用来开发网络监控工具、协议分析器等应用。网卡抓包程序...
总之,Linux下的IP数据包抓包和分析涉及网络编程和协议解析,通过C语言和原始套接字,我们可以直接与网络接口交互,获取并分析原始数据包。同时,使用Makefile进行自动化构建,确保项目的可移植性和编译效率。这是一...
通过读取网络设备的原始套接字(raw sockets),tcpdump能够解析并显示不同协议层(如IP、TCP、UDP、ICMP等)的信息。 在使用tcpdump时,我们通常会遇到以下几个核心概念: 1. **命令行参数**:tcpdump提供了丰富...
综上所述,这个“C语言实现的网卡监控抓包代码”项目涵盖了诸多核心IT概念,包括网络数据包抓取原理、C语言编程、套接字编程、网络协议理解、数据处理和文件I/O操作。对于学习计算机科学的学生而言,完成这样一个...
本项目“c语言抓包并分析”提供了一个纯C语言实现的示例,帮助开发者了解如何利用原始套接字(raw sockets)进行网络数据包的捕获和解析。以下是对该项目及相关知识点的详细解释。 1. **原始套接字(Raw Sockets)*...
"scratch_devsocket_抓包_"这个标题暗示了我们将探讨如何利用`devsocket`(设备套接字)来实现抓包功能,这通常涉及到系统底层的网络编程。下面我们将深入解析这一主题。 首先,`SOCK_RAW`是套接字(socket)编程中...
这个ARP抓包程序的实现,不仅展示了如何在Linux环境下使用原始套接字捕获网络数据,还涉及到网络协议栈中不同层次的交互,特别是数据链路层的以太网帧和网络层的ARP协议。通过这样的程序,可以监控网络流量,分析...
在IT行业中,网络数据包捕获(通常称为“抓包”)是一种常用的技术,用于监控网络通信、诊断问题或进行安全分析。WPS(Wi-Fi Protected Setup)是Wi-Fi联盟推出的一种简化Wi-Fi设备配置的方法,它允许用户快速、安全...
本程序的核心原理是利用Java的套接字编程和网络协议知识,通过捕获网络接口上的数据包来解析和显示网络流量。 在Java中,实现网络抓包主要涉及以下几个关键技术点: 1. **JNI(Java Native Interface)**:因为Java...
总的来说,这个程序展示了如何使用原始套接字进行网络数据抓包,并对抓取到的数据进行基本的分析。然而,由于涉及到底层网络操作,这种技术通常需要相应的权限,并且不适合初学者直接尝试,因为错误的使用可能会导致...
1. **套接字通信**:在Windows系统中,进程间的通信通常通过套接字(Sockets)进行,包括TCP和UDP等协议。Wireshark可以解析这些协议的数据包,帮助我们查看发送和接收的数据。 2. **过滤器的使用**:Wireshark提供...
- 创建一个原始套接字(`AF_PACKET, SOCK_RAW, ETH_P_ALL`),其中 `AF_PACKET` 表示原始网络层协议套接字,`SOCK_RAW` 表示原始套接字类型,`ETH_P_ALL` 表示接受所有以太网帧。 2. **设置混杂模式**: - 使用 ...
在传统的网络编程中,我们通常使用套接字(Sockets)进行网络通信,它们工作在网络层(IP层),遵循TCP/IP协议栈。然而,L2socket提供了一种直接在数据链路层进行通信的方法,绕过了网络层的IP处理,适用于需要底层...
3. **端口与套接字(Socket)**:Socket是应用层与TCP/IP协议族通信的接口。每个Socket由IP地址和端口号唯一标识,SocketTool能够显示通信中涉及的所有Socket连接。 4. **抓包原理**:SocketTool通过监听网络接口,...
这通常利用操作系统提供的原始套接字(raw socket)接口或者网络驱动程序的特殊功能实现。 2. **网络协议分析**:抓包软件能解析捕获到的数据包,展示各个协议层(如应用层、传输层、网络层、数据链路层等)的信息...
libpcap利用操作系统提供的原始套接字(raw sockets)或者特定的内核驱动(如PF_PACKET在Linux下),直接访问网络接口的数据链路层。当数据包在网卡上传输时,libpcap能够拦截并复制这些数据包到用户空间,供应用...