<< 파란의 무료문자 앱(ParanSms) 스토어 버전 출시 | Home | C에서 Mysql 연동 방법 >>

libpcap을 활용한 IP 정보 조회하기

1. 라이브러리 다운 및 컴파일
 - wget http://www.tcpdump.org/release/libpcap-1.0.0.tar.gz
 - ./configure --exec-prefix=/k2/src/pcap --prefix=/k2/src/pcap;
 - mkdir /k2/src/pcap/bin
 - make;make install

2. 해당 서버로 접근하는 패킷의 클라이언트 ip 추출 소스
#include <stdio.h>
#include <signal.h>

#include <pcap.h>
#include <sys/socket.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <arpa/inet.h>

static pcap_t *pd;
char *device;

// 필터링 룰
#define FILTER_RULE "host 2xx.1xx.xx.xxx and tcp port 99999"
#define PCAP_SNAPSHOT 1024
#define PCAP_TIMEOUT 100

void packet_sniff(unsigned char *, const struct pcap_pkthdr *,
const unsigned char *);
void sig_int(int sig);

int main(int argc, char *argv[])
{
char errorbuffer[PCAP_ERRBUF_SIZE];
bpf_u_int32 net;
bpf_u_int32 netmask;
struct in_addr net_addr, mask_addr;
struct bpf_program bp;

signal(SIGINT,sig_int); //signal hanlder 등록

// 네트웍 디바이스를 가져오는 함수
if(!(device = pcap_lookupdev(errorbuffer))) {
perror(errorbuffer);
exit(1);
}

// 열려진 패킷 캡쳐 디바이스에 네트웍 주소와
// 서브넷 마스크를 넘겨주는 기능(eth0, eth1)
if(pcap_lookupnet(device, &net, &netmask, errorbuffer) < 0) {
perror(errorbuffer);
exit(1);
}

net_addr.s_addr = net;
mask_addr.s_addr = netmask;

printf("Device Info : %s\n", device); // 해당 서버의 디바이스 정보
printf("Net Address Info : %s\n", inet_ntoa(net_addr)); //Net Address
printf("Netmask Info : %s\n", inet_ntoa(mask_addr)); //Netmask

// 실제 디바이스를 열어주는 기능
if((pd = pcap_open_live(device, PCAP_SNAPSHOT,
1, PCAP_TIMEOUT, errorbuffer)) == NULL) {
perror(errorbuffer);
exit(1);
}

// 정해진 필터룰에 의해 필터 프로그램을 컴파일(host, port 등 지정)
if(pcap_compile(pd, &bp, FILTER_RULE, 0, netmask) < 0) {
perror(pcap_geterr(pd));
exit(1);
}

// 컴파일한 필터룰에 의해 패킷 캡쳐 디바이스로 읽어들이는 기능
if(pcap_setfilter(pd, &bp) < 0) {
perror(pcap_geterr(pd));
exit(1);
}
// 실제 패킷을 잡아서 실행할 함수를 지정해 주는 함수
// (두번쩨 인자 0이면 계속 패킷을 받아들임)
if(pcap_loop(pd, -1, packet_sniff, 0) < 0) {
perror(pcap_geterr(pd));
exit(1);
}

pcap_close(pd);
return 1;
}

void packet_sniff(unsigned char *user, const struct pcap_pkthdr *h,
const unsigned char *p)
{
struct ip *iph;
struct ether_header *etherh;
unsigned short e_type;

// p가 ip header를 가리키도록 ethernet header의 크기만큼 증가 시킴
etherh = (struct ether_header *)p;
e_type = ntohs(etherh->ether_type);

if( e_type == ETHERTYPE_IP ) {
p += sizeof(struct ether_header);
iph = (struct ip *) p;

// ip header의 정보를 출력
printf("SRC IP = %s\n", inet_ntoa(iph->ip_src));
printf("DST IP = %s\n", inet_ntoa(iph->ip_dst));
} else if(e_type == ETHERTYPE_ARP ) {
printf("arp \n");
} else if(e_type == ETHERTYPE_REVARP ) {
printf("rarp \n");
} else {
printf("no such type -> type : %d\n", e_type);
}
}

void sig_int(int sig)
{
printf("Bye!!\n");
pcap_close(pd);
exit(0);
}
3. 소스 컴파일

gcc -D_REENTRANT -D_PTHREADS -Wno-deprecated -fPIC 
-DOMP_UNIX -c ipfilter_pcap.c -I/k2/src/pcap/include
gcc -o ipfilter_pcap ipfilter_pcap.o -lpcap -L/k2/src/pcap/lib
-I/k2/src/pcap/include

4. 실행 결과

- root 권한으로 실행해야 함

[root@mimul pcap]# ./ipfilter_pcap
Device Info : eth0
Net Address Info : 2xx.1xx.x.x
Netmask Info : 255.255.255.0
SRC IP = 2xx.xxx.x.xx
DST IP = 2xx.1xx.x.xxx
SRC IP = 2xx.xxx.x.xx
DST IP = 2xx.1xx.x.xxx
SRC IP = 2xx.xxx.x.xx
DST IP = 2xx.1xx.x.xxx

5. 기능 확장 아이디어

 - 중요 서버의 포트별 접근제어를 할 경우 기능 확장을 통해 가능할 것 같음
 - 처리 방식은 호스트 Ip와 포트, 시퀀스 정보를 가지고 접근 제한 서버로 연결을 시도할 경우 reset 패킷을 날려 세션을 차단함



Add a comment Send a TrackBack