Pcap 세미나

18

Click here to load reader

Transcript of Pcap 세미나

Page 1: Pcap 세미나

패킷 캡쳐 라이브러리

주요함수 코드분석

정보통신공학과

200801559

윤 천 호

Page 2: Pcap 세미나

목 차

1. 패킷 캡쳐 과정

2. pcap_lookupdev()

2-1. pcap_findalldevs()

2-2. pcap_freealldevs()

3. pcap_open_live()

3-1. pcap_create()

3-2. pcap_set_ 3가지 ()

3-3. pcap_check_activated()

3-4. pcap_activate()

4. pcap_next()

Page 3: Pcap 세미나

1. 패킷 캡쳐 과정

Page 4: Pcap 세미나

1. 패킷캡쳐 과정

디바이스 닫기

pcap_close()

디바이스 이름 얻기

pcap_lookupdev()

디바이스 열기

pcap_open_live()

패킷캡처

pcap_next()

Page 5: Pcap 세미나

2. pcap_lookupdev()

디바이스 이름얻기

2-1 pcap_findalldevs()

2-2 pcap_freealldevs()

Page 6: Pcap 세미나

2. pcap_lookupdev()char *pcap_lookupdev(errbuf)

register char *errbuf;

{

pcap_if_t *alldevs;

#ifndef IF_NAMESIZE

#define IF_NAMESIZE IFNAMSIZ

#endif

static char device[IF_NAMESIZE + 1];

char *ret;

if (pcap_findalldevs(&alldevs, errbuf) == -1)

return (NULL);

if (alldevs == NULL || (alldevs->flags &

PCAP_IF_LOOPBACK)) {

(void)strlcpy(errbuf, "no suitable device found",

PCAP_ERRBUF_SIZE);

ret = NULL;

}

else {

(void)strlcpy(device, alldevs-

>name, sizeof(device));

ret = device;

}

pcap_freealldevs(alldevs);

return (ret);

pcap_if_t 타입의 주소값을 저장하는 alldevs 선언

만약 IF_NAMESIZE가 정의 되어있지 않으면

IF_NAMESIZE 는 IFNAMSIZ로 정의

케릭터 배열 device[]의 크기는 IF_NAMESIZE

+1

그리고 스트링 ret 선언

함수 pcap_findalldevs() 의 반환값으로

exception에러 검출 후 그에 따른 조치

그리고 디바이스가 검색되지 않았을 경우에도

최종 반환하는 ret에 NULL값을 대입.

함수 pcap_freealldevs() 로 포인터 변수 alldevs를 초

기화

및 결과 반환

위의 반환값에서 오류가 검출되지 않았으면

name값을 device에 복사 그리고 ret에 복사

포인터 인자를 사용했기에 name에 접근이 가능

Page 7: Pcap 세미나

2-1. pcap_findalldevs()int pcap_findalldevs(pcap_if_t **alldevsp, char *errbuf){

pcap_if_t *devlist = NULL;

int ret = 0;

const char *desc;

char *AdaptersName;

ULONG NameLength;

char *name;

if (!PacketGetAdapterNames(NULL, &NameLength)){

DWORD last_error = GetLastError();

if (last_error != ERROR_INSUFFICIENT_BUFFER){

snprintf(errbuf, PCAP_ERRBUF_SIZE,"PacketGetAdapterNames: %s“,pcap_win32strerror()); return

(-1);}}

if (NameLength > 0) {AdaptersName = (char*) malloc(NameLength);}

else {*alldevsp = NULL; return 0; }

if (AdaptersName == NULL){snprintf(errbuf, PCAP_ERRBUF_SIZE, "Cannot allocate enough memory to list the adapters."); return

(-1);}

if (!PacketGetAdapterNames(AdaptersName, &NameLength))

{snprintf(errbuf, PCAP_ERRBUF_SIZE, "PacketGetAdapterNames: %s", pcap_win32strerror()); free(AdaptersName);

return (-1);}

desc = &AdaptersName[0];

while (*desc != '\0' || *(desc + 1) != '\0')

desc++;

desc += 2;

name = &AdaptersName[0];

while (*name != '\0') {

if (pcap_add_if_win32(&devlist, name, desc, errbuf) == -1) {ret = -1; break}

name += strlen(name) + 1;

desc += strlen(desc) + 1;}

if (ret != -1) {

if (pcap_platform_finddevs(&devlist, errbuf) < 0) ret = -1;}

if (ret == -1) {

if (devlist != NULL) {pcap_freealldevs(devlist); devlist = NULL;}}

*alldevsp = devlist;

만약 PacketGetAdapterNames() 함수로 디바이스의 길이를 먼저 파악.

반환값 이 부정이면 -1을 반환하여 에러처리

길이가 양수이면 Adapters 메모리할당을

하고 0 또는 음수이면 0을 리턴 하고 종료.

메모리할당

오류

만약 PacketGetAdapterNames() 함수로 어뎁터의 이름을 얻지 못했으면 -1을 반환하여 에러처

얻은 이름을 name에 대입.

lookupdev함수에서 이 name을 참조함.

Page 8: Pcap 세미나

2-2. pcap_freealldevs()

void pcap_freealldevs(pcap_if_t *alldevs)

{

pcap_if_t *curdev, *nextdev;

pcap_addr_t *curaddr, *nextaddr;

for (curdev = alldevs; curdev != NULL; curdev = nextdev) {

nextdev = curdev->next;

for (curaddr = curdev->addresses; curaddr != NULL; curaddr = nextaddr) {

nextaddr = curaddr->next;

if (curaddr->addr){free(curaddr->addr);}

if (curaddr->netmask){free(curaddr->netmask);}

if (curaddr->broadaddr){free(curaddr->broadaddr);}

if (curaddr->dstaddr){free(curaddr->dstaddr);}

free(curaddr);

}

free(curdev->name);

if (curdev->description != NULL)

free(curdev->description);

free(curdev);

}

}

인자로 받은 alldevs를 차례로 하나씩 순회 Linked List

순회된 각 디바이스의

주소정보가 담긴 구조체를

순회면서 주소 정보들을 반환.

디바이스의 이름을 반환하고,

만약 디바이스의 디스크립션이 존재하면 그것도 반환한다.

마지막으로 디바이스 자체를 반환한다음 다음 디바이스로 순회

Page 9: Pcap 세미나

2-2. pcap_freealldevs()

pcap_if_t alldevs

next

addres

saddr -> free

netmsk ->free

broadaddr ->free

dstaddr ->free

next

addres

saddr -> free

netmsk ->free

broadaddr ->free

dstaddr ->free

next

addres

saddr -> free

netmsk ->free

broadaddr ->free

dstaddr ->free

next

null

pcap_if_t alldevs

next

addres

saddr -> free

netmsk ->free

broadaddr ->free

dstaddr ->free

next

addres

saddr -> free

netmsk ->free

broadaddr ->free

dstaddr ->free

next

addres

saddr -> free

netmsk ->free

broadaddr ->free

dstaddr ->free

next

null

Page 10: Pcap 세미나

3. pcap_open_live()

디바이스 열기

3-2

pcap_set_snaplen()

pcap_set_snaplen()

pcap_set_snaplen()

3-3 pcap_check_activated()

3-1 pcap_create()

3-4 pcap_activate()

Page 11: Pcap 세미나

3. pcap_open_live()

pcap_t *pcap_open_live(const char *source, int snaplen, int promisc, int to_ms, char *errbuf)

{

pcap_t *p;

int status;

p = pcap_create(source, errbuf);

if (p == NULL)

return (NULL);

status = pcap_set_snaplen(p, snaplen);

if (status < 0)

goto fail;

status = pcap_set_promisc(p, promisc);

if (status < 0)

goto fail;

status = pcap_set_timeout(p, to_ms);

if (status < 0)

goto fail;

p->oldstyle = 1;

status = pcap_activate(p);

if (status < 0)

goto fail;

return (p);

fail:

if (status == PCAP_ERROR)

snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", source, p->errbuf);

else if (status == PCAP_ERROR_NO_SUCH_DEVICE|| status == PCAP_ERROR_PERM_DENIED || status ==

PCAP_ERROR_PROMISC_PERM_DENIED)

snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)", source, pcap_statustostr(status), p->errbuf);

else

snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", source, pcap_statustostr(status));

pcap_close(p);

return (NULL);

}

3개의 set 함수에는 pcap_check_activated() 라는 함수가 있다. 이 함수도 디바이스의 개

방 여부를 체크한다. 이상이 없다고 판단되면, 포인터로 pcap_t에 접근하여 각각 값을 set

한다. set까지 완료되면 0을 반환한다. 만약 0보다 작은 값을 반환하면 goto fail.

pcap_t, status 선언 및

함수 pcap_create()함수로 pcap_t을 생성한다.

생성이 정상적으로 되지 않을 경우 NULL 을 반환하고 종료.

포인터로 pcap_t에 접근하여 oldstyle을 1로 입력.

모든 에러를 통과하면 함수 pcap_activate() 로 디바이스를 연다.

이때도 반환값으로 열기가 성공했는지 못했는지 검출하여 에러가 있으면 goto fail.

에러가 없다면 정상적으로 디바이스가 열린것으로 간주하여 pcap_t의 주소를 반환.

Page 12: Pcap 세미나

3-1. pcap_create()pcap_t *pcap_create(const char *source, char *ebuf){

pcap_t *p;

p = malloc(sizeof(*p));

if (p == NULL) {

snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s", pcap_strerror(errno));

return (NULL);

}

memset(p, 0, sizeof(*p));

#ifndef WIN32

p->fd = -1; p->selectable_fd = -1; p->send_fd = -1;

#endif

p->opt.source = strdup(source);

if (p->opt.source == NULL) {

snprintf(ebuf, PCAP_ERRBUF_SIZE, "malloc: %s“, pcap_strerror(errno));

free(p);

return (NULL);

}

p->can_set_rfmon_op = pcap_cant_set_rfmon;

initialize_ops(p);

pcap_set_timeout(p, 0);

pcap_set_snaplen(p, 65535);

p->opt.promisc = 0;

p->opt.buffer_size = 0;

p->opt.tstamp_type = -1;

return (p);

}

pcap_t 메모리 할당 및 에러처리

Page 13: Pcap 세미나

3-2. pcap_set_ 3가지 ()

int pcap_set_snaplen(pcap_t *p, int snaplen){

if (pcap_check_activated(p))

return (PCAP_ERROR_ACTIVATED);

p->snapshot = snaplen;

return (0);

}

int pcap_set_promisc(pcap_t *p, int promisc){

if (pcap_check_activated(p))

return (PCAP_ERROR_ACTIVATED);

p->opt.promisc = promisc;

return (0);

}

int pcap_set_timeout(pcap_t *p, int timeout_ms){

if (pcap_check_activated(p))

return (PCAP_ERROR_ACTIVATED);

p->md.timeout = timeout_ms;

return (0);

}

함수 pcap_check_activated() 로

현재 활성화인지 판단.

활성화이면 에러. 아니면 패스

정보 저장 후 종료

Page 14: Pcap 세미나

3-3. pcap_check_activated()

int pcap_check_activated(pcap_t *p)

{

if (p->activated) {

snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "can't perform "

" operation on activated capture");

return (-1);

}

return (0);

}

activated값이 0이 아니면 -1반환

activated값이 0이면 0반환

Page 15: Pcap 세미나

3-4. pcap_activate()ㅇint pcap_activate(pcap_t *p)

{

int status;

if (pcap_check_activated(p))

return (PCAP_ERROR_ACTIVATED);

status = p->activate_op(p);

if (status >= 0)

p->activated = 1;

else {

if (p->errbuf[0] == '\0') {

snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "%s",

pcap_statustostr(status));

}

initialize_ops(p);

}

return (status);

}

활성화인지 판단

activate_op() 함수의 반환값이 0이거

0보다 크면 pcap_t을 활성화시키고,

그렇지 않으면 에러

Page 16: Pcap 세미나

4. pcap_next()

패킷캡쳐

Page 17: Pcap 세미나

4. pcap_next()

const u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)

{

struct oneshot_userdata s;

const u_char *pkt;

s.hdr = h;

s.pkt = &pkt;

s.pd = p;

if (pcap_dispatch(p, 1, p->oneshot_callback, (u_char *)&s)

<= 0)

return (0);

return (pkt);

}

struct oneshot_userdata {

struct pcap_pkthdr

*hdr;

const u_char **pkt;

pcap_t *pd;

};

int pcap_dispatch(pcap_t *p, int cnt, pcap_handler callback, u_char

*user)

{

return (p->read_op(p, cnt, callback, user));

}

반환값은 성공시 읽은 패킷의 갯수

0 : 저장 파일의 EOF

-1 : 에러가 발생했을 때.

pcap_perror()이나 pcap_geterr()을

사용해 에러 메시지를 확인할 수 있

다.

Page 18: Pcap 세미나