nanomq / nanomq

An ultra-lightweight and blazing-fast Messaging broker/bus for IoT edge & SDV

Home Page:https://nanomq.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[security]: potential vulnerability

shu7734 opened this issue · comments

当我发起一个非标准的Pub请求的时候,100%导致进程挂掉,提示段错误,应该是内存溢出或指针错误,可能会导致安全漏洞,至少可以用于拒绝服务攻击,Debug日志如下

`
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nng/src/sp/protocol/mqtt/mqtt_parser.c:611 conn_handler: remain len 89 max len 91 prop len 0 pos 12
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nng/src/sp/protocol/mqtt/nmq_mqtt.c:674 nano_pipe_start: client connected! addr [121.35.41.145 port [49502]

2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/apps/broker.c:253 server_cb: RECV ^^^^ ctx1 ^^^^

2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:1494 decode_pub_message: cmd: 3, retain: 0, qos: 0, dup: 0, remaining length: 201
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:1542 decode_pub_message: topic: [$SYS/brokers/connected], len: [22], qos: 0
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:1585 decode_pub_message: used pos: [24]
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:1596 decode_pub_message: payload: [], len = 177
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:1182 handle_pub: pipe_info size: [0]
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/apps/broker.c:497 server_cb: WAIT ^^^^ ctx1 ^^^^
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:1278 free_pub_packet: free topic
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:1294 free_pub_packet: free payload
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:1300 free_pub_packet: free pub_packet
2023-12-28 18:47:23 [411] DEBUG /root/nanomq/nanomq/pub_handler.c:84 init_pipe_content: pub_handler: init pipe_info
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/apps/broker.c:253 server_cb: RECV ^^^^ ctx2 ^^^^

2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/sub_handler.c:65 decode_sub_msg: remainLen: [29] packetid : [23]
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/apps/broker.c:253 server_cb: RECV ^^^^ ctx3 ^^^^

2023-12-28 18:47:23 [410] INFO /root/nanomq/nanomq/sub_handler.c:86 decode_sub_msg: topic: [devtype1/mqttx_0f8aaefa] len: [23] pid [23]
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/pub_handler.c:1494 decode_pub_message: cmd: 3, retain: 0, qos: 1, dup: 0, remaining length: 33
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/sub_handler.c:248 sub_ctx_handle: topicLen: [23] body: [devtype1/mqttx_0f8aaefa]
2023-12-28 18:47:23 [410] INFO /root/nanomq/nanomq/sub_handler.c:269 sub_ctx_handle: acl allow
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nng/src/supplemental/nanolib/mqtt_db.c:385 dbtree_node_new: New node: [devtype1]
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nng/src/supplemental/nanolib/mqtt_db.c:385 dbtree_node_new: New node: [mqttx_0f8aaefa]
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/pub_handler.c:1542 decode_pub_message: topic: [devtype1/mqttx_0f8aaefa], len: [23], qos: 1
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/pub_handler.c:1551 decode_pub_message: identifier: [24]
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/pub_handler.c:1562 decode_pub_message: property len: 0
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/pub_handler.c:1585 decode_pub_message: used pos: [28]
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/pub_handler.c:1596 decode_pub_message: payload: [hello], len = 5
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/sub_handler.c:339 sub_ctx_handle: end of sub ctx handle.

2023-12-28 18:47:23 [413] INFO /root/nanomq/nanomq/pub_handler.c:1164 handle_pub: acl allow
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nng/src/supplemental/nanolib/mqtt_db.c:734 collect_clients: Searching client: devtype1
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/sub_handler.c:188 encode_suback_msg: reason_code: [2]
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nng/src/supplemental/nanolib/mqtt_db.c:754 collect_clients: Searching client: devtype1
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nng/src/supplemental/nanolib/mqtt_db.c:756 collect_clients: add node_t: devtype1
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nng/src/supplemental/nanolib/mqtt_db.c:734 collect_clients: Searching client: mqttx_0f8aaefa
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/sub_handler.c:214 encode_suback_msg: remain: [4] varint: [4 0 0 0] len: [1] packetid: [0 17]
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nng/src/supplemental/nanolib/mqtt_db.c:737 collect_clients: Searching client: mqttx_0f8aaefa
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/pub_handler.c:1182 handle_pub: pipe_info size: [1]
2023-12-28 18:47:23 [413] DEBUG /root/nanomq/nanomq/apps/broker.c:574 server_cb: SEND ^^^^ ctx2 ^^^^
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/apps/broker.c:497 server_cb: WAIT ^^^^ ctx3 ^^^^
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:1343 encode_pub_message: start encode message
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:1380 encode_pub_message: after topic and id len in msg already [27]
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:1403 encode_pub_message: after payload len in msg already [33]
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:1413 encode_pub_message: header len [2] remain len [33]

2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:1465 encode_pub_message: end encode message
ERROR: packet id duplicates in nano_qos_db
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:1278 free_pub_packet: free topic
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:1294 free_pub_packet: free payload
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:1300 free_pub_packet: free pub_packet
2023-12-28 18:47:23 [410] DEBUG /root/nanomq/nanomq/pub_handler.c:84 init_pipe_content: pub_handler: init pipe_info
段错误
`

Thanks for spotting security issue, plz provide your data sample so that we can fix it

感谢你帮忙发现潜在的安全风险,请提供你的测试数据集以便我们尽快修复。

以下是我的Demo代码


#define MG_ARCH MG_ARCH_WIN32
#define MG_TLS MG_TLS_MBED
#include <iostream>
#include "mongoose.h"
#ifndef _LIBPATH_
#define _LIBPATH_(p,f)   p##f
#endif

#ifdef _WIN32
#ifdef _WIN64 //x64
#pragma comment(lib,"lib\\x64\\mbedTLS.lib")
#else
#pragma comment(lib,"lib\\x86\\mbedTLS.lib")
#endif // _WIN64
#endif // _WIN32
/*************************************
* 为了兼容nanomq的websocket协议,需在mg_ws_connect函数的HTTP头添加
*"Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n"
*"Sec-WebSocket-Protocol: mqtt\r\n"
* 否则无法完成握手
**************************************/

//以下为自签CA根证书
static const char* s_ca =
"-----BEGIN CERTIFICATE-----\n"
"MIIC6jCCAdICCQCbea5Ea6i87DANBgkqhkiG9w0BAQsFADA2MTQwMgYDVQQKDCtU\n"
"TFMgUHJxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxR5MCAXDTIx\n"
"MTEyNxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxDCtUTFMgUHJv\n"
"amVjdCBNaWtlWmhvbmcgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIIBIjANBgkqhkiG\n"
"9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzWP5+VG3l8Kg1sTZCKpbj3AkpSGYKZITz3wT\n"
"ZoNfcFNnwlf5l37PbHZ4QjRoA1CW00YbAWzVBpyhQhVtpXtV/ozEzN3+qCPR/3+S\n"
"n802TFoHbaRl7rA6LpEDv1IJGgO8PMAsxrP0KQ6aTCZdFudVQeYtJUtk4f2IIt4K\n"
"oeGkX3GNWQjpR2x/w1rNHrBUUGM++lzeEOR/m5GdaP6o7kyNIG03GhGqVPH5Jntx\n"
"2UvZvE2w+3lpHy0GU8mD/6YdHd5J1tI/2y8klv3Q+ZtQ+5yOW2+HAJaCdYD+k2uu\n"
"MtkKHL4y12qFIpye//AozFVJAJBQ4eaY3l1FuE/no74c5xHp8QIDAQABMA0GCSqG\n"
"SIb3DQEBCwUAA4IBAQCmAbjezu1nBVWbfGqo8jVOMPUryDoAekNDL31jrKPYYLHX\n"
"bTxC6RESpm3YuCyiOyGhK3u5L6pzTPPAPidVJzIzyDSCvamHj0mEQ6J08csl8TAR\n"
"bpRj6ud/ogmnhbpD8UU3Ic28v3ZhmSBteS20WnFQQdSmc9Fp0LDH0RggRrOsGc+j\n"
"mUyzJhtMlkUjEH3ef8wl/jPZkH6JnTDUPS9a6C6sBNJ2ggR+G3qcDIgnqqh/yetD\n"
"fz1ON32qDmE4r0DcpdA8iecdgJ9xvuZ7JCJ6NTzAA+VN748yPU8ziEWTY4DASR0u\n"
"h+r+5S6PINcOU+f++lBJsvFCtcw2FtWsqy/gNjxA\n"
"-----END CERTIFICATE-----\n"
"\n";

static const char* s_topic = "devtype1/mqttx_0f8aaefa";

static const char* s_mqtt_url = "wss://mqtt.xxxx.com/mqtt";

static struct mg_connection* s_mqttconn;
static bool mqtt_stop = false;

// Print websocket response and signal that we're done
static void fn(struct mg_connection* c, int ev, void* ev_data, void* fn_data) {
	if (ev == MG_EV_ERROR) {
		// On error, log error message
		MG_ERROR(("%p %s", c->fd, (char*)ev_data));
	}
	else if (ev == MG_EV_CONNECT) {
		if (mg_url_is_ssl(s_mqtt_url)) {
			struct mg_tls_opts opts = {
				.ca = mg_str(s_ca), .name = mg_url_host(s_mqtt_url)
			};
			mg_tls_init(c, &opts);
		}
	}
	else if (ev == MG_EV_WS_OPEN) {
		// WS connection established. Perform MQTT login
		MG_INFO(("Connected to WS. Logging in to MQTT..."));
		struct mg_mqtt_opts opts = {
			.user = mg_str("user01"),
			.pass = mg_str("xxxxxxxxxxxxxxx"),
			.client_id = mg_str("mqttx_0f8aaefa"),
			.topic = mg_str(s_topic),
			.message = mg_str("goodbye"),
			.qos = 1,
			.version = 5,
			.keepalive=300
		};
		size_t len = c->send.len;
		mg_mqtt_login(c, &opts);
		mg_ws_wrap(c, c->send.len - len, WEBSOCKET_OP_BINARY);
		c->is_hexdumping = 1;
	}
	else if (ev == MG_EV_WS_MSG) {
		struct mg_mqtt_message mm;
		struct mg_ws_message* wm = (struct mg_ws_message*)ev_data;
		uint8_t version = c->is_mqtt5 ? 5 : 4;
		MG_INFO(("GOT %d bytes WS msg", (int)wm->data.len));
		while ((mg_mqtt_parse((uint8_t*)wm->data.ptr,
			wm->data.len,
			version,
			&mm)) == MQTT_OK) {
			switch (mm.cmd) {
			case MQTT_CMD_CONNACK:
				mg_call(c, MG_EV_MQTT_OPEN, &mm.ack);
				if (mm.ack == 0) {
					struct mg_str topic = mg_str(s_topic), data = mg_str("hello");
					size_t len = c->send.len;
					MG_INFO(("CONNECTED to %s", s_mqtt_url));
					struct mg_mqtt_opts sub_opts;
					memset(&sub_opts, 0, sizeof(sub_opts));
					//sub_opts.user = mg_str("user01");
					//sub_opts.pass = mg_str("xxxxxxxxxxxxxxxx");
					//sub_opts.client_id = mg_str("mqttx_0f8aaefa");
					sub_opts.topic = topic;
					sub_opts.qos = 1;
					mg_mqtt_sub(c, &sub_opts);
					len = mg_ws_wrap(c, c->send.len - len, WEBSOCKET_OP_BINARY);
					MG_INFO(("SUBSCRIBED to %.*s", (int)topic.len, topic.ptr));
					struct mg_mqtt_opts pub_opts;
					memset(&pub_opts, 0, sizeof(pub_opts));
					pub_opts.topic = topic;
					pub_opts.message = data;
					pub_opts.qos = 1, pub_opts.retain = false;
					mg_mqtt_pub(c, &pub_opts);
					MG_INFO(("PUBLISHED %.*s -> %.*s", (int)data.len, data.ptr,
						(int)topic.len, topic.ptr));
					len = mg_ws_wrap(c, c->send.len - len, WEBSOCKET_OP_BINARY);
				}
				else {
					MG_ERROR(("%lu MQTT auth failed, code %d", c->id, mm.ack));
					c->is_draining = 1;
				}
				break;
			case MQTT_CMD_PUBLISH: {
				MG_DEBUG(("%lu [%.*s] -> [%.*s]", c->id, (int)mm.topic.len,
					mm.topic.ptr, (int)mm.data.len, mm.data.ptr));
				MG_INFO(("RECEIVED %.*s <- %.*s", (int)mm.data.len, mm.data.ptr,
					(int)mm.topic.len, mm.topic.ptr));
				//c->is_draining = 1;
				break;
			}
			}
			wm->data.ptr += mm.dgram.len;
			wm->data.len -= mm.dgram.len;
		}
	}

	if (ev == MG_EV_ERROR || ev == MG_EV_CLOSE) {
		MG_ERROR(("%p %s", c->fd, (char*)ev_data));
		c->is_closing = 1;
		s_mqttconn = NULL;
	}
}

static void mqtt_timer_fn(void* arg) {
	struct mg_mgr* mgr = (struct mg_mgr*)arg;

	if (s_mqttconn == NULL) 
	{ 
		s_mqttconn = mg_ws_connect(mgr, s_mqtt_url, fn, NULL, NULL);
	//以下请求是当时调试时写错了,却必然引发服务端出错挂掉,服务端不太好变更,只有wss端口开放出来,未测试ws是否也会出现
	size_t len = s_mqttconn->send.len;
	struct mg_str topic = mg_str(s_topic), data = mg_str("test111");
	struct mg_mqtt_opts pub_opts;
	memset(&pub_opts, 0, sizeof(pub_opts));
	pub_opts.topic = topic;
	pub_opts.message = data;
	pub_opts.qos = 1, pub_opts.retain = false;
	mg_mqtt_pub(s_mqttconn, &pub_opts);
	MG_INFO(("PUBLISHED %.*s -> %.*s", (int)data.len, data.ptr,
		(int)topic.len, topic.ptr));
	len = mg_ws_wrap(s_mqttconn, s_mqttconn->send.len, WEBSOCKET_OP_BINARY);
	}
}
int main()
{
	struct mg_mgr mgr;        // Event manager
	bool done = false;        // Event handler flips it to true
	struct mg_connection* c;  // Client connection
	mg_mgr_init(&mgr);        // Initialise event manager
	mg_log_set(MG_LL_DEBUG);  // Set log level
	mg_timer_add(&mgr, 5000, MG_TIMER_REPEAT, mqtt_timer_fn, &mgr);
	while (mqtt_stop == false) mg_mgr_poll(&mgr, 1000);
	mg_mgr_free(&mgr);                                   // Deallocate resources
}

好的 websocket确实并没有做过安全加固

Hello @shu7734

我参考你的demo进行了测试,似乎并没有触发NanoMQ的任何问题。以下是我的编译命令与日志。

make CFLAGS_EXTRA="-DMG_TLS=MG_TLS_MBED -lmbedtls -lmbedcrypto -lmbedx509"
./example
141eaf3 3 net.c:177:mg_connect          1 -1 wss://192.168.192.2:8086/mqtt
141eaf3 3 sock.c:388:mg_connect_resolve 1 4 -> 192.168.192.2:8086 pend
141eaf3 3 mqtt.c:326:mg_mqtt_pub        1 [devtype1/mqttx_0f8aaefa] -> [test111]
141eaf3 2 main.c:166:mqtt_timer_fn      PUBLISHED test111 -> devtype1/mqttx_0f8aaefa
141eaf3 2 main.c:63:fn                  Connected to WS. Logging in to MQTT...
141eaf3 3 tls_mbed.c:107:mg_tls_init    1 Setting TLS
141eb11 3 tls_mbed.c:80:mg_tls_handshak 1 success
141eb11 3 sock.c:299:read_conn          1 0x4 snd 200/2048 rcv 0/2048 n=-2 err=115
141eb11 3 sock.c:310:write_conn         1 4 snd 200/2048 rcv 0/2048 n=200 err=0
141eb11 3 sock.c:299:read_conn          1 0x4 snd 0/2048 rcv 0/2048 n=-1 err=115
141eb11 1 main.c:145:fn                 0x4
141eb11 3 net.c:151:mg_close_conn       1 4 closed
141f2e3 3 net.c:177:mg_connect          2 -1 wss://192.168.192.2:8086/mqtt
141f2e3 3 sock.c:388:mg_connect_resolve 2 4 -> 192.168.192.2:8086 pend
141f2e3 3 mqtt.c:326:mg_mqtt_pub        2 [devtype1/mqttx_0f8aaefa] -> [test111]
141f2e3 2 main.c:166:mqtt_timer_fn      PUBLISHED test111 -> devtype1/mqttx_0f8aaefa
141f2e3 2 main.c:63:fn                  Connected to WS. Logging in to MQTT...
141f2e3 3 tls_mbed.c:107:mg_tls_init    2 Setting TLS
141f301 3 tls_mbed.c:80:mg_tls_handshak 2 success
141f301 3 sock.c:299:read_conn          2 0x4 snd 200/2048 rcv 0/2048 n=-2 err=115
141f301 3 sock.c:310:write_conn         2 4 snd 200/2048 rcv 0/2048 n=200 err=0
141f301 3 sock.c:299:read_conn          2 0x4 snd 0/2048 rcv 0/2048 n=-1 err=115
141f301 1 main.c:145:fn                 0x4
141f301 3 net.c:151:mg_close_conn       2 4 closed

我注意到上述过程中,MQTT连接并没有成功连接,想请问一下,Demo这边是否需要进行修改,还是我的上述的配置或者编译过程有问题。

此外,想请问一下您使用的NanoMQ的版本或者commitid是?能否提供更多NanoMQ的Backtrace信息(NanoMQ编译时开启cmake .. -DDEBUG=ON -DASAN=ON)

没有连接成功请参考我文件前几行的注释代码,需要修改Mongoose的代码的,因为你们有两个特殊的MQTT header

具体版本我就不记得了,就是当天从master签出来的版本,目前为了进度已换成其它的MQTT Server

nanomq遵循标准mqtt协议,并没有特殊的mqtt header开头。
若是从master直接使用可能会遇到开发未完成版本和submodule不匹配的情况,还请使用release tag.

那么我将这个issue标为 invalid,有需要请reopen 并提供可复现的client或log。

没有连接成功请参考我文件前几行的注释代码,需要修改Mongoose的代码的,因为你们有两个特殊的MQTT header

具体版本我就不记得了,就是当天从master签出来的版本,目前为了进度已换成其它的MQTT Server

像这样吗?

s_mqttconn = mg_ws_connect(mgr, s_mqtt_url, fn, NULL, "Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n", "Sec-WebSocket-Protocol: mqtt\r\n");

是的,这样应该也是可以的,Demo还是没连上吗?
我是直接改Mongoose代码实现的

是的,还是无法连接。

不过好消息是,Mongoose官方的Demo可以运行。

以下是我的修改。

--- a/examples/mqtt-over-ws-client/main.c
+++ b/examples/mqtt-over-ws-client/main.c
@@ -13,7 +13,7 @@

static const char *s_url =
#if MG_TLS
-    "wss://broker.hivemq.com:8884/mqtt";
+    "wss://192.168.192.2:8086/mqtt";
#else
"ws://broker.hivemq.com:8000/mqtt";
#endif
@@ -26,7 +26,7 @@ static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
MG_ERROR(("%p %s", c->fd, (char *) ev_data));
} else if (ev == MG_EV_CONNECT) {
if (mg_url_is_ssl(s_url)) {
-      struct mg_tls_opts opts = {.ca = mg_unpacked("/certs/ca.pem"),
+      struct mg_tls_opts opts = {.ca = mg_unpacked("/home/wangha/Documents/nanomq/etc/certs/cacert.pem"),
.name = mg_url_host(s_url)};
mg_tls_init(c, &opts);
}
@@ -98,7 +98,7 @@ int main(void) {
bool done = false;        // Event handler flips it to true when done
mg_mgr_init(&mgr);        // Initialise event manager
mg_log_set(MG_LL_DEBUG);  // Set log level
-  mg_ws_connect(&mgr, s_url, fn, &done, NULL);    // Create client connection
+  mg_ws_connect(&mgr, s_url, fn, &done, "Sec-WebSocket-Protocol: mqtt\r\n");    // Create client connection
while (done == false) mg_mgr_poll(&mgr, 1000);  // Event loop
mg_mgr_free(&mgr);                              // Finished, cleanup
return 0;

我是直接改这里的

struct mg_connection *mg_ws_connect(struct mg_mgr *mgr, const char *url,
                                    mg_event_handler_t fn, void *fn_data,
                                    const char *fmt, ...) {
  struct mg_connection *c = mg_connect(mgr, url, fn, fn_data);
  if (c != NULL) {
    char nonce[16], key[30];
    struct mg_str host = mg_url_host(url);
    mg_random(nonce, sizeof(nonce));
    mg_base64_encode((unsigned char *) nonce, sizeof(nonce), key, sizeof(key));
    mg_xprintf(mg_pfn_iobuf, &c->send,
               "GET %s HTTP/1.1\r\n"
               "Upgrade: websocket\r\n"
               "Host: %.*s\r\n"
               "Connection: Upgrade\r\n"
               "Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n"
               "Sec-WebSocket-Protocol: mqtt\r\n"
               "Sec-WebSocket-Version: 13\r\n"
               "Sec-WebSocket-Key: %s\r\n",
               mg_url_uri(url), (int) host.len, host.ptr, key);