void test(const char* exp, const char* dev) { int sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); if (sock<=0) { P("socket error"); return; } //设置缓冲区 #define PER_PACKET_SIZE 2048 const int BUFFER_SIZE = 1024*1024*16; //16MB的缓冲区 struct tpacket_req req; req.tp_block_size = 4096; req.tp_block_nr = BUFFER_SIZE/req.tp_block_size; req.tp_frame_size = PER_PACKET_SIZE; req.tp_frame_nr = BUFFER_SIZE/req.tp_frame_size; if (-1==setsockopt(sock, SOL_PACKET, PACKET_RX_RING, &req, sizeof(struct tpacket_req))) { perror("setsockopt"); P("set PACKET_RX_RING error"); close(sock); return; } //映射缓冲区 char* pBuffer = (char*)mmap(0, BUFFER_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, sock, 0); if (MAP_FAILED==pBuffer) { P("mmap error"); close(sock); return; } //注意:一定要先映射后再绑定,否则会有问题 // 问题的详细描述可参考:https://lists.linux-foundation.org/pipermail/bugme-new/2003-October/009110.html if (!SetPromisc(sock, dev)) { P("SetPromisc [%s] error", dev); memset(&req, 0, sizeof(req)); if (-1==setsockopt(sock, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req))) { P("set map buffer to 0 error!"); } close(sock); return; } if (!BindDevice(sock, dev)) { P("bind [%s] error", dev); memset(&req, 0, sizeof(req)); if (-1==setsockopt(sock, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req))) { P("set map buffer to 0 error!"); } close(sock); return; } //设置过滤器 int nExpLen = strlen(exp); struct sock_fprog Filter; memset(&Filter, 0, sizeof(struct sock_fprog)); if (nExpLen>0) { if (ExpressionToFilter(exp, &Filter)) { if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter))<0) { perror("setsockopt"); } } } // struct pollfd pfd; int nIndex = 0; for (; ; ) { for (; ; ) { struct tpacket_hdr* pHead = (struct tpacket_hdr*)(pBuffer + nIndex*PER_PACKET_SIZE); if (pHead->tp_len<34 || pHead->tp_len>1614) { break; } PrintPacket((char*)pHead+pHead->tp_net); pHead->tp_len = 0; pHead->tp_status = TP_STATUS_KERNEL; //注意:pHead->tp_status这个变量并不能真正反应出包的处理状态, //在有的服务器上 TP_STATUS_USER(1)代表包可用, TP_STATUS_KERNEL(0)代表包不可用 //但是在有的服务器上,这个标志变量无效 //对于这个问题我还没找到原因 nIndex++; if (nIndex>=BUFFER_SIZE/PER_PACKET_SIZE) { nIndex = 0; } } // pfd.fd = sock; pfd.events = POLLIN | POLLERR; pfd.revents = 0; switch (poll(&pfd, 1, 1000)) { case -1: perror("poll"); P("poll error"); goto EndWhile; break; case 0: P("time out"); continue; break; } } EndWhile: if (-1==munmap(pBuffer, BUFFER_SIZE)) { P("unmap error!"); } memset(&req, 0, sizeof(req)); if (-1==setsockopt(sock, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req))) { P("set map buffer to 0 error!"); } close(sock); sock = -1; // if (nExpLen>0) { FreeFilter(&Filter); } }
void StartSniffer(struct ISlist *iq) { struct ifreq newfl; struct iovec packet_ring; struct tpacket_hdr *packet_hdr; struct pollfd pfd; register int i; int size; iq -> fd = CreateSocket(PF_PACKET, SOCK_RAW, iq -> args -> protocol); newfl = GetIndex(iq -> fd, iq -> args -> device); //promiscous mode SetPromisc(iq -> fd, newfl); //calculate packet request for packet_ring iq -> packet_req = CalculatePacket(); RequestPacketRing(iq -> fd, PACKET_RX_RING, *(iq -> packet_req)); size = iq -> packet_req -> tp_block_size * iq -> packet_req -> tp_block_nr; iq -> ps_hdr_start =(unsigned char *) mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, iq -> fd, 0); if ( iq -> ps_hdr_start == MAP_FAILED ) { perror("mmap()"); DestroySocket(iq -> fd); exit(ERROR); } pfd.fd = iq -> fd; pfd.revents = 0; pfd.events = POLLIN|POLLRDNORM|POLLERR; i = 0; while(i < iq->args->packet_num || iq->args->packet_num == 0) { packet_hdr = (struct tpacket_hdr *) (iq -> ps_hdr_start+iq -> packet_req -> tp_frame_size*i); switch(packet_hdr -> tp_status) { case TP_STATUS_KERNEL: if ( poll(&pfd, 1, -1) < 0 ) { perror("poll: "); exit(ERROR); } if ( packet_hdr -> tp_status != TP_STATUS_USER ) packet_hdr -> tp_status = TP_STATUS_USER; break; case TP_STATUS_USER: case 5: case 9: case 13: packet_ring.iov_base = ((unsigned char *)packet_hdr+packet_hdr -> tp_mac); packet_ring.iov_len = iq -> packet_req -> tp_frame_size - packet_hdr -> tp_mac; iq -> args -> FunctionPtr(&packet_ring, iq -> args -> argv); packet_hdr -> tp_status = TP_STATUS_KERNEL; if ( iq -> args->packet_num >= iq -> packet_req -> tp_frame_nr ) iq->args->packet_num--; i = (((unsigned)i) == (unsigned)iq -> packet_req -> tp_frame_nr-1)? 0 : i+1; break; default: if ( poll(&pfd, 1, -1) < 0 ) { perror("poll: "); exit(ERROR); } if ( iq -> args -> packet_num >= iq -> packet_req -> tp_frame_nr ) iq->args->packet_num--; i = (((unsigned)i) == (unsigned)iq -> packet_req -> tp_frame_nr-1)? 0 : i+1; break; } } }