| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 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 | 31 |
Tags
- 김재석
- 리리남매
- 이태원 클라쓰 15회 예고
- 유튜버 김재석
- 최강욱
- 폰폰테스트
- 픽크루
- 학교 개학 연기 4월
- 고민정
- 킹덤 고근희
- libtins
- 불가피
- 임영규
- 김영권
- 김영권 아내
- 이지혜
- 스콜피온킹
- 제넥신
- 미국 금리인하
- 해킹
- 스페인 코로나
- 양적완화
- 조희연
- 홍혜걸
- 성남 코로나 확진자
- 뭉쳐야 찬다
- 은혜의 강 교회
- 이상형 만들기
- 성남은혜의강교회
- 금리인하
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