[질문]pcap과 pthread를 이용하여 패킷을 캡쳐 하려고 합니다. 디바이스 이름을 정확하게 출력하고 싶습니다.

soulcrime의 이미지

pcap과 pthread를 이용하여 디바이스 수만큼 쓰레드를 생성하고 각각의 쓰레드에서는 해탕 디바이스로 들어오는 패킷을 캡쳐하여 해당디바이스 이름과 src_ip, dst_ip를 출력하고자 합니다.

다음과 같은 환경에서 패킷을 캡쳐하려고 합니다.
- 운영 체제 : RHEL4
- 랜포트 : 2개 (eth0 : 111.111.111.111, eth1 : 222.222.222.222)

1. 디바이스 alias를 얻어와서 얻어온 디바이스만큼 쓰레드를 생성합니다.
2. 쓰레드를 생성할때 인자로 디바이스 alias를 넘겨줍니다.
3. 쓰레드가 시작되면 디바이스 alias로 pcap_open_live()을 사용하여 장치를 열고 패킷캡쳐를 시작합니다.
(NOPROMISCUOUS 모드로 했습니다)

4. 패킷캡쳐는 pcap_next()를 사용하여 무한루프를 돌렸습니다.(데몬형태로 계속 캡쳐를 해야하기 때문입니다).

특정포트로 들어오는 패킷만 장치이름과 src_ip, dst_ip를 출력합니다.

5. 서버에서 위 프로그램을 실행시켜놓고 다른 2개의 컴퓨터에서 패킷을 발생시켜서 각각의 랜포트로 패킷을 전송합니다. (패킷은 WinSIP 으로 발생시켰습니다)
com1 : 333.333.333.333 -> eth0
com2 : 444.444.444.444 -> eth1

이렇게 전송을하면 서버에서는 다음과 같이 출력이 되어야 합니다.

eth0 333.333.333.333 ---> 111.111.111.111
eth1 444.444.444.444 ---> 222.222.222.222
| | | |

그런데 위와같이 출력이 되다가 이상하게 출력 될때가 있습니다.

eth0 333.333.333.333 ---> 111.111.111.111
eth0 444.444.444.444 ---> 222.222.222.222

이거나 eth0대신 eth1이거나

eth1 333.333.333.333 ---> 111.111.111.111
eth0 444.444.444.444 ---> 222.222.222.222

이거나 아예 아무것도 안찍힐때가 있습니다.
그래서 pcap_compile()을 이용하여 필터링을 걸어줘봤습니다.

쓰레드1(eth0) --- > dst host 111.111.111.111
쓰레드2(eth1) --- > dst host 222.222.222.222

이렇게 해봤더니 출력은

eth0 333.333.333.333 ---> 111.111.111.111
eth1 444.444.444.444 ---> 222.222.222.222

이렇게 되었지만 여전히 안찍히는 경우가 있었습니다. 즉 필터링을 안걸었을때와 같은 결과였습니다.
데이터는 제대로 들어오는것 같긴한데 왜 디바이스 alias가 위와 같이 찍히는지 아무리 찾아봐도 잘 모르겠습니다.

그래서 ifconfig로 promisc를 해지하고 해봐도 똑 같은 결과였습니다.
꼭 제대로된 결과를 찍고싶습니다. 해결책이나 조언 꼭 부탁드리겠습니다.... 꾸벅
혹시나 해서 소스도 같이 올립니다.

#define PROMISCUOUS 1
#define NOPROMISCUOUS 0
#define PCAP_SNAPSHOT 65536
#define PCAP_TIMEOUT 1
#define SIP_PORT 5060
#define PATH "/home/oracle/files/"
//////////////////////////////////////////////////////////////////////////////////////
struct thread_data {
char device_name[255];
char ip_address[255];
};

struct thread_data *data;
int DEV_MAX = 0;

//////////////////////////////////////////////////////////////////////////////////////
void SetDeviceInfo();
void *prepareCapture(void *data);
void Capturing(pcap_t *pd, char *dname);
//////////////////////////////////////////////////////////////////////////////////////
void Capturing(pcap_t *pd, char *dname)
{
unsigned char *p;
struct pcap_pkthdr ph;

int i;
////////////////////////////////////////////////////////////////////////
int j, temp;
struct ether_header *ep;
unsigned short ether_type;

struct iphdr *iph;
struct udphdr *udph;
////////////////////////////////////////////////////////////////////////

for(i=0;;i++)
{
p=(unsigned char *)pcap_next(pd, &ph);

ep = (struct ether_header *)p;
p += sizeof(struct ether_header);
ether_type = ntohs(ep->ether_type);

switch (ether_type){

case ETHERTYPE_IP :
iph = (struct iphdr *) p;

switch(iph->protocol){

case IPPROTO_TCP :
break;

case IPPROTO_UDP :
udph = (struct udphdr *) (p + iph->ihl * 4);

printf("%s\t", dname);
printf("%s -----> ", inet_ntoa(iph->saddr));
printf("%s\n", inet_ntoa(iph->daddr));

break;
}
}
}
}
//////////////////////////////////////////////////////////////////////////////////////
void *prepareCapture(void *data)
{
char errbuf[PCAP_ERRBUF_SIZE];
struct thread_data *dat = (struct thread_data*)data;
//////////////////////////////////////////////////////////////////////////////////////
////rule set
char rule[255];
sprintf(rule, "dst port %d", SIP_PORT);
//////////////////////////////////////////////////////////////////////////////////////
////device open and filter set
pcap_t *pd;
struct bpf_program fp;
bpf_u_int32 netp;
bpf_u_int32 maskp;

if(pcap_lookupnet(dat->device_name, &netp, &maskp, errbuf)<0)
{
perror(errbuf);
exit(1);
}

if((pd = pcap_open_live(dat->device_name, PCAP_SNAPSHOT, NOPROMISCUOUS, PCAP_TIMEOUT, errbuf)) == NULL)
{
perror(errbuf);
exit(1);
}

if (pcap_compile(pd, &fp, rule, -1, netp) == -1)
{
printf("compile error\n");
exit(1);
}

if (pcap_setfilter(pd, &fp) == -1)
{
printf("setfilter error\n");
exit(0);
}

////////////////////////////////////////////////////////////////////////////////////////
printf("%s\n", dat->device_name);
printf("%s\n", rule);

Capturing(pd, dat->device_name);
}

//////////////////////////////////////////////////////////////////////////////////////
void SetDeviceInfo()
{
/////////////////////////////////////////////////////////////////////////////////
//디바이스 이름을 얻어온다

char errbuf[PCAP_ERRBUF_SIZE];
int nRet;
pcap_if_t *alldevps;
char *temp_name[255];

nRet=pcap_findalldevs(&alldevps, errbuf);
if(nRet == -1)
{
printf("%s\n", errbuf);
exit(-1);
}

do{
if(alldevps->addresses == NULL)
{
break;
}else{
temp_name[DEV_MAX]=alldevps->name;
DEV_MAX++;
}
}while(alldevps=alldevps->next);
/////////////////////////////////////////////////////////////////////////////////
data=(struct thread_data*)calloc(DEV_MAX, sizeof(struct thread_data));

struct ifreq *ifr;
struct sockaddr_in *sin;
struct sockaddr *sa;

// 이더넷 설정 구조체
struct ifconf ifcfg;
int fd;
int n, m, dev_cnt = 0;
int numreqs = 30;
fd = socket(AF_INET, SOCK_DGRAM, 0);

memset(&ifcfg, 0, sizeof(ifcfg));
ifcfg.ifc_buf = NULL;
ifcfg.ifc_len = sizeof(struct ifreq) * numreqs;
ifcfg.ifc_buf = malloc(ifcfg.ifc_len);

for(;;)
{
ifcfg.ifc_len = sizeof(struct ifreq) * numreqs;
ifcfg.ifc_buf = realloc(ifcfg.ifc_buf, ifcfg.ifc_len);
if (ioctl(fd, SIOCGIFCONF, (char *)&ifcfg) < 0)
{
exit;
}
break;
}

ifr = ifcfg.ifc_req;

for (n = 0; n < ifcfg.ifc_len; n+= sizeof(struct ifreq))
{
for(dev_cnt=0; dev_cnt < DEV_MAX; dev_cnt++)
{
if(strcmp(temp_name[dev_cnt], ifr->ifr_name) == 0)
{
sin = (struct sockaddr_in *)&ifr->ifr_addr;

strcpy(data[dev_cnt].device_name, temp_name[dev_cnt]);
strcpy(data[dev_cnt].ip_address, (char *)inet_ntoa(sin->sin_addr));
}
}
ifr++;
}
}

int main()
{
SetDeviceInfo();

pthread_t *thread;
int thread_cnt;

thread = (pthread_t *)calloc(DEV_MAX, sizeof(pthread_t));

for(thread_cnt=0; thread_cnt {
if(pthread_create(&thread[thread_cnt], NULL, prepareCapture, &data[thread_cnt]) < 0)//DEV_NAME[thread_cnt]
{
printf("cannot make thread\n");
exit(1);
}
}

for(thread_cnt=0; thread_cnt {
pthread_join(thread[thread_cnt], NULL);
}

pthread_mutex_destroy(&mutex);

return 1;
}

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.