코리아오에스아이소프트코리아 - OSIsoft · 오에스아이소프트코리아코리아오에스아이소프트코리아 세미나 세미나 . 2012 . 16. PI Coresight .
Pcap 세미나
Click here to load reader
Transcript of Pcap 세미나
패킷 캡쳐 라이브러리
주요함수 코드분석
정보통신공학과
200801559
윤 천 호
목 차
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()
1. 패킷 캡쳐 과정
1. 패킷캡쳐 과정
디바이스 닫기
pcap_close()
디바이스 이름 얻기
pcap_lookupdev()
디바이스 열기
pcap_open_live()
패킷캡처
pcap_next()
2. pcap_lookupdev()
디바이스 이름얻기
2-1 pcap_findalldevs()
2-2 pcap_freealldevs()
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에 접근이 가능
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을 참조함.
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
순회된 각 디바이스의
주소정보가 담긴 구조체를
순회면서 주소 정보들을 반환.
디바이스의 이름을 반환하고,
만약 디바이스의 디스크립션이 존재하면 그것도 반환한다.
마지막으로 디바이스 자체를 반환한다음 다음 디바이스로 순회
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
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()
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의 주소를 반환.
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 메모리 할당 및 에러처리
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() 로
현재 활성화인지 판단.
활성화이면 에러. 아니면 패스
정보 저장 후 종료
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반환
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을 활성화시키고,
그렇지 않으면 에러
4. pcap_next()
패킷캡쳐
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()을
사용해 에러 메시지를 확인할 수 있
다.
끝