mirror of https://github.com/nostar/urfd.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
309 lines
7.2 KiB
309 lines
7.2 KiB
|
|
// ulxd -- The universal reflector
|
|
// Copyright © 2021 Thomas A. Early N7TAE
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
#include <cstdint>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netdb.h>
|
|
#include "IP.h"
|
|
|
|
CIp::CIp() : is_set(false)
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
CIp::CIp(const char *address, int family, int type, uint16_t port) : is_set(true)
|
|
{
|
|
Clear();
|
|
if (0 == strncasecmp(address, "none", 4))
|
|
{
|
|
is_set = false;
|
|
return;
|
|
}
|
|
struct addrinfo hints, *result;
|
|
bzero(&hints, sizeof(struct addrinfo));
|
|
hints.ai_family = family;
|
|
hints.ai_socktype = type;
|
|
if (0 == getaddrinfo(address, (port ? std::to_string(port).c_str() : nullptr), &hints, &result))
|
|
{
|
|
memcpy(&addr, result->ai_addr, result->ai_addrlen);
|
|
addr.ss_family = result->ai_family;
|
|
freeaddrinfo(result);
|
|
}
|
|
SetPort(port);
|
|
}
|
|
CIp::CIp(const int family, const uint16_t port, const char *address) : is_set(true)
|
|
{
|
|
Initialize(family, port, address);
|
|
}
|
|
|
|
void CIp::Initialize(const int family, const uint16_t port, const char *address)
|
|
{
|
|
Clear();
|
|
if (0 == strncasecmp(address, "none", 4))
|
|
{
|
|
is_set = false;
|
|
return;
|
|
}
|
|
is_set = true;
|
|
addr.ss_family = family;
|
|
if (AF_INET == family)
|
|
{
|
|
auto addr4 = (struct sockaddr_in *)&addr;
|
|
addr4->sin_port = htons(port);
|
|
if (address)
|
|
{
|
|
if (0 == strncasecmp(address, "loc", 3))
|
|
inet_pton(AF_INET, "127.0.0.1", &(addr4->sin_addr));
|
|
else if (0 == strncasecmp(address, "any", 3))
|
|
inet_pton(AF_INET, "0.0.0.0", &(addr4->sin_addr));
|
|
else
|
|
{
|
|
if (1 > inet_pton(AF_INET, address, &(addr4->sin_addr)))
|
|
{
|
|
std::cerr << "Address Initialization Error: '" << address << "' is not a valdid IPV4 address!" << std::endl;
|
|
is_set = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (AF_INET6 == family)
|
|
{
|
|
auto addr6 = (struct sockaddr_in6 *)&addr;
|
|
addr6->sin6_port = htons(port);
|
|
if (address)
|
|
{
|
|
if (0 == strncasecmp(address, "loc", 3))
|
|
inet_pton(AF_INET6, "::1", &(addr6->sin6_addr));
|
|
else if (0 == strncasecmp(address, "any", 3))
|
|
inet_pton(AF_INET6, "::", &(addr6->sin6_addr));
|
|
else
|
|
{
|
|
if (1 > inet_pton(AF_INET6, address, &(addr6->sin6_addr)))
|
|
{
|
|
std::cerr << "Address Initialization Error: '" << address << "' is not a valid IPV6 address!" << std::endl;
|
|
is_set = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
std::cerr << "Error: Wrong address family type:" << family << " for [" << (address ? address : "NULL") << "]:" << port << std::endl;
|
|
is_set = false;
|
|
}
|
|
}
|
|
|
|
bool CIp::operator==(const CIp &rhs) const // compares ports, addresses and families
|
|
{
|
|
// if anything is not equal, then we are done
|
|
if (addr.ss_family != rhs.addr.ss_family)
|
|
return false;
|
|
if (AF_INET == addr.ss_family)
|
|
{
|
|
auto l = (struct sockaddr_in *)&addr;
|
|
auto r = (struct sockaddr_in *)&rhs.addr;
|
|
if (l->sin_addr.s_addr == r->sin_addr.s_addr)
|
|
return l->sin_port == r->sin_port;
|
|
else
|
|
return false;
|
|
}
|
|
else if (AF_INET6 == addr.ss_family)
|
|
{
|
|
auto l = (struct sockaddr_in6 *)&addr;
|
|
auto r = (struct sockaddr_in6 *)&rhs.addr;
|
|
if (0 == memcmp(&(l->sin6_addr), &(r->sin6_addr), sizeof(struct in6_addr)))
|
|
return l->sin6_port == r->sin6_port;
|
|
else
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CIp::operator!=(const CIp &rhs) const // compares ports, addresses and families
|
|
{
|
|
// if anything is not equal, then we are done
|
|
if (addr.ss_family != rhs.addr.ss_family)
|
|
return true;
|
|
if (AF_INET == addr.ss_family)
|
|
{
|
|
auto l = (struct sockaddr_in *)&addr;
|
|
auto r = (struct sockaddr_in *)&rhs.addr;
|
|
if (l->sin_addr.s_addr != r->sin_addr.s_addr)
|
|
return true;
|
|
else
|
|
return l->sin_port != r->sin_port;
|
|
}
|
|
else if (AF_INET6 == addr.ss_family)
|
|
{
|
|
auto l = (struct sockaddr_in6 *)&addr;
|
|
auto r = (struct sockaddr_in6 *)&rhs.addr;
|
|
if (0 != memcmp(&(l->sin6_addr), &(r->sin6_addr), sizeof(struct in6_addr)))
|
|
return true;
|
|
else
|
|
return l->sin6_port != r->sin6_port;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CIp::AddressIsZero() const
|
|
{
|
|
if (AF_INET == addr.ss_family)
|
|
{
|
|
auto addr4 = (struct sockaddr_in *)&addr;
|
|
return (addr4->sin_addr.s_addr == 0U);
|
|
}
|
|
else
|
|
{
|
|
auto addr6 = (struct sockaddr_in6 *)&addr;
|
|
for (unsigned int i=0; i<16; i++)
|
|
{
|
|
if (addr6->sin6_addr.s6_addr[i])
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void CIp::ClearAddress()
|
|
{
|
|
if (AF_INET == addr.ss_family)
|
|
{
|
|
auto addr4 = (struct sockaddr_in *)&addr;
|
|
addr4->sin_addr.s_addr = 0U;
|
|
strcpy(straddr, "0.0.0.0");
|
|
}
|
|
else
|
|
{
|
|
auto addr6 = (struct sockaddr_in6 *)&addr;
|
|
memset(&(addr6->sin6_addr.s6_addr), 0, 16);
|
|
strcpy(straddr, "::");
|
|
}
|
|
}
|
|
|
|
const char *CIp::GetAddress() const
|
|
{
|
|
if (straddr[0])
|
|
return straddr;
|
|
|
|
if (AF_INET == addr.ss_family)
|
|
{
|
|
auto addr4 = (struct sockaddr_in *)&addr;
|
|
inet_ntop(AF_INET, &(addr4->sin_addr), straddr, INET6_ADDRSTRLEN);
|
|
}
|
|
else if (AF_INET6 == addr.ss_family)
|
|
{
|
|
auto addr6 = (struct sockaddr_in6 *)&addr;
|
|
inet_ntop(AF_INET6, &(addr6->sin6_addr), straddr, INET6_ADDRSTRLEN);
|
|
}
|
|
else
|
|
{
|
|
std::cerr << "CIp::GetAddress: unknown socket family=" << addr.ss_family << std::endl;
|
|
}
|
|
return straddr;
|
|
}
|
|
|
|
std::ostream &operator<<(std::ostream &stream, const CIp &Ip)
|
|
{
|
|
const char *sz = Ip;
|
|
if (AF_INET6 == Ip.GetFamily())
|
|
stream << "[" << sz << "]";
|
|
else
|
|
stream << sz;
|
|
const uint16_t port = Ip.GetPort();
|
|
if (port)
|
|
stream << ":" << port;
|
|
return stream;
|
|
}
|
|
|
|
uint32_t CIp::GetAddr() const
|
|
{
|
|
if (AF_INET6 == addr.ss_family)
|
|
{
|
|
auto addr6 = (struct sockaddr_in6 *)&addr;
|
|
// hash the results
|
|
auto *a = (const uint32_t *)&(addr6->sin6_addr.s6_addr);
|
|
return a[0] ^ a[1] ^ a[2] ^ a[3];
|
|
}
|
|
else
|
|
{
|
|
auto addr4 = (struct sockaddr_in *)&addr;
|
|
return addr4->sin_addr.s_addr;
|
|
}
|
|
}
|
|
|
|
int CIp::GetFamily() const
|
|
{
|
|
return addr.ss_family;
|
|
}
|
|
|
|
uint16_t CIp::GetPort() const
|
|
{
|
|
if (AF_INET == addr.ss_family)
|
|
{
|
|
auto addr4 = (struct sockaddr_in *)&addr;
|
|
return ntohs(addr4->sin_port);
|
|
}
|
|
else if (AF_INET6 == addr.ss_family)
|
|
{
|
|
auto addr6 = (struct sockaddr_in6 *)&addr;
|
|
return ntohs(addr6->sin6_port);
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
void CIp::SetPort(const uint16_t newport)
|
|
{
|
|
if (AF_INET == addr.ss_family)
|
|
{
|
|
auto addr4 = (struct sockaddr_in *)&addr;
|
|
addr4->sin_port = htons(newport);
|
|
}
|
|
else if (AF_INET6 == addr.ss_family)
|
|
{
|
|
auto addr6 = (struct sockaddr_in6 *)&addr;
|
|
addr6->sin6_port = htons(newport);
|
|
}
|
|
}
|
|
|
|
struct sockaddr *CIp::GetPointer()
|
|
{
|
|
memset(straddr, 0, INET6_ADDRSTRLEN); // things might change
|
|
return (struct sockaddr *)&addr;
|
|
}
|
|
|
|
const struct sockaddr *CIp::GetCPointer() const
|
|
{
|
|
return (const struct sockaddr *)&addr;
|
|
}
|
|
|
|
size_t CIp::GetSize() const
|
|
{
|
|
if (AF_INET == addr.ss_family)
|
|
return sizeof(struct sockaddr_in);
|
|
else
|
|
return sizeof(struct sockaddr_in6);
|
|
}
|
|
|
|
void CIp::Clear()
|
|
{
|
|
memset(&addr, 0, sizeof(struct sockaddr_storage));
|
|
memset(straddr, 0, INET6_ADDRSTRLEN);
|
|
is_set = false;
|
|
}
|