mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 22:02:49 -06:00
225 lines
5 KiB
C++
225 lines
5 KiB
C++
#include "NetworkAdapter.h"
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <net/if.h>
|
|
|
|
NAMESPACE_UPP
|
|
|
|
Vector<NetworkAdapter> GetNetworkAdaptersInfo(void)
|
|
{
|
|
Vector<NetworkAdapter> res;
|
|
|
|
// this is used to avoid adding duplicate entries
|
|
// with same MAC and differing only by adapter family
|
|
// (posix may return same interface twice for IPV4 and IPV6)
|
|
Index<String>macs;
|
|
|
|
// Get a socket handle
|
|
int sck = socket(PF_INET, SOCK_DGRAM, 0);
|
|
if(sck < 0)
|
|
return res;
|
|
|
|
// get a list of all available interfaces
|
|
// as buffer size is unknown, we check results and retry as needed
|
|
int bufSize = 4096;
|
|
struct ifconf ifc = { 0 };
|
|
caddr_t buf;
|
|
for(int iTry = 0; iTry < 4; iTry++)
|
|
{
|
|
buf = (caddr_t)new byte[bufSize];
|
|
ifc.ifc_len = bufSize;
|
|
ifc.ifc_buf = buf;
|
|
|
|
// get interfaces list,
|
|
if (ioctl(sck, SIOCGIFCONF, &ifc) < 0)
|
|
{
|
|
// failed, free buffer and leave
|
|
delete[] buf;
|
|
close(sck);
|
|
Cerr() << "Failed to get interfaces list\n";
|
|
return res;
|
|
}
|
|
|
|
// check if buffer size was big enough
|
|
if(ifc.ifc_len != bufSize)
|
|
break;
|
|
|
|
// not big enough, double size and retry
|
|
delete[] buf;
|
|
bufSize *= 2;
|
|
if(iTry >= 3)
|
|
{
|
|
Cerr() << "Max buffer size too small\n";
|
|
close(sck);
|
|
return res;
|
|
}
|
|
}
|
|
|
|
// iterate through returned data fill result vector
|
|
int nIfaces = ifc.ifc_len / sizeof(struct ifreq);
|
|
struct ifreq *iface = ifc.ifc_req;
|
|
for(int iIface = 0; iIface < nIfaces; iIface++)
|
|
{
|
|
// platform dependent code to get MAC address
|
|
String MAC;
|
|
|
|
// LINUX
|
|
#ifdef SIOCGIFHWADDR
|
|
if(ioctl(sck, SIOCGIFHWADDR, iface) < 0)
|
|
{
|
|
// couldn't get MAC, just leave it empty
|
|
continue;
|
|
}
|
|
MAC = Format("%02x:%02x:%02x:%02x:%02x:%02x",
|
|
(byte)iface->ifr_hwaddr.sa_data[0],
|
|
(byte)iface->ifr_hwaddr.sa_data[1],
|
|
(byte)iface->ifr_hwaddr.sa_data[2],
|
|
(byte)iface->ifr_hwaddr.sa_data[3],
|
|
(byte)iface->ifr_hwaddr.sa_data[4],
|
|
(byte)iface->ifr_hwaddr.sa_data[5]
|
|
);
|
|
|
|
// SOLARIS AND SysVR4 systems
|
|
#elif SIOCGENADDR
|
|
if (ioctl(sck, SIOCGENADDR, iface) < 0)
|
|
{
|
|
// couldn't get MAC, just leave it empty
|
|
continue;
|
|
}
|
|
MAC = Format("%02x:%02x:%02x:%02x:%02x:%02x",
|
|
(byte)iface->ifr_enaddr[0],
|
|
(byte)iface->ifr_enaddr[1],
|
|
(byte)iface->ifr_enaddr[2],
|
|
(byte)iface->ifr_enaddr[3],
|
|
(byte)iface->ifr_enaddr[4],
|
|
(byte)iface->ifr_enaddr[5]
|
|
);
|
|
|
|
// Mac OSX and other BSD
|
|
#elif __MACH__ || __NetBSD__ || __OpenBSD__ || __FreeBSD__
|
|
|
|
int mib[6];
|
|
mib[0] = CTL_NET;
|
|
mib[1] = AF_ROUTE;
|
|
mib[2] = 0;
|
|
mib[3] = AF_LINK;
|
|
mib[4] = NET_RT_IFLIST;
|
|
mib[5] = if_nametoindex(iface->ifr_name);
|
|
if (mib[5] == 0)
|
|
// nameless interface ? skip
|
|
continue;
|
|
|
|
int len = 0;
|
|
if (sysctl(mib, 6, NULL, (size_t*)&len, NULL, 0) != 0)
|
|
{
|
|
// sysctl error, just leave MAC empty
|
|
continue;
|
|
}
|
|
|
|
char *macbuf = new char[len];
|
|
if (!macbuf)
|
|
{
|
|
// can't allocat buffer, skip this MAC
|
|
continue;
|
|
}
|
|
if (sysctl(mib, 6, macbuf, (size_t*)&len, NULL, 0) != 0)
|
|
{
|
|
delete[] macbuf;
|
|
continue;
|
|
}
|
|
|
|
struct if_msghdr *ifm = (struct if_msghdr *)macbuf;
|
|
struct sockaddr_dl *sdl = (struct sockaddr_dl *)(ifm + 1);
|
|
byte ptr[] = (byte **)LLADDR(sdl);
|
|
|
|
MAC = Format("%02x:%02x:%02x:%02x:%02x:%02x",
|
|
ptr[0],
|
|
ptr[1],
|
|
ptr[2],
|
|
ptr[3],
|
|
ptr[4],
|
|
ptr[5]
|
|
);
|
|
|
|
delete[] macbuf;
|
|
#else
|
|
#error OS Distribution Not Recognized
|
|
#endif
|
|
|
|
// remove MAC addresses of 6 nulls...
|
|
// loopback interface, for example, don't have a MAC
|
|
if(MAC == "00:00:00:00:00:00")
|
|
MAC.Clear();
|
|
|
|
// check out if we've already stored this MAC
|
|
// in case, we just skip the interface
|
|
if(!MAC.IsEmpty() && macs.Find(MAC) >= 0)
|
|
continue;
|
|
macs.Add(MAC);
|
|
|
|
NetworkAdapter &adapter = res.Add();
|
|
|
|
// set MAC in result
|
|
adapter.mac = MAC;
|
|
|
|
// get interface name
|
|
adapter.fullname = iface->ifr_name;
|
|
|
|
// set interface type from name
|
|
if(adapter.fullname.StartsWith("eth"))
|
|
adapter.type = "ETHERNET";
|
|
else if(adapter.fullname.StartsWith("lo"))
|
|
adapter.type = "SOFTWARE_LOOPBACK";
|
|
else if(adapter.fullname.StartsWith("ppp"))
|
|
adapter.type = "MODEM";
|
|
else if(adapter.fullname.StartsWith("hci"))
|
|
adapter.type = "BLUETOOTH";
|
|
else if(adapter.fullname.StartsWith("tr"))
|
|
adapter.type = "TOKENRING";
|
|
else if(
|
|
adapter.fullname.StartsWith("vbox") ||
|
|
adapter.fullname.StartsWith("wifi") ||
|
|
adapter.fullname.StartsWith("ath")
|
|
)
|
|
adapter.type = "VIRTUALBOX";
|
|
else if(adapter.fullname.StartsWith("wlan"))
|
|
adapter.type = "IEEE80211";
|
|
else
|
|
adapter.type = "OTHER";
|
|
|
|
/*
|
|
// get interface family and set description with it
|
|
// (may be of some use...)
|
|
adapter.description = "Family: ";
|
|
int family = iface->ifr_addr.sa_family;
|
|
switch(family)
|
|
{
|
|
case AF_PACKET:
|
|
adapter.description += "AF_PACKET";
|
|
break;
|
|
case AF_INET :
|
|
adapter.description += "AF_INET";
|
|
break;
|
|
case AF_INET6 :
|
|
adapter.description += "AF_INET6";
|
|
break;
|
|
default:
|
|
adapter.description += "UNKNOWN";
|
|
}
|
|
*/
|
|
// description as name... we dont' have any better choice
|
|
adapter.description = adapter.fullname;
|
|
|
|
iface++;
|
|
}
|
|
delete[] buf;
|
|
close(sck);
|
|
|
|
return res;
|
|
}
|
|
|
|
END_UPP_NAMESPACE
|
|
|
|
#endif
|