diff --git a/include/ircd/net/sock_opts.h b/include/ircd/net/sock_opts.h index b1725ce68..269ba4c70 100644 --- a/include/ircd/net/sock_opts.h +++ b/include/ircd/net/sock_opts.h @@ -15,6 +15,7 @@ namespace ircd::net { struct sock_opts; + bool v6only(const socket &); bool blocking(const socket &); bool nodelay(const socket &); bool keepalive(const socket &); @@ -24,6 +25,7 @@ namespace ircd::net size_t read_lowat(const socket &); size_t write_lowat(const socket &); + void v6only(socket &, const bool &); void blocking(socket &, const bool &); void nodelay(socket &, const bool &); void keepalive(socket &, const bool &); @@ -45,6 +47,7 @@ struct ircd::net::sock_opts /// Magic value to not set this option on a set() pass. static constexpr int8_t IGN { std::numeric_limits::min() }; + int8_t v6only { IGN }; int8_t blocking { IGN }; // Simulates blocking behavior int8_t nodelay { IGN }; int8_t keepalive { IGN }; diff --git a/ircd/net.cc b/ircd/net.cc index 1c21541d3..bfd97a665 100644 --- a/ircd/net.cc +++ b/ircd/net.cc @@ -691,7 +691,8 @@ ircd::net::open(socket &socket, /// Construct sock_opts with the current options from socket argument ircd::net::sock_opts::sock_opts(const socket &socket) -:blocking{net::blocking(socket)} +:v6only{net::v6only(socket)} +,blocking{net::blocking(socket)} ,nodelay{net::nodelay(socket)} ,keepalive{net::keepalive(socket)} ,linger{net::linger(socket)} @@ -708,6 +709,9 @@ void ircd::net::set(socket &socket, const sock_opts &opts) { + if(opts.v6only != opts.IGN) + net::v6only(socket, opts.v6only); + if(opts.blocking != opts.IGN) net::blocking(socket, opts.blocking); @@ -855,6 +859,15 @@ ircd::net::blocking(socket &socket, sd.non_blocking(!b); } +void +ircd::net::v6only(socket &socket, + const bool &b) +{ + const ip::v6_only option{b}; + ip::tcp::socket &sd(socket); + sd.set_option(option); +} + size_t ircd::net::write_lowat(const socket &socket) { @@ -925,6 +938,15 @@ ircd::net::blocking(const socket &socket) return !sd.non_blocking(); } +bool +ircd::net::v6only(const socket &socket) +{ + const ip::tcp::socket &sd(socket); + ip::v6_only option; + sd.get_option(option); + return option.value(); +} + /////////////////////////////////////////////////////////////////////////////// // // net/listener.h