본문 바로가기

UNIX_LINUX_C_C++

Packet sniffer - libpcap사용

출처 : http://kldp.org/node/33279

libpcap 쓰면 몇십줄이면 스니퍼 완성됩니다.

/* Packet sniffer
*
* (C) Copyright 2004 Lee J. H.
*
*/

/* 사용법 : sniff <interface> <capture-file>
*/

/*
* changelog
* 2004/01/05 - pcap_loop()에서 pcap_dispatch()로 변경
* 시리얼 넘버관련 버그 수정
* perror()의 잘못된 구문을 수정
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>

#include <pcap.h>

#define C_SNIFF

#define CTRLC_ON 1

int main(int,char **);
int create_file(char *);
void exit_prog(void);
void capture(u_char *,const struct pcap_pkthdr *,const u_char *);
void sigint_hand(int);

int fd;
int serial=0;

int readoff;
char writebuffer[1048576]; /* 1M의 파일 write buffer */

pcap_t *capdev;

char flag=0;

/* 패킷 캡쳐 & 세이브 */
void capture(u_char *null,const struct pcap_pkthdr *head,const u_char *pktdata)
{
void *ptr;
int t;

if((1048576-readoff)<(8+(int)(head->len))) {
write(fd,writebuffer,readoff);
readoff=0;
}
ptr=(void *)writebuffer+readoff;
*(int *)ptr=serial;
*(int *)(ptr+4)=(int)head->len;
ptr+=8;
for(t=0;t<head->len;t++) {
*(char *)(ptr+t) = (char)(pktdata[t]);
}
readoff+=8+(head->len);
if(flag&CTRLC_ON) {
exit_prog();
}
}

/* CTRL-C (SIGINT) 시그널 처리함수 */
void sigint_hand(int null) {
flag=flag|CTRLC_ON;
return;
}

/* 프로그램 종료시이다 */
void exit_prog(void)
{
if(readoff) {
write(fd,writebuffer,readoff);
}
pcap_close(capdev);
exit(0);
}

/* 패킷을 저장할 파일을 생성한다. 만일 파일이 존재하는 경우에는 파일을 지워도 되
는지 물어본다 */
int create_file(char *filename)
{
struct stat check;
char reply;

if((stat(filename,&check))!=-1) {
/* stat()이 정상적으로 이루어졌다면 파일이 존재하는 것이다. 삭제 여부를 물어
본다 */
printf("File %s exists. Do you want to delete it? (Y/N)",filename);
sync();
reply=(char)(getchar());
if((reply!='y')&&(reply!='Y')) {
pcap_close(capdev);
exit(1);
}
printf("\n");
}
fd=creat(filename,O_CREAT|O_WRONLY|O_TRUNC);
if(fd==-1) {
printf("File %s creation failed\n",filename);
exit(1);
}
return fd;
}

/* 메인함수 */
int main(int argc,char **argv)
{
char errbuf[PCAP_ERRBUF_SIZE];

if(argc!=3) { /* 인수가 일치하지 않으면 도움말 출력하고 나간다 */
printf("Usage : sniff <interface> <cap-file>\n\n");
printf(" ex) sniff eth0 seepacket.img\n");
exit(1);
}
signal(SIGINT,sigint_hand);
capdev=pcap_open_live(argv[1],128*1024,1,0,errbuf);
if(capdev==NULL) { /* interface open failed인 경우이다 */
printf("Error opening network interface %s\n",argv[1]);
}
fd=create_file(argv[2]); /* 패킷 저장용 파일을 생성한다 */
while(1) {
pcap_dispatch(capdev,1,capture,NULL);
serial++;
if(flag&CTRLC_ON) {
exit_prog();
}
}
}