제발 도와주세요 ㅠ.ㅠ 패킷 캡쳐할때..

marionette10의 이미지

패킷 캡쳐할때 현재 eth2 에서 송신하면 eth3에서 받고 eth3에서 송신하면 eth2로 받는데..

패킷 캡쳐할때 eth2에서 받는것만 캡쳐하고싶은데..

eth2로 패킷을 송신한것도 캡쳐가 되네요..

받는것만 캡쳐하려면 필터를 주면 되는데..

eth2 ip주소를 얻어와서 어떻해 필터를 주면되죠?

예제같은 소스나 그러거 없나요? ㅠ.ㅠ 제발 도와주세요

chanik의 이미지

eth2의 IP가 192.168.123.123 이라고 가정하면, 외부로부터 받는 패킷만 캡처하려면 pcap-filter를 "dst host 192.168.123.123" 으로 주면 될 것입니다.

pcap-filter 문법은 아래 페이지 참고하시고요.
http://www.tcpdump.org/manpages/pcap-filter.7.txt

http://blog.daum.net/njaewon/33 에 간단한 캡처프로그램 샘플이 있군요. 샘플에서 조금 발췌해보면 아래와 같은 식이 되겠습니다. 그리고, 바로 코딩삽질부터 시작하지 마시고 우선 pcap 라이브러리를 잘 활용하고 있는 tcpdump나 wireshark/tshark같은 프로그램에 조금 익숙해지시는 것이 좋겠습니다.

    // 컴파일 옵션을 준다.
    if (pcap_compile(pcd, &fp, "dst host 192.168.123.123", 0, netp) == -1)
    {
        printf("compile error\n");    
        exit(1);
    }
    // 컴파일 옵션대로 패킷필터 룰을 세팅한다. 
    if (pcap_setfilter(pcd, &fp) == -1)
    {
        printf("setfilter error\n");
        exit(0);    
    }
marionette10의 이미지

쓰레드로 작동하고 있습니다.

패킷 캡쳐 각각 eth2 eth3 eht4 eth5 로 패킷을 캡쳐 하는 쓰레드를 오픈하엿고

또 eth2, eth3, eth4 eth5 로 패킷을 보내는 송신 쓰레드도 동시에 하고 있습니다.

pcap_loop 함수로 패킷을 캡쳐해서 바이트와 수신된 패킷 수 pack_recv ++ 해주고 있습니다.

그런데 저것이 무한 루프로 빠져서 끝나질 않고 있습니다.

그래서 시그널로 컨트롤 c 하면 통계 함수 호출해서 받은 패킷수를 화면에 뿌려주고 있는데

이게 송신한 바이트와 안맞아서 그러는데

여기서 받은 수신 쓰레드가 수신이 없을시 끝낼수 없나요?

for(i = 0; i < 4; i++) {
port = &ports->ports[i];
pcap1 = pcapnav_pcap(port->pcapnav);
linktype = pcap_datalink(pcap1);
validate_l2(port->pcapFilename, l2enabled, l2data, l2len, linktype);
port->linktype=linktype;
port->l2data=l2data;
port->l2len=l2len;
port->l2enabled=l2enabled;
port->pcap=NULL;
thr_id1=pthread_create(&port->portThread1, NULL, (void *)do_packets,(port_t *) port); (송신쓰레드)
thr_id=pthread_create(&port->portThread, NULL, (void *)recvpcap,(port_t *) port); (수신쓰레드)

이렇게 진행을 하고 있습니다.

chanik의 이미지

http://kldp.org/node/140637 글과 같은 내용으로 보이는데요. 질문내용을 파악하기가 어렵습니다. 질문도 좀 정리해 보시고, 코드도 빌드해서 돌려볼 수 있도록 제대로 올려주시면 댓글이 더 잘 달릴 것입니다. 오류만 재현된다면 코드가 간단할수록 좋습니다. 코드 올리실때는 아래와 같은 태그로 감싸주시고요.

[code lang="c"]
/* ... C Code ....*/
[/code]

라스코니의 이미지

어떤 작업을 일반적으로 쓰레드로 돌리면 "무한 루프로 빠져서 끝나질 않고...." 가 아니라 "사용자가 적절한 쓰레드 동기 신호를 주지 않으면 계속 작업...." 하는 것이라고 생각해야 합니다.

Ctrl + C 하면 종료하는 것도 메일 쓰레드가 ctrl + C 시그널을 받아서 나가도록 되어 있기 때문이고요.

수신이 없을시 끝낼려면 pcap 함수가 timeout 인수를 받는 것이 가능하다면 예를 들어 5 초 정도 입력이 없으면 쓰레드를 나가도록 설정할 수 있겠죠..

marionette10의 이미지

송신과 수신 쓰레드를 동시에 실행했습니다. eth2에서 송신된 패킷은 eth4로 가고 eth4에서 송신한 것은 eth2로 갑니다.

eth2,3,4,5 에서 캡쳐된 패킷 수를 각각 구하는 문제입니다.

pcap_loop로 각각 eth2, eth3, eth4 eth5 등을 캡쳐 하고 있는데요..

패킷이 수신되면 callback 함수로들어가서 처리하고 다시 나와야 되는데

callback 함수에서 계속 머물고 있어서 문제입니다..

그래서 시그널로 callback함수에 머물러있으면 시그널로 컨트롤 c해서 빠져나오게 했는데

이때 수신된 패킷수와 패킷 바이트가 송신된 패킷 수와 패킷 바이트가 맞지가 않네요

eth2에서 3개의 패킷을 송신했다면 eth4에서 패킷캡쳐를 3개를 해야하는데 1개나 아무것도 캡쳐를 못한다고 뜹니다.

문제가 무엇인지 모르겠습니다 ㅠ.ㅠ

marionette10의 이미지

수신 eth2 수신 eth3 수신 eth4 수신 eth5

송신 eth2 송신 eth3 송신 eth4 송신 eth5

이렇게 총 8개의 쓰레드를 생성하고

송신에서 쏘면 수신에서 캡쳐하여 패킷수 변수 1씩 증가하는 형식인데

수신에서 pcap_loop 콜백함수에 들어가면 프린트로 call이 찍히게 했는데

실행결과 막 진행하다가 결국

call 찍히고 멈춥니다. 그래서 시그널로 빠져나와서 통계를 프린트 하면

tx는 제대로 찍히는데 rx 수신 부분에 패킷수가 맞질 않아서 문제입니다. ㅠ.ㅠ

제발 도와주세요 ㅠ.ㅠ 네트워크 배운적이 없는데 회사에서 인턴으로 학기 인턴인데 이걸 짜오라해서...ㅠ.ㅠ

gilgil의 이미지

NIC card에서 ethernet frame을 처리할 때의 특징 중의 하나는 송신 패킷과 수신 패킷을 구분할 수 없다는 것입니다.
이를 위해서 SW측면에서 이를 구분해 주기 위해서는 ethernet header의 source mac과 destination mac을 보고 송신인지 수신인지를 체크해야 합니다.

chanik의 이미지

올려주신 코드는 [code] ... [/code]태그가 잘못 씌워져서 보기가 어렵군요. 두 태그 사이에 코드를 넣어야 하는데 닫는 태그 아래에다 넣으셨네요.

코드를 긁어다 컴파일해봐도 빠진 부분이 많아서 빌드가 안 되므로, 대략 코드를 살펴보고 느낀점만 적습니다. 제가 pcap 사용경험이 없으므로 맞지 않는 말을 하게 될지도 모르겠습니다.

첫째로, 패킷 보내는 스레드를 먼저 만들고 패킷 받는 스레드를 나중에 만들고 있는데, 받는 스레드에서 수신준비를 갖추기 전부터 보내는 스레드가 동작할 수 있으므로 초반에 보내진 일부 또는 전부의 패킷 수신이 누락될 가능성이 있겠습니다.

둘째로, 패킷 수신 스레드에 종료조건이 제대로 걸려있지 않습니다. options.limit_send 을 이용하여 종료조건을 만들고 있기는 한데, 콜백함수인 recv_callback()에는 이 조건을 확인하는 코드가 없으므로 무한루프 돌면서 계속 수신하게 되는 것이죠. pcap 자료를 보니 수신루프를 종료하려면 pcap_breakloop()을 호출하면 된다는군요.

끝으로, 프로그램 동작시킬때 tcpdump나 wireshark를 동작시켜 패킷 송수신상황을 감시하면서 해보시면 문제 파악에 도움이 될 것입니다. 그리고, 앞서 첫 댓글에 적었던 pcap-filter는 tcpdump 실행할때도 똑같이 적용되므로, 필터를 어떻게 걸어야 하는지는 tcpdump에서 먼저 확인해보시면 편할 것입니다.

marionette10의 이미지

코드를 올리기엔 헤더 파일이 너무 많아서 ...

pcap_breakloop를 호출하여 끝내도 마찬가지 입니다.

eth 4 tx 113 개 이면 eth2 rx도 113개 이어야 하는데 eth2 rx는 40개도 되었다가 73개도 되었다가 이럽니다

callback 함수를 호출하는데 문제인것 같습니다. 수신과 송신을 동시에 하다보니..

송신과 수신을 동시에 하면서 rx tx 값이 잘 나오는 프로그램이나 source 없나요?

인터페이스 4개로 서로 송수신하면서 통계를 내는건데..

큰일입니다. 수신 쓰레드가 문제인것 같은데 대체 어찌해야할지..

chanik의 이미지

이전 댓글 내용가운데 두번째 항목인 종료조건에 대한 언급만 있는 것을 보니, 다른 항목을 다 참고하시지는 않은 것 같은데요. 첫번째 항목으로 말씀드린, 수신스레드를 먼저 만들고 송신스레드를 나중에 만드는 시도를 해보셨는지요?

그리고 마지막 항목인, tcpdump나 wireshark/tshark 등을 실행시킨 상태에서 프로그램을 동작시켜 보셨나요? 검증된 캡처소프트웨어를 이용해서 실제로 각 NIC에서 오가는 패킷을 감시하면서 프로그램을 동작시키면 디버깅에 도움이 될 것입니다.

marionette10의 이미지

두번째는 종료조건을 특별히 줄게 없더라구요.. 그래서 시그널로 pcap_breakloop로 컨트롤 c누르면 pcap_breakloop로 예제처럼 했는데 그냥 프로그램이 종료되고

for(i = 0; i < 4; i++) {
thr_id=pthread_create(&port->portThread, NULL, (void *)recvpcap,(port_t *) port); //수신
thr_id=pthread_create(&port->portThread1, NULL, (void *)do_packets,(port_t *) port); //송신
}
이렇게 하면 수신 스레드가 먼저 만들어지고 송신스레드가 나중에 만들어지지 않나요?

tx값은 잘 나오는데 수신 rx값이 계속 부족하게 나오는 현상이 발생해서.. 이게 서버 장치에 연결 접속해서 패킷을 보내는거라 와이어 샤크로 찍히지가 않아

wireshark/tshark 등을 실행시킨 상태에서 프로그램을 동작시켜 보셨나요 라는 물음엔 못합니다 ㅠ.ㅠ

메일주소를 알려주시면 소스파일을 보내줄수 있는데..

죄송합니다 ㅠ.ㅠ

chanik의 이미지

스레드 생성순서는 말씀하신 바가 맞습니다. 해봐도 문제해결이 안된 것이군요. 그런데, 이전 댓글에서 "eth2에서 송신된 패킷은 eth4로 가고 eth4에서 송신한 것은 eth2로 갑니다."라는 말이 있는 것을 보면, 위 루프의 한 사이클에서 만들고 있는 수신/송신 스레드 쌍이 서로 대응되는 쌍은 아닌 것 같은데요. 그럼 여전히 송신스레드가 수신스레드보다 먼저 만들어지는 경우의 수가 남지 않나요? 아래와 같이 루프를 분리하여 수신스레드 전체를 먼저 만들고, 송신 스레드를 이후에 만들면 어떨까요?

확실히 하자면, 두 루프 사이에 nanosleep()으로 잠깐의 시차를 두어도 좋고요.

for(i = 0; i < 4; i++) {
   thr_id=pthread_create(&port->portThread, NULL, (void *)recvpcap,(port_t *) port); //수신
}
 
const struct timespec ten_ms = {0, 10*1000000};
nanosleep(&ten_ms, NULL);
 
for(i = 0; i < 4; i++) {
   thr_id=pthread_create(&port->portThread1, NULL, (void *)do_packets,(port_t *) port); //송신 
}
marionette10의 이미지

말씀하신대로 수신 쓰레드와 송신 쓰레드를 시차를 두어서 만들었는데..

적은 pcap 파일을 가지고 하면 tx나 rx 값이 맞게 잘 나오는데

100개의 패킷을 가지는 pcap 파일을 하면 tx와 rx 값이 이상하게 나옵니다 (그림 첨부)

제 생각에는 수신쓰레드에서 pcap_loop 에서 recv_callback에 빠져서 프로그램이 멈추고 있어서 signal로 빠져나와 프로그램을 종료하고 통계를 화면에 뿌려주고 있는데 수신쓰레드의 종료 시점이 문제인가.. 싶기도 하고.. ㅠ.ㅠ

아 큰일이네요 ㅠ.ㅠ 정말 ㅠ.ㅠ 너무 어렵습니다.

댓글 첨부 파일: 
첨부파일 크기
Image icon tx rx.png6.85 KB
chanik의 이미지

뭔가 결과가 달라졌다는 점이 고무적이군요.

패킷 송신스레드의 몸통인 do_packets()의 끝부분을 보면 아래의 코드가 나옵니다.

void
do_packets(port_t * file)
{
     .
     .
    /* main loop */
     .
     .
 
    if (options.limit_send == pkts_sent) {
        exit(1);
    }
    usleep(1);
    packet_stats(file);
    pthread_exit((void *) 0);
}

- 스레드 함수 안에서 exit()을 호출하는 것은 부적절합니다. exit()은 프로세스 전체를 종료할때 쓰는 함수이고, 스레드를 끝낼때는 pthread_exit()을 써야죠.
- sleep()이나 usleep()은 thread-safe 보장이 되지 않는 것으로 압니다. 특정 스레드만 쉬게하고 싶으면 nanosleep()을 써야 안전할 것입니다.

그리고, 위에 인용한 부분은 아니지만 송신/수신 스레드 join 방식도 아래와 같이 전체 스레드를 다 기다려줘야 안전할 것이고요.

    for(i = 0; i < 4; i++) {
        port = &ports->ports[i];
        pthread_join(port->portThread1, (void **) NULL);
    }
 
    for(i = 0; i < 4; i++) {
        port = &ports->ports[i];
        pthread_join(port->portThread, (void **) NULL);
    }

이 정도가 코드를 보며 드릴 수 있는 마지막 조언인것 같습니다. 각 스레드의 시작/종료 시점을 머리속에 잘 그려보시면 문제가 해결될 것입니다.
marionette10의 이미지

덕분에 많은 도움이 되었습니다.
그러나 아직까지도 패킷이 안되는데 pcap_open_live 로 디바이스를 오픈할때

PROMISCUOUS 가 적절한가요? 아 수신 쓰레드와 송신쓰레드의 문제가 아닌것 같습니다..

위에 소스를 보시면 적절하게 생성과 종료를 한것 같은데..

그리고 pcap_loop에서 콜백함수에서

종료가 되지 않아서 시그널로 종료하는데

그것때문에 그런게 아닐까요?

(소스가 짤려서 파일 첨부합니다 traf.c 를 컴파일 하면 됩니다.. )

chanik의 이미지

마지막에 올리신 코드는 붙여넣기중 문제가 생겼는지 내용도 좀 깨지면서 잘리고 보기에도 어렵습니다.
해당 댓글에 추가로 댓글이 달리기 전까지는 수정이 가능하니까 코드를 제거하든지 아니면 보기 좋게 수정해 주시면 좋겠습니다.

promiscuous 모드 설정여부는 어떤 영향이 있는지 테스트해보시면 알 수 있겟죠.
promiscuous 모드에서는 패킷들이 추가로 더 캡처될 가능성이 있지만
수신 콜백함수에서 내용물 검사하면서 걸러지거나, pcap-filter에서 차단될 수 있습니다.

그리고, 아래와 같은 식으로 버그를 잡아보시면 어떤가요?

- 스레드 갯수를 송/수신 1개씩으로 줄인 상태로 디버깅한다. 잘 되면 스레드 갯수를 늘려서 문제가 생기는지 관찰.
 
- 보내는 스레드만 동작시키는 버전, 받는 스레드만 동작시키는 버전을 만들어 따로 돌려본다.
 
- 보내는 스레드만 동작시키고 tcpdump나 tshark 등으로 수신테스트. 덤으로 pcap-filter도 연습할 수 있겠죠.
  $ sudo tshark -i eth1 -f "dst host 192.168.10.1"      # 이런 식으로 수신
  $ sudo tshark -i eth1 -f "dst host 192.168.10.1" -p   # 이렇게 하면 promiscuous 모드 끄고 수신
 
- tshark 켜둔 상태에서 받는 스레드 동작시키면서 테스트 (tshark 캡처중에도 동시에 캡처 가능함).
  패킷 100개 보냈는데, tshark에는 100개가 잡히고 받는 스레드에는 일부만 잡히는지 확인.
marionette10의 이미지

보내는 스레드와 받은 스레드를 따로 만들어서 돌려본 결과 잘나옵니다.

rx값과 tx 값이.. 근데 두개를 동시에 하면.. 안됩니다.

그래서 pcap라이브러리보다는 raw 소켓으로 패킷을 캡쳐 하라고 하는데..

raw소켓 패킷 캡쳐 source나 예제같은거 없나요?

port->sockfd=socket(PF_INET, SOCK_RAW, 145);
if(port->sockfd== -1){
printf("error\n");
exit(1);
}
while(1){
pkt_size=read(port->sockfd, buff, 1024);
if(pkt_size<0){
pthread_exit((void *) 0);
break;
}
port->stat.rxPackets++;
port->stat.rxPackets+=recvBytes;
}
이런식으로 코딩을했더니 저 while에서 무한으로 돌고 탈출을 못하더라구요 ㅠ.ㅠ

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.