170 lines
5.0 KiB
C++
170 lines
5.0 KiB
C++
/*
|
|
Copyright (c) 2014 IOnU Security Inc. All rights reserved
|
|
Created February 2014 by Kendrick Webster
|
|
|
|
Network.cpp - implementation for Network.h
|
|
*/
|
|
#include <string.h>
|
|
#include <netdb.h>
|
|
#include "Network.h"
|
|
|
|
using ionu::network::ADDRESS_STRING_LENGTH;
|
|
using ionu::network::CAddress;
|
|
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
// Address to string conversion
|
|
//-----------------------------------------------------------------------------------
|
|
|
|
std::string ionu::network::IP4AddressString(struct in_addr s)
|
|
{
|
|
return std::string(inet_ntoa(s));
|
|
}
|
|
|
|
std::string ionu::network::IP4AddressString(uint32_t a)
|
|
{
|
|
struct in_addr s;
|
|
s.s_addr = a;
|
|
return IP4AddressString(s);
|
|
}
|
|
|
|
std::string ionu::network::IP4AddressString(CAddress a)
|
|
{
|
|
return IP4AddressString(a.addr);
|
|
}
|
|
|
|
std::string ionu::network::IP4AddressString(const struct sockaddr_in& a)
|
|
{
|
|
return IP4AddressString(a.sin_addr.s_addr);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------
|
|
// Host name lookup
|
|
//-----------------------------------------------------------------------------------
|
|
|
|
static bool isAddressUsable(const struct addrinfo* a, int family, int socktype)
|
|
{
|
|
return ((a->ai_family == family) && (a->ai_socktype == socktype));
|
|
}
|
|
|
|
constexpr const char* SA_TYPE_SELECTED = "(selected)";
|
|
constexpr const char* SA_TYPE_IGNORED = "(ignored) ";
|
|
constexpr const char* SA_TYPE_NOT_SELECTED = "..........";
|
|
static void showAddress(const struct addrinfo* a, unsigned int index, const char* type, Log::severity_t dump_loglevel)
|
|
{
|
|
char addrstr[ADDRESS_STRING_LENGTH];
|
|
void* src = NULL;
|
|
|
|
switch (a->ai_family)
|
|
{
|
|
case AF_INET:
|
|
src = &(reinterpret_cast<struct sockaddr_in*>(a->ai_addr)->sin_addr);
|
|
break;
|
|
|
|
case AF_INET6:
|
|
src = &(reinterpret_cast<struct sockaddr_in6*>(a->ai_addr)->sin6_addr);
|
|
break;
|
|
}
|
|
|
|
switch (a->ai_family)
|
|
{
|
|
case AF_INET:
|
|
case AF_INET6:
|
|
if (inet_ntop(a->ai_family, src, addrstr, sizeof(addrstr)))
|
|
{
|
|
logprintf(dump_loglevel, "address %2d %s %s", index, type, addrstr);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
logprintf(dump_loglevel, "address %2d %s AF_?(%d)", index, type, a->ai_family);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// sets <ca> to the <i>'th (0-based) usable address (skipping/ignoring unusable addresses) in list <a>,
|
|
// logs the list using <dump_loglevel> (which can be set to Log::ignore if logging is not wanted)
|
|
static success_t selectUsableAddress(
|
|
unsigned int i, // 0-based index into a virtual list containing usable elements of <a>
|
|
int socktype, // SOCK_DGRAM, SOCK_STREAM, etc.
|
|
const struct addrinfo* a, // list returned by getaddrinfo
|
|
CAddress& ca, // result (output)
|
|
Log::severity_t dump_loglevel) // log severity for dumping address list/selection
|
|
{
|
|
success_t r = FAILURE;
|
|
unsigned int j = 0, n = 0;
|
|
struct sockaddr_in* addr;
|
|
while (NULL != a)
|
|
{
|
|
++j;
|
|
if (isAddressUsable(a, AF_INET, socktype))
|
|
{
|
|
if (i == n)
|
|
{
|
|
showAddress(a, j, SA_TYPE_SELECTED, dump_loglevel);
|
|
addr = reinterpret_cast<struct sockaddr_in *>(a->ai_addr);
|
|
ca.addr = addr->sin_addr.s_addr;
|
|
ca.port = addr->sin_port;
|
|
r = SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
showAddress(a, j, SA_TYPE_NOT_SELECTED, dump_loglevel);
|
|
}
|
|
++n;
|
|
}
|
|
else
|
|
{
|
|
showAddress(a, j, SA_TYPE_IGNORED, dump_loglevel);
|
|
}
|
|
a = a->ai_next;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
success_t ionu::network::HostToAddress(const CHost& h, CAddress& a,
|
|
int socktype, Log::severity_t trace_loglevel, Log::severity_t error_loglevel)
|
|
{
|
|
struct addrinfo hints, *result;
|
|
memset(&hints, 0, sizeof(struct addrinfo));
|
|
hints.ai_family = AF_INET;
|
|
hints.ai_socktype = socktype;
|
|
logprintf(trace_loglevel, "Resolving host \"%s\" ...", h.host.c_str());
|
|
int r = getaddrinfo(h.host.c_str(), NULL, &hints, &result);
|
|
if (0 != r)
|
|
{
|
|
logprintf(error_loglevel, "getaddrinfo: %s", gai_strerror(r));
|
|
return FAILURE;
|
|
}
|
|
success_t s = selectUsableAddress(0, socktype, result, a, trace_loglevel);
|
|
freeaddrinfo(result);
|
|
if (FAILURE == s)
|
|
{
|
|
logprintf(error_loglevel, "unable to resolve host \"%s\"", h.host.c_str());
|
|
return FAILURE;
|
|
}
|
|
a.port = htons(h.port);
|
|
return SUCCESS;
|
|
}
|
|
|
|
success_t ionu::network::HostListToAddressList(const host_list_t& hl, address_list_t& al,
|
|
int socktype, Log::severity_t trace_loglevel, Log::severity_t error_loglevel)
|
|
{
|
|
al.clear();
|
|
success_t r = SUCCESS;
|
|
for (const CHost& h: hl)
|
|
{
|
|
CAddress a;
|
|
if (FAILURE == HostToAddress(h, a, socktype, trace_loglevel, error_loglevel))
|
|
{
|
|
r = FAILURE;
|
|
}
|
|
else
|
|
{
|
|
al.push_back(a);
|
|
}
|
|
}
|
|
return r;
|
|
}
|