mqtt: initial support for MQTTS
No binary (build failed)
—
(log yok)
| @@ -1953,6 +1953,7 @@ curl_add_if("IPNS" NOT CURL_DISABLE_IPFS) | |
| curl_add_if("RTSP" NOT CURL_DISABLE_RTSP) | |
| curl_add_if("RTMP" USE_LIBRTMP) | |
| curl_add_if("MQTT" NOT CURL_DISABLE_MQTT) | |
| + | curl_add_if("MQTTS" NOT CURL_DISABLE_MQTT AND _ssl_enabled) |
| curl_add_if("WS" NOT CURL_DISABLE_WEBSOCKETS) | |
| curl_add_if("WSS" NOT CURL_DISABLE_WEBSOCKETS AND _ssl_enabled) | |
| if(_items) | |
| @@ -5424,6 +5424,9 @@ if test "$CURL_DISABLE_GOPHER" != "1"; then | |
| fi | |
| if test "$CURL_DISABLE_MQTT" != "1"; then | |
| SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS MQTT" | |
| + | if test "$SSL_ENABLED" = "1"; then |
| + | SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS MQTTS" |
| + | fi |
| fi | |
| if test "$CURL_DISABLE_POP3" != "1"; then | |
| SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS POP3" | |
| @@ -21,7 +21,7 @@ The curl project produces two products: | |
| ### libcurl | |
| A client-side URL transfer library, supporting DICT, FILE, FTP, FTPS, GOPHER, | |
| - | GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, |
| + | GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTMP, |
| RTMPS, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. | |
| libcurl supports HTTPS certificates, HTTP POST, HTTP PUT, FTP uploading, | |
| @@ -4,8 +4,8 @@ | |
| **curl** is a tool for transferring data from or to a server using URLs. It | |
| supports these protocols: DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, | |
| - | IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP, SCP, SFTP, |
| - | SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. |
| + | IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTMP, RTMPS, RTSP, SCP, |
| + | SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. |
| curl is powered by libcurl for all transfer-related features. See | |
| *libcurl(3)* for details. | |
| @@ -12,6 +12,10 @@ A plain "GET" subscribes to the topic and prints all published messages. | |
| Doing a "POST" publishes the post data to the topic and exits. | |
| + | ## TLS protection |
| + | |
| + | Use `mqtts://` to do MQTT over TLS: MQTTS. |
| + | |
| ### Subscribing | |
| Command usage: | |
| @@ -51,6 +51,8 @@ CURLPROTO_IMAP | |
| CURLPROTO_IMAPS | |
| CURLPROTO_LDAP | |
| CURLPROTO_LDAPS | |
| + | CURLPROTO_MQTT |
| + | CURLPROTO_MQTTS |
| CURLPROTO_POP3 | |
| CURLPROTO_POP3S | |
| CURLPROTO_RTMP | |
| @@ -42,8 +42,8 @@ set, it returns error. | |
| These are the available protocols: | |
| DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, | |
| - | MQTT, POP3, POP3S, RTMP, RTMPE, RTMPS, RTMPT, RTMPTE, RTMPTS, RTSP, SCP, SFTP, |
| - | SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS, WSS |
| + | MQTT, MQTTS, POP3, POP3S, RTMP, RTMPE, RTMPS, RTMPT, RTMPTE, RTMPTS, RTSP, |
| + | SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS, WSS |
| You can set "ALL" as a short-cut to enable all protocols. Note that by setting | |
| all, you may enable protocols that were not supported the day you write this | |
| @@ -58,6 +58,8 @@ CURLPROTO_IMAP | |
| CURLPROTO_IMAPS | |
| CURLPROTO_LDAP | |
| CURLPROTO_LDAPS | |
| + | CURLPROTO_MQTT |
| + | CURLPROTO_MQTTS |
| CURLPROTO_POP3 | |
| CURLPROTO_POP3S | |
| CURLPROTO_RTMP | |
| @@ -46,8 +46,8 @@ By default libcurl allows HTTP, HTTPS, FTP and FTPS on redirects (since | |
| These are the available protocols: | |
| DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, | |
| - | MQTT, POP3, POP3S, RTMP, RTMPE, RTMPS, RTMPT, RTMPTE, RTMPTS, RTSP, SCP, SFTP, |
| - | SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS, WSS |
| + | MQTT, MQTTS, POP3, POP3S, RTMP, RTMPE, RTMPS, RTMPT, RTMPTE, RTMPTS, RTSP, |
| + | SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS, WSS |
| You can set "ALL" as a short-cut to enable all protocols. Note that by setting | |
| all, you may enable protocols that were not supported the day you write this | |
| @@ -968,6 +968,7 @@ CURLPROTO_IMAPS 7.20.0 | |
| CURLPROTO_LDAP 7.19.4 | |
| CURLPROTO_LDAPS 7.19.4 | |
| CURLPROTO_MQTT 7.71.0 | |
| + | CURLPROTO_MQTTS 8.19.0 |
| CURLPROTO_POP3 7.20.0 | |
| CURLPROTO_POP3S 7.20.0 | |
| CURLPROTO_RTMP 7.21.0 | |
| @@ -184,6 +184,7 @@ Available substitute variables include: | |
| - `%IMAPPORT` - Port number of the IMAP server | |
| - `%LOGDIR` - Log directory relative to %PWD | |
| - `%MQTTPORT` - Port number of the MQTT server | |
| + | - `%MQTTSPORT` - Port number of the MQTTS server |
| - `%NOLISTENPORT` - Port number where no service is listening | |
| - `%POP36PORT` - IPv6 port number of the POP3 server | |
| - `%POP3PORT` - Port number of the POP3 server | |
| @@ -1100,6 +1100,7 @@ typedef CURLSTScode (*curl_hstswrite_callback)(CURL *easy, | |
| #define CURLPROTO_SMBS (1L << 27) | |
| #define CURLPROTO_MQTT (1L << 28) | |
| #define CURLPROTO_GOPHERS (1L << 29) | |
| + | #define CURLPROTO_MQTTS (1L << 30) |
| #define CURLPROTO_ALL (~0L) /* enable everything */ | |
| /* long may be 32 or 64 bits, but we should never depend on anything else | |
| @@ -36,6 +36,8 @@ | |
| #include "url.h" | |
| #include "escape.h" | |
| #include "rand.h" | |
| + | #include "cfilters.h" |
| + | #include "connect.h" |
| /* first byte is command. | |
| second byte is for flags. */ | |
| @@ -934,6 +936,50 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done) | |
| return result; | |
| } | |
| + | #ifdef USE_SSL |
| + | |
| + | static CURLcode mqtts_connecting(struct Curl_easy *data, bool *done) |
| + | { |
| + | struct connectdata *conn = data->conn; |
| + | CURLcode result; |
| + | |
| + | result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, done); |
| + | if(result) |
| + | connclose(conn, "Failed TLS connection"); |
| + | return result; |
| + | } |
| + | |
| + | /* |
| + | * MQTTS protocol handler. |
| + | */ |
| + | |
| + | const struct Curl_handler Curl_handler_mqtts = { |
| + | "mqtts", /* scheme */ |
| + | mqtt_setup_conn, /* setup_connection */ |
| + | mqtt_do, /* do_it */ |
| + | mqtt_done, /* done */ |
| + | ZERO_NULL, /* do_more */ |
| + | ZERO_NULL, /* connect_it */ |
| + | mqtts_connecting, /* connecting */ |
| + | mqtt_doing, /* doing */ |
| + | ZERO_NULL, /* proto_pollset */ |
| + | mqtt_pollset, /* doing_pollset */ |
| + | ZERO_NULL, /* domore_pollset */ |
| + | ZERO_NULL, /* perform_pollset */ |
| + | ZERO_NULL, /* disconnect */ |
| + | ZERO_NULL, /* write_resp */ |
| + | ZERO_NULL, /* write_resp_hd */ |
| + | ZERO_NULL, /* connection_check */ |
| + | ZERO_NULL, /* attach connection */ |
| + | ZERO_NULL, /* follow */ |
| + | PORT_MQTTS, /* defport */ |
| + | CURLPROTO_MQTTS, /* protocol */ |
| + | CURLPROTO_MQTT, /* family */ |
| + | PROTOPT_SSL /* flags */ |
| + | }; |
| + | |
| + | #endif |
| + | |
| /* | |
| * MQTT protocol handler. | |
| */ | |
| @@ -25,6 +25,9 @@ | |
| ***************************************************************************/ | |
| #ifndef CURL_DISABLE_MQTT | |
| extern const struct Curl_handler Curl_handler_mqtt; | |
| + | #ifdef USE_SSL |
| + | extern const struct Curl_handler Curl_handler_mqtts; |
| + | #endif |
| #endif | |
| #endif /* HEADER_CURL_MQTT_H */ | |
| @@ -1423,7 +1423,12 @@ const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme, | |
| #else | |
| NULL, | |
| #endif | |
| - | NULL, NULL, |
| + | #if defined(USE_SSL) && !defined(CURL_DISABLE_MQTT) |
| + | &Curl_handler_mqtts, |
| + | #else |
| + | NULL, |
| + | #endif |
| + | NULL, |
| #if defined(USE_SSL) && !defined(CURL_DISABLE_GOPHER) | |
| &Curl_handler_gophers, | |
| #else | |
| @@ -50,6 +50,7 @@ | |
| #define PORT_RTMPS PORT_HTTPS | |
| #define PORT_GOPHER 70 | |
| #define PORT_MQTT 1883 | |
| + | #define PORT_MQTTS 8883 |
| struct curl_trc_featt; | |
| @@ -341,6 +341,9 @@ static const char * const supported_protocols[] = { | |
| #ifndef CURL_DISABLE_MQTT | |
| "mqtt", | |
| #endif | |
| + | #if defined(USE_SSL) && !defined(CURL_DISABLE_MQTT) |
| + | "mqtts", |
| + | #endif |
| #ifndef CURL_DISABLE_POP3 | |
| "pop3", | |
| #endif | |
| @@ -51,6 +51,7 @@ static const struct detail scheme[] = { | |
| " ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \\\n" | |
| " (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))" }, | |
| { "mqtt", "#ifndef CURL_DISABLE_MQTT" }, | |
| + | { "mqtts", "#if defined(USE_SSL) && !defined(CURL_DISABLE_MQTT)" }, |
| { "pop3", "#ifndef CURL_DISABLE_POP3" }, | |
| { "pop3s", "#if defined(USE_SSL) && !defined(CURL_DISABLE_POP3)" }, | |
| { "rtmp", "#ifdef USE_LIBRTMP" }, | |
| @@ -218,6 +218,8 @@ test1620 test1621 test1622 \ | |
| \ | |
| test1630 test1631 test1632 test1633 test1634 test1635 test1636 \ | |
| \ | |
| + | test1640 \ |
| + | \ |
| test1650 test1651 test1652 test1653 test1654 test1655 test1656 test1657 \ | |
| test1658 \ | |
| test1660 test1661 test1662 test1663 test1664 test1665 \ | |
| @@ -0,0 +1,54 @@ | |
| + | <?xml version="1.0" encoding="US-ASCII"?> |
| + | <testcase> |
| + | <info> |
| + | <keywords> |
| + | MQTT |
| + | MQTT SUBSCRIBE |
| + | MQTTS |
| + | </keywords> |
| + | </info> |
| + | |
| + | # Server-side |
| + | <reply> |
| + | <data nocheck="yes"> |
| + | hello |
| + | </data> |
| + | <datacheck hex="yes"> |
| + | 00 04 31 31 39 30 68 65 6c 6c 6f 5b 4c 46 5d 0a |
| + | </datacheck> |
| + | </reply> |
| + | |
| + | # Client-side |
| + | <client> |
| + | <features> |
| + | mqtts |
| + | </features> |
| + | <server> |
| + | mqtts |
| + | </server> |
| + | <name> |
| + | MQTTS SUBSCRIBE |
| + | </name> |
| + | <command option="binary-trace"> |
| + | mqtts://%HOSTIP:%MQTTSPORT/topic --insecure |
| + | </command> |
| + | </client> |
| + | |
| + | # Verify data after the test has been "shot" |
| + | <verify> |
| + | # These are hexadecimal protocol dumps from the client |
| + | # Strip out the random part of the client id from the CONNECT message |
| + | # before comparison |
| + | <strippart> |
| + | s/^(.* 00044d5154540402003c000c6375726c).*/$1/ |
| + | </strippart> |
| + | <protocol> |
| + | client CONNECT 18 00044d5154540402003c000c6375726c |
| + | server CONNACK 2 20020000 |
| + | client SUBSCRIBE a 00010005746f70696300 |
| + | server SUBACK 3 9003000100 |
| + | server PUBLISH d 300d0005746f70696368656c6c6f0a |
| + | server DISCONNECT 0 e000 |
| + | </protocol> |
| + | </verify> |
| + | </testcase> |
| @@ -125,7 +125,7 @@ sub servername_str { | |
| $proto = uc($proto) if($proto); | |
| die "unsupported protocol: '$proto'" unless($proto && | |
| - | ($proto =~ /^(((DNS|FTP|HTTP|HTTP\/2|HTTP\/3|IMAP|POP3|GOPHER|SMTP|HTTPS-MTLS)S?)|(TFTP|SFTP|SOCKS|SSH|RTSP|HTTPTLS|DICT|SMB|SMBS|TELNET|MQTT))$/)); |
| + | ($proto =~ /^(((DNS|FTP|HTTP|HTTP\/2|HTTP\/3|IMAP|POP3|GOPHER|SMTP|HTTPS-MTLS)S?)|(TFTP|SFTP|SOCKS|SSH|RTSP|HTTPTLS|DICT|SMB|SMBS|TELNET|MQTT|MQTTS))$/)); |
| $ipver = (not $ipver) ? 'ipv4' : lc($ipver); | |
| die "unsupported IP version: '$ipver'" unless($ipver && | |
| @@ -237,8 +237,8 @@ sub init_serverpidfile_hash { | |
| } | |
| } | |
| for my $proto (('tftp', 'sftp', 'socks', 'ssh', 'rtsp', 'httptls', | |
| - | 'dict', 'smb', 'smbs', 'telnet', 'mqtt', 'https-mtls', |
| - | 'dns')) { |
| + | 'dict', 'smb', 'smbs', 'telnet', 'mqtt', 'mqtts', |
| + | 'https-mtls', 'dns')) { |
| for my $ipvnum ((4, 6)) { | |
| for my $idnum ((1, 2)) { | |
| my $serv = servername_id($proto, $ipvnum, $idnum); | |
| @@ -1030,6 +1030,7 @@ my %protofunc = ('http' => \&verifyhttp, | |
| 'pop3s' => \&verifyftp, | |
| 'imaps' => \&verifyftp, | |
| 'mqtt' => \&verifypid, | |
| + | 'mqtts' => \&verifypid, |
| 'smtps' => \&verifyftp, | |
| 'tftp' => \&verifyftp, | |
| 'ssh' => \&verifyssh, | |
| @@ -1329,6 +1330,9 @@ sub runhttpsserver { | |
| if($proto eq "gophers") { | |
| $flags .= "--connect " . protoport("gopher"); | |
| } | |
| + | elsif($proto eq "mqtts") { |
| + | $flags .= "--connect " . protoport("mqtt"); |
| + | } |
| elsif(!$proxy) { | |
| $flags .= "--connect " . protoport("http"); | |
| } | |
| @@ -2955,6 +2959,36 @@ sub startservers { | |
| $run{'mqtt'}="$pid $pid2"; | |
| } | |
| } | |
| + | elsif($what eq "mqtts" ) { |
| + | if(!$stunnel) { |
| + | # we cannot run mqtts tests without stunnel |
| + | return ("no stunnel", 4); |
| + | } |
| + | if($run{'mqtt'} && |
| + | !responsive_mqtt_server("mqtt", "", $verbose)) { |
| + | if(stopserver('mqtt')) { |
| + | return ("failed stopping unresponsive MQTT server", 3); |
| + | } |
| + | } |
| + | if(!$run{'mqtt'}) { |
| + | ($serr, $pid, $pid2, $PORT{"mqtt"}) = runmqttserver("", $verbose); |
| + | if($pid <= 0) { |
| + | return ("failed starting mqtt server", $serr); |
| + | } |
| + | logmsg sprintf("* pid mqtt => %d %d\n", $pid, $pid2) if($verbose); |
| + | $run{'mqtt'}="$pid $pid2"; |
| + | } |
| + | if(!$run{$what}) { |
| + | ($serr, $pid, $pid2, $PORT{$what}) = |
| + | runhttpsserver($verbose, $what, "", $certfile); |
| + | if($pid <= 0) { |
| + | return ("failed starting MQTTS server (stunnel)", $serr); |
| + | } |
| + | logmsg sprintf("* pid $what => %d %d\n", $pid, $pid2) |
| + | if($verbose); |
| + | $run{$what}="$pid $pid2"; |
| + | } |
| + | } |
| elsif($what eq "http-unix") { | |
| if($run{'http-unix'} && | |
| !responsive_http_server("http", $verbose, "unix", $HTTPUNIXPATH)) { | |
| @@ -3094,7 +3128,7 @@ sub subvariables { | |
| 'HTTP2', 'HTTP2TLS', | |
| 'HTTP3', | |
| 'IMAP', 'IMAP6', 'IMAPS', | |
| - | 'MQTT', |
| + | 'MQTT', 'MQTTS', |
| 'NOLISTEN', | |
| 'POP3', 'POP36', 'POP3S', | |
| 'RTSP', 'RTSP6', | |