/* Copyright (c) 2014 IOnU Security Inc. All rights reserved Created February 2014 by Kendrick Webster Network.cpp - implementation for Network.h */ #include #include #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(a->ai_addr)->sin_addr); break; case AF_INET6: src = &(reinterpret_cast(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 to the 'th (0-based) usable address (skipping/ignoring unusable addresses) in list , // logs the list using (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 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(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; }