Commit 24176883 authored by louiz’'s avatar louiz’

Add the outgoing_bind option

Lets the admin choose a local address to bind each outgoing (IRC) socket.
parent 6dcb21a0
......@@ -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);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment