Add the outgoing_bind option
Lets the admin choose a local address to bind each outgoing (IRC) socket.
This commit is contained in:
@@ -120,6 +120,15 @@ The configuration file uses a simple format of the form
|
||||
negociating a TLS session. By default this value is unset and biboumi
|
||||
tries a list of well-known paths.
|
||||
|
||||
`outgoing_bind`
|
||||
|
||||
An address (IPv4 or IPv6) to bind the outgoing sockets to. If no value is
|
||||
specified, it will use the one assigned by the operating system. You can
|
||||
for example use outgoing_bind=192.168.1.11 to force biboumi to use the
|
||||
interface with this address. Note that this is only used for connections
|
||||
to IRC servers, the connection to the XMPP server is always done locally
|
||||
on 127.0.0.1.
|
||||
|
||||
The configuration can be re-read at runtime (you can for example change the
|
||||
log level without having to restart biboumi) by sending SIGUSR1 or SIGUSR2
|
||||
(see kill(1)) to the process.
|
||||
|
||||
@@ -56,6 +56,34 @@ void TCPSocketHandler::init_socket(const struct addrinfo* rp)
|
||||
::close(this->socket);
|
||||
if ((this->socket = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1)
|
||||
throw std::runtime_error("Could not create socket: "s + strerror(errno));
|
||||
// Bind the socket to a specific address, if specified
|
||||
if (!this->bind_addr.empty())
|
||||
{
|
||||
// Convert the address from string format to a sockaddr that can be
|
||||
// used in bind()
|
||||
struct addrinfo* result;
|
||||
int err = ::getaddrinfo(this->bind_addr.data(), nullptr, nullptr, &result);
|
||||
if (err != 0)
|
||||
log_error("Failed to bind socket to " << this->bind_addr << ": "
|
||||
<< gai_strerror(err));
|
||||
else
|
||||
{
|
||||
struct addrinfo* rp;
|
||||
int bind_error;
|
||||
for (rp = result; rp; rp = rp->ai_next)
|
||||
{
|
||||
if ((bind_error = ::bind(this->socket,
|
||||
reinterpret_cast<const struct sockaddr*>(rp->ai_addr),
|
||||
rp->ai_addrlen)) == 0)
|
||||
break;
|
||||
}
|
||||
if (!rp)
|
||||
log_error("Failed to bind socket to " << this->bind_addr << ": "
|
||||
<< strerror(bind_error));
|
||||
else
|
||||
log_info("Socket successfully bound to " << this->bind_addr);
|
||||
}
|
||||
}
|
||||
int optval = 1;
|
||||
if (::setsockopt(this->socket, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) == -1)
|
||||
log_warning("Failed to enable TCP keepalive on socket: " << strerror(errno));
|
||||
|
||||
@@ -224,6 +224,12 @@ protected:
|
||||
|
||||
bool hostname_resolution_failed;
|
||||
|
||||
/**
|
||||
* Address to bind the socket to, before calling connect().
|
||||
* If empty, it’s equivalent to binding to INADDR_ANY.
|
||||
*/
|
||||
std::string bind_addr;
|
||||
|
||||
private:
|
||||
TCPSocketHandler(const TCPSocketHandler&) = delete;
|
||||
TCPSocketHandler(TCPSocketHandler&&) = delete;
|
||||
|
||||
@@ -86,6 +86,9 @@ void IrcClient::start()
|
||||
this->bridge->send_xmpp_message(this->hostname, "", "Connecting to "s +
|
||||
this->hostname + ":" + port + " (" +
|
||||
(tls ? "encrypted" : "not encrypted") + ")");
|
||||
|
||||
this->bind_addr = Config::get("outgoing_bind", "");
|
||||
|
||||
this->connect(this->hostname, port, tls);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user