2012-07-24 4 views
6

나는 (원시 소켓을 사용하여) 호스트에 TCP SYN 패킷 세트를 보내고 응답을 얻기 위해 libpcap (필터 포함)을 사용하는 프로그램이있다. 이 비동기 I/O를 프레임 워크에서 구현하려면 노력하고있어하지만 그것은 libpcap 응답의 일부 (즉, TCP SYN 및 응답 사이에 미만 100 microseconds 소요될 때 일련의 첫 번째 패킷) 누락 된 것으로 보인다.비동기식 libpcap : 패킷 손실?

pcap_t* pcap = pcap_open_live(NULL, -1, false, -1, errorBuffer); 
pcap_setnonblock(pcap, true, errorBuffer); 

가 그럼 난합니다 (filterExpression 문자열에 포함) 필터를 추가 :

struct bpf_program filter; 
pcap_compile(pcap, &filter, filterExpression.c_str(), false, 0); 
pcap_setfilter(pcap, &filter); 
pcap_freecode(&filter); 

그리고 루프에

, 각각의 패킷을 전송 한 후, 내가 알고 사용을 선택 PCAP 핸들이 같은 설정이다 나는 libpcap의에서 읽을 수있는 경우 :

int pcapFd = pcap_get_selectable_fd(pcap); 
fd_set fdRead; 
FD_ZERO(&fdRead); 
FD_SET(pcapFd, &fdRead); 
select(pcapFd + 1, &fdRead, NULL, NULL, &selectTimeout); 

을 그리고 그것을 읽고 :

if (FD_ISSET(pcapFd, &fdRead)) { 
    struct pcap_pkthdr* pktHeader; 
    const u_char* pktData; 
    if (pcap_next_ex(pcap, &pktHeader, &pktData) > 0) { 
     // Process received response. 
    } 
    else { 
     // Nothing to receive (or error). 
    } 
} 

앞에서 말했듯이 일부 패킷은 누락되었습니다 ("수신 할 수 없음"). 동기식으로 (또는 pcap_loop을 실행하는 스레드를 사용하여) 캡처 할 수 있기 때문에이 패킷이 있다는 것을 알고 있습니다. 여기에 세부 사항이 빠졌습니까? 아니면 libpcap의 문제입니까?

+0

너무 많은 요청을 너무 빨리 보내고 서버가 응답을 더 빨리 보내면 처리 할 수 ​​있으므로 OS의 네트워크 버퍼 오버로드와 패킷 삭제가 발생할 수 있습니다. 또는 수신기 소켓이 초기 응답을 처리 할 시간 내에 설정되어 있지 않을 수도 있습니다. 귀하가받는 것으로 가정 한 모든 응답이 실제로 도착하고 있는지 확인할 수 있습니까? Todo는 애플리케이션과 동일한 인터페이스에서 동시에 tcpdump를 실행합니다.tcpdump에서 여러분이 기대하는 모든 패킷을 보았을 때, 여러분의 응용 프로그램에 없다면 위의 문제 중 하나가있을 수 있습니다. – ryanbwork

+0

나는 이미 그것을 해왔다. (측면에는 tcpdump뿐 아니라 다른 스레드로도 pcap_loop한다.) 모든 패킷이 거기에 있었다. 따라서 나는 응답을 너무 빨리 보내고 있다고 생각하지 않는다. 수신기 소켓 (즉, libpcap)이 아직 설정되지 않았는지 어떻게 알 수 있습니까? 잃어버린 응답은 항상 첫 번째 또는 두 번째이므로 의미가 있습니다. –

+0

tcpdump에서 패킷을 볼 수 있더라도 응용 프로그램이받은 속도를 처리 할 수없는 경우 OS에서 패킷을 삭제할 수 있습니다. 응답이 이미 전송 된 후에 응용 프로그램이 시작되는 경우 서버에서 초기 응답을 보내기 전에 상당한 지연을 추가하십시오. 모든 응답을 성공적으로 받으면 문제점을 발견했습니다. – ryanbwork

답변

1

이것은 Linux에서 메모리 매핑을 사용하는 libpcap에서 문제가되는 것 같습니다. 자세한 내용은 my other question을 참조하십시오.

+0

그래서이 문제가 해결 되었습니까? 어떻게 libpcap에 대한 메모리 맵핑을 가능하게 하는가? – misteryes

1

pcap_t의 FD가 select() 읽을 수로보고하는 경우, 이것은 단지 하나의 패킷은 차단하지 않고 읽을 수 있다는 것을 의미한다는 보장은 없습니다 (또는 poll() 또는 무엇이든 전화 사용중인/메커니즘).

pcap_next_ex()을 사용하는 경우 하나의 패킷 만 읽습니다. 하나 이상의 패킷을 읽을 수있는 경우 다른 패킷을 select()으로 다시 보내면 다시 FD가 다시 읽을 수 있다고보고하고이 경우 다시 pcap_next_ex()을 호출하는 등의 작업을 수행해야합니다. 이는 패킷 당 하나 이상의 시스템 호출 (select())을 의미하며, 수행중인 OS의 버전 및 사용중인 libpcap의 버전에 따라 더 많은 호출이 가능합니다.

대신 패킷 수 인수가 -1 인 pcap_dispatch()을 호출하면 단일 호출 작업으로 얻을 수있는 모든 패킷이 반환되어 모든 패킷을 처리하므로 대부분의 경우 플랫폼을 사용하면 여러 패킷을 사용할 수있는 경우 하나 또는 두 개의 시스템 호출로 여러 패킷을 얻을 수 있습니다 (높은 네트워크 트래픽이 발생하면 SYN 홍수로 프로그램을 테스트하는 경우 얻을 수 있음) .

또한, 메모리 매핑 패킷 캡처를 지원하는 Linux 시스템 (모든 2.6 커널 및 모든 커널이 그렇다고 생각합니다.)과 libpcap의 최신 버전을 사용하면 pcap_next_ex()에서 복사본을 만들어야합니다 커널이 패킷을 처리하는 코드 아래에서 패킷을 변경하는 것을 피하고 링 버퍼의 슬롯을 무기한으로 고정시키는 것을 피하기 위해 여분의 복사본이 필요합니다.

+0

+1 비동기 I/O에 익숙하지 않은 사용자를위한 일반적인 함정 : 읽고 있어야합니다!))) –

+0

유용한 정보이지만 여기에는 해당되지 않습니다. 주된 문제는 활성'pcap_t'를 고발 한 후'pcap_next_ex'가 0을 반환한다고 비난하는'선택'입니다. "잃어버린 패킷"이 "수신 할 것"으로 떨어지는 것에주의하십시오. –