Libpcap güçlü bir ağ paket analiz
kütüphanesidir, ağdaki trafiği dinlemeye ve ağa paket göndermeye yarar. http://www.tcpdump.org/
Winpcap ise libpcap 'in windows
versiyonudur, https://www.winpcap.org/
libpcap gelen paketlerin henüz işletim
sistemi tarafından işlenmeden evvel bir kopyasını alır. Böylece
gelen paketler işletim sistemi tarafından herhangi bir işleme tabi
tutulmadan alınmış olur. Libpcap C/C++ ile birlikte kullanılacak
şekilde dizayn edilmiştir fakat Python, Java, C# ile
kullanılabilmesi için de ara birimler (wrapper) geliştirilmiştir.
Bu yazı kapsamında vereceğim örnekte
ağ kartından ziyade kayıtlı bir .pcap dosyasından alınan
paketler incelenmiştir. Verilen örnekte, alınan paketler analiz
edilerek kaynak ve hedef MAC adresleri, paketin tipi, ve eğer paket IP
paketi ise ip başlığındaki bazı bilgiler çekilmiştir.
Libpcap kütüphanesini projemizde
kullanabilmemiz için projemize ekleyeceğimiz header
#include
<pcap.h>
İlgili
<pcap.h>
dosyasını projemizde kullanabilmemiz için
ilk olarak proje ayarlarında winpcap kütüphanesi için dosya yolu
ayarlarını yapmamız lazım. Bunun için Visual Studio 2015'te
indirmiş olduğumuz winpcap kütüphanesi için aşağıdaki
ayarları yapmamız gerekmekte.
Project
→ Properties → C/C++ → Additional Includes'a
…..\\WpdPack\include dosya
yolunu
Project
→ Properties → Linker→ Additional Library'e
…..\\WpdPack\lib\ dosya
yolunu
Project
→ Properties → Linker→ Additional Dependencies'e ise wpcap.lib
, yazmalıyız
Proje
ayarlarımızı yaptıktan sonra direkt olarak koda giriş yapalım
:)
int
main()
{
std::string
file = "C:\\users\\ibrahim\\Downloads\\smallFlows.pcap";
char
errbuff[PCAP_ERRBUF_SIZE];
//
libpcap'i offline modda yani dosyadan çalışacak şekilde
başlatıyoruz
pcap_t
* pcap = pcap_open_offline(file.c_str(), errbuff);
//
alınacak paketin başlığı için header tanımlaması
struct
pcap_pkthdr
*header;
const
u_char
*data;
u_int
packetCount = 0;
while
(int
returnValue = pcap_next_ex(pcap, &header, &data) >= 0)
{
std::cout
<<
"
Packet : "
<<
++packetCount <<
std::endl;
std::cout
<<
"
Packet size : "
<<
header->len <<
std::endl;
//
Show Epoch Time
std::cout
<<
"
Epoch Time: "
<<
header->ts.tv_sec <<
"."
<<
header->ts.tv_usec <<
"
sn"
<<
std::endl;
}
std::cin.get();
return
0;
}
Bu
kodu çalıştırdığımızda alacağımız ekran çıktısı:
Örnekteki
while döngüsünü inceleyecek olursak pcap_next_ex(pcap, &header,
&data) fonksiyonunun paketleri sırayla okuduğunu göreceğiz. Bu
örnekte yaptığımız iş sadece paket uzunluğunu header->len
ve saniyesini header->ts.tv_sec ekrana yazdırmak oldu. Yani
sadece header değişkenimizdeki iki değeri ekrana yazdırdık. pcap_next_ex fonksiyonun geri döndürğünü değerleri inceleyecek olursak;
struct
pcap_pkthdr
*header ---> frame
başlığı ile ilgili verileri içeriyor
const
u_char
*data ---> ise
frame içeriği ile ilgili verileri içermekte. Yani içerisinde
kapsüllenmiş
şekilde Ethernet başlığı, IP başlığı,devamında UDP yada
hangi protokol içeriyorsa tüm veriler char* tipinde geri döndürülüyor.
Şimdi
ilk olarak ethernet başlığından MAC bilgilerini çekelim.
std::cout
<<
"
Destination Mac Address : "
;
for
(u_int
i = 0; i <6; i++)
{
std::cout
<<
std::hex <<
((int)data[0]<10
?"0":"")
<<
(int)data[0]<<
(i!=5?":"
:"")
;
data++;
}
std::cout<<
std::endl;
Bildiğiniz
gibi MAC adresleri 6 byte yer kaplamaktadır. Ethernet başlığının
ilk 6 byte'ı hedef adresi sonraki 6 byte'ı ise kaynak adresi ifade
eder.Aynı işlemi kaynak MAC adresini bulmak için de tekrarlıyoruz.
Son 2 byte ise Ethernet tipini belirtir. Eğer bu değer 0x0800 ise
gelen frame bir IP paketidir, anlamına gelmektedir..
unsigned
short
ethernet_type = data[0] << 8 | data[1];
data
+= 2; //
**** increment location on pointer, because ethernet type is 2 byte
****
Ethernet
başlığındaki bilgileri çektik. Şimdi ise şayet gelen frame IP
paketi içeriyorsa, IP başlığı üzerinde analiz yapıp ip paket
total length, identification number ile kaynak ve hedef ip
adreslerini çekeceğiz. IP paket başlığında hangi byte larda hangi bilgilerin saklandığını anlayabilmek için aşağıdaki ip paket başlığı yapısını inceleyiniz.
IP paket başlık yapısı
while
(int
returnValue = pcap_next_ex(pcap, &header, &data) >= 0)
{
std::cout<<"
Packet : "
<<
++packetCount <<std::endl;
std::cout
<<
"
Packet size : "<<
header->len <<
std::endl;
//
Show Epoch Time
std::cout
<<
"
Epoch Time: "
<<
header->ts.tv_sec <<
"."<<
header->ts.tv_usec <<
"
sn"<<
std::endl;
std::cout
<<
"
Destination Mac Address : "
;
for
(u_int
i = 0; i <6; i++)
{
std::cout
<<
std::hex <<
((int)data[0]<10
?"0":"")
<<
(int)data[0]<<
(i!=5?":"
:"")
;
data++;
}
std::cout<<
std::endl;
std::cout
<<
"
Source Mac Address : ";
for
(u_int
i = 0; i <6; i++)
{
std::cout
<<
std::hex <<
((int)data[0]<10
? "0"
: "")
<<
(int)data[0]
<<
(i != 5 ? ":"
: "");
data++;
}
std::cout<<
std::dec <<
std::endl;
unsigned
short
ethernet_type = data[0] << 8 | data[1];
data
+= 2; //
**** ethernet type is 2 byte ****
std::cout
<<
"
Ethernet Type : "
<<
(ethernet_type==0x0800 ? "***
IP ***"
: "-----"
) <<
std::endl;
if
(ethernet_type == 0x0800)
{
unsigned
char
lms = data[2];
unsigned
char
rms = data[3];
uint16_t
totallength = (lms << 8) | rms;
lms
= data[4];
rms
= data[5];
unsigned
short
identification = (lms << 8) | rms;
unsigned
int
ip_source = (data[15] << 24) | (data[14] << 16) |
(data[13] << 8) | data[12];
unsigned
int
ip_destination = (data[19] << 24) | (data[18] << 16) |
(data[17] << 8) | data[16];
std::cout
<<
"
IP Packet Total length : "
<<
totallength<<
std::endl;
std::cout
<<
"
IP identification number : "
<<
identification <<
std::endl;
std::cout
<<
"
IP Source: "
<<
GetIPString(ip_source) <<
std::endl;
std::cout
<<
"
IP Destination: "
<<
GetIPString(ip_destination) <<
std::endl;
}
std::cout
<<
std::endl <<
std::endl;
if
(packetCount == 4) break;
}
Not:
integer tipindeki ip adreslerini x.x.x.x formatına çevirmek için
kullandığımız fonksiyon.
#include
<winsock2.h>
#pragma
comment(lib,
"Ws2_32.lib")
std::string
GetIPString(uint32_t
x)
{
char
buffer[INET_ADDRSTRLEN
+ 1];
auto
result = inet_ntop(AF_INET,
&x,
buffer, sizeof(buffer));
if
(result == nullptr)
throw
std::runtime_error("Can't
convert IP4 address");
return
buffer;
}
Hiç yorum yok:
Yorum Gönder