[질문]pcap과 pthread를 이용하여 패킷을 캡쳐 하려고 합니다. 디바이스 이름을 정확하게 출력하고 싶습니다.
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;
}
댓글 달기