#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 (unsigned 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 (unsigned int i = 0; i < interface_names_i.size(); i++)
{
if (!flag_i)
{
if (i) cout << endl;
cout << " ------ Interface ::: " << interface_names_i [i] << " ------" << endl;
}
for (unsigned 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 <floyd@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 (unsigned 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)
//-------------------------------
assert (interface_name_max_len_ == 0);
for (unsigned 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_