diff --git a/ChangeLog.txt b/ChangeLog.txt
index b90624c88e..2324897401 100644
--- a/ChangeLog.txt
+++ b/ChangeLog.txt
@@ -8,6 +8,7 @@ Broker:
- Fix apparmor incorrectly denying access to
/var/lib/mosquitto/mosquitto.db.new. Closes #1978.
- Fix potential intermittent initial bridge connections when using poll().
+- Fix `bind_interface` option. Closes #1999.
Apps:
- Disallow control characters in mosquitto_passwd usernames.
diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml
index db3bef1e43..6ea2b10fb7 100644
--- a/man/mosquitto.conf.5.xml
+++ b/man/mosquitto.conf.5.xml
@@ -1035,21 +1035,13 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S
option but is useful
when an interface has multiple addresses or the
address may change.
- It is valid to use this option together with
+ If used at the same time as the
for the default
listener, or the bind
- address/host part of the
- definition. Care should
- be taken to ensure that the address being bound to
- is on the interface being bound to. If you set the
- to be
- eth0, and
- to
- 127.0.0.1, then the
- broker will start correctly but you will be unable
- to connect.
- This option is currently only available on
- Linux, and requires elevated privileges.
+ address/host part of the
+ , then
+ will take priority.
+ This option is not available on Windows.Not reloaded on reload signal.
diff --git a/mosquitto.conf b/mosquitto.conf
index c1f17c1b30..4e407417bd 100644
--- a/mosquitto.conf
+++ b/mosquitto.conf
@@ -229,11 +229,10 @@
# Bind the listener to a specific interface. This is similar to
# the [ip address/host name] part of the listener definition, but is useful
-# when an interface has multiple addresses or the address may change. It is
-# valid to use this with the [ip address/host name] part of the listener
-# definition, but take care that the interface you are binding to contains the
-# address you are binding to, otherwise you will not be able to connect.
-# Only available on Linux and requires elevated privileges.
+# when an interface has multiple addresses or the address may change. If used
+# with the [ip address/host name] part of the listener definition, then the
+# bind_interface option will take priority.
+# Not available on Windows.
#
# Example: bind_interface eth0
#bind_interface
diff --git a/src/net.c b/src/net.c
index b274458233..b18a401bbd 100644
--- a/src/net.c
+++ b/src/net.c
@@ -24,7 +24,7 @@ SPDX-License-Identifier: EPL-2.0 OR EDL-1.0
#include
#include
#include
-#include
+#include
#else
#include
#include
@@ -607,6 +607,52 @@ int net__tls_load_verify(struct mosquitto__listener *listener)
}
+#ifndef WIN32
+static int net__bind_interface(struct mosquitto__listener *listener, mosq_sock_t sock, struct addrinfo *rp)
+{
+ /*
+ * This binds the listener sock to a network interface.
+ * The use of SO_BINDTODEVICE requires root access, which we don't have, so instead
+ * use getifaddrs to find the interface addresses, and attempt to bind to
+ * the IP of the matching interface.
+ */
+ struct ifaddrs *ifaddr, *ifa;
+ if(getifaddrs(&ifaddr) < 0){
+ net__print_error(MOSQ_LOG_ERR, "Error: %s");
+ return MOSQ_ERR_ERRNO;
+ }
+
+ for(ifa=ifaddr; ifa!=NULL; ifa=ifa->ifa_next){
+ if(ifa->ifa_addr == NULL){
+ continue;
+ }
+
+ if(!strcasecmp(listener->bind_interface, ifa->ifa_name)
+ && ifa->ifa_addr->sa_family == rp->ai_addr->sa_family){
+
+ if(rp->ai_addr->sa_family == AF_INET){
+ memcpy(&((struct sockaddr_in *)rp->ai_addr)->sin_addr,
+ &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
+ sizeof(struct in_addr));
+
+ freeifaddrs(ifaddr);
+ return MOSQ_ERR_SUCCESS;
+ }else if(rp->ai_addr->sa_family == AF_INET6){
+ memcpy(&((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr,
+ &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr,
+ sizeof(struct in6_addr));
+ freeifaddrs(ifaddr);
+ return MOSQ_ERR_SUCCESS;
+ }
+ }
+ }
+ freeifaddrs(ifaddr);
+ log__printf(NULL, MOSQ_LOG_ERR, "Error: Interface %s not found.", listener->bind_interface);
+ return MOSQ_ERR_NOT_FOUND;
+}
+#endif
+
+
static int net__socket_listen_tcp(struct mosquitto__listener *listener)
{
mosq_sock_t sock = INVALID_SOCKET;
@@ -615,9 +661,6 @@ static int net__socket_listen_tcp(struct mosquitto__listener *listener)
char service[10];
int rc;
int ss_opt = 1;
-#ifdef SO_BINDTODEVICE
- struct ifreq ifr;
-#endif
if(!listener) return MOSQ_ERR_INVAL;
@@ -680,14 +723,9 @@ static int net__socket_listen_tcp(struct mosquitto__listener *listener)
return 1;
}
-#ifdef SO_BINDTODEVICE
+#ifndef WIN32
if(listener->bind_interface){
- memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, listener->bind_interface, sizeof(ifr.ifr_name)-1);
- ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0';
- log__printf(NULL, MOSQ_LOG_INFO, "Binding listener to interface \"%s\".", ifr.ifr_name);
- if(setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {
- net__print_error(MOSQ_LOG_ERR, "Error: %s");
+ if(net__bind_interface(listener, sock, rp)){
COMPAT_CLOSE(sock);
freeaddrinfo(ainfo);
mosquitto__free(listener->socks);