diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index f14b2d50f..d92c15fbe 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -288,6 +288,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/mifare/desfiretest.c ${PM3_ROOT}/client/src/mifare/gallaghercore.c ${PM3_ROOT}/client/src/uart/ringbuffer.c + ${PM3_ROOT}/client/src/uart/uart_common.c ${PM3_ROOT}/client/src/uart/uart_posix.c ${PM3_ROOT}/client/src/uart/uart_win32.c ${PM3_ROOT}/client/src/ui/overlays.ui diff --git a/client/Makefile b/client/Makefile index 6534f27a0..fc0dedb82 100644 --- a/client/Makefile +++ b/client/Makefile @@ -713,6 +713,7 @@ SRCS = mifare/aiddesfire.c \ proxmark3.c \ scandir.c \ uart/ringbuffer.c \ + uart/uart_common.c \ uart/uart_posix.c \ uart/uart_win32.c \ scripting.c \ diff --git a/client/experimental_lib/CMakeLists.txt b/client/experimental_lib/CMakeLists.txt index 9dae9d64b..15a74d38c 100644 --- a/client/experimental_lib/CMakeLists.txt +++ b/client/experimental_lib/CMakeLists.txt @@ -289,6 +289,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/mifare/desfiretest.c ${PM3_ROOT}/client/src/mifare/gallaghercore.c ${PM3_ROOT}/client/src/uart/ringbuffer.c + ${PM3_ROOT}/client/src/uart/uart_common.c ${PM3_ROOT}/client/src/uart/uart_posix.c ${PM3_ROOT}/client/src/uart/uart_win32.c ${PM3_ROOT}/client/src/ui/overlays.ui diff --git a/client/src/uart/uart.h b/client/src/uart/uart.h index 954fa6685..cb67d7482 100644 --- a/client/src/uart/uart.h +++ b/client/src/uart/uart.h @@ -84,6 +84,11 @@ uint32_t uart_get_timeouts(void); /* Specify the outbound address and port for TCP/UDP connections */ -bool uart_bind(void *socket, char *bindAddrStr, char *bindPortStr, bool isBindingIPv6); +bool uart_bind(void *socket, const char *bindAddrStr, const char *bindPortStr, bool isBindingIPv6); + +/* Parse address and port from string. + This could change the addrPortStr + */ +int uart_parse_address_port(char *addrPortStr, const char **addrStr, const char **portStr, bool *isIPv6); #endif // _UART_H_ diff --git a/client/src/uart/uart_common.c b/client/src/uart/uart_common.c new file mode 100644 index 000000000..3e7fc5fb5 --- /dev/null +++ b/client/src/uart/uart_common.c @@ -0,0 +1,134 @@ +//----------------------------------------------------------------------------- +// 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. +//----------------------------------------------------------------------------- +// Generic uart / rs232/ serial port library +//----------------------------------------------------------------------------- + +#include "uart.h" + +#include +#include +#include + +#include "comms.h" +#include "ui.h" + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#else +#include +#include +#include +#include +#include +#endif + +bool uart_bind(void *socket, const char *bindAddrStr, const char *bindPortStr, bool isBindingIPv6) { + if (bindAddrStr == NULL && bindPortStr == NULL) + return true; // no need to bind + + struct sockaddr_storage bindSockaddr; + memset(&bindSockaddr, 0, sizeof(bindSockaddr)); + int bindPort = 0; // 0: port unspecified + if (bindPortStr != NULL) + bindPort = atoi(bindPortStr); + + if (!isBindingIPv6) { + struct sockaddr_in *bindSockaddr4 = (struct sockaddr_in *)&bindSockaddr; + bindSockaddr4->sin_family = AF_INET; + bindSockaddr4->sin_port = htons(bindPort); + if (bindAddrStr == NULL) + bindSockaddr4->sin_addr.s_addr = INADDR_ANY; + else + bindSockaddr4->sin_addr.s_addr = inet_addr(bindAddrStr); + } else { + struct sockaddr_in6 *bindSockaddr6 = (struct sockaddr_in6 *)&bindSockaddr; + bindSockaddr6->sin6_family = AF_INET6; + bindSockaddr6->sin6_port = htons(bindPort); + if (bindAddrStr == NULL) + bindSockaddr6->sin6_addr = in6addr_any; + else + inet_pton(AF_INET6, bindAddrStr, &(bindSockaddr6->sin6_addr)); + } +#ifdef _WIN32 + int res = bind(*(SOCKET *)socket, (struct sockaddr *)&bindSockaddr, sizeof(bindSockaddr)); +#else + int res = bind(*(int *)socket, (struct sockaddr *)&bindSockaddr, sizeof(bindSockaddr)); +#endif + return (res >= 0); +} + +int uart_parse_address_port(char *addrPortStr, const char **addrStr, const char **portStr, bool *isIPv6) { + + if (addrPortStr == NULL || addrStr == NULL || portStr == NULL) { + return PM3_EINVARG; + } + + *addrStr = addrPortStr; + *portStr = NULL; + + // find the start of the address + char *endBracket = strrchr(addrPortStr, ']'); + if (addrPortStr[0] == '[') { + *addrStr += 1; + if (endBracket == NULL) { + // [] unmatched + return PM3_ESOFT; + } + } + + if (isIPv6 != NULL) { + // Assume v4 + *isIPv6 = false; + } + + // find the port + char *lColon = strchr(addrPortStr, ':'); + char *rColon = strrchr(addrPortStr, ':'); + if (rColon == NULL) { + // no colon + // "", "[]" + *portStr = NULL; + } else if (lColon == rColon) { + // only one colon + // ":", "[]:" + *portStr = rColon + 1; + } else { + // two or more colon, IPv6 address + // "[]:" + // "", "[]" + if (endBracket != NULL && rColon == endBracket + 1) { + *portStr = rColon + 1; + } else { + *portStr = NULL; + } + + if (isIPv6 != NULL) { + *isIPv6 = true; + } + } + + // handle the end of the address + if (endBracket != NULL) { + *endBracket = '\0'; + } else if (rColon != NULL && lColon == rColon) { + *rColon = '\0'; + } + + return PM3_SUCCESS; +} \ No newline at end of file diff --git a/client/src/uart/uart_posix.c b/client/src/uart/uart_posix.c index 2a74df483..c29c72826 100644 --- a/client/src/uart/uart_posix.c +++ b/client/src/uart/uart_posix.c @@ -103,19 +103,29 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) { } str_lower(prefix); - if (memcmp(prefix, "tcp:", 4) == 0) { - free(prefix); + bool isTCP = false; + bool isUDP = false; + bool isBluetooth = false; + bool isUnixSocket = false; + if (strlen(prefix) > 4) + { + isTCP = (memcmp(prefix, "tcp:", 4) == 0); + isUDP = (memcmp(prefix, "udp:", 4) == 0); + } + if (strlen(prefix) > 3) { + isBluetooth = (memcmp(prefix, "bt:", 3) == 0); + } + if (strlen(prefix) > 7) { + isUnixSocket = (memcmp(prefix, "socket:", 7) == 0); + } - if (strlen(pcPortName) <= 4) { - free(sp); - return INVALID_SERIAL_PORT; - } + if (isTCP || isUDP) { + + free(prefix); struct addrinfo *addr = NULL, *rp; char *addrPortStr = str_dup(pcPortName + 4); - char *addrstr = addrPortStr; - const char *portstr; if (addrPortStr == NULL) { PrintAndLogEx(ERR, "error: string duplication"); free(sp); @@ -126,54 +136,24 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) { // find the "bind" option char *bindAddrPortStr = strstr(addrPortStr, ",bind="); - char *bindAddrStr = NULL; - char *bindPortStr = NULL; - bool isBindingIPv6 = false; // Assume v4 + const char *bindAddrStr = NULL; + const char *bindPortStr = NULL; + bool isBindingIPv6 = false; + if (bindAddrPortStr != NULL) { *bindAddrPortStr = '\0'; // as the end of target address (and port) - bindAddrPortStr += 6; - bindAddrStr = bindAddrPortStr; + bindAddrPortStr += 6; // strlen(",bind=") - // find the start of the bind address - char *endBracket = strrchr(bindAddrPortStr, ']'); - if (bindAddrPortStr[0] == '[') { - bindAddrStr += 1; - if (endBracket == NULL) { + int result = uart_parse_address_port(bindAddrPortStr, &bindAddrStr, &bindPortStr, &isBindingIPv6); + if (result != PM3_SUCCESS) { + if (result == PM3_ESOFT) { PrintAndLogEx(ERR, "error: wrong address: [] unmatched in bind option"); - free(addrPortStr); - free(sp); - return INVALID_SERIAL_PORT; - } - } - - // find the bind port - char *lColon = strchr(bindAddrPortStr, ':'); - char *rColon = strrchr(bindAddrPortStr, ':'); - if (rColon == NULL) { - // no colon - // ",bind=", ",bind=[]" - bindPortStr = NULL; - } else if (lColon == rColon) { - // only one colon - // ",bind=:", ",bind=[]:" - bindPortStr = rColon + 1; - } else { - // two or more colon, IPv6 address - // ",bind=[]:" - // ",bind=", ",bind=[]" - if (endBracket != NULL && rColon == endBracket + 1) { - bindPortStr = rColon + 1; } else { - bindPortStr = NULL; + PrintAndLogEx(ERR, "error: failed to parse address and port in bind option"); } - isBindingIPv6 = true; - } - - // handle the end of the bind address - if (endBracket != NULL) { - *endBracket = '\0'; - } else if (rColon != NULL && lColon == rColon) { - *rColon = '\0'; + free(addrPortStr); + free(sp); + return INVALID_SERIAL_PORT; } // for bind option, it's possible to only specify address or port @@ -183,68 +163,41 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) { bindPortStr = NULL; } - // find the start of the address - char *endBracket = strrchr(addrPortStr, ']'); - if (addrPortStr[0] == '[') { - addrstr += 1; - if (endBracket == NULL) { + const char *addrStr = NULL; + const char *portStr = NULL; + bool isIPv6 = false; + + int result = uart_parse_address_port(addrPortStr, &addrStr, &portStr, &isIPv6); + if (result != PM3_SUCCESS) { + if (result == PM3_ESOFT) { PrintAndLogEx(ERR, "error: wrong address: [] unmatched"); - free(addrPortStr); - free(sp); - return INVALID_SERIAL_PORT; - } - } - - - // assume v4 - g_conn.send_via_ip = PM3_TCPv4; - - // find the port - char *lColon = strchr(addrPortStr, ':'); - char *rColon = strrchr(addrPortStr, ':'); - if (rColon == NULL) { - // no colon - // "tcp:", "tcp:[]" - portstr = "18888"; - } else if (lColon == rColon) { - // only one colon - // "tcp::", "tcp:[]:" - portstr = rColon + 1; - } else { - // two or more colon, IPv6 address - // "tcp:[]:" - // "tcp:", "tcp:[]" - if (endBracket != NULL && rColon == endBracket + 1) { - portstr = rColon + 1; } else { - portstr = "18888"; + PrintAndLogEx(ERR, "error: failed to parse address and port"); } - g_conn.send_via_ip = PM3_TCPv6; + free(addrPortStr); + free(sp); + return INVALID_SERIAL_PORT; } - // handle the end of the address - if (endBracket != NULL) { - *endBracket = '\0'; - } else if (rColon != NULL && lColon == rColon) { - *rColon = '\0'; - } + g_conn.send_via_ip = isIPv6 ? (isTCP ? PM3_TCPv6 : PM3_UDPv6) : (isTCP ? PM3_TCPv4 : PM3_UDPv4); + portStr = (portStr == NULL) ? "18888" : portStr; struct addrinfo info; memset(&info, 0, sizeof(info)); info.ai_family = PF_UNSPEC; - info.ai_socktype = SOCK_STREAM; + info.ai_socktype = isTCP ? SOCK_STREAM : SOCK_DGRAM; - if ((strstr(addrstr, "localhost") != NULL) || - (strstr(addrstr, "127.0.0.1") != NULL) || - (strstr(addrstr, "::1") != NULL)) { + if ((strstr(addrStr, "localhost") != NULL) || + (strstr(addrStr, "127.0.0.1") != NULL) || + (strstr(addrStr, "::1") != NULL)) { g_conn.send_via_local_ip = true; } - int s = getaddrinfo(addrstr, portstr, &info, &addr); + int s = getaddrinfo(addrStr, portStr, &info, &addr); if (s != 0) { - PrintAndLogEx(ERR, "error: getaddrinfo: %s", gai_strerror(s)); + PrintAndLogEx(ERR, "error: getaddrinfo: %d: %s", s, gai_strerror(s)); freeaddrinfo(addr); free(addrPortStr); free(sp); @@ -284,205 +237,26 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) { sp->fd = sfd; - int one = 1; - int res = setsockopt(sp->fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)); - if (res != 0) { - free(sp); - return INVALID_SERIAL_PORT; + if (isTCP) { + int one = 1; + int res = setsockopt(sp->fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one)); + if (res != 0) { + free(sp); + return INVALID_SERIAL_PORT; + } + } else if (isUDP) { + sp->udpBuffer = RingBuf_create(MAX(sizeof(PacketResponseNGRaw), sizeof(PacketResponseOLD)) * 30); } return sp; } - if (memcmp(prefix, "udp:", 4) == 0) { - free(prefix); - - if (strlen(pcPortName) <= 4) { - free(sp); - return INVALID_SERIAL_PORT; - } - - struct addrinfo *addr = NULL, *rp; - - char *addrPortStr = str_dup(pcPortName + 4); - char *addrstr = addrPortStr; - const char *portstr; - if (addrPortStr == NULL) { - PrintAndLogEx(ERR, "error: string duplication"); - free(sp); - return INVALID_SERIAL_PORT; - } - - timeout.tv_usec = UART_NET_CLIENT_RX_TIMEOUT_MS * 1000; - - // find the "bind" option - char *bindAddrPortStr = strstr(addrPortStr, ",bind="); - char *bindAddrStr = NULL; - char *bindPortStr = NULL; - bool isBindingIPv6 = false; // Assume v4 - if (bindAddrPortStr != NULL) { - *bindAddrPortStr = '\0'; // as the end of target address (and port) - bindAddrPortStr += 6; - bindAddrStr = bindAddrPortStr; - - // find the start of the bind address - char *endBracket = strrchr(bindAddrPortStr, ']'); - if (bindAddrPortStr[0] == '[') { - bindAddrStr += 1; - if (endBracket == NULL) { - PrintAndLogEx(ERR, "error: wrong address: [] unmatched in bind option"); - free(addrPortStr); - free(sp); - return INVALID_SERIAL_PORT; - } - } - - // find the bind port - char *lColon = strchr(bindAddrPortStr, ':'); - char *rColon = strrchr(bindAddrPortStr, ':'); - if (rColon == NULL) { - // no colon - // ",bind=", ",bind=[]" - bindPortStr = NULL; - } else if (lColon == rColon) { - // only one colon - // ",bind=:", ",bind=[]:" - bindPortStr = rColon + 1; - } else { - // two or more colon, IPv6 address - // ",bind=[]:" - // ",bind=", ",bind=[]" - if (endBracket != NULL && rColon == endBracket + 1) { - bindPortStr = rColon + 1; - } else { - bindPortStr = NULL; - } - isBindingIPv6 = true; - } - - // handle the end of the bind address - if (endBracket != NULL) { - *endBracket = '\0'; - } else if (rColon != NULL && lColon == rColon) { - *rColon = '\0'; - } - - // for bind option, it's possible to only specify address or port - if (strlen(bindAddrStr) == 0) - bindAddrStr = NULL; - if (bindPortStr != NULL && strlen(bindPortStr) == 0) - bindPortStr = NULL; - } - - // find the start of the address - char *endBracket = strrchr(addrPortStr, ']'); - if (addrPortStr[0] == '[') { - addrstr += 1; - if (endBracket == NULL) { - PrintAndLogEx(ERR, "error: wrong address: [] unmatched"); - free(addrPortStr); - free(sp); - return INVALID_SERIAL_PORT; - } - } - - // Assume v4 - g_conn.send_via_ip = PM3_UDPv4; - - // find the port - char *lColon = strchr(addrPortStr, ':'); - char *rColon = strrchr(addrPortStr, ':'); - if (rColon == NULL) { - // no colon - // "udp:", "udp:[]" - portstr = "18888"; - } else if (lColon == rColon) { - // only one colon - // "udp::", "udp:[]:" - portstr = rColon + 1; - } else { - // two or more colon, IPv6 address - // "udp:[]:" - // "udp:", "udp:[]" - if (endBracket != NULL && rColon == endBracket + 1) { - portstr = rColon + 1; - } else { - portstr = "18888"; - } - g_conn.send_via_ip = PM3_UDPv6; - } - - // handle the end of the address - if (endBracket != NULL) { - *endBracket = '\0'; - } else if (rColon != NULL && lColon == rColon) { - *rColon = '\0'; - } - - struct addrinfo info; - - memset(&info, 0, sizeof(info)); - - info.ai_family = PF_UNSPEC; - info.ai_socktype = SOCK_DGRAM; - - if ((strstr(addrstr, "localhost") != NULL) || - (strstr(addrstr, "127.0.0.1") != NULL) || - (strstr(addrstr, "::1") != NULL)) { - g_conn.send_via_local_ip = true; - } - - int s = getaddrinfo(addrstr, portstr, &info, &addr); - if (s != 0) { - PrintAndLogEx(ERR, "error: getaddrinfo: %s", gai_strerror(s)); - freeaddrinfo(addr); - free(addrPortStr); - free(sp); - return INVALID_SERIAL_PORT; - } - - int sfd; - for (rp = addr; rp != NULL; rp = rp->ai_next) { - sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - - if (sfd == -1) - continue; - - if (!uart_bind(&sfd, bindAddrStr, bindPortStr, isBindingIPv6)) { - PrintAndLogEx(ERR, "error: Could not bind. errno: %d", errno); - close(sfd); - freeaddrinfo(addr); - free(addrPortStr); - free(sp); - return INVALID_SERIAL_PORT; - } - - if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) - break; - - close(sfd); - } - - freeaddrinfo(addr); - free(addrPortStr); - - if (rp == NULL) { /* No address succeeded */ - PrintAndLogEx(ERR, "error: Could not connect"); - free(sp); - return INVALID_SERIAL_PORT; - } - - sp->fd = sfd; - sp->udpBuffer = RingBuf_create(MAX(sizeof(PacketResponseNGRaw), sizeof(PacketResponseOLD)) * 30); - return sp; - } - - - if (memcmp(prefix, "bt:", 3) == 0) { + if (isBluetooth) { free(prefix); #ifdef HAVE_BLUEZ if (strlen(pcPortName) != 20) { + PrintAndLogEx(ERR, "Error: wrong Bluetooth MAC address length"); free(sp); return INVALID_SERIAL_PORT; } @@ -534,14 +308,9 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) { // Is local socket buffer, not a TCP or any net connection! // so, you can't connect with address like: 127.0.0.1, or any IP // see http://man7.org/linux/man-pages/man7/unix.7.html - if (memcmp(prefix, "socket:", 7) == 0) { + if (isUnixSocket) { free(prefix); - if (strlen(pcPortName) <= 7) { - free(sp); - return INVALID_SERIAL_PORT; - } - // we must use max timeout! timeout.tv_usec = UART_NET_CLIENT_RX_TIMEOUT_MS * 1000; @@ -1011,36 +780,4 @@ uint32_t uart_get_speed(const serial_port sp) { return uiPortSpeed; } -bool uart_bind(void *socket, char *bindAddrStr, char *bindPortStr, bool isBindingIPv6) { - if (bindAddrStr == NULL && bindPortStr == NULL) - return true; // no need to bind - - struct sockaddr_storage bindSockaddr; - memset(&bindSockaddr, 0, sizeof(bindSockaddr)); - int bindPort = 0; // 0: port unspecified - if (bindPortStr != NULL) - bindPort = atoi(bindPortStr); - - if (!isBindingIPv6) { - struct sockaddr_in *bindSockaddr4 = (struct sockaddr_in *)&bindSockaddr; - bindSockaddr4->sin_family = AF_INET; - bindSockaddr4->sin_port = htons(bindPort); - if (bindAddrStr == NULL) - bindSockaddr4->sin_addr.s_addr = INADDR_ANY; - else - bindSockaddr4->sin_addr.s_addr = inet_addr(bindAddrStr); - } else { - struct sockaddr_in6 *bindSockaddr6 = (struct sockaddr_in6 *)&bindSockaddr; - bindSockaddr6->sin6_family = AF_INET6; - bindSockaddr6->sin6_port = htons(bindPort); - if (bindAddrStr == NULL) - bindSockaddr6->sin6_addr = in6addr_any; - else - inet_pton(AF_INET6, bindAddrStr, &(bindSockaddr6->sin6_addr)); - } - - int res = bind(*(int *)socket, (struct sockaddr *)&bindSockaddr, sizeof(bindSockaddr)); - return (res >= 0); -} - #endif diff --git a/client/src/uart/uart_win32.c b/client/src/uart/uart_win32.c index b2e6a0adc..97ecd41bd 100644 --- a/client/src/uart/uart_win32.c +++ b/client/src/uart/uart_win32.c @@ -104,227 +104,20 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) { } str_lower(prefix); - if (memcmp(prefix, "tcp:", 4) == 0) { - free(prefix); - - if (strlen(pcPortName) <= 4) { - PrintAndLogEx(ERR, "error: tcp port name length too short"); - free(sp); - return INVALID_SERIAL_PORT; - } - - struct addrinfo *addr = NULL, *rp; - - char *addrPortStr = str_dup(pcPortName + 4); - char *addrstr = addrPortStr; - const char *portstr; - if (addrPortStr == NULL) { - PrintAndLogEx(ERR, "error: string duplication"); - free(sp); - return INVALID_SERIAL_PORT; - } - - timeout.tv_usec = UART_NET_CLIENT_RX_TIMEOUT_MS * 1000; - - // find the "bind" option - char *bindAddrPortStr = strstr(addrPortStr, ",bind="); - char *bindAddrStr = NULL; - char *bindPortStr = NULL; - bool isBindingIPv6 = false; // Assume v4 - if (bindAddrPortStr != NULL) { - *bindAddrPortStr = '\0'; // as the end of target address (and port) - bindAddrPortStr += 6; - bindAddrStr = bindAddrPortStr; - - // find the start of the bind address - char *endBracket = strrchr(bindAddrPortStr, ']'); - if (bindAddrPortStr[0] == '[') { - bindAddrStr += 1; - if (endBracket == NULL) { - PrintAndLogEx(ERR, "error: wrong address: [] unmatched in bind option"); - free(addrPortStr); - free(sp); - return INVALID_SERIAL_PORT; - } - } - - // find the bind port - char *lColon = strchr(bindAddrPortStr, ':'); - char *rColon = strrchr(bindAddrPortStr, ':'); - if (rColon == NULL) { - // no colon - // ",bind=", ",bind=[]" - bindPortStr = NULL; - } else if (lColon == rColon) { - // only one colon - // ",bind=:", ",bind=[]:" - bindPortStr = rColon + 1; - } else { - // two or more colon, IPv6 address - // ",bind=[]:" - // ",bind=", ",bind=[]" - if (endBracket != NULL && rColon == endBracket + 1) { - bindPortStr = rColon + 1; - } else { - bindPortStr = NULL; - } - isBindingIPv6 = true; - } - - // handle the end of the bind address - if (endBracket != NULL) { - *endBracket = '\0'; - } else if (rColon != NULL && lColon == rColon) { - *rColon = '\0'; - } - - // for bind option, it's possible to only specify address or port - if (strlen(bindAddrStr) == 0) - bindAddrStr = NULL; - if (bindPortStr != NULL && strlen(bindPortStr) == 0) - bindPortStr = NULL; - } - - // find the start of the address - char *endBracket = strrchr(addrPortStr, ']'); - if (addrPortStr[0] == '[') { - addrstr += 1; - if (endBracket == NULL) { - PrintAndLogEx(ERR, "error: wrong address: [] unmatched"); - free(addrPortStr); - free(sp); - return INVALID_SERIAL_PORT; - } - } - - // Assume v4 - g_conn.send_via_ip = PM3_TCPv4; - - // find the port - char *lColon = strchr(addrPortStr, ':'); - char *rColon = strrchr(addrPortStr, ':'); - if (rColon == NULL) { - // no colon - // "tcp:", "tcp:[]" - portstr = "18888"; - } else if (lColon == rColon) { - // only one colon - // "tcp::", "tcp:[]:" - portstr = rColon + 1; - } else { - // two or more colon, IPv6 address - // "tcp:[]:" - // "tcp:", "tcp:[]" - if (endBracket != NULL && rColon == endBracket + 1) { - portstr = rColon + 1; - } else { - portstr = "18888"; - } - g_conn.send_via_ip = PM3_TCPv6; - } - - // handle the end of the address - if (endBracket != NULL) { - *endBracket = '\0'; - } else if (rColon != NULL && lColon == rColon) { - *rColon = '\0'; - } - - WSADATA wsaData; - struct addrinfo info; - int iResult; - - iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); - if (iResult != 0) { - PrintAndLogEx(ERR, "error: WSAStartup failed with error: %d", iResult); - free(addrPortStr); - free(sp); - return INVALID_SERIAL_PORT; - } - - memset(&info, 0, sizeof(info)); - info.ai_family = AF_UNSPEC; - info.ai_socktype = SOCK_STREAM; - info.ai_protocol = IPPROTO_TCP; - - if ((strstr(addrstr, "localhost") != NULL) || - (strstr(addrstr, "127.0.0.1") != NULL) || - (strstr(addrstr, "::1") != NULL)) { - g_conn.send_via_local_ip = true; - } - - int s = getaddrinfo(addrstr, portstr, &info, &addr); - if (s != 0) { - PrintAndLogEx(ERR, "error: getaddrinfo: %d: %s", s, gai_strerror(s)); - freeaddrinfo(addr); - free(addrPortStr); - free(sp); - WSACleanup(); - return INVALID_SERIAL_PORT; - } - - SOCKET hSocket = INVALID_SOCKET; - for (rp = addr; rp != NULL; rp = rp->ai_next) { - hSocket = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); - - if (hSocket == INVALID_SOCKET) - continue; - - if (!uart_bind(&hSocket, bindAddrStr, bindPortStr, isBindingIPv6)) { - PrintAndLogEx(ERR, "error: Could not bind. error: %u", WSAGetLastError()); - closesocket(hSocket); - hSocket = INVALID_SOCKET; - freeaddrinfo(addr); - free(addrPortStr); - free(sp); - WSACleanup(); - return INVALID_SERIAL_PORT; - } - - if (connect(hSocket, rp->ai_addr, (int)rp->ai_addrlen) != INVALID_SOCKET) - break; - - closesocket(hSocket); - hSocket = INVALID_SOCKET; - } - - freeaddrinfo(addr); - free(addrPortStr); - - if (rp == NULL) { /* No address succeeded */ - PrintAndLogEx(ERR, "error: Could not connect"); - WSACleanup(); - free(sp); - return INVALID_SERIAL_PORT; - } - - sp->hSocket = hSocket; - - int one = 1; - int res = setsockopt(sp->hSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)); - if (res != 0) { - closesocket(hSocket); - WSACleanup(); - free(sp); - return INVALID_SERIAL_PORT; - } - return sp; + bool isTCP = false; + bool isUDP = false; + if (strlen(prefix) > 4) { + isTCP = (memcmp(prefix, "tcp:", 4) == 0); + isUDP = (memcmp(prefix, "udp:", 4) == 0); } - if (memcmp(prefix, "udp:", 4) == 0) { - free(prefix); + if (isTCP || isUDP) { - if (strlen(pcPortName) <= 4) { - PrintAndLogEx(ERR, "error: tcp port name length too short"); - free(sp); - return INVALID_SERIAL_PORT; - } + free(prefix); struct addrinfo *addr = NULL, *rp; char *addrPortStr = str_dup(pcPortName + 4); - char *addrstr = addrPortStr; - const char *portstr; if (addrPortStr == NULL) { PrintAndLogEx(ERR, "error: string duplication"); free(sp); @@ -335,54 +128,24 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) { // find the "bind" option char *bindAddrPortStr = strstr(addrPortStr, ",bind="); - char *bindAddrStr = NULL; - char *bindPortStr = NULL; - bool isBindingIPv6 = false; // Assume v4 + const char *bindAddrStr = NULL; + const char *bindPortStr = NULL; + bool isBindingIPv6 = false; + if (bindAddrPortStr != NULL) { *bindAddrPortStr = '\0'; // as the end of target address (and port) - bindAddrPortStr += 6; - bindAddrStr = bindAddrPortStr; + bindAddrPortStr += 6; // strlen(",bind=") - // find the start of the bind address - char *endBracket = strrchr(bindAddrPortStr, ']'); - if (bindAddrPortStr[0] == '[') { - bindAddrStr += 1; - if (endBracket == NULL) { + int result = uart_parse_address_port(bindAddrPortStr, &bindAddrStr, &bindPortStr, &isBindingIPv6); + if (result != PM3_SUCCESS) { + if (result == PM3_ESOFT) { PrintAndLogEx(ERR, "error: wrong address: [] unmatched in bind option"); - free(addrPortStr); - free(sp); - return INVALID_SERIAL_PORT; - } - } - - // find the bind port - char *lColon = strchr(bindAddrPortStr, ':'); - char *rColon = strrchr(bindAddrPortStr, ':'); - if (rColon == NULL) { - // no colon - // ",bind=", ",bind=[]" - bindPortStr = NULL; - } else if (lColon == rColon) { - // only one colon - // ",bind=:", ",bind=[]:" - bindPortStr = rColon + 1; - } else { - // two or more colon, IPv6 address - // ",bind=[]:" - // ",bind=", ",bind=[]" - if (endBracket != NULL && rColon == endBracket + 1) { - bindPortStr = rColon + 1; } else { - bindPortStr = NULL; + PrintAndLogEx(ERR, "error: failed to parse address and port in bind option"); } - isBindingIPv6 = true; - } - - // handle the end of the bind address - if (endBracket != NULL) { - *endBracket = '\0'; - } else if (rColon != NULL && lColon == rColon) { - *rColon = '\0'; + free(addrPortStr); + free(sp); + return INVALID_SERIAL_PORT; } // for bind option, it's possible to only specify address or port @@ -392,50 +155,24 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) { bindPortStr = NULL; } - // find the start of the address - char *endBracket = strrchr(addrPortStr, ']'); - if (addrPortStr[0] == '[') { - addrstr += 1; - if (endBracket == NULL) { + const char *addrStr = NULL; + const char *portStr = NULL; + bool isIPv6 = false; + + int result = uart_parse_address_port(addrPortStr, &addrStr, &portStr, &isIPv6); + if (result != PM3_SUCCESS) { + if (result == PM3_ESOFT) { PrintAndLogEx(ERR, "error: wrong address: [] unmatched"); - free(addrPortStr); - free(sp); - return INVALID_SERIAL_PORT; - } - } - - // Assume v4 - g_conn.send_via_ip = PM3_UDPv4; - - // find the port - char *lColon = strchr(addrPortStr, ':'); - char *rColon = strrchr(addrPortStr, ':'); - if (rColon == NULL) { - // no colon - // "udp:", "udp:[]" - portstr = "18888"; - } else if (lColon == rColon) { - // only one colon - // "udp::", "udp:[]:" - portstr = rColon + 1; - } else { - // two or more colon, IPv6 address - // "udp:[]:" - // "udp:", "udp:[]" - if (endBracket != NULL && rColon == endBracket + 1) { - portstr = rColon + 1; } else { - portstr = "18888"; + PrintAndLogEx(ERR, "error: failed to parse address and port"); } - g_conn.send_via_ip = PM3_UDPv6; + free(addrPortStr); + free(sp); + return INVALID_SERIAL_PORT; } - // handle the end of the address - if (endBracket != NULL) { - *endBracket = '\0'; - } else if (rColon != NULL && lColon == rColon) { - *rColon = '\0'; - } + g_conn.send_via_ip = isIPv6 ? (isTCP ? PM3_TCPv6 : PM3_UDPv6) : (isTCP ? PM3_TCPv4 : PM3_UDPv4); + portStr = (portStr == NULL) ? "18888" : portStr; WSADATA wsaData; struct addrinfo info; @@ -451,16 +188,16 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) { memset(&info, 0, sizeof(info)); info.ai_family = AF_UNSPEC; - info.ai_socktype = SOCK_DGRAM; - info.ai_protocol = IPPROTO_UDP; + info.ai_socktype = isTCP ? SOCK_STREAM : SOCK_DGRAM; + info.ai_protocol = isTCP ? IPPROTO_TCP : IPPROTO_UDP; - if ((strstr(addrstr, "localhost") != NULL) || - (strstr(addrstr, "127.0.0.1") != NULL) || - (strstr(addrstr, "::1") != NULL)) { + if ((strstr(addrStr, "localhost") != NULL) || + (strstr(addrStr, "127.0.0.1") != NULL) || + (strstr(addrStr, "::1") != NULL)) { g_conn.send_via_local_ip = true; } - int s = getaddrinfo(addrstr, portstr, &info, &addr); + int s = getaddrinfo(addrStr, portStr, &info, &addr); if (s != 0) { PrintAndLogEx(ERR, "error: getaddrinfo: %d: %s", s, gai_strerror(s)); freeaddrinfo(addr); @@ -506,7 +243,20 @@ serial_port uart_open(const char *pcPortName, uint32_t speed) { } sp->hSocket = hSocket; - sp->udpBuffer = RingBuf_create(MAX(sizeof(PacketResponseNGRaw), sizeof(PacketResponseOLD)) * 30); + + if (isTCP) { + int one = 1; + int res = setsockopt(sp->hSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)); + if (res != 0) { + closesocket(hSocket); + WSACleanup(); + free(sp); + return INVALID_SERIAL_PORT; + } + } else if (isUDP) { + sp->udpBuffer = RingBuf_create(MAX(sizeof(PacketResponseNGRaw), sizeof(PacketResponseOLD)) * 30); + } + return sp; } @@ -795,36 +545,4 @@ int uart_send(const serial_port sp, const uint8_t *p_tx, const uint32_t len) { } } -bool uart_bind(void *socket, char *bindAddrStr, char *bindPortStr, bool isBindingIPv6) { - if (bindAddrStr == NULL && bindPortStr == NULL) - return true; // no need to bind - - struct sockaddr_storage bindSockaddr; - memset(&bindSockaddr, 0, sizeof(bindSockaddr)); - int bindPort = 0; // 0: port unspecified - if (bindPortStr != NULL) - bindPort = atoi(bindPortStr); - - if (!isBindingIPv6) { - struct sockaddr_in *bindSockaddr4 = (struct sockaddr_in *)&bindSockaddr; - bindSockaddr4->sin_family = AF_INET; - bindSockaddr4->sin_port = htons(bindPort); - if (bindAddrStr == NULL) - bindSockaddr4->sin_addr.s_addr = INADDR_ANY; - else - bindSockaddr4->sin_addr.s_addr = inet_addr(bindAddrStr); - } else { - struct sockaddr_in6 *bindSockaddr6 = (struct sockaddr_in6 *)&bindSockaddr; - bindSockaddr6->sin6_family = AF_INET6; - bindSockaddr6->sin6_port = htons(bindPort); - if (bindAddrStr == NULL) - bindSockaddr6->sin6_addr = in6addr_any; - else - inet_pton(AF_INET6, bindAddrStr, &(bindSockaddr6->sin6_addr)); - } - - int res = bind(*(SOCKET *)socket, (struct sockaddr *)&bindSockaddr, sizeof(bindSockaddr)); - return (res >= 0); -} - #endif diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 33803857d..abee08bb2 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -842,7 +842,7 @@ typedef struct { // all zero's configure: no timeout for read/write used. // took settings from libnfc/buses/uart.c -// uart_windows.c & uart_posix.c +// uart_win32.c & uart_posix.c # define UART_FPC_CLIENT_RX_TIMEOUT_MS 200 # define UART_USB_CLIENT_RX_TIMEOUT_MS 20 # define UART_NET_CLIENT_RX_TIMEOUT_MS 500