diff --git a/client/Makefile b/client/Makefile index 51a957c30..308fe2de9 100644 --- a/client/Makefile +++ b/client/Makefile @@ -831,6 +831,8 @@ SRCS = mifare/aiddesfire.c \ pm3line.c \ proxmark3.c \ scandir.c \ + relay/relay_posix.c \ + relay/relay_win32.c \ uart/ringbuffer.c \ uart/uart_common.c \ uart/uart_posix.c \ diff --git a/client/src/cmdlf.c b/client/src/cmdlf.c index e8499863a..c21a56318 100644 --- a/client/src/cmdlf.c +++ b/client/src/cmdlf.c @@ -24,17 +24,7 @@ #include #include -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#else -#include -#include -#include -#include -#endif +#include "relay/relay.h" #include "cmdparser.h" // command_t #include "comms.h" @@ -1722,33 +1712,9 @@ static int check_autocorrelate(const char *prefix, int clock) { static int lf_relay_tag(uint64_t samples, uint16_t port) { - int sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { - PrintAndLogEx(ERR, "Failed to create socket"); - return PM3_EFAILED; - } - - struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(port), .sin_addr.s_addr = INADDR_ANY }; - int opt = 1; - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); - if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - PrintAndLogEx(ERR, "Failed to bind to port " _RED_("%u"), port); - close(sock); - return PM3_EFAILED; - } - - if (listen(sock, 1) < 0) { - PrintAndLogEx(ERR, "Failed to listen on socket"); - close(sock); - return PM3_EFAILED; - } - - PrintAndLogEx(INFO, "Relay listening on port " _YELLOW_("%u") "...", port); - - int client = accept(sock, NULL, NULL); - if (client < 0) { - PrintAndLogEx(ERR, "Failed to accept connection"); - close(sock); + relay_socket_t listen_sock = RELAY_SOCKET_INVALID; + relay_socket_t client = relay_listen_accept(port, &listen_sock); + if (client == RELAY_SOCKET_INVALID) { return PM3_EFAILED; } @@ -1763,49 +1729,32 @@ static int lf_relay_tag(uint64_t samples, uint16_t port) { lf_read_internal(false, false, samples); - if (g_GraphTraceLen > 1000 && !getSignalProperties()->isnoise) { + if ((g_GraphTraceLen > 1000) && (getSignalProperties()->isnoise == false)) { PrintAndLogEx(INFO, "Tag detected! Sending %zu samples to Client...", g_GraphTraceLen); - + uint32_t len = (uint32_t)g_GraphTraceLen; - if (send(client, &len, sizeof(len), 0) < 0) { + if (relay_send_all(client, &len, sizeof(len)) != 0) { break; } - - if (send(client, g_GraphBuffer, len * sizeof(int32_t), 0) < 0) { + + if (relay_send_all(client, g_GraphBuffer, len * sizeof(int32_t)) != 0) { break; } msleep(500); } - } - close(client); - close(sock); + + relay_close(client); + relay_close(listen_sock); return PM3_SUCCESS; } static int lf_relay_rdr(const char *ip, uint16_t port) { - int sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { - PrintAndLogEx(ERR, "Failed to create socket"); - return PM3_EFAILED; - } - - struct sockaddr_in addr = {0}; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - - if (inet_pton(AF_INET, ip, &addr.sin_addr) <= 0) { - PrintAndLogEx(ERR, "Invalid IP address... %s:%u", ip, port); - close(sock); - return PM3_EFAILED; - } - - if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - PrintAndLogEx(ERR, "Connection error to %s:%u", ip, port); - close(sock); + relay_socket_t sock = relay_connect(ip, port); + if (sock == RELAY_SOCKET_INVALID) { return PM3_EFAILED; } @@ -1814,9 +1763,9 @@ static int lf_relay_rdr(const char *ip, uint16_t port) { PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); PrintAndLogEx(NORMAL, ""); - int n = 0; - do { - + bool running = true; + while (running) { + if (kbd_enter_pressed()) { SendCommandNG(CMD_BREAK_LOOP, NULL, 0); PrintAndLogEx(DEBUG, "\naborted via keyboard!"); @@ -1825,48 +1774,50 @@ static int lf_relay_rdr(const char *ip, uint16_t port) { } uint32_t incoming_len = 0; - - n = recv(sock, &incoming_len, sizeof(incoming_len), MSG_WAITALL); - - if (n > 0 && incoming_len > 0) { - - if (incoming_len > MAX_GRAPH_TRACE_LEN) { - PrintAndLogEx(ERR, "Received length " _RED_("%u") " exceeds buffer size %u, dropping", incoming_len, MAX_GRAPH_TRACE_LEN); - break; - } - - PrintAndLogEx(INFO, "Received " _YELLOW_("%u") " samples. Processing...", incoming_len); - ssize_t rx = recv(sock, g_GraphBuffer, incoming_len * sizeof(int32_t), MSG_WAITALL); - - if (rx != (ssize_t)(incoming_len * sizeof(int32_t))) { - PrintAndLogEx(ERR, "Short read: expected %u bytes, got %zd", incoming_len * (uint32_t)sizeof(int32_t), rx); - break; - } - - // if previous simulation running, we need to break it. - SendCommandNG(CMD_BREAK_LOOP, NULL, 0); - msleep(300); - - g_GraphTraceLen = incoming_len; - lf_chk_bitstream(); - lfsim_upload_gb(); - struct { - uint16_t len; - uint16_t gap; - } PACKED payload; - payload.len = (g_GraphTraceLen > UINT16_MAX) ? UINT16_MAX : (uint16_t)g_GraphTraceLen; - payload.gap = 0; - - clearCommandBuffer(); - SendCommandNG(CMD_LF_SIMULATE, (uint8_t *)&payload, sizeof(payload)); - - PrintAndLogEx(SUCCESS, "Simulation active."); + int n = relay_recv_all(sock, &incoming_len, sizeof(incoming_len)); + if (n < 0) { + break; } - } while (n > 0); + if (incoming_len == 0) { + continue; + } - close(sock); - + if (incoming_len > MAX_GRAPH_TRACE_LEN) { + PrintAndLogEx(ERR, "Received length " _RED_("%u") " exceeds buffer size %u, dropping", incoming_len, (uint32_t)MAX_GRAPH_TRACE_LEN); + break; + } + + PrintAndLogEx(INFO, "Received " _YELLOW_("%u") " samples. Processing...", incoming_len); + + int rx = relay_recv_all(sock, g_GraphBuffer, incoming_len * sizeof(int32_t)); + if (rx < 0) { + PrintAndLogEx(ERR, "Short read receiving sample data"); + break; + } + + // if previous simulation running, we need to break it. + SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + msleep(300); + + g_GraphTraceLen = incoming_len; + lf_chk_bitstream(); + lfsim_upload_gb(); + + struct { + uint16_t len; + uint16_t gap; + } PACKED payload; + payload.len = (g_GraphTraceLen > UINT16_MAX) ? UINT16_MAX : (uint16_t)g_GraphTraceLen; + payload.gap = 0; + + clearCommandBuffer(); + SendCommandNG(CMD_LF_SIMULATE, (uint8_t *)&payload, sizeof(payload)); + + PrintAndLogEx(SUCCESS, "Simulation active."); + } + + relay_close(sock); return PM3_SUCCESS; } diff --git a/client/src/relay/relay.h b/client/src/relay/relay.h new file mode 100644 index 000000000..d5397e5b1 --- /dev/null +++ b/client/src/relay/relay.h @@ -0,0 +1,62 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// TCP relay socket abstraction layer +//----------------------------------------------------------------------------- + +#ifndef RELAY_H__ +#define RELAY_H__ + +#include "common.h" + +#ifdef _WIN32 +#include +typedef SOCKET relay_socket_t; +#define RELAY_SOCKET_INVALID INVALID_SOCKET +#else +typedef int relay_socket_t; +#define RELAY_SOCKET_INVALID (-1) +#endif + +// Initialize relay subsystem (call once at startup). +// On Win32 this calls WSAStartup; on POSIX it is a no-op. +int relay_init(void); + +// Tear down relay subsystem (call once at shutdown). +// On Win32 this calls WSACleanup; on POSIX it is a no-op. +void relay_cleanup(void); + +// Create a TCP server socket bound to INADDR_ANY:, listen, and +// block until one client connects. Returns the *client* fd/SOCKET. +// On error, returns RELAY_SOCKET_INVALID. Caller owns both sockets; +// the listening socket is written to *listen_sock so it can be closed. +relay_socket_t relay_listen_accept(uint16_t port, relay_socket_t *listen_sock); + +// Connect to a TCP server at ip:port. +// Returns the connected socket or RELAY_SOCKET_INVALID on error. +relay_socket_t relay_connect(const char *ip, uint16_t port); + +// Send exactly `len` bytes from `buf`. +// Returns 0 on success, -1 on error. +int relay_send_all(relay_socket_t sock, const void *buf, uint32_t len); + +// Receive exactly `len` bytes into `buf`. +// Returns number of bytes received, or -1 on error / disconnect. +int relay_recv_all(relay_socket_t sock, void *buf, uint32_t len); + +// Close a relay socket. +void relay_close(relay_socket_t sock); + +#endif // RELAY_H__ diff --git a/client/src/relay/relay_posix.c b/client/src/relay/relay_posix.c new file mode 100644 index 000000000..e276d1cfc --- /dev/null +++ b/client/src/relay/relay_posix.c @@ -0,0 +1,148 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// TCP relay socket abstraction — POSIX implementation +//----------------------------------------------------------------------------- + +#ifndef _WIN32 + +#include "relay.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "ui.h" + +int relay_init(void) { + return PM3_SUCCESS; +} + +void relay_cleanup(void) { +} + +relay_socket_t relay_listen_accept(uint16_t port, relay_socket_t *listen_sock) { + + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + PrintAndLogEx(ERR, "Failed to create socket (%s)", strerror(errno)); + return RELAY_SOCKET_INVALID; + } + + int opt = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = htons(port), + .sin_addr.s_addr = INADDR_ANY + }; + + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + PrintAndLogEx(ERR, "Failed to bind to port " _RED_("%u") " (%s)", port, strerror(errno)); + close(sock); + return RELAY_SOCKET_INVALID; + } + + if (listen(sock, 1) < 0) { + PrintAndLogEx(ERR, "Failed to listen on socket (%s)", strerror(errno)); + close(sock); + return RELAY_SOCKET_INVALID; + } + + PrintAndLogEx(INFO, "Relay listening on port " _YELLOW_("%u") "...", port); + + int client = accept(sock, NULL, NULL); + if (client < 0) { + PrintAndLogEx(ERR, "Failed to accept connection (%s)", strerror(errno)); + close(sock); + return RELAY_SOCKET_INVALID; + } + + if (listen_sock != NULL) { + *listen_sock = sock; + } + + return client; +} + +relay_socket_t relay_connect(const char *ip, uint16_t port) { + + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0) { + PrintAndLogEx(ERR, "Failed to create socket (%s)", strerror(errno)); + return RELAY_SOCKET_INVALID; + } + + struct sockaddr_in addr = {0}; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + + if (inet_pton(AF_INET, ip, &addr.sin_addr) <= 0) { + PrintAndLogEx(ERR, "Invalid IP address... %s:%u", ip, port); + close(sock); + return RELAY_SOCKET_INVALID; + } + + if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + PrintAndLogEx(ERR, "Connection error to %s:%u (%s)", ip, port, strerror(errno)); + close(sock); + return RELAY_SOCKET_INVALID; + } + + return sock; +} + +int relay_send_all(relay_socket_t sock, const void *buf, uint32_t len) { + const uint8_t *p = (const uint8_t *)buf; + uint32_t remaining = len; + + while (remaining > 0) { + ssize_t n = send(sock, p, remaining, 0); + if (n <= 0) { + return -1; + } + p += n; + remaining -= (uint32_t)n; + } + return 0; +} + +int relay_recv_all(relay_socket_t sock, void *buf, uint32_t len) { + uint8_t *p = (uint8_t *)buf; + uint32_t remaining = len; + + while (remaining > 0) { + ssize_t n = recv(sock, p, remaining, 0); + if (n <= 0) { + return -1; + } + p += n; + remaining -= (uint32_t)n; + } + return (int)len; +} + +void relay_close(relay_socket_t sock) { + if (sock != RELAY_SOCKET_INVALID) { + close(sock); + } +} + +#endif // !_WIN32 diff --git a/client/src/relay/relay_win32.c b/client/src/relay/relay_win32.c new file mode 100644 index 000000000..aba106e7a --- /dev/null +++ b/client/src/relay/relay_win32.c @@ -0,0 +1,175 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// TCP relay socket abstraction — Win32 implementation +//----------------------------------------------------------------------------- + +#ifdef _WIN32 + +#include "relay.h" + +#include +#include + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +#include "ui.h" + +static bool g_wsa_initialized = false; + +int relay_init(void) { + if (g_wsa_initialized) { + return PM3_SUCCESS; + } + + WSADATA wsa; + int ret = WSAStartup(MAKEWORD(2, 2), &wsa); + if (ret != 0) { + PrintAndLogEx(ERR, "WSAStartup failed with error %d", ret); + return PM3_EFAILED; + } + + g_wsa_initialized = true; + return PM3_SUCCESS; +} + +void relay_cleanup(void) { + if (g_wsa_initialized) { + WSACleanup(); + g_wsa_initialized = false; + } +} + +relay_socket_t relay_listen_accept(uint16_t port, relay_socket_t *listen_sock) { + + if (relay_init() != PM3_SUCCESS) { + return RELAY_SOCKET_INVALID; + } + + SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock == INVALID_SOCKET) { + PrintAndLogEx(ERR, "Failed to create socket (WSA %d)", WSAGetLastError()); + return RELAY_SOCKET_INVALID; + } + + int opt = 1; + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt)); + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = INADDR_ANY; + + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) { + PrintAndLogEx(ERR, "Failed to bind to port " _RED_("%u") " (WSA %d)", port, WSAGetLastError()); + closesocket(sock); + return RELAY_SOCKET_INVALID; + } + + if (listen(sock, 1) == SOCKET_ERROR) { + PrintAndLogEx(ERR, "Failed to listen on socket (WSA %d)", WSAGetLastError()); + closesocket(sock); + return RELAY_SOCKET_INVALID; + } + + PrintAndLogEx(INFO, "Relay listening on port " _YELLOW_("%u") "...", port); + + SOCKET client = accept(sock, NULL, NULL); + if (client == INVALID_SOCKET) { + PrintAndLogEx(ERR, "Failed to accept connection (WSA %d)", WSAGetLastError()); + closesocket(sock); + return RELAY_SOCKET_INVALID; + } + + if (listen_sock != NULL) { + *listen_sock = sock; + } + + return client; +} + +relay_socket_t relay_connect(const char *ip, uint16_t port) { + + if (relay_init() != PM3_SUCCESS) { + return RELAY_SOCKET_INVALID; + } + + SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (sock == INVALID_SOCKET) { + PrintAndLogEx(ERR, "Failed to create socket (WSA %d)", WSAGetLastError()); + return RELAY_SOCKET_INVALID; + } + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + + if (inet_pton(AF_INET, ip, &addr.sin_addr) <= 0) { + PrintAndLogEx(ERR, "Invalid IP address... %s:%u", ip, port); + closesocket(sock); + return RELAY_SOCKET_INVALID; + } + + if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR) { + PrintAndLogEx(ERR, "Connection error to %s:%u (WSA %d)", ip, port, WSAGetLastError()); + closesocket(sock); + return RELAY_SOCKET_INVALID; + } + + return sock; +} + +int relay_send_all(relay_socket_t sock, const void *buf, uint32_t len) { + const char *p = (const char *)buf; + uint32_t remaining = len; + + while (remaining > 0) { + int n = send(sock, p, (int)remaining, 0); + if (n == SOCKET_ERROR || n <= 0) { + return -1; + } + p += n; + remaining -= (uint32_t)n; + } + return 0; +} + +int relay_recv_all(relay_socket_t sock, void *buf, uint32_t len) { + char *p = (char *)buf; + uint32_t remaining = len; + + while (remaining > 0) { + int n = recv(sock, p, (int)remaining, 0); + if (n == SOCKET_ERROR || n <= 0) { + return -1; + } + p += n; + remaining -= (uint32_t)n; + } + return (int)len; +} + +void relay_close(relay_socket_t sock) { + if (sock != INVALID_SOCKET) { + closesocket(sock); + } +} + +#endif // _WIN32