[BoB] Network
프로그램 중 네트워크 패킷을 다루기 위하 프로그래밍 공부를 하고 있습니다.
기초는 넘어가고 필요한 것만 바로 진행하기에
따라가기 위해 정리보단 결과물 위주로 올릴 것 같습니다.
개발 환경
Virtual Machine : Virtual Box
OS : Ubuntu LTS 14.04 Desktop
Process : i5-6200U x 2
RAM : 4GB (4096MB)
VRAM : 128MB
HDD : 13GBIDE : QT (설치 방법 및 사용법)
설치 Package
>> apt-get install g++
>> apt-get install libpcap*
pcap QT에서 사용하기
(P.S. project를 만들때 non-qt 를 클릭해 C 혹은 C++ 프로젝트로 생성)
프로젝트명.pro파일에 LIBS += -lpcap 을 추가 후 컴파일
패킷에서 정보 추출하는 프로그램 (출처)
#include <sys/time.h> #include <netinet/in.h> #include <net/ethernet.h> #include <pcap/pcap.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <netinet/ip.h> #include <netinet/tcp.h> #include <netinet/udp.h> #include <netinet/ip_icmp.h> #include <arpa/inet.h> #define PROMISCUOUS 1 #define NONPROMISCUOUS 0 // IP 헤더 구조체 struct ip *iph; // TCP 헤더 구조체 struct tcphdr *tcph; // 패킷을 받아들일경우 이 함수를 호출한다. // packet 가 받아들인 패킷이다. void callback(u_char *useless, const struct pcap_pkthdr *pkthdr, const u_char *packet) { static int count = 1; struct ether_header *ep; unsigned short ether_type; int chcnt =0; int length=pkthdr->len; // 이더넷 헤더를 가져온다. ep = (struct ether_header *)packet; // IP 헤더를 가져오기 위해서 // 이더넷 헤더 크기만큼 offset 한다. packet += sizeof(struct ether_header); // 프로토콜 타입을 알아낸다. ether_type = ntohs(ep->ether_type); // 만약 IP 패킷이라면 if (ether_type == ETHERTYPE_IP) { // IP 헤더에서 데이타 정보를 출력한다. iph = (struct ip *)packet; printf("IP 패킷\n"); printf("Version : %d\n", iph->ip_v); printf("Header Len : %d\n", iph->ip_hl); printf("Ident : %d\n", ntohs(iph->ip_id)); printf("TTL : %d\n", iph->ip_ttl); printf("Src Address : %s\n", inet_ntoa(iph->ip_src)); printf("Dst Address : %s\n", inet_ntoa(iph->ip_dst)); // 만약 TCP 데이타 라면 // TCP 정보를 출력한다. if (iph->ip_p == IPPROTO_TCP) { tcph = (struct tcphdr *)(packet + iph->ip_hl * 4); printf("Src Port : %d\n" , ntohs(tcph->source)); printf("Dst Port : %d\n" , ntohs(tcph->dest)); } // Packet 데이타 를 출력한다. // IP 헤더 부터 출력한다. while(length--) { printf("%02x", *(packet++)); if ((++chcnt % 16) == 0) printf("\n"); } } // IP 패킷이 아니라면 else { printf("NONE IP 패킷\n"); } printf("\n\n"); } int main(int argc, char **argv) { char *dev; char *net; char *mask; bpf_u_int32 netp; bpf_u_int32 maskp; char errbuf[PCAP_ERRBUF_SIZE]; int ret; struct pcap_pkthdr hdr; struct in_addr net_addr, mask_addr; struct ether_header *eptr; const u_char *packet; struct bpf_program fp; pcap_t *pcd; // packet capture descriptor // 사용중인 디바이스 이름을 얻어온다. dev = pcap_lookupdev(errbuf); if (dev == NULL) { printf("%s\n", errbuf); exit(1); } printf("DEV : %s\n", dev); // 디바이스 이름에 대한 네트웍/마스크 정보를 얻어온다. ret = pcap_lookupnet(dev, &netp, &maskp, errbuf); if (ret == -1) { printf("%s\n", errbuf); exit(1); } // 네트웍/마스트 정보를 점박이 3형제 스타일로 변경한다. net_addr.s_addr = netp; net = inet_ntoa(net_addr); printf("NET : %s\n", net); mask_addr.s_addr = maskp; mask = inet_ntoa(mask_addr); printf("MSK : %s\n", mask); printf("=======================\n"); // 디바이스 dev 에 대한 packet capture // descriptor 를얻어온다. pcd = pcap_open_live(dev, BUFSIZ, NONPROMISCUOUS, -1, errbuf); if (pcd == NULL) { printf("%s\n", errbuf); exit(1); } // 컴파일 옵션을 준다. if (pcap_compile(pcd, &fp, argv[2], 0, netp) == -1) { printf("compile error\n"); exit(1); } // 컴파일 옵션대로 패킷필터 룰을 세팅한다. if (pcap_setfilter(pcd, &fp) == -1) { printf("setfilter error\n"); exit(0); } // 지정된 횟수만큼 패킷캡쳐를 한다. // pcap_setfilter 을 통과한 패킷이 들어올경우 // callback 함수를 호출하도록 한다. pcap_loop(pcd, atoi(argv[1]), callback, NULL); }
실행 방법 및 결과
[root@localhost pcap_test]# ./pcap_test -1 "port 80" DEV : eth0 NET : 192.168.100.0 MSK : 255.255.255.0 ======================= IP 패킷 Version : 4 Header Len : 5 Ident : 51804 TTL : 64 Src Address : 192.168.100.130 Dst Address : 218.234.19.87 Src Port : 4996 Dst Port : 80 45000034ca5c400040065cfbc0a86482 daea1357138400502e7a303b2e7cc456 801021f0badb00000101080a0014e136 22631d7b485454502f312e3120323030 204f IP 패킷 Version : 4 Header Len : 5 Ident : 41787 TTL : 54 Src Address : 218.234.19.87 Dst Address : 192.168.100.130 Src Port : 80 Dst Port : 4996
“[BoB][Network] libpcap(winpcap) programing”에 대한 한개의 댓글