C에서 리눅스에서 PROMISC 인터페이스를 설정하고 원시 소켓을 사용하면 read()를 통해 인터페이스에서 들어오는 패킷을 읽을 수있다.PF_PACKET에서 읽음 read()가 패킷을 놓친다
그러나 모든 패킷을 가져 오지는 않습니다. Read() 블록은 "긴"시간 (< 1 초이지만 패킷은 초당 수백 개로 흐릅니다)을 사용하여 파일 디스크립터에서 다음 사용 가능한 데이터를 읽습니다.
누락되었거나 근본적으로 잘못된 것이 있어야합니다.
"libpcap 사용"은 유효한 응답자가 아닙니다. 나는 (libpcap의 패킷을 놓치지 않음)
가 FD를 초기화 자신의 코드를 보았고, 그 차이를 찾을 수 없습니다 :if ((fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {
perror("socket(PF_PACKET) failed");
return 1;
}
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1);
if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
perror("ioctl(SIOCGIFINDEX) failed");
return 1;
}
memset(&sll, 0, sizeof(sll));
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifr.ifr_ifindex;
sll.sll_protocol = htons(ETH_P_ALL);
if ((ifr.ifr_flags | IFF_UP | IFF_BROADCAST | IFF_RUNNING) != ifr.ifr_flags) {
ifr.ifr_flags |= IFF_UP | IFF_BROADCAST | IFF_RUNNING;
if(ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
perror("ioctl(SIOCSIFFLAGS) failed");
return 1;
}
}
if (bind(fd, (struct sockaddr *) &sll, sizeof(sll)) < 0) {
perror("bind(ETH_P_ALL) failed");
return 1;
}
if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0)
{
perror("ioctl(SIOCGIFHWADDR) failed");
return 1;
}
if (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211 &&
ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_PRISM &&
ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_FULL)
{
if (ifr.ifr_hwaddr.sa_family == 1)
fprintf(stderr, "\nARP linktype is set to 1 (Ethernet) ");
else
fprintf(stderr, "\nUnsupported hardware link type %4d ",
ifr.ifr_hwaddr.sa_family);
fprintf(stderr, "- expected ARPHRD_IEEE80211,\nARPHRD_IEEE80211_"
"FULL or ARPHRD_IEEE80211_PRISM instead. Make\n"
"sure RFMON is enabled: run 'airmon-ng start %s"
" <#>'\nSysfs injection support was not found "
"either.\n\n", iface);
return 1;
}
memset(&mr, 0, sizeof(mr));
mr.mr_ifindex = sll.sll_ifindex;
mr.mr_type = PACKET_MR_PROMISC;
if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) < 0) {
perror("setsockop(PACKET_MR_PROMISC) failed");
return 1;
}
읽기 :
while (caplen > 0) {
if ((caplen = read(fd, p, read_size)) < 0) {
perror("read failed");
break;
}
p += caplen;
read_size -= caplen;
}
}
나는 또한 zerocopy (= mmap 사용)로 시도했지만 문제는 동일했습니다. 코드의 다른 부분으로 인해 처음부터 다시 작성 했으므로 제대로 작동합니다. 그것은 확실히 위의 부분에 있으며 어떤 일이 벌어지고 있는지를 이해하기 위해 그것을 나눌 것입니다. sll 초기화에서 빠진 매개 변수 일 수 있습니다. 그 사이에 내가 손을 부러 뜨 렸어. – user1321333