construct/ircd/net_addrs.cc

132 lines
2.5 KiB
C++

// The Construct
//
// Copyright (C) The Construct Developers, Authors & Contributors
// Copyright (C) 2016-2020 Jason Volk <jason@zemos.net>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice is present in all copies. The
// full license for this software is available in the LICENSE file.
#include <RB_INC_IFADDRS_H
#ifdef HAVE_IFADDRS_H
bool
ircd::net::addrs::has_usable_ipv6_interface()
try
{
return !for_each([]
(const addr &a) noexcept
{
if(a.family != AF_INET6)
return true;
if(a.scope_id != 0) // global scope
return true;
if(~a.flags & IFF_UP) // not up
return true;
if(a.flags & IFF_LOOPBACK) // not usable
return true;
// return false to break
return false;
});
}
catch(const std::exception &e)
{
log::error
{
log, "Failed to check for usable IPv6 interfaces :%s",
e.what()
};
return false;
}
#else
bool
ircd::net::addrs::has_usable_ipv6_interface()
{
return false;
}
#endif
#ifdef HAVE_IFADDRS_H
[[GCC::optimize(0), clang::optnone]] //XXX: trouble
bool
ircd::net::addrs::for_each(const closure &closure)
{
return for_each(raw_closure{[&closure]
(const struct ::ifaddrs *const &ifa)
{
addr a;
a.name = ifa->ifa_name;
a.flags = ifa->ifa_flags;
if(ifa->ifa_addr) switch(ifa->ifa_addr->sa_family)
{
case AF_INET6:
{
const auto sin(reinterpret_cast<const struct ::sockaddr_in6 *>(ifa->ifa_addr));
const auto ip(reinterpret_cast<const uint128_t *>(sin->sin6_addr.s6_addr));
a.family = sin->sin6_family;
a.scope_id = sin->sin6_scope_id;
a.flowinfo = sin->sin6_flowinfo;
a.address =
{
ntoh(*ip), sin->sin6_port
};
break;
}
case AF_INET:
{
const auto &sin(reinterpret_cast<const struct ::sockaddr_in *>(ifa->ifa_addr));
a.family = sin->sin_family;
a.address =
{
ntoh(sin->sin_addr.s_addr), sin->sin_port
};
break;
}
default:
return true;
}
return closure(a);
}});
}
#else
bool
ircd::net::addrs::for_each(const closure &closure)
{
return true;
}
#endif
#ifdef HAVE_IFADDRS_H
bool
ircd::net::addrs::for_each(const raw_closure &closure)
{
struct ::ifaddrs *ifap_;
syscall(::getifaddrs, &ifap_);
const custom_ptr<struct ::ifaddrs> ifap
{
ifap_, ::freeifaddrs
};
for(auto ifa(ifap.get()); ifa; ifa = ifa->ifa_next)
if(!closure(ifa))
return false;
return true;
}
#else
bool
ircd::net::addrs::for_each(const raw_closure &closure)
{
return true;
}
#endif