#include "protoNet.h"
#include "protoDebug.h"
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <errno.h>
#include <fcntl.h>
#ifndef SIOCGIFHWADDR
#if defined(SOLARIS) || defined(IRIX)
#include <sys/sockio.h>
#include <netdb.h>
#include <sys/dlpi.h>
#include <stropts.h>
#else
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#endif #endif
#if !defined(ANDROID) || __ANDROID_API__ > 23
#include <ifaddrs.h>
#endif
#if !defined(ANDROID) || __ANDROID_API__ > 23
unsigned int ProtoNet::GetInterfaceName(const ProtoAddress& ifAddr, char* buffer, unsigned int buflen)
{
int family;
switch (ifAddr.GetType())
{
case ProtoAddress::IPv4:
family = AF_INET;
break;
#ifdef HAVE_IPV6
case ProtoAddress::IPv6:
family = AF_INET6;
break;
#endif default:
PLOG(PL_ERROR, "UnixNet::GetInterfaceName() error: invalid address type\n");
return 0;
}
struct ifaddrs* ifap;
if (0 == getifaddrs(&ifap))
{
struct ifaddrs* ptr = ifap;
unsigned int namelen = 0;
while (ptr)
{
if ((NULL != ptr->ifa_addr) && (family == ptr->ifa_addr->sa_family))
{
ProtoAddress theAddr;
theAddr.SetSockAddr(*(ptr->ifa_addr));
if (theAddr.HostIsEqual(ifAddr))
{
namelen = (unsigned int)strlen(ptr->ifa_name);
if (namelen > IFNAMSIZ) namelen = IFNAMSIZ;
if (NULL == buffer) break;
unsigned int maxlen = (buflen > IFNAMSIZ) ? IFNAMSIZ : buflen;
strncpy(buffer, ptr->ifa_name, maxlen);
break;
}
}
ptr = ptr->ifa_next;
}
freeifaddrs(ifap);
if (0 == namelen)
PLOG(PL_ERROR, "UnixNet::GetInterfaceName() error: unknown interface address\n");
return namelen;
}
else
{
PLOG(PL_ERROR, "UnixNet::GetInterfaceName() getifaddrs() error: %s\n", GetErrorString());
return 0;
}
}
bool ProtoNet::GetInterfaceAddressList(const char* interfaceName,
ProtoAddress::Type addressType,
ProtoAddressList& addrList,
unsigned int* interfaceIndex)
{
struct ifreq req;
memset(&req, 0, sizeof(struct ifreq));
strncpy(req.ifr_name, interfaceName, IFNAMSIZ);
int socketFd = -1;
switch (addressType)
{
case ProtoAddress::IPv4:
req.ifr_addr.sa_family = AF_INET;
socketFd = socket(PF_INET, SOCK_DGRAM, 0);
break;
#ifdef HAVE_IPV6
case ProtoAddress::IPv6:
req.ifr_addr.sa_family = AF_INET6;
socketFd = socket(PF_INET6, SOCK_DGRAM, 0);
break;
#endif default:
req.ifr_addr.sa_family = AF_UNSPEC;
socketFd = socket(PF_INET, SOCK_DGRAM, 0);
break;
}
if (socketFd < 0)
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() socket() error: %s\n", GetErrorString());
return false;
}
if (ProtoAddress::ETH == addressType)
{
#ifdef SIOCGIFHWADDR
if (ioctl(socketFd, SIOCGIFHWADDR, &req) < 0)
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() ioctl(SIOCGIFHWADDR) error: %s\n",
GetErrorString());
close(socketFd);
return false;
}
else
{
close(socketFd);
if (NULL != interfaceIndex) *interfaceIndex = req.ifr_ifindex;
ProtoAddress ethAddr;
if (!ethAddr.SetRawHostAddress(ProtoAddress::ETH,
(const char*)&req.ifr_hwaddr.sa_data,
IFHWADDRLEN))
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() error: invalid ETH addr?\n");
return false;
}
if (!addrList.Insert(ethAddr))
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() error: unable to add ETH addr to list.\n");
return false;
}
return true;
}
#else
#if defined(SOLARIS) || defined(IRIX)
close(socketFd);
char deviceName[32];
snprintf(deviceName, 32, "/dev/%s", interfaceName);
char* ptr = strpbrk(deviceName, "0123456789");
if (NULL == ptr)
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() invalid interface\n");
return false;
}
int ifNumber = atoi(ptr);
*ptr = '\0';
if ((socketFd = open(deviceName, O_RDWR)) < 0)
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() dlpi open() error: %s\n",
GetErrorString());
return false;
}
UINT32 buffer[8192];
union DL_primitives* dlp = (union DL_primitives*)buffer;
dlp->info_req.dl_primitive = DL_INFO_REQ;
struct strbuf msg;
msg.maxlen = 0;
msg.len = DL_INFO_REQ_SIZE;
msg.buf = (caddr_t)dlp;
if (putmsg(socketFd, &msg, NULL, RS_HIPRI) < 0)
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() dlpi putmsg(1) error: %s\n",
GetErrorString());
close(socketFd);
return false;
}
msg.maxlen = 8192;
msg.len = 0;
int flags = 0;
if (getmsg(socketFd, &msg, NULL, &flags) < 0)
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() dlpi getmsg(1) error: %s\n",
GetErrorString());
close(socketFd);
return false;
}
if ((DL_INFO_ACK != dlp->dl_primitive) ||
(msg.len < (int)DL_INFO_ACK_SIZE))
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() dlpi getmsg(1) error: unexpected response\n");
close(socketFd);
return false;
}
if (DL_STYLE2 == dlp->info_ack.dl_provider_style)
{
dlp->attach_req.dl_primitive = DL_ATTACH_REQ;
dlp->attach_req.dl_ppa = ifNumber;
msg.maxlen = 0;
msg.len = DL_ATTACH_REQ_SIZE;
msg.buf = (caddr_t)dlp;
if (putmsg(socketFd, &msg, NULL, RS_HIPRI) < 0)
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() dlpi putmsg(DL_ATTACH_REQ) error: %s\n",
GetErrorString());
close(socketFd);
return false;
}
msg.maxlen = 8192;
msg.len = 0;
flags = 0;
if (getmsg(socketFd, &msg, NULL, &flags) < 0)
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() dlpi getmsg(DL_OK_ACK) error: %s\n",
GetErrorString());
close(socketFd);
return false;
}
if ((DL_OK_ACK != dlp->dl_primitive) ||
(msg.len < (int)DL_OK_ACK_SIZE))
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() dlpi getmsg(DL_OK_ACK) error: unexpected response\n");
close(socketFd);
return false;
}
}
memset(&dlp->bind_req, 0, DL_BIND_REQ_SIZE);
dlp->bind_req.dl_primitive = DL_BIND_REQ;
#ifdef DL_HP_RAWDLS
dlp->bind_req.dl_sap = 24;
dlp->bind_req.dl_service_mode = DL_HP_RAWDLS;
#else
dlp->bind_req.dl_sap = DL_ETHER;
dlp->bind_req.dl_service_mode = DL_CLDLS;
#endif
msg.maxlen = 0;
msg.len = DL_BIND_REQ_SIZE;
msg.buf = (caddr_t)dlp;
if (putmsg(socketFd, &msg, NULL, RS_HIPRI) < 0)
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() dlpi putmsg(DL_BIND_REQ) error: %s\n",
GetErrorString());
close(socketFd);
return false;
}
msg.maxlen = 8192;
msg.len = 0;
flags = 0;
if (getmsg(socketFd, &msg, NULL, &flags) < 0)
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() dlpi getmsg(DL_BIND_ACK) error: %s\n",
GetErrorString());
close(socketFd);
return false;
}
if ((DL_BIND_ACK != dlp->dl_primitive) ||
(msg.len < (int)DL_BIND_ACK_SIZE))
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() dlpi getmsg(DL_BIND_ACK) error: unexpected response\n");
close(socketFd);
return false;
}
dlp->info_req.dl_primitive = DL_INFO_REQ;
msg.maxlen = 0;
msg.len = DL_INFO_REQ_SIZE;
msg.buf = (caddr_t)dlp;
if (putmsg(socketFd, &msg, NULL, RS_HIPRI) < 0)
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() dlpi putmsg() error: %s\n",
GetErrorString());
close(socketFd);
return false;
}
msg.maxlen = 8192;
msg.len = 0;
flags = 0;
if (getmsg(socketFd, &msg, NULL, &flags) < 0)
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() dlpi getmsg() error: %s\n",
GetErrorString());
close(socketFd);
return false;
}
if ((DL_INFO_ACK != dlp->dl_primitive) || (msg.len < (int)DL_INFO_ACK_SIZE))
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() dlpi getmsg() error: unexpected response\n");
close(socketFd);
return false;
}
ProtoAddress macAddr;
macAddr.SetRawHostAddress(addressType, (char*)(buffer + dlp->physaddr_ack.dl_addr_offset), 6);
if (NULL != interfaceIndex) *interfaceIndex = ifNumber;
close(socketFd);
if (!addrList.Insert(macAddr))
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() error: unable to add ETH addr to list.\n");
return false;
}
return true;
#else
close(socketFd); struct ifaddrs* ifap;
if (0 == getifaddrs(&ifap))
{
struct ifaddrs* ptr = ifap;
while (NULL != ptr)
{
if ((NULL != ptr->ifa_addr) && (AF_LINK == ptr->ifa_addr->sa_family))
{
if (!strcmp(interfaceName, ptr->ifa_name))
{
struct sockaddr_dl* sdl = (struct sockaddr_dl*)((void*)ptr->ifa_addr);
if (IFT_ETHER != sdl->sdl_type)
{
freeifaddrs(ifap);
PLOG(PL_WARN, "ProtoNet::GetInterfaceAddressList() error: non-Ethertype iface: %s\n", interfaceName);
return false;
}
ProtoAddress macAddr;
macAddr.SetRawHostAddress(addressType,
sdl->sdl_data + sdl->sdl_nlen,
sdl->sdl_alen);
if (NULL != interfaceIndex)
*interfaceIndex = sdl->sdl_index;
freeifaddrs(ifap);
if (!addrList.Insert(macAddr))
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() error: unable to add ETH addr to list.\n");
return false;
}
return true;
}
}
ptr = ptr->ifa_next;
}
freeifaddrs(ifap);
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() unknown interface name\n");
return false; }
else
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() getifaddrs() error: %s\n",
GetErrorString());
return false;
}
#endif #endif }
#ifdef HAVE_IPV6
struct ifaddrs* ifap;
if (0 == getifaddrs(&ifap))
{
close(socketFd);
struct ifaddrs* ptr = ifap;
bool foundIface = false;
while (NULL != ptr)
{
char ifname[IFNAMSIZ+1];
ifname[IFNAMSIZ] = '\0';
strncpy(ifname, ptr->ifa_name, IFNAMSIZ);
#ifdef LINUX
if (NULL == strchr(interfaceName, ':'))
{
char* colon = strchr(ifname, ':');
if (NULL != colon) *colon = '\0';
}
#endif if (0 == strcmp(interfaceName, ifname))
{
if ((NULL != ptr->ifa_addr) && (ptr->ifa_addr->sa_family == req.ifr_addr.sa_family))
{
ProtoAddress ifAddr;
if (!ifAddr.SetSockAddr(*(ptr->ifa_addr)))
{
PLOG(PL_WARN, "ProtoNet::GetInterfaceAddressList() error: invalid address family\n");
ptr = ptr->ifa_next;
continue;
}
if (!addrList.Insert(ifAddr))
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() error: unable to add address to list!\n");
freeifaddrs(ifap);
close(socketFd);
return false;
}
}
foundIface = true;
}
ptr = ptr->ifa_next;
}
freeifaddrs(ifap);
if (foundIface)
{
if (NULL != interfaceIndex)
*interfaceIndex = GetInterfaceIndex(interfaceName);
}
else
{
ProtoAddress ifAddr;
if (ifAddr.ConvertFromString(interfaceName))
{
char nameBuffer[IFNAMSIZ+1];
if (GetInterfaceName(ifAddr, nameBuffer, IFNAMSIZ+1))
{
return GetInterfaceAddressList(nameBuffer, addressType, addrList, interfaceIndex);
}
else
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() error: unknown interface address\n");
}
}
return false;
}
}
else
#endif if (ioctl(socketFd, SIOCGIFADDR, &req) < 0)
{
PLOG(PL_DEBUG, "ProtoNet::GetInterfaceAddressList() ioctl(SIOCGIFADDR) error for iface>%s: %s\n",
interfaceName, GetErrorString());
close(socketFd);
ProtoAddress ifAddr;
if (ifAddr.ConvertFromString(interfaceName))
{
char nameBuffer[IFNAMSIZ+1];
if (GetInterfaceName(ifAddr, nameBuffer, IFNAMSIZ+1))
{
return GetInterfaceAddressList(nameBuffer, addressType, addrList, interfaceIndex);
}
else
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() error: unknown interface address\n");
}
}
return false;
}
else
{
close(socketFd);
ProtoAddress ifAddr;
#ifdef MACOSX
if (0 == req.ifr_addr.sa_len)
{
PLOG(PL_DEBUG, "ProtoNet::GetInterfaceAddressList() warning: no addresses for given family?\n");
return false;
}
else
#endif if (ifAddr.SetSockAddr(req.ifr_addr))
{
if (addrList.Insert(ifAddr))
{
return true;
}
else
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() error: unable to add ifAddr to list\n");
return false;
}
}
else
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressList() error: invalid address family\n");
return false;
}
if (NULL != interfaceIndex)
*interfaceIndex = GetInterfaceIndex(req.ifr_name);
}
return true;
}
unsigned int ProtoNet::GetInterfaceAddressMask(const char* ifaceName, const ProtoAddress& theAddr)
{
int family;
switch (theAddr.GetType())
{
case ProtoAddress::IPv4:
family = AF_INET;
break;
case ProtoAddress::IPv6:
family = AF_INET6;
break;
default:
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressMask() error: invalid address type\n");
return 0;
}
struct ifaddrs* ifap;
if (0 == getifaddrs(&ifap))
{
struct ifaddrs* ptr = ifap;
bool foundIface = false;
while (NULL != ptr)
{
if ((NULL == ptr->ifa_addr) || (ptr->ifa_addr->sa_family != family))
{
ptr = ptr->ifa_next;
continue;
}
char ifname[IFNAMSIZ+1];
ifname[IFNAMSIZ] = '\0';
strncpy(ifname, ptr->ifa_name, IFNAMSIZ);
#ifdef LINUX
char* colon = strchr(ifname, ':');
if (NULL != colon) *colon = '\0';
#endif if (0 == strcmp(ifaceName, ifname))
{
ProtoAddress ifAddr;
if (!ifAddr.SetSockAddr(*(ptr->ifa_addr)))
{
ptr = ptr->ifa_next;
continue;
}
if (theAddr.HostIsEqual(ifAddr))
{
if (NULL == ptr->ifa_netmask)
{
freeifaddrs(ifap);
return (ifAddr.GetLength() << 3);
}
ProtoAddress maskAddr;
if (0 != ptr->ifa_netmask->sa_family)
{
maskAddr.SetSockAddr(*(ptr->ifa_netmask));
}
else
{
struct sockaddr maddr;
memcpy(&maddr, ptr->ifa_netmask, sizeof(sockaddr));
maddr.sa_family = ptr->ifa_addr->sa_family;
maskAddr.SetSockAddr(maddr);
}
freeifaddrs(ifap);
return maskAddr.GetPrefixLength();
}
foundIface = true;
}
ptr = ptr->ifa_next;
}
freeifaddrs(ifap);
if (!foundIface)
{
ProtoAddress ifAddr;
if (ifAddr.ConvertFromString(ifaceName))
{
char nameBuffer[IFNAMSIZ+1];
if (GetInterfaceName(ifAddr, nameBuffer, IFNAMSIZ+1))
{
return GetInterfaceAddressMask(nameBuffer, theAddr);
}
else
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressMask() error: unknown interface name\n");
}
}
}
}
else
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceAddressMask() getifaddrs() error: %s\n");
}
return 0;
} #endif
#if defined(SIOCGIFINDEX) && ((defined(ANDROID) && __ANDROID_API__ < 24) || !defined(HAVE_IPV6))
static int GetInterfaceList(struct ifconf& conf)
{
int sockFd = socket(PF_INET, SOCK_DGRAM, 0);
if (sockFd < 0)
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceList() socket() error: %s\n", GetErrorString());
return 0;
}
int ifNum = 32; #ifdef SIOCGIFNUM
if (ioctl(sock, SIOCGIFNUM, &ifNum) >= 0) ifNum++;
#endif int bufLen;
conf.ifc_buf = NULL;
do
{
if (NULL != conf.ifc_buf) delete[] conf.ifc_buf; bufLen = ifNum * sizeof(struct ifreq);
conf.ifc_len = bufLen;
conf.ifc_buf = new char[bufLen];
if ((NULL == conf.ifc_buf))
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceList() new conf.ifc_buf error: %s\n", GetErrorString());
conf.ifc_len = 0;
break;
}
if ((ioctl(sockFd, SIOCGIFCONF, &conf) < 0))
{
PLOG(PL_WARN, "ProtoNet::GetInterfaceList() ioctl(SIOCGIFCONF) warning: %s\n", GetErrorString());
conf.ifc_len = 0; }
ifNum *= 2; } while (conf.ifc_len >= bufLen);
close(sockFd); return (conf.ifc_len / sizeof(struct ifreq)); } #endif
unsigned int ProtoNet::GetInterfaceIndices(unsigned int* indexArray, unsigned int indexArraySize)
{
unsigned int indexCount = 0;
#if defined(HAVE_IPV6) && (!defined(ANDROID) || __ANDROID_API__ > 23)
#ifdef ANDROID
struct ifaddrs* ifap;
if (0 == getifaddrs(&ifap))
{
struct ifaddrs* ptr = ifap;
unsigned int namelen = 0;
while (ptr)
{
int ifIndex = 0;
if (NULL != ptr->ifa_name)
ifIndex = if_nametoindex(ptr->ifa_name);
if (0 != ifIndex)
{
if ((NULL != indexArray) && (indexCount < indexArraySize))
indexArray[indexCount] = ifIndex;
indexCount++;
}
else
{
PLOG(PL_WARN, "ProtoNet::GetInterfaceIndices() warning: unable to get index for interface \"%s\"\n",
(NULL != ptr->ifa_name) ? ptr->ifa_name : "unknown");
}
ptr = ptr->ifa_next;
}
freeifaddrs(ifap);
}
#else
struct if_nameindex* ifdx = if_nameindex();
if (NULL == ifdx) return 0; struct if_nameindex* ifPtr = ifdx;
while ((0 != ifPtr->if_index))
{
if ((NULL != indexArray) && (indexCount < indexArraySize))
indexArray[indexCount] = ifPtr->if_index;
indexCount++;
ifPtr++;
}
if_freenameindex(ifdx);
#endif #else
#ifdef SIOCGIFINDEX
struct ifconf conf;
conf.ifc_buf = NULL; indexCount = GetInterfaceList(conf);
if (NULL != indexArray)
{
if (indexCount < indexArraySize) indexArraySize = indexCount;
for (unsigned int i = 0; i < indexArraySize; i++)
indexArray[i] = GetInterfaceIndex(conf.ifc_req[i].ifr_name);
}
if (NULL != conf.ifc_buf) delete[] conf.ifc_buf;
#else
PLOG(PL_ERROR, "ProtoNet::GetInterfaceIndices() error: interface indices not supported\n");
#endif #endif return indexCount;
}
unsigned int ProtoNet::GetInterfaceIndex(const char* interfaceName)
{
unsigned int index = 0;
#ifdef HAVE_IPV6
index = if_nametoindex(interfaceName);
#else
#ifdef SIOCGIFINDEX
int sockFd = socket(PF_INET, SOCK_DGRAM, 0);
if (sockFd < 0)
{
PLOG(PL_WARN, "ProtoNet::GetInterfaceIndex() socket() error: %s\n",
GetErrorString());
return 0;
}
struct ifreq req;
strncpy(req.ifr_name, interfaceName, IFNAMSIZ);
if (ioctl(sockFd, SIOCGIFINDEX, &req) < 0)
PLOG(PL_WARN, "ProtoNet::GetInterfaceIndex() ioctl(SIOCGIFINDEX) error: %s\n",
GetErrorString());
else
index = req.ifr_ifindex;
close(sockFd);
#else
PLOG(PL_ERROR, "ProtoNet::GetInterfaceIndex() error: interface indices not supported\n");
return 0;
#endif #endif if (0 == index)
{
ProtoAddress ifAddr;
if (ifAddr.ResolveFromString(interfaceName))
{
char nameBuffer[IFNAMSIZ+1];
if (GetInterfaceName(ifAddr, nameBuffer, IFNAMSIZ+1))
return GetInterfaceIndex(nameBuffer);
}
}
return index;
}
unsigned int ProtoNet::GetInterfaceName(unsigned int index, char* buffer, unsigned int buflen)
{
#ifdef HAVE_IPV6
char ifName[IFNAMSIZ+1];
if (NULL != if_indextoname(index, ifName))
{
strncpy(buffer, ifName, buflen);
return (unsigned int)strlen(ifName);
}
else
{
return 0;
}
#else
#ifdef SIOCGIFNAME
int sockFd = socket(PF_INET, SOCK_DGRAM, 0);
if (sockFd < 0)
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceName() socket() error: %s\n",
GetErrorString());
return 0;
}
struct ifreq req;
req.ifr_ifindex = index;
if (ioctl(sockFd, SIOCGIFNAME, &req) < 0)
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceName() ioctl(SIOCGIFNAME) error: %s\n",
GetErrorString());
close(sockFd);
return 0;
}
close(sockFd);
if (NULL != buffer)
{
if (buflen > IFNAMSIZ)
{
buffer[IFNAMSIZ] = '\0';
buflen = IFNAMSIZ;
}
strncpy(buffer, req.ifr_name, buflen);
}
return strnlen(req.ifr_name, IFNAMSIZ);
#else
PLOG(PL_ERROR, "ProtoNet::GetInterfaceName() error: getting name by index not supported\n");
return 0;
#endif #endif }
ProtoNet::InterfaceStatus ProtoNet::GetInterfaceStatus(const char* ifaceName)
{
int fd = socket(PF_INET, SOCK_DGRAM, 0);
if (fd < 0)
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceStatus() socket() error: %s\n", GetErrorString());
return IFACE_UNKNOWN;
}
struct ifreq req;
memset(&req, 0, sizeof(req));
strncpy(req.ifr_name, ifaceName, IFNAMSIZ);
if (ioctl(fd, SIOCGIFFLAGS, &req) < 0)
{
PLOG(PL_ERROR, "ProtoNet::GetInterfaceStatus() ioctl(SIOCGIFFLAGS) error: %s\n", GetErrorString());
close(fd);
return IFACE_UNKNOWN;
}
close(fd);
if (0 != (req.ifr_flags & IFF_UP))
return IFACE_UP;
else
return IFACE_DOWN;
}
ProtoNet::InterfaceStatus ProtoNet::GetInterfaceStatus(unsigned int ifaceIndex)
{
char ifaceName[IFNAMSIZ+1];
ifaceName[IFNAMSIZ] = '\0';
if (!GetInterfaceName(ifaceIndex, ifaceName, IFNAMSIZ))
{
PLOG(PL_ERROR, "ProtoNet::InterfaceIsUp() socket() error: %s\n", GetErrorString());
return IFACE_UNKNOWN;
}
return GetInterfaceStatus(ifaceName);
}
bool ProtoNet::AddInterfaceAddress(const char* ifaceName, const ProtoAddress& ifaceAddr, unsigned int maskLen)
{
char cmd[1024];
#ifdef LINUX
#ifdef __ANDROID__
sprintf(cmd, "ip addr add %s/%u dev %s", ifaceAddr.GetHostString(), maskLen, ifaceName);
#else
switch (ifaceAddr.GetType())
{
case ProtoAddress::IPv4:
{
ProtoAddressList addrList;
GetInterfaceAddressList(ifaceName, ProtoAddress::IPv4, addrList);
unsigned int addrCount = 0;
bool hasPrimary = false;
ProtoAddress addr;
ProtoAddressList::Iterator iterator(addrList);
while (iterator.GetNextAddress(addr))
{
addrCount++;
if (!hasPrimary)
{
char ifname[IFNAMSIZ+1];
ifname[IFNAMSIZ] = '\0';
if (!GetInterfaceName(addr, ifname, IFNAMSIZ))
{
PLOG(PL_ERROR, "ProtoNet::AddInterfaceAddress() error: unable to get interface name for addr %s\n",
addr.GetHostString());
continue;
}
if (0 == strcmp(ifname, ifaceName)) hasPrimary = true;
}
}
if (hasPrimary)
{
char aliasName[IFNAMSIZ+1];
aliasName[IFNAMSIZ] = '\0';
strncpy(aliasName, ifaceName, IFNAMSIZ);
unsigned int namelen = strlen(aliasName);
if (namelen < IFNAMSIZ)
{
strcat(aliasName, ":");
namelen++;
}
else
{
PLOG(PL_ERROR, "ProtoNet::AddInterfaceAddress() error: interface name too long to alias\n");
return false;
}
char* iptr = aliasName + namelen;
int space = IFNAMSIZ - namelen;
int index = addrCount - 1;
while (index < 10)
{
int result = snprintf(iptr, space, "%d", index);
if (result < 0)
{
PLOG(PL_ERROR, "ProtoNet::AddInterfaceAddress() snprintf() error: %s\n", GetErrorString());
return false;
}
else if (result > space)
{
PLOG(PL_ERROR, "ProtoNet::AddInterfaceAddress() error: alias exceeds max interface name length\n");
return false;
}
ProtoAddress ifAddr;
if (!GetInterfaceAddress(aliasName, ProtoAddress::IPv4, ifAddr))
{
if (32 == maskLen)
sprintf(cmd, "/sbin/ifconfig %s %s broadcast 0.0.0.0 netmask 255.255.255.255", aliasName, ifaceAddr.GetHostString());
else
sprintf(cmd, "/sbin/ifconfig %s %s/%u", aliasName, ifaceAddr.GetHostString(), maskLen);
break;
}
index++;
}
if (10 == index) return false;
if (index < 0)
{
PLOG(PL_ERROR, "ProtoNet::AddInterfaceAddress() error: no available alias found\n");
return false;
}
}
else
{
if (32 == maskLen)
sprintf(cmd, "/sbin/ifconfig %s %s broadcast 0.0.0.0 netmask 255.255.255.255", ifaceName, ifaceAddr.GetHostString());
else
sprintf(cmd, "/sbin/ifconfig %s %s/%u", ifaceName, ifaceAddr.GetHostString(), maskLen);
}
break;
}
case ProtoAddress::IPv6:
{
sprintf(cmd, "/sbin/ifconfig %s add %s/%u", ifaceName, ifaceAddr.GetHostString(), maskLen);
break;
}
default:
{
PLOG(PL_ERROR, "ProtoNet::AddInterfaceAddress() error: invalid address type\n");
return false;
}
}
#endif #else
switch (ifaceAddr.GetType())
{
case ProtoAddress::IPv4:
snprintf(cmd, 1024, "/sbin/ifconfig %s %s/%u alias", ifaceName, ifaceAddr.GetHostString(), maskLen);
break;
#ifdef HAVE_IPV6
case ProtoAddress::IPv6:
snprintf(cmd, 1024, "/sbin/ifconfig %s inet6 %s/%u alias", ifaceName, ifaceAddr.GetHostString(), maskLen);
break;
#endif default:
PLOG(PL_ERROR, "ProtoNet::AddInterfaceAddress() error: invalid address type\n");
return false;
}
#endif if (system(cmd) < 0)
{
PLOG(PL_ERROR, "ProtoNet::AddInterfaceAddress() /sbin/ifconfig error: %s\n", GetErrorString());
return false;
}
return true;
}
bool ProtoNet::RemoveInterfaceAddress(const char* ifaceName, const ProtoAddress& ifaceAddr, unsigned int maskLen)
{
char cmd[1024];
#ifdef LINUX
#ifdef __ANDROID__
sprintf(cmd, "ip addr del %s/%u dev %s", ifaceAddr.GetHostString(), maskLen, ifaceName);
#else
switch (ifaceAddr.GetType())
{
case ProtoAddress::IPv4:
{
char ifname[IFNAMSIZ+1];
ifname[IFNAMSIZ] = '\0';
if (!GetInterfaceName(ifaceAddr, ifname, IFNAMSIZ))
{
PLOG(PL_ERROR, "ProtoNet::RemoveInterfaceAddress() error: unknown interface address\n");
return false;
}
if (NULL == strchr(ifname, ':'))
{
sprintf(cmd, "/sbin/ifconfig %s 0.0.0.0", ifname);
}
else
{
sprintf(cmd, "/sbin/ifconfig %s down", ifname);
}
break;
}
#ifdef HAVE_IPV6
case ProtoAddress::IPv6:
{
if (0 != maskLen)
sprintf(cmd, "/sbin/ifconfig %s del %s/%d", ifaceName, ifaceAddr.GetHostString(), maskLen);
else
sprintf(cmd, "/sbin/ifconfig %s del %s", ifaceName, ifaceAddr.GetHostString());
break;
}
#endif default:
{
PLOG(PL_ERROR, "ProtoNet::RemoveInterfaceAddress() error: invalid address type\n");
return false;
}
}
#endif #else
switch (ifaceAddr.GetType())
{
case ProtoAddress::IPv4:
snprintf(cmd, 1024, "/sbin/ifconfig %s %s -alias", ifaceName, ifaceAddr.GetHostString());
break;
#ifdef HAVE_IPV6
case ProtoAddress::IPv6:
snprintf(cmd, 1024, "/sbin/ifconfig %s inet6 %s -alias", ifaceName, ifaceAddr.GetHostString());
break;
#endif default:
PLOG(PL_ERROR, "ProtoNet::RemoveInterfaceAddress() error: invalid address type\n");
return false;
}
#endif if (system(cmd) < 0)
{
PLOG(PL_ERROR, "ProtoNet::RemoveInterfaceAddress() /sbin/ifconfig error: %s\n", GetErrorString());
return false;
}
return true;
}