Skip to content

Commit

Permalink
Add PROXY v1 support
Browse files Browse the repository at this point in the history
  • Loading branch information
ralight committed Aug 18, 2024
1 parent 49482e7 commit 18fdad5
Show file tree
Hide file tree
Showing 34 changed files with 440 additions and 84 deletions.
2 changes: 1 addition & 1 deletion ChangeLog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ Broker:
choose TLS v1.1, but this is not recommended and will be removed in a future
version.
- Add -q option to allow logging to be disabled at the command line.
- Add suport for PROXY protocol v2.
- Add suport for PROXY protocol v1 and v2.

Plugins / plugin interface:
- Add persist-sqlite plugin.
Expand Down
1 change: 1 addition & 0 deletions lib/mosquitto_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ enum mosquitto__transport {
mosq_t_sctp = 3,
mosq_t_http = 4, /* not valid for MQTT, just as a ws precursor */
mosq_t_proxy_v2 = 5, /* not valid for MQTT, just as a PROXY protocol v2 precursor */
mosq_t_proxy_v1 = 6, /* not valid for MQTT, just as a PROXY protocol v1 precursor */
};

/* Alias direction - local <-> remote */
Expand Down
44 changes: 24 additions & 20 deletions man/mosquitto.conf.5.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1289,11 +1289,18 @@ accept_protocol_versions 3, 4</programlisting>
</listitem>
</varlistentry>
<varlistentry>
<term><option>enable_proxy_protocol_v2</option> [ true | false ]</term>
<term><option>enable_proxy_protocol</option> [ 2 | 1 ]</term>
<listitem>
<para>
Enable PROXY protocol v2 support for this listener.
Defaults to false. This requires the use of a load
Enable PROXY protocol support for this listener.
Versions 1 and 2 are supported, if you have the
choice then version 2 is recommended because it
gives you access to TLS information, and support
Unix sockets.
</para>

<para>
This option requires the use of a load
balancer/proxy such as HAProxy in front of
Mosquitto, with the proxy configured to use the
PROXY protocol.
Expand All @@ -1317,28 +1324,25 @@ accept_protocol_versions 3, 4</programlisting>
</para>

<para>
This option can be used with TLS termination on the
proxy. In this case, TLS information will be passed
to the broker as well. Use <option>proxy_protocol_v2_require_tls</option>
to reject clients that do not use TLS - this is
strongly recommended. Enabling
<option>require_certificate</option> on the
listener will result in the broker checking the TLS
information provided to ensure that the client has
provided a valid certificate. Enabling
<option>use_identity_as_username</option> as well
will result in the
<replaceable>commonName</replaceable> value from
the certificate being used as the client username
instead of any provided in the CONNECT packet. In
both cases, the listener must not have TLS
configured.
When using PROXY version 2, this option can be used
with TLS termination on the proxy. In this case, TLS
information will be passed to the broker as well.
Use <option>proxy_protocol_v2_require_tls</option>
to reject clients that do not use TLS - this is strongly
recommended. Enabling <option>require_certificate</option>
on the listener will result in the broker checking the TLS
information provided to ensure that the client has provided
a valid certificate. Enabling <option>use_identity_as_username</option>
as well will result in the <replaceable>commonName</replaceable>
value from the certificate being used as the client username instead
of any provided in the CONNECT packet. In both cases, the listener
must not have TLS configured.
</para>

<para>
It is not possible to use the <option>use_subject_as_username</option>,
<option>certfile</option>, or <option>keyfile</option> options
in conjunction with <option>enable_proxy_protocol_v2</option>.
in conjunction with <option>enable_proxy_protocol</option>.
</para>
<para>Not reloaded on reload signal.</para>
</listitem>
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ add_executable(mosquitto
plugin_tick.c
plugin_unsubscribe.c
property_broker.c
proxy_v1.c
proxy_v2.c
../lib/property_mosq.c ../lib/property_mosq.h
psk_file.c
Expand Down
1 change: 1 addition & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ OBJS= mosquitto.o \
plugin_subscribe.o \
plugin_unsubscribe.o \
plugin_tick.o \
proxy_v1.o \
proxy_v2.o \
psk_file.o \
read_handle.o \
Expand Down
18 changes: 11 additions & 7 deletions src/conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1600,9 +1600,13 @@ static int config__read_file_core(struct mosquitto__config *config, bool reload,
#else
log__printf(NULL, MOSQ_LOG_WARNING, "Warning: $CONTROL support not available (enable_control_api).");
#endif
}else if(!strcmp(token, "enable_proxy_protocol_v2")){
}else if(!strcmp(token, "enable_proxy_protocol")){
REQUIRE_LISTENER(token);
if(conf__parse_bool(&token, "enable_proxy_protocol_v2", &cur_listener->enable_proxy_protocol_v2, &saveptr)) return MOSQ_ERR_INVAL;
if(conf__parse_int(&token, "enable_proxy_protocol", &cur_listener->enable_proxy_protocol, &saveptr)) return MOSQ_ERR_INVAL;
if(cur_listener->enable_proxy_protocol < 1 || cur_listener->enable_proxy_protocol > 2){
log__printf(NULL, MOSQ_LOG_ERR, "Error: enable_proxy_protocol must be 1 or 2.");
return MOSQ_ERR_INVAL;
}
}else if(!strcmp(token, "global_max_clients")){
if(conf__parse_int(&token, "global_max_clients", &config->global_max_clients, &saveptr)) return MOSQ_ERR_INVAL;
}else if(!strcmp(token, "global_max_connections")){
Expand Down Expand Up @@ -2517,19 +2521,19 @@ int config__read_file(struct mosquitto__config *config, bool reload, const char
return rc;
}

static int config__check_proxy_v2(struct mosquitto__config *config)
static int config__check_proxy(struct mosquitto__config *config)
{
for(int i=0; i<config->listener_count; i++){
struct mosquitto__listener *l = &config->listeners[i];

if(l->enable_proxy_protocol_v2){
if(l->enable_proxy_protocol == 2){
if(l->use_subject_as_username){
log__printf(NULL, MOSQ_LOG_ERR, "Error: use_subject_as_username cannot be used with enable_proxy_protocol_v2.");
log__printf(NULL, MOSQ_LOG_ERR, "Error: use_subject_as_username cannot be used with `enable_proxy_protocol 2`.");
return MOSQ_ERR_INVAL;
}

if(l->certfile || l->keyfile){
log__printf(NULL, MOSQ_LOG_ERR, "Error: certfile and keyfile cannot be used with enable_proxy_protocol_v2.");
log__printf(NULL, MOSQ_LOG_ERR, "Error: certfile and keyfile cannot be used with `enable_proxy_protocol 2`.");
return MOSQ_ERR_INVAL;
}
}
Expand Down Expand Up @@ -2563,7 +2567,7 @@ static int config__check(struct mosquitto__config *config)
}
}

return config__check_proxy_v2(config);
return config__check_proxy(config);
}

#ifdef WITH_BRIDGE
Expand Down
5 changes: 3 additions & 2 deletions src/mosquitto_broker_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ struct mosquitto__listener {
bool disable_protocol_v3;
bool disable_protocol_v4;
bool disable_protocol_v5;
bool enable_proxy_protocol_v2;
int enable_proxy_protocol;
bool proxy_protocol_v2_require_tls;
};

Expand Down Expand Up @@ -965,9 +965,10 @@ int http__write(struct mosquitto *context);
void do_disconnect(struct mosquitto *context, int reason);

/* ============================================================
* PROXY v2 related functions
* PROXY related functions
* ============================================================ */
int proxy_v2__read(struct mosquitto *context);
int proxy_v1__read(struct mosquitto *context);

/* ============================================================
* Will delay
Expand Down
6 changes: 6 additions & 0 deletions src/mux_epoll.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,9 @@ static void loop_handle_reads_writes(struct mosquitto *context, uint32_t events)
case mosq_t_proxy_v2:
rc = packet__write(context);
break;
case mosq_t_proxy_v1:
rc = packet__write(context);
break;
default:
rc = MOSQ_ERR_INVAL;
break;
Expand Down Expand Up @@ -295,6 +298,9 @@ static void loop_handle_reads_writes(struct mosquitto *context, uint32_t events)
case mosq_t_proxy_v2:
rc = proxy_v2__read(context);
break;
case mosq_t_proxy_v1:
rc = proxy_v1__read(context);
break;
default:
rc = MOSQ_ERR_INVAL;
break;
Expand Down
6 changes: 6 additions & 0 deletions src/mux_kqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,9 @@ static void loop_handle_reads_writes(struct mosquitto *context, short event)
case mosq_t_proxy_v2:
rc = packet__write(context);
break;
case mosq_t_proxy_v1:
rc = packet__write(context);
break;
default:
rc = MOSQ_ERR_INVAL;
break;
Expand Down Expand Up @@ -298,6 +301,9 @@ static void loop_handle_reads_writes(struct mosquitto *context, short event)
case mosq_t_proxy_v2:
rc = proxy_v2__read(context);
break;
case mosq_t_proxy_v1:
rc = proxy_v1__read(context);
break;
default:
rc = MOSQ_ERR_INVAL;
break;
Expand Down
6 changes: 6 additions & 0 deletions src/mux_poll.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,9 @@ static void loop_handle_reads_writes(void)
case mosq_t_proxy_v2:
rc = packet__write(context);
break;
case mosq_t_proxy_v1:
rc = packet__write(context);
break;
default:
rc = MOSQ_ERR_INVAL;
break;
Expand Down Expand Up @@ -369,6 +372,9 @@ static void loop_handle_reads_writes(void)
case mosq_t_proxy_v2:
rc = proxy_v2__read(context);
break;
case mosq_t_proxy_v1:
rc = proxy_v1__read(context);
break;
default:
rc = MOSQ_ERR_INVAL;
break;
Expand Down
10 changes: 7 additions & 3 deletions src/net.c
Original file line number Diff line number Diff line change
Expand Up @@ -190,13 +190,17 @@ struct mosquitto *net__socket_accept(struct mosquitto__listener_sock *listensock
}
new_context->listener->client_count++;

if(new_context->listener->enable_proxy_protocol_v2){
if(new_context->listener->enable_proxy_protocol){
if(context__init_sock(new_context, new_sock, false) != MOSQ_ERR_SUCCESS){
context__cleanup(new_context, true);
COMPAT_CLOSE(new_sock);
return NULL;
}
new_context->transport = mosq_t_proxy_v2;
if(new_context->listener->enable_proxy_protocol == 2){
new_context->transport = mosq_t_proxy_v2;
}else{
new_context->transport = mosq_t_proxy_v1;
}
new_context->proxy.cmd = -1;
}else{
if(context__init_sock(new_context, new_sock, true) != MOSQ_ERR_SUCCESS){
Expand Down Expand Up @@ -251,7 +255,7 @@ struct mosquitto *net__socket_accept(struct mosquitto__listener_sock *listensock
#endif

if(db.config->connection_messages == true
&& !new_context->listener->enable_proxy_protocol_v2){
&& !new_context->listener->enable_proxy_protocol){

log__printf(NULL, MOSQ_LOG_NOTICE, "New connection from %s:%d on port %d.",
new_context->address, new_context->remote_port, new_context->listener->port);
Expand Down
Loading

0 comments on commit 18fdad5

Please sign in to comment.