diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index c14aa907..a7a1069d 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -803,6 +803,16 @@ Not reloaded on reload signal. + + device + + Listen for incoming network connections only on + the specified interface. This is similar to the + preceding option but useful when an interface has + multiple addresses or the address may change. + Not reloaded on reload signal. + + directory diff --git a/mosquitto.conf b/mosquitto.conf index 248417b7..5d1bef9e 100644 --- a/mosquitto.conf +++ b/mosquitto.conf @@ -207,6 +207,11 @@ # Port to use for the default listener. #port 1883 +# Bind the listener to a specific interface. This is similar to +# bind_address above but useful when an interface has multiple +# addresses or the address may change. Only available on Linux. +#bind_interface eth0 + # The maximum number of client connections to allow. This is # a per listener setting. # Default is -1, which means unlimited connections. diff --git a/src/conf.c b/src/conf.c index d92dd2bb..ca8dd879 100644 --- a/src/conf.c +++ b/src/conf.c @@ -291,6 +291,7 @@ void config__cleanup(struct mosquitto__config *config) if(config->listeners){ for(i=0; ilistener_count; i++){ mosquitto__free(config->listeners[i].host); + mosquitto__free(config->listeners[i].bind_interface); mosquitto__free(config->listeners[i].mount_point); mosquitto__free(config->listeners[i].socks); mosquitto__free(config->listeners[i].security_options.auto_id_prefix); @@ -915,6 +916,14 @@ int config__read_file_core(struct mosquitto__config *config, bool reload, struct if(conf__attempt_resolve(config->default_listener.host, "bind_address", MOSQ_LOG_ERR, "Error")){ return MOSQ_ERR_INVAL; } + }else if(!strcmp(token, "bind_interface")){ +#ifdef SO_BINDTODEVICE + if(reload) continue; // Listeners not valid for reloading. + if(conf__parse_string(&token, "bind_interface", &cur_listener->bind_interface, saveptr)) return MOSQ_ERR_INVAL; +#else + log__printf(NULL, MOSQ_LOG_ERR, "Error: bind_interface specified but socket option not available."); + return MOSQ_ERR_INVAL; +#endif }else if(!strcmp(token, "bridge_attempt_unsubscribe")){ #ifdef WITH_BRIDGE if(reload) continue; // FIXME diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index 22d84c1b..24f194fa 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -212,6 +212,7 @@ struct mosquitto__listener { int fd; uint16_t port; char *host; + char *bind_interface; int max_connections; char *mount_point; mosq_sock_t *socks; diff --git a/src/net.c b/src/net.c index ec71fd77..63516ab7 100644 --- a/src/net.c +++ b/src/net.c @@ -22,6 +22,7 @@ Contributors: #include #include #include +#include #else #include #include @@ -395,6 +396,9 @@ int net__socket_listen(struct mosquitto__listener *listener) X509_LOOKUP *lookup; ENGINE *engine = NULL; #endif +#ifdef SO_BINDTODEVICE + struct ifreq ifr; +#endif if(!listener) return MOSQ_ERR_INVAL; @@ -446,6 +450,20 @@ int net__socket_listen(struct mosquitto__listener *listener) return 1; } +#ifdef SO_BINDTODEVICE + 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"); + COMPAT_CLOSE(sock); + return 1; + } + } +#endif + if(bind(sock, rp->ai_addr, rp->ai_addrlen) == -1){ net__print_error(MOSQ_LOG_ERR, "Error: %s"); COMPAT_CLOSE(sock);