일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 학교 개학 연기 4월
- 김재석
- 해킹
- 은혜의 강 교회
- libtins
- 고민정
- 성남 코로나 확진자
- 성남은혜의강교회
- 리리남매
- 미국 금리인하
- 스콜피온킹
- 홍혜걸
- 조희연
- 이지혜
- 스페인 코로나
- 최강욱
- 불가피
- 폰폰테스트
- 김영권 아내
- 김영권
- 유튜버 김재석
- 픽크루
- 킹덤 고근희
- 뭉쳐야 찬다
- 임영규
- 이상형 만들기
- 제넥신
- 이태원 클라쓰 15회 예고
- 금리인하
- 양적완화
Archives
- Today
- Total
Dork's port
Linux libpcap 을 이용한 packet capture 본문
패킷을 캡쳐할 수 있는 가장 유명한 라이브러리는 아마 pcap Library 일 것이다. 그래서 오늘은 네트워크를 처음 접하는 분들께
pcaplib를 사용 하는 간단한 소스코드를 소개하고자 한다. 네트워크를 처음에 공부할 때에 작성한 코드라 많이 서툴고 버그가 있을 수 도 있다.
#include <iostream> #include <pcap.h> #include <sys/socket.h> #include <errno.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netinet/ip.h> #include <netinet/tcp.h> #include <netinet/udp.h> #include <unistd.h> #include <net/ethernet.h> #include <cstdio> using namespace std; #define PROMISCUOUS 1 //Get every packet from Ethernet #define NONPROMISCUOUS 0 //Get only mine from Ethernet struct ip *iph; //Struct of IP struct tcphdr *tcph; //Struct of TCP void callback(u_char *useless, const struct pcap_pkthdr *pkthdr, const u_char *packet); void printMac(u_int8_t *addr); int lengthRet(int length, int minusLen); int main(int argc, char* argv[]) //Device , Filter { if(argc!=3) { cout<<"Usage : Pcap [Device Name] [\"Filter\"]"<<endl; cout<<"You can fine filter rules at \"www.winpcap.org/docs/docs_40_2/html/group_language.html\""<<endl; exit(1); } char * device = argv[1]; int ret; char* netAddress; char* netMask; bpf_u_int32 netp; //IP bpf_u_int32 maskp; //Subnet Mask char errBuf[PCAP_ERRBUF_SIZE]; struct in_addr addr;//Struct to save IPv4 cout<<"Device :"<<device<<endl; if(ret = pcap_lookupnet(device,&netp,&maskp,errBuf) <0) //Get Network , Subnet mask about Device { //error => return -1 & error content => errBuf perror(errBuf); //error => print errBuf & exit exit(1); } addr.s_addr = netp; if((netAddress = inet_ntoa(addr))==NULL)//inet_ntoa => convert ulong type to Dotted-Decimal Notation { perror("inet_ntoa"); exit(1); } cout<<"Network Address : "<< netAddress <<endl; addr.s_addr = maskp; netMask = inet_ntoa(addr);//Subnet Mask convert cout<<"Subnet Mask : "<<netMask<<endl; pcap_t *pcd; //Packet capture descriptor //BUFSIZ is a optimum size (defined in csdio) //Get packet capture descriptor from Device if((pcd = pcap_open_live(device,BUFSIZ, NONPROMISCUOUS , 1, errBuf))==NULL) { perror(errBuf); exit(1); } struct bpf_program fp; if(pcap_compile(pcd, &fp, argv[2] , 0, netp)==-1) //Set fp by filter rule(argv[2]) { cout<<"Setfilter error!!!"<<endl; exit(1); } if(pcap_setfilter(pcd, &fp) == -1) //apply packet filter { cout<<"Setfilter error"<<endl; exit(1); } pcap_loop(pcd, 0, callback, NULL); //count 1 -> 0 infinity loop return 0; } //packet => recevied pakcet void callback(u_char *useless, const struct pcap_pkthdr *pkthdr, const u_char *packet) { struct ether_header *ep; unsigned short ether_type; int length=pkthdr->len; ep = (struct ether_header *)packet; //Save Ethernet Header cout<<"Information of Ehernet"<<endl; cout<<"Src Mac Address : "; printMac(ep->ether_shost); cout<<"Dest Mak Address : "; printMac(ep->ether_dhost); cout<<endl<<endl; ether_type = ntohs(ep->ether_type);// ntohs(network to host short) // network => little endian length = lengthRet(length, sizeof(ep)); if(ether_type == ETHERTYPE_IP) //next protocol is IP(0x0800) defined in netinet->if_ether { packet += sizeof(struct ether_header);//To bring IP header iph = (struct ip *)packet; cout<<"Information of IP"<<endl; cout<<"Src IP Address : "<<inet_ntoa(iph->ip_src)<<endl; cout<<"Dest IP Address : "<<inet_ntoa(iph->ip_dst)<<endl; cout<<endl<<endl; length = lengthRet(length, sizeof(iph)); if(iph->ip_p== IPPROTO_TCP) //next protocol is TCP { packet = packet + iph->ip_hl * 4; tcph =(struct tcphdr *)packet; //TCP Header //iph->ip_hl => Header length //ip_hl is word so ip_hl * 4 //linux word => 4byte cout<<"Informaiton of TCP"<<endl; cout<<"Src Port : "<<ntohs(tcph->source)<<endl; cout<<"Dst Port : "<<ntohs(tcph->dest)<<endl; cout<<endl<<endl; length = lengthRet(length, sizeof(tcphdr)); packet += sizeof(struct tcphdr); //To print Data Section } for(int i=0; i<length;i++) //print data { if(i%16==0) cout<<endl; printf("%02x ", *packet++); } cout << endl << endl; }else{ cout<<"This Packet is not IP Packet"<<endl; } } void printMac(u_int8_t *addr) { int sizeOfMac=6;//mac address => 48bit //mac use hexadecimal number //Ex) AB:CD:EF:GH:YJ:KL //hexadecimal number use 4bit per 1 num //0 0 0 0 => 0 //1 1 1 1 => F => 15 for(int i=0; i<sizeOfMac;i++) { printf("%02x",addr[i]); if(i!=sizeOfMac-1) printf(":"); } cout<<endl; } int lengthRet(int length, int minusLen) { length -= minusLen; return length; } /************************Information***************************/ //Ethernet & IP Header has a next protocol Info. //Ethernet => ether_type IP => ip_p //***********************Flow chart**************************** //pcap_lookupnet => Get a Device name & Net & Subnet //pcap_open_live()=> Make a PCD(Packet Capture Descriptor) //pcap_compile() //Set fp by filter rule //pcap_setfilter() //apply packet filter //pcap_loop(); //callback a Function by PCD //Function
ethernet header부터 ip header , tcpheader까지 parsing 하며 관련된 정보를 출력하는 간단한 프로그램이다.
위의 예제로 네트워크의 헤더 구성은 어떻게 되어있는지, 어떤방식으로 parsing을 하는지 알아 볼 것을 권한다.
또한, pcap은 2계층(이더넷)부터 캡처를 하는 라이브러리로 캡처가 된 시작 포인터는 ethernet헤더이다.
그리고 pcap은 패킷의 흐름을 제어할 수 있는 라이브러리가 아닌 단지 패킷을 들여다보는 (snipping) library임을 명심하자.
패킷의 흐름을 제어하고싶다면, 라우팅테이블을 사용하거나 netfilter사용을 권장한다.
또한, 위의 파일을 컴파일시 라이브러리를 링크해줘야하므로 gcc 또는 g++ 명령어의 마지막에 -lpcap을 적어 링크를 해주길 바라며 linux에서 pcap Library는 아래의 명령어로 설치 가능하다.
# apt-get install libpcap*
'Develop' 카테고리의 다른 글
네트워크 각 헤더의 Next Type 파싱하기. (0) | 2017.09.25 |
---|---|
map 출력하기(C++) (0) | 2017.09.24 |
16진수로 값 출력 및 mac address 출력하기 (C++) (0) | 2017.09.22 |
invalid operands to binary expression (C++11) (0) | 2017.09.22 |
Checksum 계산하기[소스 코드] (C++) (0) | 2017.09.22 |
Comments