server: bind both wildcard for UDP

When possible, bind both ipv4 and ipv6 wildcard addresses
for UDP.  Even when only binding ipv6 address for TCP (Linux)
This commit is contained in:
Michael Davidsaver
2023-01-30 08:12:48 -08:00
parent b31a354915
commit 266ee52704
2 changed files with 43 additions and 27 deletions
+1 -26
View File
@@ -483,9 +483,6 @@ void Config::updateDefs(defs_t& defs) const
void Config::expand()
{
if(tcp_port==0)
tcp_port = 5075;
auto ifaces(parseAddresses(interfaces));
auto bdest(parseAddresses(beaconDestinations));
@@ -500,29 +497,7 @@ void Config::expand()
for(size_t i=0; i<ifaces.size(); i++) {
auto& ep = ifaces[i];
if(evsocket::canIPv6 && ep.addr.isAny()) {
// special handling for IP4/6 wildcard addresses
if(evsocket::ipstack==evsocket::Linsock && ep.addr.family()==AF_INET) {
// Linux IP stack disallows binding both 0.0.0.0 and [::] for the same port.
// so promote to IPv6 when possible
ep.addr = SockAddr::any(AF_INET6, ep.addr.port());
log_debug_printf(serversetup, "Promote 0.0.0.0 -> [::]%s", "\n");
} else if(evsocket::ipstack!=evsocket::Linsock) {
/* Other IP stacks allow binding different sockets.
* OSX has the added oddity of ordering dependence.
* 0.0.0.0 and then :: is allowed, but not the reverse.
*
* So when possible, we always bind both in the allowed order.
*/
ep.addr = SockAddr::any(AF_INET, ep.addr.port());
ifaces.emplace(ifaces.begin()+i+1u,
SockAddr::any(AF_INET6, ep.addr.port()));
i++; // continue after newly inserted EP
}
} else if(!ep.addr.isMCast()) {
if(!ep.addr.isMCast()) {
// no-op
} else if(!ep.iface.empty()) {
+42 -1
View File
@@ -396,12 +396,19 @@ Server::Pvt::Pvt(const Config &conf)
const auto cb(std::bind(&Pvt::onSearch, this, std::placeholders::_1));
bool bindAny = false;
std::vector<SockAddr> tcpifaces; // may have port zero
for(const auto& iface : effective.interfaces) {
SockEndpoint addr(iface.c_str());
if(!addr.addr.isMCast())
if(addr.addr.isAny()) {
bindAny = true;
} else if(!addr.addr.isMCast()) {
tcpifaces.push_back(addr.addr);
}
addr.addr.setPort(effective.udp_port);
listeners.push_back(manager.onSearch(addr, cb));
@@ -409,12 +416,24 @@ Server::Pvt::Pvt(const Config &conf)
// update to allow udp_port==0
effective.udp_port = addr.addr.port();
if(addr.addr.isAny()) {
continue; // special case handling below
}
if(addr.addr.family()==AF_INET && addr.addr.isAny()) {
// if listening on 0.0.0.0, also listen on [::]
auto any6(addr);
any6.addr = SockAddr::any(AF_INET6);
listeners.push_back(manager.onSearch(any6, cb));
} else if(addr.addr.family()==AF_INET6 && addr.addr.isAny()) {
// if listening on [::], also listen on 0.0.0.0
auto any4(addr);
any4.addr = SockAddr::any(AF_INET);
listeners.push_back(manager.onSearch(any4, cb));
}
if(evsocket::ipstack!=evsocket::Winsock
@@ -432,6 +451,28 @@ Server::Pvt::Pvt(const Config &conf)
}
}
if(bindAny) {
if(evsocket::canIPv6) {
if(evsocket::ipstack==evsocket::Linsock) {
/* Linux IP stack disallows binding both 0.0.0.0 and [::] for the same port.
* so we must always bind [::]
*/
tcpifaces.emplace_back(AF_INET6);
} else {
/* Other IP stacks allow binding different sockets.
* OSX has the added oddity of ordering dependence.
* 0.0.0.0 and then :: is allowed, but not the reverse.
*
* Always bind both in the OSX allowed order.
*/
tcpifaces.emplace_back(AF_INET);
tcpifaces.emplace_back(AF_INET6);
}
} else {
tcpifaces.emplace_back(AF_INET);
}
}
if(tcpifaces.empty()) {
log_err_printf(serversetup, "Server Unreachable. Interface address list includes not TCP interfaces.%s", "\n");
}