diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..b530e3b0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,22 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{c,h,cpp,hpp}] +indent_style = tab +indent_size = 4 + +[*.py] +indent_style = space +indent_size = 4 + +[Makefile] +indent_style = tab + +[*.{yml,yaml}] +indent_style = space +indent_size = 2 diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 00000000..5ca286b4 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,2 @@ +'Status: Available': + - '/.*/' diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 1f6ac8f4..f2f1abff 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -14,7 +14,7 @@ name: "CodeQL" on: workflow_dispatch: push: - branches: [ master, fixes, develop, 1.6.x ] + branches: [ master, fixes, develop ] pull_request: # The branches below must be a subset of the branches above branches: [ master ] diff --git a/.github/workflows/issue-labler.yml b/.github/workflows/issue-labler.yml new file mode 100644 index 00000000..96aee1bd --- /dev/null +++ b/.github/workflows/issue-labler.yml @@ -0,0 +1,19 @@ +name: "Issue Labeler" +on: + issues: + types: [opened] + +permissions: + issues: write + contents: read + +jobs: + triage: + runs-on: ubuntu-latest + steps: + - uses: github/issue-labeler@v3.4 + with: + configuration-path: .github/labeler.yml + not-before: 2024-11-03T00:00:00Z + enable-versioned-regex: 0 + repo-token: ${{ github.token }} diff --git a/.github/workflows/mosquitto-cmake.yml b/.github/workflows/mosquitto-cmake.yml index e5a0bb76..16988cf1 100644 --- a/.github/workflows/mosquitto-cmake.yml +++ b/.github/workflows/mosquitto-cmake.yml @@ -1,14 +1,21 @@ name: Mosquitto - CMake on: + workflow_dispatch: push: branches: - - develop + - master - fixes + - develop + - release/* + tags: + - 'v[0-9]+.*' pull_request: branches: - - develop + - master - fixes + - develop + - release/* jobs: build: diff --git a/.github/workflows/mosquitto-make.yml b/.github/workflows/mosquitto-make.yml index 974022f2..7e811d35 100644 --- a/.github/workflows/mosquitto-make.yml +++ b/.github/workflows/mosquitto-make.yml @@ -1,14 +1,21 @@ name: Mosquitto - Make on: + workflow_dispatch: push: branches: - - develop + - master - fixes + - develop + - release/* + tags: + - 'v[0-9]+.*' pull_request: branches: - - develop + - master - fixes + - develop + - release/* jobs: build: diff --git a/.github/workflows/windows-x86.yml b/.github/workflows/windows-x86.yml new file mode 100644 index 00000000..9971ad3c --- /dev/null +++ b/.github/workflows/windows-x86.yml @@ -0,0 +1,62 @@ +name: Windows x86 build + +on: + workflow_dispatch: + push: + branches: + - master + - fixes + - develop + - release/* + tags: + - 'v[0-9]+.*' + pull_request: + branches: + - master + - fixes + - develop + - release/* + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + mosquitto: + runs-on: windows-2022 + + steps: + - uses: actions/checkout@v4 + + + - name: vcpkg build + uses: johnwason/vcpkg-action@v6 + id: vcpkg + with: + manifest-dir: ${{ github.workspace }} + triplet: x86-windows + token: ${{ github.token }} + github-binarycache: true + + - name: Configure CMake + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DWITH_WEBSOCKETS=ON -DWITH_TESTS=OFF -DCMAKE_GENERATOR_PLATFORM=WIN32 -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x86-windows -DVCPKG_MANIFEST_MODE=ON + - name: Build + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + + - uses: suisei-cn/actions-download-file@v1.6.0 + id: vcredist + name: Download VC redistributable + with: + url: https://aka.ms/vs/17/release/vc_redist.x86.exe + target: ${{github.workspace}}/installer/ + + - name: Installer + uses: joncloud/makensis-action@v4 + with: + script-file: ${{github.workspace}}/installer/mosquitto.nsi + + - name: Upload installer to artifacts + uses: actions/upload-artifact@v4 + with: + name: installer + path: ${{ github.workspace }}/installer/mosquitto*.exe diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 8361dcbc..247a716b 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -3,10 +3,19 @@ name: Windows build on: workflow_dispatch: push: - branches: [ "master", "fixes", "develop" ] - tags: [ "v[0-9]+.*" ] + branches: + - master + - fixes + - develop + - release/* + tags: + - 'v[0-9]+.*' pull_request: - branches: [ "master", "fixes", "develop" ] + branches: + - master + - fixes + - develop + - release/* env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) @@ -34,7 +43,7 @@ jobs: github-binarycache: true - name: Configure CMake - run: cmake -B ${{github.workspace}}/build64 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DWITH_TESTS=OFF -DCMAKE_GENERATOR_PLATFORM=x64 -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-release -DVCPKG_MANIFEST_MODE=ON + run: cmake -B ${{github.workspace}}/build64 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DWITH_WEBSOCKETS=ON -DWITH_TESTS=OFF -DCMAKE_GENERATOR_PLATFORM=x64 -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-release -DVCPKG_MANIFEST_MODE=ON - name: Build run: cmake --build ${{github.workspace}}/build64 --config ${{env.BUILD_TYPE}} diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 00000000..132e07a9 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,23 @@ +cff-version: 1.2.0 +message: "If you use this software, please cite it as below." +authors: +- family-names: "Light" + given-names: "Roger A." + orcid: "https://orcid.org/0000-0001-9218-7797" +title: "My Research Software" +version: 2.0.21 +doi: 10.21105/joss.00265 +url: "https://github.com/eclise-mosquitto/mosquitto" +preferred-citation: + type: article + authors: + - family-names: "Light" + given-names: "Roger A." + orcid: "https://orcid.org/0000-0001-9218-7797" + doi: "10.21105/joss.00265" + journal: "Journal of Open Source Software" + start: 265 + title: "Mosquitto: server and client implementation of the MQTT protocol" + issue: 13 + volume: 2 + year: 2017 diff --git a/CMakeLists.txt b/CMakeLists.txt index c254173a..d649db67 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ # To configure the build options either use the CMake gui, or run the command # line utility including the "-i" option. -cmake_minimum_required(VERSION 3.14) +cmake_minimum_required(VERSION 3.18) set (VERSION 2.1.0) project(mosquitto diff --git a/ChangeLog.txt b/ChangeLog.txt index 7b939456..52605762 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -223,6 +223,90 @@ Build: - Support for openssl < 3.0 removed. +2.0.22 - 2025-07-11 +=================== + +Broker: +- Windows: Fix broker crash on startup if using `log_dest stdout` +- Bridge: Fix idle_timeout never occurring for lazy bridges. +- Fix case where max_queued_messages = 0 was not treated as unlimited. + Closes #3244. +- Fix `--version` exit code and output. Closes #3267. +- Fix crash on receiving a $CONTROL message over a bridge, if + per_listener_settings is set true and the bridge is carrying out topic + remapping. Closes #3261. +- Fix incorrect reference clock being selected on startup on Linux. + Closes #3238. +- Fix reporting of client disconnections being incorrectly attributed to "out + of memory". Closes #3253. +- Fix compilation when using `WITH_OLD_KEEPALIVE`. Closes #3250. +- Add Windows linker file for the broker to the installer. Closes #3269. +- Fix Websockets PING not being sent on Windows. Closes #3272. +- Fix problems with secure websockets. Closes #1211. +- Fix crash on exit when using WITH_EPOLL=no. Closes #3302. +- Fix clients being incorrectly expired when they have keepalive == + max_keepalive. Closes #3226, #3286. + +Dynamic security plugin: +- Fix mismatch memory free when saving config which caused memory tracking to + be incorrect. + +Client library: +- Fix C++ symbols being removed when compiled with link time optimisation. + Closes #3259. +- TLS error handling was incorrectly setting a protocol error for non-TLS + errors. This would cause the mosquitto_loop_start() thread to exit if no + broker was available on the first connection attempt. This has been fixed. + Closes #3258. +- Fix linker errors on some architectures using cmake. Closes #3167. + + +Tests: +- Fix 08-ssl-connect-cert-auth-expired and 08-ssl-connect-cert-auth-revoked + tests when running on a single CPU system. Closes #3230. + + +2.0.21 - 2025-03-06 +=================== + +Security: +- Fix leak on malicious SUBSCRIBE by authenticated client. + Closes eclipse #248. +- Further fix for CVE-2023-28366. + +Broker: +- Fix clients sending a RESERVED packet not being quickly disconnected. + Closes #2325. +- Fix `bind_interface` producing an error when used with an interface that has + an IPv6 link-local address and no other IPv6 addresses. Closes #2696. +- Fix mismatched wrapped/unwrapped memory alloc/free in properties. Closes #3192. +- Fix `allow_anonymous false` not being applied in local only mode. Closes #3198. +- Add `retain_expiry_interval` option to fix expired retained message not + being removed from memory if they are not subscribed to. Closes #3221. +- Produce an error if invalid combinations of cafile/capath/certfile/keyfile + are used. Closes #1836. Closes #3130. +- Backport keepalive checking from develop to fix problems in current + implementation. Closes #3138. + +Client library: +- Fix potential deadlock in mosquitto_sub if `-W` is used. Closes #3175. + +Apps: +- mosquitto_ctrl dynsec now also allows `-i` to specify a clientid as well as + `-c`. This matches the documentation which states `-i`. Closes #3219. +Client library: +- Fix threads linking on Windows for static libmosquitto library + Closes #3143 + +Build: +- Fix Windows builds not having websockets enabled. +- Add tzdata to docker images + +Tests: +- Fix 08-ssl-connect-cert-auth-expired and 08-ssl-connect-cert-auth-revoked + tests when under load. Closes #3208. + + 2.0.20 - 2024-10-16 =================== diff --git a/apps/db_dump/Makefile b/apps/db_dump/Makefile index 847e4dcc..4c7b74fa 100644 --- a/apps/db_dump/Makefile +++ b/apps/db_dump/Makefile @@ -32,6 +32,10 @@ BROKER_OBJS = \ OBJS_EXTERNAL = \ json_help.o +ifeq ($(UNAME),Linux) + LIBS:=$(LIBS) -lrt +endif + .PHONY: all clean reallyclean ifeq ($(WITH_FUZZING),yes) diff --git a/apps/mosquitto_ctrl/client.c b/apps/mosquitto_ctrl/client.c index e3a1f7a3..26d62a51 100644 --- a/apps/mosquitto_ctrl/client.c +++ b/apps/mosquitto_ctrl/client.c @@ -127,7 +127,11 @@ int client_request_response(struct mosq_ctrl *ctrl) int rc; time_t start; - if(ctrl->cfg.cafile == NULL && ctrl->cfg.capath == NULL){ + if(ctrl->cfg.cafile == NULL && ctrl->cfg.capath == NULL && !ctrl->cfg.tls_use_os_certs && ctrl->cfg.port != 8883 +# ifdef FINAL_WITH_TLS_PSK + && !ctrl->cfg.psk +# endif + ){ fprintf(stderr, "Warning: You are running mosquitto_ctrl without encryption.\nThis means all of the configuration changes you are making are visible on the network, including passwords.\n\n"); } diff --git a/apps/mosquitto_ctrl/dynsec.c b/apps/mosquitto_ctrl/dynsec.c index 5c6850bc..e1198f8a 100644 --- a/apps/mosquitto_ctrl/dynsec.c +++ b/apps/mosquitto_ctrl/dynsec.c @@ -52,7 +52,7 @@ void dynsec__print_usage(void) printf("Set group for anonymous clients: setAnonymousGroup \n"); printf("\nClients\n-------\n"); - printf("Create a new client: createClient [-c clientid] [-p password]\n"); + printf("Create a new client: createClient [-i clientid] [-p password]\n"); printf("Delete a client: deleteClient \n"); printf("Set a client password: setClientPassword [password]\n"); printf("Set a client password on an existing file:\n"); diff --git a/apps/mosquitto_ctrl/dynsec_client.c b/apps/mosquitto_ctrl/dynsec_client.c index 0964fad8..faea27b2 100644 --- a/apps/mosquitto_ctrl/dynsec_client.c +++ b/apps/mosquitto_ctrl/dynsec_client.c @@ -41,9 +41,9 @@ int dynsec_client__create(int argc, char *argv[], cJSON *j_command) username = argv[0]; for(i=1; iport = 8883; + cfg->tls_use_os_certs = true; } else { fprintf(stderr, "Error: Unsupported URL scheme.\n\n"); return 1; @@ -406,6 +407,8 @@ static int client_config_line_proc(struct mosq_config *cfg, int *argc, char **ar } argv++; (*argc)--; + }else if(!strcmp(argv[0], "--tls-use-os-certs")){ + cfg->tls_use_os_certs = true; }else if(!strcmp(argv[0], "--tls-version")){ if((*argc) == 1){ fprintf(stderr, "Error: --tls-version argument given but no version specified.\n\n"); @@ -622,7 +625,21 @@ int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg) } return 1; } +# ifdef FINAL_WITH_TLS_PSK + }else if (cfg->psk){ + if(mosquitto_tls_psk_set(mosq, cfg->psk, cfg->psk_identity, NULL)){ + fprintf(stderr, "Error: Problem setting TLS-PSK options.\n"); + mosquitto_lib_cleanup(); + return 1; + } +# endif + }else if(cfg->port == 8883){ + mosquitto_int_option(mosq, MOSQ_OPT_TLS_USE_OS_CERTS, 1); } + if(cfg->tls_use_os_certs){ + mosquitto_int_option(mosq, MOSQ_OPT_TLS_USE_OS_CERTS, 1); + } + mosquitto_tls_insecure_set(mosq, cfg->insecure); if(cfg->tls_engine && mosquitto_string_option(mosq, MOSQ_OPT_TLS_ENGINE, cfg->tls_engine)){ fprintf(stderr, "Error: Problem setting TLS engine, is %s a valid engine?\n", cfg->tls_engine); @@ -636,12 +653,6 @@ int client_opts_set(struct mosquitto *mosq, struct mosq_config *cfg) fprintf(stderr, "Error: Problem setting TLS ALPN protocol.\n"); return 1; } -# ifdef FINAL_WITH_TLS_PSK - if(cfg->psk && mosquitto_tls_psk_set(mosq, cfg->psk, cfg->psk_identity, NULL)){ - fprintf(stderr, "Error: Problem setting TLS-PSK options.\n"); - return 1; - } -# endif if((cfg->tls_version || cfg->ciphers) && mosquitto_tls_opts_set(mosq, 1, cfg->tls_version, cfg->ciphers)){ fprintf(stderr, "Error: Problem setting TLS options, check the options are valid.\n"); return 1; diff --git a/docker/1.5-openssl/Dockerfile b/docker/1.5-openssl/Dockerfile deleted file mode 100644 index afbaa745..00000000 --- a/docker/1.5-openssl/Dockerfile +++ /dev/null @@ -1,95 +0,0 @@ -FROM alpine:3.18 - -LABEL maintainer="Roger Light " \ - description="Eclipse Mosquitto MQTT Broker" - -ENV VERSION=1.5.11 \ - DOWNLOAD_SHA256=4a3b8a8f5505d27a7a966dd68bfd76f1e69feb51796d1b46b7271d1bb5a1a299 \ - GPG_KEYS=A0D6EEA1DCAE49A635A3B2F0779B22DFB3E717B7 \ - LWS_VERSION=4.2.1 \ - LWS_SHA256=842da21f73ccba2be59e680de10a8cce7928313048750eb6ad73b6fa50763c51 - -RUN set -x && \ - apk --no-cache add --virtual build-deps \ - build-base \ - cmake \ - gnupg \ - linux-headers \ - openssl-dev \ - util-linux-dev && \ - wget https://github.com/warmcat/libwebsockets/archive/v${LWS_VERSION}.tar.gz -O /tmp/lws.tar.gz && \ - echo "$LWS_SHA256 /tmp/lws.tar.gz" | sha256sum -c - && \ - mkdir -p /build/lws && \ - tar --strip=1 -xf /tmp/lws.tar.gz -C /build/lws && \ - rm /tmp/lws.tar.gz && \ - cd /build/lws && \ - cmake . \ - -DCMAKE_BUILD_TYPE=MinSizeRel \ - -DCMAKE_INSTALL_PREFIX=/usr \ - -DDISABLE_WERROR=ON \ - -DLWS_IPV6=ON \ - -DLWS_WITHOUT_BUILTIN_GETIFADDRS=ON \ - -DLWS_WITHOUT_CLIENT=ON \ - -DLWS_WITHOUT_EXTENSIONS=ON \ - -DLWS_WITHOUT_TESTAPPS=ON \ - -DLWS_WITH_EXTERNAL_POLL=ON \ - -DLWS_WITH_HTTP2=OFF \ - -DLWS_WITH_SHARED=OFF \ - -DLWS_WITH_ZIP_FOPS=OFF \ - -DLWS_WITH_ZLIB=OFF && \ - make -j "$(nproc)" && \ - rm -rf /root/.cmake && \ - wget https://mosquitto.org/files/source/mosquitto-${VERSION}.tar.gz -O /tmp/mosq.tar.gz && \ - echo "$DOWNLOAD_SHA256 /tmp/mosq.tar.gz" | sha256sum -c - && \ - wget https://mosquitto.org/files/source/mosquitto-${VERSION}.tar.gz.asc -O /tmp/mosq.tar.gz.asc && \ - export GNUPGHOME="$(mktemp -d)" && \ - found=''; \ - for server in \ - hkps://keys.openpgp.org \ - hkp://keyserver.ubuntu.com:80 \ - pgp.mit.edu \ - ; do \ - echo "Fetching GPG key $GPG_KEYS from $server"; \ - gpg --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$GPG_KEYS" && found=yes && break; \ - done; \ - test -z "$found" && echo >&2 "error: failed to fetch GPG key $GPG_KEYS" && exit 1; \ - gpg --batch --verify /tmp/mosq.tar.gz.asc /tmp/mosq.tar.gz && \ - gpgconf --kill all && \ - rm -rf "$GNUPGHOME" /tmp/mosq.tar.gz.asc && \ - mkdir -p /build/mosq && \ - tar --strip=1 -xf /tmp/mosq.tar.gz -C /build/mosq && \ - rm /tmp/mosq.tar.gz && \ - make -C /build/mosq -j "$(nproc)" \ - CFLAGS="-Wall -O2 -I/build/lws/include -flto" \ - LDFLAGS="-L/build/lws/lib -flto" \ - WITH_ADNS=no \ - WITH_DOCS=no \ - WITH_SHARED_LIBRARIES=yes \ - WITH_SRV=no \ - WITH_STRIP=yes \ - WITH_WEBSOCKETS=yes \ - prefix=/usr \ - binary && \ - addgroup -S -g 1883 mosquitto 2>/dev/null && \ - adduser -S -u 1883 -D -H -h /var/empty -s /sbin/nologin -G mosquitto -g mosquitto mosquitto 2>/dev/null && \ - mkdir -p /mosquitto/config /mosquitto/data /mosquitto/log && \ - install -d /usr/sbin/ && \ - install -s -m755 /build/mosq/client/mosquitto_pub /usr/bin/mosquitto_pub && \ - install -s -m755 /build/mosq/client/mosquitto_sub /usr/bin/mosquitto_sub && \ - install -s -m644 /build/mosq/lib/libmosquitto.so.1 /usr/lib/libmosquitto.so.1 && \ - install -s -m755 /build/mosq/src/mosquitto /usr/sbin/mosquitto && \ - install -s -m755 /build/mosq/src/mosquitto_passwd /usr/bin/mosquitto_passwd && \ - install -m644 /build/mosq/mosquitto.conf /mosquitto/config/mosquitto.conf && \ - chown -R mosquitto:mosquitto /mosquitto && \ - apk --no-cache add \ - ca-certificates libuuid && \ - apk del build-deps && \ - rm -rf /build - -VOLUME ["/mosquitto/data", "/mosquitto/log"] - -# Set up the entry point script and default command -COPY docker-entrypoint.sh / -EXPOSE 1883 -ENTRYPOINT ["/docker-entrypoint.sh"] -CMD ["/usr/sbin/mosquitto", "-c", "/mosquitto/config/mosquitto.conf"] diff --git a/docker/1.5-openssl/README.md b/docker/1.5-openssl/README.md deleted file mode 100644 index 8a54a86b..00000000 --- a/docker/1.5-openssl/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# Eclipse Mosquitto Docker Image -Containers built with this Dockerfile build as source from published tarballs. - -## Mount Points -A docker mount point has been created in the image to be used for configuration. -``` -/mosquitto/config -``` - -Two docker volumes have been created in the image to be used for persistent storage and logs. -``` -/mosquitto/data -/mosquitto/log -``` - -## User/Group - -The image runs mosquitto under the mosquitto user and group, which are created -with a uid and gid of 1883. - -## Configuration -When creating a container from the image, the default configuration values are used. -To use a custom configuration file, mount a **local** configuration file to `/mosquitto/config/mosquitto.conf` -``` -docker run -it -p 1883:1883 -v :/mosquitto/config/mosquitto.conf eclipse-mosquitto: -``` - -:boom: if the mosquitto configuration (mosquitto.conf) was modified -to use non-default ports, the docker run command will need to be updated -to expose the ports that have been configured, for example: - -``` -docker run -it -p 1883:1883 -p 8080:8080 -v :/mosquitto/config/mosquitto.conf eclipse-mosquitto: -``` - -Configuration can be changed to: - -* persist data to `/mosquitto/data` -* log to `/mosquitto/log/mosquitto.log` - -i.e. add the following to `mosquitto.conf`: -``` -persistence true -persistence_location /mosquitto/data/ - -log_dest file /mosquitto/log/mosquitto.log -``` - -**Note**: For any volume used, the data will be persistent between containers. diff --git a/docker/1.5-openssl/docker-entrypoint.sh b/docker/1.5-openssl/docker-entrypoint.sh deleted file mode 100755 index 583f67c9..00000000 --- a/docker/1.5-openssl/docker-entrypoint.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/ash -set -e - -# Set permissions -user="$(id -u)" -if [ "$user" = '0' ]; then - [ -d "/mosquitto" ] && chown -R mosquitto:mosquitto /mosquitto || true -fi - -exec "$@" diff --git a/docker/1.5/Dockerfile b/docker/1.5/Dockerfile deleted file mode 100644 index 45c3c162..00000000 --- a/docker/1.5/Dockerfile +++ /dev/null @@ -1,95 +0,0 @@ -FROM alpine:3.14 - -LABEL maintainer="Roger Light " \ - description="Eclipse Mosquitto MQTT Broker" - -ENV VERSION=1.5.11 \ - DOWNLOAD_SHA256=4a3b8a8f5505d27a7a966dd68bfd76f1e69feb51796d1b46b7271d1bb5a1a299 \ - GPG_KEYS=A0D6EEA1DCAE49A635A3B2F0779B22DFB3E717B7 \ - LWS_VERSION=2.4.2 \ - LWS_SHA256=73012d7fcf428dedccc816e83a63a01462e27819d5537b8e0d0c7264bfacfad6 - -RUN set -x && \ - apk --no-cache add --virtual build-deps \ - build-base \ - cmake \ - gnupg \ - libressl-dev \ - util-linux-dev && \ - wget https://github.com/warmcat/libwebsockets/archive/v${LWS_VERSION}.tar.gz -O /tmp/lws.tar.gz && \ - echo "$LWS_SHA256 /tmp/lws.tar.gz" | sha256sum -c - && \ - mkdir -p /build/lws && \ - tar --strip=1 -xf /tmp/lws.tar.gz -C /build/lws && \ - rm /tmp/lws.tar.gz && \ - cd /build/lws && \ - cmake . \ - -DCMAKE_BUILD_TYPE=MinSizeRel \ - -DCMAKE_INSTALL_PREFIX=/usr \ - -DLWS_IPV6=ON \ - -DLWS_WITHOUT_BUILTIN_GETIFADDRS=ON \ - -DLWS_WITHOUT_CLIENT=ON \ - -DLWS_WITHOUT_EXTENSIONS=ON \ - -DLWS_WITHOUT_TESTAPPS=ON \ - -DLWS_WITH_HTTP2=OFF \ - -DLWS_WITH_SHARED=OFF \ - -DLWS_WITH_ZIP_FOPS=OFF \ - -DLWS_WITH_ZLIB=OFF && \ - make -j "$(nproc)" && \ - rm -rf /root/.cmake && \ - wget https://mosquitto.org/files/source/mosquitto-${VERSION}.tar.gz -O /tmp/mosq.tar.gz && \ - echo "$DOWNLOAD_SHA256 /tmp/mosq.tar.gz" | sha256sum -c - && \ - wget https://mosquitto.org/files/source/mosquitto-${VERSION}.tar.gz.asc -O /tmp/mosq.tar.gz.asc && \ - export GNUPGHOME="$(mktemp -d)" && \ - found=''; \ - for server in \ - hkps://keys.openpgp.org \ - hkp://keyserver.ubuntu.com:80 \ - pgp.mit.edu \ - ; do \ - echo "Fetching GPG key $GPG_KEYS from $server"; \ - gpg --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$GPG_KEYS" && found=yes && break; \ - done; \ - test -z "$found" && echo >&2 "error: failed to fetch GPG key $GPG_KEYS" && exit 1; \ - gpg --batch --verify /tmp/mosq.tar.gz.asc /tmp/mosq.tar.gz && \ - gpgconf --kill all && \ - rm -rf "$GNUPGHOME" /tmp/mosq.tar.gz.asc && \ - mkdir -p /build/mosq && \ - tar --strip=1 -xf /tmp/mosq.tar.gz -C /build/mosq && \ - rm /tmp/mosq.tar.gz && \ - make -C /build/mosq -j "$(nproc)" \ - CFLAGS="-Wall -O2 -I/build/lws/include -flto" \ - LDFLAGS="-L/build/lws/lib -flto" \ - WITH_ADNS=no \ - WITH_DOCS=no \ - WITH_SHARED_LIBRARIES=yes \ - WITH_SRV=no \ - WITH_STRIP=yes \ - WITH_TLS_PSK=no \ - WITH_WEBSOCKETS=yes \ - prefix=/usr \ - binary && \ - addgroup -S -g 1883 mosquitto 2>/dev/null && \ - adduser -S -u 1883 -D -H -h /var/empty -s /sbin/nologin -G mosquitto -g mosquitto mosquitto 2>/dev/null && \ - mkdir -p /mosquitto/config /mosquitto/data /mosquitto/log && \ - install -d /usr/sbin/ && \ - install -s -m755 /build/mosq/client/mosquitto_pub /usr/bin/mosquitto_pub && \ - install -s -m755 /build/mosq/client/mosquitto_sub /usr/bin/mosquitto_sub && \ - install -s -m644 /build/mosq/lib/libmosquitto.so.1 /usr/lib/libmosquitto.so.1 && \ - install -s -m755 /build/mosq/src/mosquitto /usr/sbin/mosquitto && \ - install -s -m755 /build/mosq/src/mosquitto_passwd /usr/bin/mosquitto_passwd && \ - install -m644 /build/mosq/mosquitto.conf /mosquitto/config/mosquitto.conf && \ - chown -R mosquitto:mosquitto /mosquitto && \ - apk --no-cache add \ - ca-certificates \ - libressl \ - libuuid && \ - apk del build-deps && \ - rm -rf /build - -VOLUME ["/mosquitto/data", "/mosquitto/log"] - -# Set up the entry point script and default command -COPY docker-entrypoint.sh / -EXPOSE 1883 -ENTRYPOINT ["/docker-entrypoint.sh"] -CMD ["/usr/sbin/mosquitto", "-c", "/mosquitto/config/mosquitto.conf"] diff --git a/docker/1.5/README.md b/docker/1.5/README.md deleted file mode 100644 index 8a54a86b..00000000 --- a/docker/1.5/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# Eclipse Mosquitto Docker Image -Containers built with this Dockerfile build as source from published tarballs. - -## Mount Points -A docker mount point has been created in the image to be used for configuration. -``` -/mosquitto/config -``` - -Two docker volumes have been created in the image to be used for persistent storage and logs. -``` -/mosquitto/data -/mosquitto/log -``` - -## User/Group - -The image runs mosquitto under the mosquitto user and group, which are created -with a uid and gid of 1883. - -## Configuration -When creating a container from the image, the default configuration values are used. -To use a custom configuration file, mount a **local** configuration file to `/mosquitto/config/mosquitto.conf` -``` -docker run -it -p 1883:1883 -v :/mosquitto/config/mosquitto.conf eclipse-mosquitto: -``` - -:boom: if the mosquitto configuration (mosquitto.conf) was modified -to use non-default ports, the docker run command will need to be updated -to expose the ports that have been configured, for example: - -``` -docker run -it -p 1883:1883 -p 8080:8080 -v :/mosquitto/config/mosquitto.conf eclipse-mosquitto: -``` - -Configuration can be changed to: - -* persist data to `/mosquitto/data` -* log to `/mosquitto/log/mosquitto.log` - -i.e. add the following to `mosquitto.conf`: -``` -persistence true -persistence_location /mosquitto/data/ - -log_dest file /mosquitto/log/mosquitto.log -``` - -**Note**: For any volume used, the data will be persistent between containers. diff --git a/docker/1.5/docker-entrypoint.sh b/docker/1.5/docker-entrypoint.sh deleted file mode 100755 index 583f67c9..00000000 --- a/docker/1.5/docker-entrypoint.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/ash -set -e - -# Set permissions -user="$(id -u)" -if [ "$user" = '0' ]; then - [ -d "/mosquitto" ] && chown -R mosquitto:mosquitto /mosquitto || true -fi - -exec "$@" diff --git a/docker/1.6-openssl/Dockerfile b/docker/1.6-openssl/Dockerfile index 8c98d8ad..df7df1fd 100644 --- a/docker/1.6-openssl/Dockerfile +++ b/docker/1.6-openssl/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.18 +FROM alpine:3.22 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" @@ -86,7 +86,8 @@ RUN set -x && \ install -Dm644 /build/mosq/edl-v10 /usr/share/licenses/mosquitto/edl-v10 && \ chown -R mosquitto:mosquitto /mosquitto && \ apk --no-cache add \ - ca-certificates && \ + ca-certificates \ + tzdata && \ apk del build-deps && \ rm -rf /build diff --git a/docker/1.6/Dockerfile b/docker/1.6/Dockerfile deleted file mode 100644 index 75b8cf42..00000000 --- a/docker/1.6/Dockerfile +++ /dev/null @@ -1,101 +0,0 @@ -FROM alpine:3.14 - -LABEL maintainer="Roger Light " \ - description="Eclipse Mosquitto MQTT Broker" - -ENV VERSION=1.6.15 \ - DOWNLOAD_SHA256=5ff2271512f745bf1a451072cd3768a5daed71e90c5179fae12b049d6c02aa0f \ - GPG_KEYS=A0D6EEA1DCAE49A635A3B2F0779B22DFB3E717B7 \ - LWS_VERSION=4.2.1 \ - LWS_SHA256=842da21f73ccba2be59e680de10a8cce7928313048750eb6ad73b6fa50763c51 - -RUN set -x && \ - apk --no-cache add --virtual build-deps \ - build-base \ - cmake \ - gnupg \ - libressl-dev \ - linux-headers \ - util-linux-dev && \ - wget https://github.com/warmcat/libwebsockets/archive/v${LWS_VERSION}.tar.gz -O /tmp/lws.tar.gz && \ - echo "$LWS_SHA256 /tmp/lws.tar.gz" | sha256sum -c - && \ - mkdir -p /build/lws && \ - tar --strip=1 -xf /tmp/lws.tar.gz -C /build/lws && \ - rm /tmp/lws.tar.gz && \ - cd /build/lws && \ - cmake . \ - -DCMAKE_BUILD_TYPE=MinSizeRel \ - -DCMAKE_INSTALL_PREFIX=/usr \ - -DDISABLE_WERROR=ON \ - -DLWS_IPV6=ON \ - -DLWS_WITHOUT_BUILTIN_GETIFADDRS=ON \ - -DLWS_WITHOUT_CLIENT=ON \ - -DLWS_WITHOUT_EXTENSIONS=ON \ - -DLWS_WITHOUT_TESTAPPS=ON \ - -DLWS_WITH_EXTERNAL_POLL=ON \ - -DLWS_WITH_HTTP2=OFF \ - -DLWS_WITH_SHARED=OFF \ - -DLWS_WITH_ZIP_FOPS=OFF \ - -DLWS_WITH_ZLIB=OFF && \ - make -j "$(nproc)" && \ - rm -rf /root/.cmake && \ - wget https://mosquitto.org/files/source/mosquitto-${VERSION}.tar.gz -O /tmp/mosq.tar.gz && \ - echo "$DOWNLOAD_SHA256 /tmp/mosq.tar.gz" | sha256sum -c - && \ - wget https://mosquitto.org/files/source/mosquitto-${VERSION}.tar.gz.asc -O /tmp/mosq.tar.gz.asc && \ - export GNUPGHOME="$(mktemp -d)" && \ - found=''; \ - for server in \ - hkps://keys.openpgp.org \ - hkp://keyserver.ubuntu.com:80 \ - pgp.mit.edu \ - ; do \ - echo "Fetching GPG key $GPG_KEYS from $server"; \ - gpg --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$GPG_KEYS" && found=yes && break; \ - done; \ - test -z "$found" && echo >&2 "error: failed to fetch GPG key $GPG_KEYS" && exit 1; \ - gpg --batch --verify /tmp/mosq.tar.gz.asc /tmp/mosq.tar.gz && \ - gpgconf --kill all && \ - rm -rf "$GNUPGHOME" /tmp/mosq.tar.gz.asc && \ - mkdir -p /build/mosq && \ - tar --strip=1 -xf /tmp/mosq.tar.gz -C /build/mosq && \ - rm /tmp/mosq.tar.gz && \ - make -C /build/mosq -j "$(nproc)" \ - CFLAGS="-Wall -O2 -I/build/lws/include" \ - LDFLAGS="-L/build/lws/lib" \ - WITH_ADNS=no \ - WITH_DOCS=no \ - WITH_SHARED_LIBRARIES=yes \ - WITH_SRV=no \ - WITH_STRIP=yes \ - WITH_TLS_PSK=no \ - WITH_WEBSOCKETS=yes \ - prefix=/usr \ - binary && \ - addgroup -S -g 1883 mosquitto 2>/dev/null && \ - adduser -S -u 1883 -D -H -h /var/empty -s /sbin/nologin -G mosquitto -g mosquitto mosquitto 2>/dev/null && \ - mkdir -p /mosquitto/config /mosquitto/data /mosquitto/log && \ - install -d /usr/sbin/ && \ - install -s -m755 /build/mosq/client/mosquitto_pub /usr/bin/mosquitto_pub && \ - install -s -m755 /build/mosq/client/mosquitto_rr /usr/bin/mosquitto_rr && \ - install -s -m755 /build/mosq/client/mosquitto_sub /usr/bin/mosquitto_sub && \ - install -s -m644 /build/mosq/lib/libmosquitto.so.1 /usr/lib/libmosquitto.so.1 && \ - install -s -m755 /build/mosq/src/mosquitto /usr/sbin/mosquitto && \ - install -s -m755 /build/mosq/src/mosquitto_passwd /usr/bin/mosquitto_passwd && \ - install -m644 /build/mosq/mosquitto.conf /mosquitto/config/mosquitto.conf && \ - install -Dm644 /build/lws/LICENSE /usr/share/licenses/libwebsockets/LICENSE && \ - install -Dm644 /build/mosq/epl-v10 /usr/share/licenses/mosquitto/epl-v10 && \ - install -Dm644 /build/mosq/edl-v10 /usr/share/licenses/mosquitto/edl-v10 && \ - chown -R mosquitto:mosquitto /mosquitto && \ - apk --no-cache add \ - ca-certificates \ - libressl && \ - apk del build-deps && \ - rm -rf /build - -VOLUME ["/mosquitto/data", "/mosquitto/log"] - -# Set up the entry point script and default command -COPY docker-entrypoint.sh / -EXPOSE 1883 -ENTRYPOINT ["/docker-entrypoint.sh"] -CMD ["/usr/sbin/mosquitto", "-c", "/mosquitto/config/mosquitto.conf"] diff --git a/docker/1.6/README.md b/docker/1.6/README.md deleted file mode 100644 index 8a54a86b..00000000 --- a/docker/1.6/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# Eclipse Mosquitto Docker Image -Containers built with this Dockerfile build as source from published tarballs. - -## Mount Points -A docker mount point has been created in the image to be used for configuration. -``` -/mosquitto/config -``` - -Two docker volumes have been created in the image to be used for persistent storage and logs. -``` -/mosquitto/data -/mosquitto/log -``` - -## User/Group - -The image runs mosquitto under the mosquitto user and group, which are created -with a uid and gid of 1883. - -## Configuration -When creating a container from the image, the default configuration values are used. -To use a custom configuration file, mount a **local** configuration file to `/mosquitto/config/mosquitto.conf` -``` -docker run -it -p 1883:1883 -v :/mosquitto/config/mosquitto.conf eclipse-mosquitto: -``` - -:boom: if the mosquitto configuration (mosquitto.conf) was modified -to use non-default ports, the docker run command will need to be updated -to expose the ports that have been configured, for example: - -``` -docker run -it -p 1883:1883 -p 8080:8080 -v :/mosquitto/config/mosquitto.conf eclipse-mosquitto: -``` - -Configuration can be changed to: - -* persist data to `/mosquitto/data` -* log to `/mosquitto/log/mosquitto.log` - -i.e. add the following to `mosquitto.conf`: -``` -persistence true -persistence_location /mosquitto/data/ - -log_dest file /mosquitto/log/mosquitto.log -``` - -**Note**: For any volume used, the data will be persistent between containers. diff --git a/docker/1.6/docker-entrypoint.sh b/docker/1.6/docker-entrypoint.sh deleted file mode 100755 index 583f67c9..00000000 --- a/docker/1.6/docker-entrypoint.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/ash -set -e - -# Set permissions -user="$(id -u)" -if [ "$user" = '0' ]; then - [ -d "/mosquitto" ] && chown -R mosquitto:mosquitto /mosquitto || true -fi - -exec "$@" diff --git a/docker/2.0-openssl/Dockerfile b/docker/2.0-openssl/Dockerfile index 47b1cf63..a43ebf27 100644 --- a/docker/2.0-openssl/Dockerfile +++ b/docker/2.0-openssl/Dockerfile @@ -1,10 +1,10 @@ -FROM alpine:3.20 +FROM alpine:3.22 LABEL maintainer="Roger Light " \ description="Eclipse Mosquitto MQTT Broker" -ENV VERSION=2.0.20 \ - DOWNLOAD_SHA256=ebd07d89d2a446a7f74100ad51272e4a8bf300b61634a7812e19f068f2759de8 \ +ENV VERSION=2.0.22 \ + DOWNLOAD_SHA256=2f752589ef7db40260b633fbdb536e9a04b446a315138d64a7ff3c14e2de6b68 \ GPG_KEYS=A0D6EEA1DCAE49A635A3B2F0779B22DFB3E717B7 \ LWS_VERSION=4.2.1 \ LWS_SHA256=842da21f73ccba2be59e680de10a8cce7928313048750eb6ad73b6fa50763c51 @@ -90,7 +90,8 @@ RUN set -x && \ chown -R mosquitto:mosquitto /mosquitto && \ apk --no-cache add \ ca-certificates \ - cjson && \ + cjson \ + tzdata && \ apk del build-deps && \ rm -rf /build diff --git a/docker/2.0-openssl/README.md b/docker/2.0-openssl/README.md index 8ec812ed..7d592936 100644 --- a/docker/2.0-openssl/README.md +++ b/docker/2.0-openssl/README.md @@ -71,6 +71,19 @@ to expose the ports that have been configured, for example: docker run -it -p 1883:1883 -p 8080:8080 -v :/mosquitto/config/mosquitto.conf eclipse-mosquitto: ``` +**Important**: The default configuration only listens on the loopback +interface. This means that there is no way to access Mosquitto in the docker +container without using a custom configuration containing at least a listener. +You also need to make a decision to allow anonymous connections or to set up a +different method of client authentication. + +i.e. to configure a Mosquitto docker container as if it was running locally, +add the following to `mosquitto.conf`: +``` +listener 1883 +allow_anonymous true +``` + Configuration can be changed to: * persist data to `/mosquitto/data` diff --git a/docker/2.0/Dockerfile b/docker/2.0/Dockerfile deleted file mode 100644 index 76a38aad..00000000 --- a/docker/2.0/Dockerfile +++ /dev/null @@ -1,105 +0,0 @@ -FROM alpine:3.20 - -LABEL maintainer="Roger Light " \ - description="Eclipse Mosquitto MQTT Broker" - -ENV VERSION=2.0.19 \ - DOWNLOAD_SHA256=33af3637f119a61c509c01d2f8f6cc3d8be76f49e850132f2860af142abf82a9 \ - GPG_KEYS=A0D6EEA1DCAE49A635A3B2F0779B22DFB3E717B7 \ - LWS_VERSION=4.2.1 \ - LWS_SHA256=842da21f73ccba2be59e680de10a8cce7928313048750eb6ad73b6fa50763c51 - -RUN set -x && \ - apk --no-cache add --virtual build-deps \ - build-base \ - cmake \ - cjson-dev \ - gnupg \ - libressl-dev \ - linux-headers \ - util-linux-dev && \ - wget https://github.com/warmcat/libwebsockets/archive/v${LWS_VERSION}.tar.gz -O /tmp/lws.tar.gz && \ - echo "$LWS_SHA256 /tmp/lws.tar.gz" | sha256sum -c - && \ - mkdir -p /build/lws && \ - tar --strip=1 -xf /tmp/lws.tar.gz -C /build/lws && \ - rm /tmp/lws.tar.gz && \ - cd /build/lws && \ - cmake . \ - -DCMAKE_BUILD_TYPE=MinSizeRel \ - -DCMAKE_INSTALL_PREFIX=/usr \ - -DDISABLE_WERROR=ON \ - -DLWS_IPV6=ON \ - -DLWS_WITHOUT_BUILTIN_GETIFADDRS=ON \ - -DLWS_WITHOUT_CLIENT=ON \ - -DLWS_WITHOUT_EXTENSIONS=ON \ - -DLWS_WITHOUT_TESTAPPS=ON \ - -DLWS_WITH_EXTERNAL_POLL=ON \ - -DLWS_WITH_HTTP2=OFF \ - -DLWS_WITH_SHARED=OFF \ - -DLWS_WITH_ZIP_FOPS=OFF \ - -DLWS_WITH_ZLIB=OFF && \ - make -j "$(nproc)" && \ - rm -rf /root/.cmake && \ - wget https://mosquitto.org/files/source/mosquitto-${VERSION}.tar.gz -O /tmp/mosq.tar.gz && \ - echo "$DOWNLOAD_SHA256 /tmp/mosq.tar.gz" | sha256sum -c - && \ - wget https://mosquitto.org/files/source/mosquitto-${VERSION}.tar.gz.asc -O /tmp/mosq.tar.gz.asc && \ - export GNUPGHOME="$(mktemp -d)" && \ - found=''; \ - for server in \ - hkps://keys.openpgp.org \ - hkp://keyserver.ubuntu.com:80 \ - pgp.mit.edu \ - ; do \ - echo "Fetching GPG key $GPG_KEYS from $server"; \ - gpg --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$GPG_KEYS" && found=yes && break; \ - done; \ - test -z "$found" && echo >&2 "error: failed to fetch GPG key $GPG_KEYS" && exit 1; \ - gpg --batch --verify /tmp/mosq.tar.gz.asc /tmp/mosq.tar.gz && \ - gpgconf --kill all && \ - rm -rf "$GNUPGHOME" /tmp/mosq.tar.gz.asc && \ - mkdir -p /build/mosq && \ - tar --strip=1 -xf /tmp/mosq.tar.gz -C /build/mosq && \ - rm /tmp/mosq.tar.gz && \ - make -C /build/mosq -j "$(nproc)" \ - CFLAGS="-Wall -O2 -I/build/lws/include -I/build" \ - LDFLAGS="-L/build/lws/lib" \ - WITH_ADNS=no \ - WITH_DOCS=no \ - WITH_SHARED_LIBRARIES=yes \ - WITH_SRV=no \ - WITH_STRIP=yes \ - WITH_TLS_PSK=no \ - WITH_WEBSOCKETS=yes \ - prefix=/usr \ - binary && \ - addgroup -S -g 1883 mosquitto 2>/dev/null && \ - adduser -S -u 1883 -D -H -h /var/empty -s /sbin/nologin -G mosquitto -g mosquitto mosquitto 2>/dev/null && \ - mkdir -p /mosquitto/config /mosquitto/data /mosquitto/log && \ - install -d /usr/sbin/ && \ - install -s -m755 /build/mosq/client/mosquitto_pub /usr/bin/mosquitto_pub && \ - install -s -m755 /build/mosq/client/mosquitto_rr /usr/bin/mosquitto_rr && \ - install -s -m755 /build/mosq/client/mosquitto_sub /usr/bin/mosquitto_sub && \ - install -s -m644 /build/mosq/lib/libmosquitto.so.1 /usr/lib/libmosquitto.so.1 && \ - install -s -m755 /build/mosq/src/mosquitto /usr/sbin/mosquitto && \ - install -s -m755 /build/mosq/apps/mosquitto_ctrl/mosquitto_ctrl /usr/bin/mosquitto_ctrl && \ - install -s -m755 /build/mosq/apps/mosquitto_passwd/mosquitto_passwd /usr/bin/mosquitto_passwd && \ - install -s -m755 /build/mosq/plugins/dynamic-security/mosquitto_dynamic_security.so /usr/lib/mosquitto_dynamic_security.so && \ - install -m644 /build/mosq/mosquitto.conf /mosquitto/config/mosquitto.conf && \ - install -Dm644 /build/lws/LICENSE /usr/share/licenses/libwebsockets/LICENSE && \ - install -Dm644 /build/mosq/epl-v20 /usr/share/licenses/mosquitto/epl-v20 && \ - install -Dm644 /build/mosq/edl-v10 /usr/share/licenses/mosquitto/edl-v10 && \ - chown -R mosquitto:mosquitto /mosquitto && \ - apk --no-cache add \ - ca-certificates \ - cjson \ - libressl && \ - apk del build-deps && \ - rm -rf /build - -VOLUME ["/mosquitto/data", "/mosquitto/log"] - -# Set up the entry point script and default command -COPY docker-entrypoint.sh mosquitto-no-auth.conf / -EXPOSE 1883 -ENTRYPOINT ["/docker-entrypoint.sh"] -CMD ["/usr/sbin/mosquitto", "-c", "/mosquitto/config/mosquitto.conf"] diff --git a/docker/2.0/README.md b/docker/2.0/README.md deleted file mode 100644 index 8ec812ed..00000000 --- a/docker/2.0/README.md +++ /dev/null @@ -1,87 +0,0 @@ -# Eclipse Mosquitto Docker Image -Containers built with this Dockerfile build as source from published tarballs. - -## Mount Points -A docker mount point has been created in the image to be used for configuration. -``` -/mosquitto/config -``` - -Two docker volumes have been created in the image to be used for persistent storage and logs. -``` -/mosquitto/data -/mosquitto/log -``` - -## User/Group - -The image runs mosquitto under the mosquitto user and group, which are created -with a uid and gid of 1883. - -## Running without a configuration file -Mosquitto 2.0 requires you to configure listeners and authentication before it -will allow connections from anything other than the loopback interface. In the -context of a container, this means you would normally need to provide a -configuration file with your settings. - -If you wish to run mosquitto without any authentication, and without setting -any other configuration options, you can do so by using a configuration -provided in the container for this purpose: -``` -docker run -it -p 1883:1883 eclipse-mosquitto: mosquitto -c /mosquitto-no-auth.conf -``` - -## Configuration -To use a custom configuration file, mount a **local** configuration file to `/mosquitto/config/mosquitto.conf` - -``` -docker run -it -p 1883:1883 -v :/mosquitto/config/mosquitto.conf eclipse-mosquitto: -``` - -Your configuration file must include a `listener`, and you must configure some -form of authentication or allow unauthenticated access. If you do not do this, -clients will be unable to connect. - - -File based authentication and authorisation: -``` -listener 1883 -password_file /mosquitto/data/mosquitto.password_file -acl_file /mosquitto/data/mosquitto.aclfile -``` - -Plugin based authentication and authorisation: -``` -listener 1883 -plugin /usr/lib/mosquitto_dynamic_security.so -plugin_opt_config_file /mosquitto/data/mosquitto-dynsec.json -``` - -Unauthenticated access: -``` -listener 1883 -allow_anonymous true -``` - -:boom: if the mosquitto configuration (mosquitto.conf) was modified -to use non-default ports, the docker run command will need to be updated -to expose the ports that have been configured, for example: - -``` -docker run -it -p 1883:1883 -p 8080:8080 -v :/mosquitto/config/mosquitto.conf eclipse-mosquitto: -``` - -Configuration can be changed to: - -* persist data to `/mosquitto/data` -* log to `/mosquitto/log/mosquitto.log` - -i.e. add the following to `mosquitto.conf`: -``` -persistence true -persistence_location /mosquitto/data/ - -log_dest file /mosquitto/log/mosquitto.log -``` - -**Note**: For any volume used, the data will be persistent between containers. diff --git a/docker/2.0/docker-entrypoint.sh b/docker/2.0/docker-entrypoint.sh deleted file mode 100755 index 583f67c9..00000000 --- a/docker/2.0/docker-entrypoint.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/ash -set -e - -# Set permissions -user="$(id -u)" -if [ "$user" = '0' ]; then - [ -d "/mosquitto" ] && chown -R mosquitto:mosquitto /mosquitto || true -fi - -exec "$@" diff --git a/docker/2.0/mosquitto-no-auth.conf b/docker/2.0/mosquitto-no-auth.conf deleted file mode 100644 index 40dd92b9..00000000 --- a/docker/2.0/mosquitto-no-auth.conf +++ /dev/null @@ -1,5 +0,0 @@ -# This is a Mosquitto configuration file that creates a listener on port 1883 -# that allows unauthenticated access. - -listener 1883 -allow_anonymous true diff --git a/docker/generic/Dockerfile b/docker/generic/Dockerfile index b7970bfb..d94a2d21 100644 --- a/docker/generic/Dockerfile +++ b/docker/generic/Dockerfile @@ -13,6 +13,16 @@ ENV \ CJSON_VERSION=1.7.14 \ CJSON_SHA256=fb50a663eefdc76bafa80c82bc045af13b1363e8f45cec8b442007aef6a41343 +LABEL \ + org.opencontainers.image.authors="Roger Light " \ + org.opencontainers.image.title="mosquitto" \ + org.opencontainers.image.description="Eclipse Mosquitto MQTT Broker" \ + org.opencontainers.image.url="https://mosquitto.org/" \ + org.opencontainers.image.documentation="https://mosquitto.org/documentation/" \ + org.opencontainers.image.source="https://github.com/eclipse-mosquitto/mosquitto" \ + org.opencontainers.image.licenses="EPL-2.0" \ + org.opencontainers.image.version=${VERSION} + RUN set -x && \ apk --no-cache add --virtual build-deps \ build-base \ @@ -108,7 +118,8 @@ RUN set -x && \ install -Dm644 /build/mosq/edl-v10 /usr/share/licenses/mosquitto/edl-v10 && \ chown -R mosquitto:mosquitto /mosquitto && \ apk --no-cache add \ - ca-certificates && \ + ca-certificates \ + tzdata && \ apk del build-deps && \ rm -rf /build diff --git a/docker/generic/README.md b/docker/generic/README.md index d2c20643..dd4e6de5 100644 --- a/docker/generic/README.md +++ b/docker/generic/README.md @@ -58,3 +58,16 @@ docker run -it -p 1883:1883 -v :/mosquitto/config/mo :boom: if the mosquitto configuration (mosquitto.conf) was modified to use non-default ports, the docker run command will need to be updated to expose the ports that have been configured. + +**Important**: The default configuration only listens on the +loopback interface. This means that there is no way to access Mosquitto in the +docker container without using a custom configuration containing at least +a listener. You also need to make a decision to allow anonymous connections or +to set up a different method of client authentication. + +i.e. to configure a Mosquitto docker container as if it was running locally, +add the following to `mosquitto.conf`: +``` +listener 1883 +allow_anonymous true +``` diff --git a/docker/local/Dockerfile b/docker/local/Dockerfile index 80de59a8..94725e98 100644 --- a/docker/local/Dockerfile +++ b/docker/local/Dockerfile @@ -50,7 +50,8 @@ RUN set -x && \ argon2-libs \ ca-certificates \ cjson \ - sqlite-libs && \ + sqlite-libs \ + tzdata && \ apk del build-deps && \ rm -rf /build diff --git a/include/mosquitto/mqtt_protocol.h b/include/mosquitto/mqtt_protocol.h index 69d1ed5a..48efe416 100644 --- a/include/mosquitto/mqtt_protocol.h +++ b/include/mosquitto/mqtt_protocol.h @@ -36,6 +36,7 @@ Contributors: /* Message types */ +#define CMD_RESERVED 0x00U #define CMD_CONNECT 0x10U #define CMD_CONNACK 0x20U #define CMD_PUBLISH 0x30U diff --git a/installer/mosquitto64.nsi b/installer/mosquitto64.nsi index dfe67d30..aadacfef 100644 --- a/installer/mosquitto64.nsi +++ b/installer/mosquitto64.nsi @@ -80,6 +80,7 @@ Section "Files" SecInstall File "..\build64\vcpkg_installed\x64-windows-release\bin\sqlite3.dll" SetOutPath "$INSTDIR\devel" + File /oname=mosquitto_broker.lib "..\build64\src\Release\mosquitto.lib" File "..\build64\lib\Release\mosquitto.lib" File "..\build64\lib\cpp\Release\mosquittopp.lib" File "..\include\mosquitto.h" @@ -176,13 +177,6 @@ Section "Uninstall" Delete "$INSTDIR\epl-v20" Delete "$INSTDIR\mosquitto.ico" - Delete "$INSTDIR\cjson.dll" - Delete "$INSTDIR\libcrypto-3-x64.dll" - Delete "$INSTDIR\libssl-3-x64.dll" - Delete "$INSTDIR\pthreadVC3.dll" - Delete "$INSTDIR\uv.dll" - Delete "$INSTDIR\websockets.dll" - Delete "$INSTDIR\argon2.dll" Delete "$INSTDIR\cjson.dll" Delete "$INSTDIR\libcrypto-3-x64.dll" diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index a1bc2033..126fc40f 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -51,7 +51,7 @@ set(C_SRC util_mosq.c util_mosq.h will_mosq.c will_mosq.h) -set(LIBRARIES common-options) +set(LIBRARIES common-options libmosquitto_common) if(WITH_TLS) set (LIBRARIES ${LIBRARIES} OpenSSL::SSL) @@ -116,20 +116,16 @@ endif() if(WITH_THREADING) if(WIN32) - target_link_libraries(libmosquitto PRIVATE PThreads4W::PThreads4W) + set (LIBRARIES ${LIBRARIES} PThreads4W::PThreads4W) else() set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) - target_link_libraries(libmosquitto PRIVATE Threads::Threads) + set (LIBRARIES ${LIBRARIES} Threads::Threads) endif() endif() -target_link_libraries(libmosquitto - PUBLIC - libmosquitto_common -) -target_link_libraries(libmosquitto PRIVATE ${LIBRARIES}) +target_link_libraries(libmosquitto PUBLIC ${LIBRARIES}) set_target_properties(libmosquitto PROPERTIES OUTPUT_NAME mosquitto diff --git a/lib/handle_pubrec.c b/lib/handle_pubrec.c index 8248f5cb..cb9e8d4d 100644 --- a/lib/handle_pubrec.c +++ b/lib/handle_pubrec.c @@ -126,4 +126,3 @@ int handle__pubrec(struct mosquitto *mosq) return MOSQ_ERR_SUCCESS; } - diff --git a/lib/handle_suback.c b/lib/handle_suback.c index eca7f874..d862dab2 100644 --- a/lib/handle_suback.c +++ b/lib/handle_suback.c @@ -100,4 +100,3 @@ int handle__suback(struct mosquitto *mosq) return MOSQ_ERR_SUCCESS; } - diff --git a/lib/handle_unsuback.c b/lib/handle_unsuback.c index 2c7ed763..6d557271 100644 --- a/lib/handle_unsuback.c +++ b/lib/handle_unsuback.c @@ -99,4 +99,3 @@ int handle__unsuback(struct mosquitto *mosq) return MOSQ_ERR_SUCCESS; } - diff --git a/lib/helpers.c b/lib/helpers.c index 3f4b8a2d..06152121 100644 --- a/lib/helpers.c +++ b/lib/helpers.c @@ -114,7 +114,7 @@ libmosq_EXPORT int mosquitto_subscribe_simple( *messages = NULL; - userdata.messages = mosquitto_calloc(sizeof(struct mosquitto_message), (size_t)msg_count); + userdata.messages = mosquitto_calloc((size_t)msg_count, sizeof(struct mosquitto_message)); if(!userdata.messages){ return MOSQ_ERR_NOMEM; } diff --git a/lib/http_client.c b/lib/http_client.c index 91ed661c..bd79953c 100644 --- a/lib/http_client.c +++ b/lib/http_client.c @@ -129,9 +129,7 @@ int http_c__read(struct mosquitto *mosq) if(read_length == 0){ return MOSQ_ERR_CONN_LOST; /* EOF */ } -#ifdef WIN32 - errno = WSAGetLastError(); -#endif + WINDOWS_SET_ERRNO(); if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ diff --git a/lib/libmosquitto.c b/lib/libmosquitto.c index 03960f24..79d6830a 100644 --- a/lib/libmosquitto.c +++ b/lib/libmosquitto.c @@ -221,20 +221,23 @@ int mosquitto_reinitialise(struct mosquitto *mosq, const char *id, bool clean_st mosq->ssl = NULL; mosq->ssl_ctx = NULL; mosq->ssl_ctx_defaults = true; +#ifndef WITH_BROKER + mosq->user_ssl_ctx = NULL; +#endif mosq->tls_cert_reqs = SSL_VERIFY_PEER; mosq->tls_insecure = false; mosq->want_write = false; mosq->tls_ocsp_required = false; #endif #ifdef WITH_THREADING - pthread_mutex_init(&mosq->callback_mutex, NULL); - pthread_mutex_init(&mosq->log_callback_mutex, NULL); - pthread_mutex_init(&mosq->state_mutex, NULL); - pthread_mutex_init(&mosq->out_packet_mutex, NULL); - pthread_mutex_init(&mosq->msgtime_mutex, NULL); - pthread_mutex_init(&mosq->msgs_in.mutex, NULL); - pthread_mutex_init(&mosq->msgs_out.mutex, NULL); - pthread_mutex_init(&mosq->mid_mutex, NULL); + COMPAT_pthread_mutex_init(&mosq->callback_mutex, NULL); + COMPAT_pthread_mutex_init(&mosq->log_callback_mutex, NULL); + COMPAT_pthread_mutex_init(&mosq->state_mutex, NULL); + COMPAT_pthread_mutex_init(&mosq->out_packet_mutex, NULL); + COMPAT_pthread_mutex_init(&mosq->msgtime_mutex, NULL); + COMPAT_pthread_mutex_init(&mosq->msgs_in.mutex, NULL); + COMPAT_pthread_mutex_init(&mosq->msgs_out.mutex, NULL); + COMPAT_pthread_mutex_init(&mosq->mid_mutex, NULL); mosq->thread_id = pthread_self(); #endif if(mosq->disable_socketpair == false){ @@ -257,8 +260,8 @@ void mosquitto__destroy(struct mosquitto *mosq) #ifdef WITH_THREADING # ifdef HAVE_PTHREAD_CANCEL if(mosq->threaded == mosq_ts_self && !pthread_equal(mosq->thread_id, pthread_self())){ - pthread_cancel(mosq->thread_id); - pthread_join(mosq->thread_id, NULL); + COMPAT_pthread_cancel(mosq->thread_id); + COMPAT_pthread_join(mosq->thread_id, NULL); mosq->threaded = mosq_ts_none; } # endif @@ -267,14 +270,14 @@ void mosquitto__destroy(struct mosquitto *mosq) /* If mosq->id is not NULL then the client has already been initialised * and so the mutexes need destroying. If mosq->id is NULL, the mutexes * haven't been initialised. */ - pthread_mutex_destroy(&mosq->callback_mutex); - pthread_mutex_destroy(&mosq->log_callback_mutex); - pthread_mutex_destroy(&mosq->state_mutex); - pthread_mutex_destroy(&mosq->out_packet_mutex); - pthread_mutex_destroy(&mosq->msgtime_mutex); - pthread_mutex_destroy(&mosq->msgs_in.mutex); - pthread_mutex_destroy(&mosq->msgs_out.mutex); - pthread_mutex_destroy(&mosq->mid_mutex); + COMPAT_pthread_mutex_destroy(&mosq->callback_mutex); + COMPAT_pthread_mutex_destroy(&mosq->log_callback_mutex); + COMPAT_pthread_mutex_destroy(&mosq->state_mutex); + COMPAT_pthread_mutex_destroy(&mosq->out_packet_mutex); + COMPAT_pthread_mutex_destroy(&mosq->msgtime_mutex); + COMPAT_pthread_mutex_destroy(&mosq->msgs_in.mutex); + COMPAT_pthread_mutex_destroy(&mosq->msgs_out.mutex); + COMPAT_pthread_mutex_destroy(&mosq->mid_mutex); } #endif if(net__is_connected(mosq)){ @@ -286,6 +289,13 @@ void mosquitto__destroy(struct mosquitto *mosq) if(mosq->ssl){ SSL_free(mosq->ssl); } +#ifndef WITH_BROKER + if(mosq->user_ssl_ctx){ + SSL_CTX_free(mosq->user_ssl_ctx); + }else if(mosq->ssl_ctx){ + SSL_CTX_free(mosq->ssl_ctx); + } +#else if(mosq->ssl_ctx){ SSL_CTX_free(mosq->ssl_ctx); } @@ -293,12 +303,16 @@ void mosquitto__destroy(struct mosquitto *mosq) mosquitto_FREE(mosq->tls_capath); mosquitto_FREE(mosq->tls_certfile); mosquitto_FREE(mosq->tls_keyfile); - if(mosq->tls_pw_callback) mosq->tls_pw_callback = NULL; + mosq->tls_pw_callback = NULL; mosquitto_FREE(mosq->tls_version); mosquitto_FREE(mosq->tls_ciphers); mosquitto_FREE(mosq->tls_psk); mosquitto_FREE(mosq->tls_psk_identity); mosquitto_FREE(mosq->tls_alpn); +#endif +#ifndef OPENSSL_NO_ENGINE + mosquitto_FREE(mosq->tls_engine); +#endif #endif mosquitto_FREE(mosq->address); diff --git a/lib/logging_mosq.c b/lib/logging_mosq.c index edcf4e58..3c0b7b62 100644 --- a/lib/logging_mosq.c +++ b/lib/logging_mosq.c @@ -32,16 +32,19 @@ int log__printf(struct mosquitto *mosq, unsigned int priority, const char *fmt, va_list va; char *s; size_t len; + void (*on_log)(struct mosquitto *, void *userdata, int level, const char *str); assert(mosq); assert(fmt); COMPAT_pthread_mutex_lock(&mosq->log_callback_mutex); - if(mosq->on_log){ + on_log = mosq->on_log; + COMPAT_pthread_mutex_unlock(&mosq->log_callback_mutex); + + if(on_log){ len = strlen(fmt) + 500; s = mosquitto_malloc(len*sizeof(char)); if(!s){ - COMPAT_pthread_mutex_unlock(&mosq->log_callback_mutex); return MOSQ_ERR_NOMEM; } @@ -50,12 +53,10 @@ int log__printf(struct mosquitto *mosq, unsigned int priority, const char *fmt, va_end(va); s[len-1] = '\0'; /* Ensure string is null terminated. */ - mosq->on_log(mosq, mosq->userdata, (int)priority, s); + on_log(mosq, mosq->userdata, (int)priority, s); mosquitto_FREE(s); } - COMPAT_pthread_mutex_unlock(&mosq->log_callback_mutex); return MOSQ_ERR_SUCCESS; } - diff --git a/lib/loop.c b/lib/loop.c index 7cb666b2..daa188c0 100644 --- a/lib/loop.c +++ b/lib/loop.c @@ -135,9 +135,7 @@ int mosquitto_loop(struct mosquitto *mosq, int timeout, int max_packets) fdcount = select(maxfd+1, &readfds, &writefds, NULL, &local_timeout); #endif if(fdcount == -1){ -#ifdef WIN32 - errno = WSAGetLastError(); -#endif + WINDOWS_SET_ERRNO(); if(errno == EINTR){ return MOSQ_ERR_SUCCESS; }else{ @@ -220,9 +218,7 @@ static int interruptible_sleep(struct mosquitto *mosq, time_t reconnect_delay) fdcount = select(maxfd+1, &readfds, NULL, NULL, &local_timeout); #endif if(fdcount == -1){ -#ifdef WIN32 - errno = WSAGetLastError(); -#endif + WINDOWS_SET_ERRNO(); if(errno == EINTR){ return MOSQ_ERR_SUCCESS; }else{ diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h index 9e1ff897..94d64036 100644 --- a/lib/mosquitto_internal.h +++ b/lib/mosquitto_internal.h @@ -75,6 +75,15 @@ typedef SOCKET mosq_sock_t; typedef int mosq_sock_t; #endif +#ifdef WIN32 +# define WINDOWS_SET_ERRNO() \ + if(errno != EAGAIN){ \ + errno = WSAGetLastError(); \ + } +#else +# define WINDOWS_SET_ERRNO() +#endif + #define SAFE_PRINT(A) (A)?(A):"null" #define SAFE_FREE(A) do { free(A); (A) = NULL;} while(0) @@ -447,6 +456,7 @@ struct mosquitto { # ifndef WITH_OLD_KEEPALIVE struct mosquitto *keepalive_next; struct mosquitto *keepalive_prev; + time_t keepalive_add_time; # endif struct client_stats stats; #endif diff --git a/lib/net_mosq.c b/lib/net_mosq.c index 2c3d1849..155ce3e0 100644 --- a/lib/net_mosq.c +++ b/lib/net_mosq.c @@ -367,9 +367,7 @@ int net__try_connect_step2(struct mosquitto *mosq, uint16_t port, mosq_sock_t *s } rc = connect(*sock, rp->ai_addr, rp->ai_addrlen); -#ifdef WIN32 - errno = WSAGetLastError(); -#endif + WINDOWS_SET_ERRNO(); if(rc == 0 || errno == EINPROGRESS || errno == COMPAT_EWOULDBLOCK){ if(rc < 0 && (errno == EINPROGRESS || errno == COMPAT_EWOULDBLOCK)){ rc = MOSQ_ERR_CONN_PENDING; @@ -467,9 +465,7 @@ static int net__try_connect_tcp(const char *host, uint16_t port, mosq_sock_t *so } rc = connect(*sock, rp->ai_addr, rp->ai_addrlen); -#ifdef WIN32 - errno = WSAGetLastError(); -#endif + WINDOWS_SET_ERRNO(); if(rc == 0 || errno == EINPROGRESS || errno == COMPAT_EWOULDBLOCK){ if(rc < 0 && (errno == EINPROGRESS || errno == COMPAT_EWOULDBLOCK)){ rc = MOSQ_ERR_CONN_PENDING; @@ -1146,9 +1142,7 @@ int net__socketpair(mosq_sock_t *pairR, mosq_sock_t *pairW) continue; } if(connect(spR, (struct sockaddr *)&ss, ss_len) < 0){ -#ifdef WIN32 - errno = WSAGetLastError(); -#endif + WINDOWS_SET_ERRNO(); if(errno != EINPROGRESS && errno != COMPAT_EWOULDBLOCK){ COMPAT_CLOSE(spR); COMPAT_CLOSE(listensock); @@ -1157,9 +1151,7 @@ int net__socketpair(mosq_sock_t *pairR, mosq_sock_t *pairW) } spW = accept(listensock, NULL, 0); if(spW == -1){ -#ifdef WIN32 - errno = WSAGetLastError(); -#endif + WINDOWS_SET_ERRNO(); if(errno != EINPROGRESS && errno != COMPAT_EWOULDBLOCK){ COMPAT_CLOSE(spR); COMPAT_CLOSE(listensock); diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c index 992dec62..cae2eb65 100644 --- a/lib/packet_mosq.c +++ b/lib/packet_mosq.c @@ -294,9 +294,8 @@ int packet__write(struct mosquitto *mosq) packet->to_process -= (uint32_t)write_length; packet->pos += (uint32_t)write_length; }else{ -#ifdef WIN32 - errno = WSAGetLastError(); -#endif + WINDOWS_SET_ERRNO(); + if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK #ifdef WIN32 || errno == WSAENOTCONN @@ -363,9 +362,7 @@ static int read_header(struct mosquitto *mosq, ssize_t (*func_read)(struct mosqu if(read_length == 0){ return MOSQ_ERR_CONN_LOST; /* EOF */ } -#ifdef WIN32 - errno = WSAGetLastError(); -#endif + WINDOWS_SET_ERRNO(); if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ @@ -384,7 +381,6 @@ static int read_header(struct mosquitto *mosq, ssize_t (*func_read)(struct mosqu static int packet__read_single(struct mosquitto *mosq, enum mosquitto_client_state state, ssize_t (*local__read)(struct mosquitto *, void *, size_t)) { - uint8_t byte; ssize_t read_length; int rc = 0; @@ -402,6 +398,11 @@ static int packet__read_single(struct mosquitto *mosq, enum mosquitto_client_sta /* Clients must send CONNECT as their first command. */ if(!(mosq->bridge) && state == mosq_cs_new && (mosq->in_packet.command&0xF0) != CMD_CONNECT){ return MOSQ_ERR_PROTOCOL; + }else if((mosq->in_packet.command&0xF0) == CMD_RESERVED){ + if(mosq->protocol == mosq_p_mqtt5){ + send__disconnect(mosq, MQTT_RC_PROTOCOL_ERROR, NULL); + } + return MOSQ_ERR_PROTOCOL; } #else UNUSED(state); @@ -420,6 +421,7 @@ static int packet__read_single(struct mosquitto *mosq, enum mosquitto_client_sta * >0 means we have finished reading the remaining_length bytes. */ if(mosq->in_packet.remaining_count <= 0){ + uint8_t byte; do{ if(mosq->in_packet.packet_buffer_to_process == 0){ rc = read_header(mosq, local__read); @@ -525,9 +527,7 @@ static int packet__read_single(struct mosquitto *mosq, enum mosquitto_client_sta mosq->in_packet.to_process -= (uint32_t)read_length; mosq->in_packet.pos += (uint32_t)read_length; }else{ -#ifdef WIN32 - errno = WSAGetLastError(); -#endif + WINDOWS_SET_ERRNO(); if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ if(mosq->in_packet.to_process > 1000){ /* Update last_msg_in time if more than 1000 bytes left to diff --git a/lib/pthread_compat.h b/lib/pthread_compat.h index ca1f27dc..10077914 100644 --- a/lib/pthread_compat.h +++ b/lib/pthread_compat.h @@ -10,7 +10,7 @@ # define COMPAT_pthread_testcancel() pthread_testcancel() # define COMPAT_pthread_mutex_init(A, B) pthread_mutex_init((A), (B)) -# define COMPAT_pthread_mutex_destroy(A) pthread_mutex_init((A)) +# define COMPAT_pthread_mutex_destroy(A) pthread_mutex_destroy((A)) # define COMPAT_pthread_mutex_lock(A) pthread_mutex_lock((A)) # define COMPAT_pthread_mutex_unlock(A) pthread_mutex_unlock((A)) #else diff --git a/lib/socks_mosq.c b/lib/socks_mosq.c index c0b3c44e..8205615c 100644 --- a/lib/socks_mosq.c +++ b/lib/socks_mosq.c @@ -63,9 +63,8 @@ Contributors: static inline int socks5__network_error(struct mosquitto *mosq) { -#ifdef WIN32 - errno = WSAGetLastError(); -#endif + WINDOWS_SET_ERRNO(); + if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){ return MOSQ_ERR_SUCCESS; }else{ diff --git a/lib/thread_mosq.c b/lib/thread_mosq.c index 25a5f6d7..3e399f54 100644 --- a/lib/thread_mosq.c +++ b/lib/thread_mosq.c @@ -42,7 +42,7 @@ int mosquitto_loop_start(struct mosquitto *mosq) if(!mosq || mosq->threaded != mosq_ts_none) return MOSQ_ERR_INVAL; mosq->threaded = mosq_ts_self; - if(!pthread_create(&mosq->thread_id, NULL, mosquitto__thread_main, mosq)){ + if(!COMPAT_pthread_create(&mosq->thread_id, NULL, mosquitto__thread_main, mosq)){ #if defined(__linux__) pthread_setname_np(mosq->thread_id, "mosquitto loop"); #elif defined(__NetBSD__) @@ -83,10 +83,10 @@ int mosquitto_loop_stop(struct mosquitto *mosq, bool force) #ifdef HAVE_PTHREAD_CANCEL if(force){ - pthread_cancel(mosq->thread_id); + COMPAT_pthread_cancel(mosq->thread_id); } #endif - pthread_join(mosq->thread_id, NULL); + COMPAT_pthread_join(mosq->thread_id, NULL); mosq->thread_id = pthread_self(); mosq->threaded = mosq_ts_none; diff --git a/libcommon/topic_common.c b/libcommon/topic_common.c index 5401ddde..c3a84470 100644 --- a/libcommon/topic_common.c +++ b/libcommon/topic_common.c @@ -54,7 +54,7 @@ BROKER_EXPORT int mosquitto_pub_topic_check(const char *str) len++; str = &str[1]; } - if(len > 65535) return MOSQ_ERR_INVAL; + if(len == 0 || len > 65535) return MOSQ_ERR_INVAL; if(hier_count > TOPIC_HIERARCHY_LIMIT) return MOSQ_ERR_INVAL; return MOSQ_ERR_SUCCESS; @@ -65,7 +65,7 @@ BROKER_EXPORT int mosquitto_pub_topic_check2(const char *str, size_t len) size_t i; int hier_count = 0; - if(str == NULL || len > 65535){ + if(str == NULL || len == 0 || len > 65535){ return MOSQ_ERR_INVAL; } @@ -114,7 +114,7 @@ BROKER_EXPORT int mosquitto_sub_topic_check(const char *str) c = str[0]; str = &str[1]; } - if(len > 65535) return MOSQ_ERR_INVAL; + if(len == 0 || len > 65535) return MOSQ_ERR_INVAL; if(hier_count > TOPIC_HIERARCHY_LIMIT) return MOSQ_ERR_INVAL; return MOSQ_ERR_SUCCESS; @@ -126,7 +126,7 @@ BROKER_EXPORT int mosquitto_sub_topic_check2(const char *str, size_t len) size_t i; int hier_count = 0; - if(str == NULL || len > 65535){ + if(str == NULL || len == 0 || len > 65535){ return MOSQ_ERR_INVAL; } diff --git a/man/mosquitto.conf.5.xml b/man/mosquitto.conf.5.xml index 678a8585..ce380c35 100644 --- a/man/mosquitto.conf.5.xml +++ b/man/mosquitto.conf.5.xml @@ -1165,6 +1165,34 @@ log_timestamp_format %Y-%m-%dT%H:%M:%S Reloaded on reload signal. + + minutes + + + The default behaviour of mosquitto is to remove retained + messages that have reached their message-expiry-interval + property the next time that that message is accessed - + either by being replaced by a new message, or on the + next subscription that matches the message. If you have + a pattern of publishing many retained messages with a + message-expiry-interval, but that are not subscribed to, + then the expired retained messages will remain in + memory. This option configures the broker to + periodically check the retained tree for expired + messages. + + + + Defaults to off. Setting to a value greater than zero + means the broker will make a check at an interval of + that number of minutes. + + + This option applies globally. + + Reloaded on reload signal. + + [ true | false ] @@ -1723,6 +1751,7 @@ accept_protocol_versions 3, 4 "openssl rehash <path to capath>" each time you add/remove a certificate. + is not supported for websockets. diff --git a/man/mosquitto_ctrl.1.xml b/man/mosquitto_ctrl.1.xml index 6b763b56..55885800 100644 --- a/man/mosquitto_ctrl.1.xml +++ b/man/mosquitto_ctrl.1.xml @@ -460,6 +460,20 @@ See also . + + + + + If used, this will load and trust the OS provided CA + certificates. This can be used in conjunction with + and + and can be used on its own to enable TLS mode. This + will be set by default if + is used, or if port is 8883 and no other certificate + options are used. + + + diff --git a/man/mosquitto_pub.1.xml b/man/mosquitto_pub.1.xml index 5b46ace9..def4ffde 100644 --- a/man/mosquitto_pub.1.xml +++ b/man/mosquitto_pub.1.xml @@ -235,7 +235,7 @@ Define the path to a file containing a PEM encoded certificate for this client, if required by the server. - See also . + See also and the Encrypted Connections section. @@ -366,7 +366,7 @@ Define the path to a file containing a PEM encoded private key for this client, if required by the server. - See also . + See also and the Encrypted Connections section. @@ -924,6 +924,7 @@ $XDG_CONFIG_HOME/mosquitto_pub $HOME/.config/mosquitto_pub + $HOME/snap/mosquitto/current/.config/mosquitto_pub (for snap installs) Configuration file for default options. diff --git a/man/mosquitto_rr.1.xml b/man/mosquitto_rr.1.xml index bcc2237c..3fb1c656 100644 --- a/man/mosquitto_rr.1.xml +++ b/man/mosquitto_rr.1.xml @@ -244,7 +244,7 @@ Define the path to a file containing a PEM encoded certificate for this client, if required by the server. - See also . + See also and the Encrypted Connections section. @@ -393,7 +393,7 @@ Define the path to a file containing a PEM encoded private key for this client, if required by the server. - See also . + See also and the Encrypted Connections section. @@ -1040,6 +1040,7 @@ $XDG_CONFIG_HOME/mosquitto_rr $HOME/.config/mosquitto_rr + $HOME/snap/mosquitto/current/.config/mosquitto_rr (for snap installs) Configuration file for default options. diff --git a/man/mosquitto_sub.1.xml b/man/mosquitto_sub.1.xml index 033d71ce..de0f55b2 100644 --- a/man/mosquitto_sub.1.xml +++ b/man/mosquitto_sub.1.xml @@ -249,7 +249,7 @@ Define the path to a file containing a PEM encoded certificate for this client, if required by the server. - See also . + See also and the Encrypted Connections section. @@ -410,7 +410,7 @@ Define the path to a file containing a PEM encoded private key for this client, if required by the server. - See also . + See also and the Encrypted Connections section. @@ -1344,6 +1344,7 @@ mosquitto_sub -t 'bbc/#' -T bbc/bbc1 --remove-retained $XDG_CONFIG_HOME/mosquitto_sub $HOME/.config/mosquitto_sub + $HOME/snap/mosquitto/current/.config/mosquitto_sub (for snap installs) Configuration file for default options. diff --git a/mosquitto.conf b/mosquitto.conf index f99d64d3..12bd398d 100644 --- a/mosquitto.conf +++ b/mosquitto.conf @@ -438,6 +438,7 @@ # containing the CA certificates. For capath to work correctly, the # certificate files must have ".crt" as the file ending and you must run # "openssl rehash " each time you add/remove a certificate. +# capath is not supported for websockets. #cafile #capath diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index dc063f96..e0b74514 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,12 +1,11 @@ name: mosquitto version: 2.1.0 summary: Eclipse Mosquitto MQTT broker -description: This is a message broker that supports version 5.0, 3.1.1, and 3.1 of the MQTT - protocol. +description: This is a message broker that supports version 5.0, 3.1.1, and 3.1 of the MQTT protocol. MQTT provides a method of carrying out messaging using a publish/subscribe model. It is lightweight, both in terms of bandwidth usage and ease of implementation. This makes it particularly useful at the edge of the network - where a sensor or other simple device may be implemented using an arduino for + where a sensor or other simple device may be implemented using a microcontroller for example. confinement: strict grade: stable @@ -81,6 +80,7 @@ parts: - libmicrohttpd-dev - libsqlite3-dev - libssl-dev + - libwebsockets-dev - xsltproc stage-packages: - ca-certificates @@ -95,19 +95,19 @@ parts: - usr/bin/mosquitto_signal - usr/bin/mosquitto_sub - usr/bin/mosquitto_passwd + - usr/include/mosquitto.h + - usr/include/mosquitto/*.h + - usr/include/mosquitto_broker.h + - usr/include/mosquitto_plugin.h + - usr/include/mqtt_protocol.h + - usr/lib/*-linux-gnu/libcjson.so* + - usr/lib/*-linux-gnu/libcrypto.so* + - usr/lib/*-linux-gnu/libmicrohttpd.so* - usr/lib/*-linux-gnu/libmosquitto.so* - usr/lib/*-linux-gnu/libmosquitto_common.so* + - usr/lib/*-linux-gnu/libssl.so* - usr/lib/*-linux-gnu/mosquitto_acl_file.so* - usr/lib/*-linux-gnu/mosquitto_dynamic_security.so* - usr/lib/*-linux-gnu/mosquitto_password_file.so* - usr/lib/*-linux-gnu/mosquitto_persist_sqlite.so* - usr/lib/*-linux-gnu/mosquitto_sparkplug_aware.so* - - usr/lib/*-linux-gnu/libcjson.so* - - usr/lib/*-linux-gnu/libcrypto.so* - - usr/lib/*-linux-gnu/libmicrohttpd.so* - - usr/lib/*-linux-gnu/libssl.so* - - usr/include/mosquitto.h - - usr/include/mosquitto_broker.h - - usr/include/mosquitto_plugin.h - - usr/include/mqtt_protocol.h - - usr/include/mosquitto/*.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d1d28525..583db35c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -138,6 +138,11 @@ if(WITH_SYS_TREE) target_compile_definitions(mosquitto PRIVATE "WITH_SYS_TREE") endif() +option(WITH_OLD_KEEPALIVE "Use legacy keepalive check mechanism?" OFF) +if (WITH_OLD_KEEPALIVE) + add_definitions("-DWITH_OLD_KEEPALIVE") +endif (WITH_OLD_KEEPALIVE) + option(WITH_ADNS "Include ADNS support?" OFF) if(CMAKE_SYSTEM_NAME STREQUAL Linux) @@ -165,6 +170,7 @@ target_compile_definitions(mosquitto PRIVATE "WITH_BROKER") if(WITH_TLS) target_link_libraries(mosquitto PRIVATE OpenSSL::SSL) endif() + # Check for getaddrinfo_a include(CheckLibraryExists) check_library_exists(anl getaddrinfo_a "" HAVE_GETADDRINFO_A) diff --git a/src/bridge_topic.c b/src/bridge_topic.c index a1608f59..67c64764 100644 --- a/src/bridge_topic.c +++ b/src/bridge_topic.c @@ -57,9 +57,11 @@ static int bridge__create_prefix(char **full_prefix, const char *topic, const ch { size_t len; - if(mosquitto_pub_topic_check(prefix) != MOSQ_ERR_SUCCESS){ - log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge topic local prefix '%s'.", prefix); - return MOSQ_ERR_INVAL; + if(!prefix || strlen(prefix) != 0){ + if(mosquitto_pub_topic_check(prefix) != MOSQ_ERR_SUCCESS){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Invalid bridge topic local prefix '%s'.", prefix); + return MOSQ_ERR_INVAL; + } } if(topic){ diff --git a/src/conf.c b/src/conf.c index df4e5457..90b0f765 100644 --- a/src/conf.c +++ b/src/conf.c @@ -315,6 +315,7 @@ static void config__init_reload(struct mosquitto__config *config) config->persistent_client_expiration = 0; config->queue_qos0_messages = false; config->retain_available = true; + config->retain_expiry_interval = 0; config->set_tcp_nodelay = false; config->sys_interval = 10; config->upgrade_outgoing_qos = false; @@ -489,6 +490,13 @@ void config__bridge_cleanup(struct mosquitto__bridge *bridge) } #endif +static void print_version(void) +{ + printf("mosquitto %s\n", VERSION); + printf("Copyright © 2025 Roger Light.\n"); + printf("License EPL-2.0 OR BSD-3-Clause.\n"); +} + static void print_usage(void) { printf("mosquitto version %s\n\n", VERSION); @@ -533,7 +541,10 @@ int config__parse_args(struct mosquitto__config *config, int argc, char *argv[]) config->daemon = true; }else if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")){ print_usage(); - return MOSQ_ERR_INVAL; + return MOSQ_ERR_UNKNOWN; + }else if(!strcmp(argv[i], "--version")){ + print_version(); + return MOSQ_ERR_UNKNOWN; }else if(!strcmp(argv[i], "-p") || !strcmp(argv[i], "--port")){ if(ilocal_only == true){ - config->security_options.allow_anonymous = true; - }else{ + if(config->local_only == false){ if(config->per_listener_settings){ for(i=0; ilistener_count; i++){ /* Default option if no security options set */ @@ -2255,6 +2264,9 @@ static int config__read_file_core(struct mosquitto__config *config, bool reload, #endif }else if(!strcmp(token, "retain_available")){ if(conf__parse_bool(&token, token, &config->retain_available, &saveptr)) return MOSQ_ERR_INVAL; + }else if(!strcmp(token, "retain_expiry_interval")){ + if(conf__parse_int(&token, token, &config->retain_expiry_interval, &saveptr)) return MOSQ_ERR_INVAL; + config->retain_expiry_interval *= 60; }else if(!strcmp(token, "retry_interval")){ OPTION_UNAVAILABLE(token); }else if(!strcmp(token, "round_robin")){ @@ -2618,15 +2630,13 @@ static int config__check(struct mosquitto__config *config) #ifdef WITH_BRIDGE static int config__check_bridges(struct mosquitto__config *config) { - int i; - int j; struct mosquitto__bridge *bridge1, *bridge2; char hostname[256]; size_t len; /* Check for bridge duplicate local_clientid, need to generate missing IDs * first. */ - for(i=0; ibridge_count; i++){ + for(int i=0; ibridge_count; i++){ bridge1 = config->bridges[i]; if(!bridge1->remote_clientid){ @@ -2653,9 +2663,9 @@ static int config__check_bridges(struct mosquitto__config *config) } } - for(i=0; ibridge_count; i++){ + for(int i=0; ibridge_count; i++){ bridge1 = config->bridges[i]; - for(j=i+1; jbridge_count; j++){ + for(int j=i+1; jbridge_count; j++){ bridge2 = config->bridges[j]; if(!strcmp(bridge1->local_clientid, bridge2->local_clientid)){ log__printf(NULL, MOSQ_LOG_ERR, "Error: Bridge local_clientid " @@ -2667,6 +2677,28 @@ static int config__check_bridges(struct mosquitto__config *config) } } +#ifdef WITH_TLS + /* Check for missing TLS cafile/capath/certfile/keyfile */ + for(int i=0; ilistener_count; i++){ + bool cafile = !!config->listeners[i].cafile; + bool capath = !!config->listeners[i].capath; + bool certfile = !!config->listeners[i].certfile; + bool keyfile = !!config->listeners[i].keyfile; + + if((certfile && !keyfile) || (!certfile && keyfile)){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: Both certfile and keyfile must be provided to enable a TLS listener."); + return MOSQ_ERR_INVAL; + } + if(cafile && !certfile){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: cafile specified without certfile and keyfile."); + return MOSQ_ERR_INVAL; + } + if(capath && !certfile){ + log__printf(NULL, MOSQ_LOG_ERR, "Error: capath specified without certfile and keyfile."); + return MOSQ_ERR_INVAL; + } + } +#endif return MOSQ_ERR_SUCCESS; } #endif diff --git a/src/handle_publish.c b/src/handle_publish.c index b4cd8c7b..5a6ad3df 100644 --- a/src/handle_publish.c +++ b/src/handle_publish.c @@ -352,7 +352,7 @@ process_bad_message: } db__msg_store_free(base_msg); } - if(context->out_packet_count >= db.config->max_queued_messages){ + if(db.config->max_queued_messages > 0 && context->out_packet_count >= db.config->max_queued_messages){ rc = MQTT_RC_QUOTA_EXCEEDED; } return rc; diff --git a/src/handle_subscribe.c b/src/handle_subscribe.c index 59fcdc1e..cec73400 100644 --- a/src/handle_subscribe.c +++ b/src/handle_subscribe.c @@ -196,6 +196,7 @@ int handle__subscribe(struct mosquitto *context) break; default: mosquitto_FREE(sub.topic_filter); + mosquitto_FREE(payload); return rc2; } if(qos > 127){ @@ -208,18 +209,21 @@ int handle__subscribe(struct mosquitto *context) rc2 = plugin__handle_subscribe(context, &sub); if(rc2){ mosquitto_FREE(sub.topic_filter); + mosquitto_FREE(payload); return rc2; } rc2 = sub__add(context, &sub); if(rc2 > 0){ mosquitto_FREE(sub.topic_filter); + mosquitto_FREE(payload); return rc2; } if(context->protocol == mosq_p_mqtt311 || context->protocol == mosq_p_mqtt31){ if(rc2 == MOSQ_ERR_SUCCESS || rc2 == MOSQ_ERR_SUB_EXISTS){ if(retain__queue(context, &sub)){ mosquitto_FREE(sub.topic_filter); + mosquitto_FREE(payload); return rc; } } @@ -229,6 +233,7 @@ int handle__subscribe(struct mosquitto *context) if(retain__queue(context, &sub)){ mosquitto_FREE(sub.topic_filter); + mosquitto_FREE(payload); return rc; } } @@ -255,6 +260,7 @@ int handle__subscribe(struct mosquitto *context) if(context->protocol != mosq_p_mqtt31){ if(payloadlen == 0){ /* No subscriptions specified, protocol error. */ + fprintf(stderr, "no payload\n"); return MOSQ_ERR_MALFORMED_PACKET; } } diff --git a/src/keepalive.c b/src/keepalive.c index a40a65ea..d3561650 100644 --- a/src/keepalive.c +++ b/src/keepalive.c @@ -94,13 +94,21 @@ int keepalive__init(void) } } #endif + last_keepalive_check = db.now_s; return MOSQ_ERR_SUCCESS; } void keepalive__cleanup(void) { #ifndef WITH_OLD_KEEPALIVE - mosquitto_FREE(keepalive_list); + for(int idx=0; idxkeepalive_add_time = db.now_s; #else UNUSED(context); #endif @@ -143,7 +152,11 @@ void keepalive__check(void) int idx = (int)(i % keepalive_list_max); if(keepalive_list[idx]){ DL_FOREACH_SAFE2(keepalive_list[idx], context, ctxt_tmp, keepalive_next){ - if(net__is_connected(context)){ + /* keepalive_add_time lets us account for the client adding itself to the keepalive + * list when its last_msg_in value is greater than the last_keepalive_check. + * Without this, the client would be expired if it has keepalive == max_keepalive. + */ + if(context->keepalive_add_time <= last_keepalive_check && net__is_connected(context)){ /* Client has exceeded keepalive*1.5 */ do_disconnect(context, MOSQ_ERR_KEEPALIVE); } diff --git a/src/listeners.c b/src/listeners.c index 5ab447e8..4f17ed71 100644 --- a/src/listeners.c +++ b/src/listeners.c @@ -146,7 +146,14 @@ void listeners__add_websockets(struct lws_context *ws_context, mosq_sock_t fd) static int listeners__add_local(const char *host, uint16_t port) { struct mosquitto__listener *listeners; + bool allow_anonymous; + listeners = db.config->listeners; + if(db.config->security_options.allow_anonymous == -1){ + allow_anonymous = true; + }else{ + allow_anonymous = db.config->security_options.allow_anonymous; + } listeners[db.config->listener_count].security_options = mosquitto_calloc(1, sizeof(struct mosquitto__security_options)); if(listeners[db.config->listener_count].security_options == NULL){ @@ -154,7 +161,7 @@ static int listeners__add_local(const char *host, uint16_t port) } listener__set_defaults(&listeners[db.config->listener_count]); - listeners[db.config->listener_count].security_options->allow_anonymous = true; + listeners[db.config->listener_count].security_options->allow_anonymous = allow_anonymous; listeners[db.config->listener_count].security_options->auto_id_prefix = mosquitto_strdup("auto-"); if(listeners[db.config->listener_count].security_options->auto_id_prefix == NULL){ mosquitto_FREE(listeners[db.config->listener_count].security_options); diff --git a/src/logging.c b/src/logging.c index cb6ed929..f3d65be5 100644 --- a/src/logging.c +++ b/src/logging.c @@ -133,9 +133,11 @@ int log__init(struct mosquitto__config *config) log__printf(NULL, MOSQ_LOG_ERR, "Error: Unable to open log file %s for writing.", config->log_file); } } +#ifndef WIN32 if(log_destinations & MQTT3_LOG_STDOUT){ setvbuf(stdout, NULL, _IOLBF, 0); } +#endif #ifdef WITH_DLT if(log_destinations & MQTT3_LOG_DLT){ dlt_fifo_check(); diff --git a/src/loop.c b/src/loop.c index 4c8a0374..34bb1f59 100644 --- a/src/loop.c +++ b/src/loop.c @@ -184,6 +184,7 @@ int mosquitto_main_loop(struct mosquitto__listener_sock *listensock, int listens #endif while(g_run){ + retain__expire(); queue_plugin_msgs(); context__free_disused(); @@ -245,8 +246,6 @@ int mosquitto_main_loop(struct mosquitto__listener_sock *listensock, int listens #endif } - mux__cleanup(); - return MOSQ_ERR_SUCCESS; } diff --git a/src/mosquitto.c b/src/mosquitto.c index faa405d6..1ab3f64f 100644 --- a/src/mosquitto.c +++ b/src/mosquitto.c @@ -359,6 +359,8 @@ static void post_shutdown_cleanup(void) (void)remove(db.config->pid_file); } + mux__cleanup(); + log__close(db.config); config__cleanup(db.config); net__broker_cleanup(); @@ -387,6 +389,7 @@ int main(int argc, char *argv[]) mosquitto_time_init(); cjson_init(); + mosquitto_time_init(); #if defined(WIN32) || defined(__CYGWIN__) if(argc == 2){ if(!strcmp(argv[1], "run")){ @@ -430,7 +433,10 @@ int main(int argc, char *argv[]) db.config = &config; config__init(&config); rc = config__parse_args(&config, argc, argv); - if(rc != MOSQ_ERR_SUCCESS){ + if(rc == MOSQ_ERR_UNKNOWN){ + post_shutdown_cleanup(); + return MOSQ_ERR_SUCCESS; + }else if(rc != MOSQ_ERR_SUCCESS){ post_shutdown_cleanup(); return rc; } diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h index a5d234dd..cdea621b 100644 --- a/src/mosquitto_broker_internal.h +++ b/src/mosquitto_broker_internal.h @@ -361,6 +361,7 @@ struct mosquitto__config { bool queue_qos0_messages; bool per_listener_settings; bool retain_available; + int retain_expiry_interval; bool set_tcp_nodelay; int sys_interval; bool upgrade_outgoing_qos; @@ -894,6 +895,7 @@ void retain__clean(struct mosquitto__retainhier **retainhier); int retain__queue(struct mosquitto *context, const struct mosquitto_subscription *sub); int retain__store(const char *topic, struct mosquitto__base_msg *base_msg, char **split_topics, bool persist); void retain__expiry_check(struct mosquitto__retainhier **retainhier); + /* ============================================================ * Security related functions * ============================================================ */ diff --git a/src/net.c b/src/net.c index 0e3ecdfc..00084d36 100644 --- a/src/net.c +++ b/src/net.c @@ -123,7 +123,7 @@ struct mosquitto *net__socket_accept(struct mosquitto__listener_sock *listensock new_sock = accept(listensock->sock, NULL, 0); if(new_sock == INVALID_SOCKET){ #ifdef WIN32 - errno = WSAGetLastError(); + WINDOWS_SET_ERRNO(); if(errno == WSAEMFILE){ #else if(errno == EMFILE || errno == ENFILE){ @@ -712,6 +712,9 @@ static int net__bind_interface(struct mosquitto__listener *listener, struct addr memcpy(&((struct sockaddr_in6 *)rp->ai_addr)->sin6_addr, &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr, sizeof(struct in6_addr)); + + ((struct sockaddr_in6 *)rp->ai_addr)->sin6_scope_id = ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id; + freeifaddrs(ifaddr); return MOSQ_ERR_SUCCESS; } diff --git a/src/retain.c b/src/retain.c index c5618c24..ebfdef39 100644 --- a/src/retain.c +++ b/src/retain.c @@ -28,6 +28,8 @@ Contributors: #include "utlist.h" +static time_t next_expire_check = 0; + static struct mosquitto__retainhier *retain__add_hier_entry(struct mosquitto__retainhier *parent, struct mosquitto__retainhier **sibling, const char *topic, uint16_t len) { struct mosquitto__retainhier *child; @@ -375,3 +377,32 @@ void retain__clean(struct mosquitto__retainhier **retainhier) } +static void retain__expire_search(struct mosquitto__retainhier *retainhier) +{ + struct mosquitto__retainhier *branch, *branch_tmp; + + HASH_ITER(hh, retainhier->children, branch, branch_tmp){ + if(branch->children){ + retain__expire_search(branch); + } + if(branch->retained){ + if(branch->retained->data.expiry_time > 0 && db.now_real_s >= branch->retained->data.expiry_time){ + db__msg_store_ref_dec(&branch->retained); + branch->retained = NULL; +#ifdef WITH_SYS_TREE + db.retained_count--; +#endif + retain__clean_empty_hierarchy(retainhier); + } + } + } +} + + +void retain__expire(void) +{ + if(db.config->retain_expiry_interval > 0 && db.now_s > next_expire_check){ + retain__expire_search(db.retains); + next_expire_check = db.now_s + db.config->retain_expiry_interval; + } +} diff --git a/src/websockets.c b/src/websockets.c index 0a89fe12..35915bdf 100644 --- a/src/websockets.c +++ b/src/websockets.c @@ -566,6 +566,10 @@ static int callback_http( return -1; } wlen = (size_t)rc; + /* while still active, extend timeout */ + if(wlen){ + lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, 10); + } if(wlen < buflen){ if(fseek(u->fptr, (long)(buflen-wlen), SEEK_CUR) < 0){ fclose(u->fptr); @@ -684,10 +688,19 @@ void mosq_websockets_init(struct mosquitto__listener *listener, const struct mos info.gid = -1; info.uid = -1; #ifdef WITH_TLS - info.ssl_ca_filepath = listener->cafile; + if(listener->cafile){ + info.ssl_ca_filepath = listener->cafile; + } + else if(listener->capath){ + log__printf(NULL, MOSQ_LOG_WARNING, "Warning: CA path option is not supported for websockets"); + } info.ssl_cert_filepath = listener->certfile; info.ssl_private_key_filepath = listener->keyfile; info.ssl_cipher_list = listener->ciphers; + /* HTTP 1 only, due to HTTP 2 issues in Firefox: + https://github.com/eclipse-mosquitto/mosquitto/issues/1211 + */ + info.alpn = "h1"; #if defined(WITH_WEBSOCKETS) && LWS_LIBRARY_VERSION_NUMBER>=3001000 info.tls1_3_plus_cipher_list = listener->ciphers_tls13; #endif diff --git a/test/Makefile b/test/Makefile index 9c37cc6d..7cefb4d8 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,7 +1,7 @@ R=.. include ${R}/config.mk -.PHONY: all check test test-compile ptest clean +.PHONY: all check test test-compile ptest clean ssl all : @@ -17,13 +17,19 @@ endif check : test -test : utest +ssl: ssl/all-ca.crt + +ssl/all-ca.crt: ssl/gen.sh + cd "${ 0 + cmd_args = cmd_args.copy() - if with_test_config: + if with_test_config and use_conf_file: cmd_args.insert(0, "--test-config") - use_conf_file = len(conf_file) create_conf_file = use_conf_file and len(config) if create_conf_file: with open(conf_file, "w") as f: diff --git a/test/broker/readme.txt b/test/broker/readme.txt index 37f062e1..e7dba30e 100644 --- a/test/broker/readme.txt +++ b/test/broker/readme.txt @@ -17,3 +17,5 @@ Numbering is as follows: 10: Listener tests 11: Persistence tests 12: Property tests +13: Malformed tests +14: Dynamic security tests diff --git a/test/mosq_test.py b/test/mosq_test.py index 17bbfb95..a5c1f99d 100644 --- a/test/mosq_test.py +++ b/test/mosq_test.py @@ -65,8 +65,13 @@ def start_broker(filename, cmd=None, port=0, use_conf=False, expect_fail=False, global vg_index global vg_logfiles - if use_conf: + if use_conf == True: cmd = [get_build_root() + '/src/mosquitto', '-v', '-c', filename.replace('.py', '.conf')] + + if port == 0: + port = 1888 + else: + cmd += ['-p', str(port)] else: if cmd is None and port != 0: cmd = [get_build_root() + '/src/mosquitto', '-v', '-p', str(port)] diff --git a/test/ssl/openssl.cnf b/test/ssl/openssl.cnf index 2506e6ef..93e9c2e7 100644 --- a/test/ssl/openssl.cnf +++ b/test/ssl/openssl.cnf @@ -291,8 +291,6 @@ authorityKeyIdentifier=keyid:always,issuer # This is what PKIX recommends but some broken software chokes on critical # extensions. -#basicConstraints = critical,CA:true -# So we do this instead. basicConstraints = critical,CA:true # Key usage: this is typical for a CA certificate. However since it will diff --git a/www/files/favicon.ico b/www/files/favicon.ico index c4efbcc0..643ef390 100644 Binary files a/www/files/favicon.ico and b/www/files/favicon.ico differ diff --git a/www/files/favicon.svg b/www/files/favicon.svg new file mode 100644 index 00000000..95b573fc --- /dev/null +++ b/www/files/favicon.svg @@ -0,0 +1,3 @@ +image/svg+xml \ No newline at end of file diff --git a/www/pages/documentation/dynamic-security.md b/www/pages/documentation/dynamic-security.md index e025adb2..2b3dcca3 100644 --- a/www/pages/documentation/dynamic-security.md +++ b/www/pages/documentation/dynamic-security.md @@ -478,8 +478,8 @@ they would be provided on the command line. For example: ``` --cafile /path/to/my/CA.crt ---certfile /path/to/my/client.crt ---keyfile /path/to/my/client.key +--cert /path/to/my/client.crt +--key /path/to/my/client.key -u admin -h mosquitto.example.com diff --git a/www/pages/documentation/using-the-snap.md b/www/pages/documentation/using-the-snap.md index 41d6f3d4..15fd8fae 100644 --- a/www/pages/documentation/using-the-snap.md +++ b/www/pages/documentation/using-the-snap.md @@ -74,7 +74,30 @@ and keys, must also be placed in `/var/snap/mosquitto/common/` - in new folders if wanted. This directory is the only place accessible by Mosquitto when running as a snap. +Starting and stopping the broker service can be done with the snap command: + +``` +snap start mosquitto +snap stop mosquitto +``` + +Or via systemd: + +``` +systemctl start snap.mosquitto.mosquitto +systemctl stop snap.mosquitto.mosquitto +``` + All other aspects of running Mosquitto are the same as with any other installation methods. +## Client configuration files + +If you use the mosquitto_pub, mosquitto_rr, or mosquitto_sub configuration +files they should be placed in `$HOME/snap/mosquitto/current/.config`: + +* `$HOME/snap/mosquitto/current/.config/mosquitto_pub` +* `$HOME/snap/mosquitto/current/.config/mosquitto_rr` +* `$HOME/snap/mosquitto/current/.config/mosquitto_sub` + [authentication method]:/documentation/authentication-methods diff --git a/www/pages/download.md b/www/pages/download.md index 3200eba4..bfe5c76e 100644 --- a/www/pages/download.md +++ b/www/pages/download.md @@ -11,7 +11,7 @@ # Source -* [mosquitto-2.0.20.tar.gz](https://mosquitto.org/files/source/mosquitto-2.0.20.tar.gz) ([GPG signature](https://mosquitto.org/files/source/mosquitto-2.0.20.tar.gz.asc)) +* [mosquitto-2.0.22.tar.gz](https://mosquitto.org/files/source/mosquitto-2.0.22.tar.gz) ([GPG signature](https://mosquitto.org/files/source/mosquitto-2.0.22.tar.gz.asc)) * [Git source code repository](https://github.com/eclipse/mosquitto) (github.com) Older downloads are available at [https://mosquitto.org/files/](../files/) @@ -24,7 +24,8 @@ distributions. ## Windows -* [mosquitto-2.0.20-install-windows-x64.exe](https://mosquitto.org/files/binary/win64/mosquitto-2.0.20-install-windows-x64.exe) +* [mosquitto-2.0.22-install-windows-x64.exe](https://mosquitto.org/files/binary/win64/mosquitto-2.0.22-install-windows-x64.exe) +* [mosquitto-2.0.22-install-windows-x86.exe](https://mosquitto.org/files/binary/win32/mosquitto-2.0.22-install-windows-x86.exe) Older installers can be found at [https://mosquitto.org/files/binary/](https://mosquitto.org/files/binary/). @@ -41,6 +42,7 @@ Mosquitto can be installed from the homebrew project. See ## Debian * Mosquitto is now in Debian proper. There will be a short delay between a new release and it appearing in Debian as part of the normal Debian procedures. + The tracker for the package is at . * There are also Debian repositories provided by the mosquitto project, as described at diff --git a/www/posts/2024/10/version-2-0-19-released.md b/www/posts/2024/10/version-2-0-19-released.md index 8cc0f3bd..d3677903 100644 --- a/www/posts/2024/10/version-2-0-19-released.md +++ b/www/posts/2024/10/version-2-0-19-released.md @@ -11,12 +11,12 @@ Version 2.0.19 of Mosquitto has been released. This is a security and bugfix release. -Security: +# Security - Fix mismatched subscribe/unsubscribe with normal/shared topics. - Fix crash on bridge using remapped topic being sent a crafted packet. - Don't allow SUBACK with missing reason codes in client library. -Broker: +# Broker - Fix assert failure when loading a persistence file that contains subscriptions with no client id. - Fix local bridges being incorrectly expired when `persistent_client_expiration` @@ -25,13 +25,13 @@ Broker: - Fix mismatched subscribe/unsubscribe with normal/shared topics. - Fix crash on bridge using remapped topic being sent a crafted packet. -Client library: +# Client library - Fix some error codes being converted to string as "unknown". Closes [#2579]. - Clear SSL error state to avoid spurious error reporting. Closes [#3054]. - Fix "payload format invalid" not being allowed as a PUBREC reason code. - Don't allow SUBACK with missing reason codes. -Build: +# Build - Thread support is re-enabled on Windows. [#2579]: https://github.com/eclipse/mosquitto/issues/2579 diff --git a/www/posts/2024/10/version-2-0-20-released.md b/www/posts/2024/10/version-2-0-20-released.md index 1455a3d4..b272281c 100644 --- a/www/posts/2024/10/version-2-0-20-released.md +++ b/www/posts/2024/10/version-2-0-20-released.md @@ -11,20 +11,20 @@ Version 2.0.20 of Mosquitto has been released. This is a bugfix release. -Broker: +# Broker - Fix QoS 1 / QoS 2 publish incorrectly returning "no subscribers". Closes #3128. - Open files with appropriate access on Windows. Closes #3119. - Don't allow invalid response topic values. - Fix some strict protocol compliance issues. Closes #3052. -Client library: +# Client library - Fix cmake build on OS X. Closes #3125. -Build: +# Build - Fix build on NetBSD -[#3052]: https://github.com/eclipse/mosquitto/issues/3128 -[#3119]: https://github.com/eclipse/mosquitto/issues/3128 -[#3125]: https://github.com/eclipse/mosquitto/issues/3128 +[#3052]: https://github.com/eclipse/mosquitto/issues/3052 +[#3119]: https://github.com/eclipse/mosquitto/issues/3119 +[#3125]: https://github.com/eclipse/mosquitto/issues/3125 [#3128]: https://github.com/eclipse/mosquitto/issues/3128 diff --git a/www/posts/2025/03/version-2-0-21-released.md b/www/posts/2025/03/version-2-0-21-released.md new file mode 100644 index 00000000..4526f309 --- /dev/null +++ b/www/posts/2025/03/version-2-0-21-released.md @@ -0,0 +1,63 @@ + + +Version 2.0.21 of Mosquitto has been released. This is a security and bugfix release. + +Security: +- Fix leak on malicious SUBSCRIBE by authenticated client. + Closes [eclipse #248]. +- Further fix for CVE-2023-28366. + +# Broker +- Fix clients sending a RESERVED packet not being quickly disconnected. + Closes [#2325]. +- Fix `bind_interface` producing an error when used with an interface that has + an IPv6 link-local address and no other IPv6 addresses. Closes [#2696]. +- Fix mismatched wrapped/unwrapped memory alloc/free in properties. Closes [#3192]. +- Fix `allow_anonymous false` not being applied in local only mode. Closes [#3198]. +- Add `retain_expiry_interval` option to fix expired retained message not + being removed from memory if they are not subscribed to. Closes [#3221]. +- Produce an error if invalid combinations of cafile/capath/certfile/keyfile + are used. Closes [#1836]. Closes [#3130]. +- Backport keepalive checking from develop to fix problems in current + implementation. Closes [#3138]. + +# Client library +- Fix potential deadlock in mosquitto_sub if `-W` is used. Closes [#3175]. + +# Apps +- mosquitto_ctrl dynsec now also allows `-i` to specify a clientid as well as + `-c`. This matches the documentation which states `-i`. Closes [#3219]. +Client library: +- Fix threads linking on Windows for static libmosquitto library + Closes [#3143] + +# Build +- Fix Windows builds not having websockets enabled. +- Add tzdata to docker images + +# Tests +- Fix 08-ssl-connect-cert-auth-expired and 08-ssl-connect-cert-auth-revoked + tests when under load. Closes [#3208]. + +[#eclipse 248]: https://gitlab.eclipse.org/security/vulnerability-reports/-/issues/248 +[#1836]: https://github.com/eclipse/mosquitto/issues/1836 +[#2325]: https://github.com/eclipse/mosquitto/issues/2325 +[#2696]: https://github.com/eclipse/mosquitto/issues/2696 +[#3130]: https://github.com/eclipse/mosquitto/issues/3130 +[#3138]: https://github.com/eclipse/mosquitto/issues/3138 +[#3143]: https://github.com/eclipse/mosquitto/issues/3143 +[#3175]: https://github.com/eclipse/mosquitto/issues/3175 +[#3192]: https://github.com/eclipse/mosquitto/issues/3192 +[#3198]: https://github.com/eclipse/mosquitto/issues/3198 +[#3208]: https://github.com/eclipse/mosquitto/issues/3208 +[#3219]: https://github.com/eclipse/mosquitto/issues/3219 +[#3221]: https://github.com/eclipse/mosquitto/issues/3221 diff --git a/www/posts/2025/07/version-2-0-22-released.md b/www/posts/2025/07/version-2-0-22-released.md new file mode 100644 index 00000000..71c5a2be --- /dev/null +++ b/www/posts/2025/07/version-2-0-22-released.md @@ -0,0 +1,69 @@ + + +Version 2.0.22 of Mosquitto has been released. This is a bugfix release. + +# Broker + +- Windows: Fix broker crash on startup if using `log_dest stdout` +- Bridge: Fix `idle_timeout` never occurring for lazy bridges. +- Fix case where `max_queued_messages = 0` was not treated as unlimited. + Closes [#3244]. +- Fix `--version` exit code and output. Closes [#3267]. +- Fix crash on receiving a $CONTROL message over a bridge, if + `per_listener_settings` is set true and the bridge is carrying out topic + remapping. Closes [#3261]. +- Fix incorrect reference clock being selected on startup on Linux. + Closes [#3238]. +- Fix reporting of client disconnections being incorrectly attributed to "out + of memory". Closes [#3253]. +- Fix compilation when using `WITH_OLD_KEEPALIVE`. Closes [#3250]. +- Add Windows linker file for the broker to the installer. Closes [#3269]. +- Fix Websockets PING not being sent on Windows. Closes [#3272]. +- Fix problems with secure websockets. Closes [#1211]. +- Fix crash on exit when using `WITH_EPOLL=no`. Closes [#3302]. +- Fix clients being incorrectly expired when they have keepalive == + `max_keepalive`. Closes [#3226], [#3286]. + +# Dynamic security plugin +- Fix mismatch memory free when saving config which caused memory tracking to + be incorrect. + +# Client library +- Fix C++ symbols being removed when compiled with link time optimisation. + Closes [#3259]. +- TLS error handling was incorrectly setting a protocol error for non-TLS + errors. This would cause the `mosquitto_loop_start()` thread to exit if no + broker was available on the first connection attempt. This has been fixed. + Closes [#3258]. +- Fix linker errors on some architectures using cmake. Closes [#3167]. + + +Tests: +- Fix 08-ssl-connect-cert-auth-expired and 08-ssl-connect-cert-auth-revoked + tests when running on a single CPU system. Closes [#3230]. + +[#1211]: https://github.com/eclipse/mosquitto/issues/1211 +[#3167]: https://github.com/eclipse/mosquitto/issues/3167 +[#3226]: https://github.com/eclipse/mosquitto/issues/3226 +[#3230]: https://github.com/eclipse/mosquitto/issues/3230 +[#3238]: https://github.com/eclipse/mosquitto/issues/3238 +[#3244]: https://github.com/eclipse/mosquitto/issues/3244 +[#3250]: https://github.com/eclipse/mosquitto/issues/3250 +[#3253]: https://github.com/eclipse/mosquitto/issues/3253 +[#3258]: https://github.com/eclipse/mosquitto/issues/3258 +[#3259]: https://github.com/eclipse/mosquitto/issues/3259 +[#3261]: https://github.com/eclipse/mosquitto/issues/3261 +[#3267]: https://github.com/eclipse/mosquitto/issues/3267 +[#3269]: https://github.com/eclipse/mosquitto/issues/3269 +[#3272]: https://github.com/eclipse/mosquitto/issues/3272 +[#3286]: https://github.com/eclipse/mosquitto/issues/3286 +[#3302]: https://github.com/eclipse/mosquitto/issues/3302