// --------- Program File #1 of 3 : BEGIN ---------
// File netif.h
// ####################################
// Getting info about network interfaces
// C++-wrapper around Floyd Davidson's function
// See: http://groups.google.com/groups?selm=87ofbox7xn.fld%40barrow.com
// ====================================
// Windows 2000 Professional
// CYGWIN_NT-5.0
// gcc/g++ version 2.95.3-5 (cygwin special)
// ====================================
// Compilation :
// g++ main.cpp netif.cpp
// ====================================
// Alex Vinokur
// http://up.to/alexvn
// mailto:ale...@go.to
// ####################################
#ifndef _NETIF_H
#define _NETIF_H
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <assert.h>
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include <algorithm>
#include <iostream>
#include <iomanip>
using namespace std;
typedef unsigned long ulong;
typedef unsigned int uint;
typedef unsigned short ushort;
typedef unsigned char uchar;
#define MAX_VALUE(x,y) ((x) > (y) ? (x) : (y))
#define CERR cerr << "[" << setw (12) << __FILE__ << ", " << setw(2) << __LINE__ << "] "
#define IP_ADDRESS_NAME "IP Address"
#define HW_ADDRESS_NAME "HW Address"
#define NETMASK_NAME "Netmask"
#define BROADCAST_NAME "Broadcast"
#define MTU_NAME "MTU"
#define METRIC_NAME "Metric"
#define MAC_ADDRESS_CHAR_LEN 6
file://---------------------------
template <typename T> string to_string (const T& val_i, int width_i = -1, char fill_i = ' ')
file://---------------------------
{
ostringstream osstr;
if (width_i > 0)
{
osstr.width (width_i);
osstr.fill (fill_i);
}
osstr << val_i;
return osstr.str();
}
// ----------------------------
class NetInterface
{
private :
vector<string> interface_names_;
vector<string> property_names_;
map<string, map<string, string> > net_interfaces_;
uint interface_name_max_len_;
uint property_name_max_len_;
static uint request_counter_s;
void set_property_names_ ();
string return_property_name_ (const string& property_name_i) const;
bool floyd_davidson_get_net_interfaces_ ();
void show_net_interface_ (const string& interface_name_i, const string& property_name_i, bool flag_i) const;
void show_net_interface_ (const vector<string>& interface_names_i, const vector<string>& property_names_i, bool flag_i) const;
public :
NetInterface ();
~NetInterface() {}
string get_net_interface (const string& interface_name_i, const string& property_name_i) const;
void show_net_interface (const string& interface_name_i = string(), const string& property_name_i = string()) const;
};
#endif
// --------- Program File #1 of 3 : END -----------
// --------- Program File #2 of 3 : BEGIN ---------
// File netif.cpp
#include "netif.h"
// --- Floyd Davidson's macro ---
#define inaddrr(x) (*(struct in_addr *) &ifr->x[sizeof sa.sin_port])
#define IFRSIZE ((int)(size * sizeof (struct ifreq)))
// -------------------------------
// ---------------------------------------------
// ---------------------------------------------
uint NetInterface::request_counter_s (0);
// ---------------------------------------------
// ---------------------------------------------
NetInterface::NetInterface ()
:
interface_name_max_len_(0),
property_name_max_len_ (0)
{
set_property_names_ ();
floyd_davidson_get_net_interfaces_ ();
}
// ---------------------------------------------
void NetInterface::set_property_names_ ()
{
// ---------------------------------------------------
property_names_.push_back (IP_ADDRESS_NAME);
property_names_.push_back (HW_ADDRESS_NAME);
property_names_.push_back (NETMASK_NAME);
property_names_.push_back (BROADCAST_NAME);
property_names_.push_back (MTU_NAME);
property_names_.push_back (METRIC_NAME);
// ---------------------------------------------------
assert (property_name_max_len_ == 0);
for (int i = 0; i < property_names_.size(); i++)
{
property_name_max_len_ = MAX_VALUE(property_name_max_len_, property_names_[i].size());
}
}
// ---------------------------------------------
string NetInterface::return_property_name_(const string& property_name_i) const
{
assert (!(find (property_names_.begin(), property_names_.end(), property_name_i) == property_names_.end()));
return property_name_i;
}
// ---------------------------------------------
string NetInterface::get_net_interface (const string& interface_name_i, const string& property_name_i) const
{
if (net_interfaces_.count (interface_name_i) == 0) return string();
if (net_interfaces_.find(interface_name_i)->second.count(property_name_i) == 0) return string();
assert (net_interfaces_.count(interface_name_i) == 1);
assert (net_interfaces_.find(interface_name_i)->second.count(property_name_i) == 1);
return net_interfaces_.find(interface_name_i)->second.find(property_name_i)->second;
}
// ---------------------------------------------
void NetInterface::show_net_interface (const string& interface_name_i, const string& property_name_i) const
{
request_counter_s++;
cout << endl;
cout << endl;
cout.setf (ios::right, ios::adjustfield);
cout << " ###### Request#"
<< setw (2)
<< setfill ('0')
<< request_counter_s
<< setfill (' ')
<< " ::: "
<< (interface_name_i.empty() ? "All Interfaces" : interface_name_i)
<< " -> "
<< (property_name_i.empty() ? "All Properties" : property_name_i)
<< " ######"
<< endl;
cout.setf (ios::left, ios::adjustfield);
vector<string> interface_vect;
vector<string> property_vect;
bool flag = false;
if (interface_name_i.empty())
{
interface_vect = vector<string> (interface_names_);
}
else
{
interface_vect.push_back (interface_name_i);
}
if (property_name_i.empty())
{
property_vect = vector<string> (property_names_);
}
else
{
flag = true;
property_vect.push_back (property_name_i);
}
show_net_interface_ (interface_vect, property_vect, flag);
}
// ---------------------------------------------
void NetInterface::show_net_interface_ (const string& interface_name_i, const string& property_name_i, bool flag_i) const
{
assert (!interface_name_i.empty());
assert (!property_name_i.empty());
if (net_interfaces_.count (interface_name_i) == 0)
{
cout << "Interface - " << setw (interface_name_max_len_) << interface_name_i.c_str() << " : " << "Invalid Interface Name" <<
endl;
return;
}
if (find (property_names_.begin(), property_names_.end(), property_name_i) == property_names_.end())
{
cout << "Property - " << setw (property_name_max_len_) << property_name_i.c_str() << " : " << "Invalid Property Name" << endl;
return;
}
string if_property_value = get_net_interface(interface_name_i, property_name_i);
if (flag_i) cout << setw (interface_name_max_len_) << interface_name_i.c_str() << " ---> ";
cout << setw (property_name_max_len_) << property_name_i.c_str() << " : ";
cout << (if_property_value.empty() ? "<Missing>" : if_property_value) << endl;
}
// ---------------------------------------------
void NetInterface::show_net_interface_ (const vector<string>& interface_names_i, const vector<string>& property_names_i, bool
flag_i) const
{
cout.setf (ios::left, ios::adjustfield);
for (int i = 0; i < interface_names_i.size(); i++)
{
if (!flag_i)
{
if (i) cout << endl;
cout << " ------ Interface ::: " << interface_names_i [i] << " ------" << endl;
}
for (int j = 0; j < property_names_i.size(); j++)
{
show_net_interface_ (interface_names_i[i], property_names_i[j], flag_i);
} // for (j = 0; j < property_names_i.size(); j++)
} // for (int i = 0; i < interface_names_i.size(); i++)
}
// ---------------------------------------------
// - - - - - - - - - - - - - - - - - - - - - - -
// ### From: Floyd Davidson <fl...@ptialaska.net>
// ### Newsgroups: comp.unix.programmer
// ### Subject: Re: netdb: getaddrinfo()/getnameinfo()
// ### Date: 27 Aug 2002 14:17:56 -0800
// The Floyd Davidson's article contains function
// that enables to get info about network interfaces
// - - - - - - - - - - - - - - - - - - - - - - -
// Function floyd_davidson_get_net_interfaces_() below
// is the Floyd Davidson's function with minimal changes
// related to C++-wrapping
// ---------------------------------------------
bool NetInterface::floyd_davidson_get_net_interfaces_ ()
{
int sockfd;
int size = 1;
ifreq* ifr;
ifconf ifc;
sockaddr_in sa;
string cur_interface_name;
errno = 0;
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if(sockfd ==-1)
{
CERR << "Cannot open socket : " << strerror(errno) << endl;
return false;
}
ifc.ifc_len = IFRSIZE;
ifc.ifc_req = NULL;
do
{
++size;
// --- realloc buffer size until no overflow occurs ---
errno = 0;
ifc.ifc_req = static_cast<ifreq*>(realloc(ifc.ifc_req, IFRSIZE));
if (ifc.ifc_req == NULL)
{
CERR << "Out of memory : " << strerror(errno) << endl;
return false;
}
ifc.ifc_len = IFRSIZE;
errno = 0;
if (ioctl(sockfd, SIOCGIFCONF, &ifc))
{
CERR << "Error ioctl SIOCFIFCONF : " << strerror(errno) << endl;
return false;
}
} while (IFRSIZE <= ifc.ifc_len);
ifr = ifc.ifc_req;
for(; (ifr - ifc.ifc_req) * sizeof(ifreq) < static_cast<ulong>(ifc.ifc_len); ++ifr)
{
if (ifr->ifr_addr.sa_data == (ifr+1)->ifr_addr.sa_data) continue; // duplicate, skip it
if (ioctl(sockfd, SIOCGIFFLAGS, ifr)) continue; // failed to get flags, skip it
cur_interface_name = to_string (ifr->ifr_name);
assert (find (interface_names_.begin(), interface_names_.end(), cur_interface_name) == interface_names_.end());
interface_names_.push_back (cur_interface_name);
assert (net_interfaces_.count (cur_interface_name) == 0);
net_interfaces_[cur_interface_name] = map<string, string> ();
assert (net_interfaces_.count (cur_interface_name) == 1);
// ------ get IP_ADDRESS ------
assert (net_interfaces_[cur_interface_name].count (IP_ADDRESS_NAME) == 0);
net_interfaces_[cur_interface_name] [return_property_name_ (IP_ADDRESS_NAME)] = to_string(inet_ntoa(inaddrr(ifr_addr.sa_data)));
assert (net_interfaces_[cur_interface_name].count (IP_ADDRESS_NAME) == 1);
// ------ get HW_ADDRESS ------
if (ioctl(sockfd, SIOCGIFHWADDR, ifr) == 0)
{
// --- Select which hardware types to process. ---
assert (ifr->ifr_hwaddr.sa_family < AF_MAX);
vector<uchar> v;
uint sum = 0;
assert (MAC_ADDRESS_CHAR_LEN <= (sizeof (ifr->ifr_addr.sa_data)/sizeof(char)));
for (int i = 0; i < MAC_ADDRESS_CHAR_LEN; i++)
{
v.push_back(ifr->ifr_addr.sa_data[i]);
sum += static_cast<uint>(v[i]);
}
if(sum)
{
ostringstream osstr;
for (int i = 0; i < v.size(); i++)
{
if (i) osstr << "-";
osstr << hex << setw(2) << setfill ('0') << static_cast<uint>(v[i]) << dec;
}
assert (net_interfaces_[cur_interface_name].count (HW_ADDRESS_NAME) == 0);
net_interfaces_[cur_interface_name] [return_property_name_ (HW_ADDRESS_NAME)] = to_string(osstr.str());
assert (net_interfaces_[cur_interface_name].count (HW_ADDRESS_NAME) == 1);
}
}
// ------ get NETMASK ------
if (
(ioctl(sockfd, SIOCGIFNETMASK, ifr) == 0)
&&
strcmp("255.255.255.255", inet_ntoa(inaddrr(ifr_addr.sa_data)))
)
{
assert (net_interfaces_[cur_interface_name].count (NETMASK_NAME) == 0);
net_interfaces_[cur_interface_name] [return_property_name_ (NETMASK_NAME)] = to_string(inet_ntoa(inaddrr(ifr_addr.sa_data)));
assert (net_interfaces_[cur_interface_name].count (NETMASK_NAME) == 1);
}
// ------ get BROADCAST ------
if (ifr->ifr_flags & IFF_BROADCAST)
{
if (
(ioctl(sockfd, SIOCGIFBRDADDR, ifr) == 0)
&&
strcmp("0.0.0.0", inet_ntoa(inaddrr(ifr_addr.sa_data)))
)
{
assert (net_interfaces_[cur_interface_name].count (BROADCAST_NAME) == 0);
net_interfaces_[cur_interface_name] [return_property_name_ (BROADCAST_NAME)] =
to_string(inet_ntoa(inaddrr(ifr_addr.sa_data)));
assert (net_interfaces_[cur_interface_name].count (BROADCAST_NAME) == 1);
}
}
// ------ get MTU ------
if (ioctl(sockfd, SIOCGIFMTU, ifr) == 0)
{
assert (net_interfaces_[cur_interface_name].count (MTU_NAME) == 0);
net_interfaces_[cur_interface_name] [return_property_name_ (MTU_NAME)] = to_string(ifr->ifr_mtu);
assert (net_interfaces_[cur_interface_name].count (MTU_NAME) == 1);
}
// ------ get METRIC ------
if (ioctl(sockfd, SIOCGIFMETRIC, ifr) == 0)
{
assert (net_interfaces_[cur_interface_name].count (METRIC_NAME) == 0);
net_interfaces_[cur_interface_name] [return_property_name_ (METRIC_NAME)] = to_string(ifr->ifr_metric);
assert (net_interfaces_[cur_interface_name].count (METRIC_NAME) == 1);
}
// --------------------------------------
assert (net_interfaces_[cur_interface_name].size() <= property_names_.size());
} // for(; (ifr - ifc.ifc_req) * sizeof(ifreq) < static_cast<ulong>(ifc.ifc_len); ++ifr)
file://-------------------------------
assert (interface_name_max_len_ == 0);
for (int i = 0; i < interface_names_.size(); i++)
{
interface_name_max_len_ = MAX_VALUE(interface_name_max_len_, interface_names_[i].size());
}
int ret_code = close(sockfd);
assert (ret_code == 0);
return true;
} // get_net_interfaces_
// --------- Program File #2 of 3 : END -----------
// --------- Program File #3 of 3 : BEGIN ---------
// File main.cpp
#include "netif.h"
int main ()
{
NetInterface ni;
ni.show_net_interface ();
ni.show_net_interface ("lo");
ni.show_net_interface ("eth0");
ni.show_net_interface ("lo", HW_ADDRESS_NAME);
ni.show_net_interface ("lo", IP_ADDRESS_NAME);
ni.show_net_interface ("eth0", HW_ADDRESS_NAME);
ni.show_net_interface ("eth0", NETMASK_NAME);
ni.show_net_interface ("eth0", BROADCAST_NAME);
ni.show_net_interface ("", MTU_NAME);
ni.show_net_interface ("", METRIC_NAME);
ni.show_net_interface ("abc", "xyz");
ni.show_net_interface ("abc", HW_ADDRESS_NAME);
ni.show_net_interface ("lo", "xyz");
return 0;
}
// --------- Program File #3 of 3 : END -----------
========= C++ code : END ===========
========= Compilation & Run : BEGIN =========
%g++ main.cpp netif.cpp
%a.exe
###### Request#01 ::: All Interfaces -> All Properties ######
------ Interface ::: lo ------
IP Address : 127.0.0.1
HW Address : <Missing>
Netmask : 255.0.0.0
Broadcast : 127.255.255.255
MTU : 32768
Metric : 1
------ Interface ::: eth0 ------
IP Address : 0.0.0.0
HW Address : 00-40-d0-1f-fb-1b
Netmask : 0.0.0.0
Broadcast : 255.255.255.255
MTU : 1500
Metric : 1
------ Interface ::: ppp0 ------
IP Address : 212.150.34.218
HW Address : 00-53-45-00-00-00
Netmask : <Missing>
Broadcast : 212.150.34.218
MTU : 1500
Metric : 1
###### Request#02 ::: lo -> All Properties ######
------ Interface ::: lo ------
IP Address : 127.0.0.1
HW Address : <Missing>
Netmask : 255.0.0.0
Broadcast : 127.255.255.255
MTU : 32768
Metric : 1
###### Request#03 ::: eth0 -> All Properties ######
------ Interface ::: eth0 ------
IP Address : 0.0.0.0
HW Address : 00-40-d0-1f-fb-1b
Netmask : 0.0.0.0
Broadcast : 255.255.255.255
MTU : 1500
Metric : 1
###### Request#04 ::: lo -> HW Address ######
lo ---> HW Address : <Missing>
###### Request#05 ::: lo -> IP Address ######
lo ---> IP Address : 127.0.0.1
###### Request#06 ::: eth0 -> HW Address ######
eth0 ---> HW Address : 00-40-d0-1f-fb-1b
###### Request#07 ::: eth0 -> Netmask ######
eth0 ---> Netmask : 0.0.0.0
###### Request#08 ::: eth0 -> Broadcast ######
eth0 ---> Broadcast : 255.255.255.255
###### Request#09 ::: All Interfaces -> MTU ######
lo ---> MTU : 32768
eth0 ---> MTU : 1500
ppp0 ---> MTU : 1500
###### Request#10 ::: All Interfaces -> Metric ######
lo ---> Metric : 1
eth0 ---> Metric : 1
ppp0 ---> Metric : 1
###### Request#11 ::: abc -> xyz ######
Interface - abc : Invalid Interface Name
###### Request#12 ::: abc -> HW Address ######
Interface - abc : Invalid Interface Name
###### Request#13 ::: lo -> xyz ######
Property - xyz : Invalid Property Name
========= Compilation & Run : END ===========
==================
Alex Vinokur
mailto:ale...@go.to
http://up.to/alexvn
==================