10 Ağustos 2017 Perşembe

getifaddrs metodu

Giriş
getifaddrs() metodu Linux'ta kullanılıyor. Layer 2 ve Layer 3 bilgisini ayrı ayrı veriyor. Örneğin eth0 bu metodla iki defa okunur. İlk okumada Layer 3, ikinci okuma da Layer 2 bilgisi gelir. Her ikisini birbirinden ayırmak içim ifa_addr->family alanı kullanılır. Bu alan Layer 2 için eski ismiyle AF_PACKET yeni ismiyle PF_PACKET değerini alır. Layer 3 içinse AF_INET değerini alır.

Dolayısıyla MAC adresini almak için Layer 2 arayüzler süzülür. İskelet olarak şöyle bir kod yazılır. ifaddrs belleği getifaddrs() çağrısı tarafından yaratılır ve doldurulur. İşimiz bitince bu bellek free() ile temizlenir.
struct ifaddrs  *ifa;

if (getifaddrs(&ifaddr) == -1) 
{
  perror("getifaddrs");
  exit(EXIT_FAILURE);
}


for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) 
{
  if (ifa->ifa_addr == NULL)
    continue;  

    if (ifa->ifa_addr->sa_family==AF_PACKET))
    {
       ...
    }
}
freeifaddrs(ifaddr);
ifa_addr alanı
Kodda ifa_addr alanının NULL olmadığı kontrol ediliyor. Sebebi şu.
The ifa_addr field references either the address of the interface or the link level address of the interface, if one exists, otherwise it is NULL. (The sa_family field of the ifa_addr field should be consulted to determine the format of the ifa_addr address.)
Yani süzme için kullandığımız ifa_addr alanı NULL gelebilir ya da bir başka deyişle Layer 2 veya Layer 3 adrese sahipse olmayabilir.

ifa_addr alanı ve tipi
Açıklaması şöyle
The  ifa_addr field points to a structure containing the interface address. (The sa_family subfield should be consulted to determine the format of the address structure.) This field may contain a null pointer.
Alanın tipi AF_PACKET, AF_INET, AF_INET6 olabilir. Tipin kontrolü için örnek ver

ifa_addr alanı ipv4 ise
Eğer bir arayüzün AF_PACKET yani Layer 2 olduğunu biliyorsak MAC adresini sockaddr_ll'ye cast eder ve şöyle alırız.
struct sockaddr_ll *s = (struct sockaddr_ll*)ifa->ifa_addr;
int i;
int len = 0;
for(i = 0; i < 6; i++)
  len+=sprintf(macp+len,"%02X%s",s->sll_addr[i],i < 5 ? ":":"");
Diğer Unix sistemleri de benzer bir mantık kullanıyor. Örneğin BSD'de AF_PACKET yerine AF_LINK arayüzü olması bekleniyor. Arayüz de sockaddr_dl yapısına cast edilip kullanılıyor.

ifa_flags alanı
Ağ arayüzünün Layer 2 adresi olsa bile kart çalışmıyor olabilir. Örneğin kablosu çekilmiştir. Bu durumu da algılamak istersek şöyle yapabiliriz.
if (ifa->ifa_flags & IFF_RUNNING) {...} //Arayüzü kullanabiliriz
ifa_name alanı
Arayüzün ismin verir. Şöyle yaparız.
string interfaceName (ifa->ifa_name);
if(interfaceName == string("lo")) {...}

Hiç yorum yok:

Yorum Gönder