mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 13:53:55 -07:00
Merge branch 'RfidResearchGroup:master' into master
This commit is contained in:
commit
ac6916777f
38 changed files with 4875 additions and 57 deletions
|
@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
|
||||||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||||
|
|
||||||
## [unreleased][unreleased]
|
## [unreleased][unreleased]
|
||||||
|
- Added `mqtt` - the pm3 client can now send and receive MQTT messages or json files. (@iceman1001)
|
||||||
- Changed `hf iclass wrbl` - replay behavior to use privilege escalation if the macs field is not passed empty(@antiklesys)
|
- Changed `hf iclass wrbl` - replay behavior to use privilege escalation if the macs field is not passed empty(@antiklesys)
|
||||||
- Changed `hf iclass restore` - it now supports privilege escalation to restore card content using replay (@antiklesys)
|
- Changed `hf iclass restore` - it now supports privilege escalation to restore card content using replay (@antiklesys)
|
||||||
- Fixed `hf 15 dump` - now reads sysinfo response correct (@iceman1001)
|
- Fixed `hf 15 dump` - now reads sysinfo response correct (@iceman1001)
|
||||||
|
|
|
@ -402,6 +402,7 @@ set (TARGET_SOURCES
|
||||||
${PM3_ROOT}/client/src/cmdlfvisa2000.c
|
${PM3_ROOT}/client/src/cmdlfvisa2000.c
|
||||||
${PM3_ROOT}/client/src/cmdlfzx8211.c
|
${PM3_ROOT}/client/src/cmdlfzx8211.c
|
||||||
${PM3_ROOT}/client/src/cmdmain.c
|
${PM3_ROOT}/client/src/cmdmain.c
|
||||||
|
${PM3_ROOT}/client/src/cmdmqtt.c
|
||||||
${PM3_ROOT}/client/src/cmdnfc.c
|
${PM3_ROOT}/client/src/cmdnfc.c
|
||||||
${PM3_ROOT}/client/src/cmdparser.c
|
${PM3_ROOT}/client/src/cmdparser.c
|
||||||
${PM3_ROOT}/client/src/cmdpiv.c
|
${PM3_ROOT}/client/src/cmdpiv.c
|
||||||
|
@ -772,6 +773,7 @@ target_link_libraries(proxmark3 PRIVATE
|
||||||
pm3rrg_rdv4_reveng
|
pm3rrg_rdv4_reveng
|
||||||
pm3rrg_rdv4_hardnested
|
pm3rrg_rdv4_hardnested
|
||||||
pm3rrg_rdv4_id48
|
pm3rrg_rdv4_id48
|
||||||
|
pm3rrg_rdv4_mqtt
|
||||||
${ADDITIONAL_LNK})
|
${ADDITIONAL_LNK})
|
||||||
|
|
||||||
if (NOT SKIPPTHREAD EQUAL 1)
|
if (NOT SKIPPTHREAD EQUAL 1)
|
||||||
|
|
|
@ -131,6 +131,12 @@ WHEREAMILIBINC = -I$(WHEREAMILIBPATH)
|
||||||
WHEREAMILIB = $(WHEREAMILIBPATH)/libwhereami.a
|
WHEREAMILIB = $(WHEREAMILIBPATH)/libwhereami.a
|
||||||
WHEREAMILIBLD =
|
WHEREAMILIBLD =
|
||||||
|
|
||||||
|
## MQTT
|
||||||
|
MQTTLIBPATH = ./deps/mqtt
|
||||||
|
MQTTLIBINC = -I$(MQTTLIBPATH)
|
||||||
|
MQTTLIB = $(MQTTLIBPATH)/mqtt.a
|
||||||
|
MQTTLIBLD =
|
||||||
|
|
||||||
##########################
|
##########################
|
||||||
# common local libraries #
|
# common local libraries #
|
||||||
##########################
|
##########################
|
||||||
|
@ -239,6 +245,12 @@ STATICLIBS += $(WHEREAMILIB)
|
||||||
LDLIBS += $(WHEREAMILIBLD)
|
LDLIBS += $(WHEREAMILIBLD)
|
||||||
PM3INCLUDES += $(WHEREAMILIBINC)
|
PM3INCLUDES += $(WHEREAMILIBINC)
|
||||||
|
|
||||||
|
## MQTT
|
||||||
|
# not distributed as system library
|
||||||
|
STATICLIBS += $(MQTTLIB)
|
||||||
|
LDLIBS += $(MQTTLIBLD)
|
||||||
|
PM3INCLUDES += $(MQTTLIBINC)
|
||||||
|
|
||||||
####################
|
####################
|
||||||
# system libraries #
|
# system libraries #
|
||||||
####################
|
####################
|
||||||
|
@ -682,6 +694,7 @@ SRCS = mifare/aiddesfire.c \
|
||||||
cmdlfvisa2000.c \
|
cmdlfvisa2000.c \
|
||||||
cmdlfzx8211.c \
|
cmdlfzx8211.c \
|
||||||
cmdmain.c \
|
cmdmain.c \
|
||||||
|
cmdmqtt.c \
|
||||||
cmdnfc.c \
|
cmdnfc.c \
|
||||||
cmdparser.c \
|
cmdparser.c \
|
||||||
cmdpiv.c \
|
cmdpiv.c \
|
||||||
|
@ -877,6 +890,7 @@ endif
|
||||||
$(Q)$(MAKE) --no-print-directory -C $(REVENGLIBPATH) clean
|
$(Q)$(MAKE) --no-print-directory -C $(REVENGLIBPATH) clean
|
||||||
$(Q)$(MAKE) --no-print-directory -C $(TINYCBORLIBPATH) clean
|
$(Q)$(MAKE) --no-print-directory -C $(TINYCBORLIBPATH) clean
|
||||||
$(Q)$(MAKE) --no-print-directory -C $(WHEREAMILIBPATH) clean
|
$(Q)$(MAKE) --no-print-directory -C $(WHEREAMILIBPATH) clean
|
||||||
|
$(Q)$(MAKE) --no-print-directory -C $(MQTTLIBPATH) clean
|
||||||
@# Just in case someone compiled within these dirs:
|
@# Just in case someone compiled within these dirs:
|
||||||
$(Q)$(MAKE) --no-print-directory -C $(MBEDTLSLIBPATH) clean
|
$(Q)$(MAKE) --no-print-directory -C $(MBEDTLSLIBPATH) clean
|
||||||
|
|
||||||
|
@ -974,6 +988,10 @@ ifneq ($(WHEREAMI_FOUND),1)
|
||||||
$(Q)$(MAKE) --no-print-directory -C $(WHEREAMILIBPATH) all
|
$(Q)$(MAKE) --no-print-directory -C $(WHEREAMILIBPATH) all
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
$(MQTTLIB): .FORCE
|
||||||
|
$(info [*] MAKE $@)
|
||||||
|
$(Q)$(MAKE) --no-print-directory -C $(MQTTLIBPATH) all
|
||||||
|
|
||||||
########
|
########
|
||||||
# SWIG #
|
# SWIG #
|
||||||
########
|
########
|
||||||
|
|
|
@ -31,3 +31,6 @@ endif()
|
||||||
if (NOT TARGET pm3rrg_rdv4_whereami)
|
if (NOT TARGET pm3rrg_rdv4_whereami)
|
||||||
include(whereami.cmake)
|
include(whereami.cmake)
|
||||||
endif()
|
endif()
|
||||||
|
if (NOT TARGET pm3rrg_rdv4_mqtt)
|
||||||
|
include(mqtt.cmake)
|
||||||
|
endif()
|
|
@ -440,33 +440,32 @@ int json_dumpfd(const json_t *json, int output, size_t flags) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int json_dump_file(const json_t *json, const char *path, size_t flags) {
|
int json_dump_file(const json_t *json, const char *path, size_t flags) {
|
||||||
int result;
|
|
||||||
|
|
||||||
FILE *output = fopen(path, "w");
|
FILE *f = fopen(path, "w");
|
||||||
if (!output)
|
if (f == NULL) {
|
||||||
return -1;
|
|
||||||
|
|
||||||
result = json_dumpf(json, output, flags);
|
|
||||||
|
|
||||||
if (fclose(output) != 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags) {
|
|
||||||
int res;
|
|
||||||
hashtable_t parents_set;
|
|
||||||
|
|
||||||
if (!(flags & JSON_ENCODE_ANY)) {
|
|
||||||
if (!json_is_array(json) && !json_is_object(json))
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hashtable_init(&parents_set))
|
int res = json_dumpf(json, f, flags);
|
||||||
|
|
||||||
|
if (fclose(f) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
res = do_dump(json, flags, 0, &parents_set, callback, data);
|
|
||||||
hashtable_close(&parents_set);
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags) {
|
||||||
|
if (!(flags & JSON_ENCODE_ANY)) {
|
||||||
|
if (!json_is_array(json) && !json_is_object(json)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hashtable_t parents_set;
|
||||||
|
if (hashtable_init(&parents_set)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int res = do_dump(json, flags, 0, &parents_set, callback, data);
|
||||||
|
hashtable_close(&parents_set);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
9
client/deps/mqtt.cmake
Normal file
9
client/deps/mqtt.cmake
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
add_library(pm3rrg_rdv4_mqtt STATIC
|
||||||
|
mqtt/mqtt.c
|
||||||
|
mqtt/mqtt_pal.c
|
||||||
|
)
|
||||||
|
|
||||||
|
target_compile_definitions(pm3rrg_rdv4_mqtt PRIVATE WAI_PM3_TUNED)
|
||||||
|
target_include_directories(pm3rrg_rdv4_mqtt INTERFACE mqtt)
|
||||||
|
target_compile_options(pm3rrg_rdv4_mqtt PRIVATE -Wall -Werror -O3)
|
||||||
|
set_property(TARGET pm3rrg_rdv4_mqtt PROPERTY POSITION_INDEPENDENT_CODE ON)
|
21
client/deps/mqtt/LICENSE
Normal file
21
client/deps/mqtt/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 Liam Bindle
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
14
client/deps/mqtt/Makefile
Normal file
14
client/deps/mqtt/Makefile
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
MYSRCPATHS =
|
||||||
|
MYINCLUDES =
|
||||||
|
MYCFLAGS = -Wno-bad-function-cast -Wno-switch-enum
|
||||||
|
MYDEFS = -DWAI_PM3_TUNED
|
||||||
|
MYSRCS = \
|
||||||
|
mqtt.c \
|
||||||
|
mqtt_pal.c \
|
||||||
|
|
||||||
|
LIB_A = mqtt.a
|
||||||
|
|
||||||
|
# Transition: remove old directories and objects
|
||||||
|
MYCLEANOLDPATH = ../../mqtt
|
||||||
|
|
||||||
|
include ../../../Makefile.host
|
152
client/deps/mqtt/mbedtls_sockets.h
Normal file
152
client/deps/mqtt/mbedtls_sockets.h
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
#if !defined(__MBEDTLS_SOCKET_TEMPLATE_H__)
|
||||||
|
#define __MBEDTLS_SOCKET_TEMPLATE_H__
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <mbedtls/error.h>
|
||||||
|
#include <mbedtls/entropy.h>
|
||||||
|
#include <mbedtls/ctr_drbg.h>
|
||||||
|
#include <mbedtls/net_sockets.h>
|
||||||
|
#include <mbedtls/ssl.h>
|
||||||
|
|
||||||
|
#if !defined(MBEDTLS_NET_POLL_READ)
|
||||||
|
/* compat for older mbedtls */
|
||||||
|
#define MBEDTLS_NET_POLL_READ 1
|
||||||
|
#define MBEDTLS_NET_POLL_WRITE 1
|
||||||
|
|
||||||
|
int mbedtls_net_poll(mbedtls_net_context *ctx, uint32_t rw, uint32_t timeout) {
|
||||||
|
/* XXX this is not ideal but good enough for an example */
|
||||||
|
msleep(300);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct mbedtls_context {
|
||||||
|
mbedtls_net_context net_ctx;
|
||||||
|
mbedtls_ssl_context ssl_ctx;
|
||||||
|
mbedtls_ssl_config ssl_conf;
|
||||||
|
mbedtls_x509_crt ca_crt;
|
||||||
|
mbedtls_entropy_context entropy;
|
||||||
|
mbedtls_ctr_drbg_context ctr_drbg;
|
||||||
|
};
|
||||||
|
|
||||||
|
void failed(const char *fn, int rv);
|
||||||
|
void cert_verify_failed(uint32_t rv);
|
||||||
|
void open_nb_socket(struct mbedtls_context *ctx,
|
||||||
|
const char *hostname,
|
||||||
|
const char *port,
|
||||||
|
const char *ca_file);
|
||||||
|
|
||||||
|
|
||||||
|
void failed(const char *fn, int rv) {
|
||||||
|
char buf[100];
|
||||||
|
mbedtls_strerror(rv, buf, sizeof(buf));
|
||||||
|
printf("%s failed with %x (%s)\n", fn, -rv, buf);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cert_verify_failed(uint32_t rv) {
|
||||||
|
char buf[512];
|
||||||
|
mbedtls_x509_crt_verify_info(buf, sizeof(buf), "\t", rv);
|
||||||
|
printf("Certificate verification failed (%0" PRIx32 ")\n%s\n", rv, buf);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
A template for opening a non-blocking mbed TLS connection.
|
||||||
|
*/
|
||||||
|
void open_nb_socket(struct mbedtls_context *ctx,
|
||||||
|
const char *hostname,
|
||||||
|
const char *port,
|
||||||
|
const char *ca_file) {
|
||||||
|
|
||||||
|
const unsigned char *additional = (const unsigned char *)"Pm3 Client";
|
||||||
|
size_t additional_len = 6;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
mbedtls_net_context *net_ctx = &ctx->net_ctx;
|
||||||
|
mbedtls_ssl_context *ssl_ctx = &ctx->ssl_ctx;
|
||||||
|
mbedtls_ssl_config *ssl_conf = &ctx->ssl_conf;
|
||||||
|
mbedtls_x509_crt *ca_crt = &ctx->ca_crt;
|
||||||
|
mbedtls_entropy_context *entropy = &ctx->entropy;
|
||||||
|
mbedtls_ctr_drbg_context *ctr_drbg = &ctx->ctr_drbg;
|
||||||
|
|
||||||
|
mbedtls_entropy_init(entropy);
|
||||||
|
mbedtls_ctr_drbg_init(ctr_drbg);
|
||||||
|
rv = mbedtls_ctr_drbg_seed(ctr_drbg, mbedtls_entropy_func, entropy,
|
||||||
|
additional, additional_len);
|
||||||
|
if (rv != 0) {
|
||||||
|
failed("mbedtls_ctr_drbg_seed", rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_x509_crt_init(ca_crt);
|
||||||
|
rv = mbedtls_x509_crt_parse_file(ca_crt, ca_file);
|
||||||
|
if (rv != 0) {
|
||||||
|
failed("mbedtls_x509_crt_parse_file", rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_ssl_config_init(ssl_conf);
|
||||||
|
rv = mbedtls_ssl_config_defaults(ssl_conf, MBEDTLS_SSL_IS_CLIENT,
|
||||||
|
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||||
|
MBEDTLS_SSL_PRESET_DEFAULT);
|
||||||
|
if (rv != 0) {
|
||||||
|
failed("mbedtls_ssl_config_defaults", rv);
|
||||||
|
}
|
||||||
|
mbedtls_ssl_conf_ca_chain(ssl_conf, ca_crt, NULL);
|
||||||
|
mbedtls_ssl_conf_authmode(ssl_conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
|
||||||
|
mbedtls_ssl_conf_rng(ssl_conf, mbedtls_ctr_drbg_random, ctr_drbg);
|
||||||
|
|
||||||
|
mbedtls_net_init(net_ctx);
|
||||||
|
rv = mbedtls_net_connect(net_ctx, hostname, port, MBEDTLS_NET_PROTO_TCP);
|
||||||
|
if (rv != 0) {
|
||||||
|
failed("mbedtls_net_connect", rv);
|
||||||
|
}
|
||||||
|
rv = mbedtls_net_set_nonblock(net_ctx);
|
||||||
|
if (rv != 0) {
|
||||||
|
failed("mbedtls_net_set_nonblock", rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_ssl_init(ssl_ctx);
|
||||||
|
rv = mbedtls_ssl_setup(ssl_ctx, ssl_conf);
|
||||||
|
if (rv != 0) {
|
||||||
|
failed("mbedtls_ssl_setup", rv);
|
||||||
|
}
|
||||||
|
rv = mbedtls_ssl_set_hostname(ssl_ctx, hostname);
|
||||||
|
if (rv != 0) {
|
||||||
|
failed("mbedtls_ssl_set_hostname", rv);
|
||||||
|
}
|
||||||
|
mbedtls_ssl_set_bio(ssl_ctx, net_ctx,
|
||||||
|
mbedtls_net_send, mbedtls_net_recv, NULL);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
rv = mbedtls_ssl_handshake(ssl_ctx);
|
||||||
|
uint32_t want = 0;
|
||||||
|
if (rv == MBEDTLS_ERR_SSL_WANT_READ) {
|
||||||
|
want |= MBEDTLS_NET_POLL_READ;
|
||||||
|
} else if (rv == MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||||
|
want |= MBEDTLS_NET_POLL_WRITE;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rv = mbedtls_net_poll(net_ctx, want, (uint32_t) -1);
|
||||||
|
if (rv < 0) {
|
||||||
|
failed("mbedtls_net_poll", rv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rv != 0) {
|
||||||
|
failed("mbedtls_ssl_handshake", rv);
|
||||||
|
}
|
||||||
|
uint32_t result = mbedtls_ssl_get_verify_result(ssl_ctx);
|
||||||
|
if (result != 0) {
|
||||||
|
if (result == (uint32_t) -1) {
|
||||||
|
failed("mbedtls_ssl_get_verify_result", (int)result);
|
||||||
|
} else {
|
||||||
|
cert_verify_failed(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
1770
client/deps/mqtt/mqtt.c
Normal file
1770
client/deps/mqtt/mqtt.c
Normal file
File diff suppressed because it is too large
Load diff
1640
client/deps/mqtt/mqtt.h
Normal file
1640
client/deps/mqtt/mqtt.h
Normal file
File diff suppressed because it is too large
Load diff
235
client/deps/mqtt/mqtt_pal.c
Normal file
235
client/deps/mqtt/mqtt_pal.c
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
/*
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright(c) 2018 Liam Bindle
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files(the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions :
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "mqtt.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Implements @ref mqtt_pal_sendall and @ref mqtt_pal_recvall and
|
||||||
|
* any platform-specific helpers you'd like.
|
||||||
|
* @cond Doxygen_Suppress
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(MQTT_USE_CUSTOM_SOCKET_HANDLE)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In case of MQTT_USE_CUSTOM_SOCKET_HANDLE, a pal implemantation is
|
||||||
|
* provided by the user.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Note: Some toolchains complain on an object without symbols */
|
||||||
|
|
||||||
|
int _mqtt_pal_dummy;
|
||||||
|
|
||||||
|
#else /* defined(MQTT_USE_CUSTOM_SOCKET_HANDLE) */
|
||||||
|
|
||||||
|
#if defined(MQTT_USE_MBEDTLS)
|
||||||
|
#include <mbedtls/ssl.h>
|
||||||
|
|
||||||
|
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void *buf, size_t len, int flags) {
|
||||||
|
enum MQTTErrors error = 0;
|
||||||
|
size_t sent = 0;
|
||||||
|
while (sent < len) {
|
||||||
|
int rv = mbedtls_ssl_write(fd, (const unsigned char *)buf + sent, len - sent);
|
||||||
|
if (rv < 0) {
|
||||||
|
if (rv == MBEDTLS_ERR_SSL_WANT_READ ||
|
||||||
|
rv == MBEDTLS_ERR_SSL_WANT_WRITE
|
||||||
|
#if defined(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS)
|
||||||
|
|| rv == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS
|
||||||
|
#endif
|
||||||
|
#if defined(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)
|
||||||
|
|| rv == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
/* should call mbedtls_ssl_write later again */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
error = MQTT_ERROR_SOCKET_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Note: rv can be 0 here eg. when mbedtls just flushed
|
||||||
|
* the previous incomplete record.
|
||||||
|
*
|
||||||
|
* Note: we never send an empty TLS record.
|
||||||
|
*/
|
||||||
|
sent += (size_t) rv;
|
||||||
|
}
|
||||||
|
if (sent == 0) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return (ssize_t)sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void *buf, size_t bufsz, int flags) {
|
||||||
|
const void *const start = buf;
|
||||||
|
enum MQTTErrors error = 0;
|
||||||
|
int rv;
|
||||||
|
do {
|
||||||
|
rv = mbedtls_ssl_read(fd, (unsigned char *)buf, bufsz);
|
||||||
|
if (rv == 0) {
|
||||||
|
/*
|
||||||
|
* Note: mbedtls_ssl_read returns 0 when the underlying
|
||||||
|
* transport was closed without CloseNotify.
|
||||||
|
*
|
||||||
|
* Raise an error to trigger a reconnect.
|
||||||
|
*/
|
||||||
|
error = MQTT_ERROR_SOCKET_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (rv < 0) {
|
||||||
|
if (rv == MBEDTLS_ERR_SSL_WANT_READ ||
|
||||||
|
rv == MBEDTLS_ERR_SSL_WANT_WRITE
|
||||||
|
#if defined(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS)
|
||||||
|
|| rv == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS
|
||||||
|
#endif
|
||||||
|
#if defined(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)
|
||||||
|
|| rv == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
/* should call mbedtls_ssl_read later again */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Note: MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY is handled here. */
|
||||||
|
error = MQTT_ERROR_SOCKET_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf = (char *)buf + rv;
|
||||||
|
bufsz -= (unsigned long)rv;
|
||||||
|
} while (bufsz > 0);
|
||||||
|
if (buf == start) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return (const char *)buf - (const char *)start;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__unix__) || defined(__APPLE__) || defined(__NuttX__)
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void *buf, size_t len, int flags) {
|
||||||
|
enum MQTTErrors error = 0;
|
||||||
|
size_t sent = 0;
|
||||||
|
while (sent < len) {
|
||||||
|
ssize_t rv = send(fd, (const char *)buf + sent, len - sent, flags);
|
||||||
|
if (rv < 0) {
|
||||||
|
if (errno == EAGAIN) {
|
||||||
|
/* should call send later again */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
error = MQTT_ERROR_SOCKET_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (rv == 0) {
|
||||||
|
/* is this possible? maybe OS bug. */
|
||||||
|
error = MQTT_ERROR_SOCKET_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sent += (size_t) rv;
|
||||||
|
}
|
||||||
|
if (sent == 0) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return (ssize_t)sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void *buf, size_t bufsz, int flags) {
|
||||||
|
const void *const start = buf;
|
||||||
|
enum MQTTErrors error = 0;
|
||||||
|
ssize_t rv;
|
||||||
|
do {
|
||||||
|
rv = recv(fd, buf, bufsz, flags);
|
||||||
|
if (rv == 0) {
|
||||||
|
/*
|
||||||
|
* recv returns 0 when the socket is (half) closed by the peer.
|
||||||
|
*
|
||||||
|
* Raise an error to trigger a reconnect.
|
||||||
|
*/
|
||||||
|
error = MQTT_ERROR_SOCKET_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (rv < 0) {
|
||||||
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||||
|
/* should call recv later again */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* an error occurred that wasn't "nothing to read". */
|
||||||
|
error = MQTT_ERROR_SOCKET_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf = (char *)buf + rv;
|
||||||
|
bufsz -= (unsigned long)rv;
|
||||||
|
} while (bufsz > 0);
|
||||||
|
if (buf == start) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return (char *)buf - (const char *)start;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER) || defined(WIN32)
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void *buf, size_t len, int flags) {
|
||||||
|
size_t sent = 0;
|
||||||
|
while (sent < len) {
|
||||||
|
ssize_t tmp = send(fd, (char *)buf + sent, len - sent, flags);
|
||||||
|
if (tmp < 1) {
|
||||||
|
return MQTT_ERROR_SOCKET_ERROR;
|
||||||
|
}
|
||||||
|
sent += (size_t) tmp;
|
||||||
|
}
|
||||||
|
return sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void *buf, size_t bufsz, int flags) {
|
||||||
|
const char *const start = buf;
|
||||||
|
ssize_t rv;
|
||||||
|
do {
|
||||||
|
rv = recv(fd, buf, bufsz, flags);
|
||||||
|
if (rv > 0) {
|
||||||
|
/* successfully read bytes from the socket */
|
||||||
|
buf = (char *)buf + rv;
|
||||||
|
bufsz -= rv;
|
||||||
|
} else if (rv < 0) {
|
||||||
|
int err = WSAGetLastError();
|
||||||
|
if (err != WSAEWOULDBLOCK) {
|
||||||
|
/* an error occurred that wasn't "nothing to read". */
|
||||||
|
return MQTT_ERROR_SOCKET_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (rv > 0 && bufsz > 0);
|
||||||
|
|
||||||
|
return (ssize_t)((char *)buf - start);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#error No PAL!
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* defined(MQTT_USE_CUSTOM_SOCKET_HANDLE) */
|
||||||
|
|
||||||
|
/** @endcond */
|
173
client/deps/mqtt/mqtt_pal.h
Normal file
173
client/deps/mqtt/mqtt_pal.h
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
#if !defined(__MQTT_PAL_H__)
|
||||||
|
#define __MQTT_PAL_H__
|
||||||
|
|
||||||
|
/*
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright(c) 2018 Liam Bindle
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files(the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions :
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Includes/supports the types/calls required by the MQTT-C client.
|
||||||
|
*
|
||||||
|
* @note This is the \em only file included in mqtt.h, and mqtt.c. It is therefore
|
||||||
|
* responsible for including/supporting all the required types and calls.
|
||||||
|
*
|
||||||
|
* @defgroup pal Platform abstraction layer
|
||||||
|
* @brief Documentation of the types and calls required to port MQTT-C to a new platform.
|
||||||
|
*
|
||||||
|
* mqtt_pal.h is the \em only header file included in mqtt.c. Therefore, to port MQTT-C to a
|
||||||
|
* new platform the following types, functions, constants, and macros must be defined in
|
||||||
|
* mqtt_pal.h:
|
||||||
|
* - Types:
|
||||||
|
* - \c size_t, \c ssize_t
|
||||||
|
* - \c uint8_t, \c uint16_t, \c uint32_t
|
||||||
|
* - \c va_list
|
||||||
|
* - \c mqtt_pal_time_t : return type of \c MQTT_PAL_TIME()
|
||||||
|
* - \c mqtt_pal_mutex_t : type of the argument that is passed to \c MQTT_PAL_MUTEX_LOCK and
|
||||||
|
* \c MQTT_PAL_MUTEX_RELEASE
|
||||||
|
* - Functions:
|
||||||
|
* - \c memcpy, \c strlen
|
||||||
|
* - \c va_start, \c va_arg, \c va_end
|
||||||
|
* - Constants:
|
||||||
|
* - \c INT_MIN
|
||||||
|
*
|
||||||
|
* Additionally, three macro's are required:
|
||||||
|
* - \c MQTT_PAL_HTONS(s) : host-to-network endian conversion for uint16_t.
|
||||||
|
* - \c MQTT_PAL_NTOHS(s) : network-to-host endian conversion for uint16_t.
|
||||||
|
* - \c MQTT_PAL_TIME() : returns [type: \c mqtt_pal_time_t] current time in seconds.
|
||||||
|
* - \c MQTT_PAL_MUTEX_LOCK(mtx_pointer) : macro that locks the mutex pointed to by \c mtx_pointer.
|
||||||
|
* - \c MQTT_PAL_MUTEX_RELEASE(mtx_pointer) : macro that unlocks the mutex pointed to by
|
||||||
|
* \c mtx_pointer.
|
||||||
|
*
|
||||||
|
* Lastly, \ref mqtt_pal_sendall and \ref mqtt_pal_recvall, must be implemented in mqtt_pal.c
|
||||||
|
* for sending and receiving data using the platforms socket calls.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* UNIX-like platform support */
|
||||||
|
#if defined(__unix__) || defined(__APPLE__) || defined(__NuttX__)
|
||||||
|
#include <limits.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#define MQTT_PAL_HTONS(s) htons(s)
|
||||||
|
#define MQTT_PAL_NTOHS(s) ntohs(s)
|
||||||
|
|
||||||
|
#define MQTT_PAL_TIME() time(NULL)
|
||||||
|
|
||||||
|
typedef time_t mqtt_pal_time_t;
|
||||||
|
typedef pthread_mutex_t mqtt_pal_mutex_t;
|
||||||
|
|
||||||
|
#define MQTT_PAL_MUTEX_INIT(mtx_ptr) pthread_mutex_init(mtx_ptr, NULL)
|
||||||
|
#define MQTT_PAL_MUTEX_LOCK(mtx_ptr) pthread_mutex_lock(mtx_ptr)
|
||||||
|
#define MQTT_PAL_MUTEX_UNLOCK(mtx_ptr) pthread_mutex_unlock(mtx_ptr)
|
||||||
|
|
||||||
|
#if !defined(MQTT_USE_CUSTOM_SOCKET_HANDLE)
|
||||||
|
#if defined(MQTT_USE_MBEDTLS)
|
||||||
|
struct mbedtls_ssl_context;
|
||||||
|
typedef struct mbedtls_ssl_context *mqtt_pal_socket_handle;
|
||||||
|
#else
|
||||||
|
typedef int mqtt_pal_socket_handle;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER) || defined(WIN32)
|
||||||
|
#include <limits.h>
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef SSIZE_T ssize_t;
|
||||||
|
#define MQTT_PAL_HTONS(s) htons(s)
|
||||||
|
#define MQTT_PAL_NTOHS(s) ntohs(s)
|
||||||
|
|
||||||
|
#define MQTT_PAL_TIME() time(NULL)
|
||||||
|
|
||||||
|
typedef time_t mqtt_pal_time_t;
|
||||||
|
typedef CRITICAL_SECTION mqtt_pal_mutex_t;
|
||||||
|
|
||||||
|
#define MQTT_PAL_MUTEX_INIT(mtx_ptr) InitializeCriticalSection(mtx_ptr)
|
||||||
|
#define MQTT_PAL_MUTEX_LOCK(mtx_ptr) EnterCriticalSection(mtx_ptr)
|
||||||
|
#define MQTT_PAL_MUTEX_UNLOCK(mtx_ptr) LeaveCriticalSection(mtx_ptr)
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(MQTT_USE_CUSTOM_SOCKET_HANDLE)
|
||||||
|
typedef SOCKET mqtt_pal_socket_handle;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sends all the bytes in a buffer.
|
||||||
|
* @ingroup pal
|
||||||
|
*
|
||||||
|
* @param[in] fd The file-descriptor (or handle) of the socket.
|
||||||
|
* @param[in] buf A pointer to the first byte in the buffer to send.
|
||||||
|
* @param[in] len The number of bytes to send (starting at \p buf).
|
||||||
|
* @param[in] flags Flags which are passed to the underlying socket.
|
||||||
|
*
|
||||||
|
* @returns The number of bytes sent if successful, an \ref MQTTErrors otherwise.
|
||||||
|
*
|
||||||
|
* Note about the error handling:
|
||||||
|
* - On an error, if some bytes have been processed already,
|
||||||
|
* this function should return the number of bytes successfully
|
||||||
|
* processed. (partial success)
|
||||||
|
* - Otherwise, if the error is an equivalent of EAGAIN, return 0.
|
||||||
|
* - Otherwise, return MQTT_ERROR_SOCKET_ERROR.
|
||||||
|
*/
|
||||||
|
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void *buf, size_t len, int flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Non-blocking receive all the byte available.
|
||||||
|
* @ingroup pal
|
||||||
|
*
|
||||||
|
* @param[in] fd The file-descriptor (or handle) of the socket.
|
||||||
|
* @param[in] buf A pointer to the receive buffer.
|
||||||
|
* @param[in] bufsz The max number of bytes that can be put into \p buf.
|
||||||
|
* @param[in] flags Flags which are passed to the underlying socket.
|
||||||
|
*
|
||||||
|
* @returns The number of bytes received if successful, an \ref MQTTErrors otherwise.
|
||||||
|
*
|
||||||
|
* Note about the error handling:
|
||||||
|
* - On an error, if some bytes have been processed already,
|
||||||
|
* this function should return the number of bytes successfully
|
||||||
|
* processed. (partial success)
|
||||||
|
* - Otherwise, if the error is an equivalent of EAGAIN, return 0.
|
||||||
|
* - Otherwise, return MQTT_ERROR_SOCKET_ERROR.
|
||||||
|
*/
|
||||||
|
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void *buf, size_t bufsz, int flags);
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
73
client/deps/mqtt/posix_sockets.h
Normal file
73
client/deps/mqtt/posix_sockets.h
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#if !defined(__POSIX_SOCKET_TEMPLATE_H__)
|
||||||
|
#define __POSIX_SOCKET_TEMPLATE_H__
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
// A template for opening a non-blocking POSIX socket.
|
||||||
|
|
||||||
|
void close_nb_socket(int sockfd);
|
||||||
|
int open_nb_socket(const char *addr, const char *port);
|
||||||
|
|
||||||
|
int open_nb_socket(const char *addr, const char *port) {
|
||||||
|
|
||||||
|
struct addrinfo hints;
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
|
||||||
|
hints.ai_family = AF_UNSPEC; /* IPv4 or IPv6 */
|
||||||
|
hints.ai_socktype = SOCK_STREAM; /* Must be TCP */
|
||||||
|
|
||||||
|
struct addrinfo *p, *servinfo;
|
||||||
|
|
||||||
|
/* get address information */
|
||||||
|
int rv = getaddrinfo(addr, port, &hints, &servinfo);
|
||||||
|
if (rv != 0) {
|
||||||
|
fprintf(stderr, "Failed to open socket (getaddrinfo): %s\n", gai_strerror(rv));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open the first possible socket */
|
||||||
|
int sockfd = -1;
|
||||||
|
for (p = servinfo; p != NULL; p = p->ai_next) {
|
||||||
|
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
|
||||||
|
if (sockfd == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* connect to server */
|
||||||
|
rv = connect(sockfd, p->ai_addr, p->ai_addrlen);
|
||||||
|
if (rv == -1) {
|
||||||
|
close(sockfd);
|
||||||
|
sockfd = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// free servinfo
|
||||||
|
freeaddrinfo(servinfo);
|
||||||
|
|
||||||
|
// make non-blocking
|
||||||
|
if (sockfd != -1) {
|
||||||
|
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sockfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_nb_socket(int sockfd) {
|
||||||
|
if (sockfd != -1) {
|
||||||
|
close(sockfd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
15
client/deps/mqtt/readme.md
Normal file
15
client/deps/mqtt/readme.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
# Information
|
||||||
|
Source: https://github.com/LiamBindle/MQTT-C
|
||||||
|
License: MIT
|
||||||
|
Authors:
|
||||||
|
|
||||||
|
MQTT-C was initially developed as a CMPT 434 (Winter Term, 2018) final project at the University of Saskatchewan by:
|
||||||
|
|
||||||
|
- Liam Bindle
|
||||||
|
- Demilade Adeoye
|
||||||
|
|
||||||
|
|
||||||
|
# about
|
||||||
|
MQTT-C is an MQTT v3.1.1 client written in C. MQTT is a lightweight publisher-subscriber-based messaging protocol that is commonly used in IoT and networking applications where high-latency and low data-rate links are expected. The purpose of MQTT-C is to provide a portable MQTT client, written in C, for embedded systems and PC's alike. MQTT-C does this by providing a transparent Platform Abstraction Layer (PAL) which makes porting to new platforms easy. MQTT-C is completely thread-safe but can also run perfectly fine on single-threaded systems making MQTT-C well-suited for embedded systems and microcontrollers. Finally, MQTT-C is small; there are only two source files totalling less than 2000 lines.
|
||||||
|
|
91
client/deps/mqtt/win32_sockets.h
Normal file
91
client/deps/mqtt/win32_sockets.h
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#if !defined(__WIN32_SOCKET_TEMPLATE_H__)
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
|
void close_nb_socket(int sockfd);
|
||||||
|
int open_nb_socket(const char *addr, const char *port);
|
||||||
|
|
||||||
|
int open_nb_socket(const char *addr, const char *port) {
|
||||||
|
|
||||||
|
WSADATA wsaData;
|
||||||
|
int res = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||||
|
if (res != 0) {
|
||||||
|
fprintf(stderr, "error: WSAStartup failed with error: %i", res);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct addrinfo hints;
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_family = AF_UNSPEC; // IPv4 or IPv6
|
||||||
|
hints.ai_socktype = SOCK_STREAM; // Must be TCP
|
||||||
|
hints.ai_protocol = IPPROTO_TCP; //
|
||||||
|
|
||||||
|
struct addrinfo *p, *servinfo;
|
||||||
|
// get address information
|
||||||
|
int rv = getaddrinfo(addr, port, &hints, &servinfo);
|
||||||
|
if (rv != 0) {
|
||||||
|
fprintf(stderr, "error: getaddrinfo: %s", gai_strerror(rv));
|
||||||
|
WSACleanup();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open the first possible socket */
|
||||||
|
SOCKET hSocket = INVALID_SOCKET;
|
||||||
|
for (p = servinfo; p != NULL; p = p->ai_next) {
|
||||||
|
hSocket = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
|
||||||
|
|
||||||
|
if (hSocket == INVALID_SOCKET) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// connect to server
|
||||||
|
if (connect(hSocket, p->ai_addr, (int)p->ai_addrlen) != INVALID_SOCKET) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
closesocket(hSocket);
|
||||||
|
hSocket = INVALID_SOCKET;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// free servinfo
|
||||||
|
freeaddrinfo(servinfo);
|
||||||
|
|
||||||
|
if (p == NULL) { // No address succeeded
|
||||||
|
fprintf(stderr, "error: Could not connect");
|
||||||
|
WSACleanup();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make non-blocking
|
||||||
|
if (hSocket != INVALID_SOCKET) {
|
||||||
|
uint32_t mode = 1; // FIONBIO returns size on 32b
|
||||||
|
ioctlsocket(hSocket, FIONBIO, (u_long *)&mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
int flag = 1;
|
||||||
|
res = setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag));
|
||||||
|
if (res != 0) {
|
||||||
|
closesocket(hSocket);
|
||||||
|
WSACleanup();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_nb_socket(int sockfd) {
|
||||||
|
if (sockfd != -1) {
|
||||||
|
close(sockfd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -1135,7 +1135,7 @@ int read_iclass_csn(bool loop, bool verbose, bool shallow_mod) {
|
||||||
res = PM3_EMALLOC;
|
res = PM3_EMALLOC;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (loop && kbd_enter_pressed() == false);
|
} while (loop && (kbd_enter_pressed() == false));
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -781,17 +781,20 @@ int legic_print_type(uint32_t tagtype, uint8_t spaces) {
|
||||||
}
|
}
|
||||||
int legic_get_type(legic_card_select_t *card) {
|
int legic_get_type(legic_card_select_t *card) {
|
||||||
|
|
||||||
if (card == NULL)
|
if (card == NULL) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_HF_LEGIC_INFO, NULL, 0);
|
SendCommandNG(CMD_HF_LEGIC_INFO, NULL, 0);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(CMD_HF_LEGIC_INFO, &resp, 1500) == false)
|
if (WaitForResponseTimeout(CMD_HF_LEGIC_INFO, &resp, 1500) == false) {
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
if (resp.status != PM3_SUCCESS)
|
if (resp.status != PM3_SUCCESS) {
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(card, resp.data.asBytes, sizeof(legic_card_select_t));
|
memcpy(card, resp.data.asBytes, sizeof(legic_card_select_t));
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
@ -1527,7 +1530,7 @@ int readLegicUid(bool loop, bool verbose) {
|
||||||
PrintAndLogEx(SUCCESS, " MSN: " _GREEN_("%s"), sprint_hex(card.uid + 1, sizeof(card.uid) - 1));
|
PrintAndLogEx(SUCCESS, " MSN: " _GREEN_("%s"), sprint_hex(card.uid + 1, sizeof(card.uid) - 1));
|
||||||
legic_print_type(card.cardsize, 0);
|
legic_print_type(card.cardsize, 0);
|
||||||
|
|
||||||
} while (loop && kbd_enter_pressed() == false);
|
} while (loop && (kbd_enter_pressed() == false));
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -462,7 +462,7 @@ int CmdLFCommandRead(const char *Cmd) {
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (cm && kbd_enter_pressed() == false);
|
} while (cm && (kbd_enter_pressed() == false));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -859,7 +859,7 @@ int CmdLFRead(const char *Cmd) {
|
||||||
int ret = PM3_SUCCESS;
|
int ret = PM3_SUCCESS;
|
||||||
do {
|
do {
|
||||||
ret = lf_read_internal(realtime, verbose, samples);
|
ret = lf_read_internal(realtime, verbose, samples);
|
||||||
} while (cm && kbd_enter_pressed() == false);
|
} while (cm && (kbd_enter_pressed() == false));
|
||||||
|
|
||||||
if (ret == PM3_SUCCESS) {
|
if (ret == PM3_SUCCESS) {
|
||||||
PrintAndLogEx(SUCCESS, "Got " _YELLOW_("%zu") " samples", g_GraphTraceLen);
|
PrintAndLogEx(SUCCESS, "Got " _YELLOW_("%zu") " samples", g_GraphTraceLen);
|
||||||
|
@ -985,7 +985,7 @@ int CmdLFSniff(const char *Cmd) {
|
||||||
int ret = PM3_SUCCESS;
|
int ret = PM3_SUCCESS;
|
||||||
do {
|
do {
|
||||||
ret = lf_sniff(realtime, verbose, samples);
|
ret = lf_sniff(realtime, verbose, samples);
|
||||||
} while (cm && kbd_enter_pressed() == false);
|
} while (cm && (kbd_enter_pressed() == false));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -349,7 +349,7 @@ static int CmdAWIDReader(const char *Cmd) {
|
||||||
do {
|
do {
|
||||||
lf_read(false, 12000);
|
lf_read(false, 12000);
|
||||||
demodAWID(!cm);
|
demodAWID(!cm);
|
||||||
} while (cm && !kbd_enter_pressed());
|
} while (cm && (kbd_enter_pressed() == false));
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -445,7 +445,7 @@ static int CmdEM410xReader(const char *Cmd) {
|
||||||
if (break_first && gs_em410xid != 0) {
|
if (break_first && gs_em410xid != 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (cm && !kbd_enter_pressed());
|
} while (cm && (kbd_enter_pressed() == false));
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,7 +243,7 @@ static int CmdGuardReader(const char *Cmd) {
|
||||||
do {
|
do {
|
||||||
lf_read(false, 10000);
|
lf_read(false, 10000);
|
||||||
demodGuard(!cm);
|
demodGuard(!cm);
|
||||||
} while (cm && !kbd_enter_pressed());
|
} while (cm && (kbd_enter_pressed() == false));
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -215,7 +215,7 @@ static int CmdHIDReader(const char *Cmd) {
|
||||||
do {
|
do {
|
||||||
lf_read(false, 16000);
|
lf_read(false, 16000);
|
||||||
demodHID(!cm);
|
demodHID(!cm);
|
||||||
} while (cm && !kbd_enter_pressed());
|
} while (cm && (kbd_enter_pressed() == false));
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -912,7 +912,7 @@ static int CmdLFHitagReader(const char *Cmd) {
|
||||||
if (ht2_get_uid(&uid)) {
|
if (ht2_get_uid(&uid)) {
|
||||||
PrintAndLogEx(SUCCESS, "UID.... " _GREEN_("%08X"), uid);
|
PrintAndLogEx(SUCCESS, "UID.... " _GREEN_("%08X"), uid);
|
||||||
}
|
}
|
||||||
} while (cm && kbd_enter_pressed() == false);
|
} while (cm && (kbd_enter_pressed() == false));
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#include "commonutil.h" // ARRAYLEN
|
#include "commonutil.h" // ARRAYLEN
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
#include "cliparser.h"
|
#include "cliparser.h"
|
||||||
|
#include "cmdmqtt.h"
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
|
@ -338,6 +339,7 @@ static command_t CommandTable[] = {
|
||||||
{"hw", CmdHW, AlwaysAvailable, "{ Hardware commands... }"},
|
{"hw", CmdHW, AlwaysAvailable, "{ Hardware commands... }"},
|
||||||
{"lf", CmdLF, AlwaysAvailable, "{ Low frequency commands... }"},
|
{"lf", CmdLF, AlwaysAvailable, "{ Low frequency commands... }"},
|
||||||
{"mem", CmdFlashMem, IfPm3Flash, "{ Flash memory manipulation... }"},
|
{"mem", CmdFlashMem, IfPm3Flash, "{ Flash memory manipulation... }"},
|
||||||
|
{"mqtt", CmdMqtt, AlwaysAvailable, "{ MQTT commmands... }"},
|
||||||
{"nfc", CmdNFC, AlwaysAvailable, "{ NFC commands... }"},
|
{"nfc", CmdNFC, AlwaysAvailable, "{ NFC commands... }"},
|
||||||
{"piv", CmdPIV, AlwaysAvailable, "{ PIV commands... }"},
|
{"piv", CmdPIV, AlwaysAvailable, "{ PIV commands... }"},
|
||||||
{"reveng", CmdRev, AlwaysAvailable, "{ CRC calculations from RevEng software... }"},
|
{"reveng", CmdRev, AlwaysAvailable, "{ CRC calculations from RevEng software... }"},
|
||||||
|
|
390
client/src/cmdmqtt.c
Normal file
390
client/src/cmdmqtt.c
Normal file
|
@ -0,0 +1,390 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// See LICENSE.txt for the text of the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// MQTT commands
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#include "cmdmqtt.h"
|
||||||
|
|
||||||
|
#include "cmdparser.h"
|
||||||
|
#include "cliparser.h"
|
||||||
|
#include "mqtt.h" // MQTT support
|
||||||
|
//#include "mbedtls_sockets.h" // MQTT networkings examples
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#include "posix_sockets.h" // MQTT networkings examples
|
||||||
|
#else
|
||||||
|
#include "win32_sockets.h" // MQTT networkings examples
|
||||||
|
#endif
|
||||||
|
#include "util_posix.h" // time
|
||||||
|
#include "fileutils.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define MQTT_BUFFER_SIZE ( 1 << 16 )
|
||||||
|
|
||||||
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
|
static void mqtt_publish_callback(void **unused, struct mqtt_response_publish *published) {
|
||||||
|
// note that published->topic_name is NOT null-terminated (here we'll change it to a c-string)
|
||||||
|
char *topic_name = (char *) calloc(published->topic_name_size + 1, 1);
|
||||||
|
memcpy(topic_name, published->topic_name, published->topic_name_size);
|
||||||
|
|
||||||
|
const char *msg = published->application_message;
|
||||||
|
|
||||||
|
char *ps = strstr(msg, "Created\": \"proxmark3");
|
||||||
|
if (ps) {
|
||||||
|
int res = saveFileTXT("ice_mqtt", ".json", msg, published->application_message_size, spDefault);
|
||||||
|
if (res == PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(INFO, "Got a json file ( %s )", _GREEN_("ok"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(SUCCESS, _GREEN_("%s") " - ( %zu ) " _YELLOW_("%s"), topic_name, published->application_message_size, msg);
|
||||||
|
}
|
||||||
|
free(topic_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *mqtt_client_refresher(void *client) {
|
||||||
|
while (1) {
|
||||||
|
mqtt_sync((struct mqtt_client *) client);
|
||||||
|
msleep(100);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mqtt_exit(int status, int sockfd, pthread_t *client_daemon) {
|
||||||
|
close_nb_socket(sockfd);
|
||||||
|
|
||||||
|
if (client_daemon != NULL) {
|
||||||
|
pthread_cancel(*client_daemon);
|
||||||
|
#ifndef _WIN32
|
||||||
|
pthread_join(*client_daemon, NULL); // Wait for the thread to finish
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
static void mqtt_reconnect_client(struct mqtt_client* client, void **reconnect_state_vptr) {
|
||||||
|
|
||||||
|
struct reconnect_state_t *rs = *((struct reconnect_state_t**) reconnect_state_vptr);
|
||||||
|
|
||||||
|
// Close the clients socket if this isn't the initial reconnect call
|
||||||
|
if (client->error != MQTT_ERROR_INITIAL_RECONNECT) {
|
||||||
|
close_nb_socket(client->socketfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client->error != MQTT_ERROR_INITIAL_RECONNECT) {
|
||||||
|
PrintAndLogEx(INFO, "reconnect_client: called while client was in error state `%s`", mqtt_error_str(client->error));
|
||||||
|
}
|
||||||
|
|
||||||
|
int sockfd = open_nb_socket(rs->hostname, rs->port);
|
||||||
|
if (sockfd == -1) {
|
||||||
|
PrintAndLogEx(FAILED, "Failed to open socket");
|
||||||
|
mqtt_exit(PM3_EFAILED, sockfd, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reinitialize the client.
|
||||||
|
mqtt_reinit(client, sockfd, rs->sendbuf, rs->sendbufsz, rs->recvbuf, rs->recvbufsz);
|
||||||
|
|
||||||
|
const char* client_id = NULL;
|
||||||
|
|
||||||
|
uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION;
|
||||||
|
|
||||||
|
mqtt_connect(client, client_id, NULL, NULL, 0, NULL, NULL, connect_flags, 400);
|
||||||
|
|
||||||
|
mqtt_subscribe(client, rs->topic, 0);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int mqtt_receive(const char *addr, const char *port, const char *topic, const char *fn) {
|
||||||
|
// open the non-blocking TCP socket (connecting to the broker)
|
||||||
|
int sockfd = open_nb_socket(addr, port);
|
||||||
|
if (sockfd == -1) {
|
||||||
|
PrintAndLogEx(FAILED, "Failed to open socket");
|
||||||
|
return mqtt_exit(PM3_EFAILED, sockfd, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t sendbuf[MQTT_BUFFER_SIZE]; // 64kb sendbuf should be large enough to hold multiple whole mqtt messages
|
||||||
|
uint8_t recvbuf[MQTT_BUFFER_SIZE]; // 64kb recvbuf should be large enough any whole mqtt message expected to be received
|
||||||
|
|
||||||
|
struct mqtt_client client;
|
||||||
|
|
||||||
|
/*
|
||||||
|
struct reconnect_state_t rs;
|
||||||
|
rs.hostname = addr;
|
||||||
|
rs.port = port;
|
||||||
|
rs.topic = topic;
|
||||||
|
rs.sendbuf = sendbuf;
|
||||||
|
rs.sendbufsz = sizeof(sendbuf);
|
||||||
|
rs.recvbuf = recvbuf;
|
||||||
|
rs.recvbufsz = sizeof(recvbuf);
|
||||||
|
mqtt_init_reconnect(&client, mqtt_reconnect_client, &rs, mqtt_publish_callback);
|
||||||
|
*/
|
||||||
|
|
||||||
|
mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), mqtt_publish_callback);
|
||||||
|
|
||||||
|
char cid[20] = "pm3_";
|
||||||
|
sprintf(cid + strlen(cid), "%02x%02x%02x%02x"
|
||||||
|
, rand() % 0xFF
|
||||||
|
, rand() % 0xFF
|
||||||
|
, rand() % 0xFF
|
||||||
|
, rand() % 0xFF
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure we have a clean session
|
||||||
|
uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION;
|
||||||
|
// Send connection request to the broker
|
||||||
|
mqtt_connect(&client, cid, NULL, NULL, 0, NULL, NULL, connect_flags, 400);
|
||||||
|
|
||||||
|
// check that we don't have any errors
|
||||||
|
if (client.error != MQTT_OK) {
|
||||||
|
PrintAndLogEx(FAILED, "error: %s", mqtt_error_str(client.error));
|
||||||
|
return mqtt_exit(PM3_ESOFT, sockfd, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// start a thread to refresh the client (handle egress and ingree client traffic)
|
||||||
|
pthread_t client_daemon;
|
||||||
|
if (pthread_create(&client_daemon, NULL, mqtt_client_refresher, &client)) {
|
||||||
|
PrintAndLogEx(FAILED, "Failed to start client daemon");
|
||||||
|
return mqtt_exit(PM3_ESOFT, sockfd, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// subscribe to a topic with a max QoS level of 0
|
||||||
|
mqtt_subscribe(&client, topic, 0);
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, _CYAN_("%s") " listening at " _CYAN_("%s:%s") " for " _YELLOW_("%s") " messages", cid, addr, port, topic);
|
||||||
|
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||||
|
|
||||||
|
while (kbd_enter_pressed() == false) {
|
||||||
|
msleep(2000);
|
||||||
|
};
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, _CYAN_("%s") " disconnecting from " _CYAN_("%s"), cid, addr);
|
||||||
|
return mqtt_exit(PM3_SUCCESS, sockfd, &client_daemon);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mqtt_send(const char *addr, const char *port, const char *topic, char *msg, const char *fn) {
|
||||||
|
|
||||||
|
uint8_t *data;
|
||||||
|
size_t bytes_read = 0;
|
||||||
|
if (fn != NULL) {
|
||||||
|
int res = loadFile_TXTsafe(fn, "", (void **)&data, &bytes_read, true);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// open the non-blocking TCP socket (connecting to the broker)
|
||||||
|
int sockfd = open_nb_socket(addr, port);
|
||||||
|
|
||||||
|
if (sockfd == -1) {
|
||||||
|
PrintAndLogEx(FAILED, "Failed to open socket");
|
||||||
|
return mqtt_exit(PM3_EFAILED, sockfd, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mqtt_client client;
|
||||||
|
uint8_t sendbuf[MQTT_BUFFER_SIZE];
|
||||||
|
uint8_t recvbuf[MQTT_BUFFER_SIZE];
|
||||||
|
mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), mqtt_publish_callback);
|
||||||
|
|
||||||
|
char cid[20] = "pm3_";
|
||||||
|
sprintf(cid + strlen(cid), "%02x%02x%02x%02x"
|
||||||
|
, rand() % 0xFF
|
||||||
|
, rand() % 0xFF
|
||||||
|
, rand() % 0xFF
|
||||||
|
, rand() % 0xFF
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure we have a clean session
|
||||||
|
uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION;
|
||||||
|
// Send connection request to the broker
|
||||||
|
mqtt_connect(&client, cid, NULL, NULL, 0, NULL, NULL, connect_flags, 400);
|
||||||
|
|
||||||
|
// check that we don't have any errors
|
||||||
|
if (client.error != MQTT_OK) {
|
||||||
|
PrintAndLogEx(FAILED, "error: %s", mqtt_error_str(client.error));
|
||||||
|
mqtt_exit(PM3_EFAILED, sockfd, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// start a thread to refresh the client (handle egress and ingree client traffic)
|
||||||
|
pthread_t client_daemon;
|
||||||
|
if (pthread_create(&client_daemon, NULL, mqtt_client_refresher, &client)) {
|
||||||
|
PrintAndLogEx(FAILED, "Failed to start client daemon");
|
||||||
|
mqtt_exit(PM3_EFAILED, sockfd, NULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, _CYAN_("%s") " is ready", cid);
|
||||||
|
|
||||||
|
if (fn != NULL) {
|
||||||
|
PrintAndLogEx(INFO, "Publishing file...");
|
||||||
|
mqtt_publish(&client, topic, data, bytes_read, MQTT_PUBLISH_QOS_0);
|
||||||
|
} else {
|
||||||
|
PrintAndLogEx(INFO, "Publishing message...");
|
||||||
|
mqtt_publish(&client, topic, msg, strlen(msg) + 1, MQTT_PUBLISH_QOS_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (client.error != MQTT_OK) {
|
||||||
|
PrintAndLogEx(INFO, "error: %s", mqtt_error_str(client.error));
|
||||||
|
mqtt_exit(PM3_ESOFT, sockfd, &client_daemon);
|
||||||
|
}
|
||||||
|
|
||||||
|
msleep(4000);
|
||||||
|
|
||||||
|
PrintAndLogEx(INFO, _CYAN_("%s") " disconnecting from " _CYAN_("%s"), cid, addr);
|
||||||
|
return mqtt_exit(PM3_SUCCESS, sockfd, &client_daemon);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdMqttSend(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "mqtt send",
|
||||||
|
"This command send MQTT messages. You can send JSON file\n"
|
||||||
|
"Default server: proxdump.com:1883 topic: proxdump\n",
|
||||||
|
"mqtt send --msg \"Hello from Pm3\" --> sending msg to default server/port/topic\n"
|
||||||
|
"mqtt send -f myfile.json --> sending file to default server/port/topic\n"
|
||||||
|
"mqtt send --addr test.mosquitto.org -p 1883 --topic pm3 --msg \"custom mqtt server \"\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str0(NULL, "addr", "<str>", "MQTT server address"),
|
||||||
|
arg_str0("p", "port", "<str>", "MQTT server port"),
|
||||||
|
arg_str0(NULL, "topic", "<str>", "MQTT topic"),
|
||||||
|
arg_str0(NULL, "msg", "<str>", "Message to send over MQTT"),
|
||||||
|
arg_str0("f", "file", "<fn>", "file to send"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
|
int alen = 0;
|
||||||
|
char addr[256] = {0x00};
|
||||||
|
int res = CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)addr, sizeof(addr), &alen);
|
||||||
|
|
||||||
|
int plen = 0;
|
||||||
|
char port[10 + 1] = {0x00};
|
||||||
|
res = CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)port, sizeof(port), &plen);
|
||||||
|
|
||||||
|
int tlen = 0;
|
||||||
|
char topic[128] = {0x00};
|
||||||
|
res = CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)topic, sizeof(topic), &tlen);
|
||||||
|
|
||||||
|
int mlen = 0;
|
||||||
|
char msg[128] = {0x00};
|
||||||
|
res = CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t *)msg, sizeof(msg), &mlen);
|
||||||
|
|
||||||
|
int fnlen = 0;
|
||||||
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
|
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
|
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
// Error message if... an error occured.
|
||||||
|
if (res) {
|
||||||
|
PrintAndLogEx(FAILED, "Error parsing input strings");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alen == 0) {
|
||||||
|
strcpy(addr, "proxdump.com");
|
||||||
|
}
|
||||||
|
if (plen == 0) {
|
||||||
|
strcpy(port, "1883");
|
||||||
|
}
|
||||||
|
if (tlen == 0) {
|
||||||
|
strcpy(topic, "proxdump");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fnlen) {
|
||||||
|
return mqtt_send(addr, port, topic, NULL, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mlen) {
|
||||||
|
return mqtt_send(addr, port, topic, msg, NULL);
|
||||||
|
}
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdMqttReceive(const char *Cmd) {
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(&ctx, "mqtt receive",
|
||||||
|
"This command receives MQTT messages. JSON text will be saved to file if detected\n"
|
||||||
|
"Default server: proxdump.com:1883 topic: proxdump\n",
|
||||||
|
"mqtt receive --> listening to default server/port/topic\n"
|
||||||
|
"mqtt receive --addr test.mosquitto.org -p 1883 --topic pm3\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str0(NULL, "addr", "<str>", "MQTT server address"),
|
||||||
|
arg_str0("p", "port", "<str>", "MQTT server port"),
|
||||||
|
arg_str0(NULL, "topic", "<str>", "MQTT topic"),
|
||||||
|
arg_str0("f", "file", "<fn>", "file name to use for received files"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
|
int alen = 0;
|
||||||
|
char addr[256] = {0x00};
|
||||||
|
int res = CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)addr, sizeof(addr), &alen);
|
||||||
|
|
||||||
|
int plen = 0;
|
||||||
|
char port[10 + 1] = {0x00};
|
||||||
|
res = CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)port, sizeof(port), &plen);
|
||||||
|
|
||||||
|
int tlen = 0;
|
||||||
|
char topic[128] = {0x00};
|
||||||
|
res = CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)topic, sizeof(topic), &tlen);
|
||||||
|
|
||||||
|
int fnlen = 0;
|
||||||
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
|
CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
|
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
// Error message if... an error occured.
|
||||||
|
if (res) {
|
||||||
|
PrintAndLogEx(FAILED, "Error parsing input strings");
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alen == 0) {
|
||||||
|
strcpy(addr, "proxdump.com");
|
||||||
|
}
|
||||||
|
if (plen == 0) {
|
||||||
|
strcpy(port, "1883");
|
||||||
|
}
|
||||||
|
if (tlen == 0) {
|
||||||
|
strcpy(topic, "proxdump");
|
||||||
|
}
|
||||||
|
|
||||||
|
return mqtt_receive(addr, port, topic, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
static command_t CommandTable[] = {
|
||||||
|
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||||
|
{"send", CmdMqttSend, AlwaysAvailable, "Send messages or json file over MQTT"},
|
||||||
|
{"receive", CmdMqttReceive, AlwaysAvailable, "Receive message or json file over MQTT"},
|
||||||
|
{NULL, NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int CmdHelp(const char *Cmd) {
|
||||||
|
(void)Cmd; // Cmd is not used so far
|
||||||
|
CmdsHelp(CommandTable);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CmdMqtt(const char *Cmd) {
|
||||||
|
clearCommandBuffer();
|
||||||
|
return CmdsParse(CommandTable, Cmd);
|
||||||
|
}
|
26
client/src/cmdmqtt.h
Normal file
26
client/src/cmdmqtt.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// See LICENSE.txt for the text of the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// MQTT commands
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef CMDMQTT_H__
|
||||||
|
#define CMDMQTT_H__
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
int CmdMqtt(const char *Cmd);
|
||||||
|
|
||||||
|
#endif
|
|
@ -278,7 +278,7 @@ int saveFileEx(const char *preferredName, const char *suffix, const void *data,
|
||||||
|
|
||||||
// Opening file for writing in binary mode
|
// Opening file for writing in binary mode
|
||||||
FILE *f = fopen(fileName, "wb");
|
FILE *f = fopen(fileName, "wb");
|
||||||
if (!f) {
|
if (f == NULL) {
|
||||||
PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", fileName);
|
PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", fileName);
|
||||||
free(fileName);
|
free(fileName);
|
||||||
return PM3_EFILE;
|
return PM3_EFILE;
|
||||||
|
@ -291,6 +291,33 @@ int saveFileEx(const char *preferredName, const char *suffix, const void *data,
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int saveFileTXT(const char *preferredName, const char *suffix, const void *data, size_t datalen, savePaths_t e_save_path) {
|
||||||
|
if (data == NULL || datalen == 0) {
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *fileName = newfilenamemcopyEx(preferredName, suffix, e_save_path);
|
||||||
|
if (fileName == NULL) {
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should have a valid filename now, e.g. dumpdata-3.txt
|
||||||
|
|
||||||
|
// Opening file for writing in text mode
|
||||||
|
FILE *f = fopen(fileName, "w");
|
||||||
|
if (f == NULL) {
|
||||||
|
PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", fileName);
|
||||||
|
free(fileName);
|
||||||
|
return PM3_EFILE;
|
||||||
|
}
|
||||||
|
fwrite(data, 1, datalen, f);
|
||||||
|
fflush(f);
|
||||||
|
fclose(f);
|
||||||
|
PrintAndLogEx(SUCCESS, "Saved " _YELLOW_("%zu") " bytes to text file `" _YELLOW_("%s") "`", datalen, fileName);
|
||||||
|
free(fileName);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
int prepareJSON(json_t *root, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *)) {
|
int prepareJSON(json_t *root, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *)) {
|
||||||
if (ftype != jsfCustom) {
|
if (ftype != jsfCustom) {
|
||||||
if (data == NULL || datalen == 0) {
|
if (data == NULL || datalen == 0) {
|
||||||
|
@ -794,8 +821,9 @@ int saveFileJSONroot(const char *preferredName, void *root, size_t flags, bool v
|
||||||
}
|
}
|
||||||
|
|
||||||
int saveFileJSONrootEx(const char *preferredName, const void *root, size_t flags, bool verbose, bool overwrite, savePaths_t e_save_path) {
|
int saveFileJSONrootEx(const char *preferredName, const void *root, size_t flags, bool verbose, bool overwrite, savePaths_t e_save_path) {
|
||||||
if (root == NULL)
|
if (root == NULL) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
char *filename = NULL;
|
char *filename = NULL;
|
||||||
if (overwrite)
|
if (overwrite)
|
||||||
|
@ -975,7 +1003,7 @@ int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata,
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *f = fopen(path, "rb");
|
FILE *f = fopen(path, "rb");
|
||||||
if (!f) {
|
if (f == NULL) {
|
||||||
PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path);
|
PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path);
|
||||||
free(path);
|
free(path);
|
||||||
return PM3_EFILE;
|
return PM3_EFILE;
|
||||||
|
@ -1018,6 +1046,58 @@ int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata,
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int loadFile_TXTsafe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen, bool verbose) {
|
||||||
|
|
||||||
|
char *path;
|
||||||
|
int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, suffix, false);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
return PM3_EFILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *f = fopen(path, "r");
|
||||||
|
if (f == NULL) {
|
||||||
|
PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path);
|
||||||
|
free(path);
|
||||||
|
return PM3_EFILE;
|
||||||
|
}
|
||||||
|
free(path);
|
||||||
|
|
||||||
|
// get filesize in order to malloc memory
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
long fsize = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
|
||||||
|
if (fsize <= 0) {
|
||||||
|
PrintAndLogEx(FAILED, "error, when getting filesize");
|
||||||
|
fclose(f);
|
||||||
|
return PM3_EFILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pdata = calloc(fsize, sizeof(uint8_t));
|
||||||
|
if (*pdata == NULL) {
|
||||||
|
PrintAndLogEx(WARNING, "Failed to allocate memory");
|
||||||
|
fclose(f);
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bytes_read = fread(*pdata, 1, fsize, f);
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
if (bytes_read != fsize) {
|
||||||
|
PrintAndLogEx(FAILED, "error, bytes read mismatch file size");
|
||||||
|
free(*pdata);
|
||||||
|
return PM3_EFILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*datalen = bytes_read;
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
PrintAndLogEx(SUCCESS, "Loaded " _YELLOW_("%zu") " bytes from text file `" _YELLOW_("%s") "`", bytes_read, preferredName);
|
||||||
|
}
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) {
|
int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) {
|
||||||
char *path;
|
char *path;
|
||||||
int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, "", false);
|
int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, "", false);
|
||||||
|
@ -1121,7 +1201,7 @@ int loadFileNFC_safe(const char *preferredName, void *data, size_t maxdatalen, s
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *f = fopen(path, "r");
|
FILE *f = fopen(path, "r");
|
||||||
if (!f) {
|
if (f == NULL) {
|
||||||
PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path);
|
PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path);
|
||||||
free(path);
|
free(path);
|
||||||
return PM3_EFILE;
|
return PM3_EFILE;
|
||||||
|
@ -1446,7 +1526,9 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_
|
||||||
}
|
}
|
||||||
int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, bool verbose, void (*callback)(json_t *)) {
|
int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, bool verbose, void (*callback)(json_t *)) {
|
||||||
|
|
||||||
if (data == NULL) return PM3_EINVARG;
|
if (data == NULL) {
|
||||||
|
return PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
*datalen = 0;
|
*datalen = 0;
|
||||||
int retval = PM3_SUCCESS;
|
int retval = PM3_SUCCESS;
|
||||||
|
@ -2629,6 +2711,10 @@ int detect_nfc_dump_format(const char *preferredName, nfc_df_e *dump_type, bool
|
||||||
*dump_type = NFC_DF_14_4A;
|
*dump_type = NFC_DF_14_4A;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (str_startswith(line, "device type: iso15693")) {
|
||||||
|
*dump_type = NFC_DF_15;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (str_startswith(line, "filetype: flipper picopass device")) {
|
if (str_startswith(line, "filetype: flipper picopass device")) {
|
||||||
*dump_type = NFC_DF_PICOPASS;
|
*dump_type = NFC_DF_PICOPASS;
|
||||||
break;
|
break;
|
||||||
|
@ -2661,6 +2747,8 @@ int detect_nfc_dump_format(const char *preferredName, nfc_df_e *dump_type, bool
|
||||||
case NFC_DF_PICOPASS:
|
case NFC_DF_PICOPASS:
|
||||||
PrintAndLogEx(INFO, "Detected PICOPASS based dump format");
|
PrintAndLogEx(INFO, "Detected PICOPASS based dump format");
|
||||||
break;
|
break;
|
||||||
|
case NFC_DF_15:
|
||||||
|
PrintAndLogEx(INFO, "Detected ISO15693 based dump format");
|
||||||
case NFC_DF_UNKNOWN:
|
case NFC_DF_UNKNOWN:
|
||||||
PrintAndLogEx(WARNING, "Failed to detected dump format");
|
PrintAndLogEx(WARNING, "Failed to detected dump format");
|
||||||
break;
|
break;
|
||||||
|
@ -3210,7 +3298,7 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dumptype == NFC_DF_MFC || dumptype == NFC_DF_MFU || dumptype == NFC_DF_PICOPASS) {
|
if (dumptype == NFC_DF_MFC || dumptype == NFC_DF_MFU || dumptype == NFC_DF_PICOPASS || dumptype == NFC_DF_15) {
|
||||||
|
|
||||||
*pdump = calloc(maxdumplen, sizeof(uint8_t));
|
*pdump = calloc(maxdumplen, sizeof(uint8_t));
|
||||||
if (*pdump == NULL) {
|
if (*pdump == NULL) {
|
||||||
|
@ -3247,6 +3335,7 @@ int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft) {
|
||||||
PrintAndLogEx(INFO, "No data to save, skipping...");
|
PrintAndLogEx(INFO, "No data to save, skipping...");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveFile(fn, ".bin", d, n);
|
saveFile(fn, ".bin", d, n);
|
||||||
saveFileJSON(fn, jsft, d, n, NULL);
|
saveFileJSON(fn, jsft, d, n, NULL);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
|
|
|
@ -100,9 +100,16 @@ typedef enum {
|
||||||
NFC_DF_14_3A,
|
NFC_DF_14_3A,
|
||||||
NFC_DF_14_3B,
|
NFC_DF_14_3B,
|
||||||
NFC_DF_14_4A,
|
NFC_DF_14_4A,
|
||||||
|
NFC_DF_15,
|
||||||
NFC_DF_PICOPASS,
|
NFC_DF_PICOPASS,
|
||||||
} nfc_df_e;
|
} nfc_df_e;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ISO15_DF_UNKNOWN,
|
||||||
|
ISO15_DF_V4_BIN,
|
||||||
|
ISO15_DF_V5_BIN
|
||||||
|
} iso15_df_e;
|
||||||
|
|
||||||
int fileExists(const char *filename);
|
int fileExists(const char *filename);
|
||||||
|
|
||||||
// set a path in the path list g_session.defaultPaths
|
// set a path in the path list g_session.defaultPaths
|
||||||
|
@ -116,7 +123,7 @@ void truncate_filename(char *fn, uint16_t maxlen);
|
||||||
/**
|
/**
|
||||||
* @brief Utility function to save data to a binary file. This method takes a preferred name, but if that
|
* @brief Utility function to save data to a binary file. This method takes a preferred name, but if that
|
||||||
* file already exists, it tries with another name until it finds something suitable.
|
* file already exists, it tries with another name until it finds something suitable.
|
||||||
* E.g. dumpdata-15.txt
|
* E.g. dumpdata-15.bin
|
||||||
*
|
*
|
||||||
* @param preferredName
|
* @param preferredName
|
||||||
* @param suffix the file suffix. Including the ".".
|
* @param suffix the file suffix. Including the ".".
|
||||||
|
@ -127,6 +134,19 @@ void truncate_filename(char *fn, uint16_t maxlen);
|
||||||
int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen);
|
int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen);
|
||||||
int saveFileEx(const char *preferredName, const char *suffix, const void *data, size_t datalen, savePaths_t e_save_path);
|
int saveFileEx(const char *preferredName, const char *suffix, const void *data, size_t datalen, savePaths_t e_save_path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Utility function to save data to a text file. This method takes a preferred name, but if that
|
||||||
|
* file already exists, it tries with another name until it finds something suitable.
|
||||||
|
* E.g. dumpdata-15.txt
|
||||||
|
*
|
||||||
|
* @param preferredName
|
||||||
|
* @param suffix the file suffix. Including the ".".
|
||||||
|
* @param data The binary data to write to the file
|
||||||
|
* @param datalen the length of the data
|
||||||
|
* @return 0 for ok, 1 for failz
|
||||||
|
*/
|
||||||
|
int saveFileTXT(const char *preferredName, const char *suffix, const void *data, size_t datalen, savePaths_t e_save_path);
|
||||||
|
|
||||||
/** STUB
|
/** STUB
|
||||||
* @brief Utility function to save JSON data to a file. This method takes a preferred name, but if that
|
* @brief Utility function to save JSON data to a file. This method takes a preferred name, but if that
|
||||||
* file already exists, it tries with another name until it finds something suitable.
|
* file already exists, it tries with another name until it finds something suitable.
|
||||||
|
@ -190,6 +210,19 @@ int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, const sector
|
||||||
*/
|
*/
|
||||||
int loadFile_safe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen);
|
int loadFile_safe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen);
|
||||||
int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata, size_t *datalen, bool verbose);
|
int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata, size_t *datalen, bool verbose);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Utility function to load a text file. This method takes a preferred name.
|
||||||
|
* E.g. dumpdata-15.json, tries to search for it, and allocated memory.
|
||||||
|
*
|
||||||
|
* @param preferredName
|
||||||
|
* @param suffix the file suffix. Including the ".".
|
||||||
|
* @param data The data array to store the loaded bytes from file
|
||||||
|
* @param datalen the number of bytes loaded from file
|
||||||
|
* @return PM3_SUCCESS for ok, PM3_E* for failz
|
||||||
|
*/
|
||||||
|
int loadFile_TXTsafe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen, bool verbose);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Utility function to load data from a textfile (EML). This method takes a preferred name.
|
* @brief Utility function to load data from a textfile (EML). This method takes a preferred name.
|
||||||
* E.g. dumpdata-15.txt
|
* E.g. dumpdata-15.txt
|
||||||
|
|
|
@ -575,10 +575,11 @@ static int DesfireExchangeNative(bool activate_field, DesfireContext_t *ctx, uin
|
||||||
size_t sentdatalen = 0;
|
size_t sentdatalen = 0;
|
||||||
while (cdatalen >= sentdatalen) {
|
while (cdatalen >= sentdatalen) {
|
||||||
|
|
||||||
if ((cdatalen - sentdatalen) > DESFIRE_TX_FRAME_MAX_LEN)
|
if ((cdatalen - sentdatalen) > DESFIRE_TX_FRAME_MAX_LEN) {
|
||||||
len = DESFIRE_TX_FRAME_MAX_LEN;
|
len = DESFIRE_TX_FRAME_MAX_LEN;
|
||||||
else
|
} else {
|
||||||
len = cdatalen - sentdatalen;
|
len = cdatalen - sentdatalen;
|
||||||
|
}
|
||||||
|
|
||||||
size_t sendindx = sentdatalen;
|
size_t sendindx = sentdatalen;
|
||||||
size_t sendlen = len;
|
size_t sendlen = len;
|
||||||
|
@ -657,9 +658,10 @@ static int DesfireExchangeNative(bool activate_field, DesfireContext_t *ctx, uin
|
||||||
}
|
}
|
||||||
pos += buflen;
|
pos += buflen;
|
||||||
|
|
||||||
if (rcode != MFDES_ADDITIONAL_FRAME)
|
if (rcode != MFDES_ADDITIONAL_FRAME) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (resplen) {
|
if (resplen) {
|
||||||
*resplen = (splitbysize) ? i : pos;
|
*resplen = (splitbysize) ? i : pos;
|
||||||
|
@ -969,12 +971,14 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext_t *ctx, uint32_t aid) {
|
||||||
ctx->secureChannel = DACNone;
|
ctx->secureChannel = DACNone;
|
||||||
int res = DesfireExchangeEx(false, ctx, MFDES_SELECT_APPLICATION, data, 3, &respcode, resp, &resplen, true, 0);
|
int res = DesfireExchangeEx(false, ctx, MFDES_SELECT_APPLICATION, data, 3, &respcode, resp, &resplen, true, 0);
|
||||||
if (res == PM3_SUCCESS) {
|
if (res == PM3_SUCCESS) {
|
||||||
if (resplen != 0)
|
if (resplen != 0) {
|
||||||
return PM3_ECARDEXCHANGE;
|
return PM3_ECARDEXCHANGE;
|
||||||
|
}
|
||||||
|
|
||||||
// select operation fail
|
// select operation fail
|
||||||
if (respcode != MFDES_S_OPERATION_OK)
|
if (respcode != MFDES_S_OPERATION_OK) {
|
||||||
return PM3_EAPDU_FAIL;
|
return PM3_EAPDU_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
DesfireClearSession(ctx);
|
DesfireClearSession(ctx);
|
||||||
ctx->appSelected = (aid != 0x000000);
|
ctx->appSelected = (aid != 0x000000);
|
||||||
|
|
|
@ -832,6 +832,9 @@ const static vocabulary_t vocabulary[] = {
|
||||||
{ 0, "mem spiffs upload" },
|
{ 0, "mem spiffs upload" },
|
||||||
{ 0, "mem spiffs view" },
|
{ 0, "mem spiffs view" },
|
||||||
{ 0, "mem spiffs wipe" },
|
{ 0, "mem spiffs wipe" },
|
||||||
|
{ 1, "mqtt help" },
|
||||||
|
{ 1, "mqtt send" },
|
||||||
|
{ 1, "mqtt receive" },
|
||||||
{ 1, "nfc help" },
|
{ 1, "nfc help" },
|
||||||
{ 1, "nfc decode" },
|
{ 1, "nfc decode" },
|
||||||
{ 0, "nfc type1 read" },
|
{ 0, "nfc type1 read" },
|
||||||
|
|
|
@ -17,14 +17,12 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#include "proxmark3.h"
|
#include "proxmark3.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <libgen.h> // basename
|
#include <libgen.h> // basename
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include "pm3line.h"
|
#include "pm3line.h"
|
||||||
#include "usart_defs.h"
|
#include "usart_defs.h"
|
||||||
#include "util_posix.h"
|
#include "util_posix.h"
|
||||||
|
@ -43,7 +41,6 @@
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static int mainret = PM3_SUCCESS;
|
static int mainret = PM3_SUCCESS;
|
||||||
|
|
||||||
#ifndef LIBPM3
|
#ifndef LIBPM3
|
||||||
|
@ -209,7 +206,6 @@ static void showBanner(void) {
|
||||||
|
|
||||||
PrintAndLogEx(NORMAL, " [ " _YELLOW_("%s!")" :coffee: ]", get_quote());
|
PrintAndLogEx(NORMAL, " [ " _YELLOW_("%s!")" :coffee: ]", get_quote());
|
||||||
// PrintAndLogEx(NORMAL, " [ https://patreon.com/iceman1001/ ]");
|
// PrintAndLogEx(NORMAL, " [ https://patreon.com/iceman1001/ ]");
|
||||||
// PrintAndLogEx(NORMAL, "");
|
|
||||||
// PrintAndLogEx(NORMAL, " Monero");
|
// PrintAndLogEx(NORMAL, " Monero");
|
||||||
// PrintAndLogEx(NORMAL, " 43mNJLpgBVaTvyZmX9ajcohpvVkaRy1kbZPm8tqAb7itZgfuYecgkRF36rXrKFUkwEGeZedPsASRxgv4HPBHvJwyJdyvQuP");
|
// PrintAndLogEx(NORMAL, " 43mNJLpgBVaTvyZmX9ajcohpvVkaRy1kbZPm8tqAb7itZgfuYecgkRF36rXrKFUkwEGeZedPsASRxgv4HPBHvJwyJdyvQuP");
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
|
|
@ -75,6 +75,7 @@ typedef struct {
|
||||||
|
|
||||||
|
|
||||||
int calculate_hours_between_dates(const Date_t s, Date_t *e);
|
int calculate_hours_between_dates(const Date_t s, Date_t *e);
|
||||||
|
void add_minutes(Date_t *d, int minutes_to_add);
|
||||||
void add_hours(Date_t *d, int hours_to_add);
|
void add_hours(Date_t *d, int hours_to_add);
|
||||||
void add_days(Date_t *d, int days_to_add);
|
void add_days(Date_t *d, int days_to_add);
|
||||||
uint8_t days_in_month(int year, int month);
|
uint8_t days_in_month(int year, int month);
|
||||||
|
|
|
@ -29,7 +29,7 @@ typedef struct {
|
||||||
enum {
|
enum {
|
||||||
TAG_STATE_RESET = 0x01, // Just powered up, awaiting GetSnr
|
TAG_STATE_RESET = 0x01, // Just powered up, awaiting GetSnr
|
||||||
TAG_STATE_ACTIVATING = 0x02, // In activation phase (password mode), sent UID, awaiting reader password
|
TAG_STATE_ACTIVATING = 0x02, // In activation phase (password mode), sent UID, awaiting reader password
|
||||||
TAG_STATE_ACTIVATED = 0x03, // Activation complete, awaiting read/write commands
|
// TAG_STATE_ACTIVATED = 0x03, // Activation complete, awaiting read/write commands
|
||||||
TAG_STATE_WRITING = 0x04, // In write command, awaiting sector contents to be written
|
TAG_STATE_WRITING = 0x04, // In write command, awaiting sector contents to be written
|
||||||
} state;
|
} state;
|
||||||
uint16_t active_sector;
|
uint16_t active_sector;
|
||||||
|
|
|
@ -1136,7 +1136,7 @@
|
||||||
},
|
},
|
||||||
"help": {
|
"help": {
|
||||||
"command": "help",
|
"command": "help",
|
||||||
"description": "help Use `<command> help` for details of a command prefs { Edit client/device preferences... } -------- ----------------------- Technology ----------------------- analyse { Analyse utils... } data { Plot window / data buffer manipulation... } emv { EMV ISO-14443 / ISO-7816... } hf { High frequency commands... } hw { Hardware commands... } lf { Low frequency commands... } nfc { NFC commands... } piv { PIV commands... } reveng { CRC calculations from RevEng software... } smart { Smart card ISO-7816 commands... } script { Scripting commands... } trace { Trace manipulation... } wiegand { Wiegand format manipulation... } -------- ----------------------- General ----------------------- clear Clear screen hints Turn hints on / off msleep Add a pause in milliseconds rem Add a text line in log file quit exit Exit program --------------------------------------------------------------------------------------- auto available offline: no Run LF SEARCH / HF SEARCH / DATA PLOT / DATA SAVE",
|
"description": "help Use `<command> help` for details of a command prefs { Edit client/device preferences... } -------- ----------------------- Technology ----------------------- analyse { Analyse utils... } data { Plot window / data buffer manipulation... } emv { EMV ISO-14443 / ISO-7816... } hf { High frequency commands... } hw { Hardware commands... } lf { Low frequency commands... } mqtt { MQTT commmands... } nfc { NFC commands... } piv { PIV commands... } reveng { CRC calculations from RevEng software... } smart { Smart card ISO-7816 commands... } script { Scripting commands... } trace { Trace manipulation... } wiegand { Wiegand format manipulation... } -------- ----------------------- General ----------------------- clear Clear screen hints Turn hints on / off msleep Add a pause in milliseconds rem Add a text line in log file quit exit Exit program --------------------------------------------------------------------------------------- auto available offline: no Run LF SEARCH / HF SEARCH / DATA PLOT / DATA SAVE",
|
||||||
"notes": [
|
"notes": [
|
||||||
"auto"
|
"auto"
|
||||||
],
|
],
|
||||||
|
@ -12331,6 +12331,42 @@
|
||||||
],
|
],
|
||||||
"usage": "mem wipe [-h] [-p <dec>]"
|
"usage": "mem wipe [-h] [-p <dec>]"
|
||||||
},
|
},
|
||||||
|
"mqtt help": {
|
||||||
|
"command": "mqtt help",
|
||||||
|
"description": "help This help send Send messages or json file over MQTT receive Receive message or json file over MQTT --------------------------------------------------------------------------------------- mqtt send available offline: yes This command send MQTT messages. You can send JSON file Default server: proxdump.com:1883 topic: proxdump",
|
||||||
|
"notes": [
|
||||||
|
"mqtt send --msg \"Hello from Pm3\" -> sending msg to default server/port/topic",
|
||||||
|
"mqtt send -f myfile.json -> sending file to default server/port/topic",
|
||||||
|
"mqtt send --addr test.mosquitto.org -p 1883 --topic pm3 --msg \"custom mqtt server \""
|
||||||
|
],
|
||||||
|
"offline": true,
|
||||||
|
"options": [
|
||||||
|
"-h, --help This help",
|
||||||
|
"--addr <str> MQTT server address",
|
||||||
|
"-p, --port <str> MQTT server port",
|
||||||
|
"--topic <str> MQTT topic",
|
||||||
|
"--msg <str> Message to send over MQTT",
|
||||||
|
"-f, --file <fn> file to send"
|
||||||
|
],
|
||||||
|
"usage": "mqtt send [-h] [--addr <str>] [-p <str>] [--topic <str>] [--msg <str>] [-f <fn>]"
|
||||||
|
},
|
||||||
|
"mqtt receive": {
|
||||||
|
"command": "mqtt receive",
|
||||||
|
"description": "This command receives MQTT messages. JSON text will be saved to file if detected Default server: proxdump.com:1883 topic: proxdump",
|
||||||
|
"notes": [
|
||||||
|
"mqtt receive -> listening to default server/port/topic",
|
||||||
|
"mqtt receive --addr test.mosquitto.org -p 1883 --topic pm3"
|
||||||
|
],
|
||||||
|
"offline": true,
|
||||||
|
"options": [
|
||||||
|
"-h, --help This help",
|
||||||
|
"--addr <str> MQTT server address",
|
||||||
|
"-p, --port <str> MQTT server port",
|
||||||
|
"--topic <str> MQTT topic",
|
||||||
|
"-f, --file <fn> file to send"
|
||||||
|
],
|
||||||
|
"usage": "mqtt receive [-h] [--addr <str>] [-p <str>] [--topic <str>] [-f <fn>]"
|
||||||
|
},
|
||||||
"msleep": {
|
"msleep": {
|
||||||
"command": "msleep",
|
"command": "msleep",
|
||||||
"description": "Sleep for given amount of milliseconds",
|
"description": "Sleep for given amount of milliseconds",
|
||||||
|
@ -13375,8 +13411,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"commands_extracted": 768,
|
"commands_extracted": 770,
|
||||||
"extracted_by": "PM3Help2JSON v1.00",
|
"extracted_by": "PM3Help2JSON v1.00",
|
||||||
"extracted_on": "2025-07-06T18:10:18"
|
"extracted_on": "2025-07-08T19:08:23"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1414,6 +1414,17 @@ Check column "offline" for their availability.
|
||||||
|`mem spiffs wipe `|N |`Wipe all files from SPIFFS file system * dangerous *`
|
|`mem spiffs wipe `|N |`Wipe all files from SPIFFS file system * dangerous *`
|
||||||
|
|
||||||
|
|
||||||
|
### mqtt
|
||||||
|
|
||||||
|
{ MQTT commmands... }
|
||||||
|
|
||||||
|
|command |offline |description
|
||||||
|
|------- |------- |-----------
|
||||||
|
|`mqtt help `|Y |`This help`
|
||||||
|
|`mqtt send `|Y |`Send messages or json file over MQTT`
|
||||||
|
|`mqtt receive `|Y |`Receive message or json file over MQTT`
|
||||||
|
|
||||||
|
|
||||||
### nfc
|
### nfc
|
||||||
|
|
||||||
{ NFC commands... }
|
{ NFC commands... }
|
||||||
|
|
|
@ -24,7 +24,8 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// iCLASS / PICOPASS
|
// iCLASS / PICOPASS
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
#define PICOPASS_BLOCK_SIZE 8
|
#define PICOPASS_BLOCK_SIZE ( 8 )
|
||||||
|
#define PICOPASS_MAX_BYTES ( 4096 ) // # 32k bits = 4096 bytes
|
||||||
|
|
||||||
// iCLASS reader flags
|
// iCLASS reader flags
|
||||||
#define FLAG_ICLASS_READER_INIT 0x01
|
#define FLAG_ICLASS_READER_INIT 0x01
|
||||||
|
@ -197,5 +198,12 @@ typedef struct {
|
||||||
} header;
|
} header;
|
||||||
} PACKED iclass_card_select_resp_t;
|
} PACKED iclass_card_select_resp_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
union {
|
||||||
|
picopass_hdr_t hdr;
|
||||||
|
picopass_ns_hdr_t ns_hdr;
|
||||||
|
} header;
|
||||||
|
uint8_t data[PICOPASS_MAX_BYTES];
|
||||||
|
} PACKED iclass_tag_t;
|
||||||
|
|
||||||
#endif // _ICLASS_H_
|
#endif // _ICLASS_H_
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue